@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
@@ -56,12 +56,22 @@
56
56
  const fs = require('fs');
57
57
  const path = require('path');
58
58
  const os = require('os');
59
+ const { allow } = require('./lib/hook-exit.js');
59
60
 
60
61
  // Workspace resolution is shared across the Cursor hooks (#2587) — see
61
62
  // hooks/lib/cursor-workspace.js. Staged next to these scripts by
62
63
  // writeCursorHooksJson so the require always resolves post-install.
63
64
  const { resolveStatePath } = require('./lib/cursor-workspace.js');
64
65
  const { readSentinel, VALID_ISOLATION, extractDispatchIdentifiers, sentinelAppliesToDispatch } = require('./lib/isolation-sentinel.js');
66
+ const { REASON_CODE } = require('./lib/isolation-deny-reason.js');
67
+ // #3582: gsd-core/bin/lib/*.cjs (runtime-homes.cjs, worktree-safety.cjs,
68
+ // runtime-name-policy.cjs, capability-registry.cjs — required below, inside
69
+ // resolveIsolationEvidence and resolveFallbackIsolation) are tsc build
70
+ // artifacts (ADR-457), gitignored and absent on a raw plugin-marketplace /
71
+ // git-clone install that never ran `npm run build:lib`. Self-heal once, in
72
+ // evaluateRootIsolation, before any of those four requires run — see the
73
+ // call site below. This module itself depends on nothing under ./lib.
74
+ const { ensureRuntimeBuild, RuntimeBuildError } = require('../gsd-core/bin/ensure-runtime-build.cjs');
65
75
 
66
76
  const MSG_PRESENT =
67
77
  'GSD: Subagent session started — review .planning/STATE.md for the current phase and any blockers before acting.';
@@ -333,6 +343,41 @@ function resolveIsolationDecision(data, { clock = Date, realpath = fs.realpathSy
333
343
  return { action: 'allow' };
334
344
  }
335
345
 
346
+ // ─── #3897 rung 2: per-install runtime marker, single canonical owner ────────
347
+ // bin/install.js writes `<install>/gsd-core/.gsd-runtime` beside VERSION for
348
+ // every runtime install (#2297); this hook ships at `<install>/hooks/`, so the
349
+ // marker is the `gsd-core` sibling of this file's own directory. Previously
350
+ // this hook held its own private reader/cache (one of four #3897 found); it
351
+ // now delegates to the single canonical owner, `src/runtime-slash.cts`
352
+ // (compiled to gsd-core/bin/lib/runtime-slash.cjs), reached through
353
+ // `ensureRuntimeBuild()` like the other compiled-lib requires in this file
354
+ // (`scripts/lint-hooks-runtime-build-seam.cjs`).
355
+ function readInstallRuntimeMarker() {
356
+ try {
357
+ ensureRuntimeBuild();
358
+ const runtimeSlash = require('../gsd-core/bin/lib/runtime-slash.cjs');
359
+ return runtimeSlash.readInstallRuntimeMarker();
360
+ } catch {
361
+ // Unbuilt runtime library, or any other failure reaching the canonical
362
+ // owner — "no signal from this rung", never a resolution failure.
363
+ return null;
364
+ }
365
+ }
366
+
367
+ // Test seam — forwards to the canonical owner's seam so this hook and
368
+ // runtime-slash.cjs always share one cache (#3897 rung 2). Spawned-hook tests
369
+ // (fresh process, no marker) are unaffected.
370
+ function _setInstallRuntimeMarkerForTests(value) {
371
+ try {
372
+ ensureRuntimeBuild();
373
+ const runtimeSlash = require('../gsd-core/bin/lib/runtime-slash.cjs');
374
+ runtimeSlash._setInstallRuntimeMarkerForTests(value);
375
+ } catch {
376
+ // Test-only seam; an unbuilt library here means the test itself will fail
377
+ // downstream, which is a louder and more actionable signal than throwing here.
378
+ }
379
+ }
380
+
336
381
  /**
337
382
  * Conservative fallback resolution used when the #3045 sentinel is absent or
338
383
  * stale for `root`: re-derive isolation from the registry CAPABILITY, gated
@@ -355,7 +400,8 @@ function resolveIsolationDecision(data, { clock = Date, realpath = fs.realpathSy
355
400
  * otherwise legitimate dispatches, unlike `hooks/gsd-agent-isolation-guard.js`,
356
401
  * which degrades an undeterminable runtime to inert (#3045 MAJOR 2). Aligned
357
402
  * here: an explicit signal is now required — `GSD_RUNTIME` > config.json
358
- * `runtime` key > `~/.gsd/defaults.json` `runtime` (mirrors the Claude hook's
403
+ * `runtime` key > the per-install `.gsd-runtime` marker (#3566) >
404
+ * `~/.gsd/defaults.json` `runtime` (mirrors the Claude hook's
359
405
  * `resolveRuntimeIdentity`; `bin/install.js`'s `writeNonClaudeDefaults`
360
406
  * persists the installed runtime there for every non-Claude install,
361
407
  * including Cursor, so a REAL Cursor+GSD install still resolves confidently
@@ -372,6 +418,13 @@ function resolveFallbackIsolation(root, configPath) {
372
418
  if (!runtimeId && parsedConfig && typeof parsedConfig === 'object' && 'runtime' in parsedConfig) {
373
419
  runtimeId = resolveRuntimeNameFromCandidates(parsedConfig.runtime) || null;
374
420
  }
421
+ if (!runtimeId) {
422
+ // #3566: the per-install marker, above the host-wide defaults — same fix as
423
+ // hooks/gsd-agent-isolation-guard.js's resolveRuntimeIdentity. defaults.json
424
+ // is host-wide and names whichever runtime installed LAST (#2840's poison);
425
+ // the marker describes THIS install (written for every runtime since #2297).
426
+ runtimeId = resolveRuntimeNameFromCandidates(readInstallRuntimeMarker()) || null;
427
+ }
375
428
  if (!runtimeId) {
376
429
  try {
377
430
  const defaultsPath = path.join(os.homedir(), '.gsd', 'defaults.json');
@@ -419,6 +472,28 @@ function evaluateRootIsolation(root, subagentType, { clock = Date, dispatchIds =
419
472
  }
420
473
  if (!isGsdProject) return { action: 'allow' };
421
474
 
475
+ // #3582: self-heal the compiled runtime library BEFORE any of its four
476
+ // downstream requires (resolveFallbackIsolation's two, resolveIsolationEvidence's
477
+ // two — reached only below this point). Checked separately from the
478
+ // sentinel/fallback try block below so a build failure surfaces its own
479
+ // actionable RuntimeBuildError message rather than being folded into the
480
+ // generic "could not read or resolve ... configuration" deny reason (the
481
+ // #3050 misreport this issue exists to fix). Still fails closed either way.
482
+ try {
483
+ ensureRuntimeBuild();
484
+ } catch (err) {
485
+ return {
486
+ action: 'deny',
487
+ reason:
488
+ `GSD subagent isolation guard: cannot resolve this project's dispatch-isolation ` +
489
+ `configuration because the GSD runtime library failed to self-build. ` +
490
+ `${err instanceof RuntimeBuildError ? err.message : String(err && err.message || err)} ` +
491
+ `Refusing to allow this subagent to spawn until the runtime library is built — a guard ` +
492
+ `that cannot verify must not answer "safe" (#3050).`,
493
+ reasonCode: REASON_CODE.RUNTIME_BUILD_FAILED,
494
+ };
495
+ }
496
+
422
497
  let declaredIsolation;
423
498
  try {
424
499
  // #3045 BLOCKER fix: a fresh sentinel is authoritative for THIS
@@ -439,6 +514,7 @@ function evaluateRootIsolation(root, subagentType, { clock = Date, dispatchIds =
439
514
  `Refusing to allow this subagent to spawn without being able to verify whether ` +
440
515
  `isolation is required — a guard that cannot verify must not answer "safe" (#3050). ` +
441
516
  `Retry once the project configuration is readable.`,
517
+ reasonCode: REASON_CODE.CONFIG_UNREADABLE,
442
518
  };
443
519
  }
444
520
 
@@ -455,6 +531,7 @@ function evaluateRootIsolation(root, subagentType, { clock = Date, dispatchIds =
455
531
  `"harness-worktree", but the subagentStart payload for this dispatch carries no usable ` +
456
532
  `subagent_type. Refusing to allow it to spawn without being able to confirm whether it ` +
457
533
  `is a GSD executor — a guard that cannot verify must not answer "safe" (#3050).`,
534
+ reasonCode: REASON_CODE.NO_SUBAGENT_TYPE,
458
535
  };
459
536
  }
460
537
 
@@ -471,6 +548,7 @@ function evaluateRootIsolation(root, subagentType, { clock = Date, dispatchIds =
471
548
  `could not be determined (git did not respond). Refusing to allow subagent_type=` +
472
549
  `"${subagentType}" to spawn without being able to verify isolation — a guard that ` +
473
550
  `cannot verify must not answer "safe" (#3050). Retry once git is responsive.`,
551
+ reasonCode: REASON_CODE.CANNOT_DETERMINE_ISOLATION,
474
552
  };
475
553
  }
476
554
 
@@ -483,6 +561,7 @@ function evaluateRootIsolation(root, subagentType, { clock = Date, dispatchIds =
483
561
  `directly, with no consent and no warning. Start an isolated session first (the ` +
484
562
  `"--worktree" CLI flag or the "/worktree" chat command; Cursor manages these worktrees ` +
485
563
  `under "~/.cursor/worktrees/") and retry.`,
564
+ reasonCode: REASON_CODE.NOT_ISOLATED_WORKTREE,
486
565
  };
487
566
  }
488
567
 
@@ -490,7 +569,7 @@ function evaluateRootIsolation(root, subagentType, { clock = Date, dispatchIds =
490
569
  function main() {
491
570
  let raw = '';
492
571
  const stdinTimeout = setTimeout(() => {
493
- process.exit(0);
572
+ allow(undefined);
494
573
  }, 10000);
495
574
 
496
575
  process.stdin.setEncoding('utf8');
@@ -532,7 +611,7 @@ function main() {
532
611
  decision = { action: 'allow' };
533
612
  }
534
613
  if (decision.action === 'deny') {
535
- const out = { permission: 'deny', user_message: decision.reason };
614
+ const out = { permission: 'deny', user_message: decision.reason, reason_code: decision.reasonCode };
536
615
  if (additionalContext !== null) out.additional_context = additionalContext;
537
616
  process.stdout.write(JSON.stringify(out));
538
617
  return;
@@ -557,4 +636,5 @@ module.exports = {
557
636
  resolveFallbackIsolation,
558
637
  resolveIsolationEvidence,
559
638
  getWorkspaceRoots,
639
+ _setInstallRuntimeMarkerForTests,
560
640
  };
@@ -20,13 +20,16 @@
20
20
 
21
21
  'use strict';
22
22
 
23
- let raw = '';
23
+ const { allow } = require('./lib/hook-exit.js');
24
+
24
25
  const stdinTimeout = setTimeout(() => {
25
- process.exit(0);
26
+ allow(undefined);
26
27
  }, 10000);
27
28
 
28
29
  process.stdin.setEncoding('utf8');
29
- process.stdin.on('data', (chunk) => { raw += chunk; });
30
+ // Drain stdin (puts the stream into flowing mode so 'end' fires); the
31
+ // payload itself is unused — this hook responds unconditionally.
32
+ process.stdin.on('data', () => {});
30
33
  process.stdin.on('end', () => {
31
34
  clearTimeout(stdinTimeout);
32
35
  try {
@@ -34,6 +34,7 @@
34
34
  const fs = require('fs');
35
35
  const path = require('path');
36
36
  const os = require('os');
37
+ const { allow } = require('./lib/hook-exit.js');
37
38
 
38
39
  // Immutable, bundled subdirectories that the canonical path must expose. These
39
40
  // are the directories `@~/.claude/gsd-core/<subdir>/...` includes point into.
@@ -301,5 +302,5 @@ if (require.main === module) {
301
302
  } catch (_) {
302
303
  // Best-effort: a canonical-path failure must never abort a session.
303
304
  }
304
- process.exit(0);
305
+ allow(undefined);
305
306
  }
@@ -9,17 +9,20 @@
9
9
  # graphify.auto_update defaults to false so existing users see no behavior change.
10
10
  #
11
11
  # Gates (in fast-fail order — each shaves work off the common non-dispatch path):
12
+ # 0. .planning/config.json exists AND $CI unset/empty (#3729 — both are
13
+ # parse-free shell tests; running them before the Gate 1 node spawn keeps
14
+ # non-GSD repositories and CI off the spawn path entirely, which on
15
+ # Windows otherwise flashes a console window per Bash call)
12
16
  # 1. Stdin payload present and tool_name == "Bash"
13
17
  # 2. tool_input.command matches a HEAD-advancing git op (shell-direct or
14
18
  # the exact `gsd-tools query commit` command shape; the SDK command invokes
15
19
  # git internally, so the literal "git commit" substring never appears —
16
20
  # see #3653)
17
- # 3. $CI is unset/empty
18
- # 4. Inside a git repo
19
- # 5. Current branch == default branch (git.base_branch override, else main/master/trunk)
20
- # 6. .planning/config.json sets graphify.enabled=true AND graphify.auto_update=true
21
- # 7. graphify binary on PATH
22
- # 8. No rebuild already in flight (PID lock — kill -0 check, stale-tolerant)
21
+ # 3. Inside a git repo
22
+ # 4. Current branch == default branch (git.base_branch override, else main/master/trunk)
23
+ # 5. .planning/config.json sets graphify.enabled=true AND graphify.auto_update=true
24
+ # 6. graphify binary on PATH
25
+ # 7. No rebuild already in flight (PID lock — kill -0 check, stale-tolerant)
23
26
  #
24
27
  # When all gates pass:
25
28
  # - Writes .planning/graphs/.last-build-status.json with status="running"
@@ -30,6 +33,13 @@
30
33
 
31
34
  set -uo pipefail
32
35
 
36
+ # Gate 0 — GSD project at all, and not CI (#3729). Both are pure shell tests;
37
+ # they must precede the Gate 1 node spawn so the common non-GSD/CI path pays
38
+ # for zero child processes. Hoisting is behavior-preserving: old Gates 3 and 6
39
+ # made the same decisions, just later.
40
+ [ -f .planning/config.json ] || exit 0
41
+ [ -z "${CI:-}" ] || exit 0
42
+
33
43
  # Gate 1 — tool_name == Bash; extract command
34
44
  INPUT=$(cat 2>/dev/null || true)
35
45
  [ -n "$INPUT" ] || exit 0
@@ -71,22 +81,17 @@ case "$COMMAND" in
71
81
  *) exit 0 ;;
72
82
  esac
73
83
 
74
- # Gate 3 — not CI
75
- [ -z "${CI:-}" ] || exit 0
76
-
77
- # Gate 4 — inside git repo
84
+ # Gate 3 — inside git repo
78
85
  git rev-parse --git-dir >/dev/null 2>&1 || exit 0
79
86
 
80
- # Gate 5 — current branch == default branch
87
+ # Gate 4 — current branch == default branch (config guaranteed by Gate 0)
81
88
  DEFAULT_BRANCH=""
82
- if [ -f .planning/config.json ]; then
83
- DEFAULT_BRANCH=$(node -e '
89
+ DEFAULT_BRANCH=$(node -e '
84
90
  try {
85
91
  const c = require("./.planning/config.json");
86
92
  process.stdout.write(c.git?.base_branch || "");
87
93
  } catch { process.stdout.write(""); }
88
94
  ' 2>/dev/null || echo "")
89
- fi
90
95
  if [ -z "$DEFAULT_BRANCH" ]; then
91
96
  for cand in main master trunk; do
92
97
  if git rev-parse --verify "$cand" >/dev/null 2>&1; then
@@ -100,8 +105,7 @@ fi
100
105
  CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")
101
106
  [ "$CURRENT_BRANCH" = "$DEFAULT_BRANCH" ] || exit 0
102
107
 
103
- # Gate 6 — both graphify gates true in config
104
- [ -f .planning/config.json ] || exit 0
108
+ # Gate 5 — both graphify gates true in config (file existence checked at Gate 0)
105
109
  GATES=$(node -e '
106
110
  try {
107
111
  const c = require("./.planning/config.json");
@@ -111,11 +115,11 @@ try {
111
115
  ' 2>/dev/null || echo "0")
112
116
  [ "$GATES" = "1" ] || exit 0
113
117
 
114
- # Gate 7 — graphify on PATH
118
+ # Gate 6 — graphify on PATH
115
119
  GRAPHIFY_BIN=$(command -v graphify 2>/dev/null || true)
116
120
  [ -n "$GRAPHIFY_BIN" ] || exit 0
117
121
 
118
- # Gate 8 — no live rebuild in flight
122
+ # Gate 7 — no live rebuild in flight
119
123
  mkdir -p .planning/graphs
120
124
  LOCK_FILE=".planning/graphs/.rebuild.lock"
121
125
  if [ -f "$LOCK_FILE" ]; then
@@ -0,0 +1,76 @@
1
+ #!/bin/sh
2
+ # gsd-node-runner.sh — GSD portable node resolver (#3662).
3
+ #
4
+ # Managed JS hook commands under --portable-hooks route through this script:
5
+ #
6
+ # bash "<hooks>/gsd-node-runner.sh" "<baked-node-path>" "<script.js>" [args...]
7
+ #
8
+ # so a config root shared across environments (mounted ~/.claude, shared
9
+ # containers) resolves node at hook-fire time instead of depending on the
10
+ # absolute path of whichever environment ran the installer. Candidates, in
11
+ # order — the first executable one wins:
12
+ #
13
+ # 1. the first argument — the install-time node path, tried FIRST and by
14
+ # absolute path so the #2979/#3002/#3017/#3022 minimal-PATH guarantee
15
+ # holds (GUI launches with a stripped PATH still resolve where the
16
+ # baked path exists);
17
+ # 2. `command -v node`, accepted only when it yields an absolute path;
18
+ # 3. the well-known stable layouts: $HOME-derived mise/volta shims, the
19
+ # Homebrew prefixes, /usr/local/bin/node, /usr/bin/node.
20
+ #
21
+ # No bare `node` lookup is ever depended on: a candidate is used only after
22
+ # an explicit executable check, and when nothing resolves this script fails
23
+ # visibly (stderr diagnostic + exit 127) rather than emitting a half-resolved
24
+ # invocation.
25
+ #
26
+ # The candidate list below is a SUPERSET of the inline chain token emitted by
27
+ # buildNodeRunnerChainToken (src/runtime-hooks-surface.cts, #3662) — keep the
28
+ # two lists consistent.
29
+ #
30
+ # Diagnostic escape: GSD_NODE_RUNNER_NO_FALLBACKS=1 disables candidates 2-3
31
+ # (first-argument-only resolution) — used by the test suite and useful to
32
+ # pin down which node a given environment picks.
33
+ set -u
34
+
35
+ preferred=${1:-}
36
+ script=${2:-}
37
+ if [ -n "$script" ]; then
38
+ shift 2
39
+ elif [ -n "$preferred" ]; then
40
+ shift 1
41
+ preferred=
42
+ fi
43
+
44
+ found=''
45
+
46
+ # check <path> — record <path> if it is an absolute, executable file.
47
+ # Absolute = POSIX root (/*) or a win32 drive-letter path (C:/…), which is
48
+ # what the installer bakes on Windows; anything else (a relative `command -v`
49
+ # hit under a relative PATH entry, a bare name) is rejected so repo-cwd
50
+ # content can never reach the runner slot.
51
+ check() {
52
+ case "$1" in
53
+ /*|[A-Za-z]:/*) if [ -x "$1" ]; then found=$1; fi ;;
54
+ esac
55
+ [ -n "$found" ]
56
+ }
57
+
58
+ check "$preferred" || {
59
+ if [ "${GSD_NODE_RUNNER_NO_FALLBACKS:-0}" != "1" ]; then
60
+ path_node=$(command -v node 2>/dev/null || true)
61
+ check "$path_node" ||
62
+ check "${HOME:-}/.local/share/mise/shims/node" ||
63
+ check "${HOME:-}/.volta/bin/node" ||
64
+ check /opt/homebrew/bin/node ||
65
+ check /usr/local/bin/node ||
66
+ check /usr/bin/node ||
67
+ true
68
+ fi
69
+ }
70
+
71
+ if [ -z "$found" ]; then
72
+ echo "gsd-node-runner: no usable node found (preferred: ${preferred:-<none>})" >&2
73
+ exit 127
74
+ fi
75
+
76
+ exec "$found" "$script" "$@"
@@ -6,6 +6,7 @@
6
6
  #
7
7
  # OPT-IN: This hook is a no-op unless config.json has hooks.community: true.
8
8
  # Enable with: "hooks": { "community": true } in .planning/config.json
9
+ set -euo pipefail
9
10
 
10
11
  # Check opt-in config — exit silently if not enabled
11
12
  if [ -f .planning/config.json ]; then
@@ -11,26 +11,21 @@
11
11
  // The goal is to surface suspicious content so the orchestrator can inspect it,
12
12
  // not to create false-positive deadlocks.
13
13
 
14
- const fs = require('fs');
15
14
  const path = require('path');
15
+ const { HOOK_ON_CRASH, allow, crash } = require('./lib/hook-exit.js');
16
16
 
17
- // Prompt injection patterns (subset of security.cjs patterns, inlined for hook independence)
18
- const INJECTION_PATTERNS = [
19
- /ignore\s+(all\s+)?previous\s+instructions/i,
20
- /ignore\s+(all\s+)?above\s+instructions/i,
21
- /disregard\s+(all\s+)?previous/i,
22
- /forget\s+(all\s+)?(your\s+)?instructions/i,
23
- /override\s+(system|previous)\s+(prompt|instructions)/i,
24
- /you\s+are\s+now\s+(?:a|an|the)\s+/i,
25
- /act\s+as\s+(?:a|an|the)\s+(?!plan|phase|wave)/i,
26
- /pretend\s+(?:you(?:'re| are)\s+|to\s+be\s+)/i,
27
- /from\s+now\s+on,?\s+you\s+(?:are|will|should|must)/i,
28
- /(?:print|output|reveal|show|display|repeat)\s+(?:your\s+)?(?:system\s+)?(?:prompt|instructions)/i,
29
- /<\/?(?:system|assistant|human)>/i,
30
- /\[SYSTEM\]/i,
31
- /\[INST\]/i,
32
- /<<\s*SYS\s*>>/i,
33
- ];
17
+ // This guard is advisory-only by design (see header) — it never blocks the
18
+ // Write/Edit it scans, only adds context about it. A crash here must not
19
+ // start blocking now, which is strictly worse than the advisory it exists
20
+ // to add on top of an already-permitted operation (#3911).
21
+ const ON_CRASH = HOOK_ON_CRASH.ALLOW;
22
+
23
+ // Prompt injection patterns — shared with gsd-read-injection-scanner.js via
24
+ // hooks/lib/injection-patterns.js so the two surfaces cannot drift (#3504).
25
+ // Deliberately a subset of security.cjs's set: hooks stay loadable without the
26
+ // compiled lib tree. Staging of the lib helper is allowlisted in
27
+ // GSD_HOOK_LIB_FILES (bin/install.js).
28
+ const { INJECTION_PATTERNS } = require('./lib/injection-patterns.js');
34
29
 
35
30
  // #2304: Kimi's native hook bus delivers Kimi's tool vocabulary in the payload
36
31
  // (Write → WriteFile, Edit/MultiEdit → StrReplaceFile) while the [[hooks]]
@@ -127,7 +122,7 @@ function normalizeKimiPayload(data) {
127
122
  }
128
123
 
129
124
  let input = '';
130
- const stdinTimeout = setTimeout(() => process.exit(0), 3000);
125
+ const stdinTimeout = setTimeout(() => allow(undefined), 3000);
131
126
  process.stdin.setEncoding('utf8');
132
127
  process.stdin.on('data', chunk => input += chunk);
133
128
  process.stdin.on('end', () => {
@@ -138,7 +133,7 @@ process.stdin.on('end', () => {
138
133
 
139
134
  // Only scan Write and Edit operations
140
135
  if (toolName !== 'Write' && toolName !== 'Edit') {
141
- process.exit(0);
136
+ allow(undefined);
142
137
  }
143
138
 
144
139
  // #2595 (review Major 3, sibling sweep): typed read. A non-string
@@ -150,13 +145,26 @@ process.stdin.on('end', () => {
150
145
 
151
146
  // Only scan files going into .planning/ (agent context files)
152
147
  if (!filePath.includes('.planning/') && !filePath.includes('.planning\\')) {
153
- process.exit(0);
148
+ allow(undefined);
154
149
  }
155
150
 
156
- // Get the content being written
157
- const content = data.tool_input?.content || data.tool_input?.new_string || '';
151
+ // Get the content being written. #3504 (isolated review finding 3): the
152
+ // bare `||` chain handed a NON-STRING truthy `content` straight to
153
+ // pattern.test(), where ToString can throw ("Cannot convert object to a
154
+ // primitive value" for `{"toString": null}`) into the outer catch — the
155
+ // exact crash-to-allow class #2547/#2595 hardened inside
156
+ // normalizeKimiPayload, unreached on this read. Guarded selection: take
157
+ // the first field that is a string, or String-coerces without throwing,
158
+ // so a poisoned `content` no longer shadows a real `new_string`.
159
+ let content = '';
160
+ for (const candidate of [data.tool_input?.content, data.tool_input?.new_string]) {
161
+ if (typeof candidate === 'string' && candidate) { content = candidate; break; }
162
+ if (candidate && typeof candidate !== 'string') {
163
+ try { const s = String(candidate); if (s) { content = s; break; } } catch { /* keep looking */ }
164
+ }
165
+ }
158
166
  if (!content) {
159
- process.exit(0);
167
+ allow(undefined);
160
168
  }
161
169
 
162
170
  // Scan for injection patterns
@@ -173,7 +181,7 @@ process.stdin.on('end', () => {
173
181
  }
174
182
 
175
183
  if (findings.length === 0) {
176
- process.exit(0);
184
+ allow(undefined);
177
185
  }
178
186
 
179
187
  // Advisory warning — does not block the operation
@@ -190,7 +198,9 @@ process.stdin.on('end', () => {
190
198
 
191
199
  process.stdout.write(JSON.stringify(output));
192
200
  } catch {
193
- // Silent fail — never block tool execution
194
- process.exit(0);
201
+ // Silent fail — never block tool execution.
202
+ // ON_CRASH is declared ALLOW at module top: this preserves today's
203
+ // exit(0) fail-open behavior exactly (#3911).
204
+ crash(ON_CRASH, undefined);
195
205
  }
196
206
  });
@@ -20,6 +20,13 @@
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 guard is pure advisory UX — a reminder to Read before Write/Edit on
26
+ // non-Claude-Code runtimes. A crash here must not block a legitimate Write/
27
+ // Edit; the worst outcome of failing open is the model hitting the runtime's
28
+ // own read-before-edit rejection it was trying to help avoid (#3911).
29
+ const ON_CRASH = HOOK_ON_CRASH.ALLOW;
23
30
 
24
31
  // #2304: Kimi's native hook bus delivers Kimi's tool vocabulary in the payload
25
32
  // (Write → WriteFile, Edit/MultiEdit → StrReplaceFile) while the [[hooks]]
@@ -116,7 +123,7 @@ function normalizeKimiPayload(data) {
116
123
  }
117
124
 
118
125
  let input = '';
119
- const stdinTimeout = setTimeout(() => process.exit(0), 3000);
126
+ const stdinTimeout = setTimeout(() => allow(undefined), 3000);
120
127
  process.stdin.setEncoding('utf8');
121
128
  process.stdin.on('data', chunk => input += chunk);
122
129
  process.stdin.on('end', () => {
@@ -127,7 +134,7 @@ process.stdin.on('end', () => {
127
134
 
128
135
  // Only intercept Write and Edit tool calls
129
136
  if (toolName !== 'Write' && toolName !== 'Edit') {
130
- process.exit(0);
137
+ allow(undefined);
131
138
  }
132
139
 
133
140
  // Claude Code natively enforces read-before-edit — skip the advisory (#1984, #2344, #2520).
@@ -151,7 +158,7 @@ process.stdin.on('end', () => {
151
158
  process.env.CLAUDE_SESSION_ID ||
152
159
  process.env.CLAUDECODE;
153
160
  if (isClaudeCode) {
154
- process.exit(0);
161
+ allow(undefined);
155
162
  }
156
163
 
157
164
  // #2595 (review Major 3, sibling sweep): typed read — same class as the
@@ -160,7 +167,7 @@ process.stdin.on('end', () => {
160
167
  ? data.tool_input.file_path
161
168
  : '';
162
169
  if (!filePath) {
163
- process.exit(0);
170
+ allow(undefined);
164
171
  }
165
172
 
166
173
  // Only inject guidance when the file already exists.
@@ -174,7 +181,7 @@ process.stdin.on('end', () => {
174
181
  }
175
182
 
176
183
  if (!fileExists) {
177
- process.exit(0);
184
+ allow(undefined);
178
185
  }
179
186
 
180
187
  const fileName = path.basename(filePath);
@@ -193,7 +200,9 @@ process.stdin.on('end', () => {
193
200
 
194
201
  process.stdout.write(JSON.stringify(output));
195
202
  } catch {
196
- // Silent fail — never block tool execution
197
- process.exit(0);
203
+ // Silent fail — never block tool execution.
204
+ // ON_CRASH is declared ALLOW at module top: this preserves today's
205
+ // exit(0) fail-open behavior exactly (#3911).
206
+ crash(ON_CRASH, undefined);
198
207
  }
199
208
  });