@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.ps1 ADDED
@@ -0,0 +1,677 @@
1
+ # ─────────────────────────────────────────────────────────────────────────────
2
+ # Conductor Skills Installer (PowerShell)
3
+ # Installs Conductor workflow orchestration skills for your AI coding agent.
4
+ # https://github.com/conductor-oss/conductor-skills
5
+ # ─────────────────────────────────────────────────────────────────────────────
6
+
7
+ param(
8
+ [string]$Agent,
9
+ [string]$ProjectDir = ".",
10
+ [switch]$Global,
11
+ [switch]$All,
12
+ [switch]$Upgrade,
13
+ [switch]$Check,
14
+ [switch]$Force,
15
+ [switch]$Uninstall,
16
+ [switch]$Version
17
+ )
18
+
19
+ $ErrorActionPreference = "Stop"
20
+
21
+ $SCRIPT_VERSION = "1.4.2"
22
+ # Per-file fetches are pinned to this version's tag (see install.sh notes).
23
+ # main is only used for the "is there a newer release?" check.
24
+ $REPO_BASE = "https://raw.githubusercontent.com/conductor-oss/conductor-skills/v$SCRIPT_VERSION"
25
+ $REPO_MAIN = "https://raw.githubusercontent.com/conductor-oss/conductor-skills/main"
26
+
27
+ # When set, skip the network fetch and copy from this directory instead.
28
+ # The npm package sets this so the bundled files are used.
29
+ $LOCAL_DIR = $env:CONDUCTOR_SKILLS_LOCAL_DIR
30
+
31
+ $SKILL_FILES = @(
32
+ "skills/conductor/SKILL.md"
33
+ "skills/conductor/references/setup.md"
34
+ "skills/conductor/references/cli-index.md"
35
+ "skills/conductor/references/fallback-cli.md"
36
+ "skills/conductor/references/workflow-definition.md"
37
+ "skills/conductor/references/workers.md"
38
+ "skills/conductor/references/api-reference.md"
39
+ "skills/conductor/references/visualization.md"
40
+ "skills/conductor/references/schedules.md"
41
+ "skills/conductor/references/orkes.md"
42
+ "skills/conductor/references/optimization.md"
43
+ "skills/conductor/references/troubleshooting.md"
44
+ "skills/conductor/examples/create-and-run-workflow.md"
45
+ "skills/conductor/examples/monitor-and-retry.md"
46
+ "skills/conductor/examples/signal-wait-task.md"
47
+ "skills/conductor/examples/fork-join.md"
48
+ "skills/conductor/examples/do-while-loop.md"
49
+ "skills/conductor/examples/sub-workflow.md"
50
+ "skills/conductor/examples/review-workflow.md"
51
+ "skills/conductor/examples/llm-chat.md"
52
+ "skills/conductor/examples/ai-agent-mcp.md"
53
+ "skills/conductor/examples/ai-agent-loop.md"
54
+ "skills/conductor/examples/llm-rag.md"
55
+ "skills/conductor/examples/workflows/weather-notification.json"
56
+ "skills/conductor/examples/workflows/fork-join.json"
57
+ "skills/conductor/examples/workflows/do-while-loop.json"
58
+ "skills/conductor/examples/workflows/child-normalize.json"
59
+ "skills/conductor/examples/workflows/parent-pipeline.json"
60
+ "skills/conductor/examples/workflows/llm-chat.json"
61
+ "skills/conductor/examples/workflows/ai-agent-mcp.json"
62
+ "skills/conductor/examples/workflows/ai-agent-loop.json"
63
+ "skills/conductor/examples/workflows/llm-rag.json"
64
+ "skills/conductor/scripts/conductor_api.py"
65
+ )
66
+
67
+ $VALID_AGENTS = @("claude","codex","gemini","cursor","windsurf","cline","aider","copilot","amazonq","opencode","roo","amp")
68
+ $GLOBAL_AGENTS = @("claude","codex","gemini","cursor","windsurf","roo","amp","aider","opencode")
69
+
70
+ # ─────────────────────────────────────────────────────────────────────────────
71
+ # Helpers
72
+ # ─────────────────────────────────────────────────────────────────────────────
73
+
74
+ function Write-Info { param([string]$Msg) Write-Host "[info] $Msg" -ForegroundColor Blue }
75
+ function Write-Ok { param([string]$Msg) Write-Host "[ok] $Msg" -ForegroundColor Green }
76
+ function Write-Warn { param([string]$Msg) Write-Host "[warn] $Msg" -ForegroundColor Yellow }
77
+ function Write-Err { param([string]$Msg) Write-Host "[error] $Msg" -ForegroundColor Red }
78
+
79
+ # ─────────────────────────────────────────────────────────────────────────────
80
+ # Agent detection
81
+ # ─────────────────────────────────────────────────────────────────────────────
82
+
83
+ function Detect-Agents {
84
+ $detected = @()
85
+ $installDir = $env:USERPROFILE
86
+
87
+ if (Get-Command claude -ErrorAction SilentlyContinue) { $detected += "claude" }
88
+ if ((Get-Command codex -ErrorAction SilentlyContinue) -or (Test-Path (Join-Path $installDir ".codex"))) { $detected += "codex" }
89
+ if ((Get-Command gemini -ErrorAction SilentlyContinue) -or (Test-Path (Join-Path $installDir ".gemini"))) { $detected += "gemini" }
90
+ if (Test-Path (Join-Path $installDir ".cursor")) { $detected += "cursor" }
91
+ if (Test-Path (Join-Path $installDir ".codeium")) { $detected += "windsurf" }
92
+ if (Test-Path (Join-Path $installDir ".cline")) { $detected += "cline" }
93
+ if (Get-Command aider -ErrorAction SilentlyContinue) { $detected += "aider" }
94
+ if (Test-Path (Join-Path $installDir ".config\github-copilot")) { $detected += "copilot" }
95
+ if ((Get-Command q -ErrorAction SilentlyContinue) -or (Test-Path (Join-Path $installDir ".amazonq"))) { $detected += "amazonq" }
96
+ if (Get-Command opencode -ErrorAction SilentlyContinue) { $detected += "opencode" }
97
+ if (Test-Path (Join-Path $installDir ".roo")) { $detected += "roo" }
98
+ if ((Get-Command amp -ErrorAction SilentlyContinue) -or (Test-Path (Join-Path $installDir ".config\amp"))) { $detected += "amp" }
99
+
100
+ return $detected
101
+ }
102
+
103
+ # ─────────────────────────────────────────────────────────────────────────────
104
+ # Manifest tracking
105
+ # ─────────────────────────────────────────────────────────────────────────────
106
+
107
+ $GLOBAL_MANIFEST = Join-Path $env:USERPROFILE ".conductor-skills\manifest.json"
108
+
109
+ function Get-ManifestPath {
110
+ param([bool]$IsGlobal, [string]$ProjDir = ".")
111
+ if ($IsGlobal) { return $GLOBAL_MANIFEST }
112
+ return Join-Path $ProjDir ".conductor-skills\manifest.json"
113
+ }
114
+
115
+ function Ensure-Manifest {
116
+ param([string]$ManifestPath)
117
+ $dir = Split-Path -Parent $ManifestPath
118
+ if ($dir -and !(Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null }
119
+ if (!(Test-Path $ManifestPath)) {
120
+ '{"schema_version":1,"installations":{}}' | Set-Content -Path $ManifestPath
121
+ }
122
+ }
123
+
124
+ function Read-ManifestVersion {
125
+ param([string]$ManifestPath, [string]$AgentName)
126
+ if (!(Test-Path $ManifestPath)) { return "" }
127
+ try {
128
+ $m = Get-Content $ManifestPath -Raw | ConvertFrom-Json
129
+ $entry = $m.installations.PSObject.Properties | Where-Object { $_.Name -eq $AgentName }
130
+ if ($entry) { return $entry.Value.version }
131
+ } catch {}
132
+ return ""
133
+ }
134
+
135
+ function Write-ManifestEntry {
136
+ param([string]$ManifestPath, [string]$AgentName, [string]$Ver, [string]$Mode, [string]$TargetPath)
137
+ Ensure-Manifest -ManifestPath $ManifestPath
138
+ $m = Get-Content $ManifestPath -Raw | ConvertFrom-Json
139
+ $now = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
140
+
141
+ $existingEntry = $m.installations.PSObject.Properties | Where-Object { $_.Name -eq $AgentName }
142
+ $installedAt = $now
143
+ if ($existingEntry) { $installedAt = $existingEntry.Value.installed_at }
144
+
145
+ $entry = [PSCustomObject]@{
146
+ version = $Ver
147
+ installed_at = $installedAt
148
+ updated_at = $now
149
+ mode = $Mode
150
+ target_path = $TargetPath
151
+ }
152
+
153
+ if ($existingEntry) {
154
+ $m.installations.PSObject.Properties.Remove($AgentName)
155
+ }
156
+ $m.installations | Add-Member -NotePropertyName $AgentName -NotePropertyValue $entry
157
+ $m | ConvertTo-Json -Depth 10 | Set-Content -Path $ManifestPath
158
+ }
159
+
160
+ function Remove-ManifestEntry {
161
+ param([string]$ManifestPath, [string]$AgentName)
162
+ if (!(Test-Path $ManifestPath)) { return }
163
+ try {
164
+ $m = Get-Content $ManifestPath -Raw | ConvertFrom-Json
165
+ $m.installations.PSObject.Properties.Remove($AgentName)
166
+ $m | ConvertTo-Json -Depth 10 | Set-Content -Path $ManifestPath
167
+ } catch {}
168
+ }
169
+
170
+ function Get-ManifestAgents {
171
+ param([string]$ManifestPath)
172
+ if (!(Test-Path $ManifestPath)) { return @() }
173
+ try {
174
+ $m = Get-Content $ManifestPath -Raw | ConvertFrom-Json
175
+ return @($m.installations.PSObject.Properties.Name)
176
+ } catch { return @() }
177
+ }
178
+
179
+ # ─────────────────────────────────────────────────────────────────────────────
180
+ # Remote version check
181
+ # ─────────────────────────────────────────────────────────────────────────────
182
+
183
+ function Fetch-RemoteVersion {
184
+ if ($LOCAL_DIR -and (Test-Path (Join-Path $LOCAL_DIR "VERSION"))) {
185
+ return (Get-Content (Join-Path $LOCAL_DIR "VERSION") -Raw).Trim()
186
+ }
187
+ try {
188
+ $ver = (Invoke-WebRequest -Uri "$REPO_MAIN/VERSION" -UseBasicParsing -ErrorAction Stop).Content.Trim()
189
+ return $ver
190
+ } catch { return "" }
191
+ }
192
+
193
+ # ─────────────────────────────────────────────────────────────────────────────
194
+ # Download & assembly
195
+ # ─────────────────────────────────────────────────────────────────────────────
196
+
197
+ function Download-Files {
198
+ param([string]$TmpDir)
199
+
200
+ if ($LOCAL_DIR) {
201
+ if (-not (Test-Path -PathType Container $LOCAL_DIR)) {
202
+ Write-Err "CONDUCTOR_SKILLS_LOCAL_DIR=$LOCAL_DIR is not a directory"
203
+ exit 1
204
+ }
205
+ Write-Info "Copying skill files from $LOCAL_DIR..."
206
+ foreach ($file in $SKILL_FILES) {
207
+ $src = Join-Path $LOCAL_DIR $file
208
+ $dest = Join-Path $TmpDir $file
209
+ if (-not (Test-Path $src)) {
210
+ Write-Err "Missing file in local source: $file"
211
+ Remove-Item -Recurse -Force $TmpDir -ErrorAction SilentlyContinue
212
+ exit 1
213
+ }
214
+ $dir = Split-Path -Parent $dest
215
+ if ($dir -and !(Test-Path $dir)) {
216
+ New-Item -ItemType Directory -Path $dir -Force | Out-Null
217
+ }
218
+ Copy-Item $src $dest
219
+ }
220
+ Write-Ok "Copied $($SKILL_FILES.Count) files"
221
+ return
222
+ }
223
+
224
+ Write-Info "Downloading skill files..."
225
+ foreach ($file in $SKILL_FILES) {
226
+ $dir = Split-Path -Parent (Join-Path $TmpDir $file)
227
+ if ($dir -and !(Test-Path $dir)) {
228
+ New-Item -ItemType Directory -Path $dir -Force | Out-Null
229
+ }
230
+ $url = "$REPO_BASE/$file"
231
+ $dest = Join-Path $TmpDir $file
232
+ try {
233
+ Invoke-WebRequest -Uri $url -OutFile $dest -UseBasicParsing -ErrorAction Stop | Out-Null
234
+ } catch {
235
+ Write-Err "Failed to download $file"
236
+ Write-Err "Check your internet connection and try again."
237
+ Remove-Item -Recurse -Force $TmpDir -ErrorAction SilentlyContinue
238
+ exit 1
239
+ }
240
+ }
241
+ Write-Ok "Downloaded $($SKILL_FILES.Count) files"
242
+ }
243
+
244
+ function Assemble-Content {
245
+ param([string]$TmpDir, [string]$Output)
246
+
247
+ $content = @()
248
+ $content += Get-Content (Join-Path $TmpDir "skills/conductor/SKILL.md") -Raw
249
+ $content += "`n---`n"
250
+ $content += "# References`n"
251
+ foreach ($f in Get-ChildItem (Join-Path $TmpDir "skills/conductor/references") -Filter "*.md") {
252
+ $content += Get-Content $f.FullName -Raw
253
+ $content += "`n---`n"
254
+ }
255
+ $content += "# Examples`n"
256
+ foreach ($f in Get-ChildItem (Join-Path $TmpDir "skills/conductor/examples") -Filter "*.md") {
257
+ $content += Get-Content $f.FullName -Raw
258
+ $content += "`n---`n"
259
+ }
260
+ $content -join "`n" | Set-Content -Path $Output -NoNewline
261
+ }
262
+
263
+ # ─────────────────────────────────────────────────────────────────────────────
264
+ # Safe file writing
265
+ # ─────────────────────────────────────────────────────────────────────────────
266
+
267
+ function Safe-Write {
268
+ param([string]$Target, [string]$Source, [bool]$ForceWrite)
269
+
270
+ if ((Test-Path $Target) -and !$ForceWrite) {
271
+ Write-Warn "File already exists: $Target"
272
+ $answer = Read-Host " Overwrite? [y/N]"
273
+ if ($answer -notmatch "^[Yy]") {
274
+ Write-Info "Skipped. Use -Force to overwrite."
275
+ return $false
276
+ }
277
+ }
278
+
279
+ $dir = Split-Path -Parent $Target
280
+ if ($dir -and !(Test-Path $dir)) {
281
+ New-Item -ItemType Directory -Path $dir -Force | Out-Null
282
+ }
283
+ Copy-Item -Path $Source -Destination $Target -Force
284
+ Write-Ok "Installed: $Target"
285
+ return $true
286
+ }
287
+
288
+ # ─────────────────────────────────────────────────────────────────────────────
289
+ # Global install paths
290
+ # ─────────────────────────────────────────────────────────────────────────────
291
+
292
+ function Supports-Global {
293
+ param([string]$AgentName)
294
+ return $GLOBAL_AGENTS -contains $AgentName
295
+ }
296
+
297
+ function Get-GlobalPath {
298
+ param([string]$AgentName)
299
+ $installDir = $env:USERPROFILE
300
+ switch ($AgentName) {
301
+ "claude" { return "__claude__" }
302
+ "codex" { $codexHome = if ($env:CODEX_HOME) { $env:CODEX_HOME } else { Join-Path $installDir ".codex" }; return Join-Path $codexHome "AGENTS.md" }
303
+ "cursor" { return Join-Path $installDir ".cursor\skills\conductor\SKILL.md" }
304
+ "gemini" { return Join-Path $installDir ".gemini\GEMINI.md" }
305
+ "windsurf" { return Join-Path $installDir ".codeium\windsurf\memories\global_rules.md" }
306
+ "roo" { return Join-Path $installDir ".roo\rules\conductor.md" }
307
+ "amp" { return Join-Path $installDir ".config\AGENTS.md" }
308
+ "aider" { return Join-Path $installDir ".aider.conf.yml" }
309
+ "opencode" { return Join-Path $installDir ".config\opencode\skills\conductor\SKILL.md" }
310
+ }
311
+ }
312
+
313
+ function Get-TargetPath {
314
+ param([string]$AgentName, [string]$ProjDir)
315
+ switch ($AgentName) {
316
+ "claude" { return "__claude__" }
317
+ "codex" { return Join-Path $ProjDir "AGENTS.md" }
318
+ "gemini" { return Join-Path $ProjDir "GEMINI.md" }
319
+ "cursor" { return Join-Path $ProjDir ".cursor\rules\conductor.mdc" }
320
+ "windsurf" { return Join-Path $ProjDir ".windsurfrules" }
321
+ "cline" { return Join-Path $ProjDir ".clinerules" }
322
+ "aider" { return Join-Path $ProjDir ".conductor-skills" }
323
+ "copilot" { return Join-Path $ProjDir ".github\copilot-instructions.md" }
324
+ "amazonq" { return Join-Path $ProjDir ".amazonq\rules\conductor.md" }
325
+ "opencode" { return Join-Path $ProjDir "AGENTS.md" }
326
+ "roo" { return Join-Path $ProjDir ".roo\rules\conductor.md" }
327
+ "amp" { return Join-Path $ProjDir ".amp\instructions.md" }
328
+ }
329
+ }
330
+
331
+ # ─────────────────────────────────────────────────────────────────────────────
332
+ # Per-agent install logic
333
+ # ─────────────────────────────────────────────────────────────────────────────
334
+
335
+ function Install-Claude {
336
+ # Claude Code installs plugins via in-session /plugin commands, not a
337
+ # shell subcommand. Print clear instructions.
338
+ if (!(Get-Command claude -ErrorAction SilentlyContinue)) {
339
+ Write-Warn "'claude' CLI not found, but the Claude install is in-session anyway."
340
+ }
341
+ Write-Info "Conductor Skills is a Claude Code plugin. Run these in your Claude Code session:"
342
+ Write-Host ""
343
+ Write-Host " /plugin marketplace add conductor-oss/conductor-skills"
344
+ Write-Host " /plugin install conductor@conductor-skills"
345
+ Write-Host ""
346
+ Write-Info "Once installed, slash commands like /conductor, /conductor-setup,"
347
+ Write-Info "/conductor-optimize, and /conductor-scaffold-worker become available."
348
+ Write-Ok "Claude Code install instructions printed above."
349
+ return $true
350
+ }
351
+
352
+ function Install-ToFile {
353
+ param([string]$Target, [string]$Assembled, [bool]$ForceWrite, [string]$Prefix = "")
354
+
355
+ if ($Prefix) {
356
+ $tmpFile = [System.IO.Path]::GetTempFileName()
357
+ ($Prefix + (Get-Content $Assembled -Raw)) | Set-Content -Path $tmpFile -NoNewline
358
+ Safe-Write -Target $Target -Source $tmpFile -ForceWrite $ForceWrite
359
+ Remove-Item $tmpFile -ErrorAction SilentlyContinue
360
+ } else {
361
+ Safe-Write -Target $Target -Source $Assembled -ForceWrite $ForceWrite
362
+ }
363
+ }
364
+
365
+ function Install-AiderToDir {
366
+ param([string]$SkillDir, [string]$TmpDir, [string]$Config, [string]$ReadPrefix)
367
+
368
+ New-Item -ItemType Directory -Path (Join-Path $SkillDir "references") -Force | Out-Null
369
+ New-Item -ItemType Directory -Path (Join-Path $SkillDir "examples") -Force | Out-Null
370
+ New-Item -ItemType Directory -Path (Join-Path $SkillDir "scripts") -Force | Out-Null
371
+
372
+ Write-Info "Copying skill files to $SkillDir ..."
373
+ Copy-Item (Join-Path $TmpDir "skills/conductor/SKILL.md") $SkillDir -Force
374
+ foreach ($f in Get-ChildItem (Join-Path $TmpDir "skills/conductor/references") -Filter "*.md") {
375
+ Copy-Item $f.FullName (Join-Path $SkillDir "references") -Force
376
+ }
377
+ foreach ($f in Get-ChildItem (Join-Path $TmpDir "skills/conductor/examples") -Filter "*.md") {
378
+ Copy-Item $f.FullName (Join-Path $SkillDir "examples") -Force
379
+ }
380
+ $scriptsDir = Join-Path $TmpDir "skills/conductor/scripts"
381
+ if (Test-Path $scriptsDir) {
382
+ foreach ($f in Get-ChildItem $scriptsDir -Filter "*.py") {
383
+ Copy-Item $f.FullName (Join-Path $SkillDir "scripts") -Force
384
+ }
385
+ }
386
+ Write-Ok "Files copied to $SkillDir"
387
+
388
+ if ((Test-Path $Config) -and (Select-String -Path $Config -Pattern "conductor-skills" -Quiet)) {
389
+ Write-Info "Aider config already references conductor-skills, skipping."
390
+ } else {
391
+ Write-Info "Adding read entries to $Config ..."
392
+ $entries = @("", "# Conductor Skills", "read:")
393
+ foreach ($file in $SKILL_FILES) {
394
+ $relative = $file -replace "^skills/conductor/", ""
395
+ $entries += " - ${ReadPrefix}${relative}"
396
+ }
397
+ $entries -join "`n" | Add-Content -Path $Config
398
+ Write-Ok "Updated: $Config"
399
+ }
400
+ }
401
+
402
+ function Install-ForAgent {
403
+ param([string]$AgentName, [string]$ProjDir, [bool]$IsGlobal, [bool]$ForceWrite, [string]$TmpDir, [string]$Assembled)
404
+
405
+ if ($AgentName -eq "claude") {
406
+ return Install-Claude
407
+ }
408
+
409
+ if ($IsGlobal) {
410
+ $installDir = $env:USERPROFILE
411
+ if ($AgentName -eq "aider") {
412
+ Install-AiderToDir -SkillDir (Join-Path $installDir ".conductor-skills") -TmpDir $TmpDir -Config (Join-Path $installDir ".aider.conf.yml") -ReadPrefix "$installDir/.conductor-skills/"
413
+ } else {
414
+ $targetPath = Get-GlobalPath -AgentName $AgentName
415
+ Install-ToFile -Target $targetPath -Assembled $Assembled -ForceWrite $ForceWrite
416
+ }
417
+ } else {
418
+ switch ($AgentName) {
419
+ "codex" { Install-ToFile -Target (Join-Path $ProjDir "AGENTS.md") -Assembled $Assembled -ForceWrite $ForceWrite }
420
+ "gemini" { Install-ToFile -Target (Join-Path $ProjDir "GEMINI.md") -Assembled $Assembled -ForceWrite $ForceWrite }
421
+ "cursor" {
422
+ $frontmatter = "---`ndescription: Conductor workflow orchestration - create, run, monitor, and manage workflows`nglobs: `"**/*`"`nalwaysApply: true`n---`n`n"
423
+ Install-ToFile -Target (Join-Path $ProjDir ".cursor\rules\conductor.mdc") -Assembled $Assembled -ForceWrite $ForceWrite -Prefix $frontmatter
424
+ }
425
+ "windsurf" { Install-ToFile -Target (Join-Path $ProjDir ".windsurfrules") -Assembled $Assembled -ForceWrite $ForceWrite }
426
+ "cline" { Install-ToFile -Target (Join-Path $ProjDir ".clinerules") -Assembled $Assembled -ForceWrite $ForceWrite }
427
+ "aider" { Install-AiderToDir -SkillDir (Join-Path $ProjDir ".conductor-skills") -TmpDir $TmpDir -Config (Join-Path $ProjDir ".aider.conf.yml") -ReadPrefix ".conductor-skills/" }
428
+ "copilot" { Install-ToFile -Target (Join-Path $ProjDir ".github\copilot-instructions.md") -Assembled $Assembled -ForceWrite $ForceWrite }
429
+ "amazonq" { Install-ToFile -Target (Join-Path $ProjDir ".amazonq\rules\conductor.md") -Assembled $Assembled -ForceWrite $ForceWrite }
430
+ "opencode" { Install-ToFile -Target (Join-Path $ProjDir "AGENTS.md") -Assembled $Assembled -ForceWrite $ForceWrite }
431
+ "roo" { Install-ToFile -Target (Join-Path $ProjDir ".roo\rules\conductor.md") -Assembled $Assembled -ForceWrite $ForceWrite }
432
+ "amp" { Install-ToFile -Target (Join-Path $ProjDir ".amp\instructions.md") -Assembled $Assembled -ForceWrite $ForceWrite }
433
+ }
434
+ }
435
+ return $true
436
+ }
437
+
438
+ # ─────────────────────────────────────────────────────────────────────────────
439
+ # Uninstall
440
+ # ─────────────────────────────────────────────────────────────────────────────
441
+
442
+ function Uninstall-Agent {
443
+ param([string]$AgentName, [string]$ProjDir, [bool]$IsGlobal)
444
+
445
+ if ($AgentName -eq "claude") {
446
+ Write-Info "To remove the Conductor skill from Claude Code, run:"
447
+ Write-Host " /plugin uninstall conductor@conductor-skills (in your Claude Code session)"
448
+ return
449
+ }
450
+
451
+ if ($IsGlobal) {
452
+ if ($AgentName -eq "aider") {
453
+ $skillDir = Join-Path $env:USERPROFILE ".conductor-skills"
454
+ if (Test-Path $skillDir) {
455
+ Remove-Item -Recurse -Force $skillDir
456
+ Write-Ok "Removed: $skillDir"
457
+ Write-Info "Note: You may also want to remove the 'read:' entries from ~/.aider.conf.yml"
458
+ } else {
459
+ Write-Warn "Nothing to uninstall: $skillDir not found"
460
+ }
461
+ return
462
+ }
463
+ $target = Get-GlobalPath -AgentName $AgentName
464
+ } else {
465
+ $target = Get-TargetPath -AgentName $AgentName -ProjDir $ProjDir
466
+ if ($AgentName -eq "aider") {
467
+ if (Test-Path $target) {
468
+ Remove-Item -Recurse -Force $target
469
+ Write-Ok "Removed: $target"
470
+ Write-Info "Note: You may also want to remove the 'read:' entries from .aider.conf.yml"
471
+ } else {
472
+ Write-Warn "Nothing to uninstall: $target not found"
473
+ }
474
+ return
475
+ }
476
+ }
477
+
478
+ if (Test-Path $target) {
479
+ Remove-Item -Force $target
480
+ Write-Ok "Removed: $target"
481
+ } else {
482
+ Write-Warn "Nothing to uninstall: $target not found"
483
+ }
484
+ }
485
+
486
+ # ─────────────────────────────────────────────────────────────────────────────
487
+ # Check mode (dry run)
488
+ # ─────────────────────────────────────────────────────────────────────────────
489
+
490
+ function Do-Check {
491
+ param([string[]]$Agents)
492
+
493
+ $manifest = Get-ManifestPath -IsGlobal $true
494
+
495
+ Write-Host ""
496
+ Write-Host "Detected agents:" -ForegroundColor White
497
+ if ($Agents.Count -eq 0) {
498
+ Write-Warn "No AI coding agents detected on this system."
499
+ return
500
+ }
501
+
502
+ foreach ($a in $Agents) {
503
+ $installedVer = Read-ManifestVersion -ManifestPath $manifest -AgentName $a
504
+ $globalSupport = if (Supports-Global -AgentName $a) { "yes" } else { "no" }
505
+
506
+ if ($installedVer) {
507
+ if ($installedVer -eq $SCRIPT_VERSION) {
508
+ Write-Host " * $a v$installedVer (up to date)" -ForegroundColor Green
509
+ } else {
510
+ Write-Host " * $a v$installedVer -> v$SCRIPT_VERSION (upgrade available)" -ForegroundColor Yellow
511
+ }
512
+ } else {
513
+ Write-Host " * $a (not installed) global: $globalSupport" -ForegroundColor Blue
514
+ }
515
+ }
516
+ Write-Host ""
517
+ }
518
+
519
+ # ─────────────────────────────────────────────────────────────────────────────
520
+ # Main
521
+ # ─────────────────────────────────────────────────────────────────────────────
522
+
523
+ if ($Version) {
524
+ Write-Host "v$SCRIPT_VERSION"
525
+ exit 0
526
+ }
527
+
528
+ # Require -Agent or -All
529
+ if (-not $Agent -and -not $All) {
530
+ Write-Err "Missing required -Agent parameter (or use -All)"
531
+ exit 1
532
+ }
533
+
534
+ # Resolve project dir
535
+ $ProjectDir = (Resolve-Path $ProjectDir).Path
536
+
537
+ Write-Host ""
538
+ Write-Host "Conductor Skills Installer v$SCRIPT_VERSION" -ForegroundColor White
539
+ Write-Host ""
540
+
541
+ # Build agent list
542
+ $agentList = @()
543
+ if ($All) {
544
+ $agentList = @(Detect-Agents)
545
+ if ($agentList.Count -eq 0) {
546
+ Write-Warn "No AI coding agents detected on this system."
547
+ Write-Host ""
548
+ Write-Info "Supported agents: claude, codex, gemini, cursor, windsurf, cline,"
549
+ Write-Info " aider, copilot, amazonq, opencode, roo, amp"
550
+ Write-Host ""
551
+ Write-Info "Install one of the above, then re-run this command."
552
+ exit 0
553
+ }
554
+ Write-Info "Detected agents: $($agentList -join ', ')"
555
+ Write-Host ""
556
+ } else {
557
+ $Agent = $Agent.ToLower()
558
+ if ($VALID_AGENTS -notcontains $Agent) {
559
+ Write-Err "Unknown agent: $Agent"
560
+ exit 1
561
+ }
562
+ $agentList = @($Agent)
563
+ }
564
+
565
+ # Check mode
566
+ if ($Check) {
567
+ Do-Check -Agents $agentList
568
+ exit 0
569
+ }
570
+
571
+ # Determine manifest path
572
+ $useGlobalManifest = $Global -or $All
573
+ $manifest = Get-ManifestPath -IsGlobal $useGlobalManifest -ProjDir $ProjectDir
574
+
575
+ # Handle uninstall
576
+ if ($Uninstall) {
577
+ foreach ($a in $agentList) {
578
+ $useGlobal = [bool]$Global
579
+ if ($All -and (Supports-Global -AgentName $a)) { $useGlobal = $true }
580
+ Write-Info "Uninstalling $a ..."
581
+ Uninstall-Agent -AgentName $a -ProjDir $ProjectDir -IsGlobal $useGlobal
582
+ Remove-ManifestEntry -ManifestPath $manifest -AgentName $a
583
+ }
584
+ Write-Host ""
585
+ Write-Ok "Done!"
586
+ exit 0
587
+ }
588
+
589
+ # Check for upgrade
590
+ $targetVersion = $SCRIPT_VERSION
591
+ if ($Upgrade) {
592
+ Write-Info "Checking for updates..."
593
+ $remoteVer = Fetch-RemoteVersion
594
+ if (-not $remoteVer) {
595
+ Write-Warn "Could not check for updates (offline?). Using bundled v$SCRIPT_VERSION."
596
+ } elseif ($remoteVer -ne $SCRIPT_VERSION) {
597
+ Write-Info "Update available: v$SCRIPT_VERSION -> v$remoteVer"
598
+ $targetVersion = $remoteVer
599
+ } else {
600
+ Write-Info "Already at latest version (v$SCRIPT_VERSION)."
601
+ }
602
+ Write-Host ""
603
+ }
604
+
605
+ # Download files to temp dir
606
+ $tmpDir = Join-Path ([System.IO.Path]::GetTempPath()) "conductor-skills-$(Get-Random)"
607
+ New-Item -ItemType Directory -Path $tmpDir -Force | Out-Null
608
+
609
+ try {
610
+ Download-Files -TmpDir $tmpDir
611
+
612
+ $assembled = Join-Path $tmpDir "_assembled.md"
613
+ Assemble-Content -TmpDir $tmpDir -Output $assembled
614
+ $size = (Get-Item $assembled).Length
615
+ Write-Ok "Assembled skill content ($size bytes)"
616
+
617
+ $installedCount = 0
618
+ $skippedCount = 0
619
+
620
+ foreach ($a in $agentList) {
621
+ Write-Host ""
622
+
623
+ # Determine if global for this agent
624
+ $useGlobal = [bool]$Global
625
+ if ($All) {
626
+ if (Supports-Global -AgentName $a) {
627
+ $useGlobal = $true
628
+ } else {
629
+ Write-Info "${a}: skipped (project-only install). Use -ProjectDir <path> to include."
630
+ $skippedCount++
631
+ continue
632
+ }
633
+ }
634
+
635
+ # Validate global support for single-agent mode
636
+ if ($useGlobal -and !(Supports-Global -AgentName $a)) {
637
+ Write-Err "Global install is not supported for $a. Run from your project directory instead."
638
+ continue
639
+ }
640
+
641
+ # Idempotency check
642
+ $installedVer = Read-ManifestVersion -ManifestPath $manifest -AgentName $a
643
+ if ($installedVer -and ($installedVer -eq $targetVersion) -and !$Force -and !$Upgrade) {
644
+ Write-Ok "$a already at v$installedVer, skipping."
645
+ $skippedCount++
646
+ continue
647
+ }
648
+
649
+ if ($installedVer -and ($installedVer -ne $targetVersion)) {
650
+ Write-Info "Upgrading $a from v$installedVer to v$targetVersion ..."
651
+ } else {
652
+ Write-Info "Installing for $a ..."
653
+ }
654
+
655
+ # Perform install
656
+ $result = Install-ForAgent -AgentName $a -ProjDir $ProjectDir -IsGlobal $useGlobal -ForceWrite $Force -TmpDir $tmpDir -Assembled $assembled
657
+ if ($result -ne $false) {
658
+ $targetPath = if ($useGlobal) { Get-GlobalPath -AgentName $a } else { Get-TargetPath -AgentName $a -ProjDir $ProjectDir }
659
+ $mode = if ($useGlobal) { "global" } else { "project" }
660
+ Write-ManifestEntry -ManifestPath $manifest -AgentName $a -Ver $targetVersion -Mode $mode -TargetPath $targetPath
661
+ $installedCount++
662
+ }
663
+ }
664
+
665
+ Write-Host ""
666
+ Write-Host "Done! Installed: $installedCount, Skipped: $skippedCount" -ForegroundColor Green
667
+ Write-Host ""
668
+ Write-Host "Next steps:"
669
+ Write-Host ' Ask your agent to connect to your Conductor server, e.g.:'
670
+ Write-Host ""
671
+ Write-Host ' "Connect to my Conductor server at http://localhost:8080/api"'
672
+ Write-Host ""
673
+ Write-Host " Docs: https://github.com/conductor-oss/conductor-skills" -ForegroundColor Blue
674
+ Write-Host ""
675
+ } finally {
676
+ Remove-Item -Recurse -Force $tmpDir -ErrorAction SilentlyContinue
677
+ }