@mmerterden/multi-agent-pipeline 11.5.0 → 12.1.0

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 (82) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/docs/adr/0007-multi-tool-adapter-framework.md +2 -2
  3. package/docs/adr/0008-installer-modularization-and-secret-leak-defense.md +2 -0
  4. package/docs/adr/README.md +1 -0
  5. package/docs/features.md +2 -2
  6. package/install/claude.mjs +51 -1
  7. package/install/index.mjs +34 -1
  8. package/package.json +2 -2
  9. package/pipeline/commands/multi-agent/SKILL.md +1 -0
  10. package/pipeline/commands/multi-agent/analysis/SKILL.md +1 -0
  11. package/pipeline/commands/multi-agent/analysis-resolve/SKILL.md +1 -0
  12. package/pipeline/commands/multi-agent/autopilot/SKILL.md +1 -0
  13. package/pipeline/commands/multi-agent/build-optimize/SKILL.md +1 -0
  14. package/pipeline/commands/multi-agent/channels/SKILL.md +1 -0
  15. package/pipeline/commands/multi-agent/create-jira/SKILL.md +1 -0
  16. package/pipeline/commands/multi-agent/dev/SKILL.md +1 -0
  17. package/pipeline/commands/multi-agent/dev-autopilot/SKILL.md +1 -0
  18. package/pipeline/commands/multi-agent/dev-local/SKILL.md +1 -0
  19. package/pipeline/commands/multi-agent/dev-local-autopilot/SKILL.md +1 -0
  20. package/pipeline/commands/multi-agent/diff-explain/SKILL.md +1 -0
  21. package/pipeline/commands/multi-agent/finish/SKILL.md +1 -0
  22. package/pipeline/commands/multi-agent/garbage-collect/SKILL.md +29 -3
  23. package/pipeline/commands/multi-agent/help/SKILL.md +3 -2
  24. package/pipeline/commands/multi-agent/issue/SKILL.md +1 -0
  25. package/pipeline/commands/multi-agent/jira/SKILL.md +1 -0
  26. package/pipeline/commands/multi-agent/kill/SKILL.md +1 -0
  27. package/pipeline/commands/multi-agent/language/SKILL.md +20 -1
  28. package/pipeline/commands/multi-agent/local/SKILL.md +1 -0
  29. package/pipeline/commands/multi-agent/local-autopilot/SKILL.md +1 -0
  30. package/pipeline/commands/multi-agent/log/SKILL.md +1 -0
  31. package/pipeline/commands/multi-agent/manual-test/SKILL.md +1 -0
  32. package/pipeline/commands/multi-agent/prune-logs/SKILL.md +1 -0
  33. package/pipeline/commands/multi-agent/purge/SKILL.md +27 -24
  34. package/pipeline/commands/multi-agent/refactor/SKILL.md +1 -0
  35. package/pipeline/commands/multi-agent/resume/SKILL.md +1 -0
  36. package/pipeline/commands/multi-agent/review/SKILL.md +1 -0
  37. package/pipeline/commands/multi-agent/review-issue/SKILL.md +1 -0
  38. package/pipeline/commands/multi-agent/review-jira/SKILL.md +1 -0
  39. package/pipeline/commands/multi-agent/scan/SKILL.md +1 -0
  40. package/pipeline/commands/multi-agent/search/SKILL.md +1 -0
  41. package/pipeline/commands/multi-agent/setup/SKILL.md +1 -0
  42. package/pipeline/commands/multi-agent/stack/SKILL.md +1 -0
  43. package/pipeline/commands/multi-agent/status/SKILL.md +1 -0
  44. package/pipeline/commands/multi-agent/sync/SKILL.md +20 -2
  45. package/pipeline/commands/multi-agent/test/SKILL.md +1 -0
  46. package/pipeline/commands/multi-agent/uninstall/SKILL.md +87 -0
  47. package/pipeline/commands/multi-agent/update/SKILL.md +1 -0
  48. package/pipeline/lib/multi-repo-pipeline.sh +6 -1
  49. package/pipeline/multi-agent-refs/cross-cli-contract.md +5 -5
  50. package/pipeline/multi-agent-refs/phases/phase-0-init.md +12 -1
  51. package/pipeline/scripts/_cost.mjs +35 -0
  52. package/pipeline/scripts/agent-guard.py +8 -3
  53. package/pipeline/scripts/cost-budget-check.mjs +2 -1
  54. package/pipeline/scripts/cost-lib.sh +43 -0
  55. package/pipeline/scripts/fixtures/install-layout.tsv +4 -2
  56. package/pipeline/scripts/gc-tmp.sh +67 -8
  57. package/pipeline/scripts/gc-worktrees.sh +140 -0
  58. package/pipeline/scripts/localize-commands.mjs +130 -0
  59. package/pipeline/scripts/phase-tracker.sh +10 -19
  60. package/pipeline/scripts/prune-logs.sh +100 -15
  61. package/pipeline/scripts/purge.sh +235 -0
  62. package/pipeline/scripts/render-agent-log-cost.sh +7 -13
  63. package/pipeline/scripts/render-cost-summary.sh +4 -7
  64. package/pipeline/scripts/run-aggregator.mjs +2 -3
  65. package/pipeline/scripts/smoke-description-tr.sh +82 -0
  66. package/pipeline/scripts/smoke-gc-tmp.sh +50 -4
  67. package/pipeline/scripts/smoke-gc-worktrees.sh +125 -0
  68. package/pipeline/scripts/smoke-prune-logs.sh +57 -7
  69. package/pipeline/scripts/smoke-purge.sh +138 -0
  70. package/pipeline/scripts/smoke-source-parity.sh +85 -0
  71. package/pipeline/scripts/smoke-update-check.sh +13 -0
  72. package/pipeline/scripts/uninstall.mjs +41 -6
  73. package/pipeline/scripts/update-check.sh +9 -0
  74. package/pipeline/skills/.skill-manifest.json +7 -7
  75. package/pipeline/skills/.skills-index.json +9 -9
  76. package/pipeline/skills/shared/README.md +19 -10
  77. package/pipeline/skills/shared/core/multi-agent/SKILL.md +1 -0
  78. package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +2 -2
  79. package/pipeline/skills/shared/core/multi-agent-uninstall/SKILL.md +74 -0
  80. package/pipeline/skills/skills-index.md +1 -1
  81. package/pipeline/commands/multi-agent/delete/SKILL.md +0 -67
  82. package/pipeline/skills/shared/core/multi-agent-delete/SKILL.md +0 -66
@@ -1,42 +1,45 @@
1
1
  ---
2
2
  description: "⚠️ Wipes every worktree, branch, log, and state file. Irreversible; asks for double confirmation."
3
+ description-tr: "⚠️ Tüm worktree, branch, log ve state dosyalarını siler. Geri alınamaz; çift onay ister."
3
4
  ---
4
5
 
5
6
  # multi-agent purge - Full Reset
6
7
 
7
- Reset every multi-agent state. Nuclear option - requires double confirmation.
8
+ Reset every multi-agent worktree, its local branch, and the project task
9
+ counter. Nuclear option - requires double confirmation. Backed by
10
+ `$HOME/.claude/scripts/purge.sh`, which is safe by default (dry-run, deletes
11
+ nothing until `--yes`), resolves every `rm` target strictly inside
12
+ `<repo>/.worktrees/`, and never touches the main worktree or main/master/develop.
13
+
14
+ Task log dirs are NOT purge territory - use `/multi-agent:prune-logs`. The
15
+ audit trail and metrics corpus at the log root are always preserved.
8
16
 
9
17
  ## Steps
10
18
 
11
- 1. **Scan** - find every worktree:
19
+ 1. **Preview (dry-run)** - list every worktree, branch, and the counter that
20
+ would be removed in the current repo:
12
21
  ```bash
13
- find {repo}/.worktrees/ -name "agent-state.json" -maxdepth 2
14
- ```
15
-
16
- 2. **Show the list**:
17
- ```
18
- ⚠️ WARNING - these will be deleted:
19
- - .worktrees/{JIRA-KEY}-12345/ (branch: feature/{JIRA-KEY}-12345-...)
20
- - .worktrees/{JIRA-KEY}-12345/ (branch: feature/{JIRA-KEY}-12345-...)
21
- - $HOME/.claude/logs/multi-agent/{project}/.counter
22
- Total: N worktrees, N branches
22
+ bash $HOME/.claude/scripts/purge.sh
23
23
  ```
24
+ Nothing to remove -> report "nothing to purge" and stop.
24
25
 
25
- 3. **First confirmation**: "This is irreversible. Are you sure?"
26
+ 2. **First confirmation** - native `AskUserQuestion` picker (no typed keyword),
27
+ in `outputLanguage`, including the dry-run counts:
28
+ - `question`: "Wipe the listed worktrees, branches, and counter?"
29
+ - `header`: "Purge" · `options`: `{ label: "Continue", description: "Proceed to the final confirmation" }`, `{ label: "Cancel", description: "Abort, change nothing" }`
30
+ - **Cancel** → exit.
26
31
 
27
- 4. **Second confirmation** (paranoia gate) - a native `AskUserQuestion` picker (no typed keyword):
28
- - `question`: "This is irreversible. Permanently wipe every worktree, branch, log, and state file now?" (`outputLanguage`)
29
- - `header`: "Purge" (English, <=12 chars) · `options`: `{ label: "Purge permanently", description: "Delete all worktrees, branches, logs, and state" }`, `{ label: "Cancel", description: "Abort, change nothing" }`
32
+ 3. **Second confirmation** (paranoia gate) - a second `AskUserQuestion` picker:
33
+ - `question`: "This is irreversible. Permanently wipe every worktree, branch, and state now?" (`outputLanguage`)
34
+ - `header`: "Confirm" · `options`: `{ label: "Purge permanently", description: "Delete all worktrees, branches, and the counter" }`, `{ label: "Cancel", description: "Abort, change nothing" }`
30
35
  - Anything other than **Purge permanently** → cancel.
31
36
 
32
- 5. **Delete** (per worktree):
37
+ 4. **Remote branches** - ask once whether to delete the remote branches too;
38
+ on yes, add `--delete-remote` to the apply command.
39
+
40
+ 5. **Purge** - re-run with `--yes` (plus `--delete-remote` if chosen):
33
41
  ```bash
34
- git worktree remove .worktrees/{JIRA-KEY}-{id} --force
35
- git branch -D {branch-name}
42
+ bash $HOME/.claude/scripts/purge.sh --yes
36
43
  ```
37
44
 
38
- 6. **Remote branches** - ask: "Delete the remote branches too?"
39
-
40
- 7. **Reset the counter** - remove `$HOME/.claude/logs/multi-agent/{project}/.counter`
41
-
42
- 8. **Confirm**: `🔥 Purge complete`
45
+ 6. **Report** - echo the script's summary line.
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  description: "Analyse the project: extract adapted best-practices, hunt real bugs + improvement areas, check upstream drift of derived skills, draft one plan, take approval, develop, then ask whether to sync."
3
+ description-tr: "Projeyi analiz eder: uyarlanmış best-practice'leri çıkarır, gerçek bug + iyileştirme alanlarını avlar, türetilmiş skill'lerin upstream drift'ini kontrol eder, tek plan taslağı çıkarır, onay alır, geliştirir, sonra sync isteyip istemediğini sorar."
3
4
  allowed-tools: Read, Write, Edit, Bash, Glob, Grep, Agent, AskUserQuestion, WebFetch
4
5
  ---
5
6
 
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  description: "Resume a stopped or failed task from the phase where it left off."
3
+ description-tr: "Durmuş veya hata almış bir görevi kaldığı fazdan devam ettirir."
3
4
  argument-hint: "[#id] - optional: task ID (e.g. #2). If omitted, the most recent paused task is used."
4
5
  ---
5
6
 
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  description: "Run parallel review on a branch's diff or a Pull Request: 2 models on Claude Code (Fable + Sonnet), 3 models on Copilot CLI (GPT + Opus + Sonnet). On PR input, posts per-finding inline comments and sets approve/needs-work review state."
3
+ description-tr: "Bir branch diff'i veya Pull Request üzerinde paralel review koşar: Claude Code'da 2 model (Fable + Sonnet), Copilot CLI'da 3 model (GPT + Opus + Sonnet). PR girdisinde bulgu başına inline yorum atar ve approve/needs-work durumunu işaretler."
3
4
  argument-hint: "[#N | repo#N | PR-URL | branch] - optional: PR by number/URL, repo+number, or local branch. Supports GitHub and Bitbucket Server URLs. If omitted (interactive), open GitHub + Bitbucket PRs are listed for multi-select; autopilot falls back to the current branch."
4
5
  ---
5
6
 
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  description: "Assess whether a GitHub issue is ready for multi-agent development: fetch it, grade scope / acceptance criteria / repro / design / API / stack readiness, then (after confirm) post the gaps as an issue comment. Read-only on code."
3
+ description-tr: "Bir GitHub issue'sunun multi-agent geliştirmeye hazır olup olmadığını değerlendirir: getirir; kapsam / kabul kriterleri / repro / tasarım / API / stack hazırlığını puanlar, sonra (onay sonrası) eksikleri issue yorumu olarak gönderir. Kodda salt-okunur."
3
4
  argument-hint: "[#N | repo#N | GitHub issue URL] - optional; with no argument, pick from open issues"
4
5
  ---
5
6
 
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  description: "Assess whether a Jira issue is ready for multi-agent development: fetch it, grade scope / acceptance criteria / repro / design / API / stack readiness, then (after confirm) post the gaps as a Jira comment. Read-only on code."
3
+ description-tr: "Bir Jira issue'sunun multi-agent geliştirmeye hazır olup olmadığını değerlendirir: getirir; kapsam / kabul kriterleri / repro / tasarım / API / stack hazırlığını puanlar, sonra (onay sonrası) eksikleri Jira yorumu olarak gönderir. Kodda salt-okunur."
3
4
  argument-hint: "[JIRA-KEY | Jira URL] - optional; with no argument, pick from your open Jira issues"
4
5
  ---
5
6
 
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  description: "Skill security scan: walks local skill directories against a tiered pattern catalog."
3
+ description-tr: "Skill güvenlik taraması: yerel skill dizinlerini kademeli desen kataloğuna göre tarar."
3
4
  allowed-tools: Bash, Read
4
5
  argument-hint: "[--strict] [--threshold critical|high|medium|low] [--json] [--root PATH]"
5
6
  ---
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  description: "Log search across every agent-log.md with smart ranking and filters. Optional --semantic flag queries the per-repo triage corpus."
3
+ description-tr: "Tüm agent-log.md dosyalarında akıllı sıralama ve filtrelerle log araması. İsteğe bağlı --semantic bayrağı repo bazlı triyaj korpusunu sorgular."
3
4
  allowed-tools: Bash, Read
4
5
  argument-hint: "\"query\" [--project NAME] [--since 7d] [--phase N] [--semantic] [--json|--tsv]"
5
6
  ---
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  description: "First-run setup wizard: keychain token discovery, Git Identity onboarding, and pipeline preparation."
3
+ description-tr: "İlk kurulum sihirbazı: keychain token keşfi, Git Identity kaydı ve pipeline hazırlığı."
3
4
  allowed-tools: Bash, Read, Write, AskUserQuestion, WebFetch
4
5
  ---
5
6
 
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  description: "Select the active stack for this repo by enabling the matching marketplace plugin(s) in .claude/settings.json (ios/android/mobile/backend/frontend/fullstack/all)."
3
+ description-tr: "Bu repo için aktif stack'i seçer: eşleşen marketplace plugin'lerini .claude/settings.json'da etkinleştirir (ios/android/mobile/backend/frontend/fullstack/all)."
3
4
  allowed-tools: Bash, Read, Edit, Write
4
5
  ---
5
6
 
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  description: "Show every multi-agent task's ID, phase, branch, and status."
3
+ description-tr: "Tüm multi-agent görevlerinin ID, faz, branch ve durumunu gösterir."
3
4
  ---
4
5
 
5
6
  # multi-agent status - Task Status Dashboard
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  description: "One-shot sync of the entire multi-agent ecosystem: Claude Code, Copilot CLI, pipeline repo, and website."
3
+ description-tr: "Tüm multi-agent ekosisteminin tek atımlık senkronu: Claude Code, Copilot CLI, pipeline repo ve website."
3
4
  argument-hint: "[release] [--platform=<macos|linux|windows>]"
4
5
  allowed-tools: Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion, WebFetch
5
6
  ---
@@ -130,6 +131,23 @@ If nothing is stale → report "All targets up to date" and stop.
130
131
  ~/multi-agent-pipeline/pipeline/commands/ 2>/dev/null \
131
132
  && { echo "ABORT: corporate reference leaked into pipeline/commands"; exit 1; } || true
132
133
  ```
134
+ - **Localized picker descriptions are an installed-tree artifact.** When
135
+ `outputLanguage=tr`, the installed `description:` values are Turkish and a
136
+ `description-en:` sidecar holds the English original (see
137
+ `localize-commands.mjs`). The repo must ALWAYS receive the English form:
138
+ after copying commands into `pipeline/commands/`, normalize the copy and
139
+ verify no sidecar or Turkish description leaked:
140
+ ```bash
141
+ # normalize: restore English descriptions, strip description-en sidecars
142
+ node ~/multi-agent-pipeline/pipeline/scripts/localize-commands.mjs restore \
143
+ --dir ~/multi-agent-pipeline/pipeline/commands/multi-agent
144
+ # backstop: no sidecar may survive into the repo
145
+ grep -rl "^description-en:" ~/multi-agent-pipeline/pipeline/commands/ 2>/dev/null \
146
+ && { echo "ABORT: description-en sidecar leaked into pipeline/commands"; exit 1; } || true
147
+ # backstop: repo description lines must be English (Turkish-diacritics proxy)
148
+ grep -rn '^description:.*[çğıöşüÇĞİÖŞÜ]' ~/multi-agent-pipeline/pipeline/commands/ 2>/dev/null \
149
+ && { echo "ABORT: localized description leaked into pipeline/commands"; exit 1; } || true
150
+ ```
133
151
 
134
152
  6. **Cross-platform smoke gate** (final step of the REPO sync, before push):
135
153
  ```bash
@@ -242,11 +260,11 @@ This runs on the Claude <-> Copilot axis — the two CLIs the pipeline supports
242
260
  **38 commands are synced** (canonical inventory - must match `cross-cli-contract.md` section 1; drift = contract violation):
243
261
 
244
262
  ```
245
- analysis, analysis-resolve, autopilot, build-optimize, channels, create-jira, delete, dev,
263
+ analysis, analysis-resolve, autopilot, build-optimize, channels, create-jira, dev,
246
264
  dev-autopilot, dev-local, dev-local-autopilot, diff-explain, finish, garbage-collect,
247
265
  help, issue, jira, kill, language, local,
248
266
  local-autopilot, log, manual-test, prune-logs, purge, refactor, resume, review, review-issue, review-jira,
249
- scan, search, setup, stack, status, sync, test, update
267
+ scan, search, setup, stack, status, sync, test, uninstall, update
250
268
  ```
251
269
 
252
270
  **NOT synced**: `$HOME/.claude/multi-agent-refs/*` - lazy-load references, Claude Code specific
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  description: "UI Bug Hunter - iOS Simulator (simctl) + Android Emulator (adb). Auto-detects platform. Screenshot + tap + analyze on the booted device. The Phase 5 Manual Test flow lives at /multi-agent:manual-test."
3
+ description-tr: "UI Bug Hunter - iOS Simulator (simctl) + Android Emulator (adb). Platformu otomatik algılar. Açık cihazda screenshot + tap + analiz. Faz 5 Manuel Test akışı /multi-agent:manual-test'te."
3
4
  argument-hint: '[scenario] - e.g. "dark mode" | "accessibility" | "dynamic type" | "screenshot tr" | "store-ready" | (empty = full sweep)'
4
5
  ---
5
6
 
@@ -0,0 +1,87 @@
1
+ ---
2
+ description: "Uninstall the pipeline from Claude Code + Copilot CLI. Keychain access tokens are always left untouched; --all-data also clears pipeline settings and logs. Asks for double confirmation."
3
+ description-tr: "Pipeline'ı Claude Code + Copilot CLI'dan kaldırır. Keychain erişim token'larına asla dokunulmaz; --all-data ayrıca pipeline ayarlarını ve loglarını da siler. Çift onay ister."
4
+ argument-hint: "[--dry-run] [--all-data] [--claude] [--copilot] [--target=<path>]"
5
+ ---
6
+
7
+ # multi-agent uninstall - Token-Preserving Uninstall
8
+
9
+ Uninstalls the pipeline itself from the system. **This is different from `:purge`:**
10
+
11
+ | Command | What it removes |
12
+ |---|---|
13
+ | `:purge` | Active tasks' worktrees / branches / logs / state (development data) |
14
+ | `:uninstall` | The pipeline itself: skills, commands, agents, scripts - from every CLI |
15
+
16
+ ## Two modes
17
+
18
+ | Mode | Flag | Removes | Keeps |
19
+ |---|---|---|---|
20
+ | **Standard** (default) | (none) | distributed files: commands, skills, agents, scripts, refs, schemas, lib | tokens, `CLAUDE.md`, `rules/`, `multi-agent-preferences.json`, all logs |
21
+ | **Full cleanup** | `--all-data` | standard PLUS `multi-agent-preferences.json` + `~/.claude/logs/multi-agent/` (task logs, state, metrics, audit) | tokens, `CLAUDE.md`, `rules/` (user-owned) |
22
+
23
+ Tokens in the OS credential store are NEVER removed by either mode.
24
+
25
+ ## Never deleted (either mode)
26
+
27
+ - **Keychain / Credential Manager / libsecret** personal access tokens (GitHub, Jira, Bitbucket, Confluence, Telegram, Vercel, Firebase, etc.)
28
+ - `~/.claude/CLAUDE.md` (user customisations)
29
+ - `~/.claude/rules/` (user-owned; installed write-if-missing, never overwritten)
30
+ - User content OUTSIDE the `<!-- multi-agent-pipeline:begin/end -->` markers (`copilot-instructions.md`)
31
+
32
+ Settings (`multi-agent-preferences.json`) and the log root (`~/.claude/logs/multi-agent/`) are kept by default and removed only when the user picks full cleanup (`--all-data`).
33
+
34
+ ## Steps
35
+
36
+ 1. **Determine scope** - parse `$ARGUMENTS`:
37
+ - No target flag: every installed target (default)
38
+ - `--claude / --copilot`: selective
39
+ - `--all-data`: full cleanup (also removes settings + logs)
40
+ - `--target=<path>`: adapter target (default: cwd)
41
+ - `--dry-run`: report only, delete nothing
42
+
43
+ 2. **Ask the cleanup depth** (skip if the user already passed `--all-data` or `--dry-run`) - native `AskUserQuestion` picker in `outputLanguage`:
44
+ - `question`: "How much should uninstall remove? Tokens are preserved either way."
45
+ - `header`: "Scope" · `options`:
46
+ `{ label: "Standard", description: "Remove pipeline files; keep settings + logs" }`,
47
+ `{ label: "Full cleanup", description: "Also remove settings + all task logs/state/metrics" }`
48
+ - **Full cleanup** adds `--all-data` to the flag set below.
49
+
50
+ 3. **Show a preview** (run the script with `--dry-run`, carrying the chosen flags):
51
+ ```bash
52
+ node "$HOME/.claude/scripts/uninstall.mjs" --dry-run --yes <flags>
53
+ ```
54
+ Show the output raw to the user. In full-cleanup mode the preview lists the extra settings + log removals.
55
+
56
+ 4. **First confirmation** - native `AskUserQuestion` picker (no typed y/N):
57
+ - `question`: "Remove the pipeline from the listed targets? Tokens are NOT touched." (`outputLanguage`)
58
+ - `header`: "Uninstall" · `options`: `{ label: "Continue", description: "Proceed to the final confirmation" }`, `{ label: "Cancel", description: "Keep everything installed" }`
59
+ - **Cancel** → exit.
60
+
61
+ 5. **Second confirmation** (paranoia gate, same pattern as `:purge`) - a second `AskUserQuestion` picker:
62
+ - `question`: full cleanup -> "This also erases settings + all logs and is irreversible. Proceed?"; standard -> "This is irreversible. Permanently remove the pipeline files now?" (`outputLanguage`)
63
+ - `header`: "Confirm" · `options`: `{ label: "Remove permanently", description: "Run the uninstall; tokens are preserved" }`, `{ label: "Cancel", description: "Abort, change nothing" }`
64
+ - Anything other than **Remove permanently** → cancel.
65
+
66
+ 6. **Remove** - run the real script with `--yes` (and `--all-data` if full cleanup was chosen):
67
+ ```bash
68
+ node "$HOME/.claude/scripts/uninstall.mjs" --yes <flags>
69
+ ```
70
+
71
+ 7. **Confirm**:
72
+ ```
73
+ ✓ multi-agent-pipeline removed.
74
+ ℹ Personal access tokens preserved in Keychain.
75
+ ```
76
+ Remind the user how to inspect the tokens (cross-platform - same command on every backend):
77
+ - `~/.claude/lib/credential-store.sh get "<service>"`
78
+
79
+ 8. **Reinstall** (if the user wants to):
80
+ ```bash
81
+ npx @mmerterden/multi-agent-pipeline install
82
+ ```
83
+
84
+ ## Notes
85
+
86
+ - This command does NOT remove the *installed copy* of the npm package. It only removes the distributed files. `npm uninstall -g @mmerterden/multi-agent-pipeline` is a separate step.
87
+ - `--dry-run` is always safe - zero side effects.
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  description: "Update the pipeline to the latest version: git pull, install, migrate."
3
+ description-tr: "Pipeline'ı son sürüme günceller: git pull, install, migrate."
3
4
  allowed-tools: Bash, Read, Write, AskUserQuestion
4
5
  ---
5
6
 
@@ -67,7 +67,12 @@ cmd_prepare() {
67
67
  echo "[$name] worktree already present at $target"
68
68
  else
69
69
  echo "[$name] cloning into $target"
70
- git clone --quiet "$url" "$target" || { echo "ERR: clone failed for $name" >&2; return 3; }
70
+ # Disable git's `ext::`/`fd::` remote helpers (arbitrary command execution
71
+ # at clone time) in case a repo URL ever comes from an untrusted
72
+ # .gitmodules suggestion, and end options with `--` so a URL like
73
+ # `--upload-pack=...` can't inject a clone option. https/ssh/git@ and
74
+ # local/file paths all still work.
75
+ git -c protocol.ext.allow=never -c protocol.fd.allow=never clone --quiet -- "$url" "$target" || { echo "ERR: clone failed for $name" >&2; return 3; }
71
76
  fi
72
77
  cd "$target"
73
78
  if git rev-parse --verify "$BRANCH" >/dev/null 2>&1; then
@@ -9,11 +9,11 @@
9
9
  ## 1. Command Inventory (38 commands)
10
10
 
11
11
  ```
12
- analysis, analysis-resolve, autopilot, build-optimize, channels, create-jira, delete, dev,
12
+ analysis, analysis-resolve, autopilot, build-optimize, channels, create-jira, dev,
13
13
  dev-autopilot, dev-local, dev-local-autopilot, diff-explain, finish, garbage-collect,
14
14
  help, issue, jira, kill, language, local,
15
15
  local-autopilot, log, manual-test, prune-logs, purge, refactor, resume, review, review-issue, review-jira,
16
- scan, search, setup, stack, status, sync, test, update
16
+ scan, search, setup, stack, status, sync, test, uninstall, update
17
17
  ```
18
18
 
19
19
  Categories:
@@ -23,7 +23,7 @@ Categories:
23
23
  - **Full 8-phase modes**: `autopilot`, `local`, `local-autopilot`
24
24
  - **Fast modes** (Init -> Dev(Opus) -> Commit -> Report): `dev`, `dev-autopilot`, `dev-local`, `dev-local-autopilot`
25
25
  - **Tail modes** (run the pipeline tail over already-done local work): `finish`
26
- - **Ops commands** (one-shot, no worktree): `status`, `log`, `kill`, `purge`, `delete`, `resume`, `review`, `review-jira`, `review-issue`, `analysis`, `analysis-resolve`, `build-optimize`, `channels`, `scan`, `search`, `diff-explain`, `garbage-collect`, `prune-logs`
26
+ - **Ops commands** (one-shot, no worktree): `status`, `log`, `kill`, `purge`, `uninstall`, `resume`, `review`, `review-jira`, `review-issue`, `analysis`, `analysis-resolve`, `build-optimize`, `channels`, `scan`, `search`, `diff-explain`, `garbage-collect`, `prune-logs`
27
27
  - **Meta-ops**: `setup`, `sync`, `update`, `help`, `refactor`, `test`, `stack`, `manual-test`, `language`
28
28
 
29
29
  > **Inventory drift is a contract violation.** Adding a slash command under `pipeline/commands/multi-agent/` without updating this list + its counterpart Copilot dir (`pipeline/skills/shared/core/multi-agent-<cmd>/`) is a merge blocker. `smoke-commands-skills-parity.sh` enforces command ↔ skill directory parity; `smoke-cross-cli-behavior.sh` enforces behavior parity. This doc is the authoritative command list - bump the count + table together.
@@ -163,10 +163,10 @@ argument-hint: "<input hint>"
163
163
 
164
164
  | Direction | Action |
165
165
  |---|---|
166
- | Claude → Copilot | Add `name`, `user-invocable: true`, `argument-hint`; remove `allowed-tools`; may optionally translate `description` into Turkish (existing pattern) |
166
+ | Claude → Copilot | Add `name`, `user-invocable: true`, `argument-hint`; remove `allowed-tools`; `description` stays English (localization happens only in the installed Claude tree via `description-tr` + `localize-commands.mjs`, never in repo or Copilot files) |
167
167
  | Copilot → Claude | Remove `name`, `user-invocable`, `argument-hint`; add `allowed-tools` (inferred from command's actual tool calls) |
168
168
 
169
- **Invariant**: the `description` field, after potential translation, must have the same meaning on both sides. Translation is allowed; semantic drift is not.
169
+ **Invariant**: the English `description` must have the same meaning on both sides, and a `description-tr` line (when present) must be a faithful translation of it. Semantic drift is not allowed. `description-en` sidecars are an installed-tree artifact and must never appear in repo or Copilot files.
170
170
 
171
171
  ---
172
172
 
@@ -425,7 +425,7 @@ git -C $PROJECT_ROOT config user.email "{identity.email}"
425
425
 
426
426
  `worktreePath` = `$PROJECT_ROOT`, `localMode` = `true`.
427
427
 
428
- **If normal mode** (worktree - default): 2. Worktree path: Jira → `.worktrees/{jiraId}/`, GitHub → `.worktrees/GH{issueNo}/`, free-text → `.worktrees/task-{shortId}/` 3. **Heal stale admin state first** (see "Worktree stale-lock heal" below), then `git -C $PROJECT_ROOT worktree add {path} -b {branch} origin/{baseBranch}` (if exists: enter, pull) 4. Set identity: `git -C {worktree-path} config user.name/email` 5. Create log dir + `agent-log.md` + `agent-state.json`:
428
+ **If normal mode** (worktree - default): 2. Worktree path: Jira → `.worktrees/{jiraId}/`, GitHub → `.worktrees/GH{issueNo}/`, free-text → `.worktrees/task-{shortId}/` 3. **Heal stale admin state first** (see "Worktree stale-lock heal" below) and **apply the residue guard** (see "Worktree residue guard" below), then `git -C $PROJECT_ROOT worktree add {path} -b {branch} origin/{baseBranch}` (if exists: enter, pull) 4. Set identity: `git -C {worktree-path} config user.name/email` 5. Create log dir + `agent-log.md` + `agent-state.json`:
429
429
 
430
430
  **Worktree stale-lock heal (required before every `worktree add`):** a run killed mid-`worktree add` (OOM, SIGTERM, disk full) leaves a locked or broken admin entry under `.git/worktrees/{id}/`, so the retry fails with `fatal: '<path>' already exists`. Always run the heal first - it is a no-op on a clean repo:
431
431
 
@@ -438,6 +438,14 @@ fi
438
438
 
439
439
  If the path is still registered and healthy after the heal, enter + pull instead of re-adding (existing behavior). Only when `worktree add` still fails after the heal do the rollback / collision flow in the multi-repo block below.
440
440
 
441
+ **Worktree residue guard (required once per repo, idempotent):** every worktree dir contains a `.git` file, so a blanket `git add -A` / `git add .` in the parent tree records `.worktrees/{id}` as a gitlink ("Subproject commit ...") that pollutes the branch and later needs a manual removal commit. Keep `.worktrees/` out of the index via the clone-local exclude file (never committed, so no PR noise in shared repos):
442
+
443
+ ```bash
444
+ ex="$(git -C "$PROJECT_ROOT" rev-parse --path-format=absolute --git-common-dir)/info/exclude"
445
+ mkdir -p "$(dirname "$ex")"
446
+ grep -qxF '.worktrees/' "$ex" 2>/dev/null || printf '.worktrees/\n' >> "$ex"
447
+ ```
448
+
441
449
  **v2.1.0+ Multi-Repo Worktree Setup**:
442
450
 
443
451
  When `state.projects[].length > 1`, repeat steps 2-4 **serially per repo** (worktrees are cheap; serial keeps git index sane and surfaces collisions one at a time):
@@ -448,6 +456,9 @@ for proj in "${PROJECTS[@]}"; do
448
456
  git -C "$proj" worktree prune 2>/dev/null || true # heal stale admin state
449
457
  git -C "$proj" worktree list --porcelain | grep -qF "$WT_PATH" \
450
458
  && git -C "$proj" worktree unlock "$WT_PATH" 2>/dev/null || true
459
+ ex="$(git -C "$proj" rev-parse --path-format=absolute --git-common-dir)/info/exclude"
460
+ mkdir -p "$(dirname "$ex")"
461
+ grep -qxF '.worktrees/' "$ex" 2>/dev/null || printf '.worktrees/\n' >> "$ex" # residue guard
451
462
  git -C "$proj" worktree add "$WT_PATH" -b "$BRANCH" "origin/$BASE_BRANCH"
452
463
  git -C "$WT_PATH" config user.name "${proj_identity_name}"
453
464
  git -C "$WT_PATH" config user.email "${proj_identity_email}"
@@ -0,0 +1,35 @@
1
+ /**
2
+ * @file _cost.mjs - shared token-cost pricing math for the .mjs cost scripts
3
+ * (cost-budget-check.mjs, run-aggregator.mjs).
4
+ *
5
+ * The single source of the pricing formula for Node callers. Rate DATA still
6
+ * lives in cost-table.json; this module owns only the arithmetic so the formula
7
+ * is not copy-pasted across scripts. Zero runtime dependencies (ADR-0004).
8
+ *
9
+ * @module pipeline/scripts/_cost
10
+ */
11
+
12
+ /**
13
+ * USD cost for a token trio given a rate object.
14
+ *
15
+ * tokensIn is fresh (cache-exclusive) input; tokensCached is priced at the
16
+ * discounted cacheReadPerMtok rate, falling back to inPerMtok when absent.
17
+ * Missing per-Mtok rate fields default to 0. Returns null when `rate` is falsy.
18
+ *
19
+ * @param {{inPerMtok?:number,outPerMtok?:number,cacheReadPerMtok?:number}|null|undefined} rate
20
+ * @param {number} [tokensIn]
21
+ * @param {number} [tokensOut]
22
+ * @param {number} [tokensCached]
23
+ * @returns {number|null}
24
+ */
25
+ export function costUsd(rate, tokensIn = 0, tokensOut = 0, tokensCached = 0) {
26
+ if (!rate) return null;
27
+ const rin = rate.inPerMtok || 0;
28
+ const rout = rate.outPerMtok || 0;
29
+ const rcache = rate.cacheReadPerMtok ?? rin;
30
+ return (
31
+ ((tokensIn || 0) / 1_000_000) * rin +
32
+ ((tokensCached || 0) / 1_000_000) * rcache +
33
+ ((tokensOut || 0) / 1_000_000) * rout
34
+ );
35
+ }
@@ -40,7 +40,8 @@ def decide(cmd: str) -> str:
40
40
  try:
41
41
  toks = shlex.split(cmd)
42
42
  except Exception:
43
- toks = cmd.split()
43
+ # A force-push we can't tokenize -> can't prove it's safe -> block.
44
+ return "BLOCK_FORCE"
44
45
  if any(t in PROTECTED or t.split(":")[-1] in PROTECTED for t in toks):
45
46
  return "BLOCK_FORCE"
46
47
  # non-flag args after `push`; only a remote (or nothing) means a bare push
@@ -52,8 +53,12 @@ def decide(cmd: str) -> str:
52
53
  if seen and not t.startswith("-"):
53
54
  args.append(t)
54
55
  nonremote = [a for a in args if a not in REMOTES]
55
- if not nonremote and os.environ.get("CUR_BRANCH", "") in PROTECTED:
56
- return "BLOCK_FORCE"
56
+ if not nonremote:
57
+ # Bare force-push: the target is the current branch. Block if it's
58
+ # protected OR undeterminable (fail-closed for a data-loss guard).
59
+ cur = os.environ.get("CUR_BRANCH", "")
60
+ if cur in PROTECTED or cur == "":
61
+ return "BLOCK_FORCE"
57
62
 
58
63
  return "OK"
59
64
 
@@ -34,6 +34,7 @@
34
34
  import { readFileSync, existsSync } from "fs";
35
35
  import { dirname, join } from "path";
36
36
  import { fileURLToPath } from "url";
37
+ import { costUsd } from "./_cost.mjs";
37
38
 
38
39
  const __dirname = dirname(fileURLToPath(import.meta.url));
39
40
 
@@ -138,7 +139,7 @@ for (const p of Object.values(tracker.phases || {})) {
138
139
  tokensOut += Number(p?.tokens_out || 0);
139
140
  }
140
141
 
141
- const usd = (tokensIn * rate.inPerMtok + tokensOut * rate.outPerMtok) / 1_000_000;
142
+ const usd = costUsd(rate, tokensIn, tokensOut);
142
143
  const pctOfMax = (usd / cfg.maxUsd) * 100;
143
144
  const usdStr = `$${usd.toFixed(2)}`;
144
145
  const totalTok = tokensIn + tokensOut;
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env bash
2
+ # cost-lib.sh - shared token-cost pricing math, sourced by the bash cost
3
+ # renderers (phase-tracker.sh, render-agent-log-cost.sh, render-cost-summary.sh).
4
+ #
5
+ # The single source of the pricing formula for shell callers. Rate DATA still
6
+ # lives in cost-table.json; this file owns only the arithmetic so the formula
7
+ # is not copy-pasted across scripts.
8
+ #
9
+ # COST_JQ_DEFS is a jq prelude string callers prepend to their own jq program:
10
+ #
11
+ # cost_usd_of($rate; $tin; $tout; $tcached)
12
+ # -> USD for one row given a rate object (or null) and token counts.
13
+ # tokens_in is fresh input (cache-exclusive); tokens_cached is priced at
14
+ # the discounted cacheReadPerMtok rate (falling back to inPerMtok when
15
+ # absent). Returns null when $rate is null.
16
+ # cost_floor_cents($u)
17
+ # -> floor USD to whole cents; null passes through.
18
+ #
19
+ # cost_usd <rate-json> <tin> <tout> [tcached] - scalar convenience wrapper
20
+ # that prints the raw (unrounded) USD via jq. Prints nothing when jq is absent.
21
+
22
+ COST_JQ_DEFS='
23
+ def cost_usd_of($rate; $tin; $tout; $tcached):
24
+ if $rate == null then null
25
+ else ( ($tin / 1000000) * $rate.inPerMtok
26
+ + ($tcached / 1000000) * ($rate.cacheReadPerMtok // $rate.inPerMtok)
27
+ + ($tout / 1000000) * $rate.outPerMtok )
28
+ end;
29
+ def cost_floor_cents($u):
30
+ if $u == null then null else (($u * 100) | floor) / 100 end;
31
+ '
32
+
33
+ cost_usd() {
34
+ local rate="$1" tin="$2" tout="$3" tcached="${4:-0}"
35
+ command -v jq >/dev/null 2>&1 || return 0
36
+ jq -n \
37
+ --argjson rate "$rate" \
38
+ --argjson tin "$tin" \
39
+ --argjson tout "$tout" \
40
+ --argjson tcached "$tcached" \
41
+ "$COST_JQ_DEFS"'
42
+ cost_usd_of($rate; $tin; $tout; $tcached)'
43
+ }
@@ -1,3 +1,4 @@
1
+ .claude/.pipeline-version 1
1
2
  .claude/CLAUDE.md 1
2
3
  .claude/agents 8
3
4
  .claude/commands 44
@@ -6,12 +7,13 @@
6
7
  .claude/multi-agent-refs 51
7
8
  .claude/rules 12
8
9
  .claude/schemas 23
9
- .claude/scripts 184
10
+ .claude/scripts 193
10
11
  .claude/settings.json 1
11
12
  .claude/skills 428
13
+ .copilot/.pipeline-version 1
12
14
  .copilot/agents 8
13
15
  .copilot/copilot-instructions.md 1
14
16
  .copilot/lib 25
15
17
  .copilot/schemas 23
16
- .copilot/scripts 184
18
+ .copilot/scripts 193
17
19
  .copilot/skills 467