@opengsd/gsd-core 1.12.0 → 1.14.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 (455) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.opencode/plugins/gsd-core.js +12 -0
  4. package/agents/gsd-advisor-researcher.compact.md +85 -0
  5. package/agents/gsd-ai-researcher.compact.md +96 -0
  6. package/agents/gsd-assumptions-analyzer.compact.md +81 -0
  7. package/agents/gsd-code-fixer.compact.md +458 -0
  8. package/agents/gsd-code-fixer.md +5 -5
  9. package/agents/gsd-code-reviewer.compact.md +269 -0
  10. package/agents/gsd-code-reviewer.md +15 -3
  11. package/agents/gsd-codebase-mapper.compact.md +760 -0
  12. package/agents/gsd-debug-session-manager.compact.md +345 -0
  13. package/agents/gsd-doc-classifier.compact.md +192 -0
  14. package/agents/gsd-doc-synthesizer.compact.md +200 -0
  15. package/agents/gsd-doc-verifier.compact.md +143 -0
  16. package/agents/gsd-doc-writer.compact.md +440 -0
  17. package/agents/gsd-dom-verifier.compact.md +138 -0
  18. package/agents/gsd-domain-researcher.compact.md +141 -0
  19. package/agents/gsd-eval-auditor.compact.md +160 -0
  20. package/agents/gsd-eval-planner.compact.md +137 -0
  21. package/agents/gsd-executor.md +63 -35
  22. package/agents/gsd-framework-selector.compact.md +82 -0
  23. package/agents/gsd-integration-checker.compact.md +245 -0
  24. package/agents/gsd-intel-updater.compact.md +226 -0
  25. package/agents/gsd-mempalace-curator.compact.md +45 -0
  26. package/agents/gsd-nyquist-auditor.compact.md +179 -0
  27. package/agents/gsd-pattern-mapper.compact.md +275 -0
  28. package/agents/gsd-plan-checker.md +76 -57
  29. package/agents/gsd-planner.md +14 -0
  30. package/agents/gsd-project-researcher.compact.md +587 -0
  31. package/agents/gsd-research-synthesizer.compact.md +212 -0
  32. package/agents/gsd-roadmapper.compact.md +454 -0
  33. package/agents/gsd-roadmapper.md +13 -0
  34. package/agents/gsd-security-auditor.compact.md +162 -0
  35. package/agents/gsd-ui-auditor.compact.md +404 -0
  36. package/agents/gsd-ui-checker.compact.md +277 -0
  37. package/agents/gsd-ui-checker.md +19 -3
  38. package/agents/gsd-ui-researcher.compact.md +282 -0
  39. package/agents/gsd-ui-researcher.md +29 -0
  40. package/agents/gsd-user-profiler.compact.md +108 -0
  41. package/agents/gsd-verifier.md +23 -1
  42. package/bin/install.js +444 -134
  43. package/commands/gsd/cleanup.md +1 -0
  44. package/commands/gsd/code-review.md +2 -1
  45. package/commands/gsd/complete-milestone.md +1 -0
  46. package/commands/gsd/config.md +1 -0
  47. package/commands/gsd/debug.md +1 -0
  48. package/commands/gsd/execute-phase.md +1 -1
  49. package/commands/gsd/graphify.md +1 -0
  50. package/commands/gsd/health.md +1 -0
  51. package/commands/gsd/mempalace-capture.md +1 -0
  52. package/commands/gsd/mempalace-recall.md +1 -0
  53. package/commands/gsd/new-milestone.md +1 -0
  54. package/commands/gsd/new-project.md +1 -0
  55. package/commands/gsd/next.md +1 -0
  56. package/commands/gsd/ns-workflow.md +2 -1
  57. package/commands/gsd/pause-work.md +1 -0
  58. package/commands/gsd/phase.md +2 -1
  59. package/commands/gsd/pr-branch.md +1 -0
  60. package/commands/gsd/quick-batch.md +105 -0
  61. package/commands/gsd/resume-work.md +1 -0
  62. package/commands/gsd/review-backlog.md +1 -0
  63. package/commands/gsd/settings.md +2 -1
  64. package/commands/gsd/stats.md +1 -0
  65. package/commands/gsd/surface.md +18 -8
  66. package/commands/gsd/thread.md +1 -0
  67. package/commands/gsd/workspace.md +1 -0
  68. package/commands/gsd/workstreams.md +1 -0
  69. package/gsd-core/bin/check-latest-version.cjs +8 -3
  70. package/gsd-core/bin/gsd-tools.cjs +532 -174
  71. package/gsd-core/bin/lib/adr-parser.cjs +1 -1
  72. package/gsd-core/bin/lib/artifacts.cjs +2 -1
  73. package/gsd-core/bin/lib/audit.cjs +39 -22
  74. package/gsd-core/bin/lib/broken-windows.cjs +168 -49
  75. package/gsd-core/bin/lib/capability-activation.cjs +27 -0
  76. package/gsd-core/bin/lib/capability-lifecycle.cjs +10 -6
  77. package/gsd-core/bin/lib/capability-loader.cjs +135 -1
  78. package/gsd-core/bin/lib/capability-registry.cjs +528 -116
  79. package/gsd-core/bin/lib/capability-source.cjs +19 -2
  80. package/gsd-core/bin/lib/capability-state.cjs +7 -1
  81. package/gsd-core/bin/lib/capability-validator.cjs +134 -5
  82. package/gsd-core/bin/lib/capability-writer.cjs +14 -4
  83. package/gsd-core/bin/lib/check-command-router.cjs +198 -38
  84. package/gsd-core/bin/lib/claude-orchestration.cjs +10 -25
  85. package/gsd-core/bin/lib/clusters.cjs +1 -0
  86. package/gsd-core/bin/lib/code-review-depth.cjs +2 -2
  87. package/gsd-core/bin/lib/command-aliases.cjs +16 -0
  88. package/gsd-core/bin/lib/commands.cjs +981 -79
  89. package/gsd-core/bin/lib/config-loader.cjs +4 -0
  90. package/gsd-core/bin/lib/config.cjs +153 -38
  91. package/gsd-core/bin/lib/core-utils.cjs +34 -7
  92. package/gsd-core/bin/lib/coverage.cjs +1 -1
  93. package/gsd-core/bin/lib/decisions.cjs +343 -28
  94. package/gsd-core/bin/lib/edge-probe.cjs +14 -1
  95. package/gsd-core/bin/lib/external-descriptor-trust.cjs +29 -14
  96. package/gsd-core/bin/lib/file-overlap-partitioner.cjs +74 -0
  97. package/gsd-core/bin/lib/frontmatter.cjs +137 -23
  98. package/gsd-core/bin/lib/gap-checker.cjs +22 -13
  99. package/gsd-core/bin/lib/git-base-branch.cjs +10 -2
  100. package/gsd-core/bin/lib/gsd2-import.cjs +1 -2
  101. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +8 -2
  102. package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +54 -11
  103. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +87 -23
  104. package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +1 -1
  105. package/gsd-core/bin/lib/host-integration.cjs +57 -5
  106. package/gsd-core/bin/lib/init-command-router.cjs +14 -0
  107. package/gsd-core/bin/lib/init.cjs +539 -60
  108. package/gsd-core/bin/lib/install-engine.cjs +199 -14
  109. package/gsd-core/bin/lib/install-model-override-resolver.cjs +45 -0
  110. package/gsd-core/bin/lib/install-profiles.cjs +36 -14
  111. package/gsd-core/bin/lib/installer-migration-report.cjs +1 -0
  112. package/gsd-core/bin/lib/installer-migrations.cjs +33 -4
  113. package/gsd-core/bin/lib/io.cjs +35 -0
  114. package/gsd-core/bin/lib/loop-resolver.cjs +64 -39
  115. package/gsd-core/bin/lib/markdown-table.cjs +123 -0
  116. package/gsd-core/bin/lib/mcp-catalog.cjs +2 -2
  117. package/gsd-core/bin/lib/milestone.cjs +41 -10
  118. package/gsd-core/bin/lib/model-resolver.cjs +101 -10
  119. package/gsd-core/bin/lib/phase-command-router.cjs +20 -7
  120. package/gsd-core/bin/lib/phase-id.cjs +412 -31
  121. package/gsd-core/bin/lib/phase-lifecycle.cjs +61 -0
  122. package/gsd-core/bin/lib/phase.cjs +941 -98
  123. package/gsd-core/bin/lib/plan-document.cjs +10 -0
  124. package/gsd-core/bin/lib/planning-inspect.cjs +34 -18
  125. package/gsd-core/bin/lib/planning-snapshot.cjs +206 -30
  126. package/gsd-core/bin/lib/planning-workspace.cjs +153 -29
  127. package/gsd-core/bin/lib/pristine-baseline.cjs +182 -0
  128. package/gsd-core/bin/lib/prohibition-enforcement.cjs +91 -4
  129. package/gsd-core/bin/lib/quick-batch-command-router.cjs +285 -0
  130. package/gsd-core/bin/lib/quick-batch-dispatch.cjs +250 -0
  131. package/gsd-core/bin/lib/quick-batch.cjs +840 -0
  132. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +61 -2
  133. package/gsd-core/bin/lib/research-store.cjs +11 -12
  134. package/gsd-core/bin/lib/review-lane-descriptor.cjs +53 -5
  135. package/gsd-core/bin/lib/review-lane-invocation.cjs +96 -1
  136. package/gsd-core/bin/lib/review-lane-runner.cjs +136 -10
  137. package/gsd-core/bin/lib/reviewer-step-dispatch.cjs +337 -0
  138. package/gsd-core/bin/lib/roadmap-parser.cjs +555 -41
  139. package/gsd-core/bin/lib/roadmap.cjs +292 -69
  140. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +260 -43
  141. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +28 -20
  142. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +294 -108
  143. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +408 -47
  144. package/gsd-core/bin/lib/security.cjs +126 -7
  145. package/gsd-core/bin/lib/shell-command-projection.cjs +4 -0
  146. package/gsd-core/bin/lib/smart-entry.cjs +7 -9
  147. package/gsd-core/bin/lib/state-document.cjs +159 -32
  148. package/gsd-core/bin/lib/state-md-schema.cjs +44 -27
  149. package/gsd-core/bin/lib/state-transition.cjs +465 -62
  150. package/gsd-core/bin/lib/state.cjs +906 -151
  151. package/gsd-core/bin/lib/surface.cjs +83 -10
  152. package/gsd-core/bin/lib/task-command-router.cjs +12 -6
  153. package/gsd-core/bin/lib/tdd-red-evidence.cjs +133 -0
  154. package/gsd-core/bin/lib/uat.cjs +1420 -516
  155. package/gsd-core/bin/lib/update-context.cjs +36 -26
  156. package/gsd-core/bin/lib/validate.cjs +230 -12
  157. package/gsd-core/bin/lib/vendor/js-yaml.cjs +11 -3
  158. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  159. package/gsd-core/bin/lib/verification.cjs +316 -23
  160. package/gsd-core/bin/lib/verify-command-grounding.cjs +1 -1
  161. package/gsd-core/bin/lib/verify-command-router.cjs +1 -0
  162. package/gsd-core/bin/lib/verify.cjs +531 -36
  163. package/gsd-core/bin/lib/workstream-inventory.cjs +21 -2
  164. package/gsd-core/bin/lib/worktree-safety.cjs +21 -7
  165. package/gsd-core/bin/shared/config-defaults.manifest.json +1 -0
  166. package/gsd-core/bin/shared/config-schema.manifest.json +13 -0
  167. package/gsd-core/bin/verify-reapply-patches.cjs +507 -81
  168. package/gsd-core/references/agent-contracts.md +3 -3
  169. package/gsd-core/references/compact-content-gate.md +66 -0
  170. package/gsd-core/references/edge-probe.md +17 -13
  171. package/gsd-core/references/execute-mvp-tdd.md +18 -16
  172. package/gsd-core/references/execute-phase-response-language.md +6 -0
  173. package/gsd-core/references/executor-examples.md +42 -0
  174. package/gsd-core/references/few-shot-examples/plan-checker.md +15 -15
  175. package/gsd-core/references/loop-hook-dispatch.md +18 -0
  176. package/gsd-core/references/model-profiles.md +12 -3
  177. package/gsd-core/references/mvp-concepts.md +2 -2
  178. package/gsd-core/references/plan-checker-examples.md +41 -0
  179. package/gsd-core/references/planner-antipatterns.md +25 -0
  180. package/gsd-core/references/planner-chunked.md +5 -1
  181. package/gsd-core/references/planner-coupling.md +42 -0
  182. package/gsd-core/references/planner-quick-batch.md +71 -0
  183. package/gsd-core/references/planner-reviews.md +47 -0
  184. package/gsd-core/references/planner-revision.md +75 -2
  185. package/gsd-core/references/planning-config.md +5 -1
  186. package/gsd-core/references/response-language-directive.md +9 -0
  187. package/gsd-core/references/revision-loop.md +118 -11
  188. package/gsd-core/references/tdd.md +17 -9
  189. package/gsd-core/references/thinking-models-planning.md +18 -2
  190. package/gsd-core/references/verification-patterns.md +17 -4
  191. package/gsd-core/references/verifier-evidence-gate.md +160 -0
  192. package/gsd-core/references/worktree-path-safety.md +112 -2
  193. package/gsd-core/templates/README.md +7 -1
  194. package/gsd-core/templates/phase-prompt.md +4 -0
  195. package/gsd-core/templates/state.md +6 -3
  196. package/gsd-core/templates/summary.compact.md +212 -0
  197. package/gsd-core/templates/user-setup.compact.md +199 -0
  198. package/gsd-core/templates/user-setup.md +0 -9
  199. package/gsd-core/templates/verification-report.md +5 -0
  200. package/gsd-core/workflows/add-backlog.md +2 -0
  201. package/gsd-core/workflows/add-phase.md +2 -0
  202. package/gsd-core/workflows/add-tests.md +1 -1
  203. package/gsd-core/workflows/add-todo.md +4 -3
  204. package/gsd-core/workflows/ai-integration-phase.md +1 -1
  205. package/gsd-core/workflows/analyze-dependencies.md +2 -0
  206. package/gsd-core/workflows/audit-fix.md +2 -0
  207. package/gsd-core/workflows/audit-milestone.md +2 -0
  208. package/gsd-core/workflows/audit-uat.md +2 -0
  209. package/gsd-core/workflows/autonomous.md +15 -10
  210. package/gsd-core/workflows/check-todos.md +5 -3
  211. package/gsd-core/workflows/cleanup.md +4 -2
  212. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +22 -13
  213. package/gsd-core/workflows/code-review-fix.md +5 -3
  214. package/gsd-core/workflows/code-review.md +211 -43
  215. package/gsd-core/workflows/complete-milestone/detail/elaboration.md +274 -0
  216. package/gsd-core/workflows/complete-milestone.md +40 -254
  217. package/gsd-core/workflows/debug.md +1 -1
  218. package/gsd-core/workflows/diagnose-issues.md +5 -1
  219. package/gsd-core/workflows/discuss-phase/modes/advisor.md +2 -0
  220. package/gsd-core/workflows/discuss-phase/modes/all.md +2 -0
  221. package/gsd-core/workflows/discuss-phase/modes/analyze.md +2 -0
  222. package/gsd-core/workflows/discuss-phase/modes/auto.md +2 -0
  223. package/gsd-core/workflows/discuss-phase/modes/batch.md +2 -0
  224. package/gsd-core/workflows/discuss-phase/modes/chain.md +2 -0
  225. package/gsd-core/workflows/discuss-phase/modes/default.md +2 -0
  226. package/gsd-core/workflows/discuss-phase/modes/power.md +2 -0
  227. package/gsd-core/workflows/discuss-phase/modes/text.md +2 -0
  228. package/gsd-core/workflows/discuss-phase/templates/context.md +2 -0
  229. package/gsd-core/workflows/discuss-phase/templates/discussion-log.md +2 -0
  230. package/gsd-core/workflows/discuss-phase-assumptions.md +1 -1
  231. package/gsd-core/workflows/discuss-phase-power.md +2 -0
  232. package/gsd-core/workflows/discuss-phase.md +1 -1
  233. package/gsd-core/workflows/do.md +43 -13
  234. package/gsd-core/workflows/docs-update/detail/elaboration.md +179 -0
  235. package/gsd-core/workflows/docs-update.md +15 -156
  236. package/gsd-core/workflows/edit-phase.md +2 -0
  237. package/gsd-core/workflows/eval-review.md +1 -1
  238. package/gsd-core/workflows/execute-phase/detail/elaboration.md +124 -0
  239. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +20 -3
  240. package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +56 -0
  241. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +24 -3
  242. package/gsd-core/workflows/execute-phase/steps/executor-progress-policy.md +43 -0
  243. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +8 -2
  244. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +2 -0
  245. package/gsd-core/workflows/execute-phase/steps/sequential-root-pin.md +35 -0
  246. package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +25 -0
  247. package/gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md +2 -0
  248. package/gsd-core/workflows/execute-phase.md +78 -159
  249. package/gsd-core/workflows/execute-plan.md +28 -15
  250. package/gsd-core/workflows/explore.md +2 -0
  251. package/gsd-core/workflows/extract-learnings.md +2 -0
  252. package/gsd-core/workflows/fast.md +6 -0
  253. package/gsd-core/workflows/forensics.md +2 -0
  254. package/gsd-core/workflows/graduation.md +1 -1
  255. package/gsd-core/workflows/health.md +1 -1
  256. package/gsd-core/workflows/help/modes/brief.md +2 -0
  257. package/gsd-core/workflows/help/modes/default.md +2 -0
  258. package/gsd-core/workflows/help/modes/full.compact.md +398 -0
  259. package/gsd-core/workflows/help/modes/full.md +12 -0
  260. package/gsd-core/workflows/help/modes/topic.md +2 -0
  261. package/gsd-core/workflows/help.md +3 -1
  262. package/gsd-core/workflows/import.md +3 -3
  263. package/gsd-core/workflows/inbox.md +1 -1
  264. package/gsd-core/workflows/ingest-docs.md +1 -1
  265. package/gsd-core/workflows/insert-phase.md +2 -0
  266. package/gsd-core/workflows/list-phase-assumptions.md +2 -0
  267. package/gsd-core/workflows/list-seeds.md +2 -0
  268. package/gsd-core/workflows/list-workspaces.md +2 -0
  269. package/gsd-core/workflows/manager.md +3 -3
  270. package/gsd-core/workflows/map-codebase.md +52 -3
  271. package/gsd-core/workflows/milestone-summary.md +2 -0
  272. package/gsd-core/workflows/mvp-phase.md +1 -1
  273. package/gsd-core/workflows/new-milestone.md +55 -13
  274. package/gsd-core/workflows/new-project/detail/elaboration.md +216 -0
  275. package/gsd-core/workflows/new-project.md +37 -205
  276. package/gsd-core/workflows/new-workspace.md +1 -1
  277. package/gsd-core/workflows/next.md +2 -0
  278. package/gsd-core/workflows/node-repair.md +2 -0
  279. package/gsd-core/workflows/note.md +2 -0
  280. package/gsd-core/workflows/onboard.md +1 -1
  281. package/gsd-core/workflows/pause-work.md +19 -4
  282. package/gsd-core/workflows/plan-phase/detail/elaboration.md +209 -0
  283. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +100 -18
  284. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +2 -0
  285. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +9 -0
  286. package/gsd-core/workflows/plan-phase.md +144 -185
  287. package/gsd-core/workflows/plan-review-convergence.md +102 -10
  288. package/gsd-core/workflows/plant-seed.md +1 -1
  289. package/gsd-core/workflows/pr-branch.md +30 -10
  290. package/gsd-core/workflows/profile-user.md +1 -1
  291. package/gsd-core/workflows/progress/steps/forensic-audit.md +1 -1
  292. package/gsd-core/workflows/progress.md +25 -3
  293. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +37 -2
  294. package/gsd-core/workflows/quick/steps/research-phase.md +3 -3
  295. package/gsd-core/workflows/quick-batch/steps/batch-init.md +55 -0
  296. package/gsd-core/workflows/quick-batch/steps/completion.md +65 -0
  297. package/gsd-core/workflows/quick-batch/steps/merge-wave.md +100 -0
  298. package/gsd-core/workflows/quick-batch/steps/plan-checker-loop.md +147 -0
  299. package/gsd-core/workflows/quick-batch/steps/planner-wave.md +158 -0
  300. package/gsd-core/workflows/quick-batch/steps/research-phase.md +95 -0
  301. package/gsd-core/workflows/quick-batch/steps/resume-mode.md +49 -0
  302. package/gsd-core/workflows/quick-batch/steps/verification-wave.md +73 -0
  303. package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +169 -0
  304. package/gsd-core/workflows/quick-batch.md +203 -0
  305. package/gsd-core/workflows/quick.md +21 -4
  306. package/gsd-core/workflows/reapply-patches.md +79 -3
  307. package/gsd-core/workflows/remove-phase.md +2 -0
  308. package/gsd-core/workflows/remove-workspace.md +1 -1
  309. package/gsd-core/workflows/resume-project.md +6 -2
  310. package/gsd-core/workflows/review.md +215 -10
  311. package/gsd-core/workflows/scan.md +2 -0
  312. package/gsd-core/workflows/section-manifest.json +12 -0
  313. package/gsd-core/workflows/secure-phase.md +1 -1
  314. package/gsd-core/workflows/session-report.md +2 -0
  315. package/gsd-core/workflows/settings-advanced.md +2 -0
  316. package/gsd-core/workflows/settings-integrations.md +9 -8
  317. package/gsd-core/workflows/settings.md +19 -6
  318. package/gsd-core/workflows/ship.md +10 -10
  319. package/gsd-core/workflows/sketch-wrap-up.md +2 -0
  320. package/gsd-core/workflows/sketch.md +1 -1
  321. package/gsd-core/workflows/smart-entry.md +1 -1
  322. package/gsd-core/workflows/spec-phase.md +24 -19
  323. package/gsd-core/workflows/spike-wrap-up.md +2 -0
  324. package/gsd-core/workflows/spike.md +1 -1
  325. package/gsd-core/workflows/stats.md +2 -0
  326. package/gsd-core/workflows/sync-skills.md +12 -4
  327. package/gsd-core/workflows/thread.md +2 -0
  328. package/gsd-core/workflows/transition.md +2 -0
  329. package/gsd-core/workflows/ui-phase.md +26 -5
  330. package/gsd-core/workflows/ui-review.md +1 -1
  331. package/gsd-core/workflows/ultraplan-phase.md +2 -0
  332. package/gsd-core/workflows/undo.md +1 -1
  333. package/gsd-core/workflows/update.md +48 -43
  334. package/gsd-core/workflows/validate-phase.md +1 -1
  335. package/gsd-core/workflows/verify-work/detail/elaboration.md +230 -0
  336. package/gsd-core/workflows/verify-work.md +68 -182
  337. package/hooks/dist/gsd-agent-isolation-guard.js +42 -16
  338. package/hooks/dist/gsd-check-update-worker.js +19 -2
  339. package/hooks/dist/gsd-context-monitor.js +371 -27
  340. package/hooks/dist/gsd-cursor-subagent-start.js +34 -14
  341. package/hooks/dist/gsd-node-runner.sh +1 -0
  342. package/hooks/dist/gsd-prompt-guard.js +30 -5
  343. package/hooks/dist/gsd-read-guard.js +2 -0
  344. package/hooks/dist/gsd-read-injection-scanner.js +5 -5
  345. package/hooks/dist/gsd-secret-read-guard.js +1105 -0
  346. package/hooks/dist/gsd-statusline.js +18 -10
  347. package/hooks/dist/gsd-validate-commit.sh +474 -7
  348. package/hooks/dist/gsd-workflow-guard.js +2 -1
  349. package/hooks/dist/gsd-worktree-path-guard.js +25 -14
  350. package/hooks/dist/gsd-write-guard.js +46 -1
  351. package/hooks/dist/lib/dispatch-identity.js +187 -0
  352. package/hooks/dist/lib/filename-classification.js +64 -0
  353. package/hooks/dist/lib/git-cmd.js +210 -1
  354. package/hooks/dist/lib/injection-patterns.js +36 -6
  355. package/hooks/dist/lib/isolation-deny-reason.js +53 -1
  356. package/hooks/dist/lib/isolation-sentinel.js +58 -19
  357. package/hooks/dist/managed-hooks-registry.cjs +1 -0
  358. package/hooks/gsd-agent-isolation-guard.js +42 -16
  359. package/hooks/gsd-check-update-worker.js +19 -2
  360. package/hooks/gsd-context-monitor.js +371 -27
  361. package/hooks/gsd-cursor-subagent-start.js +34 -14
  362. package/hooks/gsd-node-runner.sh +1 -0
  363. package/hooks/gsd-prompt-guard.js +30 -5
  364. package/hooks/gsd-read-guard.js +2 -0
  365. package/hooks/gsd-read-injection-scanner.js +5 -5
  366. package/hooks/gsd-secret-read-guard.js +1105 -0
  367. package/hooks/gsd-statusline.js +18 -10
  368. package/hooks/gsd-validate-commit.sh +474 -7
  369. package/hooks/gsd-workflow-guard.js +2 -1
  370. package/hooks/gsd-worktree-path-guard.js +25 -14
  371. package/hooks/gsd-write-guard.js +46 -1
  372. package/hooks/hooks.json +6 -0
  373. package/hooks/lib/dispatch-identity.js +187 -0
  374. package/hooks/lib/filename-classification.js +64 -0
  375. package/hooks/lib/git-cmd.js +210 -1
  376. package/hooks/lib/injection-patterns.js +36 -6
  377. package/hooks/lib/isolation-deny-reason.js +53 -1
  378. package/hooks/lib/isolation-sentinel.js +58 -19
  379. package/hooks/managed-hooks-registry.cjs +1 -0
  380. package/package.json +13 -9
  381. package/scripts/benchmark-compact-content-variants.cjs +298 -0
  382. package/scripts/benchmark-compact-content.cjs +368 -0
  383. package/scripts/build-hooks.js +11 -4
  384. package/scripts/check-contract-drift.cjs +4 -1
  385. package/scripts/check-env.cjs +36 -8
  386. package/scripts/check-glossary-refs.cjs +25 -21
  387. package/scripts/ci-next-health.cjs +271 -0
  388. package/scripts/ci-prepare-test-scope.cjs +7 -7
  389. package/scripts/ci-test-scope.cjs +133 -20
  390. package/scripts/ci-timeout-report.cjs +1 -1
  391. package/scripts/diff-touches-shipped-paths.cjs +1 -1
  392. package/scripts/docs-guard-registry.cjs +17 -2
  393. package/scripts/gen-adr-index.cjs +8 -2
  394. package/scripts/gen-inventory-manifest.cjs +12 -0
  395. package/scripts/gen-loop-host-contract.cjs +67 -15
  396. package/scripts/gen-platform-conformance-tier.cjs +557 -0
  397. package/scripts/lib/drift-scan.cjs +1 -1
  398. package/scripts/lib/macos-conformance-tier.generated.cjs +210 -0
  399. package/scripts/lib/npm-version-check-diagnosis.cjs +59 -0
  400. package/scripts/lib/platform-conformance-tier.generated.cjs +276 -0
  401. package/scripts/lib/shellcheck-fetch.cjs +247 -0
  402. package/scripts/lib/suite-detection.cjs +32 -0
  403. package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -6
  404. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
  405. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
  406. package/scripts/lint-allowed-tools-parity.cjs +221 -0
  407. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +24 -2
  408. package/scripts/lint-phase-enumeration-drift.cjs +24 -6
  409. package/scripts/lint-phase-id-drift.cjs +465 -15
  410. package/scripts/lint-portable-grep.cjs +176 -0
  411. package/scripts/lint-response-language-coverage.cjs +530 -0
  412. package/scripts/lint-source-test-name-collision.cjs +1 -1
  413. package/scripts/lint-test-file-count.allowlist.json +4 -1
  414. package/scripts/lint-vendored-deps.cjs +128 -17
  415. package/scripts/lint-workflow-shellcheck-baseline.json +1112 -0
  416. package/scripts/lint-workflow-shellcheck.cjs +614 -0
  417. package/scripts/npm-audit-baseline.cjs +376 -0
  418. package/scripts/prompt-injection-scan.sh +22 -0
  419. package/scripts/require-issue-link-policy.cjs +16 -1
  420. package/scripts/workflow-size.cjs +139 -0
  421. package/skills/gsd-cleanup/SKILL.md +1 -0
  422. package/skills/gsd-code-review/SKILL.md +2 -1
  423. package/skills/gsd-complete-milestone/SKILL.md +1 -0
  424. package/skills/gsd-config/SKILL.md +1 -0
  425. package/skills/gsd-debug/SKILL.md +1 -0
  426. package/skills/gsd-execute-phase/SKILL.md +1 -1
  427. package/skills/gsd-graphify/SKILL.md +1 -0
  428. package/skills/gsd-health/SKILL.md +1 -0
  429. package/skills/gsd-mempalace-capture/SKILL.md +1 -0
  430. package/skills/gsd-mempalace-recall/SKILL.md +1 -0
  431. package/skills/gsd-new-milestone/SKILL.md +1 -0
  432. package/skills/gsd-new-project/SKILL.md +1 -0
  433. package/skills/gsd-next/SKILL.md +1 -0
  434. package/skills/gsd-ns-workflow/SKILL.md +1 -0
  435. package/skills/gsd-pause-work/SKILL.md +1 -0
  436. package/skills/gsd-phase/SKILL.md +2 -1
  437. package/skills/gsd-pr-branch/SKILL.md +1 -0
  438. package/skills/gsd-quick-batch/SKILL.md +105 -0
  439. package/skills/gsd-resume-work/SKILL.md +1 -0
  440. package/skills/gsd-review-backlog/SKILL.md +1 -0
  441. package/skills/gsd-settings/SKILL.md +2 -1
  442. package/skills/gsd-stats/SKILL.md +1 -0
  443. package/skills/gsd-surface/SKILL.md +18 -8
  444. package/skills/gsd-thread/SKILL.md +1 -0
  445. package/skills/gsd-workspace/SKILL.md +1 -0
  446. package/skills/gsd-workstreams/SKILL.md +1 -0
  447. package/vscode/package.json +1 -1
  448. package/gsd-core/templates/claude-md.md +0 -145
  449. package/gsd-core/templates/codebase/concerns.md +0 -310
  450. package/gsd-core/templates/codebase/conventions.md +0 -307
  451. package/gsd-core/templates/codebase/integrations.md +0 -280
  452. package/gsd-core/templates/codebase/structure.md +0 -285
  453. package/gsd-core/templates/codebase/testing.md +0 -480
  454. package/gsd-core/templates/debug-subagent-prompt.md +0 -91
  455. package/gsd-core/templates/discovery.md +0 -146
@@ -14,7 +14,13 @@ const node_path_1 = __importDefault(require("node:path"));
14
14
  const node_child_process_1 = require("node:child_process");
15
15
  // eslint-disable-next-line @typescript-eslint/no-require-imports
16
16
  const io = require("./io.cjs");
17
- const { output, error, ERROR_REASON } = io;
17
+ const { output, ERROR_REASON } = io;
18
+ // Explicitly annotated so TypeScript applies never-return control-flow narrowing.
19
+ // A destructured `const { error } = io` is a const WITHOUT a type annotation, and TS
20
+ // only narrows after a never-returning call when the callee is a function declaration
21
+ // or an annotated const. Without the annotation every `error(...)` guard below would
22
+ // need a dead `throw` after it to convince the checker that the value is non-null.
23
+ const error = io.error;
18
24
  // eslint-disable-next-line @typescript-eslint/no-require-imports
19
25
  const planningWorkspaceMod = require("./planning-workspace.cjs");
20
26
  const { planningDir } = planningWorkspaceMod;
@@ -31,7 +37,7 @@ const ui_safety_gate_cjs_1 = require("./ui-safety-gate.cjs");
31
37
  const ui_frontend_evidence_cjs_1 = require("./ui-frontend-evidence.cjs");
32
38
  // eslint-disable-next-line @typescript-eslint/no-require-imports
33
39
  const verifyModule = require("./verify.cjs");
34
- const { cmdVerifySchemaDrift, cmdVerifyCodebaseDrift } = verifyModule;
40
+ const { cmdVerifySchemaDrift, cmdVerifyCodebaseDrift, cmdVerifyContextDrift } = verifyModule;
35
41
  // eslint-disable-next-line @typescript-eslint/no-require-imports
36
42
  const roadmapModule = require("./roadmap.cjs");
37
43
  const { getRoadmapPhaseWithFallback } = roadmapModule;
@@ -39,6 +45,7 @@ const { getRoadmapPhaseWithFallback } = roadmapModule;
39
45
  const gapCheckerModule = require("./gap-checker.cjs");
40
46
  const { runGapAnalysis } = gapCheckerModule;
41
47
  const prohibition_enforcement_cjs_1 = require("./prohibition-enforcement.cjs");
48
+ const tdd_red_evidence_cjs_1 = require("./tdd-red-evidence.cjs");
42
49
  // eslint-disable-next-line @typescript-eslint/no-require-imports
43
50
  const gatePredicateEval = require("./gate-predicate-evaluator.cjs");
44
51
  const { evaluatePredicate } = gatePredicateEval;
@@ -88,7 +95,12 @@ function readIfExists(filePath) {
88
95
  }
89
96
  }
90
97
  function resolvePath(inputPath, projectDir) {
91
- return node_path_1.default.isAbsolute(inputPath) ? inputPath : node_path_1.default.join(projectDir, inputPath);
98
+ const candidate = node_path_1.default.isAbsolute(inputPath) ? inputPath : node_path_1.default.join(projectDir, inputPath);
99
+ const contained = (0, security_cjs_1.tryWithinRoot)(candidate, projectDir, security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
100
+ if (contained === null) {
101
+ error(`path escapes its allowed directory: ${inputPath}`, ERROR_REASON.USAGE);
102
+ }
103
+ return contained;
92
104
  }
93
105
  function readWorkflowConfig(projectDir) {
94
106
  const configPath = node_path_1.default.join(projectDir, '.planning', 'config.json');
@@ -271,9 +283,34 @@ function loadDecisionExtraction(contextPath) {
271
283
  outcome: extraction.outcome,
272
284
  };
273
285
  }
286
+ /**
287
+ * `check decision-coverage-plan` — blocking plan-phase decision-coverage gate
288
+ * (#2492, #1365 fail-loud, #2770 empty-arg fail-closed).
289
+ *
290
+ * Invocation (the context path may be supplied EITHER way; #4130 follow-up):
291
+ * gsd_run check decision-coverage-plan <phase-dir> <context-path> (positional, the workflow caller's form)
292
+ * gsd_run check decision-coverage-plan --context <path> [<phase-dir>]
293
+ *
294
+ * `--context <path>` follows the sibling flag convention (`check predicate`,
295
+ * #2008): `--flag value` pairs parsed by the shared partitionPredicateArgs
296
+ * pass, the flag WINNING over a same-purpose positional when both appear,
297
+ * and a valueless `--context` counting as no context at all (it falls
298
+ * through to the #2770 caller-error branch, not to the "CONTEXT.md missing"
299
+ * green skip). The positional form keeps working unchanged — no sibling
300
+ * check verb deprecates positionals and the plan-phase workflow passes them.
301
+ */
274
302
  function cmdDecisionCoveragePlan(projectDir, args, raw) {
275
- const phaseDir = args[2] ? resolvePath(args[2], projectDir) : '';
276
- const contextArg = args[3];
303
+ // args[0]='check', args[1]=subcommand — partition the REST so flag tokens
304
+ // and their values never land in a positional slot.
305
+ const { flags, positionals } = partitionPredicateArgs(args.slice(2));
306
+ const phaseDir = positionals[0] ? resolvePath(positionals[0], projectDir) : '';
307
+ // A VALUELESS `--context` stays a bare token in the positionals (sibling
308
+ // parser semantics); it must not then be read as the context PATH — a
309
+ // `--`-prefixed "path" is a caller mistake, and #2770's law says a missing
310
+ // context argument fails CLOSED, never a silent "CONTEXT.md missing" green
311
+ // skip. So only a non-flag positional may serve as the context.
312
+ const positionalContext = positionals[1] && !positionals[1].startsWith('--') ? positionals[1] : '';
313
+ const contextArg = flags['context'] ?? positionalContext ?? '';
277
314
  const contextPath = contextArg ? resolvePath(contextArg, projectDir) : '';
278
315
  if (!gateEnabled(projectDir)) {
279
316
  output({ passed: true, skipped: true, reason: 'workflow.context_coverage_gate is false', total: 0, covered: 0, uncovered: [], message: 'Decision coverage gate disabled by config.' }, raw, undefined);
@@ -308,12 +345,15 @@ function cmdDecisionCoveragePlan(projectDir, args, raw) {
308
345
  uncovered: [],
309
346
  message: partialParse
310
347
  ? 'Decision coverage gate: decisions could not be fully parsed — one or more ' +
311
- '`- **D-NN ...**` bullets appear malformed (missing `:` or ` — ` separator). ' +
312
- 'Fix the bullet format so all D-NN decisions can be read before re-running the gate.'
348
+ '`- **D-NN ...**` bullets appear malformed (missing `:` or ` — ` separator, or a phase ' +
349
+ 'prefix that is not a digit run, e.g. `D4x-01`). Fix the bullet format so all decisions ' +
350
+ 'can be read before re-running the gate.'
313
351
  : 'Decision coverage gate: could not parse decisions — possible format mismatch. ' +
314
352
  'The CONTEXT.md appears to be decision-shaped (has a <decisions> block, a decisions heading, ' +
315
- 'or D- tokens) but no D-NN bullets could be extracted. Check the formatting of the decisions ' +
316
- 'block and ensure bullets follow the `- **D-NN:** text` or `- **D-NN — title** body` form.',
353
+ 'or D- tokens) but no decision bullets could be extracted. Check the formatting of the decisions ' +
354
+ 'block and ensure bullets follow the `- **D-NN:** text`, `- **D4-NN:** text` (phase-prefixed), ' +
355
+ 'or `- **D-NN — title** body` form. An ID grammar the parser does not support (e.g. `DEC-01`) ' +
356
+ 'also lands here.',
317
357
  }, raw, undefined);
318
358
  return;
319
359
  }
@@ -353,11 +393,6 @@ function recentCommitMessages(projectDir) {
353
393
  return '';
354
394
  }
355
395
  }
356
- function isInsideRoot(candidatePath, rootDir) {
357
- const root = node_path_1.default.resolve(rootDir);
358
- const target = node_path_1.default.resolve(root, candidatePath);
359
- return target === root || target.startsWith(`${root}${node_path_1.default.sep}`);
360
- }
361
396
  function readModifiedFilesContent(projectDir, summaries) {
362
397
  const out = [];
363
398
  let total = 0;
@@ -370,9 +405,17 @@ function readModifiedFilesContent(projectDir, summaries) {
370
405
  for (const file of files) {
371
406
  if (total >= 50)
372
407
  break;
373
- if (!file || !isInsideRoot(file, projectDir))
408
+ if (!file)
409
+ continue;
410
+ // Migrated off the hand-rolled prefix check (ADR-4650): resolve+contain in one
411
+ // step via the canonical realpath predicate — the eventual read below follows
412
+ // symlinks, so containment must be decided on the resolved target, not a lexical
413
+ // prefix. Read the value the predicate RETURNED; do not re-derive the path.
414
+ const candidate = node_path_1.default.isAbsolute(file) ? file : node_path_1.default.join(projectDir, file);
415
+ const contained = (0, security_cjs_1.tryWithinRoot)(candidate, projectDir, security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
416
+ if (contained === null)
374
417
  continue;
375
- const raw = readIfExists(resolvePath(file, projectDir));
418
+ const raw = readIfExists(contained);
376
419
  out.push(raw.length > 256 * 1024 ? raw.slice(0, 256 * 1024) : raw);
377
420
  total++;
378
421
  }
@@ -410,9 +453,11 @@ function cmdDecisionCoverageVerify(projectDir, args, raw) {
410
453
  not_honored: [],
411
454
  message: partialParse
412
455
  ? 'Decision coverage verify (warning): decisions could not be fully parsed — one or more ' +
413
- '`- **D-NN ...**` bullets appear malformed. Fix the bullet format in the CONTEXT.md decisions block.'
456
+ '`- **D-NN ...**` bullets appear malformed (missing `:` or ` — ` separator, or a phase ' +
457
+ 'prefix that is not a digit run). Fix the bullet format in the CONTEXT.md decisions block.'
414
458
  : 'Decision coverage verify (warning): could not parse decisions — possible format mismatch. ' +
415
- 'Check the formatting of the CONTEXT.md decisions block.',
459
+ 'Check the formatting of the CONTEXT.md decisions block (accepted forms: `- **D-NN:** text`, ' +
460
+ '`- **D4-NN:** text` (phase-prefixed), `- **D-NN — title** body`).',
416
461
  }, raw, undefined);
417
462
  return;
418
463
  }
@@ -825,6 +870,74 @@ function cmdTddReviewCheckpoint(projectDir, args, raw) {
825
870
  // the host-loop dispatch's advisory branch can surface it.
826
871
  output(result, raw, undefined);
827
872
  }
873
+ // ─── tdd-red-evidence (#3770) ──────────────────────────────────────────────────
874
+ /**
875
+ * tdd-red-evidence: validates a persisted RED-phase test-run record for a
876
+ * `type: tdd` plan (#3770). Only an INTENTIONAL failure of the target test
877
+ * (verdict RED_EVIDENCE_OK) may authorize GREEN; zero-test discovery, fixture/
878
+ * load crashes, nonzero exits without a failing test, unrelated failures, and
879
+ * unexpected greens are INVALID_RED and block GREEN.
880
+ *
881
+ * The record is the JSON the executor persists after running the RED command:
882
+ * { command, exitCode, output, targetTest, targetFile?, expected?, actual? }
883
+ * Fail-closed: a missing/unreadable/unparseable record is INVALID_RED
884
+ * (reason unreadable_record), never a pass.
885
+ *
886
+ * Args: check tdd-red-evidence <record.json>
887
+ */
888
+ function cmdTddRedEvidence(_projectDir, args, raw) {
889
+ const recordPath = typeof args[2] === 'string' ? args[2] : '';
890
+ if (!recordPath) {
891
+ error('tdd-red-evidence requires a record path: check tdd-red-evidence <record.json>', ERROR_REASON.SDK_MISSING_ARG);
892
+ return;
893
+ }
894
+ const resolved = node_path_1.default.resolve(recordPath);
895
+ const text = readIfExists(resolved);
896
+ const input = (() => {
897
+ if (!text)
898
+ return null;
899
+ try {
900
+ return (JSON.parse(text) ?? {});
901
+ }
902
+ catch {
903
+ return null;
904
+ }
905
+ })();
906
+ if (!input) {
907
+ output({
908
+ passed: false,
909
+ block: true,
910
+ verdict: 'INVALID_RED',
911
+ reason: 'unreadable_record',
912
+ record: resolved,
913
+ readError: text ? `record is not valid JSON: ${resolved}` : `record not found or unreadable: ${resolved}`,
914
+ }, raw, undefined);
915
+ return;
916
+ }
917
+ const evidenceInput = {
918
+ command: input['command'],
919
+ exitCode: input['exitCode'],
920
+ output: input['output'],
921
+ targetTest: input['targetTest'],
922
+ targetFile: input['targetFile'],
923
+ expected: input['expected'],
924
+ actual: input['actual'],
925
+ };
926
+ const result = (0, tdd_red_evidence_cjs_1.classifyRedEvidence)(evidenceInput);
927
+ const record = (0, tdd_red_evidence_cjs_1.buildRedEvidenceRecord)(evidenceInput, result);
928
+ output({
929
+ // Uniform gate contract: block = !passed. INVALID_RED blocks GREEN.
930
+ passed: result.verdict === 'RED_EVIDENCE_OK',
931
+ block: result.verdict !== 'RED_EVIDENCE_OK',
932
+ verdict: result.verdict,
933
+ reason: result.reason,
934
+ evidence: result.evidence,
935
+ record,
936
+ message: result.verdict === 'RED_EVIDENCE_OK'
937
+ ? `RED evidence verified: target test "${result.evidence.target_test}" failed as expected (exit ${result.evidence.exit_code}). GREEN authorized.`
938
+ : `INVALID_RED (${result.reason}): GREEN blocked. Fix the RED phase — only an intentional failure of target test "${result.evidence.target_test}" authorizes production edits.`,
939
+ }, raw, undefined);
940
+ }
828
941
  /**
829
942
  * Resolve a phase argument to an absolute phase directory, or '' when it
830
943
  * cannot be resolved. Shared by every `check` arm that probes a phase's
@@ -950,8 +1063,9 @@ function cmdGapAnalysisPlanPost(projectDir, args, raw) {
950
1063
  error('gap-analysis.plan-post requires a phase-dir argument: check gap-analysis.plan-post <phase-dir> [phase-req-ids]', ERROR_REASON.SDK_MISSING_ARG);
951
1064
  return;
952
1065
  }
1066
+ const resolvedPhaseDir = resolvePath(phaseDir, projectDir);
953
1067
  const phaseReqIds = args[3] ?? undefined;
954
- const result = runGapAnalysis(projectDir, phaseDir, { phaseReqIds });
1068
+ const result = runGapAnalysis(projectDir, resolvedPhaseDir, { phaseReqIds });
955
1069
  // Uniform gate contract: block = false (gap-analysis is always advisory, never blocks).
956
1070
  // `message` carries the human-readable gap analysis report so the dispatch's
957
1071
  // advisory branch can surface it. --raw emits JSON (rawValue=undefined), not
@@ -1002,21 +1116,21 @@ function buildPredicateDeps() {
1002
1116
  node_path_1.default.win32.basename(artifactSuffix) !== artifactSuffix) {
1003
1117
  return null;
1004
1118
  }
1005
- const directPath = (0, security_cjs_1.validatePath)(artifactSuffix, phaseDir);
1006
- if (directPath.safe && node_fs_1.default.existsSync(directPath.resolved) && node_fs_1.default.statSync(directPath.resolved).isFile()) {
1007
- return directPath.resolved;
1119
+ const directContained = (0, security_cjs_1.tryWithinRoot)(artifactSuffix, phaseDir);
1120
+ if (directContained !== null && node_fs_1.default.existsSync(directContained) && node_fs_1.default.statSync(directContained).isFile()) {
1121
+ return directContained;
1008
1122
  }
1009
- const planningPath = (0, security_cjs_1.validatePath)(node_path_1.default.join('.planning', artifactSuffix), phaseDir);
1010
- if (planningPath.safe && node_fs_1.default.existsSync(planningPath.resolved) && node_fs_1.default.statSync(planningPath.resolved).isFile()) {
1011
- return planningPath.resolved;
1123
+ const planningContained = (0, security_cjs_1.tryWithinRoot)(node_path_1.default.join('.planning', artifactSuffix), phaseDir);
1124
+ if (planningContained !== null && node_fs_1.default.existsSync(planningContained) && node_fs_1.default.statSync(planningContained).isFile()) {
1125
+ return planningContained;
1012
1126
  }
1013
1127
  try {
1014
1128
  const files = node_fs_1.default.readdirSync(phaseDir);
1015
1129
  for (const f of files) {
1016
1130
  if (f.endsWith('-' + artifactSuffix) || f === artifactSuffix) {
1017
- const candidate = (0, security_cjs_1.validatePath)(f, phaseDir);
1018
- if (candidate.safe && node_fs_1.default.statSync(candidate.resolved).isFile())
1019
- return candidate.resolved;
1131
+ const candidateContained = (0, security_cjs_1.tryWithinRoot)(f, phaseDir);
1132
+ if (candidateContained !== null && node_fs_1.default.statSync(candidateContained).isFile())
1133
+ return candidateContained;
1020
1134
  }
1021
1135
  }
1022
1136
  }
@@ -1032,23 +1146,42 @@ function buildPredicateDeps() {
1032
1146
  }
1033
1147
  };
1034
1148
  }
1035
- /** Parse `--flag value` pairs from an args array into a map (last write wins). */
1036
- function parsePredicateFlags(args) {
1037
- const out = {};
1149
+ /**
1150
+ * Split an args array into `--flag value` pairs and the leftover positional
1151
+ * tokens, in ONE pass, with the semantics `check predicate` established
1152
+ * (#2008): a `--flag` followed by a non-`--` token consumes it as the value
1153
+ * (last write wins); a `--flag` with no value stays a bare token and moves to
1154
+ * the positionals; everything else is positional. `parsePredicateFlags` is
1155
+ * the flags half of this same pass — there is exactly one parser, so the
1156
+ * flag-taking check verbs cannot drift apart (#4130 follow-up: `check
1157
+ * decision-coverage-plan --context <path>` shares it).
1158
+ */
1159
+ function partitionPredicateArgs(args) {
1160
+ const flags = {};
1161
+ const positionals = [];
1038
1162
  for (let i = 0; i < args.length; i++) {
1039
1163
  const a = args[i];
1040
1164
  if (typeof a !== 'string')
1041
1165
  continue;
1042
- if (!a.startsWith('--'))
1166
+ if (!a.startsWith('--')) {
1167
+ positionals.push(a);
1043
1168
  continue;
1169
+ }
1044
1170
  const key = a.slice(2);
1045
1171
  const next = args[i + 1];
1046
1172
  if (key.length > 0 && typeof next === 'string' && !next.startsWith('--')) {
1047
- out[key] = next;
1173
+ flags[key] = next;
1048
1174
  i++;
1049
1175
  }
1176
+ else {
1177
+ positionals.push(a);
1178
+ }
1050
1179
  }
1051
- return out;
1180
+ return { flags, positionals };
1181
+ }
1182
+ /** Parse `--flag value` pairs from an args array into a map (last write wins). */
1183
+ function parsePredicateFlags(args) {
1184
+ return partitionPredicateArgs(args).flags;
1052
1185
  }
1053
1186
  /**
1054
1187
  * `check predicate` — generic evaluator for capability gate `check.predicate`
@@ -1083,10 +1216,15 @@ function cmdCheckPredicate(projectDir, args, raw) {
1083
1216
  error('predicate --predicate value must be valid JSON', ERROR_REASON.USAGE);
1084
1217
  return;
1085
1218
  }
1219
+ const rawPhaseDir = flags['phase-dir'];
1220
+ let resolvedPhaseDir = rawPhaseDir;
1221
+ if (typeof rawPhaseDir === 'string' && rawPhaseDir !== '') {
1222
+ resolvedPhaseDir = resolvePath(rawPhaseDir, projectDir);
1223
+ }
1086
1224
  const ctx = {
1087
1225
  cwd: projectDir,
1088
1226
  phaseNumber: flags['phase-number'],
1089
- phaseDir: flags['phase-dir'],
1227
+ phaseDir: resolvedPhaseDir,
1090
1228
  phaseReqIds: flags['phase-req-ids'],
1091
1229
  };
1092
1230
  let result;
@@ -1180,7 +1318,12 @@ function cmdApiCoverageVerifyPre(projectDir, args, raw) {
1180
1318
  // Defense-in-depth: the resolved dir must be inside the phases root (or a
1181
1319
  // milestone archive under .planning/milestones).
1182
1320
  const milestonesRoot = node_path_1.default.join(pDir, 'milestones');
1183
- if (!isInsideRoot(resolvedDir, phasesRoot) && !isInsideRoot(resolvedDir, milestonesRoot)) {
1321
+ // Lexical containment (ADR-4650): resolvedDir is a directory path, not read
1322
+ // through here — mirrors the prior path.resolve(root, candidate)-based check
1323
+ // without introducing a filesystem/realpath dependency this defense-in-depth
1324
+ // recheck never had.
1325
+ if ((0, security_cjs_1.tryWithinRootLexical)(resolvedDir, phasesRoot) === null &&
1326
+ (0, security_cjs_1.tryWithinRootLexical)(resolvedDir, milestonesRoot) === null) {
1184
1327
  output({
1185
1328
  block: true,
1186
1329
  passed: false,
@@ -1472,6 +1615,12 @@ function routeCheckCommand({ args, cwd, raw }) {
1472
1615
  cmdTddReviewCheckpoint(cwd, args, raw);
1473
1616
  return;
1474
1617
  }
1618
+ if (subcommand === 'tdd-red-evidence') {
1619
+ // #3770: intentional-RED evidence gate — only a target-test failure may
1620
+ // authorize GREEN. Validates the persisted record; never executes anything.
1621
+ cmdTddRedEvidence(cwd, args, raw);
1622
+ return;
1623
+ }
1475
1624
  if (subcommand === 'ui-safety-gate') {
1476
1625
  cmdUiSafetyGate(cwd, args, raw);
1477
1626
  return;
@@ -1491,12 +1640,21 @@ function routeCheckCommand({ args, cwd, raw }) {
1491
1640
  cmdVerifyCodebaseDrift(cwd, raw);
1492
1641
  return;
1493
1642
  }
1643
+ if (subcommand === 'verify-context-drift') {
1644
+ // Delegates to verify.context-drift — drift capability gate at plan:pre (non-blocking).
1645
+ // Dot-to-hyphen normalization means query "verify.context-drift" routes here.
1646
+ const phaseArg = typeof args[2] === 'string' ? args[2] : '';
1647
+ cmdVerifyContextDrift(cwd, phaseArg, raw);
1648
+ return;
1649
+ }
1494
1650
  if (subcommand === 'predicate') {
1495
1651
  // Generic gate-predicate evaluator (#2008). The workflow gate-dispatch calls
1496
1652
  // this for any gate whose `check` carries a `predicate` (instead of a `query`),
1497
1653
  // passing the predicate object as --predicate '<json>'. NOTE: unlike the
1498
1654
  // `check.query` subcommands above (which take positional phase args), this
1499
- // subcommand parses --flag value pairs.
1655
+ // subcommand is flag-driven. `decision-coverage-plan` above now ALSO accepts
1656
+ // `--context <path>` (its positionals still work) — both share
1657
+ // partitionPredicateArgs, the one flag parser.
1500
1658
  cmdCheckPredicate(cwd, args, raw);
1501
1659
  return;
1502
1660
  }
@@ -1508,7 +1666,7 @@ function routeCheckCommand({ args, cwd, raw }) {
1508
1666
  (0, prohibition_enforcement_cjs_1.routeProhibitionEnforcement)(args, raw);
1509
1667
  return;
1510
1668
  }
1511
- error('Unknown check subcommand. Available: api-coverage-verify-pre, auto-mode, decision-coverage-plan, decision-coverage-verify, gap-analysis-plan-post, predicate, prohibition-enforcement, tdd-review-checkpoint, ui-plan-gate, ui-safety-gate, verify-command-paths, verify-failure-directions, verify-schema-drift, verify-codebase-drift', ERROR_REASON.SDK_UNKNOWN_COMMAND);
1669
+ error('Unknown check subcommand. Available: api-coverage-verify-pre, auto-mode, decision-coverage-plan, decision-coverage-verify, gap-analysis-plan-post, predicate, prohibition-enforcement, tdd-red-evidence, tdd-review-checkpoint, ui-plan-gate, ui-safety-gate, verify-command-paths, verify-failure-directions, verify-schema-drift, verify-codebase-drift, verify-context-drift', ERROR_REASON.SDK_UNKNOWN_COMMAND);
1512
1670
  }
1513
1671
  module.exports = {
1514
1672
  routeCheckCommand,
@@ -1520,9 +1678,11 @@ module.exports = {
1520
1678
  cmdVerifyCommandPaths,
1521
1679
  cmdVerifyFailureDirections,
1522
1680
  cmdTddReviewCheckpoint,
1681
+ cmdTddRedEvidence,
1523
1682
  cmdCheckPredicate,
1524
1683
  buildPredicateDeps,
1525
1684
  parsePredicateFlags,
1685
+ partitionPredicateArgs,
1526
1686
  // Fail-closed phase-scope reader for the api-coverage gate — exported for
1527
1687
  // in-process failure-injection tests (#2365 review).
1528
1688
  readPhaseScope,
@@ -43,6 +43,9 @@
43
43
  *
44
44
  * Zero external dependencies. Pure functions. Never throws on bad input.
45
45
  */
46
+ // eslint-disable-next-line @typescript-eslint/no-require-imports -- file-overlap-partitioner.cjs is an export= CommonJS module
47
+ const fileOverlapPartitionerMod = require("./file-overlap-partitioner.cjs");
48
+ const { partitionByFileOverlap } = fileOverlapPartitionerMod;
46
49
  // ─── Constants ────────────────────────────────────────────────────────────────
47
50
  /**
48
51
  * The Agent SDK version that introduced the Workflow tool (#1143 prior art).
@@ -226,33 +229,15 @@ function detectWorkflowBackend(input) {
226
229
  *
227
230
  * This is the same overlap rule execute-phase applies inline — the only difference
228
231
  * is the execution vehicle (Workflow `parallel()` vs one-agent-per-message).
232
+ *
233
+ * #3674: the algorithm itself now lives in the generic, dependency-free
234
+ * `file-overlap-partitioner.cts` module (`partitionByFileOverlap`) — this is a
235
+ * thin adapter mapping this module's own `Plan[]` shape onto that module's
236
+ * generic `{ id, files }[]` input and back. Behavior-preserving extraction:
237
+ * same greedy first-fit algorithm, same output, only the implementation moved.
229
238
  */
230
239
  function partitionStages(plans) {
231
- const stages = [];
232
- for (const plan of plans) {
233
- const fileSet = new Set(plan.files_modified);
234
- let placed = false;
235
- for (const stage of stages) {
236
- let overlap = false;
237
- for (const f of fileSet) {
238
- if (stage.files.has(f)) {
239
- overlap = true;
240
- break;
241
- }
242
- }
243
- if (!overlap) {
244
- stage.plans.push(plan);
245
- for (const f of fileSet)
246
- stage.files.add(f);
247
- placed = true;
248
- break;
249
- }
250
- }
251
- if (!placed) {
252
- stages.push({ plans: [plan], files: new Set(fileSet) });
253
- }
254
- }
255
- return stages.map((s) => s.plans.map((p) => p.id));
240
+ return partitionByFileOverlap(plans.map((p) => ({ id: p.id, files: p.files_modified })));
256
241
  }
257
242
  /**
258
243
  * Quote a free-text value for safe embedding as a JavaScript/Workflow double-quoted
@@ -95,6 +95,7 @@ exports.CLUSTERS = Object.freeze({
95
95
  'undo',
96
96
  'fast',
97
97
  'quick',
98
+ 'quick-batch',
98
99
  'autonomous',
99
100
  'config',
100
101
  'progress',
@@ -61,7 +61,7 @@ function normalizeRelPath(p, repoRoot) {
61
61
  let relativized = false;
62
62
  if (typeof repoRoot === 'string' && repoRoot !== '') {
63
63
  const rootNormalized = repoRoot.trim().replace(/\\/g, '/').replace(/\/+$/, '');
64
- if (rootNormalized !== '' && value.startsWith(`${rootNormalized}/`)) {
64
+ if (rootNormalized !== '' && value.startsWith(`${rootNormalized}/`)) { // allow-handrolled-containment: display-path normalization — strips a caller-declared repoRoot prefix so a path renders repo-relative, not a security root-confinement decision
65
65
  value = value.slice(rootNormalized.length + 1);
66
66
  relativized = true;
67
67
  }
@@ -86,7 +86,7 @@ function normalizeRelPath(p, repoRoot) {
86
86
  * with `rulePath + '/'`. Both arguments must already be normalized. Case-sensitive.
87
87
  */
88
88
  function ruleMatchesFile(rulePath, filePath) {
89
- return filePath === rulePath || filePath.startsWith(`${rulePath}/`);
89
+ return filePath === rulePath || filePath.startsWith(`${rulePath}/`); // allow-handrolled-containment: rule-to-file segment match for selecting which review-depth rule applies — not a filesystem root-confinement gate
90
90
  }
91
91
  /**
92
92
  * Validate + normalize a single rule path (not yet matched against files).
@@ -248,6 +248,14 @@ exports.VERIFY_COMMAND_ALIASES = [
248
248
  ],
249
249
  "subcommand": "codebase-drift",
250
250
  "mutation": false
251
+ },
252
+ {
253
+ "canonical": "verify.context-drift",
254
+ "aliases": [
255
+ "verify context-drift"
256
+ ],
257
+ "subcommand": "context-drift",
258
+ "mutation": false
251
259
  }
252
260
  ];
253
261
  exports.INIT_COMMAND_ALIASES = [
@@ -299,6 +307,14 @@ exports.INIT_COMMAND_ALIASES = [
299
307
  "subcommand": "quick",
300
308
  "mutation": false
301
309
  },
310
+ {
311
+ "canonical": "init.quick-batch",
312
+ "aliases": [
313
+ "init quick-batch"
314
+ ],
315
+ "subcommand": "quick-batch",
316
+ "mutation": false
317
+ },
302
318
  {
303
319
  "canonical": "init.ingest-docs",
304
320
  "aliases": [