#!/usr/bin/env bash # # convert.sh — Convert agency agent .md files into tool-specific formats. # # Reads all agent files from the standard category directories and outputs # converted files to integrations//. Run this to regenerate all # integration files after adding or modifying agents. # # Usage: # ./scripts/convert.sh [--tool ] [--out ] [--parallel] [--jobs N] [--help] # # Tools: # antigravity — Antigravity skill files (~/.gemini/antigravity/skills/) # gemini-cli — Gemini CLI subagent files (~/.gemini/agents/*.md) # opencode — OpenCode agent files (.opencode/agents/*.md) # cursor — Cursor rule files (.cursor/rules/*.mdc) # aider — Single CONVENTIONS.md for Aider # windsurf — Single .windsurfrules for Windsurf # openclaw — OpenClaw workspaces (integrations/openclaw//SOUL.md) # qwen — Qwen Code SubAgent files (~/.qwen/agents/*.md) # kimi — Kimi Code CLI agent files (~/.config/kimi/agents/) # codex — Codex custom agent TOML files (~/.codex/agents/*.toml) # all — All tools (default) # # Output is written to integrations// relative to the repo root. # This script never touches user config dirs — see install.sh for that. # # --parallel When tool is 'all', run independent tools in parallel (output order may vary). # --jobs N Max parallel jobs when using --parallel (default: nproc or 4). set -euo pipefail # --- Colour helpers --- if [[ -t 1 && -z "${NO_COLOR:-}" && "${TERM:-}" != "dumb" ]]; then GREEN=$'\033[0;32m'; YELLOW=$'\033[1;33m'; RED=$'\033[0;31m'; BOLD=$'\033[1m'; RESET=$'\033[0m' else GREEN=''; YELLOW=''; RED=''; BOLD=''; RESET='' fi info() { printf "${GREEN}[OK]${RESET} %s\n" "$*"; } warn() { printf "${YELLOW}[!!]${RESET} %s\n" "$*"; } error() { printf "${RED}[ERR]${RESET} %s\n" "$*" >&2; } header() { echo -e "\n${BOLD}$*${RESET}"; } # Progress bar: [=======> ] 3/8 (tqdm-style) progress_bar() { local current="$1" total="$2" width="${3:-20}" i filled empty (( total > 0 )) || return filled=$(( width * current / total )) empty=$(( width - filled )) printf "\r [" for (( i=0; i"; (( empty-- )); fi for (( i=0; i/dev/null) && [[ -n "$n" ]] && echo "$n" && return n=$(sysctl -n hw.ncpu 2>/dev/null) && [[ -n "$n" ]] && echo "$n" && return echo 4 } # --- Frontmatter helpers: get_field / get_body / slugify now live in lib.sh --- # Escape a value for a TOML basic string, including control characters that # cannot appear raw in TOML source. toml_escape_string() { printf '%s' "$1" | perl -0pe ' s/\\/\\\\/g; s/"/\\"/g; s/\n/\\n/g; s/\r/\\r/g; s/\t/\\t/g; s/\f/\\f/g; s/\x08/\\b/g; s/([\x00-\x07\x0B\x0E-\x1F\x7F])/sprintf("\\u%04X", ord($1))/ge; ' } # --- Per-tool converters --- convert_antigravity() { local file="$1" local name description slug outdir outfile body name="$(get_field "name" "$file")" description="$(get_field "description" "$file")" slug="agency-$(slugify "$name")" body="$(get_body "$file")" outdir="$OUT_DIR/antigravity/$slug" outfile="$outdir/SKILL.md" mkdir -p "$outdir" # Antigravity SKILL.md format mirrors community skills in ~/.gemini/antigravity/skills/ cat > "$outfile" < "$outfile" < "$outfile" < "$outfile" < "$outfile" < "$outdir/SOUL.md" < "$outdir/AGENTS.md" < "$outdir/IDENTITY.md" < "$outdir/IDENTITY.md" < "$outfile" < "$outfile" < "$agent_file" < "$outdir/system.md" < "$AIDER_TMP" <<'HEREDOC' # The Agency — AI Agent Conventions # # This file provides Aider with the full roster of specialized AI agents from # The Agency (https://github.com/msitarzewski/agency-agents). # # To activate an agent, reference it by name in your Aider session prompt, e.g.: # "Use the Frontend Developer agent to review this component." # # Generated by scripts/convert.sh — do not edit manually. HEREDOC cat > "$WINDSURF_TMP" <<'HEREDOC' # The Agency — AI Agent Rules for Windsurf # # Full roster of specialized AI agents from The Agency. # To activate an agent, reference it by name in your Windsurf conversation. # # Generated by scripts/convert.sh — do not edit manually. HEREDOC accumulate_aider() { local file="$1" local name description body name="$(get_field "name" "$file")" description="$(get_field "description" "$file")" body="$(get_body "$file")" cat >> "$AIDER_TMP" < ${description} ${body} HEREDOC } accumulate_windsurf() { local file="$1" local name description body name="$(get_field "name" "$file")" description="$(get_field "description" "$file")" body="$(get_body "$file")" cat >> "$WINDSURF_TMP" < "$AGENCY_CONVERT_OUT_DIR/{}" 2>&1' for t in "${parallel_tools[@]}"; do [[ -f "$parallel_out_dir/$t" ]] && cat "$parallel_out_dir/$t" done rm -rf "$parallel_out_dir" local idx=8 for t in aider windsurf; do progress_bar "$idx" "$n_tools" printf "\n" header "Converting: $t ($idx/$n_tools)" local count count="$(run_conversions "$t")" total=$(( total + count )) info "Converted $count agents for $t" (( idx++ )) || true done else local i=0 for t in "${tools_to_run[@]}"; do (( i++ )) || true progress_bar "$i" "$n_tools" printf "\n" header "Converting: $t ($i/$n_tools)" local count count="$(run_conversions "$t")" total=$(( total + count )) info "Converted $count agents for $t" done fi # Write single-file outputs after accumulation if [[ "$tool" == "all" || "$tool" == "aider" ]]; then mkdir -p "$OUT_DIR/aider" cp "$AIDER_TMP" "$OUT_DIR/aider/CONVENTIONS.md" info "Wrote integrations/aider/CONVENTIONS.md" fi if [[ "$tool" == "all" || "$tool" == "windsurf" ]]; then mkdir -p "$OUT_DIR/windsurf" cp "$WINDSURF_TMP" "$OUT_DIR/windsurf/.windsurfrules" info "Wrote integrations/windsurf/.windsurfrules" fi echo "" if $use_parallel && [[ "$tool" == "all" ]]; then info "Done. $n_tools tools (parallel; total conversions not aggregated)." else info "Done. Total conversions: $total" fi } main "$@"