@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
@@ -111,7 +111,13 @@ const RULE_W024 = {
111
111
  function buildValidPhaseSet(snapshot) {
112
112
  const valid = new Set();
113
113
  for (const dir of snapshot.phaseDirs.value) {
114
- const token = extractPhaseToken(dir);
114
+ // #612: the pre-migration source of this third was
115
+ // `collectDiskPhases(planBase, convention)`, whose keys came from the
116
+ // convention-aware extractor. Left convention-less here, a bracket repo's
117
+ // `GSD.02-05-slug` contributes `GSD.02` instead of `05`, so every STATE.md
118
+ // reference to a real phase falls outside the valid set and W002 fires on
119
+ // all of them.
120
+ const token = extractPhaseToken(dir, snapshot.phaseIdConvention);
115
121
  if (token)
116
122
  valid.add(token);
117
123
  }
@@ -233,31 +239,71 @@ const RULE_W021 = {
233
239
  description: "Phase's integer prefix implies a different milestone than its ROADMAP section (phase_id_convention: milestone-prefixed)",
234
240
  repairable: false,
235
241
  check: (snapshot) => {
236
- const convention = snapshot.config.value?.['phase_id_convention'];
237
- if (convention !== 'milestone-prefixed')
238
- return [];
239
242
  const diagnostics = [];
240
- for (const entry of snapshot.roadmapDeclaredPhases.value) {
241
- // `entry.milestone === null` means the builder never found this phase
242
- // heading inside any versioned (`v\d+\.\d+`) section — the original
243
- // `checkMilestonePrefixMismatches` only ever iterates phases found
244
- // WITHIN a section, so a phase outside any section is equivalently
245
- // never checked here.
246
- if (entry.milestone === null)
247
- continue;
248
- const expectedMilestone = getMilestoneFromPhaseId(entry.phaseId);
249
- if (expectedMilestone === null || expectedMilestone === entry.milestone)
250
- continue;
251
- diagnostics.push({
252
- code: 'W021',
253
- severity: SEVERITY.WARNING,
254
- message: `Phase ${entry.phaseId}: integer prefix implies ${expectedMilestone} but listed under ${entry.milestone}`,
255
- remedy: adviseRemedy('gsd-tools roadmap upgrade --convention milestone-prefixed'),
256
- });
243
+ // Two INDEPENDENT gates, evaluated in the order the pre-migration
244
+ // `cmdValidateHealth` block emitted them (milestone-prefixed first, then
245
+ // bracket). They are deliberately NOT written as if/else: the two read
246
+ // DIFFERENT config bases and can both be true at once.
247
+ //
248
+ // milestone-prefixed — `snapshot.config` (ROOT config only), exactly as
249
+ // this gate has always read it. Federating THIS one silently moved a
250
+ // legacy convention's answer in BOTH directions on workstream repos: a
251
+ // W021 that fires at base vanishing, and one silent at base firing.
252
+ // bracket — `snapshot.phaseIdConvention` (federated workstream -> root),
253
+ // because the bracket reads this half reports on are themselves
254
+ // federated; gating it on the root answer would split the check against
255
+ // the reads it describes.
256
+ //
257
+ // A workstream that overrides a `milestone-prefixed` ROOT to `bracket` is
258
+ // the case that makes the distinction observable, and it is the reason an
259
+ // early `return` here would be a bug: the root-configured M-NN gate must
260
+ // still fire, or the repo looks healthier than it is.
261
+ const rootConvention = snapshot.config.value?.['phase_id_convention'];
262
+ if (rootConvention === 'milestone-prefixed') {
263
+ diagnostics.push(...checkMilestonePrefixW021(snapshot));
264
+ }
265
+ // #612: an ADDITIVE sibling branch — the milestone-prefixed gate above is
266
+ // untouched. Gated strictly on the ACTIVE convention, never on
267
+ // project_code presence: reads are selected per convention, and a CHECK
268
+ // that can fail a repo runs only for the convention that repo opted into.
269
+ if (snapshot.phaseIdConvention === 'bracket') {
270
+ for (const mm of snapshot.roadmapBracketIncoherences.value) {
271
+ diagnostics.push({
272
+ code: 'W021',
273
+ severity: SEVERITY.WARNING,
274
+ message: mm.kind === 'missing-bracket'
275
+ ? `Phase ${mm.phaseId}: heading is not in bracket form under the 'bracket' convention (expected \`[CODE.${mm.sectionMilestone}] ${mm.phaseId}:\`)`
276
+ : `Phase ${mm.phaseId}: bracket milestone ${mm.phaseMilestone} does not match its section milestone ${mm.sectionMilestone}`,
277
+ remedy: adviseRemedy('Bracket migration lands with the #612 migrator (PR-3); until then, manually align the bracket milestone in this heading to match the enclosing section.'),
278
+ });
279
+ }
257
280
  }
258
281
  return diagnostics;
259
282
  },
260
283
  };
284
+ /** The milestone-prefixed half of W021, unchanged by #612. */
285
+ function checkMilestonePrefixW021(snapshot) {
286
+ const diagnostics = [];
287
+ for (const entry of snapshot.roadmapDeclaredPhases.value) {
288
+ // `entry.milestone === null` means the builder never found this phase
289
+ // heading inside any versioned (`v\d+\.\d+`) section — the original
290
+ // `checkMilestonePrefixMismatches` only ever iterates phases found
291
+ // WITHIN a section, so a phase outside any section is equivalently
292
+ // never checked here.
293
+ if (entry.milestone === null)
294
+ continue;
295
+ const expectedMilestone = getMilestoneFromPhaseId(entry.phaseId);
296
+ if (expectedMilestone === null || expectedMilestone === entry.milestone)
297
+ continue;
298
+ diagnostics.push({
299
+ code: 'W021',
300
+ severity: SEVERITY.WARNING,
301
+ message: `Phase ${entry.phaseId}: integer prefix implies ${expectedMilestone} but listed under ${entry.milestone}`,
302
+ remedy: adviseRemedy('gsd-tools roadmap upgrade --convention milestone-prefixed'),
303
+ });
304
+ }
305
+ return diagnostics;
306
+ }
261
307
  // ─── W026 — STATE says milestone complete but ROADMAP lists unstarted phase ─
262
308
  const RULE_W026 = {
263
309
  code: 'W026',
@@ -282,7 +328,14 @@ const RULE_W026 = {
282
328
  // unwindowed `phaseDirNames2` (`verify.cts:2372-2382`, a direct
283
329
  // `readdirSync` of the phases dir), not the current-milestone-windowed
284
330
  // `phaseDirs`.
285
- const hasDirectory = matchPhaseDirs(snapshot.allPhaseDirNames.value, normalized).matches.length > 0;
331
+ // #612: the directory read widens with the heading read that produced
332
+ // `currentMilestoneRoadmapPhaseIds`, or every bracket phase resolves to
333
+ // nothing, reads as unstarted, and this UNGATED warning false-fires on
334
+ // any bracket repo whose STATE says the milestone is complete. #2528
335
+ // moved the read onto the shared selector; the convention rides along,
336
+ // since the selector's primary match IS the `phaseTokenMatches` call this
337
+ // line used to make directly.
338
+ const hasDirectory = matchPhaseDirs(snapshot.allPhaseDirNames.value, normalized, snapshot.phaseIdConvention).matches.length > 0;
286
339
  if (!hasDirectory)
287
340
  unstarted.push(phaseId);
288
341
  }
@@ -35,10 +35,8 @@
35
35
  * src/health-diagnostic-rules/worktree-health.cts, compiled to
36
36
  * gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs (gitignored).
37
37
  */
38
- var __importDefault = (this && this.__importDefault) || function (mod) {
39
- return (mod && mod.__esModule) ? mod : { "default": mod };
40
- };
41
- const node_path_1 = __importDefault(require("node:path"));
38
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
39
+ const shellCmdProjection = require("../shell-command-projection.cjs");
42
40
  // eslint-disable-next-line @typescript-eslint/no-require-imports
43
41
  const healthDiagnosticMod = require("../health-diagnostic-types.cjs");
44
42
  const { SEVERITY, adviseRemedy } = healthDiagnosticMod;
@@ -121,15 +119,31 @@ function checkW017(snapshot) {
121
119
  // against `process.cwd()`. Per this batch's brief: the interpolated command
122
120
  // (with the real path) lives in `message`; `remedy.args.command` stays a
123
121
  // static `<path>` template, mirroring the split the brief specifies.
122
+ // ─── #3663 — path-comparison provenance helper ─────────────────────────────
123
+ //
124
+ // snapshot.cwd is raw process-cwd-derived — path.resolve() normalizes
125
+ // separators and relative segments but NOT casing, and a process launched via
126
+ // a differently-cased path echoes that spelling back. finding.path is
127
+ // `git worktree list`-derived, which self-normalizes to the canonical
128
+ // on-disk casing (forward slashes). Comparing those two spellings strictly
129
+ // misclassifies the ACTIVE worktree as stale on win32 — so the comparison
130
+ // folds case ONLY on win32 (case-insensitive filesystem, via the Shell
131
+ // Command Projection seam's toComparablePathKey — the platform-conditional
132
+ // fold policy lives there, not per call site) and stays case-sensitive on
133
+ // POSIX, where differently-cased paths are genuinely different directories.
134
+ // No realpath resolution — that would change symlink matching behavior.
135
+ function isActiveWorktreePath(activeCwd, worktreePath, platform = process.platform) {
136
+ const active = shellCmdProjection.toComparablePathKey(activeCwd, platform);
137
+ const worktree = shellCmdProjection.toComparablePathKey(worktreePath, platform);
138
+ return active === worktree || active.startsWith(worktree + '/');
139
+ }
124
140
  function checkW027(snapshot) {
125
141
  const diagnostics = [];
126
142
  const activeCwd = snapshot.cwd;
127
143
  for (const finding of snapshot.worktreeHealth.value) {
128
144
  if (finding.kind !== 'stale')
129
145
  continue;
130
- const normalizedWorktree = node_path_1.default.resolve(finding.path);
131
- const isActiveWorktree = activeCwd === normalizedWorktree || activeCwd.startsWith(normalizedWorktree + node_path_1.default.sep);
132
- if (isActiveWorktree)
146
+ if (isActiveWorktreePath(activeCwd, finding.path))
133
147
  continue;
134
148
  diagnostics.push({
135
149
  code: 'W027',
@@ -170,4 +184,4 @@ const RULES = [
170
184
  check: checkW027,
171
185
  },
172
186
  ];
173
- module.exports = { RULES };
187
+ module.exports = { RULES, isActiveWorktreePath };
@@ -103,7 +103,7 @@ const CONSISTENCY_RULES = [
103
103
  // (`verify.cts:2405-2553`) — ported verbatim, not reinvented.
104
104
  // eslint-disable-next-line @typescript-eslint/no-require-imports
105
105
  const planningWorkspaceMod = require("./planning-workspace.cjs");
106
- const { planningRoot, planningDir } = planningWorkspaceMod;
106
+ const { planningDir } = planningWorkspaceMod;
107
107
  // eslint-disable-next-line @typescript-eslint/no-require-imports
108
108
  const configLoaderMod = require("./config-loader.cjs");
109
109
  const { CONFIG_DEFAULTS } = configLoaderMod;
@@ -113,6 +113,12 @@ const { getMilestoneInfo } = roadmapParserMod;
113
113
  // eslint-disable-next-line @typescript-eslint/no-require-imports
114
114
  const stateMod = require("./state.cjs");
115
115
  const { writeStateMd } = stateMod;
116
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
117
+ const frontmatter = require("./frontmatter.cjs");
118
+ const { extractFrontmatter } = frontmatter;
119
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
120
+ const stateTransitionMod = require("./state-transition.cjs");
121
+ const { rebuildStateTransaction } = stateTransitionMod;
116
122
  const clock_cjs_1 = require("./clock.cjs");
117
123
  const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs");
118
124
  const runtime_slash_cjs_1 = require("./runtime-slash.cjs");
@@ -160,7 +166,13 @@ function evaluateConsistencyRules(snapshot) {
160
166
  * document for the read side.
161
167
  */
162
168
  function repairPaths(cwd) {
163
- const rootBase = planningRoot(cwd);
169
+ // #3749: the project root is PROJECT-aware but deliberately NOT workstream-
170
+ // scoped — under GSD_PROJECT, config.json/MILESTONES.md/milestones belong to
171
+ // `.planning/<project>/` (the same base init.new-project's config_path
172
+ // names); under GSD_WORKSTREAM they stay at the workstream PARENT, keeping
173
+ // the documented root-vs-workstream split. planningDir(cwd, null) is exactly
174
+ // that base: project env honored, ws env suppressed.
175
+ const rootBase = planningDir(cwd, null);
164
176
  const wsBase = planningDir(cwd);
165
177
  return {
166
178
  rootBase,
@@ -268,7 +280,15 @@ function runRepairAction(cwd, action, paths) {
268
280
  stateContent += `**Status:** Resuming\n\n`;
269
281
  stateContent += `## Session Log\n\n`;
270
282
  stateContent += `- ${clock_cjs_1.realClock.localToday()}: STATE.md regenerated by ${slash('health')} --repair\n`;
271
- writeStateMd(statePath, stateContent, cwd);
283
+ // ADR-3473 §8.6: `/gsd-health --repair` is a factory reset, so
284
+ // preservation must not run; the snapshot of the file being replaced is
285
+ // still captured, and `{}` is the correct, legal snapshot of a
286
+ // STATE.md that had no parseable frontmatter — which is the usual
287
+ // reason this repair fires.
288
+ const priorState = node_fs_1.default.existsSync(statePath) ? ((0, shell_command_projection_cjs_1.platformReadSync)(statePath) ?? '') : '';
289
+ writeStateMd(statePath, stateContent, rebuildStateTransaction({
290
+ snapshot: extractFrontmatter(priorState, statePath),
291
+ }), cwd);
272
292
  return { success: true, path: 'STATE.md', extraDetails };
273
293
  }
274
294
  case REMEDY_ACTION.ADD_NYQUIST_KEY:
@@ -72,7 +72,7 @@ const INTERFACE_POINTS = Object.freeze(['command', 'dispatch', 'model', 'hooks',
72
72
  const SAFE_DEFAULTS = {
73
73
  embeddingMode: 'declarative',
74
74
  commandSurface: 'prose-only',
75
- dispatch: { namedDispatch: false, nested: false, maxDepth: 0, background: false, subagentToolkit: 'read-only', backgroundDispatch: false, isolation: 'none' },
75
+ dispatch: { namedDispatch: false, nested: false, maxDepth: 0, background: false, subagentToolkit: 'read-only', backgroundDispatch: false, isolation: 'none', maxConcurrency: 1 },
76
76
  modelMode: 'passive',
77
77
  hookBus: 'none',
78
78
  stateIO: 'session-log-append',
@@ -84,7 +84,7 @@ const PROFILE_BASELINES = Object.freeze({
84
84
  'programmatic-cli': Object.freeze({
85
85
  embeddingMode: 'imperative',
86
86
  commandSurface: 'slash-file',
87
- dispatch: Object.freeze({ namedDispatch: true, nested: true, maxDepth: -1, background: true, subagentToolkit: 'full', backgroundDispatch: true, isolation: 'none' }),
87
+ dispatch: Object.freeze({ namedDispatch: true, nested: true, maxDepth: -1, background: true, subagentToolkit: 'full', backgroundDispatch: true, isolation: 'none', maxConcurrency: 1 }),
88
88
  modelMode: 'passive',
89
89
  hookBus: 'host',
90
90
  stateIO: 'filesystem',
@@ -95,7 +95,7 @@ const PROFILE_BASELINES = Object.freeze({
95
95
  'declarative-cli': Object.freeze({
96
96
  embeddingMode: 'declarative',
97
97
  commandSurface: 'slash-file',
98
- dispatch: Object.freeze({ namedDispatch: true, nested: false, maxDepth: 1, background: false, subagentToolkit: 'full', backgroundDispatch: false, isolation: 'none' }),
98
+ dispatch: Object.freeze({ namedDispatch: true, nested: false, maxDepth: 1, background: false, subagentToolkit: 'full', backgroundDispatch: false, isolation: 'none', maxConcurrency: 1 }),
99
99
  modelMode: 'passive',
100
100
  hookBus: 'host',
101
101
  stateIO: 'filesystem',
@@ -106,7 +106,7 @@ const PROFILE_BASELINES = Object.freeze({
106
106
  'ide': Object.freeze({
107
107
  embeddingMode: 'imperative',
108
108
  commandSurface: 'palette',
109
- dispatch: Object.freeze({ namedDispatch: true, nested: true, maxDepth: 5, background: true, subagentToolkit: 'full', backgroundDispatch: true, isolation: 'none' }),
109
+ dispatch: Object.freeze({ namedDispatch: true, nested: true, maxDepth: 5, background: true, subagentToolkit: 'full', backgroundDispatch: true, isolation: 'none', maxConcurrency: 1 }),
110
110
  modelMode: 'active',
111
111
  hookBus: 'engine',
112
112
  stateIO: 'sandboxed-storage',
@@ -235,7 +235,7 @@ const DEFAULT_ENGINE = {
235
235
  axes: {
236
236
  embeddingMode: 'imperative',
237
237
  commandSurface: 'slash-file',
238
- dispatch: { namedDispatch: true, nested: true, maxDepth: -1, background: true, subagentToolkit: 'full', backgroundDispatch: true, isolation: 'none' },
238
+ dispatch: { namedDispatch: true, nested: true, maxDepth: -1, background: true, subagentToolkit: 'full', backgroundDispatch: true, isolation: 'none', maxConcurrency: 1 },
239
239
  modelMode: 'active',
240
240
  hookBus: 'host',
241
241
  stateIO: 'filesystem',
@@ -246,6 +246,19 @@ const DEFAULT_ENGINE = {
246
246
  known: HOST_INTEGRATION_AXES,
247
247
  };
248
248
  // ---------------------------------------------------------------------------
249
+ // isPositiveSafeInteger — shared predicate (#3673)
250
+ // ---------------------------------------------------------------------------
251
+ /**
252
+ * True iff `v` is a positive (>0) JS safe integer. Single source of truth for
253
+ * the dispatch.maxConcurrency contract: used by negotiateHostCapabilities
254
+ * below, and by gsd-core/bin/gsd-tools.cjs's routeDispatchCapacity (which
255
+ * requires this module's compiled output rather than reimplementing the
256
+ * predicate), so the two consumers cannot silently diverge.
257
+ */
258
+ function isPositiveSafeInteger(v) {
259
+ return typeof v === 'number' && Number.isSafeInteger(v) && v > 0;
260
+ }
261
+ // ---------------------------------------------------------------------------
249
262
  // negotiateHostCapabilities
250
263
  // ---------------------------------------------------------------------------
251
264
  /**
@@ -335,6 +348,7 @@ function negotiateHostCapabilities(host, engine = DEFAULT_ENGINE) {
335
348
  let effectiveSubagentToolkit;
336
349
  let effectiveMaxDepth;
337
350
  let effectiveIsolation;
351
+ let effectiveMaxConcurrency;
338
352
  if (hostDispatch === null) {
339
353
  // Host didn't declare dispatch at all — fail-closed to most-restrictive values
340
354
  warnings.push(`host did not declare 'dispatch'`);
@@ -345,6 +359,7 @@ function negotiateHostCapabilities(host, engine = DEFAULT_ENGINE) {
345
359
  effectiveSubagentToolkit = 'read-only';
346
360
  effectiveMaxDepth = 0;
347
361
  effectiveIsolation = 'none';
362
+ effectiveMaxConcurrency = 1;
348
363
  }
349
364
  else {
350
365
  // N1: observability warnings for 'undocumented' sentinel on dispatch fields
@@ -408,6 +423,41 @@ function negotiateHostCapabilities(host, engine = DEFAULT_ENGINE) {
408
423
  const eDepthNum = engineDispatch.maxDepth < 0 ? Infinity : engineDispatch.maxDepth;
409
424
  const minDepth = Math.min(hDepthNum, eDepthNum);
410
425
  effectiveMaxDepth = minDepth === Infinity ? -1 : minDepth;
426
+ // maxConcurrency (#3673, ADR-1239 Phase 1): a positive-safe-integer
427
+ // passthrough with a fail-closed floor of 1. UNLIKE maxDepth, there is no
428
+ // min(host, engine) reduction here — the design doc explicitly rejects an
429
+ // engine-side ceiling for this field (no competing intrinsic worker
430
+ // ceiling to cap against at the negotiation layer); a `--jobs N` cap is
431
+ // applied later, at the Phase 4 scheduler.
432
+ const hostMaxConcurrency = hostDispatch.maxConcurrency;
433
+ if (hostMaxConcurrency === UNDOCUMENTED) {
434
+ warnings.push(`dispatch.maxConcurrency is undocumented — degraded closed (1)`);
435
+ effectiveMaxConcurrency = 1;
436
+ }
437
+ else if (isPositiveSafeInteger(hostMaxConcurrency)) {
438
+ effectiveMaxConcurrency = hostMaxConcurrency;
439
+ }
440
+ else if (hostMaxConcurrency === undefined) {
441
+ warnings.push(`host did not declare 'dispatch.maxConcurrency' — treating as 1`);
442
+ effectiveMaxConcurrency = 1;
443
+ }
444
+ else if (typeof hostMaxConcurrency !== 'number') {
445
+ warnings.push(`host dispatch.maxConcurrency is not a number — treating as 1`);
446
+ effectiveMaxConcurrency = 1;
447
+ }
448
+ else if (!Number.isSafeInteger(hostMaxConcurrency)) {
449
+ if (Number.isInteger(hostMaxConcurrency)) {
450
+ warnings.push(`host dispatch.maxConcurrency is an unsafe integer — treating as 1`);
451
+ }
452
+ else {
453
+ warnings.push(`host dispatch.maxConcurrency is not an integer — treating as 1`);
454
+ }
455
+ effectiveMaxConcurrency = 1;
456
+ }
457
+ else {
458
+ warnings.push(`host dispatch.maxConcurrency is non-positive — treating as 1`);
459
+ effectiveMaxConcurrency = 1;
460
+ }
411
461
  // If namedDispatch is false, cap maxDepth/nested/background/backgroundDispatch to 0/false/false/false (struct consistency)
412
462
  if (!effectiveNamedDispatch) {
413
463
  effectiveMaxDepth = 0;
@@ -424,6 +474,7 @@ function negotiateHostCapabilities(host, engine = DEFAULT_ENGINE) {
424
474
  subagentToolkit: effectiveSubagentToolkit,
425
475
  backgroundDispatch: effectiveBackgroundDispatch,
426
476
  isolation: effectiveIsolation,
477
+ maxConcurrency: effectiveMaxConcurrency,
427
478
  };
428
479
  // ---------------------------------------------------------------------------
429
480
  // Assemble effective axes
@@ -653,10 +704,25 @@ function extensionEventSurfaceFor(extensionEvents) {
653
704
  * per-host branch ADR-1239 exists to remove. Omit `prompt` entirely and the
654
705
  * resolution is byte-identical to Phase 2's (the unconsumed-resolver shape).
655
706
  *
656
- * Argv order is base args → cwd flag → prompt, so the prompt stays the final
657
- * positional token for the hosts that read it that way.
707
+ * Argv order is base args → model flag → cwd flag → prompt, so the prompt
708
+ * stays the final positional token for the hosts that read it that way. The
709
+ * model flag is placed BEFORE the cwd flag (not after, and not appended at
710
+ * the very end) purely to keep it clear of that trailing positional — the
711
+ * model value itself is never the prompt-adjacent token a host might scan
712
+ * for last.
713
+ *
714
+ * `model` (Phase 4, #3714) is optional, descriptor-gated exactly like prompt:
715
+ * a `modelFlag` string on the descriptor names the flag that pins the
716
+ * spawned executor's model (codex: `--model`); `null`/absent means the host
717
+ * exposes no such override on this exec path, and `[modelFlag, model]` is
718
+ * appended ONLY when both the descriptor's `modelFlag` and the caller's
719
+ * `model` are non-empty strings. Omitting `model` entirely (or passing it to
720
+ * a host with no `modelFlag`) is byte-identical to the resolver's behavior
721
+ * before this parameter existed. This function decides no policy about WHICH
722
+ * model to pass or what 'inherit' means — that is entirely the caller's job;
723
+ * this seam only shapes descriptor + values into argv.
658
724
  */
659
- function resolveOrchestratorExec(orchestratorExec, cwd, prompt) {
725
+ function resolveOrchestratorExec(orchestratorExec, cwd, prompt, model) {
660
726
  if (!orchestratorExec || typeof orchestratorExec !== 'object' || Array.isArray(orchestratorExec)) {
661
727
  return { ok: false, reason: 'missing_command' };
662
728
  }
@@ -676,11 +742,22 @@ function resolveOrchestratorExec(orchestratorExec, cwd, prompt) {
676
742
  if (oe.promptFlag !== undefined && oe.promptFlag !== null && typeof oe.promptFlag !== 'string') {
677
743
  return { ok: false, reason: 'invalid_prompt_flag' };
678
744
  }
745
+ if (oe.modelFlag !== undefined && oe.modelFlag !== null && typeof oe.modelFlag !== 'string') {
746
+ return { ok: false, reason: 'invalid_model_flag' };
747
+ }
679
748
  // An executor spawned with no instruction is a hang, not a degraded run —
680
749
  // fail closed rather than launching a prompt-less process.
681
750
  if (prompt !== undefined && (typeof prompt !== 'string' || prompt.length === 0)) {
682
751
  return { ok: false, reason: 'invalid_prompt' };
683
752
  }
753
+ // Unlike `prompt` — where empty is a hang, not a degraded run, hence the
754
+ // fail-closed check above — an absent/null/empty model is simply "use the
755
+ // host default", the same benign degradation `cwdFlag: null` already
756
+ // expresses. Only a present-but-non-string value (number/bool/array/object)
757
+ // is a caller error; null/undefined/'' fall through to "omit the flag".
758
+ if (model !== undefined && model !== null && typeof model !== 'string') {
759
+ return { ok: false, reason: 'invalid_model' };
760
+ }
684
761
  // Leading-dash guard, mirroring worktree-safety.cts's `unsafe_leading_dash`
685
762
  // check on git arguments. A positional prompt (or a cwd) beginning with '-'
686
763
  // is parsed by the spawned CLI as a FLAG, not a value — the same failure the
@@ -695,10 +772,17 @@ function resolveOrchestratorExec(orchestratorExec, cwd, prompt) {
695
772
  if (cwd.startsWith('-')) {
696
773
  return { ok: false, reason: 'unsafe_leading_dash_cwd' };
697
774
  }
775
+ if (typeof model === 'string' && model.startsWith('-')) {
776
+ return { ok: false, reason: 'unsafe_leading_dash_model' };
777
+ }
698
778
  const baseArgs = Array.isArray(oe.args) ? [...oe.args] : [];
699
- const args = typeof oe.cwdFlag === 'string' && oe.cwdFlag.length > 0
700
- ? [...baseArgs, oe.cwdFlag, cwd]
701
- : baseArgs;
779
+ let args = baseArgs;
780
+ if (typeof oe.modelFlag === 'string' && oe.modelFlag.length > 0 && typeof model === 'string' && model.length > 0) {
781
+ args = [...args, oe.modelFlag, model];
782
+ }
783
+ args = typeof oe.cwdFlag === 'string' && oe.cwdFlag.length > 0
784
+ ? [...args, oe.cwdFlag, cwd]
785
+ : args;
702
786
  if (typeof prompt === 'string') {
703
787
  if (typeof oe.promptFlag === 'string' && oe.promptFlag.length > 0) {
704
788
  args.push(oe.promptFlag, prompt);
@@ -720,6 +804,7 @@ module.exports = {
720
804
  EXTENSION_EVENT_SURFACES,
721
805
  degradationFor,
722
806
  profileOf,
807
+ isPositiveSafeInteger,
723
808
  negotiateHostCapabilities,
724
809
  shouldFlattenDispatch,
725
810
  resolveDispatchType,