@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
@@ -117,6 +117,47 @@ function statOrNull(p) {
117
117
  }
118
118
  }
119
119
 
120
+ /**
121
+ * Collect `<dir>/<subdir>/<file>` entries as `<subdir>/<file>` keys — ONE level of
122
+ * subdirectory beneath `dir` itself, where the subdirectory's NAME is the thing being
123
+ * collected (unlike `collectNested`, there is no fixed subdir name to look for; every
124
+ * child directory of `dir` is scanned). This is what makes `gsd-core/bin/lib/<subdir>/*.cjs`
125
+ * (e.g. `health-diagnostic-rules/`, `installer-migrations/`, `host-integration-adapters/`,
126
+ * `observability/`) visible to the `cli_modules` family, mirroring the shape
127
+ * `docs/INVENTORY.md`'s CLI Modules table already uses for these files.
128
+ *
129
+ * Same defensive `statOrNull`-based style as `collectNested`: a stat/readdir failure on
130
+ * one entry is swallowed rather than thrown, so one unreadable subdirectory cannot take
131
+ * down `--check` for the whole repo.
132
+ */
133
+ function collectOneLevelSubdirs({ dir, filter }) {
134
+ if (!fs.existsSync(dir)) return [];
135
+ const out = [];
136
+ let children;
137
+ try {
138
+ children = fs.readdirSync(dir);
139
+ } catch {
140
+ return [];
141
+ }
142
+ for (const child of children) {
143
+ const childStat = statOrNull(path.join(dir, child));
144
+ if (!childStat || !childStat.isDirectory()) continue;
145
+ const subdirPath = path.join(dir, child);
146
+ let files;
147
+ try {
148
+ files = fs.readdirSync(subdirPath);
149
+ } catch {
150
+ continue;
151
+ }
152
+ for (const file of files) {
153
+ const fileStat = statOrNull(path.join(subdirPath, file));
154
+ if (!fileStat || !fileStat.isFile() || !filter(file)) continue;
155
+ out.push([child, file].join('/'));
156
+ }
157
+ }
158
+ return out.sort();
159
+ }
160
+
120
161
  function collectNested({ root, subdir, filter }) {
121
162
  if (!fs.existsSync(root)) return [];
122
163
  const out = [];
@@ -150,11 +191,16 @@ function collectNested({ root, subdir, filter }) {
150
191
  function buildManifest() {
151
192
  const manifest = { families: {} };
152
193
  for (const { name, dir, filter, toName } of FAMILIES) {
153
- manifest.families[name] = fs
194
+ const flat = fs
154
195
  .readdirSync(dir)
155
196
  .filter((f) => fs.statSync(path.join(dir, f)).isFile() && filter(f))
156
- .map(toName)
157
- .sort();
197
+ .map(toName);
198
+ // `cli_modules` also ships subdirectory modules (`health-diagnostic-rules/`,
199
+ // `installer-migrations/`, `host-integration-adapters/`, `observability/`) invisible to
200
+ // the flat readdirSync above; merge them into the SAME sorted array, matching the single
201
+ // "CLI Modules" table shape docs/INVENTORY.md already uses (#3309).
202
+ const nested = name === 'cli_modules' ? collectOneLevelSubdirs({ dir, filter }) : [];
203
+ manifest.families[name] = [...flat, ...nested].sort();
158
204
  }
159
205
  for (const family of NESTED_FAMILIES) {
160
206
  manifest.families[family.name] = collectNested(family);
@@ -209,4 +255,4 @@ if (require.main === module) {
209
255
  // `DEFECT.GENERATIVE-FIX` divergence class: adding a family here while the test kept
210
256
  // its own list meant the test silently verified fewer families than shipped, and still
211
257
  // passed. The test now imports these, so the two surfaces cannot drift.
212
- module.exports = { FAMILIES, NESTED_FAMILIES, collectNested, buildManifest };
258
+ module.exports = { FAMILIES, NESTED_FAMILIES, collectNested, collectOneLevelSubdirs, buildManifest };
@@ -20,6 +20,8 @@ const fs = require('node:fs');
20
20
  const path = require('node:path');
21
21
 
22
22
  const { ExitError, runMain } = require('./lib/cli-exit.cjs');
23
+ const { escapeRegex: escapeRegExp } = require('../gsd-core/bin/lib/pattern.cjs');
24
+ const { normalizeEol } = require('../gsd-core/bin/lib/text-lines.cjs');
23
25
 
24
26
  const ROOT = path.resolve(__dirname, '..');
25
27
  const WORKFLOWS_DIR = path.join(ROOT, 'gsd-core', 'workflows');
@@ -191,13 +193,6 @@ function parseLoopHostBlock(content, fileName) {
191
193
  * @param {string} fileName For error messages
192
194
  * @returns {string[]} Array of error strings; empty = OK
193
195
  */
194
- /**
195
- * Escape a string for literal use in a RegExp.
196
- */
197
- function escapeRegExp(s) {
198
- return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
199
- }
200
-
201
196
  function crossCheckRoles(content, agentRoles, fileName) {
202
197
  const errors = [];
203
198
  for (const role of agentRoles) {
@@ -375,21 +370,6 @@ function serializeContract(contract) {
375
370
  return lines.join('\n');
376
371
  }
377
372
 
378
- // ─── --check diff helper ──────────────────────────────────────────────────────
379
-
380
- /**
381
- * Normalize line endings to LF for CRLF-agnostic comparison.
382
- * FIX 4: The serializer has no nondeterministic content (no timestamp), so
383
- * the generated-by-line stripping that was here has been removed — full content
384
- * comparison is now used so header drift is caught by --check.
385
- *
386
- * @param {string} content
387
- * @returns {string}
388
- */
389
- function normalizeLineEndings(content) {
390
- return content.replace(/\r/g, '');
391
- }
392
-
393
373
  // ─── Main ─────────────────────────────────────────────────────────────────────
394
374
 
395
375
  function main() {
@@ -415,7 +395,7 @@ function main() {
415
395
 
416
396
  const committed = fs.readFileSync(CONTRACT_PATH, 'utf8');
417
397
  // FIX 4: Compare full content (no generated-by stripping) so header drift is caught.
418
- if (normalizeLineEndings(committed) !== normalizeLineEndings(live)) {
398
+ if (normalizeEol(committed) !== normalizeEol(live)) {
419
399
  process.stderr.write(
420
400
  'gsd-core/bin/lib/loop-host-contract.cjs is stale. Run:\n' +
421
401
  ' node scripts/gen-loop-host-contract.cjs --write\n',
@@ -466,8 +446,11 @@ const HOST_LOOP_FILES = STEP_WORKFLOWS.map((w) => 'gsd-core/workflows/' + w.file
466
446
  * @param {string} text Content of a workflow file (or any text).
467
447
  * @returns {Set<string>}
468
448
  */
449
+ /** The call-site shape both scanners key on — one regex, two consumers (#3606). */
450
+ const CALL_SITE_RE = /loop render-hooks\s+([a-z:]+)/g;
451
+
469
452
  function scanWiredPoints(text) {
470
- const re = /loop render-hooks\s+([a-z:]+)/g;
453
+ const re = CALL_SITE_RE;
471
454
  const result = new Set();
472
455
  let m;
473
456
  while ((m = re.exec(text)) !== null) {
@@ -476,6 +459,132 @@ function scanWiredPoints(text) {
476
459
  return result;
477
460
  }
478
461
 
462
+ // ─── Hook-kind coverage (#3606) ──────────────────────────────────────────────
463
+
464
+ const HOOK_KINDS = ['contribution', 'step', 'gate'];
465
+
466
+ /**
467
+ * The kinds one call site's dispatch text actually covers (#3606).
468
+ *
469
+ * A point having a `loop render-hooks <point>` call site proves the hooks are
470
+ * RENDERED, not that they are DISPATCHED — a consumer that iterates only
471
+ * `kind == "gate"` (or narrows `kind == "step"` to one `ref.skill`) silently
472
+ * drops every other registered kind. Coverage rules for the text following a
473
+ * call site, up to the next call site or the region cap, judged LINE by line:
474
+ *
475
+ * - A deferral line (one carrying an `@`-included path to the generic
476
+ * contract, e.g. `@gsd-core/references/loop-hook-dispatch.md`) that names a
477
+ * kind (`kind == "step"`) covers that kind; a deferral line with no kind
478
+ * discriminator ("apply each entry") covers every kind. A bare §-citation
479
+ * of the reference (validation guidance only, no `@`) covers nothing —
480
+ * plan-phase cites the gate-validation section while dispatching only gates.
481
+ * - Otherwise a kind is covered when some LINE dispatches it unconditionally:
482
+ * a `kind == "<kind>"` discriminator with NO same-line narrowing to one
483
+ * hook (`ref.skill ==`, `ref.agent ==`, `ref.command ==`). A narrowed line
484
+ * special-cases ONE hook and proves nothing about the kind generally — the
485
+ * exact hand-rolled-consumer shape the reference warns about.
486
+ *
487
+ * Quote style and spacing vary across the corpus (`kind == "step"`,
488
+ * `kind === 'gate'`), so the matcher is tolerant of both quote characters and
489
+ * of `==`/`===`.
490
+ *
491
+ * Pure: same input, same output; CRLF-safe (line splitting tolerates \r).
492
+ *
493
+ * @param {string} region Dispatch text following one call site.
494
+ * @returns {Set<string>}
495
+ */
496
+ function coveredKindsInRegion(region) {
497
+ const covered = new Set();
498
+ // Same-SEGMENT narrowing to ONE hook voids credit: `ref.skill ==`, `capId ==`,
499
+ // and `into ==` each special-case a subset, not the kind generally
500
+ // (plan-phase's `kind == "contribution" and capId == "security"` is the
501
+ // hand-rolled shape; `into == "planner"` covers only planner-targeted
502
+ // contributions). Segments, not lines: execute-phase legitimately writes
503
+ // "dispatch `kind == "step"` hooks per … . `ref.skill == "code-review"`:" —
504
+ // the deferral is one sentence, the specialization the next; narrowing in a
505
+ // DIFFERENT segment must not void the deferral's credit.
506
+ const narrowingRe = /(?:ref\.(?:skill|agent|command)|capId|into)\s*={2,3}/;
507
+ // Negated mentions describe an absence, not a dispatch ("Branch 1 — no active
508
+ // step hooks (`activeHooks` has no entry with `kind == "step"`)" — ship.md).
509
+ const negationRe = /\b(?:no|without|absent|lacks?|missing)\b[^.|]*kind\s*={2,3}/;
510
+ const deferralRe = /@\S*loop-hook-dispatch\.md/;
511
+ for (const line of region.split(/\r?\n/)) {
512
+ // Sentence segments: a `.`/`;` followed by whitespace ends a segment. A
513
+ // period NOT followed by whitespace (the `.md` inside a deferral path,
514
+ // `ref.skill`) is not a boundary.
515
+ for (const segment of line.split(/(?<=[.;])\s+/)) {
516
+ const kindDiscriminators = [];
517
+ for (const kind of HOOK_KINDS) {
518
+ if (new RegExp(`kind\\s*={2,3}\\s*["']${kind}["']`).test(segment)) kindDiscriminators.push(kind);
519
+ }
520
+ if (kindDiscriminators.length === 0) {
521
+ // A deferral with no kind discriminator ("apply each entry per …")
522
+ // still covers every kind.
523
+ if (deferralRe.test(segment)) for (const kind of HOOK_KINDS) covered.add(kind);
524
+ continue;
525
+ }
526
+ if (negationRe.test(segment)) continue;
527
+ if (deferralRe.test(segment)) {
528
+ // Deferral naming kinds ("dispatch `kind == "step"` hooks per …").
529
+ if (!narrowingRe.test(segment)) for (const kind of kindDiscriminators) covered.add(kind);
530
+ continue;
531
+ }
532
+ if (!narrowingRe.test(segment)) for (const kind of kindDiscriminators) covered.add(kind);
533
+ }
534
+ }
535
+ return covered;
536
+ }
537
+
538
+ /**
539
+ * Scan every `loop render-hooks <point>` call site in `text` and accumulate,
540
+ * per point, the union of hook kinds its dispatch regions cover (#3606).
541
+ *
542
+ * @param {string} text Content of a workflow file (or any text).
543
+ * @returns {Map<string, Set<string>>} point → covered kinds.
544
+ */
545
+ function scanWiredKinds(text) {
546
+ const result = new Map();
547
+ const siteRe = CALL_SITE_RE;
548
+ const sites = [];
549
+ let m;
550
+ while ((m = siteRe.exec(text)) !== null) sites.push({ point: m[1], start: m.index });
551
+ const REGION_CAP = 6000;
552
+ for (let i = 0; i < sites.length; i++) {
553
+ const regionEnd = i + 1 < sites.length ? sites[i + 1].start : Math.min(text.length, sites[i].start + REGION_CAP);
554
+ const region = text.slice(sites[i].start, regionEnd);
555
+ const covered = coveredKindsInRegion(region);
556
+ if (!result.has(sites[i].point)) result.set(sites[i].point, new Set());
557
+ for (const kind of covered) result.get(sites[i].point).add(kind);
558
+ }
559
+ return result;
560
+ }
561
+
562
+ /**
563
+ * Read every host-loop workflow file and return, per point, the union of hook
564
+ * kinds its call sites' dispatch text covers (#3606).
565
+ *
566
+ * @param {string} [repoRoot] Path to the repository root. Defaults to ROOT.
567
+ * @returns {Map<string, Set<string>>}
568
+ */
569
+ function getWiredKinds(repoRoot) {
570
+ const resolvedRoot = repoRoot !== undefined ? repoRoot : ROOT;
571
+ const result = new Map();
572
+ for (const relPath of HOST_LOOP_FILES) {
573
+ const absPath = path.join(resolvedRoot, relPath);
574
+ let content;
575
+ try {
576
+ content = fs.readFileSync(absPath, 'utf8');
577
+ } catch (err) {
578
+ throw new Error('getWiredKinds: cannot read host-loop file ' + absPath + ': ' + err.message);
579
+ }
580
+ for (const [point, kinds] of scanWiredKinds(content)) {
581
+ if (!result.has(point)) result.set(point, new Set());
582
+ for (const kind of kinds) result.get(point).add(kind);
583
+ }
584
+ }
585
+ return result;
586
+ }
587
+
479
588
  /**
480
589
  * Read every host-loop workflow file and return the union of all wired loop points
481
590
  * (i.e. points that have a `loop render-hooks <point>` call site).
@@ -509,7 +618,7 @@ module.exports = {
509
618
  assertPointsCoverage,
510
619
  buildContract,
511
620
  serializeContract,
512
- normalizeLineEndings,
621
+ normalizeLineEndings: normalizeEol,
513
622
  STEP_WORKFLOWS,
514
623
  HOST_LOOP_FILES,
515
624
  CANONICAL_POINTS,
@@ -517,6 +626,10 @@ module.exports = {
517
626
  ROLE_TO_AGENT,
518
627
  scanWiredPoints,
519
628
  getWiredLoopPoints,
629
+ coveredKindsInRegion,
630
+ scanWiredKinds,
631
+ getWiredKinds,
632
+ HOOK_KINDS,
520
633
  };
521
634
 
522
635
  // ─── CLI entry point ──────────────────────────────────────────────────────────
@@ -35,6 +35,7 @@ const path = require('node:path');
35
35
 
36
36
  const { ExitError, runMain } = require('./lib/cli-exit.cjs');
37
37
  const { renderMarkdown } = require('./registry-schema.cjs');
38
+ const { normalizeEol } = require('../gsd-core/bin/lib/text-lines.cjs');
38
39
 
39
40
  const SOURCES = [
40
41
  { type: 'capability', jsonFile: 'capabilities.json', mdFile: 'capability-registry.md' },
@@ -42,18 +43,6 @@ const SOURCES = [
42
43
  { type: 'reviewer', jsonFile: 'reviewers.json', mdFile: 'reviewer-registry.md', optional: true },
43
44
  ];
44
45
 
45
- /**
46
- * The generator always writes LF; a Windows checkout (autocrlf) may present
47
- * committed files with CRLF. Normalize before comparing so `--check` only
48
- * fails on real content drift, not checkout-introduced line-ending noise.
49
- *
50
- * @param {string} content
51
- * @returns {string}
52
- */
53
- function normalizeLineEndings(content) {
54
- return content.replace(/\r/g, '');
55
- }
56
-
57
46
  function getRegistriesDir() {
58
47
  return path.join(process.cwd(), 'docs', 'registries');
59
48
  }
@@ -126,7 +115,7 @@ function main() {
126
115
  continue;
127
116
  }
128
117
  const committed = fs.readFileSync(mdPath, 'utf8');
129
- if (normalizeLineEndings(committed) !== normalizeLineEndings(rendered)) {
118
+ if (normalizeEol(committed) !== normalizeEol(rendered)) {
130
119
  process.stderr.write(`${mdFile} is stale. Run:\n node scripts/gen-registry.cjs --write\n`);
131
120
  anyDrift = true;
132
121
  }
@@ -149,4 +138,4 @@ function main() {
149
138
 
150
139
  if (require.main === module) runMain(main);
151
140
 
152
- module.exports = { main, renderFor, SOURCES, normalizeLineEndings };
141
+ module.exports = { main, renderFor, SOURCES, normalizeLineEndings: normalizeEol };
@@ -0,0 +1,185 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * gen-scripts-cli-exit.cjs — generates scripts/lib/cli-exit.cjs from a fresh
4
+ * compile of src/cli-exit.cts.
5
+ *
6
+ * ADR-3889 Phase 0 (#3904): scripts/lib/cli-exit.cjs used to be a hand-written
7
+ * fork of gsd-core/bin/lib/cli-exit.cjs (the compiled artifact of
8
+ * src/cli-exit.cts). The two drifted — only the .cts copy routed a
9
+ * non-ExitError throw through getJsonErrorMode() to emit a structured
10
+ * { ok:false, reason, message } envelope. This script makes scripts/lib/cli-exit.cjs
11
+ * a generated artifact of the SAME source, so the two surfaces cannot diverge
12
+ * again.
13
+ *
14
+ * scripts/ runs straight from the repo checkout and must work on an unbuilt
15
+ * clone (scripts/check-env.cjs requires this file before any build runs), so
16
+ * the generated file is compiled to a THROWAWAY outDir rather than read from
17
+ * gsd-core/bin/lib/ — reading the tracked build output would let a stale build
18
+ * produce a false green.
19
+ *
20
+ * Usage:
21
+ * node scripts/gen-scripts-cli-exit.cjs # same as --write
22
+ * node scripts/gen-scripts-cli-exit.cjs --write # write scripts/lib/cli-exit.cjs
23
+ * node scripts/gen-scripts-cli-exit.cjs --check # exit 1 if committed file is stale
24
+ */
25
+
26
+ 'use strict';
27
+
28
+ const { execFileSync } = require('node:child_process');
29
+ const fs = require('node:fs');
30
+ const os = require('node:os');
31
+ const path = require('node:path');
32
+
33
+ const REPO_ROOT = path.resolve(__dirname, '..');
34
+ const OUTPUT_PATH = path.join(REPO_ROOT, 'scripts', 'lib', 'cli-exit.cjs');
35
+ const COMPILE_TIMEOUT_MS = 60_000;
36
+
37
+ /** Frozen reason codes so tests assert on structure, not prose. */
38
+ const REASON = Object.freeze({
39
+ OK: 'ok_generated_sync',
40
+ DRIFTED: 'fail_generated_drifted',
41
+ BUILD_FAILED: 'fail_build_failed',
42
+ MISSING_EMIT: 'fail_missing_emit',
43
+ USAGE: 'fail_usage',
44
+ });
45
+
46
+ const USAGE_MESSAGE = [
47
+ 'Usage: node scripts/gen-scripts-cli-exit.cjs [--write|--check]',
48
+ ' (no flag) same as --write',
49
+ ' --write write scripts/lib/cli-exit.cjs',
50
+ ' --check exit 1 if the committed file is stale',
51
+ ].join('\n');
52
+
53
+ const BANNER = [
54
+ '// GENERATED FILE — DO NOT EDIT BY HAND.',
55
+ '// Source of truth: src/cli-exit.cts. Regenerate with:',
56
+ '// node scripts/gen-scripts-cli-exit.cjs --write',
57
+ '// Byte-compared by `npm run lint:generated-sync` (#3904, ADR-3889 Phase 0).',
58
+ '//',
59
+ '// Why this copy exists: scripts/ runs straight from the repo checkout and must',
60
+ '// work on an unbuilt clone — 64+ scripts require this file, including',
61
+ '// check-env.cjs, which runs before any build. gsd-core/bin/lib/cli-exit.cjs is',
62
+ '// gitignored tsc output and doubles as the build sentinel, so it cannot be',
63
+ '// required from here. Hence one source, two emitted locations.',
64
+ '',
65
+ '',
66
+ ].join('\n');
67
+
68
+ /** Compile the whole project to a throwaway outDir so the work tree is untouched. */
69
+ function compileToTemp() {
70
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-scripts-cli-exit-'));
71
+ try {
72
+ execFileSync(
73
+ process.execPath,
74
+ [
75
+ path.join(REPO_ROOT, 'node_modules', 'typescript', 'bin', 'tsc'),
76
+ '-p', path.join(REPO_ROOT, 'tsconfig.build.json'),
77
+ '--outDir', tmp,
78
+ // A throwaway outDir must not reuse the in-tree incremental state, or
79
+ // tsc skips emit for files it believes are already current.
80
+ '--incremental', 'false',
81
+ '--tsBuildInfoFile', 'null',
82
+ ],
83
+ { cwd: REPO_ROOT, encoding: 'utf8', stdio: 'pipe', timeout: COMPILE_TIMEOUT_MS },
84
+ );
85
+ return { ok: true, dir: tmp };
86
+ } catch (err) {
87
+ fs.rmSync(tmp, { recursive: true, force: true });
88
+ const detail = [err.stdout, err.stderr].filter(Boolean).join('\n').trim();
89
+ return { ok: false, detail };
90
+ }
91
+ }
92
+
93
+ /**
94
+ * Compile src/cli-exit.cts to a throwaway outDir and return the expected
95
+ * generated content (banner + compiled bytes), or a failure descriptor.
96
+ *
97
+ * @returns {{ ok: true, content: string } | { ok: false, reason: string, detail?: string }}
98
+ */
99
+ function buildExpectedContent() {
100
+ const build = compileToTemp();
101
+ if (!build.ok) {
102
+ return { ok: false, reason: REASON.BUILD_FAILED, detail: build.detail };
103
+ }
104
+ try {
105
+ const emitted = path.join(build.dir, 'cli-exit.cjs');
106
+ if (!fs.existsSync(emitted)) {
107
+ return { ok: false, reason: REASON.MISSING_EMIT, detail: `no emit produced at ${emitted} from src/cli-exit.cts` };
108
+ }
109
+ const compiled = fs.readFileSync(emitted, 'utf8');
110
+ return { ok: true, content: BANNER + compiled };
111
+ } finally {
112
+ fs.rmSync(build.dir, { recursive: true, force: true });
113
+ }
114
+ }
115
+
116
+ function doWrite() {
117
+ const result = buildExpectedContent();
118
+ if (!result.ok) {
119
+ console.error(`FAIL gen-scripts-cli-exit: ${result.reason}`);
120
+ if (result.detail) console.error(result.detail);
121
+ return 1;
122
+ }
123
+ fs.mkdirSync(path.dirname(OUTPUT_PATH), { recursive: true });
124
+ fs.writeFileSync(OUTPUT_PATH, result.content, 'utf8');
125
+ console.log(`ok gen-scripts-cli-exit: wrote ${path.relative(REPO_ROOT, OUTPUT_PATH)}`);
126
+ return 0;
127
+ }
128
+
129
+ function doCheck() {
130
+ const result = buildExpectedContent();
131
+ if (!result.ok) {
132
+ console.error(`FAIL gen-scripts-cli-exit: ${result.reason}`);
133
+ if (result.detail) console.error(result.detail);
134
+ return 1;
135
+ }
136
+
137
+ if (!fs.existsSync(OUTPUT_PATH)) {
138
+ console.error(`FAIL gen-scripts-cli-exit: ${REASON.MISSING_EMIT}`);
139
+ console.error(` ${path.relative(REPO_ROOT, OUTPUT_PATH)} does not exist. Run:`);
140
+ console.error(' node scripts/gen-scripts-cli-exit.cjs --write');
141
+ return 1;
142
+ }
143
+
144
+ const committed = fs.readFileSync(OUTPUT_PATH, 'utf8');
145
+ if (committed !== result.content) {
146
+ console.error(`FAIL gen-scripts-cli-exit: ${REASON.DRIFTED}`);
147
+ console.error(
148
+ ` ${path.relative(REPO_ROOT, OUTPUT_PATH)} (${committed.length} bytes) != ` +
149
+ `compile of src/cli-exit.cts (${result.content.length} bytes)`,
150
+ );
151
+ console.error('');
152
+ console.error('Regenerate with:');
153
+ console.error(' node scripts/gen-scripts-cli-exit.cjs --write');
154
+ return 1;
155
+ }
156
+
157
+ console.log(`ok gen-scripts-cli-exit: ${path.relative(REPO_ROOT, OUTPUT_PATH)} matches src/cli-exit.cts`);
158
+ return 0;
159
+ }
160
+
161
+ function main() {
162
+ const flag = process.argv[2];
163
+ const extra = process.argv[3];
164
+
165
+ if (flag !== undefined && flag !== '--write' && flag !== '--check') {
166
+ console.error(`FAIL gen-scripts-cli-exit: ${REASON.USAGE}`);
167
+ console.error(` unrecognized argument: ${flag}`);
168
+ console.error(USAGE_MESSAGE);
169
+ return 1;
170
+ }
171
+
172
+ if (extra !== undefined) {
173
+ console.error(`FAIL gen-scripts-cli-exit: ${REASON.USAGE}`);
174
+ console.error(` unexpected extra argument: ${extra}`);
175
+ console.error(USAGE_MESSAGE);
176
+ return 1;
177
+ }
178
+
179
+ if (flag === '--check') return doCheck();
180
+ return doWrite();
181
+ }
182
+
183
+ if (require.main === module) process.exitCode = main();
184
+
185
+ module.exports = { REASON, buildExpectedContent, OUTPUT_PATH, BANNER };