@mmerterden/multi-agent-pipeline 12.5.0 → 12.7.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 (290) hide show
  1. package/CHANGELOG.md +213 -0
  2. package/README.md +19 -19
  3. package/docs/FIGMA_PIPELINE.md +34 -34
  4. package/docs/adr/0001-three-model-triage.md +12 -12
  5. package/docs/adr/0002-instruction-driven-flag.md +5 -5
  6. package/docs/adr/0003-unified-shared-skills.md +5 -5
  7. package/docs/adr/0004-zero-dependency-philosophy.md +5 -5
  8. package/docs/adr/0005-lazy-phase-docs.md +2 -2
  9. package/docs/adr/0006-skills-core-external-split.md +6 -6
  10. package/docs/adr/0007-multi-tool-adapter-framework.md +19 -19
  11. package/docs/adr/0008-installer-modularization-and-secret-leak-defense.md +19 -19
  12. package/docs/adr/README.md +1 -1
  13. package/docs/best-practices.md +3 -3
  14. package/docs/features.md +48 -28
  15. package/docs/performance.md +16 -16
  16. package/docs/recovery-guide.md +39 -39
  17. package/index.js +11 -5
  18. package/install/_common.mjs +5 -11
  19. package/install/_copilot-instructions.mjs +2 -2
  20. package/install/_dev-only-files.mjs +2 -1
  21. package/install/_platform-filter.mjs +1 -1
  22. package/install/_telemetry.mjs +1 -1
  23. package/install/claude.mjs +10 -9
  24. package/install/copilot.mjs +10 -19
  25. package/install/index.mjs +7 -15
  26. package/install/templates/copilot-instructions.md +54 -54
  27. package/install.js +1 -1
  28. package/package.json +15 -11
  29. package/pipeline/agents/security-auditor.md +1 -1
  30. package/pipeline/commands/archive-guard.md +5 -5
  31. package/pipeline/commands/multi-agent/SKILL.md +3 -1
  32. package/pipeline/commands/multi-agent/analysis/SKILL.md +1 -1
  33. package/pipeline/commands/multi-agent/analysis-resolve/SKILL.md +1 -1
  34. package/pipeline/commands/multi-agent/autopilot/SKILL.md +1 -1
  35. package/pipeline/commands/multi-agent/build-optimize/SKILL.md +1 -1
  36. package/pipeline/commands/multi-agent/create-jira/SKILL.md +1 -1
  37. package/pipeline/commands/multi-agent/design-check/SKILL.md +287 -0
  38. package/pipeline/commands/multi-agent/dev/SKILL.md +1 -1
  39. package/pipeline/commands/multi-agent/dev-autopilot/SKILL.md +1 -1
  40. package/pipeline/commands/multi-agent/dev-local/SKILL.md +1 -1
  41. package/pipeline/commands/multi-agent/dev-local-autopilot/SKILL.md +1 -1
  42. package/pipeline/commands/multi-agent/diff-explain/SKILL.md +1 -1
  43. package/pipeline/commands/multi-agent/finish/SKILL.md +6 -6
  44. package/pipeline/commands/multi-agent/forget/SKILL.md +1 -1
  45. package/pipeline/commands/multi-agent/garbage-collect/SKILL.md +1 -1
  46. package/pipeline/commands/multi-agent/help/SKILL.md +46 -6
  47. package/pipeline/commands/multi-agent/issue/SKILL.md +1 -1
  48. package/pipeline/commands/multi-agent/jira/SKILL.md +1 -1
  49. package/pipeline/commands/multi-agent/kill/SKILL.md +1 -1
  50. package/pipeline/commands/multi-agent/language/SKILL.md +1 -1
  51. package/pipeline/commands/multi-agent/local/SKILL.md +1 -1
  52. package/pipeline/commands/multi-agent/local-autopilot/SKILL.md +1 -1
  53. package/pipeline/commands/multi-agent/log/SKILL.md +1 -1
  54. package/pipeline/commands/multi-agent/manual-test/SKILL.md +1 -1
  55. package/pipeline/commands/multi-agent/prune-logs/SKILL.md +1 -1
  56. package/pipeline/commands/multi-agent/purge/SKILL.md +1 -1
  57. package/pipeline/commands/multi-agent/refactor/SKILL.md +107 -19
  58. package/pipeline/commands/multi-agent/resume/SKILL.md +2 -2
  59. package/pipeline/commands/multi-agent/review/SKILL.md +2 -2
  60. package/pipeline/commands/multi-agent/review-issue/SKILL.md +1 -1
  61. package/pipeline/commands/multi-agent/review-jira/SKILL.md +1 -1
  62. package/pipeline/commands/multi-agent/routines/SKILL.md +1 -1
  63. package/pipeline/commands/multi-agent/save/SKILL.md +1 -1
  64. package/pipeline/commands/multi-agent/scan/SKILL.md +1 -1
  65. package/pipeline/commands/multi-agent/search/SKILL.md +1 -1
  66. package/pipeline/commands/multi-agent/setup/SKILL.md +2 -2
  67. package/pipeline/commands/multi-agent/stack/SKILL.md +3 -3
  68. package/pipeline/commands/multi-agent/status/SKILL.md +1 -1
  69. package/pipeline/commands/multi-agent/sync/SKILL.md +123 -16
  70. package/pipeline/commands/multi-agent/test/SKILL.md +2 -2
  71. package/pipeline/commands/multi-agent/uninstall/SKILL.md +1 -1
  72. package/pipeline/commands/multi-agent/update/SKILL.md +3 -3
  73. package/pipeline/commands/sim-test.md +5 -5
  74. package/pipeline/eval/run-metrics-fixture.json +60 -13
  75. package/pipeline/lib/account-resolver.sh +1 -1
  76. package/pipeline/lib/channels-multi-repo.sh +1 -1
  77. package/pipeline/lib/context-link-extractor.sh +1 -1
  78. package/pipeline/lib/credential-store.sh +33 -1
  79. package/pipeline/lib/fetch-confluence.sh +1 -1
  80. package/pipeline/lib/fetch-crashlytics.sh +1 -1
  81. package/pipeline/lib/fetch-fortify.sh +1 -1
  82. package/pipeline/lib/fetch-graylog.sh +1 -1
  83. package/pipeline/lib/fetch-swagger.sh +1 -1
  84. package/pipeline/lib/issue-fetcher.sh +1 -1
  85. package/pipeline/lib/multi-repo-pipeline.sh +1 -1
  86. package/pipeline/lib/repo-cache.sh +1 -1
  87. package/pipeline/lib/submodule-detector.sh +1 -1
  88. package/pipeline/multi-agent-refs/component-dispatch.md +1 -1
  89. package/pipeline/multi-agent-refs/component-generation.md +121 -0
  90. package/pipeline/multi-agent-refs/cross-cli-contract.md +4 -4
  91. package/pipeline/multi-agent-refs/features/model-fallback.md +2 -2
  92. package/pipeline/multi-agent-refs/phases/phase-3-dev.md +2 -2
  93. package/pipeline/multi-agent-refs/phases/phase-4-review.md +1 -1
  94. package/pipeline/multi-agent-refs/phases/phase-5-test.md +4 -4
  95. package/pipeline/preferences-template.json +23 -12
  96. package/pipeline/schemas/agent-state.schema.json +125 -5
  97. package/pipeline/schemas/analysis-output.schema.json +18 -4
  98. package/pipeline/schemas/analysis-spec.schema.json +120 -32
  99. package/pipeline/schemas/clarify-output.schema.json +15 -5
  100. package/pipeline/schemas/design-check-config.schema.json +183 -0
  101. package/pipeline/schemas/dev-critic-output.schema.json +20 -5
  102. package/pipeline/schemas/figma-project-config.schema.json +42 -10
  103. package/pipeline/schemas/learnings-ledger.schema.json +10 -2
  104. package/pipeline/schemas/migrations/figma-config-1.0.0-to-2.0.0.mjs +1 -4
  105. package/pipeline/schemas/migrations/prefs-2.0.0-to-2.1.0.mjs +24 -7
  106. package/pipeline/schemas/migrations/state-2.0.0-to-2.1.0.mjs +30 -12
  107. package/pipeline/schemas/plan-todos.schema.json +6 -3
  108. package/pipeline/schemas/planning-output.schema.json +5 -1
  109. package/pipeline/schemas/prefs.schema.json +215 -197
  110. package/pipeline/schemas/test-gap.schema.json +5 -5
  111. package/pipeline/schemas/token-budget.json +8 -8
  112. package/pipeline/schemas/triage-corpus.schema.json +1 -1
  113. package/pipeline/scripts/README.md +7 -5
  114. package/pipeline/scripts/aggregate-metrics.mjs +18 -6
  115. package/pipeline/scripts/build-skills-index.mjs +6 -2
  116. package/pipeline/scripts/build-stack-plugins.mjs +142 -39
  117. package/pipeline/scripts/check-derived-drift.mjs +196 -0
  118. package/pipeline/scripts/check-md-links.mjs +6 -2
  119. package/pipeline/scripts/classify-plan-safety.mjs +26 -8
  120. package/pipeline/scripts/cost-budget-check.mjs +11 -6
  121. package/pipeline/scripts/cost-table.json +1 -1
  122. package/pipeline/scripts/diff-explain.mjs +7 -3
  123. package/pipeline/scripts/diff-risk-score.mjs +13 -3
  124. package/pipeline/scripts/eval-golden-tasks-live.mjs +8 -3
  125. package/pipeline/scripts/eval-golden-tasks.mjs +21 -9
  126. package/pipeline/scripts/eval-intent.mjs +8 -4
  127. package/pipeline/scripts/eval-mine-corpus.mjs +14 -4
  128. package/pipeline/scripts/evidence-gate.mjs +7 -2
  129. package/pipeline/scripts/fixtures/install-layout.tsv +7 -7
  130. package/pipeline/scripts/gen-mode-dispatch.mjs +38 -21
  131. package/pipeline/scripts/gen-skills-index.mjs +18 -3
  132. package/pipeline/scripts/learning-curve.mjs +13 -3
  133. package/pipeline/scripts/learnings-ledger.mjs +119 -34
  134. package/pipeline/scripts/lint-mcp-refs.mjs +218 -0
  135. package/pipeline/scripts/lint-skills.mjs +20 -9
  136. package/pipeline/scripts/localize-commands.mjs +6 -1
  137. package/pipeline/scripts/match-skills.mjs +15 -4
  138. package/pipeline/scripts/memory-load.sh +5 -1
  139. package/pipeline/scripts/migrate-prefs.mjs +33 -16
  140. package/pipeline/scripts/phase-tracker.sh +3 -1
  141. package/pipeline/scripts/render-work-summary.sh +4 -1
  142. package/pipeline/scripts/repo-map.mjs +110 -64
  143. package/pipeline/scripts/review-scope.mjs +7 -1
  144. package/pipeline/scripts/routine-registry.mjs +4 -9
  145. package/pipeline/scripts/run-aggregator.mjs +11 -5
  146. package/pipeline/scripts/run-metrics.mjs +13 -8
  147. package/pipeline/scripts/run-smokes.mjs +57 -3
  148. package/pipeline/scripts/scorecard.mjs +258 -0
  149. package/pipeline/scripts/smoke-command-inventory.sh +81 -0
  150. package/pipeline/scripts/smoke-commands-skills-parity.sh +1 -1
  151. package/pipeline/scripts/smoke-compliance-skills.sh +4 -4
  152. package/pipeline/scripts/smoke-context-budget.sh +72 -0
  153. package/pipeline/scripts/smoke-cross-cli-behavior.sh +12 -2
  154. package/pipeline/scripts/smoke-generate-issue.sh +6 -5
  155. package/pipeline/scripts/smoke-model-fallback.sh +1 -1
  156. package/pipeline/scripts/smoke-no-mcp-in-dev-phases.sh +86 -7
  157. package/pipeline/scripts/smoke-own-punctuation.sh +103 -0
  158. package/pipeline/scripts/smoke-per-repo-memory.sh +2 -2
  159. package/pipeline/scripts/smoke-review-readiness.sh +3 -2
  160. package/pipeline/scripts/smoke-schema-validation.sh +19 -5
  161. package/pipeline/scripts/smoke-shadow-git.sh +4 -2
  162. package/pipeline/scripts/smoke-workflow-audit.sh +43 -11
  163. package/pipeline/scripts/smoke-write-state.sh +49 -5
  164. package/pipeline/scripts/test-gap-rules/android.json +11 -11
  165. package/pipeline/scripts/test-gap-rules/ios.json +16 -11
  166. package/pipeline/scripts/test-gap-rules/node.json +19 -7
  167. package/pipeline/scripts/test-gap-rules/python.json +10 -4
  168. package/pipeline/scripts/test-gap-scan.mjs +44 -12
  169. package/pipeline/scripts/test-integrity-gate.mjs +5 -1
  170. package/pipeline/scripts/token-budget-report.mjs +44 -21
  171. package/pipeline/scripts/triage-memory.mjs +142 -32
  172. package/pipeline/scripts/uninstall.mjs +75 -31
  173. package/pipeline/scripts/validate-analysis-doc.mjs +15 -5
  174. package/pipeline/scripts/validate-diff-risk.mjs +32 -18
  175. package/pipeline/scripts/validate-test-gap.mjs +17 -7
  176. package/pipeline/scripts/validate-triage.mjs +17 -5
  177. package/pipeline/scripts/write-state.mjs +32 -9
  178. package/pipeline/skills/.skill-manifest.json +24 -8
  179. package/pipeline/skills/.skills-index.json +125 -89
  180. package/pipeline/skills/shared/README.md +65 -61
  181. package/pipeline/skills/shared/core/apple-archive-compliance/SKILL.md +10 -8
  182. package/pipeline/skills/shared/core/google-play-compliance/SKILL.md +1 -1
  183. package/pipeline/skills/shared/core/multi-agent/SKILL.md +26 -279
  184. package/pipeline/skills/shared/core/multi-agent-analysis/SKILL.md +1 -1
  185. package/pipeline/skills/shared/core/multi-agent-analysis-resolve/SKILL.md +1 -1
  186. package/pipeline/skills/shared/core/multi-agent-autopilot/SKILL.md +1 -1
  187. package/pipeline/skills/shared/core/multi-agent-build-optimize/SKILL.md +1 -1
  188. package/pipeline/skills/shared/core/multi-agent-create-jira/SKILL.md +1 -1
  189. package/pipeline/skills/shared/core/multi-agent-design-check/SKILL.md +248 -0
  190. package/pipeline/skills/shared/core/multi-agent-dev/SKILL.md +1 -1
  191. package/pipeline/skills/shared/core/multi-agent-dev-autopilot/SKILL.md +1 -1
  192. package/pipeline/skills/shared/core/multi-agent-dev-local/SKILL.md +1 -1
  193. package/pipeline/skills/shared/core/multi-agent-dev-local-autopilot/SKILL.md +1 -1
  194. package/pipeline/skills/shared/core/multi-agent-diff-explain/SKILL.md +1 -1
  195. package/pipeline/skills/shared/core/multi-agent-finish/SKILL.md +1 -1
  196. package/pipeline/skills/shared/core/multi-agent-forget/SKILL.md +1 -1
  197. package/pipeline/skills/shared/core/multi-agent-garbage-collect/SKILL.md +1 -1
  198. package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +23 -1
  199. package/pipeline/skills/shared/core/multi-agent-issue/SKILL.md +1 -1
  200. package/pipeline/skills/shared/core/multi-agent-jira/SKILL.md +1 -1
  201. package/pipeline/skills/shared/core/multi-agent-kill/SKILL.md +1 -1
  202. package/pipeline/skills/shared/core/multi-agent-language/SKILL.md +1 -1
  203. package/pipeline/skills/shared/core/multi-agent-local/SKILL.md +1 -1
  204. package/pipeline/skills/shared/core/multi-agent-local-autopilot/SKILL.md +1 -1
  205. package/pipeline/skills/shared/core/multi-agent-log/SKILL.md +1 -1
  206. package/pipeline/skills/shared/core/multi-agent-manual-test/SKILL.md +1 -1
  207. package/pipeline/skills/shared/core/multi-agent-prune-logs/SKILL.md +1 -1
  208. package/pipeline/skills/shared/core/multi-agent-purge/SKILL.md +1 -1
  209. package/pipeline/skills/shared/core/multi-agent-refactor/SKILL.md +82 -18
  210. package/pipeline/skills/shared/core/multi-agent-resume/SKILL.md +1 -1
  211. package/pipeline/skills/shared/core/multi-agent-review/SKILL.md +2 -2
  212. package/pipeline/skills/shared/core/multi-agent-review-issue/SKILL.md +1 -1
  213. package/pipeline/skills/shared/core/multi-agent-review-jira/SKILL.md +1 -1
  214. package/pipeline/skills/shared/core/multi-agent-routines/SKILL.md +1 -1
  215. package/pipeline/skills/shared/core/multi-agent-save/SKILL.md +1 -1
  216. package/pipeline/skills/shared/core/multi-agent-scan/SKILL.md +1 -1
  217. package/pipeline/skills/shared/core/multi-agent-search/SKILL.md +1 -1
  218. package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +1 -1
  219. package/pipeline/skills/shared/core/multi-agent-stack/SKILL.md +3 -3
  220. package/pipeline/skills/shared/core/multi-agent-status/SKILL.md +1 -1
  221. package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +51 -9
  222. package/pipeline/skills/shared/core/multi-agent-test/SKILL.md +2 -2
  223. package/pipeline/skills/shared/core/multi-agent-uninstall/SKILL.md +1 -1
  224. package/pipeline/skills/shared/core/multi-agent-update/SKILL.md +1 -1
  225. package/pipeline/skills/shared/external/accessibility-compliance-accessibility-audit/SKILL.md +1 -1
  226. package/pipeline/skills/shared/external/agent-introspection-debugging/SKILL.md +4 -4
  227. package/pipeline/skills/shared/external/agentflow/SKILL.md +1 -1
  228. package/pipeline/skills/shared/external/android-jetpack-compose-expert/SKILL.md +1 -1
  229. package/pipeline/skills/shared/external/android_ui_verification/SKILL.md +1 -1
  230. package/pipeline/skills/shared/external/api-patterns/SKILL.md +1 -1
  231. package/pipeline/skills/shared/external/api-security-best-practices/SKILL.md +1 -1
  232. package/pipeline/skills/shared/external/app-store-changelog/SKILL.md +1 -1
  233. package/pipeline/skills/shared/external/backlog/BACKLOG.md +1 -1
  234. package/pipeline/skills/shared/external/backlog/SKILL.md +12 -12
  235. package/pipeline/skills/shared/external/ci-cd-pipelines/SKILL.md +1 -1
  236. package/pipeline/skills/shared/external/context-compression/SKILL.md +1 -1
  237. package/pipeline/skills/shared/external/council/SKILL.md +3 -3
  238. package/pipeline/skills/shared/external/css-modern/SKILL.md +1 -1
  239. package/pipeline/skills/shared/external/database-patterns/SKILL.md +1 -1
  240. package/pipeline/skills/shared/external/debugging-strategies/SKILL.md +1 -1
  241. package/pipeline/skills/shared/external/docker-expert/SKILL.md +1 -1
  242. package/pipeline/skills/shared/external/fastapi-pro/SKILL.md +1 -1
  243. package/pipeline/skills/shared/external/firebase/SKILL.md +1 -1
  244. package/pipeline/skills/shared/external/github-actions-templates/SKILL.md +1 -1
  245. package/pipeline/skills/shared/external/help-skills/SKILL.md +1 -1
  246. package/pipeline/skills/shared/external/hig-components-content/SKILL.md +1 -1
  247. package/pipeline/skills/shared/external/hig-components-layout/SKILL.md +1 -1
  248. package/pipeline/skills/shared/external/hig-components-status/SKILL.md +1 -1
  249. package/pipeline/skills/shared/external/hig-components-system/SKILL.md +1 -1
  250. package/pipeline/skills/shared/external/hig-foundations/SKILL.md +1 -1
  251. package/pipeline/skills/shared/external/hig-inputs/SKILL.md +1 -1
  252. package/pipeline/skills/shared/external/hig-patterns/SKILL.md +1 -1
  253. package/pipeline/skills/shared/external/hig-platforms/SKILL.md +1 -1
  254. package/pipeline/skills/shared/external/hig-technologies/SKILL.md +1 -1
  255. package/pipeline/skills/shared/external/html-semantic/SKILL.md +1 -1
  256. package/pipeline/skills/shared/external/humanizer/SKILL.md +1 -1
  257. package/pipeline/skills/shared/external/ios-debugger-agent/SKILL.md +1 -1
  258. package/pipeline/skills/shared/external/ios-developer/SKILL.md +1 -1
  259. package/pipeline/skills/shared/external/kotlin-coroutines-expert/SKILL.md +1 -1
  260. package/pipeline/skills/shared/external/macos-menubar-tuist-app/SKILL.md +1 -1
  261. package/pipeline/skills/shared/external/macos-spm-app-packaging/SKILL.md +1 -1
  262. package/pipeline/skills/shared/external/monorepo-architect/SKILL.md +1 -1
  263. package/pipeline/skills/shared/external/nextjs-app-router/SKILL.md +1 -1
  264. package/pipeline/skills/shared/external/nodejs-backend-patterns/SKILL.md +1 -1
  265. package/pipeline/skills/shared/external/observability-engineer/SKILL.md +1 -1
  266. package/pipeline/skills/shared/external/python-patterns/SKILL.md +1 -1
  267. package/pipeline/skills/shared/external/react-best-practices/SKILL.md +1 -1
  268. package/pipeline/skills/shared/external/rest-api-design/SKILL.md +1 -1
  269. package/pipeline/skills/shared/external/search-first/SKILL.md +2 -2
  270. package/pipeline/skills/shared/external/skill-creator/SKILL.md +12 -12
  271. package/pipeline/skills/shared/external/skill-creator/audit.md +21 -21
  272. package/pipeline/skills/shared/external/skill-creator/checklist.md +3 -3
  273. package/pipeline/skills/shared/external/skill-creator/examples.md +10 -10
  274. package/pipeline/skills/shared/external/skill-creator/label-check.md +17 -17
  275. package/pipeline/skills/shared/external/skill-creator/scripts/audit-panel.js +86 -50
  276. package/pipeline/skills/shared/external/skill-creator/template.md +9 -9
  277. package/pipeline/skills/shared/external/swift-concurrency-expert/SKILL.md +1 -1
  278. package/pipeline/skills/shared/external/swiftui-performance-audit/SKILL.md +1 -1
  279. package/pipeline/skills/shared/external/swiftui-ui-patterns/SKILL.md +1 -1
  280. package/pipeline/skills/shared/external/swiftui-view-refactor/SKILL.md +1 -1
  281. package/pipeline/skills/shared/external/tailwind-css/SKILL.md +1 -1
  282. package/pipeline/skills/shared/external/testing-backend/SKILL.md +1 -1
  283. package/pipeline/skills/shared/external/typescript-patterns/SKILL.md +1 -1
  284. package/pipeline/skills/shared/external/vue-composition/SKILL.md +1 -1
  285. package/pipeline/skills/shared/external/web-accessibility/SKILL.md +1 -1
  286. package/pipeline/skills/shared/external/web-performance/SKILL.md +1 -1
  287. package/pipeline/skills/shared/external/web-testing/SKILL.md +1 -1
  288. package/pipeline/skills/shared/external/xcode-build-benchmark/schemas/build-benchmark.schema.json +9 -49
  289. package/pipeline/skills/skills-index.md +63 -59
  290. package/pipeline/scripts/smoke-plugin-validate.sh +0 -64
@@ -90,11 +90,20 @@ function git(args) {
90
90
 
91
91
  function resolveBase() {
92
92
  if (BASE) return BASE;
93
- for (const ref of ["origin/main", "main", "origin/master", "master", "develop", "origin/develop"]) {
93
+ for (const ref of [
94
+ "origin/main",
95
+ "main",
96
+ "origin/master",
97
+ "master",
98
+ "develop",
99
+ "origin/develop",
100
+ ]) {
94
101
  try {
95
102
  execFileSync("git", ["-C", ROOT, "rev-parse", "--verify", ref], { stdio: "ignore" });
96
103
  return ref;
97
- } catch { /* continue */ }
104
+ } catch {
105
+ /* continue */
106
+ }
98
107
  }
99
108
  throw new Error("no base ref found");
100
109
  }
@@ -133,9 +142,15 @@ function isExcluded(path) {
133
142
  }
134
143
 
135
144
  function isTestPath(path) {
136
- if (Array.isArray(rules.testPathSuffixes) && rules.testPathSuffixes.some((s) => path.endsWith(s))) return true;
137
- if (Array.isArray(rules.testPathPrefixes) && rules.testPathPrefixes.some((p) => basename(path).startsWith(p))) return true;
138
- if (Array.isArray(rules.testPathContains) && rules.testPathContains.some((c) => path.includes(c))) return true;
145
+ if (Array.isArray(rules.testPathSuffixes) && rules.testPathSuffixes.some((s) => path.endsWith(s)))
146
+ return true;
147
+ if (
148
+ Array.isArray(rules.testPathPrefixes) &&
149
+ rules.testPathPrefixes.some((p) => basename(path).startsWith(p))
150
+ )
151
+ return true;
152
+ if (Array.isArray(rules.testPathContains) && rules.testPathContains.some((c) => path.includes(c)))
153
+ return true;
139
154
  return false;
140
155
  }
141
156
 
@@ -227,8 +242,11 @@ function scanTreeForTests() {
227
242
  if (!SCAN_TREE) return hits;
228
243
  const visit = (dir) => {
229
244
  let entries;
230
- try { entries = readdirSync(dir, { withFileTypes: true }); }
231
- catch { return; }
245
+ try {
246
+ entries = readdirSync(dir, { withFileTypes: true });
247
+ } catch {
248
+ return;
249
+ }
232
250
  for (const ent of entries) {
233
251
  const full = join(dir, ent.name);
234
252
  const rel = full.replace(ROOT + "/", "");
@@ -238,7 +256,11 @@ function scanTreeForTests() {
238
256
  visit(full);
239
257
  } else if (ent.isFile() && isTestPath(rel)) {
240
258
  let body;
241
- try { body = readFileSync(full, "utf8"); } catch { continue; }
259
+ try {
260
+ body = readFileSync(full, "utf8");
261
+ } catch {
262
+ continue;
263
+ }
242
264
  // crude symbol mention: any Identifier-ish token. Cap body size.
243
265
  const slice = body.slice(0, 400_000);
244
266
  const tokens = slice.match(/[A-Za-z_][A-Za-z0-9_]{2,}/g) || [];
@@ -258,7 +280,14 @@ function severityFor(symbol, kind) {
258
280
  // Public API additions without tests are important; pure boolean exports
259
281
  // (e.g. const FLAG = true) tend to be suggestion-tier.
260
282
  if (kind === "objc_export" || kind === "interface" || kind === "public_proto") return "important";
261
- if (kind.startsWith("public_") || kind === "open_class" || kind === "open_fun" || kind === "named_export" || kind === "default_export") return "suggestion";
283
+ if (
284
+ kind.startsWith("public_") ||
285
+ kind === "open_class" ||
286
+ kind === "open_fun" ||
287
+ kind === "named_export" ||
288
+ kind === "default_export"
289
+ )
290
+ return "suggestion";
262
291
  if (kind === "view_struct" || kind === "config_struct") return "important";
263
292
  if (kind === "composable_fun") return "important";
264
293
  if (kind === "top_def" || kind === "top_class" || kind === "async_def") return "suggestion";
@@ -272,7 +301,10 @@ function symbolMentionedInTest(diffText, symbol) {
272
301
  let inTestFile = false;
273
302
  for (const line of lines) {
274
303
  const fm = line.match(/^diff --git a\/(.+?) b\/(.+)$/);
275
- if (fm) { inTestFile = isTestPath(fm[2]); continue; }
304
+ if (fm) {
305
+ inTestFile = isTestPath(fm[2]);
306
+ continue;
307
+ }
276
308
  if (!inTestFile) continue;
277
309
  if (!line.startsWith("+")) continue;
278
310
  if (re.test(line)) return true;
@@ -327,8 +359,8 @@ function main() {
327
359
  testsScanned: tests.length,
328
360
  gapCount: gaps.length,
329
361
  gapBySeverity: {
330
- blocking: gaps.filter((g) => g.severity === "blocking").length,
331
- important: gaps.filter((g) => g.severity === "important").length,
362
+ blocking: gaps.filter((g) => g.severity === "blocking").length,
363
+ important: gaps.filter((g) => g.severity === "important").length,
332
364
  suggestion: gaps.filter((g) => g.severity === "suggestion").length,
333
365
  },
334
366
  };
@@ -76,7 +76,11 @@ function main() {
76
76
  }
77
77
 
78
78
  process.stdout.write(
79
- JSON.stringify({ schemaVersion: "1.0.0", count: findings.length, findings }, null, PRETTY ? 2 : 0),
79
+ JSON.stringify(
80
+ { schemaVersion: "1.0.0", count: findings.length, findings },
81
+ null,
82
+ PRETTY ? 2 : 0,
83
+ ),
80
84
  );
81
85
  }
82
86
 
@@ -23,10 +23,10 @@ import os from "node:os";
23
23
  import path from "node:path";
24
24
 
25
25
  const args = parseArgs(process.argv.slice(2));
26
- const METRICS = process.env.METRICS_FILE
27
- || path.join(os.homedir(), ".claude/logs/multi-agent/metrics.jsonl");
28
- const BUDGET = process.env.BUDGET_FILE
29
- || path.join(os.homedir(), ".claude/configs/token-budget.json");
26
+ const METRICS =
27
+ process.env.METRICS_FILE || path.join(os.homedir(), ".claude/logs/multi-agent/metrics.jsonl");
28
+ const BUDGET =
29
+ process.env.BUDGET_FILE || path.join(os.homedir(), ".claude/configs/token-budget.json");
30
30
  const SUMMARY = path.join(os.homedir(), ".claude/logs/multi-agent/metrics-summary.md");
31
31
 
32
32
  const PERIOD_DAYS = { daily: 1, weekly: 7, monthly: 30 };
@@ -41,17 +41,28 @@ if (!fs.existsSync(METRICS)) {
41
41
 
42
42
  const lines = fs.readFileSync(METRICS, "utf8").split("\n").filter(Boolean);
43
43
  const events = lines
44
- .map(l => { try { return JSON.parse(l); } catch { return null; } })
45
- .filter(e => e && e.ts)
46
- .filter(e => Date.parse(e.ts) >= cutoffMs)
47
- .filter(e => !args.task || e.task_id === args.task);
44
+ .map((l) => {
45
+ try {
46
+ return JSON.parse(l);
47
+ } catch {
48
+ return null;
49
+ }
50
+ })
51
+ .filter((e) => e && e.ts)
52
+ .filter((e) => Date.parse(e.ts) >= cutoffMs)
53
+ .filter((e) => !args.task || e.task_id === args.task);
48
54
 
49
55
  // Per-task aggregation
50
56
  const byTask = new Map();
51
57
  for (const e of events) {
52
- if (!byTask.has(e.task_id)) byTask.set(e.task_id, {
53
- tokens_in: 0, tokens_out: 0, premium_calls: 0, phases: new Set(), models: new Set()
54
- });
58
+ if (!byTask.has(e.task_id))
59
+ byTask.set(e.task_id, {
60
+ tokens_in: 0,
61
+ tokens_out: 0,
62
+ premium_calls: 0,
63
+ phases: new Set(),
64
+ models: new Set(),
65
+ });
55
66
  const t = byTask.get(e.task_id);
56
67
  t.phases.add(e.phase);
57
68
  const d = e.details || {};
@@ -64,21 +75,26 @@ for (const e of events) {
64
75
  // Budget (best-effort)
65
76
  let budget = {};
66
77
  if (fs.existsSync(BUDGET)) {
67
- try { budget = JSON.parse(fs.readFileSync(BUDGET, "utf8")); }
68
- catch { /* tolerate malformed */ }
78
+ try {
79
+ budget = JSON.parse(fs.readFileSync(BUDGET, "utf8"));
80
+ } catch {
81
+ /* tolerate malformed */
82
+ }
69
83
  }
70
84
  const limits = {
71
85
  perTaskTokens: budget.perTaskTokens || 250000,
72
86
  perTaskTokensMultiRepo: budget.perTaskTokensMultiRepo || 500000,
73
- perTaskUsd: budget.perTaskUsd || 2.50,
74
- perTaskUsdMultiRepo: budget.perTaskUsdMultiRepo || 5.00,
87
+ perTaskUsd: budget.perTaskUsd || 2.5,
88
+ perTaskUsdMultiRepo: budget.perTaskUsdMultiRepo || 5.0,
75
89
  };
76
90
  // Crude USD estimate: opus ~$15/M in, $75/M out; sonnet ~$3/M, $15/M out.
77
91
  function estimateUsd(t) {
78
92
  const inK = t.tokens_in / 1e6;
79
93
  const outK = t.tokens_out / 1e6;
80
94
  const opusShare = t.models.has("opus") ? 0.5 : 0; // rough
81
- return (inK * (15 * opusShare + 3 * (1 - opusShare))) + (outK * (75 * opusShare + 15 * (1 - opusShare)));
95
+ return (
96
+ inK * (15 * opusShare + 3 * (1 - opusShare)) + outK * (75 * opusShare + 15 * (1 - opusShare))
97
+ );
82
98
  }
83
99
 
84
100
  const summary = {
@@ -100,14 +116,18 @@ for (const [taskId, t] of byTask) {
100
116
  const isMulti = t.phases.has("4") && t.premium_calls > 5; // heuristic
101
117
  const tokenLimit = isMulti ? limits.perTaskTokensMultiRepo : limits.perTaskTokens;
102
118
  const usdLimit = isMulti ? limits.perTaskUsdMultiRepo : limits.perTaskUsd;
103
- if (total > tokenLimit) summary.breaches.push({ taskId, kind: "tokens", actual: total, limit: tokenLimit });
104
- if (usd > usdLimit) summary.breaches.push({ taskId, kind: "usd", actual: usd.toFixed(2), limit: usdLimit });
119
+ if (total > tokenLimit)
120
+ summary.breaches.push({ taskId, kind: "tokens", actual: total, limit: tokenLimit });
121
+ if (usd > usdLimit)
122
+ summary.breaches.push({ taskId, kind: "usd", actual: usd.toFixed(2), limit: usdLimit });
105
123
  }
106
124
 
107
125
  if (args.json) {
108
126
  console.log(JSON.stringify(summary, null, 2));
109
127
  } else {
110
- console.log(`Token & cost report - ${summary.period} (${summary.windowStart} → ${summary.windowEnd})`);
128
+ console.log(
129
+ `Token & cost report - ${summary.period} (${summary.windowStart} → ${summary.windowEnd})`,
130
+ );
111
131
  console.log(` tasks: ${summary.taskCount}`);
112
132
  console.log(` tokens in: ${summary.totalTokensIn.toLocaleString()}`);
113
133
  console.log(` tokens out: ${summary.totalTokensOut.toLocaleString()}`);
@@ -123,10 +143,13 @@ if (args.json) {
123
143
  }
124
144
 
125
145
  if (args.append) {
126
- const row = `| ${summary.windowEnd.slice(0,10)} | ${summary.period} | ${summary.taskCount} | ${summary.totalTokensIn} | ${summary.totalTokensOut} | $${summary.totalUsd.toFixed(2)} | ${summary.breaches.length} |`;
146
+ const row = `| ${summary.windowEnd.slice(0, 10)} | ${summary.period} | ${summary.taskCount} | ${summary.totalTokensIn} | ${summary.totalTokensOut} | $${summary.totalUsd.toFixed(2)} | ${summary.breaches.length} |`;
127
147
  if (!fs.existsSync(SUMMARY)) {
128
148
  fs.mkdirSync(path.dirname(SUMMARY), { recursive: true });
129
- fs.writeFileSync(SUMMARY, "# Multi-Agent Pipeline Metrics Summary\n\n| date | period | tasks | tokens_in | tokens_out | est_usd | breaches |\n|---|---|---|---|---|---|---|\n");
149
+ fs.writeFileSync(
150
+ SUMMARY,
151
+ "# Multi-Agent Pipeline Metrics Summary\n\n| date | period | tasks | tokens_in | tokens_out | est_usd | breaches |\n|---|---|---|---|---|---|---|\n",
152
+ );
130
153
  }
131
154
  fs.appendFileSync(SUMMARY, row + "\n");
132
155
  }
@@ -53,8 +53,10 @@ for (let i = 1; i < argv.length; i++) {
53
53
  if (a.startsWith("--")) {
54
54
  const k = a.slice(2);
55
55
  const v = argv[i + 1];
56
- if (v !== undefined && !v.startsWith("--")) { flags[k] = v; i++; }
57
- else flags[k] = true;
56
+ if (v !== undefined && !v.startsWith("--")) {
57
+ flags[k] = v;
58
+ i++;
59
+ } else flags[k] = true;
58
60
  }
59
61
  }
60
62
 
@@ -63,21 +65,50 @@ function die(msg, code = 1) {
63
65
  process.exit(code);
64
66
  }
65
67
 
68
+ // Resolves to the MAIN repository name even when called from inside a pipeline
69
+ // worktree. `--show-toplevel` returns the worktree root, whose basename is the
70
+ // task id, which would shard the per-repo store one directory per task and make
71
+ // prior-art recall always miss. `--git-common-dir` points at the main
72
+ // repository's .git for every linked worktree.
66
73
  function repoSlug() {
67
74
  if (flags["repo-slug"]) return String(flags["repo-slug"]);
68
75
  if (process.env.MULTI_AGENT_REPO_SLUG) return process.env.MULTI_AGENT_REPO_SLUG;
76
+ try {
77
+ const commonDir = execFileSync(
78
+ "git",
79
+ ["rev-parse", "--path-format=absolute", "--git-common-dir"],
80
+ { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] },
81
+ ).trim();
82
+ if (commonDir) {
83
+ const base = basename(commonDir);
84
+ const root = base === ".git" ? dirname(commonDir) : commonDir.replace(/\.git$/, "");
85
+ const slug = basename(root);
86
+ if (slug) return slug;
87
+ }
88
+ } catch {
89
+ /* not a git repo, or git too old for --path-format */
90
+ }
69
91
  try {
70
92
  const top = execFileSync("git", ["rev-parse", "--show-toplevel"], {
71
93
  encoding: "utf8",
72
94
  stdio: ["ignore", "pipe", "ignore"],
73
95
  }).trim();
74
96
  if (top) return basename(top);
75
- } catch { /* not a git repo */ }
97
+ } catch {
98
+ /* not a git repo */
99
+ }
76
100
  return "default";
77
101
  }
78
102
 
79
103
  function corpusPath(slug) {
80
- return join(homedir(), ".claude", "memory", "multi-agent", slug || repoSlug(), "triage-corpus.jsonl");
104
+ return join(
105
+ homedir(),
106
+ ".claude",
107
+ "memory",
108
+ "multi-agent",
109
+ slug || repoSlug(),
110
+ "triage-corpus.jsonl",
111
+ );
81
112
  }
82
113
 
83
114
  function ensureDir(p) {
@@ -89,10 +120,12 @@ function ensureDir(p) {
89
120
  // flagged stale so a reused finding is verified, not trusted blindly.
90
121
  function repoTop() {
91
122
  try {
92
- return execFileSync("git", ["rev-parse", "--show-toplevel"], {
93
- encoding: "utf8",
94
- stdio: ["ignore", "pipe", "ignore"],
95
- }).trim() || null;
123
+ return (
124
+ execFileSync("git", ["rev-parse", "--show-toplevel"], {
125
+ encoding: "utf8",
126
+ stdio: ["ignore", "pipe", "ignore"],
127
+ }).trim() || null
128
+ );
96
129
  } catch {
97
130
  return null;
98
131
  }
@@ -101,27 +134,84 @@ function repoTop() {
101
134
  function fileSha(file, top) {
102
135
  if (!file || !top) return null;
103
136
  try {
104
- return execFileSync("git", ["hash-object", "--", file], {
105
- cwd: top,
106
- encoding: "utf8",
107
- stdio: ["ignore", "pipe", "ignore"],
108
- }).trim() || null;
137
+ return (
138
+ execFileSync("git", ["hash-object", "--", file], {
139
+ cwd: top,
140
+ encoding: "utf8",
141
+ stdio: ["ignore", "pipe", "ignore"],
142
+ }).trim() || null
143
+ );
109
144
  } catch {
110
145
  return null;
111
146
  }
112
147
  }
113
148
 
114
149
  const STOP = new Set([
115
- "the","a","an","and","or","but","of","in","on","at","to","for","with","by","is","are",
116
- "be","been","being","this","that","these","those","it","its","as","not","no","do","does",
117
- "did","done","have","has","had","will","would","should","could","may","might","can","cant",
118
- "don","wont","you","your","i","we","they","them","he","she","his","her","our","their"
150
+ "the",
151
+ "a",
152
+ "an",
153
+ "and",
154
+ "or",
155
+ "but",
156
+ "of",
157
+ "in",
158
+ "on",
159
+ "at",
160
+ "to",
161
+ "for",
162
+ "with",
163
+ "by",
164
+ "is",
165
+ "are",
166
+ "be",
167
+ "been",
168
+ "being",
169
+ "this",
170
+ "that",
171
+ "these",
172
+ "those",
173
+ "it",
174
+ "its",
175
+ "as",
176
+ "not",
177
+ "no",
178
+ "do",
179
+ "does",
180
+ "did",
181
+ "done",
182
+ "have",
183
+ "has",
184
+ "had",
185
+ "will",
186
+ "would",
187
+ "should",
188
+ "could",
189
+ "may",
190
+ "might",
191
+ "can",
192
+ "cant",
193
+ "don",
194
+ "wont",
195
+ "you",
196
+ "your",
197
+ "i",
198
+ "we",
199
+ "they",
200
+ "them",
201
+ "he",
202
+ "she",
203
+ "his",
204
+ "her",
205
+ "our",
206
+ "their",
119
207
  ]);
120
208
 
121
209
  function tokenize(text) {
122
210
  if (!text) return new Set();
123
211
  const out = new Set();
124
- for (const m of String(text).toLowerCase().matchAll(/[a-z][a-z0-9_]{2,}/g)) {
212
+ for (const m of String(text)
213
+ .toLowerCase()
214
+ .matchAll(/[a-z][a-z0-9_]{2,}/g)) {
125
215
  if (!STOP.has(m[0])) out.add(m[0]);
126
216
  }
127
217
  return out;
@@ -157,8 +247,11 @@ function readCorpus(slug) {
157
247
  const rows = [];
158
248
  for (const line of raw.split("\n")) {
159
249
  if (!line.trim()) continue;
160
- try { rows.push(JSON.parse(line)); }
161
- catch { /* skip corrupted line */ }
250
+ try {
251
+ rows.push(JSON.parse(line));
252
+ } catch {
253
+ /* skip corrupted line */
254
+ }
162
255
  }
163
256
  return rows;
164
257
  }
@@ -180,18 +273,23 @@ function ingest() {
180
273
  const slug = repoSlug();
181
274
 
182
275
  let triage;
183
- try { triage = JSON.parse(readFileSync(triagePath, "utf8")); }
184
- catch (e) { die(`cannot parse triage JSON: ${e.message}`, 1); }
276
+ try {
277
+ triage = JSON.parse(readFileSync(triagePath, "utf8"));
278
+ } catch (e) {
279
+ die(`cannot parse triage JSON: ${e.message}`, 1);
280
+ }
185
281
 
186
282
  const ts = new Date().toISOString();
187
283
  const top = repoTop();
188
284
  const corpus = readCorpus(slug);
189
- const seen = new Set(corpus.map((r) => `${r.task_id}::${r.classification}::${r.file}::${r.issue}`));
285
+ const seen = new Set(
286
+ corpus.map((r) => `${r.task_id}::${r.classification}::${r.file}::${r.issue}`),
287
+ );
190
288
 
191
289
  const buckets = [
192
- ["accepted", triage.accepted || []],
193
- ["deferred", (triage.deferred || []).map((d) => ({ ...d.finding, _reason: d.reason }))],
194
- ["rejected", (triage.rejected || []).map((d) => ({ ...d.finding, _reason: d.reason }))],
290
+ ["accepted", triage.accepted || []],
291
+ ["deferred", (triage.deferred || []).map((d) => ({ ...d.finding, _reason: d.reason }))],
292
+ ["rejected", (triage.rejected || []).map((d) => ({ ...d.finding, _reason: d.reason }))],
195
293
  ];
196
294
 
197
295
  let written = 0;
@@ -265,12 +363,16 @@ function query() {
265
363
  score: Math.round(score * 1000) / 1000,
266
364
  };
267
365
  });
268
- process.stdout.write(JSON.stringify({ ok: true, slug, total: filtered.length, hits: ranked }) + "\n");
366
+ process.stdout.write(
367
+ JSON.stringify({ ok: true, slug, total: filtered.length, hits: ranked }) + "\n",
368
+ );
269
369
  process.exit(0);
270
370
  }
271
371
 
272
372
  function pathCmd() {
273
- process.stdout.write(corpusPath(flags["repo-slug"] ? String(flags["repo-slug"]) : repoSlug()) + "\n");
373
+ process.stdout.write(
374
+ corpusPath(flags["repo-slug"] ? String(flags["repo-slug"]) : repoSlug()) + "\n",
375
+ );
274
376
  process.exit(0);
275
377
  }
276
378
 
@@ -295,10 +397,18 @@ function statsCmd() {
295
397
  }
296
398
 
297
399
  switch (SUB) {
298
- case "ingest": ingest(); break;
299
- case "query": query(); break;
300
- case "path": pathCmd(); break;
301
- case "stats": statsCmd(); break;
400
+ case "ingest":
401
+ ingest();
402
+ break;
403
+ case "query":
404
+ query();
405
+ break;
406
+ case "path":
407
+ pathCmd();
408
+ break;
409
+ case "stats":
410
+ statsCmd();
411
+ break;
302
412
  default:
303
413
  process.stderr.write("usage: triage-memory.mjs <ingest|query|path|stats> [flags]\n");
304
414
  process.exit(64);