@mmerterden/multi-agent-pipeline 20.33.0 → 20.35.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 (390) hide show
  1. package/CHANGELOG.md +98 -1
  2. package/README.md +3 -1
  3. package/README.tr.md +2 -1
  4. package/docs/adr/0018-cross-repo-links-not-a-global-graph.md +43 -0
  5. package/docs/adr/README.md +2 -1
  6. package/docs/facts.json +5 -4
  7. package/docs/features.md +1 -1
  8. package/install/_dev-only-files.mjs +1 -0
  9. package/install/catalog-history.json +1 -1
  10. package/install/claude.mjs +24 -2
  11. package/install/templates/claude-hooks.json +34 -1
  12. package/manifest.json +393 -339
  13. package/package.json +3 -1
  14. package/pipeline/agents/bulk-reader.md +3 -0
  15. package/pipeline/agents/code-reviewer.md +9 -0
  16. package/pipeline/agents/explorer.md +4 -0
  17. package/pipeline/agents/plan-critic.md +4 -2
  18. package/pipeline/commands/multi-agent/SKILL.md +17 -136
  19. package/pipeline/commands/multi-agent/channels/SKILL.md +16 -298
  20. package/pipeline/commands/multi-agent/graph/SKILL.md +5 -2
  21. package/pipeline/commands/multi-agent/language/SKILL.md +3 -3
  22. package/pipeline/commands/multi-agent/office-on/SKILL.md +7 -3
  23. package/pipeline/commands/multi-agent/office-status/SKILL.md +3 -2
  24. package/pipeline/commands/multi-agent/resume/SKILL.md +8 -22
  25. package/pipeline/commands/multi-agent/review/SKILL.md +7 -131
  26. package/pipeline/commands/multi-agent/setup/SKILL.md +19 -224
  27. package/pipeline/contract/CHANGELOG.md +9 -0
  28. package/pipeline/contract/README.md +6 -2
  29. package/pipeline/contract/fixtures/error-invalid-request.json +1 -1
  30. package/pipeline/contract/fixtures/error-unauthorized.json +1 -1
  31. package/pipeline/contract/fixtures/error-unsigned.json +1 -1
  32. package/pipeline/contract/manifest.json +14 -1
  33. package/pipeline/contract/types/index.d.ts +24 -2
  34. package/pipeline/lib/json-file-lock.mjs +61 -15
  35. package/pipeline/lib/office-remote.mjs +228 -0
  36. package/pipeline/lib/qr-code.mjs +360 -0
  37. package/pipeline/lib/repo-hygiene.sh +1 -0
  38. package/pipeline/lib/run-completion.mjs +17 -0
  39. package/pipeline/multi-agent-refs/channels/generator.md +146 -0
  40. package/pipeline/multi-agent-refs/channels/issue-comment.md +1 -1
  41. package/pipeline/multi-agent-refs/channels/menu.md +55 -0
  42. package/pipeline/multi-agent-refs/channels/multi-repo.md +6 -0
  43. package/pipeline/multi-agent-refs/channels/preview.md +25 -0
  44. package/pipeline/multi-agent-refs/channels/reference.md +98 -0
  45. package/pipeline/multi-agent-refs/features/autopilot-circuit-breaker.md +1 -1
  46. package/pipeline/multi-agent-refs/features/code-graph.md +27 -0
  47. package/pipeline/multi-agent-refs/features/office-remote-protocol.md +166 -0
  48. package/pipeline/multi-agent-refs/features/office-threat-model.md +2 -2
  49. package/pipeline/multi-agent-refs/features/plan-critic.md +5 -2
  50. package/pipeline/multi-agent-refs/features/review-delta.md +4 -1
  51. package/pipeline/multi-agent-refs/features/scope-check.md +25 -1
  52. package/pipeline/multi-agent-refs/features/verify-by-test.md +10 -0
  53. package/pipeline/multi-agent-refs/keychain.md +7 -0
  54. package/pipeline/multi-agent-refs/knowledge.md +9 -0
  55. package/pipeline/multi-agent-refs/orchestrator/dispatcher.md +163 -0
  56. package/pipeline/multi-agent-refs/phases/phase-0-init.md +6 -2
  57. package/pipeline/multi-agent-refs/phases/phase-1-plan.md +8 -10
  58. package/pipeline/multi-agent-refs/phases/phase-2-dev.md +18 -20
  59. package/pipeline/multi-agent-refs/phases/phase-3-review.md +20 -14
  60. package/pipeline/multi-agent-refs/phases/phase-4-commit.md +8 -7
  61. package/pipeline/multi-agent-refs/phases/phase-5-report.md +6 -3
  62. package/pipeline/multi-agent-refs/picker-contract.md +1 -1
  63. package/pipeline/multi-agent-refs/resume/details.md +35 -0
  64. package/pipeline/multi-agent-refs/review/inputs.md +87 -0
  65. package/pipeline/multi-agent-refs/review/module-guides.md +25 -0
  66. package/pipeline/multi-agent-refs/review/valven.md +42 -0
  67. package/pipeline/multi-agent-refs/rules.md +3 -2
  68. package/pipeline/multi-agent-refs/setup/accounts.md +27 -0
  69. package/pipeline/multi-agent-refs/setup/app-store-connect.md +5 -0
  70. package/pipeline/multi-agent-refs/setup/firebase.md +5 -0
  71. package/pipeline/multi-agent-refs/setup/google-play.md +4 -0
  72. package/pipeline/multi-agent-refs/setup/hooks-and-plugins.md +21 -0
  73. package/pipeline/multi-agent-refs/setup/language.md +46 -0
  74. package/pipeline/multi-agent-refs/setup/multi-repo-group.md +51 -0
  75. package/pipeline/multi-agent-refs/setup/summaries.md +63 -0
  76. package/pipeline/multi-agent-refs/setup/token-save-flow.md +51 -0
  77. package/pipeline/multi-agent-refs/tracker-contract.md +1 -1
  78. package/pipeline/office/NOTICE.md +4 -1
  79. package/pipeline/office/assets/char_12.png +0 -0
  80. package/pipeline/office/assets/char_13.png +0 -0
  81. package/pipeline/office/assets/char_14.png +0 -0
  82. package/pipeline/office/assets/char_15.png +0 -0
  83. package/pipeline/office/assets/char_16.png +0 -0
  84. package/pipeline/office/assets/char_17.png +0 -0
  85. package/pipeline/office/assets/char_18.png +0 -0
  86. package/pipeline/office/assets/char_19.png +0 -0
  87. package/pipeline/office/assets/char_20.png +0 -0
  88. package/pipeline/office/assets/char_21.png +0 -0
  89. package/pipeline/office/assets/char_22.png +0 -0
  90. package/pipeline/office/assets/char_23.png +0 -0
  91. package/pipeline/office/assets/char_24.png +0 -0
  92. package/pipeline/office/assets/char_25.png +0 -0
  93. package/pipeline/office/assets/char_26.png +0 -0
  94. package/pipeline/office/assets/char_27.png +0 -0
  95. package/pipeline/office/assets/char_28.png +0 -0
  96. package/pipeline/office/assets/char_29.png +0 -0
  97. package/pipeline/office/assets/char_30.png +0 -0
  98. package/pipeline/office/index.html +304 -55
  99. package/pipeline/office/toolkit.json +1 -1
  100. package/pipeline/rules/response-shape.md +6 -7
  101. package/pipeline/schemas/agent-state.schema.json +36 -0
  102. package/pipeline/schemas/phases.json +4 -4
  103. package/pipeline/schemas/plan-critique.schema.json +9 -2
  104. package/pipeline/schemas/planning-output.schema.json +43 -2
  105. package/pipeline/schemas/pr-reach.schema.json +55 -0
  106. package/pipeline/schemas/prefs.schema.json +37 -8
  107. package/pipeline/schemas/reviewer-output.schema.json +20 -2
  108. package/pipeline/schemas/token-budget.json +4 -4
  109. package/pipeline/schemas/triage-output.schema.json +32 -3
  110. package/pipeline/schemas/unattended-policy.json +2 -1
  111. package/pipeline/scripts/_graph-analysis.mjs +270 -0
  112. package/pipeline/scripts/_guard_rules.py +449 -1
  113. package/pipeline/scripts/_memory-policy.mjs +165 -0
  114. package/pipeline/scripts/_secret-scan.mjs +105 -0
  115. package/pipeline/scripts/_test-gaming.mjs +36 -0
  116. package/pipeline/scripts/_unified-diff.mjs +2 -2
  117. package/pipeline/scripts/agent-guard.py +79 -19
  118. package/pipeline/scripts/anonymize-findings.mjs +99 -0
  119. package/pipeline/scripts/answer-check.mjs +113 -0
  120. package/pipeline/scripts/answer-check.sh +20 -0
  121. package/pipeline/scripts/autopilot-publish.mjs +9 -2
  122. package/pipeline/scripts/capture-flush.sh +12 -2
  123. package/pipeline/scripts/check-read-size.sh +9 -0
  124. package/pipeline/scripts/code-graph-rules/android.json +8 -3
  125. package/pipeline/scripts/contract-server.mjs +71 -16
  126. package/pipeline/scripts/debt-ledger.mjs +323 -0
  127. package/pipeline/scripts/file-context.mjs +261 -0
  128. package/pipeline/scripts/file-context.sh +20 -0
  129. package/pipeline/scripts/gate-ledger.mjs +144 -21
  130. package/pipeline/scripts/graph-links.mjs +230 -0
  131. package/pipeline/scripts/graph-query.mjs +133 -1
  132. package/pipeline/scripts/graph-report.mjs +65 -0
  133. package/pipeline/scripts/learn-from-transcripts.mjs +12 -48
  134. package/pipeline/scripts/learnings-ledger.mjs +143 -24
  135. package/pipeline/scripts/office-build.mjs +276 -5
  136. package/pipeline/scripts/office-control.mjs +70 -10
  137. package/pipeline/scripts/office-pair.mjs +407 -0
  138. package/pipeline/scripts/office-remote-client.mjs +463 -0
  139. package/pipeline/scripts/phase-tracker.sh +8 -0
  140. package/pipeline/scripts/phase0-exit-gate.mjs +40 -37
  141. package/pipeline/scripts/phone-devices.mjs +9 -1
  142. package/pipeline/scripts/plan-critique-gate.mjs +11 -2
  143. package/pipeline/scripts/pre-commit-check.sh +28 -2
  144. package/pipeline/scripts/pre-push-check.sh +6 -12
  145. package/pipeline/scripts/rework-base.mjs +87 -0
  146. package/pipeline/scripts/rework-rulings.mjs +106 -0
  147. package/pipeline/scripts/run-commit-check.mjs +104 -0
  148. package/pipeline/scripts/run-scope-guard.mjs +58 -3
  149. package/pipeline/scripts/run-scope-guard.sh +13 -1
  150. package/pipeline/scripts/scope-check-gate.mjs +213 -2
  151. package/pipeline/scripts/task-mirror.mjs +106 -15
  152. package/pipeline/scripts/task-mirror.sh +3 -2
  153. package/pipeline/scripts/test-stability-gate.mjs +112 -0
  154. package/pipeline/scripts/triage-memory.mjs +64 -37
  155. package/pipeline/scripts/update-check.sh +7 -1
  156. package/pipeline/scripts/update-issue-progress.sh +73 -8
  157. package/pipeline/scripts/validate-planning.mjs +172 -4
  158. package/pipeline/scripts/validate-reviewer.mjs +20 -0
  159. package/pipeline/scripts/validate-triage.mjs +149 -4
  160. package/pipeline/scripts/work-items.mjs +119 -1
  161. package/pipeline/scripts/worktree-prepare-all.mjs +200 -0
  162. package/pipeline/scripts/worktree-prepare.sh +40 -4
  163. package/pipeline/scripts/write-state.mjs +67 -24
  164. package/pipeline/skills/.skill-manifest.json +9 -9
  165. package/pipeline/skills/shared/core/google-play-compliance/SKILL.md +5 -5
  166. package/pipeline/skills/shared/core/google-play-compliance/references/rules.yml +1 -1
  167. package/pipeline/skills/shared/core/multi-agent-channels/SKILL.md +1 -1
  168. package/pipeline/skills/shared/core/multi-agent-graph/SKILL.md +5 -2
  169. package/pipeline/skills/shared/core/multi-agent-language/SKILL.md +4 -4
  170. package/pipeline/skills/shared/core/multi-agent-office-status/SKILL.md +2 -2
  171. package/pipeline/skills/shared/core/multi-agent-review/SKILL.md +2 -0
  172. package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +4 -4
  173. package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +14 -0
  174. package/pipeline/skills/shared/external/android-architecture/references/patterns.md +6 -0
  175. package/pipeline/skills/shared/external/android-build-quality-gates/references/patterns.md +10 -0
  176. package/pipeline/skills/shared/external/android-datastore/references/patterns.md +11 -0
  177. package/pipeline/skills/shared/external/android-design-tokens-codegen/references/patterns.md +8 -0
  178. package/pipeline/skills/shared/external/android-jetpack-compose-expert/references/patterns.md +6 -0
  179. package/pipeline/skills/shared/external/android-mvi-viewmodel/references/patterns.md +10 -0
  180. package/pipeline/skills/shared/external/android-performance/references/patterns.md +13 -0
  181. package/pipeline/skills/shared/external/android-security/references/patterns.md +16 -0
  182. package/pipeline/skills/shared/external/api-patterns/references/contract-details.md +9 -0
  183. package/pipeline/skills/shared/external/api-security-best-practices/references/abuse-controls.md +12 -0
  184. package/pipeline/skills/shared/external/api-security-best-practices/references/identity-and-access.md +13 -0
  185. package/pipeline/skills/shared/external/api-security-best-practices/references/request-handling.md +12 -0
  186. package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +9 -0
  187. package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +8 -0
  188. package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +10 -0
  189. package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +21 -0
  190. package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +9 -0
  191. package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +7 -0
  192. package/pipeline/skills/shared/external/app-store-review/SKILL.md +2 -2
  193. package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +10 -0
  194. package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +10 -1
  195. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +22 -0
  196. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +17 -0
  197. package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +22 -0
  198. package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +17 -0
  199. package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +9 -0
  200. package/pipeline/skills/shared/external/authentication/references/passkeys.md +11 -0
  201. package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +13 -0
  202. package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +9 -0
  203. package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +10 -0
  204. package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +15 -0
  205. package/pipeline/skills/shared/external/compose-components/references/patterns.md +7 -0
  206. package/pipeline/skills/shared/external/compose-navigation/references/patterns.md +7 -0
  207. package/pipeline/skills/shared/external/compose-testing/references/patterns.md +15 -0
  208. package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +9 -0
  209. package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +11 -0
  210. package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +10 -0
  211. package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +13 -0
  212. package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +20 -0
  213. package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +16 -0
  214. package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +16 -0
  215. package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +14 -0
  216. package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +13 -0
  217. package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +10 -0
  218. package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +10 -0
  219. package/pipeline/skills/shared/external/fastapi-pro/references/app-structure.md +10 -0
  220. package/pipeline/skills/shared/external/gradle-kotlin-dsl/references/patterns.md +17 -0
  221. package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +12 -0
  222. package/pipeline/skills/shared/external/hig-app-icons/references/icon-workflow.md +10 -0
  223. package/pipeline/skills/shared/external/hig-components-content/references/content-views.md +10 -0
  224. package/pipeline/skills/shared/external/hig-components-layout/references/bars-and-tabs.md +11 -0
  225. package/pipeline/skills/shared/external/hig-foundations/references/foundations-detail.md +13 -0
  226. package/pipeline/skills/shared/external/hig-foundations/references/type-color-spacing.md +13 -0
  227. package/pipeline/skills/shared/external/hig-patterns/references/onboarding-and-states.md +11 -0
  228. package/pipeline/skills/shared/external/hig-platforms/references/ipad-layout.md +12 -0
  229. package/pipeline/skills/shared/external/hig-technologies/references/technologies.md +16 -0
  230. package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +9 -0
  231. package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +18 -0
  232. package/pipeline/skills/shared/external/ios-accessibility/references/large-content-and-appearance.md +9 -0
  233. package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +9 -0
  234. package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +7 -0
  235. package/pipeline/skills/shared/external/ios-coding-standard/references/STANDARD.md +13 -0
  236. package/pipeline/skills/shared/external/ios-design-review/references/appearance-matrix.md +9 -0
  237. package/pipeline/skills/shared/external/ios-design-review/references/checklist.md +15 -0
  238. package/pipeline/skills/shared/external/ios-haptics/references/core-haptics.md +11 -0
  239. package/pipeline/skills/shared/external/ios-iphone-duo/references/api-map.md +11 -0
  240. package/pipeline/skills/shared/external/ios-iphone-duo/references/fixed-assumptions.md +15 -0
  241. package/pipeline/skills/shared/external/ios-iphone-duo/references/poses-and-panes.md +11 -0
  242. package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +18 -0
  243. package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +19 -0
  244. package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +15 -0
  245. package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +7 -0
  246. package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +8 -0
  247. package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +12 -0
  248. package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +17 -0
  249. package/pipeline/skills/shared/external/ios-security/references/app-review-guidelines.md +8 -0
  250. package/pipeline/skills/shared/external/ios-security/references/cryptokit-advanced.md +14 -0
  251. package/pipeline/skills/shared/external/ios-security/references/file-storage-patterns.md +8 -0
  252. package/pipeline/skills/shared/external/ios-security/references/privacy-manifest.md +9 -0
  253. package/pipeline/skills/shared/external/ios-sf-symbols/references/effects-and-custom-symbols.md +9 -0
  254. package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +13 -0
  255. package/pipeline/skills/shared/external/kotlin-coroutines-expert/references/patterns.md +8 -0
  256. package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +21 -0
  257. package/pipeline/skills/shared/external/localization-reuse-map/reference/format-and-output.md +9 -0
  258. package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +12 -0
  259. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +16 -0
  260. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +21 -0
  261. package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +10 -0
  262. package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +9 -0
  263. package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +12 -0
  264. package/pipeline/skills/shared/external/nodejs-backend-patterns/references/runtime-patterns.md +11 -0
  265. package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +11 -0
  266. package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +18 -0
  267. package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +11 -0
  268. package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +11 -0
  269. package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +15 -0
  270. package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +14 -0
  271. package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +14 -0
  272. package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +14 -0
  273. package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +14 -0
  274. package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +10 -0
  275. package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +12 -0
  276. package/pipeline/skills/shared/external/retrofit-networking/references/patterns.md +14 -0
  277. package/pipeline/skills/shared/external/room-database/references/patterns.md +16 -0
  278. package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +10 -0
  279. package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +10 -0
  280. package/pipeline/skills/shared/external/spm-build-analysis/references/build-optimization-sources.md +14 -0
  281. package/pipeline/skills/shared/external/spm-build-analysis/references/spm-analysis-checks.md +19 -0
  282. package/pipeline/skills/shared/external/storekit/references/core-patterns.md +13 -0
  283. package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +31 -0
  284. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +8 -0
  285. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +9 -0
  286. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +10 -0
  287. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +8 -0
  288. package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +24 -0
  289. package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +8 -0
  290. package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +14 -0
  291. package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +12 -0
  292. package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +10 -0
  293. package/pipeline/skills/shared/external/swift-concurrency-expert/references/swift-6-2-concurrency.md +8 -0
  294. package/pipeline/skills/shared/external/swift-concurrency-pro/references/actors.md +10 -0
  295. package/pipeline/skills/shared/external/swift-concurrency-pro/references/cancellation.md +7 -0
  296. package/pipeline/skills/shared/external/swift-concurrency-pro/references/interop.md +10 -0
  297. package/pipeline/skills/shared/external/swift-concurrency-pro/references/new-features.md +11 -0
  298. package/pipeline/skills/shared/external/swift-concurrency-pro/references/structured.md +9 -0
  299. package/pipeline/skills/shared/external/swift-concurrency-pro/references/testing.md +13 -0
  300. package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +7 -0
  301. package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +14 -0
  302. package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +16 -0
  303. package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +17 -0
  304. package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +19 -0
  305. package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +16 -0
  306. package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +19 -0
  307. package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +18 -0
  308. package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +16 -0
  309. package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +17 -0
  310. package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +17 -0
  311. package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +17 -0
  312. package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +18 -0
  313. package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +21 -0
  314. package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +16 -0
  315. package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +16 -0
  316. package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +9 -0
  317. package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +24 -0
  318. package/pipeline/skills/shared/external/swift-testing-pro/references/async-tests.md +9 -0
  319. package/pipeline/skills/shared/external/swift-testing-pro/references/new-features.md +11 -0
  320. package/pipeline/skills/shared/external/swift-testing-pro/references/writing-better-tests.md +13 -0
  321. package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +8 -0
  322. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +17 -0
  323. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +12 -0
  324. package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +11 -0
  325. package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +7 -0
  326. package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +13 -0
  327. package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +24 -0
  328. package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +12 -0
  329. package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +15 -0
  330. package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +15 -0
  331. package/pipeline/skills/shared/external/swiftui-animation/references/scroll-effects.md +12 -0
  332. package/pipeline/skills/shared/external/swiftui-expert-skill/references/accessibility-patterns.md +11 -0
  333. package/pipeline/skills/shared/external/swiftui-expert-skill/references/animation-advanced.md +7 -0
  334. package/pipeline/skills/shared/external/swiftui-expert-skill/references/animation-basics.md +13 -0
  335. package/pipeline/skills/shared/external/swiftui-expert-skill/references/animation-transitions.md +9 -0
  336. package/pipeline/skills/shared/external/swiftui-expert-skill/references/charts-accessibility.md +9 -0
  337. package/pipeline/skills/shared/external/swiftui-expert-skill/references/charts.md +17 -0
  338. package/pipeline/skills/shared/external/swiftui-expert-skill/references/image-optimization.md +9 -0
  339. package/pipeline/skills/shared/external/swiftui-expert-skill/references/latest-apis.md +10 -0
  340. package/pipeline/skills/shared/external/swiftui-expert-skill/references/layout-best-practices.md +12 -0
  341. package/pipeline/skills/shared/external/swiftui-expert-skill/references/list-patterns.md +12 -0
  342. package/pipeline/skills/shared/external/swiftui-expert-skill/references/macos-scenes.md +13 -0
  343. package/pipeline/skills/shared/external/swiftui-expert-skill/references/macos-views.md +12 -0
  344. package/pipeline/skills/shared/external/swiftui-expert-skill/references/macos-window-styling.md +12 -0
  345. package/pipeline/skills/shared/external/swiftui-expert-skill/references/performance-patterns.md +7 -0
  346. package/pipeline/skills/shared/external/swiftui-expert-skill/references/scroll-patterns.md +9 -0
  347. package/pipeline/skills/shared/external/swiftui-expert-skill/references/sheet-navigation-patterns.md +10 -0
  348. package/pipeline/skills/shared/external/swiftui-expert-skill/references/state-management.md +18 -0
  349. package/pipeline/skills/shared/external/swiftui-expert-skill/references/view-structure.md +16 -0
  350. package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +11 -0
  351. package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +8 -0
  352. package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +14 -0
  353. package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +9 -0
  354. package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +22 -0
  355. package/pipeline/skills/shared/external/swiftui-liquid-glass/references/uikit-glass.md +14 -0
  356. package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +10 -0
  357. package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +10 -0
  358. package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +13 -0
  359. package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +10 -0
  360. package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +14 -0
  361. package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +30 -0
  362. package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +16 -0
  363. package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +11 -0
  364. package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +11 -0
  365. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +10 -0
  366. package/pipeline/skills/shared/external/swiftui-performance-audit/references/code-smells.md +8 -0
  367. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/app-wiring.md +12 -0
  368. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/menu-bar.md +10 -0
  369. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/navigationstack.md +11 -0
  370. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/scroll-reveal.md +12 -0
  371. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/sheets.md +14 -0
  372. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/tabview.md +10 -0
  373. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +10 -0
  374. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +13 -0
  375. package/pipeline/skills/shared/external/swiftui-view-refactor/references/mv-patterns.md +12 -0
  376. package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +8 -0
  377. package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +8 -0
  378. package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +14 -0
  379. package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +17 -0
  380. package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +11 -0
  381. package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +11 -0
  382. package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +27 -0
  383. package/pipeline/skills/shared/external/xcode-build-fixer/references/build-settings-best-practices.md +9 -0
  384. package/pipeline/skills/shared/external/xcode-build-fixer/references/fix-patterns.md +7 -0
  385. package/pipeline/skills/shared/external/xcode-build-orchestrator/references/build-settings-best-practices.md +9 -0
  386. package/pipeline/skills/shared/external/xcode-compilation-analyzer/references/build-optimization-sources.md +14 -0
  387. package/pipeline/skills/shared/external/xcode-compilation-analyzer/references/code-compilation-checks.md +8 -0
  388. package/pipeline/skills/shared/external/xcode-project-analyzer/references/build-optimization-sources.md +14 -0
  389. package/pipeline/skills/shared/external/xcode-project-analyzer/references/build-settings-best-practices.md +9 -0
  390. package/pipeline/skills/shared/external/xcode-project-analyzer/references/project-audit-checks.md +13 -0
@@ -526,6 +526,23 @@ fi
526
526
  # scanned whole.
527
527
  UNCHANGED_RENAMES=$(git diff --cached -M --diff-filter=R --name-status 2>/dev/null | awk -F'\t' '$1 == "R100" { print $3 }')
528
528
 
529
+ # Paths that never belong in a commit, whatever they contain: signing material
530
+ # and keystores, and the dependency and build trees of the iOS and Swift
531
+ # toolchains. Checked by name before the content scan, which skips binaries.
532
+ blocked_path() {
533
+ local f="$1"
534
+ if printf '%s' "$f" | grep -qiE '\.(p12|pfx|p8|mobileprovision|provisionprofile|jks|keystore)$'; then
535
+ echo "BLOCKED: signing material or keystore staged: $f" >&2
536
+ FOUND=1
537
+ elif printf '%s' "$f" | grep -qE '(^|/)(Pods|\.build|DerivedData|\.DerivedData)/'; then
538
+ echo "BLOCKED: dependency or build output staged: $f" >&2
539
+ FOUND=1
540
+ fi
541
+ }
542
+ while IFS= read -r -d '' file; do
543
+ [ -n "$file" ] && blocked_path "$file"
544
+ done < <(git diff --cached --name-only --diff-filter=ACMR -z 2>/dev/null)
545
+
529
546
  # Already-staged content - the common case, and the only source when nothing
530
547
  # in the triggering command itself runs `git add`.
531
548
  while IFS= read -r -d '' file; do
@@ -717,8 +734,10 @@ fi
717
734
 
718
735
  # Attended commit inside a pipeline run: the run's gate ledger should hold a
719
736
  # passing build and test verdict for HEAD (evidence-gate.mjs records both in an
720
- # attended run too). prefs.global.attendedCommitGate.mode: warn (default) says so
721
- # on stderr and lets the commit through, block refuses it, off skips the check.
737
+ # attended run too), and from the commit phase on the review verdict.
738
+ # prefs.global.attendedCommitGate.mode: auto (default) refuses the commit when
739
+ # the committing session drives the run and warns otherwise, warn always lets
740
+ # it through with a note on stderr, block always refuses, off skips the check.
722
741
  # Outside a run gate-ledger.mjs says nothing; any error of its own is not a
723
742
  # reason to refuse a commit a person is watching.
724
743
  if [ "$IS_COMMIT_HOOK" = "1" ] && ! ma_unattended && command -v node >/dev/null 2>&1; then
@@ -727,6 +746,13 @@ if [ "$IS_COMMIT_HOOK" = "1" ] && ! ma_unattended && command -v node >/dev/null
727
746
  [ "$?" = "4" ] && exit 2
728
747
  fi
729
748
 
749
+ # A commit inside a live pipeline run is authored by the run's identity
750
+ # (run-commit-check.mjs); outside a bound run it says nothing.
751
+ if [ "$IS_COMMIT_HOOK" = "1" ] && command -v node >/dev/null 2>&1 && [ -f "$PRE_COMMIT_DIR/run-commit-check.mjs" ]; then
752
+ printf '%s' "${HOOK_INPUT:-}" | node "$PRE_COMMIT_DIR/run-commit-check.mjs" --repo "${COMMIT_DIR:-${REPO_ROOT:-$PWD}}"
753
+ [ "$?" = "2" ] && exit 2
754
+ fi
755
+
730
756
  # Unattended commit: the verification gates must have passed for this HEAD.
731
757
  # The environment is the hook's own, inherited from the process the launcher
732
758
  # started, so the run cannot talk its way past it by editing its state. An
@@ -2,19 +2,13 @@
2
2
  # pre-push-check.sh - primary gate before every push.
3
3
  #
4
4
  # Purpose:
5
- # The repo HAS workflows (test.yml, ci-lite.yml), but they have not executed
6
- # since 2026-07-02: every attempt after that day - the last on 2026-07-25 -
7
- # finished in about four seconds with zero steps recorded, which is a
8
- # runner/quota block rather than a test failure. Both are now dormant by
9
- # declaration too (ADR-0011: the push triggers are commented out). So this
10
- # hook is not a second opinion - it is the only thing standing between a
11
- # broken commit and npm.
5
+ # The local gate before every push. The repository's CI workflows are dormant
6
+ # (ADR-0011), so this is what stands between a commit and npm.
12
7
  #
13
- # It therefore runs the CANONICAL chain, `npm test`, rather than a hand-picked
14
- # subset. A subset drifts from the chain as steps are added, and a bare
15
- # `for f in smoke-*.sh` loop cannot tell a passing suite from one that exited 0
16
- # having asserted nothing; run-smokes.mjs can. A safety net with holes in it is worse than a known gap:
17
- # it is trusted.
8
+ # It runs the canonical chain, `npm test`, rather than a hand-picked subset:
9
+ # a subset drifts from the chain as steps are added, and a bare
10
+ # `for f in smoke-*.sh` loop cannot tell a passing suite from one that exited
11
+ # 0 having asserted nothing; run-smokes.mjs can.
18
12
  #
19
13
  # Two modes, because a gate that runs INSIDE the push is a gate that breaks
20
14
  # pushes. Git opens the connection to the remote before this hook fires, so a
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @file rework-base.mjs - the tree a rework round started from.
4
+ *
5
+ * scope-check-gate.mjs --rejected compares the rework against the tree the
6
+ * review read, because rejected findings carry that tree's line numbers. Each
7
+ * review round rewrites triage-output.json, so the base is kept per round:
8
+ * `.pipeline/rework-base-<iteration>`. `record` writes HEAD for the round when
9
+ * the round has none yet (a resumed re-entry keeps the base it started from)
10
+ * and prints it; `get` only prints it.
11
+ *
12
+ * Usage:
13
+ * rework-base.mjs record --worktree <dir> --iteration <N>
14
+ * rework-base.mjs get --worktree <dir> --iteration <N>
15
+ *
16
+ * Exit: 0 printed, 1 no base recorded for the round (get) or HEAD unreadable
17
+ * (record), 64 usage.
18
+ */
19
+
20
+ import { execFileSync } from "node:child_process";
21
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
22
+ import { join } from "node:path";
23
+
24
+ import { invokedDirectly } from "../lib/invoked-directly.mjs";
25
+
26
+ const SHA = /^[0-9a-f]{40,64}$/;
27
+
28
+ export function basePath(worktree, iteration) {
29
+ return join(worktree, ".pipeline", `rework-base-${iteration}`);
30
+ }
31
+
32
+ function read(path) {
33
+ if (!existsSync(path)) return null;
34
+ const sha = readFileSync(path, "utf8").trim();
35
+ return SHA.test(sha) ? sha : null;
36
+ }
37
+
38
+ export function record(worktree, iteration) {
39
+ const path = basePath(worktree, iteration);
40
+ const kept = read(path);
41
+ if (kept) return kept;
42
+ const head = execFileSync("git", ["-C", worktree, "rev-parse", "HEAD"], {
43
+ encoding: "utf8",
44
+ stdio: ["ignore", "pipe", "ignore"],
45
+ timeout: 30_000,
46
+ }).trim();
47
+ if (!SHA.test(head)) throw new Error("HEAD is not a commit");
48
+ mkdirSync(join(worktree, ".pipeline"), { recursive: true });
49
+ writeFileSync(path, head + "\n");
50
+ return head;
51
+ }
52
+
53
+ export function get(worktree, iteration) {
54
+ return read(basePath(worktree, iteration));
55
+ }
56
+
57
+ function main() {
58
+ const [cmd, ...rest] = process.argv.slice(2);
59
+ const opt = (f) => {
60
+ const i = rest.indexOf(f);
61
+ return i >= 0 ? rest[i + 1] : undefined;
62
+ };
63
+ const worktree = opt("--worktree");
64
+ const iteration = Number(opt("--iteration"));
65
+ if (
66
+ !["record", "get"].includes(cmd) ||
67
+ rest.length !== 4 ||
68
+ !worktree ||
69
+ !Number.isInteger(iteration) ||
70
+ iteration < 1
71
+ ) {
72
+ console.error("usage: rework-base.mjs record|get --worktree <dir> --iteration <N>");
73
+ return 64;
74
+ }
75
+ let sha;
76
+ try {
77
+ sha = cmd === "record" ? record(worktree, iteration) : get(worktree, iteration);
78
+ } catch (err) {
79
+ console.error(`rework-base: ${err.message}`);
80
+ return 1;
81
+ }
82
+ if (!sha) return 1;
83
+ process.stdout.write(sha + "\n");
84
+ return 0;
85
+ }
86
+
87
+ if (invokedDirectly(import.meta.url)) process.exit(main());
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * rework-rulings.mjs - what happens to each open finding when the rework cap
4
+ * is reached.
5
+ *
6
+ * Phase 2 allows a fixed number of rework rounds. At the cap every accepted
7
+ * finding still open gets one ruling, recorded, never dropped:
8
+ *
9
+ * escalate load-bearing: blocking severity, or a security finding
10
+ * (ruleId SEC-* / CON-SEC-*, a security criteriaSource, or the
11
+ * security-auditor's `security` object). The run stops and the
12
+ * user decides.
13
+ * parked anything else. It leaves the loop as a follow-up with its
14
+ * reason, shown before commit (Phase 4 Step 0b), carried in the
15
+ * PR follow-ups and recorded in the debt list, so the run can finish instead of stopping on a
16
+ * finding that is safe to defer.
17
+ *
18
+ * The run escalates when any ruling is `escalate`; otherwise it continues.
19
+ *
20
+ * Usage:
21
+ * rework-rulings.mjs --triage <triage-output.json> [--state <agent-state.json>]
22
+ *
23
+ * --state records the result as reviewIterations[-1].rulings.
24
+ *
25
+ * Output: {escalate, parked, rulings[]} as JSON on stdout.
26
+ * Exit: 0 decided (either way) · 2 usage or unreadable triage · 3 state write failed
27
+ *
28
+ * @module pipeline/scripts/rework-rulings
29
+ */
30
+
31
+ import { invokedDirectly } from "../lib/invoked-directly.mjs";
32
+ import { readRegularJson } from "../lib/regular-file.mjs";
33
+ import { updateState } from "./gate-ledger.mjs";
34
+
35
+ const SECURITY_RULE = /^(CON-)?SEC-/i;
36
+
37
+ /** True when a finding may not leave the loop without the user. */
38
+ export function loadBearing(f) {
39
+ if (f?.severity === "blocking") return true;
40
+ if (typeof f?.ruleId === "string" && SECURITY_RULE.test(f.ruleId)) return true;
41
+ if (f?.security && typeof f.security === "object") return true;
42
+ return typeof f?.criteriaSource === "string" && /security/i.test(f.criteriaSource);
43
+ }
44
+
45
+ /** One ruling per accepted finding of a triage output. */
46
+ export function rule(triage) {
47
+ const rulings = (triage?.accepted ?? []).map((f) => {
48
+ const escalate = loadBearing(f);
49
+ return {
50
+ fingerprint: f.fingerprint ?? null,
51
+ file: f.file ?? null,
52
+ line: Number.isInteger(f.line) ? f.line : null,
53
+ severity: f.severity ?? null,
54
+ ruling: escalate ? "escalate" : "parked",
55
+ reason: escalate
56
+ ? f.severity === "blocking"
57
+ ? "blocking finding open at the rework cap"
58
+ : "security finding open at the rework cap"
59
+ : `rework cap reached; ${f.severity ?? "unrated"} finding parked as a follow-up`,
60
+ issue: f.issue ?? "",
61
+ };
62
+ });
63
+ return {
64
+ escalate: rulings.some((r) => r.ruling === "escalate"),
65
+ parked: rulings.filter((r) => r.ruling === "parked").length,
66
+ rulings,
67
+ };
68
+ }
69
+
70
+ function flag(argv, name) {
71
+ const i = argv.indexOf(`--${name}`);
72
+ return i >= 0 ? argv[i + 1] : undefined;
73
+ }
74
+
75
+ if (invokedDirectly(import.meta.url)) {
76
+ const argv = process.argv.slice(2);
77
+ const triagePath = flag(argv, "triage");
78
+ if (!triagePath) {
79
+ console.error("usage: rework-rulings.mjs --triage <path> [--state <path>]");
80
+ process.exit(2);
81
+ }
82
+ const triage = readRegularJson(triagePath, null);
83
+ if (!triage || !Array.isArray(triage.accepted)) {
84
+ console.error(`rework-rulings: no accepted[] in ${triagePath}`);
85
+ process.exit(2);
86
+ }
87
+ const result = rule(triage);
88
+ const statePath = flag(argv, "state");
89
+ if (statePath) {
90
+ try {
91
+ await updateState(statePath, (s) => {
92
+ const iterations = Array.isArray(s.reviewIterations) ? [...s.reviewIterations] : [];
93
+ if (!iterations.length) iterations.push({ iteration: 1 });
94
+ iterations[iterations.length - 1] = {
95
+ ...iterations[iterations.length - 1],
96
+ rulings: result.rulings,
97
+ };
98
+ return { ...s, reviewIterations: iterations };
99
+ });
100
+ } catch (e) {
101
+ console.error(`rework-rulings: state not written: ${e.message}`);
102
+ process.exitCode = 3;
103
+ }
104
+ }
105
+ process.stdout.write(JSON.stringify(result) + "\n");
106
+ }
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @file run-commit-check.mjs - a commit inside a pipeline run is authored by
4
+ * the identity Phase 0 chose for it.
5
+ *
6
+ * Called by pre-commit-check.sh with the hook payload on stdin. For a `git
7
+ * commit` made in the session a live run is bound to, the author git will
8
+ * record (`--author`, `-c user.email=`, else `git var GIT_AUTHOR_IDENT` in the
9
+ * repository) must carry the run's identity email (`projects[].identity` for
10
+ * the repository's worktree, else `identity`). Outside a bound run, for a run
11
+ * that is not live, or with no identity recorded, it says nothing.
12
+ *
13
+ * Usage: run-commit-check.mjs --repo <dir> < hook-payload.json
14
+ * Exit: 0 fine or not judged; 2 the author is not the run's identity.
15
+ *
16
+ * @module pipeline/scripts/run-commit-check
17
+ */
18
+
19
+ import { spawnSync } from "node:child_process";
20
+ import { readFileSync, realpathSync } from "node:fs";
21
+ import { resolve } from "node:path";
22
+
23
+ import { invokedDirectly } from "../lib/invoked-directly.mjs";
24
+ import { findActiveRun } from "./_active-run.mjs";
25
+
26
+ const SESSION_BOUND = new Set(["session", "host-session"]);
27
+ const LIVE = new Set(["in_progress", "awaiting_input"]);
28
+ const COMMIT = /\bgit\b(?:\s+-[cC]\s+\S+|\s+--?[\w-]+(?:=\S+)?)*\s+commit\b/;
29
+
30
+ const real = (p) => {
31
+ try {
32
+ return realpathSync(resolve(p));
33
+ } catch {
34
+ return resolve(p);
35
+ }
36
+ };
37
+
38
+ /** The author email this command makes git record, or null to ask git. */
39
+ export function commandAuthor(command) {
40
+ const author = /--author[=\s]+(['"]?)[^<'"]*<([^>]+)>\1/.exec(command);
41
+ if (author) return author[2].trim();
42
+ const cfg = /-c\s+user\.email=(['"]?)([^\s'"]+)\1/.exec(command);
43
+ return cfg ? cfg[2].trim() : null;
44
+ }
45
+
46
+ /** The identity email the run expects for a commit in `repo`, or null. */
47
+ export function expectedEmail(state, repo) {
48
+ const here = real(repo);
49
+ for (const p of Array.isArray(state.projects) ? state.projects : []) {
50
+ if (p?.worktreePath && real(p.worktreePath) === here && p.identity?.email)
51
+ return p.identity.email;
52
+ }
53
+ return typeof state.identity?.email === "string" && state.identity.email
54
+ ? state.identity.email
55
+ : null;
56
+ }
57
+
58
+ function gitAuthorEmail(repo) {
59
+ const r = spawnSync("git", ["-C", repo, "var", "GIT_AUTHOR_IDENT"], {
60
+ encoding: "utf8",
61
+ timeout: 5000,
62
+ });
63
+ return /<([^>]*)>/.exec(r.stdout || "")?.[1]?.trim() || null;
64
+ }
65
+
66
+ /** The refusal line, or null. */
67
+ export function verdict(payload, repo, env = process.env) {
68
+ const command = payload?.tool_input?.command;
69
+ if (typeof command !== "string" || !COMMIT.test(command)) return null;
70
+ const run = findActiveRun({
71
+ sessionId: typeof payload.session_id === "string" ? payload.session_id : null,
72
+ cwd: typeof payload.cwd === "string" ? payload.cwd : repo,
73
+ env,
74
+ });
75
+ if (!run || !SESSION_BOUND.has(run.matchedBy) || !LIVE.has(run.state?.status)) return null;
76
+ const want = expectedEmail(run.state, repo);
77
+ if (!want) return null;
78
+ const got = commandAuthor(command) || gitAuthorEmail(repo);
79
+ if (!got || got.toLowerCase() === want.toLowerCase()) return null;
80
+ return `BLOCKED: this commit would be authored by ${got}, and run ${run.state.taskId || run.statePath} commits as ${want} (the identity chosen in Phase 0). Set the worktree's user.email to it, or drop the override.`;
81
+ }
82
+
83
+ function main(argv) {
84
+ const i = argv.indexOf("--repo");
85
+ const repo = i >= 0 && argv[i + 1] ? argv[i + 1] : process.cwd();
86
+ let payload;
87
+ try {
88
+ payload = JSON.parse(readFileSync(0, "utf8"));
89
+ } catch {
90
+ return 0;
91
+ }
92
+ const line = verdict(payload, repo);
93
+ if (!line) return 0;
94
+ process.stderr.write(`${line}\n`);
95
+ return 2;
96
+ }
97
+
98
+ if (invokedDirectly(import.meta.url)) {
99
+ try {
100
+ process.exitCode = main(process.argv.slice(2));
101
+ } catch {
102
+ process.exitCode = 0;
103
+ }
104
+ }
@@ -51,6 +51,12 @@ const FIGMA_TOOL = /^mcp__.*figma/i;
51
51
  const SESSION_BOUND = new Set(["session", "host-session"]);
52
52
  const LIVE = new Set(["in_progress", "awaiting_input"]);
53
53
  const FILE_TOOLS = new Set(["Edit", "Write", "NotebookEdit", "MultiEdit"]);
54
+ const STATE_FILES = new Set(["agent-state.json", "tracker-state.json"]);
55
+ const STATE_REDIRECT =
56
+ /(?:>>?|\btee\s+(?:-a\s+)?)\s*['"]?[^\s'"|;&]*(?:agent|tracker)-state\.json\b/;
57
+ const FIGMA_URL = /\bhttps?:\/\/(?:[\w-]+\.)*figma\.com(?=[/:?#\s'"]|$)/i;
58
+ const ADD_ALL = /\bgit\s+(?:-C\s+\S+\s+)?add\s+(?:[^;&|\n]*\s)?(?:-A|--all|\.)(?=$|[\s;&|])/;
59
+ const HTTP_CLIENT = /(?:^|[\s;&|(])(?:curl|wget|http|https|xh)\s/;
54
60
 
55
61
  const deny = (reason) => ({
56
62
  hookSpecificOutput: {
@@ -76,7 +82,39 @@ async function recordMcpCall(statePath, tool, phase) {
76
82
  });
77
83
  }
78
84
 
79
- async function figmaDecision(payload, run) {
85
+ /** A Figma design read over HTTP: a WebFetch of figma.com, or curl and the like at it. */
86
+ function figmaOverHttp(payload) {
87
+ const ti = payload.tool_input || {};
88
+ if (payload.tool_name === "WebFetch") return typeof ti.url === "string" && FIGMA_URL.test(ti.url);
89
+ if (payload.tool_name !== "Bash" || typeof ti.command !== "string") return false;
90
+ return HTTP_CLIENT.test(ti.command) && FIGMA_URL.test(ti.command);
91
+ }
92
+
93
+ /** An autopilot run answers its own questions: it derives, or it records a halt. */
94
+ function askDecision(run) {
95
+ const s = run.state;
96
+ if (!LIVE.has(s.status) || modeOf(s) !== "autopilot") return null;
97
+ return deny(
98
+ `run ${s.taskId || run.statePath} is on autopilot, which asks nobody. Derive the answer from the analysis, the repo and the preferences, or record a halt (status "paused" with a haltReason) for a decision only the user can make.`,
99
+ );
100
+ }
101
+
102
+ /** A write to run state that bypasses write-state.mjs, or null. */
103
+ function stateWriteDecision(payload) {
104
+ const ti = payload.tool_input || {};
105
+ const raw = FILE_TOOLS.has(payload.tool_name) ? ti.file_path || ti.notebook_path : null;
106
+ const byFile = typeof raw === "string" && STATE_FILES.has(basename(raw));
107
+ const byShell =
108
+ payload.tool_name === "Bash" &&
109
+ typeof ti.command === "string" &&
110
+ STATE_REDIRECT.test(ti.command);
111
+ if (!byFile && !byShell) return null;
112
+ return deny(
113
+ 'run state is written through write-state.mjs only, which locks the file, merges the patch and refuses unearned phase moves; pipe the patch into node "$HOME/.claude/scripts/write-state.mjs" <path> instead.',
114
+ );
115
+ }
116
+
117
+ async function figmaDecision(payload, run, { record = true } = {}) {
80
118
  const tool = payload.tool_name;
81
119
  const state = run.state;
82
120
  // A finished, failed or abandoned run governs nothing and records nothing.
@@ -88,7 +126,7 @@ async function figmaDecision(payload, run) {
88
126
  `${tool} is a Figma call at Phase ${at} of run ${state.taskId || run.statePath}. The design is read during analysis only (through Phase ${figmaThroughPhase()}); later phases work from the analysis document and the repo's Code Connect mappings. If a variant or value is missing, halt and re-run /multi-agent:analysis.`,
89
127
  );
90
128
  }
91
- await recordMcpCall(run.statePath, tool, Math.min(5, Math.max(0, at)));
129
+ if (record) await recordMcpCall(run.statePath, tool, Math.min(5, Math.max(0, at)));
92
130
  return null;
93
131
  }
94
132
 
@@ -152,8 +190,16 @@ function boundaryDecision(payload, run, env) {
152
190
  export async function decide(payload, env = process.env) {
153
191
  if (!payload || typeof payload !== "object") return null;
154
192
  const tool = typeof payload.tool_name === "string" ? payload.tool_name : "";
193
+ const stateWrite = stateWriteDecision(payload);
194
+ if (stateWrite) return stateWrite;
155
195
  const figma = FIGMA_TOOL.test(tool);
156
- if (!figma && !FILE_TOOLS.has(tool)) return null;
196
+ const figmaHttp = !figma && figmaOverHttp(payload);
197
+ const asking = tool === "AskUserQuestion";
198
+ const addAll =
199
+ tool === "Bash" &&
200
+ typeof payload.tool_input?.command === "string" &&
201
+ ADD_ALL.test(payload.tool_input.command);
202
+ if (!figma && !figmaHttp && !asking && !addAll && !FILE_TOOLS.has(tool)) return null;
157
203
  const run = findActiveRun({
158
204
  sessionId: typeof payload.session_id === "string" ? payload.session_id : null,
159
205
  cwd: typeof payload.cwd === "string" ? payload.cwd : null,
@@ -162,6 +208,15 @@ export async function decide(payload, env = process.env) {
162
208
  // Only a run bound to this session: an old local-mode run matched by its
163
209
  // worktree (the project root) must not govern every later session there.
164
210
  if (!run || !SESSION_BOUND.has(run.matchedBy)) return null;
211
+ if (asking) return askDecision(run);
212
+ if (addAll) {
213
+ return LIVE.has(run.state.status)
214
+ ? deny(
215
+ `run ${run.state.taskId || run.statePath} stages the task's files by name: git add -A, --all and . also take agent artefacts and anything sensitive in the tree.`,
216
+ )
217
+ : null;
218
+ }
219
+ if (figmaHttp) return figmaDecision(payload, run, { record: false });
165
220
  return figma ? figmaDecision(payload, run) : boundaryDecision(payload, run, env);
166
221
  }
167
222
 
@@ -19,5 +19,17 @@ CORE="$HERE/run-scope-guard.mjs"
19
19
  [ -f "$CORE" ] || exit 0
20
20
  command -v node >/dev/null 2>&1 || exit 0
21
21
 
22
- node "$CORE" 2>/dev/null || true
22
+ # Most Bash and WebFetch calls concern neither Figma nor run state; those end
23
+ # here without starting node.
24
+ INPUT="$(cat)"
25
+ case "$INPUT" in
26
+ *'"tool_name":"Bash"'* | *'"tool_name": "Bash"'* | *'"tool_name":"WebFetch"'* | *'"tool_name": "WebFetch"'*)
27
+ case "$INPUT" in
28
+ *[Ff]igma* | *agent-state.json* | *tracker-state.json* | *" add "*) ;;
29
+ *) exit 0 ;;
30
+ esac
31
+ ;;
32
+ esac
33
+
34
+ printf '%s' "$INPUT" | node "$CORE" 2>/dev/null || true
23
35
  exit 0