@mmerterden/multi-agent-pipeline 20.2.1 → 20.3.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 (621) hide show
  1. package/CHANGELOG.md +912 -1
  2. package/README.md +104 -81
  3. package/README.tr.md +103 -62
  4. package/docs/FIGMA_PIPELINE.md +35 -35
  5. package/docs/adr/0006-skills-core-external-split.md +1 -1
  6. package/docs/adr/0007-multi-tool-adapter-framework.md +6 -0
  7. package/docs/adr/0008-installer-modularization-and-secret-leak-defense.md +7 -0
  8. package/docs/architecture.md +50 -14
  9. package/docs/best-practices.md +1 -1
  10. package/docs/ecosystem.md +56 -32
  11. package/docs/facts.json +10 -10
  12. package/docs/features.md +97 -5
  13. package/docs/recovery-guide.md +7 -14
  14. package/docs/server-readiness.md +31 -24
  15. package/index.js +1 -1
  16. package/install/_common.mjs +3 -5
  17. package/install/_platform-filter.mjs +23 -1
  18. package/install/_unattended-profile.mjs +321 -75
  19. package/install/claude.mjs +51 -10
  20. package/install/codex.mjs +2 -0
  21. package/install/copilot.mjs +2 -0
  22. package/install/index.mjs +30 -17
  23. package/install/templates/claude-hooks.json +16 -5
  24. package/install/templates/copilot-instructions.md +1 -1
  25. package/install/templates/multi-agent-autopilot-awake.plist.template +48 -0
  26. package/install/templates/multi-agent-autopilot.plist.template +12 -5
  27. package/install/unattended-profile-legacy.json +80 -0
  28. package/manifest.json +616 -483
  29. package/package.json +8 -3
  30. package/pipeline/agents/code-reviewer.md +10 -0
  31. package/pipeline/agents/plan-critic.md +98 -0
  32. package/pipeline/agents/security-auditor.md +10 -0
  33. package/pipeline/agents/task-clarifier.md +10 -0
  34. package/pipeline/commands/multi-agent/SKILL.md +2 -2
  35. package/pipeline/commands/multi-agent/analysis/SKILL.md +6 -2
  36. package/pipeline/commands/multi-agent/analysis-jira/SKILL.md +12 -1
  37. package/pipeline/commands/multi-agent/analysis-resolve/SKILL.md +4 -0
  38. package/pipeline/commands/multi-agent/autopilot/SKILL.md +6 -2
  39. package/pipeline/commands/multi-agent/autopilot-off/SKILL.md +36 -6
  40. package/pipeline/commands/multi-agent/autopilot-on/SKILL.md +77 -12
  41. package/pipeline/commands/multi-agent/autopilot-status/SKILL.md +29 -8
  42. package/pipeline/commands/multi-agent/build-optimize/SKILL.md +4 -0
  43. package/pipeline/commands/multi-agent/channels/SKILL.md +9 -9
  44. package/pipeline/commands/multi-agent/complaint-analysis/SKILL.md +5 -1
  45. package/pipeline/commands/multi-agent/create-jira/SKILL.md +4 -0
  46. package/pipeline/commands/multi-agent/design-check/SKILL.md +16 -11
  47. package/pipeline/commands/multi-agent/diff-explain/SKILL.md +4 -0
  48. package/pipeline/commands/multi-agent/doctor/SKILL.md +4 -0
  49. package/pipeline/commands/multi-agent/feedback/SKILL.md +5 -1
  50. package/pipeline/commands/multi-agent/forget/SKILL.md +4 -0
  51. package/pipeline/commands/multi-agent/garbage-collect/SKILL.md +4 -0
  52. package/pipeline/commands/multi-agent/graph/SKILL.md +4 -0
  53. package/pipeline/commands/multi-agent/help/SKILL.md +37 -39
  54. package/pipeline/commands/multi-agent/ios-coding-standard/SKILL.md +4 -0
  55. package/pipeline/commands/multi-agent/issue/SKILL.md +7 -1
  56. package/pipeline/commands/multi-agent/jira/SKILL.md +7 -1
  57. package/pipeline/commands/multi-agent/kill/SKILL.md +9 -3
  58. package/pipeline/commands/multi-agent/language/SKILL.md +4 -0
  59. package/pipeline/commands/multi-agent/log/SKILL.md +4 -0
  60. package/pipeline/commands/multi-agent/manual-test/SKILL.md +5 -0
  61. package/pipeline/commands/multi-agent/model/SKILL.md +4 -0
  62. package/pipeline/commands/multi-agent/prune-logs/SKILL.md +4 -0
  63. package/pipeline/commands/multi-agent/prune-prompts/SKILL.md +4 -0
  64. package/pipeline/commands/multi-agent/purge/SKILL.md +4 -0
  65. package/pipeline/commands/multi-agent/refactor/SKILL.md +5 -0
  66. package/pipeline/commands/multi-agent/research/SKILL.md +49 -0
  67. package/pipeline/commands/multi-agent/resume/SKILL.md +29 -6
  68. package/pipeline/commands/multi-agent/review/SKILL.md +28 -9
  69. package/pipeline/commands/multi-agent/review-analysis/SKILL.md +5 -1
  70. package/pipeline/commands/multi-agent/review-issue/SKILL.md +4 -0
  71. package/pipeline/commands/multi-agent/review-jira/SKILL.md +4 -0
  72. package/pipeline/commands/multi-agent/route-off/SKILL.md +4 -0
  73. package/pipeline/commands/multi-agent/route-on/SKILL.md +4 -0
  74. package/pipeline/commands/multi-agent/route-status/SKILL.md +4 -0
  75. package/pipeline/commands/multi-agent/routines/SKILL.md +4 -0
  76. package/pipeline/commands/multi-agent/save/SKILL.md +6 -2
  77. package/pipeline/commands/multi-agent/scaffold/SKILL.md +47 -0
  78. package/pipeline/commands/multi-agent/scan/SKILL.md +4 -0
  79. package/pipeline/commands/multi-agent/search/SKILL.md +12 -8
  80. package/pipeline/commands/multi-agent/security-review/SKILL.md +4 -0
  81. package/pipeline/commands/multi-agent/serve/SKILL.md +62 -0
  82. package/pipeline/commands/multi-agent/setup/SKILL.md +27 -36
  83. package/pipeline/commands/multi-agent/stack/SKILL.md +4 -0
  84. package/pipeline/commands/multi-agent/status/SKILL.md +10 -9
  85. package/pipeline/commands/multi-agent/steer/SKILL.md +5 -1
  86. package/pipeline/commands/multi-agent/store-ready/SKILL.md +4 -0
  87. package/pipeline/commands/multi-agent/sync/SKILL.md +13 -13
  88. package/pipeline/commands/multi-agent/test/SKILL.md +4 -0
  89. package/pipeline/commands/multi-agent/test-accessibility/SKILL.md +4 -0
  90. package/pipeline/commands/multi-agent/test-dark-mode/SKILL.md +4 -0
  91. package/pipeline/commands/multi-agent/test-dynamic-type/SKILL.md +4 -0
  92. package/pipeline/commands/multi-agent/test-screenshots/SKILL.md +5 -1
  93. package/pipeline/commands/multi-agent/testflight-validation/SKILL.md +4 -0
  94. package/pipeline/commands/multi-agent/uninstall/SKILL.md +5 -1
  95. package/pipeline/commands/multi-agent/update/SKILL.md +4 -0
  96. package/pipeline/contract/CHANGELOG.md +74 -0
  97. package/pipeline/contract/README.md +126 -0
  98. package/pipeline/contract/build.mjs +427 -0
  99. package/pipeline/contract/fixtures/answer-result.json +11 -0
  100. package/pipeline/contract/fixtures/error-invalid-request.json +8 -0
  101. package/pipeline/contract/fixtures/error-unauthorized.json +5 -0
  102. package/pipeline/contract/fixtures/error-unsigned.json +5 -0
  103. package/pipeline/contract/fixtures/issues-empty.json +18 -0
  104. package/pipeline/contract/fixtures/launch-plan.json +31 -0
  105. package/pipeline/contract/fixtures/runs-awaiting-question.json +70 -0
  106. package/pipeline/contract/fixtures/runs-empty.json +6 -0
  107. package/pipeline/contract/fixtures/runs-failed.json +84 -0
  108. package/pipeline/contract/fixtures/runs-old-schema.json +70 -0
  109. package/pipeline/contract/fixtures/runs-pr-opened-redacted.json +101 -0
  110. package/pipeline/contract/fixtures/runs-pr-opened.json +106 -0
  111. package/pipeline/contract/fixtures/runs-running.json +84 -0
  112. package/pipeline/contract/fixtures/worktrees-empty.json +4 -0
  113. package/pipeline/contract/frozen/toolbox.json +107 -0
  114. package/pipeline/contract/manifest.json +263 -0
  115. package/pipeline/contract/types/index.d.ts +343 -0
  116. package/pipeline/lib/_jira-auth.sh +6 -2
  117. package/pipeline/lib/account-resolver.sh +1 -1
  118. package/pipeline/lib/autopilot-state.sh +19 -0
  119. package/pipeline/lib/context-link-extractor.sh +12 -5
  120. package/pipeline/lib/credential-inventory.sh +12 -5
  121. package/pipeline/lib/credential-store.sh +116 -185
  122. package/pipeline/lib/fetch-confluence.sh +44 -3
  123. package/pipeline/lib/fetch-document.sh +3 -4
  124. package/pipeline/lib/fetch-fortify.sh +1 -1
  125. package/pipeline/lib/figma-mcp-refresh.sh +2 -2
  126. package/pipeline/lib/figma-token.sh +5 -1
  127. package/pipeline/lib/issue-fetcher.sh +233 -16
  128. package/pipeline/lib/json-file-lock.mjs +172 -0
  129. package/pipeline/lib/model-dispatch.sh +21 -12
  130. package/pipeline/lib/model-rung.sh +6 -1
  131. package/pipeline/lib/multi-repo-pipeline.sh +1 -1
  132. package/pipeline/lib/outbound-gate.mjs +46 -16
  133. package/pipeline/lib/parse-complaints.sh +14 -7
  134. package/pipeline/lib/plan-todos.sh +3 -3
  135. package/pipeline/lib/post-pr-review.sh +9 -9
  136. package/pipeline/lib/pr-request-location.mjs +85 -0
  137. package/pipeline/lib/regular-file.mjs +153 -0
  138. package/pipeline/lib/repo-hygiene.sh +17 -0
  139. package/pipeline/lib/route-state.sh +5 -1
  140. package/pipeline/lib/run-paths.sh +3 -2
  141. package/pipeline/lib/stack-detect.sh +19 -1
  142. package/pipeline/lib/unattended-profile-check.mjs +178 -0
  143. package/pipeline/lib/unattended-settings-location.mjs +28 -0
  144. package/pipeline/lib/unattended.mjs +76 -0
  145. package/pipeline/lib/unattended.sh +32 -0
  146. package/pipeline/lib/untrusted.mjs +76 -0
  147. package/pipeline/lib/user-facing.mjs +82 -0
  148. package/pipeline/lib/user-facing.sh +58 -0
  149. package/pipeline/multi-agent-refs/_dev-context.md +1 -1
  150. package/pipeline/multi-agent-refs/analysis/evidence.md +4 -0
  151. package/pipeline/multi-agent-refs/analysis/locked.md +2 -2
  152. package/pipeline/multi-agent-refs/analysis/render.md +4 -3
  153. package/pipeline/multi-agent-refs/analysis/resolve.md +3 -1
  154. package/pipeline/multi-agent-refs/analysis/synthesis.md +4 -5
  155. package/pipeline/multi-agent-refs/analysis-template.md +10 -17
  156. package/pipeline/multi-agent-refs/channels/jira.md +1 -1
  157. package/pipeline/multi-agent-refs/component-dispatch.md +3 -3
  158. package/pipeline/multi-agent-refs/conventions-defaults.md +32 -32
  159. package/pipeline/multi-agent-refs/cross-cli-contract.md +10 -17
  160. package/pipeline/multi-agent-refs/features/autopilot-circuit-breaker.md +37 -9
  161. package/pipeline/multi-agent-refs/features/autopilot-operations.md +277 -0
  162. package/pipeline/multi-agent-refs/features/constitution.md +196 -0
  163. package/pipeline/multi-agent-refs/features/doctor.md +6 -3
  164. package/pipeline/multi-agent-refs/features/external-context-injection.md +6 -1
  165. package/pipeline/multi-agent-refs/features/jira-context.md +1 -1
  166. package/pipeline/multi-agent-refs/features/maturity-followup.md +43 -23
  167. package/pipeline/multi-agent-refs/features/model-fallback.md +9 -0
  168. package/pipeline/multi-agent-refs/features/phone-api.md +306 -0
  169. package/pipeline/multi-agent-refs/features/plan-critic.md +159 -0
  170. package/pipeline/multi-agent-refs/features/research.md +150 -0
  171. package/pipeline/multi-agent-refs/features/review-decision.md +185 -0
  172. package/pipeline/multi-agent-refs/features/scaffold.md +160 -0
  173. package/pipeline/multi-agent-refs/features/security-audit.md +6 -2
  174. package/pipeline/multi-agent-refs/features/skill-conformance.md +4 -1
  175. package/pipeline/multi-agent-refs/features/stack-adapters.md +116 -0
  176. package/pipeline/multi-agent-refs/features/unattended-gates.md +316 -0
  177. package/pipeline/multi-agent-refs/features/unattended-security.md +731 -0
  178. package/pipeline/multi-agent-refs/features/url-enrichment.md +2 -2
  179. package/pipeline/multi-agent-refs/features/usage-reporting.md +127 -35
  180. package/pipeline/multi-agent-refs/features/verify-by-test.md +1 -1
  181. package/pipeline/multi-agent-refs/features/visual-evidence.md +7 -7
  182. package/pipeline/multi-agent-refs/keychain.md +6 -11
  183. package/pipeline/multi-agent-refs/payload-contracts.md +2 -2
  184. package/pipeline/multi-agent-refs/phases/log-format.md +2 -3
  185. package/pipeline/multi-agent-refs/phases/modes.md +10 -12
  186. package/pipeline/multi-agent-refs/phases/operations.md +11 -5
  187. package/pipeline/multi-agent-refs/phases/phase-0-init.md +73 -81
  188. package/pipeline/multi-agent-refs/phases/phase-1-plan.md +22 -22
  189. package/pipeline/multi-agent-refs/phases/phase-2-dev.md +42 -66
  190. package/pipeline/multi-agent-refs/phases/phase-3-review.md +45 -79
  191. package/pipeline/multi-agent-refs/phases/phase-4-commit.md +28 -38
  192. package/pipeline/multi-agent-refs/phases/phase-5-report.md +27 -25
  193. package/pipeline/multi-agent-refs/phases.md +1 -1
  194. package/pipeline/multi-agent-refs/picker-contract.md +1 -1
  195. package/pipeline/multi-agent-refs/progress-contract.md +13 -16
  196. package/pipeline/multi-agent-refs/readiness-review.md +1 -1
  197. package/pipeline/multi-agent-refs/research/engine.md +91 -0
  198. package/pipeline/multi-agent-refs/rules.md +6 -4
  199. package/pipeline/multi-agent-refs/setup/repo-discovery.md +2 -2
  200. package/pipeline/multi-agent-refs/tracker-contract.md +2 -2
  201. package/pipeline/multi-agent-refs/unattended-contract.md +68 -16
  202. package/pipeline/rules/figma-pipeline.md +12 -12
  203. package/pipeline/schemas/agent-state.schema.json +480 -18
  204. package/pipeline/schemas/analysis-spec.schema.json +4 -4
  205. package/pipeline/schemas/answer-request.schema.json +24 -0
  206. package/pipeline/schemas/answer-result.schema.json +28 -0
  207. package/pipeline/schemas/autopilot-config.schema.json +111 -13
  208. package/pipeline/schemas/command-parameters.schema.json +99 -0
  209. package/pipeline/schemas/constitution.schema.json +56 -0
  210. package/pipeline/schemas/contract-error.schema.json +52 -0
  211. package/pipeline/schemas/design-check-config.schema.json +5 -1
  212. package/pipeline/schemas/issues.schema.json +61 -0
  213. package/pipeline/schemas/launch-plan.schema.json +46 -0
  214. package/pipeline/schemas/launch-request.schema.json +45 -0
  215. package/pipeline/schemas/launch.json +61 -0
  216. package/pipeline/schemas/launch.schema.json +84 -0
  217. package/pipeline/schemas/phases.json +2 -2
  218. package/pipeline/schemas/phases.schema.json +68 -0
  219. package/pipeline/schemas/phone-devices.schema.json +61 -0
  220. package/pipeline/schemas/phone-signed-request.schema.json +67 -0
  221. package/pipeline/schemas/plan-critique.schema.json +99 -0
  222. package/pipeline/schemas/plan-todos.schema.json +7 -7
  223. package/pipeline/schemas/planning-output.schema.json +5 -0
  224. package/pipeline/schemas/pr-request.schema.json +46 -0
  225. package/pipeline/schemas/prefs.schema.json +79 -8
  226. package/pipeline/schemas/research-output.schema.json +118 -0
  227. package/pipeline/schemas/review-file-exclusions.schema.json +25 -0
  228. package/pipeline/schemas/reviewer-output.schema.json +40 -4
  229. package/pipeline/schemas/run-questions.json +392 -0
  230. package/pipeline/schemas/run-questions.schema.json +118 -0
  231. package/pipeline/schemas/runs-index.schema.json +189 -0
  232. package/pipeline/schemas/scaffold-manifest.schema.json +43 -0
  233. package/pipeline/schemas/secret-patterns.schema.json +28 -0
  234. package/pipeline/schemas/stack-adapters.json +527 -0
  235. package/pipeline/schemas/stack-adapters.schema.json +184 -0
  236. package/pipeline/schemas/token-budget.json +1 -1
  237. package/pipeline/schemas/token-budget.schema.json +26 -0
  238. package/pipeline/schemas/triage-output.schema.json +64 -3
  239. package/pipeline/schemas/unattended-policy.json +139 -0
  240. package/pipeline/schemas/unattended-policy.schema.json +73 -0
  241. package/pipeline/schemas/unattended-profile.json +248 -0
  242. package/pipeline/schemas/unattended-profile.schema.json +198 -0
  243. package/pipeline/schemas/worktrees.schema.json +51 -0
  244. package/pipeline/scripts/README.md +1 -0
  245. package/pipeline/scripts/_autopilot-config.mjs +130 -0
  246. package/pipeline/scripts/_autopilot-ops.mjs +567 -0
  247. package/pipeline/scripts/_autopilot-outcomes.mjs +174 -0
  248. package/pipeline/scripts/_command-contract.mjs +384 -0
  249. package/pipeline/scripts/_cost.mjs +40 -0
  250. package/pipeline/scripts/_notices.mjs +160 -0
  251. package/pipeline/scripts/_phone-auth.mjs +485 -0
  252. package/pipeline/scripts/_pre-existing.mjs +294 -0
  253. package/pipeline/scripts/_redact.mjs +77 -0
  254. package/pipeline/scripts/_run-paths.mjs +4 -2
  255. package/pipeline/scripts/_stack-adapter.mjs +678 -0
  256. package/pipeline/scripts/_stack-routing.mjs +1 -1
  257. package/pipeline/scripts/agent-guard.py +348 -37
  258. package/pipeline/scripts/agent-guard.sh +41 -13
  259. package/pipeline/scripts/analysis-story-tree.mjs +79 -3
  260. package/pipeline/scripts/answer-question.mjs +181 -0
  261. package/pipeline/scripts/audit-log-rotate.sh +1 -4
  262. package/pipeline/scripts/audit-log.sh +4 -4
  263. package/pipeline/scripts/autopilot-arming.mjs +389 -21
  264. package/pipeline/scripts/autopilot-awake.mjs +255 -0
  265. package/pipeline/scripts/autopilot-intake.mjs +137 -36
  266. package/pipeline/scripts/autopilot-menubar.swift +156 -44
  267. package/pipeline/scripts/autopilot-publish.mjs +1625 -0
  268. package/pipeline/scripts/autopilot-runner.mjs +1678 -222
  269. package/pipeline/scripts/autopilot-status.sh +198 -33
  270. package/pipeline/scripts/build-lock.sh +120 -0
  271. package/pipeline/scripts/build-references.mjs +4 -1
  272. package/pipeline/scripts/build-stack-plugins.mjs +59 -22
  273. package/pipeline/scripts/capture-flush.sh +1 -1
  274. package/pipeline/scripts/capture-resume.sh +13 -9
  275. package/pipeline/scripts/check-derived-drift.mjs +52 -11
  276. package/pipeline/scripts/commands.mjs +88 -0
  277. package/pipeline/scripts/constitution.mjs +362 -0
  278. package/pipeline/scripts/contract-server.mjs +776 -0
  279. package/pipeline/scripts/cost-analyze.mjs +89 -39
  280. package/pipeline/scripts/diff-explain.mjs +12 -1
  281. package/pipeline/scripts/doctor.mjs +77 -28
  282. package/pipeline/scripts/evidence-gate.mjs +192 -12
  283. package/pipeline/scripts/feedback-send.mjs +4 -2
  284. package/pipeline/scripts/gate-ledger.mjs +449 -0
  285. package/pipeline/scripts/gc-abandoned.sh +132 -13
  286. package/pipeline/scripts/gen-facts.mjs +31 -15
  287. package/pipeline/scripts/gen-mode-dispatch.mjs +3 -3
  288. package/pipeline/scripts/github-ssh-setup.sh +140 -29
  289. package/pipeline/scripts/graph-mermaid.mjs +4 -1
  290. package/pipeline/scripts/issues.mjs +236 -0
  291. package/pipeline/scripts/jira-attach.sh +6 -2
  292. package/pipeline/scripts/jira-search.sh +4 -3
  293. package/pipeline/scripts/keychain-save.sh +125 -24
  294. package/pipeline/scripts/keychain.py +63 -93
  295. package/pipeline/scripts/launch-request.mjs +747 -0
  296. package/pipeline/scripts/localize-commands.mjs +4 -10
  297. package/pipeline/scripts/log-metric.sh +6 -5
  298. package/pipeline/scripts/maturity-followup.mjs +13 -4
  299. package/pipeline/scripts/memory-save.sh +25 -0
  300. package/pipeline/scripts/migrate-prefs.mjs +4 -3
  301. package/pipeline/scripts/open-questions-gate.mjs +276 -0
  302. package/pipeline/scripts/phase-tracker.sh +41 -27
  303. package/pipeline/scripts/phase0-exit-gate.mjs +22 -4
  304. package/pipeline/scripts/phone-devices.mjs +224 -0
  305. package/pipeline/scripts/plan-coverage-gate.mjs +200 -66
  306. package/pipeline/scripts/plan-critique-gate.mjs +591 -0
  307. package/pipeline/scripts/pr-request.mjs +188 -0
  308. package/pipeline/scripts/pre-commit-check.sh +115 -4
  309. package/pipeline/scripts/probe-evidence-capability.sh +44 -5
  310. package/pipeline/scripts/record-phase.mjs +71 -0
  311. package/pipeline/scripts/render-agent-log-cost.sh +17 -2
  312. package/pipeline/scripts/render-cost-summary.sh +1 -1
  313. package/pipeline/scripts/render-work-summary.sh +1 -1
  314. package/pipeline/scripts/require-supported-version.sh +4 -1
  315. package/pipeline/scripts/research-gate.mjs +704 -0
  316. package/pipeline/scripts/review-decision-gate.mjs +403 -0
  317. package/pipeline/scripts/routine-registry.mjs +5 -2
  318. package/pipeline/scripts/runs-index.mjs +135 -27
  319. package/pipeline/scripts/scaffold-gate.mjs +393 -0
  320. package/pipeline/scripts/skill-conformance.mjs +25 -8
  321. package/pipeline/scripts/skill-siblings.mjs +2 -1
  322. package/pipeline/scripts/smoke-cross-cli-behavior.sh +32 -6
  323. package/pipeline/scripts/smoke-schema-validation.sh +6 -2
  324. package/pipeline/scripts/spec-consistency-gate.mjs +469 -0
  325. package/pipeline/scripts/symbol-existence-gate.mjs +450 -0
  326. package/pipeline/scripts/test-gap-scan.mjs +40 -2
  327. package/pipeline/scripts/test-integrity-gate.mjs +20 -4
  328. package/pipeline/scripts/test-strength.mjs +484 -0
  329. package/pipeline/scripts/test-summary.mjs +651 -0
  330. package/pipeline/scripts/triage-memory.mjs +49 -9
  331. package/pipeline/scripts/unattended_policy.py +2786 -0
  332. package/pipeline/scripts/uninstall.mjs +10 -10
  333. package/pipeline/scripts/update-issue-progress.sh +1 -1
  334. package/pipeline/scripts/usage-identity.mjs +288 -0
  335. package/pipeline/scripts/usage-register.mjs +185 -65
  336. package/pipeline/scripts/usage-report.mjs +230 -66
  337. package/pipeline/scripts/validate-complaint-doc.mjs +28 -10
  338. package/pipeline/scripts/validate-planning.mjs +6 -0
  339. package/pipeline/scripts/verify-citations.mjs +151 -38
  340. package/pipeline/scripts/verify.mjs +58 -18
  341. package/pipeline/scripts/worktree-prepare.sh +126 -0
  342. package/pipeline/scripts/worktrees.mjs +124 -0
  343. package/pipeline/scripts/write-state.mjs +48 -17
  344. package/pipeline/skills/.skill-manifest.json +222 -226
  345. package/pipeline/skills/.skills-index.json +77 -88
  346. package/pipeline/skills/shared/README.md +44 -45
  347. package/pipeline/skills/shared/core/apple-archive-compliance/SKILL.md +3 -2
  348. package/pipeline/skills/shared/core/google-play-compliance/SKILL.md +3 -2
  349. package/pipeline/skills/shared/core/multi-agent/SKILL.md +10 -9
  350. package/pipeline/skills/shared/core/multi-agent-analysis/SKILL.md +6 -5
  351. package/pipeline/skills/shared/core/multi-agent-analysis-jira/SKILL.md +11 -3
  352. package/pipeline/skills/shared/core/multi-agent-analysis-resolve/SKILL.md +2 -1
  353. package/pipeline/skills/shared/core/multi-agent-autopilot/SKILL.md +4 -3
  354. package/pipeline/skills/shared/core/multi-agent-autopilot-off/SKILL.md +32 -6
  355. package/pipeline/skills/shared/core/multi-agent-autopilot-on/SKILL.md +66 -8
  356. package/pipeline/skills/shared/core/multi-agent-autopilot-status/SKILL.md +27 -9
  357. package/pipeline/skills/shared/core/multi-agent-build-optimize/SKILL.md +2 -1
  358. package/pipeline/skills/shared/core/multi-agent-channels/SKILL.md +7 -4
  359. package/pipeline/skills/shared/core/multi-agent-complaint-analysis/SKILL.md +3 -2
  360. package/pipeline/skills/shared/core/multi-agent-create-jira/SKILL.md +2 -1
  361. package/pipeline/skills/shared/core/multi-agent-design-check/SKILL.md +7 -5
  362. package/pipeline/skills/shared/core/multi-agent-diff-explain/SKILL.md +2 -1
  363. package/pipeline/skills/shared/core/multi-agent-doctor/SKILL.md +3 -2
  364. package/pipeline/skills/shared/core/multi-agent-feedback/SKILL.md +2 -1
  365. package/pipeline/skills/shared/core/multi-agent-forget/SKILL.md +2 -1
  366. package/pipeline/skills/shared/core/multi-agent-garbage-collect/SKILL.md +2 -1
  367. package/pipeline/skills/shared/core/multi-agent-graph/SKILL.md +2 -1
  368. package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +2 -1
  369. package/pipeline/skills/shared/core/multi-agent-ios-coding-standard/SKILL.md +2 -1
  370. package/pipeline/skills/shared/core/multi-agent-issue/SKILL.md +3 -2
  371. package/pipeline/skills/shared/core/multi-agent-jira/SKILL.md +2 -1
  372. package/pipeline/skills/shared/core/multi-agent-kill/SKILL.md +7 -4
  373. package/pipeline/skills/shared/core/multi-agent-language/SKILL.md +2 -1
  374. package/pipeline/skills/shared/core/multi-agent-log/SKILL.md +2 -1
  375. package/pipeline/skills/shared/core/multi-agent-manual-test/SKILL.md +2 -1
  376. package/pipeline/skills/shared/core/multi-agent-model/SKILL.md +2 -1
  377. package/pipeline/skills/shared/core/multi-agent-prune-logs/SKILL.md +2 -1
  378. package/pipeline/skills/shared/core/multi-agent-prune-prompts/SKILL.md +2 -1
  379. package/pipeline/skills/shared/core/multi-agent-purge/SKILL.md +2 -1
  380. package/pipeline/skills/shared/core/multi-agent-refactor/SKILL.md +2 -1
  381. package/pipeline/skills/shared/core/multi-agent-research/SKILL.md +35 -0
  382. package/pipeline/skills/shared/core/multi-agent-resume/SKILL.md +7 -3
  383. package/pipeline/skills/shared/core/multi-agent-review/SKILL.md +7 -5
  384. package/pipeline/skills/shared/core/multi-agent-review-analysis/SKILL.md +2 -1
  385. package/pipeline/skills/shared/core/multi-agent-review-issue/SKILL.md +3 -2
  386. package/pipeline/skills/shared/core/multi-agent-review-jira/SKILL.md +2 -1
  387. package/pipeline/skills/shared/core/multi-agent-route-off/SKILL.md +2 -1
  388. package/pipeline/skills/shared/core/multi-agent-route-on/SKILL.md +2 -1
  389. package/pipeline/skills/shared/core/multi-agent-route-status/SKILL.md +2 -1
  390. package/pipeline/skills/shared/core/multi-agent-routines/SKILL.md +2 -1
  391. package/pipeline/skills/shared/core/multi-agent-save/SKILL.md +3 -2
  392. package/pipeline/skills/shared/core/multi-agent-scaffold/SKILL.md +30 -0
  393. package/pipeline/skills/shared/core/multi-agent-scan/SKILL.md +2 -1
  394. package/pipeline/skills/shared/core/multi-agent-search/SKILL.md +4 -3
  395. package/pipeline/skills/shared/core/multi-agent-security-review/SKILL.md +2 -1
  396. package/pipeline/skills/shared/core/multi-agent-serve/SKILL.md +60 -0
  397. package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +8 -8
  398. package/pipeline/skills/shared/core/multi-agent-stack/SKILL.md +2 -1
  399. package/pipeline/skills/shared/core/multi-agent-status/SKILL.md +7 -8
  400. package/pipeline/skills/shared/core/multi-agent-steer/SKILL.md +2 -1
  401. package/pipeline/skills/shared/core/multi-agent-store-ready/SKILL.md +2 -1
  402. package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +10 -10
  403. package/pipeline/skills/shared/core/multi-agent-test/SKILL.md +2 -1
  404. package/pipeline/skills/shared/core/multi-agent-test-accessibility/SKILL.md +2 -1
  405. package/pipeline/skills/shared/core/multi-agent-test-dark-mode/SKILL.md +2 -1
  406. package/pipeline/skills/shared/core/multi-agent-test-dynamic-type/SKILL.md +2 -1
  407. package/pipeline/skills/shared/core/multi-agent-test-screenshots/SKILL.md +2 -1
  408. package/pipeline/skills/shared/core/multi-agent-testflight-validation/SKILL.md +2 -1
  409. package/pipeline/skills/shared/core/multi-agent-uninstall/SKILL.md +3 -2
  410. package/pipeline/skills/shared/core/multi-agent-update/SKILL.md +2 -1
  411. package/pipeline/skills/shared/external/NOTICE-avdlee-swiftui-agent-skill.md +46 -0
  412. package/pipeline/skills/shared/external/NOTICE-dimillian-skills.md +9 -3
  413. package/pipeline/skills/shared/external/NOTICE-paul-hudson-skills.md +54 -0
  414. package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +9 -11
  415. package/pipeline/skills/shared/external/NOTICE-vibeship-spawner-skills.md +203 -0
  416. package/pipeline/skills/shared/external/NOTICE-xcode-build-skills.md +10 -3
  417. package/pipeline/skills/shared/external/accessibility-compliance-accessibility-audit/SKILL.md +131 -25
  418. package/pipeline/skills/shared/external/agent-introspection-debugging/SKILL.md +4 -3
  419. package/pipeline/skills/shared/external/alarmkit/SKILL.md +2 -1
  420. package/pipeline/skills/shared/external/android-architecture/SKILL.md +85 -76
  421. package/pipeline/skills/shared/external/android-build-quality-gates/SKILL.md +51 -3
  422. package/pipeline/skills/shared/external/android-build-quality-gates/references/patterns.md +9 -0
  423. package/pipeline/skills/shared/external/android-datastore/SKILL.md +4 -3
  424. package/pipeline/skills/shared/external/android-design-tokens-codegen/SKILL.md +4 -3
  425. package/pipeline/skills/shared/external/android-jetpack-compose-expert/SKILL.md +106 -181
  426. package/pipeline/skills/shared/external/android-jetpack-compose-expert/references/patterns.md +147 -0
  427. package/pipeline/skills/shared/external/android-mvi-viewmodel/SKILL.md +45 -4
  428. package/pipeline/skills/shared/external/android-performance/SKILL.md +27 -2
  429. package/pipeline/skills/shared/external/android-performance/references/patterns.md +37 -37
  430. package/pipeline/skills/shared/external/api-patterns/SKILL.md +111 -67
  431. package/pipeline/skills/shared/external/api-patterns/references/contract-details.md +128 -0
  432. package/pipeline/skills/shared/external/api-security-best-practices/SKILL.md +136 -186
  433. package/pipeline/skills/shared/external/api-security-best-practices/references/abuse-controls.md +140 -0
  434. package/pipeline/skills/shared/external/api-security-best-practices/references/identity-and-access.md +207 -0
  435. package/pipeline/skills/shared/external/api-security-best-practices/references/operations.md +66 -0
  436. package/pipeline/skills/shared/external/api-security-best-practices/references/request-handling.md +175 -0
  437. package/pipeline/skills/shared/external/app-clips/SKILL.md +2 -0
  438. package/pipeline/skills/shared/external/app-intents/SKILL.md +2 -0
  439. package/pipeline/skills/shared/external/app-store-changelog/SKILL.md +4 -3
  440. package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +2 -0
  441. package/pipeline/skills/shared/external/app-store-review/SKILL.md +2 -0
  442. package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +2 -0
  443. package/pipeline/skills/shared/external/architecture/SKILL.md +106 -39
  444. package/pipeline/skills/shared/external/architecture/references/adr-and-review.md +76 -0
  445. package/pipeline/skills/shared/external/authentication/SKILL.md +2 -0
  446. package/pipeline/skills/shared/external/avkit/SKILL.md +2 -0
  447. package/pipeline/skills/shared/external/background-processing/SKILL.md +2 -1
  448. package/pipeline/skills/shared/external/backlog/SKILL.md +3 -2
  449. package/pipeline/skills/shared/external/callkit-voip/SKILL.md +2 -0
  450. package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +1 -1
  451. package/pipeline/skills/shared/external/ci-cd-pipelines/SKILL.md +3 -2
  452. package/pipeline/skills/shared/external/clean-code/SKILL.md +192 -90
  453. package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +2 -1
  454. package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +1 -1
  455. package/pipeline/skills/shared/external/compose-components/SKILL.md +4 -4
  456. package/pipeline/skills/shared/external/compose-navigation/SKILL.md +22 -22
  457. package/pipeline/skills/shared/external/compose-navigation/references/patterns.md +10 -10
  458. package/pipeline/skills/shared/external/compose-testing/SKILL.md +13 -6
  459. package/pipeline/skills/shared/external/compose-testing/references/patterns.md +59 -59
  460. package/pipeline/skills/shared/external/contacts-framework/SKILL.md +2 -0
  461. package/pipeline/skills/shared/external/context-compression/SKILL.md +118 -250
  462. package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +2 -0
  463. package/pipeline/skills/shared/external/core-data/SKILL.md +2 -0
  464. package/pipeline/skills/shared/external/core-motion/SKILL.md +2 -0
  465. package/pipeline/skills/shared/external/core-nfc/SKILL.md +2 -0
  466. package/pipeline/skills/shared/external/coreml/SKILL.md +2 -1
  467. package/pipeline/skills/shared/external/council/SKILL.md +2 -1
  468. package/pipeline/skills/shared/external/cryptokit/SKILL.md +2 -0
  469. package/pipeline/skills/shared/external/css-modern/SKILL.md +3 -2
  470. package/pipeline/skills/shared/external/database-patterns/SKILL.md +3 -2
  471. package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +2 -0
  472. package/pipeline/skills/shared/external/debugging-strategies/SKILL.md +130 -20
  473. package/pipeline/skills/shared/external/debugging-strategies/references/hard-cases.md +54 -0
  474. package/pipeline/skills/shared/external/device-integrity/SKILL.md +2 -0
  475. package/pipeline/skills/shared/external/docker-expert/SKILL.md +137 -381
  476. package/pipeline/skills/shared/external/docker-expert/references/patterns.md +98 -0
  477. package/pipeline/skills/shared/external/energykit/SKILL.md +2 -1
  478. package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +3 -1
  479. package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +2 -2
  480. package/pipeline/skills/shared/external/fastapi-pro/SKILL.md +116 -185
  481. package/pipeline/skills/shared/external/fastapi-pro/references/app-structure.md +235 -0
  482. package/pipeline/skills/shared/external/fastapi-pro/references/testing-and-deployment.md +69 -0
  483. package/pipeline/skills/shared/external/firebase/SKILL.md +4 -3
  484. package/pipeline/skills/shared/external/github-actions-templates/SKILL.md +151 -293
  485. package/pipeline/skills/shared/external/github-actions-templates/references/patterns.md +96 -0
  486. package/pipeline/skills/shared/external/healthkit/SKILL.md +2 -0
  487. package/pipeline/skills/shared/external/hig-components-content/SKILL.md +69 -72
  488. package/pipeline/skills/shared/external/hig-components-content/references/content-views.md +111 -0
  489. package/pipeline/skills/shared/external/hig-components-layout/SKILL.md +77 -86
  490. package/pipeline/skills/shared/external/hig-components-layout/references/containers.md +98 -0
  491. package/pipeline/skills/shared/external/hig-components-status/SKILL.md +150 -78
  492. package/pipeline/skills/shared/external/hig-components-system/SKILL.md +76 -97
  493. package/pipeline/skills/shared/external/hig-components-system/references/surfaces.md +98 -0
  494. package/pipeline/skills/shared/external/hig-foundations/SKILL.md +48 -76
  495. package/pipeline/skills/shared/external/hig-foundations/references/foundations-detail.md +132 -0
  496. package/pipeline/skills/shared/external/hig-inputs/SKILL.md +147 -106
  497. package/pipeline/skills/shared/external/hig-patterns/SKILL.md +61 -77
  498. package/pipeline/skills/shared/external/hig-patterns/references/patterns.md +92 -0
  499. package/pipeline/skills/shared/external/hig-platforms/SKILL.md +147 -77
  500. package/pipeline/skills/shared/external/hig-technologies/SKILL.md +61 -121
  501. package/pipeline/skills/shared/external/hig-technologies/references/technologies.md +108 -0
  502. package/pipeline/skills/shared/external/homekit-matter/SKILL.md +2 -0
  503. package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +1 -1
  504. package/pipeline/skills/shared/external/html-semantic/SKILL.md +3 -2
  505. package/pipeline/skills/shared/external/humanizer/SKILL.md +2 -1
  506. package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +2 -0
  507. package/pipeline/skills/shared/external/ios-coding-standard/SKILL.md +2 -1
  508. package/pipeline/skills/shared/external/ios-coding-standard/references/STANDARD.md +14 -2
  509. package/pipeline/skills/shared/external/ios-coding-standard/references/rules.yml +2 -2
  510. package/pipeline/skills/shared/external/ios-debugger-agent/SKILL.md +4 -3
  511. package/pipeline/skills/shared/external/ios-localization/SKILL.md +8 -6
  512. package/pipeline/skills/shared/external/ios-localization/evals/evals.json +2 -2
  513. package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +11 -11
  514. package/pipeline/skills/shared/external/ios-module-structure/SKILL.md +2 -1
  515. package/pipeline/skills/shared/external/ios-networking/SKILL.md +2 -0
  516. package/pipeline/skills/shared/external/ios-simulator/SKILL.md +2 -0
  517. package/pipeline/skills/shared/external/kotlin-coroutines-expert/SKILL.md +102 -193
  518. package/pipeline/skills/shared/external/kotlin-coroutines-expert/references/patterns.md +103 -0
  519. package/pipeline/skills/shared/external/live-activities/SKILL.md +4 -2
  520. package/pipeline/skills/shared/external/live-activities/evals/evals.json +2 -2
  521. package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +7 -9
  522. package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +3 -3
  523. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +2 -2
  524. package/pipeline/skills/shared/external/macos-menubar-tuist-app/SKILL.md +4 -3
  525. package/pipeline/skills/shared/external/macos-spm-app-packaging/SKILL.md +5 -3
  526. package/pipeline/skills/shared/external/mapkit-location/SKILL.md +2 -0
  527. package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +1 -1
  528. package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +2 -0
  529. package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +1 -1
  530. package/pipeline/skills/shared/external/monorepo-architect/SKILL.md +149 -46
  531. package/pipeline/skills/shared/external/monorepo-architect/references/patterns.md +70 -0
  532. package/pipeline/skills/shared/external/musickit-audio/SKILL.md +2 -0
  533. package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +1 -1
  534. package/pipeline/skills/shared/external/natural-language/SKILL.md +2 -0
  535. package/pipeline/skills/shared/external/nextjs-app-router/SKILL.md +3 -2
  536. package/pipeline/skills/shared/external/nodejs-backend-patterns/SKILL.md +91 -21
  537. package/pipeline/skills/shared/external/nodejs-backend-patterns/references/runtime-patterns.md +247 -0
  538. package/pipeline/skills/shared/external/nodejs-backend-patterns/references/testing-and-frameworks.md +57 -0
  539. package/pipeline/skills/shared/external/observability-engineer/SKILL.md +155 -232
  540. package/pipeline/skills/shared/external/observability-engineer/references/patterns.md +75 -0
  541. package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +2 -0
  542. package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +2 -2
  543. package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +18 -18
  544. package/pipeline/skills/shared/external/pdfkit/SKILL.md +2 -1
  545. package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +2 -0
  546. package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +1 -1
  547. package/pipeline/skills/shared/external/permissionkit/SKILL.md +2 -0
  548. package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +2 -1
  549. package/pipeline/skills/shared/external/push-notifications/SKILL.md +2 -0
  550. package/pipeline/skills/shared/external/python-patterns/SKILL.md +3 -2
  551. package/pipeline/skills/shared/external/react-best-practices/SKILL.md +3 -2
  552. package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +2 -2
  553. package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +1 -1
  554. package/pipeline/skills/shared/external/rest-api-design/SKILL.md +3 -2
  555. package/pipeline/skills/shared/external/retrofit-networking/SKILL.md +7 -7
  556. package/pipeline/skills/shared/external/retrofit-networking/references/patterns.md +69 -69
  557. package/pipeline/skills/shared/external/room-database/references/patterns.md +126 -126
  558. package/pipeline/skills/shared/external/search-first/SKILL.md +2 -1
  559. package/pipeline/skills/shared/external/security-review/SKILL.md +4 -3
  560. package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +2 -2
  561. package/pipeline/skills/shared/external/signal-community/SKILL.md +1 -1
  562. package/pipeline/skills/shared/external/skill-creator/SKILL.md +2 -1
  563. package/pipeline/skills/shared/external/speech-recognition/SKILL.md +2 -1
  564. package/pipeline/skills/shared/external/spm-build-analysis/SKILL.md +2 -0
  565. package/pipeline/skills/shared/external/storekit/SKILL.md +2 -0
  566. package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +2 -0
  567. package/pipeline/skills/shared/external/swift-architecture/SKILL.md +2 -1
  568. package/pipeline/skills/shared/external/swift-charts/SKILL.md +2 -1
  569. package/pipeline/skills/shared/external/swift-codable/SKILL.md +2 -0
  570. package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +3 -1
  571. package/pipeline/skills/shared/external/swift-concurrency-expert/SKILL.md +5 -4
  572. package/pipeline/skills/shared/external/swift-concurrency-pro/SKILL.md +2 -1
  573. package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +2 -0
  574. package/pipeline/skills/shared/external/swift-language/SKILL.md +3 -1
  575. package/pipeline/skills/shared/external/swift-security/SKILL.md +2 -1
  576. package/pipeline/skills/shared/external/swift-testing/SKILL.md +2 -0
  577. package/pipeline/skills/shared/external/swift-testing-pro/SKILL.md +2 -1
  578. package/pipeline/skills/shared/external/swift-testing-pro/references/new-features.md +10 -0
  579. package/pipeline/skills/shared/external/swiftdata/SKILL.md +2 -0
  580. package/pipeline/skills/shared/external/swiftdata-pro/SKILL.md +2 -1
  581. package/pipeline/skills/shared/external/swiftlint/SKILL.md +2 -0
  582. package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +2 -0
  583. package/pipeline/skills/shared/external/swiftui-expert-skill/SKILL.md +3 -1
  584. package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +2 -0
  585. package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +2 -0
  586. package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +2 -0
  587. package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +2 -0
  588. package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +3 -1
  589. package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +3 -1
  590. package/pipeline/skills/shared/external/swiftui-performance-audit/SKILL.md +5 -4
  591. package/pipeline/skills/shared/external/swiftui-pro/SKILL.md +2 -1
  592. package/pipeline/skills/shared/external/swiftui-ui-patterns/SKILL.md +5 -4
  593. package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +2 -0
  594. package/pipeline/skills/shared/external/swiftui-view-refactor/SKILL.md +4 -3
  595. package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +2 -0
  596. package/pipeline/skills/shared/external/tailwind-css/SKILL.md +3 -2
  597. package/pipeline/skills/shared/external/testing-backend/SKILL.md +3 -2
  598. package/pipeline/skills/shared/external/tipkit/SKILL.md +2 -0
  599. package/pipeline/skills/shared/external/typescript-patterns/SKILL.md +3 -2
  600. package/pipeline/skills/shared/external/vision-framework/SKILL.md +2 -0
  601. package/pipeline/skills/shared/external/vue-composition/SKILL.md +3 -2
  602. package/pipeline/skills/shared/external/weatherkit/SKILL.md +2 -0
  603. package/pipeline/skills/shared/external/web-accessibility/SKILL.md +3 -2
  604. package/pipeline/skills/shared/external/web-performance/SKILL.md +3 -2
  605. package/pipeline/skills/shared/external/web-testing/SKILL.md +3 -2
  606. package/pipeline/skills/shared/external/widgetkit/SKILL.md +2 -0
  607. package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +1 -1
  608. package/pipeline/skills/shared/external/xcode-build-benchmark/SKILL.md +2 -0
  609. package/pipeline/skills/shared/external/xcode-build-fixer/SKILL.md +2 -0
  610. package/pipeline/skills/shared/external/xcode-build-orchestrator/SKILL.md +2 -0
  611. package/pipeline/skills/shared/external/xcode-compilation-analyzer/SKILL.md +2 -0
  612. package/pipeline/skills/shared/external/xcode-project-analyzer/SKILL.md +2 -0
  613. package/pipeline/skills/skills-index.md +40 -41
  614. package/docs/token-budget-history.md +0 -24
  615. package/pipeline/skills/shared/external/agentflow/SKILL.md +0 -199
  616. package/pipeline/skills/shared/external/android-ui-verification/SKILL.md +0 -66
  617. package/pipeline/skills/shared/external/api-security-best-practices/references/auth.md +0 -299
  618. package/pipeline/skills/shared/external/api-security-best-practices/references/input-validation.md +0 -255
  619. package/pipeline/skills/shared/external/api-security-best-practices/references/rate-limiting.md +0 -167
  620. package/pipeline/skills/shared/external/closed-loop-delivery/SKILL.md +0 -116
  621. package/pipeline/skills/shared/external/ios-developer/SKILL.md +0 -216
@@ -0,0 +1,403 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * review-decision-gate.mjs - a blocking finding needs more than one model's
4
+ * opinion before it stops an autopilot run.
5
+ *
6
+ * Every reviewer on Claude Code is a Claude model, so a panel shares its blind
7
+ * spots and a single reviewer's blocker is a judgement nobody independent has
8
+ * checked. With the quality gates active (lib/unattended.mjs, gatesActive), an
9
+ * `accepted[]` finding of severity `blocking` keeps that severity only when:
10
+ *
11
+ * corroborated at least two independent reviewer outputs of the iteration
12
+ * carry a blocking finding that is the same finding (below);
13
+ * failing-test its `verification` (Step 3.7, verify-by-test) is
14
+ * `confirmed` and `evidencePath` is a non-empty log inside the
15
+ * checkout that shows a failing test and no pass;
16
+ * test-integrity it is the finding test-integrity-gate.mjs produced for that
17
+ * file, which is a command's output and not a model's.
18
+ *
19
+ * Anything else is lowered to `important`, stays in `accepted[]` (triage judged
20
+ * it real and in scope, so the rework still fixes it) and is listed with its
21
+ * reason in the report and in the ledger entry. `approved` is recomputed.
22
+ *
23
+ * The same finding: the same file (diff prefixes stripped) and either the same
24
+ * fingerprint (finding-fingerprint.mjs: file plus ruleId, else file plus the
25
+ * normalized issue text) or cited lines at most LINE_WINDOW apart, where a
26
+ * whole-file finding (line 0) matches by fingerprint only and two findings
27
+ * citing different ruleIds or different CWEs never match. Independence is one
28
+ * entry of `state.reviewIterations[i].reviewers[]` (or one `--source` file):
29
+ * a separate dispatch that saw the diff and not the other outputs.
30
+ *
31
+ * Step 2.5, the rebuttal round, shows each reviewer the others' findings and
32
+ * replaces its output, which is how reviewers converge on each other. With the
33
+ * gates active a reviewer entry with `roundCount` above 1 fails the gate (exit
34
+ * 1, nothing rewritten); `--rebuttal-allowed` is the check Step 2.5 runs before
35
+ * dispatching the round.
36
+ *
37
+ * The verdict is recorded as `review-decision` through gate-ledger.mjs. With
38
+ * the gates off the decisions are printed marked advisory, the exit is 0 and
39
+ * neither the triage file nor the state is written.
40
+ *
41
+ * Usage:
42
+ * review-decision-gate.mjs <triage.json> [--state <agent-state.json>] [--iteration <n>]
43
+ * [--source <reviewer-output.json>]... [--integrity <test-integrity.json>]
44
+ * [--repo <dir>] [--dry-run] [--json]
45
+ * review-decision-gate.mjs --rebuttal-allowed [--state <agent-state.json>] [--json]
46
+ *
47
+ * Exit (gates active): 0 decided · 1 a rebuttal round ran, or --rebuttal-allowed refused ·
48
+ * 2 usage · 3 unreadable input, or an accepted blocker with no reviewer record (an empty
49
+ * `reviewers: []` is no record). A missing or empty --integrity file is no findings,
50
+ * and a missing or empty --source is an audit that did not run.
51
+ * Attended: 0, and 2 on a usage error.
52
+ *
53
+ * @module pipeline/scripts/review-decision-gate
54
+ */
55
+
56
+ import { existsSync, readFileSync, realpathSync, statSync, writeFileSync } from "node:fs";
57
+ import { isAbsolute, join, relative, resolve } from "node:path";
58
+
59
+ import { invokedDirectly } from "../lib/invoked-directly.mjs";
60
+ import { findingFingerprint, FINGERPRINT_RE, normalizeFile } from "./_fingerprint.mjs";
61
+ import { compileMarkers, getAdapter, resolveStack } from "./_stack-adapter.mjs";
62
+ import { gateContext, recordQuietly } from "./gate-ledger.mjs";
63
+ import { summarize } from "./test-summary.mjs";
64
+
65
+ export const GATE = "review-decision";
66
+ export const LINE_WINDOW = 3;
67
+ const FAILURE_MARKER = /\bFAILED\b|✗|\b[1-9][0-9]*\s+(?:failures?|failing|failed)\b/;
68
+
69
+ function fingerprintOf(f) {
70
+ return typeof f?.fingerprint === "string" && FINGERPRINT_RE.test(f.fingerprint)
71
+ ? f.fingerprint
72
+ : findingFingerprint(f);
73
+ }
74
+
75
+ function category(f) {
76
+ if (typeof f?.ruleId === "string" && f.ruleId.trim()) return `rule:${f.ruleId.trim()}`;
77
+ if (typeof f?.security?.cwe === "string") return `cwe:${f.security.cwe}`;
78
+ return null;
79
+ }
80
+
81
+ /**
82
+ * @param {object} a
83
+ * @param {object} b
84
+ * @returns {boolean}
85
+ */
86
+ export function sameFinding(a, b) {
87
+ if (normalizeFile(a?.file) !== normalizeFile(b?.file)) return false;
88
+ if (fingerprintOf(a) === fingerprintOf(b)) return true;
89
+ const ca = category(a);
90
+ const cb = category(b);
91
+ if (ca && cb && ca !== cb) return false;
92
+ const la = Number.isInteger(a?.line) ? a.line : 0;
93
+ const lb = Number.isInteger(b?.line) ? b.line : 0;
94
+ return la > 0 && lb > 0 && Math.abs(la - lb) <= LINE_WINDOW;
95
+ }
96
+
97
+ function real(p) {
98
+ try {
99
+ return realpathSync(p);
100
+ } catch {
101
+ return resolve(p);
102
+ }
103
+ }
104
+
105
+ function failureMarkers(root) {
106
+ const list = [FAILURE_MARKER];
107
+ try {
108
+ for (const { id } of resolveStack(root).adapters) {
109
+ const m = compileMarkers(getAdapter(id), "test");
110
+ if (m) list.push(...m.failure);
111
+ }
112
+ } catch {
113
+ // An unreadable adapter file leaves the generic marker.
114
+ }
115
+ return list;
116
+ }
117
+
118
+ /**
119
+ * Does the log at `path` show a failing test?
120
+ *
121
+ * @param {string} path relative to `root`, or absolute inside it
122
+ * @param {string} root the checkout
123
+ * @returns {{ok: boolean, reason: string}}
124
+ */
125
+ export function evidenceFromLog(path, root) {
126
+ if (typeof path !== "string" || !path.trim()) {
127
+ return { ok: false, reason: "no evidencePath recorded" };
128
+ }
129
+ const abs = isAbsolute(path) ? path : join(root, path);
130
+ if (!existsSync(abs)) return { ok: false, reason: `evidence log ${path} does not exist` };
131
+ const rel = relative(real(root), real(abs));
132
+ if (rel.startsWith("..") || isAbsolute(rel)) {
133
+ return { ok: false, reason: `evidence log ${path} is outside the checkout` };
134
+ }
135
+ let body;
136
+ try {
137
+ if (statSync(abs).size === 0) return { ok: false, reason: `evidence log ${path} is empty` };
138
+ body = readFileSync(abs, "utf8");
139
+ } catch (err) {
140
+ return { ok: false, reason: `evidence log ${path} is unreadable: ${err.message}` };
141
+ }
142
+ if (!body.trim()) return { ok: false, reason: `evidence log ${path} is empty` };
143
+ const summary = summarize(body, { source: path });
144
+ if (summary.status === "failed") {
145
+ return { ok: true, reason: `${path}: ${summary.failed} failed of ${summary.executed}` };
146
+ }
147
+ if (summary.status === "passed") {
148
+ return { ok: false, reason: `evidence log ${path} shows a pass (${summary.executed} passed)` };
149
+ }
150
+ if (summary.status === "no-tests") {
151
+ return { ok: false, reason: `evidence log ${path} shows no test executed` };
152
+ }
153
+ if (failureMarkers(root).some((re) => re.test(body))) {
154
+ return { ok: true, reason: `${path}: failure marker, counts unparsed` };
155
+ }
156
+ return { ok: false, reason: `evidence log ${path} shows no failing test` };
157
+ }
158
+
159
+ function blockingOf(output) {
160
+ const list = Array.isArray(output?.findings) ? output.findings : [];
161
+ return list.filter((f) => f && typeof f === "object" && f.severity === "blocking");
162
+ }
163
+
164
+ /**
165
+ * Did a rebuttal round replace any reviewer output?
166
+ * @param {object[]} reviewers
167
+ */
168
+ export function rebuttalRecorded(reviewers) {
169
+ return (Array.isArray(reviewers) ? reviewers : []).some(
170
+ (r) => Number.isInteger(r?.roundCount) && r.roundCount > 1,
171
+ );
172
+ }
173
+
174
+ /**
175
+ * Apply the decision rule. Pure: the input is not mutated.
176
+ *
177
+ * @param {{triage: object, reviewers: object[], integrity?: object[], root: string}} input
178
+ * @returns {{triage: object, kept: object[], downgraded: object[]}}
179
+ */
180
+ export function decide({ triage, reviewers, integrity = [], root }) {
181
+ const next = structuredClone(triage);
182
+ const sources = (Array.isArray(reviewers) ? reviewers : []).map(blockingOf);
183
+ const gateFindings = (Array.isArray(integrity) ? integrity : []).filter(
184
+ (f) => f && f.tag === "test_integrity",
185
+ );
186
+ const kept = [];
187
+ const downgraded = [];
188
+ for (const f of Array.isArray(next.accepted) ? next.accepted : []) {
189
+ if (!f || f.severity !== "blocking") continue;
190
+ const id = {
191
+ fingerprint: fingerprintOf(f),
192
+ file: f.file,
193
+ line: f.line,
194
+ issue: f.issue,
195
+ };
196
+ const count = sources.filter((list) => list.some((raw) => sameFinding(f, raw))).length;
197
+ if (count >= 2) {
198
+ kept.push({ ...id, basis: "corroborated", sources: count });
199
+ continue;
200
+ }
201
+ if (gateFindings.some((g) => normalizeFile(g.file) === normalizeFile(f.file))) {
202
+ kept.push({ ...id, basis: "test-integrity", sources: count });
203
+ continue;
204
+ }
205
+ const v = f.verification;
206
+ let evidence = null;
207
+ if (v && v.result === "confirmed") {
208
+ evidence = evidenceFromLog(v.evidencePath, root);
209
+ if (evidence.ok) {
210
+ kept.push({ ...id, basis: "failing-test", sources: count, evidence: evidence.reason });
211
+ continue;
212
+ }
213
+ }
214
+ const why = [
215
+ `raised by ${count} reviewer${count === 1 ? "" : "s"}, two needed`,
216
+ evidence
217
+ ? `verify-by-test evidence rejected: ${evidence.reason}`
218
+ : "no failing test recorded (verify-by-test)",
219
+ ].join("; ");
220
+ f.severity = "important";
221
+ downgraded.push({ ...id, sources: count, reason: `lowered to important: ${why}` });
222
+ }
223
+ next.approved = !(next.accepted || []).some((f) => f?.severity === "blocking");
224
+ return { triage: next, kept, downgraded };
225
+ }
226
+
227
+ // ---------------------------------------------------------------------------
228
+ // CLI
229
+
230
+ function readJson(p, what) {
231
+ try {
232
+ return JSON.parse(readFileSync(p, "utf8"));
233
+ } catch (err) {
234
+ throw new Error(`cannot read ${what} ${p}: ${err.message}`, { cause: err });
235
+ }
236
+ }
237
+
238
+ /**
239
+ * Step 1.76's findings. No flag, no file or an empty file is the gate's own
240
+ * "no findings" output; a file with content that is not JSON is unreadable.
241
+ */
242
+ function readIntegrity(p) {
243
+ if (!p || !existsSync(p)) return [];
244
+ let body;
245
+ try {
246
+ body = readFileSync(p, "utf8");
247
+ } catch (err) {
248
+ throw new Error(`cannot read test-integrity output ${p}: ${err.message}`, { cause: err });
249
+ }
250
+ if (!body.trim()) return [];
251
+ try {
252
+ const doc = JSON.parse(body);
253
+ return Array.isArray(doc?.findings) ? doc.findings : [];
254
+ } catch (err) {
255
+ throw new Error(`cannot read test-integrity output ${p}: ${err.message}`, { cause: err });
256
+ }
257
+ }
258
+
259
+ function parse(argv) {
260
+ const opts = { source: [], json: false, dryRun: false, rebuttalAllowed: false, triage: null };
261
+ const single = new Set(["--state", "--iteration", "--integrity", "--repo"]);
262
+ for (let i = 0; i < argv.length; i++) {
263
+ const a = argv[i];
264
+ if (a === "--json") opts.json = true;
265
+ else if (a === "--dry-run") opts.dryRun = true;
266
+ else if (a === "--rebuttal-allowed") opts.rebuttalAllowed = true;
267
+ else if (a === "--source" || single.has(a)) {
268
+ const v = argv[++i];
269
+ if (v === undefined) throw new Error(`${a} needs a value`);
270
+ if (a === "--source") opts.source.push(v);
271
+ else opts[a.slice(2)] = v;
272
+ } else if (a.startsWith("--")) throw new Error(`unexpected argument ${a}`);
273
+ else if (opts.triage) throw new Error(`one triage file only, got ${a} too`);
274
+ else opts.triage = a;
275
+ }
276
+ if (!opts.rebuttalAllowed && !opts.triage) throw new Error("a triage file is required");
277
+ if (opts.iteration !== undefined && !/^[1-9][0-9]*$/.test(opts.iteration)) {
278
+ throw new Error("--iteration must be a positive integer");
279
+ }
280
+ return opts;
281
+ }
282
+
283
+ function reviewerRecord(opts, state) {
284
+ const iterations = Array.isArray(state?.reviewIterations) ? state.reviewIterations : [];
285
+ const at = opts.iteration ? Number(opts.iteration) - 1 : iterations.length - 1;
286
+ const fromState = Array.isArray(iterations[at]?.reviewers) ? iterations[at].reviewers : [];
287
+ const extra = opts.source
288
+ .filter((p) => existsSync(p) && readFileSync(p, "utf8").trim())
289
+ .map((p) => readJson(p, "reviewer output"));
290
+ const all = [...fromState, ...extra];
291
+ return all.length ? all : null;
292
+ }
293
+
294
+ function emit(json, result, stream) {
295
+ if (json) {
296
+ writeFileSync(1, `${JSON.stringify(result, null, 2)}\n`);
297
+ return;
298
+ }
299
+ const lines = [
300
+ `${GATE}${result.advisory ? " (advisory, the quality gates are off)" : ""}: ${result.summary}`,
301
+ ];
302
+ for (const d of result.downgraded || []) lines.push(` ${d.file}:${d.line} ${d.reason}`);
303
+ writeFileSync(stream, `${lines.join("\n")}\n`);
304
+ }
305
+
306
+ async function main(argv) {
307
+ let opts;
308
+ try {
309
+ opts = parse(argv);
310
+ } catch (err) {
311
+ process.stderr.write(`review-decision-gate: ${err.message}\n`);
312
+ return 2;
313
+ }
314
+ const ctx = gateContext({ statePath: opts.state || null, repo: opts.repo || process.cwd() });
315
+ const advisory = !ctx.active;
316
+
317
+ if (opts.rebuttalAllowed) {
318
+ if (advisory) {
319
+ if (opts.json) writeFileSync(1, `${JSON.stringify({ rebuttalAllowed: true })}\n`);
320
+ return 0;
321
+ }
322
+ const why =
323
+ "the quality gates are active: reviewers stay blind to each other, Step 2.5 does not run";
324
+ if (opts.json) writeFileSync(1, `${JSON.stringify({ rebuttalAllowed: false, reason: why })}\n`);
325
+ else writeFileSync(1, `rebuttal round: off (${why})\n`);
326
+ return 1;
327
+ }
328
+
329
+ const state = ctx.state;
330
+ const worktree =
331
+ typeof state?.worktreePath === "string" && existsSync(state.worktreePath)
332
+ ? state.worktreePath
333
+ : null;
334
+ const root = opts.repo || worktree || process.cwd();
335
+
336
+ let result;
337
+ let decided = null;
338
+ try {
339
+ const triage = readJson(opts.triage, "the triage output");
340
+ if (!triage || typeof triage !== "object" || !Array.isArray(triage.accepted)) {
341
+ throw new Error(`${opts.triage} is not a triage output (no accepted[])`);
342
+ }
343
+ const reviewers = reviewerRecord(opts, state);
344
+ const integrity = readIntegrity(opts.integrity);
345
+ if (rebuttalRecorded(reviewers)) {
346
+ result = {
347
+ gate: GATE,
348
+ verdict: "rebuttal-round",
349
+ summary:
350
+ "a Step 2.5 rebuttal round replaced reviewer output; with the quality gates active reviewers stay blind to each other",
351
+ };
352
+ } else {
353
+ const blockers = triage.accepted.filter((f) => f?.severity === "blocking");
354
+ if (blockers.length && !reviewers) {
355
+ throw new Error(
356
+ "no reviewer record for this iteration (state.reviewIterations[].reviewers or --source), so no blocker can be checked for corroboration",
357
+ );
358
+ }
359
+ decided = decide({ triage, reviewers: reviewers || [], integrity, root });
360
+ result = {
361
+ gate: GATE,
362
+ verdict: "pass",
363
+ summary: `${blockers.length} blocking finding(s): ${decided.kept.length} kept, ${decided.downgraded.length} lowered to important`,
364
+ approved: decided.triage.approved,
365
+ kept: decided.kept,
366
+ downgraded: decided.downgraded,
367
+ };
368
+ }
369
+ } catch (err) {
370
+ result = { gate: GATE, verdict: "unreadable", summary: err.message };
371
+ }
372
+
373
+ if (advisory) {
374
+ emit(opts.json, { ...result, advisory: true }, 1);
375
+ return 0;
376
+ }
377
+
378
+ if (decided && !opts.dryRun)
379
+ writeFileSync(opts.triage, `${JSON.stringify(decided.triage, null, 2)}\n`);
380
+ const detail =
381
+ result.verdict === "pass"
382
+ ? {
383
+ kept: result.kept.length,
384
+ downgraded: result.downgraded.map(({ fingerprint, file, line, reason }) => ({
385
+ fingerprint,
386
+ file,
387
+ line,
388
+ reason,
389
+ })),
390
+ }
391
+ : { verdict: result.verdict, reason: result.summary };
392
+ await recordQuietly(GATE, result.verdict === "pass" ? "pass" : "fail", detail, {
393
+ repo: existsSync(root) ? root : null,
394
+ statePath: ctx.statePath,
395
+ });
396
+ emit(opts.json, result, result.verdict === "pass" ? 1 : 2);
397
+ if (result.verdict === "pass") return 0;
398
+ return result.verdict === "rebuttal-round" ? 1 : 3;
399
+ }
400
+
401
+ if (invokedDirectly(import.meta.url)) {
402
+ main(process.argv.slice(2)).then((code) => process.exit(code));
403
+ }
@@ -28,6 +28,7 @@
28
28
  import { existsSync, readFileSync, writeFileSync, mkdirSync, rmSync, renameSync } from "node:fs";
29
29
  import { join, dirname } from "node:path";
30
30
  import { runMain } from "../lib/fatal.mjs";
31
+ import { hostCommand } from "../lib/user-facing.mjs";
31
32
 
32
33
  const NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
33
34
  const MAX_NAME = 40;
@@ -59,7 +60,7 @@ function fail(msg) {
59
60
  }
60
61
 
61
62
  function homeDir(args) {
62
- return args.home || process.env.HOME || process.env.USERPROFILE || "";
63
+ return args.home || process.env.HOME || "";
63
64
  }
64
65
  function prefsPath(home) {
65
66
  return join(home, ".claude", "multi-agent-preferences.json");
@@ -174,7 +175,9 @@ function cmdAdd(home, args) {
174
175
  prefs.global.routines = routines;
175
176
  writePrefs(home, prefs);
176
177
  console.log(`routine-registry: saved "${name}" -> ${join(dir, "SKILL.md")}`);
177
- console.log("routine-registry: available as /multi-agent:" + name + " after a session reload");
178
+ console.log(
179
+ `routine-registry: available as ${hostCommand(name, import.meta.dirname)} after a session reload`,
180
+ );
178
181
  }
179
182
 
180
183
  function cmdRemove(home, name) {
@@ -22,9 +22,16 @@
22
22
  *
23
23
  * Read-only. Never writes, never migrates, never deletes.
24
24
  *
25
+ * The JSON is a contract (pipeline/schemas/runs-index.schema.json). Fields are
26
+ * only ever added: `subs` stays the count a reader already decodes, and the
27
+ * sub-steps themselves are `subList`. `--redact` drops every field the schema
28
+ * marks `x-sensitivity: local` - paths and the PR URL - and scrubs the free
29
+ * text a phase wrote into `now`, sub-step names and a pending question.
30
+ *
25
31
  * Usage:
26
32
  * node runs-index.mjs # human table, grouped
27
33
  * node runs-index.mjs --json # the same records as JSON
34
+ * node runs-index.mjs --json --redact # without the fields specific to this machine
28
35
  * node runs-index.mjs --group waiting # one group only
29
36
  * node runs-index.mjs --task-id <id> # one run
30
37
  *
@@ -36,8 +43,10 @@
36
43
  */
37
44
 
38
45
  import { existsSync, readFileSync } from "node:fs";
46
+ import { readRegularFile } from "../lib/regular-file.mjs";
39
47
  import { join } from "node:path";
40
48
  import { costUsd } from "./_cost.mjs";
49
+ import { omit, scrub } from "./_redact.mjs";
41
50
  import { listRuns, logsRoot, resolveRunDir, taskIdVariants } from "./_run-paths.mjs";
42
51
  import { runMain } from "../lib/fatal.mjs";
43
52
  import { invokedDirectly } from "../lib/invoked-directly.mjs";
@@ -48,9 +57,24 @@ import { invokedDirectly } from "../lib/invoked-directly.mjs";
48
57
  * under an eight-phase contract, 4 under six), so a literal would survive a
49
58
  * renumbering unchanged and silently regroup every run.
50
59
  */
51
- const PHASE_WAITING_FROM = JSON.parse(
60
+ const PHASE_CONTRACT = JSON.parse(
52
61
  readFileSync(new URL("../schemas/phases.json", import.meta.url), "utf8"),
53
- ).thresholds.waitingFromPhase;
62
+ );
63
+ const PHASE_WAITING_FROM = PHASE_CONTRACT.thresholds.waitingFromPhase;
64
+
65
+ /**
66
+ * The last phase id, so the Phase column reads "current/last" in the same
67
+ * numbering the run records use. Phases are numbered from 0, so this is one
68
+ * less than the phase count.
69
+ */
70
+ const LAST_PHASE = PHASE_CONTRACT.phases[PHASE_CONTRACT.phases.length - 1].id;
71
+
72
+ export const CONTRACT_VERSION = "1.1.0";
73
+
74
+ const STATE_MAX_BYTES = 16 * 1024 * 1024;
75
+
76
+ /** The run fields runs-index.schema.json marks x-sensitivity local. */
77
+ export const LOCAL_RUN_FIELDS = ["dir", "worktreePath", "prUrl", "duplicateOf"];
54
78
 
55
79
  const GROUPS = {
56
80
  waiting: "Waiting on you",
@@ -60,10 +84,11 @@ const GROUPS = {
60
84
  };
61
85
 
62
86
  function parseArgs(argv) {
63
- const flags = { json: false, group: null, taskId: null };
87
+ const flags = { json: false, redact: false, group: null, taskId: null };
64
88
  for (let i = 0; i < argv.length; i++) {
65
89
  const a = argv[i];
66
90
  if (a === "--json") flags.json = true;
91
+ else if (a === "--redact") flags.redact = true;
67
92
  else if (a === "--group") flags.group = argv[++i];
68
93
  else if (a.startsWith("--group=")) flags.group = a.slice(8);
69
94
  else if (a === "--task-id") flags.taskId = argv[++i];
@@ -84,9 +109,9 @@ function parseArgs(argv) {
84
109
  }
85
110
 
86
111
  function readJson(path) {
87
- if (!path || !existsSync(path)) return null;
112
+ if (!path) return null;
88
113
  try {
89
- return JSON.parse(readFileSync(path, "utf-8"));
114
+ return JSON.parse(readRegularFile(path, { maxBytes: STATE_MAX_BYTES }));
90
115
  } catch {
91
116
  // A truncated state file is a fact about the run, not a reason to refuse
92
117
  // the whole index. It surfaces as `stateReadable: false`.
@@ -134,10 +159,12 @@ function summarisePhases(tracker) {
134
159
  let usd = 0;
135
160
  const rows = phases.map((p) => {
136
161
  // phase-tracker.sh writes flat `tokens_in` / `tokens_out` / `tokens_cached`
137
- // on each phase, not a nested `tokens` object.
138
- const tin = Number(p.tokens_in ?? 0) || 0;
139
- const tout = Number(p.tokens_out ?? 0) || 0;
140
- const tcached = Number(p.tokens_cached ?? 0) || 0;
162
+ // on each phase, not a nested `tokens` object. Token counts are whole
163
+ // numbers in the contract, so a fractional value a writer produced is
164
+ // rounded here rather than handed to a decoder that reads an integer.
165
+ const tin = Math.round(Number(p.tokens_in ?? 0) || 0);
166
+ const tout = Math.round(Number(p.tokens_out ?? 0) || 0);
167
+ const tcached = Math.round(Number(p.tokens_cached ?? 0) || 0);
141
168
  tokensIn += tin;
142
169
  tokensOut += tout;
143
170
  tokensCached += tcached;
@@ -152,6 +179,13 @@ function summarisePhases(tracker) {
152
179
  completedAt: p.completed_at ?? null,
153
180
  now: p.now ?? null,
154
181
  subs: Array.isArray(p.subs) ? p.subs.length : 0,
182
+ subList: Array.isArray(p.subs)
183
+ ? p.subs.map((sub) => ({
184
+ id: String(sub?.id ?? ""),
185
+ name: sub?.name ?? "",
186
+ status: sub?.status ?? "pending",
187
+ }))
188
+ : [],
155
189
  };
156
190
  });
157
191
  return {
@@ -175,12 +209,37 @@ function groupOf(state) {
175
209
  const prUrl = state?.pr?.url ?? state?.prUrl ?? null;
176
210
  if (status === "awaiting_input" || status === "awaiting-user-test-main-checkout")
177
211
  return "waiting";
212
+ // A paused run names the step it re-enters. It is waiting on a person at any
213
+ // phase, and at phase 0 it must not read as a run left at intake, which the
214
+ // question group offers to garbage-collect.
215
+ if (state?.waitingFor) return "waiting";
178
216
  if (prUrl) return "waiting";
179
217
  if (Number.isFinite(phase) && phase >= PHASE_WAITING_FROM) return "waiting";
180
218
  if (Number.isFinite(phase) && phase === 0) return "question";
181
219
  return "stopped";
182
220
  }
183
221
 
222
+ /**
223
+ * The question a run stopped on, in the shape answer-question.mjs accepts an
224
+ * answer to, or null. Only a run with `waitingFor: "question"` has one: a stale
225
+ * record left beside another pause is not a question anyone can answer.
226
+ *
227
+ * @param {object|null} state
228
+ */
229
+ function questionOf(state) {
230
+ const q = state?.pendingQuestion;
231
+ if (state?.waitingFor !== "question" || !q || typeof q !== "object") return null;
232
+ return {
233
+ id: String(q.id ?? ""),
234
+ stepId: String(q.stepId ?? ""),
235
+ text: String(q.text ?? ""),
236
+ kind: q.kind === "multi-select" ? "multi-select" : "single-select",
237
+ options: Array.isArray(q.options)
238
+ ? q.options.map((o) => ({ id: String(o?.id ?? ""), label: String(o?.label ?? "") }))
239
+ : [],
240
+ };
241
+ }
242
+
184
243
  /**
185
244
  * Every run, enriched, in one stable order.
186
245
  *
@@ -229,8 +288,13 @@ export function buildIndex() {
229
288
  worktreePath: state?.worktreePath ?? null,
230
289
  prUrl,
231
290
  autopilot: Boolean(state?.autopilot),
232
- schemaVersion: state?.schemaVersion ?? null,
291
+ // agent-state.schema.json declares a string; a number a hand-edited
292
+ // state carries is printed as its string so the field keeps one type.
293
+ schemaVersion: state?.schemaVersion == null ? null : String(state.schemaVersion),
233
294
  rev: Number.isInteger(state?.rev) ? state.rev : null,
295
+ sessionId: typeof state?.sessionId === "string" ? state.sessionId : null,
296
+ waitingFor: typeof state?.waitingFor === "string" ? state.waitingFor : null,
297
+ pendingQuestion: questionOf(state),
234
298
  group: groupOf(state),
235
299
  phases: phases.phases,
236
300
  tokens: phases.tokens,
@@ -278,7 +342,7 @@ function renderHuman(records) {
278
342
  " ID Phase Status Branch Age ~USD",
279
343
  );
280
344
  for (const r of rows) {
281
- const phase = r.currentPhase === null ? " -" : `${r.currentPhase}/7`;
345
+ const phase = r.currentPhase === null ? " -" : `${r.currentPhase}/${LAST_PHASE}`;
282
346
  out.push(
283
347
  " " +
284
348
  [
@@ -306,34 +370,78 @@ function renderHuman(records) {
306
370
  return out.join("\n");
307
371
  }
308
372
 
373
+ /**
374
+ * The --json envelope. Redaction is applied here, after grouping and
375
+ * filtering, so a redacted index and a full one list the same runs.
376
+ */
377
+ export function envelope(records, { redact = false } = {}) {
378
+ const runs = redact
379
+ ? records.map((r) => ({
380
+ ...omit(r, LOCAL_RUN_FIELDS),
381
+ pendingQuestion: r.pendingQuestion && {
382
+ ...r.pendingQuestion,
383
+ text: scrub(r.pendingQuestion.text),
384
+ options: r.pendingQuestion.options.map((o) => ({ ...o, label: scrub(o.label) })),
385
+ },
386
+ phases: r.phases.map((p) => ({
387
+ ...p,
388
+ name: scrub(p.name),
389
+ now: p.now === null ? null : scrub(p.now),
390
+ subList: p.subList.map((sub) => ({ ...sub, name: scrub(sub.name) })),
391
+ })),
392
+ }))
393
+ : records;
394
+ const out = { contractVersion: CONTRACT_VERSION };
395
+ if (!redact) out.logsRoot = logsRoot();
396
+ out.count = runs.length;
397
+ out.runs = runs;
398
+ return out;
399
+ }
400
+
401
+ /** The group names --group accepts. */
402
+ export const GROUP_NAMES = Object.keys(GROUPS);
403
+
404
+ /**
405
+ * The records one invocation selects: every run, one task id, or one group.
406
+ * `found` is false only when a task id was asked for and no run carries it.
407
+ * The CLI and contract-server.mjs both call this, so a filter means the same
408
+ * thing on either carrier.
409
+ *
410
+ * @param {{taskId?: string|null, group?: string|null}} [opts]
411
+ * @returns {{found: boolean, records: object[]}}
412
+ */
413
+ export function selectRuns({ taskId = null, group = null } = {}) {
414
+ let records = buildIndex();
415
+ if (taskId) {
416
+ const wanted = new Set(taskIdVariants(taskId));
417
+ records = records.filter((r) => wanted.has(r.taskId));
418
+ if (!records.length) return { found: false, records };
419
+ }
420
+ if (group) records = records.filter((r) => r.group === group);
421
+ return { found: true, records };
422
+ }
423
+
309
424
  function main() {
310
425
  const flags = parseArgs(process.argv.slice(2));
311
426
  if (flags.help) {
312
427
  process.stdout.write(
313
- "Usage: runs-index.mjs [--json] [--group waiting|stopped|question|unknown] [--task-id <id>]\n",
428
+ "Usage: runs-index.mjs [--json [--redact]] [--group waiting|stopped|question|unknown] [--task-id <id>]\n",
314
429
  );
315
430
  return 0;
316
431
  }
317
432
 
318
- let records = buildIndex();
319
-
320
- if (flags.taskId) {
321
- const wanted = new Set(taskIdVariants(flags.taskId));
322
- records = records.filter((r) => wanted.has(r.taskId));
323
- if (!records.length) {
324
- const dir = resolveRunDir(flags.taskId);
325
- process.stderr.write(
326
- `runs-index: no run for ${flags.taskId}${dir ? ` (directory ${dir} has no markers)` : ""}\n`,
327
- );
328
- return 0;
329
- }
433
+ const { found, records } = selectRuns(flags);
434
+ if (!found) {
435
+ const dir = resolveRunDir(flags.taskId);
436
+ process.stderr.write(
437
+ `runs-index: no run for ${flags.taskId}${dir ? ` (directory ${dir} has no markers)` : ""}\n`,
438
+ );
439
+ return 0;
330
440
  }
331
- if (flags.group) records = records.filter((r) => r.group === flags.group);
332
441
 
333
442
  if (flags.json) {
334
443
  process.stdout.write(
335
- JSON.stringify({ logsRoot: logsRoot(), count: records.length, runs: records }, null, 2) +
336
- "\n",
444
+ JSON.stringify(envelope(records, { redact: flags.redact }), null, 2) + "\n",
337
445
  );
338
446
  } else {
339
447
  process.stdout.write(renderHuman(records) + "\n");