@opengsd/gsd-core 1.13.0 → 1.15.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 (441) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.ja-JP.md +3 -3
  4. package/README.ko-KR.md +3 -3
  5. package/README.pt-BR.md +3 -3
  6. package/README.zh-CN.md +3 -3
  7. package/agents/gsd-advisor-researcher.compact.md +85 -0
  8. package/agents/gsd-ai-researcher.compact.md +96 -0
  9. package/agents/gsd-assumptions-analyzer.compact.md +81 -0
  10. package/agents/gsd-code-fixer.compact.md +459 -0
  11. package/agents/gsd-code-fixer.md +9 -8
  12. package/agents/gsd-code-reviewer.compact.md +269 -0
  13. package/agents/gsd-code-reviewer.md +15 -3
  14. package/agents/gsd-codebase-mapper.compact.md +760 -0
  15. package/agents/gsd-debug-session-manager.compact.md +360 -0
  16. package/agents/gsd-debug-session-manager.md +17 -2
  17. package/agents/gsd-debugger.md +2 -2
  18. package/agents/gsd-doc-classifier.compact.md +192 -0
  19. package/agents/gsd-doc-synthesizer.compact.md +200 -0
  20. package/agents/gsd-doc-verifier.compact.md +143 -0
  21. package/agents/gsd-doc-writer.compact.md +440 -0
  22. package/agents/gsd-dom-verifier.compact.md +138 -0
  23. package/agents/gsd-domain-researcher.compact.md +141 -0
  24. package/agents/gsd-eval-auditor.compact.md +160 -0
  25. package/agents/gsd-eval-auditor.md +1 -1
  26. package/agents/gsd-eval-planner.compact.md +137 -0
  27. package/agents/gsd-executor.md +13 -8
  28. package/agents/gsd-framework-selector.compact.md +82 -0
  29. package/agents/gsd-integration-checker.compact.md +245 -0
  30. package/agents/gsd-intel-updater.compact.md +226 -0
  31. package/agents/gsd-intel-updater.md +1 -1
  32. package/agents/gsd-mempalace-curator.compact.md +45 -0
  33. package/agents/gsd-nyquist-auditor.compact.md +179 -0
  34. package/agents/gsd-pattern-mapper.compact.md +275 -0
  35. package/agents/gsd-phase-researcher.md +19 -11
  36. package/agents/gsd-plan-checker.md +8 -7
  37. package/agents/gsd-planner.md +12 -8
  38. package/agents/gsd-project-researcher.compact.md +587 -0
  39. package/agents/gsd-project-researcher.md +1 -1
  40. package/agents/gsd-research-synthesizer.compact.md +212 -0
  41. package/agents/gsd-research-synthesizer.md +1 -1
  42. package/agents/gsd-roadmapper.compact.md +454 -0
  43. package/agents/gsd-roadmapper.md +13 -0
  44. package/agents/gsd-security-auditor.compact.md +162 -0
  45. package/agents/gsd-ui-auditor.compact.md +404 -0
  46. package/agents/gsd-ui-auditor.md +155 -17
  47. package/agents/gsd-ui-checker.compact.md +277 -0
  48. package/agents/gsd-ui-researcher.compact.md +282 -0
  49. package/agents/gsd-ui-researcher.md +1 -1
  50. package/agents/gsd-user-profiler.compact.md +108 -0
  51. package/agents/gsd-verifier.md +10 -9
  52. package/bin/install.js +848 -163
  53. package/commands/gsd/autonomous.md +2 -2
  54. package/commands/gsd/capture.md +1 -1
  55. package/commands/gsd/cleanup.md +1 -0
  56. package/commands/gsd/code-review.md +2 -1
  57. package/commands/gsd/complete-milestone.md +1 -0
  58. package/commands/gsd/config.md +1 -0
  59. package/commands/gsd/debug.md +1 -0
  60. package/commands/gsd/graphify.md +1 -0
  61. package/commands/gsd/health.md +1 -0
  62. package/commands/gsd/mempalace-capture.md +8 -3
  63. package/commands/gsd/mempalace-recall.md +1 -0
  64. package/commands/gsd/new-milestone.md +1 -0
  65. package/commands/gsd/new-project.md +1 -0
  66. package/commands/gsd/next.md +1 -0
  67. package/commands/gsd/pause-work.md +1 -0
  68. package/commands/gsd/phase.md +1 -0
  69. package/commands/gsd/plan-review-convergence.md +6 -6
  70. package/commands/gsd/pr-branch.md +1 -0
  71. package/commands/gsd/progress.md +1 -1
  72. package/commands/gsd/quick-batch.md +1 -1
  73. package/commands/gsd/resume-work.md +1 -0
  74. package/commands/gsd/review-backlog.md +1 -0
  75. package/commands/gsd/review.md +2 -3
  76. package/commands/gsd/settings.md +2 -1
  77. package/commands/gsd/stats.md +1 -0
  78. package/commands/gsd/thread.md +1 -0
  79. package/commands/gsd/workspace.md +1 -0
  80. package/commands/gsd/workstreams.md +1 -0
  81. package/gsd-core/bin/check-latest-version.cjs +8 -3
  82. package/gsd-core/bin/gsd-tools.cjs +672 -146
  83. package/gsd-core/bin/lib/adr-parser.cjs +4 -2
  84. package/gsd-core/bin/lib/artifacts.cjs +2 -1
  85. package/gsd-core/bin/lib/audit.cjs +119 -34
  86. package/gsd-core/bin/lib/broken-windows.cjs +168 -49
  87. package/gsd-core/bin/lib/capability-lifecycle.cjs +10 -6
  88. package/gsd-core/bin/lib/capability-loader.cjs +135 -1
  89. package/gsd-core/bin/lib/capability-registry.cjs +96 -189
  90. package/gsd-core/bin/lib/capability-source.cjs +19 -2
  91. package/gsd-core/bin/lib/capability-validator.cjs +14 -2
  92. package/gsd-core/bin/lib/check-command-router.cjs +213 -49
  93. package/gsd-core/bin/lib/code-review-depth.cjs +2 -2
  94. package/gsd-core/bin/lib/codex-agent-toml.cjs +21 -25
  95. package/gsd-core/bin/lib/commands.cjs +823 -112
  96. package/gsd-core/bin/lib/config-loader.cjs +66 -4
  97. package/gsd-core/bin/lib/config.cjs +186 -45
  98. package/gsd-core/bin/lib/coverage.cjs +1 -1
  99. package/gsd-core/bin/lib/decisions.cjs +164 -45
  100. package/gsd-core/bin/lib/external-descriptor-trust.cjs +29 -14
  101. package/gsd-core/bin/lib/frontmatter.cjs +13 -0
  102. package/gsd-core/bin/lib/graphify.cjs +10 -2
  103. package/gsd-core/bin/lib/gsd2-import.cjs +1 -2
  104. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +12 -1
  105. package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +1 -1
  106. package/gsd-core/bin/lib/host-runtime-detection.cjs +9 -0
  107. package/gsd-core/bin/lib/init.cjs +614 -86
  108. package/gsd-core/bin/lib/install-engine.cjs +29 -3
  109. package/gsd-core/bin/lib/install-profiles.cjs +14 -0
  110. package/gsd-core/bin/lib/installer-migrations.cjs +41 -5
  111. package/gsd-core/bin/lib/loop-resolver.cjs +50 -31
  112. package/gsd-core/bin/lib/mcp-catalog.cjs +2 -2
  113. package/gsd-core/bin/lib/milestone.cjs +37 -13
  114. package/gsd-core/bin/lib/model-resolver.cjs +253 -53
  115. package/gsd-core/bin/lib/phase-command-router.cjs +16 -2
  116. package/gsd-core/bin/lib/phase-id-card.cjs +32 -0
  117. package/gsd-core/bin/lib/phase-id-display.cjs +78 -0
  118. package/gsd-core/bin/lib/phase-id.cjs +268 -27
  119. package/gsd-core/bin/lib/phase-lifecycle.cjs +61 -0
  120. package/gsd-core/bin/lib/phase-locator.cjs +29 -10
  121. package/gsd-core/bin/lib/phase.cjs +393 -88
  122. package/gsd-core/bin/lib/plan-document.cjs +49 -1
  123. package/gsd-core/bin/lib/planning-document.cjs +459 -0
  124. package/gsd-core/bin/lib/planning-inspect.cjs +52 -19
  125. package/gsd-core/bin/lib/planning-snapshot.cjs +61 -12
  126. package/gsd-core/bin/lib/planning-workspace.cjs +57 -3
  127. package/gsd-core/bin/lib/pr-branch-patterns.cjs +57 -0
  128. package/gsd-core/bin/lib/pristine-baseline.cjs +182 -0
  129. package/gsd-core/bin/lib/probe-core.cjs +7 -1
  130. package/gsd-core/bin/lib/prohibition-enforcement.cjs +91 -4
  131. package/gsd-core/bin/lib/project-root.cjs +41 -2
  132. package/gsd-core/bin/lib/quick-batch.cjs +1 -1
  133. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +61 -2
  134. package/gsd-core/bin/lib/research-store.cjs +11 -12
  135. package/gsd-core/bin/lib/review-lane-descriptor.cjs +10 -30
  136. package/gsd-core/bin/lib/review-lane-invocation.cjs +23 -0
  137. package/gsd-core/bin/lib/review-reviewer-selection.cjs +2 -2
  138. package/gsd-core/bin/lib/reviewer-step-dispatch.cjs +337 -0
  139. package/gsd-core/bin/lib/roadmap-command-router.cjs +12 -4
  140. package/gsd-core/bin/lib/roadmap-parser.cjs +219 -18
  141. package/gsd-core/bin/lib/roadmap-upgrade.cjs +1539 -13
  142. package/gsd-core/bin/lib/roadmap.cjs +356 -42
  143. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +310 -41
  144. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +15 -4
  145. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +13 -5
  146. package/gsd-core/bin/lib/runtime-homes.cjs +4 -0
  147. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +408 -37
  148. package/gsd-core/bin/lib/runtime-name-policy.cjs +111 -1
  149. package/gsd-core/bin/lib/security.cjs +126 -7
  150. package/gsd-core/bin/lib/shell-command-projection.cjs +10 -6
  151. package/gsd-core/bin/lib/state-document.cjs +130 -28
  152. package/gsd-core/bin/lib/state-md-schema.cjs +21 -14
  153. package/gsd-core/bin/lib/state-transition.cjs +181 -30
  154. package/gsd-core/bin/lib/state.cjs +265 -27
  155. package/gsd-core/bin/lib/surface.cjs +77 -3
  156. package/gsd-core/bin/lib/task-command-router.cjs +12 -6
  157. package/gsd-core/bin/lib/tdd-red-evidence.cjs +78 -5
  158. package/gsd-core/bin/lib/uat-predicate.cjs +47 -4
  159. package/gsd-core/bin/lib/uat.cjs +9 -1
  160. package/gsd-core/bin/lib/ui-consideration-probe.cjs +15 -2
  161. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +100 -9
  162. package/gsd-core/bin/lib/undo-commit-selection.cjs +131 -0
  163. package/gsd-core/bin/lib/update-context.cjs +30 -24
  164. package/gsd-core/bin/lib/vendor/js-yaml.cjs +11 -3
  165. package/gsd-core/bin/lib/verification.cjs +315 -30
  166. package/gsd-core/bin/lib/verify-command-grounding.cjs +47 -3
  167. package/gsd-core/bin/lib/verify.cjs +320 -48
  168. package/gsd-core/bin/lib/workstream-inventory.cjs +1 -0
  169. package/gsd-core/bin/lib/worktree-base-ref.cjs +482 -73
  170. package/gsd-core/bin/lib/worktree-safety.cjs +797 -58
  171. package/gsd-core/bin/shared/config-defaults.manifest.json +4 -0
  172. package/gsd-core/bin/shared/config-schema.manifest.json +6 -0
  173. package/gsd-core/bin/verify-reapply-patches.cjs +439 -80
  174. package/gsd-core/references/checkpoints.md +5 -3
  175. package/gsd-core/references/compact-content-gate.md +66 -0
  176. package/gsd-core/references/edge-probe-fixtures/01-round-half-even/expected-coverage.json +28 -3
  177. package/gsd-core/references/edge-probe-fixtures/02-merge-intervals/expected-coverage.json +37 -4
  178. package/gsd-core/references/edge-probe-fixtures/03-truncate-graphemes/expected-coverage.json +28 -3
  179. package/gsd-core/references/edge-probe-fixtures/04-money-rounding/expected-coverage.json +28 -3
  180. package/gsd-core/references/edge-probe-fixtures/05-list-dedupe/expected-coverage.json +37 -4
  181. package/gsd-core/references/edge-probe-fixtures/06-resolved-mixed/expected-coverage.json +37 -4
  182. package/gsd-core/references/edge-probe.md +195 -21
  183. package/gsd-core/references/execute-phase-between-wave-reset.md +7 -6
  184. package/gsd-core/references/execute-phase-wave-guard.md +22 -11
  185. package/gsd-core/references/gsd-run-resolver.md +1 -1
  186. package/gsd-core/references/loop-hook-dispatch.md +18 -0
  187. package/gsd-core/references/model-profiles.md +13 -4
  188. package/gsd-core/references/phase-argument-parsing.md +9 -7
  189. package/gsd-core/references/phase-id-convention.md +28 -0
  190. package/gsd-core/references/planner-gap-closure.md +2 -0
  191. package/gsd-core/references/planner-load-graph-context.md +24 -13
  192. package/gsd-core/references/planner-verify-command-grounding.md +14 -0
  193. package/gsd-core/references/planning-config.md +14 -2
  194. package/gsd-core/references/tdd.md +30 -4
  195. package/gsd-core/references/thinking-models-planning.md +18 -2
  196. package/gsd-core/references/ui-consideration-probe.md +10 -5
  197. package/gsd-core/references/verification-patterns.md +17 -4
  198. package/gsd-core/references/verify-command-path-resolvability.md +10 -2
  199. package/gsd-core/references/worktree-path-safety.md +433 -2
  200. package/gsd-core/templates/README.md +7 -1
  201. package/gsd-core/templates/state.md +6 -3
  202. package/gsd-core/templates/summary.compact.md +212 -0
  203. package/gsd-core/templates/user-setup.compact.md +199 -0
  204. package/gsd-core/templates/user-setup.md +0 -9
  205. package/gsd-core/templates/verification-report.md +1 -1
  206. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  207. package/gsd-core/workflows/add-backlog.md +1 -1
  208. package/gsd-core/workflows/add-phase.md +1 -1
  209. package/gsd-core/workflows/add-tests.md +2 -2
  210. package/gsd-core/workflows/add-todo.md +6 -5
  211. package/gsd-core/workflows/ai-integration-phase.md +11 -3
  212. package/gsd-core/workflows/audit-fix.md +1 -1
  213. package/gsd-core/workflows/audit-milestone.md +1 -1
  214. package/gsd-core/workflows/audit-uat.md +1 -1
  215. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +9 -18
  216. package/gsd-core/workflows/autonomous.md +29 -16
  217. package/gsd-core/workflows/check-todos.md +6 -4
  218. package/gsd-core/workflows/cleanup.md +5 -3
  219. package/gsd-core/workflows/code-review/steps/dispatch-fix.md +4 -3
  220. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +8 -1
  221. package/gsd-core/workflows/code-review-fix.md +108 -22
  222. package/gsd-core/workflows/code-review.md +216 -73
  223. package/gsd-core/workflows/complete-milestone/detail/elaboration.md +274 -0
  224. package/gsd-core/workflows/complete-milestone.md +41 -264
  225. package/gsd-core/workflows/debug.md +3 -3
  226. package/gsd-core/workflows/diagnose-issues.md +1 -1
  227. package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
  228. package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
  229. package/gsd-core/workflows/discuss-phase-assumptions.md +1 -1
  230. package/gsd-core/workflows/discuss-phase.md +1 -1
  231. package/gsd-core/workflows/do.md +2 -2
  232. package/gsd-core/workflows/docs-update/detail/elaboration.md +179 -0
  233. package/gsd-core/workflows/docs-update.md +17 -158
  234. package/gsd-core/workflows/edit-phase.md +1 -1
  235. package/gsd-core/workflows/eval-review.md +10 -3
  236. package/gsd-core/workflows/execute-phase/detail/elaboration.md +124 -0
  237. package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +1017 -0
  238. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +19 -4
  239. package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +56 -0
  240. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +43 -4
  241. package/gsd-core/workflows/execute-phase/steps/executor-progress-policy.md +43 -0
  242. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +1 -1
  243. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +1 -1
  244. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
  245. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +1 -1
  246. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +46 -9
  247. package/gsd-core/workflows/execute-phase/steps/protected-branch.md +1 -1
  248. package/gsd-core/workflows/execute-phase/steps/ready-wave-gate.md +37 -0
  249. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +1 -1
  250. package/gsd-core/workflows/execute-phase/steps/sequential-root-pin.md +35 -0
  251. package/gsd-core/workflows/execute-phase/steps/stale-reverification.md +24 -0
  252. package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +1 -1
  253. package/gsd-core/workflows/execute-phase/steps/threat-id-gate.md +28 -0
  254. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +1 -1
  255. package/gsd-core/workflows/execute-phase/steps/worktree-base-check.md +25 -0
  256. package/gsd-core/workflows/execute-phase.md +83 -172
  257. package/gsd-core/workflows/execute-plan.md +24 -10
  258. package/gsd-core/workflows/explore.md +3 -3
  259. package/gsd-core/workflows/extract-learnings.md +2 -1
  260. package/gsd-core/workflows/fast.md +1 -1
  261. package/gsd-core/workflows/forensics.md +1 -1
  262. package/gsd-core/workflows/graduation.md +1 -1
  263. package/gsd-core/workflows/health.md +2 -2
  264. package/gsd-core/workflows/help/modes/full.compact.md +398 -0
  265. package/gsd-core/workflows/help/modes/full.md +5 -5
  266. package/gsd-core/workflows/help/modes/topic.md +15 -5
  267. package/gsd-core/workflows/help.md +1 -1
  268. package/gsd-core/workflows/import.md +2 -2
  269. package/gsd-core/workflows/inbox.md +2 -2
  270. package/gsd-core/workflows/ingest-docs.md +3 -3
  271. package/gsd-core/workflows/insert-phase.md +1 -1
  272. package/gsd-core/workflows/list-seeds.md +1 -1
  273. package/gsd-core/workflows/list-workspaces.md +1 -1
  274. package/gsd-core/workflows/manager.md +2 -2
  275. package/gsd-core/workflows/map-codebase.md +52 -5
  276. package/gsd-core/workflows/milestone-summary.md +1 -1
  277. package/gsd-core/workflows/mvp-phase.md +1 -1
  278. package/gsd-core/workflows/new-milestone.md +56 -14
  279. package/gsd-core/workflows/new-project/detail/elaboration.md +216 -0
  280. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +3 -3
  281. package/gsd-core/workflows/new-project/steps/codebase-map-offer.md +1 -1
  282. package/gsd-core/workflows/new-project.md +39 -209
  283. package/gsd-core/workflows/new-workspace.md +2 -2
  284. package/gsd-core/workflows/next.md +1 -1
  285. package/gsd-core/workflows/note.md +1 -1
  286. package/gsd-core/workflows/onboard.md +1 -1
  287. package/gsd-core/workflows/pause-work.md +1 -1
  288. package/gsd-core/workflows/plan-phase/detail/elaboration.md +209 -0
  289. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +17 -5
  290. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
  291. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +23 -5
  292. package/gsd-core/workflows/plan-phase.md +45 -187
  293. package/gsd-core/workflows/plan-review-convergence.md +21 -5
  294. package/gsd-core/workflows/plant-seed.md +62 -20
  295. package/gsd-core/workflows/pr-branch.md +132 -20
  296. package/gsd-core/workflows/profile-user.md +2 -2
  297. package/gsd-core/workflows/progress.md +1 -1
  298. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +25 -0
  299. package/gsd-core/workflows/quick/steps/quick-verification.md +1 -1
  300. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +1 -1
  301. package/gsd-core/workflows/quick-batch/steps/batch-init.md +1 -1
  302. package/gsd-core/workflows/quick-batch/steps/completion.md +1 -1
  303. package/gsd-core/workflows/quick-batch/steps/merge-wave.md +1 -1
  304. package/gsd-core/workflows/quick-batch/steps/planner-wave.md +1 -1
  305. package/gsd-core/workflows/quick-batch/steps/research-phase.md +1 -1
  306. package/gsd-core/workflows/quick-batch/steps/resume-mode.md +1 -1
  307. package/gsd-core/workflows/quick-batch/steps/verification-wave.md +1 -1
  308. package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
  309. package/gsd-core/workflows/quick-batch.md +1 -1
  310. package/gsd-core/workflows/quick.md +29 -10
  311. package/gsd-core/workflows/reapply-patches.md +86 -6
  312. package/gsd-core/workflows/remove-phase.md +1 -1
  313. package/gsd-core/workflows/remove-workspace.md +2 -2
  314. package/gsd-core/workflows/resume-project.md +1 -1
  315. package/gsd-core/workflows/review.md +31 -16
  316. package/gsd-core/workflows/scan.md +1 -1
  317. package/gsd-core/workflows/secure-phase.md +3 -2
  318. package/gsd-core/workflows/settings-advanced.md +30 -10
  319. package/gsd-core/workflows/settings-integrations.md +2 -3
  320. package/gsd-core/workflows/settings.md +22 -9
  321. package/gsd-core/workflows/ship.md +3 -2
  322. package/gsd-core/workflows/sketch-wrap-up.md +1 -1
  323. package/gsd-core/workflows/sketch.md +1 -1
  324. package/gsd-core/workflows/smart-entry.md +2 -2
  325. package/gsd-core/workflows/spec-phase.md +15 -5
  326. package/gsd-core/workflows/spike-wrap-up.md +1 -1
  327. package/gsd-core/workflows/spike.md +1 -1
  328. package/gsd-core/workflows/stats.md +1 -1
  329. package/gsd-core/workflows/sync-skills.md +5 -5
  330. package/gsd-core/workflows/thread.md +1 -1
  331. package/gsd-core/workflows/transition.md +1 -1
  332. package/gsd-core/workflows/ui-phase.md +44 -8
  333. package/gsd-core/workflows/ui-review.md +18 -4
  334. package/gsd-core/workflows/ultraplan-phase.md +1 -1
  335. package/gsd-core/workflows/undo.md +339 -20
  336. package/gsd-core/workflows/update.md +14 -12
  337. package/gsd-core/workflows/validate-phase.md +3 -2
  338. package/gsd-core/workflows/verify-work/detail/elaboration.md +230 -0
  339. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
  340. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
  341. package/gsd-core/workflows/verify-work.md +101 -196
  342. package/hooks/dist/gsd-agent-isolation-guard.js +66 -16
  343. package/hooks/dist/gsd-context-monitor.js +88 -15
  344. package/hooks/dist/gsd-cursor-subagent-start.js +34 -14
  345. package/hooks/dist/gsd-secret-read-guard.js +71 -19
  346. package/hooks/dist/gsd-statusline.js +81 -20
  347. package/hooks/dist/gsd-validate-commit.sh +97 -8
  348. package/hooks/dist/gsd-worktree-path-guard.js +25 -14
  349. package/hooks/dist/gsd-write-guard.js +46 -1
  350. package/hooks/dist/lib/dispatch-identity.js +187 -0
  351. package/hooks/dist/lib/filename-classification.js +64 -0
  352. package/hooks/dist/lib/isolation-deny-reason.js +53 -1
  353. package/hooks/dist/lib/isolation-sentinel.js +58 -19
  354. package/hooks/gsd-agent-isolation-guard.js +66 -16
  355. package/hooks/gsd-context-monitor.js +88 -15
  356. package/hooks/gsd-cursor-subagent-start.js +34 -14
  357. package/hooks/gsd-secret-read-guard.js +71 -19
  358. package/hooks/gsd-statusline.js +81 -20
  359. package/hooks/gsd-validate-commit.sh +97 -8
  360. package/hooks/gsd-worktree-path-guard.js +25 -14
  361. package/hooks/gsd-write-guard.js +46 -1
  362. package/hooks/lib/dispatch-identity.js +187 -0
  363. package/hooks/lib/filename-classification.js +64 -0
  364. package/hooks/lib/isolation-deny-reason.js +53 -1
  365. package/hooks/lib/isolation-sentinel.js +58 -19
  366. package/package.json +11 -6
  367. package/scripts/benchmark-compact-content-variants.cjs +298 -0
  368. package/scripts/benchmark-compact-content.cjs +368 -0
  369. package/scripts/build-hooks.js +15 -6
  370. package/scripts/check-contract-drift.cjs +131 -12
  371. package/scripts/check-env.cjs +36 -8
  372. package/scripts/check-glossary-refs.cjs +25 -21
  373. package/scripts/ci-next-health.cjs +271 -0
  374. package/scripts/ci-prepare-test-scope.cjs +7 -7
  375. package/scripts/ci-test-scope.cjs +126 -20
  376. package/scripts/ci-timeout-report.cjs +1 -1
  377. package/scripts/command-contract-helpers.cjs +3 -0
  378. package/scripts/diff-touches-shipped-paths.cjs +1 -1
  379. package/scripts/docs-guard-registry.cjs +35 -2
  380. package/scripts/gen-adr-index.cjs +8 -2
  381. package/scripts/gen-inventory-manifest.cjs +12 -0
  382. package/scripts/gen-loop-host-contract.cjs +69 -0
  383. package/scripts/gen-platform-conformance-tier.cjs +557 -0
  384. package/scripts/lib/drift-scan.cjs +1 -1
  385. package/scripts/lib/macos-conformance-tier.generated.cjs +224 -0
  386. package/scripts/lib/ndjson-reporter.cjs +3 -2
  387. package/scripts/lib/npm-version-check-diagnosis.cjs +59 -0
  388. package/scripts/lib/platform-conformance-tier.generated.cjs +287 -0
  389. package/scripts/lib/suite-detection.cjs +32 -0
  390. package/scripts/lint-allowed-tools-parity.cjs +221 -0
  391. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +47 -3
  392. package/scripts/lint-phase-arg-assignment.cjs +257 -0
  393. package/scripts/lint-phase-id-drift.cjs +623 -13
  394. package/scripts/lint-pr-branch-pattern-drift.cjs +148 -0
  395. package/scripts/lint-response-language-coverage.cjs +9 -3
  396. package/scripts/lint-retired-runtime-name.cjs +619 -0
  397. package/scripts/lint-source-test-name-collision.cjs +1 -1
  398. package/scripts/lint-state-write-path-drift.cjs +93 -0
  399. package/scripts/lint-test-file-count.allowlist.json +29 -9
  400. package/scripts/lint-vendored-deps.cjs +128 -17
  401. package/scripts/lint-workflow-shellcheck-baseline.json +100 -0
  402. package/scripts/prompt-injection-scan.sh +18 -0
  403. package/scripts/release-tarball-smoke.cjs +194 -1
  404. package/scripts/workflow-size.cjs +139 -0
  405. package/skills/gsd-autonomous/SKILL.md +2 -2
  406. package/skills/gsd-capture/SKILL.md +1 -1
  407. package/skills/gsd-cleanup/SKILL.md +1 -0
  408. package/skills/gsd-code-review/SKILL.md +2 -1
  409. package/skills/gsd-complete-milestone/SKILL.md +1 -0
  410. package/skills/gsd-config/SKILL.md +1 -0
  411. package/skills/gsd-debug/SKILL.md +1 -0
  412. package/skills/gsd-graphify/SKILL.md +1 -0
  413. package/skills/gsd-health/SKILL.md +1 -0
  414. package/skills/gsd-mempalace-capture/SKILL.md +8 -3
  415. package/skills/gsd-mempalace-recall/SKILL.md +1 -0
  416. package/skills/gsd-new-milestone/SKILL.md +1 -0
  417. package/skills/gsd-new-project/SKILL.md +1 -0
  418. package/skills/gsd-next/SKILL.md +1 -0
  419. package/skills/gsd-pause-work/SKILL.md +1 -0
  420. package/skills/gsd-phase/SKILL.md +1 -0
  421. package/skills/gsd-plan-review-convergence/SKILL.md +5 -5
  422. package/skills/gsd-pr-branch/SKILL.md +1 -0
  423. package/skills/gsd-progress/SKILL.md +1 -1
  424. package/skills/gsd-quick-batch/SKILL.md +1 -1
  425. package/skills/gsd-resume-work/SKILL.md +1 -0
  426. package/skills/gsd-review/SKILL.md +2 -3
  427. package/skills/gsd-review-backlog/SKILL.md +1 -0
  428. package/skills/gsd-settings/SKILL.md +2 -1
  429. package/skills/gsd-stats/SKILL.md +1 -0
  430. package/skills/gsd-thread/SKILL.md +1 -0
  431. package/skills/gsd-workspace/SKILL.md +1 -0
  432. package/skills/gsd-workstreams/SKILL.md +1 -0
  433. package/vscode/package.json +1 -1
  434. package/gsd-core/templates/claude-md.md +0 -145
  435. package/gsd-core/templates/codebase/concerns.md +0 -310
  436. package/gsd-core/templates/codebase/conventions.md +0 -307
  437. package/gsd-core/templates/codebase/integrations.md +0 -280
  438. package/gsd-core/templates/codebase/structure.md +0 -285
  439. package/gsd-core/templates/codebase/testing.md +0 -480
  440. package/gsd-core/templates/debug-subagent-prompt.md +0 -91
  441. package/gsd-core/templates/discovery.md +0 -146
@@ -0,0 +1,337 @@
1
+ "use strict";
2
+ /**
3
+ * Reviewer Step Dispatch (#4209 Phase 1 Plan 2, ADR-2782 seam).
4
+ *
5
+ * ONE interpreter for "a step declares `supportsReviewerLanes: true`" — see
6
+ * `gsd-core/references/loop-hook-dispatch.md` for the canonical explanation of the trait and how
7
+ * `review-lane dispatch-step` re-derives it. This module trusts `trait` exactly as given: it is
8
+ * the CALLER's job to have derived it correctly. Every direct or lifecycle caller routes through
9
+ * `dispatchReviewerLanes` so selection/plan/invoke logic is owned once, not re-derived per
10
+ * feature. This module owns NONE of those primitives — it wires `resolveReviewerSelection`
11
+ * (selection) and `resolveLanePlan` (planning), the same building blocks
12
+ * `gsd-core/bin/gsd-tools.cjs`'s `review-lane plan` subcommand uses. Invocation (`runLane`) needs
13
+ * OS-aware spawn/probe plumbing this module does not own, so `deps.invoke` is the one required,
14
+ * caller-supplied seam (wired for real in `gsd-core/bin/gsd-tools.cjs`'s `review-lane
15
+ * dispatch-step` route).
16
+ *
17
+ * Fail-closed contract:
18
+ * - Trait not exactly `true`, or nothing selected → inert. Zero plan/invoke calls.
19
+ * - Missing/unsafe request-level input (paths escaping `repoRoot`, absent depth/base SHA) stops
20
+ * the WHOLE dispatch before any lane is planned or invoked.
21
+ * - An explicitly requested lane the selector could not resolve does not silently narrow the
22
+ * result to only what worked: lanes that DID resolve still run and their results are kept,
23
+ * but the aggregate `ok` is `false` so no caller mistakes a partial run for a clean one.
24
+ * - Once a lane is planned, a per-lane plan/budget/invoke failure never displaces or cancels a
25
+ * sibling lane already run.
26
+ * - A lane whose `promptChannel` is `'none'` (it reviews the working tree on its own terms, fed
27
+ * nothing — e.g. `coderabbit`) cannot receive the bounded prompt below and is rejected before
28
+ * plan/invoke, same as an unresolved slug.
29
+ *
30
+ * The bounded source-review prompt built here is METADATA ONLY — repository root, canonical
31
+ * file paths, review depth, base SHA, and four fixed prohibitions. It never embeds file
32
+ * contents. If the assembled prompt exceeds a lane's resolved budget, that lane's dispatch
33
+ * hard-fails before `invoke` runs for it — no silent truncation of the file list.
34
+ */
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.SOURCE_REVIEW_PROHIBITIONS = exports.DISPATCH_REASON = void 0;
40
+ exports.buildSourceReviewPrompt = buildSourceReviewPrompt;
41
+ exports.dispatchReviewerLanes = dispatchReviewerLanes;
42
+ const node_fs_1 = __importDefault(require("node:fs"));
43
+ const node_path_1 = __importDefault(require("node:path"));
44
+ const prompt_budget_cjs_1 = require("./prompt-budget.cjs");
45
+ const security_cjs_1 = require("./security.cjs");
46
+ const review_lane_invocation_cjs_1 = require("./review-lane-invocation.cjs");
47
+ const review_reviewer_selection_cjs_1 = require("./review-reviewer-selection.cjs");
48
+ /** Closed set of request-level (not per-lane) halt reasons. Mirrors `LANE_UNAVAILABLE`'s shape. */
49
+ exports.DISPATCH_REASON = Object.freeze({
50
+ TRAIT_NOT_ENABLED: 'trait_not_enabled',
51
+ NO_LANES_SELECTED: 'no_lanes_selected',
52
+ SELECTION_FAILED: 'selection_failed',
53
+ INVALID_PATHS: 'invalid_paths',
54
+ PATH_ESCAPES_REPO_ROOT: 'path_escapes_repo_root',
55
+ MISSING_PROVENANCE: 'missing_provenance',
56
+ INVALID_PROVENANCE: 'invalid_provenance',
57
+ PROMPT_WRITE_FAILED: 'prompt_write_failed',
58
+ });
59
+ /** Fixed, non-negotiable prompt constraints (SAFE-03..SAFE-06). Order is the display order. */
60
+ exports.SOURCE_REVIEW_PROHIBITIONS = Object.freeze([
61
+ 'Do not modify any source file.',
62
+ 'Do not run tests.',
63
+ 'Do not start background processes.',
64
+ 'Do not poll or wait — return findings from a single read-only pass.',
65
+ ]);
66
+ // #4209 RQ-04: a control character (newline, CR, NUL, ...) in ANY string this module embeds
67
+ // into the external prompt (`buildSourceReviewPrompt`) lets it inject a fabricated section —
68
+ // not just via `paths` (agy-F1's original finding), since `depth`, `baseSha`, and `repoRoot` land
69
+ // in that same markdown. Every embedded string is checked against this ONE shared boundary.
70
+ const CONTROL_CHAR = /[\x00-\x1f\x7f\u2028\u2029]/;
71
+ function defaultWritePromptFile(filePath, content) {
72
+ node_fs_1.default.writeFileSync(filePath, content, 'utf8');
73
+ }
74
+ /**
75
+ * Validate that every path is a non-empty string resolving INSIDE `repoRoot` — blocks `..`
76
+ * traversal and absolute paths pointing elsewhere before any lane sees them.
77
+ */
78
+ function validatePaths(repoRoot, paths) {
79
+ if (!Array.isArray(paths) || paths.length === 0) {
80
+ return { ok: false, reason: exports.DISPATCH_REASON.INVALID_PATHS };
81
+ }
82
+ const root = node_path_1.default.resolve(String(repoRoot ?? ''));
83
+ // repoRoot itself may be a symlink (e.g. a `/tmp`-based worktree on macOS, where `/tmp` is
84
+ // itself a symlink to `/private/tmp`) — realpath it once so the per-path comparison below
85
+ // compares like with like, not a resolved child path against an unresolved root.
86
+ let realRoot;
87
+ try {
88
+ realRoot = node_fs_1.default.realpathSync(root);
89
+ }
90
+ catch {
91
+ realRoot = root;
92
+ }
93
+ // #4209 agy-F1: a control character (newline, CR, NUL, ...) in a path lets a maliciously
94
+ // named repo file inject a fabricated section into the markdown prompt built from `paths`
95
+ // below (buildSourceReviewPrompt) — reject it here, at the shared trust boundary, rather than
96
+ // relying on the incidental quoting `git diff --name-only` happens to apply upstream.
97
+ for (const p of paths) {
98
+ if (typeof p !== 'string' || p.length === 0 || CONTROL_CHAR.test(p)) {
99
+ return { ok: false, reason: exports.DISPATCH_REASON.INVALID_PATHS };
100
+ }
101
+ // ADR-4650 decision 6: lexical family — this is the first of the two
102
+ // deliberate halves (#4209 WR-05); the ENOENT-tolerant realpath half
103
+ // below cannot be folded into a single `tryWithinRoot` call (its
104
+ // ancestor-walk would accept a deleted path via the nearest existing
105
+ // ancestor, not the explicit `continue` this code requires).
106
+ const resolved = node_path_1.default.resolve(root, p);
107
+ if ((0, security_cjs_1.tryWithinRootLexical)(p, root) === null) {
108
+ return { ok: false, reason: exports.DISPATCH_REASON.PATH_ESCAPES_REPO_ROOT };
109
+ }
110
+ // #4209 WR-05: `path.resolve` is lexical only — a symlink whose OWN path sits inside
111
+ // repoRoot can still point outside it, passing the check above while listing an
112
+ // out-of-repo file for the external lane to read. `fs.realpathSync` follows the link;
113
+ // ENOENT is expected and benign here (a `git diff --name-only` path can legitimately name
114
+ // a file already deleted in a stale worktree) and is not itself an escape.
115
+ let real;
116
+ try {
117
+ real = node_fs_1.default.realpathSync(resolved);
118
+ }
119
+ catch {
120
+ continue;
121
+ }
122
+ if ((0, security_cjs_1.tryWithinRootLexical)(real, realRoot) === null) {
123
+ return { ok: false, reason: exports.DISPATCH_REASON.PATH_ESCAPES_REPO_ROOT };
124
+ }
125
+ }
126
+ return { ok: true };
127
+ }
128
+ // `resolveLaneBudget` (review-lane-invocation.cjs) resolves the number; `null` and a resolved
129
+ // `0` both mean unbounded (#2797) — the caller's overflow check must test both `!== null` and
130
+ // `!== 0`. See the call site below.
131
+ /**
132
+ * One-line depth definition for an external reviewer lane, condensed from `<depth_levels>` in
133
+ * `agents/gsd-code-reviewer.md` (#4209 review: a bare `quick`/`standard`/`deep` label means
134
+ * nothing to a third-party CLI that never sees that agent's system prompt — unlike the internal
135
+ * reviewer, whose own persona fully defines these three terms). Every category named here must
136
+ * stay a strict subset of what `<depth_levels>` actually does — `tests/reviewer-step-dispatch
137
+ * .test.cjs`'s "depthMeaning tracks depth_levels" tests assert each case against the real agent
138
+ * file, not just against this function, so the two cannot silently drift again. An unrecognised
139
+ * depth normalizes to `standard`'s text, matching `agents/gsd-code-reviewer.md`'s own "if depth
140
+ * is not one of quick/standard/deep, default to standard" rule — the raw label is not repeated
141
+ * here since `buildSourceReviewPrompt` already states it once, verbatim, earlier in the prompt.
142
+ */
143
+ function depthMeaning(depth) {
144
+ switch (depth) {
145
+ case 'quick':
146
+ return 'pattern-scan without reading full file contents: hardcoded secrets, dangerous functions, debug artifacts, empty catch blocks, commented-out code';
147
+ case 'standard':
148
+ return 'read each changed file in context for bugs, security, and quality problems; cross-reference imports and exports';
149
+ case 'deep':
150
+ return 'standard, plus cross-file analysis: trace call chains, check type consistency at API boundaries, verify error propagation, check state mutation consistency, detect circular dependencies';
151
+ default:
152
+ return depthMeaning('standard');
153
+ }
154
+ }
155
+ /**
156
+ * Build the bounded source-review prompt. Metadata only — repoRoot, paths, depth, base SHA, and
157
+ * the four fixed prohibitions. NEVER embeds file contents.
158
+ */
159
+ function buildSourceReviewPrompt(input) {
160
+ // Base SHA is identical for every file and already stated once above — repeating it per line
161
+ // (as an earlier version of this prompt did) wastes real tokens at O(files), for zero
162
+ // information gain, on every dispatched lane.
163
+ const fileLines = input.paths.map((p) => `- ${p}`).join('\n');
164
+ const ruleLines = exports.SOURCE_REVIEW_PROHIBITIONS.map((r, i) => `${i + 1}. ${r}`).join('\n');
165
+ return [
166
+ '## Source Review Request',
167
+ '',
168
+ `Repository root: ${input.repoRoot}`,
169
+ `Review depth: ${input.depth}`,
170
+ `Base SHA: ${input.baseSha}`,
171
+ '',
172
+ 'Review the changes introduced in each file below relative to the base SHA above, at the',
173
+ `requested depth (${depthMeaning(input.depth)}). Report every bug, security issue, and`,
174
+ 'code-quality problem you find. For every claim you make, cite the exact file path and line',
175
+ 'number(s) it applies to — a claim with no file:line citation cannot be independently',
176
+ 're-verified and will be discarded by the consolidating reviewer. Performance issues',
177
+ '(O(n²), memory leaks) are out of scope unless also correctness issues (e.g. an infinite',
178
+ 'loop) — do not flag them otherwise.',
179
+ '',
180
+ '### Files in scope',
181
+ fileLines,
182
+ '',
183
+ '### Rules',
184
+ ruleLines,
185
+ ].join('\n');
186
+ }
187
+ /**
188
+ * Dispatch every selected reviewer lane for one opted-in step. See module docstring for scope.
189
+ */
190
+ async function dispatchReviewerLanes(input, deps) {
191
+ if (input.trait !== true) {
192
+ return { dispatched: false, ok: true, reason: exports.DISPATCH_REASON.TRAIT_NOT_ENABLED, results: [] };
193
+ }
194
+ const resolveSelection = deps.resolveSelection ?? review_reviewer_selection_cjs_1.resolveReviewerSelection;
195
+ const selection = resolveSelection(input.selection);
196
+ if (selection.selected.length === 0) {
197
+ // Distinguish "explicitly requested but every candidate was unavailable" (a real failure —
198
+ // `errors` is non-empty) from "nothing was ever requested" (a clean, inert no-op).
199
+ const reason = selection.errors.length > 0
200
+ ? exports.DISPATCH_REASON.SELECTION_FAILED
201
+ : exports.DISPATCH_REASON.NO_LANES_SELECTED;
202
+ return { dispatched: false, ok: selection.errors.length === 0, reason, selection, results: [] };
203
+ }
204
+ const pathCheck = validatePaths(input.repoRoot, input.paths);
205
+ if (!pathCheck.ok) {
206
+ return { dispatched: false, ok: false, reason: pathCheck.reason, selection, results: [] };
207
+ }
208
+ // #4209 RQ-04: depth/baseSha/repoRoot/runDir land in the SAME markdown prompt `paths` does
209
+ // (buildSourceReviewPrompt, `dispatchReviewerLanes`'s `runDir`-derived promptPath write) — a
210
+ // control character in any of them is the identical injection vector agy-F1 found in `paths`,
211
+ // so this trust boundary must reject it here too, not just for the file list.
212
+ if (typeof input.depth !== 'string' || input.depth.length === 0
213
+ || typeof input.baseSha !== 'string' || input.baseSha.length === 0
214
+ || typeof input.repoRoot !== 'string' || input.repoRoot.length === 0
215
+ || typeof input.runDir !== 'string' || input.runDir.length === 0) {
216
+ return { dispatched: false, ok: false, reason: exports.DISPATCH_REASON.MISSING_PROVENANCE, selection, results: [] };
217
+ }
218
+ // #4209 WR-04: a present-but-malicious field (control character) is a different failure mode
219
+ // than an absent one — MISSING_PROVENANCE above means "the caller never supplied this"; this
220
+ // branch means "the caller supplied something and it's an injection attempt," which a caller
221
+ // handling the two reasons differently (e.g. surfacing one as a config problem, the other as
222
+ // a security event) must be able to tell apart.
223
+ if (CONTROL_CHAR.test(input.depth) || CONTROL_CHAR.test(input.baseSha)
224
+ || CONTROL_CHAR.test(input.repoRoot) || CONTROL_CHAR.test(input.runDir)) {
225
+ return { dispatched: false, ok: false, reason: exports.DISPATCH_REASON.INVALID_PROVENANCE, selection, results: [] };
226
+ }
227
+ // #4209 WR-03 (considered, declined): gating `depth` to code-review's quick/standard/deep
228
+ // enum here would reject the deliberately capability-neutral case this function supports —
229
+ // see "a second, unrelated synthetic step context dispatches through the same function
230
+ // identically" below, which passes a wholly different depth vocabulary on purpose to prove
231
+ // this dispatcher has no code-review-specific special-casing. `depthMeaning()`'s `standard`
232
+ // fallback for an off-enum value is accepted, not a bug, for that reason.
233
+ const { configGet, getLane, plan } = deps;
234
+ const writePromptFile = deps.writePromptFile ?? defaultWritePromptFile;
235
+ const prompt = buildSourceReviewPrompt(input);
236
+ const estimatedTokens = (0, prompt_budget_cjs_1.estimateTokens)(prompt);
237
+ // Written once, before any lane's plan() runs: `promptPath` is derived from `runDir` alone
238
+ // (see `artifactPaths`), constant across every lane in this dispatch by construction — there
239
+ // is no per-lane variance to defend against, so writing it per-lane (as an earlier version of
240
+ // this function did) was pure redundancy, not a real safeguard.
241
+ // A hoisted, whole-dispatch write (see the doc comment above) that throws must not escape as
242
+ // an uncaught exception — no lane can succeed anyway if the shared prompt file was never
243
+ // written, so this is a dispatch-level halt like `validatePaths`/`MISSING_PROVENANCE` above,
244
+ // not a per-lane failure.
245
+ try {
246
+ writePromptFile((0, review_lane_invocation_cjs_1.artifactPaths)(input.runDir, '').promptPath, prompt);
247
+ }
248
+ catch {
249
+ return { dispatched: false, ok: false, reason: exports.DISPATCH_REASON.PROMPT_WRITE_FAILED, selection, results: [] };
250
+ }
251
+ const results = [];
252
+ // Never narrow the requested set: an explicit reviewer the selector could not resolve is
253
+ // already surfaced in `selection.errors` — reflect that in the aggregate `ok` even though
254
+ // lanes that DID resolve still run below and keep their own results.
255
+ let anyFailed = selection.errors.length > 0;
256
+ // Tracks whether any lane actually reached plan() — `dispatched` must stay false when every
257
+ // selected slug turned out to be unresolvable, even though a `results` entry was still pushed.
258
+ let planned = false;
259
+ for (const slug of selection.selected) {
260
+ const lane = getLane(slug);
261
+ if (!lane) {
262
+ results.push({ slug, ok: false, reason: 'malformed_lane', detail: 'no such declared lane' });
263
+ anyFailed = true;
264
+ continue;
265
+ }
266
+ // #4209 review: a `promptChannel: 'none'` lane (coderabbit) is fed nothing and reviews
267
+ // whatever it independently sees fit (its own working-tree diff, review.md:367) rather than
268
+ // the bounded `paths`/`depth`/`baseSha` scope `buildSourceReviewPrompt` promises — silently
269
+ // dispatching it here would violate this interpreter's own scoped, metadata-only review
270
+ // contract. Reject before plan()/invoke() rather than let the mismatch surface as an
271
+ // unexplained out-of-scope review.
272
+ if (lane.transport === 'spawn' && lane.invoke.promptChannel === 'none') {
273
+ results.push({
274
+ slug,
275
+ ok: false,
276
+ reason: 'prompt_channel_unsupported',
277
+ detail: `lane '${slug}' declares promptChannel 'none' and cannot receive a scoped source-review prompt`,
278
+ });
279
+ anyFailed = true;
280
+ continue;
281
+ }
282
+ // A single throwing plan()/invoke() must not take down every sibling lane already collected
283
+ // in `results` — same rationale as gsd-tools.cjs's resolveLanePlan guard
284
+ // (#2494/#2605/#1698/#1936/#2073/#2176/#2589/#2794): belt and braces on purpose.
285
+ let planOutcome;
286
+ try {
287
+ planOutcome = plan(lane, { configGet, runDir: input.runDir, repoRoot: input.repoRoot });
288
+ }
289
+ catch (e) {
290
+ results.push({ slug, ok: false, reason: 'malformed_lane', detail: e instanceof Error ? e.message : String(e) });
291
+ anyFailed = true;
292
+ continue;
293
+ }
294
+ if (!planOutcome.ok) {
295
+ results.push({ slug, ok: false, reason: planOutcome.reason, detail: planOutcome.detail });
296
+ anyFailed = true;
297
+ continue;
298
+ }
299
+ const budget = (0, review_lane_invocation_cjs_1.resolveLaneBudget)(lane, configGet);
300
+ if (budget !== null && budget !== 0 && estimatedTokens > budget) {
301
+ results.push({
302
+ slug,
303
+ ok: false,
304
+ reason: 'budget_exceeded',
305
+ detail: `estimated ${estimatedTokens} tokens exceeds resolved budget ${budget} for lane '${slug}'`,
306
+ });
307
+ anyFailed = true;
308
+ continue;
309
+ }
310
+ planned = true;
311
+ let invokeOutcome;
312
+ try {
313
+ invokeOutcome = await deps.invoke(lane, planOutcome.plan);
314
+ }
315
+ catch (e) {
316
+ results.push({ slug, ok: false, reason: 'invoke_failed', detail: e instanceof Error ? e.message : String(e) });
317
+ anyFailed = true;
318
+ continue;
319
+ }
320
+ if (!invokeOutcome.ok)
321
+ anyFailed = true;
322
+ results.push({
323
+ slug,
324
+ ok: invokeOutcome.ok,
325
+ reason: invokeOutcome.reason,
326
+ detail: invokeOutcome.detail,
327
+ reviewPath: invokeOutcome.reviewPath,
328
+ errPath: invokeOutcome.errPath,
329
+ });
330
+ }
331
+ return {
332
+ dispatched: planned,
333
+ ok: !anyFailed,
334
+ selection,
335
+ results,
336
+ };
337
+ }
@@ -19,6 +19,9 @@ const { routeCjsCommandFamily } = cjsCommandRouterAdapter;
19
19
  // eslint-disable-next-line @typescript-eslint/no-require-imports
20
20
  const roadmapUpgrade = require("./roadmap-upgrade.cjs");
21
21
  // eslint-disable-next-line @typescript-eslint/no-require-imports
22
+ const phaseIdCardMod = require("./phase-id-card.cjs");
23
+ const { phaseIdCard } = phaseIdCardMod;
24
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
22
25
  const planningWorkspace = require("./planning-workspace.cjs");
23
26
  const { planningDir } = planningWorkspace;
24
27
  // eslint-disable-next-line @typescript-eslint/no-require-imports
@@ -234,7 +237,7 @@ function routeRoadmapCommand({ roadmap, args, cwd, raw, error }) {
234
237
  'upgrade': () => {
235
238
  const dryRun = !args.includes('--apply');
236
239
  // Parse `--convention <value>` and `--convention=<value>`. When the flag is
237
- // absent entirely, default to the only supported convention; when present
240
+ // absent entirely, default to the legacy supported convention; when present
238
241
  // with a missing/unsupported value, fall through to the rejection below
239
242
  // (fail-closed — never silently run a migration the user did not request).
240
243
  let convention = 'milestone-prefixed';
@@ -245,13 +248,18 @@ function routeRoadmapCommand({ roadmap, args, cwd, raw, error }) {
245
248
  ? token.slice(token.indexOf('=') + 1)
246
249
  : (args[conventionFlagIdx + 1] ?? '');
247
250
  }
248
- if (convention !== 'milestone-prefixed') {
251
+ if (convention !== 'milestone-prefixed' && convention !== 'bracket') {
249
252
  // No-throw hub contract (ADR-0012): a hub-dispatched handler must not call
250
253
  // process.exit. Throw instead — the hub converts this to HandlerFailure and
251
254
  // the adapter routes it through the injected error() boundary.
252
- throw new Error('Only --convention milestone-prefixed is supported');
255
+ throw new Error('Only --convention milestone-prefixed or bracket is supported');
256
+ }
257
+ if (convention === 'bracket') {
258
+ // Keep stdout machine-readable for the dry-run JSON plan. The card is
259
+ // human guidance emitted at command start for both dry-run and apply.
260
+ process.stderr.write(`${phaseIdCard({ title: 'Bracket phase-ID convention' })}\n`);
253
261
  }
254
- const plan = roadmapUpgrade.computeMigrationPlan(cwd);
262
+ const plan = roadmapUpgrade.computeMigrationPlan(cwd, { convention });
255
263
  roadmapUpgrade.applyMigration(cwd, plan, { dryRun });
256
264
  },
257
265
  },