@opengsd/gsd-core 1.15.0 → 1.16.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 (487) 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 +85 -5
  4. package/agents/gsd-code-fixer.compact.md +1 -1
  5. package/agents/gsd-code-fixer.md +1 -1
  6. package/agents/gsd-code-reviewer.compact.md +5 -3
  7. package/agents/gsd-code-reviewer.md +8 -6
  8. package/agents/gsd-debug-session-manager.compact.md +1 -1
  9. package/agents/gsd-debug-session-manager.md +1 -1
  10. package/agents/gsd-debugger.md +2 -2
  11. package/agents/gsd-eval-auditor.compact.md +1 -1
  12. package/agents/gsd-eval-auditor.md +1 -1
  13. package/agents/gsd-executor.md +4 -4
  14. package/agents/gsd-intel-updater.compact.md +1 -1
  15. package/agents/gsd-intel-updater.md +1 -1
  16. package/agents/gsd-mempalace-curator.md +2 -2
  17. package/agents/gsd-phase-researcher.md +1 -1
  18. package/agents/gsd-plan-checker.md +7 -2
  19. package/agents/gsd-planner.md +3 -3
  20. package/agents/gsd-project-researcher.compact.md +1 -1
  21. package/agents/gsd-project-researcher.md +1 -1
  22. package/agents/gsd-research-synthesizer.compact.md +1 -1
  23. package/agents/gsd-research-synthesizer.md +1 -1
  24. package/agents/gsd-ui-auditor.compact.md +21 -30
  25. package/agents/gsd-ui-auditor.md +42 -51
  26. package/agents/gsd-ui-researcher.compact.md +1 -1
  27. package/agents/gsd-ui-researcher.md +1 -1
  28. package/agents/gsd-verifier.md +31 -9
  29. package/bin/install.js +126 -196
  30. package/commands/gsd/add-tests.md +6 -1
  31. package/commands/gsd/ai-integration-phase.md +6 -1
  32. package/commands/gsd/audit-fix.md +5 -0
  33. package/commands/gsd/audit-milestone.md +6 -1
  34. package/commands/gsd/autonomous.md +5 -0
  35. package/commands/gsd/capture.md +8 -4
  36. package/commands/gsd/code-review.md +7 -2
  37. package/commands/gsd/complete-milestone.md +4 -0
  38. package/commands/gsd/config.md +7 -3
  39. package/commands/gsd/debug.md +11 -7
  40. package/commands/gsd/discuss-phase.md +7 -3
  41. package/commands/gsd/docs-update.md +12 -7
  42. package/commands/gsd/eval-review.md +6 -1
  43. package/commands/gsd/execute-phase.md +12 -7
  44. package/commands/gsd/extract-learnings.md +5 -0
  45. package/commands/gsd/fast.md +4 -0
  46. package/commands/gsd/forensics.md +5 -1
  47. package/commands/gsd/graphify.md +10 -6
  48. package/commands/gsd/health.md +5 -0
  49. package/commands/gsd/help.md +7 -2
  50. package/commands/gsd/import.md +7 -3
  51. package/commands/gsd/inbox.md +5 -0
  52. package/commands/gsd/ingest-docs.md +5 -1
  53. package/commands/gsd/manager.md +6 -1
  54. package/commands/gsd/map-codebase.md +7 -3
  55. package/commands/gsd/mempalace-capture.md +5 -1
  56. package/commands/gsd/mempalace-recall.md +5 -1
  57. package/commands/gsd/milestone-summary.md +5 -1
  58. package/commands/gsd/mvp-phase.md +8 -3
  59. package/commands/gsd/new-milestone.md +6 -1
  60. package/commands/gsd/new-project.md +5 -0
  61. package/commands/gsd/next.md +6 -1
  62. package/commands/gsd/ns-context.md +4 -0
  63. package/commands/gsd/ns-ideate.md +4 -0
  64. package/commands/gsd/ns-manage.md +4 -0
  65. package/commands/gsd/ns-project.md +4 -0
  66. package/commands/gsd/ns-review.md +4 -0
  67. package/commands/gsd/ns-workflow.md +4 -0
  68. package/commands/gsd/onboard.md +6 -1
  69. package/commands/gsd/pause-work.md +5 -1
  70. package/commands/gsd/phase.md +8 -4
  71. package/commands/gsd/plan-phase.md +6 -1
  72. package/commands/gsd/plan-review-convergence.md +5 -1
  73. package/commands/gsd/pr-branch.md +4 -0
  74. package/commands/gsd/profile-user.md +5 -1
  75. package/commands/gsd/progress.md +6 -1
  76. package/commands/gsd/quick-batch.md +20 -8
  77. package/commands/gsd/quick.md +12 -7
  78. package/commands/gsd/review.md +5 -1
  79. package/commands/gsd/secure-phase.md +6 -1
  80. package/commands/gsd/ship.md +5 -0
  81. package/commands/gsd/sketch.md +7 -2
  82. package/commands/gsd/spec-phase.md +5 -1
  83. package/commands/gsd/spike.md +8 -3
  84. package/commands/gsd/surface.md +5 -1
  85. package/commands/gsd/thread.md +4 -0
  86. package/commands/gsd/ui-phase.md +6 -1
  87. package/commands/gsd/ui-review.md +6 -1
  88. package/commands/gsd/ultraplan-phase.md +5 -1
  89. package/commands/gsd/undo.md +5 -1
  90. package/commands/gsd/update.md +6 -2
  91. package/commands/gsd/validate-phase.md +6 -1
  92. package/commands/gsd/verify-work.md +6 -1
  93. package/commands/gsd/workspace.md +7 -3
  94. package/gsd-core/bin/gsd-tools.cjs +142 -56
  95. package/gsd-core/bin/lib/active-workstream-store.cjs +15 -0
  96. package/gsd-core/bin/lib/agent-install-check.cjs +4 -1
  97. package/gsd-core/bin/lib/audit.cjs +78 -44
  98. package/gsd-core/bin/lib/broken-windows.cjs +13 -13
  99. package/gsd-core/bin/lib/capability-activation.cjs +9 -4
  100. package/gsd-core/bin/lib/capability-registry.cjs +183 -103
  101. package/gsd-core/bin/lib/capability-validator.cjs +16 -0
  102. package/gsd-core/bin/lib/check-auto-mode.cjs +35 -0
  103. package/gsd-core/bin/lib/check-command-router.cjs +164 -1712
  104. package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +13 -2
  105. package/gsd-core/bin/lib/cli-exit.cjs +12 -0
  106. package/gsd-core/bin/lib/codex-agent-toml.cjs +11 -8
  107. package/gsd-core/bin/lib/command-aliases.cjs +7 -0
  108. package/gsd-core/bin/lib/command-routing-hub.cjs +48 -1
  109. package/gsd-core/bin/lib/commands.cjs +173 -170
  110. package/gsd-core/bin/lib/complexity-trigger.cjs +8 -7
  111. package/gsd-core/bin/lib/config.cjs +43 -12
  112. package/gsd-core/bin/lib/core-utils.cjs +6 -1
  113. package/gsd-core/bin/lib/coverage.cjs +4 -8
  114. package/gsd-core/bin/lib/decision-coverage-support.cjs +259 -0
  115. package/gsd-core/bin/lib/drift.cjs +177 -42
  116. package/gsd-core/bin/lib/frontmatter-fence.cjs +90 -0
  117. package/gsd-core/bin/lib/frontmatter-splice.cjs +494 -0
  118. package/gsd-core/bin/lib/frontmatter.cjs +413 -234
  119. package/gsd-core/bin/lib/gap-checker.cjs +72 -29
  120. package/gsd-core/bin/lib/gate-api-coverage-verify-pre.cjs +381 -0
  121. package/gsd-core/bin/lib/gate-args.cjs +53 -0
  122. package/gsd-core/bin/lib/gate-codebase-drift.cjs +285 -0
  123. package/gsd-core/bin/lib/gate-config.cjs +46 -0
  124. package/gsd-core/bin/lib/gate-context-drift.cjs +141 -0
  125. package/gsd-core/bin/lib/gate-decision-coverage-plan.cjs +169 -0
  126. package/gsd-core/bin/lib/gate-decision-coverage-verify.cjs +126 -0
  127. package/gsd-core/bin/lib/gate-evaluation-scope.cjs +555 -0
  128. package/gsd-core/bin/lib/gate-evidence.cjs +138 -0
  129. package/gsd-core/bin/lib/gate-exit.cjs +27 -0
  130. package/gsd-core/bin/lib/gate-gap-analysis-plan-post.cjs +61 -0
  131. package/gsd-core/bin/lib/gate-phase-context.cjs +170 -0
  132. package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +1 -1
  133. package/gsd-core/bin/lib/gate-predicate.cjs +165 -0
  134. package/gsd-core/bin/lib/gate-prohibition-enforcement.cjs +94 -0
  135. package/gsd-core/bin/lib/gate-schema-drift.cjs +165 -0
  136. package/gsd-core/bin/lib/gate-tdd-red-evidence.cjs +100 -0
  137. package/gsd-core/bin/lib/gate-tdd-review-checkpoint.cjs +182 -0
  138. package/gsd-core/bin/lib/gate-ui-plan.cjs +86 -0
  139. package/gsd-core/bin/lib/gate-ui-safety.cjs +80 -0
  140. package/gsd-core/bin/lib/gate-verdict.cjs +64 -0
  141. package/gsd-core/bin/lib/gate-verify-command-paths.cjs +78 -0
  142. package/gsd-core/bin/lib/gate-verify-failure-directions.cjs +41 -0
  143. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +43 -47
  144. package/gsd-core/bin/lib/health-diagnostic.cjs +45 -8
  145. package/gsd-core/bin/lib/init.cjs +162 -96
  146. package/gsd-core/bin/lib/install-engine.cjs +19 -35
  147. package/gsd-core/bin/lib/install-profiles.cjs +7 -4
  148. package/gsd-core/bin/lib/io.cjs +122 -3
  149. package/gsd-core/bin/lib/loop-resolver.cjs +95 -0
  150. package/gsd-core/bin/lib/markdown-sectionizer.cjs +75 -1
  151. package/gsd-core/bin/lib/milestone.cjs +19 -1
  152. package/gsd-core/bin/lib/model-resolver.cjs +18 -18
  153. package/gsd-core/bin/lib/observability/event.cjs +1 -1
  154. package/gsd-core/bin/lib/observability/logger.cjs +46 -1
  155. package/gsd-core/bin/lib/pattern.cjs +10 -0
  156. package/gsd-core/bin/lib/phase-command-router.cjs +11 -4
  157. package/gsd-core/bin/lib/phase-estimation.cjs +5 -4
  158. package/gsd-core/bin/lib/phase-id.cjs +1 -1
  159. package/gsd-core/bin/lib/phase-lifecycle.cjs +9 -2
  160. package/gsd-core/bin/lib/phase-status.cjs +360 -0
  161. package/gsd-core/bin/lib/phase.cjs +280 -80
  162. package/gsd-core/bin/lib/plan-document.cjs +93 -19
  163. package/gsd-core/bin/lib/plan-drift-guard.cjs +5 -0
  164. package/gsd-core/bin/lib/planning-document.cjs +273 -40
  165. package/gsd-core/bin/lib/planning-inspect.cjs +42 -8
  166. package/gsd-core/bin/lib/planning-snapshot.cjs +18 -0
  167. package/gsd-core/bin/lib/planning-workspace.cjs +76 -53
  168. package/gsd-core/bin/lib/pristine-baseline.cjs +10 -0
  169. package/gsd-core/bin/lib/profile-output.cjs +6 -3
  170. package/gsd-core/bin/lib/prohibition-enforcement.cjs +0 -55
  171. package/gsd-core/bin/lib/quick-batch-command-router.cjs +35 -9
  172. package/gsd-core/bin/lib/quick-batch-dispatch.cjs +11 -8
  173. package/gsd-core/bin/lib/real-home-guard.cjs +9 -1
  174. package/gsd-core/bin/lib/report-parser.cjs +269 -0
  175. package/gsd-core/bin/lib/roadmap-command-router.cjs +13 -15
  176. package/gsd-core/bin/lib/roadmap-parser.cjs +82 -15
  177. package/gsd-core/bin/lib/roadmap-upgrade.cjs +127 -65
  178. package/gsd-core/bin/lib/roadmap.cjs +169 -72
  179. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +91 -157
  180. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +2 -1
  181. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +57 -1
  182. package/gsd-core/bin/lib/runtime-homes.cjs +13 -10
  183. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +307 -591
  184. package/gsd-core/bin/lib/runtime-name-policy.cjs +142 -27
  185. package/gsd-core/bin/lib/runtime-slash.cjs +47 -30
  186. package/gsd-core/bin/lib/shell-command-projection.cjs +37 -2
  187. package/gsd-core/bin/lib/smart-entry.cjs +19 -3
  188. package/gsd-core/bin/lib/stale-bake-guard.cjs +32 -48
  189. package/gsd-core/bin/lib/state-contract.cjs +15 -18
  190. package/gsd-core/bin/lib/state-document.cjs +100 -22
  191. package/gsd-core/bin/lib/state.cjs +214 -105
  192. package/gsd-core/bin/lib/surface.cjs +2 -1
  193. package/gsd-core/bin/lib/tdd-red-evidence.cjs +48 -152
  194. package/gsd-core/bin/lib/uat-predicate.cjs +313 -35
  195. package/gsd-core/bin/lib/uat.cjs +424 -7
  196. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +94 -58
  197. package/gsd-core/bin/lib/vendor/README.md +31 -9
  198. package/gsd-core/bin/lib/vendor/saxes.cjs +1934 -0
  199. package/gsd-core/bin/lib/vendor/saxes.cjs.LICENSE.txt +92 -0
  200. package/gsd-core/bin/lib/vendor/tap-parser.cjs +8927 -0
  201. package/gsd-core/bin/lib/vendor/tap-parser.cjs.LICENSE.txt +152 -0
  202. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  203. package/gsd-core/bin/lib/verification.cjs +1165 -314
  204. package/gsd-core/bin/lib/verify-command-router.cjs +18 -7
  205. package/gsd-core/bin/lib/verify.cjs +286 -567
  206. package/gsd-core/bin/lib/workstream-inventory-builder.cjs +14 -6
  207. package/gsd-core/bin/lib/workstream-inventory.cjs +31 -21
  208. package/gsd-core/bin/lib/workstream-name-policy.cjs +31 -1
  209. package/gsd-core/bin/lib/workstream.cjs +11 -2
  210. package/gsd-core/bin/shared/config-defaults.manifest.json +5 -0
  211. package/gsd-core/bin/shared/config-schema.manifest.json +4 -0
  212. package/gsd-core/references/autonomous-smart-discuss.md +2 -1
  213. package/gsd-core/references/autonomous-ui-design-contract.md +3 -3
  214. package/gsd-core/references/execute-mvp-tdd.md +5 -10
  215. package/gsd-core/references/execute-phase-between-wave-reset.md +3 -0
  216. package/gsd-core/references/execute-phase-response-language.md +1 -1
  217. package/gsd-core/references/gsd-run-resolver.md +1 -1
  218. package/gsd-core/references/loop-hook-dispatch.md +7 -1
  219. package/gsd-core/references/offer-next.md +1 -1
  220. package/gsd-core/references/planning-config.md +1 -1
  221. package/gsd-core/references/spidr-splitting.md +1 -1
  222. package/gsd-core/references/tdd.md +10 -4
  223. package/gsd-core/references/verifier-phase-gates.md +5 -2
  224. package/gsd-core/references/verify-mvp-mode.md +2 -2
  225. package/gsd-core/references/workstream-flag.md +33 -3
  226. package/gsd-core/templates/README.md +1 -1
  227. package/gsd-core/templates/UAT.md +17 -1
  228. package/gsd-core/templates/config.json +2 -11
  229. package/gsd-core/templates/verification-report.md +1 -1
  230. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  231. package/gsd-core/workflows/add-backlog.md +1 -1
  232. package/gsd-core/workflows/add-phase.md +8 -7
  233. package/gsd-core/workflows/add-tests.md +3 -2
  234. package/gsd-core/workflows/add-todo.md +4 -3
  235. package/gsd-core/workflows/ai-integration-phase.md +3 -2
  236. package/gsd-core/workflows/audit-fix.md +1 -1
  237. package/gsd-core/workflows/audit-milestone.md +4 -3
  238. package/gsd-core/workflows/audit-uat.md +1 -1
  239. package/gsd-core/workflows/autonomous.md +28 -18
  240. package/gsd-core/workflows/check-todos.md +6 -5
  241. package/gsd-core/workflows/cleanup.md +1 -1
  242. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +20 -13
  243. package/gsd-core/workflows/code-review-fix.md +5 -4
  244. package/gsd-core/workflows/code-review.md +84 -90
  245. package/gsd-core/workflows/complete-milestone/detail/elaboration.md +4 -3
  246. package/gsd-core/workflows/complete-milestone.md +12 -7
  247. package/gsd-core/workflows/debug.md +30 -5
  248. package/gsd-core/workflows/diagnose-issues.md +3 -2
  249. package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
  250. package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
  251. package/gsd-core/workflows/discuss-phase-assumptions.md +4 -3
  252. package/gsd-core/workflows/discuss-phase.md +4 -3
  253. package/gsd-core/workflows/do.md +1 -1
  254. package/gsd-core/workflows/docs-update.md +4 -3
  255. package/gsd-core/workflows/edit-phase.md +4 -3
  256. package/gsd-core/workflows/eval-review.md +5 -3
  257. package/gsd-core/workflows/execute-phase/detail/elaboration.md +1 -1
  258. package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +4 -2
  259. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +15 -4
  260. package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +10 -7
  261. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +1 -1
  262. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +3 -1
  263. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +2 -2
  264. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
  265. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +1 -1
  266. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +1 -1
  267. package/gsd-core/workflows/execute-phase/steps/protected-branch.md +1 -1
  268. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +1 -1
  269. package/gsd-core/workflows/execute-phase/steps/regression-gate.md +2 -0
  270. package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +1 -1
  271. package/gsd-core/workflows/execute-phase/steps/verify-phase-goal.md +187 -0
  272. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +2 -3
  273. package/gsd-core/workflows/execute-phase.md +78 -170
  274. package/gsd-core/workflows/execute-plan.md +13 -19
  275. package/gsd-core/workflows/explore.md +2 -2
  276. package/gsd-core/workflows/extract-learnings.md +3 -2
  277. package/gsd-core/workflows/fast.md +1 -1
  278. package/gsd-core/workflows/forensics.md +1 -1
  279. package/gsd-core/workflows/graduation.md +1 -1
  280. package/gsd-core/workflows/health.md +2 -1
  281. package/gsd-core/workflows/import.md +3 -2
  282. package/gsd-core/workflows/inbox.md +1 -1
  283. package/gsd-core/workflows/ingest-docs.md +1 -1
  284. package/gsd-core/workflows/insert-phase.md +4 -3
  285. package/gsd-core/workflows/list-seeds.md +1 -1
  286. package/gsd-core/workflows/list-workspaces.md +1 -1
  287. package/gsd-core/workflows/manager.md +5 -3
  288. package/gsd-core/workflows/map-codebase.md +4 -3
  289. package/gsd-core/workflows/milestone-summary.md +3 -2
  290. package/gsd-core/workflows/mvp-phase.md +14 -14
  291. package/gsd-core/workflows/new-milestone.md +10 -10
  292. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
  293. package/gsd-core/workflows/new-project.md +1 -1
  294. package/gsd-core/workflows/new-workspace.md +1 -1
  295. package/gsd-core/workflows/next.md +1 -1
  296. package/gsd-core/workflows/pause-work.md +2 -2
  297. package/gsd-core/workflows/plan-phase/detail/elaboration.md +1 -1
  298. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +1 -1
  299. package/gsd-core/workflows/plan-phase/steps/closed-phase-gate.md +1 -1
  300. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
  301. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +1 -1
  302. package/gsd-core/workflows/plan-phase.md +27 -18
  303. package/gsd-core/workflows/plan-review-convergence.md +1 -1
  304. package/gsd-core/workflows/plant-seed.md +1 -1
  305. package/gsd-core/workflows/pr-branch.md +1 -1
  306. package/gsd-core/workflows/profile-user.md +1 -1
  307. package/gsd-core/workflows/progress.md +19 -49
  308. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +4 -2
  309. package/gsd-core/workflows/quick/steps/quick-verification.md +4 -4
  310. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +30 -11
  311. package/gsd-core/workflows/quick-batch/steps/batch-init.md +1 -1
  312. package/gsd-core/workflows/quick-batch/steps/completion.md +1 -1
  313. package/gsd-core/workflows/quick-batch/steps/merge-wave.md +1 -1
  314. package/gsd-core/workflows/quick-batch/steps/planner-wave.md +1 -1
  315. package/gsd-core/workflows/quick-batch/steps/research-phase.md +1 -1
  316. package/gsd-core/workflows/quick-batch/steps/resume-mode.md +1 -1
  317. package/gsd-core/workflows/quick-batch/steps/verification-wave.md +9 -3
  318. package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
  319. package/gsd-core/workflows/quick-batch.md +15 -10
  320. package/gsd-core/workflows/quick.md +42 -31
  321. package/gsd-core/workflows/remove-phase.md +3 -2
  322. package/gsd-core/workflows/remove-workspace.md +1 -1
  323. package/gsd-core/workflows/resume-project.md +3 -2
  324. package/gsd-core/workflows/review.md +3 -2
  325. package/gsd-core/workflows/scan.md +3 -2
  326. package/gsd-core/workflows/secure-phase.md +11 -12
  327. package/gsd-core/workflows/settings-advanced.md +1 -1
  328. package/gsd-core/workflows/settings-integrations.md +1 -1
  329. package/gsd-core/workflows/settings.md +1 -1
  330. package/gsd-core/workflows/ship.md +12 -12
  331. package/gsd-core/workflows/sketch-wrap-up.md +1 -1
  332. package/gsd-core/workflows/sketch.md +1 -1
  333. package/gsd-core/workflows/smart-entry.md +1 -1
  334. package/gsd-core/workflows/spec-phase.md +1 -1
  335. package/gsd-core/workflows/spike-wrap-up.md +1 -1
  336. package/gsd-core/workflows/spike.md +1 -1
  337. package/gsd-core/workflows/stats.md +1 -1
  338. package/gsd-core/workflows/sync-skills.md +1 -1
  339. package/gsd-core/workflows/thread.md +2 -2
  340. package/gsd-core/workflows/transition.md +13 -23
  341. package/gsd-core/workflows/ui-phase.md +5 -4
  342. package/gsd-core/workflows/ui-review.md +4 -3
  343. package/gsd-core/workflows/ultraplan-phase.md +3 -2
  344. package/gsd-core/workflows/undo.md +1 -1
  345. package/gsd-core/workflows/validate-phase.md +10 -12
  346. package/gsd-core/workflows/verify-work/detail/elaboration.md +43 -3
  347. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
  348. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +5 -3
  349. package/gsd-core/workflows/verify-work.md +68 -59
  350. package/hooks/dist/gsd-agent-isolation-guard.js +8 -0
  351. package/hooks/dist/gsd-check-update-worker.js +8 -0
  352. package/hooks/dist/gsd-check-update.js +8 -0
  353. package/hooks/dist/gsd-context-monitor.js +31 -8
  354. package/hooks/dist/gsd-cursor-subagent-start.js +8 -0
  355. package/hooks/dist/gsd-secret-read-guard.js +147 -16
  356. package/hooks/dist/gsd-statusline.js +15 -7
  357. package/hooks/dist/gsd-update-banner.js +8 -0
  358. package/hooks/dist/gsd-windsurf-pre-write.js +11 -2
  359. package/hooks/dist/gsd-workflow-guard.js +5 -4
  360. package/hooks/dist/gsd-worktree-path-guard.js +6 -2
  361. package/hooks/dist/lib/cli-exit.js +12 -0
  362. package/hooks/dist/lib/git-probe.js +17 -1
  363. package/hooks/dist/lib/isolation-sentinel.js +2 -2
  364. package/hooks/gsd-agent-isolation-guard.js +8 -0
  365. package/hooks/gsd-check-update-worker.js +8 -0
  366. package/hooks/gsd-check-update.js +8 -0
  367. package/hooks/gsd-context-monitor.js +31 -8
  368. package/hooks/gsd-cursor-subagent-start.js +8 -0
  369. package/hooks/gsd-secret-read-guard.js +147 -16
  370. package/hooks/gsd-statusline.js +15 -7
  371. package/hooks/gsd-update-banner.js +8 -0
  372. package/hooks/gsd-windsurf-pre-write.js +11 -2
  373. package/hooks/gsd-workflow-guard.js +5 -4
  374. package/hooks/gsd-worktree-path-guard.js +6 -2
  375. package/hooks/hooks.json +5 -5
  376. package/hooks/lib/cli-exit.js +12 -0
  377. package/hooks/lib/git-probe.js +17 -1
  378. package/hooks/lib/isolation-sentinel.js +2 -2
  379. package/package.json +21 -4
  380. package/scripts/changeset/parse.cjs +52 -4
  381. package/scripts/ci-timeout-report.cjs +770 -4
  382. package/scripts/command-contract-helpers.cjs +12 -8
  383. package/scripts/docs-guard-registry.cjs +6 -0
  384. package/scripts/gen-features.cjs +13 -8
  385. package/scripts/gen-hooks-cli-exit.cjs +12 -28
  386. package/scripts/gen-loop-host-contract.cjs +10 -1
  387. package/scripts/gen-platform-conformance-tier.cjs +187 -1
  388. package/scripts/gen-plugin-skills.cjs +87 -1
  389. package/scripts/gen-research-agents.cjs +24 -31
  390. package/scripts/gen-scripts-cli-exit.cjs +30 -3
  391. package/scripts/gen-test-timings.cjs +32 -7
  392. package/scripts/lib/cli-exit.cjs +12 -0
  393. package/scripts/lib/macos-conformance-tier.generated.cjs +20 -2
  394. package/scripts/lib/ndjson-reporter.cjs +28 -3
  395. package/scripts/lib/platform-conformance-tier.generated.cjs +34 -5
  396. package/scripts/lib/registration-ledger-preload.cjs +155 -0
  397. package/scripts/lib/vendor-bundle.cjs +59 -0
  398. package/scripts/lib/vendor-licenses/saxes-6.0.0.txt +64 -0
  399. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
  400. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
  401. package/scripts/lint-completion-predicate-drift.cjs +18 -19
  402. package/scripts/lint-descriptions.cjs +7 -3
  403. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +10 -0
  404. package/scripts/lint-eslint-glob-coverage.allowlist.json +20 -0
  405. package/scripts/lint-frontmatter-fence-drift.cjs +313 -0
  406. package/scripts/lint-frontmatter-scalar-broad-grep.cjs +122 -16
  407. package/scripts/lint-phase-enumeration-drift.cjs +12 -8
  408. package/scripts/lint-phase-id-drift.cjs +29 -0
  409. package/scripts/lint-planning-document-positive-control.cjs +329 -0
  410. package/scripts/lint-response-language-coverage.cjs +3 -0
  411. package/scripts/lint-skill-deps.cjs +7 -3
  412. package/scripts/lint-test-file-count.allowlist.json +11 -1
  413. package/scripts/lint-test-file-count.cjs +34 -1
  414. package/scripts/lint-vendored-deps.cjs +41 -5
  415. package/scripts/lint-workflow-shellcheck-baseline.json +10 -10
  416. package/scripts/mutation-matrix.cjs +50 -5
  417. package/scripts/require-issue-link-policy.cjs +6 -2
  418. package/scripts/sync-runtime-launcher.cjs +184 -2
  419. package/scripts/verify-npm-publish.cjs +76 -20
  420. package/skills/gsd-add-tests/SKILL.md +6 -1
  421. package/skills/gsd-ai-integration-phase/SKILL.md +6 -1
  422. package/skills/gsd-audit-fix/SKILL.md +5 -0
  423. package/skills/gsd-audit-milestone/SKILL.md +6 -1
  424. package/skills/gsd-autonomous/SKILL.md +5 -0
  425. package/skills/gsd-capture/SKILL.md +8 -4
  426. package/skills/gsd-code-review/SKILL.md +7 -2
  427. package/skills/gsd-complete-milestone/SKILL.md +4 -0
  428. package/skills/gsd-config/SKILL.md +8 -4
  429. package/skills/gsd-debug/SKILL.md +11 -7
  430. package/skills/gsd-discuss-phase/SKILL.md +7 -3
  431. package/skills/gsd-docs-update/SKILL.md +12 -7
  432. package/skills/gsd-eval-review/SKILL.md +6 -1
  433. package/skills/gsd-execute-phase/SKILL.md +12 -7
  434. package/skills/gsd-extract-learnings/SKILL.md +5 -0
  435. package/skills/gsd-fast/SKILL.md +4 -0
  436. package/skills/gsd-forensics/SKILL.md +5 -1
  437. package/skills/gsd-graphify/SKILL.md +10 -6
  438. package/skills/gsd-health/SKILL.md +5 -0
  439. package/skills/gsd-help/SKILL.md +7 -2
  440. package/skills/gsd-import/SKILL.md +7 -3
  441. package/skills/gsd-inbox/SKILL.md +5 -0
  442. package/skills/gsd-ingest-docs/SKILL.md +5 -1
  443. package/skills/gsd-manager/SKILL.md +6 -1
  444. package/skills/gsd-map-codebase/SKILL.md +7 -3
  445. package/skills/gsd-mempalace-capture/SKILL.md +5 -1
  446. package/skills/gsd-mempalace-recall/SKILL.md +5 -1
  447. package/skills/gsd-milestone-summary/SKILL.md +5 -1
  448. package/skills/gsd-mvp-phase/SKILL.md +8 -3
  449. package/skills/gsd-new-milestone/SKILL.md +6 -1
  450. package/skills/gsd-new-project/SKILL.md +5 -0
  451. package/skills/gsd-next/SKILL.md +6 -1
  452. package/skills/gsd-ns-context/SKILL.md +4 -0
  453. package/skills/gsd-ns-ideate/SKILL.md +4 -0
  454. package/skills/gsd-ns-manage/SKILL.md +4 -0
  455. package/skills/gsd-ns-project/SKILL.md +4 -0
  456. package/skills/gsd-ns-review/SKILL.md +4 -0
  457. package/skills/gsd-ns-workflow/SKILL.md +4 -0
  458. package/skills/gsd-onboard/SKILL.md +6 -1
  459. package/skills/gsd-pause-work/SKILL.md +5 -1
  460. package/skills/gsd-phase/SKILL.md +8 -4
  461. package/skills/gsd-plan-phase/SKILL.md +6 -1
  462. package/skills/gsd-plan-review-convergence/SKILL.md +5 -1
  463. package/skills/gsd-pr-branch/SKILL.md +4 -0
  464. package/skills/gsd-profile-user/SKILL.md +5 -1
  465. package/skills/gsd-progress/SKILL.md +6 -1
  466. package/skills/gsd-quick/SKILL.md +16 -10
  467. package/skills/gsd-quick-batch/SKILL.md +20 -8
  468. package/skills/gsd-review/SKILL.md +5 -1
  469. package/skills/gsd-review-backlog/SKILL.md +3 -2
  470. package/skills/gsd-secure-phase/SKILL.md +6 -1
  471. package/skills/gsd-ship/SKILL.md +5 -0
  472. package/skills/gsd-sketch/SKILL.md +7 -2
  473. package/skills/gsd-spec-phase/SKILL.md +5 -1
  474. package/skills/gsd-spike/SKILL.md +8 -3
  475. package/skills/gsd-surface/SKILL.md +5 -1
  476. package/skills/gsd-thread/SKILL.md +4 -0
  477. package/skills/gsd-ui-phase/SKILL.md +6 -1
  478. package/skills/gsd-ui-review/SKILL.md +6 -1
  479. package/skills/gsd-ultraplan-phase/SKILL.md +5 -1
  480. package/skills/gsd-undo/SKILL.md +5 -1
  481. package/skills/gsd-update/SKILL.md +6 -2
  482. package/skills/gsd-validate-phase/SKILL.md +6 -1
  483. package/skills/gsd-verify-work/SKILL.md +6 -1
  484. package/skills/gsd-workspace/SKILL.md +7 -3
  485. package/skills/gsd-workstreams/SKILL.md +6 -6
  486. package/vscode/package.json +1 -1
  487. package/gsd-core/workflows/execute-phase/steps/stale-reverification.md +0 -24
@@ -71,7 +71,7 @@ const planningScopeMod = require("./planning-scope.cjs");
71
71
  const { SCOPE } = planningScopeMod;
72
72
  // eslint-disable-next-line @typescript-eslint/no-require-imports
73
73
  const verificationMod = require("./verification.cjs");
74
- const { readVerificationStatus } = verificationMod;
74
+ const { readVerificationStatus, VerificationStatusError, failOnVerificationStatusError } = verificationMod;
75
75
  // eslint-disable-next-line @typescript-eslint/no-require-imports
76
76
  const phaseIdMod = require("./phase-id.cjs");
77
77
  const { phaseKeyFromDir, phaseKeyFromToken, phaseMarkdownRegexSource } = phaseIdMod;
@@ -304,6 +304,8 @@ function containmentEnforcingVerificationFs(planningRoot) {
304
304
  return node_fs_1.default.readFileSync(filePath, encoding);
305
305
  },
306
306
  statSync(filePath) {
307
+ // #5118: a code-less containment throw here is NOT "phase directory
308
+ // not found" — readVerificationStatus falls through to `missing`.
307
309
  assertContained(filePath);
308
310
  return node_fs_1.default.statSync(filePath);
309
311
  },
@@ -1016,6 +1018,17 @@ function buildPhaseGoalAndDependencies(cwd, roadmapDoc, phaseId, phaseDirLabel,
1016
1018
  }
1017
1019
  // ─── Entry points ─────────────────────────────────────────────────────────────
1018
1020
  function buildPlanningInspect(cwd) {
1021
+ return buildPlanningInspectResult(cwd).payload;
1022
+ }
1023
+ /**
1024
+ * #5118: the inspect payload plus the first verification report whose
1025
+ * `status` is outside the closed set (`statusError`, or `null`) — the
1026
+ * aggregate CARRIES the owner's error in its own result, and `planning
1027
+ * inspect` fails with it instead of printing an answer computed over a
1028
+ * report the owner refused.
1029
+ */
1030
+ function buildPlanningInspectResult(cwd) {
1031
+ let statusError = null;
1019
1032
  const diagnostics = [];
1020
1033
  const paths = planningPaths(cwd);
1021
1034
  const planningExists = node_fs_1.default.existsSync(paths.planning);
@@ -1078,8 +1091,8 @@ function buildPlanningInspect(cwd) {
1078
1091
  // GAP 2 (#2790 follow-up security review): `readVerificationStatus`
1079
1092
  // (`src/verification.cts`) is a shared owner with its own unguarded
1080
1093
  // `readFileSync` — a `*-VERIFICATION.md` symlinked outside the planning
1081
- // root would leak an unrecognized `status:` value verbatim via its
1082
- // "Unexpected verification status '<value>'" `next_action` string. Fixed
1094
+ // root would leak its unrecognized `status:` value verbatim (today via
1095
+ // the VerificationStatusError message, #5118). Fixed
1083
1096
  // from THIS consumer's side via the injectable `opts.fs` seam that
1084
1097
  // function already exposes, never by touching its signature — see
1085
1098
  // `containmentEnforcingVerificationFs`'s doc comment. This same seam's
@@ -1094,9 +1107,22 @@ function buildPlanningInspect(cwd) {
1094
1107
  // (`superseded`) rather than document text, and GAP 1's directory
1095
1108
  // containment check already covers the escaped-DIRECTORY case for it —
1096
1109
  // so it needs no fix of its own.
1097
- const verification = readVerificationStatus(phaseDir, {
1098
- fs: containmentEnforcingVerificationFs(paths.planning),
1099
- });
1110
+ // #5118: an out-of-set report status is carried, not thrown past the
1111
+ // other phases — the row reads `status: null` and the command fails with
1112
+ // the first such error once the payload is built.
1113
+ let verification;
1114
+ try {
1115
+ verification = readVerificationStatus(phaseDir, {
1116
+ fs: containmentEnforcingVerificationFs(paths.planning),
1117
+ });
1118
+ }
1119
+ catch (err) {
1120
+ if (!(err instanceof VerificationStatusError))
1121
+ throw err;
1122
+ if (statusError === null)
1123
+ statusError = err;
1124
+ verification = { status: null, next_action: err.message, route: '' };
1125
+ }
1100
1126
  const token = /^(\d+(?:\.\d+)*)/.exec(phase.dir);
1101
1127
  const phaseId = token ? token[1] : null;
1102
1128
  const { goal, dependencies } = buildPhaseGoalAndDependencies(cwd, roadmapDoc, phaseId, phase.dir, diagnostics);
@@ -1129,6 +1155,8 @@ function buildPlanningInspect(cwd) {
1129
1155
  verification: {
1130
1156
  status: verification.status,
1131
1157
  next_action: verification.next_action ?? null,
1158
+ // #5118: additive — the bare command the owner routes this status to.
1159
+ route: verification.route,
1132
1160
  },
1133
1161
  roadmap_acceptance: {
1134
1162
  checkbox: checkboxByPhaseKey.has(phaseKeyFromDir(phase.dir))
@@ -1150,7 +1178,7 @@ function buildPlanningInspect(cwd) {
1150
1178
  const phaseScope = worstScope(snapshot.phaseDirs.scope, snapshot.phases.scope, ...phaseRows.map((p) => p.scope));
1151
1179
  const acceptedPhases = makeFraction(phaseRows.filter((p) => p.complete).length, phaseRows.length, phaseScope, 'progress.accepted_phases', diagnostics);
1152
1180
  const completedPlans = makeFraction(phaseRows.reduce((sum, p) => sum + p.summary_count, 0), phaseRows.reduce((sum, p) => sum + p.plan_count, 0), phaseScope, 'progress.completed_plans', diagnostics);
1153
- return {
1181
+ const payload = {
1154
1182
  schema_version: PLANNING_INSPECT_SCHEMA_VERSION,
1155
1183
  generated_from: {
1156
1184
  cwd: toPosix(cwd),
@@ -1178,6 +1206,7 @@ function buildPlanningInspect(cwd) {
1178
1206
  },
1179
1207
  diagnostics,
1180
1208
  };
1209
+ return { payload, statusError };
1181
1210
  }
1182
1211
  /**
1183
1212
  * `planning inspect` — emit the schema-v1 snapshot.
@@ -1187,7 +1216,12 @@ function buildPlanningInspect(cwd) {
1187
1216
  * transparently on stdout. Bypassing `output()` would lose that for free.
1188
1217
  */
1189
1218
  function cmdPlanningInspect(cwd, raw) {
1190
- output(buildPlanningInspect(cwd), raw);
1219
+ const { payload, statusError } = buildPlanningInspectResult(cwd);
1220
+ // #5118: a read-only aggregate over a refused report prints nothing and
1221
+ // fails with the error's own reason (`verification_status_invalid`).
1222
+ if (statusError)
1223
+ failOnVerificationStatusError(statusError);
1224
+ output(payload, raw);
1191
1225
  }
1192
1226
  const planningInspect = {
1193
1227
  PLANNING_INSPECT_SCHEMA_VERSION,
@@ -124,10 +124,12 @@ function buildPhaseSnapshot(phasesDir, dir, convention) {
124
124
  // report exactly like its legacy twin.
125
125
  const completionResult = isPhaseComplete(fullPhaseDir, { convention });
126
126
  const scanResult = scanPhasePlans(fullPhaseDir);
127
+ const statusError = completionResult.value.statusError;
127
128
  return {
128
129
  dir,
129
130
  complete: completionResult.value.complete,
130
131
  verificationStatus: completionResult.value.verification.status,
132
+ verificationStatusError: statusError ? { file: statusError.file, message: statusError.message } : null,
131
133
  planCount: scanResult.planCount,
132
134
  summaryCount: scanResult.summaryCount,
133
135
  scope: worstScope(completionResult.scope, scanResult.scope),
@@ -882,6 +884,22 @@ function buildCurrentMilestoneRoadmapPhaseIdsField(cwd, roadmapPath, convention)
882
884
  // and `bracketGroup` is 0. Inferring the convention from a matched bracket's
883
885
  // shape would run a repo-failing check against a repo that never opted in.
884
886
  const bracketGroup = convention === 'bracket' ? 1 : 0;
887
+ // #5007 (Phase 6 / ADR-4910 §8): already composed from `phaseHeadingPrefixSrcFor`
888
+ // directly, not a hand-rolled literal — the site's only marked defect was
889
+ // this doc comment's own prose quoting the pattern verbatim (fixed above),
890
+ // which is exactly what the drift detector matched. Audited against the
891
+ // design doc's suggested further swap onto `buildPhaseHeadingScanRegex`
892
+ // (the same owner `bracketGroup`/`phaseNumGroup` above hand-derives) and
893
+ // deliberately did NOT make that swap: the owner's regex requires a title
894
+ // (`${OPTIONAL_PHASE_TAG_SOURCE}\s*:\s*([^\n]+)` — at least one non-newline
895
+ // character after the colon), while this site's own tail is bare `:` with
896
+ // no title requirement. A live probe against this function (a `### Phase 3:`
897
+ // heading with no title text) confirms the current, pre-migration behavior
898
+ // DOES count that phase — swapping to the owner would silently drop it from
899
+ // W026's scan, and no existing test (including the ADR-612 census test
900
+ // pinned to this site by name) would catch that narrowing, since the census
901
+ // only pins `phaseHeadingPrefixSrcFor`'s own output, not this regex's tail.
902
+ // Kept as its own composition to preserve this exact byte-for-behavior.
885
903
  const phasePattern = new RegExp(`#{2,4}\\s*${phaseHeadingPrefixSrcFor(PHASE_HEADING_BASELINE.LABEL_ONLY, convention, Boolean(bracketGroup))}(${PHASE_NUMBER_TOKEN_SOURCE})(?:\\s*\\([^)\\n]{0,200}\\))?\\s*:`, 'gi');
886
904
  const value = [];
887
905
  for (const m of scoped.matchAll(phasePattern)) {
@@ -144,60 +144,73 @@ function planningDir(cwd, ws, project) {
144
144
  function planningRoot(cwd) {
145
145
  return node_path_1.default.join(cwd, '.planning');
146
146
  }
147
+ const CONFIG_VALUE_ABSENT = Object.freeze({ present: false, value: undefined });
147
148
  /**
148
- * #3972: the ONE owner of "is this planning scope opted out of worktrees?" —
149
- * the effective `workflow.use_worktrees === false` read every
150
- * isolation-deciding surface must share (config-get's merged view is the
151
- * contract). Ladder: the scoped config's OWN key wins (planningDir is
152
- * project- and workstream-aware); otherwise the flat root's key, but only
153
- * under the GSD_WORKSTREAM env gate — config-get deliberately does NOT
154
- * inherit root under GSD_PROJECT alone, and this read must not diverge
155
- * (#3963). Strict `=== false` (never coerced); any read failure degrades to
156
- * "not opted out" (worktrees on — the fail-safe direction: the guard keeps
157
- * enforcing). Direct file reads only — never loadConfig, which normalizes
158
- * and rewrites config on paths that back sentinel writes.
149
+ * The value one config file sets at `keyPath`, if it sets one at all. Every
150
+ * segment must be an OWN property of a plain (non-null, non-array) object, so
151
+ * an absent, unreadable, or unparseable file — or a non-object anywhere on the
152
+ * path — does not set the key.
159
153
  */
160
- function worktreesOptedOut(cwd) {
161
- // #3972 review: the WHOLE body is guarded — planningDir/planningRoot
162
- // themselves throw on a GSD_PROJECT/GSD_WORKSTREAM value containing path
163
- // separators or `..`, and this contract ("any failure degrades to not
164
- // opted out — worktrees on, keep enforcing") must hold for that shape too.
154
+ function ownConfigValue(configPath, keyPath) {
155
+ let node;
165
156
  try {
166
- return worktreesOptedOutUnguarded(cwd);
157
+ node = JSON.parse(String(node_fs_1.default.readFileSync(configPath, 'utf8')));
167
158
  }
168
159
  catch {
169
- return false;
160
+ return CONFIG_VALUE_ABSENT;
161
+ }
162
+ for (const key of keyPath) {
163
+ if (node === null || typeof node !== 'object' || Array.isArray(node))
164
+ return CONFIG_VALUE_ABSENT;
165
+ if (!Object.prototype.hasOwnProperty.call(node, key))
166
+ return CONFIG_VALUE_ABSENT;
167
+ node = node[key];
170
168
  }
169
+ return { present: true, value: node };
171
170
  }
172
- function worktreesOptedOutUnguarded(cwd) {
173
- const readCfg = (p) => {
174
- try {
175
- return JSON.parse(String(node_fs_1.default.readFileSync(p, 'utf8')));
176
- }
177
- catch {
178
- return null;
171
+ /**
172
+ * #3972/#4975: the ONE scope-aware config read for surfaces that must answer
173
+ * with the value `config-get <keyPath>` reports but may not call loadConfig
174
+ * (it normalizes and rewrites config.json, spawns git, and prints warnings).
175
+ * Ladder: the scoped config's OWN key wins (planningDir is project- and
176
+ * workstream-aware); otherwise the flat root's key, but only under the
177
+ * GSD_WORKSTREAM env gate — config-get deliberately does NOT inherit root
178
+ * under GSD_PROJECT alone, and no reader of this ladder may diverge (#3963).
179
+ * An unreadable or unparseable file sets nothing, so the ladder moves on:
180
+ * under GSD_WORKSTREAM a broken workstream config inherits the root's key.
181
+ * That is the one place this read and config-get part ways — for a scoped
182
+ * config.json that exists but cannot be read or parsed, config-get fails
183
+ * with CONFIG_PARSE_FAILED instead of reporting a value.
184
+ * The value is returned uncoerced; each caller applies its own strict
185
+ * comparison. Never throws: planningDir/planningRoot reject a
186
+ * GSD_PROJECT/GSD_WORKSTREAM value containing path separators or `..`, and
187
+ * that shape resolves to "not present".
188
+ */
189
+ function readScopedConfigValue(cwd, keyPath) {
190
+ try {
191
+ const scoped = ownConfigValue(node_path_1.default.join(planningDir(cwd), 'config.json'), keyPath);
192
+ if (scoped.present)
193
+ return scoped;
194
+ if (resolveEnvWorkstream() !== null) {
195
+ return ownConfigValue(node_path_1.default.join(planningRoot(cwd), 'config.json'), keyPath);
179
196
  }
180
- };
181
- const ownKey = (cfg) => {
182
- if (cfg === null || typeof cfg !== 'object')
183
- return { present: false, value: undefined };
184
- const wf = cfg.workflow;
185
- if (wf === null || typeof wf !== 'object' || Array.isArray(wf))
186
- return { present: false, value: undefined };
187
- const wfRec = wf;
188
- return Object.prototype.hasOwnProperty.call(wfRec, 'use_worktrees')
189
- ? { present: true, value: wfRec['use_worktrees'] }
190
- : { present: false, value: undefined };
191
- };
192
- const scoped = ownKey(readCfg(node_path_1.default.join(planningDir(cwd), 'config.json')));
193
- if (scoped.present)
194
- return scoped.value === false;
195
- if (resolveEnvWorkstream() !== null) {
196
- const root = ownKey(readCfg(node_path_1.default.join(planningRoot(cwd), 'config.json')));
197
- if (root.present)
198
- return root.value === false;
199
197
  }
200
- return false;
198
+ catch {
199
+ // Degrade to "not present" — see the contract above.
200
+ }
201
+ return CONFIG_VALUE_ABSENT;
202
+ }
203
+ /**
204
+ * #3972: the ONE owner of "is this planning scope opted out of worktrees?" —
205
+ * the effective `workflow.use_worktrees === false` read every
206
+ * isolation-deciding surface must share (config-get's merged view is the
207
+ * contract), resolved on the readScopedConfigValue ladder. Strict `=== false`
208
+ * (never coerced); a config that cannot be read never opts out by itself
209
+ * (worktrees on — the fail-safe direction: the guard keeps enforcing).
210
+ */
211
+ function worktreesOptedOut(cwd) {
212
+ const { present, value } = readScopedConfigValue(cwd, ['workflow', 'use_worktrees']);
213
+ return present && value === false;
201
214
  }
202
215
  /**
203
216
  * #612: resolve `phase_id_convention` with the SAME workstream->root federation
@@ -305,8 +318,8 @@ function listAvailableWorkstreams(cwd) {
305
318
  function quickDirFrom(planningBase) {
306
319
  return node_path_1.default.join(planningBase, 'quick');
307
320
  }
308
- // #4256: the todos directory — deliberately ROOT-SCOPED, unlike every other
309
- // planningPaths key. Todos are shared project state by construction: the
321
+ // #4256: the todos directory — deliberately ROOT-SCOPED, like debug (#5042).
322
+ // Todos are shared project state by construction: the
310
323
  // migrateToWorkstreams contract keeps them among the shared files that "stay
311
324
  // in place" at .planning/todos/ (workstream.cts), and every workflow writer
312
325
  // writes that literal cwd-relative root path. The six todos readers
@@ -330,6 +343,14 @@ function todosDirFrom(planningBase) {
330
343
  function todosDir(cwd) {
331
344
  return todosDirFrom(planningRoot(cwd));
332
345
  }
346
+ // Debug sessions are shared project state: the workflow and debugger agent
347
+ // write them under the root .planning/debug directory in every workstream.
348
+ function debugDirFrom(planningBase) {
349
+ return node_path_1.default.join(planningBase, 'debug');
350
+ }
351
+ function debugDir(cwd) {
352
+ return debugDirFrom(planningRoot(cwd));
353
+ }
333
354
  function planningPaths(cwd, ws) {
334
355
  const base = planningDir(cwd, ws);
335
356
  return {
@@ -340,14 +361,13 @@ function planningPaths(cwd, ws) {
340
361
  config: node_path_1.default.join(base, 'config.json'),
341
362
  phases: node_path_1.default.join(base, 'phases'),
342
363
  requirements: node_path_1.default.join(base, 'REQUIREMENTS.md'),
343
- // #3149: the debug-session directory. Single source for both `state.load`'s
344
- // `debug_dir` field and `init.debug`'s — previously each composed its own
345
- // `path.join(planning, 'debug')` (DEFECT.GENERATIVE-FIX).
346
- debug: node_path_1.default.join(base, 'debug'),
364
+ // #3149/#5042: the debug-session directory shared by state.load,
365
+ // init.debug, and the root-scoped writers.
366
+ debug: debugDir(cwd),
347
367
  // #2142: quick-task directory, composed via the shared quickDirFrom helper.
348
368
  quick: quickDirFrom(base),
349
- // #4256: todos directory — deliberately ROOT-scoped while the rest of
350
- // this record follows the active workstream/project (todos are shared
369
+ // #4256: todos directory — deliberately ROOT-scoped like debug, while
370
+ // most other keys follow the active workstream/project (todos are shared
351
371
  // project state per the migrateToWorkstreams contract), composed via the
352
372
  // shared todosDir helper so this key and every direct caller agree.
353
373
  todos: todosDir(cwd),
@@ -612,6 +632,7 @@ function findContextMdIn(absDirOrFiles) {
612
632
  }
613
633
  module.exports = {
614
634
  worktreesOptedOut,
635
+ readScopedConfigValue,
615
636
  createPlanningWorkspace,
616
637
  createSharedPointerAdapter,
617
638
  createSessionScopedPointerAdapter,
@@ -623,6 +644,8 @@ module.exports = {
623
644
  listAvailableWorkstreams,
624
645
  planningPaths,
625
646
  quickDirFrom,
647
+ debugDirFrom,
648
+ debugDir,
626
649
  todosDirFrom,
627
650
  todosDir,
628
651
  withPlanningLock,
@@ -27,6 +27,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
27
27
  Object.defineProperty(exports, "__esModule", { value: true });
28
28
  exports.sha256File = sha256File;
29
29
  exports.findPristineByHash = findPristineByHash;
30
+ exports.isCleanRelativePosixPath = isCleanRelativePosixPath;
31
+ exports.gitExec = gitExec;
30
32
  exports.findPristineInGit = findPristineInGit;
31
33
  const node_fs_1 = __importDefault(require("node:fs"));
32
34
  const node_path_1 = __importDefault(require("node:path"));
@@ -125,6 +127,14 @@ const GIT_MAX_COMMITS_PER_FILE = 100;
125
127
  const GIT_SUBPROCESS_TIMEOUT_MS = 10_000;
126
128
  /** git log --format=%H output cap; 100 full shas are ~4 KB, this is headroom. */
127
129
  const GIT_MAX_BUFFER_BYTES = 16 * 1024 * 1024;
130
+ /**
131
+ * #5105 review finding 1/4: shared containment guard AND the shared
132
+ * non-trimming `git` subprocess runner, exported so `uat.cts`'s
133
+ * `readBaselineAtHead` (byte-exact `git show HEAD:<path>` read) can route
134
+ * through the same bounded, `windowsHide`d, stderr-discarding call this
135
+ * module already uses, rather than maintaining a second private
136
+ * `execFileSync` wrapper that can drift from this one's timeout/maxBuffer.
137
+ */
128
138
  function isCleanRelativePosixPath(relPath) {
129
139
  if (!relPath || relPath.startsWith('/') || relPath.includes('\\') || relPath.includes('\0')) {
130
140
  return false;
@@ -29,6 +29,7 @@ const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs")
29
29
  const runtime_homes_cjs_1 = require("./runtime-homes.cjs");
30
30
  const runtime_slash_cjs_1 = require("./runtime-slash.cjs");
31
31
  const runtime_name_policy_cjs_1 = require("./runtime-name-policy.cjs");
32
+ const frontmatter_fence_cjs_1 = require("./frontmatter-fence.cjs");
32
33
  // ─── Constants ────────────────────────────────────────────────────────────────
33
34
  const DIMENSION_KEYS = [
34
35
  'communication_style', 'decision_speed', 'explanation_depth',
@@ -203,6 +204,7 @@ function buildClaudeMdWorkflowEnforcement(runtime) {
203
204
  'Before using Edit, Write, or other file-changing tools, start work through a GSD command so planning artifacts and execution context stay in sync.',
204
205
  '',
205
206
  'Use these entry points:',
207
+ `- \`${String((0, runtime_slash_cjs_1.formatGsdSlash)('fast', runtime))}\` for a trivial task inline, with no subagents and no PLAN.md`,
206
208
  `- \`${String((0, runtime_slash_cjs_1.formatGsdSlash)('quick', runtime))}\` for small fixes, doc updates, and ad-hoc tasks`,
207
209
  `- \`${String((0, runtime_slash_cjs_1.formatGsdSlash)('debug', runtime))}\` for investigation and bug fixing`,
208
210
  `- \`${String((0, runtime_slash_cjs_1.formatGsdSlash)('execute-phase', runtime))}\` for planned phase work`,
@@ -477,10 +479,11 @@ function generateSkillsSection(cwd) {
477
479
  */
478
480
  function extractSkillFrontmatter(content) {
479
481
  const result = { name: '', description: '' };
480
- const fmMatch = content.match(/^---\s*\r?\n([\s\S]*?)\r?\n---/);
481
- if (!fmMatch)
482
+ // The block is the one the one fence owner (`locateFrontmatterFence`) finds.
483
+ const fence = (0, frontmatter_fence_cjs_1.locateFrontmatterFence)(content);
484
+ if (!fence?.closed)
482
485
  return result;
483
- const fmBlock = fmMatch[1];
486
+ const fmBlock = content.slice(fence.openEnd, fence.bodyEnd);
484
487
  const lines = fmBlock.split('\n');
485
488
  let currentKey = '';
486
489
  for (const line of lines) {
@@ -58,14 +58,9 @@ exports.eslintHasFatalError = eslintHasFatalError;
58
58
  exports.eslintJsonHasRule = eslintJsonHasRule;
59
59
  exports.defaultProveFailFirst = defaultProveFailFirst;
60
60
  exports.runProhibitionEnforcement = runProhibitionEnforcement;
61
- exports.routeProhibitionEnforcement = routeProhibitionEnforcement;
62
61
  const node_fs_1 = __importDefault(require("node:fs"));
63
62
  const node_path_1 = __importDefault(require("node:path"));
64
63
  const node_child_process_1 = require("node:child_process");
65
- // Import the leaf I/O module directly (core.cjs re-export spine retired in epic #1267).
66
- // eslint-disable-next-line @typescript-eslint/no-require-imports
67
- const io = require("./io.cjs");
68
- const { output, error, ERROR_REASON } = io;
69
64
  const probe_core_cjs_1 = require("./probe-core.cjs");
70
65
  /**
71
66
  * READ-BACK ADAPTER (#1278, plan 01-03): reconstruct a `CheckDescriptor` from the flat scalar keys
@@ -730,53 +725,3 @@ function runProhibitionEnforcement(prohibition, check, options = {}) {
730
725
  ...(mode ? { mode } : {}),
731
726
  };
732
727
  }
733
- /**
734
- * Parse a `{ prohibition, check, mode }` request from a JSON file path or inline `--json` string.
735
- * Returns null on any parse failure (the caller surfaces a structured error, never a throw).
736
- */
737
- function parseRequest(args) {
738
- // args[0] = 'check', args[1] = 'prohibition-enforcement', args[2] = <json-file-path | --json>
739
- const jsonFlagIdx = args.indexOf('--json');
740
- let payload = '';
741
- if (jsonFlagIdx !== -1 && typeof args[jsonFlagIdx + 1] === 'string') {
742
- payload = args[jsonFlagIdx + 1];
743
- }
744
- else if (typeof args[2] === 'string' && args[2]) {
745
- try {
746
- payload = node_fs_1.default.readFileSync(args[2], 'utf-8');
747
- }
748
- catch {
749
- return null;
750
- }
751
- }
752
- else {
753
- return null;
754
- }
755
- try {
756
- const parsed = JSON.parse(payload);
757
- const checkRaw = parsed['check'];
758
- const check = (checkRaw && typeof checkRaw === 'object')
759
- ? checkRaw
760
- : null;
761
- const modeRaw = parsed['mode'];
762
- const mode = typeof modeRaw === 'string' ? modeRaw : undefined;
763
- return { prohibition: parsed['prohibition'] ?? null, check, ...(mode ? { mode } : {}) };
764
- }
765
- catch {
766
- return null;
767
- }
768
- }
769
- /**
770
- * CLI surface: `gsd_run check prohibition-enforcement <request.json>` (or `--json '<inline>'`).
771
- * Parses the request, runs the producer, and emits the result as JSON. Honors the no-throw
772
- * contract: malformed input -> structured `error(...)`, never an uncaught throw.
773
- */
774
- function routeProhibitionEnforcement(args, raw) {
775
- const req = parseRequest(args);
776
- if (!req) {
777
- error('prohibition-enforcement requires a JSON request: check prohibition-enforcement <request.json> | --json \'{"prohibition":{...},"check":{...}}\'', ERROR_REASON.SDK_MISSING_ARG);
778
- return;
779
- }
780
- const result = runProhibitionEnforcement(req.prohibition, req.check, req.mode ? { mode: req.mode } : {});
781
- output(result, raw, undefined);
782
- }
@@ -35,9 +35,19 @@ const commandRoutingHub = require("./command-routing-hub.cjs");
35
35
  // eslint-disable-next-line @typescript-eslint/no-require-imports
36
36
  const cjsCommandRouterAdapter = require("./cjs-command-router-adapter.cjs");
37
37
  const security_cjs_1 = require("./security.cjs");
38
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
39
+ const nodeFs = require("node:fs");
40
+ // #5118: the writer set is owned by src/verification.cts.
41
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
42
+ const verificationMod = require("./verification.cjs");
38
43
  const { output, ERROR_REASON } = io;
44
+ const { VERIFIER_STATUSES } = verificationMod;
39
45
  const { makeInvalidArgs } = commandRoutingHub;
40
46
  const { routeHubCommandFamily } = cjsCommandRouterAdapter;
47
+ /** Default stdin reader for `parse-args --stdin` (fd 0, UTF-8, whole stream). */
48
+ function readProcessStdin() {
49
+ return nodeFs.readFileSync(0, 'utf8');
50
+ }
41
51
  // ─── Small arg-parsing helpers (local — no new shared convention needed) ────
42
52
  /** `--flag value` lookup; undefined when the flag is absent. */
43
53
  function argValue(args, flag) {
@@ -57,7 +67,7 @@ function parseJsonArg(raw, label) {
57
67
  return { ok: true, value: parsed.value };
58
68
  }
59
69
  // ─── Implementation ───────────────────────────────────────────────────────────
60
- function routeQuickBatchCommand({ args, cwd, raw, error, _quickBatch, _quickBatchDispatch }) {
70
+ function routeQuickBatchCommand({ args, cwd, raw, error, _quickBatch, _quickBatchDispatch, _readStdin }) {
61
71
  const qb = _quickBatch ?? quickBatch;
62
72
  const dispatch = _quickBatchDispatch ?? quickBatchDispatch;
63
73
  /** Forward a `Result<T>` from either module straight to output()/error(). */
@@ -211,7 +221,7 @@ function routeQuickBatchCommand({ args, cwd, raw, error, _quickBatch, _quickBatc
211
221
  // `quick-batch verification-routing --status <passed|gaps_found|human_needed>`
212
222
  'verification-routing': () => {
213
223
  const status = argValue(args, '--status');
214
- if (status !== 'passed' && status !== 'gaps_found' && status !== 'human_needed') {
224
+ if (typeof status !== 'string' || !VERIFIER_STATUSES.has(status)) {
215
225
  return makeInvalidArgs('--status', 'Usage: gsd-tools quick-batch verification-routing --status <passed|gaps_found|human_needed>', ERROR_REASON.USAGE);
216
226
  }
217
227
  output(dispatch.routeVerificationOutcome(status), raw);
@@ -252,17 +262,33 @@ function routeQuickBatchCommand({ args, cwd, raw, error, _quickBatch, _quickBatc
252
262
  planContent,
253
263
  }), raw);
254
264
  },
255
- // `quick-batch parse-args --text "<raw $ARGUMENTS string>"` (preferred —
256
- // callers pass the ENTIRE, still-quoted $ARGUMENTS as ONE argv element;
257
- // this handler does the whitespace split itself, in Node, so shell
258
- // pathname expansion (globbing) on attacker-influenced task text never
259
- // happens before this parser sees it — quoting `"$ARGUMENTS"` at the
260
- // call site is what closes that off; splitting it here is what keeps
261
- // the caller from having to word-split it unsafely beforehand).
265
+ // `quick-batch parse-args --stdin` (preferred, #4780 — the caller feeds
266
+ // the typed text through a QUOTED heredoc, so the shell never parses it:
267
+ // quotes, `$(...)`, backticks and newlines in attacker-influenced task
268
+ // text cannot break out of any shell position, because there is no
269
+ // shell position for the text to occupy).
270
+ // `quick-batch parse-args --text "<raw string>"` (still supported for a
271
+ // caller that already holds the text as ONE real argv element with no
272
+ // shell quoting involved, e.g. a test harness; it is NOT safe to build
273
+ // that argument by splicing user text into a shell command line).
274
+ // In both forms this handler does the whitespace split itself, in Node,
275
+ // so shell pathname expansion (globbing) never happens.
262
276
  // `quick-batch parse-args -- <already-tokenized args>` (legacy/direct
263
277
  // form — still supported for a caller that already has a real argv
264
278
  // array with no shell splitting involved, e.g. a test harness).
265
279
  'parse-args': () => {
280
+ if (args.includes('--stdin')) {
281
+ let stdinText;
282
+ try {
283
+ stdinText = (_readStdin ?? readProcessStdin)();
284
+ }
285
+ catch (readError) {
286
+ return makeInvalidArgs('--stdin', `could not read standard input: ${readError instanceof Error ? readError.message : String(readError)}`, ERROR_REASON.USAGE);
287
+ }
288
+ const stdinTokens = stdinText.trim().length === 0 ? [] : stdinText.trim().split(/\s+/);
289
+ emit(dispatch.parseQuickBatchArgs(stdinTokens));
290
+ return;
291
+ }
266
292
  const textArg = argValue(args, '--text');
267
293
  if (textArg !== undefined) {
268
294
  const rawArgs = textArg.trim().length === 0 ? [] : textArg.trim().split(/\s+/);
@@ -140,6 +140,16 @@ function computeSpawnPlan(input) {
140
140
  }
141
141
  return { spawn, pending };
142
142
  }
143
+ /**
144
+ * #5118: one routing entry per writer-set status, keyed by the owner's type —
145
+ * no status literal is compared (local/no-verification-status-literal's
146
+ * type-aware arm), and `Record<VerifierStatus, …>` makes the table total.
147
+ */
148
+ const VERIFICATION_OUTCOME_ROUTES = Object.freeze({
149
+ passed: { action: 'complete' },
150
+ human_needed: { action: 'human_needed' },
151
+ gaps_found: { action: 'fail', failureReason: 'verification reported gaps_found (no automatic gap-fix retry in v1)' },
152
+ });
143
153
  /**
144
154
  * Route a verifier's status to an item action. `human_needed` is terminal
145
155
  * for the item — the caller must NOT call `completeQuickItem` (row 30, no
@@ -147,14 +157,7 @@ function computeSpawnPlan(input) {
147
157
  * WITHOUT an automatic gap-fix retry (row 31,34). `passed` completes it.
148
158
  */
149
159
  function routeVerificationOutcome(status) {
150
- switch (status) {
151
- case 'passed':
152
- return { action: 'complete' };
153
- case 'human_needed':
154
- return { action: 'human_needed' };
155
- case 'gaps_found':
156
- return { action: 'fail', failureReason: 'verification reported gaps_found (no automatic gap-fix retry in v1)' };
157
- }
160
+ return VERIFICATION_OUTCOME_ROUTES[status];
158
161
  }
159
162
  /**
160
163
  * Route a merge attempt's outcome to an item action. Both `merge_failed`
@@ -105,6 +105,14 @@ const SANDBOX_MARKER = 'GSD_TEST_HOME_SANDBOX';
105
105
  * `statSync` follows symlinks and reports the inode itself, so a case-variant
106
106
  * HOME, a symlinked HOME, and a bind-mounted HOME all compare equal.
107
107
  *
108
+ * `identify` calls `fs.statSync(p, { bigint: true })`, not the plain numeric
109
+ * form. Node documents that the default numeric `dev`/`ino` lose precision past
110
+ * `Number.MAX_SAFE_INTEGER` (2^53), and NTFS/ReFS file IDs routinely exceed
111
+ * that — so on Windows two DISTINCT directories can round to the same numeric
112
+ * `ino` and compare equal here, which is a fail-OPEN in a module whose whole
113
+ * job is refusing writes into the real home. `{ bigint: true }` reports the
114
+ * true 64-bit values with no precision loss.
115
+ *
108
116
  * Fails CLOSED, and "closed" here means returning FALSE. The sole caller is the
109
117
  * passwd-less marker branch, which READS a true as permission to proceed:
110
118
  *
@@ -130,7 +138,7 @@ function sameDirectory(a, b) {
130
138
  }
131
139
  function identify(p) {
132
140
  try {
133
- const st = node_fs_1.default.statSync(p);
141
+ const st = node_fs_1.default.statSync(p, { bigint: true });
134
142
  return { kind: 'ok', dev: st.dev, ino: st.ino };
135
143
  }
136
144
  catch (err) {