@opengsd/gsd-core 1.10.0 → 1.12.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 (544) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/agents/gsd-code-fixer.md +1 -1
  4. package/agents/gsd-debug-session-manager.md +12 -1
  5. package/agents/gsd-debugger.md +1 -1
  6. package/agents/gsd-doc-synthesizer.md +2 -4
  7. package/agents/gsd-dom-verifier.md +169 -0
  8. package/agents/gsd-eval-auditor.md +1 -1
  9. package/agents/gsd-executor.md +22 -14
  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 +5 -3
  13. package/agents/gsd-pattern-mapper.md +11 -0
  14. package/agents/gsd-phase-researcher.md +23 -2
  15. package/agents/gsd-plan-checker.md +50 -53
  16. package/agents/gsd-planner.md +50 -50
  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 +63 -4
  21. package/agents/gsd-ui-researcher.md +41 -3
  22. package/agents/gsd-user-profiler.md +3 -0
  23. package/agents/gsd-verifier.md +13 -4
  24. package/bin/install.js +1448 -1103
  25. package/commands/gsd/code-review.md +1 -1
  26. package/commands/gsd/discuss-phase.md +1 -1
  27. package/commands/gsd/execute-phase.md +1 -1
  28. package/commands/gsd/import.md +1 -1
  29. package/commands/gsd/map-codebase.md +1 -1
  30. package/commands/gsd/mempalace-capture.md +1 -1
  31. package/commands/gsd/mempalace-recall.md +1 -1
  32. package/commands/gsd/new-milestone.md +1 -1
  33. package/commands/gsd/quick.md +9 -5
  34. package/commands/gsd/review-backlog.md +2 -1
  35. package/commands/gsd/verify-work.md +1 -1
  36. package/gsd-core/bin/gsd-tools.cjs +1035 -138
  37. package/gsd-core/bin/lib/active-workstream-store.cjs +146 -22
  38. package/gsd-core/bin/lib/adr-parser.cjs +13 -7
  39. package/gsd-core/bin/lib/agent-install-check.cjs +392 -32
  40. package/gsd-core/bin/lib/api-coverage.cjs +33 -14
  41. package/gsd-core/bin/lib/artifacts.cjs +5 -0
  42. package/gsd-core/bin/lib/assumption-delta.cjs +32 -15
  43. package/gsd-core/bin/lib/audit-command-router.cjs +9 -2
  44. package/gsd-core/bin/lib/audit.cjs +1026 -268
  45. package/gsd-core/bin/lib/broken-windows.cjs +306 -28
  46. package/gsd-core/bin/lib/capability-consent.cjs +149 -15
  47. package/gsd-core/bin/lib/capability-lifecycle.cjs +45 -0
  48. package/gsd-core/bin/lib/capability-lock.cjs +10 -4
  49. package/gsd-core/bin/lib/capability-registry.cjs +845 -130
  50. package/gsd-core/bin/lib/capability-source.cjs +92 -0
  51. package/gsd-core/bin/lib/capability-state.cjs +18 -3
  52. package/gsd-core/bin/lib/capability-trust.cjs +444 -25
  53. package/gsd-core/bin/lib/capability-validator.cjs +700 -40
  54. package/gsd-core/bin/lib/capability-writer.cjs +3 -2
  55. package/gsd-core/bin/lib/check-command-router.cjs +216 -42
  56. package/gsd-core/bin/lib/claude-orchestration.cjs +56 -3
  57. package/gsd-core/bin/lib/cli-exit.cjs +496 -10
  58. package/gsd-core/bin/lib/code-review-depth.cjs +288 -0
  59. package/gsd-core/bin/lib/codex-agent-toml.cjs +735 -0
  60. package/gsd-core/bin/lib/command-aliases.cjs +22 -0
  61. package/gsd-core/bin/lib/command-arg-projection.cjs +144 -14
  62. package/gsd-core/bin/lib/command-roster.cjs +44 -1
  63. package/gsd-core/bin/lib/command-routing-hub.cjs +31 -2
  64. package/gsd-core/bin/lib/commands.cjs +1172 -108
  65. package/gsd-core/bin/lib/commonjs-marker.cjs +12 -6
  66. package/gsd-core/bin/lib/complexity-trigger.cjs +1192 -0
  67. package/gsd-core/bin/lib/config-loader.cjs +187 -23
  68. package/gsd-core/bin/lib/config.cjs +102 -3
  69. package/gsd-core/bin/lib/configuration.cjs +129 -37
  70. package/gsd-core/bin/lib/core-utils.cjs +208 -33
  71. package/gsd-core/bin/lib/decisions.cjs +23 -0
  72. package/gsd-core/bin/lib/edge-probe.cjs +9 -1
  73. package/gsd-core/bin/lib/estimate-cli.cjs +55 -11
  74. package/gsd-core/bin/lib/exit-code-registry.cjs +98 -0
  75. package/gsd-core/bin/lib/fallow-runner.cjs +20 -44
  76. package/gsd-core/bin/lib/frontmatter.cjs +899 -229
  77. package/gsd-core/bin/lib/gap-checker.cjs +95 -10
  78. package/gsd-core/bin/lib/git-base-branch.cjs +276 -39
  79. package/gsd-core/bin/lib/gsd2-import.cjs +10 -1
  80. package/gsd-core/bin/lib/health-diagnostic-rules/agent-install.cjs +101 -0
  81. package/gsd-core/bin/lib/health-diagnostic-rules/config-validation.cjs +348 -0
  82. package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +149 -0
  83. package/gsd-core/bin/lib/health-diagnostic-rules/install-surface-shadowing.cjs +98 -0
  84. package/gsd-core/bin/lib/health-diagnostic-rules/milestone-archive-hygiene.cjs +100 -0
  85. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +222 -0
  86. package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +268 -0
  87. package/gsd-core/bin/lib/health-diagnostic-rules/root-existence.cjs +161 -0
  88. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +303 -0
  89. package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +187 -0
  90. package/gsd-core/bin/lib/health-diagnostic-types.cjs +68 -0
  91. package/gsd-core/bin/lib/health-diagnostic.cjs +451 -0
  92. package/gsd-core/bin/lib/host-integration.cjs +39 -6
  93. package/gsd-core/bin/lib/host-runtime-detection.cjs +134 -0
  94. package/gsd-core/bin/lib/init-command-router.cjs +118 -21
  95. package/gsd-core/bin/lib/init.cjs +439 -168
  96. package/gsd-core/bin/lib/install-effort-resolver.cjs +73 -30
  97. package/gsd-core/bin/lib/install-engine.cjs +811 -259
  98. package/gsd-core/bin/lib/install-fs-adapter.cjs +262 -0
  99. package/gsd-core/bin/lib/install-model-override-resolver.cjs +235 -0
  100. package/gsd-core/bin/lib/install-profiles.cjs +212 -61
  101. package/gsd-core/bin/lib/install-scope.cjs +270 -0
  102. package/gsd-core/bin/lib/install-shadow-report.cjs +385 -0
  103. package/gsd-core/bin/lib/installed-surface-resolver.cjs +381 -0
  104. package/gsd-core/bin/lib/installer-migration-report.cjs +3 -0
  105. package/gsd-core/bin/lib/installer-migrations/010-antigravity-retire-confighome-artifacts.cjs +169 -0
  106. package/gsd-core/bin/lib/installer-migrations.cjs +148 -38
  107. package/gsd-core/bin/lib/intel.cjs +101 -26
  108. package/gsd-core/bin/lib/io.cjs +170 -15
  109. package/gsd-core/bin/lib/learnings.cjs +85 -14
  110. package/gsd-core/bin/lib/legacy-cleanup.cjs +8 -2
  111. package/gsd-core/bin/lib/markdown-sectionizer.cjs +2 -1
  112. package/gsd-core/bin/lib/markdown-table.cjs +183 -22
  113. package/gsd-core/bin/lib/milestone-lock.cjs +248 -0
  114. package/gsd-core/bin/lib/milestone.cjs +842 -73
  115. package/gsd-core/bin/lib/model-catalog.cjs +232 -16
  116. package/gsd-core/bin/lib/model-resolver.cjs +193 -68
  117. package/gsd-core/bin/lib/normalize-test-command.cjs +1 -1
  118. package/gsd-core/bin/lib/onboard-projection.cjs +5 -1
  119. package/gsd-core/bin/lib/pattern.cjs +122 -0
  120. package/gsd-core/bin/lib/phase-estimation.cjs +18 -9
  121. package/gsd-core/bin/lib/phase-id.cjs +514 -40
  122. package/gsd-core/bin/lib/phase-lifecycle.cjs +52 -19
  123. package/gsd-core/bin/lib/phase-locator.cjs +262 -34
  124. package/gsd-core/bin/lib/phase.cjs +1038 -214
  125. package/gsd-core/bin/lib/plan-dependency-graph.cjs +72 -1
  126. package/gsd-core/bin/lib/plan-document.cjs +263 -0
  127. package/gsd-core/bin/lib/plan-drift-guard.cjs +120 -0
  128. package/gsd-core/bin/lib/plan-scan.cjs +98 -3
  129. package/gsd-core/bin/lib/planning-command-router.cjs +61 -0
  130. package/gsd-core/bin/lib/planning-inspect.cjs +1168 -0
  131. package/gsd-core/bin/lib/planning-scope.cjs +31 -0
  132. package/gsd-core/bin/lib/planning-snapshot.cjs +894 -0
  133. package/gsd-core/bin/lib/planning-workspace.cjs +112 -6
  134. package/gsd-core/bin/lib/probe-core.cjs +5 -2
  135. package/gsd-core/bin/lib/profile-output.cjs +1 -1
  136. package/gsd-core/bin/lib/profile-pipeline-command-router.cjs +50 -7
  137. package/gsd-core/bin/lib/profile-pipeline.cjs +6 -3
  138. package/gsd-core/bin/lib/real-home-guard.cjs +419 -0
  139. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +766 -0
  140. package/gsd-core/bin/lib/retired-artifact-cleanup.cjs +11 -6
  141. package/gsd-core/bin/lib/review-lane-descriptor.cjs +22 -13
  142. package/gsd-core/bin/lib/review-lane-invocation.cjs +30 -0
  143. package/gsd-core/bin/lib/review-lane-runner.cjs +421 -66
  144. package/gsd-core/bin/lib/review-reviewer-selection.cjs +13 -18
  145. package/gsd-core/bin/lib/roadmap-command-router.cjs +59 -11
  146. package/gsd-core/bin/lib/roadmap-parser.cjs +1006 -184
  147. package/gsd-core/bin/lib/roadmap-upgrade.cjs +37 -10
  148. package/gsd-core/bin/lib/roadmap.cjs +442 -96
  149. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +702 -52
  150. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +14 -2
  151. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +459 -55
  152. package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +3 -2
  153. package/gsd-core/bin/lib/runtime-homes.cjs +69 -3
  154. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +402 -58
  155. package/gsd-core/bin/lib/runtime-identity.cjs +234 -0
  156. package/gsd-core/bin/lib/runtime-name-policy.cjs +3 -1
  157. package/gsd-core/bin/lib/runtime-slash.cjs +96 -8
  158. package/gsd-core/bin/lib/security.cjs +104 -5
  159. package/gsd-core/bin/lib/shell-command-projection.cjs +342 -7
  160. package/gsd-core/bin/lib/smart-entry.cjs +133 -23
  161. package/gsd-core/bin/lib/spec-section.cjs +12 -7
  162. package/gsd-core/bin/lib/state-command-router.cjs +52 -19
  163. package/gsd-core/bin/lib/state-contract.cjs +359 -0
  164. package/gsd-core/bin/lib/state-document.cjs +338 -8
  165. package/gsd-core/bin/lib/state-md-schema.cjs +221 -0
  166. package/gsd-core/bin/lib/state-transition.cjs +846 -176
  167. package/gsd-core/bin/lib/state.cjs +2589 -369
  168. package/gsd-core/bin/lib/surface.cjs +33 -11
  169. package/gsd-core/bin/lib/task-command-router.cjs +111 -1
  170. package/gsd-core/bin/lib/task-content-resolution.cjs +368 -0
  171. package/gsd-core/bin/lib/teams-status.cjs +4 -1
  172. package/gsd-core/bin/lib/text-lines.cjs +80 -0
  173. package/gsd-core/bin/lib/token-scanner.cjs +76 -0
  174. package/gsd-core/bin/lib/uat-predicate.cjs +67 -23
  175. package/gsd-core/bin/lib/uat.cjs +1761 -167
  176. package/gsd-core/bin/lib/ui-consideration-probe.cjs +9 -1
  177. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +157 -0
  178. package/gsd-core/bin/lib/ui-safety-gate.cjs +51 -12
  179. package/gsd-core/bin/lib/unusable-input.cjs +37 -0
  180. package/gsd-core/bin/lib/update-context.cjs +8 -2
  181. package/gsd-core/bin/lib/user-artifact-staging.cjs +705 -0
  182. package/gsd-core/bin/lib/validate-command-router.cjs +2 -2
  183. package/gsd-core/bin/lib/validate.cjs +20 -6
  184. package/gsd-core/bin/lib/vendor/README.md +75 -0
  185. package/gsd-core/bin/lib/vendor/js-yaml.cjs +3014 -0
  186. package/gsd-core/bin/lib/vendor/re2js.cjs +6480 -0
  187. package/gsd-core/bin/lib/vendor/re2js.d.cts +938 -0
  188. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  189. package/gsd-core/bin/lib/verification.cjs +272 -9
  190. package/gsd-core/bin/lib/verify-command-grounding.cjs +846 -0
  191. package/gsd-core/bin/lib/verify.cjs +453 -918
  192. package/gsd-core/bin/lib/workstream-inventory-builder.cjs +53 -32
  193. package/gsd-core/bin/lib/workstream-inventory.cjs +63 -10
  194. package/gsd-core/bin/lib/workstream-name-policy.cjs +25 -4
  195. package/gsd-core/bin/lib/workstream.cjs +2 -2
  196. package/gsd-core/bin/lib/worktree-base-ref.cjs +66 -12
  197. package/gsd-core/bin/lib/worktree-safety.cjs +341 -18
  198. package/gsd-core/bin/shared/config-defaults.manifest.json +8 -1
  199. package/gsd-core/bin/shared/config-schema.manifest.json +12 -1
  200. package/gsd-core/bin/shared/exit-codes.json +8 -0
  201. package/gsd-core/bin/shared/exit-codes.sh +20 -0
  202. package/gsd-core/bin/shared/model-catalog.json +8 -1
  203. package/gsd-core/references/agent-contracts.md +44 -26
  204. package/gsd-core/references/api-coverage.md +24 -2
  205. package/gsd-core/references/autonomous-smart-discuss.md +3 -3
  206. package/gsd-core/references/checkpoints.md +39 -21
  207. package/gsd-core/references/context-budget.md +1 -1
  208. package/gsd-core/references/decimal-phase-calculation.md +5 -5
  209. package/gsd-core/references/dispatch-isolation-gate.md +138 -0
  210. package/gsd-core/references/doc-conflict-engine.md +1 -1
  211. package/gsd-core/references/edge-probe.md +8 -0
  212. package/gsd-core/references/execute-mvp-tdd.md +4 -6
  213. package/gsd-core/references/execute-phase-between-wave-reset.md +15 -14
  214. package/gsd-core/references/execute-phase-context-guard.md +1 -1
  215. package/gsd-core/references/execute-phase-response-language.md +1 -1
  216. package/gsd-core/references/execute-phase-wave-guard.md +17 -11
  217. package/gsd-core/references/failing-direction.md +78 -0
  218. package/gsd-core/references/gate-prompts.md +1 -1
  219. package/gsd-core/references/git-integration.md +5 -5
  220. package/gsd-core/references/git-planning-commit.md +5 -4
  221. package/gsd-core/references/gsd-run-resolver.md +1 -1
  222. package/gsd-core/references/loop-hook-dispatch.md +61 -2
  223. package/gsd-core/references/model-profiles.md +12 -4
  224. package/gsd-core/references/mvp-concepts.md +9 -9
  225. package/gsd-core/references/nyquist-compliance.md +74 -0
  226. package/gsd-core/references/offer-next.md +3 -5
  227. package/gsd-core/references/phase-argument-parsing.md +3 -3
  228. package/gsd-core/references/planner-failing-direction.md +53 -0
  229. package/gsd-core/references/planner-guidance.md +3 -9
  230. package/gsd-core/references/planner-human-verify-mode.md +15 -1
  231. package/gsd-core/references/planner-preconditions.md +1 -1
  232. package/gsd-core/references/planner-reviews.md +1 -1
  233. package/gsd-core/references/planner-revision.md +1 -1
  234. package/gsd-core/references/planner-verify-command-grounding.md +17 -0
  235. package/gsd-core/references/planning-config.md +44 -13
  236. package/gsd-core/references/reviewer-instances.md +31 -0
  237. package/gsd-core/references/revision-loop.md +1 -1
  238. package/gsd-core/references/runtime-aware-dispatch.md +1 -1
  239. package/gsd-core/references/specless-probe-fallback.md +1 -1
  240. package/gsd-core/references/tdd.md +1 -3
  241. package/gsd-core/references/ui-brand.md +65 -21
  242. package/gsd-core/references/ui-consideration-probe.md +1 -1
  243. package/gsd-core/references/universal-anti-patterns.md +5 -5
  244. package/gsd-core/references/verifier-phase-gates.md +192 -0
  245. package/gsd-core/references/verify-command-path-resolvability.md +42 -0
  246. package/gsd-core/references/verify-mvp-mode.md +2 -2
  247. package/gsd-core/references/workstream-flag.md +33 -17
  248. package/gsd-core/templates/README.md +1 -1
  249. package/gsd-core/templates/SECURITY.md +3 -3
  250. package/gsd-core/templates/UI-SPEC.md +25 -3
  251. package/gsd-core/templates/VALIDATION.md +3 -3
  252. package/gsd-core/templates/discussion-log.md +1 -1
  253. package/gsd-core/templates/phase-prompt.md +5 -4
  254. package/gsd-core/templates/state.md +11 -4
  255. package/gsd-core/templates/verification-report.md +9 -1
  256. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  257. package/gsd-core/workflows/add-backlog.md +1 -1
  258. package/gsd-core/workflows/add-phase.md +3 -3
  259. package/gsd-core/workflows/add-tests.md +3 -8
  260. package/gsd-core/workflows/add-todo.md +1 -1
  261. package/gsd-core/workflows/ai-integration-phase.md +13 -20
  262. package/gsd-core/workflows/audit-fix.md +12 -3
  263. package/gsd-core/workflows/audit-milestone.md +9 -9
  264. package/gsd-core/workflows/audit-uat.md +17 -2
  265. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +2 -2
  266. package/gsd-core/workflows/autonomous.md +11 -27
  267. package/gsd-core/workflows/check-todos.md +1 -1
  268. package/gsd-core/workflows/cleanup.md +64 -5
  269. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +14 -4
  270. package/gsd-core/workflows/code-review-fix.md +38 -11
  271. package/gsd-core/workflows/code-review.md +159 -52
  272. package/gsd-core/workflows/complete-milestone.md +151 -23
  273. package/gsd-core/workflows/debug.md +12 -8
  274. package/gsd-core/workflows/diagnose-issues.md +47 -15
  275. package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
  276. package/gsd-core/workflows/discuss-phase/modes/chain.md +5 -8
  277. package/gsd-core/workflows/discuss-phase/modes/default.md +1 -1
  278. package/gsd-core/workflows/discuss-phase/modes/text.md +1 -1
  279. package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +1 -3
  280. package/gsd-core/workflows/discuss-phase-assumptions.md +4 -3
  281. package/gsd-core/workflows/discuss-phase.md +1 -1
  282. package/gsd-core/workflows/do.md +3 -6
  283. package/gsd-core/workflows/docs-update.md +5 -4
  284. package/gsd-core/workflows/edit-phase.md +27 -2
  285. package/gsd-core/workflows/eval-review.md +7 -14
  286. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +1 -1
  287. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +142 -15
  288. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +1 -1
  289. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +1 -1
  290. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +77 -0
  291. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +24 -4
  292. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +2 -2
  293. package/gsd-core/workflows/execute-phase/steps/protected-branch.md +21 -0
  294. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +2 -2
  295. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +39 -0
  296. package/gsd-core/workflows/execute-phase.md +72 -100
  297. package/gsd-core/workflows/execute-plan.md +52 -15
  298. package/gsd-core/workflows/explore.md +131 -4
  299. package/gsd-core/workflows/extract-learnings.md +1 -1
  300. package/gsd-core/workflows/fast.md +10 -2
  301. package/gsd-core/workflows/forensics.md +1 -1
  302. package/gsd-core/workflows/graduation.md +5 -5
  303. package/gsd-core/workflows/health.md +76 -10
  304. package/gsd-core/workflows/import.md +18 -15
  305. package/gsd-core/workflows/inbox.md +4 -5
  306. package/gsd-core/workflows/ingest-docs.md +49 -16
  307. package/gsd-core/workflows/insert-phase.md +5 -5
  308. package/gsd-core/workflows/list-seeds.md +5 -3
  309. package/gsd-core/workflows/list-workspaces.md +1 -1
  310. package/gsd-core/workflows/manager.md +12 -23
  311. package/gsd-core/workflows/map-codebase.md +1 -1
  312. package/gsd-core/workflows/milestone-summary.md +1 -1
  313. package/gsd-core/workflows/mvp-phase.md +8 -5
  314. package/gsd-core/workflows/new-milestone.md +22 -29
  315. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
  316. package/gsd-core/workflows/new-project.md +26 -40
  317. package/gsd-core/workflows/new-workspace.md +1 -1
  318. package/gsd-core/workflows/next.md +14 -2
  319. package/gsd-core/workflows/pause-work.md +1 -1
  320. package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +1 -1
  321. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +1 -1
  322. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +2 -4
  323. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +3 -3
  324. package/gsd-core/workflows/plan-phase.md +162 -59
  325. package/gsd-core/workflows/plan-review-convergence.md +96 -11
  326. package/gsd-core/workflows/plant-seed.md +2 -2
  327. package/gsd-core/workflows/pr-branch.md +187 -51
  328. package/gsd-core/workflows/profile-user.md +16 -14
  329. package/gsd-core/workflows/progress.md +61 -18
  330. package/gsd-core/workflows/quick/steps/discussion-phase.md +1 -3
  331. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +5 -7
  332. package/gsd-core/workflows/quick/steps/quick-verification.md +28 -9
  333. package/gsd-core/workflows/quick/steps/research-phase.md +4 -6
  334. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +3 -3
  335. package/gsd-core/workflows/quick.md +55 -44
  336. package/gsd-core/workflows/remove-phase.md +4 -4
  337. package/gsd-core/workflows/remove-workspace.md +2 -2
  338. package/gsd-core/workflows/resume-project.md +8 -12
  339. package/gsd-core/workflows/review.md +219 -20
  340. package/gsd-core/workflows/scan.md +1 -1
  341. package/gsd-core/workflows/secure-phase.md +3 -3
  342. package/gsd-core/workflows/session-report.md +2 -1
  343. package/gsd-core/workflows/settings-advanced.md +7 -9
  344. package/gsd-core/workflows/settings-integrations.md +64 -31
  345. package/gsd-core/workflows/settings.md +69 -7
  346. package/gsd-core/workflows/ship.md +116 -50
  347. package/gsd-core/workflows/sketch-wrap-up.md +11 -17
  348. package/gsd-core/workflows/sketch.md +12 -18
  349. package/gsd-core/workflows/smart-entry.md +3 -5
  350. package/gsd-core/workflows/spec-phase.md +53 -13
  351. package/gsd-core/workflows/spike-wrap-up.md +7 -11
  352. package/gsd-core/workflows/spike.md +20 -31
  353. package/gsd-core/workflows/stats.md +2 -2
  354. package/gsd-core/workflows/sync-skills.md +64 -9
  355. package/gsd-core/workflows/thread.md +11 -7
  356. package/gsd-core/workflows/transition.md +49 -14
  357. package/gsd-core/workflows/ui-phase.md +15 -21
  358. package/gsd-core/workflows/ui-review.md +8 -12
  359. package/gsd-core/workflows/ultraplan-phase.md +5 -13
  360. package/gsd-core/workflows/undo.md +8 -16
  361. package/gsd-core/workflows/update.md +7 -11
  362. package/gsd-core/workflows/validate-phase.md +3 -3
  363. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +25 -1
  364. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
  365. package/gsd-core/workflows/verify-work.md +66 -25
  366. package/hooks/dist/gsd-agent-isolation-guard.js +158 -30
  367. package/hooks/dist/gsd-check-update-worker.js +56 -13
  368. package/hooks/dist/gsd-check-update.js +19 -1
  369. package/hooks/dist/gsd-config-reload.js +18 -12
  370. package/hooks/dist/gsd-context-monitor.js +19 -10
  371. package/hooks/dist/gsd-cursor-post-tool.js +3 -1
  372. package/hooks/dist/gsd-cursor-pre-tool.js +2 -3
  373. package/hooks/dist/gsd-cursor-session-start.js +2 -1
  374. package/hooks/dist/gsd-cursor-stop.js +2 -1
  375. package/hooks/dist/gsd-cursor-subagent-start.js +83 -3
  376. package/hooks/dist/gsd-cursor-subagent-stop.js +6 -3
  377. package/hooks/dist/gsd-ensure-canonical-path.js +2 -1
  378. package/hooks/dist/gsd-graphify-update.sh +22 -18
  379. package/hooks/dist/gsd-node-runner.sh +76 -0
  380. package/hooks/dist/gsd-phase-boundary.sh +1 -0
  381. package/hooks/dist/gsd-prompt-guard.js +37 -27
  382. package/hooks/dist/gsd-read-guard.js +16 -7
  383. package/hooks/dist/gsd-read-injection-scanner.js +55 -32
  384. package/hooks/dist/gsd-session-state.sh +1 -0
  385. package/hooks/dist/gsd-statusline.js +231 -24
  386. package/hooks/dist/gsd-update-banner.js +22 -1
  387. package/hooks/dist/gsd-validate-commit.sh +80 -6
  388. package/hooks/dist/gsd-windsurf-pre-command.js +16 -11
  389. package/hooks/dist/gsd-windsurf-pre-write.js +22 -13
  390. package/hooks/dist/gsd-workflow-guard.js +162 -46
  391. package/hooks/dist/gsd-worktree-path-guard.js +36 -21
  392. package/hooks/dist/gsd-write-guard.js +35 -25
  393. package/hooks/dist/lib/cli-exit.js +560 -0
  394. package/hooks/dist/lib/exit-code-registry.js +98 -0
  395. package/hooks/dist/lib/git-cmd.js +92 -59
  396. package/hooks/dist/lib/git-probe.js +84 -0
  397. package/hooks/dist/lib/hook-exit.js +81 -0
  398. package/hooks/dist/lib/injection-patterns.js +45 -0
  399. package/hooks/dist/lib/isolation-deny-reason.js +39 -0
  400. package/hooks/dist/lib/isolation-sentinel.js +9 -0
  401. package/hooks/dist/managed-hooks-registry.cjs +3 -0
  402. package/hooks/gsd-agent-isolation-guard.js +158 -30
  403. package/hooks/gsd-check-update-worker.js +56 -13
  404. package/hooks/gsd-check-update.js +19 -1
  405. package/hooks/gsd-config-reload.js +18 -12
  406. package/hooks/gsd-context-monitor.js +19 -10
  407. package/hooks/gsd-cursor-post-tool.js +3 -1
  408. package/hooks/gsd-cursor-pre-tool.js +2 -3
  409. package/hooks/gsd-cursor-session-start.js +2 -1
  410. package/hooks/gsd-cursor-stop.js +2 -1
  411. package/hooks/gsd-cursor-subagent-start.js +83 -3
  412. package/hooks/gsd-cursor-subagent-stop.js +6 -3
  413. package/hooks/gsd-ensure-canonical-path.js +2 -1
  414. package/hooks/gsd-graphify-update.sh +22 -18
  415. package/hooks/gsd-node-runner.sh +76 -0
  416. package/hooks/gsd-phase-boundary.sh +1 -0
  417. package/hooks/gsd-prompt-guard.js +37 -27
  418. package/hooks/gsd-read-guard.js +16 -7
  419. package/hooks/gsd-read-injection-scanner.js +55 -32
  420. package/hooks/gsd-session-state.sh +1 -0
  421. package/hooks/gsd-statusline.js +231 -24
  422. package/hooks/gsd-update-banner.js +22 -1
  423. package/hooks/gsd-validate-commit.sh +80 -6
  424. package/hooks/gsd-windsurf-pre-command.js +16 -11
  425. package/hooks/gsd-windsurf-pre-write.js +22 -13
  426. package/hooks/gsd-workflow-guard.js +162 -46
  427. package/hooks/gsd-worktree-path-guard.js +36 -21
  428. package/hooks/gsd-write-guard.js +35 -25
  429. package/hooks/lib/cli-exit.js +560 -0
  430. package/hooks/lib/exit-code-registry.js +98 -0
  431. package/hooks/lib/git-cmd.js +92 -59
  432. package/hooks/lib/git-probe.js +84 -0
  433. package/hooks/lib/hook-exit.js +81 -0
  434. package/hooks/lib/injection-patterns.js +45 -0
  435. package/hooks/lib/isolation-deny-reason.js +39 -0
  436. package/hooks/lib/isolation-sentinel.js +9 -0
  437. package/hooks/managed-hooks-registry.cjs +3 -0
  438. package/package.json +28 -11
  439. package/pi/gsd.cjs +19 -5
  440. package/scripts/base64-scan.sh +74 -12
  441. package/scripts/baselines/planning-prompt-drift-baseline.json +4 -0
  442. package/scripts/baselines/planning-snapshot-bypass-baseline.json +12 -0
  443. package/scripts/baselines/unreachable-guard-drift-baseline.json +4 -0
  444. package/scripts/build-hooks.js +5 -0
  445. package/scripts/changeset/lint.cjs +60 -5
  446. package/scripts/check-alias-drift.cjs +7 -43
  447. package/scripts/check-contract-drift.cjs +297 -0
  448. package/scripts/check-glossary-refs.cjs +77 -15
  449. package/scripts/check-mutation-score-ratchet.cjs +156 -0
  450. package/scripts/ci-check-job-near-cap.cjs +49 -0
  451. package/scripts/ci-pr-mergeability.cjs +262 -0
  452. package/scripts/ci-test-scope.cjs +64 -14
  453. package/scripts/ci-timeout-report.cjs +230 -0
  454. package/scripts/command-contract-helpers.cjs +903 -1
  455. package/scripts/docs-guard-registry.cjs +396 -0
  456. package/scripts/gen-adr-index.cjs +728 -38
  457. package/scripts/gen-capability-registry.cjs +11 -21
  458. package/scripts/gen-context-index.cjs +2 -11
  459. package/scripts/gen-exit-code-docs.cjs +318 -0
  460. package/scripts/gen-exit-code-registry.cjs +891 -0
  461. package/scripts/gen-features.cjs +836 -0
  462. package/scripts/gen-health-docs.cjs +390 -0
  463. package/scripts/gen-hooks-cli-exit.cjs +239 -0
  464. package/scripts/gen-install-tree-fixtures.cjs +2 -2
  465. package/scripts/gen-inventory-manifest.cjs +50 -4
  466. package/scripts/gen-loop-host-contract.cjs +138 -25
  467. package/scripts/gen-registry.cjs +3 -14
  468. package/scripts/gen-scripts-cli-exit.cjs +185 -0
  469. package/scripts/gen-state-md-docs.cjs +727 -0
  470. package/scripts/{test-failure-reasons.cjs → gsd-test-gate-reasons.cjs} +6 -0
  471. package/scripts/lib/alias-drift-families.cjs +46 -0
  472. package/scripts/lib/ci-job-timing.cjs +72 -0
  473. package/scripts/lib/cli-exit.cjs +546 -44
  474. package/scripts/lib/drift-scan.cjs +308 -0
  475. package/scripts/lib/exit-code-registry.cjs +98 -0
  476. package/scripts/lib/ndjson-reporter.cjs +119 -0
  477. package/scripts/lint-allow-test-rule-refs.allowlist.json +1 -26
  478. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +4 -0
  479. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +3 -0
  480. package/scripts/lint-canary-version-leak.cjs +73 -0
  481. package/scripts/lint-command-contract.cjs +96 -13
  482. package/scripts/lint-completion-predicate-drift.cjs +933 -0
  483. package/scripts/lint-completion-ratio-drift.cjs +214 -0
  484. package/scripts/lint-default-flip-documentation.cjs +193 -0
  485. package/scripts/lint-docs-guard-registration.cjs +495 -0
  486. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +193 -0
  487. package/scripts/lint-eslint-glob-coverage.allowlist.json +38 -0
  488. package/scripts/lint-eslint-glob-coverage.cjs +340 -0
  489. package/scripts/{lint-fix-has-regression-test.cjs → lint-fix-has-regression-tests.cjs} +12 -6
  490. package/scripts/lint-frontmatter-scalar-broad-grep.cjs +237 -0
  491. package/scripts/lint-health-diagnostic-rule-table.cjs +461 -0
  492. package/scripts/lint-hooks-runtime-build-seam.cjs +262 -0
  493. package/scripts/lint-milestone-window-drift.cjs +468 -0
  494. package/scripts/lint-mutation-test-derivation-drift.cjs +86 -0
  495. package/scripts/lint-phase-enumeration-drift.cjs +492 -0
  496. package/scripts/lint-plan-count-drift.cjs +318 -0
  497. package/scripts/lint-planning-artifact-writer-drift.cjs +398 -0
  498. package/scripts/lint-planning-prompt-drift.cjs +471 -0
  499. package/scripts/lint-planning-snapshot-bypass-drift.cjs +544 -0
  500. package/scripts/lint-regression-test-names.cjs +15 -13
  501. package/scripts/lint-removed-but-needed.cjs +488 -0
  502. package/scripts/lint-seam-enforcement.cjs +182 -0
  503. package/scripts/lint-slug-derivation-drift.cjs +921 -0
  504. package/scripts/lint-source-test-name-collision.cjs +241 -0
  505. package/scripts/lint-state-field-drift.cjs +805 -0
  506. package/scripts/lint-state-write-path-drift.cjs +950 -0
  507. package/scripts/lint-test-file-count.allowlist.json +137 -8
  508. package/scripts/lint-test-file-count.cjs +25 -3
  509. package/scripts/lint-unreachable-guard-drift.cjs +830 -0
  510. package/scripts/lint-vendored-deps.cjs +297 -0
  511. package/scripts/mutation-matrix.cjs +599 -50
  512. package/scripts/pr-changed-files.cjs +63 -0
  513. package/scripts/pr-template-policy.cjs +14 -4
  514. package/scripts/prompt-injection-scan.sh +100 -14
  515. package/scripts/require-issue-link-policy.cjs +192 -0
  516. package/scripts/secret-scan.sh +75 -13
  517. package/scripts/select-docs-guards.cjs +56 -0
  518. package/scripts/sync-runtime-launcher.cjs +24 -7
  519. package/skills/gsd-autonomous/SKILL.md +0 -1
  520. package/skills/gsd-code-review/SKILL.md +1 -1
  521. package/skills/gsd-discuss-phase/SKILL.md +1 -1
  522. package/skills/gsd-execute-phase/SKILL.md +1 -2
  523. package/skills/gsd-import/SKILL.md +1 -1
  524. package/skills/gsd-map-codebase/SKILL.md +1 -1
  525. package/skills/gsd-mempalace-capture/SKILL.md +1 -1
  526. package/skills/gsd-mempalace-recall/SKILL.md +1 -1
  527. package/skills/gsd-new-milestone/SKILL.md +1 -1
  528. package/skills/gsd-next/SKILL.md +0 -1
  529. package/skills/gsd-plan-phase/SKILL.md +0 -1
  530. package/skills/gsd-progress/SKILL.md +0 -1
  531. package/skills/gsd-quick/SKILL.md +9 -5
  532. package/skills/gsd-review-backlog/SKILL.md +2 -1
  533. package/skills/gsd-stats/SKILL.md +0 -1
  534. package/skills/gsd-verify-work/SKILL.md +1 -1
  535. package/vscode/package.json +1 -1
  536. package/bin/lib/ui-safety-gate.cjs +0 -107
  537. package/gsd-core/workflows/discovery-phase.md +0 -298
  538. package/gsd-core/workflows/plan-milestone-gaps.md +0 -281
  539. package/gsd-core/workflows/verify-phase.md +0 -574
  540. package/scripts/affected-tests-lib.cjs +0 -554
  541. package/scripts/lint-allow-test-rule-refs.cjs +0 -162
  542. package/scripts/lint-emitted-drift-ack.cjs +0 -344
  543. package/scripts/run-affected-tests.cjs +0 -7
  544. package/scripts/run-tests.cjs +0 -1051
@@ -43,8 +43,9 @@
43
43
  // authoritative — `none`/`orchestrator-worktree` ALLOW immediately
44
44
  // (sequential/orchestrator-managed dispatch is legitimate, not a bug); an
45
45
  // absent/stale sentinel falls back to a conservative registry+config check
46
- // (GSD_RUNTIME env > .planning/config.json `runtime` — no confident signal
47
- // degrades to inert rather than guessing 'claude', see resolveRegistryIsolation)
46
+ // (GSD_RUNTIME env > .planning/config.json `runtime` > the per-install
47
+ // `.gsd-runtime` marker, #3566 — no confident signal degrades to inert rather
48
+ // than guessing 'claude', see resolveRegistryIsolation)
48
49
  // gated additionally by `workflow.use_worktrees` — read directly, in-process,
49
50
  // no subprocess spawn.
50
51
  //
@@ -63,6 +64,32 @@ const fs = require('fs');
63
64
  const path = require('path');
64
65
  const os = require('os');
65
66
  const { readSentinel, VALID_ISOLATION, extractDispatchIdentifiers, sentinelAppliesToDispatch } = require('./lib/isolation-sentinel.js');
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;
85
+ // #3582: gsd-core/bin/lib/*.cjs (runtime-name-policy.cjs, capability-registry.cjs
86
+ // below) are tsc build artifacts (ADR-457), gitignored and absent on a raw
87
+ // plugin-marketplace / git-clone install that never ran `npm run build:lib`.
88
+ // Self-heal before the first such require (resolveRegistryIsolation, below) —
89
+ // see ensureRuntimeBuild's own header for the full rationale. This module
90
+ // itself (gsd-core/bin/ensure-runtime-build.cjs) depends on nothing under
91
+ // ./lib, so requiring it here is always safe.
92
+ const { ensureRuntimeBuild, RuntimeBuildError } = require('../gsd-core/bin/ensure-runtime-build.cjs');
66
93
 
67
94
  // No other executor-shaped subagent_type exists in agents/ today
68
95
  // (verified: only agents/gsd-executor.md). A Set, not a bare string compare,
@@ -85,6 +112,42 @@ function parseHarnessFlag(flag) {
85
112
  return { param: m[1], value: m[2] };
86
113
  }
87
114
 
115
+ // ─── #3897 rung 2: per-install runtime marker, single canonical owner ────────
116
+ // bin/install.js writes `<install>/gsd-core/.gsd-runtime` for EVERY runtime
117
+ // install (#2297), co-located with VERSION. Unlike `~/.gsd/defaults.json` —
118
+ // which is host-wide and names whichever runtime's install ran LAST, the exact
119
+ // leakage #2840's config.cjs change exists to prevent — the marker describes
120
+ // THIS install, which is the property runtime identity needs on a machine
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`).
126
+ function readInstallRuntimeMarker() {
127
+ try {
128
+ ensureRuntimeBuild();
129
+ const runtimeSlash = require('../gsd-core/bin/lib/runtime-slash.cjs');
130
+ return runtimeSlash.readInstallRuntimeMarker();
131
+ } catch {
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;
135
+ }
136
+ }
137
+
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).
140
+ function _setInstallRuntimeMarkerForTests(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
+ }
149
+ }
150
+
88
151
  /**
89
152
  * Resolve this project's declared `runtime` identity WITHOUT defaulting to
90
153
  * 'claude' when no explicit signal exists (#3045 MAJOR 2).
@@ -100,9 +163,10 @@ function parseHarnessFlag(flag) {
100
163
  *
101
164
  * Returns `{ runtimeId, confident }`. `confident` is true only when an
102
165
  * explicit signal exists (GSD_RUNTIME env override, a `runtime` key literally
103
- * present in config.json, or a `runtime` persisted to `~/.gsd/defaults.json`
104
- * by the installer — see below); false means "cannot determine" and callers
105
- * must NOT silently substitute 'claude' — see resolveRegistryIsolation.
166
+ * present in config.json, the per-install `.gsd-runtime` marker, or a
167
+ * `runtime` persisted to `~/.gsd/defaults.json` by the installer — see
168
+ * below); false means "cannot determine" and callers must NOT silently
169
+ * substitute 'claude' — see resolveRegistryIsolation.
106
170
  *
107
171
  * #3045 BLOCKER 2 fix: precedence is GSD_RUNTIME env > config.json `runtime`
108
172
  * key > `~/.gsd/defaults.json` `runtime`. The first two are unchanged; the
@@ -117,6 +181,17 @@ function parseHarnessFlag(flag) {
117
181
  * (`nativeModelAliases` short-circuits it) and therefore correctly still rely
118
182
  * on config.json/env. Reading the installer's own persisted signal makes
119
183
  * "confident" the common case instead.
184
+ *
185
+ * #3566: the per-install `.gsd-runtime` marker now sits BETWEEN config.json
186
+ * and defaults.json. defaults.json is host-wide and names whichever runtime
187
+ * installed LAST — on a 2-runtime machine that confidently resolves the WRONG
188
+ * runtime (a Codex install's `runtime:"codex"` leaking into Claude projects),
189
+ * and when the wrong runtime declares no harnessIsolationFlag the guard goes
190
+ * silently inert. The marker describes THIS install (written for every
191
+ * runtime since #2297), which is the source #2840's config.cjs change names
192
+ * as correct. defaults.json stays as the final rung so single-runtime default
193
+ * installs and pre-#2297 installs (no marker on disk) keep the #3045
194
+ * BLOCKER 2 behavior.
120
195
  */
121
196
  function resolveRuntimeIdentity(cwd, configPath, resolveRuntimeNameFromCandidates) {
122
197
  const envRuntime = resolveRuntimeNameFromCandidates(process.env.GSD_RUNTIME);
@@ -132,6 +207,13 @@ function resolveRuntimeIdentity(cwd, configPath, resolveRuntimeNameFromCandidate
132
207
  if (configRuntime) return { runtimeId: configRuntime, confident: true };
133
208
  }
134
209
 
210
+ // #3566: the per-install marker, above the host-wide defaults — see the
211
+ // block comment on readInstallRuntimeMarker. An empty/whitespace-only file
212
+ // or an unknown value degrades exactly like the other rungs (no signal /
213
+ // future-runtime tolerance via resolveRuntimeNameFromCandidates).
214
+ const markerRuntime = resolveRuntimeNameFromCandidates(readInstallRuntimeMarker());
215
+ if (markerRuntime) return { runtimeId: markerRuntime, confident: true };
216
+
135
217
  // #3045 BLOCKER 2: fall back to the installer-persisted default. Read
136
218
  // defensively — an absent/corrupt/non-object defaults.json is "no signal",
137
219
  // never a resolution failure (this function only ever throws for the
@@ -183,6 +265,15 @@ function resolveHarnessFlag(runtimeId, runtimes) {
183
265
  * run, e.g. a manual Agent() call before any sentinel has been written).
184
266
  */
185
267
  function resolveRegistryIsolation(cwd, configPath) {
268
+ // #3582: self-heal the compiled runtime library BEFORE either require
269
+ // below — this is the only reaching path to both (resolveRegistryIsolation
270
+ // is the sole caller of each), so one call here covers both. Throws
271
+ // RuntimeBuildError on an unbuildable tree; the caller (resolveIsolationState)
272
+ // already wraps this whole function in try/catch and folds any error into
273
+ // its fail-closed `error` result — evaluateDispatch below distinguishes a
274
+ // RuntimeBuildError there so it surfaces this seam's actionable message
275
+ // instead of being misreported as an unreadable config.json (#3050 lesson).
276
+ ensureRuntimeBuild();
186
277
  const { resolveRuntimeNameFromCandidates } = require('../gsd-core/bin/lib/runtime-name-policy.cjs');
187
278
  const { runtimes } = require('../gsd-core/bin/lib/capability-registry.cjs');
188
279
 
@@ -208,18 +299,40 @@ function resolveRegistryIsolation(cwd, configPath) {
208
299
 
209
300
  if (isolation === 'harness-worktree') {
210
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;
211
313
  try {
212
- const raw = fs.readFileSync(configPath, 'utf-8');
213
- const parsedCfg = JSON.parse(raw);
214
- if (parsedCfg && typeof parsedCfg === 'object' && parsedCfg.workflow &&
215
- typeof parsedCfg.workflow === 'object' && parsedCfg.workflow.use_worktrees === false) {
216
- useWorktrees = false;
217
- }
314
+ ensureRuntimeBuild();
315
+ const { worktreesOptedOut } = require('../gsd-core/bin/lib/planning-workspace.cjs');
316
+ useWorktrees = !worktreesOptedOut(cwd);
317
+ ladderAnswered = true;
218
318
  } catch {
219
- // Unreadable config already propagated to the outer caller's catch
220
- // before this point in practice (resolveRuntimeIdentity reads it
221
- // first); tolerate defensively and keep the conservative (enforce)
222
- // 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
+ }
223
336
  }
224
337
  if (!useWorktrees) isolation = 'none';
225
338
  }
@@ -360,13 +473,27 @@ function evaluateDispatch(data, { clock = Date } = {}) {
360
473
  if (!state.gsdProject) return { action: 'allow' };
361
474
 
362
475
  if (state.error) {
363
- const reason =
364
- `Agent isolation guard: could not read or resolve this project's dispatch-isolation ` +
365
- `configuration ('.planning/config.json' under '${cwd}'). Refusing to dispatch ` +
366
- `subagent_type="${subagentType}" without being able to verify whether isolation is ` +
367
- `required — a guard that cannot verify must not answer "safe" (#3050). Retry once the ` +
368
- `project configuration is readable.`;
369
- return { action: 'block', reason };
476
+ // #3582: a missing/unbuildable compiled runtime library (RuntimeBuildError,
477
+ // thrown by ensureRuntimeBuild in resolveRegistryIsolation) is a DIFFERENT,
478
+ // actionable failure from an unreadable/unparsable config.json — surface
479
+ // its own message instead of misreporting it as the generic
480
+ // "could not read or resolve ... configuration" text (the exact #3050
481
+ // misreport this issue exists to fix). Both cases still fail closed
482
+ // (block); only the message differs.
483
+ const isBuildFailure = state.error instanceof RuntimeBuildError;
484
+ const reason = isBuildFailure
485
+ ? `Agent isolation guard: cannot resolve this project's dispatch-isolation ` +
486
+ `configuration because the GSD runtime library failed to self-build. ` +
487
+ `${state.error.message} Refusing to dispatch subagent_type="${subagentType}" until ` +
488
+ `the runtime library is built — a guard that cannot verify must not answer "safe" ` +
489
+ `(#3050).`
490
+ : `Agent isolation guard: could not read or resolve this project's dispatch-isolation ` +
491
+ `configuration ('.planning/config.json' under '${cwd}'). Refusing to dispatch ` +
492
+ `subagent_type="${subagentType}" without being able to verify whether isolation is ` +
493
+ `required — a guard that cannot verify must not answer "safe" (#3050). Retry once the ` +
494
+ `project configuration is readable.`;
495
+ const reasonCode = isBuildFailure ? REASON_CODE.RUNTIME_BUILD_FAILED : REASON_CODE.CONFIG_UNREADABLE;
496
+ return { action: 'block', reason, reasonCode };
370
497
  }
371
498
 
372
499
  if (state.isolation !== 'harness-worktree') return { action: 'allow' };
@@ -382,13 +509,13 @@ function evaluateDispatch(data, { clock = Date } = {}) {
382
509
  `${parsed.param}="${parsed.value}". Add ${parsed.param}="${parsed.value}" to the Agent() ` +
383
510
  `call so the executor runs in an isolated worktree instead of the primary checkout ` +
384
511
  `(gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md).`;
385
- return { action: 'block', reason };
512
+ return { action: 'block', reason, reasonCode: REASON_CODE.HARNESS_FLAG_MISSING };
386
513
  }
387
514
 
388
515
  /* istanbul ignore next -- stdin adapter, exercised via spawnSync in tests */
389
516
  function main() {
390
517
  let input = '';
391
- const stdinTimeout = setTimeout(() => process.exit(0), 3000);
518
+ const stdinTimeout = setTimeout(() => allow(undefined), 3000);
392
519
  process.stdin.setEncoding('utf8');
393
520
  process.stdin.on('data', (chunk) => { input += chunk; });
394
521
  process.stdin.on('end', () => {
@@ -397,19 +524,19 @@ function main() {
397
524
  const data = JSON.parse(input);
398
525
  const decision = evaluateDispatch(data);
399
526
  if (decision.action === 'block') {
400
- const out = { decision: 'block', reason: decision.reason };
401
- process.stdout.write(JSON.stringify(out));
527
+ const out = { decision: 'block', reason: decision.reason, reason_code: decision.reasonCode };
402
528
  // Kimi feeds stderr (not stdout) back to the model on exit 2.
403
- process.stderr.write(decision.reason);
404
- process.exit(2);
529
+ deny(out, decision.reason);
405
530
  }
406
- process.exit(0);
531
+ allow(undefined);
407
532
  } catch {
408
533
  // Silent fail — never block valid tool calls due to hook errors
409
534
  // (malformed payload, etc.). This is distinct from resolveIsolationState's
410
535
  // internal error handling, which DOES deny — this outer catch only
411
536
  // covers payload parsing before applicability could even be determined.
412
- 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);
413
540
  }
414
541
  });
415
542
  }
@@ -425,4 +552,5 @@ module.exports = {
425
552
  resolveHarnessFlag,
426
553
  resolveRegistryIsolation,
427
554
  parseHarnessFlag,
555
+ _setInstallRuntimeMarkerForTests,
428
556
  };
@@ -11,18 +11,61 @@
11
11
 
12
12
  const fs = require('fs');
13
13
  const path = require('path');
14
- const { isSemverNewer } = require('../gsd-core/bin/lib/semver-compare.cjs');
15
- // Latest-version lookup is delegated to the single deterministic adapter
16
- // (#498). checkLatestVersion() owns the npm-view call, the timeout/semver
17
- // policy, and the package name — sourced from the baked Package Identity seam.
18
- // The previous `require('../package.json').name` (#378) never yielded a name in
19
- // the installed tree — at the time it resolved to the synthetic
20
- // {"type":"commonjs"} marker GSD wrote at the config root, which has no `.name`,
21
- // so the background check never reported updates. Since #2544 GSD writes no
22
- // marker there at all, so that require would now fail to resolve outright.
23
- // Either way the name must come from the baked seam, never a walk-up.
24
- const { checkLatestVersion } = require('../gsd-core/bin/check-latest-version.cjs');
25
- const { PACKAGE_NAME } = require('../gsd-core/bin/lib/package-identity.cjs');
14
+
15
+ // #3582: gsd-core/bin/lib/semver-compare.cjs and package-identity.cjs (and,
16
+ // transitively, check-latest-version.cjs's own gsd-core/bin/lib/cli-exit.cjs
17
+ // + shell-command-projection.cjs) are tsc build artifacts (ADR-457),
18
+ // gitignored and absent on a raw plugin-marketplace / git-clone install that
19
+ // never ran `npm run build:lib`. This worker is a DETACHED SessionStart
20
+ // background process (spawned with stdio: 'ignore') — a build failure here
21
+ // must DEGRADE to the no-signal fallbacks below (mirroring the
22
+ // managed-hooks-registry.cjs degrade just below) so the worker still runs to
23
+ // completion and writes a result cache record, rather than dying silently
24
+ // with no visible signal and no cache-file write at all.
25
+ //
26
+ // This try/require/ensureRuntimeBuild/require/catch shape repeats (with
27
+ // different destructured names) in hooks/gsd-check-update.js and
28
+ // hooks/gsd-update-banner.js. It is deliberately NOT extracted into a shared
29
+ // hooks/lib/ helper: scripts/lint-hooks-runtime-build-seam.cjs enforces this
30
+ // exact seam textually, PER FILE — it greps each hooks/ file for its OWN
31
+ // literal `require('.../ensure-runtime-build.cjs')` + `ensureRuntimeBuild(`
32
+ // call co-occurring with its OWN literal `require('.../gsd-core/bin/lib/*.cjs')`.
33
+ // A generic helper taking the compiled module's path as a variable would move
34
+ // the literal compiled-lib require OUT of this file and into the helper,
35
+ // called with a non-literal argument — the scan's regex (see that script's
36
+ // "Known limitations") cannot see a require() called with a variable, so this
37
+ // file would then read as "requires nothing" and the lint would stop
38
+ // protecting it. A ceremony-only helper (just the ensureRuntimeBuild call,
39
+ // each caller keeping its own literal compiled-lib require) fails the SAME
40
+ // way from the other side: it would remove this file's own literal
41
+ // `require('.../ensure-runtime-build.cjs')` + `ensureRuntimeBuild(` call,
42
+ // which the lint also requires to be textually present in THIS file. Either
43
+ // shape needs the lint script itself widened to special-case the helper,
44
+ // which is a bigger, riskier change than the ~6 duplicated lines it would
45
+ // save; kept inline instead.
46
+ let isSemverNewer = () => false;
47
+ let checkLatestVersion = () => ({ ok: false });
48
+ let PACKAGE_NAME = null;
49
+ try {
50
+ const { ensureRuntimeBuild } = require('../gsd-core/bin/ensure-runtime-build.cjs');
51
+ ensureRuntimeBuild();
52
+ ({ isSemverNewer } = require('../gsd-core/bin/lib/semver-compare.cjs'));
53
+ // Latest-version lookup is delegated to the single deterministic adapter
54
+ // (#498). checkLatestVersion() owns the npm-view call, the timeout/semver
55
+ // policy, and the package name — sourced from the baked Package Identity seam.
56
+ // The previous `require('../package.json').name` (#378) never yielded a name in
57
+ // the installed tree — at the time it resolved to the synthetic
58
+ // {"type":"commonjs"} marker GSD wrote at the config root, which has no `.name`,
59
+ // so the background check never reported updates. Since #2544 GSD writes no
60
+ // marker there at all, so that require would now fail to resolve outright.
61
+ // Either way the name must come from the baked seam, never a walk-up.
62
+ ({ checkLatestVersion } = require('../gsd-core/bin/check-latest-version.cjs'));
63
+ ({ PACKAGE_NAME } = require('../gsd-core/bin/lib/package-identity.cjs'));
64
+ } catch (e) {
65
+ // Runtime library missing/broken and could not self-build — degrade to the
66
+ // no-signal fallbacks declared above; the worker still writes a result
67
+ // cache record (package_name: null, update_available: false).
68
+ }
26
69
  // Authoritative list of managed hooks — shared with tests to retire source-grep
27
70
  // assertions (pending-migration-to-typed-ir [#455]).
28
71
  // NOTE: managed-hooks-registry.cjs must be in HOOKS_TO_COPY (scripts/build-hooks.js)
@@ -63,7 +106,7 @@ try {
63
106
  // (e.g., gsd-intel-*.js) must be ignored to avoid permanent stale warnings (#1750)
64
107
  // MANAGED_HOOKS is imported from ./managed-hooks-registry.cjs above.
65
108
 
66
- let staleHooks = [];
109
+ const staleHooks = [];
67
110
  if (configDir) {
68
111
  // #3023: the bundle's directory name is runtime-descriptor-driven (pi stages
69
112
  // it as `gsd-hooks/`), so deriving it as `<configDir>/hooks` silently scanned
@@ -8,7 +8,25 @@ const path = require('path');
8
8
  const os = require('os');
9
9
  const { spawn } = require('child_process');
10
10
 
11
- const { updateCacheFileName } = require('../gsd-core/bin/lib/package-identity.cjs');
11
+ // #3582: gsd-core/bin/lib/package-identity.cjs is a tsc build artifact
12
+ // (ADR-457), gitignored and absent on a raw plugin-marketplace / git-clone
13
+ // install that never ran `npm run build:lib`. This SessionStart hook must
14
+ // DEGRADE (fall back to a generic cache filename) rather than crash session
15
+ // start. gsd-check-update-worker.js — the process this hook spawns — degrades
16
+ // identically and independently, so the shared fallback literal keeps the
17
+ // cache path consistent between writer and reader even in the (rare)
18
+ // doubly-degraded case. This try/require/ensureRuntimeBuild/require/catch
19
+ // shape is deliberately duplicated (not extracted to hooks/lib/) — see
20
+ // gsd-check-update-worker.js's identical #3582 comment for why.
21
+ let updateCacheFileName = 'gsd-update-check.json';
22
+ try {
23
+ const { ensureRuntimeBuild } = require('../gsd-core/bin/ensure-runtime-build.cjs');
24
+ ensureRuntimeBuild();
25
+ ({ updateCacheFileName } = require('../gsd-core/bin/lib/package-identity.cjs'));
26
+ } catch (e) {
27
+ // Runtime library missing/broken and could not self-build — degrade to the
28
+ // fallback filename above rather than crash the SessionStart hook.
29
+ }
12
30
 
13
31
  const homeDir = os.homedir();
14
32
  const cwd = process.cwd();
@@ -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
  });
@@ -22,6 +22,13 @@ const fs = require('fs');
22
22
  const os = require('os');
23
23
  const path = require('path');
24
24
  const { spawn } = require('child_process');
25
+ const { HOOK_ON_CRASH, allow, crash } = require('./lib/hook-exit.js');
26
+
27
+ // This hook only injects an advisory context-usage warning; it never blocks
28
+ // the tool call it rides in on. A crash here (e.g. a malformed bridge file)
29
+ // must not turn a PostToolUse advisory into a blocked tool call — losing a
30
+ // context warning is far cheaper than stalling the agent's work (#3911).
31
+ const ON_CRASH = HOOK_ON_CRASH.ALLOW;
25
32
 
26
33
  const WARNING_THRESHOLD = 35; // remaining_percentage <= 35%
27
34
  const CRITICAL_THRESHOLD = 25; // remaining_percentage <= 25%
@@ -33,7 +40,7 @@ let input = '';
33
40
  // Windows/Git Bash, or slow Claude Code piping during large outputs),
34
41
  // exit silently instead of hanging until Claude Code kills the process
35
42
  // and reports "hook error". See #775, #1162.
36
- const stdinTimeout = setTimeout(() => process.exit(0), 10000);
43
+ const stdinTimeout = setTimeout(() => allow(undefined), 10000);
37
44
  process.stdin.setEncoding('utf8');
38
45
  process.stdin.on('data', chunk => input += chunk);
39
46
  process.stdin.on('end', () => {
@@ -43,14 +50,14 @@ process.stdin.on('end', () => {
43
50
  const sessionId = data.session_id;
44
51
 
45
52
  if (!sessionId) {
46
- process.exit(0);
53
+ allow(undefined);
47
54
  }
48
55
 
49
56
  // Reject session IDs that contain path traversal sequences or path separators.
50
57
  // session_id is used to construct file paths in /tmp — an unsanitized value
51
58
  // could escape the temp directory and read or write arbitrary files.
52
59
  if (/[/\\]|\.\./.test(sessionId)) {
53
- process.exit(0);
60
+ allow(undefined);
54
61
  }
55
62
 
56
63
  // Check if context warnings are disabled via config.
@@ -61,7 +68,7 @@ process.stdin.on('end', () => {
61
68
  const configPath = path.join(cwd, '.planning', 'config.json');
62
69
  const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
63
70
  if (config.hooks?.context_warnings === false) {
64
- process.exit(0);
71
+ allow(undefined);
65
72
  }
66
73
  } catch (e) {
67
74
  // Missing or unparseable config → proceed with defaults (context warnings enabled)
@@ -77,7 +84,7 @@ process.stdin.on('end', () => {
77
84
  try {
78
85
  metricsRaw = fs.readFileSync(metricsPath, 'utf8');
79
86
  } catch (e) {
80
- if (e && e.code === 'ENOENT') process.exit(0);
87
+ if (e && e.code === 'ENOENT') allow(undefined);
81
88
  throw e;
82
89
  }
83
90
  const metrics = JSON.parse(metricsRaw);
@@ -85,7 +92,7 @@ process.stdin.on('end', () => {
85
92
 
86
93
  // Ignore stale metrics
87
94
  if (metrics.timestamp && (now - metrics.timestamp) > STALE_SECONDS) {
88
- process.exit(0);
95
+ allow(undefined);
89
96
  }
90
97
 
91
98
  const remaining = metrics.remaining_percentage;
@@ -93,7 +100,7 @@ process.stdin.on('end', () => {
93
100
 
94
101
  // No warning needed
95
102
  if (remaining > WARNING_THRESHOLD) {
96
- process.exit(0);
103
+ allow(undefined);
97
104
  }
98
105
 
99
106
  // Debounce: check if we warned recently
@@ -121,7 +128,7 @@ process.stdin.on('end', () => {
121
128
  if (!firstWarn && warnData.callsSinceWarn < DEBOUNCE_CALLS && !severityEscalated) {
122
129
  // Update counter and exit without warning
123
130
  fs.writeFileSync(warnPath, JSON.stringify(warnData));
124
- process.exit(0);
131
+ allow(undefined);
125
132
  }
126
133
 
127
134
  // Reset debounce counter
@@ -208,7 +215,9 @@ process.stdin.on('end', () => {
208
215
  process.stdout.write(JSON.stringify(output));
209
216
  }
210
217
  } catch (e) {
211
- // Silent fail -- never block tool execution
212
- process.exit(0);
218
+ // Silent fail -- never block tool execution.
219
+ // ON_CRASH is declared ALLOW at module top: this preserves today's
220
+ // exit(0) fail-open behavior exactly (#3911).
221
+ crash(ON_CRASH, undefined);
213
222
  }
214
223
  });
@@ -22,6 +22,8 @@
22
22
 
23
23
  'use strict';
24
24
 
25
+ const { allow } = require('./lib/hook-exit.js');
26
+
25
27
  const WRITE_TOOL_RE = /write|edit|replace|create|delete|remove|append|apply|patch|insert|mkdir/i;
26
28
  const PATH_KEY_RE = /^(path|file|file_?path|filepath|target_?path|target|dir|directory|uri|filename)$/i;
27
29
  const PLANNING_PATH_RE = /(^|[\\/])\.planning([\\/]|$)/;
@@ -29,7 +31,7 @@ const PLANNING_PATH_RE = /(^|[\\/])\.planning([\\/]|$)/;
29
31
  let raw = '';
30
32
  const stdinTimeout = setTimeout(() => {
31
33
  // Timeout guard: exit silently rather than hanging.
32
- process.exit(0);
34
+ allow(undefined);
33
35
  }, 10000);
34
36
 
35
37
  process.stdin.setEncoding('utf8');
@@ -22,8 +22,7 @@
22
22
 
23
23
  'use strict';
24
24
 
25
- const fs = require('fs');
26
- const path = require('path');
25
+ const { allow } = require('./lib/hook-exit.js');
27
26
 
28
27
  const WRITE_TOOL_RE = /write|edit|replace|create|delete|remove|append|apply|patch|insert|mkdir/i;
29
28
  const PATH_KEY_RE = /^(path|file|file_?path|filepath|target_?path|target|dir|directory|uri|filename)$/i;
@@ -31,7 +30,7 @@ const PLANNING_PATH_RE = /(^|[\\/])\.planning([\\/]|$)/;
31
30
 
32
31
  let raw = '';
33
32
  const stdinTimeout = setTimeout(() => {
34
- process.exit(0);
33
+ allow(undefined);
35
34
  }, 10000);
36
35
 
37
36
  process.stdin.setEncoding('utf8');
@@ -23,6 +23,7 @@
23
23
  'use strict';
24
24
 
25
25
  const fs = require('fs');
26
+ const { allow } = require('./lib/hook-exit.js');
26
27
 
27
28
  const MSG_PRESENT =
28
29
  'GSD: .planning/STATE.md is present — review the current phase and any blockers before acting.';
@@ -37,7 +38,7 @@ const { resolveStatePath } = require('./lib/cursor-workspace.js');
37
38
  let raw = '';
38
39
  const stdinTimeout = setTimeout(() => {
39
40
  // Timeout guard: exit silently rather than hanging.
40
- process.exit(0);
41
+ allow(undefined);
41
42
  }, 10000);
42
43
 
43
44
  process.stdin.setEncoding('utf8');
@@ -21,6 +21,7 @@
21
21
  'use strict';
22
22
 
23
23
  const fs = require('fs');
24
+ const { allow } = require('./lib/hook-exit.js');
24
25
 
25
26
  // Workspace resolution is shared across the Cursor hooks (#2587) — see
26
27
  // hooks/lib/cursor-workspace.js. Staged next to these scripts by
@@ -29,7 +30,7 @@ const { resolveStatePath } = require('./lib/cursor-workspace.js');
29
30
 
30
31
  let raw = '';
31
32
  const stdinTimeout = setTimeout(() => {
32
- process.exit(0);
33
+ allow(undefined);
33
34
  }, 10000);
34
35
 
35
36
  process.stdin.setEncoding('utf8');