@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
@@ -0,0 +1,390 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * Generates the `<error_codes>` and `<repair_actions>` tables in
6
+ * `gsd-core/workflows/health.md` from `src/health-diagnostic.cts`'s `RULES`
7
+ * table (Phase 11 follow-up, #3309 "Proposed behavior": "health.md's tables
8
+ * are generated rather than hand-maintained, closing the 16-vs-30+
9
+ * documentation gap structurally").
10
+ *
11
+ * Sources:
12
+ * - The 31 real rules in the compiled `RULES` array
13
+ * (`gsd-core/bin/lib/health-diagnostic.cjs`, built from
14
+ * `src/health-diagnostic.cts` + `src/health-diagnostic-rules/*.cts`),
15
+ * each carrying a static `description`/`repairable` (see
16
+ * `src/health-diagnostic-types.cts`'s `Rule` interface).
17
+ * - `PRECHECK_CODES` below — E001, E010, I010 — the three diagnostics
18
+ * `cmdValidateHealth` (`src/verify.cts`) emits as pre-checks OUTSIDE the
19
+ * rule table entirely (ADR-3180 §8.2 rule 4, "no precedence system" —
20
+ * see `.gsd/phase/refactor-3309-health-diagnostic-rule-table/40-design.md`,
21
+ * "Two guards that stay OUTSIDE the rule table entirely"). These will
22
+ * never appear in `RULES`, so they are a small, static, clearly-labeled
23
+ * list merged in here instead.
24
+ * - `REMEDY_ACTION_METADATA` below — the Effect/Risk prose for each of the
25
+ * 6 real repair actions (`REMEDY_ACTION`, excluding `ADVISE`, which never
26
+ * acts). Static because the compiled module carries no Effect/Risk text
27
+ * of its own — only the action identifier.
28
+ *
29
+ * Deliberately EXCLUDED from the generated `<error_codes>` table: `W025`
30
+ * (the `workflow.use_worktrees`/`dispatch.isolation` check, #2486). It is a
31
+ * workflow-layer diagnostic emitted directly by this same file's own
32
+ * `run_health_check` step (a bash block in `health.md` itself), never by
33
+ * `cmdValidateHealth`/`RULES` — it has no `Rule` entry and is not one of the
34
+ * three pre-checks above. It stays fully documented in prose at its own step
35
+ * (`<step name="run_health_check">`), which is the authoritative, more
36
+ * detailed source `<error_codes>` used to merely summarize; dropping the
37
+ * redundant table row is not a loss of information, and folding it back in
38
+ * here would require this generator to parse bash, which it does not do.
39
+ * Same reasoning for `I002` (stale Windows task-directory cleanup,
40
+ * `<stale_task_cleanup>` step) — it was never part of the `<error_codes>`
41
+ * tagged region even before this generator existed.
42
+ *
43
+ * Usage:
44
+ * node scripts/gen-health-docs.cjs # print both tables to stdout
45
+ * node scripts/gen-health-docs.cjs --write # rewrite the tagged regions in health.md
46
+ * node scripts/gen-health-docs.cjs --check # exit 1 if either region is stale
47
+ * node scripts/gen-health-docs.cjs --write --target <path> # test-only: target a fixture file
48
+ */
49
+
50
+ const fs = require('node:fs');
51
+ const path = require('node:path');
52
+
53
+ const { ExitError, runMain } = require('./lib/cli-exit.cjs');
54
+
55
+ const ROOT = path.resolve(__dirname, '..');
56
+ const HEALTH_MD_REL = 'gsd-core/workflows/health.md';
57
+ const HEALTH_MD_PATH = path.join(ROOT, HEALTH_MD_REL);
58
+ const COMPILED_MODULE_REL = 'gsd-core/bin/lib/health-diagnostic.cjs';
59
+ const COMPILED_MODULE_PATH = path.join(ROOT, COMPILED_MODULE_REL);
60
+
61
+ const ERROR_CODES_START = '<error_codes>';
62
+ const ERROR_CODES_END = '</error_codes>';
63
+ const REPAIR_ACTIONS_START = '<repair_actions>';
64
+ const REPAIR_ACTIONS_END = '</repair_actions>';
65
+
66
+ /**
67
+ * The 3 pre-check diagnostics `cmdValidateHealth` emits OUTSIDE the rule
68
+ * table (see module header). All three are non-repairable safety rails, not
69
+ * `.planning/` findings a remedy could act on.
70
+ */
71
+ const PRECHECK_CODES = [
72
+ {
73
+ code: 'E001',
74
+ severity: 'error',
75
+ description: '.planning/ directory not found',
76
+ repairable: false,
77
+ },
78
+ {
79
+ code: 'E010',
80
+ severity: 'error',
81
+ description: "CWD resolves to the user's home directory — health check would target the wrong .planning/",
82
+ repairable: false,
83
+ },
84
+ {
85
+ code: 'I010',
86
+ severity: 'info',
87
+ description: 'Resolved CWD reported alongside the E010 home-directory guard',
88
+ repairable: false,
89
+ },
90
+ ];
91
+
92
+ /**
93
+ * Effect/Risk prose per real `REMEDY_ACTION` (everything except `ADVISE`,
94
+ * which never acts and has no row in `<repair_actions>`). Text for the 5
95
+ * actions the hand-written table already documented is reused VERBATIM;
96
+ * `addAiIntegrationPhaseKey` is new — #3309 itself notes it was "live in
97
+ * code, missing from docs" (mirrors `addNyquistKey`, its structural sibling:
98
+ * same shape, one config key each).
99
+ */
100
+ const REMEDY_ACTION_METADATA = new Map([
101
+ ['createConfig', { effect: 'Create config.json with defaults', risk: 'None' }],
102
+ ['resetConfig', { effect: 'Delete + recreate config.json', risk: 'Loses custom settings' }],
103
+ [
104
+ 'regenerateState',
105
+ {
106
+ effect: 'Create STATE.md from ROADMAP structure when it is missing',
107
+ risk: 'Loses session history',
108
+ },
109
+ ],
110
+ [
111
+ 'addNyquistKey',
112
+ { effect: 'Add workflow.nyquist_validation: true to config.json', risk: 'None — matches existing default' },
113
+ ],
114
+ [
115
+ 'addAiIntegrationPhaseKey',
116
+ { effect: 'Add workflow.ai_integration_phase: true to config.json', risk: 'None — matches existing default' },
117
+ ],
118
+ [
119
+ 'backfillMilestones',
120
+ {
121
+ effect: 'Synthesize missing MILESTONES.md entries from `.planning/milestones/vX.Y-ROADMAP.md` snapshots',
122
+ risk: 'None — additive only; triggered by `--backfill` flag',
123
+ },
124
+ ],
125
+ ]);
126
+
127
+ /** Order the Effect/Risk table renders in — matches `REMEDY_ACTION`'s own declaration order. */
128
+ const REMEDY_ACTION_ORDER = [
129
+ 'createConfig',
130
+ 'resetConfig',
131
+ 'regenerateState',
132
+ 'addNyquistKey',
133
+ 'addAiIntegrationPhaseKey',
134
+ 'backfillMilestones',
135
+ ];
136
+
137
+ /**
138
+ * Per-code override for the "Repairable" cell's display text, for codes
139
+ * whose remedy is conditional on a flag the plain `Yes`/`No` can't express
140
+ * (mirrors the hand-written table's pre-existing `W018` row: `Yes (--backfill)`).
141
+ */
142
+ const REPAIRABLE_DISPLAY_OVERRIDE = new Map([['W018', 'Yes (`--backfill`)']]);
143
+
144
+ const STATIC_NOT_REPAIRABLE_BULLETS = [
145
+ 'PROJECT.md, ROADMAP.md content',
146
+ 'Phase directory renaming',
147
+ 'Orphaned plan cleanup',
148
+ ];
149
+
150
+ const FOOTNOTE_PARAGRAPH =
151
+ 'Note: this table is **generated** — do not hand-edit it. It is produced by ' +
152
+ '`node scripts/gen-health-docs.cjs --write` from `src/health-diagnostic.cts`\'s `RULES` table ' +
153
+ '(31 rules as of #3309, each carrying a static `description`/`repairable` on its `Rule` entry — ' +
154
+ 'see `src/health-diagnostic-types.cts`) plus the 3 pre-checks that stay outside the rule table by ' +
155
+ 'design (`E001`, `E010`, `I010` — safety rails in `cmdValidateHealth`, `src/verify.cts`, never ' +
156
+ '`.planning/` findings). `scripts/lint-health-diagnostic-rule-table.cjs` already enforces the 1:1 ' +
157
+ 'code invariant this table depends on (no duplicate codes; severity is always a `Rule` property, ' +
158
+ 'never set per emit call) — before assigning a new code, add a `Rule` entry under ' +
159
+ '`src/health-diagnostic-rules/` (its `code` is simply the next free number the lint guard has not ' +
160
+ 'yet seen) and run `node scripts/gen-health-docs.cjs --write` to regenerate this table; ' +
161
+ '`npm run lint:generated-sync` fails if it drifts. `W025` (the `workflow.use_worktrees`/' +
162
+ '`dispatch.isolation` check, #2486) is a workflow-layer diagnostic emitted directly by this file\'s ' +
163
+ 'own `run_health_check` step, not by `cmdValidateHealth` — it stays documented in that step, not in ' +
164
+ 'this generated table.';
165
+
166
+ /**
167
+ * Load the compiled health-diagnostic module. Throws a clear ExitError (not
168
+ * a raw MODULE_NOT_FOUND) if `npm run build:lib` has not run — mirrors
169
+ * `scripts/lint-health-diagnostic-rule-table.cjs`'s `loadCompiledModule`.
170
+ */
171
+ function loadCompiledModule(compiledPath = COMPILED_MODULE_PATH) {
172
+ if (!fs.existsSync(compiledPath)) {
173
+ throw new ExitError(
174
+ 2,
175
+ `gen-health-docs: compiled artifact not found at ${COMPILED_MODULE_REL}.\n` +
176
+ 'Run `npm run build:lib` first.',
177
+ );
178
+ }
179
+ return require(compiledPath);
180
+ }
181
+
182
+ /**
183
+ * Sort order for the `<error_codes>` table: E-codes, then W-codes
184
+ * numerically, then I-codes — matching the hand-written table's pre-existing
185
+ * order. NOT insertion order from `RULES` (which is grouped by
186
+ * subject-area file, not sorted by code).
187
+ */
188
+ const PREFIX_RANK = { E: 0, W: 1, I: 2 };
189
+
190
+ function parseCode(code) {
191
+ const m = code.match(/^([A-Z]+)(\d+)$/);
192
+ if (!m) throw new Error(`gen-health-docs: unparseable diagnostic code "${code}"`);
193
+ return { prefix: m[1], number: Number(m[2]) };
194
+ }
195
+
196
+ function compareCodes(a, b) {
197
+ const pa = parseCode(a.code);
198
+ const pb = parseCode(b.code);
199
+ const rankA = PREFIX_RANK[pa.prefix] ?? 99;
200
+ const rankB = PREFIX_RANK[pb.prefix] ?? 99;
201
+ if (rankA !== rankB) return rankA - rankB;
202
+ return pa.number - pb.number;
203
+ }
204
+
205
+ /**
206
+ * Combine the 31 real rules + the 3 static pre-checks into one sorted row
207
+ * list for the `<error_codes>` table.
208
+ *
209
+ * @param {Array<{code: string, severity: string, description: string, repairable: boolean}>} rules
210
+ */
211
+ function buildErrorCodeRows(rules) {
212
+ const seen = new Set();
213
+ const rows = [];
214
+ for (const entry of [...rules, ...PRECHECK_CODES]) {
215
+ if (seen.has(entry.code)) {
216
+ throw new Error(`gen-health-docs: duplicate diagnostic code "${entry.code}" across RULES + PRECHECK_CODES`);
217
+ }
218
+ seen.add(entry.code);
219
+ rows.push(entry);
220
+ }
221
+ rows.sort(compareCodes);
222
+ return rows;
223
+ }
224
+
225
+ /** Escape a cell's markdown-table-hostile characters (mirrors gen-adr-index.cjs's `cellText`). */
226
+ function cellText(text) {
227
+ return String(text)
228
+ .replace(/\\/g, '\\\\')
229
+ .replace(/\|/g, '\\|')
230
+ .replace(/</g, '&lt;')
231
+ .replace(/>/g, '&gt;')
232
+ .replace(/\r?\n/g, ' ')
233
+ .trim();
234
+ }
235
+
236
+ function repairableCell(row) {
237
+ if (REPAIRABLE_DISPLAY_OVERRIDE.has(row.code)) return REPAIRABLE_DISPLAY_OVERRIDE.get(row.code);
238
+ return row.repairable ? 'Yes' : 'No';
239
+ }
240
+
241
+ function renderErrorCodesRegion(rules) {
242
+ const rows = buildErrorCodeRows(rules);
243
+ const lines = ['', '| Code | Severity | Description | Repairable |', '|------|----------|-------------|------------|'];
244
+ for (const row of rows) {
245
+ lines.push(`| ${row.code} | ${row.severity} | ${cellText(row.description)} | ${repairableCell(row)} |`);
246
+ }
247
+ lines.push('', FOOTNOTE_PARAGRAPH, '');
248
+ return lines.join('\n');
249
+ }
250
+
251
+ function renderRepairActionsRegion() {
252
+ const lines = ['', '| Action | Effect | Risk |', '|--------|--------|------|'];
253
+ for (const action of REMEDY_ACTION_ORDER) {
254
+ const meta = REMEDY_ACTION_METADATA.get(action);
255
+ if (!meta) {
256
+ throw new Error(
257
+ `gen-health-docs: no Effect/Risk metadata registered for repair action "${action}" — add an entry to REMEDY_ACTION_METADATA.`,
258
+ );
259
+ }
260
+ lines.push(`| ${action} | ${meta.effect} | ${meta.risk} |`);
261
+ }
262
+ lines.push('', '**Not repairable (too risky):**');
263
+ for (const bullet of STATIC_NOT_REPAIRABLE_BULLETS) lines.push(`- ${bullet}`);
264
+ lines.push('');
265
+ return lines.join('\n');
266
+ }
267
+
268
+ /**
269
+ * Splice `newInner` between `${startTag}`/`${endTag}` inside `text`. Throws
270
+ * if either tag is missing, or if the tags appear more than once (this
271
+ * generator only ever targets the FIRST occurrence pair, and a duplicate
272
+ * tag anywhere in the file would silently corrupt the splice).
273
+ */
274
+ function spliceRegion(text, startTag, endTag, newInner) {
275
+ const startIdx = text.indexOf(startTag);
276
+ const endIdx = text.indexOf(endTag);
277
+ if (startIdx === -1 || endIdx === -1) {
278
+ throw new ExitError(
279
+ 1,
280
+ `gen-health-docs: ${HEALTH_MD_REL} is missing the ${startTag}/${endTag} tags.`,
281
+ );
282
+ }
283
+ if (text.indexOf(startTag, startIdx + 1) !== -1 || text.indexOf(endTag, endIdx + 1) !== -1) {
284
+ throw new ExitError(1, `gen-health-docs: ${HEALTH_MD_REL} has more than one ${startTag}/${endTag} pair.`);
285
+ }
286
+ const before = text.slice(0, startIdx + startTag.length);
287
+ const after = text.slice(endIdx);
288
+ return `${before}${newInner}\n${after}`;
289
+ }
290
+
291
+ /**
292
+ * Regenerate `health.md`'s full text from `rules` (the compiled `RULES`
293
+ * array) and the current on-disk `health.md` content.
294
+ */
295
+ function regenerateHealthMd(rules, currentText) {
296
+ let out = spliceRegion(currentText, ERROR_CODES_START, ERROR_CODES_END, renderErrorCodesRegion(rules));
297
+ out = spliceRegion(out, REPAIR_ACTIONS_START, REPAIR_ACTIONS_END, renderRepairActionsRegion());
298
+ return out;
299
+ }
300
+
301
+ /**
302
+ * @param {string[]} argv
303
+ * @returns {{write: boolean, check: boolean, targetPath: string|null}}
304
+ */
305
+ function parseArgs(argv) {
306
+ const opts = { write: false, check: false, targetPath: null };
307
+ for (let i = 0; i < argv.length; i++) {
308
+ const arg = argv[i];
309
+ if (arg === '--write') opts.write = true;
310
+ else if (arg === '--check') opts.check = true;
311
+ else if (arg === '--target') {
312
+ const value = argv[i + 1];
313
+ if (value === undefined) throw new ExitError(1, '--target requires a path argument.');
314
+ opts.targetPath = value;
315
+ i++;
316
+ } else {
317
+ throw new ExitError(1, `unknown flag: ${arg}\nRecognized flags: --write, --check, --target <path>.`);
318
+ }
319
+ }
320
+ return opts;
321
+ }
322
+
323
+ function main() {
324
+ const { write, check, targetPath } = parseArgs(process.argv.slice(2));
325
+ const { RULES } = loadCompiledModule();
326
+
327
+ // `--target` overrides the real committed health.md path, exclusively for
328
+ // test isolation (mirrors gen-section-manifest.cjs's `--manifest-path`
329
+ // override) — no production caller ever passes it.
330
+ const resolvedPath = targetPath ? path.resolve(targetPath) : HEALTH_MD_PATH;
331
+ const displayPath = targetPath ? targetPath : HEALTH_MD_REL;
332
+
333
+ const currentText = fs.existsSync(resolvedPath) ? fs.readFileSync(resolvedPath, 'utf8') : null;
334
+ if (currentText === null) {
335
+ throw new ExitError(1, `gen-health-docs: ${displayPath} not found.`);
336
+ }
337
+
338
+ const expected = regenerateHealthMd(RULES, currentText);
339
+
340
+ if (write) {
341
+ fs.writeFileSync(resolvedPath, expected, 'utf8');
342
+ process.stdout.write(
343
+ `Wrote ${displayPath} — ${RULES.length + PRECHECK_CODES.length} error/warning/info code(s), ` +
344
+ `${REMEDY_ACTION_ORDER.length} repair action(s).\n`,
345
+ );
346
+ return 0;
347
+ }
348
+
349
+ if (check) {
350
+ if (expected !== currentText) {
351
+ process.stderr.write(
352
+ `${displayPath} is stale — its <error_codes>/<repair_actions> tables do not match ` +
353
+ "src/health-diagnostic.cts's RULES table.\nRun:\n node scripts/gen-health-docs.cjs --write\n\n",
354
+ );
355
+ throw new ExitError(1);
356
+ }
357
+ process.stdout.write(
358
+ `${displayPath} is up to date (${RULES.length + PRECHECK_CODES.length} codes, ${REMEDY_ACTION_ORDER.length} repair actions).\n`,
359
+ );
360
+ return 0;
361
+ }
362
+
363
+ process.stdout.write(renderErrorCodesRegion(RULES) + '\n\n' + renderRepairActionsRegion() + '\n');
364
+ return 0;
365
+ }
366
+
367
+ // Guarded: requiring this module (the test suite imports the pure render
368
+ // functions directly) must not also run the generator as a side effect.
369
+ if (require.main === module) runMain(main);
370
+
371
+ module.exports = {
372
+ loadCompiledModule,
373
+ buildErrorCodeRows,
374
+ renderErrorCodesRegion,
375
+ renderRepairActionsRegion,
376
+ regenerateHealthMd,
377
+ spliceRegion,
378
+ compareCodes,
379
+ parseCode,
380
+ PRECHECK_CODES,
381
+ REMEDY_ACTION_METADATA,
382
+ REMEDY_ACTION_ORDER,
383
+ REPAIRABLE_DISPLAY_OVERRIDE,
384
+ HEALTH_MD_PATH,
385
+ COMPILED_MODULE_PATH,
386
+ ERROR_CODES_START,
387
+ ERROR_CODES_END,
388
+ REPAIR_ACTIONS_START,
389
+ REPAIR_ACTIONS_END,
390
+ };
@@ -0,0 +1,239 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * gen-hooks-cli-exit.cjs — generates hooks/lib/cli-exit.js from a fresh
4
+ * compile of src/cli-exit.cts.
5
+ *
6
+ * ADR-3889 Phase 7 (#3911): shipped hooks must be able to terminate through
7
+ * `terminateNow` WITHOUT depending on any build artifact. hooks/ runs
8
+ * straight from a raw, unbuilt clone (a hook is required by name via
9
+ * `require('./lib/cli-exit.js')` relative to the hook's own __dirname), so
10
+ * the generated file is compiled to a THROWAWAY outDir rather than read from
11
+ * gsd-core/bin/lib/ — reading the tracked build output would let a stale
12
+ * build produce a false green. This mirrors scripts/gen-scripts-cli-exit.cjs
13
+ * exactly (same compile-to-temp strategy, same banner/check/write shape);
14
+ * kept as a SIBLING script rather than folded into that one because
15
+ * gen-scripts-cli-exit.cjs is hard-coded to a single output path/extension
16
+ * (`scripts/lib/cli-exit.cjs`) throughout its BANNER prose and REASON
17
+ * messaging — parameterizing it for a second, differently-extensioned
18
+ * target (`.js`, not `.cjs`, to match the hooks/lib/*.js convention) would
19
+ * tangle a script that is otherwise simple and single-purpose.
20
+ *
21
+ * Usage:
22
+ * node scripts/gen-hooks-cli-exit.cjs # same as --write
23
+ * node scripts/gen-hooks-cli-exit.cjs --write # write hooks/lib/cli-exit.js
24
+ * node scripts/gen-hooks-cli-exit.cjs --check # exit 1 if committed file is stale
25
+ * node scripts/gen-hooks-cli-exit.cjs --out <path> # override the output path (default: hooks/lib/cli-exit.js) — honoured by BOTH --write and --check
26
+ *
27
+ * `--out` restores parity with the sibling scripts/gen-exit-code-registry.cjs,
28
+ * which already supports `--out`/`--scripts-out`/`--hooks-out`/`--dts-out`/
29
+ * `--sh-out` overrides honoured by its own `--check`. This script hardcoding
30
+ * `OUTPUT_PATH` with no override was an inconsistency between two sibling
31
+ * generators, not an intentionally narrower surface — tests need to redirect
32
+ * `--check` at a disposable tmpdir copy instead of corrupting the real
33
+ * committed artifact in place.
34
+ */
35
+
36
+ 'use strict';
37
+
38
+ const { execFileSync } = require('node:child_process');
39
+ const fs = require('node:fs');
40
+ const os = require('node:os');
41
+ const path = require('node:path');
42
+
43
+ const REPO_ROOT = path.resolve(__dirname, '..');
44
+ const OUTPUT_PATH = path.join(REPO_ROOT, 'hooks', 'lib', 'cli-exit.js');
45
+ const COMPILE_TIMEOUT_MS = 60_000;
46
+
47
+ /** Frozen reason codes so tests assert on structure, not prose. */
48
+ const REASON = Object.freeze({
49
+ OK: 'ok_generated_sync',
50
+ DRIFTED: 'fail_generated_drifted',
51
+ BUILD_FAILED: 'fail_build_failed',
52
+ MISSING_EMIT: 'fail_missing_emit',
53
+ USAGE: 'fail_usage',
54
+ });
55
+
56
+ const USAGE_MESSAGE = [
57
+ 'Usage: node scripts/gen-hooks-cli-exit.cjs [--write|--check] [--out <path>]',
58
+ ' (no flag) same as --write',
59
+ ' --write write hooks/lib/cli-exit.js',
60
+ ' --check exit 1 if the committed file is stale',
61
+ ' --out override the output artifact path (default: hooks/lib/cli-exit.js)',
62
+ ].join('\n');
63
+
64
+ const BANNER = [
65
+ '// GENERATED FILE — DO NOT EDIT BY HAND.',
66
+ '// Source of truth: src/cli-exit.cts. Regenerate with:',
67
+ '// node scripts/gen-hooks-cli-exit.cjs --write',
68
+ '// Byte-compared by `npm run lint:generated-sync` (#3911, ADR-3889 Phase 7).',
69
+ '//',
70
+ '// Why this copy exists: hooks/ runs straight from a raw, unbuilt clone — a',
71
+ '// shipped hook must be able to `require(\'./lib/cli-exit.js\')` relative to',
72
+ '// its own __dirname and terminate through `terminateNow` without depending',
73
+ '// on any build artifact. gsd-core/bin/lib/cli-exit.cjs is gitignored tsc',
74
+ '// output and doubles as the build sentinel, so it cannot be required from',
75
+ '// here. `.js`, not `.cjs`, to match the hooks/lib/*.js convention. Hence one',
76
+ '// source, three emitted locations (gsd-core/bin/lib, scripts/lib, hooks/lib).',
77
+ '',
78
+ '',
79
+ ].join('\n');
80
+
81
+ /** Compile the whole project to a throwaway outDir so the work tree is untouched. */
82
+ function compileToTemp() {
83
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-hooks-cli-exit-'));
84
+ try {
85
+ execFileSync(
86
+ process.execPath,
87
+ [
88
+ path.join(REPO_ROOT, 'node_modules', 'typescript', 'bin', 'tsc'),
89
+ '-p', path.join(REPO_ROOT, 'tsconfig.build.json'),
90
+ '--outDir', tmp,
91
+ // A throwaway outDir must not reuse the in-tree incremental state, or
92
+ // tsc skips emit for files it believes are already current.
93
+ '--incremental', 'false',
94
+ '--tsBuildInfoFile', 'null',
95
+ ],
96
+ { cwd: REPO_ROOT, encoding: 'utf8', stdio: 'pipe', timeout: COMPILE_TIMEOUT_MS },
97
+ );
98
+ return { ok: true, dir: tmp };
99
+ } catch (err) {
100
+ fs.rmSync(tmp, { recursive: true, force: true });
101
+ const detail = [err.stdout, err.stderr].filter(Boolean).join('\n').trim();
102
+ return { ok: false, detail };
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Compile src/cli-exit.cts to a throwaway outDir and return the expected
108
+ * generated content (banner + compiled bytes, with the sibling registry
109
+ * require rewritten to the `.js` extension hooks/lib/ uses), or a failure
110
+ * descriptor.
111
+ *
112
+ * @returns {{ ok: true, content: string } | { ok: false, reason: string, detail?: string }}
113
+ */
114
+ function buildExpectedContent() {
115
+ const build = compileToTemp();
116
+ if (!build.ok) {
117
+ return { ok: false, reason: REASON.BUILD_FAILED, detail: build.detail };
118
+ }
119
+ try {
120
+ const emitted = path.join(build.dir, 'cli-exit.cjs');
121
+ if (!fs.existsSync(emitted)) {
122
+ return { ok: false, reason: REASON.MISSING_EMIT, detail: `no emit produced at ${emitted} from src/cli-exit.cts` };
123
+ }
124
+ const compiled = fs.readFileSync(emitted, 'utf8');
125
+ // hooks/lib/ ships `.js`, not `.cjs` (matching the hooks/lib/*.js
126
+ // convention — see the module header), so the sibling registry require
127
+ // tsc emits for src/cli-exit.cts's `require('./exit-code-registry.cjs')`
128
+ // must be rewritten to resolve the `.js` copy scripts/gen-exit-code-
129
+ // registry.cjs emits alongside this file, not the `.cjs` one. A literal,
130
+ // anchored replace (never a regex) so this can only ever touch the exact
131
+ // string tsc is known to emit for that one import.
132
+ const REGISTRY_REQUIRE_CJS = 'require("./exit-code-registry.cjs")';
133
+ const REGISTRY_REQUIRE_JS = 'require("./exit-code-registry.js")';
134
+ if (!compiled.includes(REGISTRY_REQUIRE_CJS)) {
135
+ return {
136
+ ok: false,
137
+ reason: REASON.MISSING_EMIT,
138
+ detail: `expected compiled output to contain ${REGISTRY_REQUIRE_CJS} (the sibling registry require) — tsc's emit shape may have changed`,
139
+ };
140
+ }
141
+ const rewritten = compiled.split(REGISTRY_REQUIRE_CJS).join(REGISTRY_REQUIRE_JS);
142
+ return { ok: true, content: BANNER + rewritten };
143
+ } finally {
144
+ fs.rmSync(build.dir, { recursive: true, force: true });
145
+ }
146
+ }
147
+
148
+ function doWrite(outPath) {
149
+ const result = buildExpectedContent();
150
+ if (!result.ok) {
151
+ console.error(`FAIL gen-hooks-cli-exit: ${result.reason}`);
152
+ if (result.detail) console.error(result.detail);
153
+ return 1;
154
+ }
155
+ fs.mkdirSync(path.dirname(outPath), { recursive: true });
156
+ fs.writeFileSync(outPath, result.content, 'utf8');
157
+ console.log(`ok gen-hooks-cli-exit: wrote ${path.relative(REPO_ROOT, outPath)}`);
158
+ return 0;
159
+ }
160
+
161
+ function doCheck(outPath) {
162
+ const result = buildExpectedContent();
163
+ if (!result.ok) {
164
+ console.error(`FAIL gen-hooks-cli-exit: ${result.reason}`);
165
+ if (result.detail) console.error(result.detail);
166
+ return 1;
167
+ }
168
+
169
+ if (!fs.existsSync(outPath)) {
170
+ console.error(`FAIL gen-hooks-cli-exit: ${REASON.MISSING_EMIT}`);
171
+ console.error(` ${path.relative(REPO_ROOT, outPath)} does not exist. Run:`);
172
+ console.error(' node scripts/gen-hooks-cli-exit.cjs --write');
173
+ return 1;
174
+ }
175
+
176
+ const committed = fs.readFileSync(outPath, 'utf8');
177
+ if (committed !== result.content) {
178
+ console.error(`FAIL gen-hooks-cli-exit: ${REASON.DRIFTED}`);
179
+ console.error(
180
+ ` ${path.relative(REPO_ROOT, outPath)} (${committed.length} bytes) != ` +
181
+ `compile of src/cli-exit.cts (${result.content.length} bytes)`,
182
+ );
183
+ console.error('');
184
+ console.error('Regenerate with:');
185
+ console.error(' node scripts/gen-hooks-cli-exit.cjs --write');
186
+ return 1;
187
+ }
188
+
189
+ console.log(`ok gen-hooks-cli-exit: ${path.relative(REPO_ROOT, outPath)} matches src/cli-exit.cts`);
190
+ return 0;
191
+ }
192
+
193
+ /**
194
+ * @returns {{mode:'write'|'check', outPath:?string}}
195
+ */
196
+ function parseArgs(argv) {
197
+ let mode = null;
198
+ let outPath = null;
199
+
200
+ for (let i = 0; i < argv.length; i++) {
201
+ const arg = argv[i];
202
+ if (arg === '--write' || arg === '--check') {
203
+ if (mode !== null) {
204
+ throw new Error(`conflicting mode flags: --${mode} and ${arg}`);
205
+ }
206
+ mode = arg === '--write' ? 'write' : 'check';
207
+ } else if (arg === '--out') {
208
+ const value = argv[++i];
209
+ if (value === undefined) throw new Error('--out requires a value');
210
+ outPath = value;
211
+ } else if (arg.startsWith('--out=')) {
212
+ outPath = arg.slice('--out='.length);
213
+ } else {
214
+ throw new Error(`unrecognized argument: ${arg}`);
215
+ }
216
+ }
217
+
218
+ return { mode: mode || 'write', outPath };
219
+ }
220
+
221
+ function main() {
222
+ let args;
223
+ try {
224
+ args = parseArgs(process.argv.slice(2));
225
+ } catch (err) {
226
+ console.error(`FAIL gen-hooks-cli-exit: ${REASON.USAGE}`);
227
+ console.error(` ${err.message}`);
228
+ console.error(USAGE_MESSAGE);
229
+ return 1;
230
+ }
231
+
232
+ const outPath = args.outPath || OUTPUT_PATH;
233
+
234
+ return args.mode === 'check' ? doCheck(outPath) : doWrite(outPath);
235
+ }
236
+
237
+ if (require.main === module) process.exitCode = main();
238
+
239
+ module.exports = { REASON, buildExpectedContent, OUTPUT_PATH, BANNER };
@@ -21,7 +21,7 @@ const ROOT = path.resolve(__dirname, '..');
21
21
  // buildParityManifest) is the canonical single source of truth in
22
22
  // tests/helpers/install-shared.cjs (issue #2266/#2267) — this generator does
23
23
  // not keep its own inline copy of the walk/exclusion logic.
24
- const { runMinimalInstall, RUNTIME_META, buildInstallTree, BUILD_SCRIPT } = require(path.join(ROOT, 'tests', 'helpers', 'install-shared.cjs'));
24
+ const { runMinimalInstall, RUNTIME_META, buildInstallTree, extraEmitRootsFor, BUILD_SCRIPT } = require(path.join(ROOT, 'tests', 'helpers', 'install-shared.cjs'));
25
25
  const FIXTURE_DIR = path.join(ROOT, 'tests', 'fixtures', 'install-tree');
26
26
 
27
27
  function cleanup(root) {
@@ -51,7 +51,7 @@ for (const runtime of targets) {
51
51
  const { configDir, root } = runMinimalInstall({ runtime, scope: 'global' });
52
52
  let actual;
53
53
  try {
54
- actual = buildInstallTree(configDir, root);
54
+ actual = buildInstallTree(configDir, root, extraEmitRootsFor(runtime, 'global', root));
55
55
  } finally {
56
56
  cleanup(root);
57
57
  }