@mmerterden/multi-agent-pipeline 20.2.0 → 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 +923 -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 -31
  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 +82 -7
  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 -63
  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
@@ -2,18 +2,41 @@
2
2
  """Decision core for agent-guard.sh (see that file for the hook contract).
3
3
 
4
4
  Reads the PreToolUse payload JSON on stdin and prints exactly one decision:
5
- BLOCK_ATTRIB | BLOCK_FORCE | OK
5
+ BLOCK_ATTRIB | BLOCK_FORCE | BLOCK_UNATTENDED<TAB>reason | BLOCK_PARSE | OK
6
6
 
7
7
  Never executes the command. shlex.split only tokenizes shell-like text; a
8
- `$(...)` in the command is a literal token, never a subshell. Any error prints
9
- OK (fail-open) so a guard bug cannot break a legitimate tool call.
8
+ `$(...)` in the command is a literal token, never a subshell. The processes it
9
+ does start are read-only `git rev-parse` / `git diff --name-only` calls on a
10
+ path, with argv and no shell.
11
+
12
+ Attended (MULTI_AGENT_UNATTENDED unset): the attribution and force-push rules
13
+ only, and any error prints OK (fail-open) so a guard bug cannot break a
14
+ legitimate tool call. Unattended: unattended_policy.py is consulted as well,
15
+ and an error prints BLOCK_PARSE (fail-closed).
10
16
  """
11
17
  import json
12
18
  import os
13
19
  import re
14
20
  import shlex
21
+ import signal
15
22
  import sys
16
23
 
24
+ # An internal deadline well under the hook timeout: if the guard cannot decide
25
+ # in this long, it prints the blocking verdict when unattended (fail-closed) and
26
+ # the allow verdict when attended (a guard bug must not break legitimate work).
27
+ # MA_GUARD_DEADLINE_SECONDS may lower it, never raise it: a longer deadline
28
+ # would let the hook timeout decide instead of the guard.
29
+ DEADLINE_SECONDS = 5
30
+
31
+
32
+ def deadline_seconds(env=None) -> float:
33
+ env = os.environ if env is None else env
34
+ try:
35
+ v = float(env.get("MA_GUARD_DEADLINE_SECONDS", ""))
36
+ except ValueError:
37
+ return DEADLINE_SECONDS
38
+ return v if 0 < v < DEADLINE_SECONDS else DEADLINE_SECONDS
39
+
17
40
  # --- Rule data (extend here; this is the hookify-style rule surface) ----------
18
41
  PROTECTED = {"main", "master", "develop"}
19
42
  REMOTES = {"origin", "upstream"}
@@ -126,9 +149,80 @@ def segments(cmd: str) -> list:
126
149
  return [(seg, tokenize(seg)) for seg in SEPARATORS.split(cmd)]
127
150
 
128
151
 
129
- def decide(cmd: str) -> str:
152
+ # `git push` options that take the NEXT token as their value. Without this list
153
+ # `git push -f -o ci.skip origin` reads `ci.skip` as the repository and
154
+ # `origin` as a branch name, and the bare-push check never runs.
155
+ PUSH_VALUE_OPTIONS = {"-o", "--push-option", "--repo", "--receive-pack", "--exec"}
156
+ # Pushes that rewrite or remove every ref, protected ones included.
157
+ PUSH_ALL_REFS = {"--all", "--mirror", "--branches"}
158
+ PUSH_DELETE = {"-d", "--delete", "--prune"}
159
+ # Pushes that can remove or rewrite a protected ref with no force flag: a
160
+ # mirror (force + prune over every ref), a prune, a delete, and a refspec with
161
+ # an empty source (`:main`), which deletes its destination.
162
+ PUSH_GATE = re.compile(r"(^|\s)(-d|--delete|--mirror|--prune)(\s|=|$)|(^|\s)\+?:\S")
163
+ # A destination that names the branch the checkout is on.
164
+ CURRENT_BRANCH_REFS = {"HEAD", "@"}
165
+ SHORT_FORCE = re.compile(r"^-[A-Za-z]*f[A-Za-z]*$")
166
+
167
+
168
+ SHELLS = {"sh", "bash", "zsh", "dash", "ksh", "fish"}
169
+ MAX_DEPTH = 3
170
+
171
+
172
+ def flatten(cmd: str) -> str:
173
+ """cmd with every unquoted `(`, `)` and backtick turned into a separator,
174
+ so a command inside a subshell or a substitution is a segment of its own.
175
+ Like the separator split, this can only add segments."""
176
+ out, q, i = [], None, 0
177
+ while i < len(cmd):
178
+ c = cmd[i]
179
+ if q == "'":
180
+ q = None if c == "'" else q
181
+ elif c == "\\" and i + 1 < len(cmd):
182
+ out.append(cmd[i : i + 2])
183
+ i += 2
184
+ continue
185
+ elif q == '"':
186
+ q = None if c == '"' else q
187
+ elif c in ("'", '"'):
188
+ q = c
189
+ elif c in "()`":
190
+ out.append(" ; ")
191
+ i += 1
192
+ continue
193
+ out.append(c)
194
+ i += 1
195
+ return "".join(out)
196
+
197
+
198
+ def _nested_payload(toks: list):
199
+ """The command line a segment hands to another shell: the `-c` argument
200
+ of sh/bash/zsh (after any env assignments or wrappers), or the words of
201
+ `eval`. None when the segment runs no nested line."""
202
+ i = 0
203
+ while i < len(toks) and (re.match(r"^[A-Za-z_][A-Za-z0-9_]*=", toks[i]) or os.path.basename(toks[i]) in ("env", "nohup", "command", "builtin", "exec", "nice", "time")):
204
+ i += 1
205
+ if i >= len(toks):
206
+ return None
207
+ base = os.path.basename(toks[i]).lower()
208
+ if base == "eval":
209
+ return " ".join(toks[i + 1 :])
210
+ if base not in SHELLS:
211
+ return None
212
+ has_c = False
213
+ for t in toks[i + 1 :]:
214
+ if t.startswith("-") and not t.startswith("--"):
215
+ has_c = has_c or "c" in t[1:]
216
+ continue
217
+ if t.startswith("--"):
218
+ continue
219
+ return t if has_c else None
220
+ return None
221
+
222
+
223
+ def decide(cmd: str, depth: int = 0) -> str:
130
224
  low = cmd.lower()
131
- segs = segments(cmd)
225
+ segs = segments(flatten(cmd))
132
226
 
133
227
  # Rule 1: AI attribution inside a git commit.
134
228
  commits = re.search(r"git\s+commit", low) or any(
@@ -138,22 +232,124 @@ def decide(cmd: str) -> str:
138
232
  return "BLOCK_ATTRIB"
139
233
 
140
234
  # Rule 2: force-push to a protected branch. Evaluate each push segment on its
141
- # own so a neighbouring command's flags cannot implicate it.
235
+ # own so a neighbouring command's flags cannot implicate it. A `cd` earlier
236
+ # on the line moves the push into another checkout, whose branch is the one
237
+ # that counts.
238
+ cwd = None
142
239
  for seg, toks in segs:
240
+ if toks and toks[0] in ("{", "}"):
241
+ toks = toks[1:]
242
+ if toks and toks[0] in ("cd", "pushd"):
243
+ cwd = _cd_target(toks, cwd)
244
+ continue
245
+ payload = _nested_payload(toks)
246
+ if payload and depth < MAX_DEPTH:
247
+ verdict = decide(payload, depth + 1)
248
+ if verdict != "OK":
249
+ return verdict
250
+ continue
143
251
  if git_subcommand(toks) != "push" and not re.search(r"git\s+push", seg.lower()):
144
252
  continue
145
- verdict = _decide_push(seg)
253
+ verdict = _decide_push(seg, toks, cwd)
146
254
  if verdict != "OK":
147
255
  return verdict
148
256
 
149
257
  return "OK"
150
258
 
151
259
 
260
+ def _cd_target(toks: list, cwd):
261
+ """The directory a `cd` moves to, or "" when it cannot be read literally
262
+ (`cd`, `cd -`, `cd ~`, `cd "$X"`): a push after it is on an unknown branch.
263
+ Once unknown, a relative cd stays unknown; only an absolute one resolves."""
264
+ args = [t for t in toks[1:] if not t.startswith("-")]
265
+ if not args or any(ch in args[0] for ch in "$`~*?"):
266
+ return ""
267
+ if os.path.isabs(args[0]):
268
+ return os.path.normpath(args[0])
269
+ if cwd == "":
270
+ return ""
271
+ base = cwd if cwd else os.getcwd()
272
+ return os.path.normpath(os.path.join(base, args[0]))
273
+
274
+
275
+ def _branch_of(directory: str) -> str:
276
+ """The branch checked out in `directory`, read with the same read-only
277
+ `git rev-parse` the wrapper runs for the cwd. "" when it cannot be read."""
278
+ if not directory:
279
+ return ""
280
+ try:
281
+ import subprocess
282
+
283
+ out = subprocess.run(
284
+ ["git", "-C", directory, "rev-parse", "--abbrev-ref", "HEAD"],
285
+ capture_output=True,
286
+ text=True,
287
+ timeout=3,
288
+ )
289
+ return out.stdout.strip() if out.returncode == 0 else ""
290
+ except Exception:
291
+ return ""
292
+
293
+
294
+ def _parse_push(toks: list):
295
+ """(git_dir, options, positionals) for a tokenized `git ... push ...`.
296
+
297
+ git_dir is the directory named by `-C` / `--work-tree` / `--git-dir`, or
298
+ None. Values of options that take one are consumed, never read as a
299
+ repository or refspec.
300
+ """
301
+ git_dir, i = None, 0
302
+ while i < len(toks) and os.path.basename(toks[i]).lower() != "git":
303
+ i += 1
304
+ i += 1
305
+ while i < len(toks):
306
+ t = toks[i]
307
+ if t in ("-C", "--work-tree", "--git-dir"):
308
+ if i + 1 < len(toks):
309
+ val = toks[i + 1]
310
+ if t == "--git-dir":
311
+ val = os.path.dirname(val.rstrip("/")) or "."
312
+ git_dir = val if git_dir is None or os.path.isabs(val) else os.path.join(git_dir, val)
313
+ i += 2
314
+ continue
315
+ if t.startswith("--work-tree=") or t.startswith("--git-dir="):
316
+ key, _, val = t.partition("=")
317
+ if key == "--git-dir":
318
+ val = os.path.dirname(val.rstrip("/")) or "."
319
+ git_dir = val
320
+ i += 1
321
+ continue
322
+ if t in GIT_VALUE_OPTIONS:
323
+ i += 2
324
+ continue
325
+ if t.startswith("-"):
326
+ i += 1
327
+ continue
328
+ break
329
+ # toks[i] is the subcommand
330
+ opts, positionals = [], []
331
+ j = i + 1
332
+ while j < len(toks):
333
+ t = toks[j]
334
+ if t in PUSH_VALUE_OPTIONS:
335
+ opts.append((t, toks[j + 1] if j + 1 < len(toks) else ""))
336
+ j += 2
337
+ continue
338
+ if t.startswith("-"):
339
+ key, _, val = t.partition("=")
340
+ opts.append((key, val))
341
+ else:
342
+ positionals.append(t)
343
+ j += 1
344
+ return git_dir, opts, positionals
345
+
346
+
152
347
  def _ref_target(arg: str) -> tuple:
153
- """(forced, branch) for one push argument.
348
+ """(forced, branch) for one refspec.
154
349
 
155
350
  The destination is the part after the last `:`; a leading `+` on it is a
156
- force-push; `refs/heads/main` names the same branch as `main`.
351
+ force-push; `refs/heads/main` names the same branch as `main`. A refspec
352
+ with no `:` pushes to the branch of the same name.
157
353
  """
158
354
  dst = arg.rsplit(":", 1)[-1]
159
355
  forced = dst.startswith("+") or arg.startswith("+")
@@ -163,51 +359,166 @@ def _ref_target(arg: str) -> tuple:
163
359
  return forced, name
164
360
 
165
361
 
166
- def _decide_push(cmd: str) -> str:
167
- """Verdict for a single `git push ...` command."""
362
+ def _decide_push(cmd: str, toks=None, cwd=None) -> str:
363
+ """Verdict for a single `git push ...` command.
364
+
365
+ `git push [options] [<repository> [<refspec>...]]`: the first positional is
366
+ always the repository, whatever it is called; everything after it is a
367
+ refspec. A refspec of HEAD or @, or none at all, targets the branch that is
368
+ checked out in the directory the push runs in.
369
+ """
370
+ if toks is None:
371
+ toks = tokenize(cmd)
168
372
  force_flag = bool(FORCE.search(cmd))
169
- if not force_flag and not FORCED_REFSPEC.search(cmd):
373
+ if not force_flag and not FORCED_REFSPEC.search(cmd) and not PUSH_GATE.search(cmd):
170
374
  return "OK"
171
375
  try:
172
- toks = shlex.split(cmd)
376
+ shlex.split(cmd)
173
377
  except Exception:
174
378
  # A force-push we can't tokenize -> can't prove it's safe -> block.
175
379
  return "BLOCK_FORCE"
176
- # non-flag args after `push`; only a remote (or nothing) means a bare push
177
- args, seen = [], False
178
- for t in toks:
179
- if t == "push":
180
- seen = True
181
- continue
182
- if seen and not t.startswith("-"):
183
- args.append(t)
184
- targets = [_ref_target(a) for a in args]
380
+ git_dir, opts, positionals = _parse_push(toks)
381
+ keys = {k for k, _ in opts}
382
+ force_flag = any(
383
+ k in ("--force", "--force-with-lease", "--force-if-includes") or SHORT_FORCE.match(k) for k in keys
384
+ )
385
+ repo_opt = any(k == "--repo" for k in keys)
386
+ refspecs = positionals if repo_opt else positionals[1:]
387
+ if "--mirror" in keys:
388
+ return "BLOCK_FORCE"
389
+ deleting = bool(keys & PUSH_DELETE) or any(r.lstrip("+").startswith(":") for r in refspecs)
390
+
391
+ if git_dir is not None:
392
+ base = cwd if cwd else os.getcwd()
393
+ current = _branch_of(git_dir if os.path.isabs(git_dir) else os.path.join(base, git_dir))
394
+ elif cwd is not None:
395
+ current = _branch_of(cwd)
396
+ else:
397
+ current = os.environ.get("CUR_BRANCH", "")
398
+
399
+ targets = []
400
+ for ref in refspecs:
401
+ forced, name = _ref_target(ref)
402
+ if name in CURRENT_BRANCH_REFS:
403
+ name = current or "HEAD"
404
+ targets.append((forced, name))
405
+
185
406
  if any(forced and name in PROTECTED for forced, name in targets):
186
407
  return "BLOCK_FORCE"
187
- if force_flag:
188
- if any(name in PROTECTED for _, name in targets):
408
+ if not (force_flag or deleting):
409
+ return "OK"
410
+ if keys & PUSH_ALL_REFS:
411
+ return "BLOCK_FORCE"
412
+ if any(name in PROTECTED for _, name in targets):
413
+ return "BLOCK_FORCE"
414
+ if "--prune" in keys and (not targets or any("*" in name for _, name in targets)):
415
+ return "BLOCK_FORCE"
416
+ unresolved = any(name == "HEAD" for _, name in targets)
417
+ if force_flag and (not targets or unresolved):
418
+ # The target is the current branch. Block if it's protected OR
419
+ # undeterminable (fail-closed for a data-loss guard).
420
+ if current in PROTECTED or current in ("", "HEAD"):
189
421
  return "BLOCK_FORCE"
190
- nonremote = [a for a in args if a not in REMOTES]
191
- if not nonremote:
192
- # Bare force-push: the target is the current branch. Block if it's
193
- # protected OR undeterminable (fail-closed for a data-loss guard).
194
- cur = os.environ.get("CUR_BRANCH", "")
195
- if cur in PROTECTED or cur == "":
196
- return "BLOCK_FORCE"
197
-
198
422
  return "OK"
199
423
 
200
424
 
425
+ def unattended() -> bool:
426
+ """MULTI_AGENT_UNATTENDED=1 in the hook's own environment - the launcher's,
427
+ never anything the run wrote (lib/unattended.sh ma_unattended)."""
428
+ return os.environ.get("MULTI_AGENT_UNATTENDED", "") == "1"
429
+
430
+
431
+ def git_subcommand_mode() -> None:
432
+ """`agent-guard.py --git-subcommand`: read a Bash payload (or a raw command
433
+ on argv) and print each git subcommand it runs, one per line, using the same
434
+ tokenizer the guard uses. pre-commit-check.sh reads this to detect a commit
435
+ without a regex. Never executes anything."""
436
+ if len(sys.argv) > 2:
437
+ cmd = sys.argv[2]
438
+ else:
439
+ try:
440
+ data = json.load(sys.stdin)
441
+ cmd = (data.get("tool_input") or {}).get("command", "")
442
+ except Exception:
443
+ cmd = ""
444
+ if not isinstance(cmd, str) or not cmd:
445
+ return
446
+ try:
447
+ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
448
+ import unattended_policy
449
+
450
+ for sub in unattended_policy.git_subcommands(cmd):
451
+ print(sub)
452
+ except Exception:
453
+ # Fall back to the git subcommand of the whole token list; a caller that
454
+ # gets nothing scans anyway, so silence here only costs an extra scan.
455
+ subs = git_subcommand(tokenize(cmd))
456
+ if subs:
457
+ print(subs)
458
+
459
+
460
+ def commit_dir_mode() -> None:
461
+ """`agent-guard.py --commit-dir`: read a Bash payload and print the
462
+ directory the first commit-writing git command on the line runs in, after
463
+ any `cd` / `git -C`, resolved from the payload's cwd. Prints nothing when
464
+ there is no commit or the directory cannot be read literally, so the caller
465
+ keeps its own cwd. Never executes anything."""
466
+ try:
467
+ data = json.load(sys.stdin)
468
+ cmd = (data.get("tool_input") or {}).get("command", "")
469
+ base = data.get("cwd") or os.getcwd()
470
+ except Exception:
471
+ return
472
+ if not isinstance(cmd, str) or not cmd:
473
+ return
474
+ try:
475
+ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
476
+ import unattended_policy
477
+
478
+ dirs = unattended_policy.git_commit_dirs(cmd, base)
479
+ except Exception:
480
+ return
481
+ if dirs and dirs[0] and os.path.isdir(dirs[0]):
482
+ print(dirs[0])
483
+
484
+
201
485
  def main() -> None:
486
+ if len(sys.argv) > 1 and sys.argv[1] == "--git-subcommand":
487
+ git_subcommand_mode()
488
+ return
489
+ if len(sys.argv) > 1 and sys.argv[1] == "--commit-dir":
490
+ commit_dir_mode()
491
+ return
492
+ strict = unattended()
493
+
494
+ def _deadline(_signum, _frame):
495
+ # os._exit skips the stdio flush, so the verdict is flushed first or
496
+ # the wrapper reads nothing.
497
+ print("BLOCK_UNATTENDED\tthe guard hit its internal deadline" if strict else "OK", flush=True)
498
+ os._exit(0)
499
+
500
+ try:
501
+ signal.signal(signal.SIGALRM, _deadline)
502
+ signal.setitimer(signal.ITIMER_REAL, deadline_seconds())
503
+ except (ValueError, AttributeError, OSError):
504
+ pass
202
505
  try:
203
506
  data = json.load(sys.stdin)
204
507
  cmd = (data.get("tool_input") or {}).get("command", "")
205
- if not isinstance(cmd, str) or not cmd:
206
- print("OK")
207
- return
208
- print(decide(cmd))
508
+ verdict = decide(cmd) if isinstance(cmd, str) and cmd else "OK"
509
+ if verdict == "OK" and strict:
510
+ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
511
+ import unattended_policy
512
+
513
+ reason = unattended_policy.check(data)
514
+ if reason:
515
+ verdict = "BLOCK_UNATTENDED\t" + reason.replace("\n", " ")
516
+ print(verdict)
209
517
  except Exception:
210
- print("OK")
518
+ # Attended: a guard bug must not break a legitimate tool call.
519
+ # Unattended: nobody is there to notice a gap, so an input the guard
520
+ # cannot judge is refused.
521
+ print("BLOCK_PARSE" if strict else "OK")
211
522
 
212
523
 
213
524
  if __name__ == "__main__":
@@ -1,33 +1,52 @@
1
1
  #!/usr/bin/env bash
2
- # agent-guard.sh - PreToolUse Bash guard for the multi-agent pipeline.
2
+ # agent-guard.sh - PreToolUse guard for the multi-agent pipeline.
3
3
  #
4
- # Turns two prompt-level rules into deterministic, OS-enforced gates:
4
+ # Turns prompt-level rules into deterministic, OS-enforced gates:
5
5
  # 1. No AI/assistant attribution in git commit messages (Co-Authored-By: Claude,
6
6
  # "Generated with Claude Code", robot emoji, Anthropic no-reply address).
7
- # 2. No force-push to a protected branch (main / master / develop).
7
+ # 2. No force-push to a protected branch (main / master / develop), whichever
8
+ # remote, push options or `git -C` directory the push names.
9
+ # 3. With MULTI_AGENT_UNATTENDED=1 in the hook's environment only: no outward
10
+ # writes (push, PR, issue, tracker publishers, mutating API calls), no
11
+ # Keychain reads, no fetch outside the network allowlist, no package
12
+ # installs or manifest edits, no writes into protected paths
13
+ # (scripts/unattended_policy.py, schemas/unattended-policy.json).
8
14
  #
9
- # Contract (Claude Code PreToolUse hook):
10
- # - Reads the tool-call JSON on stdin: {"tool_input":{"command":"..."}, ...}.
15
+ # Contract (Claude Code PreToolUse hook, matcher Bash and Edit|Write|NotebookEdit):
16
+ # - Reads the tool-call JSON on stdin: {"tool_name":..., "tool_input":{...}, "cwd":...}.
11
17
  # - Exit 2 -> BLOCK the tool call (reason on stderr, shown to the model).
12
18
  # - Exit 0 -> allow.
13
19
  #
14
- # Safety design (fail-OPEN):
20
+ # Safety design:
15
21
  # - The command string is ONLY parsed/pattern-matched, NEVER executed or eval'd
16
22
  # (the decision core is agent-guard.py; shlex tokenizes without running).
17
- # - Any internal error (bad JSON, missing python3/helper, empty input) -> exit 0.
18
- # A guard bug must never break a legitimate tool call.
23
+ # - Attended: any internal error (bad JSON, missing python3/helper, empty
24
+ # input) -> exit 0. A guard bug must never break a legitimate tool call.
25
+ # - Unattended: the same errors -> exit 2. Nobody is watching to notice a gap.
19
26
  # - No network, no file writes, no secret values printed.
20
- # - The single exec is a read-only `git rev-parse` to learn the current branch.
27
+ # - The execs are read-only `git rev-parse` / `git diff --name-only` calls.
21
28
 
22
29
  set -u
23
30
 
24
31
  HERE="$(cd "$(dirname "$0")" 2>/dev/null && pwd || true)"
25
32
  HELPER="$HERE/agent-guard.py"
26
- [ -f "$HELPER" ] || exit 0
27
- command -v python3 >/dev/null 2>&1 || exit 0
33
+
34
+ STRICT=0
35
+ [ "${MULTI_AGENT_UNATTENDED:-}" = "1" ] && STRICT=1
36
+
37
+ refuse_unjudged() {
38
+ if [ "$STRICT" = "1" ]; then
39
+ echo "BLOCKED by agent-guard (unattended): $1, so this tool call cannot be judged and is refused." >&2
40
+ exit 2
41
+ fi
42
+ exit 0
43
+ }
44
+
45
+ [ -f "$HELPER" ] || refuse_unjudged "agent-guard.py is missing"
46
+ command -v python3 >/dev/null 2>&1 || refuse_unjudged "python3 is not on PATH"
28
47
 
29
48
  PAYLOAD="$(cat 2>/dev/null || true)"
30
- [ -z "$PAYLOAD" ] && exit 0
49
+ [ -z "$PAYLOAD" ] && refuse_unjudged "the hook received no payload"
31
50
 
32
51
  CUR_BRANCH="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || true)"
33
52
 
@@ -43,6 +62,15 @@ case "$DECISION" in
43
62
  echo "BLOCKED by agent-guard: force-push to a protected branch (main/master/develop) is not allowed." >&2
44
63
  echo "Rewriting shared history is a data-loss risk. Push a normal commit, or force-push a feature branch." >&2
45
64
  exit 2 ;;
46
- *)
65
+ BLOCK_UNATTENDED*)
66
+ echo "BLOCKED by agent-guard (unattended policy): ${DECISION#BLOCK_UNATTENDED?}." >&2
67
+ echo "This run has nobody watching it. Outward writes go through pr-request.json and the runner;" >&2
68
+ echo "see multi-agent-refs/features/unattended-security.md. Record what is needed and continue." >&2
69
+ exit 2 ;;
70
+ BLOCK_PARSE)
71
+ refuse_unjudged "the guard could not parse the tool call" ;;
72
+ OK)
47
73
  exit 0 ;;
74
+ *)
75
+ refuse_unjudged "the guard returned no decision" ;;
48
76
  esac
@@ -38,6 +38,16 @@
38
38
  * after `~/.claude` is deleted, and for a SECOND ANALYST - who is precisely the
39
39
  * person positioned to open a duplicate tree.
40
40
  *
41
+ * THE SPEC HAS TO BE CONSISTENT, NOT ONLY CLOSED
42
+ *
43
+ * After planning, `spec-consistency-gate.mjs` checks the document against the
44
+ * planned stories: every requirement in a story and in a Test Plan row, and no
45
+ * row that waives a binding constitution rule. With the quality gates active
46
+ * (lib/unattended.mjs, gatesActive) a gap is exit 4, the same refusal as an
47
+ * open placeholder, and the verdict is recorded in the gate ledger. Attended,
48
+ * it is an advisory `consistency:` line in the preview and a `consistency`
49
+ * field in the JSON, and the exit code is what it was.
50
+ *
41
51
  * Usage:
42
52
  * analysis-story-tree.mjs <analysis.md> [--json] [--prefs FILE]
43
53
  *
@@ -47,7 +57,18 @@
47
57
  import { readFileSync, existsSync } from "node:fs";
48
58
  import { createHash } from "node:crypto";
49
59
  import { homedir } from "node:os";
50
- import { join } from "node:path";
60
+ import { dirname, join } from "node:path";
61
+ import { hostCommand } from "../lib/user-facing.mjs";
62
+ import { resolveConstitution } from "./constitution.mjs";
63
+ import { gateContext, recordQuietly } from "./gate-ledger.mjs";
64
+ import {
65
+ describe,
66
+ detail as consistencyDetail,
67
+ evaluate,
68
+ LEDGER,
69
+ storyTasks,
70
+ summary,
71
+ } from "./spec-consistency-gate.mjs";
51
72
 
52
73
  const argv = process.argv.slice(2);
53
74
  const JSON_OUT = argv.includes("--json");
@@ -364,7 +385,28 @@ export function plan(text, prefs) {
364
385
  };
365
386
  }
366
387
 
367
- function main() {
388
+ /**
389
+ * The consistency verdict for this document and its planned stories.
390
+ *
391
+ * @returns {object} a spec-consistency-gate result
392
+ */
393
+ function consistencyOf(text, nodes) {
394
+ const constitution = resolveConstitution({
395
+ repo: dirname(file),
396
+ feature: frontMatter(text).feature || null,
397
+ });
398
+ if (constitution.error) {
399
+ return { gate: "spec-consistency", verdict: "unreadable", reason: constitution.error };
400
+ }
401
+ return evaluate({
402
+ docs: [{ path: file, text }],
403
+ tasks: storyTasks(nodes),
404
+ taskSource: "story-tree",
405
+ constitution,
406
+ });
407
+ }
408
+
409
+ async function main() {
368
410
  if (!file) return die("usage: analysis-story-tree.mjs <analysis.md> [--json] [--prefs FILE]", 3);
369
411
  if (!existsSync(file)) return die(`analysis-story-tree: no such file: ${file}`, 3);
370
412
  const text = readFileSync(file, "utf8");
@@ -378,7 +420,9 @@ function main() {
378
420
  `analysis-story-tree: the document is not issue-ready (${open.length} open item(s))\n`,
379
421
  );
380
422
  for (const m of open.slice(0, 5)) process.stderr.write(` ${m}\n`);
381
- process.stderr.write(" run /multi-agent:analysis-resolve to close them first\n");
423
+ process.stderr.write(
424
+ ` run ${hostCommand("analysis-resolve", import.meta.dirname)} to close them first\n`,
425
+ );
382
426
  process.exitCode = 4;
383
427
  return;
384
428
  }
@@ -401,6 +445,33 @@ function main() {
401
445
  return;
402
446
  }
403
447
 
448
+ const ctx = gateContext({ repo: process.cwd() });
449
+ const consistency = consistencyOf(text, result.nodes);
450
+ if (ctx.active) {
451
+ await recordQuietly(
452
+ "spec-consistency",
453
+ LEDGER[consistency.verdict],
454
+ {
455
+ verdict: consistency.verdict,
456
+ source: "analysis-jira",
457
+ ...(consistency.reason ? { reason: consistency.reason } : {}),
458
+ },
459
+ { repo: process.cwd(), statePath: ctx.statePath },
460
+ );
461
+ if (consistency.verdict === "gap" || consistency.verdict === "unreadable") {
462
+ process.stderr.write(
463
+ `analysis-story-tree: the document is not issue-ready (spec-consistency: ${summary(consistency)})\n`,
464
+ );
465
+ for (const line of describe(consistency).slice(0, 10)) process.stderr.write(`${line}\n`);
466
+ process.stderr.write(
467
+ ` add the missing rows to the document, or re-run ${hostCommand("analysis", import.meta.dirname)}, then plan again\n`,
468
+ );
469
+ process.exitCode = 4;
470
+ return;
471
+ }
472
+ }
473
+ result.consistency = ctx.active ? consistency : { ...consistency, advisory: true };
474
+
404
475
  if (JSON_OUT) {
405
476
  process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
406
477
  return;
@@ -417,6 +488,11 @@ function main() {
417
488
  );
418
489
  if (c.uncovered.length) process.stdout.write(` not in any story: ${c.uncovered.join(", ")}\n`);
419
490
  if (c.invented.length) process.stdout.write(` cited but undefined: ${c.invented.join(", ")}\n`);
491
+ const k = result.consistency;
492
+ process.stdout.write(
493
+ `consistency: ${k.verdict} (${k.advisory ? "advisory, " : ""}${consistencyDetail(k)})\n`,
494
+ );
495
+ for (const line of describe(k)) process.stdout.write(`${line}\n`);
420
496
  process.stdout.write(`\n${result.writeCount} issue(s) would be created:\n`);
421
497
  for (const s of result.nodes) {
422
498
  process.stdout.write(` ${result.prefsUsed.storyIssueType} ${s.title}\n`);