@conductor-oss/conductor-skills 1.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/.claude-plugin/marketplace.json +20 -0
  2. package/.claude-plugin/plugin.json +13 -0
  3. package/LICENSE.txt +176 -0
  4. package/README.md +352 -0
  5. package/VERSION +1 -0
  6. package/bin/conductor-skills.js +135 -0
  7. package/commands/conductor-optimize.md +18 -0
  8. package/commands/conductor-scaffold-worker.md +19 -0
  9. package/commands/conductor-setup.md +15 -0
  10. package/commands/conductor.md +15 -0
  11. package/install.ps1 +677 -0
  12. package/install.sh +855 -0
  13. package/package.json +50 -0
  14. package/skills/conductor/SKILL.md +151 -0
  15. package/skills/conductor/examples/ai-agent-loop.md +119 -0
  16. package/skills/conductor/examples/ai-agent-mcp.md +129 -0
  17. package/skills/conductor/examples/create-and-run-workflow.md +50 -0
  18. package/skills/conductor/examples/do-while-loop.md +72 -0
  19. package/skills/conductor/examples/fork-join.md +52 -0
  20. package/skills/conductor/examples/llm-chat.md +61 -0
  21. package/skills/conductor/examples/llm-rag.md +115 -0
  22. package/skills/conductor/examples/monitor-and-retry.md +54 -0
  23. package/skills/conductor/examples/review-workflow.md +67 -0
  24. package/skills/conductor/examples/signal-wait-task.md +36 -0
  25. package/skills/conductor/examples/sub-workflow.md +52 -0
  26. package/skills/conductor/examples/workflows/ai-agent-loop.json +88 -0
  27. package/skills/conductor/examples/workflows/ai-agent-mcp.json +69 -0
  28. package/skills/conductor/examples/workflows/child-normalize.json +21 -0
  29. package/skills/conductor/examples/workflows/do-while-loop.json +35 -0
  30. package/skills/conductor/examples/workflows/fork-join.json +61 -0
  31. package/skills/conductor/examples/workflows/llm-chat.json +28 -0
  32. package/skills/conductor/examples/workflows/llm-rag.json +49 -0
  33. package/skills/conductor/examples/workflows/parent-pipeline.json +35 -0
  34. package/skills/conductor/examples/workflows/weather-notification.json +42 -0
  35. package/skills/conductor/references/api-reference.md +111 -0
  36. package/skills/conductor/references/cli-index.md +92 -0
  37. package/skills/conductor/references/fallback-cli.md +36 -0
  38. package/skills/conductor/references/optimization.md +148 -0
  39. package/skills/conductor/references/orkes.md +57 -0
  40. package/skills/conductor/references/schedules.md +81 -0
  41. package/skills/conductor/references/setup.md +126 -0
  42. package/skills/conductor/references/troubleshooting.md +35 -0
  43. package/skills/conductor/references/visualization.md +49 -0
  44. package/skills/conductor/references/workers.md +227 -0
  45. package/skills/conductor/references/workflow-definition.md +672 -0
  46. package/skills/conductor/scripts/conductor_api.py +396 -0
package/install.sh ADDED
@@ -0,0 +1,855 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # ─────────────────────────────────────────────────────────────────────────────
5
+ # Conductor Skills Installer
6
+ # Installs Conductor workflow orchestration skills for your AI coding agent.
7
+ # https://github.com/conductor-oss/conductor-skills
8
+ # ─────────────────────────────────────────────────────────────────────────────
9
+
10
+ VERSION="1.4.2"
11
+ # Per-file fetches are pinned to this version's tag so the installer and the
12
+ # files it pulls always come from the same release. Pages can serve a cached
13
+ # install.sh older than `main`; pinning prevents schema drift.
14
+ # `main` is only used for fetch_remote_version (the "is there a newer release?"
15
+ # check), never for file content.
16
+ REPO_BASE="https://raw.githubusercontent.com/conductor-oss/conductor-skills/v${VERSION}"
17
+ REPO_MAIN="https://raw.githubusercontent.com/conductor-oss/conductor-skills/main"
18
+
19
+ # When set, skip the network fetch and copy from this directory instead.
20
+ # The npm package sets this so the bundled files are used.
21
+ LOCAL_DIR="${CONDUCTOR_SKILLS_LOCAL_DIR:-}"
22
+
23
+ # Files to ship to non-Claude agents (Claude uses the marketplace flow).
24
+ SKILL_FILES=(
25
+ "skills/conductor/SKILL.md"
26
+ "skills/conductor/references/setup.md"
27
+ "skills/conductor/references/cli-index.md"
28
+ "skills/conductor/references/fallback-cli.md"
29
+ "skills/conductor/references/workflow-definition.md"
30
+ "skills/conductor/references/workers.md"
31
+ "skills/conductor/references/api-reference.md"
32
+ "skills/conductor/references/visualization.md"
33
+ "skills/conductor/references/schedules.md"
34
+ "skills/conductor/references/orkes.md"
35
+ "skills/conductor/references/optimization.md"
36
+ "skills/conductor/references/troubleshooting.md"
37
+ "skills/conductor/examples/create-and-run-workflow.md"
38
+ "skills/conductor/examples/monitor-and-retry.md"
39
+ "skills/conductor/examples/signal-wait-task.md"
40
+ "skills/conductor/examples/fork-join.md"
41
+ "skills/conductor/examples/do-while-loop.md"
42
+ "skills/conductor/examples/sub-workflow.md"
43
+ "skills/conductor/examples/review-workflow.md"
44
+ "skills/conductor/examples/llm-chat.md"
45
+ "skills/conductor/examples/ai-agent-mcp.md"
46
+ "skills/conductor/examples/ai-agent-loop.md"
47
+ "skills/conductor/examples/llm-rag.md"
48
+ "skills/conductor/examples/workflows/weather-notification.json"
49
+ "skills/conductor/examples/workflows/fork-join.json"
50
+ "skills/conductor/examples/workflows/do-while-loop.json"
51
+ "skills/conductor/examples/workflows/child-normalize.json"
52
+ "skills/conductor/examples/workflows/parent-pipeline.json"
53
+ "skills/conductor/examples/workflows/llm-chat.json"
54
+ "skills/conductor/examples/workflows/ai-agent-mcp.json"
55
+ "skills/conductor/examples/workflows/ai-agent-loop.json"
56
+ "skills/conductor/examples/workflows/llm-rag.json"
57
+ "skills/conductor/scripts/conductor_api.py"
58
+ )
59
+
60
+ # Colors (if terminal supports them)
61
+ if [ -t 1 ]; then
62
+ RED='\033[0;31m'
63
+ GREEN='\033[0;32m'
64
+ YELLOW='\033[1;33m'
65
+ BLUE='\033[0;34m'
66
+ BOLD='\033[1m'
67
+ NC='\033[0m'
68
+ else
69
+ RED='' GREEN='' YELLOW='' BLUE='' BOLD='' NC=''
70
+ fi
71
+
72
+ # ─────────────────────────────────────────────────────────────────────────────
73
+ # Helpers
74
+ # ─────────────────────────────────────────────────────────────────────────────
75
+
76
+ info() { echo -e "${BLUE}[info]${NC} $*"; }
77
+ ok() { echo -e "${GREEN}[ok]${NC} $*"; }
78
+ warn() { echo -e "${YELLOW}[warn]${NC} $*"; }
79
+ error() { echo -e "${RED}[error]${NC} $*" >&2; }
80
+
81
+ usage() {
82
+ cat <<EOF
83
+ ${BOLD}Conductor Skills Installer v${VERSION}${NC}
84
+
85
+ Usage:
86
+ install.sh [--agent <name> | --all] [--global] [--project-dir <path>]
87
+ [--upgrade] [--check] [--force] [--uninstall]
88
+
89
+ Options:
90
+ --agent <name> Install for a specific agent
91
+ --all Auto-detect all agents and install for each
92
+ --global Install globally (available in all projects)
93
+ --project-dir <path> Target project directory (default: current directory)
94
+ --upgrade Check for newer version and upgrade installed agents
95
+ --check Dry run — show what would be installed, no changes
96
+ --force Overwrite existing files without prompting
97
+ --uninstall Remove installed skill files
98
+ --version Print version and exit
99
+ --help Show this help message
100
+
101
+ Supported agents:
102
+ claude Claude Code (Anthropic)
103
+ codex Codex CLI (OpenAI)
104
+ gemini Gemini CLI (Google)
105
+ cursor Cursor
106
+ windsurf Windsurf (Codeium)
107
+ cline Cline
108
+ aider Aider
109
+ copilot GitHub Copilot
110
+ amazonq Amazon Q Developer
111
+ opencode OpenCode
112
+ roo Roo Code
113
+ amp Amp
114
+
115
+ Examples:
116
+ # Auto-detect and install for all agents
117
+ install.sh --all
118
+
119
+ # Install globally for Codex CLI
120
+ install.sh --agent codex --global
121
+
122
+ # Check what would be installed
123
+ install.sh --all --check
124
+
125
+ # Upgrade all installed agents to latest
126
+ install.sh --all --upgrade
127
+
128
+ # Uninstall from all agents
129
+ install.sh --all --uninstall
130
+
131
+ EOF
132
+ exit 0
133
+ }
134
+
135
+ # ─────────────────────────────────────────────────────────────────────────────
136
+ # Agent detection
137
+ # ─────────────────────────────────────────────────────────────────────────────
138
+
139
+ detect_agents() {
140
+ local detected=()
141
+
142
+ command -v claude &>/dev/null && detected+=(claude)
143
+ { command -v codex &>/dev/null || [ -d "$HOME/.codex" ]; } && detected+=(codex)
144
+ { command -v gemini &>/dev/null || [ -d "$HOME/.gemini" ]; } && detected+=(gemini)
145
+ [ -d "$HOME/.cursor" ] && detected+=(cursor)
146
+ [ -d "$HOME/.codeium" ] && detected+=(windsurf)
147
+ [ -d "$HOME/.cline" ] && detected+=(cline)
148
+ command -v aider &>/dev/null && detected+=(aider)
149
+ [ -d "$HOME/.config/github-copilot" ] && detected+=(copilot)
150
+ { command -v q &>/dev/null || [ -d "$HOME/.amazonq" ]; } && detected+=(amazonq)
151
+ command -v opencode &>/dev/null && detected+=(opencode)
152
+ [ -d "$HOME/.roo" ] && detected+=(roo)
153
+ { command -v amp &>/dev/null || [ -d "$HOME/.config/amp" ]; } && detected+=(amp)
154
+
155
+ echo "${detected[@]}"
156
+ }
157
+
158
+ # ─────────────────────────────────────────────────────────────────────────────
159
+ # Manifest tracking
160
+ # ─────────────────────────────────────────────────────────────────────────────
161
+
162
+ GLOBAL_MANIFEST="$HOME/.conductor-skills/manifest.json"
163
+
164
+ get_manifest_path() {
165
+ local is_global="$1"
166
+ local project_dir="${2:-.}"
167
+ if [ "$is_global" = "true" ]; then
168
+ echo "$GLOBAL_MANIFEST"
169
+ else
170
+ echo "$project_dir/.conductor-skills/manifest.json"
171
+ fi
172
+ }
173
+
174
+ ensure_manifest() {
175
+ local manifest="$1"
176
+ local dir
177
+ dir=$(dirname "$manifest")
178
+ mkdir -p "$dir"
179
+ if [ ! -f "$manifest" ]; then
180
+ echo '{"schema_version":1,"installations":{}}' > "$manifest"
181
+ fi
182
+ }
183
+
184
+ read_manifest_version() {
185
+ local manifest="$1"
186
+ local agent="$2"
187
+
188
+ if [ ! -f "$manifest" ]; then
189
+ echo ""
190
+ return
191
+ fi
192
+
193
+ python3 -c "
194
+ import json, sys
195
+ try:
196
+ m = json.load(open('$manifest'))
197
+ print(m.get('installations',{}).get('$agent',{}).get('version',''))
198
+ except: pass
199
+ " 2>/dev/null || echo ""
200
+ }
201
+
202
+ write_manifest_entry() {
203
+ local manifest="$1"
204
+ local agent="$2"
205
+ local ver="$3"
206
+ local mode="$4"
207
+ local target_path="$5"
208
+
209
+ ensure_manifest "$manifest"
210
+
211
+ python3 -c "
212
+ import json, datetime
213
+ m = json.load(open('$manifest'))
214
+ now = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
215
+ entry = m.setdefault('installations',{}).get('$agent',{})
216
+ m['installations']['$agent'] = {
217
+ 'version': '$ver',
218
+ 'installed_at': entry.get('installed_at', now),
219
+ 'updated_at': now,
220
+ 'mode': '$mode',
221
+ 'target_path': '$target_path'
222
+ }
223
+ json.dump(m, open('$manifest','w'), indent=2)
224
+ " 2>/dev/null
225
+ }
226
+
227
+ remove_manifest_entry() {
228
+ local manifest="$1"
229
+ local agent="$2"
230
+
231
+ if [ ! -f "$manifest" ]; then
232
+ return
233
+ fi
234
+
235
+ python3 -c "
236
+ import json
237
+ m = json.load(open('$manifest'))
238
+ m.get('installations',{}).pop('$agent', None)
239
+ json.dump(m, open('$manifest','w'), indent=2)
240
+ " 2>/dev/null
241
+ }
242
+
243
+ list_manifest_agents() {
244
+ local manifest="$1"
245
+
246
+ if [ ! -f "$manifest" ]; then
247
+ echo ""
248
+ return
249
+ fi
250
+
251
+ python3 -c "
252
+ import json
253
+ try:
254
+ m = json.load(open('$manifest'))
255
+ agents = list(m.get('installations',{}).keys())
256
+ print(' '.join(agents))
257
+ except: pass
258
+ " 2>/dev/null || echo ""
259
+ }
260
+
261
+ # ─────────────────────────────────────────────────────────────────────────────
262
+ # Remote version check
263
+ # ─────────────────────────────────────────────────────────────────────────────
264
+
265
+ fetch_remote_version() {
266
+ if [ -n "$LOCAL_DIR" ] && [ -f "$LOCAL_DIR/VERSION" ]; then
267
+ cat "$LOCAL_DIR/VERSION" | tr -d '[:space:]'
268
+ return
269
+ fi
270
+ local remote_ver
271
+ remote_ver=$(curl -sSfL "$REPO_MAIN/VERSION" 2>/dev/null | tr -d '[:space:]') || true
272
+ echo "$remote_ver"
273
+ }
274
+
275
+ # ─────────────────────────────────────────────────────────────────────────────
276
+ # Download & assembly
277
+ # ─────────────────────────────────────────────────────────────────────────────
278
+
279
+ download_files() {
280
+ local tmp_dir="$1"
281
+
282
+ if [ -n "$LOCAL_DIR" ]; then
283
+ if [ ! -d "$LOCAL_DIR" ]; then
284
+ error "CONDUCTOR_SKILLS_LOCAL_DIR=$LOCAL_DIR is not a directory"
285
+ exit 1
286
+ fi
287
+ info "Copying skill files from $LOCAL_DIR..."
288
+ for file in "${SKILL_FILES[@]}"; do
289
+ local src="$LOCAL_DIR/$file"
290
+ local dest="$tmp_dir/$file"
291
+ if [ ! -f "$src" ]; then
292
+ error "Missing file in local source: $file"
293
+ # tmp_dir cleanup handled by EXIT trap
294
+ exit 1
295
+ fi
296
+ mkdir -p "$(dirname "$dest")"
297
+ cp "$src" "$dest"
298
+ done
299
+ ok "Copied ${#SKILL_FILES[@]} files"
300
+ return
301
+ fi
302
+
303
+ info "Downloading skill files..."
304
+ for file in "${SKILL_FILES[@]}"; do
305
+ local dir
306
+ dir=$(dirname "$file")
307
+ mkdir -p "$tmp_dir/$dir"
308
+ if ! curl -sSfL "$REPO_BASE/$file" -o "$tmp_dir/$file" 2>/dev/null; then
309
+ error "Failed to download $file"
310
+ error "Check your internet connection and try again."
311
+ # tmp_dir cleanup handled by EXIT trap
312
+ exit 1
313
+ fi
314
+ done
315
+ ok "Downloaded ${#SKILL_FILES[@]} files"
316
+ }
317
+
318
+ assemble_content() {
319
+ local tmp_dir="$1"
320
+ local output="$2"
321
+
322
+ {
323
+ cat "$tmp_dir/skills/conductor/SKILL.md"
324
+ echo ""
325
+ echo "---"
326
+ echo ""
327
+ echo "# References"
328
+ echo ""
329
+ for f in "$tmp_dir"/skills/conductor/references/*.md; do
330
+ cat "$f"
331
+ echo ""
332
+ echo "---"
333
+ echo ""
334
+ done
335
+ echo "# Examples"
336
+ echo ""
337
+ for f in "$tmp_dir"/skills/conductor/examples/*.md; do
338
+ cat "$f"
339
+ echo ""
340
+ echo "---"
341
+ echo ""
342
+ done
343
+ } > "$output"
344
+ }
345
+
346
+ # ─────────────────────────────────────────────────────────────────────────────
347
+ # Safe file writing (respects --force)
348
+ # ─────────────────────────────────────────────────────────────────────────────
349
+
350
+ safe_write() {
351
+ local target="$1"
352
+ local source="$2"
353
+ local force="$3"
354
+
355
+ if [ -f "$target" ] && [ "$force" != "true" ]; then
356
+ warn "File already exists: $target"
357
+ printf " Overwrite? [y/N] "
358
+ read -r answer
359
+ if [[ ! "$answer" =~ ^[Yy] ]]; then
360
+ info "Skipped. Use --force to overwrite."
361
+ return 1
362
+ fi
363
+ fi
364
+
365
+ local dir
366
+ dir=$(dirname "$target")
367
+ mkdir -p "$dir"
368
+ cp "$source" "$target"
369
+ ok "Installed: $target"
370
+ }
371
+
372
+ # ─────────────────────────────────────────────────────────────────────────────
373
+ # Global install paths
374
+ # ─────────────────────────────────────────────────────────────────────────────
375
+
376
+ supports_global() {
377
+ local agent="$1"
378
+ case "$agent" in
379
+ claude|codex|gemini|cursor|windsurf|roo|amp|aider|opencode) return 0 ;;
380
+ *) return 1 ;;
381
+ esac
382
+ }
383
+
384
+ get_global_path() {
385
+ local agent="$1"
386
+ case "$agent" in
387
+ claude) echo "__claude__" ;;
388
+ codex) echo "${CODEX_HOME:-$HOME/.codex}/AGENTS.md" ;;
389
+ cursor) echo "$HOME/.cursor/skills/conductor/SKILL.md" ;;
390
+ gemini) echo "$HOME/.gemini/GEMINI.md" ;;
391
+ windsurf) echo "$HOME/.codeium/windsurf/memories/global_rules.md" ;;
392
+ roo) echo "$HOME/.roo/rules/conductor.md" ;;
393
+ amp) echo "$HOME/.config/AGENTS.md" ;;
394
+ aider) echo "$HOME/.aider.conf.yml" ;;
395
+ opencode) echo "$HOME/.config/opencode/skills/conductor/SKILL.md" ;;
396
+ esac
397
+ }
398
+
399
+ get_target_path() {
400
+ local agent="$1"
401
+ local project_dir="$2"
402
+
403
+ case "$agent" in
404
+ claude) echo "__claude__" ;;
405
+ codex) echo "$project_dir/AGENTS.md" ;;
406
+ gemini) echo "$project_dir/GEMINI.md" ;;
407
+ cursor) echo "$project_dir/.cursor/rules/conductor.mdc" ;;
408
+ windsurf) echo "$project_dir/.windsurfrules" ;;
409
+ cline) echo "$project_dir/.clinerules" ;;
410
+ aider) echo "$project_dir/.conductor-skills" ;;
411
+ copilot) echo "$project_dir/.github/copilot-instructions.md" ;;
412
+ amazonq) echo "$project_dir/.amazonq/rules/conductor.md" ;;
413
+ opencode) echo "$project_dir/AGENTS.md" ;;
414
+ roo) echo "$project_dir/.roo/rules/conductor.md" ;;
415
+ amp) echo "$project_dir/.amp/instructions.md" ;;
416
+ esac
417
+ }
418
+
419
+ # ─────────────────────────────────────────────────────────────────────────────
420
+ # Per-agent install logic
421
+ # ─────────────────────────────────────────────────────────────────────────────
422
+
423
+ install_claude() {
424
+ # Claude Code installs plugins via the in-session `/plugin` commands, not a
425
+ # shell subcommand. Print clear instructions; do not try to invoke a CLI
426
+ # subcommand that does not exist.
427
+ if ! command -v claude &>/dev/null; then
428
+ warn "'claude' CLI not found, but the Claude install is in-session anyway."
429
+ fi
430
+
431
+ info "Conductor Skills is a Claude Code plugin. Run these in your Claude Code session:"
432
+ echo ""
433
+ echo " /plugin marketplace add conductor-oss/conductor-skills"
434
+ echo " /plugin install conductor@conductor-skills"
435
+ echo ""
436
+ info "Once installed, slash commands like /conductor, /conductor-setup,"
437
+ info "/conductor-optimize, and /conductor-scaffold-worker become available."
438
+ ok "Claude Code install instructions printed above."
439
+ }
440
+
441
+ install_to_file() {
442
+ local target="$1"
443
+ local assembled="$2"
444
+ local force="$3"
445
+ local prefix="${4:-}"
446
+
447
+ if [ -n "$prefix" ]; then
448
+ local tmp_with_prefix
449
+ tmp_with_prefix=$(mktemp)
450
+ {
451
+ echo "$prefix"
452
+ cat "$assembled"
453
+ } > "$tmp_with_prefix"
454
+ safe_write "$target" "$tmp_with_prefix" "$force"
455
+ rm -f "$tmp_with_prefix"
456
+ else
457
+ safe_write "$target" "$assembled" "$force"
458
+ fi
459
+ }
460
+
461
+ install_aider_to_dir() {
462
+ local skill_dir="$1"
463
+ local tmp_dir="$2"
464
+ local config="$3"
465
+ local read_prefix="$4"
466
+
467
+ mkdir -p "$skill_dir/references" "$skill_dir/examples" "$skill_dir/scripts"
468
+
469
+ info "Copying skill files to $skill_dir ..."
470
+ cp "$tmp_dir/skills/conductor/SKILL.md" "$skill_dir/"
471
+ for f in "$tmp_dir"/skills/conductor/references/*.md; do
472
+ cp "$f" "$skill_dir/references/"
473
+ done
474
+ for f in "$tmp_dir"/skills/conductor/examples/*.md; do
475
+ cp "$f" "$skill_dir/examples/"
476
+ done
477
+ for f in "$tmp_dir"/skills/conductor/scripts/*.py; do
478
+ [ -f "$f" ] && cp "$f" "$skill_dir/scripts/"
479
+ done
480
+ ok "Files copied to $skill_dir"
481
+
482
+ if [ -f "$config" ] && grep -q "conductor-skills" "$config" 2>/dev/null; then
483
+ info "Aider config already references conductor-skills, skipping."
484
+ else
485
+ info "Adding read entries to $config ..."
486
+ {
487
+ echo ""
488
+ echo "# Conductor Skills"
489
+ echo "read:"
490
+ for file in "${SKILL_FILES[@]}"; do
491
+ echo " - ${read_prefix}${file#skills/conductor/}"
492
+ done
493
+ } >> "$config"
494
+ ok "Updated: $config"
495
+ fi
496
+ }
497
+
498
+ # Install a single agent. Returns 0 on success, 1 on skip/failure.
499
+ install_for_agent() {
500
+ local agent="$1"
501
+ local project_dir="$2"
502
+ local is_global="$3"
503
+ local force="$4"
504
+ local tmp_dir="$5"
505
+ local assembled="$6"
506
+
507
+ # Claude has its own install path
508
+ if [ "$agent" = "claude" ]; then
509
+ install_claude
510
+ return $?
511
+ fi
512
+
513
+ if [ "$is_global" = "true" ]; then
514
+ local target_path
515
+ target_path=$(get_global_path "$agent")
516
+
517
+ if [ "$agent" = "aider" ]; then
518
+ install_aider_to_dir "$HOME/.conductor-skills" "$tmp_dir" "$HOME/.aider.conf.yml" "$HOME/.conductor-skills/"
519
+ else
520
+ install_to_file "$target_path" "$assembled" "$force"
521
+ fi
522
+ else
523
+ case "$agent" in
524
+ codex)
525
+ install_to_file "$project_dir/AGENTS.md" "$assembled" "$force"
526
+ ;;
527
+ gemini)
528
+ install_to_file "$project_dir/GEMINI.md" "$assembled" "$force"
529
+ ;;
530
+ cursor)
531
+ local frontmatter
532
+ frontmatter=$(cat <<'FRONT'
533
+ ---
534
+ description: Conductor workflow orchestration - create, run, monitor, and manage workflows
535
+ globs: "**/*"
536
+ alwaysApply: true
537
+ ---
538
+
539
+ FRONT
540
+ )
541
+ install_to_file "$project_dir/.cursor/rules/conductor.mdc" "$assembled" "$force" "$frontmatter"
542
+ ;;
543
+ windsurf)
544
+ install_to_file "$project_dir/.windsurfrules" "$assembled" "$force"
545
+ ;;
546
+ cline)
547
+ install_to_file "$project_dir/.clinerules" "$assembled" "$force"
548
+ ;;
549
+ aider)
550
+ install_aider_to_dir "$project_dir/.conductor-skills" "$tmp_dir" "$project_dir/.aider.conf.yml" ".conductor-skills/"
551
+ ;;
552
+ copilot)
553
+ install_to_file "$project_dir/.github/copilot-instructions.md" "$assembled" "$force"
554
+ ;;
555
+ amazonq)
556
+ install_to_file "$project_dir/.amazonq/rules/conductor.md" "$assembled" "$force"
557
+ ;;
558
+ opencode)
559
+ install_to_file "$project_dir/AGENTS.md" "$assembled" "$force"
560
+ ;;
561
+ roo)
562
+ install_to_file "$project_dir/.roo/rules/conductor.md" "$assembled" "$force"
563
+ ;;
564
+ amp)
565
+ install_to_file "$project_dir/.amp/instructions.md" "$assembled" "$force"
566
+ ;;
567
+ esac
568
+ fi
569
+ }
570
+
571
+ # ─────────────────────────────────────────────────────────────────────────────
572
+ # Uninstall
573
+ # ─────────────────────────────────────────────────────────────────────────────
574
+
575
+ uninstall_agent() {
576
+ local agent="$1"
577
+ local project_dir="$2"
578
+ local is_global="$3"
579
+
580
+ if [ "$agent" = "claude" ]; then
581
+ info "To remove the Conductor skill from Claude Code, run:"
582
+ echo " /plugin uninstall conductor@conductor-skills (in your Claude Code session)"
583
+ return
584
+ fi
585
+
586
+ local target
587
+ if [ "$is_global" = "true" ]; then
588
+ if [ "$agent" = "aider" ]; then
589
+ local skill_dir="$HOME/.conductor-skills"
590
+ if [ -d "$skill_dir" ]; then
591
+ rm -rf "$skill_dir"
592
+ ok "Removed: $skill_dir"
593
+ info "Note: You may also want to remove the 'read:' entries from ~/.aider.conf.yml"
594
+ else
595
+ warn "Nothing to uninstall: $skill_dir not found"
596
+ fi
597
+ return
598
+ fi
599
+ target=$(get_global_path "$agent")
600
+ else
601
+ target=$(get_target_path "$agent" "$project_dir")
602
+ if [ "$agent" = "aider" ]; then
603
+ if [ -d "$target" ]; then
604
+ rm -rf "$target"
605
+ ok "Removed: $target"
606
+ info "Note: You may also want to remove the 'read:' entries from .aider.conf.yml"
607
+ else
608
+ warn "Nothing to uninstall: $target not found"
609
+ fi
610
+ return
611
+ fi
612
+ fi
613
+
614
+ if [ -f "$target" ]; then
615
+ rm -f "$target"
616
+ ok "Removed: $target"
617
+ else
618
+ warn "Nothing to uninstall: $target not found"
619
+ fi
620
+ }
621
+
622
+ # ─────────────────────────────────────────────────────────────────────────────
623
+ # Check mode (dry run)
624
+ # ─────────────────────────────────────────────────────────────────────────────
625
+
626
+ do_check() {
627
+ local agents=("$@")
628
+
629
+ local manifest
630
+ manifest=$(get_manifest_path "true" "")
631
+
632
+ echo ""
633
+ echo -e "${BOLD}Detected agents:${NC}"
634
+ if [ ${#agents[@]} -eq 0 ]; then
635
+ warn "No AI coding agents detected on this system."
636
+ return
637
+ fi
638
+
639
+ for agent in "${agents[@]}"; do
640
+ local installed_ver
641
+ installed_ver=$(read_manifest_version "$manifest" "$agent")
642
+ local global_support="yes"
643
+ supports_global "$agent" || global_support="no"
644
+
645
+ if [ -n "$installed_ver" ]; then
646
+ if [ "$installed_ver" = "$VERSION" ]; then
647
+ echo -e " ${GREEN}●${NC} $agent v${installed_ver} (up to date)"
648
+ else
649
+ echo -e " ${YELLOW}●${NC} $agent v${installed_ver} → v${VERSION} (upgrade available)"
650
+ fi
651
+ else
652
+ echo -e " ${BLUE}●${NC} $agent (not installed) global: $global_support"
653
+ fi
654
+ done
655
+ echo ""
656
+ }
657
+
658
+ # ─────────────────────────────────────────────────────────────────────────────
659
+ # Main
660
+ # ─────────────────────────────────────────────────────────────────────────────
661
+
662
+ main() {
663
+ local agent=""
664
+ local project_dir="."
665
+ local force="false"
666
+ local uninstall="false"
667
+ local global="false"
668
+ local all="false"
669
+ local upgrade="false"
670
+ local check="false"
671
+
672
+ while [[ $# -gt 0 ]]; do
673
+ case "$1" in
674
+ --agent) agent="$2"; shift 2 ;;
675
+ --project-dir) project_dir="$2"; shift 2 ;;
676
+ --global) global="true"; shift ;;
677
+ --all) all="true"; shift ;;
678
+ --upgrade) upgrade="true"; shift ;;
679
+ --check) check="true"; shift ;;
680
+ --force) force="true"; shift ;;
681
+ --uninstall) uninstall="true"; shift ;;
682
+ --version) echo "v${VERSION}"; exit 0 ;;
683
+ --help|-h) usage ;;
684
+ *) error "Unknown option: $1"; usage ;;
685
+ esac
686
+ done
687
+
688
+ # Require --agent or --all
689
+ if [ -z "$agent" ] && [ "$all" != "true" ]; then
690
+ error "Missing required --agent flag (or use --all)"
691
+ echo ""
692
+ usage
693
+ fi
694
+
695
+ # Resolve project dir to absolute path
696
+ project_dir=$(cd "$project_dir" && pwd)
697
+
698
+ echo ""
699
+ echo -e "${BOLD}Conductor Skills Installer v${VERSION}${NC}"
700
+ echo ""
701
+
702
+ # Build agent list
703
+ local agents=()
704
+ if [ "$all" = "true" ]; then
705
+ local detected
706
+ detected=$(detect_agents)
707
+ if [ -z "$detected" ]; then
708
+ warn "No AI coding agents detected on this system."
709
+ echo ""
710
+ info "Supported agents: claude, codex, gemini, cursor, windsurf, cline,"
711
+ info " aider, copilot, amazonq, opencode, roo, amp"
712
+ echo ""
713
+ info "Install one of the above, then re-run this command."
714
+ exit 0
715
+ fi
716
+ # shellcheck disable=SC2206
717
+ agents=($detected)
718
+ info "Detected agents: ${agents[*]}"
719
+ echo ""
720
+ else
721
+ agent=$(echo "$agent" | tr '[:upper:]' '[:lower:]')
722
+ case "$agent" in
723
+ claude|codex|gemini|cursor|windsurf|cline|aider|copilot|amazonq|opencode|roo|amp) ;;
724
+ *) error "Unknown agent: $agent"; echo ""; usage ;;
725
+ esac
726
+ agents=("$agent")
727
+ fi
728
+
729
+ # Check mode — dry run
730
+ if [ "$check" = "true" ]; then
731
+ do_check "${agents[@]}"
732
+ exit 0
733
+ fi
734
+
735
+ # Determine manifest path
736
+ local manifest
737
+ if [ "$global" = "true" ] || [ "$all" = "true" ]; then
738
+ manifest=$(get_manifest_path "true" "")
739
+ else
740
+ manifest=$(get_manifest_path "false" "$project_dir")
741
+ fi
742
+
743
+ # Handle uninstall
744
+ if [ "$uninstall" = "true" ]; then
745
+ for a in "${agents[@]}"; do
746
+ local use_global="$global"
747
+ if [ "$all" = "true" ] && supports_global "$a"; then
748
+ use_global="true"
749
+ fi
750
+ info "Uninstalling ${BOLD}${a}${NC} ..."
751
+ uninstall_agent "$a" "$project_dir" "$use_global"
752
+ remove_manifest_entry "$manifest" "$a"
753
+ done
754
+ echo ""
755
+ ok "Done!"
756
+ return
757
+ fi
758
+
759
+ # Check for upgrade
760
+ local target_version="$VERSION"
761
+ if [ "$upgrade" = "true" ]; then
762
+ info "Checking for updates..."
763
+ local remote_ver
764
+ remote_ver=$(fetch_remote_version)
765
+ if [ -z "$remote_ver" ]; then
766
+ warn "Could not check for updates (offline?). Using bundled v${VERSION}."
767
+ elif [ "$remote_ver" != "$VERSION" ]; then
768
+ info "Update available: v${VERSION} → v${remote_ver}"
769
+ target_version="$remote_ver"
770
+ else
771
+ info "Already at latest version (v${VERSION})."
772
+ fi
773
+ echo ""
774
+ fi
775
+
776
+ # Download files to temp dir (not local — the EXIT trap must access it after main returns)
777
+ tmp_dir=$(mktemp -d)
778
+ trap 'rm -rf "$tmp_dir"' EXIT
779
+
780
+ download_files "$tmp_dir"
781
+
782
+ # Assemble into single file
783
+ local assembled="$tmp_dir/_assembled.md"
784
+ assemble_content "$tmp_dir" "$assembled"
785
+ ok "Assembled skill content ($(wc -c < "$assembled" | tr -d ' ') bytes)"
786
+
787
+ # Install for each agent
788
+ local installed_count=0
789
+ local skipped_count=0
790
+
791
+ for a in "${agents[@]}"; do
792
+ echo ""
793
+
794
+ # Determine if global for this agent
795
+ local use_global="$global"
796
+ if [ "$all" = "true" ]; then
797
+ if supports_global "$a"; then
798
+ use_global="true"
799
+ else
800
+ info "${BOLD}${a}${NC}: skipped (project-only install). Use --project-dir <path> to include."
801
+ skipped_count=$((skipped_count + 1))
802
+ continue
803
+ fi
804
+ fi
805
+
806
+ # Validate global support for single-agent mode
807
+ if [ "$use_global" = "true" ] && ! supports_global "$a"; then
808
+ error "Global install is not supported for $a. Run from your project directory instead."
809
+ continue
810
+ fi
811
+
812
+ # Idempotency check
813
+ local installed_ver
814
+ installed_ver=$(read_manifest_version "$manifest" "$a")
815
+ if [ -n "$installed_ver" ] && [ "$installed_ver" = "$target_version" ] && [ "$force" != "true" ] && [ "$upgrade" != "true" ]; then
816
+ ok "${a} already at v${installed_ver}, skipping."
817
+ skipped_count=$((skipped_count + 1))
818
+ continue
819
+ fi
820
+
821
+ if [ -n "$installed_ver" ] && [ "$installed_ver" != "$target_version" ]; then
822
+ info "Upgrading ${BOLD}${a}${NC} from v${installed_ver} to v${target_version} ..."
823
+ else
824
+ info "Installing for ${BOLD}${a}${NC} ..."
825
+ fi
826
+
827
+ # Perform install
828
+ if install_for_agent "$a" "$project_dir" "$use_global" "$force" "$tmp_dir" "$assembled"; then
829
+ # Determine target path for manifest
830
+ local target_path
831
+ if [ "$use_global" = "true" ]; then
832
+ target_path=$(get_global_path "$a")
833
+ else
834
+ target_path=$(get_target_path "$a" "$project_dir")
835
+ fi
836
+ local mode
837
+ if [ "$use_global" = "true" ]; then mode="global"; else mode="project"; fi
838
+ write_manifest_entry "$manifest" "$a" "$target_version" "$mode" "$target_path"
839
+ installed_count=$((installed_count + 1))
840
+ fi
841
+ done
842
+
843
+ echo ""
844
+ echo -e "${GREEN}${BOLD}Done!${NC} Installed: ${installed_count}, Skipped: ${skipped_count}"
845
+ echo ""
846
+ echo "Next steps:"
847
+ echo " Ask your agent to connect to your Conductor server, e.g.:"
848
+ echo ""
849
+ echo ' "Connect to my Conductor server at http://localhost:8080/api"'
850
+ echo ""
851
+ echo -e " Docs: ${BLUE}https://github.com/conductor-oss/conductor-skills${NC}"
852
+ echo ""
853
+ }
854
+
855
+ main "$@"