@opengsd/gsd-core 1.11.0 → 1.13.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 (498) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.opencode/plugins/gsd-core.js +12 -0
  4. package/agents/gsd-code-fixer.md +1 -1
  5. package/agents/gsd-debug-session-manager.md +1 -1
  6. package/agents/gsd-debugger.md +1 -1
  7. package/agents/gsd-dom-verifier.md +169 -0
  8. package/agents/gsd-eval-auditor.md +1 -1
  9. package/agents/gsd-executor.md +78 -42
  10. package/agents/gsd-framework-selector.md +1 -3
  11. package/agents/gsd-intel-updater.md +1 -1
  12. package/agents/gsd-mempalace-curator.md +0 -1
  13. package/agents/gsd-pattern-mapper.md +11 -0
  14. package/agents/gsd-phase-researcher.md +3 -1
  15. package/agents/gsd-plan-checker.md +91 -112
  16. package/agents/gsd-planner.md +20 -4
  17. package/agents/gsd-project-researcher.md +1 -1
  18. package/agents/gsd-research-synthesizer.md +2 -2
  19. package/agents/gsd-roadmapper.md +15 -11
  20. package/agents/gsd-ui-checker.md +82 -7
  21. package/agents/gsd-ui-researcher.md +70 -3
  22. package/agents/gsd-verifier.md +24 -2
  23. package/bin/install.js +847 -200
  24. package/commands/gsd/discuss-phase.md +1 -1
  25. package/commands/gsd/execute-phase.md +1 -1
  26. package/commands/gsd/import.md +1 -1
  27. package/commands/gsd/ns-workflow.md +2 -1
  28. package/commands/gsd/phase.md +1 -1
  29. package/commands/gsd/quick-batch.md +105 -0
  30. package/commands/gsd/quick.md +8 -4
  31. package/commands/gsd/surface.md +18 -8
  32. package/gsd-core/bin/gsd-tools.cjs +761 -100
  33. package/gsd-core/bin/lib/active-workstream-store.cjs +8 -0
  34. package/gsd-core/bin/lib/adr-parser.cjs +13 -7
  35. package/gsd-core/bin/lib/agent-install-check.cjs +162 -0
  36. package/gsd-core/bin/lib/api-coverage.cjs +30 -9
  37. package/gsd-core/bin/lib/artifacts.cjs +2 -0
  38. package/gsd-core/bin/lib/assumption-delta.cjs +30 -11
  39. package/gsd-core/bin/lib/audit.cjs +163 -41
  40. package/gsd-core/bin/lib/broken-windows.cjs +306 -28
  41. package/gsd-core/bin/lib/capability-activation.cjs +27 -0
  42. package/gsd-core/bin/lib/capability-lock.cjs +10 -4
  43. package/gsd-core/bin/lib/capability-registry.cjs +785 -144
  44. package/gsd-core/bin/lib/capability-state.cjs +25 -4
  45. package/gsd-core/bin/lib/capability-validator.cjs +321 -18
  46. package/gsd-core/bin/lib/capability-writer.cjs +14 -4
  47. package/gsd-core/bin/lib/check-command-router.cjs +229 -6
  48. package/gsd-core/bin/lib/claude-orchestration.cjs +10 -25
  49. package/gsd-core/bin/lib/cli-exit.cjs +496 -10
  50. package/gsd-core/bin/lib/clusters.cjs +1 -0
  51. package/gsd-core/bin/lib/code-review-depth.cjs +288 -0
  52. package/gsd-core/bin/lib/codex-agent-toml.cjs +410 -4
  53. package/gsd-core/bin/lib/command-aliases.cjs +16 -0
  54. package/gsd-core/bin/lib/command-arg-projection.cjs +144 -14
  55. package/gsd-core/bin/lib/command-routing-hub.cjs +31 -2
  56. package/gsd-core/bin/lib/commands.cjs +877 -54
  57. package/gsd-core/bin/lib/complexity-trigger.cjs +26 -6
  58. package/gsd-core/bin/lib/config-loader.cjs +121 -29
  59. package/gsd-core/bin/lib/config.cjs +92 -2
  60. package/gsd-core/bin/lib/configuration.cjs +129 -37
  61. package/gsd-core/bin/lib/core-utils.cjs +118 -14
  62. package/gsd-core/bin/lib/decisions.cjs +213 -1
  63. package/gsd-core/bin/lib/edge-probe.cjs +23 -2
  64. package/gsd-core/bin/lib/estimate-cli.cjs +55 -11
  65. package/gsd-core/bin/lib/exit-code-registry.cjs +98 -0
  66. package/gsd-core/bin/lib/file-overlap-partitioner.cjs +74 -0
  67. package/gsd-core/bin/lib/frontmatter.cjs +975 -326
  68. package/gsd-core/bin/lib/gap-checker.cjs +41 -8
  69. package/gsd-core/bin/lib/git-base-branch.cjs +182 -39
  70. package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +7 -3
  71. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +8 -2
  72. package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +60 -14
  73. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +75 -22
  74. package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +22 -8
  75. package/gsd-core/bin/lib/health-diagnostic.cjs +23 -3
  76. package/gsd-core/bin/lib/host-integration.cjs +96 -11
  77. package/gsd-core/bin/lib/init-command-router.cjs +132 -21
  78. package/gsd-core/bin/lib/init.cjs +252 -56
  79. package/gsd-core/bin/lib/install-engine.cjs +252 -15
  80. package/gsd-core/bin/lib/install-model-override-resolver.cjs +78 -1
  81. package/gsd-core/bin/lib/install-profiles.cjs +100 -18
  82. package/gsd-core/bin/lib/installer-migration-report.cjs +4 -0
  83. package/gsd-core/bin/lib/installer-migrations/010-antigravity-retire-confighome-artifacts.cjs +169 -0
  84. package/gsd-core/bin/lib/installer-migrations.cjs +10 -7
  85. package/gsd-core/bin/lib/intel.cjs +101 -26
  86. package/gsd-core/bin/lib/io.cjs +195 -15
  87. package/gsd-core/bin/lib/learnings.cjs +85 -14
  88. package/gsd-core/bin/lib/legacy-cleanup.cjs +8 -2
  89. package/gsd-core/bin/lib/loop-resolver.cjs +14 -8
  90. package/gsd-core/bin/lib/markdown-table.cjs +175 -4
  91. package/gsd-core/bin/lib/milestone.cjs +112 -7
  92. package/gsd-core/bin/lib/model-catalog.cjs +177 -19
  93. package/gsd-core/bin/lib/model-resolver.cjs +10 -28
  94. package/gsd-core/bin/lib/onboard-projection.cjs +5 -1
  95. package/gsd-core/bin/lib/phase-command-router.cjs +13 -6
  96. package/gsd-core/bin/lib/phase-estimation.cjs +17 -8
  97. package/gsd-core/bin/lib/phase-id.cjs +321 -13
  98. package/gsd-core/bin/lib/phase-lifecycle.cjs +24 -16
  99. package/gsd-core/bin/lib/phase-locator.cjs +138 -17
  100. package/gsd-core/bin/lib/phase.cjs +1175 -115
  101. package/gsd-core/bin/lib/plan-document.cjs +273 -0
  102. package/gsd-core/bin/lib/plan-scan.cjs +13 -2
  103. package/gsd-core/bin/lib/planning-command-router.cjs +61 -0
  104. package/gsd-core/bin/lib/planning-inspect.cjs +1168 -0
  105. package/gsd-core/bin/lib/planning-snapshot.cjs +165 -34
  106. package/gsd-core/bin/lib/planning-workspace.cjs +159 -28
  107. package/gsd-core/bin/lib/probe-core.cjs +4 -1
  108. package/gsd-core/bin/lib/profile-pipeline-command-router.cjs +50 -7
  109. package/gsd-core/bin/lib/profile-pipeline.cjs +6 -3
  110. package/gsd-core/bin/lib/quick-batch-command-router.cjs +285 -0
  111. package/gsd-core/bin/lib/quick-batch-dispatch.cjs +250 -0
  112. package/gsd-core/bin/lib/quick-batch.cjs +840 -0
  113. package/gsd-core/bin/lib/real-home-guard.cjs +419 -0
  114. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +71 -45
  115. package/gsd-core/bin/lib/review-lane-descriptor.cjs +62 -14
  116. package/gsd-core/bin/lib/review-lane-invocation.cjs +73 -1
  117. package/gsd-core/bin/lib/review-lane-runner.cjs +136 -10
  118. package/gsd-core/bin/lib/roadmap-command-router.cjs +45 -31
  119. package/gsd-core/bin/lib/roadmap-parser.cjs +577 -41
  120. package/gsd-core/bin/lib/roadmap.cjs +248 -64
  121. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +329 -41
  122. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +16 -17
  123. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +320 -109
  124. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +487 -83
  125. package/gsd-core/bin/lib/runtime-identity.cjs +234 -0
  126. package/gsd-core/bin/lib/runtime-slash.cjs +72 -2
  127. package/gsd-core/bin/lib/shell-command-projection.cjs +75 -8
  128. package/gsd-core/bin/lib/smart-entry.cjs +19 -31
  129. package/gsd-core/bin/lib/spec-section.cjs +12 -7
  130. package/gsd-core/bin/lib/state-command-router.cjs +47 -18
  131. package/gsd-core/bin/lib/state-contract.cjs +359 -0
  132. package/gsd-core/bin/lib/state-document.cjs +216 -5
  133. package/gsd-core/bin/lib/state-md-schema.cjs +231 -0
  134. package/gsd-core/bin/lib/state-transition.cjs +850 -145
  135. package/gsd-core/bin/lib/state.cjs +1629 -287
  136. package/gsd-core/bin/lib/surface.cjs +33 -10
  137. package/gsd-core/bin/lib/task-command-router.cjs +111 -1
  138. package/gsd-core/bin/lib/task-content-resolution.cjs +368 -0
  139. package/gsd-core/bin/lib/tdd-red-evidence.cjs +133 -0
  140. package/gsd-core/bin/lib/teams-status.cjs +4 -1
  141. package/gsd-core/bin/lib/uat-predicate.cjs +58 -20
  142. package/gsd-core/bin/lib/uat.cjs +2542 -387
  143. package/gsd-core/bin/lib/ui-consideration-probe.cjs +9 -1
  144. package/gsd-core/bin/lib/ui-safety-gate.cjs +37 -7
  145. package/gsd-core/bin/lib/unusable-input.cjs +13 -0
  146. package/gsd-core/bin/lib/update-context.cjs +6 -2
  147. package/gsd-core/bin/lib/validate-command-router.cjs +2 -2
  148. package/gsd-core/bin/lib/validate.cjs +230 -12
  149. package/gsd-core/bin/lib/vendor/README.md +43 -5
  150. package/gsd-core/bin/lib/vendor/js-yaml.cjs +3014 -0
  151. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  152. package/gsd-core/bin/lib/verification.cjs +287 -13
  153. package/gsd-core/bin/lib/verify-command-grounding.cjs +846 -0
  154. package/gsd-core/bin/lib/verify-command-router.cjs +1 -0
  155. package/gsd-core/bin/lib/verify.cjs +441 -56
  156. package/gsd-core/bin/lib/workstream-inventory.cjs +20 -2
  157. package/gsd-core/bin/lib/workstream-name-policy.cjs +25 -4
  158. package/gsd-core/bin/lib/worktree-base-ref.cjs +66 -12
  159. package/gsd-core/bin/lib/worktree-safety.cjs +185 -21
  160. package/gsd-core/bin/shared/config-defaults.manifest.json +7 -1
  161. package/gsd-core/bin/shared/config-schema.manifest.json +13 -0
  162. package/gsd-core/bin/shared/exit-codes.json +8 -0
  163. package/gsd-core/bin/shared/exit-codes.sh +20 -0
  164. package/gsd-core/bin/shared/model-catalog.json +8 -1
  165. package/gsd-core/bin/verify-reapply-patches.cjs +70 -3
  166. package/gsd-core/references/agent-contracts.md +6 -5
  167. package/gsd-core/references/api-coverage.md +24 -2
  168. package/gsd-core/references/autonomous-smart-discuss.md +3 -3
  169. package/gsd-core/references/checkpoints.md +37 -19
  170. package/gsd-core/references/decimal-phase-calculation.md +5 -5
  171. package/gsd-core/references/edge-probe.md +17 -5
  172. package/gsd-core/references/execute-mvp-tdd.md +18 -18
  173. package/gsd-core/references/execute-phase-between-wave-reset.md +9 -12
  174. package/gsd-core/references/execute-phase-response-language.md +6 -0
  175. package/gsd-core/references/execute-phase-wave-guard.md +11 -9
  176. package/gsd-core/references/executor-examples.md +42 -0
  177. package/gsd-core/references/failing-direction.md +78 -0
  178. package/gsd-core/references/few-shot-examples/plan-checker.md +15 -15
  179. package/gsd-core/references/gate-prompts.md +1 -1
  180. package/gsd-core/references/git-integration.md +5 -5
  181. package/gsd-core/references/git-planning-commit.md +3 -3
  182. package/gsd-core/references/gsd-run-resolver.md +1 -1
  183. package/gsd-core/references/loop-hook-dispatch.md +22 -0
  184. package/gsd-core/references/model-profiles.md +1 -1
  185. package/gsd-core/references/mvp-concepts.md +2 -2
  186. package/gsd-core/references/nyquist-compliance.md +74 -0
  187. package/gsd-core/references/offer-next.md +3 -5
  188. package/gsd-core/references/phase-argument-parsing.md +3 -3
  189. package/gsd-core/references/plan-checker-examples.md +41 -0
  190. package/gsd-core/references/planner-antipatterns.md +25 -0
  191. package/gsd-core/references/planner-chunked.md +5 -1
  192. package/gsd-core/references/planner-coupling.md +42 -0
  193. package/gsd-core/references/planner-failing-direction.md +53 -0
  194. package/gsd-core/references/planner-human-verify-mode.md +15 -1
  195. package/gsd-core/references/planner-quick-batch.md +71 -0
  196. package/gsd-core/references/planner-reviews.md +47 -0
  197. package/gsd-core/references/planner-revision.md +76 -3
  198. package/gsd-core/references/planner-verify-command-grounding.md +17 -0
  199. package/gsd-core/references/planning-config.md +39 -9
  200. package/gsd-core/references/response-language-directive.md +9 -0
  201. package/gsd-core/references/reviewer-instances.md +31 -0
  202. package/gsd-core/references/revision-loop.md +118 -11
  203. package/gsd-core/references/runtime-aware-dispatch.md +1 -1
  204. package/gsd-core/references/tdd.md +15 -12
  205. package/gsd-core/references/ui-brand.md +65 -21
  206. package/gsd-core/references/ui-consideration-probe.md +1 -1
  207. package/gsd-core/references/universal-anti-patterns.md +2 -2
  208. package/gsd-core/references/verifier-evidence-gate.md +160 -0
  209. package/gsd-core/references/verify-command-path-resolvability.md +42 -0
  210. package/gsd-core/references/verify-mvp-mode.md +1 -1
  211. package/gsd-core/references/workstream-flag.md +11 -11
  212. package/gsd-core/templates/README.md +1 -1
  213. package/gsd-core/templates/SECURITY.md +3 -3
  214. package/gsd-core/templates/UI-SPEC.md +25 -3
  215. package/gsd-core/templates/VALIDATION.md +3 -3
  216. package/gsd-core/templates/phase-prompt.md +7 -0
  217. package/gsd-core/templates/state.md +7 -0
  218. package/gsd-core/templates/verification-report.md +5 -0
  219. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  220. package/gsd-core/workflows/add-backlog.md +3 -1
  221. package/gsd-core/workflows/add-phase.md +5 -3
  222. package/gsd-core/workflows/add-tests.md +4 -9
  223. package/gsd-core/workflows/add-todo.md +2 -2
  224. package/gsd-core/workflows/ai-integration-phase.md +5 -10
  225. package/gsd-core/workflows/analyze-dependencies.md +2 -0
  226. package/gsd-core/workflows/audit-fix.md +14 -3
  227. package/gsd-core/workflows/audit-milestone.md +11 -9
  228. package/gsd-core/workflows/audit-uat.md +19 -2
  229. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +2 -2
  230. package/gsd-core/workflows/autonomous.md +12 -26
  231. package/gsd-core/workflows/check-todos.md +2 -2
  232. package/gsd-core/workflows/cleanup.md +3 -3
  233. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +16 -14
  234. package/gsd-core/workflows/code-review-fix.md +3 -1
  235. package/gsd-core/workflows/code-review.md +192 -69
  236. package/gsd-core/workflows/complete-milestone.md +28 -14
  237. package/gsd-core/workflows/debug.md +6 -4
  238. package/gsd-core/workflows/diagnose-issues.md +17 -7
  239. package/gsd-core/workflows/discuss-phase/modes/advisor.md +3 -1
  240. package/gsd-core/workflows/discuss-phase/modes/all.md +2 -0
  241. package/gsd-core/workflows/discuss-phase/modes/analyze.md +2 -0
  242. package/gsd-core/workflows/discuss-phase/modes/auto.md +2 -0
  243. package/gsd-core/workflows/discuss-phase/modes/batch.md +2 -0
  244. package/gsd-core/workflows/discuss-phase/modes/chain.md +5 -7
  245. package/gsd-core/workflows/discuss-phase/modes/default.md +2 -0
  246. package/gsd-core/workflows/discuss-phase/modes/power.md +2 -0
  247. package/gsd-core/workflows/discuss-phase/modes/text.md +3 -1
  248. package/gsd-core/workflows/discuss-phase/templates/context.md +2 -0
  249. package/gsd-core/workflows/discuss-phase/templates/discussion-log.md +2 -0
  250. package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +1 -3
  251. package/gsd-core/workflows/discuss-phase-assumptions.md +3 -3
  252. package/gsd-core/workflows/discuss-phase-power.md +2 -0
  253. package/gsd-core/workflows/discuss-phase.md +2 -2
  254. package/gsd-core/workflows/do.md +46 -19
  255. package/gsd-core/workflows/docs-update.md +6 -5
  256. package/gsd-core/workflows/edit-phase.md +3 -1
  257. package/gsd-core/workflows/eval-review.md +5 -10
  258. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +3 -1
  259. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +129 -11
  260. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +1 -1
  261. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +1 -1
  262. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
  263. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +29 -5
  264. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +2 -2
  265. package/gsd-core/workflows/execute-phase/steps/protected-branch.md +21 -0
  266. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +4 -2
  267. package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +25 -0
  268. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +39 -0
  269. package/gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md +2 -0
  270. package/gsd-core/workflows/execute-phase.md +68 -66
  271. package/gsd-core/workflows/execute-plan.md +25 -20
  272. package/gsd-core/workflows/explore.md +3 -1
  273. package/gsd-core/workflows/extract-learnings.md +3 -1
  274. package/gsd-core/workflows/fast.md +8 -2
  275. package/gsd-core/workflows/forensics.md +3 -1
  276. package/gsd-core/workflows/graduation.md +6 -6
  277. package/gsd-core/workflows/health.md +4 -7
  278. package/gsd-core/workflows/help/modes/brief.md +2 -0
  279. package/gsd-core/workflows/help/modes/default.md +2 -0
  280. package/gsd-core/workflows/help/modes/full.md +12 -0
  281. package/gsd-core/workflows/help/modes/topic.md +2 -0
  282. package/gsd-core/workflows/help.md +2 -0
  283. package/gsd-core/workflows/import.md +17 -14
  284. package/gsd-core/workflows/inbox.md +5 -6
  285. package/gsd-core/workflows/ingest-docs.md +45 -12
  286. package/gsd-core/workflows/insert-phase.md +7 -5
  287. package/gsd-core/workflows/list-phase-assumptions.md +2 -0
  288. package/gsd-core/workflows/list-seeds.md +7 -3
  289. package/gsd-core/workflows/list-workspaces.md +3 -1
  290. package/gsd-core/workflows/manager.md +15 -26
  291. package/gsd-core/workflows/map-codebase.md +3 -1
  292. package/gsd-core/workflows/milestone-summary.md +3 -1
  293. package/gsd-core/workflows/mvp-phase.md +3 -3
  294. package/gsd-core/workflows/new-milestone.md +10 -22
  295. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
  296. package/gsd-core/workflows/new-project.md +17 -29
  297. package/gsd-core/workflows/new-workspace.md +2 -2
  298. package/gsd-core/workflows/next.md +4 -2
  299. package/gsd-core/workflows/node-repair.md +2 -0
  300. package/gsd-core/workflows/note.md +2 -0
  301. package/gsd-core/workflows/onboard.md +1 -1
  302. package/gsd-core/workflows/pause-work.md +20 -5
  303. package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +1 -1
  304. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +100 -18
  305. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +4 -4
  306. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +12 -3
  307. package/gsd-core/workflows/plan-phase.md +251 -54
  308. package/gsd-core/workflows/plan-review-convergence.md +148 -19
  309. package/gsd-core/workflows/plant-seed.md +3 -3
  310. package/gsd-core/workflows/pr-branch.md +195 -51
  311. package/gsd-core/workflows/profile-user.md +17 -15
  312. package/gsd-core/workflows/progress/steps/forensic-audit.md +1 -1
  313. package/gsd-core/workflows/progress.md +52 -15
  314. package/gsd-core/workflows/quick/steps/discussion-phase.md +1 -3
  315. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +38 -5
  316. package/gsd-core/workflows/quick/steps/quick-verification.md +2 -4
  317. package/gsd-core/workflows/quick/steps/research-phase.md +5 -7
  318. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +3 -3
  319. package/gsd-core/workflows/quick-batch/steps/batch-init.md +55 -0
  320. package/gsd-core/workflows/quick-batch/steps/completion.md +65 -0
  321. package/gsd-core/workflows/quick-batch/steps/merge-wave.md +100 -0
  322. package/gsd-core/workflows/quick-batch/steps/plan-checker-loop.md +147 -0
  323. package/gsd-core/workflows/quick-batch/steps/planner-wave.md +158 -0
  324. package/gsd-core/workflows/quick-batch/steps/research-phase.md +95 -0
  325. package/gsd-core/workflows/quick-batch/steps/resume-mode.md +49 -0
  326. package/gsd-core/workflows/quick-batch/steps/verification-wave.md +73 -0
  327. package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +169 -0
  328. package/gsd-core/workflows/quick-batch.md +203 -0
  329. package/gsd-core/workflows/quick.md +33 -32
  330. package/gsd-core/workflows/reapply-patches.md +2 -0
  331. package/gsd-core/workflows/remove-phase.md +6 -4
  332. package/gsd-core/workflows/remove-workspace.md +3 -3
  333. package/gsd-core/workflows/resume-project.md +14 -14
  334. package/gsd-core/workflows/review.md +404 -21
  335. package/gsd-core/workflows/scan.md +3 -1
  336. package/gsd-core/workflows/section-manifest.json +12 -0
  337. package/gsd-core/workflows/secure-phase.md +3 -3
  338. package/gsd-core/workflows/session-report.md +2 -0
  339. package/gsd-core/workflows/settings-advanced.md +9 -9
  340. package/gsd-core/workflows/settings-integrations.md +66 -32
  341. package/gsd-core/workflows/settings.md +4 -6
  342. package/gsd-core/workflows/ship.md +22 -16
  343. package/gsd-core/workflows/sketch-wrap-up.md +13 -17
  344. package/gsd-core/workflows/sketch.md +13 -19
  345. package/gsd-core/workflows/smart-entry.md +4 -6
  346. package/gsd-core/workflows/spec-phase.md +31 -4
  347. package/gsd-core/workflows/spike-wrap-up.md +9 -11
  348. package/gsd-core/workflows/spike.md +21 -32
  349. package/gsd-core/workflows/stats.md +4 -2
  350. package/gsd-core/workflows/sync-skills.md +13 -5
  351. package/gsd-core/workflows/thread.md +13 -7
  352. package/gsd-core/workflows/transition.md +7 -5
  353. package/gsd-core/workflows/ui-phase.md +36 -21
  354. package/gsd-core/workflows/ui-review.md +7 -11
  355. package/gsd-core/workflows/ultraplan-phase.md +7 -13
  356. package/gsd-core/workflows/undo.md +9 -17
  357. package/gsd-core/workflows/update.md +47 -48
  358. package/gsd-core/workflows/validate-phase.md +3 -3
  359. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +25 -1
  360. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
  361. package/gsd-core/workflows/verify-work.md +106 -21
  362. package/hooks/dist/gsd-agent-isolation-guard.js +77 -38
  363. package/hooks/dist/gsd-check-update-worker.js +19 -2
  364. package/hooks/dist/gsd-config-reload.js +18 -12
  365. package/hooks/dist/gsd-context-monitor.js +302 -22
  366. package/hooks/dist/gsd-cursor-post-tool.js +3 -1
  367. package/hooks/dist/gsd-cursor-pre-tool.js +3 -1
  368. package/hooks/dist/gsd-cursor-session-start.js +2 -1
  369. package/hooks/dist/gsd-cursor-stop.js +2 -1
  370. package/hooks/dist/gsd-cursor-subagent-start.js +28 -23
  371. package/hooks/dist/gsd-cursor-subagent-stop.js +3 -1
  372. package/hooks/dist/gsd-ensure-canonical-path.js +2 -1
  373. package/hooks/dist/gsd-graphify-update.sh +22 -18
  374. package/hooks/dist/gsd-node-runner.sh +77 -0
  375. package/hooks/dist/gsd-phase-boundary.sh +1 -0
  376. package/hooks/dist/gsd-prompt-guard.js +46 -12
  377. package/hooks/dist/gsd-read-guard.js +18 -7
  378. package/hooks/dist/gsd-read-injection-scanner.js +22 -13
  379. package/hooks/dist/gsd-secret-read-guard.js +1079 -0
  380. package/hooks/dist/gsd-session-state.sh +1 -0
  381. package/hooks/dist/gsd-statusline.js +222 -29
  382. package/hooks/dist/gsd-validate-commit.sh +523 -12
  383. package/hooks/dist/gsd-windsurf-pre-command.js +16 -11
  384. package/hooks/dist/gsd-windsurf-pre-write.js +22 -13
  385. package/hooks/dist/gsd-workflow-guard.js +36 -17
  386. package/hooks/dist/gsd-worktree-path-guard.js +36 -21
  387. package/hooks/dist/gsd-write-guard.js +35 -25
  388. package/hooks/dist/lib/cli-exit.js +560 -0
  389. package/hooks/dist/lib/exit-code-registry.js +98 -0
  390. package/hooks/dist/lib/git-cmd.js +210 -1
  391. package/hooks/dist/lib/git-probe.js +84 -0
  392. package/hooks/dist/lib/hook-exit.js +81 -0
  393. package/hooks/dist/lib/injection-patterns.js +36 -6
  394. package/hooks/dist/managed-hooks-registry.cjs +4 -0
  395. package/hooks/gsd-agent-isolation-guard.js +77 -38
  396. package/hooks/gsd-check-update-worker.js +19 -2
  397. package/hooks/gsd-config-reload.js +18 -12
  398. package/hooks/gsd-context-monitor.js +302 -22
  399. package/hooks/gsd-cursor-post-tool.js +3 -1
  400. package/hooks/gsd-cursor-pre-tool.js +3 -1
  401. package/hooks/gsd-cursor-session-start.js +2 -1
  402. package/hooks/gsd-cursor-stop.js +2 -1
  403. package/hooks/gsd-cursor-subagent-start.js +28 -23
  404. package/hooks/gsd-cursor-subagent-stop.js +3 -1
  405. package/hooks/gsd-ensure-canonical-path.js +2 -1
  406. package/hooks/gsd-graphify-update.sh +22 -18
  407. package/hooks/gsd-node-runner.sh +77 -0
  408. package/hooks/gsd-phase-boundary.sh +1 -0
  409. package/hooks/gsd-prompt-guard.js +46 -12
  410. package/hooks/gsd-read-guard.js +18 -7
  411. package/hooks/gsd-read-injection-scanner.js +22 -13
  412. package/hooks/gsd-secret-read-guard.js +1079 -0
  413. package/hooks/gsd-session-state.sh +1 -0
  414. package/hooks/gsd-statusline.js +222 -29
  415. package/hooks/gsd-validate-commit.sh +523 -12
  416. package/hooks/gsd-windsurf-pre-command.js +16 -11
  417. package/hooks/gsd-windsurf-pre-write.js +22 -13
  418. package/hooks/gsd-workflow-guard.js +36 -17
  419. package/hooks/gsd-worktree-path-guard.js +36 -21
  420. package/hooks/gsd-write-guard.js +35 -25
  421. package/hooks/hooks.json +6 -0
  422. package/hooks/lib/cli-exit.js +560 -0
  423. package/hooks/lib/exit-code-registry.js +98 -0
  424. package/hooks/lib/git-cmd.js +210 -1
  425. package/hooks/lib/git-probe.js +84 -0
  426. package/hooks/lib/hook-exit.js +81 -0
  427. package/hooks/lib/injection-patterns.js +36 -6
  428. package/hooks/managed-hooks-registry.cjs +4 -0
  429. package/package.json +14 -9
  430. package/scripts/base64-scan.sh +74 -12
  431. package/scripts/build-hooks.js +12 -0
  432. package/scripts/check-glossary-refs.cjs +77 -15
  433. package/scripts/check-mutation-score-ratchet.cjs +156 -0
  434. package/scripts/ci-check-job-near-cap.cjs +49 -0
  435. package/scripts/ci-pr-mergeability.cjs +262 -0
  436. package/scripts/ci-test-scope.cjs +52 -12
  437. package/scripts/ci-timeout-report.cjs +230 -0
  438. package/scripts/docs-guard-registry.cjs +406 -0
  439. package/scripts/gen-capability-registry.cjs +8 -6
  440. package/scripts/gen-exit-code-docs.cjs +318 -0
  441. package/scripts/gen-exit-code-registry.cjs +891 -0
  442. package/scripts/gen-features.cjs +836 -0
  443. package/scripts/gen-hooks-cli-exit.cjs +239 -0
  444. package/scripts/gen-install-tree-fixtures.cjs +2 -2
  445. package/scripts/gen-loop-host-contract.cjs +189 -4
  446. package/scripts/gen-scripts-cli-exit.cjs +185 -0
  447. package/scripts/gen-state-md-docs.cjs +727 -0
  448. package/scripts/{test-failure-reasons.cjs → gsd-test-gate-reasons.cjs} +6 -0
  449. package/scripts/lib/ci-job-timing.cjs +72 -0
  450. package/scripts/lib/cli-exit.cjs +546 -44
  451. package/scripts/lib/drift-scan.cjs +32 -2
  452. package/scripts/lib/exit-code-registry.cjs +98 -0
  453. package/scripts/lib/ndjson-reporter.cjs +119 -0
  454. package/scripts/lib/shellcheck-fetch.cjs +247 -0
  455. package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -6
  456. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
  457. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
  458. package/scripts/lint-docs-guard-registration.cjs +495 -0
  459. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +198 -0
  460. package/scripts/lint-eslint-glob-coverage.allowlist.json +4 -0
  461. package/scripts/{lint-fix-has-regression-test.cjs → lint-fix-has-regression-tests.cjs} +12 -6
  462. package/scripts/lint-health-diagnostic-rule-table.cjs +65 -8
  463. package/scripts/lint-mutation-test-derivation-drift.cjs +86 -0
  464. package/scripts/lint-phase-enumeration-drift.cjs +45 -14
  465. package/scripts/lint-phase-id-drift.cjs +133 -8
  466. package/scripts/lint-planning-prompt-drift.cjs +38 -1
  467. package/scripts/lint-portable-grep.cjs +176 -0
  468. package/scripts/lint-removed-but-needed.cjs +184 -16
  469. package/scripts/lint-response-language-coverage.cjs +524 -0
  470. package/scripts/lint-seam-enforcement.cjs +182 -0
  471. package/scripts/lint-slug-derivation-drift.cjs +921 -0
  472. package/scripts/lint-source-test-name-collision.cjs +241 -0
  473. package/scripts/lint-state-write-path-drift.cjs +337 -432
  474. package/scripts/lint-test-file-count.allowlist.json +124 -4
  475. package/scripts/lint-test-file-count.cjs +25 -3
  476. package/scripts/lint-unreachable-guard-drift.cjs +51 -64
  477. package/scripts/lint-vendored-deps.cjs +208 -35
  478. package/scripts/lint-workflow-shellcheck-baseline.json +1027 -0
  479. package/scripts/lint-workflow-shellcheck.cjs +614 -0
  480. package/scripts/mutation-matrix.cjs +599 -50
  481. package/scripts/npm-audit-baseline.cjs +376 -0
  482. package/scripts/prompt-injection-scan.sh +83 -14
  483. package/scripts/require-issue-link-policy.cjs +16 -1
  484. package/scripts/secret-scan.sh +75 -13
  485. package/scripts/select-docs-guards.cjs +56 -0
  486. package/scripts/sync-runtime-launcher.cjs +22 -3
  487. package/skills/gsd-discuss-phase/SKILL.md +1 -1
  488. package/skills/gsd-execute-phase/SKILL.md +1 -1
  489. package/skills/gsd-import/SKILL.md +1 -1
  490. package/skills/gsd-ns-workflow/SKILL.md +1 -0
  491. package/skills/gsd-phase/SKILL.md +1 -1
  492. package/skills/gsd-quick/SKILL.md +8 -4
  493. package/skills/gsd-quick-batch/SKILL.md +105 -0
  494. package/skills/gsd-surface/SKILL.md +18 -8
  495. package/vscode/package.json +1 -1
  496. package/bin/lib/ui-safety-gate.cjs +0 -109
  497. package/scripts/lint-emitted-drift-ack.cjs +0 -344
  498. package/scripts/state-write-path-drift-baseline.json +0 -19
@@ -37,7 +37,7 @@ No Pass/Fail buttons. No severity questions. Just: "Here's what should happen. D
37
37
  If $ARGUMENTS contains a phase number, load context:
38
38
 
39
39
  ```bash
40
- _GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif command -v gsd-tools >/dev/null 2>&1; then GSD_TOOLS="$(command -v gsd-tools)"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif [ -f "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${GSD_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${GSD_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
40
+ _GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; _gsd_at() { for _p; do if [ -f "$_p" ]; then GSD_TOOLS="$_p"; return 0; fi; done; return 1; }; if _gsd_at "${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}" "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" "${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}"; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif unset -f gsd_run; _G="$(command -v gsd_run)"; then GSD_TOOLS="$_G"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif _gsd_at "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}" "${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}" "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}" "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}" "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}" "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}" "${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}" "${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}" "${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}" "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}" "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}" "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}"; then gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd_run is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi; GSD_IDENTITY_STATUS=unverified; case "$(gsd_run runtime-identity --raw 2>/dev/null || true)" in '{"packageName":"@opengsd/gsd-core"'*'}') GSD_IDENTITY_STATUS=ok;; esac; export GSD_IDENTITY_STATUS; [ "$GSD_IDENTITY_STATUS" = ok ] || echo "WARNING: \"$GSD_TOOLS\" did not prove it is @opengsd/gsd-core - it is either a different package or an @opengsd/gsd-core older than the runtime-identity verb. See docs/how-to/diagnose-a-foreign-gsd-tools.md" >&2; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${GSD_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${GSD_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
41
41
  GSD_WS=""
42
42
  echo "$ARGUMENTS" | grep -qE -- '--ws[[:space:]]+[A-Za-z0-9._-]+' && GSD_WS=$(echo "$ARGUMENTS" | grep -oE -- '--ws[[:space:]]+[A-Za-z0-9._-]+')
43
43
  PHASE_ARG=$(echo "$ARGUMENTS" | sed -E 's/--ws[[:space:]]+[A-Za-z0-9._-]+//g' | xargs)
@@ -50,7 +50,7 @@ AGENT_SKILLS_CHECKER=$(gsd_run query agent-skills gsd-plan-checker)
50
50
 
51
51
  Parse JSON for: `planner_model`, `checker_model`, `commit_docs`, `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `has_verification`, `uat_path`, `state_path`, `roadmap_path`, `response_language`.
52
52
 
53
- **If `response_language` is set:** All user-facing questions, prompts, and explanations in this workflow MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
53
+ **If `response_language` is set:** All user-facing output of this workflow — narration between tool calls, status updates, progress notes, findings, questions, prompts, and explanations — MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
54
54
 
55
55
  ```bash
56
56
  # MVP mode detection via the centralized phase.mvp-mode resolver.
@@ -61,15 +61,26 @@ MVP_MODE=$(gsd_run query phase.mvp-mode "${phase_number}" ${GSD_WS} --pick activ
61
61
  </step>
62
62
 
63
63
  <step name="verify_pre_hooks">
64
- **Verify:pre gate dispatch.** Before verification begins, dispatch every active
65
- gate hook registered at the `verify:pre` loop extension point. Each gate is
66
- data-driven — resolved from the capability registry, not hardcoded here.
64
+ **Verify:pre capability dispatch.** Before verification begins, dispatch every
65
+ active hook registered at the `verify:pre` loop extension point — of **every**
66
+ kind, not gates alone. Each hook is data-driven — resolved from the capability
67
+ registry, not hardcoded here.
67
68
 
68
69
  ```bash
69
70
  VERIFY_PRE_HOOKS_JSON=$(gsd_run loop render-hooks verify:pre --raw)
70
71
  PHASE_DIR=$(printf '%s' "$INIT" | jq -r '.phase_dir // empty')
71
72
  ```
72
73
 
74
+ Read the `activeHooks` array from `VERIFY_PRE_HOOKS_JSON` in-context (do NOT pipe through a shell parser).
75
+
76
+ **If `activeHooks` is empty or absent:** skip silently to `check_active_session`.
77
+
78
+ **Contribution dispatch:** inject every `kind == "contribution"` fragment per @gsd-core/references/loop-hook-dispatch.md (skip when none), before the steps and gates below.
79
+
80
+ **Step dispatch:** dispatch every `kind == "step"` hook per @gsd-core/references/loop-hook-dispatch.md (skip when none) — not one shape of one. A step here is advisory: it never blocks the start of UAT, and a step that errors is routed by its own `onError` without failing verification. ⚠ **Validate `ref.command` in-context before any shell use** (third-party manifest input) — loop-hook-dispatch.md § `step`.
81
+
82
+ Record the union of `produces` artefact names declared by the active step entries as `VERIFY_PRE_PRODUCED` — `extract_tests` consumes it below. An entry declaring `produces: []` contributes nothing, which is the normal case.
83
+
73
84
  ⚠ **Validate `check` before shell use** (third-party manifest input) — `loop-hook-dispatch.md` § `gate`.
74
85
 
75
86
  Resolve active gate hooks from `VERIFY_PRE_HOOKS_JSON` where `kind == "gate"`.
@@ -161,6 +172,27 @@ ls "$phase_dir"/*-SUMMARY.md 2>/dev/null || true
161
172
  ```
162
173
 
163
174
  Read each SUMMARY.md to extract testable deliverables.
175
+
176
+ **Commit-claim reconciliation (#3968).** A SUMMARY's `commits:` frontmatter is a MEASURED
177
+ number (the executor derives it from its on-disk plan commit ledger and records the base as
178
+ `plan_head_before:`), and this is where that claim is checked against reality with the SAME
179
+ instrument — the executor's own narration is never the last word. For each `*-SUMMARY.md`:
180
+ ```bash
181
+ BASE=$(grep -oE '^plan_head_before: [0-9a-f]{7,40}' "$SUMMARY_FILE" | awk '{print $2}')
182
+ CLAIMED=$(grep -oE '^commits: [0-9]+' "$SUMMARY_FILE" | grep -oE '[0-9]+' || echo absent)
183
+ ACTUAL=$(git rev-list --count "${BASE}"..HEAD)
184
+ ```
185
+ - A `commits: absent` or `plan_head_before: absent` SUMMARY (pre-#3968 legacy) is reported as
186
+ a WARNING with the measured git state, not a mismatch.
187
+ - `ACTUAL == CLAIMED` is consistent. `ACTUAL == CLAIMED + 1` is ALSO consistent: the
188
+ SUMMARY/metadata commit itself lands after the executor measured, so exactly one
189
+ post-measurement commit is expected.
190
+ - Anything else is a **BLOCKER** — the phase must not read as done: real project evidence
191
+ (#3968) showed 14 plans declaring `commits: 1` with zero git activity, their code sitting
192
+ uncommitted and one `git reset --hard` from loss. Record it as `commit_claim_mismatch`
193
+ with both numbers and the SUMMARY path; a mismatch means either the executor narrated
194
+ instead of measuring or commits were lost after the fact — both require reconciliation
195
+ before the phase can pass.
164
196
  </step>
165
197
 
166
198
  <step name="extract_tests">
@@ -187,6 +219,35 @@ Read the JSON result (`mode`, `total`, `all_auto_covered`, `auto_passed[]`, `pre
187
219
 
188
220
  The cold-start smoke test injection below still applies in `coverage` mode.
189
221
 
222
+ **Verify:pre produced-artefact seam (#3866).** If `VERIFY_PRE_PRODUCED` (recorded in
223
+ `verify_pre_hooks`) is empty or absent, skip this paragraph entirely — derivation is unchanged.
224
+ Otherwise, for each artefact name in it, locate the artefact the producing step wrote under
225
+ `$PHASE_DIR` and merge its checkpoints into the test list **additively**.
226
+
227
+ **The artefact contract.** A consumable artefact is a Markdown file holding a list of checkpoint
228
+ entries in the **same shape `extract_tests` already emits and `create_uat_file` already consumes** —
229
+ each entry a `name` (brief test name) and an `expected` (specific, user-observable outcome).
230
+ Nothing else is read: extra fields are ignored, not an error. There is no new schema and no new
231
+ parser — a producing step writes what a checkpoint already looks like. An artefact that yields zero
232
+ parseable entries is treated exactly like an absent one (see below).
233
+
234
+ Merge rules:
235
+
236
+ - ⚠ **Validate the artefact name in-context before resolving it** (third-party manifest input).
237
+ An artefact name is a registry-declared name, **not** a path: check the value you read from
238
+ `produces` against `^[A-Za-z0-9][A-Za-z0-9._-]*$` yourself — **never** by pasting it into a
239
+ shell command to be tested there. A name carrying `/`, `..`, a leading `-`, a leading path
240
+ separator, or any shell metacharacter is a malformed manifest: record a warning, skip that
241
+ name, continue. Only a validated name is resolved, and only against what the step wrote inside
242
+ `$PHASE_DIR` — never above it, and never through a symlink that leaves it.
243
+ - A name with no artefact on disk means that step was inactive, skipped, or failed. Note it to the
244
+ user and derive normally — **never drop a deliverable and never block UAT over it.**
245
+ - Merged entries are added to, never subtracted from, what `coverage:` classification and the
246
+ prose fallback produce. An `auto_passed[]` entry stays un-presented; a `present[]` entry stays a
247
+ human checkpoint. This seam can deepen UAT, not suppress it.
248
+ - Deduplicate against already-derived checkpoints by `name`, keeping the earlier entry's
249
+ `expected` text so a produced artefact cannot silently rewrite a criterion.
250
+
190
251
  **Extract testable deliverables from SUMMARY.md (legacy fallback — used when `mode: legacy`):**
191
252
 
192
253
  Parse for:
@@ -534,6 +595,8 @@ VERIFY_POST_HOOKS_JSON=$(gsd_run loop render-hooks verify:post --raw)
534
595
  SECURITY_FILE=$(ls "${PHASE_DIR}"/*-SECURITY.md 2>/dev/null | head -1)
535
596
  ```
536
597
 
598
+ **Generic step dispatch:** dispatch every `kind == "step"` hook from `VERIFY_POST_HOOKS_JSON` per @gsd-core/references/loop-hook-dispatch.md (skip silently when none). Each step is advisory and best-effort — honor `onError` and continue. The secure-phase handling below is an additional specialization of one such hook, not a replacement for the generic dispatch.
599
+
537
600
  Resolve active step hooks from `VERIFY_POST_HOOKS_JSON` where `kind == "step"` and `ref.skill == "secure-phase"`.
538
601
 
539
602
  If an active secure-phase step hook exists AND `SECURITY_FILE` is empty, dispatch the registry-provided skill stem:
@@ -633,7 +696,7 @@ All tests passed. Phase {phase} marked complete.
633
696
  <step name="scan_phase_artifacts">
634
697
  Run phase artifact scan to surface any open items before marking phase verified:
635
698
 
636
- `audit-open` is CJS-only until registered on `gsd-tools.cjs query`:
699
+ `audit-open` is CJS-only until registered on `gsd_run query`:
637
700
 
638
701
  ```bash
639
702
  gsd_run query audit-open --json
@@ -647,9 +710,12 @@ Parse the JSON output. For the CURRENT PHASE ONLY, surface:
647
710
  If any are found, display:
648
711
  ```
649
712
  Phase {N} Artifact Check
650
- ─────────────────────────────────────────────────
713
+
714
+ ---
715
+
651
716
  {list each item with status and file path}
652
- ─────────────────────────────────────────────────
717
+
718
+ ---
653
719
  These items are open. Proceed anyway? [Y/n]
654
720
  ```
655
721
 
@@ -685,9 +751,7 @@ Diagnosis runs automatically - no user prompt. Parallel agents investigate simul
685
751
 
686
752
  Display:
687
753
  ```
688
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
689
- GSD ► PLANNING FIXES
690
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
754
+ ### GSD ► PLANNING FIXES
691
755
 
692
756
  ◆ Spawning planner for gap closure... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
693
757
  ```
@@ -752,9 +816,7 @@ On return:
752
816
 
753
817
  Display:
754
818
  ```
755
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
756
- GSD ► VERIFYING FIX PLANS
757
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
819
+ ### GSD ► VERIFYING FIX PLANS
758
820
 
759
821
  ◆ Spawning plan checker... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
760
822
  ```
@@ -795,7 +857,7 @@ Return one of:
795
857
 
796
858
  On return:
797
859
  - **VERIFICATION PASSED:** Proceed to `present_ready`
798
- - **ISSUES FOUND:** Proceed to `revision_loop`
860
+ - **ISSUES FOUND:** Count BLOCKER + WARNING entries in the YAML issues block; an entry whose severity is missing or unrecognized counts as a BLOCKER (fail closed). If zero — every entry is explicitly INFO — display `ℹ advisory — {dimension}: {description}` per entry and proceed to `present_ready`; INFO is advisory and never enters the loop (#3724). Otherwise proceed to `revision_loop`
799
861
  </step>
800
862
 
801
863
  <step name="revision_loop">
@@ -828,6 +890,15 @@ ${AGENT_SKILLS_PLANNER}
828
890
 
829
891
  <instructions>
830
892
  Read existing PLAN.md files. Make targeted updates to address checker issues.
893
+
894
+ `required_property` + evidence + severity BIND. `fix_hint` is ONE non-binding example route: a
895
+ smaller or different mechanism reaching the same property addresses the issue in full — say which
896
+ you used. Re-check locked decisions, capability guidance (CLAUDE.md, project skills) and the
897
+ constraints these plans already encode BEFORE editing; if a hint would contradict one, or the
898
+ property is unreachable without breaking one, return `## REVISION_CONFLICT` with the conflict and
899
+ the alternatives rather than applying or working around it. Full contract:
900
+ `gsd-core/references/planner-revision.md`, which you load in revision mode.
901
+
831
902
  Do NOT replan from scratch unless issues are fundamental.
832
903
  </instructions>
833
904
  """,
@@ -839,7 +910,23 @@ Do NOT replan from scratch unless issues are fundamental.
839
910
 
840
911
  > **ORCHESTRATOR RULE — CODEX RUNTIME**: After calling Agent() above, stop working on this task immediately. Do not read more files, edit code, or run tests related to this task while the subagent is active. Wait for the subagent to return its result. This prevents duplicate work, conflicting edits, and wasted context. Only resume when the subagent result is available.
841
912
 
842
- After planner returns → spawn checker again (verify_gap_plans logic)
913
+ **If the planner returns `## REVISION_CONFLICT`:** do NOT increment `iteration_count` and do NOT
914
+ re-spawn the checker — a conflict is not resolvable by re-running the same loop, so it must not
915
+ consume retry budget. Present the conflict table and its alternatives to the user and ask which
916
+ to take: adopt a named alternative / override the named constraint and apply the hint / amend the
917
+ constraint itself. Every option resolves the conflict; accepting the plans with the blocker still
918
+ open is NOT offered here — that choice belongs to the max-iteration escalation below. Re-spawn
919
+ the planner with the chosen resolution and then **re-evaluate its return from the top of this
920
+ handler** — never fall through to the checker spawn below, because a second conflict is still a
921
+ conflict, not a revised plan, and only a NON-conflict return may reach the checker or increment
922
+ `iteration_count`.
923
+
924
+ **Bounded:** a conflict naming the SAME `required_property` twice in a row (no successful revision in between) is a stall, and so is
925
+ the THIRD conflict return of this loop whatever property it names — alternating property names
926
+ would otherwise never trip the repeat rule. Stop re-spawning and route it to the same
927
+ max-iteration escalation below.
928
+
929
+ **On any other return** → spawn checker again (verify_gap_plans logic)
843
930
  Increment iteration_count
844
931
 
845
932
  **If iteration_count >= 3:**
@@ -858,9 +945,7 @@ Wait for user response.
858
945
  **Present completion and next steps:**
859
946
 
860
947
  ```
861
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
862
- GSD ► FIXES READY ✓
863
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
948
+ ### GSD ► FIXES READY ✓
864
949
 
865
950
  **Phase {X}: {Name}** — {N} gap(s) diagnosed, {M} fix plan(s) created
866
951
 
@@ -871,7 +956,7 @@ Wait for user response.
871
956
 
872
957
  Plans verified and ready for execution.
873
958
 
874
- ───────────────────────────────────────────────────────────────
959
+ ---
875
960
 
876
961
  ## ▶ Next Up — [${PROJECT_CODE}] ${PROJECT_TITLE}
877
962
 
@@ -879,7 +964,7 @@ Plans verified and ready for execution.
879
964
 
880
965
  `/clear` then `/gsd:execute-phase {phase} --gaps-only`
881
966
 
882
- ───────────────────────────────────────────────────────────────
967
+ ---
883
968
  ```
884
969
  </step>
885
970
 
@@ -65,6 +65,23 @@ const path = require('path');
65
65
  const os = require('os');
66
66
  const { readSentinel, VALID_ISOLATION, extractDispatchIdentifiers, sentinelAppliesToDispatch } = require('./lib/isolation-sentinel.js');
67
67
  const { REASON_CODE } = require('./lib/isolation-deny-reason.js');
68
+ const { HOOK_ON_CRASH, allow, deny, crash } = require('./lib/hook-exit.js');
69
+
70
+ // Required at module top, alongside the other ./lib requires — NOT behind
71
+ // ensureRuntimeBuild() below. Terminating on a parse/timeout failure must
72
+ // never depend on the gitignored build artifacts this hook self-heals for
73
+ // its own registry lookups (#3911).
74
+ //
75
+ // This guard's outer catch (main(), below) has always exited 0 (fail open):
76
+ // that outer catch only covers payload PARSING failing before applicability
77
+ // could even be determined (malformed stdin JSON, etc.) — the guard's real
78
+ // fail-closed logic (a GSD project whose dispatch-isolation configuration
79
+ // cannot be verified) is handled separately, inside evaluateDispatch/
80
+ // resolveIsolationState, and already returns a 'block' decision through the
81
+ // normal exit-2 path rather than through this catch. So an unparseable
82
+ // payload has nothing to enforce; allowing it preserves today's behavior
83
+ // exactly.
84
+ const ON_CRASH = HOOK_ON_CRASH.ALLOW;
68
85
  // #3582: gsd-core/bin/lib/*.cjs (runtime-name-policy.cjs, capability-registry.cjs
69
86
  // below) are tsc build artifacts (ADR-457), gitignored and absent on a raw
70
87
  // plugin-marketplace / git-clone install that never ran `npm run build:lib`.
@@ -95,40 +112,40 @@ function parseHarnessFlag(flag) {
95
112
  return { param: m[1], value: m[2] };
96
113
  }
97
114
 
98
- // ─── #3566: per-install runtime marker ────────────────────────────────────────
115
+ // ─── #3897 rung 2: per-install runtime marker, single canonical owner ────────
99
116
  // bin/install.js writes `<install>/gsd-core/.gsd-runtime` for EVERY runtime
100
117
  // install (#2297), co-located with VERSION. Unlike `~/.gsd/defaults.json` —
101
118
  // which is host-wide and names whichever runtime's install ran LAST, the exact
102
119
  // leakage #2840's config.cjs change exists to prevent — the marker describes
103
120
  // THIS install, which is the property runtime identity needs on a machine
104
- // with 2+ runtimes. Mirrors readInstallRuntimeMarker in src/model-resolver.cts
105
- // (same cache + test-seam shape); this hook cannot import that module without
106
- // dragging the whole model-resolution stack into a PreToolUse hot path, so the
107
- // 5-line read lives here against the same sibling-layout assumption the hook's
108
- // own require('../gsd-core/bin/lib/…') already makes. Epic #3473 B3 owns
109
- // consolidating every marker reader into one shared seam.
110
- let _installMarkerCache; // undefined = unread; null = known absent; string = value
111
-
121
+ // with 2+ runtimes. Previously this hook held its own private reader/cache
122
+ // (one of four #3897 found); it now delegates to the single canonical owner,
123
+ // `src/runtime-slash.cts` (compiled to gsd-core/bin/lib/runtime-slash.cjs),
124
+ // reached through `ensureRuntimeBuild()` like every other compiled-lib require
125
+ // in this file (`scripts/lint-hooks-runtime-build-seam.cjs`).
112
126
  function readInstallRuntimeMarker() {
113
- if (_installMarkerCache !== undefined) return _installMarkerCache;
114
127
  try {
115
- const markerPath = path.join(__dirname, '..', 'gsd-core', '.gsd-runtime');
116
- const raw = fs.readFileSync(markerPath, 'utf-8').trim();
117
- _installMarkerCache = raw || null;
128
+ ensureRuntimeBuild();
129
+ const runtimeSlash = require('../gsd-core/bin/lib/runtime-slash.cjs');
130
+ return runtimeSlash.readInstallRuntimeMarker();
118
131
  } catch {
119
- // No marker: dev/source tree, or an install predating #2297 — "no signal
120
- // from this rung", never a resolution failure. Falls through to the
121
- // defaults rung below.
122
- _installMarkerCache = null;
132
+ // Unbuilt runtime library, or any other failure reaching the canonical
133
+ // owner — "no signal from this rung" (N4), never a resolution failure.
134
+ return null;
123
135
  }
124
- return _installMarkerCache;
125
136
  }
126
137
 
127
- // Test seam for the marker rung (the dev/source tree has no marker file, so
128
- // the read always bottoms out at null there — same seam contract as
129
- // model-resolver.cts's _setInstallRuntimeMarkerForTests, #2297).
138
+ // Test seam for the marker rung — forwards to the canonical owner's seam so
139
+ // this hook and runtime-slash.cjs always share one cache (#3897 rung 2).
130
140
  function _setInstallRuntimeMarkerForTests(value) {
131
- _installMarkerCache = value;
141
+ try {
142
+ ensureRuntimeBuild();
143
+ const runtimeSlash = require('../gsd-core/bin/lib/runtime-slash.cjs');
144
+ runtimeSlash._setInstallRuntimeMarkerForTests(value);
145
+ } catch {
146
+ // Test-only seam; an unbuilt library here means the test itself will fail
147
+ // downstream, which is a louder and more actionable signal than throwing here.
148
+ }
132
149
  }
133
150
 
134
151
  /**
@@ -282,18 +299,40 @@ function resolveRegistryIsolation(cwd, configPath) {
282
299
 
283
300
  if (isolation === 'harness-worktree') {
284
301
  let useWorktrees = true;
302
+ // #3972: the opt-out read shares the ONE owner every other
303
+ // isolation-deciding surface uses — planning-workspace's
304
+ // worktreesOptedOut ladder (scoped own-key wins; root inherited under
305
+ // the GSD_WORKSTREAM gate; strict === false). A flat single-file read
306
+ // here made a workstream-LOCAL opt-out invisible, so the sentinel-absent
307
+ // fallback denied a sequential dispatch the config explicitly allowed.
308
+ // Reached through ensureRuntimeBuild() like every other compiled-lib
309
+ // require in this file (scripts/lint-hooks-runtime-build-seam.cjs); if
310
+ // the library is unreachable the flat-root read below remains as the
311
+ // degraded fallback — today's behavior, never worse.
312
+ let ladderAnswered = false;
285
313
  try {
286
- const raw = fs.readFileSync(configPath, 'utf-8');
287
- const parsedCfg = JSON.parse(raw);
288
- if (parsedCfg && typeof parsedCfg === 'object' && parsedCfg.workflow &&
289
- typeof parsedCfg.workflow === 'object' && parsedCfg.workflow.use_worktrees === false) {
290
- useWorktrees = false;
291
- }
314
+ ensureRuntimeBuild();
315
+ const { worktreesOptedOut } = require('../gsd-core/bin/lib/planning-workspace.cjs');
316
+ useWorktrees = !worktreesOptedOut(cwd);
317
+ ladderAnswered = true;
292
318
  } catch {
293
- // Unreadable config already propagated to the outer caller's catch
294
- // before this point in practice (resolveRuntimeIdentity reads it
295
- // first); tolerate defensively and keep the conservative (enforce)
296
- // default rather than silently disabling the guard.
319
+ // Unbuilt runtime library or a ladder failure — fall through to the
320
+ // legacy flat-root read (conservative: keep enforcing).
321
+ }
322
+ if (!ladderAnswered) {
323
+ try {
324
+ const raw = fs.readFileSync(configPath, 'utf-8');
325
+ const parsedCfg = JSON.parse(raw);
326
+ if (parsedCfg && typeof parsedCfg === 'object' && parsedCfg.workflow &&
327
+ typeof parsedCfg.workflow === 'object' && parsedCfg.workflow.use_worktrees === false) {
328
+ useWorktrees = false;
329
+ }
330
+ } catch {
331
+ // Unreadable config already propagated to the outer caller's catch
332
+ // before this point in practice (resolveRuntimeIdentity reads it
333
+ // first); tolerate defensively and keep the conservative (enforce)
334
+ // default rather than silently disabling the guard.
335
+ }
297
336
  }
298
337
  if (!useWorktrees) isolation = 'none';
299
338
  }
@@ -476,7 +515,7 @@ function evaluateDispatch(data, { clock = Date } = {}) {
476
515
  /* istanbul ignore next -- stdin adapter, exercised via spawnSync in tests */
477
516
  function main() {
478
517
  let input = '';
479
- const stdinTimeout = setTimeout(() => process.exit(0), 3000);
518
+ const stdinTimeout = setTimeout(() => allow(undefined), 3000);
480
519
  process.stdin.setEncoding('utf8');
481
520
  process.stdin.on('data', (chunk) => { input += chunk; });
482
521
  process.stdin.on('end', () => {
@@ -486,18 +525,18 @@ function main() {
486
525
  const decision = evaluateDispatch(data);
487
526
  if (decision.action === 'block') {
488
527
  const out = { decision: 'block', reason: decision.reason, reason_code: decision.reasonCode };
489
- process.stdout.write(JSON.stringify(out));
490
528
  // Kimi feeds stderr (not stdout) back to the model on exit 2.
491
- process.stderr.write(decision.reason);
492
- process.exit(2);
529
+ deny(out, decision.reason);
493
530
  }
494
- process.exit(0);
531
+ allow(undefined);
495
532
  } catch {
496
533
  // Silent fail — never block valid tool calls due to hook errors
497
534
  // (malformed payload, etc.). This is distinct from resolveIsolationState's
498
535
  // internal error handling, which DOES deny — this outer catch only
499
536
  // covers payload parsing before applicability could even be determined.
500
- process.exit(0);
537
+ // ON_CRASH is declared ALLOW at module top: this preserves today's
538
+ // exit(0) fail-open behavior exactly (#3911).
539
+ crash(ON_CRASH, undefined);
501
540
  }
502
541
  });
503
542
  }
@@ -156,5 +156,22 @@ const result = {
156
156
  };
157
157
 
158
158
  if (cacheFile) {
159
- try { fs.writeFileSync(cacheFile, JSON.stringify(result)); } catch (e) {}
160
- }
159
+ // #4091: the cache file is shared per-PACKAGE across every runtime's worker
160
+ // (#607/#1421), so concurrent statusline/banner readers parse it while this
161
+ // worker writes it. A direct writeFileSync truncates before writing — a
162
+ // reader landing mid-write sees a torn/empty record (its JSON.parse catch
163
+ // swallows it, so the symptom is an intermittently blank update segment).
164
+ // Publish atomically instead: stage under a unique same-directory temp
165
+ // (same filesystem, so rename(2) is atomic — readers see the old or the new
166
+ // record, never a partial one), then renameSync into place. Failure policy
167
+ // is unchanged (#3582 degrade): any error is swallowed and the temp, if
168
+ // left behind, is best-effort removed.
169
+ const tmp = cacheFile + '.tmp-' + process.pid;
170
+ try {
171
+ fs.writeFileSync(tmp, JSON.stringify(result));
172
+ fs.renameSync(tmp, cacheFile);
173
+ } catch (e) {
174
+ try {
175
+ fs.rmSync(tmp, { force: true });
176
+ } catch (e2) {}
177
+ }}
@@ -20,11 +20,17 @@
20
20
 
21
21
  const fs = require('fs');
22
22
  const path = require('path');
23
+ const { HOOK_ON_CRASH, allow, crash } = require('./lib/hook-exit.js');
24
+
25
+ // This hook only injects an advisory config-reload summary; a crash mid-parse
26
+ // must not block the session or the FileChanged event that triggered it — the
27
+ // agent simply keeps using the config context it already had (#3911).
28
+ const ON_CRASH = HOOK_ON_CRASH.ALLOW;
23
29
 
24
30
  let input = '';
25
31
  // Timeout guard: if stdin does not close within 8s exit silently rather than
26
32
  // hanging until Claude Code kills the process and reports "hook error".
27
- const stdinTimeout = setTimeout(() => process.exit(0), 8000);
33
+ const stdinTimeout = setTimeout(() => allow(undefined), 8000);
28
34
  process.stdin.setEncoding('utf8');
29
35
  process.stdin.on('data', chunk => (input += chunk));
30
36
  process.stdin.on('end', () => {
@@ -42,24 +48,23 @@ process.stdin.on('end', () => {
42
48
  // inject spurious additionalContext.
43
49
  const basename = path.basename(filePath);
44
50
  if (basename !== 'config.json') {
45
- process.exit(0);
51
+ allow(undefined);
46
52
  }
47
53
  const expectedPath = path.resolve(cwd, '.planning', 'config.json');
48
54
  if (path.resolve(filePath) !== expectedPath) {
49
- process.exit(0);
55
+ allow(undefined);
50
56
  }
51
57
 
52
58
  // On unlink (deletion) emit a brief notice and exit
53
59
  if (event === 'unlink') {
54
- process.stdout.write(JSON.stringify({
60
+ allow({
55
61
  hookSpecificOutput: {
56
62
  hookEventName: 'FileChanged',
57
63
  additionalContext:
58
64
  'GSD config (.planning/config.json) was deleted. ' +
59
65
  'Falling back to built-in defaults for this session.',
60
66
  },
61
- }));
62
- process.exit(0);
67
+ });
63
68
  }
64
69
 
65
70
  // Read the updated config file
@@ -68,17 +73,16 @@ process.stdin.on('end', () => {
68
73
  const raw = fs.readFileSync(filePath, 'utf8');
69
74
  config = JSON.parse(raw);
70
75
  } catch (e) {
71
- if (e && e.code === 'ENOENT') process.exit(0);
76
+ if (e && e.code === 'ENOENT') allow(undefined);
72
77
  // Malformed JSON — inform the agent without crashing
73
- process.stdout.write(JSON.stringify({
78
+ allow({
74
79
  hookSpecificOutput: {
75
80
  hookEventName: 'FileChanged',
76
81
  additionalContext:
77
82
  'GSD config (.planning/config.json) was modified but could not be parsed. ' +
78
83
  'Check the file for JSON syntax errors.',
79
84
  },
80
- }));
81
- process.exit(0);
85
+ });
82
86
  }
83
87
 
84
88
  // Build a concise summary of key config fields the agent cares about
@@ -127,7 +131,9 @@ process.stdin.on('end', () => {
127
131
  },
128
132
  }));
129
133
  } catch (e) {
130
- // Silent fail — never block the session on a config reload error
131
- process.exit(0);
134
+ // Silent fail — never block the session on a config reload error.
135
+ // ON_CRASH is declared ALLOW at module top: this preserves today's
136
+ // exit(0) fail-open behavior exactly (#3911).
137
+ crash(ON_CRASH, undefined);
132
138
  }
133
139
  });