diff --git a/scripts/install.sh b/scripts/install.sh index c9dd2a74..e829794e 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -7,7 +7,7 @@ # is missing or stale. # # Usage: -# ./scripts/install.sh [--tool ] [--interactive] [--no-interactive] [--help] +# ./scripts/install.sh [--tool ] [--division ] [--interactive] [--no-interactive] [--help] # # Tools: # claude-code -- Copy agents to ~/.claude/agents/ @@ -23,6 +23,10 @@ # # Flags: # --tool Install only the specified tool +# --division Install only agents from specified division(s) (comma-separated) +# Valid: design, engineering, game-development, marketing, paid-media, +# sales, product, project-management, testing, support, spatial-computing, +# specialized # --interactive Show interactive selector (default when run in a terminal) # --no-interactive Skip interactive selector, install all detected tools # --help Show this help @@ -83,6 +87,58 @@ INTEGRATIONS="$REPO_ROOT/integrations" ALL_TOOLS=(claude-code copilot antigravity gemini-cli opencode openclaw cursor aider windsurf) +# --------------------------------------------------------------------------- +# Division filtering +# --------------------------------------------------------------------------- +ALL_DIVISIONS=( + design engineering game-development marketing paid-media sales product + project-management testing support spatial-computing specialized +) +FILTER_DIVISIONS=() # empty = all divisions + +slugify() { + echo "$1" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//;s/-$//' +} + +get_field() { + sed -n '/^---$/,/^---$/p' "$2" | grep "^${1}:" | head -1 | sed "s/^${1}:[[:space:]]*//" | sed 's/^["'"'"']//;s/["'"'"']$//' +} + +# Return the list of division dirs to install (filtered or all) +active_divisions() { + if [[ ${#FILTER_DIVISIONS[@]} -gt 0 ]]; then + printf '%s\n' "${FILTER_DIVISIONS[@]}" + else + printf '%s\n' "${ALL_DIVISIONS[@]}" + fi +} + +# Build a newline-separated list of allowed slugs from active divisions +_allowed_slugs_cache="" +allowed_slugs() { + if [[ -n "$_allowed_slugs_cache" ]]; then + printf '%s' "$_allowed_slugs_cache" + return + fi + local slugs="" div + for div in $(active_divisions); do + [[ -d "$REPO_ROOT/$div" ]] || continue + while IFS= read -r -d '' f; do + local name; name="$(get_field name "$f")" + [[ -n "$name" ]] && slugs+="$(slugify "$name")"$'\n' + done < <(find "$REPO_ROOT/$div" -name "*.md" -type f -print0) + done + _allowed_slugs_cache="$slugs" + printf '%s' "$slugs" +} + +# Check if a slug matches the allowed set (no-op when no filter) +slug_allowed() { + [[ ${#FILTER_DIVISIONS[@]} -eq 0 ]] && return 0 + local slug="$1" + allowed_slugs | grep -qxF "$slug" +} + # --------------------------------------------------------------------------- # Usage # --------------------------------------------------------------------------- @@ -267,8 +323,7 @@ install_claude_code() { local count=0 mkdir -p "$dest" local dir f first_line - for dir in design engineering game-development marketing paid-media sales product project-management \ - testing support spatial-computing specialized; do + for dir in $(active_divisions); do [[ -d "$REPO_ROOT/$dir" ]] || continue while IFS= read -r -d '' f; do first_line="$(head -1 "$f")" @@ -285,8 +340,7 @@ install_copilot() { local count=0 mkdir -p "$dest" local dir f first_line - for dir in design engineering game-development marketing paid-media sales product project-management \ - testing support spatial-computing specialized; do + for dir in $(active_divisions); do [[ -d "$REPO_ROOT/$dir" ]] || continue while IFS= read -r -d '' f; do first_line="$(head -1 "$f")" @@ -307,6 +361,7 @@ install_antigravity() { local d while IFS= read -r -d '' d; do local name; name="$(basename "$d")" + slug_allowed "$name" || continue mkdir -p "$dest/$name" cp "$d/SKILL.md" "$dest/$name/SKILL.md" (( count++ )) || true @@ -324,6 +379,7 @@ install_gemini_cli() { local d while IFS= read -r -d '' d; do local name; name="$(basename "$d")" + slug_allowed "$name" || continue mkdir -p "$dest/skills/$name" cp "$d/SKILL.md" "$dest/skills/$name/SKILL.md" (( count++ )) || true @@ -339,6 +395,8 @@ install_opencode() { mkdir -p "$dest" local f while IFS= read -r -d '' f; do + local slug; slug="$(basename "$f" .md)" + slug_allowed "$slug" || continue cp "$f" "$dest/"; (( count++ )) || true done < <(find "$src" -maxdepth 1 -name "*.md" -print0) ok "OpenCode: $count agents -> $dest" @@ -354,6 +412,7 @@ install_openclaw() { local d while IFS= read -r -d '' d; do local name; name="$(basename "$d")" + slug_allowed "$name" || continue mkdir -p "$dest/$name" cp "$d/SOUL.md" "$dest/$name/SOUL.md" cp "$d/AGENTS.md" "$dest/$name/AGENTS.md" @@ -378,6 +437,8 @@ install_cursor() { mkdir -p "$dest" local f while IFS= read -r -d '' f; do + local slug; slug="$(basename "$f" .mdc)" + slug_allowed "$slug" || continue cp "$f" "$dest/"; (( count++ )) || true done < <(find "$src" -maxdepth 1 -name "*.mdc" -print0) ok "Cursor: $count rules -> $dest" @@ -434,6 +495,21 @@ main() { while [[ $# -gt 0 ]]; do case "$1" in --tool) tool="${2:?'--tool requires a value'}"; shift 2; interactive_mode="no" ;; + --division) + local divs="${2:?'--division requires a value'}" + IFS=',' read -ra _divs <<< "$divs" + local _d + for _d in "${_divs[@]}"; do + _d="$(echo "$_d" | xargs)" # trim whitespace + local valid_div=false _ad + for _ad in "${ALL_DIVISIONS[@]}"; do [[ "$_ad" == "$_d" ]] && valid_div=true && break; done + if ! $valid_div; then + err "Unknown division '$_d'. Valid: ${ALL_DIVISIONS[*]}" + exit 1 + fi + FILTER_DIVISIONS+=("$_d") + done + shift 2 ;; --interactive) interactive_mode="yes"; shift ;; --no-interactive) interactive_mode="no"; shift ;; --help|-h) usage ;; @@ -496,6 +572,9 @@ main() { header "The Agency -- Installing agents" printf " Repo: %s\n" "$REPO_ROOT" printf " Installing: %s\n" "${SELECTED_TOOLS[*]}" + if [[ ${#FILTER_DIVISIONS[@]} -gt 0 ]]; then + printf " Divisions: %s\n" "${FILTER_DIVISIONS[*]}" + fi printf "\n" local installed=0 t