@mmerterden/multi-agent-pipeline 16.18.0 → 16.19.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 (200) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/README.md +5 -5
  3. package/README.tr.md +2 -2
  4. package/docs/FIGMA_PIPELINE.md +1 -1
  5. package/docs/adr/0001-three-model-triage.md +4 -2
  6. package/docs/architecture.md +2 -2
  7. package/docs/ecosystem.md +13 -11
  8. package/docs/features.md +2 -2
  9. package/index.js +1 -1
  10. package/install/_common.mjs +25 -1
  11. package/install/_dev-only-files.mjs +2 -2
  12. package/install/_mcp-register.mjs +4 -3
  13. package/install/_plugin-skills.mjs +1 -3
  14. package/install/copilot.mjs +18 -9
  15. package/install/index.mjs +2 -4
  16. package/install/templates/copilot-instructions.md +7 -7
  17. package/package.json +1 -1
  18. package/pipeline/claude-md-template.md +2 -2
  19. package/pipeline/commands/multi-agent/SKILL.md +5 -5
  20. package/pipeline/commands/multi-agent/complaint-analysis/SKILL.md +1 -1
  21. package/pipeline/commands/multi-agent/design-check/SKILL.md +1 -1
  22. package/pipeline/commands/multi-agent/help/SKILL.md +2 -2
  23. package/pipeline/commands/multi-agent/local-autopilot/SKILL.md +1 -1
  24. package/pipeline/commands/multi-agent/review/SKILL.md +27 -14
  25. package/pipeline/commands/multi-agent/review-analysis/SKILL.md +1 -1
  26. package/pipeline/commands/multi-agent/store-ready/SKILL.md +2 -2
  27. package/pipeline/commands/multi-agent/sync/SKILL.md +2 -2
  28. package/pipeline/commands/sim-test.md +54 -15
  29. package/pipeline/lib/credential-inventory.sh +15 -2
  30. package/pipeline/lib/credential-store-resolver.sh +14 -4
  31. package/pipeline/lib/credential-store.sh +8 -2
  32. package/pipeline/lib/extract-conventions.sh +1 -14
  33. package/pipeline/lib/fetch-confluence.sh +12 -4
  34. package/pipeline/lib/fetch-crashlytics.sh +11 -8
  35. package/pipeline/lib/fetch-document.sh +1 -1
  36. package/pipeline/lib/fetch-figma-annotations.sh +7 -5
  37. package/pipeline/lib/fetch-fortify.sh +5 -3
  38. package/pipeline/lib/fetch-graylog.sh +5 -3
  39. package/pipeline/lib/figma-mcp-refresh.sh +1 -1
  40. package/pipeline/lib/figma-screenshot.sh +27 -24
  41. package/pipeline/lib/figma-token.sh +8 -4
  42. package/pipeline/lib/issue-fetcher.sh +0 -1
  43. package/pipeline/lib/jira-publish.sh +7 -5
  44. package/pipeline/lib/md2confluence-v3.py +13 -7
  45. package/pipeline/lib/multi-repo-pipeline.sh +18 -8
  46. package/pipeline/lib/plan-todos.sh +11 -0
  47. package/pipeline/lib/post-pr-review.sh +9 -2
  48. package/pipeline/lib/repo-cache.sh +18 -10
  49. package/pipeline/lib/review-watch.sh +60 -14
  50. package/pipeline/lib/shadow-git.sh +8 -4
  51. package/pipeline/lib/vercel-deploy.sh +2 -2
  52. package/pipeline/multi-agent-refs/_dev-context.md +5 -2
  53. package/pipeline/multi-agent-refs/analysis/locked.md +4 -4
  54. package/pipeline/multi-agent-refs/analysis/render.md +1 -1
  55. package/pipeline/multi-agent-refs/cross-cli-contract.md +1 -1
  56. package/pipeline/multi-agent-refs/outside-the-pipeline.md +6 -6
  57. package/pipeline/multi-agent-refs/phases/log-format.md +1 -1
  58. package/pipeline/multi-agent-refs/phases/modes.md +1 -1
  59. package/pipeline/multi-agent-refs/phases/phase-0-init.md +4 -2
  60. package/pipeline/multi-agent-refs/phases/phase-1-analysis.md +3 -3
  61. package/pipeline/multi-agent-refs/phases/phase-2-planning.md +5 -5
  62. package/pipeline/multi-agent-refs/phases/phase-4-review.md +21 -16
  63. package/pipeline/multi-agent-refs/tracker-contract.md +1 -1
  64. package/pipeline/rules/figma-pipeline.md +18 -72
  65. package/pipeline/rules/outside-the-pipeline.md +4 -3
  66. package/pipeline/schemas/agent-state.schema.json +1 -1
  67. package/pipeline/schemas/token-budget.json +1 -1
  68. package/pipeline/scripts/_stack-routing.mjs +1 -1
  69. package/pipeline/scripts/agent-guard.py +102 -21
  70. package/pipeline/scripts/anonymize-findings.mjs +7 -6
  71. package/pipeline/scripts/build-skills-index.mjs +14 -3
  72. package/pipeline/scripts/cost-budget-check.mjs +5 -3
  73. package/pipeline/scripts/cost-lib.sh +0 -15
  74. package/pipeline/scripts/diff-explain.mjs +22 -12
  75. package/pipeline/scripts/gc-refs.sh +6 -2
  76. package/pipeline/scripts/gc-tmp.sh +1 -1
  77. package/pipeline/scripts/gc-worktrees.sh +1 -1
  78. package/pipeline/scripts/gen-mode-dispatch.mjs +3 -3
  79. package/pipeline/scripts/github-ssh-setup.sh +7 -2
  80. package/pipeline/scripts/graph-build.mjs +2 -2
  81. package/pipeline/scripts/jira-wiki-escape.mjs +2 -1
  82. package/pipeline/scripts/keychain.py +12 -11
  83. package/pipeline/scripts/learning-curve.mjs +1 -1
  84. package/pipeline/scripts/migrate-prefs.mjs +1 -1
  85. package/pipeline/scripts/output-quality-check.sh +3 -1
  86. package/pipeline/scripts/phase-tracker.sh +1 -1
  87. package/pipeline/scripts/phase0-exit-gate.mjs +2 -1
  88. package/pipeline/scripts/plan-coverage-gate.mjs +2 -1
  89. package/pipeline/scripts/pre-commit-check.sh +23 -13
  90. package/pipeline/scripts/prune-logs.sh +1 -1
  91. package/pipeline/scripts/render-agent-log-cost.sh +3 -1
  92. package/pipeline/scripts/render-cost-summary.sh +4 -2
  93. package/pipeline/scripts/render-work-summary.sh +5 -3
  94. package/pipeline/scripts/repo-map.mjs +3 -2
  95. package/pipeline/scripts/scan-skills.sh +6 -2
  96. package/pipeline/scripts/search-logs.sh +8 -6
  97. package/pipeline/scripts/sign-skills.sh +3 -1
  98. package/pipeline/scripts/smoke-cross-cli-behavior.sh +1 -1
  99. package/pipeline/scripts/triage-memory.mjs +25 -4
  100. package/pipeline/scripts/uninstall.mjs +20 -12
  101. package/pipeline/scripts/update-check.sh +2 -2
  102. package/pipeline/scripts/update-issue-progress.sh +6 -5
  103. package/pipeline/scripts/validate-analysis-doc.mjs +6 -6
  104. package/pipeline/scripts/verify-skills.sh +3 -1
  105. package/pipeline/scripts/worktree-finalize.sh +22 -10
  106. package/pipeline/skills/.skill-manifest.json +81 -57
  107. package/pipeline/skills/.skills-index.json +19 -19
  108. package/pipeline/skills/shared/README.md +8 -8
  109. package/pipeline/skills/shared/core/multi-agent/SKILL.md +7 -7
  110. package/pipeline/skills/shared/core/multi-agent-design-check/SKILL.md +1 -1
  111. package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +2 -2
  112. package/pipeline/skills/shared/core/multi-agent-local/SKILL.md +1 -1
  113. package/pipeline/skills/shared/core/multi-agent-local-autopilot/SKILL.md +2 -2
  114. package/pipeline/skills/shared/core/multi-agent-review/SKILL.md +23 -14
  115. package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +2 -2
  116. package/pipeline/skills/shared/external/NOTICE-dimillian-skills.md +56 -0
  117. package/pipeline/skills/shared/external/accessibility-compliance-accessibility-audit/SKILL.md +0 -4
  118. package/pipeline/skills/shared/external/api-patterns/SKILL.md +12 -24
  119. package/pipeline/skills/shared/external/app-store-changelog/references/release-notes-guidelines.md +34 -0
  120. package/pipeline/skills/shared/external/app-store-changelog/scripts/collect_release_changes.sh +33 -0
  121. package/pipeline/skills/shared/external/architecture/SKILL.md +7 -9
  122. package/pipeline/skills/shared/external/debugging-strategies/SKILL.md +0 -4
  123. package/pipeline/skills/shared/external/fastapi-pro/SKILL.md +0 -1
  124. package/pipeline/skills/shared/external/github-actions-templates/SKILL.md +0 -14
  125. package/pipeline/skills/shared/external/hig-components-content/SKILL.md +13 -13
  126. package/pipeline/skills/shared/external/hig-components-layout/SKILL.md +16 -16
  127. package/pipeline/skills/shared/external/hig-components-status/SKILL.md +6 -6
  128. package/pipeline/skills/shared/external/hig-components-system/SKILL.md +13 -13
  129. package/pipeline/skills/shared/external/hig-foundations/SKILL.md +23 -23
  130. package/pipeline/skills/shared/external/hig-inputs/SKILL.md +18 -18
  131. package/pipeline/skills/shared/external/hig-patterns/SKILL.md +30 -30
  132. package/pipeline/skills/shared/external/hig-platforms/SKILL.md +11 -11
  133. package/pipeline/skills/shared/external/hig-technologies/SKILL.md +33 -33
  134. package/pipeline/skills/shared/external/ios-coding-standard/references/STANDARD.md +52 -52
  135. package/pipeline/skills/shared/external/ios-coding-standard/references/lint-local.sh +1 -1
  136. package/pipeline/skills/shared/external/ios-coding-standard/references/rules.yml +11 -11
  137. package/pipeline/skills/shared/external/ios-developer/SKILL.md +0 -1
  138. package/pipeline/skills/shared/external/ios-module-structure/SKILL.md +7 -3
  139. package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +9 -15
  140. package/pipeline/skills/shared/external/macos-spm-app-packaging/SKILL.md +0 -5
  141. package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/bootstrap/Package.swift +17 -0
  142. package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/bootstrap/Sources/MyApp/Resources/.keep +0 -0
  143. package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/bootstrap/Sources/MyApp/main.swift +11 -0
  144. package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/bootstrap/version.env +2 -0
  145. package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/build_icon.sh +49 -0
  146. package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/compile_and_run.sh +63 -0
  147. package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/launch.sh +28 -0
  148. package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/make_appcast.sh +82 -0
  149. package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/package_app.sh +206 -0
  150. package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/setup_dev_signing.sh +52 -0
  151. package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/sign-and-notarize.sh +52 -0
  152. package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/version.env +2 -0
  153. package/pipeline/skills/shared/external/macos-spm-app-packaging/references/packaging.md +17 -0
  154. package/pipeline/skills/shared/external/macos-spm-app-packaging/references/release.md +32 -0
  155. package/pipeline/skills/shared/external/macos-spm-app-packaging/references/scaffold.md +79 -0
  156. package/pipeline/skills/shared/external/monorepo-architect/SKILL.md +0 -1
  157. package/pipeline/skills/shared/external/nodejs-backend-patterns/SKILL.md +0 -4
  158. package/pipeline/skills/shared/external/swift-concurrency-expert/references/approachable-concurrency.md +63 -0
  159. package/pipeline/skills/shared/external/swift-concurrency-expert/references/swift-6-2-concurrency.md +272 -0
  160. package/pipeline/skills/shared/external/swift-concurrency-expert/references/swiftui-concurrency-tour-wwdc.md +33 -0
  161. package/pipeline/skills/shared/external/swiftui-performance-audit/references/code-smells.md +150 -0
  162. package/pipeline/skills/shared/external/swiftui-performance-audit/references/demystify-swiftui-performance-wwdc23.md +46 -0
  163. package/pipeline/skills/shared/external/swiftui-performance-audit/references/optimizing-swiftui-performance-instruments.md +29 -0
  164. package/pipeline/skills/shared/external/swiftui-performance-audit/references/profiling-intake.md +44 -0
  165. package/pipeline/skills/shared/external/swiftui-performance-audit/references/report-template.md +47 -0
  166. package/pipeline/skills/shared/external/swiftui-performance-audit/references/understanding-hangs-in-your-app.md +33 -0
  167. package/pipeline/skills/shared/external/swiftui-performance-audit/references/understanding-improving-swiftui-performance.md +52 -0
  168. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/app-wiring.md +201 -0
  169. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/async-state.md +96 -0
  170. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/components-index.md +46 -0
  171. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/controls.md +57 -0
  172. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/deeplinks.md +66 -0
  173. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/focus.md +90 -0
  174. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/form.md +97 -0
  175. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/grids.md +71 -0
  176. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/haptics.md +71 -0
  177. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/input-toolbar.md +51 -0
  178. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/lightweight-clients.md +93 -0
  179. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/list.md +86 -0
  180. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/loading-placeholders.md +38 -0
  181. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/macos-settings.md +71 -0
  182. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/matched-transitions.md +59 -0
  183. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/media.md +73 -0
  184. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/menu-bar.md +101 -0
  185. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/navigationstack.md +159 -0
  186. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/overlay.md +45 -0
  187. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/performance.md +62 -0
  188. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/previews.md +48 -0
  189. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/scroll-reveal.md +133 -0
  190. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/scrollview.md +87 -0
  191. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/searchable.md +71 -0
  192. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/sheets.md +155 -0
  193. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/split-views.md +72 -0
  194. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/tabview.md +114 -0
  195. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/theming.md +71 -0
  196. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/title-menus.md +93 -0
  197. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/top-bar.md +49 -0
  198. package/pipeline/skills/shared/external/swiftui-view-refactor/references/mv-patterns.md +161 -0
  199. package/pipeline/skills/skills-index.md +8 -8
  200. package/pipeline/skills/shared/external/help-skills/SKILL.md +0 -166
@@ -89,7 +89,7 @@ Phase 0: Init -> Phase 3: Dev (self-contained) -> Phase 4: Review -> Phase 5: Te
89
89
  | Phase 1 (Analysis) | Parallel Explore agents + analysis document | **SKIP** - tile flips to `skipped` at Step 7.5 | **SKIP** |
90
90
  | Phase 2 (Planning) | TaskCreate + architecture review + **Plan Approval Gate** | **SKIP** (no plan means no plan gate) | **SKIP** |
91
91
  | Phase 3 (Dev) | Follows the Phase 2 plan, TDD cycle (Sonnet) | **Self-contained** (Opus): agent scans relevant files, implements with TDD, builds | Same, on the local branch |
92
- | Phase 4 (Review) | Parallel review + Fable triage (Claude: 2-model / Copilot: 3-model) | **Same** - gates, parallel review, triage; blocking findings return to Phase 3 (cap 3) | **Same**, on the local branch diff |
92
+ | Phase 4 (Review) | Parallel review + Fable triage (3 reviewers on every host: Claude Code Fable + Opus + Sonnet, Copilot GPT-5.4 + Opus + Sonnet) | **Same** - gates, parallel review, triage; blocking findings return to Phase 3 (cap 3) | **Same**, on the local branch diff |
93
93
  | Phase 5 (User Test) | Interactive prompt | **Interactive prompt** | Not in the set - no worktree to check out |
94
94
  | Phase 6 (Commit) | Commit + PR | Same - still asks | Same |
95
95
  | Phase 7 (Report) | Full report + channels multi-select | Simplified - no analysis section, review section IS present, channels menu still pauses | Same |
@@ -142,7 +142,7 @@ Results are cached in `global.serviceStatus` (existing TTL contract, default 300
142
142
  **Figma MCP expired / rejected - CRITICAL path.** The `figma_mcp` OAuth token (`figu_`) expires on a schedule (90 days), unlike the PATs. Because a dead MCP token silently degrades every Figma consumer to Tier 2/3 and has cost rebuild rounds, an expired `figma_mcp` is never deferred to mid-run:
143
143
 
144
144
  1. **Silent renewal first**: run `~/.claude/lib/figma-mcp-refresh.sh` (refresh grant via `<key>_Refresh` + the `.figma-oauth.json` client credentials next to `prefs.global.tokenScripts.figma_mcp`). Exit 0 → re-probe, log `→ figma mcp token renewed silently`, continue. No question asked.
145
- 2. **Renewal impossible/rejected** (exit 1/2) → AskUserQuestion at init (`question`/`description` in `outputLanguage`): "Figma MCP token expired - update it now?"
145
+ 2. **Renewal impossible/rejected** (exit 1/2) → ask once at init through the native picker (`picker-contract.md`; `question`/`description` in `outputLanguage`): "Figma MCP credential expired - update it now?" The answer routes to a script or the clipboard Save Flow; the value itself is never typed in chat.
146
146
  - **Regenerate now (script)** - shown only when `prefs.global.tokenScripts.figma_mcp` is set: run that script (browser OAuth flow), then re-probe and continue.
147
147
  - **Save a new token** - Token Save Flow from `setup.md` (clipboard path).
148
148
  - **Continue degraded** - proceed on Tier 2 (REST PAT) for this run; log the downgrade.
@@ -269,7 +269,7 @@ Scan `$HOME` (maxdepth 2) for project markers (`.xcodeproj`, `Package.swift`, `b
269
269
  ```
270
270
  6. Sort: `develop*` first, then `release/*`, then `main`/`master`. Surface through the
271
271
  **native picker** per `picker-contract.md` (`AskUserQuestion` on Claude Code,
272
- `ask_choice.sh` on Copilot CLI) - `question` + `description` in `outputLanguage`,
272
+ `ask-choice.sh` on Copilot CLI) - `question` + `description` in `outputLanguage`,
273
273
  `label` = the branch name verbatim (a proper noun, never translated) with the recent
274
274
  branch first and marked `(Recommended)`. The ASCII sketch
275
275
  below is what the options carry, not a menu to print:
@@ -425,6 +425,8 @@ git -C $PROJECT_ROOT config user.email "{identity.email}"
425
425
 
426
426
  **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` at `$HOME/.claude/logs/multi-agent/{project}/{task-id}/`, never inside the worktree:
427
427
 
428
+ **Worktree location convention (cited by every other command):** always `{projectRoot}/.worktrees/{taskId}`, inside the repo, never under `$HOME`. `{taskId}` is the directory name from the rule above (`DC-<shortId>` for `/multi-agent:design-check`). `.worktrees` is fixed, not a preference: no `worktreeBasePath` key exists, and `gc-worktrees.sh`, `purge.sh`, the cost renderers and `usage-report.mjs` resolve `<repo>/.worktrees/` by name. Multi-repo tasks get one worktree per repo (the loop below); `--local` creates none and `worktreePath` is `$PROJECT_ROOT`.
429
+
428
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:
429
431
 
430
432
  ```bash
@@ -1,6 +1,6 @@
1
- ### Phase 1: Analysis (Fable)
1
+ ### Phase 1: Analysis (Sonnet)
2
2
 
3
- > **TLDR** - Fable-driven codebase exploration (Opus when the fallback ladder engages). Detects if the issue is already fixed (git blame, closed PRs), then launches parallel Explore sub-agents to map the affected code paths. Outputs: impact analysis, stack detection (auto-selects platform guide), relevant files, risk areas. Feeds Phase 2 planning.
3
+ > **TLDR** - Sonnet-driven codebase exploration: the `explorer` persona declares `preferredModel: sonnet` (haiku when the fallback ladder engages). Detects if the issue is already fixed (git blame, closed PRs), then launches parallel Explore sub-agents to map the affected code paths. Outputs: impact analysis, stack detection (auto-selects platform guide), relevant files, risk areas. Feeds Phase 2 planning.
4
4
 
5
5
  <!-- progress-contract: applied -->
6
6
  Progress emission per `$HOME/.claude/multi-agent-refs/progress-contract.md` - lines for each Explore dispatch, each finish, analyst synthesis start, `analysis.json` write.
@@ -217,7 +217,7 @@ Forward the explorer call's token totals into the tracker so Phase 7's Cost Brea
217
217
 
218
218
  ```bash
219
219
  LOG_METRIC_FORWARD_TO_TRACKER=1 $HOME/.claude/scripts/log-metric.sh "$TASK_ID" 1 analysis.completed \
220
- model=opus tokens_in=$IN tokens_out=$OUT duration_ms=$DUR
220
+ model=sonnet tokens_in=$IN tokens_out=$OUT duration_ms=$DUR
221
221
  ```
222
222
 
223
223
  Best-effort. See `$HOME/.claude/multi-agent-refs/progress-contract.md#token-telemetry-forwarding` for the canonical contract.
@@ -215,7 +215,7 @@ Otherwise (normal mode), run the gate. The gate has **two modes** that chain: Cl
215
215
 
216
216
  ##### 5a - Clarification Mode (conditional, max 2 rounds)
217
217
 
218
- Trigger if the plan Opus produced in Step 1-4 carries ANY ambiguity signal from Phase 1 analysis:
218
+ Trigger if the plan Fable produced in Step 1-4 carries ANY ambiguity signal from Phase 1 analysis:
219
219
 
220
220
  | Signal | Check |
221
221
  |---|---|
@@ -300,12 +300,12 @@ Handle the selection:
300
300
  - Set `state.status = "paused"`, log `🧠 Phase 2: Plan aborted by user`, stop
301
301
  - **Other (free-text edit request)**:
302
302
  - Treat the typed text as an edit request. Append to `state.phases["2"].planEditRequests`, bump `planIterations`
303
- - Pass the edit request + current plan to Opus; Opus revises and returns a new plan (same schema, same validator)
303
+ - Pass the edit request + current plan to the planning model (Fable; Opus when the fallback ladder engages); it revises and returns a new plan (same schema, same validator)
304
304
  - Re-render the plan (5b), loop
305
305
 
306
306
  No hard cap on edit iterations - the user controls exit via the Approve / Cancel options. Between iterations, keep only the **latest plan** as canonical; previous renders are in the log for audit but do not re-enter the validator.
307
307
 
308
- **Validator**: every revised plan goes through `node $HOME/.claude/scripts/validate-planning.mjs -` before re-render. If validation fails after an edit, log `⚠️ Phase 2: Plan validator failed after edit request #N - retrying Opus once` and retry once; on second failure surface the validator error to the user and go back to approval prompt with the pre-edit plan.
308
+ **Validator**: every revised plan goes through `node $HOME/.claude/scripts/validate-planning.mjs -` before re-render. If validation fails after an edit, log `⚠️ Phase 2: Plan validator failed after edit request #N - retrying the planning model once` and retry once; on second failure surface the validator error to the user and go back to approval prompt with the pre-edit plan.
309
309
 
310
310
  #### Step 6 - Mode-specific short-circuit (reference)
311
311
 
@@ -321,11 +321,11 @@ The pipeline shapes interact with the gate as follows. This table is the source
321
321
 
322
322
  #### Telemetry - token forwarding
323
323
 
324
- After plan generation (and after each edit-loop iteration), forward Opus call totals so Phase 7's Cost Breakdown captures Phase 2:
324
+ After plan generation (and after each edit-loop iteration), forward the planning model's call totals so Phase 7's Cost Breakdown captures Phase 2 (`model=` names the rung that actually ran: `fable`, or `opus` after a fallback step):
325
325
 
326
326
  ```bash
327
327
  LOG_METRIC_FORWARD_TO_TRACKER=1 $HOME/.claude/scripts/log-metric.sh "$TASK_ID" 2 plan.generated \
328
- model=opus tokens_in=$IN tokens_out=$OUT duration_ms=$DUR iteration=$N
328
+ model=fable tokens_in=$IN tokens_out=$OUT duration_ms=$DUR iteration=$N
329
329
  ```
330
330
 
331
331
  Best-effort. See `$HOME/.claude/multi-agent-refs/progress-contract.md#token-telemetry-forwarding`.
@@ -104,7 +104,7 @@ If changes include UI files (iOS: `*View.swift`, `*Screen.swift`, `*Cell.swift`;
104
104
  - Missing safe area / keyboard avoidance → **important**
105
105
  - Hardcoded colors instead of system/semantic colors → **suggestion**
106
106
 
107
- **iOS - SwiftUI interaction & accessibility conventions.** Gated to changed SwiftUI files. These are rule-registry territory as of v14.0.0, not a list transcribed here: Step 1.78 resolves them from whichever registry declares SwiftUI scope, so the criteria and their severities live in one place instead of drifting between this doc and the skill. Reviewers receive the resolved rule IDs. Native-SwiftUI-first unless the project's `figma-config` `ui.*` declares a custom system, in which case check against that system. Reference skills, when no registry covers the change: `figma-navigation`, `figma-overlays`, `figma-bottom-sheets`, `figma-to-swiftui`.
107
+ **iOS - SwiftUI interaction & accessibility conventions.** Gated to changed SwiftUI files. These are rule-registry territory as of v14.0.0, not a list transcribed here: Step 1.78 resolves them from whichever registry declares SwiftUI scope, so the criteria and their severities live in one place instead of drifting between this doc and the skill. Reviewers receive the resolved rule IDs. Native-SwiftUI-first unless the project's `figma-config` `ui.*` declares a custom system, in which case check against that system. Reference skills, when no registry covers the change: the enabled stack plugin's `navigation`, `overlays` and `bottom-sheets` skills (`ai-ios-toolkit:*` / `ai-android-toolkit:*`), plus `figma-to-swiftui`.
108
108
 
109
109
  **Android - Material Design compliance** (skills: `ai-android-toolkit:compose-components`, `ai-android-toolkit:android-architecture`):
110
110
  - Non-Material3 component when M3 equivalent exists → **suggestion**
@@ -303,17 +303,19 @@ looks like it ran. The full statement lives in the managed block at `~/.codex/AG
303
303
  Sub-agent delegation itself is authorized by that same managed block; without it Phase 4
304
304
  degrades to a single in-thread review.
305
305
 
306
- **Single-vendor caveat.** Every Codex reviewer is an OpenAI model, so the
307
- cross-vendor disagreement that Claude Code and Copilot CLI get for free is absent.
308
- The diversity budget shifts to reasoning effort and persona focus: Reviewer 1 runs
309
- `xhigh` on security and architecture, Reviewer 2 runs a different model family
310
- member on edge cases, Reviewer 3 runs `medium` on quality. Treat consensus among
311
- them as weaker evidence than the same consensus on a two-vendor host, and say so
312
- in the triage note when all three agree on a borderline finding.
306
+ **Single-vendor caveat.** Every Codex reviewer is an OpenAI model, and every Claude
307
+ Code reviewer is an Anthropic model, so the cross-vendor disagreement that Copilot CLI
308
+ gets for free (GPT-5.4 beside two Claude models) is absent on both. The diversity budget
309
+ shifts to model generation, reasoning effort and persona focus: on Codex Reviewer 1 runs
310
+ `xhigh` on security and architecture, Reviewer 2 runs a different model family member
311
+ on edge cases, Reviewer 3 runs `medium` on quality; on Claude Code the three slots are
312
+ three different Claude tiers. Treat consensus among a single-vendor panel as weaker
313
+ evidence than the same consensus on Copilot CLI, and say so in the triage note when all
314
+ three agree on a borderline finding.
313
315
 
314
316
  Each reviewer inherits the `code-reviewer` agent's focus areas (Security, Architecture, Quality, Performance) and output contract. The orchestrator overrides only the model and the stack-specific skill per-reviewer - no prompt duplication.
315
317
 
316
- **Model override wiring:** `code-reviewer.md` declares `preferredModel: fable`, so Reviewer 1 uses the persona default (Fable 5). Reviewer 2 (`claude-opus-5` on Claude Code, `gpt-5.4` elsewhere) and Reviewer 3 (`claude-sonnet-5`) set `PHASE_MODEL_OVERRIDE=<model>` before dispatch - the orchestrator exports `CLAUDE_CODE_SUBAGENT_MODEL` on Claude Code, or passes `--model` on Copilot CLI. Full precedence rule: `skills/shared/core/multi-agent/SKILL.md#agent-dispatch--per-persona-model-routing-v610`. Fable dispatches are subject to the fallback contract (`$HOME/.claude/multi-agent-refs/features/model-fallback.md`): dispatch-error retry walks `fable -> opus -> sonnet` and budget-ceiling downgrade.
318
+ **Model override wiring:** `code-reviewer.md` declares `preferredModel: fable`, so Reviewer 1 uses the persona default (Fable 5). Reviewer 2 (`claude-opus-5` on Claude Code, `gpt-5.4` elsewhere) and Reviewer 3 (`claude-sonnet-5`) set `PHASE_MODEL_OVERRIDE=<model>` before dispatch - the orchestrator exports `CLAUDE_CODE_SUBAGENT_MODEL` on Claude Code, or passes `--model` on Copilot CLI. Full precedence rule: `skills/shared/core/multi-agent/SKILL.md#agent-dispatch--per-persona-model-routing`. Fable dispatches are subject to the fallback contract (`$HOME/.claude/multi-agent-refs/features/model-fallback.md`): dispatch-error retry walks `fable -> opus -> sonnet` and budget-ceiling downgrade.
317
319
 
318
320
  **Stack-specific skills loaded per reviewer** (from Phase 1 `detectedStack`). All three columns are used on every host; Reviewer 2 reads them as Opus on Claude Code and as GPT-5.4 elsewhere.
319
321
 
@@ -401,7 +403,7 @@ Exit 0 = valid. Exit 2 = contradiction (approved=true with blocking findings) -
401
403
  - Max one round. Results replace the original outputs.
402
404
  4. Proceed to Step 3 triage with the round-2 outputs.
403
405
 
404
- **Parity contract:** both CLI sides (Claude 2-model, Copilot 3-model) run the round identically. Telemetry emits `review_round_count={1|2}` per reviewer for Phase 7 rollup.
406
+ **Parity contract:** every host (three reviewers each: Claude Code, Copilot CLI, Codex CLI) runs the round identically. Telemetry emits `review_round_count={1|2}` per reviewer for Phase 7 rollup.
405
407
 
406
408
  **Cost ceiling:** rebuttal round consumes ~1× the original Step 2 token budget. Smoke + budget tests treat this as opt-in so the default cost stays the same.
407
409
 
@@ -495,7 +497,7 @@ bash $HOME/.claude/scripts/log-metric.sh "$TASK_ID" 4 memory.hit rows=$CITED_COU
495
497
  **Triage prompt skeleton:**
496
498
 
497
499
  ```
498
- You are the Review Triage agent. Two reviewers returned findings on this diff.
500
+ You are the Review Triage agent. Three reviewers (fewer on a single-scope run) returned findings on this diff.
499
501
  Your job: separate signal from noise. Do NOT add new findings. Do NOT re-review code.
500
502
 
501
503
  For each finding, decide:
@@ -567,10 +569,13 @@ emit() { # $1=event $2=model $3=duration $4=tokens_in $5=tokens_out
567
569
  model="$2" duration_ms="$3" tokens_in="$4" tokens_out="$5"
568
570
  }
569
571
  emit review.reviewer_call fable "$R1_DURATION" "$R1_IN" "$R1_OUT" # opus on Copilot CLI
570
- emit review.reviewer_call sonnet "$SONNET_DURATION" "$SONNET_IN" "$SONNET_OUT"
571
572
  # Reviewer 2 is Opus on Claude Code and GPT-5.4 elsewhere:
572
- [ "${CLI_HOST:-claude}" = "copilot" ] && \
573
- emit review.reviewer_call gpt-5.4 "$GPT_DURATION" "$GPT_IN" "$GPT_OUT"
573
+ if [ "${CLI_HOST:-claude}" = "claude" ]; then
574
+ emit review.reviewer_call opus "$R2_DURATION" "$R2_IN" "$R2_OUT"
575
+ else
576
+ emit review.reviewer_call gpt-5.4 "$R2_DURATION" "$R2_IN" "$R2_OUT"
577
+ fi
578
+ emit review.reviewer_call sonnet "$SONNET_DURATION" "$SONNET_IN" "$SONNET_OUT"
574
579
  emit review.triage_call fable "$TRIAGE_DURATION" "$TRIAGE_IN" "$TRIAGE_OUT"
575
580
  bash "$M" "$TASK_ID" 4 review.completed raw_count=$RAW accepted=$ACC \
576
581
  deferred=$DEF rejected=$REJ approved=$APPROVED duration_ms=$DURATION
@@ -584,7 +589,7 @@ Opt-in via `prefs.global.triageCrossCheck.enabled` (default `false`). Sampled ru
584
589
 
585
590
  ##### 3.6 Consensus surfacing (anti-correlation)
586
591
 
587
- **Rationale:** Reviewer 1 (Fable) and Reviewer 3 (Sonnet) are both Anthropic Claude models, so unanimous agreement on a *judgment call* is not independent confirmation - same-family models drift the same way on ambiguous prompts. Treating "both approved" as proof produces false-consensus passes. Triage therefore records a `consensus` block (schema v3.1.0) and surfaces disagreement and unverified agreement to the user rather than burying it.
592
+ **Rationale:** On Claude Code all three reviewers are Anthropic models, on Codex CLI all three are OpenAI, and on Copilot CLI two of three are Anthropic, so unanimous agreement on a *judgment call* is not independent confirmation: same-family models drift the same way on ambiguous prompts, and "all approved" taken as proof produces false-consensus passes. Triage therefore records a `consensus` block (schema v3.1.0) and surfaces disagreement and unverified agreement instead of burying it.
588
593
 
589
594
  After the triage verdict is computed, populate `triage.consensus`:
590
595
 
@@ -631,7 +636,7 @@ Statement shape: the durable rule/root cause, not the symptom - "force-unwrapp
631
636
 
632
637
  Progress line: ` → writing lesson to learnings ledger ({N} entries)`
633
638
 
634
- Log: "Phase 4: Review - raw={N1+N2} accepted={Na} deferred={Nd} rejected={Nr} approved={bool} consensus={verdict}"
639
+ Log: "Phase 4: Review - raw={N1+N2+N3} accepted={Na} deferred={Nd} rejected={Nr} approved={bool} consensus={verdict}"
635
640
 
636
641
  ---
637
642
 
@@ -246,7 +246,7 @@ bash $HOME/.claude/scripts/phase-tracker.sh model <N> <model_name>
246
246
 
247
247
  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).
248
248
 
249
- **MANDATORY: per-phase token narration on completion (v9.10.2).** The native
249
+ **Required: per-phase token narration on completion (v9.10.2).** The native
250
250
  TaskList widget cannot display per-phase tokens - it shows name, status, and
251
251
  duration only. Without this rule the user sees durations and nothing else
252
252
  until the Phase 7 Cost Breakdown. So whenever a phase transitions to
@@ -96,7 +96,7 @@ Re-fetching Figma in dev phases:
96
96
 
97
97
  ### Verification
98
98
 
99
- The pipeline ships a smoke gate `pipeline/scripts/smoke-no-mcp-in-dev-phases.sh` that reads `state.telemetry.mcpCalls[]`. If any entry has `phase >= 2`, the gate fails. CI runs this gate after every run as a regression check.
99
+ The pipeline ships a smoke gate `pipeline/scripts/smoke-no-mcp-in-dev-phases.sh` that reads `state.telemetry.mcpCalls[]`. If any entry has `phase >= 2`, the gate fails. It is a maintainer-side regression check: it runs locally as part of `npm test` and the pre-push hook, not in CI (the CI workflow is dormant) and not after every pipeline run.
100
100
 
101
101
  Memory: [[mcp-only-in-analysis]]
102
102
 
@@ -174,12 +174,14 @@ When Figma pipeline is active (`figmaConfigPath` set in project preferences),
174
174
  multi-agent Phase 3 (DEV) dispatches Figma sub-phases instead of standard TDD:
175
175
 
176
176
  ```
177
- Phase 3.0: figma-to-swift-ui-start → Branch, assign, registry
178
- Phase 3.1: figma-to-swiftui → Full 8-phase implementation
179
- Phase 3.2: figma-commit → 14-item review + commit + PR
180
- Phase 3.3: figma-iteration-commit → Batch iteration commit (if iterating)
177
+ Phase 3.0: figma-validate → registry, Code Connect, token compliance (halts Phase 3 on failure)
178
+ Phase 3.1: create-component / create-screen → full implementation by the enabled stack plugin (evolve-component for an existing one)
179
+ Phase 3.2: figma-commit → 14-item review + commit + PR
180
+ Phase 3.3: figma-iteration-commit → Batch iteration commit (if iterating)
181
181
  ```
182
182
 
183
+ Skill names are the enabled stack plugin's (`ai-ios-toolkit:*` / `ai-android-toolkit:*`); the dispatch contract is `multi-agent-refs/component-dispatch.md`.
184
+
183
185
  ### Abstraction Layers
184
186
 
185
187
  | Layer | Provider Options | Config |
@@ -219,70 +221,14 @@ Provider interfaces are defined inline in the plugin skill sets - see the `ai-
219
221
  13. Build verification (xcodebuild)
220
222
  14. Test verification (ViewInspector + Snapshot)
221
223
 
222
- ### Command Catalog (31 commands)
223
-
224
- **Core Pipeline:**
225
-
226
- | Command | What It Does |
227
- |---------|-------------|
228
- | `/figma-to-swiftui <url>` | Full 8-phase pipeline |
229
- | `/figma-to-swift-ui-start #N` | Start from issue: branch, assign |
230
- | `/figma-to-swift-ui-implement <url>` | Phases 0-4 only (implementation) |
231
- | `/figma-to-swift-ui-test <url>` | Phase 5 only (tests) |
232
- | `/figma-to-swift-ui-wiki <Name>` | Phase 7 only (wiki docs) |
233
- | `/figma-to-swift-ui-code-connect <url>` | Phase 6 only (Code Connect) |
234
- | `/figma-to-swift-ui-confluence-sync` | Sync wiki → Confluence |
235
- | `/figma-to-swift-ui-status-update` | Refresh Confluence dashboard |
236
-
237
- **Issue & Board:**
238
-
239
- | Command | What It Does |
240
- |---------|-------------|
241
- | `/figma-issue open <url>` | Create GitHub Issue + optional Jira |
242
- | `/figma-review <Name>` | Interactive review (approve/bug) |
243
- | `/figma-validate <url>` | Pre-implementation validation |
244
-
245
- **Commit & PR:**
246
-
247
- | Command | What It Does |
248
- |---------|-------------|
249
- | `/figma-commit <Name>` | 14-item review + commit + PR |
250
- | `/figma-iteration-commit <Name>` | Commit to iteration/develop + PR |
251
-
252
- **Iteration & Batch:**
253
-
254
- | Command | What It Does |
255
- |---------|-------------|
256
- | `/figma-iterate` | Auto loop: pick → implement → commit |
257
- | `/figma-cli-iterate` | Full CLI iterate (all phases) |
258
- | `/figma-cli-lean-iterate` | Lean iterate (skip test+wiki) |
259
- | `/figma-cli-iterate-mend` | Re-implement discarded components |
260
- | `/figma-cli-skip` | Mark component as skipped |
261
- | `/figma-skip` | Skip + update Confluence |
262
-
263
- **Bugfix:**
264
-
265
- | Command | What It Does |
266
- |---------|-------------|
267
- | `/figma-fix` | Apply targeted bug fixes |
268
- | `/figma-mend` | Re-implement from scratch |
269
-
270
- **Setup & Utility:**
271
-
272
- | Command | What It Does |
273
- |---------|-------------|
274
- | `/figma-setup` | Environment setup wizard |
275
- | `/figma-utility` | Figma data fetch (screenshots, metadata) |
276
- | `/figma-remote-mcp-auth` | Figma MCP OAuth flow |
277
- | `/figma-ui-patterns` | UI pattern library index |
278
- | `/figma-price-integration` | Price protocol adoption guide |
279
-
280
- **Performance (batch production):**
281
-
282
- | Command | What It Does |
283
- |---------|-------------|
284
- | `/performance-start #N` | Start component with perf tracking |
285
- | `/performance-swiftui` | Perf-optimized pipeline |
286
- | `/performance-tour` | Batch produce multiple components |
287
- | `/performance-review-next` | Interactive batch review |
288
- | `/performance-iteration-commit-all` | Batch validate + push all |
224
+ ### Figma Skill Surfaces (current)
225
+
226
+ The old 31-command personal catalog is retired; none of those `/figma-*` commands ships with the pipeline. Figma capabilities live on three surfaces. Screens are ALWAYS drawn 1:1 from the Figma design context resolved in analysis, and a Code Connect-mapped component is ALWAYS used when one exists (see the fallback chain + Code Connect rules above).
227
+
228
+ | Surface | What it carries | When to use |
229
+ |---------|-----------------|-------------|
230
+ | `ai-ios-toolkit` / `ai-android-toolkit` (marketplace stack plugins, enabled per repo by `/multi-agent:stack`; skill names below are the iOS plugin's, the Android plugin carries the Compose equivalents) | Component skills: `create-component`, `create-screen`, `evolve-component`, `figma-validate`, `figma-review`, `figma-commit`, `figma-iteration-commit`, `figma-component-start`, `figma-utility`, `figma-setup`, `code-connect`, `component-docs`, `component-wiki`, plus the `navigation` / `overlays` / `bottom-sheets` / `ui-patterns` reference skills | Direct component work in a repo where the stack plugin is enabled; Phase 3 dispatches here for `taskType === component` |
231
+ | Pipeline commands | `/multi-agent:analysis` (the only phase allowed to fetch Figma), `/multi-agent:design-check` (mock-mode vs Figma conformance, Phase 4 Step 2.8), `/multi-agent:review` (cites the analysis doc, never Figma) | Inside multi-agent pipeline runs |
232
+ | Legacy `/figma-to-swiftui` (single standalone command) | The old full 8-phase flow | Kept for the old flow only; prefer the plugin's `create-component` for new work |
233
+
234
+ The pipeline keeps no Figma command catalog of its own: the routing table for component skills is maintained inside each stack plugin's `index` skill, and `/multi-agent:stack` decides which plugin is active for a repo.
@@ -21,6 +21,7 @@ available. Read the effective `enabledPlugins` and load each enabled toolkit's
21
21
  `ai-common-toolkit` and `ai-analyst-toolkit` are on everywhere. Nothing enabled
22
22
  is a normal state.
23
23
 
24
- **multi-agent-toolkit MCP.** 80+ tools for a running app: `ui-inspect`,
25
- `crash-logs`, `design-check`, `ios-app-store-audit`, `ios-testflight`. Use them
26
- instead of guessing about on-screen state. Not registered is a silent no-op.
24
+ **multi-agent-toolkit MCP.** 80+ tools for a running app: `ios_get_ui_tree` /
25
+ `android_get_ui_tree`, `ios_list_crashes` / `android_list_crashes`, `design_*`,
26
+ `ios_app_store_audit`, `ios_testflight_validate`. Use them instead of guessing
27
+ about on-screen state. Not registered is a silent no-op.
@@ -107,7 +107,7 @@
107
107
  "siblings": {
108
108
  "type": "array",
109
109
  "maxItems": 10,
110
- "description": "Repos the dev-context picker offered that this run does not modify: read-only siblings, plus any extra the user selected. Persisted at Phase 0 because the phases that consume them run much later - Phase 4's platform-parity cross-check reads this and nothing else, so a picker result that is not written here is a step that can never fire.",
110
+ "description": "Repos the dev-context picker offered that this run does not modify: read-only siblings, plus any extra the user selected. Persisted at Phase 0 because the phases that consume them run much later - Phase 4's platform-parity cross-check reads this as the fourth of its four counterpart sources (after --with, prefs.projects[<slug>].counterpartRoots[] and the primary checkout's sibling directories; see multi-agent-refs/platform-parity.md), so a picker result that is not written here is a candidate the check can never see.",
111
111
  "items": {
112
112
  "type": "object",
113
113
  "additionalProperties": false,
@@ -36,6 +36,6 @@
36
36
  "warn_tokens": 5600
37
37
  }
38
38
  },
39
- "total_max_tokens": 57850,
39
+ "total_max_tokens": 58250,
40
40
  "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. Total bumped 50000 -> 51000 at v12.5.0 after the worktree residue/traversal-prune contract (Phase 0 + Phase 5 heal) and the Reflexion causal-diagnosis contract (Phase 4 lesson memory) landed; the prose was compressed first (161 tokens reclaimed) and every per-phase max still passes - only the aggregate needed room. Recalibrated again at v13.6.0 after the install-relative path correction: an instruction that names `pipeline/scripts/x` resolves only from a repo checkout, and a run happens in the user's worktree, so 157 references across these docs moved to `$HOME/.claude/...` at +5 bytes each - 196 tokens of pure correctness cost. Same discipline as before: prose was compressed FIRST (149 tokens reclaimed, by pointing Phase 1's Figma tier table at the Phase 0 probe that already resolved it and Phase 4's Codex constraints at the always-loaded AGENTS.md block), and only then were the budgets moved. Five warn lines had been permanently amber, which makes the amber tier useless as a signal, so every warn was reset to the documented current+10% and the four maxes that the new warn would have collided with were reset to current+25%. Aggregate 51000 -> 51500. Total bumped 51500 -> 52200 at v14.0.0 after Phase 4 Review entered the four --dev mode phase sets and the criteria-resolution contract (Step 1.78) landed. Same discipline as every prior bump: prose was compressed FIRST, 820 tokens reclaimed, before the number moved. Two of those compressions are structural rather than cosmetic - the hardcoded SwiftUI interaction list in Step 1.5 and the SwiftUI convention paragraph in Step 2.8 were transcriptions of rules that now live in a scoped registry, so keeping them here would have re-created the drift this release exists to remove, and the third moved the Step 1.78 full contract into refs/features/skill-conformance.md leaving a pointer. What remains is contract text that cannot be inferred: the manifest's four consumer-visible parts, the conformance checklist the reviewers must return, and the fail-closed semantics. Every per-phase max still passes (phase-4 12405/14750); only the aggregate needed room. Total bumped 52200 -> 52700 at v14.1.0 after two more contracts landed: stack skill routing (Phase 3 pre-flight step 9) and worktree finalize (Phase 6 step 9). Compression came first, as always, and twice: 224 tokens out of Phase 3 by pointing its criteria-ledger and routing steps at their feature files instead of restating them, and 190 out of Phase 6 by moving the finalize contract into refs/features/worktree-finalize.md and leaving the invocation plus the exit-3 semantics. Both new contracts follow the pattern the earlier ones set: the phase doc carries the call and the decision, the feature file carries the reasoning, and the feature files are outside this budget because it loops only the eight phase-N-* keys. Every per-phase max still passes (phase-3 7677/8950, phase-6 5223/6150 and both under warn); only the aggregate needed room. Total bumped 52700 -> 52750 for the Phase 0 Step 3 branch-persistence correction: the step wrote the legacy `projects[].branches` while the TTL filter two sections below read `global.recentBranches`, and both spots named a `{name, lastUsed}` shape the schema rejects (`branch` required, `additionalProperties: false`), so the recent-branch picker option could never populate and a literal implementation would have failed prefs validation. Naming the right target, the right key and the legacy field to avoid costs 41 tokens over the one line it replaces. Compression came first and was applied three times to the replacement text itself, from 120 tokens down to 66, by moving the rationale out of the phase doc entirely: the reasoning now lives where it is enforced, in the migrate-prefs carry-forward comment and the smoke-pref-migration f7 block, leaving the phase doc with only the instruction. 50 was the smallest step that clears it; phase-0-init sits at 10893/12400, far under its own max, so this is purely an aggregate ceiling. v15.0.0: total 52750 -> 53100, the stack-skill tables in phase-1/2/4 now carry plugin-namespaced names (ai-<stack>-toolkit:<skill>) - functional prefixes, ~170 tokens. v15.10.0: total 53350 -> 53950 for the memory-recall + context-offload contracts (Phase 1 two-block durable-knowledge injection and its telemetry, Phase 3 build-log offload pipe, Phase 4 ranked prior art, offload pipe and recall telemetry). Compression came first and twice, taking the new prose from 1168 tokens to 580: the reasoning behind the two blocks lives in multi-agent-refs/prompt-assembly.md and the reasoning behind the offload filter lives in the offload-ref.sh header, both outside this budget, so the phase docs carry only the call, the pref that gates it and the one fact an agent cannot infer - that the evidence gate still reads the whole build log, so offloading changes what is read, never what counts as a verified pass. Every per-phase max still passes (phase-3 7985/8950, phase-4 12997/14750); phase-3 and phase-4 crossed their warn lines and are left amber on purpose, because that is the signal that those two docs are the next ones needing structural compression rather than another bump. v15.13.0: total 53950 -> 54050 for the prefs-to-flag bridges. Five settings had shipped declared-but-inert: contextOffload.minLines and .tailLines (fixed in 15.11.0), learningsLedger.maxBriefEntries, and testGap.scanTree and .promoteSeverity - the last two declared in the schema AND implemented as flags in the scanner, with nothing in between reading the pref and passing the flag. Wiring three of them costs the phase docs 94 tokens, which is the wiring itself and not prose: two `--max` substitutions and a three-line GAP_FLAGS block. Compression came first and twice, as always: the rationale that would have sat in phase-5 now lives in the header of smoke-prefs-consumed.sh, the gate that makes this class fail a build instead of shipping, and a `--severity-promote` table row was dropped because the invocation above it now shows the flag and names the pref that triggers it, which the row did not. 100 was the smallest step that clears it. Every per-phase max still passes; phase-3 and phase-4 remain amber on purpose. v15.14.0: total 54050 -> 54400 for the supported-version gate. Phase 0 Step 0.6 stopped being purely advisory: a release can now publish an npm dist-tag `required` that names the oldest runnable version, and below it the run halts instead of nagging. What the phase doc has to carry is the part an agent cannot infer - the third stdout field, that the halt is identical in autopilot, and that the run must NOT continue on the freshly updated install because its docs were already loaded from the old version. Compression came first, as always, and took the new prose from 469 tokens to 337: the rationale for the floor, the exemption list, the fail-open rules and the `npm dist-tag add` recipe all moved to multi-agent-refs/rules.md \"Supported Version Gate\" (loaded by 25 commands, outside this budget) and to the header of require-supported-version.sh, leaving the phase doc with the call, the decision table and the halt. 350 was the smallest step that clears it. Every per-phase max still passes (phase-0-init 11230/12400); phase-3 and phase-4 remain amber on purpose. v15.17.0: total 54400 -> 54900 for the Phase 1 analysis-document step. Phase 2 and Phase 3 pre-flights had BLOCKED on `analysis/<feature>-<platform>.md` since v9.0.0 while nothing produced it, so a full run either aborted at Phase 2 or the model ignored its own BLOCKING contract; Step 4 is the producer. What the phase doc carries is only what cannot be inferred: the when-table (taskType x Figma reference), the four refs in load order, the two artefacts, and that the doc validator fails closed. Compression came first and took the step from 745 tokens to 497: the history of why the gap existed moved to the CHANGELOG, the per-ref one-line descriptions moved into the refs' own headers, and the autopilot carve-out collapsed to one clause. The 17.4k-token analysis engine itself is NOT in this budget - it moved out of commands/ into multi-agent-refs/analysis/{locked,evidence,synthesis,render}.md, loaded on demand, which also took analysis/SKILL.md from 18081 to 5974 tokens and retired its lint grace entry. 500 was the smallest step that clears it; phase-1-analysis sits at 4338/4600 and is amber on purpose, like phase-3 and phase-4. v15.18.0: total 54900 -> 55250 for analysis mode. Three phase docs gained a mode branch that cannot be inferred: Phase 4 reviews a document instead of a diff (validator, the one question reviewers answer, the open-question walk), and Phase 6 publishes instead of committing. Compression came first and was applied twice to the new prose and once to old: the Phase 4 branch went from 320 tokens to 180 and the Phase 6 branch from 190 to 120 by pointing at multi-agent-refs/analysis/{resolve,render}.md, which now hold the walks themselves, and the front-matter parse contract stopped being spelled out in both pre-flights. The analysis engine keeps leaving this budget rather than entering it: intake joined locked/evidence/synthesis/render/resolve in multi-agent-refs/analysis/, which is what let analysis/SKILL.md drop under the 6000 hard cap after its grace entry was retired. 350 was the smallest step that clears it; phase-4 and phase-6 are amber on purpose, as phase-1 and phase-3 already were. v15.20.0: total 55250 -> 55500 for the TDD bridge. Phase 3 pre-flight read the analysis doc's concept table and even said test method names come from it, while nothing read Section 15 - so the RED step invented tests and the analysis test matrix never reached development. Phase 3 step 5b now loads it into state.dev.testPlan[] and Phase 4 step 1.45 cross-checks every planned row against a real test, which is what turns \"analysis quality is output quality\" from a slogan into a finding. Compression came first on both blocks, 300 tokens down to 175, by dropping the enumerated failure modes to one line each and the rationale to one clause; the reasoning lives in the CHANGELOG. 250 was the smallest step that clears it. v15.21.0: total 55500 -> 55800 for the post-analysis confirmation. Phase 2 gained Step 0.9, the last human checkpoint before Phase 3: derived values are shown for confirmation and only Section 20 rows are asked, through the resolve engine that already exists in refs. It belongs here rather than Phase 4 because Phase 4 runs after development, where an answer arrives too late to change anything. Compression came first and twice, 430 tokens down to 250, by collapsing the derived-vs-asked explanation to one sentence each and moving the walk itself to multi-agent-refs/analysis/resolve.md, which Phase 4 and analysis-resolve already mount. 300 was the smallest step that clears it. v15.22.0: total 55800 -> 55900 for the analyst-toolkit hooks. Phase 1 Step 4 now names the two prefs that decide whether a document is produced at all and how deep it goes (forceFull, mode) - the first of those had shipped declared-but-inert and smoke-prefs-consumed caught it - and Phase 4 triage gained one clause: a finding that blames a third-party library asks evidence-github whether it is already open upstream, which turns it into a deferred item with a citation instead of Phase 3 rework on code that is not ours. Compression came first and three times, taking the new prose from 220 tokens to 110, and the Phase 1d evidence contract itself never entered this budget - it lives in multi-agent-refs/analysis/evidence.md beside the phases it belongs to. 100 was the smallest step that clears it, leaving 34 tokens of headroom. phase-4 stays amber and the debt named at v15.10.0 stands: it is the doc that needs structural compression rather than another bump, and the two candidates are the inline triage JSON shape and the 3.4 telemetry block, both of which restate something already authoritative elsewhere. v16.0.0: total 55900 -> 56350 for the depth picker. `--dev` and the four dev-* commands are gone; depth is Phase 0 Step 7.5, which costs phase-0-init a step it did not have. Compression came first and three times, taking the step from 530 tokens to 300: the question wording, the per-taskType recommendation and the mode tables all live in phases/modes.md (outside this budget), so the phase doc carries only what an agent cannot infer - that the step runs after Step 7 and why, who is exempt, that ASK_CHOICE_DEFAULT must be passed explicitly because ask-choice.sh takes the FIRST option on a non-TTY, and that Short flips the Phase 1/2 tiles late rather than pre-marking them. The phase-4 telemetry block named as compression debt at v15.22.0 was collapsed to an emit() helper (-27) and the four dev-* mode files left the tree entirely, but neither offsets a genuinely new phase step. 450 was the smallest step that clears it, leaving 119 tokens of headroom. phase-4 remains amber and its other named candidate, the inline triage JSON shape, was left alone on purpose: it is the prompt the triage agent is handed, not a restatement for readers. v16.2.0: total 56350 -> 56600 for the spec-freshness and reuse-tag contracts. Phase 3 step 3 had compared `state.run.lastAnalysisDigest` since it was written, against a key nothing ever set and that the state schema did not declare, so the staleness branch was unreachable and every run reported fresh by default. Phase 1 now persists the digest and a `base_commit` anchor, and step 3 gained the repo-drift half the digest cannot see: a reused document keeps a matching digest precisely because its evidence inputs did not change, while the code underneath it moved. The second contract is the Section 14 tag reaching development: Phase 2 carries it onto the todo as `sourceTag` and Phase 3 treats it as an instruction, which is what stops a Reuse row from being re-implemented. Compression came first and took the four additions from 380 tokens to 214, by moving every rationale clause out of the phase docs: why the commit anchor exists rather than a digest recomputation lives in this note and the CHANGELOG, and the schema descriptions carry the field semantics. The baseline had 9 tokens of headroom, so no addition of any size could have fit without a bump. 250 was the smallest step that clears it, leaving 45 tokens. phase-3 and phase-4 remain amber. v16.13.0: total 57600 -> 57700 for the code-graph injection and the fable-rung switch. Phase 1 gained Step 2.6 (query the graph, hand Explore a ranked starting set), Phase 7 gained the post-branch graph refresh, and Phase 0 Step 0 gained one line: a prefs switch that resolves every preferredModel: fable persona to opus for the run, which also collapses the Phase 4 Claude Code panel from three reviewers to two. Compression came first and mostly structurally: of roughly 1,630 tokens of new contract text, 1,310 never entered this budget at all - the whole code-graph contract lives in multi-agent-refs/features/code-graph.md (604) and the fable switch's scope table, per-host effects and cost-accounting consequence live in features/model-fallback.md (+707), leaving the phase docs with the call, the pref that gates it and the one fact an agent cannot infer. Phase 4 was compressed on top of that: its TLDR restated the reviewer matrix 270 lines below it, so 36 tokens came back and the doc nets +6 despite carrying two new clauses. One of those clauses is a correction rather than a feature - the consensus rule still said reviewerCount is 2 on Claude Code, which stopped being true when the third reviewer landed in 16.12.0, and the cross-CLI smoke never caught it because it reads the matrix line instead. 100 was the smallest step that clears it, leaving 54 tokens. phase-3 and phase-4 remain amber. v16.17.0: total 57700 -> 57850 for the platform-parity cross-check. Phase 4 gained Step 1.8: when dev-context carries a counterpart app repo, the review compares the change against the other platform on four axes. Compression came first and structurally, as always - of roughly 1,610 tokens of new contract text, 1,490 never entered this budget at all, because the four axes, the file cap, the graph-query recipe, the read-only prohibitions and the rule that an extractor miss may not be reported as an absence all live in multi-agent-refs/platform-parity.md. The step itself was then cut from ~200 tokens to 120 by deleting everything the ref already owns, leaving the trigger, the pointer and the two facts an agent must not infer: the counterpart repo is read-only, and parity findings are never blocking. The baseline had 13 tokens of headroom, so no addition of any size could have fit without a bump. 150 was the smallest step that clears it, leaving 35 tokens. phase-3 and phase-4 remain amber, and phase-4's structural-compression debt still stands."
41
41
  }
@@ -95,7 +95,7 @@ export const STACK_ONLY = {
95
95
  // substring across stacks.
96
96
  export const STACK_PATTERNS = {
97
97
  "ai-ios-toolkit":
98
- /(swiftui|swift-|ios-|hig-|apple-|storekit|widgetkit|healthkit|homekit|mapkit|musickit|passkit|pencilkit|realitykit|weatherkit|alarmkit|callkit|cloudkit|coreml|core-|eventkit|energykit|permissionkit|tipkit|shareplay|live-activities|background-processing|app-store|app-clips|app-intents|authentication|contacts-framework|device-integrity|macos-|natural-language|photos-camera|push-notifications|speech-recognition|swiftdata|vision-framework|debugging-instruments|help-skills)/i,
98
+ /(swiftui|swift-|ios-|hig-|apple-|storekit|widgetkit|healthkit|homekit|mapkit|musickit|passkit|pencilkit|realitykit|weatherkit|alarmkit|callkit|cloudkit|coreml|core-|eventkit|energykit|permissionkit|tipkit|shareplay|live-activities|background-processing|app-store|app-clips|app-intents|authentication|contacts-framework|device-integrity|macos-|natural-language|photos-camera|push-notifications|speech-recognition|swiftdata|vision-framework|debugging-instruments)/i,
99
99
  "ai-android-toolkit": /(android|compose-|kotlin-|room-database|retrofit-|gradle-|play-store)/i,
100
100
  "ai-backend-toolkit":
101
101
  /(fastapi|nodejs|docker|api-pattern|api-security|github-actions|observability|^architecture$|monorepo|clean-code|debugging-strategies|agentflow|closed-loop|context-compression|python-patterns|database-patterns|rest-api-design|testing-backend|ci-cd-pipelines)/i,
@@ -51,13 +51,68 @@ FORCE = re.compile(
51
51
  )
52
52
 
53
53
 
54
+ # A refspec whose destination starts with `+` is a force-push without any flag:
55
+ # `git push origin +main`, `git push origin HEAD:+main`.
56
+ FORCED_REFSPEC = re.compile(r"(^|\s|:)\+\S")
57
+
58
+ # git's own options, which sit between `git` and the subcommand:
59
+ # `git -C /tmp/wt commit`, `git -c user.name=x commit`, `git --no-pager push`.
60
+ GIT_VALUE_OPTIONS = {"-C", "-c", "--git-dir", "--work-tree", "--exec-path", "--namespace"}
61
+ GIT_FLAG_OPTIONS = {
62
+ "--no-pager",
63
+ "--paginate",
64
+ "-p",
65
+ "-P",
66
+ "--bare",
67
+ "--literal-pathspecs",
68
+ "--glob-pathspecs",
69
+ "--noglob-pathspecs",
70
+ "--icase-pathspecs",
71
+ "--no-replace-objects",
72
+ "--no-optional-locks",
73
+ }
74
+
75
+
54
76
  # Shell separators that end one command and start the next. Used to attribute a
55
77
  # flag to the command it actually belongs to.
56
78
  SEPARATORS = re.compile(r"&&|\|\||;|\||\n")
57
79
 
58
80
 
59
- def push_segments(cmd: str) -> list:
60
- """The sub-commands that invoke `git push`.
81
+ def tokenize(cmd: str) -> list:
82
+ """shlex tokens, or whitespace tokens when shlex cannot parse (an unbalanced
83
+ quote). Never returns None: a guard has to reason about a segment it cannot
84
+ parse cleanly, not skip it."""
85
+ try:
86
+ return shlex.split(cmd)
87
+ except Exception:
88
+ return cmd.split()
89
+
90
+
91
+ def git_subcommand(toks: list) -> str:
92
+ """The git subcommand in a token list, skipping git's global options.
93
+
94
+ `git -C <dir> commit` and `git -c k=v push` are the same commands as
95
+ `git commit` and `git push`; matching `git\s+commit` saw neither.
96
+ Returns "" when the tokens do not invoke git.
97
+ """
98
+ for i, t in enumerate(toks):
99
+ if os.path.basename(t).lower() != "git":
100
+ continue
101
+ j = i + 1
102
+ while j < len(toks):
103
+ opt = toks[j]
104
+ if opt in GIT_VALUE_OPTIONS:
105
+ j += 2
106
+ elif opt.startswith("-"):
107
+ j += 1
108
+ else:
109
+ return opt.lower()
110
+ return ""
111
+ return ""
112
+
113
+
114
+ def segments(cmd: str) -> list:
115
+ """The sub-commands of a shell line, paired with their tokens.
61
116
 
62
117
  A flag must be attributed to its own command. Scanning the whole string made
63
118
  `git commit -f ... && git push origin main` read as a force-push, because the
@@ -68,44 +123,70 @@ def push_segments(cmd: str) -> list:
68
123
  only ever produce MORE segments to inspect, never fewer - the safe direction
69
124
  for a guard.
70
125
  """
71
- return [seg for seg in SEPARATORS.split(cmd) if re.search(r"git\s+push", seg.lower())]
126
+ return [(seg, tokenize(seg)) for seg in SEPARATORS.split(cmd)]
72
127
 
73
128
 
74
129
  def decide(cmd: str) -> str:
75
130
  low = cmd.lower()
131
+ segs = segments(cmd)
76
132
 
77
133
  # Rule 1: AI attribution inside a git commit.
78
- if re.search(r"git\s+commit", low) and ATTRIBUTION.search(cmd):
134
+ commits = re.search(r"git\s+commit", low) or any(
135
+ git_subcommand(toks) == "commit" for _, toks in segs
136
+ )
137
+ if commits and ATTRIBUTION.search(cmd):
79
138
  return "BLOCK_ATTRIB"
80
139
 
81
140
  # Rule 2: force-push to a protected branch. Evaluate each push segment on its
82
141
  # own so a neighbouring command's flags cannot implicate it.
83
- for segment in push_segments(cmd):
84
- verdict = _decide_push(segment)
142
+ for seg, toks in segs:
143
+ if git_subcommand(toks) != "push" and not re.search(r"git\s+push", seg.lower()):
144
+ continue
145
+ verdict = _decide_push(seg)
85
146
  if verdict != "OK":
86
147
  return verdict
87
148
 
88
149
  return "OK"
89
150
 
90
151
 
152
+ def _ref_target(arg: str) -> tuple:
153
+ """(forced, branch) for one push argument.
154
+
155
+ The destination is the part after the last `:`; a leading `+` on it is a
156
+ force-push; `refs/heads/main` names the same branch as `main`.
157
+ """
158
+ dst = arg.rsplit(":", 1)[-1]
159
+ forced = dst.startswith("+") or arg.startswith("+")
160
+ name = dst.lstrip("+")
161
+ if name.startswith("refs/heads/"):
162
+ name = name[len("refs/heads/"):]
163
+ return forced, name
164
+
165
+
91
166
  def _decide_push(cmd: str) -> str:
92
167
  """Verdict for a single `git push ...` command."""
93
- if FORCE.search(cmd):
94
- try:
95
- toks = shlex.split(cmd)
96
- except Exception:
97
- # A force-push we can't tokenize -> can't prove it's safe -> block.
98
- return "BLOCK_FORCE"
99
- if any(t in PROTECTED or t.split(":")[-1] in PROTECTED for t in toks):
168
+ force_flag = bool(FORCE.search(cmd))
169
+ if not force_flag and not FORCED_REFSPEC.search(cmd):
170
+ return "OK"
171
+ try:
172
+ toks = shlex.split(cmd)
173
+ except Exception:
174
+ # A force-push we can't tokenize -> can't prove it's safe -> block.
175
+ return "BLOCK_FORCE"
176
+ # non-flag args after `push`; only a remote (or nothing) means a bare push
177
+ args, seen = [], False
178
+ for t in toks:
179
+ if t == "push":
180
+ seen = True
181
+ continue
182
+ if seen and not t.startswith("-"):
183
+ args.append(t)
184
+ targets = [_ref_target(a) for a in args]
185
+ if any(forced and name in PROTECTED for forced, name in targets):
186
+ return "BLOCK_FORCE"
187
+ if force_flag:
188
+ if any(name in PROTECTED for _, name in targets):
100
189
  return "BLOCK_FORCE"
101
- # non-flag args after `push`; only a remote (or nothing) means a bare push
102
- args, seen = [], False
103
- for t in toks:
104
- if t == "push":
105
- seen = True
106
- continue
107
- if seen and not t.startswith("-"):
108
- args.append(t)
109
190
  nonremote = [a for a in args if a not in REMOTES]
110
191
  if not nonremote:
111
192
  # Bare force-push: the target is the current branch. Block if it's
@@ -12,11 +12,11 @@
12
12
  // Pattern source: karpathy/llm-council backend/council.py stage 2, which labels
13
13
  // peer answers "Response A/B/C" and keeps label_to_model out of the prompt.
14
14
  //
15
- // A residual worth naming: with only two reviewers on Claude Code the label set
16
- // is {Source A, Source B} and the triage model is one of them, so it retains a
17
- // 50% prior on which findings are its own. Anonymization removes the signal, not
18
- // the guess - llm-council's four-model council has a stronger version of the
19
- // same property. The value here is that nothing TELLS the judge.
15
+ // A residual worth naming: on both hosts the triage model is one of the three
16
+ // reviewers, so with the label set {Source A, Source B, Source C} it retains a
17
+ // one-in-three prior on which findings are its own. Anonymization removes the
18
+ // signal, not the guess - llm-council's four-model council has the same property
19
+ // at one in four. The value here is that nothing TELLS the judge.
20
20
  //
21
21
  // What this does NOT do: scrub identity out of free text. A reviewer that writes
22
22
  // "as Sonnet would" in `issue`, or whose prose style is recognisable, is not
@@ -36,6 +36,7 @@
36
36
  // Exit codes: 0 ok, 64 usage, 65 input is not JSON.
37
37
 
38
38
  import { readFileSync, writeFileSync } from "node:fs";
39
+ import { pathToFileURL } from "node:url";
39
40
 
40
41
  const IDENTITY_KEYS = [
41
42
  "reviewer",
@@ -136,7 +137,7 @@ export function anonymize(input, { seed } = {}) {
136
137
  return { findings: tagged, map: { seed: seedText, labelToModel, malformed } };
137
138
  }
138
139
 
139
- const isMain = process.argv[1] && import.meta.url === `file://${process.argv[1]}`;
140
+ const isMain = process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href;
140
141
  if (isMain) {
141
142
  const args = process.argv.slice(2);
142
143
  const flag = (name) => {