@mmerterden/multi-agent-pipeline 10.8.0 → 10.12.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 (49) hide show
  1. package/CHANGELOG.md +182 -0
  2. package/README.md +3 -1
  3. package/docs/engineering.md +76 -0
  4. package/docs/features.md +40 -36
  5. package/package.json +1 -1
  6. package/pipeline/commands/multi-agent/channels.md +42 -6
  7. package/pipeline/commands/multi-agent/finish.md +15 -6
  8. package/pipeline/commands/multi-agent/generate-bug.md +33 -0
  9. package/pipeline/commands/multi-agent/generate-task.md +33 -0
  10. package/pipeline/commands/multi-agent/help.md +12 -0
  11. package/pipeline/commands/multi-agent/manual-test.md +9 -2
  12. package/pipeline/commands/multi-agent/refs/channels/pr.md +1 -1
  13. package/pipeline/commands/multi-agent/refs/cross-cli-contract.md +7 -6
  14. package/pipeline/commands/multi-agent/refs/generate-issue.md +197 -0
  15. package/pipeline/commands/multi-agent/refs/keychain.md +12 -0
  16. package/pipeline/commands/multi-agent/refs/phases/phase-0-init.md +40 -2
  17. package/pipeline/commands/multi-agent/refs/phases/phase-3-dev.md +12 -0
  18. package/pipeline/commands/multi-agent/refs/phases/phase-4-review.md +4 -23
  19. package/pipeline/commands/multi-agent/refs/phases/phase-5-test.md +6 -1
  20. package/pipeline/commands/multi-agent/refs/phases/phase-7-report.md +5 -1
  21. package/pipeline/commands/multi-agent/refs/progress-contract.md +1 -0
  22. package/pipeline/commands/multi-agent/refs/tracker-contract.md +56 -13
  23. package/pipeline/commands/multi-agent/resume.md +6 -2
  24. package/pipeline/commands/multi-agent/sync.md +5 -5
  25. package/pipeline/commands/multi-agent.md +4 -0
  26. package/pipeline/lib/figma-mcp-refresh.sh +79 -0
  27. package/pipeline/preferences-template.json +2 -1
  28. package/pipeline/schemas/prefs.schema.json +35 -0
  29. package/pipeline/schemas/token-budget.json +7 -7
  30. package/pipeline/scripts/README.md +1 -0
  31. package/pipeline/scripts/fixtures/install-layout.tsv +6 -6
  32. package/pipeline/scripts/phase-tracker.sh +134 -22
  33. package/pipeline/scripts/smoke-channels-approval-gate.sh +60 -0
  34. package/pipeline/scripts/smoke-generate-issue.sh +114 -0
  35. package/pipeline/scripts/smoke-phase-tracker.sh +69 -0
  36. package/pipeline/scripts/smoke-progress-contract.sh +9 -0
  37. package/pipeline/scripts/smoke-tasklist-ordering.sh +1 -0
  38. package/pipeline/scripts/smoke-token-preflight.sh +82 -0
  39. package/pipeline/scripts/smoke-tracker-contract.sh +62 -0
  40. package/pipeline/scripts/smoke-update-check.sh +122 -0
  41. package/pipeline/scripts/update-check.sh +82 -0
  42. package/pipeline/skills/.skills-index.json +22 -4
  43. package/pipeline/skills/shared/core/multi-agent/SKILL.md +2 -1
  44. package/pipeline/skills/shared/core/multi-agent-channels/SKILL.md +4 -2
  45. package/pipeline/skills/shared/core/multi-agent-generate-bug/SKILL.md +39 -0
  46. package/pipeline/skills/shared/core/multi-agent-generate-task/SKILL.md +39 -0
  47. package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +4 -0
  48. package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +5 -5
  49. package/pipeline/skills/skills-index.md +5 -3
@@ -58,8 +58,9 @@ Phases by mode:
58
58
  | Mode | Phases |
59
59
  |---|---|
60
60
  | Full pipeline | 0,1,2,3,4,5,6,7 |
61
- | `--dev` | 0,3,6,7 |
62
- | `--autopilot`, `--dev autopilot` | same as dev, with confirmations skipped |
61
+ | `--dev` | 0,3,5,6,7 |
62
+ | `--dev autopilot`, `--dev local`, `--dev local autopilot` | 0,3,6,7 (Phase 5 interactive test gate dropped) |
63
+ | `--autopilot` | same as full pipeline, with confirmations skipped |
63
64
 
64
65
  Register each phase:
65
66
 
@@ -118,9 +119,10 @@ Mode-specific phase sets:
118
119
  | Mode | TaskCreate set (in order) |
119
120
  |---|---|
120
121
  | Full pipeline (`/multi-agent`, `:autopilot`, `:local`, `:local-autopilot`) | 0 → 1 → 2 → 3 → 4 → 5 → 6 → 7 (all 8) |
121
- | `:dev`, `:dev-autopilot`, `:dev-local`, `:dev-local-autopilot` | 0 → 3 → 5 → 6 → 7 (5 phases - 1/2/4 omitted entirely) |
122
+ | `:dev` | 0 → 3 → 5 → 6 → 7 (5 phases - 1/2/4 omitted entirely) |
123
+ | `:dev-autopilot`, `:dev-local`, `:dev-local-autopilot` | 0 → 3 → 6 → 7 (4 phases - 1/2/4/5 omitted entirely; the autopilot/local variants drop the interactive Phase 5 test gate) |
122
124
 
123
- Note: in `--dev` modes the omitted phases (1, 2, 4) **do not get TaskCreate calls at all** - they're not part of the mode's phase set. The "[SKIPPED]" pattern above only applies if a normally-included phase is conditionally skipped at runtime.
125
+ Note: in `--dev` modes the omitted phases (1, 2, 4 - plus 5 in the autopilot/local variants) **do not get TaskCreate calls at all** - they're not part of the mode's phase set. The "[SKIPPED]" pattern above only applies if a normally-included phase is conditionally skipped at runtime. The authoritative per-mode set is the `for p in ...` init block in each mode's own entry doc; this table mirrors those blocks.
124
126
 
125
127
  **Enforcement**: `smoke-tasklist-ordering.sh` scans every mode entry point doc (`commands/multi-agent.md`, `commands/multi-agent/{autopilot,local,local-autopilot,dev,dev-autopilot,dev-local,dev-local-autopilot}.md` + Copilot mirrors) for the explicit "in phase-number order" rule. Inventory drift fails the smoke.
126
128
 
@@ -172,23 +174,40 @@ TaskUpdate({taskId: <dev_task>, activeForm: "Editing TopBarView.swift"})
172
174
  TaskUpdate({taskId: <dev_task>, activeForm: "Running xcodebuild test"})
173
175
  ```
174
176
 
175
- **Other CLIs** - `meta Now` key plus a render call:
177
+ **Other CLIs** - the dedicated `now` action (quiet: writes `meta.Now`, never renders; the card picks it up at the next boundary render/update):
176
178
  ```bash
177
- bash $HOME/.claude/scripts/phase-tracker.sh meta 3 Now "editing TopBarView.swift"
178
- bash $HOME/.claude/scripts/phase-tracker.sh render
179
+ bash $HOME/.claude/scripts/phase-tracker.sh now 3 "editing TopBarView.swift"
179
180
  ```
180
181
 
181
- The `Now` meta key shows up in the bordered card as `Now: editing TopBarView.swift`.
182
+ The `Now` value shows up in the bordered card as `Now: editing TopBarView.swift` (truncated to 60 chars by the script).
183
+
184
+ **Progress-line mirror (required).** Every `normal`-tier progress line from the progress contract's canonical "When to emit" set is ALSO mirrored to the active phase, so the tracker always answers "what is it doing right now":
185
+
186
+ - Claude Code: `TaskUpdate({activeForm: "<line text, arrow prefix stripped>"})`
187
+ - Other CLIs: `phase-tracker.sh now <N> "<line text, arrow prefix stripped>"`
188
+
189
+ Throttling rules: mirror only canonical-set lines (`verbose`-tier internals are not mirrored); at most one mirror per emitted line; skip the mirror when the text is identical to the last mirrored value; the mirror itself never triggers a render. Text is truncated to 60 chars.
190
+
191
+ ### Delegated phases - mirror limitation + chunked dispatch (required)
192
+
193
+ When a phase's work is delegated to a subagent (Phase 3 Dev on Opus in `--dev` modes, `figma-to-component` dispatch, Phase 1 explorers, Phase 4 reviewers), the visual channel freezes for the duration of the Agent call: the orchestrator is blocked while the call is in flight, so it cannot fire `TaskUpdate` / `now` / `tokens`, and a subagent cannot drive the parent session's TaskList (its own TaskCreate/TaskUpdate calls land on an invisible child list). The progress-line mirror above can therefore only fire while the orchestrator holds control. Rules:
194
+
195
+ 1. **Pre-dispatch marker.** Immediately before every Agent call, set the active-phase line to the delegation itself, so the frozen interval at least states what is running and on which model:
196
+ - Claude Code: `TaskUpdate({activeForm: "Dev subagent (opus): <task subject>"})`
197
+ - Other CLIs: `phase-tracker.sh now <N> "dev subagent (opus): <task subject>"`
198
+ 2. **Chunk long delegations.** A phase whose delegated work spans multiple tasks MUST NOT go out as one monolithic Agent call. Dispatch per task (the Phase 2 task graph, or in `--dev` mode the self-generated task list, is the natural chunk boundary) so the orchestrator regains control at each boundary and refreshes `activeForm`, `tokens`, and `now` between chunks. Single-task phases and inherently atomic dispatches (one reviewer, one explorer) are exempt.
199
+ 3. **Post-chunk accounting.** When each chunk returns, record its token estimate (`phase-tracker.sh tokens <N> <in> <out>`) before dispatching the next chunk - not accumulated once at phase end.
182
200
 
183
201
  ### 5. Token accounting - automatic (manual top-up optional)
184
202
 
185
203
  The native TaskList header automatically prints `↑Nk tokens · thought for Ns` - Claude Code uses session-level metrics. For per-phase token attribution:
186
204
 
187
205
  ```bash
188
- bash $HOME/.claude/scripts/phase-tracker.sh tokens <N> <input_count> <output_count>
206
+ bash $HOME/.claude/scripts/phase-tracker.sh tokens <N> <input_count> <output_count> [cached_count]
207
+ bash $HOME/.claude/scripts/phase-tracker.sh model <N> <model_name>
189
208
  ```
190
209
 
191
- Token counts are additive - multiple calls accumulate. Stored per phase in the state file; surfaced in `:log` reports.
210
+ Token counts are additive - multiple calls accumulate. `input_count` is FRESH input (cache-exclusive); the optional 4th arg is the prompt-cache-read count, priced at the discounted rate. `model` tags the phase so the card and the cost helper can price it. Stored per phase in the state file; surfaced in `:log` reports, on the bash card tile (`<elapsed> · <tok> tok · ~$<usd>`), and in the card footer (total USD + cached tokens).
192
211
 
193
212
  **MANDATORY: per-phase token narration on completion (v9.10.2).** The native
194
213
  TaskList widget cannot display per-phase tokens - it shows name, status, and
@@ -203,9 +222,22 @@ Phase <N> <name> tamamlandi - ~<in> giris / ~<out> cikis token (<model>, ~$<usd>
203
222
  Phase <N> <name> done - ~<in> in / ~<out> out tokens (<model>, ~$<usd>)
204
223
  ```
205
224
 
206
- USD comes from `cost-table.json` rates for the phase's model (same math as
207
- `render-agent-log-cost.sh`: floor to cents). Phases with zero recorded tokens
208
- print `(no LLM calls)` instead of fabricating numbers.
225
+ USD comes from `phase-tracker.sh cost <N>` - the single pricing implementation
226
+ (cost-table.json rates, cached tokens at the discounted rate, floored to
227
+ cents; prints `-` when the model is unknown). Do not re-implement the math
228
+ inline. Phases with zero recorded tokens print `(no LLM calls)` instead of
229
+ fabricating numbers.
230
+
231
+ **Completion tile suffix (Claude Code).** The native widget cannot show
232
+ per-phase tokens, but subject edits after creation are safe (tile order is
233
+ fixed at TaskCreate time). So on phase completion, in addition to the
234
+ narration line, append the spend to the tile subject:
235
+
236
+ ```text
237
+ TaskUpdate({taskId: <phase_task>, subject: "Phase 3: Dev · ~35k tok · ~$0.26"})
238
+ ```
239
+
240
+ Skip the suffix when the phase recorded zero tokens (subject stays clean).
209
241
 
210
242
  **Honesty note:** on Claude Code the orchestrator does not receive its own
211
243
  usage metering, so per-phase counts are content-size estimates (chars/4 for
@@ -259,11 +291,22 @@ When `/multi-agent:resume <task_id>` is called:
259
291
 
260
292
  The `tasklist_id` meta from the previous session is replaced with the new IDs during resume.
261
293
 
294
+ ## Continuation runs (finish / manual-test)
295
+
296
+ A pre-existing `tracker-state.json` for the task is never re-initialized. Rules for any command that continues an earlier run (`/multi-agent:finish`, `/multi-agent:manual-test`, resume):
297
+
298
+ 1. `init` runs ONLY when no state file exists for the task. Otherwise the existing file is kept - phase history (elapsed, tokens, model, meta) survives.
299
+ 2. The continuing command re-declares its phase set with `add` - `add` is idempotent, so existing phases keep their name, status, and token history; only genuinely new phases are appended. The card renders phases sorted by numeric id, so mixed sets stay in order.
300
+ 3. If Phase 5 was left `in_progress` with `Now: awaiting local test (user)`, the continuing command marks it `update 5 completed` + `meta 5 Result "local test done (user)"` before its own work starts (finish may re-open it with `update 5 in_progress` when its build+test gate runs; elapsed keeps the original `started_at`, which is acceptable).
301
+ 4. On Claude Code, rebuild the FULL TaskList from the state file (completed tiles included) in phase order before any `TaskUpdate`, refreshing every `tasklist_id` meta - exactly the Resume behaviour above.
302
+ 5. Print ONE line in `outputLanguage` summarizing the inherited history, e.g. `Continuing PROJ-12345: phases 0-3 finished earlier (12m, 38.4k tok, ~$0.74)` (USD via `cost total`), then `render`.
303
+
262
304
  ## Anti-patterns
263
305
 
264
306
  ❌ **TaskList only** → `:resume` will not work; no run history is preserved.
265
307
  ❌ **`phase-tracker.sh` only** in Claude Code → the user sees no widget, only bash stdout snapshots - the #1 source of "I see no phases" complaints.
266
308
  ❌ **Wiring `phase-tracker.sh render` to `statusLine` config** → it drops below the screen as a placeholder; the user complained, removed in v7.9.0.
309
+ ❌ **One monolithic subagent call for a whole multi-task phase** → the tile freezes for the entire phase (no `activeForm`, no `tokens`, no `now`) - the user sees a dead widget for 20+ minutes. Chunk per task; see "Delegated phases" above.
267
310
 
268
311
  ## Verification
269
312
 
@@ -31,6 +31,10 @@ Resume a paused or failed task from the last successful phase.
31
31
  - Phase 3 code → already in the worktree
32
32
  - Recent `git log --oneline -10` in the worktree grounds what was actually committed vs. claimed.
33
33
 
34
- 4. **Continue the pipeline** - start from the next phase (same pipeline as the main multi-agent command).
34
+ 4. **Rebuild the phase tiles** - load `tracker-state.json` for the task (never re-init it; `refs/tracker-contract.md` "Resume behaviour" + "Continuation runs"):
35
+ - Claude Code: `TaskCreate` every phase from the state file in phase order, then `TaskUpdate` each to its stored status, and replace every `tasklist_id` meta with the new IDs.
36
+ - Other CLIs: a single `bash $HOME/.claude/scripts/phase-tracker.sh render`.
35
37
 
36
- 5. **Log**: `🔄 Resumed {JIRA-KEY}-{id} from Phase {N}`
38
+ 5. **Continue the pipeline** - start from the next phase (same pipeline as the main multi-agent command).
39
+
40
+ 6. **Log**: `🔄 Resumed {JIRA-KEY}-{id} from Phase {N}`
@@ -58,7 +58,7 @@ Run every step automatically:
58
58
  Step 0: FIGMA_SYNC SKIP (deprecated - feedback_figma_source_deprecated)
59
59
  Step 1: PLATFORM Detect macOS / Linux / Windows (Git Bash / WSL); export PLATFORM env
60
60
  Step 1.5: DETECT Compare timestamps, find stale targets
61
- Step 2: COPILOT Claude Code -> Copilot CLI (instructions + 35 sub-command skills)
61
+ Step 2: COPILOT Claude Code -> Copilot CLI (instructions + 37 sub-command skills)
62
62
  Step 3: REPO Claude Code -> pipeline repo (genericized, personal data scrub, bash -n on all sh)
63
63
  Step 3c: PLUGINS pipeline shared/external -> multi-agent-plugins marketplace (rebuild knowledge/,
64
64
  bump changed plugins' patch version, commit + push the plugins repo)
@@ -277,14 +277,14 @@ This runs on the Claude <-> Copilot axis — the two CLIs the pipeline supports
277
277
  |-------------|-------------|
278
278
  | `~/.claude/commands/multi-agent/{cmd}.md` | `~/.copilot/skills/multi-agent-{cmd}/SKILL.md` |
279
279
 
280
- **35 commands are synced** (canonical inventory - must match `cross-cli-contract.md` section 1; drift = contract violation):
280
+ **37 commands are synced** (canonical inventory - must match `cross-cli-contract.md` section 1; drift = contract violation):
281
281
 
282
282
  ```
283
283
  analysis, analysis-resolve, autopilot, build-optimize, channels, delete, dev,
284
284
  dev-autopilot, dev-local, dev-local-autopilot, diff-explain, finish, garbage-collect,
285
- help, issue, jira, kill, language, local, local-autopilot, log, manual-test,
286
- prune-logs, purge, refactor, resume, review, scan, search, setup, stack, status,
287
- sync, test, update
285
+ generate-bug, generate-task, help, issue, jira, kill, language, local,
286
+ local-autopilot, log, manual-test, prune-logs, purge, refactor, resume, review,
287
+ scan, search, setup, stack, status, sync, test, update
288
288
  ```
289
289
 
290
290
  **NOT synced**: `refs/*` - lazy-load references, Claude Code specific
@@ -77,6 +77,8 @@ Lib scripts (`~/.claude/lib/`):
77
77
  | `analysis ["<feature>"]` | Standalone feature-spec analizi: Figma / Swagger / Confluence / Jira / repo girdileri sabit 7-bölümlük şablona dökülür, humanizer'dan geçer, Local/Confluence/Jira hedef(ler)ine post edilir. Worktree veya commit yok. Dev'e zincirleme yok. |
78
78
  | `build-optimize` | iOS-only Xcode build performance wrapper. Vendored `xcode-build-orchestrator`'a dispatch eder; benchmark + compilation / project / SPM analyzer'lar + recommend-first plan `.build-benchmark/optimization-plan.md`. Non-iOS stack'lerde fail-fast. |
79
79
  | `channels [PR-url\|#N\|Jira-url\|Jira-id] [--channels pr,jira,confluence,wiki] [--content normal,test,auto-diff,note] [--message "..."]` | Post task report to multi-select channels (PR description, Jira comment, Confluence page, Wiki pages) with multi-select content sources. Humanizer pass per-channel. Bitbucket PR updates use reviewer-preserving PUT. Phase 7 delegates to this command; also invocable post-hoc for fixes made outside the pipeline. No worktree. |
80
+ | `generate-task ["desc"] [figma-url]` | Create a standards-compliant Jira **Task**: mines the project's recent Tasks for conventions (summary format, template, labels, priority), detects the active sprint, asks about unknown fields, then full draft preview + explicit approval before create. No worktree, no commits. |
81
+ | `generate-bug ["desc"] [figma-url]` | Create a standards-compliant Jira **Bug**: same convention mining + active-sprint detection; free-text logs/devices map to Steps to Reproduce / Environment; full draft preview + explicit approval before create. No worktree, no commits. |
80
82
  | `test` or `test [args]` | UI Bug Hunter - screenshot + tap + analyze on booted simulator via MCP (read `$HOME/.claude/commands/sim-test.md`). `/multi-agent:test` also resolves here via the `commands/multi-agent/test.md` delegate. |
81
83
  | `manual-test [#id]` | Phase 5 standalone Manual Test - checks out the task branch, prints Xcode / SourceTree hints, waits for user verdict (`ok` / `fix: ...`). |
82
84
  | `stack [ios\|android\|backend\|mobile\|all]` | Swap skills for next conversation. No arg = show current stack. |
@@ -116,6 +118,8 @@ This command uses lazy loading for token efficiency. Read the relevant sub-file
116
118
  | `local-autopilot` | `$HOME/.claude/commands/multi-agent/local-autopilot.md` |
117
119
  | `dev-local` | `$HOME/.claude/commands/multi-agent/dev-local.md` |
118
120
  | `dev-local-autopilot` | `$HOME/.claude/commands/multi-agent/dev-local-autopilot.md` |
121
+ | `generate-task` | `$HOME/.claude/commands/multi-agent/generate-task.md` (loads `refs/generate-issue.md`) |
122
+ | `generate-bug` | `$HOME/.claude/commands/multi-agent/generate-bug.md` (loads `refs/generate-issue.md`) |
119
123
  | `stack` | `$HOME/.claude/commands/multi-agent/stack.md` |
120
124
  | `language` | Handled inline - set/show prompt language in preferences |
121
125
  | SwiftUI component task (iOS) | `$HOME/.claude/commands/multi-agent/refs/swiftui-guide.md` |
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env bash
2
+ # figma-mcp-refresh.sh - silent Figma MCP (figu_) token renewal via OAuth refresh grant.
3
+ #
4
+ # Used by the Phase 0 token pre-flight (refs/phases/phase-0-init.md Step 0.7) and the
5
+ # expired-token decision (refs/keychain.md). Never prints token values - status lines only.
6
+ #
7
+ # Flow:
8
+ # 1. Resolve the access-token Keychain name from prefs.global.keychainMapping.figma_mcp.
9
+ # 2. Read the refresh token from "<name>_Refresh" (written by the user's generation script).
10
+ # 3. Read client credentials from .figma-oauth.json next to prefs.global.tokenScripts.figma_mcp.
11
+ # 4. POST grant_type=refresh_token to the Figma token endpoint.
12
+ # 5. On success save the new access token (and rotated refresh token) back to the Keychain.
13
+ #
14
+ # Exit codes:
15
+ # 0 renewed (access token replaced in Keychain)
16
+ # 1 refresh grant rejected by Figma (refresh token dead - run the generation script)
17
+ # 2 prerequisites missing (no mapping / no refresh entry / no oauth config)
18
+
19
+ set -euo pipefail
20
+
21
+ PREFS_FILE="${PREFS_FILE:-$HOME/.claude/multi-agent-preferences.json}"
22
+ TOKEN_ENDPOINT="https://api.figma.com/v1/oauth/token"
23
+ ACCOUNT="${USER:-$(whoami)}"
24
+
25
+ say() { printf '%s\n' "$*"; }
26
+
27
+ [ -f "$PREFS_FILE" ] || { say "figma-mcp-refresh: prefs file missing ($PREFS_FILE)"; exit 2; }
28
+
29
+ KEY_NAME=$(jq -r '.global.keychainMapping.figma_mcp // empty' "$PREFS_FILE")
30
+ [ -n "$KEY_NAME" ] || { say "figma-mcp-refresh: keychainMapping.figma_mcp not set"; exit 2; }
31
+
32
+ REFRESH_KEY="${KEY_NAME}_Refresh"
33
+ REFRESH_TOKEN=$(security find-generic-password -s "$REFRESH_KEY" -w 2>/dev/null || true)
34
+ [ -n "$REFRESH_TOKEN" ] || { say "figma-mcp-refresh: no refresh token at '$REFRESH_KEY'"; exit 2; }
35
+
36
+ SCRIPT_PATH=$(jq -r '.global.tokenScripts.figma_mcp // empty' "$PREFS_FILE")
37
+ OAUTH_CONFIG=""
38
+ if [ -n "$SCRIPT_PATH" ]; then
39
+ OAUTH_CONFIG="$(dirname "$SCRIPT_PATH")/.figma-oauth.json"
40
+ fi
41
+ [ -n "$OAUTH_CONFIG" ] && [ -f "$OAUTH_CONFIG" ] || { say "figma-mcp-refresh: .figma-oauth.json not found (tokenScripts.figma_mcp unset or sibling config missing)"; exit 2; }
42
+
43
+ CLIENT_ID=$(jq -r '.client_id // empty' "$OAUTH_CONFIG")
44
+ CLIENT_SECRET=$(jq -r '.client_secret // empty' "$OAUTH_CONFIG")
45
+ [ -n "$CLIENT_ID" ] || { say "figma-mcp-refresh: client_id missing in .figma-oauth.json"; exit 2; }
46
+
47
+ CURL_ARGS=(
48
+ --data-urlencode "grant_type=refresh_token"
49
+ --data-urlencode "refresh_token=${REFRESH_TOKEN}"
50
+ --data-urlencode "client_id=${CLIENT_ID}"
51
+ )
52
+ [ -n "$CLIENT_SECRET" ] && CURL_ARGS+=( --data-urlencode "client_secret=${CLIENT_SECRET}" )
53
+
54
+ RESPONSE=$(curl -s --max-time 20 -X POST "$TOKEN_ENDPOINT" \
55
+ -H "Content-Type: application/x-www-form-urlencoded" \
56
+ "${CURL_ARGS[@]}")
57
+
58
+ NEW_ACCESS=$(printf '%s' "$RESPONSE" | jq -r '.access_token // empty' 2>/dev/null || true)
59
+ NEW_REFRESH=$(printf '%s' "$RESPONSE" | jq -r '.refresh_token // empty' 2>/dev/null || true)
60
+ EXPIRES_IN=$(printf '%s' "$RESPONSE" | jq -r '.expires_in // "?"' 2>/dev/null || true)
61
+
62
+ if [ -z "$NEW_ACCESS" ]; then
63
+ ERR=$(printf '%s' "$RESPONSE" | jq -r '.error // .message // "unknown"' 2>/dev/null || echo "unknown")
64
+ say "figma-mcp-refresh: refresh grant rejected ($ERR) - regenerate via tokenScripts.figma_mcp"
65
+ exit 1
66
+ fi
67
+
68
+ # Save new access token first, then the rotated refresh token - order matters so a
69
+ # mid-write failure never leaves us with a lost refresh token AND a stale access token.
70
+ security delete-generic-password -s "$KEY_NAME" -a "$ACCOUNT" >/dev/null 2>&1 || true
71
+ security add-generic-password -s "$KEY_NAME" -a "$ACCOUNT" -w "$NEW_ACCESS" -T "" -U
72
+
73
+ if [ -n "$NEW_REFRESH" ]; then
74
+ security delete-generic-password -s "$REFRESH_KEY" -a "$ACCOUNT" >/dev/null 2>&1 || true
75
+ security add-generic-password -s "$REFRESH_KEY" -a "$ACCOUNT" -w "$NEW_REFRESH" -T "" -U
76
+ fi
77
+
78
+ say "figma-mcp-refresh: renewed '$KEY_NAME' (expires_in=${EXPIRES_IN}s, refresh $( [ -n "$NEW_REFRESH" ] && echo rotated || echo unchanged ))"
79
+ exit 0
@@ -14,6 +14,7 @@
14
14
  "firebase": null,
15
15
  "jenkins": null
16
16
  },
17
+ "tokenScripts": {},
17
18
  "platformIdentityRouting": {},
18
19
  "recentProjects": [],
19
20
  "recentBranches": {},
@@ -153,4 +154,4 @@
153
154
  "overrides": {}
154
155
  }
155
156
  }
156
- }
157
+ }
@@ -179,6 +179,17 @@
179
179
  }
180
180
  }
181
181
  },
182
+ "tokenScripts": {
183
+ "type": "object",
184
+ "additionalProperties": {
185
+ "type": [
186
+ "string",
187
+ "null"
188
+ ]
189
+ },
190
+ "default": {},
191
+ "description": "Maps service ids to user-owned token generation scripts (absolute paths, personal - never synced). Used by the Phase 0 token pre-flight: figma_mcp silent renewal reads the .figma-oauth.json next to tokenScripts.figma_mcp; the 'Regenerate now (script)' option runs the script itself."
192
+ },
182
193
  "platformIdentityRouting": {
183
194
  "type": "object",
184
195
  "description": "v2.1.0+. Maps repo URL glob patterns to identity names. Used in Phase 0 to auto-select git identity + PAT based on repo origin. Prevents corporate identity leaking into personal repos and vice versa.",
@@ -701,6 +712,30 @@
701
712
  "default": false,
702
713
  "description": "v6.1.0+ \u2014 Phase 4 Step 2.5 rebuttal round. When reviewers disagree (mixed blocker/approved verdict), each reviewer is re-prompted with the others' opposing arguments for one additional round before triage. Lifts signal quality on ambiguous findings at ~1\u00d7 Step 2 token cost. Off by default \u2014 flip for security-critical or release-branch reviews."
703
714
  },
715
+ "updateCheck": {
716
+ "type": "object",
717
+ "additionalProperties": false,
718
+ "description": "v10.9+ - Phase 0 Step 0.6 advisory version check. Once per ttlHours window, a bounded (3s) registry read compares the installed version against dist-tags.latest. Newer version found: interactive modes ask 'Update now / Continue' (yes runs the /multi-agent:update flow, then the run continues); autopilot logs one line and never asks. Offline/failed checks are silent; the step never blocks the pipeline.",
719
+ "properties": {
720
+ "enabled": {
721
+ "type": "boolean",
722
+ "default": true,
723
+ "description": "Master switch. On by default - the cost is at most one 3s-bounded curl per ttlHours."
724
+ },
725
+ "ttlHours": {
726
+ "type": "integer",
727
+ "minimum": 1,
728
+ "maximum": 168,
729
+ "default": 24,
730
+ "description": "Cache window for the registry read."
731
+ },
732
+ "autoUpdate": {
733
+ "type": "boolean",
734
+ "default": false,
735
+ "description": "When true, skip the question and run the update flow automatically before the run starts (interactive AND autopilot). Off by default - self-modifying ~/.claude without asking is a surprise."
736
+ }
737
+ }
738
+ },
704
739
  "verifyByTest": {
705
740
  "type": "object",
706
741
  "additionalProperties": false,
@@ -3,15 +3,15 @@
3
3
  "$id": "https://github.com/mmerterden/multi-agent-pipeline/pipeline/schemas/token-budget.json",
4
4
  "description": "Per-phase token budget for lazy-loaded pipeline docs. Enforced by smoke-token-budget.sh.",
5
5
  "phases": {
6
- "phase-0-init": { "max_tokens": 11250, "warn_tokens": 9900 },
6
+ "phase-0-init": { "max_tokens": 12400, "warn_tokens": 10900 },
7
7
  "phase-1-analysis": { "max_tokens": 3750, "warn_tokens": 3300 },
8
8
  "phase-2-planning": { "max_tokens": 6500, "warn_tokens": 5750 },
9
- "phase-3-dev": { "max_tokens": 7650, "warn_tokens": 6750 },
10
- "phase-4-review": { "max_tokens": 11100, "warn_tokens": 9750 },
11
- "phase-5-test": { "max_tokens": 2300, "warn_tokens": 2000 },
12
- "phase-6-commit": { "max_tokens": 5550, "warn_tokens": 4900 },
9
+ "phase-3-dev": { "max_tokens": 7900, "warn_tokens": 6950 },
10
+ "phase-4-review": { "max_tokens": 13250, "warn_tokens": 11650 },
11
+ "phase-5-test": { "max_tokens": 2550, "warn_tokens": 2250 },
12
+ "phase-6-commit": { "max_tokens": 6150, "warn_tokens": 5400 },
13
13
  "phase-7-report": { "max_tokens": 5600, "warn_tokens": 4950 }
14
14
  },
15
- "total_max_tokens": 46500,
16
- "note": "Token estimate = ceil(chars / 4). Per-phase budget rule: warn = current+10% (rounded to nearest 50), max = current+25%. Gives ~6 edit cycles of headroom before warn trips - intentionally quiet under normal maintenance, loud when a phase grows unusually. Only the active phase is loaded (lazy). Recalibrated at v10.0.0 after the validator/consistency/simplifier/lesson gate contracts landed in phases 1-4 (prose already compressed; the residual growth is the gate contracts themselves)."
15
+ "total_max_tokens": 50000,
16
+ "note": "Token estimate = ceil(chars / 4). Per-phase budget rule: warn = current+10% (rounded to nearest 50), max = current+25%. Gives ~6 edit cycles of headroom before warn trips - intentionally quiet under normal maintenance, loud when a phase grows unusually. Only the active phase is loaded (lazy). Recalibrated at v10.0.0 after the validator/consistency/simplifier/lesson gate contracts landed in phases 1-4. Recalibrated again at v10.9.0 after the verify-by-test (Phase 4 Step 3.7), update-check (Phase 0 Step 0.6), immutable-test (Phase 3 GREEN) and redTests re-entry contracts landed - Step 3.7 prose was compressed to a pointer into refs/features/verify-by-test.md before the recalibration."
17
17
  }
@@ -24,6 +24,7 @@ Validate contracts. Each emits `══ <name> smoke: N passed, M failed ══`
24
24
  - `smoke-phase4-triage.sh` - Phase 4 reviewer → triage flow
25
25
  - `smoke-verify-by-test.sh` - Phase 4 Step 3.7 verify-by-test contract (v10.8.0)
26
26
  - `smoke-handoff-contract.sh` - phase-boundary structured handoff + handoff-first resume (v10.8.0)
27
+ - `smoke-update-check.sh` - Phase 0 Step 0.6 advisory update-check contract (v10.9.0)
27
28
 
28
29
  ### Schema + state
29
30
  - `smoke-schema-validation.sh` - all JSON schemas validate
@@ -1,16 +1,16 @@
1
1
  .claude/CLAUDE.md 1
2
2
  .claude/agents 8
3
- .claude/commands 89
4
- .claude/lib 23
3
+ .claude/commands 92
4
+ .claude/lib 24
5
5
  .claude/multi-agent-preferences.json 1
6
6
  .claude/rules 12
7
7
  .claude/schemas 23
8
- .claude/scripts 169
8
+ .claude/scripts 174
9
9
  .claude/settings.json 1
10
10
  .claude/skills 560
11
11
  .copilot/agents 8
12
12
  .copilot/copilot-instructions.md 1
13
- .copilot/lib 23
13
+ .copilot/lib 24
14
14
  .copilot/schemas 23
15
- .copilot/scripts 169
16
- .copilot/skills 596
15
+ .copilot/scripts 174
16
+ .copilot/skills 598