@opengsd/gsd-core 1.10.0 → 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (544) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/agents/gsd-code-fixer.md +1 -1
  4. package/agents/gsd-debug-session-manager.md +12 -1
  5. package/agents/gsd-debugger.md +1 -1
  6. package/agents/gsd-doc-synthesizer.md +2 -4
  7. package/agents/gsd-dom-verifier.md +169 -0
  8. package/agents/gsd-eval-auditor.md +1 -1
  9. package/agents/gsd-executor.md +22 -14
  10. package/agents/gsd-framework-selector.md +1 -3
  11. package/agents/gsd-intel-updater.md +1 -1
  12. package/agents/gsd-mempalace-curator.md +5 -3
  13. package/agents/gsd-pattern-mapper.md +11 -0
  14. package/agents/gsd-phase-researcher.md +23 -2
  15. package/agents/gsd-plan-checker.md +50 -53
  16. package/agents/gsd-planner.md +50 -50
  17. package/agents/gsd-project-researcher.md +1 -1
  18. package/agents/gsd-research-synthesizer.md +2 -2
  19. package/agents/gsd-roadmapper.md +15 -11
  20. package/agents/gsd-ui-checker.md +63 -4
  21. package/agents/gsd-ui-researcher.md +41 -3
  22. package/agents/gsd-user-profiler.md +3 -0
  23. package/agents/gsd-verifier.md +13 -4
  24. package/bin/install.js +1448 -1103
  25. package/commands/gsd/code-review.md +1 -1
  26. package/commands/gsd/discuss-phase.md +1 -1
  27. package/commands/gsd/execute-phase.md +1 -1
  28. package/commands/gsd/import.md +1 -1
  29. package/commands/gsd/map-codebase.md +1 -1
  30. package/commands/gsd/mempalace-capture.md +1 -1
  31. package/commands/gsd/mempalace-recall.md +1 -1
  32. package/commands/gsd/new-milestone.md +1 -1
  33. package/commands/gsd/quick.md +9 -5
  34. package/commands/gsd/review-backlog.md +2 -1
  35. package/commands/gsd/verify-work.md +1 -1
  36. package/gsd-core/bin/gsd-tools.cjs +1035 -138
  37. package/gsd-core/bin/lib/active-workstream-store.cjs +146 -22
  38. package/gsd-core/bin/lib/adr-parser.cjs +13 -7
  39. package/gsd-core/bin/lib/agent-install-check.cjs +392 -32
  40. package/gsd-core/bin/lib/api-coverage.cjs +33 -14
  41. package/gsd-core/bin/lib/artifacts.cjs +5 -0
  42. package/gsd-core/bin/lib/assumption-delta.cjs +32 -15
  43. package/gsd-core/bin/lib/audit-command-router.cjs +9 -2
  44. package/gsd-core/bin/lib/audit.cjs +1026 -268
  45. package/gsd-core/bin/lib/broken-windows.cjs +306 -28
  46. package/gsd-core/bin/lib/capability-consent.cjs +149 -15
  47. package/gsd-core/bin/lib/capability-lifecycle.cjs +45 -0
  48. package/gsd-core/bin/lib/capability-lock.cjs +10 -4
  49. package/gsd-core/bin/lib/capability-registry.cjs +845 -130
  50. package/gsd-core/bin/lib/capability-source.cjs +92 -0
  51. package/gsd-core/bin/lib/capability-state.cjs +18 -3
  52. package/gsd-core/bin/lib/capability-trust.cjs +444 -25
  53. package/gsd-core/bin/lib/capability-validator.cjs +700 -40
  54. package/gsd-core/bin/lib/capability-writer.cjs +3 -2
  55. package/gsd-core/bin/lib/check-command-router.cjs +216 -42
  56. package/gsd-core/bin/lib/claude-orchestration.cjs +56 -3
  57. package/gsd-core/bin/lib/cli-exit.cjs +496 -10
  58. package/gsd-core/bin/lib/code-review-depth.cjs +288 -0
  59. package/gsd-core/bin/lib/codex-agent-toml.cjs +735 -0
  60. package/gsd-core/bin/lib/command-aliases.cjs +22 -0
  61. package/gsd-core/bin/lib/command-arg-projection.cjs +144 -14
  62. package/gsd-core/bin/lib/command-roster.cjs +44 -1
  63. package/gsd-core/bin/lib/command-routing-hub.cjs +31 -2
  64. package/gsd-core/bin/lib/commands.cjs +1172 -108
  65. package/gsd-core/bin/lib/commonjs-marker.cjs +12 -6
  66. package/gsd-core/bin/lib/complexity-trigger.cjs +1192 -0
  67. package/gsd-core/bin/lib/config-loader.cjs +187 -23
  68. package/gsd-core/bin/lib/config.cjs +102 -3
  69. package/gsd-core/bin/lib/configuration.cjs +129 -37
  70. package/gsd-core/bin/lib/core-utils.cjs +208 -33
  71. package/gsd-core/bin/lib/decisions.cjs +23 -0
  72. package/gsd-core/bin/lib/edge-probe.cjs +9 -1
  73. package/gsd-core/bin/lib/estimate-cli.cjs +55 -11
  74. package/gsd-core/bin/lib/exit-code-registry.cjs +98 -0
  75. package/gsd-core/bin/lib/fallow-runner.cjs +20 -44
  76. package/gsd-core/bin/lib/frontmatter.cjs +899 -229
  77. package/gsd-core/bin/lib/gap-checker.cjs +95 -10
  78. package/gsd-core/bin/lib/git-base-branch.cjs +276 -39
  79. package/gsd-core/bin/lib/gsd2-import.cjs +10 -1
  80. package/gsd-core/bin/lib/health-diagnostic-rules/agent-install.cjs +101 -0
  81. package/gsd-core/bin/lib/health-diagnostic-rules/config-validation.cjs +348 -0
  82. package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +149 -0
  83. package/gsd-core/bin/lib/health-diagnostic-rules/install-surface-shadowing.cjs +98 -0
  84. package/gsd-core/bin/lib/health-diagnostic-rules/milestone-archive-hygiene.cjs +100 -0
  85. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +222 -0
  86. package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +268 -0
  87. package/gsd-core/bin/lib/health-diagnostic-rules/root-existence.cjs +161 -0
  88. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +303 -0
  89. package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +187 -0
  90. package/gsd-core/bin/lib/health-diagnostic-types.cjs +68 -0
  91. package/gsd-core/bin/lib/health-diagnostic.cjs +451 -0
  92. package/gsd-core/bin/lib/host-integration.cjs +39 -6
  93. package/gsd-core/bin/lib/host-runtime-detection.cjs +134 -0
  94. package/gsd-core/bin/lib/init-command-router.cjs +118 -21
  95. package/gsd-core/bin/lib/init.cjs +439 -168
  96. package/gsd-core/bin/lib/install-effort-resolver.cjs +73 -30
  97. package/gsd-core/bin/lib/install-engine.cjs +811 -259
  98. package/gsd-core/bin/lib/install-fs-adapter.cjs +262 -0
  99. package/gsd-core/bin/lib/install-model-override-resolver.cjs +235 -0
  100. package/gsd-core/bin/lib/install-profiles.cjs +212 -61
  101. package/gsd-core/bin/lib/install-scope.cjs +270 -0
  102. package/gsd-core/bin/lib/install-shadow-report.cjs +385 -0
  103. package/gsd-core/bin/lib/installed-surface-resolver.cjs +381 -0
  104. package/gsd-core/bin/lib/installer-migration-report.cjs +3 -0
  105. package/gsd-core/bin/lib/installer-migrations/010-antigravity-retire-confighome-artifacts.cjs +169 -0
  106. package/gsd-core/bin/lib/installer-migrations.cjs +148 -38
  107. package/gsd-core/bin/lib/intel.cjs +101 -26
  108. package/gsd-core/bin/lib/io.cjs +170 -15
  109. package/gsd-core/bin/lib/learnings.cjs +85 -14
  110. package/gsd-core/bin/lib/legacy-cleanup.cjs +8 -2
  111. package/gsd-core/bin/lib/markdown-sectionizer.cjs +2 -1
  112. package/gsd-core/bin/lib/markdown-table.cjs +183 -22
  113. package/gsd-core/bin/lib/milestone-lock.cjs +248 -0
  114. package/gsd-core/bin/lib/milestone.cjs +842 -73
  115. package/gsd-core/bin/lib/model-catalog.cjs +232 -16
  116. package/gsd-core/bin/lib/model-resolver.cjs +193 -68
  117. package/gsd-core/bin/lib/normalize-test-command.cjs +1 -1
  118. package/gsd-core/bin/lib/onboard-projection.cjs +5 -1
  119. package/gsd-core/bin/lib/pattern.cjs +122 -0
  120. package/gsd-core/bin/lib/phase-estimation.cjs +18 -9
  121. package/gsd-core/bin/lib/phase-id.cjs +514 -40
  122. package/gsd-core/bin/lib/phase-lifecycle.cjs +52 -19
  123. package/gsd-core/bin/lib/phase-locator.cjs +262 -34
  124. package/gsd-core/bin/lib/phase.cjs +1038 -214
  125. package/gsd-core/bin/lib/plan-dependency-graph.cjs +72 -1
  126. package/gsd-core/bin/lib/plan-document.cjs +263 -0
  127. package/gsd-core/bin/lib/plan-drift-guard.cjs +120 -0
  128. package/gsd-core/bin/lib/plan-scan.cjs +98 -3
  129. package/gsd-core/bin/lib/planning-command-router.cjs +61 -0
  130. package/gsd-core/bin/lib/planning-inspect.cjs +1168 -0
  131. package/gsd-core/bin/lib/planning-scope.cjs +31 -0
  132. package/gsd-core/bin/lib/planning-snapshot.cjs +894 -0
  133. package/gsd-core/bin/lib/planning-workspace.cjs +112 -6
  134. package/gsd-core/bin/lib/probe-core.cjs +5 -2
  135. package/gsd-core/bin/lib/profile-output.cjs +1 -1
  136. package/gsd-core/bin/lib/profile-pipeline-command-router.cjs +50 -7
  137. package/gsd-core/bin/lib/profile-pipeline.cjs +6 -3
  138. package/gsd-core/bin/lib/real-home-guard.cjs +419 -0
  139. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +766 -0
  140. package/gsd-core/bin/lib/retired-artifact-cleanup.cjs +11 -6
  141. package/gsd-core/bin/lib/review-lane-descriptor.cjs +22 -13
  142. package/gsd-core/bin/lib/review-lane-invocation.cjs +30 -0
  143. package/gsd-core/bin/lib/review-lane-runner.cjs +421 -66
  144. package/gsd-core/bin/lib/review-reviewer-selection.cjs +13 -18
  145. package/gsd-core/bin/lib/roadmap-command-router.cjs +59 -11
  146. package/gsd-core/bin/lib/roadmap-parser.cjs +1006 -184
  147. package/gsd-core/bin/lib/roadmap-upgrade.cjs +37 -10
  148. package/gsd-core/bin/lib/roadmap.cjs +442 -96
  149. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +702 -52
  150. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +14 -2
  151. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +459 -55
  152. package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +3 -2
  153. package/gsd-core/bin/lib/runtime-homes.cjs +69 -3
  154. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +402 -58
  155. package/gsd-core/bin/lib/runtime-identity.cjs +234 -0
  156. package/gsd-core/bin/lib/runtime-name-policy.cjs +3 -1
  157. package/gsd-core/bin/lib/runtime-slash.cjs +96 -8
  158. package/gsd-core/bin/lib/security.cjs +104 -5
  159. package/gsd-core/bin/lib/shell-command-projection.cjs +342 -7
  160. package/gsd-core/bin/lib/smart-entry.cjs +133 -23
  161. package/gsd-core/bin/lib/spec-section.cjs +12 -7
  162. package/gsd-core/bin/lib/state-command-router.cjs +52 -19
  163. package/gsd-core/bin/lib/state-contract.cjs +359 -0
  164. package/gsd-core/bin/lib/state-document.cjs +338 -8
  165. package/gsd-core/bin/lib/state-md-schema.cjs +221 -0
  166. package/gsd-core/bin/lib/state-transition.cjs +846 -176
  167. package/gsd-core/bin/lib/state.cjs +2589 -369
  168. package/gsd-core/bin/lib/surface.cjs +33 -11
  169. package/gsd-core/bin/lib/task-command-router.cjs +111 -1
  170. package/gsd-core/bin/lib/task-content-resolution.cjs +368 -0
  171. package/gsd-core/bin/lib/teams-status.cjs +4 -1
  172. package/gsd-core/bin/lib/text-lines.cjs +80 -0
  173. package/gsd-core/bin/lib/token-scanner.cjs +76 -0
  174. package/gsd-core/bin/lib/uat-predicate.cjs +67 -23
  175. package/gsd-core/bin/lib/uat.cjs +1761 -167
  176. package/gsd-core/bin/lib/ui-consideration-probe.cjs +9 -1
  177. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +157 -0
  178. package/gsd-core/bin/lib/ui-safety-gate.cjs +51 -12
  179. package/gsd-core/bin/lib/unusable-input.cjs +37 -0
  180. package/gsd-core/bin/lib/update-context.cjs +8 -2
  181. package/gsd-core/bin/lib/user-artifact-staging.cjs +705 -0
  182. package/gsd-core/bin/lib/validate-command-router.cjs +2 -2
  183. package/gsd-core/bin/lib/validate.cjs +20 -6
  184. package/gsd-core/bin/lib/vendor/README.md +75 -0
  185. package/gsd-core/bin/lib/vendor/js-yaml.cjs +3014 -0
  186. package/gsd-core/bin/lib/vendor/re2js.cjs +6480 -0
  187. package/gsd-core/bin/lib/vendor/re2js.d.cts +938 -0
  188. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  189. package/gsd-core/bin/lib/verification.cjs +272 -9
  190. package/gsd-core/bin/lib/verify-command-grounding.cjs +846 -0
  191. package/gsd-core/bin/lib/verify.cjs +453 -918
  192. package/gsd-core/bin/lib/workstream-inventory-builder.cjs +53 -32
  193. package/gsd-core/bin/lib/workstream-inventory.cjs +63 -10
  194. package/gsd-core/bin/lib/workstream-name-policy.cjs +25 -4
  195. package/gsd-core/bin/lib/workstream.cjs +2 -2
  196. package/gsd-core/bin/lib/worktree-base-ref.cjs +66 -12
  197. package/gsd-core/bin/lib/worktree-safety.cjs +341 -18
  198. package/gsd-core/bin/shared/config-defaults.manifest.json +8 -1
  199. package/gsd-core/bin/shared/config-schema.manifest.json +12 -1
  200. package/gsd-core/bin/shared/exit-codes.json +8 -0
  201. package/gsd-core/bin/shared/exit-codes.sh +20 -0
  202. package/gsd-core/bin/shared/model-catalog.json +8 -1
  203. package/gsd-core/references/agent-contracts.md +44 -26
  204. package/gsd-core/references/api-coverage.md +24 -2
  205. package/gsd-core/references/autonomous-smart-discuss.md +3 -3
  206. package/gsd-core/references/checkpoints.md +39 -21
  207. package/gsd-core/references/context-budget.md +1 -1
  208. package/gsd-core/references/decimal-phase-calculation.md +5 -5
  209. package/gsd-core/references/dispatch-isolation-gate.md +138 -0
  210. package/gsd-core/references/doc-conflict-engine.md +1 -1
  211. package/gsd-core/references/edge-probe.md +8 -0
  212. package/gsd-core/references/execute-mvp-tdd.md +4 -6
  213. package/gsd-core/references/execute-phase-between-wave-reset.md +15 -14
  214. package/gsd-core/references/execute-phase-context-guard.md +1 -1
  215. package/gsd-core/references/execute-phase-response-language.md +1 -1
  216. package/gsd-core/references/execute-phase-wave-guard.md +17 -11
  217. package/gsd-core/references/failing-direction.md +78 -0
  218. package/gsd-core/references/gate-prompts.md +1 -1
  219. package/gsd-core/references/git-integration.md +5 -5
  220. package/gsd-core/references/git-planning-commit.md +5 -4
  221. package/gsd-core/references/gsd-run-resolver.md +1 -1
  222. package/gsd-core/references/loop-hook-dispatch.md +61 -2
  223. package/gsd-core/references/model-profiles.md +12 -4
  224. package/gsd-core/references/mvp-concepts.md +9 -9
  225. package/gsd-core/references/nyquist-compliance.md +74 -0
  226. package/gsd-core/references/offer-next.md +3 -5
  227. package/gsd-core/references/phase-argument-parsing.md +3 -3
  228. package/gsd-core/references/planner-failing-direction.md +53 -0
  229. package/gsd-core/references/planner-guidance.md +3 -9
  230. package/gsd-core/references/planner-human-verify-mode.md +15 -1
  231. package/gsd-core/references/planner-preconditions.md +1 -1
  232. package/gsd-core/references/planner-reviews.md +1 -1
  233. package/gsd-core/references/planner-revision.md +1 -1
  234. package/gsd-core/references/planner-verify-command-grounding.md +17 -0
  235. package/gsd-core/references/planning-config.md +44 -13
  236. package/gsd-core/references/reviewer-instances.md +31 -0
  237. package/gsd-core/references/revision-loop.md +1 -1
  238. package/gsd-core/references/runtime-aware-dispatch.md +1 -1
  239. package/gsd-core/references/specless-probe-fallback.md +1 -1
  240. package/gsd-core/references/tdd.md +1 -3
  241. package/gsd-core/references/ui-brand.md +65 -21
  242. package/gsd-core/references/ui-consideration-probe.md +1 -1
  243. package/gsd-core/references/universal-anti-patterns.md +5 -5
  244. package/gsd-core/references/verifier-phase-gates.md +192 -0
  245. package/gsd-core/references/verify-command-path-resolvability.md +42 -0
  246. package/gsd-core/references/verify-mvp-mode.md +2 -2
  247. package/gsd-core/references/workstream-flag.md +33 -17
  248. package/gsd-core/templates/README.md +1 -1
  249. package/gsd-core/templates/SECURITY.md +3 -3
  250. package/gsd-core/templates/UI-SPEC.md +25 -3
  251. package/gsd-core/templates/VALIDATION.md +3 -3
  252. package/gsd-core/templates/discussion-log.md +1 -1
  253. package/gsd-core/templates/phase-prompt.md +5 -4
  254. package/gsd-core/templates/state.md +11 -4
  255. package/gsd-core/templates/verification-report.md +9 -1
  256. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  257. package/gsd-core/workflows/add-backlog.md +1 -1
  258. package/gsd-core/workflows/add-phase.md +3 -3
  259. package/gsd-core/workflows/add-tests.md +3 -8
  260. package/gsd-core/workflows/add-todo.md +1 -1
  261. package/gsd-core/workflows/ai-integration-phase.md +13 -20
  262. package/gsd-core/workflows/audit-fix.md +12 -3
  263. package/gsd-core/workflows/audit-milestone.md +9 -9
  264. package/gsd-core/workflows/audit-uat.md +17 -2
  265. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +2 -2
  266. package/gsd-core/workflows/autonomous.md +11 -27
  267. package/gsd-core/workflows/check-todos.md +1 -1
  268. package/gsd-core/workflows/cleanup.md +64 -5
  269. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +14 -4
  270. package/gsd-core/workflows/code-review-fix.md +38 -11
  271. package/gsd-core/workflows/code-review.md +159 -52
  272. package/gsd-core/workflows/complete-milestone.md +151 -23
  273. package/gsd-core/workflows/debug.md +12 -8
  274. package/gsd-core/workflows/diagnose-issues.md +47 -15
  275. package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
  276. package/gsd-core/workflows/discuss-phase/modes/chain.md +5 -8
  277. package/gsd-core/workflows/discuss-phase/modes/default.md +1 -1
  278. package/gsd-core/workflows/discuss-phase/modes/text.md +1 -1
  279. package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +1 -3
  280. package/gsd-core/workflows/discuss-phase-assumptions.md +4 -3
  281. package/gsd-core/workflows/discuss-phase.md +1 -1
  282. package/gsd-core/workflows/do.md +3 -6
  283. package/gsd-core/workflows/docs-update.md +5 -4
  284. package/gsd-core/workflows/edit-phase.md +27 -2
  285. package/gsd-core/workflows/eval-review.md +7 -14
  286. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +1 -1
  287. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +142 -15
  288. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +1 -1
  289. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +1 -1
  290. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +77 -0
  291. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +24 -4
  292. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +2 -2
  293. package/gsd-core/workflows/execute-phase/steps/protected-branch.md +21 -0
  294. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +2 -2
  295. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +39 -0
  296. package/gsd-core/workflows/execute-phase.md +72 -100
  297. package/gsd-core/workflows/execute-plan.md +52 -15
  298. package/gsd-core/workflows/explore.md +131 -4
  299. package/gsd-core/workflows/extract-learnings.md +1 -1
  300. package/gsd-core/workflows/fast.md +10 -2
  301. package/gsd-core/workflows/forensics.md +1 -1
  302. package/gsd-core/workflows/graduation.md +5 -5
  303. package/gsd-core/workflows/health.md +76 -10
  304. package/gsd-core/workflows/import.md +18 -15
  305. package/gsd-core/workflows/inbox.md +4 -5
  306. package/gsd-core/workflows/ingest-docs.md +49 -16
  307. package/gsd-core/workflows/insert-phase.md +5 -5
  308. package/gsd-core/workflows/list-seeds.md +5 -3
  309. package/gsd-core/workflows/list-workspaces.md +1 -1
  310. package/gsd-core/workflows/manager.md +12 -23
  311. package/gsd-core/workflows/map-codebase.md +1 -1
  312. package/gsd-core/workflows/milestone-summary.md +1 -1
  313. package/gsd-core/workflows/mvp-phase.md +8 -5
  314. package/gsd-core/workflows/new-milestone.md +22 -29
  315. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
  316. package/gsd-core/workflows/new-project.md +26 -40
  317. package/gsd-core/workflows/new-workspace.md +1 -1
  318. package/gsd-core/workflows/next.md +14 -2
  319. package/gsd-core/workflows/pause-work.md +1 -1
  320. package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +1 -1
  321. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +1 -1
  322. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +2 -4
  323. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +3 -3
  324. package/gsd-core/workflows/plan-phase.md +162 -59
  325. package/gsd-core/workflows/plan-review-convergence.md +96 -11
  326. package/gsd-core/workflows/plant-seed.md +2 -2
  327. package/gsd-core/workflows/pr-branch.md +187 -51
  328. package/gsd-core/workflows/profile-user.md +16 -14
  329. package/gsd-core/workflows/progress.md +61 -18
  330. package/gsd-core/workflows/quick/steps/discussion-phase.md +1 -3
  331. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +5 -7
  332. package/gsd-core/workflows/quick/steps/quick-verification.md +28 -9
  333. package/gsd-core/workflows/quick/steps/research-phase.md +4 -6
  334. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +3 -3
  335. package/gsd-core/workflows/quick.md +55 -44
  336. package/gsd-core/workflows/remove-phase.md +4 -4
  337. package/gsd-core/workflows/remove-workspace.md +2 -2
  338. package/gsd-core/workflows/resume-project.md +8 -12
  339. package/gsd-core/workflows/review.md +219 -20
  340. package/gsd-core/workflows/scan.md +1 -1
  341. package/gsd-core/workflows/secure-phase.md +3 -3
  342. package/gsd-core/workflows/session-report.md +2 -1
  343. package/gsd-core/workflows/settings-advanced.md +7 -9
  344. package/gsd-core/workflows/settings-integrations.md +64 -31
  345. package/gsd-core/workflows/settings.md +69 -7
  346. package/gsd-core/workflows/ship.md +116 -50
  347. package/gsd-core/workflows/sketch-wrap-up.md +11 -17
  348. package/gsd-core/workflows/sketch.md +12 -18
  349. package/gsd-core/workflows/smart-entry.md +3 -5
  350. package/gsd-core/workflows/spec-phase.md +53 -13
  351. package/gsd-core/workflows/spike-wrap-up.md +7 -11
  352. package/gsd-core/workflows/spike.md +20 -31
  353. package/gsd-core/workflows/stats.md +2 -2
  354. package/gsd-core/workflows/sync-skills.md +64 -9
  355. package/gsd-core/workflows/thread.md +11 -7
  356. package/gsd-core/workflows/transition.md +49 -14
  357. package/gsd-core/workflows/ui-phase.md +15 -21
  358. package/gsd-core/workflows/ui-review.md +8 -12
  359. package/gsd-core/workflows/ultraplan-phase.md +5 -13
  360. package/gsd-core/workflows/undo.md +8 -16
  361. package/gsd-core/workflows/update.md +7 -11
  362. package/gsd-core/workflows/validate-phase.md +3 -3
  363. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +25 -1
  364. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
  365. package/gsd-core/workflows/verify-work.md +66 -25
  366. package/hooks/dist/gsd-agent-isolation-guard.js +158 -30
  367. package/hooks/dist/gsd-check-update-worker.js +56 -13
  368. package/hooks/dist/gsd-check-update.js +19 -1
  369. package/hooks/dist/gsd-config-reload.js +18 -12
  370. package/hooks/dist/gsd-context-monitor.js +19 -10
  371. package/hooks/dist/gsd-cursor-post-tool.js +3 -1
  372. package/hooks/dist/gsd-cursor-pre-tool.js +2 -3
  373. package/hooks/dist/gsd-cursor-session-start.js +2 -1
  374. package/hooks/dist/gsd-cursor-stop.js +2 -1
  375. package/hooks/dist/gsd-cursor-subagent-start.js +83 -3
  376. package/hooks/dist/gsd-cursor-subagent-stop.js +6 -3
  377. package/hooks/dist/gsd-ensure-canonical-path.js +2 -1
  378. package/hooks/dist/gsd-graphify-update.sh +22 -18
  379. package/hooks/dist/gsd-node-runner.sh +76 -0
  380. package/hooks/dist/gsd-phase-boundary.sh +1 -0
  381. package/hooks/dist/gsd-prompt-guard.js +37 -27
  382. package/hooks/dist/gsd-read-guard.js +16 -7
  383. package/hooks/dist/gsd-read-injection-scanner.js +55 -32
  384. package/hooks/dist/gsd-session-state.sh +1 -0
  385. package/hooks/dist/gsd-statusline.js +231 -24
  386. package/hooks/dist/gsd-update-banner.js +22 -1
  387. package/hooks/dist/gsd-validate-commit.sh +80 -6
  388. package/hooks/dist/gsd-windsurf-pre-command.js +16 -11
  389. package/hooks/dist/gsd-windsurf-pre-write.js +22 -13
  390. package/hooks/dist/gsd-workflow-guard.js +162 -46
  391. package/hooks/dist/gsd-worktree-path-guard.js +36 -21
  392. package/hooks/dist/gsd-write-guard.js +35 -25
  393. package/hooks/dist/lib/cli-exit.js +560 -0
  394. package/hooks/dist/lib/exit-code-registry.js +98 -0
  395. package/hooks/dist/lib/git-cmd.js +92 -59
  396. package/hooks/dist/lib/git-probe.js +84 -0
  397. package/hooks/dist/lib/hook-exit.js +81 -0
  398. package/hooks/dist/lib/injection-patterns.js +45 -0
  399. package/hooks/dist/lib/isolation-deny-reason.js +39 -0
  400. package/hooks/dist/lib/isolation-sentinel.js +9 -0
  401. package/hooks/dist/managed-hooks-registry.cjs +3 -0
  402. package/hooks/gsd-agent-isolation-guard.js +158 -30
  403. package/hooks/gsd-check-update-worker.js +56 -13
  404. package/hooks/gsd-check-update.js +19 -1
  405. package/hooks/gsd-config-reload.js +18 -12
  406. package/hooks/gsd-context-monitor.js +19 -10
  407. package/hooks/gsd-cursor-post-tool.js +3 -1
  408. package/hooks/gsd-cursor-pre-tool.js +2 -3
  409. package/hooks/gsd-cursor-session-start.js +2 -1
  410. package/hooks/gsd-cursor-stop.js +2 -1
  411. package/hooks/gsd-cursor-subagent-start.js +83 -3
  412. package/hooks/gsd-cursor-subagent-stop.js +6 -3
  413. package/hooks/gsd-ensure-canonical-path.js +2 -1
  414. package/hooks/gsd-graphify-update.sh +22 -18
  415. package/hooks/gsd-node-runner.sh +76 -0
  416. package/hooks/gsd-phase-boundary.sh +1 -0
  417. package/hooks/gsd-prompt-guard.js +37 -27
  418. package/hooks/gsd-read-guard.js +16 -7
  419. package/hooks/gsd-read-injection-scanner.js +55 -32
  420. package/hooks/gsd-session-state.sh +1 -0
  421. package/hooks/gsd-statusline.js +231 -24
  422. package/hooks/gsd-update-banner.js +22 -1
  423. package/hooks/gsd-validate-commit.sh +80 -6
  424. package/hooks/gsd-windsurf-pre-command.js +16 -11
  425. package/hooks/gsd-windsurf-pre-write.js +22 -13
  426. package/hooks/gsd-workflow-guard.js +162 -46
  427. package/hooks/gsd-worktree-path-guard.js +36 -21
  428. package/hooks/gsd-write-guard.js +35 -25
  429. package/hooks/lib/cli-exit.js +560 -0
  430. package/hooks/lib/exit-code-registry.js +98 -0
  431. package/hooks/lib/git-cmd.js +92 -59
  432. package/hooks/lib/git-probe.js +84 -0
  433. package/hooks/lib/hook-exit.js +81 -0
  434. package/hooks/lib/injection-patterns.js +45 -0
  435. package/hooks/lib/isolation-deny-reason.js +39 -0
  436. package/hooks/lib/isolation-sentinel.js +9 -0
  437. package/hooks/managed-hooks-registry.cjs +3 -0
  438. package/package.json +28 -11
  439. package/pi/gsd.cjs +19 -5
  440. package/scripts/base64-scan.sh +74 -12
  441. package/scripts/baselines/planning-prompt-drift-baseline.json +4 -0
  442. package/scripts/baselines/planning-snapshot-bypass-baseline.json +12 -0
  443. package/scripts/baselines/unreachable-guard-drift-baseline.json +4 -0
  444. package/scripts/build-hooks.js +5 -0
  445. package/scripts/changeset/lint.cjs +60 -5
  446. package/scripts/check-alias-drift.cjs +7 -43
  447. package/scripts/check-contract-drift.cjs +297 -0
  448. package/scripts/check-glossary-refs.cjs +77 -15
  449. package/scripts/check-mutation-score-ratchet.cjs +156 -0
  450. package/scripts/ci-check-job-near-cap.cjs +49 -0
  451. package/scripts/ci-pr-mergeability.cjs +262 -0
  452. package/scripts/ci-test-scope.cjs +64 -14
  453. package/scripts/ci-timeout-report.cjs +230 -0
  454. package/scripts/command-contract-helpers.cjs +903 -1
  455. package/scripts/docs-guard-registry.cjs +396 -0
  456. package/scripts/gen-adr-index.cjs +728 -38
  457. package/scripts/gen-capability-registry.cjs +11 -21
  458. package/scripts/gen-context-index.cjs +2 -11
  459. package/scripts/gen-exit-code-docs.cjs +318 -0
  460. package/scripts/gen-exit-code-registry.cjs +891 -0
  461. package/scripts/gen-features.cjs +836 -0
  462. package/scripts/gen-health-docs.cjs +390 -0
  463. package/scripts/gen-hooks-cli-exit.cjs +239 -0
  464. package/scripts/gen-install-tree-fixtures.cjs +2 -2
  465. package/scripts/gen-inventory-manifest.cjs +50 -4
  466. package/scripts/gen-loop-host-contract.cjs +138 -25
  467. package/scripts/gen-registry.cjs +3 -14
  468. package/scripts/gen-scripts-cli-exit.cjs +185 -0
  469. package/scripts/gen-state-md-docs.cjs +727 -0
  470. package/scripts/{test-failure-reasons.cjs → gsd-test-gate-reasons.cjs} +6 -0
  471. package/scripts/lib/alias-drift-families.cjs +46 -0
  472. package/scripts/lib/ci-job-timing.cjs +72 -0
  473. package/scripts/lib/cli-exit.cjs +546 -44
  474. package/scripts/lib/drift-scan.cjs +308 -0
  475. package/scripts/lib/exit-code-registry.cjs +98 -0
  476. package/scripts/lib/ndjson-reporter.cjs +119 -0
  477. package/scripts/lint-allow-test-rule-refs.allowlist.json +1 -26
  478. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +4 -0
  479. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +3 -0
  480. package/scripts/lint-canary-version-leak.cjs +73 -0
  481. package/scripts/lint-command-contract.cjs +96 -13
  482. package/scripts/lint-completion-predicate-drift.cjs +933 -0
  483. package/scripts/lint-completion-ratio-drift.cjs +214 -0
  484. package/scripts/lint-default-flip-documentation.cjs +193 -0
  485. package/scripts/lint-docs-guard-registration.cjs +495 -0
  486. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +193 -0
  487. package/scripts/lint-eslint-glob-coverage.allowlist.json +38 -0
  488. package/scripts/lint-eslint-glob-coverage.cjs +340 -0
  489. package/scripts/{lint-fix-has-regression-test.cjs → lint-fix-has-regression-tests.cjs} +12 -6
  490. package/scripts/lint-frontmatter-scalar-broad-grep.cjs +237 -0
  491. package/scripts/lint-health-diagnostic-rule-table.cjs +461 -0
  492. package/scripts/lint-hooks-runtime-build-seam.cjs +262 -0
  493. package/scripts/lint-milestone-window-drift.cjs +468 -0
  494. package/scripts/lint-mutation-test-derivation-drift.cjs +86 -0
  495. package/scripts/lint-phase-enumeration-drift.cjs +492 -0
  496. package/scripts/lint-plan-count-drift.cjs +318 -0
  497. package/scripts/lint-planning-artifact-writer-drift.cjs +398 -0
  498. package/scripts/lint-planning-prompt-drift.cjs +471 -0
  499. package/scripts/lint-planning-snapshot-bypass-drift.cjs +544 -0
  500. package/scripts/lint-regression-test-names.cjs +15 -13
  501. package/scripts/lint-removed-but-needed.cjs +488 -0
  502. package/scripts/lint-seam-enforcement.cjs +182 -0
  503. package/scripts/lint-slug-derivation-drift.cjs +921 -0
  504. package/scripts/lint-source-test-name-collision.cjs +241 -0
  505. package/scripts/lint-state-field-drift.cjs +805 -0
  506. package/scripts/lint-state-write-path-drift.cjs +950 -0
  507. package/scripts/lint-test-file-count.allowlist.json +137 -8
  508. package/scripts/lint-test-file-count.cjs +25 -3
  509. package/scripts/lint-unreachable-guard-drift.cjs +830 -0
  510. package/scripts/lint-vendored-deps.cjs +297 -0
  511. package/scripts/mutation-matrix.cjs +599 -50
  512. package/scripts/pr-changed-files.cjs +63 -0
  513. package/scripts/pr-template-policy.cjs +14 -4
  514. package/scripts/prompt-injection-scan.sh +100 -14
  515. package/scripts/require-issue-link-policy.cjs +192 -0
  516. package/scripts/secret-scan.sh +75 -13
  517. package/scripts/select-docs-guards.cjs +56 -0
  518. package/scripts/sync-runtime-launcher.cjs +24 -7
  519. package/skills/gsd-autonomous/SKILL.md +0 -1
  520. package/skills/gsd-code-review/SKILL.md +1 -1
  521. package/skills/gsd-discuss-phase/SKILL.md +1 -1
  522. package/skills/gsd-execute-phase/SKILL.md +1 -2
  523. package/skills/gsd-import/SKILL.md +1 -1
  524. package/skills/gsd-map-codebase/SKILL.md +1 -1
  525. package/skills/gsd-mempalace-capture/SKILL.md +1 -1
  526. package/skills/gsd-mempalace-recall/SKILL.md +1 -1
  527. package/skills/gsd-new-milestone/SKILL.md +1 -1
  528. package/skills/gsd-next/SKILL.md +0 -1
  529. package/skills/gsd-plan-phase/SKILL.md +0 -1
  530. package/skills/gsd-progress/SKILL.md +0 -1
  531. package/skills/gsd-quick/SKILL.md +9 -5
  532. package/skills/gsd-review-backlog/SKILL.md +2 -1
  533. package/skills/gsd-stats/SKILL.md +0 -1
  534. package/skills/gsd-verify-work/SKILL.md +1 -1
  535. package/vscode/package.json +1 -1
  536. package/bin/lib/ui-safety-gate.cjs +0 -107
  537. package/gsd-core/workflows/discovery-phase.md +0 -298
  538. package/gsd-core/workflows/plan-milestone-gaps.md +0 -281
  539. package/gsd-core/workflows/verify-phase.md +0 -574
  540. package/scripts/affected-tests-lib.cjs +0 -554
  541. package/scripts/lint-allow-test-rule-refs.cjs +0 -162
  542. package/scripts/lint-emitted-drift-ack.cjs +0 -344
  543. package/scripts/run-affected-tests.cjs +0 -7
  544. package/scripts/run-tests.cjs +0 -1051
@@ -43,6 +43,10 @@ const node_fs_1 = __importDefault(require("node:fs"));
43
43
  const node_path_1 = __importDefault(require("node:path"));
44
44
  const node_child_process_1 = require("node:child_process");
45
45
  const markdown_sectionizer_cjs_1 = require("./markdown-sectionizer.cjs");
46
+ // #3696: the calendar-validity predicate moved to the STATE.md document module
47
+ // so `state validate` can assert the same `last_activity` invariant this reader
48
+ // already enforces (ADR-227). Two copies would let the two surfaces disagree
49
+ // about whether a STATE.md is usable — which is the defect #3696 reports.
46
50
  // eslint-disable-next-line @typescript-eslint/no-require-imports
47
51
  const ioMod = require("./io.cjs");
48
52
  const { output } = ioMod;
@@ -57,10 +61,13 @@ const phaseLifecycle = require("./phase-lifecycle.cjs");
57
61
  const { deriveProgressFromRoadmap } = phaseLifecycle;
58
62
  // eslint-disable-next-line @typescript-eslint/no-require-imports
59
63
  const stateDocument = require("./state-document.cjs");
60
- const { stateExtractField } = stateDocument;
64
+ const { stateFieldValue } = stateDocument;
61
65
  // eslint-disable-next-line @typescript-eslint/no-require-imports
62
66
  const phaseId = require("./phase-id.cjs");
63
- const { comparePhaseNum, extractPhaseToken, normalizePhaseName, phaseTokenMatches } = phaseId;
67
+ const { comparePhaseNum, extractPhaseToken, matchPhaseDirs, normalizePhaseName, stripProjectCodePrefix } = phaseId;
68
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
69
+ const stateMod = require("./state.cjs");
70
+ const { readStateHeadFreshness } = stateMod;
64
71
  // eslint-disable-next-line @typescript-eslint/no-require-imports
65
72
  const unusableInput = require("./unusable-input.cjs");
66
73
  const { warnUnusableInput, UNUSABLE_REASON } = unusableInput;
@@ -86,15 +93,6 @@ exports.SITUATIONS = Object.freeze([
86
93
  'unknown',
87
94
  ]);
88
95
  // ─── Detection ─────────────────────────────────────────────────────────────────
89
- /** Frontmatter scalar helper: prefer YAML frontmatter, fall back to body field. */
90
- function fmScalar(fm, body, key, bodyField) {
91
- const v = fm[key];
92
- if (typeof v === 'string' && v.trim())
93
- return v.trim();
94
- if (typeof v === 'number' || typeof v === 'boolean')
95
- return String(v);
96
- return stateExtractField(body, bodyField);
97
- }
98
96
  /** Read a scalar value from a nested frontmatter object (e.g. progress.total_phases). */
99
97
  function fmScalarKey(obj, key) {
100
98
  if (!obj || typeof obj !== 'object')
@@ -115,17 +113,95 @@ function parseIntOrNull(s) {
115
113
  }
116
114
  function phaseTokenFromDirName(name) {
117
115
  const token = extractPhaseToken(name);
118
- return /^\d+(?:[A-Z])?(?:\.\d+)*(?:-|$)/i.test(token) ? token : null;
116
+ // #2528: the shape probe runs on the PROJECT-CODE-STRIPPED token. A prefixed
117
+ // directory tokenizes to `MEM-05-80-20`, which does not start with a digit,
118
+ // so the unstripped probe rejected it and the entry was dropped before any
119
+ // resolution ran — every phase in a project-coded plan was invisible here.
120
+ // The full token is still what is returned: `comparePhaseNum` strips the
121
+ // prefix itself, so the sort is unaffected, and `matchPhaseDirs` needs the
122
+ // real directory name.
123
+ const probe = stripProjectCodePrefix(token);
124
+ return /^\d+(?:[A-Z])?(?:\.\d+)*(?:-|$)/i.test(probe) ? token : null;
119
125
  }
120
126
  /**
121
127
  * Parse a `last_activity` value that may be an ISO date or a free-form string
122
128
  * into an epoch-ms timestamp. Returns null when unparseable.
129
+ *
130
+ * #2570: `last_activity` routinely carries a trailing " — <description>" — the
131
+ * shape `templates/state.md` itself prescribes (`Last activity: [YYYY-MM-DD] —
132
+ * [What happened]`), which gsd-core's own STATE.md mirrors into frontmatter.
133
+ * `Date.parse` on the whole string returns NaN, and because `staleActivity`
134
+ * treats null as "not stale" (fails open), the ONLY idle/staleness detector
135
+ * never fired on any project whose last_activity retained its description.
136
+ * Be liberal in what we accept (Postel): read the leading ISO date/time token
137
+ * when the value carries one, so the description suffix — whatever separator
138
+ * (em dash or hyphen) it uses — no longer silently blinds the detector; fall
139
+ * back to a whole-string parse for any other shape a hand edit might use.
140
+ */
141
+ /** Leading ISO date, with an optional time-of-day and offset. */
142
+ const ISO_LEADING_RE = /^(\d{4})-(\d{2})-(\d{2})((?:[T ]\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:?\d{2})?)?)/;
143
+ /**
144
+ * A NAMED timezone designator at the start of the un-reconstructable remainder
145
+ * (#2571). ISO_LEADING_RE's offset group captures only `Z` / `±HH:MM`, so a
146
+ * named zone (GMT, EST, ...) is not in the leading token — it sits here.
147
+ * Reconstructing the token without it would let Date.parse read the time as
148
+ * LOCAL, shifting the instant by the host's offset (a wrong, host-dependent
149
+ * value), so a zone-shaped remainder must fail open (ADR-227).
150
+ *
151
+ * The shape is a short all-caps run (2–5 letters) that stands alone — the
152
+ * negative lookahead excludes the first letter of a Capitalised word like
153
+ * "Milestone", and an optional trailing offset is subsumed because the leading
154
+ * all-caps run already matches. Everything else — a lowercase or Capitalised
155
+ * description, a separator — is describable text and is reconstructed from the
156
+ * leading date.
157
+ *
158
+ * Consulted ONLY when the leading token captured a time-of-day (see the caller):
159
+ * a zone designator qualifies a clock time, so a BARE date can carry no zone
160
+ * hazard — reconstructing it is always just that date's UTC midnight, whatever
161
+ * trails it. Gating on the time keeps a description that merely opens with a
162
+ * tech acronym ("2026-06-08 CI green", "API refactor") on the reconstruct path
163
+ * instead of failing open. The prior "any letter" guard was too liberal — it
164
+ * failed open on every letter-led description and re-opened #2570.
123
165
  */
166
+ const ZONE_DESIGNATOR_RE = /^\s*[A-Z]{2,5}(?![A-Za-z])/;
124
167
  function parseActivityTimestamp(raw) {
125
168
  if (!raw)
126
169
  return null;
127
- const ms = Date.parse(raw);
128
- return Number.isNaN(ms) ? null : ms;
170
+ const trimmed = raw.trim();
171
+ const iso = trimmed.match(ISO_LEADING_RE);
172
+ if (iso) {
173
+ const [, year, month, day, time] = iso;
174
+ // Reject an impossible calendar date outright rather than letting
175
+ // Date.parse substitute a rolled-forward one. null = "no activity signal",
176
+ // the safe default staleActivity already fails open on.
177
+ if (!stateDocument.isRealCalendarDate(Number(year), Number(month), Number(day)))
178
+ return null;
179
+ // The date is real, so stay as liberal as before (Postel): a whole-string
180
+ // parse still wins when the engine can make sense of the value. Reading the
181
+ // token first would silently DROP a trailing zone name -- "2026-06-08
182
+ // 12:34:56 GMT" parses whole as 12:34:56Z but as local time from the token,
183
+ // shifting the instant by the host's UTC offset.
184
+ const whole = Date.parse(trimmed);
185
+ if (!Number.isNaN(whole))
186
+ return whole;
187
+ // Whole-string failed: the value carries a suffix the engine can't read as
188
+ // one instant (#2570). Reconstruct from the leading token UNLESS the remainder
189
+ // is a named zone the token dropped (GMT, EST, ...): reconstructing without it
190
+ // reads the time as LOCAL and shifts the instant by the host's offset, so a
191
+ // zone-shaped remainder fails open (ADR-227: never propagate a wrong instant;
192
+ // null is the base's not-stale default). An ordinary description -- the #2570
193
+ // template's " -- description", or a hand edit's bare-space/tab/colon suffix --
194
+ // carries no zone and IS reconstructed. See ZONE_DESIGNATOR_RE for the shape;
195
+ // the earlier "any letter" guard failed open on every description and re-opened
196
+ // #2570 for whitespace-separated suffixes.
197
+ const rest = trimmed.slice(iso[0].length);
198
+ if (time && ZONE_DESIGNATOR_RE.test(rest))
199
+ return null;
200
+ const ms = Date.parse(`${year}-${month}-${day}${time}`);
201
+ return Number.isNaN(ms) ? null : ms;
202
+ }
203
+ const direct = Date.parse(trimmed);
204
+ return Number.isNaN(direct) ? null : direct;
129
205
  }
130
206
  /** Read-only git signals. Any git error is swallowed → "no git signal". */
131
207
  function readGitSignals(cwd) {
@@ -137,6 +213,7 @@ function readGitSignals(cwd) {
137
213
  maxBuffer: 4 * 1024 * 1024,
138
214
  windowsHide: true,
139
215
  stdio: ['pipe', 'pipe', 'pipe'],
216
+ timeout: 10_000,
140
217
  });
141
218
  }
142
219
  catch {
@@ -186,7 +263,16 @@ function detectVerifyFailed(cwd, currentPhaseRaw) {
186
263
  let targetDir;
187
264
  if (phaseToken) {
188
265
  const normalized = normalizePhaseName(phaseToken);
189
- targetDir = entries.find((name) => phaseTokenMatches(name, normalized));
266
+ // #2528: the fourth directory-resolution site, and the one where a miss is
267
+ // silent — a phase whose directory cannot be found reports "not failed",
268
+ // which reads identically to a healthy phase. It must therefore apply the
269
+ // same canonical selection as the locator and the two command scans, or a
270
+ // dir like `05-80-20-cleanup` (phase 5 named "80/20 Cleanup") never
271
+ // surfaces its own failed verification. `entries` is already sorted, and
272
+ // `matchPhaseDirs` filters without reordering, so taking the first match
273
+ // preserves the previous `.find()` selection exactly.
274
+ const { matches } = matchPhaseDirs(entries, normalized);
275
+ targetDir = matches[0];
190
276
  if (!targetDir)
191
277
  return false;
192
278
  }
@@ -253,6 +339,9 @@ function detectSignals(cwd, now = Date.now) {
253
339
  stale_activity: false,
254
340
  roadmap_total_phases: null,
255
341
  roadmap_completed_phases: null,
342
+ // No STATE.md (or unreadable) → no stamp to compare. Unknown, not fresh.
343
+ state_commits_behind: null,
344
+ state_commit_stale: null,
256
345
  };
257
346
  if (!hasPlanning)
258
347
  return empty;
@@ -266,21 +355,29 @@ function detectSignals(cwd, now = Date.now) {
266
355
  // - body prose: `Phase: 3`, `**Status:** verifying`, `Total Phases: 5`
267
356
  // Read each field across every form, scalar-first then nested then body, so
268
357
  // the classifier works on real STATE.md files written by current GSD.
269
- const statusRaw = fmScalar(fm, body, 'status', 'Status');
270
- const pausedAtRaw = fmScalar(fm, body, 'paused_at', 'Paused At');
271
- const lastActivityRaw = fmScalar(fm, body, 'last_activity', 'Last Activity');
358
+ const statusRaw = stateFieldValue(fm, body, 'status', 'Status').value;
359
+ const pausedAtRaw = stateFieldValue(fm, body, 'paused_at', 'Paused At').value;
360
+ const lastActivityRaw = stateFieldValue(fm, body, 'last_activity', 'Last Activity').value;
272
361
  // current_phase: scalar fm → nested (none) → body "Current Phase" → body "Phase".
273
362
  // The body `Phase:` field is the canonical location in prose-form STATE.md
274
363
  // (e.g. "Phase: 3" or "Phase: 3 — ui-review"); parse the leading number.
275
- const currentPhaseRaw = fmScalar(fm, body, 'current_phase', 'Current Phase') ??
276
- stateExtractField(body, 'Phase');
364
+ // #3187 / ADR-3180 Amendment 3 ("0.x split"): this read is DELIBERATELY
365
+ // unscoped — smart-entry classifies `gsd next` routing over the whole body,
366
+ // whereas state.cts's copies of this same field scope it to `## Current
367
+ // Position` (#1776/#2956). Those are two different questions sharing a
368
+ // name; folding the scoped read in here would silently change smart-entry's
369
+ // routing, an undisclosed Tier-2 change (design's Rejected #3). Both owner
370
+ // calls below intentionally pass the unscoped `body`, never a Current-
371
+ // Position slice.
372
+ const currentPhaseRaw = stateFieldValue(fm, body, 'current_phase', 'Current Phase').value ??
373
+ stateFieldValue(fm, body, null, 'Phase').value;
277
374
  // total_phases & percent: nested `progress:` object takes precedence in the
278
375
  // nested schema; scalar fm / body fields cover the flat schema.
279
376
  const progressFm = typeof fm.progress === 'object' ? fm.progress : null;
280
377
  const totalPhasesRaw = fmScalarKey(progressFm, 'total_phases') ??
281
- fmScalar(fm, body, 'total_phases', 'Total Phases');
378
+ stateFieldValue(fm, body, 'total_phases', 'Total Phases').value;
282
379
  const progressRaw = fmScalarKey(progressFm, 'percent') ??
283
- fmScalar(fm, body, 'progress', 'Progress');
380
+ stateFieldValue(fm, body, 'progress', 'Progress').value;
284
381
  // Blockers list: `- <text>` items under a `## Blockers` heading.
285
382
  const blockers = [];
286
383
  const blockersSection = (0, markdown_sectionizer_cjs_1.collectSection)(body, (h) => h.level === 2 && h.text.trim().toLowerCase() === 'blockers', { levelBounded: true });
@@ -326,6 +423,11 @@ function detectSignals(cwd, now = Date.now) {
326
423
  /* ROADMAP.md unreadable — leave null; isComplete falls back to legacy. */
327
424
  }
328
425
  }
426
+ // #2573: commit-age freshness proxy. Derived through state.cjs's
427
+ // readStateHeadFreshness so the tri-state and the hash fence stay identical
428
+ // to validate.health's W024 — one derivation, two surfaces.
429
+ const stateHeadRaw = stateFieldValue(fm, body, 'state_head', 'State Head').value;
430
+ const freshness = readStateHeadFreshness(cwd, stateHeadRaw);
329
431
  return {
330
432
  current_phase: parseIntOrNull(currentPhaseRaw),
331
433
  total_phases: parseIntOrNull(totalPhasesRaw),
@@ -342,6 +444,8 @@ function detectSignals(cwd, now = Date.now) {
342
444
  stale_activity: staleActivity,
343
445
  roadmap_total_phases: roadmapTotalPhases,
344
446
  roadmap_completed_phases: roadmapCompletedPhases,
447
+ state_commits_behind: freshness.commits_behind,
448
+ state_commit_stale: freshness.commit_stale,
345
449
  };
346
450
  }
347
451
  // ─── Situation classification ─────────────────────────────────────────────────
@@ -422,7 +526,13 @@ function classify(s) {
422
526
  return 'planning';
423
527
  if (/\bexecut(e|ing)|active|in.progress|building\b/i.test(s.status))
424
528
  return 'executing';
425
- if (/\bverify|review|needs.review|pending.review\b/i.test(s.status))
529
+ // #3864: `verif` (not `verify`) — the same stem state-document's
530
+ // normalizeStateStatus matches. "verified" and "verification" contain no
531
+ // "verify" substring, so the exact word left them falling through to
532
+ // `unknown` (or idle-stranded on a clean unpushed tree — differently
533
+ // wrong). verify_failed is tested above, so a failed verification still
534
+ // wins over this branch.
535
+ if (/\bverif|review|needs.review|pending.review\b/i.test(s.status))
426
536
  return 'verify-pending';
427
537
  if (isIdleStranded(s))
428
538
  return 'idle-stranded';
@@ -26,6 +26,9 @@ exports.SECTION_HEADERS = void 0;
26
26
  exports.countSectionDataRows = countSectionDataRows;
27
27
  exports.specSectionStatus = specSectionStatus;
28
28
  const node_fs_1 = __importDefault(require("node:fs"));
29
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
30
+ const cliExitModule = require("./cli-exit.cjs");
31
+ const { ExitError, runMain } = cliExitModule;
29
32
  /**
30
33
  * Canonical SPEC section header matchers — the SINGLE source of truth for the headings
31
34
  * `templates/spec.md` renders. Suffix-tolerant by design: `prohibitions` matches BOTH
@@ -101,11 +104,13 @@ const VALID_KEYS = ['edges', 'prohibitions'];
101
104
  // 2 only on a usage error (missing args / bad key). `require.main === module` so it runs only when
102
105
  // the compiled `.cjs` is executed directly, never when imported by tests.
103
106
  if (require.main === module) {
104
- const specFile = process.argv[2];
105
- const key = process.argv[3];
106
- if (!specFile || !key || !VALID_KEYS.includes(key)) {
107
- process.stderr.write('usage: spec-section.cjs <specFile> <edges|prohibitions>\n');
108
- process.exit(2);
109
- }
110
- process.stdout.write(JSON.stringify(specSectionStatus(specFile, key)) + '\n');
107
+ runMain(() => {
108
+ const specFile = process.argv[2];
109
+ const key = process.argv[3];
110
+ if (!specFile || !key || !VALID_KEYS.includes(key)) {
111
+ process.stderr.write('usage: spec-section.cjs <specFile> <edges|prohibitions>\n');
112
+ throw new ExitError(2);
113
+ }
114
+ process.stdout.write(JSON.stringify(specSectionStatus(specFile, key)) + '\n');
115
+ });
111
116
  }
@@ -53,8 +53,19 @@ function routeStateCommand({ state, args, cwd, raw, error }) {
53
53
  handlers: {
54
54
  load: () => state.cmdStateLoad(cwd, raw),
55
55
  json: () => state.cmdStateJson(cwd, raw),
56
- get: () => state.cmdStateGet(cwd, args[2], raw),
57
- update: () => state.cmdStateUpdate(cwd, args[2], args[3]),
56
+ // ADR-3473 §8.4 / #3358 gap: these two read args[2]/args[3] positionally
57
+ // without ever calling parseNamedArgsOrExit, so an unrecognized flag or
58
+ // stray positional was silently dropped instead of rejected. No flags
59
+ // are declared — none are documented for these subcommands
60
+ // (docs/CLI-TOOLS.md:86,89) and no shipped workflow passes any.
61
+ get: () => {
62
+ (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { positionals: 3 }, error);
63
+ state.cmdStateGet(cwd, args[2], raw);
64
+ },
65
+ update: () => {
66
+ (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { positionals: 4 }, error);
67
+ state.cmdStateUpdate(cwd, args[2], args[3]);
68
+ },
58
69
  patch: () => {
59
70
  const patches = {};
60
71
  if (args.length === 3 && typeof args[2] === 'string' && args[2].trim().startsWith('{')) {
@@ -90,7 +101,7 @@ function routeStateCommand({ state, args, cwd, raw, error }) {
90
101
  },
91
102
  'advance-plan': () => state.cmdStateAdvancePlan(cwd, raw),
92
103
  'record-metric': () => {
93
- const a = (0, command_arg_projection_cjs_1.parseNamedArgs)(args, ['phase', 'plan', 'duration', 'tasks', 'files']);
104
+ const a = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { valueFlags: ['phase', 'plan', 'duration', 'tasks', 'files'], positionals: 2 }, error);
94
105
  state.cmdStateRecordMetric(cwd, {
95
106
  phase: strArg(a, 'phase'),
96
107
  plan: strArg(a, 'plan'),
@@ -101,7 +112,7 @@ function routeStateCommand({ state, args, cwd, raw, error }) {
101
112
  },
102
113
  'update-progress': () => state.cmdStateUpdateProgress(cwd, raw),
103
114
  'add-decision': () => {
104
- const a = (0, command_arg_projection_cjs_1.parseNamedArgs)(args, ['phase', 'summary', 'summary-file', 'rationale', 'rationale-file']);
115
+ const a = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { valueFlags: ['phase', 'summary', 'summary-file', 'rationale', 'rationale-file'], positionals: 2 }, error);
105
116
  state.cmdStateAddDecision(cwd, {
106
117
  phase: strArg(a, 'phase'),
107
118
  summary: strArg(a, 'summary'),
@@ -111,11 +122,11 @@ function routeStateCommand({ state, args, cwd, raw, error }) {
111
122
  }, raw);
112
123
  },
113
124
  'add-blocker': () => {
114
- const a = (0, command_arg_projection_cjs_1.parseNamedArgs)(args, ['text', 'text-file']);
125
+ const a = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { valueFlags: ['text', 'text-file'], positionals: 2 }, error);
115
126
  state.cmdStateAddBlocker(cwd, { text: strArg(a, 'text'), text_file: strArg(a, 'text-file') }, raw);
116
127
  },
117
128
  'add-roadmap-evolution': () => {
118
- const a = (0, command_arg_projection_cjs_1.parseNamedArgs)(args, ['phase', 'action', 'after', 'note', 'note-file'], ['urgent']);
129
+ const a = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { valueFlags: ['phase', 'action', 'after', 'note', 'note-file'], booleanFlags: ['urgent'], positionals: 2 }, error);
119
130
  state.cmdStateAddRoadmapEvolution(cwd, {
120
131
  phase: strArg(a, 'phase'),
121
132
  action: strArg(a, 'action'),
@@ -125,47 +136,69 @@ function routeStateCommand({ state, args, cwd, raw, error }) {
125
136
  urgent: a['urgent'] === true,
126
137
  }, raw);
127
138
  },
128
- 'resolve-blocker': () => state.cmdStateResolveBlocker(cwd, strArg((0, command_arg_projection_cjs_1.parseNamedArgs)(args, ['text']), 'text'), raw),
139
+ 'resolve-blocker': () => state.cmdStateResolveBlocker(cwd, strArg((0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { valueFlags: ['text'], positionals: 2 }, error), 'text'), raw),
129
140
  'record-session': () => {
130
- const a = (0, command_arg_projection_cjs_1.parseNamedArgs)(args, ['stopped-at', 'resume-file']);
141
+ const a = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { valueFlags: ['stopped-at', 'resume-file'], positionals: 2 }, error);
131
142
  // Pass resume_file as-is (undefined when --resume-file was not provided) so
132
143
  // cmdStateRecordSession can distinguish "caller explicitly passed a value" from
133
144
  // "option was not supplied" and apply the template-default-only replacement guard.
134
145
  state.cmdStateRecordSession(cwd, { stopped_at: strArg(a, 'stopped-at'), resume_file: strArg(a, 'resume-file') }, raw);
135
146
  },
136
147
  'begin-phase': () => {
137
- const a = (0, command_arg_projection_cjs_1.parseNamedArgs)(args, ['phase', 'name', 'plans']);
148
+ const a = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { valueFlags: ['phase', 'name', 'plans'], positionals: 2 }, error);
138
149
  state.cmdStateBeginPhase(cwd, strArg(a, 'phase'), strArg(a, 'name'), parsePlans(strArg(a, 'plans')), raw);
139
150
  },
140
151
  'signal-waiting': () => {
141
- const a = (0, command_arg_projection_cjs_1.parseNamedArgs)(args, ['type', 'question', 'options', 'phase']);
152
+ const a = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { valueFlags: ['type', 'question', 'options', 'phase'], positionals: 2 }, error);
142
153
  state.cmdSignalWaiting(cwd, strArg(a, 'type'), strArg(a, 'question'), strArg(a, 'options'), strArg(a, 'phase'), raw);
143
154
  },
144
155
  'signal-resume': () => state.cmdSignalResume(cwd, raw),
145
156
  'planned-phase': () => {
146
- const a = (0, command_arg_projection_cjs_1.parseNamedArgs)(args, ['phase', 'name', 'plans']);
147
- state.cmdStatePlannedPhase(cwd, strArg(a, 'phase'), parsePlans(strArg(a, 'plans')), raw);
157
+ const a = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { valueFlags: ['phase', 'name', 'plans'], positionals: 2 }, error);
158
+ // #3395: --name was parsed here but never forwarded (the StateModule
159
+ // signature had no channel for it), so the argument was silently
160
+ // dropped. It now persists into the Current Position `Phase:` line and
161
+ // the authoritative current_phase_name, mirroring begin-phase.
162
+ state.cmdStatePlannedPhase(cwd, strArg(a, 'phase'), strArg(a, 'name'), parsePlans(strArg(a, 'plans')), raw);
163
+ },
164
+ validate: () => {
165
+ // #3696: --strict makes the verdict gateable by exit status. The
166
+ // default stays exit 0 — the exit code is Tier-2 observable output
167
+ // reaching unenumerable downstream consumers (ADR-3180 Decision 3).
168
+ const a = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { booleanFlags: ['strict'], positionals: 2 }, error);
169
+ state.cmdStateValidate(cwd, raw, { strict: a['strict'] === true });
148
170
  },
149
- validate: () => state.cmdStateValidate(cwd, raw),
150
171
  sync: () => {
151
- const a = (0, command_arg_projection_cjs_1.parseNamedArgs)(args, [], ['verify']);
172
+ const a = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { booleanFlags: ['verify'], positionals: 2 }, error);
152
173
  state.cmdStateSync(cwd, { verify: a['verify'] }, raw);
153
174
  },
154
175
  prune: () => {
155
- const a = (0, command_arg_projection_cjs_1.parseNamedArgs)(args, ['keep-recent'], ['dry-run']);
176
+ const a = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { valueFlags: ['keep-recent'], booleanFlags: ['dry-run'], positionals: 2 }, error);
156
177
  state.cmdStatePrune(cwd, { keepRecent: strArg(a, 'keep-recent') || '3', dryRun: a['dry-run'] === true }, raw);
157
178
  },
158
179
  rebuild: () => {
159
- const a = (0, command_arg_projection_cjs_1.parseNamedArgs)(args, [], ['dry-run', 'verbose']);
180
+ const a = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { booleanFlags: ['dry-run', 'verbose'], positionals: 2 }, error);
160
181
  state.cmdStateRebuild(cwd, { dryRun: a['dry-run'] === true, verbose: a['verbose'] === true }, raw);
161
182
  },
162
- // complete-phase: CJS-only — no SDK counterpart.
183
+ // complete-phase: CJS-only — no SDK counterpart. Supports two shapes:
184
+ // the documented `--phase N` flag (docs/COMMANDS.md:2207) and an
185
+ // undocumented-but-preserved bare positional `state complete-phase N`
186
+ // (N3). A single static `positionals` count cannot represent both: if
187
+ // args[2] is the flag `--phase`, the boundary must be 2 so the generic
188
+ // flag/value walk (which starts at the boundary) recognizes `--phase`
189
+ // and consumes its value; only when args[2] is itself a bare, non-flag
190
+ // token does the boundary widen to 3 to accept it as the positional
191
+ // phase. Getting this wrong either breaks the documented flag form
192
+ // (boundary 3 treats `--phase`'s value as an unexpected trailing
193
+ // positional) or silently re-admits unknown flags (a static boundary
194
+ // of 3 with an empty args[2] never validates anything past it).
163
195
  'complete-phase': () => {
164
- const a = (0, command_arg_projection_cjs_1.parseNamedArgs)(args, ['phase']);
196
+ const bareTrailingPositional = args[2] !== undefined && !args[2].startsWith('--');
197
+ const a = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { valueFlags: ['phase'], positionals: bareTrailingPositional ? 3 : 2 }, error);
165
198
  state.cmdStateCompletePhase(cwd, raw, strArg(a, 'phase') || args[2]);
166
199
  },
167
200
  'milestone-switch': () => {
168
- const a = (0, command_arg_projection_cjs_1.parseNamedArgs)(args, ['milestone', 'name']);
201
+ const a = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { valueFlags: ['milestone', 'name'], positionals: 2 }, error);
169
202
  state.cmdStateMilestoneSwitch(cwd, strArg(a, 'milestone'), strArg(a, 'name'), raw);
170
203
  },
171
204
  },