@opengsd/gsd-core 1.11.0 → 1.13.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 (498) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.opencode/plugins/gsd-core.js +12 -0
  4. package/agents/gsd-code-fixer.md +1 -1
  5. package/agents/gsd-debug-session-manager.md +1 -1
  6. package/agents/gsd-debugger.md +1 -1
  7. package/agents/gsd-dom-verifier.md +169 -0
  8. package/agents/gsd-eval-auditor.md +1 -1
  9. package/agents/gsd-executor.md +78 -42
  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 +0 -1
  13. package/agents/gsd-pattern-mapper.md +11 -0
  14. package/agents/gsd-phase-researcher.md +3 -1
  15. package/agents/gsd-plan-checker.md +91 -112
  16. package/agents/gsd-planner.md +20 -4
  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 +82 -7
  21. package/agents/gsd-ui-researcher.md +70 -3
  22. package/agents/gsd-verifier.md +24 -2
  23. package/bin/install.js +847 -200
  24. package/commands/gsd/discuss-phase.md +1 -1
  25. package/commands/gsd/execute-phase.md +1 -1
  26. package/commands/gsd/import.md +1 -1
  27. package/commands/gsd/ns-workflow.md +2 -1
  28. package/commands/gsd/phase.md +1 -1
  29. package/commands/gsd/quick-batch.md +105 -0
  30. package/commands/gsd/quick.md +8 -4
  31. package/commands/gsd/surface.md +18 -8
  32. package/gsd-core/bin/gsd-tools.cjs +761 -100
  33. package/gsd-core/bin/lib/active-workstream-store.cjs +8 -0
  34. package/gsd-core/bin/lib/adr-parser.cjs +13 -7
  35. package/gsd-core/bin/lib/agent-install-check.cjs +162 -0
  36. package/gsd-core/bin/lib/api-coverage.cjs +30 -9
  37. package/gsd-core/bin/lib/artifacts.cjs +2 -0
  38. package/gsd-core/bin/lib/assumption-delta.cjs +30 -11
  39. package/gsd-core/bin/lib/audit.cjs +163 -41
  40. package/gsd-core/bin/lib/broken-windows.cjs +306 -28
  41. package/gsd-core/bin/lib/capability-activation.cjs +27 -0
  42. package/gsd-core/bin/lib/capability-lock.cjs +10 -4
  43. package/gsd-core/bin/lib/capability-registry.cjs +785 -144
  44. package/gsd-core/bin/lib/capability-state.cjs +25 -4
  45. package/gsd-core/bin/lib/capability-validator.cjs +321 -18
  46. package/gsd-core/bin/lib/capability-writer.cjs +14 -4
  47. package/gsd-core/bin/lib/check-command-router.cjs +229 -6
  48. package/gsd-core/bin/lib/claude-orchestration.cjs +10 -25
  49. package/gsd-core/bin/lib/cli-exit.cjs +496 -10
  50. package/gsd-core/bin/lib/clusters.cjs +1 -0
  51. package/gsd-core/bin/lib/code-review-depth.cjs +288 -0
  52. package/gsd-core/bin/lib/codex-agent-toml.cjs +410 -4
  53. package/gsd-core/bin/lib/command-aliases.cjs +16 -0
  54. package/gsd-core/bin/lib/command-arg-projection.cjs +144 -14
  55. package/gsd-core/bin/lib/command-routing-hub.cjs +31 -2
  56. package/gsd-core/bin/lib/commands.cjs +877 -54
  57. package/gsd-core/bin/lib/complexity-trigger.cjs +26 -6
  58. package/gsd-core/bin/lib/config-loader.cjs +121 -29
  59. package/gsd-core/bin/lib/config.cjs +92 -2
  60. package/gsd-core/bin/lib/configuration.cjs +129 -37
  61. package/gsd-core/bin/lib/core-utils.cjs +118 -14
  62. package/gsd-core/bin/lib/decisions.cjs +213 -1
  63. package/gsd-core/bin/lib/edge-probe.cjs +23 -2
  64. package/gsd-core/bin/lib/estimate-cli.cjs +55 -11
  65. package/gsd-core/bin/lib/exit-code-registry.cjs +98 -0
  66. package/gsd-core/bin/lib/file-overlap-partitioner.cjs +74 -0
  67. package/gsd-core/bin/lib/frontmatter.cjs +975 -326
  68. package/gsd-core/bin/lib/gap-checker.cjs +41 -8
  69. package/gsd-core/bin/lib/git-base-branch.cjs +182 -39
  70. package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +7 -3
  71. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +8 -2
  72. package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +60 -14
  73. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +75 -22
  74. package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +22 -8
  75. package/gsd-core/bin/lib/health-diagnostic.cjs +23 -3
  76. package/gsd-core/bin/lib/host-integration.cjs +96 -11
  77. package/gsd-core/bin/lib/init-command-router.cjs +132 -21
  78. package/gsd-core/bin/lib/init.cjs +252 -56
  79. package/gsd-core/bin/lib/install-engine.cjs +252 -15
  80. package/gsd-core/bin/lib/install-model-override-resolver.cjs +78 -1
  81. package/gsd-core/bin/lib/install-profiles.cjs +100 -18
  82. package/gsd-core/bin/lib/installer-migration-report.cjs +4 -0
  83. package/gsd-core/bin/lib/installer-migrations/010-antigravity-retire-confighome-artifacts.cjs +169 -0
  84. package/gsd-core/bin/lib/installer-migrations.cjs +10 -7
  85. package/gsd-core/bin/lib/intel.cjs +101 -26
  86. package/gsd-core/bin/lib/io.cjs +195 -15
  87. package/gsd-core/bin/lib/learnings.cjs +85 -14
  88. package/gsd-core/bin/lib/legacy-cleanup.cjs +8 -2
  89. package/gsd-core/bin/lib/loop-resolver.cjs +14 -8
  90. package/gsd-core/bin/lib/markdown-table.cjs +175 -4
  91. package/gsd-core/bin/lib/milestone.cjs +112 -7
  92. package/gsd-core/bin/lib/model-catalog.cjs +177 -19
  93. package/gsd-core/bin/lib/model-resolver.cjs +10 -28
  94. package/gsd-core/bin/lib/onboard-projection.cjs +5 -1
  95. package/gsd-core/bin/lib/phase-command-router.cjs +13 -6
  96. package/gsd-core/bin/lib/phase-estimation.cjs +17 -8
  97. package/gsd-core/bin/lib/phase-id.cjs +321 -13
  98. package/gsd-core/bin/lib/phase-lifecycle.cjs +24 -16
  99. package/gsd-core/bin/lib/phase-locator.cjs +138 -17
  100. package/gsd-core/bin/lib/phase.cjs +1175 -115
  101. package/gsd-core/bin/lib/plan-document.cjs +273 -0
  102. package/gsd-core/bin/lib/plan-scan.cjs +13 -2
  103. package/gsd-core/bin/lib/planning-command-router.cjs +61 -0
  104. package/gsd-core/bin/lib/planning-inspect.cjs +1168 -0
  105. package/gsd-core/bin/lib/planning-snapshot.cjs +165 -34
  106. package/gsd-core/bin/lib/planning-workspace.cjs +159 -28
  107. package/gsd-core/bin/lib/probe-core.cjs +4 -1
  108. package/gsd-core/bin/lib/profile-pipeline-command-router.cjs +50 -7
  109. package/gsd-core/bin/lib/profile-pipeline.cjs +6 -3
  110. package/gsd-core/bin/lib/quick-batch-command-router.cjs +285 -0
  111. package/gsd-core/bin/lib/quick-batch-dispatch.cjs +250 -0
  112. package/gsd-core/bin/lib/quick-batch.cjs +840 -0
  113. package/gsd-core/bin/lib/real-home-guard.cjs +419 -0
  114. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +71 -45
  115. package/gsd-core/bin/lib/review-lane-descriptor.cjs +62 -14
  116. package/gsd-core/bin/lib/review-lane-invocation.cjs +73 -1
  117. package/gsd-core/bin/lib/review-lane-runner.cjs +136 -10
  118. package/gsd-core/bin/lib/roadmap-command-router.cjs +45 -31
  119. package/gsd-core/bin/lib/roadmap-parser.cjs +577 -41
  120. package/gsd-core/bin/lib/roadmap.cjs +248 -64
  121. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +329 -41
  122. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +16 -17
  123. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +320 -109
  124. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +487 -83
  125. package/gsd-core/bin/lib/runtime-identity.cjs +234 -0
  126. package/gsd-core/bin/lib/runtime-slash.cjs +72 -2
  127. package/gsd-core/bin/lib/shell-command-projection.cjs +75 -8
  128. package/gsd-core/bin/lib/smart-entry.cjs +19 -31
  129. package/gsd-core/bin/lib/spec-section.cjs +12 -7
  130. package/gsd-core/bin/lib/state-command-router.cjs +47 -18
  131. package/gsd-core/bin/lib/state-contract.cjs +359 -0
  132. package/gsd-core/bin/lib/state-document.cjs +216 -5
  133. package/gsd-core/bin/lib/state-md-schema.cjs +231 -0
  134. package/gsd-core/bin/lib/state-transition.cjs +850 -145
  135. package/gsd-core/bin/lib/state.cjs +1629 -287
  136. package/gsd-core/bin/lib/surface.cjs +33 -10
  137. package/gsd-core/bin/lib/task-command-router.cjs +111 -1
  138. package/gsd-core/bin/lib/task-content-resolution.cjs +368 -0
  139. package/gsd-core/bin/lib/tdd-red-evidence.cjs +133 -0
  140. package/gsd-core/bin/lib/teams-status.cjs +4 -1
  141. package/gsd-core/bin/lib/uat-predicate.cjs +58 -20
  142. package/gsd-core/bin/lib/uat.cjs +2542 -387
  143. package/gsd-core/bin/lib/ui-consideration-probe.cjs +9 -1
  144. package/gsd-core/bin/lib/ui-safety-gate.cjs +37 -7
  145. package/gsd-core/bin/lib/unusable-input.cjs +13 -0
  146. package/gsd-core/bin/lib/update-context.cjs +6 -2
  147. package/gsd-core/bin/lib/validate-command-router.cjs +2 -2
  148. package/gsd-core/bin/lib/validate.cjs +230 -12
  149. package/gsd-core/bin/lib/vendor/README.md +43 -5
  150. package/gsd-core/bin/lib/vendor/js-yaml.cjs +3014 -0
  151. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  152. package/gsd-core/bin/lib/verification.cjs +287 -13
  153. package/gsd-core/bin/lib/verify-command-grounding.cjs +846 -0
  154. package/gsd-core/bin/lib/verify-command-router.cjs +1 -0
  155. package/gsd-core/bin/lib/verify.cjs +441 -56
  156. package/gsd-core/bin/lib/workstream-inventory.cjs +20 -2
  157. package/gsd-core/bin/lib/workstream-name-policy.cjs +25 -4
  158. package/gsd-core/bin/lib/worktree-base-ref.cjs +66 -12
  159. package/gsd-core/bin/lib/worktree-safety.cjs +185 -21
  160. package/gsd-core/bin/shared/config-defaults.manifest.json +7 -1
  161. package/gsd-core/bin/shared/config-schema.manifest.json +13 -0
  162. package/gsd-core/bin/shared/exit-codes.json +8 -0
  163. package/gsd-core/bin/shared/exit-codes.sh +20 -0
  164. package/gsd-core/bin/shared/model-catalog.json +8 -1
  165. package/gsd-core/bin/verify-reapply-patches.cjs +70 -3
  166. package/gsd-core/references/agent-contracts.md +6 -5
  167. package/gsd-core/references/api-coverage.md +24 -2
  168. package/gsd-core/references/autonomous-smart-discuss.md +3 -3
  169. package/gsd-core/references/checkpoints.md +37 -19
  170. package/gsd-core/references/decimal-phase-calculation.md +5 -5
  171. package/gsd-core/references/edge-probe.md +17 -5
  172. package/gsd-core/references/execute-mvp-tdd.md +18 -18
  173. package/gsd-core/references/execute-phase-between-wave-reset.md +9 -12
  174. package/gsd-core/references/execute-phase-response-language.md +6 -0
  175. package/gsd-core/references/execute-phase-wave-guard.md +11 -9
  176. package/gsd-core/references/executor-examples.md +42 -0
  177. package/gsd-core/references/failing-direction.md +78 -0
  178. package/gsd-core/references/few-shot-examples/plan-checker.md +15 -15
  179. package/gsd-core/references/gate-prompts.md +1 -1
  180. package/gsd-core/references/git-integration.md +5 -5
  181. package/gsd-core/references/git-planning-commit.md +3 -3
  182. package/gsd-core/references/gsd-run-resolver.md +1 -1
  183. package/gsd-core/references/loop-hook-dispatch.md +22 -0
  184. package/gsd-core/references/model-profiles.md +1 -1
  185. package/gsd-core/references/mvp-concepts.md +2 -2
  186. package/gsd-core/references/nyquist-compliance.md +74 -0
  187. package/gsd-core/references/offer-next.md +3 -5
  188. package/gsd-core/references/phase-argument-parsing.md +3 -3
  189. package/gsd-core/references/plan-checker-examples.md +41 -0
  190. package/gsd-core/references/planner-antipatterns.md +25 -0
  191. package/gsd-core/references/planner-chunked.md +5 -1
  192. package/gsd-core/references/planner-coupling.md +42 -0
  193. package/gsd-core/references/planner-failing-direction.md +53 -0
  194. package/gsd-core/references/planner-human-verify-mode.md +15 -1
  195. package/gsd-core/references/planner-quick-batch.md +71 -0
  196. package/gsd-core/references/planner-reviews.md +47 -0
  197. package/gsd-core/references/planner-revision.md +76 -3
  198. package/gsd-core/references/planner-verify-command-grounding.md +17 -0
  199. package/gsd-core/references/planning-config.md +39 -9
  200. package/gsd-core/references/response-language-directive.md +9 -0
  201. package/gsd-core/references/reviewer-instances.md +31 -0
  202. package/gsd-core/references/revision-loop.md +118 -11
  203. package/gsd-core/references/runtime-aware-dispatch.md +1 -1
  204. package/gsd-core/references/tdd.md +15 -12
  205. package/gsd-core/references/ui-brand.md +65 -21
  206. package/gsd-core/references/ui-consideration-probe.md +1 -1
  207. package/gsd-core/references/universal-anti-patterns.md +2 -2
  208. package/gsd-core/references/verifier-evidence-gate.md +160 -0
  209. package/gsd-core/references/verify-command-path-resolvability.md +42 -0
  210. package/gsd-core/references/verify-mvp-mode.md +1 -1
  211. package/gsd-core/references/workstream-flag.md +11 -11
  212. package/gsd-core/templates/README.md +1 -1
  213. package/gsd-core/templates/SECURITY.md +3 -3
  214. package/gsd-core/templates/UI-SPEC.md +25 -3
  215. package/gsd-core/templates/VALIDATION.md +3 -3
  216. package/gsd-core/templates/phase-prompt.md +7 -0
  217. package/gsd-core/templates/state.md +7 -0
  218. package/gsd-core/templates/verification-report.md +5 -0
  219. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  220. package/gsd-core/workflows/add-backlog.md +3 -1
  221. package/gsd-core/workflows/add-phase.md +5 -3
  222. package/gsd-core/workflows/add-tests.md +4 -9
  223. package/gsd-core/workflows/add-todo.md +2 -2
  224. package/gsd-core/workflows/ai-integration-phase.md +5 -10
  225. package/gsd-core/workflows/analyze-dependencies.md +2 -0
  226. package/gsd-core/workflows/audit-fix.md +14 -3
  227. package/gsd-core/workflows/audit-milestone.md +11 -9
  228. package/gsd-core/workflows/audit-uat.md +19 -2
  229. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +2 -2
  230. package/gsd-core/workflows/autonomous.md +12 -26
  231. package/gsd-core/workflows/check-todos.md +2 -2
  232. package/gsd-core/workflows/cleanup.md +3 -3
  233. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +16 -14
  234. package/gsd-core/workflows/code-review-fix.md +3 -1
  235. package/gsd-core/workflows/code-review.md +192 -69
  236. package/gsd-core/workflows/complete-milestone.md +28 -14
  237. package/gsd-core/workflows/debug.md +6 -4
  238. package/gsd-core/workflows/diagnose-issues.md +17 -7
  239. package/gsd-core/workflows/discuss-phase/modes/advisor.md +3 -1
  240. package/gsd-core/workflows/discuss-phase/modes/all.md +2 -0
  241. package/gsd-core/workflows/discuss-phase/modes/analyze.md +2 -0
  242. package/gsd-core/workflows/discuss-phase/modes/auto.md +2 -0
  243. package/gsd-core/workflows/discuss-phase/modes/batch.md +2 -0
  244. package/gsd-core/workflows/discuss-phase/modes/chain.md +5 -7
  245. package/gsd-core/workflows/discuss-phase/modes/default.md +2 -0
  246. package/gsd-core/workflows/discuss-phase/modes/power.md +2 -0
  247. package/gsd-core/workflows/discuss-phase/modes/text.md +3 -1
  248. package/gsd-core/workflows/discuss-phase/templates/context.md +2 -0
  249. package/gsd-core/workflows/discuss-phase/templates/discussion-log.md +2 -0
  250. package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +1 -3
  251. package/gsd-core/workflows/discuss-phase-assumptions.md +3 -3
  252. package/gsd-core/workflows/discuss-phase-power.md +2 -0
  253. package/gsd-core/workflows/discuss-phase.md +2 -2
  254. package/gsd-core/workflows/do.md +46 -19
  255. package/gsd-core/workflows/docs-update.md +6 -5
  256. package/gsd-core/workflows/edit-phase.md +3 -1
  257. package/gsd-core/workflows/eval-review.md +5 -10
  258. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +3 -1
  259. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +129 -11
  260. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +1 -1
  261. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +1 -1
  262. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
  263. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +29 -5
  264. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +2 -2
  265. package/gsd-core/workflows/execute-phase/steps/protected-branch.md +21 -0
  266. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +4 -2
  267. package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +25 -0
  268. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +39 -0
  269. package/gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md +2 -0
  270. package/gsd-core/workflows/execute-phase.md +68 -66
  271. package/gsd-core/workflows/execute-plan.md +25 -20
  272. package/gsd-core/workflows/explore.md +3 -1
  273. package/gsd-core/workflows/extract-learnings.md +3 -1
  274. package/gsd-core/workflows/fast.md +8 -2
  275. package/gsd-core/workflows/forensics.md +3 -1
  276. package/gsd-core/workflows/graduation.md +6 -6
  277. package/gsd-core/workflows/health.md +4 -7
  278. package/gsd-core/workflows/help/modes/brief.md +2 -0
  279. package/gsd-core/workflows/help/modes/default.md +2 -0
  280. package/gsd-core/workflows/help/modes/full.md +12 -0
  281. package/gsd-core/workflows/help/modes/topic.md +2 -0
  282. package/gsd-core/workflows/help.md +2 -0
  283. package/gsd-core/workflows/import.md +17 -14
  284. package/gsd-core/workflows/inbox.md +5 -6
  285. package/gsd-core/workflows/ingest-docs.md +45 -12
  286. package/gsd-core/workflows/insert-phase.md +7 -5
  287. package/gsd-core/workflows/list-phase-assumptions.md +2 -0
  288. package/gsd-core/workflows/list-seeds.md +7 -3
  289. package/gsd-core/workflows/list-workspaces.md +3 -1
  290. package/gsd-core/workflows/manager.md +15 -26
  291. package/gsd-core/workflows/map-codebase.md +3 -1
  292. package/gsd-core/workflows/milestone-summary.md +3 -1
  293. package/gsd-core/workflows/mvp-phase.md +3 -3
  294. package/gsd-core/workflows/new-milestone.md +10 -22
  295. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
  296. package/gsd-core/workflows/new-project.md +17 -29
  297. package/gsd-core/workflows/new-workspace.md +2 -2
  298. package/gsd-core/workflows/next.md +4 -2
  299. package/gsd-core/workflows/node-repair.md +2 -0
  300. package/gsd-core/workflows/note.md +2 -0
  301. package/gsd-core/workflows/onboard.md +1 -1
  302. package/gsd-core/workflows/pause-work.md +20 -5
  303. package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +1 -1
  304. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +100 -18
  305. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +4 -4
  306. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +12 -3
  307. package/gsd-core/workflows/plan-phase.md +251 -54
  308. package/gsd-core/workflows/plan-review-convergence.md +148 -19
  309. package/gsd-core/workflows/plant-seed.md +3 -3
  310. package/gsd-core/workflows/pr-branch.md +195 -51
  311. package/gsd-core/workflows/profile-user.md +17 -15
  312. package/gsd-core/workflows/progress/steps/forensic-audit.md +1 -1
  313. package/gsd-core/workflows/progress.md +52 -15
  314. package/gsd-core/workflows/quick/steps/discussion-phase.md +1 -3
  315. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +38 -5
  316. package/gsd-core/workflows/quick/steps/quick-verification.md +2 -4
  317. package/gsd-core/workflows/quick/steps/research-phase.md +5 -7
  318. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +3 -3
  319. package/gsd-core/workflows/quick-batch/steps/batch-init.md +55 -0
  320. package/gsd-core/workflows/quick-batch/steps/completion.md +65 -0
  321. package/gsd-core/workflows/quick-batch/steps/merge-wave.md +100 -0
  322. package/gsd-core/workflows/quick-batch/steps/plan-checker-loop.md +147 -0
  323. package/gsd-core/workflows/quick-batch/steps/planner-wave.md +158 -0
  324. package/gsd-core/workflows/quick-batch/steps/research-phase.md +95 -0
  325. package/gsd-core/workflows/quick-batch/steps/resume-mode.md +49 -0
  326. package/gsd-core/workflows/quick-batch/steps/verification-wave.md +73 -0
  327. package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +169 -0
  328. package/gsd-core/workflows/quick-batch.md +203 -0
  329. package/gsd-core/workflows/quick.md +33 -32
  330. package/gsd-core/workflows/reapply-patches.md +2 -0
  331. package/gsd-core/workflows/remove-phase.md +6 -4
  332. package/gsd-core/workflows/remove-workspace.md +3 -3
  333. package/gsd-core/workflows/resume-project.md +14 -14
  334. package/gsd-core/workflows/review.md +404 -21
  335. package/gsd-core/workflows/scan.md +3 -1
  336. package/gsd-core/workflows/section-manifest.json +12 -0
  337. package/gsd-core/workflows/secure-phase.md +3 -3
  338. package/gsd-core/workflows/session-report.md +2 -0
  339. package/gsd-core/workflows/settings-advanced.md +9 -9
  340. package/gsd-core/workflows/settings-integrations.md +66 -32
  341. package/gsd-core/workflows/settings.md +4 -6
  342. package/gsd-core/workflows/ship.md +22 -16
  343. package/gsd-core/workflows/sketch-wrap-up.md +13 -17
  344. package/gsd-core/workflows/sketch.md +13 -19
  345. package/gsd-core/workflows/smart-entry.md +4 -6
  346. package/gsd-core/workflows/spec-phase.md +31 -4
  347. package/gsd-core/workflows/spike-wrap-up.md +9 -11
  348. package/gsd-core/workflows/spike.md +21 -32
  349. package/gsd-core/workflows/stats.md +4 -2
  350. package/gsd-core/workflows/sync-skills.md +13 -5
  351. package/gsd-core/workflows/thread.md +13 -7
  352. package/gsd-core/workflows/transition.md +7 -5
  353. package/gsd-core/workflows/ui-phase.md +36 -21
  354. package/gsd-core/workflows/ui-review.md +7 -11
  355. package/gsd-core/workflows/ultraplan-phase.md +7 -13
  356. package/gsd-core/workflows/undo.md +9 -17
  357. package/gsd-core/workflows/update.md +47 -48
  358. package/gsd-core/workflows/validate-phase.md +3 -3
  359. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +25 -1
  360. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
  361. package/gsd-core/workflows/verify-work.md +106 -21
  362. package/hooks/dist/gsd-agent-isolation-guard.js +77 -38
  363. package/hooks/dist/gsd-check-update-worker.js +19 -2
  364. package/hooks/dist/gsd-config-reload.js +18 -12
  365. package/hooks/dist/gsd-context-monitor.js +302 -22
  366. package/hooks/dist/gsd-cursor-post-tool.js +3 -1
  367. package/hooks/dist/gsd-cursor-pre-tool.js +3 -1
  368. package/hooks/dist/gsd-cursor-session-start.js +2 -1
  369. package/hooks/dist/gsd-cursor-stop.js +2 -1
  370. package/hooks/dist/gsd-cursor-subagent-start.js +28 -23
  371. package/hooks/dist/gsd-cursor-subagent-stop.js +3 -1
  372. package/hooks/dist/gsd-ensure-canonical-path.js +2 -1
  373. package/hooks/dist/gsd-graphify-update.sh +22 -18
  374. package/hooks/dist/gsd-node-runner.sh +77 -0
  375. package/hooks/dist/gsd-phase-boundary.sh +1 -0
  376. package/hooks/dist/gsd-prompt-guard.js +46 -12
  377. package/hooks/dist/gsd-read-guard.js +18 -7
  378. package/hooks/dist/gsd-read-injection-scanner.js +22 -13
  379. package/hooks/dist/gsd-secret-read-guard.js +1079 -0
  380. package/hooks/dist/gsd-session-state.sh +1 -0
  381. package/hooks/dist/gsd-statusline.js +222 -29
  382. package/hooks/dist/gsd-validate-commit.sh +523 -12
  383. package/hooks/dist/gsd-windsurf-pre-command.js +16 -11
  384. package/hooks/dist/gsd-windsurf-pre-write.js +22 -13
  385. package/hooks/dist/gsd-workflow-guard.js +36 -17
  386. package/hooks/dist/gsd-worktree-path-guard.js +36 -21
  387. package/hooks/dist/gsd-write-guard.js +35 -25
  388. package/hooks/dist/lib/cli-exit.js +560 -0
  389. package/hooks/dist/lib/exit-code-registry.js +98 -0
  390. package/hooks/dist/lib/git-cmd.js +210 -1
  391. package/hooks/dist/lib/git-probe.js +84 -0
  392. package/hooks/dist/lib/hook-exit.js +81 -0
  393. package/hooks/dist/lib/injection-patterns.js +36 -6
  394. package/hooks/dist/managed-hooks-registry.cjs +4 -0
  395. package/hooks/gsd-agent-isolation-guard.js +77 -38
  396. package/hooks/gsd-check-update-worker.js +19 -2
  397. package/hooks/gsd-config-reload.js +18 -12
  398. package/hooks/gsd-context-monitor.js +302 -22
  399. package/hooks/gsd-cursor-post-tool.js +3 -1
  400. package/hooks/gsd-cursor-pre-tool.js +3 -1
  401. package/hooks/gsd-cursor-session-start.js +2 -1
  402. package/hooks/gsd-cursor-stop.js +2 -1
  403. package/hooks/gsd-cursor-subagent-start.js +28 -23
  404. package/hooks/gsd-cursor-subagent-stop.js +3 -1
  405. package/hooks/gsd-ensure-canonical-path.js +2 -1
  406. package/hooks/gsd-graphify-update.sh +22 -18
  407. package/hooks/gsd-node-runner.sh +77 -0
  408. package/hooks/gsd-phase-boundary.sh +1 -0
  409. package/hooks/gsd-prompt-guard.js +46 -12
  410. package/hooks/gsd-read-guard.js +18 -7
  411. package/hooks/gsd-read-injection-scanner.js +22 -13
  412. package/hooks/gsd-secret-read-guard.js +1079 -0
  413. package/hooks/gsd-session-state.sh +1 -0
  414. package/hooks/gsd-statusline.js +222 -29
  415. package/hooks/gsd-validate-commit.sh +523 -12
  416. package/hooks/gsd-windsurf-pre-command.js +16 -11
  417. package/hooks/gsd-windsurf-pre-write.js +22 -13
  418. package/hooks/gsd-workflow-guard.js +36 -17
  419. package/hooks/gsd-worktree-path-guard.js +36 -21
  420. package/hooks/gsd-write-guard.js +35 -25
  421. package/hooks/hooks.json +6 -0
  422. package/hooks/lib/cli-exit.js +560 -0
  423. package/hooks/lib/exit-code-registry.js +98 -0
  424. package/hooks/lib/git-cmd.js +210 -1
  425. package/hooks/lib/git-probe.js +84 -0
  426. package/hooks/lib/hook-exit.js +81 -0
  427. package/hooks/lib/injection-patterns.js +36 -6
  428. package/hooks/managed-hooks-registry.cjs +4 -0
  429. package/package.json +14 -9
  430. package/scripts/base64-scan.sh +74 -12
  431. package/scripts/build-hooks.js +12 -0
  432. package/scripts/check-glossary-refs.cjs +77 -15
  433. package/scripts/check-mutation-score-ratchet.cjs +156 -0
  434. package/scripts/ci-check-job-near-cap.cjs +49 -0
  435. package/scripts/ci-pr-mergeability.cjs +262 -0
  436. package/scripts/ci-test-scope.cjs +52 -12
  437. package/scripts/ci-timeout-report.cjs +230 -0
  438. package/scripts/docs-guard-registry.cjs +406 -0
  439. package/scripts/gen-capability-registry.cjs +8 -6
  440. package/scripts/gen-exit-code-docs.cjs +318 -0
  441. package/scripts/gen-exit-code-registry.cjs +891 -0
  442. package/scripts/gen-features.cjs +836 -0
  443. package/scripts/gen-hooks-cli-exit.cjs +239 -0
  444. package/scripts/gen-install-tree-fixtures.cjs +2 -2
  445. package/scripts/gen-loop-host-contract.cjs +189 -4
  446. package/scripts/gen-scripts-cli-exit.cjs +185 -0
  447. package/scripts/gen-state-md-docs.cjs +727 -0
  448. package/scripts/{test-failure-reasons.cjs → gsd-test-gate-reasons.cjs} +6 -0
  449. package/scripts/lib/ci-job-timing.cjs +72 -0
  450. package/scripts/lib/cli-exit.cjs +546 -44
  451. package/scripts/lib/drift-scan.cjs +32 -2
  452. package/scripts/lib/exit-code-registry.cjs +98 -0
  453. package/scripts/lib/ndjson-reporter.cjs +119 -0
  454. package/scripts/lib/shellcheck-fetch.cjs +247 -0
  455. package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -6
  456. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
  457. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
  458. package/scripts/lint-docs-guard-registration.cjs +495 -0
  459. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +198 -0
  460. package/scripts/lint-eslint-glob-coverage.allowlist.json +4 -0
  461. package/scripts/{lint-fix-has-regression-test.cjs → lint-fix-has-regression-tests.cjs} +12 -6
  462. package/scripts/lint-health-diagnostic-rule-table.cjs +65 -8
  463. package/scripts/lint-mutation-test-derivation-drift.cjs +86 -0
  464. package/scripts/lint-phase-enumeration-drift.cjs +45 -14
  465. package/scripts/lint-phase-id-drift.cjs +133 -8
  466. package/scripts/lint-planning-prompt-drift.cjs +38 -1
  467. package/scripts/lint-portable-grep.cjs +176 -0
  468. package/scripts/lint-removed-but-needed.cjs +184 -16
  469. package/scripts/lint-response-language-coverage.cjs +524 -0
  470. package/scripts/lint-seam-enforcement.cjs +182 -0
  471. package/scripts/lint-slug-derivation-drift.cjs +921 -0
  472. package/scripts/lint-source-test-name-collision.cjs +241 -0
  473. package/scripts/lint-state-write-path-drift.cjs +337 -432
  474. package/scripts/lint-test-file-count.allowlist.json +124 -4
  475. package/scripts/lint-test-file-count.cjs +25 -3
  476. package/scripts/lint-unreachable-guard-drift.cjs +51 -64
  477. package/scripts/lint-vendored-deps.cjs +208 -35
  478. package/scripts/lint-workflow-shellcheck-baseline.json +1027 -0
  479. package/scripts/lint-workflow-shellcheck.cjs +614 -0
  480. package/scripts/mutation-matrix.cjs +599 -50
  481. package/scripts/npm-audit-baseline.cjs +376 -0
  482. package/scripts/prompt-injection-scan.sh +83 -14
  483. package/scripts/require-issue-link-policy.cjs +16 -1
  484. package/scripts/secret-scan.sh +75 -13
  485. package/scripts/select-docs-guards.cjs +56 -0
  486. package/scripts/sync-runtime-launcher.cjs +22 -3
  487. package/skills/gsd-discuss-phase/SKILL.md +1 -1
  488. package/skills/gsd-execute-phase/SKILL.md +1 -1
  489. package/skills/gsd-import/SKILL.md +1 -1
  490. package/skills/gsd-ns-workflow/SKILL.md +1 -0
  491. package/skills/gsd-phase/SKILL.md +1 -1
  492. package/skills/gsd-quick/SKILL.md +8 -4
  493. package/skills/gsd-quick-batch/SKILL.md +105 -0
  494. package/skills/gsd-surface/SKILL.md +18 -8
  495. package/vscode/package.json +1 -1
  496. package/bin/lib/ui-safety-gate.cjs +0 -109
  497. package/scripts/lint-emitted-drift-ack.cjs +0 -344
  498. package/scripts/state-write-path-drift-baseline.json +0 -19
@@ -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,51 +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']);
157
+ const a = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { valueFlags: ['phase', 'name', 'plans'], positionals: 2 }, error);
147
158
  // #3395: --name was parsed here but never forwarded (the StateModule
148
159
  // signature had no channel for it), so the argument was silently
149
160
  // dropped. It now persists into the Current Position `Phase:` line and
150
161
  // the authoritative current_phase_name, mirroring begin-phase.
151
162
  state.cmdStatePlannedPhase(cwd, strArg(a, 'phase'), strArg(a, 'name'), parsePlans(strArg(a, 'plans')), raw);
152
163
  },
153
- validate: () => state.cmdStateValidate(cwd, raw),
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 });
170
+ },
154
171
  sync: () => {
155
- 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);
156
173
  state.cmdStateSync(cwd, { verify: a['verify'] }, raw);
157
174
  },
158
175
  prune: () => {
159
- 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);
160
177
  state.cmdStatePrune(cwd, { keepRecent: strArg(a, 'keep-recent') || '3', dryRun: a['dry-run'] === true }, raw);
161
178
  },
162
179
  rebuild: () => {
163
- 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);
164
181
  state.cmdStateRebuild(cwd, { dryRun: a['dry-run'] === true, verbose: a['verbose'] === true }, raw);
165
182
  },
166
- // 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).
167
195
  'complete-phase': () => {
168
- 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);
169
198
  state.cmdStateCompletePhase(cwd, raw, strArg(a, 'phase') || args[2]);
170
199
  },
171
200
  'milestone-switch': () => {
172
- 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);
173
202
  state.cmdStateMilestoneSwitch(cwd, strArg(a, 'milestone'), strArg(a, 'name'), raw);
174
203
  },
175
204
  },
@@ -0,0 +1,359 @@
1
+ "use strict";
2
+ /**
3
+ * State Contract Module — `.planning/state.json` schema v1 (#3227).
4
+ *
5
+ * A **best-effort publisher** invoked at 11 step-boundary commands
6
+ * (`state.*`, `phase.*`, `milestone.complete`). It composes existing
7
+ * canonical owners; it introduces no second answer to any question GSD
8
+ * already answers:
9
+ * - `planning-workspace.cjs`'s `planningPaths` for every `.planning/` path
10
+ * (workstream-aware — never re-derived here).
11
+ * - `phase-lifecycle.cjs`'s `locateProgressTable` (this issue's Edit 1) for
12
+ * "where is the Progress table" — the SAME table
13
+ * `deriveProgressFromRoadmap` counts from, so `phases[]` and
14
+ * `deriveProgressFromRoadmap`'s `totalPhases` can never disagree about
15
+ * which rows are data rows.
16
+ * - `phase-id.cjs`'s `isSentinelPhaseId` / `parsePhaseFromProse` for
17
+ * sentinel exclusion and STATE.md phase-token parsing.
18
+ * - `roadmap-parser.cjs`'s `getMilestoneInfo` for milestone identity.
19
+ * - `markdown-sectionizer.cjs`'s `collectSection` for the `## Phases`
20
+ * checkbox fallback.
21
+ * - `state-document.cjs`'s `stateFieldValue` + `frontmatter.cjs`'s
22
+ * `extractFrontmatter`/`stripFrontmatter` for STATE.md's `current_phase`.
23
+ * - `shell-command-projection.cjs`'s `platformReadSync`/`platformWriteSync`
24
+ * — the CLAUDE.md-designated single OS-facing I/O seam. `platformWriteSync`
25
+ * is ALREADY atomic (sibling tmp + `retryRenameSync`, Windows transient-
26
+ * lock retry, EXDEV fallback) — this module adds no sixth atomic-write
27
+ * helper (the repo already carries five).
28
+ * - `smart-entry.cjs`'s `classifyProject` for `next` — this is what makes
29
+ * "`next` equals smart-entry's recommended action" true BY CONSTRUCTION
30
+ * rather than by a second copy of the routing table.
31
+ *
32
+ * WHY NOT `PlanningSnapshot` / `buildPlanningInspect`. `PlanningSnapshot` is
33
+ * an explicitly-additive INTERNAL diagnostic shape (ADR-3180 §8.1) still
34
+ * growing across phases; freezing it as an external contract is the exact
35
+ * Hyrum's-Law break `planning.inspect` (`src/planning-inspect.cts`) already
36
+ * refused for the same reason (#2790). `state.json` declares its OWN flat,
37
+ * minimal, six-key schema instead — see PUBLIC SURFACE below.
38
+ *
39
+ * NOT built (Gall's Law / Zawinski's Law — see `.gsd/phase/feat-3227-state-
40
+ * contract/40-design.md`): a `--watch` mode, a reader API inside gsd-core, a
41
+ * diff/event stream, a config toggle, milestone-scoping of `phases[]`. This
42
+ * module answers "where is this project right now" and nothing else — a
43
+ * request for document *contents* belongs to `planning.inspect`.
44
+ *
45
+ * REQUIRE-CYCLE HAZARD (the single most important implementation
46
+ * constraint). `src/state.cts` imports THIS module, and `src/smart-entry.cts`
47
+ * imports `state.cjs` and destructures `readStateHeadFreshness` off it at
48
+ * MODULE LOAD time. A top-level `import smartEntry = require('./smart-entry.cjs')`
49
+ * here would therefore close the cycle
50
+ * `state.cjs -> state-contract.cjs -> smart-entry.cjs -> state.cjs`, binding
51
+ * `readStateHeadFreshness` to `undefined` inside `smart-entry.cjs` and
52
+ * throwing at its first call. Every owner below is required LAZILY, inside
53
+ * the function body, via a small cached loader — never at module top level —
54
+ * which also keeps this module's (and its owners') load cost off every
55
+ * command that imports `state.cjs` but never reaches a publish boundary.
56
+ * Someone will be tempted to "tidy" the lazy requires into top-level ones;
57
+ * doing so reopens the cycle.
58
+ *
59
+ * `withPlanningLock` is deliberately NOT taken around the write (Rejected §3
60
+ * of the design doc): it is not re-entrant, several phase commands already
61
+ * hold it when they would call this publisher, and `platformWriteSync`'s
62
+ * tmp+rename already makes each publish all-or-nothing without it.
63
+ *
64
+ * ADR-457 build-at-publish: source in src/state-contract.cts, compiled to
65
+ * gsd-core/bin/lib/state-contract.cjs (gitignored).
66
+ */
67
+ var __importDefault = (this && this.__importDefault) || function (mod) {
68
+ return (mod && mod.__esModule) ? mod : { "default": mod };
69
+ };
70
+ Object.defineProperty(exports, "__esModule", { value: true });
71
+ exports.PUBLISH_REASON = exports.PHASE_STATUS = exports.PHASE_KEY_ORDER = exports.CONTRACT_KEY_ORDER = exports.STATE_CONTRACT_FLAVOR = exports.STATE_CONTRACT_VERSION = void 0;
72
+ exports.buildStateContract = buildStateContract;
73
+ exports.publishStateContract = publishStateContract;
74
+ const node_path_1 = __importDefault(require("node:path"));
75
+ const node_fs_1 = __importDefault(require("node:fs"));
76
+ // ─── Public wire vocabulary ────────────────────────────────────────────────
77
+ exports.STATE_CONTRACT_VERSION = '1.0.0';
78
+ exports.STATE_CONTRACT_FLAVOR = 'core';
79
+ /** Key order of the emitted contract object — an observable, pinned by test. */
80
+ exports.CONTRACT_KEY_ORDER = Object.freeze(['contract', 'flavor', 'milestone', 'phases', 'next', 'updated_at']);
81
+ /** Key order of each emitted phase object — an observable, pinned by test. */
82
+ exports.PHASE_KEY_ORDER = Object.freeze(['number', 'name', 'status']);
83
+ /** Frozen three-value phase status vocabulary. Conservative in what we send (Postel's Law). */
84
+ exports.PHASE_STATUS = Object.freeze({
85
+ COMPLETE: 'complete',
86
+ IN_PROGRESS: 'in_progress',
87
+ PENDING: 'pending',
88
+ });
89
+ /** Frozen `publishStateContract` result reasons. */
90
+ exports.PUBLISH_REASON = Object.freeze({
91
+ PUBLISHED: 'published',
92
+ NO_PLANNING_DIR: 'no_planning_dir',
93
+ WRITE_FAILED: 'write_failed',
94
+ });
95
+ let _owners = null;
96
+ /**
97
+ * Lazily require every owner this module composes. MUST stay lazy — see the
98
+ * "REQUIRE-CYCLE HAZARD" module-doc comment above. Cached after first call so
99
+ * repeat invocations within one process (multiple publishes in one command,
100
+ * or across the several boundary commands in a test run) pay the require
101
+ * cost once.
102
+ */
103
+ function owners() {
104
+ if (_owners)
105
+ return _owners;
106
+ /* eslint-disable @typescript-eslint/no-require-imports */
107
+ const planningWorkspaceMod = require('./planning-workspace.cjs');
108
+ const shellCommandProjectionMod = require('./shell-command-projection.cjs');
109
+ const phaseLifecycleMod = require('./phase-lifecycle.cjs');
110
+ const phaseIdMod = require('./phase-id.cjs');
111
+ const roadmapParserMod = require('./roadmap-parser.cjs');
112
+ const markdownSectionizerMod = require('./markdown-sectionizer.cjs');
113
+ const stateDocumentMod = require('./state-document.cjs');
114
+ const frontmatterMod = require('./frontmatter.cjs');
115
+ const smartEntryMod = require('./smart-entry.cjs');
116
+ /* eslint-enable @typescript-eslint/no-require-imports */
117
+ _owners = {
118
+ planningPaths: planningWorkspaceMod.planningPaths,
119
+ platformReadSync: shellCommandProjectionMod.platformReadSync,
120
+ platformWriteSync: shellCommandProjectionMod.platformWriteSync,
121
+ locateProgressTable: phaseLifecycleMod.locateProgressTable,
122
+ isSentinelPhaseId: phaseIdMod.isSentinelPhaseId,
123
+ parsePhaseFromProse: phaseIdMod.parsePhaseFromProse,
124
+ getMilestoneInfo: roadmapParserMod.getMilestoneInfo,
125
+ collectSection: markdownSectionizerMod.collectSection,
126
+ stateFieldValue: stateDocumentMod.stateFieldValue,
127
+ extractFrontmatter: frontmatterMod.extractFrontmatter,
128
+ stripFrontmatter: frontmatterMod.stripFrontmatter,
129
+ classifyProject: smartEntryMod.classifyProject,
130
+ };
131
+ return _owners;
132
+ }
133
+ // ─── milestone ──────────────────────────────────────────────────────────────
134
+ function buildMilestone(cwd) {
135
+ try {
136
+ const { value } = owners().getMilestoneInfo(cwd);
137
+ if (!value)
138
+ return null;
139
+ // U+2014 EM DASH, spaced on both sides. Never fabricate a name — version
140
+ // alone when no name-bearing evidence resolved (design row 21).
141
+ return value.name && value.name.length > 0 ? `${value.version} — ${value.name}` : value.version;
142
+ }
143
+ catch {
144
+ return null;
145
+ }
146
+ }
147
+ // ─── phases: Progress-table (primary) enumerator ───────────────────────────
148
+ const PHASE_CELL_RE = /^(\d+(?:\.\d+)*)\s*[.:)–—-]?\s*(.*)$/;
149
+ function statusFromProgressCell(raw) {
150
+ const normalized = (raw ?? '').trim().toLowerCase().replace(/\s+/g, ' ');
151
+ if (normalized === 'complete')
152
+ return exports.PHASE_STATUS.COMPLETE;
153
+ if (normalized === 'in progress')
154
+ return exports.PHASE_STATUS.IN_PROGRESS;
155
+ // Everything else — 'not started', 'deferred' (design row 12, lossy by
156
+ // design), '', and any unrecognized word — folds to pending. An
157
+ // unrecognized status must never reach the wire as a 4th value.
158
+ return exports.PHASE_STATUS.PENDING;
159
+ }
160
+ function phasesFromProgressTable(table) {
161
+ const { isSentinelPhaseId } = owners();
162
+ const phases = [];
163
+ for (const row of table.rows) {
164
+ const cell = (row['Phase'] ?? '').trim();
165
+ if (!/^\d/.test(cell))
166
+ continue; // stray note row, no leading digit
167
+ if (isSentinelPhaseId(cell))
168
+ continue; // phase 0 / 999.x sentinels
169
+ const m = PHASE_CELL_RE.exec(cell);
170
+ const number = m ? m[1] : cell;
171
+ const name = m && m[2].trim().length > 0 ? m[2].trim() : null;
172
+ phases.push({ number, name, status: statusFromProgressCell(row['Status']) });
173
+ }
174
+ return phases;
175
+ }
176
+ // ─── phases: `## Phases` checkbox fallback ─────────────────────────────────
177
+ // `- [x] **Phase 1: Foundation**` / `- [ ] **Phase 2.1: Hardening**`.
178
+ const PHASE_BULLET_RE = /^[ \t]*[-*][ \t]+\[([ xX])\][ \t]+\*\*Phase[ \t]+(\d+(?:\.\d+)*)[ \t]*:?[ \t]*([^*\n]*)\*\*/gm;
179
+ /**
180
+ * STATE.md's current phase, via the same frontmatter-then-body chain
181
+ * `cmdStateCompletePhase` uses (`stateFieldValue` owns the #1760 fallback
182
+ * ladder). Any failure anywhere in the chain yields `null` — treat current
183
+ * phase as unknown so every unchecked bullet is PENDING rather than
184
+ * IN_PROGRESS by a guess.
185
+ */
186
+ function currentPhaseFromState(statePath) {
187
+ const { platformReadSync, extractFrontmatter, stripFrontmatter, stateFieldValue, parsePhaseFromProse } = owners();
188
+ try {
189
+ const raw = platformReadSync(statePath);
190
+ if (raw === null)
191
+ return null;
192
+ const fm = extractFrontmatter(raw, statePath);
193
+ const body = stripFrontmatter(raw);
194
+ const { value } = stateFieldValue(fm, body, 'current_phase', 'Current Phase');
195
+ if (!value)
196
+ return null;
197
+ return parsePhaseFromProse(value).phase;
198
+ }
199
+ catch {
200
+ return null;
201
+ }
202
+ }
203
+ /**
204
+ * Fallback enumerator when the ROADMAP carries no Progress table.
205
+ *
206
+ * Scoping to `## Phases` is load-bearing negative space (design "Not-
207
+ * corruption" section): it is what keeps `- [x] 01-01: a plan` (a PLAN
208
+ * bullet under `## Phase Details`) and `- ✅ **v1.0 MVP** - Phases 1-4`
209
+ * (a MILESTONE bullet under `## Milestones`) from being read as phases. The
210
+ * `**Phase N` anchor inside `PHASE_BULLET_RE` is the second layer of that
211
+ * defence — a plan bullet's text never starts with `**Phase`.
212
+ */
213
+ function phasesFromChecklist(roadmapContent, cwd, statePath) {
214
+ const { collectSection, isSentinelPhaseId } = owners();
215
+ const section = collectSection(roadmapContent, (h) => /^phases$/i.test(h.text.trim()));
216
+ if (!section)
217
+ return [];
218
+ const currentPhase = currentPhaseFromState(statePath);
219
+ const phases = [];
220
+ let match;
221
+ const pattern = new RegExp(PHASE_BULLET_RE.source, PHASE_BULLET_RE.flags);
222
+ while ((match = pattern.exec(section.body)) !== null) {
223
+ const checked = match[1] === 'x' || match[1] === 'X';
224
+ const number = match[2];
225
+ if (isSentinelPhaseId(number))
226
+ continue;
227
+ const name = match[3].replace(/\r$/, '').trim();
228
+ const status = checked
229
+ ? exports.PHASE_STATUS.COMPLETE
230
+ : (currentPhase !== null && number === currentPhase ? exports.PHASE_STATUS.IN_PROGRESS : exports.PHASE_STATUS.PENDING);
231
+ phases.push({ number, name: name.length > 0 ? name : null, status });
232
+ }
233
+ return phases;
234
+ }
235
+ function buildPhases(cwd, paths) {
236
+ const { platformReadSync, locateProgressTable } = owners();
237
+ try {
238
+ let content = platformReadSync(paths.roadmap);
239
+ if (content === null)
240
+ return [];
241
+ if (content.charCodeAt(0) === 0xfeff)
242
+ content = content.slice(1); // strip leading BOM
243
+ const table = locateProgressTable(content);
244
+ if (table)
245
+ return phasesFromProgressTable(table);
246
+ return phasesFromChecklist(content, cwd, paths.state);
247
+ }
248
+ catch {
249
+ return [];
250
+ }
251
+ }
252
+ // ─── next ───────────────────────────────────────────────────────────────────
253
+ function buildNext(cwd, deps) {
254
+ try {
255
+ const classify = deps?.classify ?? owners().classifyProject;
256
+ const result = classify(cwd);
257
+ const action = result.actions.find((a) => a.id === result.recommended);
258
+ if (!action)
259
+ return null;
260
+ return { command: action.command, label: action.label, reason: result.summary };
261
+ }
262
+ catch {
263
+ return null;
264
+ }
265
+ }
266
+ // ─── Entry points ───────────────────────────────────────────────────────────
267
+ /**
268
+ * Build the state-contract snapshot. PURE — writes nothing. Every stage is
269
+ * independently try/caught (milestone, phases, next) so one bad document
270
+ * cannot lose the others; `updated_at` and the frozen `contract`/`flavor`
271
+ * keys always resolve.
272
+ */
273
+ function buildStateContract(cwd, deps) {
274
+ const nowFn = deps?.now ?? Date.now;
275
+ const updated_at = new Date(nowFn()).toISOString();
276
+ // #2245 shape: `planningPaths` -> `planningDir` throws a plain Error for an
277
+ // invalid GSD_WORKSTREAM/GSD_PROJECT segment. This call must not be hoisted
278
+ // outside a try, or that throw escapes uncaught and breaks the invariant
279
+ // this function is documented as upholding (see `getMilestoneInfo`'s
280
+ // equivalent guard comment in src/roadmap-parser.cts for the same shape).
281
+ let paths;
282
+ try {
283
+ paths = owners().planningPaths(cwd);
284
+ }
285
+ catch {
286
+ paths = null;
287
+ }
288
+ if (!paths) {
289
+ return {
290
+ contract: exports.STATE_CONTRACT_VERSION,
291
+ flavor: exports.STATE_CONTRACT_FLAVOR,
292
+ milestone: null,
293
+ phases: [],
294
+ next: null,
295
+ updated_at,
296
+ };
297
+ }
298
+ const milestone = buildMilestone(cwd);
299
+ const phases = buildPhases(cwd, paths);
300
+ const next = buildNext(cwd, deps);
301
+ return {
302
+ contract: exports.STATE_CONTRACT_VERSION,
303
+ flavor: exports.STATE_CONTRACT_FLAVOR,
304
+ milestone,
305
+ phases,
306
+ next,
307
+ updated_at,
308
+ };
309
+ }
310
+ /**
311
+ * Publish the state-contract snapshot to `<planning>/state.json`. NEVER
312
+ * throws — for any input, ever (acceptance criterion 3: the parent boundary
313
+ * command's exit code and stdout must be unchanged whatever happens here).
314
+ *
315
+ * No `.planning/` directory at all: writes nothing, creates nothing. This
316
+ * guard is essential — `platformWriteSync` does `mkdirSync(dirname,
317
+ * {recursive:true})`, so without it the publisher would conjure a
318
+ * `.planning/` tree inside a non-GSD directory.
319
+ *
320
+ * `withPlanningLock` is deliberately NOT taken here — see the module-doc
321
+ * "REQUIRE-CYCLE HAZARD" section's sibling note: it is not re-entrant and
322
+ * several phase commands already hold it when they call this publisher, so
323
+ * acquiring it here would throw in exactly the situation this function must
324
+ * never perturb. `platformWriteSync`'s sibling-tmp + rename already makes
325
+ * each publish all-or-nothing without it.
326
+ */
327
+ function publishStateContract(cwd, deps) {
328
+ try {
329
+ const { planningPaths, platformWriteSync } = owners();
330
+ // Resolve the planning root BEFORE anything else. A resolution failure
331
+ // (invalid GSD_WORKSTREAM/GSD_PROJECT segment — the #2245 shape) means no
332
+ // write was ever attempted, so it must map to `no_planning_dir`, not
333
+ // `write_failed` — that reason is reserved for an attempted-and-failed
334
+ // write, and reporting it here would send a caller looking at disk
335
+ // permissions for a problem that isn't there.
336
+ let paths;
337
+ try {
338
+ paths = planningPaths(cwd);
339
+ }
340
+ catch {
341
+ return { published: false, reason: exports.PUBLISH_REASON.NO_PLANNING_DIR };
342
+ }
343
+ if (!node_fs_1.default.existsSync(paths.planning)) {
344
+ return { published: false, reason: exports.PUBLISH_REASON.NO_PLANNING_DIR };
345
+ }
346
+ const snapshot = buildStateContract(cwd, deps);
347
+ const statePath = node_path_1.default.join(paths.planning, 'state.json');
348
+ try {
349
+ platformWriteSync(statePath, JSON.stringify(snapshot, null, 2) + '\n');
350
+ }
351
+ catch {
352
+ return { published: false, reason: exports.PUBLISH_REASON.WRITE_FAILED };
353
+ }
354
+ return { published: true, reason: exports.PUBLISH_REASON.PUBLISHED };
355
+ }
356
+ catch {
357
+ return { published: false, reason: exports.PUBLISH_REASON.WRITE_FAILED };
358
+ }
359
+ }