@opengsd/get-shit-done-redux 1.0.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 (1466) hide show
  1. package/LICENSE +21 -0
  2. package/README.ja-JP.md +870 -0
  3. package/README.ko-KR.md +861 -0
  4. package/README.md +300 -0
  5. package/README.pt-BR.md +492 -0
  6. package/README.zh-CN.md +842 -0
  7. package/agents/gsd-advisor-researcher.md +127 -0
  8. package/agents/gsd-ai-researcher.md +133 -0
  9. package/agents/gsd-assumptions-analyzer.md +105 -0
  10. package/agents/gsd-code-fixer.md +668 -0
  11. package/agents/gsd-code-reviewer.md +387 -0
  12. package/agents/gsd-codebase-mapper.md +853 -0
  13. package/agents/gsd-debug-session-manager.md +314 -0
  14. package/agents/gsd-debugger.md +1452 -0
  15. package/agents/gsd-doc-classifier.md +168 -0
  16. package/agents/gsd-doc-synthesizer.md +204 -0
  17. package/agents/gsd-doc-verifier.md +217 -0
  18. package/agents/gsd-doc-writer.md +615 -0
  19. package/agents/gsd-domain-researcher.md +153 -0
  20. package/agents/gsd-eval-auditor.md +191 -0
  21. package/agents/gsd-eval-planner.md +154 -0
  22. package/agents/gsd-executor.md +774 -0
  23. package/agents/gsd-framework-selector.md +160 -0
  24. package/agents/gsd-integration-checker.md +470 -0
  25. package/agents/gsd-intel-updater.md +342 -0
  26. package/agents/gsd-nyquist-auditor.md +203 -0
  27. package/agents/gsd-pattern-mapper.md +335 -0
  28. package/agents/gsd-phase-researcher.md +928 -0
  29. package/agents/gsd-plan-checker.md +978 -0
  30. package/agents/gsd-planner.md +1278 -0
  31. package/agents/gsd-project-researcher.md +677 -0
  32. package/agents/gsd-research-synthesizer.md +247 -0
  33. package/agents/gsd-roadmapper.md +688 -0
  34. package/agents/gsd-security-auditor.md +155 -0
  35. package/agents/gsd-ui-auditor.md +495 -0
  36. package/agents/gsd-ui-checker.md +309 -0
  37. package/agents/gsd-ui-researcher.md +380 -0
  38. package/agents/gsd-user-profiler.md +171 -0
  39. package/agents/gsd-verifier.md +917 -0
  40. package/bin/gsd-sdk.js +37 -0
  41. package/bin/install.js +11468 -0
  42. package/bin/lib/ui-safety-gate.cjs +107 -0
  43. package/commands/gsd/add-tests.md +42 -0
  44. package/commands/gsd/ai-integration-phase.md +37 -0
  45. package/commands/gsd/audit-fix.md +34 -0
  46. package/commands/gsd/audit-milestone.md +37 -0
  47. package/commands/gsd/audit-uat.md +24 -0
  48. package/commands/gsd/autonomous.md +46 -0
  49. package/commands/gsd/capture.md +62 -0
  50. package/commands/gsd/cleanup.md +24 -0
  51. package/commands/gsd/code-review.md +59 -0
  52. package/commands/gsd/complete-milestone.md +143 -0
  53. package/commands/gsd/config.md +58 -0
  54. package/commands/gsd/debug.md +52 -0
  55. package/commands/gsd/discuss-phase.md +76 -0
  56. package/commands/gsd/docs-update.md +49 -0
  57. package/commands/gsd/eval-review.md +33 -0
  58. package/commands/gsd/execute-phase.md +64 -0
  59. package/commands/gsd/explore.md +27 -0
  60. package/commands/gsd/extract-learnings.md +23 -0
  61. package/commands/gsd/fast.md +31 -0
  62. package/commands/gsd/forensics.md +57 -0
  63. package/commands/gsd/graphify.md +199 -0
  64. package/commands/gsd/health.md +31 -0
  65. package/commands/gsd/help.md +28 -0
  66. package/commands/gsd/import.md +41 -0
  67. package/commands/gsd/inbox.md +39 -0
  68. package/commands/gsd/ingest-docs.md +42 -0
  69. package/commands/gsd/manager.md +45 -0
  70. package/commands/gsd/map-codebase.md +83 -0
  71. package/commands/gsd/milestone-summary.md +51 -0
  72. package/commands/gsd/mvp-phase.md +45 -0
  73. package/commands/gsd/new-milestone.md +45 -0
  74. package/commands/gsd/new-project.md +47 -0
  75. package/commands/gsd/ns-context.md +23 -0
  76. package/commands/gsd/ns-ideate.md +24 -0
  77. package/commands/gsd/ns-manage.md +29 -0
  78. package/commands/gsd/ns-project.md +22 -0
  79. package/commands/gsd/ns-review.md +26 -0
  80. package/commands/gsd/ns-workflow.md +28 -0
  81. package/commands/gsd/pause-work.md +43 -0
  82. package/commands/gsd/phase.md +56 -0
  83. package/commands/gsd/plan-phase.md +62 -0
  84. package/commands/gsd/plan-review-convergence.md +59 -0
  85. package/commands/gsd/pr-branch.md +26 -0
  86. package/commands/gsd/profile-user.md +46 -0
  87. package/commands/gsd/progress.md +46 -0
  88. package/commands/gsd/quick.md +174 -0
  89. package/commands/gsd/resume-work.md +30 -0
  90. package/commands/gsd/review-backlog.md +63 -0
  91. package/commands/gsd/review.md +41 -0
  92. package/commands/gsd/secure-phase.md +36 -0
  93. package/commands/gsd/settings.md +29 -0
  94. package/commands/gsd/ship.md +24 -0
  95. package/commands/gsd/sketch.md +60 -0
  96. package/commands/gsd/spec-phase.md +63 -0
  97. package/commands/gsd/spike.md +57 -0
  98. package/commands/gsd/stats.md +19 -0
  99. package/commands/gsd/surface.md +155 -0
  100. package/commands/gsd/thread.md +24 -0
  101. package/commands/gsd/ui-phase.md +35 -0
  102. package/commands/gsd/ui-review.md +33 -0
  103. package/commands/gsd/ultraplan-phase.md +34 -0
  104. package/commands/gsd/undo.md +35 -0
  105. package/commands/gsd/update.md +48 -0
  106. package/commands/gsd/validate-phase.md +36 -0
  107. package/commands/gsd/verify-work.md +39 -0
  108. package/commands/gsd/workspace.md +52 -0
  109. package/commands/gsd/workstreams.md +70 -0
  110. package/get-shit-done/bin/check-latest-version.cjs +104 -0
  111. package/get-shit-done/bin/gsd-tools.cjs +1630 -0
  112. package/get-shit-done/bin/lib/active-workstream-store.cjs +85 -0
  113. package/get-shit-done/bin/lib/adr-parser.cjs +394 -0
  114. package/get-shit-done/bin/lib/artifacts.cjs +53 -0
  115. package/get-shit-done/bin/lib/audit.cjs +755 -0
  116. package/get-shit-done/bin/lib/cjs-command-router-adapter.cjs +39 -0
  117. package/get-shit-done/bin/lib/cjs-sdk-bridge.cjs +136 -0
  118. package/get-shit-done/bin/lib/clusters.cjs +135 -0
  119. package/get-shit-done/bin/lib/code-review-flags.cjs +74 -0
  120. package/get-shit-done/bin/lib/command-aliases.generated.cjs +824 -0
  121. package/get-shit-done/bin/lib/command-routing-hub.cjs +239 -0
  122. package/get-shit-done/bin/lib/commands.cjs +1035 -0
  123. package/get-shit-done/bin/lib/config-schema.cjs +31 -0
  124. package/get-shit-done/bin/lib/config.cjs +704 -0
  125. package/get-shit-done/bin/lib/configuration.generated.cjs +253 -0
  126. package/get-shit-done/bin/lib/context-utilization.cjs +47 -0
  127. package/get-shit-done/bin/lib/core.cjs +1922 -0
  128. package/get-shit-done/bin/lib/decisions.cjs +19 -0
  129. package/get-shit-done/bin/lib/decisions.generated.cjs +121 -0
  130. package/get-shit-done/bin/lib/docs.cjs +270 -0
  131. package/get-shit-done/bin/lib/drift.cjs +388 -0
  132. package/get-shit-done/bin/lib/fallow-runner.cjs +109 -0
  133. package/get-shit-done/bin/lib/frontmatter.cjs +389 -0
  134. package/get-shit-done/bin/lib/gap-checker.cjs +205 -0
  135. package/get-shit-done/bin/lib/graphify.cjs +592 -0
  136. package/get-shit-done/bin/lib/gsd2-import.cjs +514 -0
  137. package/get-shit-done/bin/lib/init-command-router.cjs +174 -0
  138. package/get-shit-done/bin/lib/init.cjs +2096 -0
  139. package/get-shit-done/bin/lib/install-profiles.cjs +603 -0
  140. package/get-shit-done/bin/lib/installer-migration-authoring.cjs +117 -0
  141. package/get-shit-done/bin/lib/installer-migration-report.cjs +354 -0
  142. package/get-shit-done/bin/lib/installer-migrations/000-first-time-baseline.cjs +220 -0
  143. package/get-shit-done/bin/lib/installer-migrations/001-legacy-orphan-files.cjs +41 -0
  144. package/get-shit-done/bin/lib/installer-migrations/002-codex-legacy-hooks-json.cjs +80 -0
  145. package/get-shit-done/bin/lib/installer-migrations.cjs +776 -0
  146. package/get-shit-done/bin/lib/intel.cjs +643 -0
  147. package/get-shit-done/bin/lib/learnings.cjs +379 -0
  148. package/get-shit-done/bin/lib/milestone.cjs +314 -0
  149. package/get-shit-done/bin/lib/model-catalog.cjs +136 -0
  150. package/get-shit-done/bin/lib/model-profiles.cjs +25 -0
  151. package/get-shit-done/bin/lib/phase-command-router.cjs +226 -0
  152. package/get-shit-done/bin/lib/phase.cjs +1490 -0
  153. package/get-shit-done/bin/lib/phases-command-router.cjs +97 -0
  154. package/get-shit-done/bin/lib/plan-scan.cjs +26 -0
  155. package/get-shit-done/bin/lib/plan-scan.generated.cjs +97 -0
  156. package/get-shit-done/bin/lib/planning-workspace.cjs +415 -0
  157. package/get-shit-done/bin/lib/profile-output.cjs +1130 -0
  158. package/get-shit-done/bin/lib/profile-pipeline.cjs +539 -0
  159. package/get-shit-done/bin/lib/project-root.generated.cjs +117 -0
  160. package/get-shit-done/bin/lib/prompt-budget.cjs +399 -0
  161. package/get-shit-done/bin/lib/review-reviewer-selection.cjs +125 -0
  162. package/get-shit-done/bin/lib/roadmap-command-router.cjs +99 -0
  163. package/get-shit-done/bin/lib/roadmap.cjs +642 -0
  164. package/get-shit-done/bin/lib/runtime-artifact-layout.cjs +301 -0
  165. package/get-shit-done/bin/lib/runtime-homes.cjs +185 -0
  166. package/get-shit-done/bin/lib/runtime-slash.cjs +109 -0
  167. package/get-shit-done/bin/lib/schema-detect.cjs +21 -0
  168. package/get-shit-done/bin/lib/schema-detect.generated.cjs +170 -0
  169. package/get-shit-done/bin/lib/secrets.cjs +20 -0
  170. package/get-shit-done/bin/lib/secrets.generated.cjs +37 -0
  171. package/get-shit-done/bin/lib/security.cjs +504 -0
  172. package/get-shit-done/bin/lib/shell-command-projection.cjs +552 -0
  173. package/get-shit-done/bin/lib/state-command-router.cjs +346 -0
  174. package/get-shit-done/bin/lib/state-document.cjs +12 -0
  175. package/get-shit-done/bin/lib/state-document.generated.cjs +127 -0
  176. package/get-shit-done/bin/lib/state.cjs +1940 -0
  177. package/get-shit-done/bin/lib/surface.cjs +430 -0
  178. package/get-shit-done/bin/lib/template.cjs +228 -0
  179. package/get-shit-done/bin/lib/uat.cjs +289 -0
  180. package/get-shit-done/bin/lib/validate-command-router.cjs +129 -0
  181. package/get-shit-done/bin/lib/verify-command-router.cjs +122 -0
  182. package/get-shit-done/bin/lib/verify.cjs +1458 -0
  183. package/get-shit-done/bin/lib/workstream-inventory-builder.generated.cjs +79 -0
  184. package/get-shit-done/bin/lib/workstream-inventory.cjs +132 -0
  185. package/get-shit-done/bin/lib/workstream-name-policy.cjs +19 -0
  186. package/get-shit-done/bin/lib/workstream-name-policy.generated.cjs +61 -0
  187. package/get-shit-done/bin/lib/workstream.cjs +374 -0
  188. package/get-shit-done/bin/lib/worktree-safety.cjs +985 -0
  189. package/get-shit-done/bin/verify-reapply-patches.cjs +336 -0
  190. package/get-shit-done/contexts/dev.md +21 -0
  191. package/get-shit-done/contexts/research.md +22 -0
  192. package/get-shit-done/contexts/review.md +23 -0
  193. package/get-shit-done/references/agent-contracts.md +79 -0
  194. package/get-shit-done/references/ai-evals.md +156 -0
  195. package/get-shit-done/references/ai-frameworks.md +186 -0
  196. package/get-shit-done/references/artifact-types.md +131 -0
  197. package/get-shit-done/references/autonomous-smart-discuss.md +277 -0
  198. package/get-shit-done/references/checkpoints.md +814 -0
  199. package/get-shit-done/references/common-bug-patterns.md +114 -0
  200. package/get-shit-done/references/context-budget.md +85 -0
  201. package/get-shit-done/references/continuation-format.md +253 -0
  202. package/get-shit-done/references/debugger-philosophy.md +76 -0
  203. package/get-shit-done/references/decimal-phase-calculation.md +64 -0
  204. package/get-shit-done/references/doc-conflict-engine.md +91 -0
  205. package/get-shit-done/references/domain-probes.md +125 -0
  206. package/get-shit-done/references/execute-mvp-tdd.md +81 -0
  207. package/get-shit-done/references/executor-examples.md +110 -0
  208. package/get-shit-done/references/few-shot-examples/plan-checker.md +73 -0
  209. package/get-shit-done/references/few-shot-examples/verifier.md +109 -0
  210. package/get-shit-done/references/gate-prompts.md +100 -0
  211. package/get-shit-done/references/gates.md +70 -0
  212. package/get-shit-done/references/git-integration.md +298 -0
  213. package/get-shit-done/references/git-planning-commit.md +40 -0
  214. package/get-shit-done/references/ios-scaffold.md +123 -0
  215. package/get-shit-done/references/mandatory-initial-read.md +2 -0
  216. package/get-shit-done/references/model-profile-resolution.md +38 -0
  217. package/get-shit-done/references/model-profiles.md +245 -0
  218. package/get-shit-done/references/mvp-concepts.md +49 -0
  219. package/get-shit-done/references/phase-argument-parsing.md +61 -0
  220. package/get-shit-done/references/planner-antipatterns.md +89 -0
  221. package/get-shit-done/references/planner-chunked.md +49 -0
  222. package/get-shit-done/references/planner-gap-closure.md +62 -0
  223. package/get-shit-done/references/planner-graphify-auto-update.md +67 -0
  224. package/get-shit-done/references/planner-human-verify-mode.md +57 -0
  225. package/get-shit-done/references/planner-mvp-mode.md +53 -0
  226. package/get-shit-done/references/planner-reviews.md +39 -0
  227. package/get-shit-done/references/planner-revision.md +87 -0
  228. package/get-shit-done/references/planner-source-audit.md +73 -0
  229. package/get-shit-done/references/planning-config.md +471 -0
  230. package/get-shit-done/references/project-skills-discovery.md +19 -0
  231. package/get-shit-done/references/questioning.md +162 -0
  232. package/get-shit-done/references/revision-loop.md +97 -0
  233. package/get-shit-done/references/scout-codebase.md +51 -0
  234. package/get-shit-done/references/skeleton-template.md +48 -0
  235. package/get-shit-done/references/sketch-interactivity.md +41 -0
  236. package/get-shit-done/references/sketch-theme-system.md +94 -0
  237. package/get-shit-done/references/sketch-tooling.md +45 -0
  238. package/get-shit-done/references/sketch-variant-patterns.md +81 -0
  239. package/get-shit-done/references/spidr-splitting.md +69 -0
  240. package/get-shit-done/references/tdd.md +330 -0
  241. package/get-shit-done/references/thinking-models-debug.md +44 -0
  242. package/get-shit-done/references/thinking-models-execution.md +50 -0
  243. package/get-shit-done/references/thinking-models-planning.md +62 -0
  244. package/get-shit-done/references/thinking-models-research.md +50 -0
  245. package/get-shit-done/references/thinking-models-verification.md +55 -0
  246. package/get-shit-done/references/thinking-partner.md +96 -0
  247. package/get-shit-done/references/ui-brand.md +160 -0
  248. package/get-shit-done/references/universal-anti-patterns.md +63 -0
  249. package/get-shit-done/references/user-profiling.md +681 -0
  250. package/get-shit-done/references/user-story-template.md +58 -0
  251. package/get-shit-done/references/verification-overrides.md +227 -0
  252. package/get-shit-done/references/verification-patterns.md +612 -0
  253. package/get-shit-done/references/verify-mvp-mode.md +85 -0
  254. package/get-shit-done/references/workstream-flag.md +111 -0
  255. package/get-shit-done/references/worktree-path-safety.md +89 -0
  256. package/get-shit-done/templates/AI-SPEC.md +246 -0
  257. package/get-shit-done/templates/DEBUG.md +169 -0
  258. package/get-shit-done/templates/README.md +77 -0
  259. package/get-shit-done/templates/SECURITY.md +61 -0
  260. package/get-shit-done/templates/UAT.md +265 -0
  261. package/get-shit-done/templates/UI-SPEC.md +100 -0
  262. package/get-shit-done/templates/VALIDATION.md +76 -0
  263. package/get-shit-done/templates/claude-md.md +145 -0
  264. package/get-shit-done/templates/codebase/architecture.md +255 -0
  265. package/get-shit-done/templates/codebase/concerns.md +310 -0
  266. package/get-shit-done/templates/codebase/conventions.md +307 -0
  267. package/get-shit-done/templates/codebase/integrations.md +280 -0
  268. package/get-shit-done/templates/codebase/stack.md +186 -0
  269. package/get-shit-done/templates/codebase/structure.md +285 -0
  270. package/get-shit-done/templates/codebase/testing.md +480 -0
  271. package/get-shit-done/templates/config.json +62 -0
  272. package/get-shit-done/templates/context.md +352 -0
  273. package/get-shit-done/templates/continue-here.md +78 -0
  274. package/get-shit-done/templates/copilot-instructions.md +7 -0
  275. package/get-shit-done/templates/debug-subagent-prompt.md +91 -0
  276. package/get-shit-done/templates/dev-preferences.md +21 -0
  277. package/get-shit-done/templates/discovery.md +146 -0
  278. package/get-shit-done/templates/discussion-log.md +63 -0
  279. package/get-shit-done/templates/milestone-archive.md +123 -0
  280. package/get-shit-done/templates/milestone.md +115 -0
  281. package/get-shit-done/templates/phase-prompt.md +610 -0
  282. package/get-shit-done/templates/planner-subagent-prompt.md +117 -0
  283. package/get-shit-done/templates/project.md +186 -0
  284. package/get-shit-done/templates/requirements.md +231 -0
  285. package/get-shit-done/templates/research-project/ARCHITECTURE.md +204 -0
  286. package/get-shit-done/templates/research-project/FEATURES.md +147 -0
  287. package/get-shit-done/templates/research-project/PITFALLS.md +200 -0
  288. package/get-shit-done/templates/research-project/STACK.md +120 -0
  289. package/get-shit-done/templates/research-project/SUMMARY.md +170 -0
  290. package/get-shit-done/templates/research.md +592 -0
  291. package/get-shit-done/templates/retrospective.md +54 -0
  292. package/get-shit-done/templates/roadmap.md +202 -0
  293. package/get-shit-done/templates/spec.md +307 -0
  294. package/get-shit-done/templates/state.md +184 -0
  295. package/get-shit-done/templates/summary-complex.md +59 -0
  296. package/get-shit-done/templates/summary-minimal.md +41 -0
  297. package/get-shit-done/templates/summary-standard.md +48 -0
  298. package/get-shit-done/templates/summary.md +248 -0
  299. package/get-shit-done/templates/user-profile.md +146 -0
  300. package/get-shit-done/templates/user-setup.md +311 -0
  301. package/get-shit-done/templates/verification-report.md +322 -0
  302. package/get-shit-done/workflows/add-backlog.md +101 -0
  303. package/get-shit-done/workflows/add-phase.md +123 -0
  304. package/get-shit-done/workflows/add-tests.md +365 -0
  305. package/get-shit-done/workflows/add-todo.md +171 -0
  306. package/get-shit-done/workflows/ai-integration-phase.md +305 -0
  307. package/get-shit-done/workflows/analyze-dependencies.md +96 -0
  308. package/get-shit-done/workflows/audit-fix.md +188 -0
  309. package/get-shit-done/workflows/audit-milestone.md +368 -0
  310. package/get-shit-done/workflows/audit-uat.md +120 -0
  311. package/get-shit-done/workflows/autonomous.md +805 -0
  312. package/get-shit-done/workflows/check-todos.md +190 -0
  313. package/get-shit-done/workflows/cleanup.md +165 -0
  314. package/get-shit-done/workflows/code-review-fix.md +512 -0
  315. package/get-shit-done/workflows/code-review.md +666 -0
  316. package/get-shit-done/workflows/complete-milestone.md +865 -0
  317. package/get-shit-done/workflows/debug.md +242 -0
  318. package/get-shit-done/workflows/diagnose-issues.md +251 -0
  319. package/get-shit-done/workflows/discovery-phase.md +291 -0
  320. package/get-shit-done/workflows/discuss-phase/modes/advisor.md +175 -0
  321. package/get-shit-done/workflows/discuss-phase/modes/all.md +28 -0
  322. package/get-shit-done/workflows/discuss-phase/modes/analyze.md +44 -0
  323. package/get-shit-done/workflows/discuss-phase/modes/auto.md +56 -0
  324. package/get-shit-done/workflows/discuss-phase/modes/batch.md +52 -0
  325. package/get-shit-done/workflows/discuss-phase/modes/chain.md +97 -0
  326. package/get-shit-done/workflows/discuss-phase/modes/default.md +141 -0
  327. package/get-shit-done/workflows/discuss-phase/modes/power.md +44 -0
  328. package/get-shit-done/workflows/discuss-phase/modes/text.md +55 -0
  329. package/get-shit-done/workflows/discuss-phase/templates/checkpoint.json +18 -0
  330. package/get-shit-done/workflows/discuss-phase/templates/context.md +136 -0
  331. package/get-shit-done/workflows/discuss-phase/templates/discussion-log.md +50 -0
  332. package/get-shit-done/workflows/discuss-phase-assumptions.md +685 -0
  333. package/get-shit-done/workflows/discuss-phase-power.md +291 -0
  334. package/get-shit-done/workflows/discuss-phase.md +499 -0
  335. package/get-shit-done/workflows/do.md +122 -0
  336. package/get-shit-done/workflows/docs-update.md +1172 -0
  337. package/get-shit-done/workflows/edit-phase.md +305 -0
  338. package/get-shit-done/workflows/eval-review.md +166 -0
  339. package/get-shit-done/workflows/execute-phase/steps/codebase-drift-gate.md +81 -0
  340. package/get-shit-done/workflows/execute-phase/steps/per-plan-worktree-gate.md +94 -0
  341. package/get-shit-done/workflows/execute-phase/steps/post-merge-gate.md +116 -0
  342. package/get-shit-done/workflows/execute-phase.md +1717 -0
  343. package/get-shit-done/workflows/execute-plan.md +536 -0
  344. package/get-shit-done/workflows/explore.md +154 -0
  345. package/get-shit-done/workflows/extract-learnings.md +253 -0
  346. package/get-shit-done/workflows/fast.md +124 -0
  347. package/get-shit-done/workflows/forensics.md +289 -0
  348. package/get-shit-done/workflows/graduation.md +206 -0
  349. package/get-shit-done/workflows/health.md +234 -0
  350. package/get-shit-done/workflows/help/modes/brief.md +22 -0
  351. package/get-shit-done/workflows/help/modes/default.md +50 -0
  352. package/get-shit-done/workflows/help/modes/full.md +784 -0
  353. package/get-shit-done/workflows/help/modes/topic.md +74 -0
  354. package/get-shit-done/workflows/help.md +24 -0
  355. package/get-shit-done/workflows/import.md +264 -0
  356. package/get-shit-done/workflows/inbox.md +387 -0
  357. package/get-shit-done/workflows/ingest-docs.md +339 -0
  358. package/get-shit-done/workflows/insert-phase.md +162 -0
  359. package/get-shit-done/workflows/list-phase-assumptions.md +178 -0
  360. package/get-shit-done/workflows/list-workspaces.md +67 -0
  361. package/get-shit-done/workflows/manager.md +403 -0
  362. package/get-shit-done/workflows/map-codebase.md +454 -0
  363. package/get-shit-done/workflows/milestone-summary.md +234 -0
  364. package/get-shit-done/workflows/mvp-phase.md +232 -0
  365. package/get-shit-done/workflows/new-milestone.md +645 -0
  366. package/get-shit-done/workflows/new-project.md +1487 -0
  367. package/get-shit-done/workflows/new-workspace.md +250 -0
  368. package/get-shit-done/workflows/next.md +231 -0
  369. package/get-shit-done/workflows/node-repair.md +92 -0
  370. package/get-shit-done/workflows/note.md +158 -0
  371. package/get-shit-done/workflows/pause-work.md +254 -0
  372. package/get-shit-done/workflows/plan-milestone-gaps.md +291 -0
  373. package/get-shit-done/workflows/plan-phase.md +1800 -0
  374. package/get-shit-done/workflows/plan-review-convergence.md +340 -0
  375. package/get-shit-done/workflows/plant-seed.md +240 -0
  376. package/get-shit-done/workflows/pr-branch.md +157 -0
  377. package/get-shit-done/workflows/profile-user.md +463 -0
  378. package/get-shit-done/workflows/progress.md +660 -0
  379. package/get-shit-done/workflows/quick.md +1049 -0
  380. package/get-shit-done/workflows/reapply-patches.md +426 -0
  381. package/get-shit-done/workflows/remove-phase.md +166 -0
  382. package/get-shit-done/workflows/remove-workspace.md +118 -0
  383. package/get-shit-done/workflows/resume-project.md +342 -0
  384. package/get-shit-done/workflows/review.md +633 -0
  385. package/get-shit-done/workflows/scan.md +115 -0
  386. package/get-shit-done/workflows/secure-phase.md +190 -0
  387. package/get-shit-done/workflows/session-report.md +146 -0
  388. package/get-shit-done/workflows/settings-advanced.md +590 -0
  389. package/get-shit-done/workflows/settings-integrations.md +292 -0
  390. package/get-shit-done/workflows/settings.md +545 -0
  391. package/get-shit-done/workflows/ship.md +366 -0
  392. package/get-shit-done/workflows/sketch-wrap-up.md +296 -0
  393. package/get-shit-done/workflows/sketch.md +371 -0
  394. package/get-shit-done/workflows/spec-phase.md +262 -0
  395. package/get-shit-done/workflows/spike-wrap-up.md +317 -0
  396. package/get-shit-done/workflows/spike.md +463 -0
  397. package/get-shit-done/workflows/stats.md +90 -0
  398. package/get-shit-done/workflows/sync-skills.md +182 -0
  399. package/get-shit-done/workflows/thread.md +232 -0
  400. package/get-shit-done/workflows/transition.md +704 -0
  401. package/get-shit-done/workflows/ui-phase.md +338 -0
  402. package/get-shit-done/workflows/ui-review.md +203 -0
  403. package/get-shit-done/workflows/ultraplan-phase.md +209 -0
  404. package/get-shit-done/workflows/undo.md +314 -0
  405. package/get-shit-done/workflows/update.md +664 -0
  406. package/get-shit-done/workflows/validate-phase.md +189 -0
  407. package/get-shit-done/workflows/verify-phase.md +554 -0
  408. package/get-shit-done/workflows/verify-work.md +791 -0
  409. package/hooks/dist/gsd-check-update-worker.js +117 -0
  410. package/hooks/dist/gsd-check-update.js +64 -0
  411. package/hooks/dist/gsd-context-monitor.js +192 -0
  412. package/hooks/dist/gsd-graphify-update.sh +158 -0
  413. package/hooks/dist/gsd-phase-boundary.sh +47 -0
  414. package/hooks/dist/gsd-prompt-guard.js +97 -0
  415. package/hooks/dist/gsd-read-guard.js +101 -0
  416. package/hooks/dist/gsd-read-injection-scanner.js +152 -0
  417. package/hooks/dist/gsd-session-state.sh +59 -0
  418. package/hooks/dist/gsd-statusline.js +537 -0
  419. package/hooks/dist/gsd-update-banner.js +134 -0
  420. package/hooks/dist/gsd-validate-commit.sh +57 -0
  421. package/hooks/dist/gsd-workflow-guard.js +94 -0
  422. package/hooks/dist/lib/git-cmd.js +150 -0
  423. package/hooks/dist/lib/gsd-graphify-rebuild.sh +65 -0
  424. package/hooks/gsd-check-update-worker.js +117 -0
  425. package/hooks/gsd-check-update.js +64 -0
  426. package/hooks/gsd-context-monitor.js +192 -0
  427. package/hooks/gsd-graphify-update.sh +158 -0
  428. package/hooks/gsd-phase-boundary.sh +47 -0
  429. package/hooks/gsd-prompt-guard.js +97 -0
  430. package/hooks/gsd-read-guard.js +101 -0
  431. package/hooks/gsd-read-injection-scanner.js +152 -0
  432. package/hooks/gsd-session-state.sh +59 -0
  433. package/hooks/gsd-statusline.js +537 -0
  434. package/hooks/gsd-update-banner.js +134 -0
  435. package/hooks/gsd-validate-commit.sh +57 -0
  436. package/hooks/gsd-workflow-guard.js +94 -0
  437. package/hooks/lib/git-cmd.js +150 -0
  438. package/hooks/lib/gsd-graphify-rebuild.sh +65 -0
  439. package/package.json +98 -0
  440. package/scripts/audit-workflow-script-paths.cjs +73 -0
  441. package/scripts/base64-scan.sh +262 -0
  442. package/scripts/build-hooks.js +227 -0
  443. package/scripts/changeset/cli.cjs +408 -0
  444. package/scripts/changeset/github-release-notes.cjs +198 -0
  445. package/scripts/changeset/lint.cjs +110 -0
  446. package/scripts/changeset/new.cjs +137 -0
  447. package/scripts/changeset/parse.cjs +114 -0
  448. package/scripts/changeset/render.cjs +34 -0
  449. package/scripts/changeset/serialize.cjs +130 -0
  450. package/scripts/command-contract-helpers.cjs +64 -0
  451. package/scripts/diff-touches-shipped-paths.cjs +147 -0
  452. package/scripts/fix-slash-commands.cjs +147 -0
  453. package/scripts/gen-inventory-manifest.cjs +109 -0
  454. package/scripts/lint-command-contract.cjs +108 -0
  455. package/scripts/lint-descriptions.cjs +83 -0
  456. package/scripts/lint-docs-required.cjs +222 -0
  457. package/scripts/lint-no-source-grep-extras.cjs +81 -0
  458. package/scripts/lint-no-source-grep.cjs +174 -0
  459. package/scripts/lint-pr-check-project-dir.cjs +98 -0
  460. package/scripts/lint-shared-module-handsync.cjs +331 -0
  461. package/scripts/lint-shell-command-projection-drift.cjs +57 -0
  462. package/scripts/lint-skill-deps.cjs +180 -0
  463. package/scripts/lint-test-file-count.allowlist.json +35 -0
  464. package/scripts/lint-test-file-count.cjs +190 -0
  465. package/scripts/pr-template-policy.cjs +268 -0
  466. package/scripts/prompt-injection-scan.sh +203 -0
  467. package/scripts/release-tarball-smoke.cjs +677 -0
  468. package/scripts/run-tests.cjs +178 -0
  469. package/scripts/secret-scan.sh +229 -0
  470. package/scripts/shared-module-handsync-allowlist.json +145 -0
  471. package/scripts/strip-prose-atrefs.cjs +106 -0
  472. package/scripts/sync-rulesets.sh +34 -0
  473. package/scripts/verify-tarball-sdk-dist.sh +69 -0
  474. package/sdk/dist/cli-transport.d.ts +19 -0
  475. package/sdk/dist/cli-transport.d.ts.map +1 -0
  476. package/sdk/dist/cli-transport.js +104 -0
  477. package/sdk/dist/cli-transport.js.map +1 -0
  478. package/sdk/dist/cli.d.ts +46 -0
  479. package/sdk/dist/cli.d.ts.map +1 -0
  480. package/sdk/dist/cli.js +511 -0
  481. package/sdk/dist/cli.js.map +1 -0
  482. package/sdk/dist/config.d.ts +108 -0
  483. package/sdk/dist/config.d.ts.map +1 -0
  484. package/sdk/dist/config.js +116 -0
  485. package/sdk/dist/config.js.map +1 -0
  486. package/sdk/dist/configuration/index.d.ts +85 -0
  487. package/sdk/dist/configuration/index.d.ts.map +1 -0
  488. package/sdk/dist/configuration/index.js +257 -0
  489. package/sdk/dist/configuration/index.js.map +1 -0
  490. package/sdk/dist/context-engine.d.ts +49 -0
  491. package/sdk/dist/context-engine.d.ts.map +1 -0
  492. package/sdk/dist/context-engine.js +142 -0
  493. package/sdk/dist/context-engine.js.map +1 -0
  494. package/sdk/dist/context-truncation.d.ts +33 -0
  495. package/sdk/dist/context-truncation.d.ts.map +1 -0
  496. package/sdk/dist/context-truncation.js +197 -0
  497. package/sdk/dist/context-truncation.js.map +1 -0
  498. package/sdk/dist/errors.d.ts +46 -0
  499. package/sdk/dist/errors.d.ts.map +1 -0
  500. package/sdk/dist/errors.js +64 -0
  501. package/sdk/dist/errors.js.map +1 -0
  502. package/sdk/dist/event-stream.d.ts +53 -0
  503. package/sdk/dist/event-stream.d.ts.map +1 -0
  504. package/sdk/dist/event-stream.js +321 -0
  505. package/sdk/dist/event-stream.js.map +1 -0
  506. package/sdk/dist/golden/capture.d.ts +15 -0
  507. package/sdk/dist/golden/capture.d.ts.map +1 -0
  508. package/sdk/dist/golden/capture.js +67 -0
  509. package/sdk/dist/golden/capture.js.map +1 -0
  510. package/sdk/dist/golden/golden-integration-covered.d.ts +6 -0
  511. package/sdk/dist/golden/golden-integration-covered.d.ts.map +1 -0
  512. package/sdk/dist/golden/golden-integration-covered.js +30 -0
  513. package/sdk/dist/golden/golden-integration-covered.js.map +1 -0
  514. package/sdk/dist/golden/golden-mutation-covered.d.ts +7 -0
  515. package/sdk/dist/golden/golden-mutation-covered.d.ts.map +1 -0
  516. package/sdk/dist/golden/golden-mutation-covered.js +17 -0
  517. package/sdk/dist/golden/golden-mutation-covered.js.map +1 -0
  518. package/sdk/dist/golden/golden-policy.d.ts +10 -0
  519. package/sdk/dist/golden/golden-policy.d.ts.map +1 -0
  520. package/sdk/dist/golden/golden-policy.js +98 -0
  521. package/sdk/dist/golden/golden-policy.js.map +1 -0
  522. package/sdk/dist/golden/init-golden-normalize.d.ts +8 -0
  523. package/sdk/dist/golden/init-golden-normalize.d.ts.map +1 -0
  524. package/sdk/dist/golden/init-golden-normalize.js +14 -0
  525. package/sdk/dist/golden/init-golden-normalize.js.map +1 -0
  526. package/sdk/dist/golden/read-only-golden-rows.d.ts +20 -0
  527. package/sdk/dist/golden/read-only-golden-rows.d.ts.map +1 -0
  528. package/sdk/dist/golden/read-only-golden-rows.js +67 -0
  529. package/sdk/dist/golden/read-only-golden-rows.js.map +1 -0
  530. package/sdk/dist/golden/registry-canonical-commands.d.ts +6 -0
  531. package/sdk/dist/golden/registry-canonical-commands.d.ts.map +1 -0
  532. package/sdk/dist/golden/registry-canonical-commands.js +30 -0
  533. package/sdk/dist/golden/registry-canonical-commands.js.map +1 -0
  534. package/sdk/dist/gsd-tools-error.d.ts +23 -0
  535. package/sdk/dist/gsd-tools-error.d.ts.map +1 -0
  536. package/sdk/dist/gsd-tools-error.js +29 -0
  537. package/sdk/dist/gsd-tools-error.js.map +1 -0
  538. package/sdk/dist/gsd-tools.d.ts +97 -0
  539. package/sdk/dist/gsd-tools.d.ts.map +1 -0
  540. package/sdk/dist/gsd-tools.js +168 -0
  541. package/sdk/dist/gsd-tools.js.map +1 -0
  542. package/sdk/dist/gsd-transport-policy.d.ts +10 -0
  543. package/sdk/dist/gsd-transport-policy.d.ts.map +1 -0
  544. package/sdk/dist/gsd-transport-policy.js +32 -0
  545. package/sdk/dist/gsd-transport-policy.js.map +1 -0
  546. package/sdk/dist/gsd-transport.d.ts +39 -0
  547. package/sdk/dist/gsd-transport.d.ts.map +1 -0
  548. package/sdk/dist/gsd-transport.js +78 -0
  549. package/sdk/dist/gsd-transport.js.map +1 -0
  550. package/sdk/dist/index.d.ts +127 -0
  551. package/sdk/dist/index.d.ts.map +1 -0
  552. package/sdk/dist/index.js +300 -0
  553. package/sdk/dist/index.js.map +1 -0
  554. package/sdk/dist/init-runner.d.ts +90 -0
  555. package/sdk/dist/init-runner.d.ts.map +1 -0
  556. package/sdk/dist/init-runner.js +613 -0
  557. package/sdk/dist/init-runner.js.map +1 -0
  558. package/sdk/dist/logger.d.ts +50 -0
  559. package/sdk/dist/logger.d.ts.map +1 -0
  560. package/sdk/dist/logger.js +70 -0
  561. package/sdk/dist/logger.js.map +1 -0
  562. package/sdk/dist/model-catalog.d.ts +31 -0
  563. package/sdk/dist/model-catalog.d.ts.map +1 -0
  564. package/sdk/dist/model-catalog.js +31 -0
  565. package/sdk/dist/model-catalog.js.map +1 -0
  566. package/sdk/dist/phase-prompt.d.ts +72 -0
  567. package/sdk/dist/phase-prompt.d.ts.map +1 -0
  568. package/sdk/dist/phase-prompt.js +213 -0
  569. package/sdk/dist/phase-prompt.js.map +1 -0
  570. package/sdk/dist/phase-runner.d.ts +145 -0
  571. package/sdk/dist/phase-runner.d.ts.map +1 -0
  572. package/sdk/dist/phase-runner.js +1206 -0
  573. package/sdk/dist/phase-runner.js.map +1 -0
  574. package/sdk/dist/plan-parser.d.ts +55 -0
  575. package/sdk/dist/plan-parser.d.ts.map +1 -0
  576. package/sdk/dist/plan-parser.js +389 -0
  577. package/sdk/dist/plan-parser.js.map +1 -0
  578. package/sdk/dist/planning-journal.d.ts +64 -0
  579. package/sdk/dist/planning-journal.d.ts.map +1 -0
  580. package/sdk/dist/planning-journal.js +88 -0
  581. package/sdk/dist/planning-journal.js.map +1 -0
  582. package/sdk/dist/planning-runtime.d.ts +67 -0
  583. package/sdk/dist/planning-runtime.d.ts.map +1 -0
  584. package/sdk/dist/planning-runtime.js +58 -0
  585. package/sdk/dist/planning-runtime.js.map +1 -0
  586. package/sdk/dist/project-root/index.d.ts +46 -0
  587. package/sdk/dist/project-root/index.d.ts.map +1 -0
  588. package/sdk/dist/project-root/index.js +138 -0
  589. package/sdk/dist/project-root/index.js.map +1 -0
  590. package/sdk/dist/prompt-builder.d.ts +44 -0
  591. package/sdk/dist/prompt-builder.d.ts.map +1 -0
  592. package/sdk/dist/prompt-builder.js +180 -0
  593. package/sdk/dist/prompt-builder.js.map +1 -0
  594. package/sdk/dist/prompt-sanitizer.d.ts +35 -0
  595. package/sdk/dist/prompt-sanitizer.d.ts.map +1 -0
  596. package/sdk/dist/prompt-sanitizer.js +101 -0
  597. package/sdk/dist/prompt-sanitizer.js.map +1 -0
  598. package/sdk/dist/query/active-workstream-store.d.ts +7 -0
  599. package/sdk/dist/query/active-workstream-store.d.ts.map +1 -0
  600. package/sdk/dist/query/active-workstream-store.js +56 -0
  601. package/sdk/dist/query/active-workstream-store.js.map +1 -0
  602. package/sdk/dist/query/agent-failure-classifier.d.ts +38 -0
  603. package/sdk/dist/query/agent-failure-classifier.d.ts.map +1 -0
  604. package/sdk/dist/query/agent-failure-classifier.js +83 -0
  605. package/sdk/dist/query/agent-failure-classifier.js.map +1 -0
  606. package/sdk/dist/query/audit-open.d.ts +46 -0
  607. package/sdk/dist/query/audit-open.d.ts.map +1 -0
  608. package/sdk/dist/query/audit-open.js +662 -0
  609. package/sdk/dist/query/audit-open.js.map +1 -0
  610. package/sdk/dist/query/check-auto-mode.d.ts +13 -0
  611. package/sdk/dist/query/check-auto-mode.d.ts.map +1 -0
  612. package/sdk/dist/query/check-auto-mode.js +40 -0
  613. package/sdk/dist/query/check-auto-mode.js.map +1 -0
  614. package/sdk/dist/query/check-completion.d.ts +10 -0
  615. package/sdk/dist/query/check-completion.d.ts.map +1 -0
  616. package/sdk/dist/query/check-completion.js +157 -0
  617. package/sdk/dist/query/check-completion.js.map +1 -0
  618. package/sdk/dist/query/check-decision-coverage.d.ts +33 -0
  619. package/sdk/dist/query/check-decision-coverage.d.ts.map +1 -0
  620. package/sdk/dist/query/check-decision-coverage.js +472 -0
  621. package/sdk/dist/query/check-decision-coverage.js.map +1 -0
  622. package/sdk/dist/query/check-gates.d.ts +10 -0
  623. package/sdk/dist/query/check-gates.d.ts.map +1 -0
  624. package/sdk/dist/query/check-gates.js +89 -0
  625. package/sdk/dist/query/check-gates.js.map +1 -0
  626. package/sdk/dist/query/check-ship-ready.d.ts +17 -0
  627. package/sdk/dist/query/check-ship-ready.d.ts.map +1 -0
  628. package/sdk/dist/query/check-ship-ready.js +121 -0
  629. package/sdk/dist/query/check-ship-ready.js.map +1 -0
  630. package/sdk/dist/query/check-verification-status.d.ts +10 -0
  631. package/sdk/dist/query/check-verification-status.d.ts.map +1 -0
  632. package/sdk/dist/query/check-verification-status.js +142 -0
  633. package/sdk/dist/query/check-verification-status.js.map +1 -0
  634. package/sdk/dist/query/command-aliases.generated.d.ts +31 -0
  635. package/sdk/dist/query/command-aliases.generated.d.ts.map +1 -0
  636. package/sdk/dist/query/command-aliases.generated.js +133 -0
  637. package/sdk/dist/query/command-aliases.generated.js.map +1 -0
  638. package/sdk/dist/query/command-catalog.d.ts +9 -0
  639. package/sdk/dist/query/command-catalog.d.ts.map +1 -0
  640. package/sdk/dist/query/command-catalog.js +17 -0
  641. package/sdk/dist/query/command-catalog.js.map +1 -0
  642. package/sdk/dist/query/command-definition.d.ts +19 -0
  643. package/sdk/dist/query/command-definition.d.ts.map +1 -0
  644. package/sdk/dist/query/command-definition.js +44 -0
  645. package/sdk/dist/query/command-definition.js.map +1 -0
  646. package/sdk/dist/query/command-family-handlers.d.ts +3 -0
  647. package/sdk/dist/query/command-family-handlers.d.ts.map +1 -0
  648. package/sdk/dist/query/command-family-handlers.js +101 -0
  649. package/sdk/dist/query/command-family-handlers.js.map +1 -0
  650. package/sdk/dist/query/command-manifest.d.ts +2 -0
  651. package/sdk/dist/query/command-manifest.d.ts.map +1 -0
  652. package/sdk/dist/query/command-manifest.init.d.ts +6 -0
  653. package/sdk/dist/query/command-manifest.init.d.ts.map +1 -0
  654. package/sdk/dist/query/command-manifest.init.js +23 -0
  655. package/sdk/dist/query/command-manifest.init.js.map +1 -0
  656. package/sdk/dist/query/command-manifest.js +17 -0
  657. package/sdk/dist/query/command-manifest.js.map +1 -0
  658. package/sdk/dist/query/command-manifest.non-family.d.ts +9 -0
  659. package/sdk/dist/query/command-manifest.non-family.d.ts.map +1 -0
  660. package/sdk/dist/query/command-manifest.non-family.js +60 -0
  661. package/sdk/dist/query/command-manifest.non-family.js.map +1 -0
  662. package/sdk/dist/query/command-manifest.phase.d.ts +6 -0
  663. package/sdk/dist/query/command-manifest.phase.d.ts.map +1 -0
  664. package/sdk/dist/query/command-manifest.phase.js +16 -0
  665. package/sdk/dist/query/command-manifest.phase.js.map +1 -0
  666. package/sdk/dist/query/command-manifest.phases.d.ts +7 -0
  667. package/sdk/dist/query/command-manifest.phases.d.ts.map +1 -0
  668. package/sdk/dist/query/command-manifest.phases.js +10 -0
  669. package/sdk/dist/query/command-manifest.phases.js.map +1 -0
  670. package/sdk/dist/query/command-manifest.roadmap.d.ts +6 -0
  671. package/sdk/dist/query/command-manifest.roadmap.d.ts.map +1 -0
  672. package/sdk/dist/query/command-manifest.roadmap.js +10 -0
  673. package/sdk/dist/query/command-manifest.roadmap.js.map +1 -0
  674. package/sdk/dist/query/command-manifest.state.d.ts +9 -0
  675. package/sdk/dist/query/command-manifest.state.d.ts.map +1 -0
  676. package/sdk/dist/query/command-manifest.state.js +30 -0
  677. package/sdk/dist/query/command-manifest.state.js.map +1 -0
  678. package/sdk/dist/query/command-manifest.types.d.ts +12 -0
  679. package/sdk/dist/query/command-manifest.types.d.ts.map +1 -0
  680. package/sdk/dist/query/command-manifest.types.js +2 -0
  681. package/sdk/dist/query/command-manifest.types.js.map +1 -0
  682. package/sdk/dist/query/command-manifest.validate.d.ts +6 -0
  683. package/sdk/dist/query/command-manifest.validate.d.ts.map +1 -0
  684. package/sdk/dist/query/command-manifest.validate.js +10 -0
  685. package/sdk/dist/query/command-manifest.validate.js.map +1 -0
  686. package/sdk/dist/query/command-manifest.verify.d.ts +6 -0
  687. package/sdk/dist/query/command-manifest.verify.d.ts.map +1 -0
  688. package/sdk/dist/query/command-manifest.verify.js +16 -0
  689. package/sdk/dist/query/command-manifest.verify.js.map +1 -0
  690. package/sdk/dist/query/command-static-catalog-domain.d.ts +3 -0
  691. package/sdk/dist/query/command-static-catalog-domain.d.ts.map +1 -0
  692. package/sdk/dist/query/command-static-catalog-domain.js +110 -0
  693. package/sdk/dist/query/command-static-catalog-domain.js.map +1 -0
  694. package/sdk/dist/query/command-static-catalog-foundation.d.ts +7 -0
  695. package/sdk/dist/query/command-static-catalog-foundation.d.ts.map +1 -0
  696. package/sdk/dist/query/command-static-catalog-foundation.js +106 -0
  697. package/sdk/dist/query/command-static-catalog-foundation.js.map +1 -0
  698. package/sdk/dist/query/command-topology.d.ts +32 -0
  699. package/sdk/dist/query/command-topology.d.ts.map +1 -0
  700. package/sdk/dist/query/command-topology.js +66 -0
  701. package/sdk/dist/query/command-topology.js.map +1 -0
  702. package/sdk/dist/query/commands-list.d.ts +14 -0
  703. package/sdk/dist/query/commands-list.d.ts.map +1 -0
  704. package/sdk/dist/query/commands-list.js +18 -0
  705. package/sdk/dist/query/commands-list.js.map +1 -0
  706. package/sdk/dist/query/commit.d.ts +179 -0
  707. package/sdk/dist/query/commit.d.ts.map +1 -0
  708. package/sdk/dist/query/commit.js +632 -0
  709. package/sdk/dist/query/commit.js.map +1 -0
  710. package/sdk/dist/query/config-gates.d.ts +12 -0
  711. package/sdk/dist/query/config-gates.d.ts.map +1 -0
  712. package/sdk/dist/query/config-gates.js +66 -0
  713. package/sdk/dist/query/config-gates.js.map +1 -0
  714. package/sdk/dist/query/config-mutation.d.ts +86 -0
  715. package/sdk/dist/query/config-mutation.d.ts.map +1 -0
  716. package/sdk/dist/query/config-mutation.js +602 -0
  717. package/sdk/dist/query/config-mutation.js.map +1 -0
  718. package/sdk/dist/query/config-query.d.ts +57 -0
  719. package/sdk/dist/query/config-query.d.ts.map +1 -0
  720. package/sdk/dist/query/config-query.js +277 -0
  721. package/sdk/dist/query/config-query.js.map +1 -0
  722. package/sdk/dist/query/config-schema.d.ts +19 -0
  723. package/sdk/dist/query/config-schema.d.ts.map +1 -0
  724. package/sdk/dist/query/config-schema.js +26 -0
  725. package/sdk/dist/query/config-schema.js.map +1 -0
  726. package/sdk/dist/query/decisions.d.ts +58 -0
  727. package/sdk/dist/query/decisions.d.ts.map +1 -0
  728. package/sdk/dist/query/decisions.js +165 -0
  729. package/sdk/dist/query/decisions.js.map +1 -0
  730. package/sdk/dist/query/detect-custom-files.d.ts +11 -0
  731. package/sdk/dist/query/detect-custom-files.d.ts.map +1 -0
  732. package/sdk/dist/query/detect-custom-files.js +89 -0
  733. package/sdk/dist/query/detect-custom-files.js.map +1 -0
  734. package/sdk/dist/query/detect-phase-type.d.ts +9 -0
  735. package/sdk/dist/query/detect-phase-type.d.ts.map +1 -0
  736. package/sdk/dist/query/detect-phase-type.js +124 -0
  737. package/sdk/dist/query/detect-phase-type.js.map +1 -0
  738. package/sdk/dist/query/docs-init.d.ts +26 -0
  739. package/sdk/dist/query/docs-init.d.ts.map +1 -0
  740. package/sdk/dist/query/docs-init.js +231 -0
  741. package/sdk/dist/query/docs-init.js.map +1 -0
  742. package/sdk/dist/query/fallow-audit.d.ts +44 -0
  743. package/sdk/dist/query/fallow-audit.d.ts.map +1 -0
  744. package/sdk/dist/query/fallow-audit.js +44 -0
  745. package/sdk/dist/query/fallow-audit.js.map +1 -0
  746. package/sdk/dist/query/frontmatter-mutation.d.ts +77 -0
  747. package/sdk/dist/query/frontmatter-mutation.d.ts.map +1 -0
  748. package/sdk/dist/query/frontmatter-mutation.js +299 -0
  749. package/sdk/dist/query/frontmatter-mutation.js.map +1 -0
  750. package/sdk/dist/query/frontmatter.d.ts +93 -0
  751. package/sdk/dist/query/frontmatter.d.ts.map +1 -0
  752. package/sdk/dist/query/frontmatter.js +364 -0
  753. package/sdk/dist/query/frontmatter.js.map +1 -0
  754. package/sdk/dist/query/helpers.d.ts +194 -0
  755. package/sdk/dist/query/helpers.d.ts.map +1 -0
  756. package/sdk/dist/query/helpers.js +540 -0
  757. package/sdk/dist/query/helpers.js.map +1 -0
  758. package/sdk/dist/query/index.d.ts +8 -0
  759. package/sdk/dist/query/index.d.ts.map +1 -0
  760. package/sdk/dist/query/index.js +6 -0
  761. package/sdk/dist/query/index.js.map +1 -0
  762. package/sdk/dist/query/init-complex.d.ts +47 -0
  763. package/sdk/dist/query/init-complex.d.ts.map +1 -0
  764. package/sdk/dist/query/init-complex.js +735 -0
  765. package/sdk/dist/query/init-complex.js.map +1 -0
  766. package/sdk/dist/query/init.d.ts +106 -0
  767. package/sdk/dist/query/init.d.ts.map +1 -0
  768. package/sdk/dist/query/init.js +1228 -0
  769. package/sdk/dist/query/init.js.map +1 -0
  770. package/sdk/dist/query/intel.d.ts +43 -0
  771. package/sdk/dist/query/intel.d.ts.map +1 -0
  772. package/sdk/dist/query/intel.js +416 -0
  773. package/sdk/dist/query/intel.js.map +1 -0
  774. package/sdk/dist/query/mutation-event-decorator.d.ts +5 -0
  775. package/sdk/dist/query/mutation-event-decorator.d.ts.map +1 -0
  776. package/sdk/dist/query/mutation-event-decorator.js +28 -0
  777. package/sdk/dist/query/mutation-event-decorator.js.map +1 -0
  778. package/sdk/dist/query/mutation-event-mapper.d.ts +4 -0
  779. package/sdk/dist/query/mutation-event-mapper.d.ts.map +1 -0
  780. package/sdk/dist/query/mutation-event-mapper.js +70 -0
  781. package/sdk/dist/query/mutation-event-mapper.js.map +1 -0
  782. package/sdk/dist/query/mvp.d.ts +113 -0
  783. package/sdk/dist/query/mvp.d.ts.map +1 -0
  784. package/sdk/dist/query/mvp.js +225 -0
  785. package/sdk/dist/query/mvp.js.map +1 -0
  786. package/sdk/dist/query/phase-filesystem-adapter.d.ts +4 -0
  787. package/sdk/dist/query/phase-filesystem-adapter.d.ts.map +1 -0
  788. package/sdk/dist/query/phase-filesystem-adapter.js +33 -0
  789. package/sdk/dist/query/phase-filesystem-adapter.js.map +1 -0
  790. package/sdk/dist/query/phase-lifecycle-policy.d.ts +34 -0
  791. package/sdk/dist/query/phase-lifecycle-policy.d.ts.map +1 -0
  792. package/sdk/dist/query/phase-lifecycle-policy.js +138 -0
  793. package/sdk/dist/query/phase-lifecycle-policy.js.map +1 -0
  794. package/sdk/dist/query/phase-lifecycle.d.ts +116 -0
  795. package/sdk/dist/query/phase-lifecycle.d.ts.map +1 -0
  796. package/sdk/dist/query/phase-lifecycle.js +1823 -0
  797. package/sdk/dist/query/phase-lifecycle.js.map +1 -0
  798. package/sdk/dist/query/phase-list-queries.d.ts +20 -0
  799. package/sdk/dist/query/phase-list-queries.d.ts.map +1 -0
  800. package/sdk/dist/query/phase-list-queries.js +129 -0
  801. package/sdk/dist/query/phase-list-queries.js.map +1 -0
  802. package/sdk/dist/query/phase-ready.d.ts +9 -0
  803. package/sdk/dist/query/phase-ready.d.ts.map +1 -0
  804. package/sdk/dist/query/phase-ready.js +132 -0
  805. package/sdk/dist/query/phase-ready.js.map +1 -0
  806. package/sdk/dist/query/phase-roadmap-mutation.d.ts +25 -0
  807. package/sdk/dist/query/phase-roadmap-mutation.d.ts.map +1 -0
  808. package/sdk/dist/query/phase-roadmap-mutation.js +76 -0
  809. package/sdk/dist/query/phase-roadmap-mutation.js.map +1 -0
  810. package/sdk/dist/query/phase-uat-passed.d.ts +46 -0
  811. package/sdk/dist/query/phase-uat-passed.d.ts.map +1 -0
  812. package/sdk/dist/query/phase-uat-passed.js +238 -0
  813. package/sdk/dist/query/phase-uat-passed.js.map +1 -0
  814. package/sdk/dist/query/phase.d.ts +104 -0
  815. package/sdk/dist/query/phase.d.ts.map +1 -0
  816. package/sdk/dist/query/phase.js +617 -0
  817. package/sdk/dist/query/phase.js.map +1 -0
  818. package/sdk/dist/query/pipeline.d.ts +53 -0
  819. package/sdk/dist/query/pipeline.d.ts.map +1 -0
  820. package/sdk/dist/query/pipeline.js +198 -0
  821. package/sdk/dist/query/pipeline.js.map +1 -0
  822. package/sdk/dist/query/plan-scan.d.ts +14 -0
  823. package/sdk/dist/query/plan-scan.d.ts.map +1 -0
  824. package/sdk/dist/query/plan-scan.js +70 -0
  825. package/sdk/dist/query/plan-scan.js.map +1 -0
  826. package/sdk/dist/query/plan-task-structure.d.ts +9 -0
  827. package/sdk/dist/query/plan-task-structure.d.ts.map +1 -0
  828. package/sdk/dist/query/plan-task-structure.js +59 -0
  829. package/sdk/dist/query/plan-task-structure.js.map +1 -0
  830. package/sdk/dist/query/profile-extract-messages.d.ts +40 -0
  831. package/sdk/dist/query/profile-extract-messages.d.ts.map +1 -0
  832. package/sdk/dist/query/profile-extract-messages.js +195 -0
  833. package/sdk/dist/query/profile-extract-messages.js.map +1 -0
  834. package/sdk/dist/query/profile-output.d.ts +11 -0
  835. package/sdk/dist/query/profile-output.d.ts.map +1 -0
  836. package/sdk/dist/query/profile-output.js +873 -0
  837. package/sdk/dist/query/profile-output.js.map +1 -0
  838. package/sdk/dist/query/profile-questionnaire-data.d.ts +21 -0
  839. package/sdk/dist/query/profile-questionnaire-data.d.ts.map +1 -0
  840. package/sdk/dist/query/profile-questionnaire-data.js +171 -0
  841. package/sdk/dist/query/profile-questionnaire-data.js.map +1 -0
  842. package/sdk/dist/query/profile-sample.d.ts +22 -0
  843. package/sdk/dist/query/profile-sample.d.ts.map +1 -0
  844. package/sdk/dist/query/profile-sample.js +136 -0
  845. package/sdk/dist/query/profile-sample.js.map +1 -0
  846. package/sdk/dist/query/profile-scan-sessions.d.ts +49 -0
  847. package/sdk/dist/query/profile-scan-sessions.d.ts.map +1 -0
  848. package/sdk/dist/query/profile-scan-sessions.js +137 -0
  849. package/sdk/dist/query/profile-scan-sessions.js.map +1 -0
  850. package/sdk/dist/query/profile.d.ts +61 -0
  851. package/sdk/dist/query/profile.d.ts.map +1 -0
  852. package/sdk/dist/query/profile.js +307 -0
  853. package/sdk/dist/query/profile.js.map +1 -0
  854. package/sdk/dist/query/progress.d.ts +77 -0
  855. package/sdk/dist/query/progress.d.ts.map +1 -0
  856. package/sdk/dist/query/progress.js +481 -0
  857. package/sdk/dist/query/progress.js.map +1 -0
  858. package/sdk/dist/query/prompt-budget.d.ts +14 -0
  859. package/sdk/dist/query/prompt-budget.d.ts.map +1 -0
  860. package/sdk/dist/query/prompt-budget.js +417 -0
  861. package/sdk/dist/query/prompt-budget.js.map +1 -0
  862. package/sdk/dist/query/query-cli-adapter.d.ts +8 -0
  863. package/sdk/dist/query/query-cli-adapter.d.ts.map +1 -0
  864. package/sdk/dist/query/query-cli-adapter.js +32 -0
  865. package/sdk/dist/query/query-cli-adapter.js.map +1 -0
  866. package/sdk/dist/query/query-cli-output.d.ts +9 -0
  867. package/sdk/dist/query/query-cli-output.d.ts.map +1 -0
  868. package/sdk/dist/query/query-cli-output.js +28 -0
  869. package/sdk/dist/query/query-cli-output.js.map +1 -0
  870. package/sdk/dist/query/query-command-diagnosis.d.ts +6 -0
  871. package/sdk/dist/query/query-command-diagnosis.d.ts.map +1 -0
  872. package/sdk/dist/query/query-command-diagnosis.js +6 -0
  873. package/sdk/dist/query/query-command-diagnosis.js.map +1 -0
  874. package/sdk/dist/query/query-command-resolution-strategy.d.ts +29 -0
  875. package/sdk/dist/query/query-command-resolution-strategy.d.ts.map +1 -0
  876. package/sdk/dist/query/query-command-resolution-strategy.js +103 -0
  877. package/sdk/dist/query/query-command-resolution-strategy.js.map +1 -0
  878. package/sdk/dist/query/query-command-semantics.d.ts +7 -0
  879. package/sdk/dist/query/query-command-semantics.d.ts.map +1 -0
  880. package/sdk/dist/query/query-command-semantics.js +7 -0
  881. package/sdk/dist/query/query-command-semantics.js.map +1 -0
  882. package/sdk/dist/query/query-dispatch-contract.d.ts +21 -0
  883. package/sdk/dist/query/query-dispatch-contract.d.ts.map +1 -0
  884. package/sdk/dist/query/query-dispatch-contract.js +2 -0
  885. package/sdk/dist/query/query-dispatch-contract.js.map +1 -0
  886. package/sdk/dist/query/query-dispatch-error-mapper.d.ts +6 -0
  887. package/sdk/dist/query/query-dispatch-error-mapper.d.ts.map +1 -0
  888. package/sdk/dist/query/query-dispatch-error-mapper.js +6 -0
  889. package/sdk/dist/query/query-dispatch-error-mapper.js.map +1 -0
  890. package/sdk/dist/query/query-dispatch-formatting.d.ts +6 -0
  891. package/sdk/dist/query/query-dispatch-formatting.d.ts.map +1 -0
  892. package/sdk/dist/query/query-dispatch-formatting.js +6 -0
  893. package/sdk/dist/query/query-dispatch-formatting.js.map +1 -0
  894. package/sdk/dist/query/query-dispatch-observability.d.ts +2 -0
  895. package/sdk/dist/query/query-dispatch-observability.d.ts.map +1 -0
  896. package/sdk/dist/query/query-dispatch-observability.js +7 -0
  897. package/sdk/dist/query/query-dispatch-observability.js.map +1 -0
  898. package/sdk/dist/query/query-dispatch.d.ts +48 -0
  899. package/sdk/dist/query/query-dispatch.d.ts.map +1 -0
  900. package/sdk/dist/query/query-dispatch.js +175 -0
  901. package/sdk/dist/query/query-dispatch.js.map +1 -0
  902. package/sdk/dist/query/query-error-details-schema.d.ts +19 -0
  903. package/sdk/dist/query/query-error-details-schema.d.ts.map +1 -0
  904. package/sdk/dist/query/query-error-details-schema.js +10 -0
  905. package/sdk/dist/query/query-error-details-schema.js.map +1 -0
  906. package/sdk/dist/query/query-error-taxonomy.d.ts +38 -0
  907. package/sdk/dist/query/query-error-taxonomy.d.ts.map +1 -0
  908. package/sdk/dist/query/query-error-taxonomy.js +74 -0
  909. package/sdk/dist/query/query-error-taxonomy.js.map +1 -0
  910. package/sdk/dist/query/query-fallback-bridge-adapter.d.ts +14 -0
  911. package/sdk/dist/query/query-fallback-bridge-adapter.d.ts.map +1 -0
  912. package/sdk/dist/query/query-fallback-bridge-adapter.js +33 -0
  913. package/sdk/dist/query/query-fallback-bridge-adapter.js.map +1 -0
  914. package/sdk/dist/query/query-fallback-executor.d.ts +11 -0
  915. package/sdk/dist/query/query-fallback-executor.d.ts.map +1 -0
  916. package/sdk/dist/query/query-fallback-executor.js +31 -0
  917. package/sdk/dist/query/query-fallback-executor.js.map +1 -0
  918. package/sdk/dist/query/query-fallback-output-classifier.d.ts +6 -0
  919. package/sdk/dist/query/query-fallback-output-classifier.d.ts.map +1 -0
  920. package/sdk/dist/query/query-fallback-output-classifier.js +27 -0
  921. package/sdk/dist/query/query-fallback-output-classifier.js.map +1 -0
  922. package/sdk/dist/query/query-fallback-policy.d.ts +6 -0
  923. package/sdk/dist/query/query-fallback-policy.d.ts.map +1 -0
  924. package/sdk/dist/query/query-fallback-policy.js +7 -0
  925. package/sdk/dist/query/query-fallback-policy.js.map +1 -0
  926. package/sdk/dist/query/query-native-dispatch-adapter.d.ts +7 -0
  927. package/sdk/dist/query/query-native-dispatch-adapter.d.ts.map +1 -0
  928. package/sdk/dist/query/query-native-dispatch-adapter.js +6 -0
  929. package/sdk/dist/query/query-native-dispatch-adapter.js.map +1 -0
  930. package/sdk/dist/query/query-policy-capability.d.ts +10 -0
  931. package/sdk/dist/query/query-policy-capability.d.ts.map +1 -0
  932. package/sdk/dist/query/query-policy-capability.js +17 -0
  933. package/sdk/dist/query/query-policy-capability.js.map +1 -0
  934. package/sdk/dist/query/query-runtime-context.d.ts +19 -0
  935. package/sdk/dist/query/query-runtime-context.d.ts.map +1 -0
  936. package/sdk/dist/query/query-runtime-context.js +31 -0
  937. package/sdk/dist/query/query-runtime-context.js.map +1 -0
  938. package/sdk/dist/query/query-unknown-command-hints.d.ts +2 -0
  939. package/sdk/dist/query/query-unknown-command-hints.d.ts.map +1 -0
  940. package/sdk/dist/query/query-unknown-command-hints.js +6 -0
  941. package/sdk/dist/query/query-unknown-command-hints.js.map +1 -0
  942. package/sdk/dist/query/registry-assembly-descriptor.d.ts +12 -0
  943. package/sdk/dist/query/registry-assembly-descriptor.d.ts.map +1 -0
  944. package/sdk/dist/query/registry-assembly-descriptor.js +61 -0
  945. package/sdk/dist/query/registry-assembly-descriptor.js.map +1 -0
  946. package/sdk/dist/query/registry-assembly-invariants.d.ts +30 -0
  947. package/sdk/dist/query/registry-assembly-invariants.d.ts.map +1 -0
  948. package/sdk/dist/query/registry-assembly-invariants.js +77 -0
  949. package/sdk/dist/query/registry-assembly-invariants.js.map +1 -0
  950. package/sdk/dist/query/registry-assembly.d.ts +10 -0
  951. package/sdk/dist/query/registry-assembly.d.ts.map +1 -0
  952. package/sdk/dist/query/registry-assembly.js +53 -0
  953. package/sdk/dist/query/registry-assembly.js.map +1 -0
  954. package/sdk/dist/query/registry.d.ts +90 -0
  955. package/sdk/dist/query/registry.d.ts.map +1 -0
  956. package/sdk/dist/query/registry.js +129 -0
  957. package/sdk/dist/query/registry.js.map +1 -0
  958. package/sdk/dist/query/requirements-extract-from-plans.d.ts +9 -0
  959. package/sdk/dist/query/requirements-extract-from-plans.d.ts.map +1 -0
  960. package/sdk/dist/query/requirements-extract-from-plans.js +76 -0
  961. package/sdk/dist/query/requirements-extract-from-plans.js.map +1 -0
  962. package/sdk/dist/query/roadmap-update-plan-progress.d.ts +11 -0
  963. package/sdk/dist/query/roadmap-update-plan-progress.d.ts.map +1 -0
  964. package/sdk/dist/query/roadmap-update-plan-progress.js +124 -0
  965. package/sdk/dist/query/roadmap-update-plan-progress.js.map +1 -0
  966. package/sdk/dist/query/roadmap.d.ts +160 -0
  967. package/sdk/dist/query/roadmap.d.ts.map +1 -0
  968. package/sdk/dist/query/roadmap.js +982 -0
  969. package/sdk/dist/query/roadmap.js.map +1 -0
  970. package/sdk/dist/query/route-next-action.d.ts +9 -0
  971. package/sdk/dist/query/route-next-action.d.ts.map +1 -0
  972. package/sdk/dist/query/route-next-action.js +318 -0
  973. package/sdk/dist/query/route-next-action.js.map +1 -0
  974. package/sdk/dist/query/schema-detect.d.ts +21 -0
  975. package/sdk/dist/query/schema-detect.d.ts.map +1 -0
  976. package/sdk/dist/query/schema-detect.js +146 -0
  977. package/sdk/dist/query/schema-detect.js.map +1 -0
  978. package/sdk/dist/query/secrets.d.ts +27 -0
  979. package/sdk/dist/query/secrets.d.ts.map +1 -0
  980. package/sdk/dist/query/secrets.js +42 -0
  981. package/sdk/dist/query/secrets.js.map +1 -0
  982. package/sdk/dist/query/skill-manifest.d.ts +50 -0
  983. package/sdk/dist/query/skill-manifest.d.ts.map +1 -0
  984. package/sdk/dist/query/skill-manifest.js +171 -0
  985. package/sdk/dist/query/skill-manifest.js.map +1 -0
  986. package/sdk/dist/query/skills.d.ts +27 -0
  987. package/sdk/dist/query/skills.d.ts.map +1 -0
  988. package/sdk/dist/query/skills.js +137 -0
  989. package/sdk/dist/query/skills.js.map +1 -0
  990. package/sdk/dist/query/state-document.d.ts +14 -0
  991. package/sdk/dist/query/state-document.d.ts.map +1 -0
  992. package/sdk/dist/query/state-document.js +110 -0
  993. package/sdk/dist/query/state-document.js.map +1 -0
  994. package/sdk/dist/query/state-mutation.d.ts +224 -0
  995. package/sdk/dist/query/state-mutation.d.ts.map +1 -0
  996. package/sdk/dist/query/state-mutation.js +1635 -0
  997. package/sdk/dist/query/state-mutation.js.map +1 -0
  998. package/sdk/dist/query/state-project-load.d.ts +23 -0
  999. package/sdk/dist/query/state-project-load.d.ts.map +1 -0
  1000. package/sdk/dist/query/state-project-load.js +75 -0
  1001. package/sdk/dist/query/state-project-load.js.map +1 -0
  1002. package/sdk/dist/query/state.d.ts +78 -0
  1003. package/sdk/dist/query/state.d.ts.map +1 -0
  1004. package/sdk/dist/query/state.js +443 -0
  1005. package/sdk/dist/query/state.js.map +1 -0
  1006. package/sdk/dist/query/summary.d.ts +18 -0
  1007. package/sdk/dist/query/summary.d.ts.map +1 -0
  1008. package/sdk/dist/query/summary.js +249 -0
  1009. package/sdk/dist/query/summary.js.map +1 -0
  1010. package/sdk/dist/query/template.d.ts +46 -0
  1011. package/sdk/dist/query/template.d.ts.map +1 -0
  1012. package/sdk/dist/query/template.js +210 -0
  1013. package/sdk/dist/query/template.js.map +1 -0
  1014. package/sdk/dist/query/uat.d.ts +42 -0
  1015. package/sdk/dist/query/uat.d.ts.map +1 -0
  1016. package/sdk/dist/query/uat.js +339 -0
  1017. package/sdk/dist/query/uat.js.map +1 -0
  1018. package/sdk/dist/query/utils.d.ts +59 -0
  1019. package/sdk/dist/query/utils.d.ts.map +1 -0
  1020. package/sdk/dist/query/utils.js +74 -0
  1021. package/sdk/dist/query/utils.js.map +1 -0
  1022. package/sdk/dist/query/validate.d.ts +67 -0
  1023. package/sdk/dist/query/validate.d.ts.map +1 -0
  1024. package/sdk/dist/query/validate.js +1001 -0
  1025. package/sdk/dist/query/validate.js.map +1 -0
  1026. package/sdk/dist/query/verify.d.ts +98 -0
  1027. package/sdk/dist/query/verify.d.ts.map +1 -0
  1028. package/sdk/dist/query/verify.js +593 -0
  1029. package/sdk/dist/query/verify.js.map +1 -0
  1030. package/sdk/dist/query/websearch.d.ts +24 -0
  1031. package/sdk/dist/query/websearch.d.ts.map +1 -0
  1032. package/sdk/dist/query/websearch.js +68 -0
  1033. package/sdk/dist/query/websearch.js.map +1 -0
  1034. package/sdk/dist/query/workspace.d.ts +62 -0
  1035. package/sdk/dist/query/workspace.d.ts.map +1 -0
  1036. package/sdk/dist/query/workspace.js +104 -0
  1037. package/sdk/dist/query/workspace.js.map +1 -0
  1038. package/sdk/dist/query/workstream-inventory.d.ts +24 -0
  1039. package/sdk/dist/query/workstream-inventory.d.ts.map +1 -0
  1040. package/sdk/dist/query/workstream-inventory.js +120 -0
  1041. package/sdk/dist/query/workstream-inventory.js.map +1 -0
  1042. package/sdk/dist/query/workstream.d.ts +35 -0
  1043. package/sdk/dist/query/workstream.d.ts.map +1 -0
  1044. package/sdk/dist/query/workstream.js +298 -0
  1045. package/sdk/dist/query/workstream.js.map +1 -0
  1046. package/sdk/dist/query/worktree.d.ts +9 -0
  1047. package/sdk/dist/query/worktree.d.ts.map +1 -0
  1048. package/sdk/dist/query/worktree.js +79 -0
  1049. package/sdk/dist/query/worktree.js.map +1 -0
  1050. package/sdk/dist/query-command-executor.d.ts +22 -0
  1051. package/sdk/dist/query-command-executor.d.ts.map +1 -0
  1052. package/sdk/dist/query-command-executor.js +22 -0
  1053. package/sdk/dist/query-command-executor.js.map +1 -0
  1054. package/sdk/dist/query-execution-policy.d.ts +24 -0
  1055. package/sdk/dist/query-execution-policy.d.ts.map +1 -0
  1056. package/sdk/dist/query-execution-policy.js +27 -0
  1057. package/sdk/dist/query-execution-policy.js.map +1 -0
  1058. package/sdk/dist/query-failure-classification.d.ts +9 -0
  1059. package/sdk/dist/query-failure-classification.d.ts.map +1 -0
  1060. package/sdk/dist/query-failure-classification.js +32 -0
  1061. package/sdk/dist/query-failure-classification.js.map +1 -0
  1062. package/sdk/dist/query-gsd-tools-path.d.ts +2 -0
  1063. package/sdk/dist/query-gsd-tools-path.d.ts.map +1 -0
  1064. package/sdk/dist/query-gsd-tools-path.js +2 -0
  1065. package/sdk/dist/query-gsd-tools-path.js.map +1 -0
  1066. package/sdk/dist/query-gsd-tools-runtime.d.ts +20 -0
  1067. package/sdk/dist/query-gsd-tools-runtime.d.ts.map +1 -0
  1068. package/sdk/dist/query-gsd-tools-runtime.js +47 -0
  1069. package/sdk/dist/query-gsd-tools-runtime.js.map +1 -0
  1070. package/sdk/dist/query-hotpath-methods.d.ts +19 -0
  1071. package/sdk/dist/query-hotpath-methods.d.ts.map +1 -0
  1072. package/sdk/dist/query-hotpath-methods.js +34 -0
  1073. package/sdk/dist/query-hotpath-methods.js.map +1 -0
  1074. package/sdk/dist/query-native-direct-adapter.d.ts +20 -0
  1075. package/sdk/dist/query-native-direct-adapter.d.ts.map +1 -0
  1076. package/sdk/dist/query-native-direct-adapter.js +52 -0
  1077. package/sdk/dist/query-native-direct-adapter.js.map +1 -0
  1078. package/sdk/dist/query-native-hotpath-adapter.d.ts +15 -0
  1079. package/sdk/dist/query-native-hotpath-adapter.d.ts.map +1 -0
  1080. package/sdk/dist/query-native-hotpath-adapter.js +32 -0
  1081. package/sdk/dist/query-native-hotpath-adapter.js.map +1 -0
  1082. package/sdk/dist/query-raw-output-projection.d.ts +6 -0
  1083. package/sdk/dist/query-raw-output-projection.d.ts.map +1 -0
  1084. package/sdk/dist/query-raw-output-projection.js +86 -0
  1085. package/sdk/dist/query-raw-output-projection.js.map +1 -0
  1086. package/sdk/dist/query-runtime-bridge.d.ts +61 -0
  1087. package/sdk/dist/query-runtime-bridge.d.ts.map +1 -0
  1088. package/sdk/dist/query-runtime-bridge.js +144 -0
  1089. package/sdk/dist/query-runtime-bridge.js.map +1 -0
  1090. package/sdk/dist/query-subprocess-adapter.d.ts +18 -0
  1091. package/sdk/dist/query-subprocess-adapter.d.ts.map +1 -0
  1092. package/sdk/dist/query-subprocess-adapter.js +92 -0
  1093. package/sdk/dist/query-subprocess-adapter.js.map +1 -0
  1094. package/sdk/dist/query-tools-error-factory.d.ts +16 -0
  1095. package/sdk/dist/query-tools-error-factory.d.ts.map +1 -0
  1096. package/sdk/dist/query-tools-error-factory.js +33 -0
  1097. package/sdk/dist/query-tools-error-factory.js.map +1 -0
  1098. package/sdk/dist/research-gate.d.ts +24 -0
  1099. package/sdk/dist/research-gate.d.ts.map +1 -0
  1100. package/sdk/dist/research-gate.js +70 -0
  1101. package/sdk/dist/research-gate.js.map +1 -0
  1102. package/sdk/dist/runtime-bridge-sync/index.d.ts +96 -0
  1103. package/sdk/dist/runtime-bridge-sync/index.d.ts.map +1 -0
  1104. package/sdk/dist/runtime-bridge-sync/index.js +109 -0
  1105. package/sdk/dist/runtime-bridge-sync/index.js.map +1 -0
  1106. package/sdk/dist/runtime-bridge-sync/worker.d.ts +2 -0
  1107. package/sdk/dist/runtime-bridge-sync/worker.d.ts.map +1 -0
  1108. package/sdk/dist/runtime-bridge-sync/worker.js +180 -0
  1109. package/sdk/dist/runtime-bridge-sync/worker.js.map +1 -0
  1110. package/sdk/dist/runtime-gate.d.ts +14 -0
  1111. package/sdk/dist/runtime-gate.d.ts.map +1 -0
  1112. package/sdk/dist/runtime-gate.js +48 -0
  1113. package/sdk/dist/runtime-gate.js.map +1 -0
  1114. package/sdk/dist/sdk-package-compatibility.d.ts +38 -0
  1115. package/sdk/dist/sdk-package-compatibility.d.ts.map +1 -0
  1116. package/sdk/dist/sdk-package-compatibility.js +90 -0
  1117. package/sdk/dist/sdk-package-compatibility.js.map +1 -0
  1118. package/sdk/dist/session-runner.d.ts +40 -0
  1119. package/sdk/dist/session-runner.d.ts.map +1 -0
  1120. package/sdk/dist/session-runner.js +274 -0
  1121. package/sdk/dist/session-runner.js.map +1 -0
  1122. package/sdk/dist/tool-scoping.d.ts +31 -0
  1123. package/sdk/dist/tool-scoping.d.ts.map +1 -0
  1124. package/sdk/dist/tool-scoping.js +54 -0
  1125. package/sdk/dist/tool-scoping.js.map +1 -0
  1126. package/sdk/dist/types.d.ts +794 -0
  1127. package/sdk/dist/types.d.ts.map +1 -0
  1128. package/sdk/dist/types.js +77 -0
  1129. package/sdk/dist/types.js.map +1 -0
  1130. package/sdk/dist/workstream-inventory/builder.d.ts +88 -0
  1131. package/sdk/dist/workstream-inventory/builder.d.ts.map +1 -0
  1132. package/sdk/dist/workstream-inventory/builder.js +84 -0
  1133. package/sdk/dist/workstream-inventory/builder.js.map +1 -0
  1134. package/sdk/dist/workstream-name-policy.d.ts +37 -0
  1135. package/sdk/dist/workstream-name-policy.d.ts.map +1 -0
  1136. package/sdk/dist/workstream-name-policy.js +53 -0
  1137. package/sdk/dist/workstream-name-policy.js.map +1 -0
  1138. package/sdk/dist/workstream-utils.d.ts +23 -0
  1139. package/sdk/dist/workstream-utils.d.ts.map +1 -0
  1140. package/sdk/dist/workstream-utils.js +34 -0
  1141. package/sdk/dist/workstream-utils.js.map +1 -0
  1142. package/sdk/dist/ws-transport.d.ts +32 -0
  1143. package/sdk/dist/ws-transport.d.ts.map +1 -0
  1144. package/sdk/dist/ws-transport.js +84 -0
  1145. package/sdk/dist/ws-transport.js.map +1 -0
  1146. package/sdk/package-lock.json +2530 -0
  1147. package/sdk/package.json +77 -0
  1148. package/sdk/prompts/templates/project.md +186 -0
  1149. package/sdk/prompts/templates/requirements.md +231 -0
  1150. package/sdk/prompts/templates/research-project/ARCHITECTURE.md +204 -0
  1151. package/sdk/prompts/templates/research-project/FEATURES.md +147 -0
  1152. package/sdk/prompts/templates/research-project/PITFALLS.md +200 -0
  1153. package/sdk/prompts/templates/research-project/STACK.md +120 -0
  1154. package/sdk/prompts/templates/research-project/SUMMARY.md +170 -0
  1155. package/sdk/prompts/templates/roadmap.md +202 -0
  1156. package/sdk/prompts/templates/state.md +175 -0
  1157. package/sdk/shared/config-defaults.manifest.json +75 -0
  1158. package/sdk/shared/config-schema.manifest.json +151 -0
  1159. package/sdk/shared/model-catalog.json +122 -0
  1160. package/sdk/src/assembled-prompts.test.ts +349 -0
  1161. package/sdk/src/bug-3589-planning-paths-validation.test.ts +89 -0
  1162. package/sdk/src/bug-3591-gsdtools-runtime-workstream.test.ts +179 -0
  1163. package/sdk/src/cli-transport.test.ts +388 -0
  1164. package/sdk/src/cli-transport.ts +130 -0
  1165. package/sdk/src/cli.test.ts +426 -0
  1166. package/sdk/src/cli.ts +589 -0
  1167. package/sdk/src/config.test.ts +277 -0
  1168. package/sdk/src/config.ts +202 -0
  1169. package/sdk/src/configuration/index.test.ts +318 -0
  1170. package/sdk/src/configuration/index.ts +325 -0
  1171. package/sdk/src/context-engine.test.ts +295 -0
  1172. package/sdk/src/context-engine.ts +170 -0
  1173. package/sdk/src/context-truncation.test.ts +163 -0
  1174. package/sdk/src/context-truncation.ts +233 -0
  1175. package/sdk/src/e2e.integration.test.ts +181 -0
  1176. package/sdk/src/errors.ts +72 -0
  1177. package/sdk/src/event-stream.test.ts +661 -0
  1178. package/sdk/src/event-stream.ts +441 -0
  1179. package/sdk/src/golden/capture.ts +95 -0
  1180. package/sdk/src/golden/fixtures/generate-slug.golden.json +1 -0
  1181. package/sdk/src/golden/fixtures/profile-sample-sessions/demo-project/sample.jsonl +3 -0
  1182. package/sdk/src/golden/fixtures/summary-extract-sample.md +26 -0
  1183. package/sdk/src/golden/fixtures/uat-render-checkpoint-sample.md +15 -0
  1184. package/sdk/src/golden/golden-integration-covered.ts +30 -0
  1185. package/sdk/src/golden/golden-mutation-covered.ts +17 -0
  1186. package/sdk/src/golden/golden-policy.test.ts +8 -0
  1187. package/sdk/src/golden/golden-policy.ts +120 -0
  1188. package/sdk/src/golden/golden.integration.test.ts +1031 -0
  1189. package/sdk/src/golden/init-golden-normalize.ts +15 -0
  1190. package/sdk/src/golden/read-only-golden-rows.ts +77 -0
  1191. package/sdk/src/golden/read-only-parity.integration.test.ts +133 -0
  1192. package/sdk/src/golden/registry-canonical-commands.ts +31 -0
  1193. package/sdk/src/gsd-tools-error.test.ts +21 -0
  1194. package/sdk/src/gsd-tools-error.ts +65 -0
  1195. package/sdk/src/gsd-tools.test.ts +472 -0
  1196. package/sdk/src/gsd-tools.ts +237 -0
  1197. package/sdk/src/gsd-transport-policy.test.ts +34 -0
  1198. package/sdk/src/gsd-transport-policy.ts +48 -0
  1199. package/sdk/src/gsd-transport.test.ts +299 -0
  1200. package/sdk/src/gsd-transport.ts +118 -0
  1201. package/sdk/src/index.ts +366 -0
  1202. package/sdk/src/init-e2e.integration.test.ts +138 -0
  1203. package/sdk/src/init-runner.test.ts +740 -0
  1204. package/sdk/src/init-runner.ts +734 -0
  1205. package/sdk/src/lifecycle-e2e.integration.test.ts +258 -0
  1206. package/sdk/src/logger.test.ts +149 -0
  1207. package/sdk/src/logger.ts +113 -0
  1208. package/sdk/src/milestone-runner.test.ts +421 -0
  1209. package/sdk/src/model-catalog.ts +70 -0
  1210. package/sdk/src/phase-prompt.ts +259 -0
  1211. package/sdk/src/phase-runner.integration.test.ts +377 -0
  1212. package/sdk/src/phase-runner.test.ts +3660 -0
  1213. package/sdk/src/phase-runner.ts +1442 -0
  1214. package/sdk/src/plan-parser.test.ts +579 -0
  1215. package/sdk/src/plan-parser.ts +431 -0
  1216. package/sdk/src/planning-journal.test.ts +70 -0
  1217. package/sdk/src/planning-journal.ts +153 -0
  1218. package/sdk/src/planning-runtime.test.ts +29 -0
  1219. package/sdk/src/planning-runtime.ts +100 -0
  1220. package/sdk/src/project-root/index.test.ts +186 -0
  1221. package/sdk/src/project-root/index.ts +144 -0
  1222. package/sdk/src/prompt-builder.test.ts +318 -0
  1223. package/sdk/src/prompt-builder.ts +218 -0
  1224. package/sdk/src/prompt-sanitizer.test.ts +260 -0
  1225. package/sdk/src/prompt-sanitizer.ts +116 -0
  1226. package/sdk/src/query/QUERY-HANDLERS.md +349 -0
  1227. package/sdk/src/query/active-workstream-store.ts +50 -0
  1228. package/sdk/src/query/agent-failure-classifier.test.ts +157 -0
  1229. package/sdk/src/query/agent-failure-classifier.ts +105 -0
  1230. package/sdk/src/query/audit-open.ts +722 -0
  1231. package/sdk/src/query/check-auto-mode.test.ts +77 -0
  1232. package/sdk/src/query/check-auto-mode.ts +49 -0
  1233. package/sdk/src/query/check-completion.test.ts +113 -0
  1234. package/sdk/src/query/check-completion.ts +182 -0
  1235. package/sdk/src/query/check-decision-coverage.test.ts +519 -0
  1236. package/sdk/src/query/check-decision-coverage.ts +554 -0
  1237. package/sdk/src/query/check-gates.test.ts +103 -0
  1238. package/sdk/src/query/check-gates.ts +112 -0
  1239. package/sdk/src/query/check-ship-ready.test.ts +303 -0
  1240. package/sdk/src/query/check-ship-ready.ts +136 -0
  1241. package/sdk/src/query/check-verification-status.test.ts +143 -0
  1242. package/sdk/src/query/check-verification-status.ts +160 -0
  1243. package/sdk/src/query/command-aliases.generated.ts +154 -0
  1244. package/sdk/src/query/command-catalog.ts +31 -0
  1245. package/sdk/src/query/command-definition.test.ts +47 -0
  1246. package/sdk/src/query/command-definition.ts +70 -0
  1247. package/sdk/src/query/command-family-handlers.ts +123 -0
  1248. package/sdk/src/query/command-manifest.init.ts +24 -0
  1249. package/sdk/src/query/command-manifest.non-family.ts +86 -0
  1250. package/sdk/src/query/command-manifest.phase.ts +17 -0
  1251. package/sdk/src/query/command-manifest.phases.ts +11 -0
  1252. package/sdk/src/query/command-manifest.roadmap.ts +11 -0
  1253. package/sdk/src/query/command-manifest.state.ts +31 -0
  1254. package/sdk/src/query/command-manifest.ts +17 -0
  1255. package/sdk/src/query/command-manifest.types.ts +13 -0
  1256. package/sdk/src/query/command-manifest.validate.ts +11 -0
  1257. package/sdk/src/query/command-manifest.verify.ts +17 -0
  1258. package/sdk/src/query/command-resolution.test.ts +70 -0
  1259. package/sdk/src/query/command-seam-coverage.test.ts +118 -0
  1260. package/sdk/src/query/command-static-catalog-domain.ts +111 -0
  1261. package/sdk/src/query/command-static-catalog-foundation.ts +111 -0
  1262. package/sdk/src/query/command-topology.test.ts +28 -0
  1263. package/sdk/src/query/command-topology.ts +114 -0
  1264. package/sdk/src/query/commands-list.test.ts +36 -0
  1265. package/sdk/src/query/commands-list.ts +19 -0
  1266. package/sdk/src/query/commit.test.ts +485 -0
  1267. package/sdk/src/query/commit.ts +717 -0
  1268. package/sdk/src/query/config-gates.test.ts +89 -0
  1269. package/sdk/src/query/config-gates.ts +69 -0
  1270. package/sdk/src/query/config-mutation.test.ts +598 -0
  1271. package/sdk/src/query/config-mutation.ts +705 -0
  1272. package/sdk/src/query/config-query.test.ts +472 -0
  1273. package/sdk/src/query/config-query.ts +314 -0
  1274. package/sdk/src/query/config-schema.ts +35 -0
  1275. package/sdk/src/query/decisions.test.ts +221 -0
  1276. package/sdk/src/query/decisions.ts +196 -0
  1277. package/sdk/src/query/decomposed-handlers.test.ts +431 -0
  1278. package/sdk/src/query/detect-custom-files.test.ts +115 -0
  1279. package/sdk/src/query/detect-custom-files.ts +96 -0
  1280. package/sdk/src/query/detect-phase-type.test.ts +105 -0
  1281. package/sdk/src/query/detect-phase-type.ts +141 -0
  1282. package/sdk/src/query/docs-init.ts +258 -0
  1283. package/sdk/src/query/fallow-audit.ts +88 -0
  1284. package/sdk/src/query/frontmatter-array.test.ts +14 -0
  1285. package/sdk/src/query/frontmatter-mutation.test.ts +259 -0
  1286. package/sdk/src/query/frontmatter-mutation.ts +328 -0
  1287. package/sdk/src/query/frontmatter.test.ts +326 -0
  1288. package/sdk/src/query/frontmatter.ts +395 -0
  1289. package/sdk/src/query/helpers.test.ts +615 -0
  1290. package/sdk/src/query/helpers.ts +566 -0
  1291. package/sdk/src/query/index-thin-seam.test.ts +16 -0
  1292. package/sdk/src/query/index.ts +9 -0
  1293. package/sdk/src/query/init-complex.test.ts +788 -0
  1294. package/sdk/src/query/init-complex.ts +815 -0
  1295. package/sdk/src/query/init-workstream-milestone-op.test.ts +321 -0
  1296. package/sdk/src/query/init.test.ts +791 -0
  1297. package/sdk/src/query/init.ts +1335 -0
  1298. package/sdk/src/query/intel.test.ts +90 -0
  1299. package/sdk/src/query/intel.ts +404 -0
  1300. package/sdk/src/query/mutation-event-decorator.test.ts +45 -0
  1301. package/sdk/src/query/mutation-event-decorator.ts +37 -0
  1302. package/sdk/src/query/mutation-event-mapper.test.ts +33 -0
  1303. package/sdk/src/query/mutation-event-mapper.ts +102 -0
  1304. package/sdk/src/query/mvp.test.ts +335 -0
  1305. package/sdk/src/query/mvp.ts +292 -0
  1306. package/sdk/src/query/normalize-query-command.test.ts +102 -0
  1307. package/sdk/src/query/phase-filesystem-adapter.ts +35 -0
  1308. package/sdk/src/query/phase-lifecycle-policy.ts +171 -0
  1309. package/sdk/src/query/phase-lifecycle.test.ts +1971 -0
  1310. package/sdk/src/query/phase-lifecycle.ts +2210 -0
  1311. package/sdk/src/query/phase-list-queries.test.ts +88 -0
  1312. package/sdk/src/query/phase-list-queries.ts +152 -0
  1313. package/sdk/src/query/phase-ready.test.ts +65 -0
  1314. package/sdk/src/query/phase-ready.ts +159 -0
  1315. package/sdk/src/query/phase-roadmap-mutation.ts +82 -0
  1316. package/sdk/src/query/phase-uat-passed.test.ts +593 -0
  1317. package/sdk/src/query/phase-uat-passed.ts +297 -0
  1318. package/sdk/src/query/phase.test.ts +693 -0
  1319. package/sdk/src/query/phase.ts +741 -0
  1320. package/sdk/src/query/pipeline.test.ts +169 -0
  1321. package/sdk/src/query/pipeline.ts +243 -0
  1322. package/sdk/src/query/plan-scan.test.ts +35 -0
  1323. package/sdk/src/query/plan-scan.ts +82 -0
  1324. package/sdk/src/query/plan-task-structure.test.ts +65 -0
  1325. package/sdk/src/query/plan-task-structure.ts +63 -0
  1326. package/sdk/src/query/policy-convergence.test.ts +28 -0
  1327. package/sdk/src/query/profile-extract-messages.ts +247 -0
  1328. package/sdk/src/query/profile-output.ts +929 -0
  1329. package/sdk/src/query/profile-questionnaire-data.ts +181 -0
  1330. package/sdk/src/query/profile-sample.ts +184 -0
  1331. package/sdk/src/query/profile-scan-sessions.ts +174 -0
  1332. package/sdk/src/query/profile.test.ts +136 -0
  1333. package/sdk/src/query/profile.ts +337 -0
  1334. package/sdk/src/query/progress.test.ts +156 -0
  1335. package/sdk/src/query/progress.ts +566 -0
  1336. package/sdk/src/query/prompt-budget.ts +556 -0
  1337. package/sdk/src/query/query-cli-adapter.test.ts +79 -0
  1338. package/sdk/src/query/query-cli-adapter.ts +39 -0
  1339. package/sdk/src/query/query-cli-output.test.ts +33 -0
  1340. package/sdk/src/query/query-cli-output.ts +35 -0
  1341. package/sdk/src/query/query-command-diagnosis.test.ts +22 -0
  1342. package/sdk/src/query/query-command-diagnosis.ts +5 -0
  1343. package/sdk/src/query/query-command-resolution-strategy.test.ts +34 -0
  1344. package/sdk/src/query/query-command-resolution-strategy.ts +121 -0
  1345. package/sdk/src/query/query-command-semantics.test.ts +22 -0
  1346. package/sdk/src/query/query-command-semantics.ts +22 -0
  1347. package/sdk/src/query/query-dispatch-contract.ts +30 -0
  1348. package/sdk/src/query/query-dispatch-error-mapper.ts +5 -0
  1349. package/sdk/src/query/query-dispatch-formatting.ts +5 -0
  1350. package/sdk/src/query/query-dispatch-observability.ts +6 -0
  1351. package/sdk/src/query/query-dispatch.test.ts +699 -0
  1352. package/sdk/src/query/query-dispatch.ts +243 -0
  1353. package/sdk/src/query/query-error-details-schema.ts +29 -0
  1354. package/sdk/src/query/query-error-taxonomy.test.ts +39 -0
  1355. package/sdk/src/query/query-error-taxonomy.ts +117 -0
  1356. package/sdk/src/query/query-fallback-bridge-adapter.test.ts +32 -0
  1357. package/sdk/src/query/query-fallback-bridge-adapter.ts +54 -0
  1358. package/sdk/src/query/query-fallback-executor.test.ts +82 -0
  1359. package/sdk/src/query/query-fallback-executor.ts +44 -0
  1360. package/sdk/src/query/query-fallback-output-classifier.test.ts +36 -0
  1361. package/sdk/src/query/query-fallback-output-classifier.ts +31 -0
  1362. package/sdk/src/query/query-fallback-policy.test.ts +13 -0
  1363. package/sdk/src/query/query-fallback-policy.ts +11 -0
  1364. package/sdk/src/query/query-native-dispatch-adapter.ts +16 -0
  1365. package/sdk/src/query/query-policy-capability.test.ts +10 -0
  1366. package/sdk/src/query/query-policy-capability.ts +26 -0
  1367. package/sdk/src/query/query-policy-snapshot.test.ts +9 -0
  1368. package/sdk/src/query/query-registry-capability.test.ts +14 -0
  1369. package/sdk/src/query/query-runtime-context.ts +44 -0
  1370. package/sdk/src/query/query-unknown-command-hints.test.ts +9 -0
  1371. package/sdk/src/query/query-unknown-command-hints.ts +5 -0
  1372. package/sdk/src/query/registry-assembly-descriptor.ts +87 -0
  1373. package/sdk/src/query/registry-assembly-invariants.ts +127 -0
  1374. package/sdk/src/query/registry-assembly.test.ts +138 -0
  1375. package/sdk/src/query/registry-assembly.ts +78 -0
  1376. package/sdk/src/query/registry.test.ts +208 -0
  1377. package/sdk/src/query/registry.ts +142 -0
  1378. package/sdk/src/query/requirements-extract-from-plans.test.ts +58 -0
  1379. package/sdk/src/query/requirements-extract-from-plans.ts +86 -0
  1380. package/sdk/src/query/roadmap-update-plan-progress.test.ts +233 -0
  1381. package/sdk/src/query/roadmap-update-plan-progress.ts +159 -0
  1382. package/sdk/src/query/roadmap.test.ts +1250 -0
  1383. package/sdk/src/query/roadmap.ts +1131 -0
  1384. package/sdk/src/query/route-next-action.test.ts +61 -0
  1385. package/sdk/src/query/route-next-action.ts +345 -0
  1386. package/sdk/src/query/schema-detect.ts +189 -0
  1387. package/sdk/src/query/secrets.test.ts +66 -0
  1388. package/sdk/src/query/secrets.ts +43 -0
  1389. package/sdk/src/query/skill-manifest.test.ts +62 -0
  1390. package/sdk/src/query/skill-manifest.ts +216 -0
  1391. package/sdk/src/query/skills.test.ts +234 -0
  1392. package/sdk/src/query/skills.ts +143 -0
  1393. package/sdk/src/query/state-document.test.ts +197 -0
  1394. package/sdk/src/query/state-document.ts +129 -0
  1395. package/sdk/src/query/state-mutation.test.ts +1210 -0
  1396. package/sdk/src/query/state-mutation.ts +1814 -0
  1397. package/sdk/src/query/state-project-load.ts +80 -0
  1398. package/sdk/src/query/state.test.ts +616 -0
  1399. package/sdk/src/query/state.ts +476 -0
  1400. package/sdk/src/query/sub-repos-root.integration.test.ts +79 -0
  1401. package/sdk/src/query/summary.test.ts +95 -0
  1402. package/sdk/src/query/summary.ts +296 -0
  1403. package/sdk/src/query/template.test.ts +180 -0
  1404. package/sdk/src/query/template.ts +242 -0
  1405. package/sdk/src/query/uat.test.ts +77 -0
  1406. package/sdk/src/query/uat.ts +365 -0
  1407. package/sdk/src/query/utils.test.ts +82 -0
  1408. package/sdk/src/query/utils.ts +106 -0
  1409. package/sdk/src/query/validate.test.ts +924 -0
  1410. package/sdk/src/query/validate.ts +1054 -0
  1411. package/sdk/src/query/verify.test.ts +414 -0
  1412. package/sdk/src/query/verify.ts +656 -0
  1413. package/sdk/src/query/websearch.test.ts +31 -0
  1414. package/sdk/src/query/websearch.ts +82 -0
  1415. package/sdk/src/query/workspace.test.ts +120 -0
  1416. package/sdk/src/query/workspace.ts +145 -0
  1417. package/sdk/src/query/workstream-inventory.ts +143 -0
  1418. package/sdk/src/query/workstream.test.ts +153 -0
  1419. package/sdk/src/query/workstream.ts +324 -0
  1420. package/sdk/src/query/worktree.ts +84 -0
  1421. package/sdk/src/query-command-executor.ts +31 -0
  1422. package/sdk/src/query-execution-policy.test.ts +52 -0
  1423. package/sdk/src/query-execution-policy.ts +46 -0
  1424. package/sdk/src/query-failure-classification.test.ts +23 -0
  1425. package/sdk/src/query-failure-classification.ts +42 -0
  1426. package/sdk/src/query-gsd-tools-path.ts +1 -0
  1427. package/sdk/src/query-gsd-tools-runtime.ts +89 -0
  1428. package/sdk/src/query-hotpath-methods.ts +48 -0
  1429. package/sdk/src/query-native-direct-adapter.test.ts +35 -0
  1430. package/sdk/src/query-native-direct-adapter.ts +70 -0
  1431. package/sdk/src/query-native-hotpath-adapter.test.ts +43 -0
  1432. package/sdk/src/query-native-hotpath-adapter.ts +45 -0
  1433. package/sdk/src/query-raw-output-projection.test.ts +39 -0
  1434. package/sdk/src/query-raw-output-projection.ts +93 -0
  1435. package/sdk/src/query-runtime-bridge.test.ts +150 -0
  1436. package/sdk/src/query-runtime-bridge.ts +215 -0
  1437. package/sdk/src/query-runtime-seam-coverage.test.ts +20 -0
  1438. package/sdk/src/query-subprocess-adapter.test.ts +84 -0
  1439. package/sdk/src/query-subprocess-adapter.ts +146 -0
  1440. package/sdk/src/query-tools-error-factory.test.ts +35 -0
  1441. package/sdk/src/query-tools-error-factory.ts +76 -0
  1442. package/sdk/src/research-gate.test.ts +190 -0
  1443. package/sdk/src/research-gate.ts +94 -0
  1444. package/sdk/src/runtime-bridge-options.test.ts +33 -0
  1445. package/sdk/src/runtime-bridge-sync/index.test.ts +164 -0
  1446. package/sdk/src/runtime-bridge-sync/index.ts +154 -0
  1447. package/sdk/src/runtime-bridge-sync/projectdir-regression.test.ts +150 -0
  1448. package/sdk/src/runtime-bridge-sync/worker.ts +224 -0
  1449. package/sdk/src/runtime-gate.test.ts +84 -0
  1450. package/sdk/src/runtime-gate.ts +52 -0
  1451. package/sdk/src/sdk-package-compatibility.test.ts +97 -0
  1452. package/sdk/src/sdk-package-compatibility.ts +141 -0
  1453. package/sdk/src/session-runner.test.ts +164 -0
  1454. package/sdk/src/session-runner.ts +327 -0
  1455. package/sdk/src/tool-scoping.test.ts +160 -0
  1456. package/sdk/src/tool-scoping.ts +61 -0
  1457. package/sdk/src/types.ts +927 -0
  1458. package/sdk/src/workflow-agent-skills-consistency.test.ts +98 -0
  1459. package/sdk/src/workstream-inventory/builder.test.ts +241 -0
  1460. package/sdk/src/workstream-inventory/builder.ts +170 -0
  1461. package/sdk/src/workstream-name-policy.ts +57 -0
  1462. package/sdk/src/workstream-utils.ts +36 -0
  1463. package/sdk/src/ws-flag.test.ts +285 -0
  1464. package/sdk/src/ws-transport.test.ts +161 -0
  1465. package/sdk/src/ws-transport.ts +93 -0
  1466. package/sdk/tsconfig.json +20 -0
@@ -0,0 +1,2210 @@
1
+ /**
2
+ * Phase lifecycle handlers — add, insert, scaffold operations.
3
+ *
4
+ * Ported from get-shit-done/bin/lib/phase.cjs and commands.cjs.
5
+ * Provides phaseAdd (append phase), phaseAddBatch (append multiple phases),
6
+ * phaseInsert (decimal phase insertion), and phaseScaffold (template file/directory creation).
7
+ *
8
+ * Shared helpers replaceInCurrentMilestone and readModifyWriteRoadmapMd
9
+ * are exported for use by downstream handlers (phaseComplete in Plan 03).
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * import { phaseAdd, phaseInsert, phaseScaffold } from './phase-lifecycle.js';
14
+ *
15
+ * await phaseAdd(['New Feature'], '/project');
16
+ * await phaseInsert(['10', 'Urgent Fix'], '/project');
17
+ * await phaseScaffold(['context', '9'], '/project');
18
+ * ```
19
+ */
20
+
21
+ import { readFile, writeFile, mkdir, readdir, rename, rm } from 'node:fs/promises';
22
+ import { existsSync } from 'node:fs';
23
+ import { join, relative } from 'node:path';
24
+ import { GSDError, ErrorClassification } from '../errors.js';
25
+ import {
26
+ escapeRegex,
27
+ normalizeMd,
28
+ normalizePhaseName,
29
+ comparePhaseNum,
30
+ phaseTokenMatches,
31
+ toPosixPath,
32
+ planningPaths,
33
+ } from './helpers.js';
34
+ import { extractFrontmatter } from './frontmatter.js';
35
+ import { extractCurrentMilestone, phaseMarkdownRegexSource } from './roadmap.js';
36
+ import { getMilestonePhaseFilter } from './state.js';
37
+ import { isCanonicalPlanFile, describeNonCanonicalPlans } from './phase.js';
38
+ import {
39
+ acquireStateLock,
40
+ readModifyWriteStateMdFull,
41
+ releaseStateLock,
42
+ stateReplaceField,
43
+ } from './state-mutation.js';
44
+ import { stateExtractField, stateReplaceFieldWithFallback } from './state-document.js';
45
+ import type { QueryHandler } from './utils.js';
46
+ import {
47
+ assertNoNullBytes,
48
+ assertSafePhaseDirName,
49
+ assertSafeProjectCode,
50
+ buildPhaseRoadmapEntry,
51
+ collectDecimalSuffixesFromDirNames,
52
+ collectDecimalSuffixesFromRoadmap,
53
+ computeNextDecimalPhase,
54
+ computeNextSequentialPhaseId,
55
+ computePhaseDirectory,
56
+ extractOneLinerFromBody,
57
+ generatePhaseSlug,
58
+ parseMultiwordArg,
59
+ } from './phase-lifecycle-policy.js';
60
+ import {
61
+ archiveDirectories,
62
+ ensureDirectoryWithGitkeep,
63
+ listDirectories,
64
+ } from './phase-filesystem-adapter.js';
65
+ import {
66
+ readModifyWriteRoadmapMd,
67
+ replaceInCurrentMilestone,
68
+ } from './phase-roadmap-mutation.js';
69
+
70
+ export { readModifyWriteRoadmapMd, replaceInCurrentMilestone };
71
+
72
+ // ─── Milestone-scoped directory helpers (#3816) ───────────────────────────
73
+
74
+ /**
75
+ * Read the current milestone identifier from STATE.md.
76
+ * Returns null on any error (absent, unreadable, or no `milestone:` field).
77
+ */
78
+ async function readCurrentMilestoneFromState(
79
+ projectDir: string,
80
+ workstream?: string,
81
+ ): Promise<string | null> {
82
+ try {
83
+ const statePath = planningPaths(projectDir, workstream).state;
84
+ const content = await readFile(statePath, 'utf-8');
85
+ const m = content.match(/^milestone:\s*(.+)$/m);
86
+ if (!m) return null;
87
+ return m[1].trim().replace(/^["']|["']$/g, '');
88
+ } catch {
89
+ return null;
90
+ }
91
+ }
92
+
93
+ /**
94
+ * Resolve the phases directory for a `phase.add` / `phase.add-batch` write.
95
+ *
96
+ * When the project uses a milestone-scoped layout (`.planning/milestones/
97
+ * <milestone>-phases/` already exists on disk), return that path so newly
98
+ * created phase directories land in the correct location alongside existing
99
+ * phases (#3816 fix for Symptom 3a).
100
+ *
101
+ * Falls back to the flat `.planning/phases/` path for all other projects.
102
+ */
103
+ async function resolveWritePhasesDir(
104
+ projectDir: string,
105
+ workstream?: string,
106
+ ): Promise<string> {
107
+ const flatPhasesDir = planningPaths(projectDir, workstream).phases;
108
+ try {
109
+ const milestone = await readCurrentMilestoneFromState(projectDir, workstream);
110
+ if (!milestone) return flatPhasesDir;
111
+ const milestoneScopedDir = join(projectDir, '.planning', 'milestones', `${milestone}-phases`);
112
+ if (existsSync(milestoneScopedDir)) {
113
+ return milestoneScopedDir;
114
+ }
115
+ } catch { /* fall through to flat layout */ }
116
+ return flatPhasesDir;
117
+ }
118
+
119
+ /**
120
+ * Find the insertion point for a new phase entry in the ROADMAP.md content.
121
+ *
122
+ * #3816 fix for Symptom 3b: the previous implementation used
123
+ * `lastIndexOf('\n---')` which would place a new phase AFTER the Backlog
124
+ * section when Backlog precedes the trailing `---`. The new implementation
125
+ * inserts at the end of the active milestone section (just before the next
126
+ * `## Backlog` / `## Planned` / etc. heading, or before the trailing `---`).
127
+ *
128
+ * Returns the index at which the new phase entry should be inserted.
129
+ */
130
+ function findPhaseInsertionPoint(rawContent: string): number {
131
+ // Look for the next top-level (## or ###) section that marks the end of the
132
+ // active phases list: Backlog, Planned milestones, or similar.
133
+ // Matches lines starting with ## or ### that are NOT the trailing `---`.
134
+ // We insert BEFORE this heading.
135
+ const backlogBoundaryRe = /\n(#{2,3}\s+(?:Backlog|Planned|Shipped|Archived)\b[^\n]*)/i;
136
+ const boundaryMatch = rawContent.match(backlogBoundaryRe);
137
+ if (boundaryMatch && boundaryMatch.index !== undefined) {
138
+ return boundaryMatch.index;
139
+ }
140
+
141
+ // Fallback: insert before the last `\n---` separator (original behaviour for
142
+ // ROADMAPs without a Backlog section).
143
+ const lastSeparator = rawContent.lastIndexOf('\n---');
144
+ if (lastSeparator > 0) return lastSeparator;
145
+
146
+ return rawContent.length;
147
+ }
148
+
149
+ // ─── phaseAdd handler ───────────────────────────────────────────────────
150
+
151
+ /**
152
+ * Query handler for phase.add.
153
+ *
154
+ * Port of cmdPhaseAdd from phase.cjs lines 312-392.
155
+ * Creates a new phase directory with .gitkeep, appends a phase section
156
+ * to ROADMAP.md before the last "---" separator.
157
+ *
158
+ * @param args - description (required), optional customId, optional --dry-run flag.
159
+ * Recognized flags: --dry-run (compute result without writing to disk).
160
+ * Any other --flag argument is rejected with a validation error.
161
+ * @param projectDir - Project root directory
162
+ * @returns QueryResult with { phase_number, padded, name, slug, directory, naming_mode }
163
+ * In --dry-run mode also includes { dry_run: true, roadmap_entry: string }
164
+ */
165
+ export const phaseAdd: QueryHandler = async (args, projectDir, workstream) => {
166
+ // ── Flag parsing ────────────────────────────────────────────────────────
167
+ // Mirrors the CJS phase add router (phase-command-router.cjs): recognise
168
+ // --dry-run and --id <value>; reject every other --flag; ignore --raw so it
169
+ // never leaks into the description; join the remaining positional tokens
170
+ // with a single space so multi-word descriptions like `phase add User
171
+ // Dashboard` produce description "User Dashboard". customId comes from the
172
+ // --id flag, never from positional[1].
173
+ let dryRun = false;
174
+ let customIdArg: string | null = null;
175
+ const positional: string[] = [];
176
+
177
+ for (let i = 0; i < args.length; i++) {
178
+ const arg = args[i]!;
179
+ if (arg === '--raw') {
180
+ // CJS router strips --raw before invoking the handler; preserve parity
181
+ // so a stray --raw never poisons the description.
182
+ continue;
183
+ }
184
+ if (arg === '--dry-run') {
185
+ dryRun = true;
186
+ continue;
187
+ }
188
+ if (arg === '--id') {
189
+ const id = args[i + 1];
190
+ if (!id || id.startsWith('--')) {
191
+ throw new GSDError('--id requires a value', ErrorClassification.Validation);
192
+ }
193
+ customIdArg = id;
194
+ i++;
195
+ continue;
196
+ }
197
+ if (arg.startsWith('--')) {
198
+ throw new GSDError(`phase add does not support ${arg}`, ErrorClassification.Validation);
199
+ }
200
+ positional.push(arg);
201
+ }
202
+
203
+ const description = positional.join(' ').trim();
204
+ if (!description) {
205
+ throw new GSDError('description required for phase add', ErrorClassification.Validation);
206
+ }
207
+ assertNoNullBytes(description, 'description');
208
+
209
+ const configPath = planningPaths(projectDir, workstream).config;
210
+ let config: Record<string, unknown> = {};
211
+ try {
212
+ config = JSON.parse(await readFile(configPath, 'utf-8'));
213
+ } catch { /* use defaults */ }
214
+
215
+ const slug = generatePhaseSlug(description);
216
+ // customId always comes from the --id flag; positional tokens are reserved
217
+ // for the description (which is joined above).
218
+ const customId = customIdArg;
219
+
220
+ // Optional project code prefix (e.g., 'CK' -> 'CK-01-foundation')
221
+ const projectCode = (config.project_code as string) || '';
222
+ assertSafeProjectCode(projectCode);
223
+ const prefix = projectCode ? `${projectCode}-` : '';
224
+
225
+ // ── Helper: compute newPhaseId / dirName / computedPhaseEntry from raw ROADMAP content ──
226
+ // Extracted as a local async function so it can be called both inside the
227
+ // roadmap lock (non-dry-run) and outside (dry-run, where no write occurs and
228
+ // there is no race condition to guard against).
229
+ const computePhaseFields = async (rawRoadmapContent: string) => {
230
+ const milestoneContent = await extractCurrentMilestone(rawRoadmapContent, projectDir);
231
+ // #3816: use milestone-scoped directory if it exists, otherwise flat layout
232
+ const phasesDir = await resolveWritePhasesDir(projectDir, workstream);
233
+ const dirNames = await listDirectories(phasesDir);
234
+
235
+ const nextSequentialPhaseId = computeNextSequentialPhaseId(milestoneContent, dirNames);
236
+ const { phaseId: resolvedPhaseId, dirName: resolvedDirName } = computePhaseDirectory(
237
+ config.phase_naming,
238
+ slug,
239
+ prefix,
240
+ nextSequentialPhaseId,
241
+ customId || undefined,
242
+ );
243
+
244
+ if (!resolvedDirName) {
245
+ throw new GSDError('Phase directory name was not computed', ErrorClassification.Execution);
246
+ }
247
+ if (resolvedPhaseId === '') {
248
+ throw new GSDError('Phase ID was not computed', ErrorClassification.Execution);
249
+ }
250
+
251
+ const resolvedEntry = buildPhaseRoadmapEntry(resolvedPhaseId, description, config.phase_naming);
252
+
253
+ return { resolvedPhaseId, resolvedDirName, resolvedEntry };
254
+ };
255
+
256
+ let newPhaseId: number | string = '';
257
+ let dirName = '';
258
+ let computedPhaseEntry = '';
259
+
260
+ if (dryRun) {
261
+ // Dry-run: no write, no race condition — compute outside the lock.
262
+ const roadmapPath = planningPaths(projectDir, workstream).roadmap;
263
+ let rawRoadmapContent = '';
264
+ try {
265
+ rawRoadmapContent = await readFile(roadmapPath, 'utf-8');
266
+ } catch { /* ROADMAP.md may not exist yet */ }
267
+
268
+ const { resolvedPhaseId, resolvedDirName, resolvedEntry } = await computePhaseFields(rawRoadmapContent);
269
+ newPhaseId = resolvedPhaseId;
270
+ dirName = resolvedDirName;
271
+ computedPhaseEntry = resolvedEntry;
272
+ } else {
273
+ // Real write path: hold the roadmap lock across the entire read → compute → write
274
+ // cycle so that two concurrent phase.add calls cannot both observe the same
275
+ // maxPhase and produce duplicate phase IDs.
276
+ await readModifyWriteRoadmapMd(projectDir, async (roadmapRaw) => {
277
+ const { resolvedPhaseId, resolvedDirName, resolvedEntry } = await computePhaseFields(roadmapRaw);
278
+ newPhaseId = resolvedPhaseId;
279
+ dirName = resolvedDirName;
280
+ computedPhaseEntry = resolvedEntry;
281
+
282
+ // #3816: resolve to milestone-scoped dir if it exists
283
+ const phasesWriteDir = await resolveWritePhasesDir(projectDir, workstream);
284
+ const dirPath = join(phasesWriteDir, dirName);
285
+
286
+ // Create directory with .gitkeep so git tracks empty folders
287
+ await ensureDirectoryWithGitkeep(dirPath);
288
+
289
+ // #3816: insert before Backlog/Planned boundary, not after last `---`
290
+ const insertIdx = findPhaseInsertionPoint(roadmapRaw);
291
+ return roadmapRaw.slice(0, insertIdx) + computedPhaseEntry + roadmapRaw.slice(insertIdx);
292
+ }, workstream);
293
+ }
294
+
295
+ const result: Record<string, unknown> = {
296
+ phase_number: typeof newPhaseId === 'number' ? newPhaseId : String(newPhaseId),
297
+ padded: typeof newPhaseId === 'number' ? String(newPhaseId).padStart(2, '0') : String(newPhaseId),
298
+ name: description,
299
+ slug,
300
+ // #3816: result.directory must reflect the actual write location
301
+ directory: toPosixPath(relative(projectDir, join(await resolveWritePhasesDir(projectDir, workstream), dirName))),
302
+ naming_mode: config.phase_naming || 'sequential',
303
+ };
304
+
305
+ if (dryRun) {
306
+ result.dry_run = true;
307
+ result.roadmap_entry = computedPhaseEntry;
308
+ }
309
+
310
+ return { data: result };
311
+ };
312
+
313
+ // ─── phaseAddBatch handler ────────────────────────────────────────────────
314
+
315
+ /**
316
+ * Query handler for phase.add-batch.
317
+ *
318
+ * Port of cmdPhaseAddBatch from phase.cjs lines 411-478.
319
+ * Appends multiple phases in one locked ROADMAP pass (sequential or custom naming).
320
+ *
321
+ * @param args - Either `--descriptions` followed by a JSON array string, or one description per arg (`--raw` ignored)
322
+ */
323
+ export const phaseAddBatch: QueryHandler = async (args, projectDir, workstream) => {
324
+ let descriptions: string[];
325
+ const descIdx = args.indexOf('--descriptions');
326
+ if (descIdx !== -1) {
327
+ // CJS router parity (phase-command-router.cjs): a dangling --descriptions
328
+ // or one whose value is another flag must surface the same JSON-array error
329
+ // string, not silently fall through to positional parsing or throw a
330
+ // different "valid JSON" variant.
331
+ const rawValue = args[descIdx + 1];
332
+ if (rawValue === undefined || rawValue.startsWith('--')) {
333
+ throw new GSDError('--descriptions must be a JSON array', ErrorClassification.Validation);
334
+ }
335
+ let parsed: unknown;
336
+ try {
337
+ parsed = JSON.parse(rawValue);
338
+ } catch {
339
+ throw new GSDError('--descriptions must be a JSON array', ErrorClassification.Validation);
340
+ }
341
+ if (!Array.isArray(parsed)) {
342
+ throw new GSDError('--descriptions must be a JSON array', ErrorClassification.Validation);
343
+ }
344
+ descriptions = parsed.map((x) => String(x));
345
+ } else {
346
+ descriptions = args.filter((a) => a !== '--raw');
347
+ }
348
+
349
+ if (descriptions.length === 0) {
350
+ throw new GSDError('descriptions array required for phase add-batch', ErrorClassification.Validation);
351
+ }
352
+
353
+ for (const d of descriptions) {
354
+ assertNoNullBytes(d, 'description');
355
+ if (!d.trim()) {
356
+ throw new GSDError('description must be non-empty', ErrorClassification.Validation);
357
+ }
358
+ }
359
+
360
+ const roadmapPath = planningPaths(projectDir, workstream).roadmap;
361
+ if (!existsSync(roadmapPath)) {
362
+ throw new GSDError('ROADMAP.md not found', ErrorClassification.Validation);
363
+ }
364
+
365
+ let config: Record<string, unknown> = {};
366
+ try {
367
+ config = JSON.parse(await readFile(planningPaths(projectDir, workstream).config, 'utf-8'));
368
+ } catch { /* use defaults */ }
369
+
370
+ const projectCode = (config.project_code as string) || '';
371
+ assertSafeProjectCode(projectCode);
372
+ const prefix = projectCode ? `${projectCode}-` : '';
373
+
374
+ const added: Array<{
375
+ phase_number: string | number;
376
+ padded: string;
377
+ name: string;
378
+ slug: string;
379
+ directory: string;
380
+ naming_mode: unknown;
381
+ }> = [];
382
+
383
+ await readModifyWriteRoadmapMd(projectDir, async (initialContent) => {
384
+ let rawContent = initialContent;
385
+ const content = await extractCurrentMilestone(rawContent, projectDir);
386
+ let maxPhase = 0;
387
+
388
+ // #3816: resolve to milestone-scoped dir if it exists for the whole batch
389
+ const phasesWriteDir = await resolveWritePhasesDir(projectDir, workstream);
390
+
391
+ if (config.phase_naming !== 'custom') {
392
+ const dirNames = await listDirectories(phasesWriteDir);
393
+ maxPhase = computeNextSequentialPhaseId(content, dirNames) - 1;
394
+ }
395
+
396
+ for (const description of descriptions) {
397
+ const slug = generatePhaseSlug(description);
398
+ let newPhaseId: number | string;
399
+ let dirName: string;
400
+
401
+ if (config.phase_naming === 'custom') {
402
+ // Match CJS cmdPhaseAddBatch: slug.toUpperCase().replace(/-/g, '-') (identity on hyphens)
403
+ newPhaseId = slug.toUpperCase();
404
+ dirName = `${prefix}${newPhaseId}-${slug}`;
405
+ } else {
406
+ maxPhase += 1;
407
+ newPhaseId = maxPhase;
408
+ dirName = `${prefix}${String(newPhaseId).padStart(2, '0')}-${slug}`;
409
+ }
410
+
411
+ assertSafePhaseDirName(dirName);
412
+ // #3816: use resolved milestone-scoped dir for directory creation
413
+ const dirPath = join(phasesWriteDir, dirName);
414
+ await ensureDirectoryWithGitkeep(dirPath);
415
+
416
+ const phaseEntry =
417
+ buildPhaseRoadmapEntry(newPhaseId, description, config.phase_naming);
418
+
419
+ // #3816: insert before Backlog/Planned boundary, not after last `---`
420
+ const insertIdx = findPhaseInsertionPoint(rawContent);
421
+ rawContent = rawContent.slice(0, insertIdx) + phaseEntry + rawContent.slice(insertIdx);
422
+
423
+ added.push({
424
+ phase_number: typeof newPhaseId === 'number' ? newPhaseId : String(newPhaseId),
425
+ padded: typeof newPhaseId === 'number' ? String(newPhaseId).padStart(2, '0') : String(newPhaseId),
426
+ name: description,
427
+ slug,
428
+ // #3816: result.directory reflects the actual write location
429
+ directory: toPosixPath(relative(projectDir, join(phasesWriteDir, dirName))),
430
+ naming_mode: config.phase_naming || 'sequential',
431
+ });
432
+ }
433
+
434
+ return rawContent;
435
+ }, workstream);
436
+
437
+ return { data: { phases: added, count: added.length } };
438
+ };
439
+
440
+ // ─── phaseInsert handler ────────────────────────────────────────────────
441
+
442
+ /**
443
+ * Query handler for phase.insert.
444
+ *
445
+ * Port of cmdPhaseInsert from phase.cjs lines 394-492.
446
+ * Creates a decimal phase directory after a target phase, inserting
447
+ * the phase section in ROADMAP.md after the target.
448
+ *
449
+ * @param args - args[0]: afterPhase (required), args[1]: description (required)
450
+ * @param projectDir - Project root directory
451
+ * @returns QueryResult with { phase_number, after_phase, name, slug, directory }
452
+ */
453
+ export const phaseInsert: QueryHandler = async (args, projectDir, workstream) => {
454
+ // CJS router parity (phase-command-router.cjs): explicitly reject
455
+ // --dry-run (insert is destructive on disk + roadmap and has no preview
456
+ // path), strip --raw, and join all positional args after `afterPhase` into
457
+ // a single space-delimited description so `phase insert 1 Fix Critical Bug`
458
+ // produces description "Fix Critical Bug" instead of just "Fix".
459
+ const positional: string[] = [];
460
+ for (const arg of args) {
461
+ if (arg === '--dry-run') {
462
+ throw new GSDError('phase insert does not support --dry-run', ErrorClassification.Validation);
463
+ }
464
+ if (arg === '--raw') continue;
465
+ if (arg.startsWith('--')) {
466
+ throw new GSDError(`phase insert does not support ${arg}`, ErrorClassification.Validation);
467
+ }
468
+ positional.push(arg);
469
+ }
470
+
471
+ const afterPhase = positional[0];
472
+ const description = positional.slice(1).join(' ').trim();
473
+
474
+ if (!afterPhase || !description) {
475
+ throw new GSDError('after-phase and description required for phase insert', ErrorClassification.Validation);
476
+ }
477
+ assertNoNullBytes(afterPhase, 'afterPhase');
478
+ assertNoNullBytes(description, 'description');
479
+
480
+ const slug = generatePhaseSlug(description);
481
+ let decimalPhase = '';
482
+ let dirName = '';
483
+
484
+ await readModifyWriteRoadmapMd(projectDir, async (rawContent) => {
485
+ const content = await extractCurrentMilestone(rawContent, projectDir);
486
+
487
+ // Normalize input then strip leading zeros for flexible matching
488
+ const normalizedAfter = normalizePhaseName(afterPhase);
489
+ const unpadded = normalizedAfter.replace(/^0+/, '');
490
+ const afterPhaseEscaped = unpadded.replace(/\./g, '\\.');
491
+ const targetPattern = new RegExp(`#{2,4}\\s*Phase\\s+0*${afterPhaseEscaped}:`, 'i');
492
+ const headingMatch = targetPattern.test(content);
493
+
494
+ // #3815: also recognise the checked-bullet phase format used by projects
495
+ // that list phases as `- [ ] **Phase N: name**` or `- [ ] Phase N: name`
496
+ // (both bold and plain variants). This mirrors the patterns already used
497
+ // by phaseRemove / phaseComplete so insert is consistent with its siblings.
498
+ //
499
+ // Bullet-style is only used when there are NO heading-style phases at all in
500
+ // the milestone content. If the ROADMAP mixes headings + bullets (hybrid
501
+ // format), a bullet-only match means the detail section is missing — that
502
+ // is the #3098 case and must continue to produce the "missing a detail
503
+ // section" error. Only a purely bullet-style ROADMAP (zero heading-style
504
+ // phase entries in the milestone) goes through the bullet insert path.
505
+ const bulletPattern = new RegExp(
506
+ `-\\s*\\[[ x]\\]\\s*(?:\\*\\*)?Phase\\s+0*${afterPhaseEscaped}[:\\s]`,
507
+ 'i',
508
+ );
509
+ const anyHeadingPattern = /#{2,4}\s*Phase\s+\d/i;
510
+ const roadmapHasHeadingPhases = anyHeadingPattern.test(content);
511
+ const isBulletStyle = !headingMatch && bulletPattern.test(content) && !roadmapHasHeadingPhases;
512
+
513
+ if (!headingMatch && !isBulletStyle) {
514
+ // Bug #3098 parity: when the ROADMAP uses heading-style phases and only
515
+ // the summary checklist exists for this phase (no `### Phase N:` detail
516
+ // section), point the user at the missing detail section rather than
517
+ // implying the phase is absent.
518
+ const checklistPattern = new RegExp(
519
+ `-\\s*\\[[ x]\\]\\s*(?:\\*\\*)?Phase\\s+0*${afterPhaseEscaped}[:\\s]`,
520
+ 'i',
521
+ );
522
+ if (checklistPattern.test(content)) {
523
+ throw new GSDError(
524
+ `Phase ${afterPhase} exists in roadmap summary but is missing a detail section (### Phase ${afterPhase}: ...).`,
525
+ ErrorClassification.Validation,
526
+ );
527
+ }
528
+ throw new GSDError(`Phase ${afterPhase} not found in ROADMAP.md`, ErrorClassification.Validation);
529
+ }
530
+
531
+ // Calculate next decimal by scanning both directories AND ROADMAP.md entries
532
+ const phasesDir = planningPaths(projectDir, workstream).phases;
533
+ const normalizedBase = normalizePhaseName(afterPhase);
534
+ const decimalSet = new Set<number>();
535
+
536
+ try {
537
+ const dirs = await listDirectories(phasesDir);
538
+ for (const suffix of collectDecimalSuffixesFromDirNames(normalizedBase, dirs)) {
539
+ decimalSet.add(suffix);
540
+ }
541
+ } catch { /* intentionally empty */ }
542
+
543
+ // Also scan ROADMAP.md content for decimal entries
544
+ for (const suffix of collectDecimalSuffixesFromRoadmap(normalizedBase, rawContent)) {
545
+ decimalSet.add(suffix);
546
+ }
547
+ decimalPhase = computeNextDecimalPhase(normalizedBase, decimalSet).next;
548
+
549
+ // Optional project code prefix
550
+ let insertConfig: Record<string, unknown> = {};
551
+ try {
552
+ insertConfig = JSON.parse(await readFile(planningPaths(projectDir, workstream).config, 'utf-8'));
553
+ } catch { /* use defaults */ }
554
+ const projectCode = (insertConfig.project_code as string) || '';
555
+ assertSafeProjectCode(projectCode);
556
+ const pfx = projectCode ? `${projectCode}-` : '';
557
+ dirName = `${pfx}${decimalPhase}-${slug}`;
558
+ assertSafePhaseDirName(dirName);
559
+ const dirPath = join(phasesDir, dirName);
560
+
561
+ // Create directory with .gitkeep
562
+ await ensureDirectoryWithGitkeep(dirPath);
563
+
564
+ if (isBulletStyle) {
565
+ // #3815: Insert in checked-bullet format, mirroring the style of the
566
+ // surrounding entries. Detect whether the matched bullet uses bold
567
+ // (`**Phase N: …**`) to preserve file-internal format consistency.
568
+ const boldBulletPattern = new RegExp(
569
+ `-\\s*\\[[ x]\\]\\s*\\*\\*Phase\\s+0*${afterPhaseEscaped}:`,
570
+ 'i',
571
+ );
572
+ const useBold = boldBulletPattern.test(content);
573
+ const phaseLabel = useBold
574
+ ? `**Phase ${decimalPhase}: ${description}**`
575
+ : `Phase ${decimalPhase}: ${description}`;
576
+ const bulletEntry = `\n- [ ] ${phaseLabel}`;
577
+
578
+ // Locate the target bullet line in the raw content
579
+ const targetBulletPattern = new RegExp(
580
+ `(-\\s*\\[[ x]\\]\\s*(?:\\*\\*)?Phase\\s+0*${afterPhaseEscaped}[:\\s][^\\n]*)`,
581
+ 'i',
582
+ );
583
+ const bulletMatchResult = rawContent.match(targetBulletPattern);
584
+ if (!bulletMatchResult) {
585
+ throw new GSDError(`Could not find Phase ${afterPhase} bullet line`, ErrorClassification.Execution);
586
+ }
587
+
588
+ const bulletLineEnd = rawContent.indexOf(bulletMatchResult[0]) + bulletMatchResult[0].length;
589
+ // Find where the next phase bullet starts (or use end of content)
590
+ const afterBullet = rawContent.slice(bulletLineEnd);
591
+ const nextBulletMatch = afterBullet.match(/\n-\s*\[[ x]\]\s*(?:\*\*)?Phase\s+\d/i);
592
+
593
+ let insertIdx: number;
594
+ if (nextBulletMatch && nextBulletMatch.index !== undefined) {
595
+ insertIdx = bulletLineEnd + nextBulletMatch.index;
596
+ } else {
597
+ insertIdx = bulletLineEnd;
598
+ }
599
+
600
+ return rawContent.slice(0, insertIdx) + bulletEntry + rawContent.slice(insertIdx);
601
+ }
602
+
603
+ // Heading-style insert (original path)
604
+ // Build phase entry
605
+ const phaseEntry = `\n### Phase ${decimalPhase}: ${description} (INSERTED)\n\n**Goal:** [Urgent work - to be planned]\n**Requirements**: TBD\n**Depends on:** Phase ${afterPhase}\n**Plans:** 0 plans\n\nPlans:\n- [ ] TBD (run /gsd-plan-phase ${decimalPhase} to break down)\n`;
606
+
607
+ // Insert after the target phase section
608
+ const headerPattern = new RegExp(`(#{2,4}\\s*Phase\\s+0*${afterPhaseEscaped}:[^\\n]*\\n)`, 'i');
609
+ const headerMatch = rawContent.match(headerPattern);
610
+ if (!headerMatch) {
611
+ throw new GSDError(`Could not find Phase ${afterPhase} header`, ErrorClassification.Execution);
612
+ }
613
+
614
+ const headerIdx = rawContent.indexOf(headerMatch[0]);
615
+ const afterHeader = rawContent.slice(headerIdx + headerMatch[0].length);
616
+ const nextPhaseMatch = afterHeader.match(/\n#{2,4}\s+Phase\s+\d/i);
617
+
618
+ let insertIdx: number;
619
+ if (nextPhaseMatch && nextPhaseMatch.index !== undefined) {
620
+ insertIdx = headerIdx + headerMatch[0].length + nextPhaseMatch.index;
621
+ } else {
622
+ insertIdx = rawContent.length;
623
+ }
624
+
625
+ return rawContent.slice(0, insertIdx) + phaseEntry + rawContent.slice(insertIdx);
626
+ }, workstream);
627
+
628
+ if (!decimalPhase) {
629
+ throw new GSDError('Decimal phase was not computed', ErrorClassification.Execution);
630
+ }
631
+ if (!dirName) {
632
+ throw new GSDError('Phase directory name was not computed', ErrorClassification.Execution);
633
+ }
634
+
635
+ const result = {
636
+ phase_number: decimalPhase,
637
+ after_phase: afterPhase,
638
+ name: description,
639
+ slug,
640
+ directory: toPosixPath(relative(projectDir, join(planningPaths(projectDir, workstream).phases, dirName))),
641
+ };
642
+
643
+ return { data: result };
644
+ };
645
+
646
+ // ─── phaseScaffold handler ──────────────────────────────────────────────
647
+
648
+ /**
649
+ * Internal helper: find phase directory matching a phase identifier.
650
+ *
651
+ * Reuses the same logic as findPhase handler but returns just the directory info.
652
+ */
653
+ async function findPhaseDir(
654
+ projectDir: string,
655
+ phase: string,
656
+ workstream?: string,
657
+ ): Promise<{ dirPath: string; dirName: string; phaseName: string | null } | null> {
658
+ const phasesDir = planningPaths(projectDir, workstream).phases;
659
+ const normalized = normalizePhaseName(phase);
660
+ const dirs = await listDirectories(phasesDir);
661
+ const match = dirs.find((d) => phaseTokenMatches(d, normalized));
662
+ if (!match) return null;
663
+
664
+ // Extract phase name from directory
665
+ const dirMatch = match.match(/^(?:[A-Z]{1,6}-)?\d+[A-Z]?(?:\.\d+)*-(.+)/i);
666
+ const phaseName = dirMatch ? dirMatch[1] : null;
667
+
668
+ return {
669
+ dirPath: join(phasesDir, match),
670
+ dirName: match,
671
+ phaseName,
672
+ };
673
+ }
674
+
675
+ /**
676
+ * Query handler for phase.scaffold.
677
+ *
678
+ * Port of cmdScaffold from commands.cjs lines 750-806.
679
+ * Creates template files (context, uat, verification) or phase directories.
680
+ *
681
+ * @param args - Positional `[type, phase, name?]` **or** gsd-tools style
682
+ * `[type, '--phase', N, '--name', title]` (name may be multiple words).
683
+ * @param projectDir - Project root directory
684
+ * @returns QueryResult with { created, path } or { created: false, reason: 'already_exists' }
685
+ */
686
+ function normalizeScaffoldArgs(args: string[]): string[] {
687
+ const type = args[0];
688
+ if (!type || !args.includes('--phase')) {
689
+ return args;
690
+ }
691
+ const phaseIdx = args.indexOf('--phase');
692
+ const phase = phaseIdx !== -1 && args[phaseIdx + 1] && !args[phaseIdx + 1].startsWith('--')
693
+ ? args[phaseIdx + 1]
694
+ : '';
695
+ const nameIdx = args.indexOf('--name');
696
+ let name: string | undefined;
697
+ if (nameIdx !== -1) {
698
+ const tail = args.slice(nameIdx + 1);
699
+ const stop = tail.findIndex(a => a.startsWith('--'));
700
+ const parts = stop === -1 ? tail : tail.slice(0, stop);
701
+ name = parts.join(' ').trim() || undefined;
702
+ }
703
+ return [type, phase, ...(name !== undefined && name !== '' ? [name] : [])];
704
+ }
705
+
706
+ export const phaseScaffold: QueryHandler = async (args, projectDir, workstream) => {
707
+ const normalized = normalizeScaffoldArgs(args);
708
+ const type = normalized[0];
709
+ const phase = normalized[1];
710
+ const name = normalized[2] || undefined;
711
+
712
+ if (!type) {
713
+ throw new GSDError('type required for scaffold', ErrorClassification.Validation);
714
+ }
715
+
716
+ const validTypes = new Set(['context', 'uat', 'verification', 'phase-dir']);
717
+ if (!validTypes.has(type)) {
718
+ throw new GSDError(
719
+ `Unknown scaffold type: ${type}. Available: context, uat, verification, phase-dir`,
720
+ ErrorClassification.Validation,
721
+ );
722
+ }
723
+
724
+ if (phase) {
725
+ assertNoNullBytes(phase, 'phase');
726
+ }
727
+ if (name) {
728
+ assertNoNullBytes(name, 'name');
729
+ }
730
+
731
+ const padded = phase ? normalizePhaseName(phase) : '00';
732
+ const today = new Date().toISOString().split('T')[0];
733
+
734
+ // Handle phase-dir type separately
735
+ if (type === 'phase-dir') {
736
+ if (!phase || !name) {
737
+ throw new GSDError('phase and name required for phase-dir scaffold', ErrorClassification.Validation);
738
+ }
739
+ const slug = generatePhaseSlug(name);
740
+ // #3287: apply project_code prefix to stay consistent with phase.add/phase.insert
741
+ let scaffoldConfig: Record<string, unknown> = {};
742
+ try {
743
+ scaffoldConfig = JSON.parse(await readFile(planningPaths(projectDir, workstream).config, 'utf-8'));
744
+ } catch { /* use defaults */ }
745
+ const scaffoldProjectCode = (scaffoldConfig.project_code as string) || '';
746
+ assertSafeProjectCode(scaffoldProjectCode);
747
+ const scaffoldPrefix = scaffoldProjectCode ? `${scaffoldProjectCode}-` : '';
748
+ const dirNameNew = `${scaffoldPrefix}${padded}-${slug}`;
749
+ assertSafePhaseDirName(dirNameNew, 'scaffold phase directory');
750
+ const phasesParent = planningPaths(projectDir, workstream).phases;
751
+ await mkdir(phasesParent, { recursive: true });
752
+ const dirPath = join(phasesParent, dirNameNew);
753
+ await ensureDirectoryWithGitkeep(dirPath);
754
+ return {
755
+ data: {
756
+ created: true,
757
+ directory: toPosixPath(relative(projectDir, dirPath)),
758
+ path: dirPath,
759
+ },
760
+ };
761
+ }
762
+
763
+ // For context/uat/verification types, find the phase directory
764
+ const phaseInfo = phase ? await findPhaseDir(projectDir, phase, workstream) : null;
765
+ if (phase && !phaseInfo) {
766
+ throw new GSDError(`Phase ${phase} directory not found`, ErrorClassification.Blocked);
767
+ }
768
+
769
+ const phaseDir = phaseInfo!.dirPath;
770
+ const phaseName = name || phaseInfo?.phaseName || 'Unnamed';
771
+
772
+ let filePath: string;
773
+ let content: string;
774
+
775
+ switch (type) {
776
+ case 'context': {
777
+ filePath = join(phaseDir, `${padded}-CONTEXT.md`);
778
+ content = `---\nphase: "${padded}"\nname: "${phaseName}"\ncreated: ${today}\n---\n\n# Phase ${phase}: ${phaseName} — Context\n\n## Decisions\n\n_Decisions will be captured during /gsd-discuss-phase ${phase}_\n\n## Discretion Areas\n\n_Areas where the executor can use judgment_\n\n## Deferred Ideas\n\n_Ideas to consider later_\n`;
779
+ break;
780
+ }
781
+ case 'uat': {
782
+ filePath = join(phaseDir, `${padded}-UAT.md`);
783
+ content = `---\nphase: "${padded}"\nname: "${phaseName}"\ncreated: ${today}\nstatus: pending\n---\n\n# Phase ${phase}: ${phaseName} — User Acceptance Testing\n\n## Test Results\n\n| # | Test | Status | Notes |\n|---|------|--------|-------|\n\n## Summary\n\n_Pending UAT_\n`;
784
+ break;
785
+ }
786
+ case 'verification': {
787
+ filePath = join(phaseDir, `${padded}-VERIFICATION.md`);
788
+ content = `---\nphase: "${padded}"\nname: "${phaseName}"\ncreated: ${today}\nstatus: pending\n---\n\n# Phase ${phase}: ${phaseName} — Verification\n\n## Goal-Backward Verification\n\n**Phase Goal:** [From ROADMAP.md]\n\n## Checks\n\n| # | Requirement | Status | Evidence |\n|---|------------|--------|----------|\n\n## Result\n\n_Pending verification_\n`;
789
+ break;
790
+ }
791
+ default:
792
+ throw new GSDError(`Unknown scaffold type: ${type}`, ErrorClassification.Validation);
793
+ }
794
+
795
+ // Check if file already exists
796
+ if (existsSync(filePath)) {
797
+ return {
798
+ data: {
799
+ created: false,
800
+ reason: 'already_exists',
801
+ path: filePath,
802
+ },
803
+ };
804
+ }
805
+
806
+ await writeFile(filePath, content, 'utf-8');
807
+ const relPath = toPosixPath(relative(projectDir, filePath));
808
+ return { data: { created: true, path: relPath } };
809
+ };
810
+
811
+ // ─── renameDecimalPhases ───────────────────────────────────────────────
812
+
813
+ /**
814
+ * Renumber sibling decimal phases after a decimal phase is removed.
815
+ *
816
+ * Port of renameDecimalPhases from phase.cjs lines 499-524.
817
+ * e.g. removing 06.2 -> 06.3 becomes 06.2, 06.4 becomes 06.3, etc.
818
+ * Renames directories AND files inside them that contain the old phase ID.
819
+ *
820
+ * CRITICAL: Sorted in DESCENDING order to avoid rename conflicts.
821
+ *
822
+ * @param phasesDir - Path to the phases directory
823
+ * @param baseInt - The integer part of the decimal phase (e.g. "06")
824
+ * @param removedDecimal - The decimal part that was removed (e.g. 2 for 06.2)
825
+ * @returns { renamedDirs, renamedFiles }
826
+ */
827
+ async function renameDecimalPhases(
828
+ phasesDir: string,
829
+ baseInt: string,
830
+ removedDecimal: number,
831
+ ): Promise<{ renamedDirs: Array<{ from: string; to: string }>; renamedFiles: Array<{ from: string; to: string }> }> {
832
+ const renamedDirs: Array<{ from: string; to: string }> = [];
833
+ const renamedFiles: Array<{ from: string; to: string }> = [];
834
+
835
+ const decPattern = new RegExp(`^${escapeRegex(baseInt)}\\.(\\d+)-(.+)$`);
836
+ const entries = await readdir(phasesDir, { withFileTypes: true });
837
+ const dirs = entries.filter(e => e.isDirectory()).map(e => e.name);
838
+
839
+ const toRename = dirs
840
+ .map(dir => {
841
+ const m = dir.match(decPattern);
842
+ return m ? { dir, oldDecimal: parseInt(m[1], 10), slug: m[2] } : null;
843
+ })
844
+ .filter((item): item is NonNullable<typeof item> => item !== null && item.oldDecimal > removedDecimal)
845
+ .sort((a, b) => b.oldDecimal - a.oldDecimal); // DESCENDING to avoid conflicts
846
+
847
+ for (const item of toRename) {
848
+ const newDecimal = item.oldDecimal - 1;
849
+ const oldPhaseId = `${baseInt}.${item.oldDecimal}`;
850
+ const newPhaseId = `${baseInt}.${newDecimal}`;
851
+ const newDirName = `${baseInt}.${newDecimal}-${item.slug}`;
852
+
853
+ await rename(join(phasesDir, item.dir), join(phasesDir, newDirName));
854
+ renamedDirs.push({ from: item.dir, to: newDirName });
855
+
856
+ // Rename files inside that contain the old phase ID
857
+ const files = await readdir(join(phasesDir, newDirName));
858
+ for (const f of files) {
859
+ if (f.includes(oldPhaseId)) {
860
+ const newFileName = f.replace(oldPhaseId, newPhaseId);
861
+ await rename(join(phasesDir, newDirName, f), join(phasesDir, newDirName, newFileName));
862
+ renamedFiles.push({ from: f, to: newFileName });
863
+ }
864
+ }
865
+ }
866
+
867
+ return { renamedDirs, renamedFiles };
868
+ }
869
+
870
+ // ─── renameIntegerPhases ───────────────────────────────────────────────
871
+
872
+ /**
873
+ * Renumber all integer phases after a removed integer phase.
874
+ *
875
+ * Port of renameIntegerPhases from phase.cjs lines 531-564.
876
+ * e.g. removing phase 5 -> phase 6 becomes 5, phase 7 becomes 6, etc.
877
+ * Handles letter suffixes (12A) and decimals (6.1).
878
+ *
879
+ * CRITICAL: Sorted in DESCENDING order to avoid rename conflicts.
880
+ *
881
+ * @param phasesDir - Path to the phases directory
882
+ * @param removedInt - The integer phase number that was removed
883
+ * @returns { renamedDirs, renamedFiles }
884
+ */
885
+ async function renameIntegerPhases(
886
+ phasesDir: string,
887
+ removedInt: number,
888
+ ): Promise<{ renamedDirs: Array<{ from: string; to: string }>; renamedFiles: Array<{ from: string; to: string }> }> {
889
+ const renamedDirs: Array<{ from: string; to: string }> = [];
890
+ const renamedFiles: Array<{ from: string; to: string }> = [];
891
+
892
+ const entries = await readdir(phasesDir, { withFileTypes: true });
893
+ const dirs = entries.filter(e => e.isDirectory()).map(e => e.name);
894
+
895
+ const toRename = dirs
896
+ .map(dir => {
897
+ const m = dir.match(/^(\d+)([A-Z])?(?:\.(\d+))?-(.+)$/i);
898
+ if (!m) return null;
899
+ const dirInt = parseInt(m[1], 10);
900
+ // CJS parity: skip backlog phases (999.x). These are parked ideas with a
901
+ // numbering convention that lives outside the active sequence; renumbering
902
+ // them would clobber the convention and corrupt downstream lookups.
903
+ // (bug-2434)
904
+ if (dirInt <= removedInt || dirInt >= 999) return null;
905
+ return {
906
+ dir,
907
+ oldInt: dirInt,
908
+ letter: m[2] ? m[2].toUpperCase() : '',
909
+ decimal: m[3] !== undefined ? parseInt(m[3], 10) : null,
910
+ slug: m[4],
911
+ };
912
+ })
913
+ .filter((item): item is NonNullable<typeof item> => item !== null)
914
+ .sort((a, b) => a.oldInt !== b.oldInt
915
+ ? b.oldInt - a.oldInt
916
+ : (b.decimal ?? 0) - (a.decimal ?? 0)); // DESCENDING
917
+
918
+ for (const item of toRename) {
919
+ const newInt = item.oldInt - 1;
920
+ const newPadded = String(newInt).padStart(2, '0');
921
+ const oldPadded = String(item.oldInt).padStart(2, '0');
922
+ const letterSuffix = item.letter || '';
923
+ const decimalSuffix = item.decimal !== null ? `.${item.decimal}` : '';
924
+ const oldPrefix = `${oldPadded}${letterSuffix}${decimalSuffix}`;
925
+ const newPrefix = `${newPadded}${letterSuffix}${decimalSuffix}`;
926
+ const newDirName = `${newPrefix}-${item.slug}`;
927
+
928
+ await rename(join(phasesDir, item.dir), join(phasesDir, newDirName));
929
+ renamedDirs.push({ from: item.dir, to: newDirName });
930
+
931
+ // Rename files that start with the old prefix
932
+ const files = await readdir(join(phasesDir, newDirName));
933
+ for (const f of files) {
934
+ if (f.startsWith(oldPrefix)) {
935
+ const newFileName = newPrefix + f.slice(oldPrefix.length);
936
+ await rename(join(phasesDir, newDirName, f), join(phasesDir, newDirName, newFileName));
937
+ renamedFiles.push({ from: f, to: newFileName });
938
+ }
939
+ }
940
+ }
941
+
942
+ return { renamedDirs, renamedFiles };
943
+ }
944
+
945
+ // ─── updateRoadmapAfterPhaseRemoval ────────────────────────────────────
946
+
947
+ /**
948
+ * Decrement integer phase number while skipping non-renumbered ranges. Mirrors
949
+ * `decrementRoadmapPhaseNumber` in phase.cjs lines 860-864.
950
+ *
951
+ * Skips when:
952
+ * • not an integer
953
+ * • num <= removedInt (already-renumbered phases stay put)
954
+ * • num >= 999 (backlog/parked-idea numbering range)
955
+ *
956
+ * Returns the original raw string when the guards trip so the regex pass
957
+ * leaves dates and unrelated numerics intact.
958
+ */
959
+ function decrementRoadmapPhaseNumber(raw: string, removedInt: number): string {
960
+ const num = parseInt(raw, 10);
961
+ if (!Number.isInteger(num) || num <= removedInt || num >= 999) return raw;
962
+ return String(num - 1);
963
+ }
964
+
965
+ /**
966
+ * Decrement integer or decimal phase token (e.g. "5" or "5.2"). Mirrors
967
+ * `decrementRoadmapPhaseToken` in phase.cjs lines 866-872 — preserves the
968
+ * decimal suffix when present and applies the same guards.
969
+ */
970
+ function decrementRoadmapPhaseToken(raw: string, removedInt: number): string {
971
+ const match = String(raw).match(/^(\d+)(\.\d+)?$/);
972
+ if (!match) return raw;
973
+ const num = parseInt(match[1]!, 10);
974
+ if (!Number.isInteger(num) || num <= removedInt || num >= 999) return raw;
975
+ return `${num - 1}${match[2] || ''}`;
976
+ }
977
+
978
+ /**
979
+ * Decrement zero-padded phase number while preserving the original pad width.
980
+ * Mirrors `decrementRoadmapPaddedPhaseNumber` in phase.cjs lines 874-878.
981
+ */
982
+ function decrementRoadmapPaddedPhaseNumber(raw: string, removedInt: number): string {
983
+ const num = parseInt(raw, 10);
984
+ if (!Number.isInteger(num) || num <= removedInt || num >= 999) return raw;
985
+ return String(num - 1).padStart(raw.length, '0');
986
+ }
987
+
988
+ /**
989
+ * Remove a phase section from ROADMAP.md and renumber subsequent integer phases.
990
+ *
991
+ * Port of updateRoadmapAfterPhaseRemoval from phase.cjs lines 880-922.
992
+ * Uses readModifyWriteRoadmapMd for atomic writes.
993
+ *
994
+ * The renumbering pass uses **5 targeted regex replacements** (not a loop)
995
+ * because the loop approach is dangerous:
996
+ * • It can match YYYY-MM-DD substrings and corrupt dates (bug-2435).
997
+ * • It can rename backlog phases (999.x) that should stay frozen (bug-2434).
998
+ * • It can renumber the same phase multiple times if the regex matches
999
+ * overlap (bug-3355 — phase 7 → 6 → 5 → ...).
1000
+ *
1001
+ * The CJS pattern uses negative lookbehind/ahead on the padded-prefix regex
1002
+ * to skip dates and decrement helpers that guard against `num >= 999`. Keep
1003
+ * this implementation byte-for-byte in lockstep with phase.cjs:880-922 —
1004
+ * deviations are how the three bugs above slipped in.
1005
+ *
1006
+ * @param projectDir - Project root directory
1007
+ * @param targetPhase - Phase identifier that was removed
1008
+ * @param isDecimal - Whether the removed phase was a decimal phase
1009
+ * @param removedInt - The integer part of the removed phase
1010
+ */
1011
+ async function updateRoadmapAfterPhaseRemoval(
1012
+ projectDir: string,
1013
+ targetPhase: string,
1014
+ isDecimal: boolean,
1015
+ removedInt: number,
1016
+ workstream?: string,
1017
+ ): Promise<void> {
1018
+ await readModifyWriteRoadmapMd(projectDir, (content) => {
1019
+ const escaped = escapeRegex(targetPhase);
1020
+
1021
+ // Remove the phase section (header + body until next phase header or end).
1022
+ //
1023
+ // #3601: the end-of-section lookahead is DEPTH-AWARE. The named capture
1024
+ // (?<h>#{2,4}) records the hash count of the header being removed and the
1025
+ // lookahead requires the same depth via \k<h>(?!#). Two contracts are
1026
+ // preserved:
1027
+ //
1028
+ // (#3601 case) Remove `### Phase 2:` and stop at `### Phase 2.1:` —
1029
+ // Phase 2.1 is a peer-level decimal phase (depth 3) and must survive.
1030
+ //
1031
+ // (#3355 case) Remove `### Phase 27:` and CONTINUE past
1032
+ // `#### Phase 27.1:` (depth 4 — child of Phase 27) until the next
1033
+ // depth-3 header. The child decimal is part of the integer phase
1034
+ // being removed.
1035
+ //
1036
+ // The `(?!#)` negative lookahead after the backreference prevents the
1037
+ // depth-3 match from being satisfied by a depth-4+ header that starts
1038
+ // with the same three hashes. `[^\n:]+` accepts numeric, decimal, AND
1039
+ // custom phase IDs (PROJ-42) as terminators.
1040
+ content = content.replace(
1041
+ new RegExp(
1042
+ `\\n?(?<h>#{2,4})\\s*Phase\\s+${escaped}\\s*:[\\s\\S]*?(?=\\n\\k<h>(?!#)\\s+Phase\\s+[^\\n:]+\\s*:|$)`,
1043
+ 'i',
1044
+ ),
1045
+ '',
1046
+ );
1047
+
1048
+ // Remove checkbox lines referencing the phase
1049
+ content = content.replace(
1050
+ new RegExp(`\\n?-\\s*\\[[ x]\\]\\s*.*Phase\\s+${escaped}[:\\s][^\\n]*`, 'gi'),
1051
+ '',
1052
+ );
1053
+
1054
+ // Remove table rows referencing the phase
1055
+ content = content.replace(
1056
+ new RegExp(`\\n?\\|\\s*${escaped}\\.?\\s[^|]*\\|[^\\n]*`, 'gi'),
1057
+ '',
1058
+ );
1059
+
1060
+ if (!isDecimal) {
1061
+ // Phase headers: ### Phase N: / ### Phase N.M:
1062
+ content = content.replace(
1063
+ /(#{2,4}\s*Phase\s+)(\d+(?:\.\d+)?)(\s*:)/gi,
1064
+ (_match, prefix: string, num: string, suffix: string) =>
1065
+ `${prefix}${decrementRoadmapPhaseToken(num, removedInt)}${suffix}`,
1066
+ );
1067
+
1068
+ // Checkbox-list summary references: `- [ ] Phase N:`
1069
+ content = content.replace(
1070
+ /(-\s*\[[ x]\]\s*.*?Phase\s+)(\d+)(\s*:|\s+)/gi,
1071
+ (_match, prefix: string, num: string, suffix: string) =>
1072
+ `${prefix}${decrementRoadmapPhaseNumber(num, removedInt)}${suffix}`,
1073
+ );
1074
+
1075
+ // Table-row phase numbers: `| N. ` — bare integer in a cell.
1076
+ content = content.replace(
1077
+ /(\|\s*)(\d+)(\.\s)/g,
1078
+ (_match, prefix: string, num: string, suffix: string) =>
1079
+ `${prefix}${decrementRoadmapPhaseNumber(num, removedInt)}${suffix}`,
1080
+ );
1081
+
1082
+ // Padded plan references: NN-NN (optionally followed by an arbitrary
1083
+ // kebab-case slug, then -PLAN.md / -SUMMARY.md).
1084
+ //
1085
+ // #2435: negative lookbehind `(?<![0-9-])` and negative lookahead
1086
+ // `(?![0-9-])` exclude YYYY-MM-DD substrings.
1087
+ //
1088
+ // #3602: the original pattern only allowed a compact `-(PLAN|SUMMARY).md`
1089
+ // immediately after the plan number; a slug between the number and the
1090
+ // `-PLAN.md` / `-SUMMARY.md` suffix (e.g.
1091
+ // `07-01-cherry-pick-foundation-PLAN.md`) made the lookahead fail and
1092
+ // left the stale `07-01-` prefix in ROADMAP text while the on-disk file
1093
+ // was already renumbered to `06-01-…`. The slug segment
1094
+ // `(?:-[A-Za-z][A-Za-z0-9-]*)*` allows any number of kebab-case tokens
1095
+ // before the canonical PLAN/SUMMARY suffix.
1096
+ content = content.replace(
1097
+ /(?<![0-9-])(\d{2})-(\d{2})(?=(?:(?:-[A-Za-z][A-Za-z0-9-]*)*-(?:PLAN|SUMMARY)\.md)?(?![0-9-]))/g,
1098
+ (_match, phaseNum: string, planNum: string) =>
1099
+ `${decrementRoadmapPaddedPhaseNumber(phaseNum, removedInt)}-${planNum}`,
1100
+ );
1101
+
1102
+ // Depends-on references — two bold-colon variants in the wild.
1103
+ content = content.replace(
1104
+ /(\*\*Depends on\*\*\s*:\s*Phase\s+)(\d+(?:\.\d+)?)\b/gi,
1105
+ (_match, prefix: string, num: string) =>
1106
+ `${prefix}${decrementRoadmapPhaseToken(num, removedInt)}`,
1107
+ );
1108
+ content = content.replace(
1109
+ /(Depends on:\*\*\s*Phase\s+)(\d+(?:\.\d+)?)\b/gi,
1110
+ (_match, prefix: string, num: string) =>
1111
+ `${prefix}${decrementRoadmapPhaseToken(num, removedInt)}`,
1112
+ );
1113
+ }
1114
+
1115
+ return content;
1116
+ }, workstream);
1117
+ }
1118
+
1119
+ // ─── phaseRemove handler ───────────────────────────────────────────────
1120
+
1121
+ /**
1122
+ * Query handler for phase.remove.
1123
+ *
1124
+ * Port of cmdPhaseRemove from phase.cjs lines 597-661.
1125
+ * Deletes phase directory, renumbers subsequent phases on disk,
1126
+ * updates ROADMAP.md (removes section + renumbers), and decrements
1127
+ * STATE.md total_phases count.
1128
+ *
1129
+ * @param args - args[0]: targetPhase (required), args[1]: '--force' (optional)
1130
+ * @param projectDir - Project root directory
1131
+ * @returns QueryResult with { removed, directory_deleted, renamed_directories, renamed_files, roadmap_updated, state_updated }
1132
+ */
1133
+ export const phaseRemove: QueryHandler = async (args, projectDir, workstream) => {
1134
+ let force = false;
1135
+ const positional: string[] = [];
1136
+ for (const token of args) {
1137
+ if (token === '--force') {
1138
+ force = true;
1139
+ continue;
1140
+ }
1141
+ if (token.startsWith('--')) {
1142
+ throw new GSDError(`phase remove does not support ${token}`, ErrorClassification.Validation);
1143
+ }
1144
+ positional.push(token);
1145
+ }
1146
+
1147
+ if (positional.length > 1) {
1148
+ throw new GSDError('phase remove accepts exactly one phase number', ErrorClassification.Validation);
1149
+ }
1150
+
1151
+ const targetPhase = positional[0];
1152
+ if (!targetPhase) {
1153
+ throw new GSDError('phase number required for phase remove', ErrorClassification.Validation);
1154
+ }
1155
+ assertNoNullBytes(targetPhase, 'targetPhase');
1156
+
1157
+ const paths = planningPaths(projectDir, workstream);
1158
+ const phasesDir = paths.phases;
1159
+
1160
+ if (!existsSync(paths.roadmap)) {
1161
+ throw new GSDError('ROADMAP.md not found', ErrorClassification.Validation);
1162
+ }
1163
+
1164
+ const normalized = normalizePhaseName(targetPhase);
1165
+ const isDecimal = targetPhase.includes('.');
1166
+
1167
+ // Find target directory
1168
+ const entries = await readdir(phasesDir, { withFileTypes: true });
1169
+ const dirs = entries.filter(e => e.isDirectory()).map(e => e.name);
1170
+ const targetDir = dirs.find(d => phaseTokenMatches(d, normalized)) ?? null;
1171
+ if (!targetDir) {
1172
+ throw new GSDError(`Phase ${targetPhase} not found`, ErrorClassification.Validation);
1173
+ }
1174
+
1175
+ // Guard against removing executed work
1176
+ if (!force) {
1177
+ const files = await readdir(join(phasesDir, targetDir));
1178
+ const summaries = files.filter(f => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md');
1179
+ if (summaries.length > 0) {
1180
+ throw new GSDError(
1181
+ `Phase ${targetPhase} has ${summaries.length} executed plan(s). Use --force to remove anyway.`,
1182
+ ErrorClassification.Validation,
1183
+ );
1184
+ }
1185
+ }
1186
+
1187
+ // Delete directory
1188
+ await rm(join(phasesDir, targetDir), { recursive: true, force: true });
1189
+
1190
+ // Renumber subsequent phases on disk
1191
+ let renamedDirs: Array<{ from: string; to: string }> = [];
1192
+ let renamedFiles: Array<{ from: string; to: string }> = [];
1193
+ try {
1194
+ let renamed: { renamedDirs: Array<{ from: string; to: string }>; renamedFiles: Array<{ from: string; to: string }> };
1195
+ if (isDecimal) {
1196
+ const parts = normalized.split('.');
1197
+ if (parts.length < 2 || !parts[1]) {
1198
+ throw new GSDError(`Invalid decimal phase identifier: ${targetPhase}`, ErrorClassification.Validation);
1199
+ }
1200
+ const decimalPart = parseInt(parts[1], 10);
1201
+ if (isNaN(decimalPart)) {
1202
+ throw new GSDError(`Invalid decimal part in phase: ${targetPhase}`, ErrorClassification.Validation);
1203
+ }
1204
+ renamed = await renameDecimalPhases(phasesDir, parts[0], decimalPart);
1205
+ } else {
1206
+ renamed = await renameIntegerPhases(phasesDir, parseInt(normalized, 10));
1207
+ }
1208
+ renamedDirs = renamed.renamedDirs;
1209
+ renamedFiles = renamed.renamedFiles;
1210
+ } catch { /* intentionally empty — renaming is best-effort */ }
1211
+
1212
+ // Update ROADMAP.md
1213
+ await updateRoadmapAfterPhaseRemoval(projectDir, targetPhase, isDecimal, parseInt(normalized, 10), workstream);
1214
+
1215
+ // Update STATE.md: decrement total_phases
1216
+ let stateUpdated = false;
1217
+ const statePath = paths.state;
1218
+ if (existsSync(statePath)) {
1219
+ const lockPath = await acquireStateLock(statePath);
1220
+ try {
1221
+ let stateContent = await readFile(statePath, 'utf-8');
1222
+
1223
+ // Decrement total_phases in frontmatter
1224
+ const totalPhasesMatch = stateContent.match(/total_phases:\s*(\d+)/);
1225
+ if (totalPhasesMatch) {
1226
+ const oldTotal = parseInt(totalPhasesMatch[1], 10);
1227
+ stateContent = stateContent.replace(
1228
+ /total_phases:\s*\d+/,
1229
+ `total_phases: ${oldTotal - 1}`,
1230
+ );
1231
+ }
1232
+
1233
+ // Decrement "of N" pattern in body (e.g., "Plan: 2 of 3")
1234
+ const ofMatch = stateContent.match(/(\bof\s+)(\d+)(\s*(?:\(|phases?))/i);
1235
+ if (ofMatch) {
1236
+ stateContent = stateContent.replace(
1237
+ /(\bof\s+)(\d+)(\s*(?:\(|phases?))/i,
1238
+ `$1${parseInt(ofMatch[2], 10) - 1}$3`,
1239
+ );
1240
+ }
1241
+
1242
+ // Also try stateReplaceField for "Total Phases" field
1243
+ const totalRaw = stateExtractField(stateContent, 'Total Phases');
1244
+ if (totalRaw) {
1245
+ const replaced = stateReplaceField(stateContent, 'Total Phases', String(parseInt(totalRaw, 10) - 1));
1246
+ if (replaced) stateContent = replaced;
1247
+ }
1248
+
1249
+ await writeFile(statePath, stateContent, 'utf-8');
1250
+ stateUpdated = true;
1251
+ } finally {
1252
+ await releaseStateLock(lockPath);
1253
+ }
1254
+ }
1255
+
1256
+ return {
1257
+ data: {
1258
+ removed: targetPhase,
1259
+ directory_deleted: targetDir,
1260
+ renamed_directories: renamedDirs,
1261
+ renamed_files: renamedFiles,
1262
+ roadmap_updated: true,
1263
+ state_updated: stateUpdated,
1264
+ },
1265
+ };
1266
+ };
1267
+
1268
+ // ─── updatePerformanceMetricsSection ───────────────────────────────────────
1269
+
1270
+ /**
1271
+ * Update the Performance Metrics section in STATE.md content.
1272
+ *
1273
+ * Port of updatePerformanceMetricsSection from state.cjs lines 1125-1156.
1274
+ * Updates "Total plans completed" counter and upserts a row in the By Phase table.
1275
+ *
1276
+ * @param content - STATE.md content
1277
+ * @param phaseNum - Phase number being completed
1278
+ * @param planCount - Total number of plans in the phase
1279
+ * @param summaryCount - Number of completed summaries
1280
+ * @returns Modified content
1281
+ */
1282
+ function updatePerformanceMetricsSection(
1283
+ content: string,
1284
+ phaseNum: string,
1285
+ planCount: number,
1286
+ summaryCount: number,
1287
+ ): string {
1288
+ // Update Velocity: Total plans completed
1289
+ const totalMatch = content.match(/Total plans completed:\s*(\d+|\[N\])/);
1290
+ const prevTotal = totalMatch && totalMatch[1] !== '[N]' ? parseInt(totalMatch[1], 10) : 0;
1291
+ const newTotal = prevTotal + summaryCount;
1292
+ content = content.replace(
1293
+ /Total plans completed:\s*(\d+|\[N\])/,
1294
+ `Total plans completed: ${newTotal}`,
1295
+ );
1296
+
1297
+ // Update By Phase table — upsert row for this phase
1298
+ const byPhaseTablePattern = /(\|\s*Phase\s*\|\s*Plans\s*\|\s*Total\s*\|\s*Avg\/Plan\s*\|[ \t]*\n\|(?:[- :\t]+\|)+[ \t]*\n)((?:[ \t]*\|[^\n]*\n)*)(?=\n|$)/i;
1299
+ const byPhaseMatch = content.match(byPhaseTablePattern);
1300
+ if (byPhaseMatch) {
1301
+ let tableBody = byPhaseMatch[2].trim();
1302
+ const phaseRowPattern = new RegExp(`^\\|\\s*${escapeRegex(String(phaseNum))}\\s*\\|.*$`, 'm');
1303
+ const newRow = `| ${phaseNum} | ${summaryCount} | - | - |`;
1304
+
1305
+ if (phaseRowPattern.test(tableBody)) {
1306
+ // Update existing row
1307
+ tableBody = tableBody.replace(new RegExp(`^\\|\\s*${escapeRegex(String(phaseNum))}\\s*\\|.*$`, 'm'), newRow);
1308
+ } else {
1309
+ // Remove placeholder row and add new row
1310
+ tableBody = tableBody.replace(/^\|\s*-\s*\|\s*-\s*\|\s*-\s*\|\s*-\s*\|$/m, '').trim();
1311
+ tableBody = tableBody ? tableBody + '\n' + newRow : newRow;
1312
+ }
1313
+
1314
+ content = content.replace(byPhaseTablePattern, `$1${tableBody}\n`);
1315
+ }
1316
+
1317
+ return content;
1318
+ }
1319
+
1320
+ // ─── phaseComplete handler ────────────────────────────────────────────────
1321
+
1322
+ /**
1323
+ * Query handler for phase.complete.
1324
+ *
1325
+ * Port of cmdPhaseComplete from phase.cjs lines 663-932.
1326
+ * Marks a phase as done — updates ROADMAP.md (checkbox, progress table,
1327
+ * plan count, plan checkboxes), REQUIREMENTS.md (requirement checkboxes,
1328
+ * traceability table), and STATE.md (current phase, status, progress,
1329
+ * performance metrics) atomically with per-file locks.
1330
+ *
1331
+ * @param args - args[0]: phaseNum (required)
1332
+ * @param projectDir - Project root directory
1333
+ * @returns QueryResult with completion details and warnings
1334
+ */
1335
+ export const phaseComplete: QueryHandler = async (args, projectDir, workstream) => {
1336
+ const phaseNum = args[0];
1337
+ if (!phaseNum) {
1338
+ throw new GSDError('phase number required for phase complete', ErrorClassification.Validation);
1339
+ }
1340
+ assertNoNullBytes(phaseNum, 'phaseNum');
1341
+
1342
+ const paths = planningPaths(projectDir, workstream);
1343
+ const today = new Date().toISOString().split('T')[0];
1344
+
1345
+ // Step A: Validate phase exists and get info
1346
+ const phaseInfo = await findPhaseDir(projectDir, phaseNum, workstream);
1347
+ if (!phaseInfo) {
1348
+ throw new GSDError(`Phase ${phaseNum} not found`, ErrorClassification.Validation);
1349
+ }
1350
+
1351
+ const phaseDir = phaseInfo.dirPath;
1352
+ let phaseFiles: string[];
1353
+ try {
1354
+ phaseFiles = await readdir(phaseDir);
1355
+ } catch {
1356
+ phaseFiles = [];
1357
+ }
1358
+
1359
+ const plans = phaseFiles.filter(f => f.endsWith('-PLAN.md') || f === 'PLAN.md');
1360
+ const summaries = phaseFiles.filter(f => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md');
1361
+ const planCount = plans.length;
1362
+ const summaryCount = summaries.length;
1363
+ let requirementsUpdated = false;
1364
+
1365
+ // Step B: Check for verification warnings (non-blocking)
1366
+ const warnings: string[] = [];
1367
+ for (const file of phaseFiles.filter(f => f.includes('-UAT') && f.endsWith('.md'))) {
1368
+ try {
1369
+ const content = await readFile(join(phaseDir, file), 'utf-8');
1370
+ if (/result: pending/.test(content)) warnings.push(`${file}: has pending tests`);
1371
+ if (/result: blocked/.test(content)) warnings.push(`${file}: has blocked tests`);
1372
+ if (/status: partial/.test(content)) warnings.push(`${file}: testing incomplete (partial)`);
1373
+ if (/status: diagnosed/.test(content)) warnings.push(`${file}: has diagnosed gaps`);
1374
+ } catch { /* intentionally empty */ }
1375
+ }
1376
+ for (const file of phaseFiles.filter(f => f.includes('-VERIFICATION') && f.endsWith('.md'))) {
1377
+ try {
1378
+ const content = await readFile(join(phaseDir, file), 'utf-8');
1379
+ if (/status: human_needed/.test(content)) warnings.push(`${file}: needs human verification`);
1380
+ if (/status: gaps_found/.test(content)) warnings.push(`${file}: has unresolved gaps`);
1381
+ } catch { /* intentionally empty */ }
1382
+ }
1383
+
1384
+ // Step C: Update ROADMAP.md atomically
1385
+ if (existsSync(paths.roadmap)) {
1386
+ await readModifyWriteRoadmapMd(projectDir, async (roadmapContent) => {
1387
+ // Padding-tolerant fragment so a padded input like "02.7" still matches
1388
+ // un-padded ROADMAP prose ("### Phase 2.7:"). CJS routes every phase-
1389
+ // number ROADMAP regex through phaseMarkdownRegexSource (#3537) —
1390
+ // mirror that contract here so phase.complete with the padded form
1391
+ // produces the same ROADMAP as the un-padded form.
1392
+ const phaseEscaped = phaseMarkdownRegexSource(phaseNum);
1393
+
1394
+ // Checkbox: - [ ] Phase N: -> - [x] Phase N: (...completed DATE)
1395
+ // CJS parity (phase.cjs): direct replace, NOT scoped through
1396
+ // replaceInCurrentMilestone. Same reasoning as the plan-count
1397
+ // update below — milestone wrapped in <details> would otherwise be
1398
+ // skipped (bug-2005).
1399
+ const checkboxPattern = new RegExp(
1400
+ `(-\\s*\\[)[ ](\\]\\s*.*Phase\\s+${phaseEscaped}[:\\s][^\\n]*)`,
1401
+ 'i',
1402
+ );
1403
+ roadmapContent = roadmapContent.replace(checkboxPattern, `$1x$2 (completed ${today})`);
1404
+
1405
+ // Progress table: update Status to Complete, add date
1406
+ const tableRowPattern = new RegExp(
1407
+ `^(\\|\\s*${phaseEscaped}\\.?\\s[^|]*(?:\\|[^\\n]*))$`,
1408
+ 'im',
1409
+ );
1410
+ roadmapContent = roadmapContent.replace(tableRowPattern, (fullRow) => {
1411
+ const cells = fullRow.split('|').slice(1, -1);
1412
+ if (cells.length === 5) {
1413
+ cells[2] = ` ${summaryCount}/${planCount} `;
1414
+ cells[3] = ' Complete ';
1415
+ cells[4] = ` ${today} `;
1416
+ } else if (cells.length === 4) {
1417
+ cells[1] = ` ${summaryCount}/${planCount} `;
1418
+ cells[2] = ' Complete ';
1419
+ cells[3] = ` ${today} `;
1420
+ }
1421
+ return '|' + cells.join('|') + '|';
1422
+ });
1423
+
1424
+ // Update plan count in phase section.
1425
+ // CJS parity (phase.cjs:1076-1083): direct replace, NOT scoped through
1426
+ // replaceInCurrentMilestone. Scoping to "after last </details>" fails
1427
+ // when the current milestone itself is wrapped in <details open>...
1428
+ // </details> — there's no content after the close tag, so the regex
1429
+ // never matches and **Plans:** stays at 0/N (bug-2005).
1430
+ const planCountPattern = new RegExp(
1431
+ `(#{2,4}\\s*Phase\\s+${phaseEscaped}(?:(?!\\n#{2,4})[\\s\\S])*?\\*\\*Plans:\\*\\*[ \\t]*)[^\\n]+`,
1432
+ 'i',
1433
+ );
1434
+ roadmapContent = roadmapContent.replace(
1435
+ planCountPattern,
1436
+ `$1${summaryCount}/${planCount} plans complete`,
1437
+ );
1438
+
1439
+ // Mark completed plan checkboxes
1440
+ for (const summaryFile of summaries) {
1441
+ const planId = summaryFile.replace('-SUMMARY.md', '').replace('SUMMARY.md', '');
1442
+ if (!planId) continue;
1443
+ const planEscaped = escapeRegex(planId);
1444
+ const planCheckboxPattern = new RegExp(
1445
+ `(-\\s*\\[) (\\]\\s*(?:\\*\\*)?${planEscaped}(?:\\*\\*)?)`,
1446
+ 'i',
1447
+ );
1448
+ roadmapContent = roadmapContent.replace(planCheckboxPattern, '$1x$2');
1449
+ }
1450
+
1451
+ // Step D: Update REQUIREMENTS.md
1452
+ const reqPath = paths.requirements;
1453
+ if (existsSync(reqPath)) {
1454
+ const currentMilestoneRoadmap = await extractCurrentMilestone(roadmapContent, projectDir);
1455
+ const phaseSectionMatch = currentMilestoneRoadmap.match(
1456
+ new RegExp(`(#{2,4}\\s*Phase\\s+${phaseEscaped}[:\\s][\\s\\S]*?)(?=#{2,4}\\s*Phase\\s+|$)`, 'i'),
1457
+ );
1458
+
1459
+ const sectionText = phaseSectionMatch ? phaseSectionMatch[1] : '';
1460
+ const reqMatch = sectionText.match(/\*\*Requirements\*?\*?:?\s*([^\n]+)/i);
1461
+
1462
+ let reqContent = await readFile(reqPath, 'utf-8');
1463
+ let reqContentChanged = false;
1464
+
1465
+ if (reqMatch) {
1466
+ const reqIds = reqMatch[1].replace(/[[\]]/g, '').split(/[,\s]+/).map(r => r.trim()).filter(Boolean);
1467
+
1468
+ for (const reqId of reqIds) {
1469
+ const reqEscaped = escapeRegex(reqId);
1470
+ const before = reqContent;
1471
+ // Update checkbox: - [ ] **REQ-ID** -> - [x] **REQ-ID**
1472
+ reqContent = reqContent.replace(
1473
+ new RegExp(`(-\\s*\\[)[ ](\\]\\s*\\*\\*${reqEscaped}\\*\\*)`, 'gi'),
1474
+ '$1x$2',
1475
+ );
1476
+ // Update traceability table: Pending/In Progress -> Complete
1477
+ reqContent = reqContent.replace(
1478
+ new RegExp(`(\\|\\s*${reqEscaped}\\s*\\|[^|]+\\|)\\s*(?:Pending|In Progress)\\s*(\\|)`, 'gi'),
1479
+ '$1 Complete $2',
1480
+ );
1481
+ if (reqContent !== before) reqContentChanged = true;
1482
+ }
1483
+ }
1484
+
1485
+ // Bug #2526 parity (phase.cjs:1140-1167): independent of whether the
1486
+ // roadmap declared a Requirements: line, scan the REQUIREMENTS.md
1487
+ // body for `**REQ-ID**` references and compare against the IDs that
1488
+ // actually appear in the Traceability table. Surface every body
1489
+ // ID that has no traceability row so the operator can keep the
1490
+ // table in sync.
1491
+ const bodyReqIds: string[] = [];
1492
+ const bodyReqPattern = /\*\*([A-Z][A-Z0-9]*-\d+)\*\*/g;
1493
+ let bodyMatch: RegExpExecArray | null;
1494
+ while ((bodyMatch = bodyReqPattern.exec(reqContent)) !== null) {
1495
+ if (!bodyReqIds.includes(bodyMatch[1]!)) bodyReqIds.push(bodyMatch[1]!);
1496
+ }
1497
+
1498
+ const traceabilityHeadingMatch = reqContent.match(/^#{1,6}\s+Traceability\b/im);
1499
+ const traceabilitySection = traceabilityHeadingMatch
1500
+ ? reqContent.slice(traceabilityHeadingMatch.index!)
1501
+ : '';
1502
+ const tableReqIds = new Set<string>();
1503
+ const tableRowPattern = /^\|\s*([A-Z][A-Z0-9]*-\d+)\s*\|/gm;
1504
+ let tableMatch: RegExpExecArray | null;
1505
+ while ((tableMatch = tableRowPattern.exec(traceabilitySection)) !== null) {
1506
+ tableReqIds.add(tableMatch[1]!);
1507
+ }
1508
+
1509
+ const unregistered = bodyReqIds.filter((id) => !tableReqIds.has(id));
1510
+ if (unregistered.length > 0) {
1511
+ warnings.push(
1512
+ `REQUIREMENTS.md: ${unregistered.length} REQ-ID(s) found in body but missing from Traceability table: ${unregistered.join(', ')} — add them manually to keep traceability in sync`,
1513
+ );
1514
+ }
1515
+
1516
+ if (reqContentChanged) {
1517
+ await writeFile(reqPath, reqContent, 'utf-8');
1518
+ requirementsUpdated = true;
1519
+ }
1520
+ }
1521
+
1522
+ return roadmapContent;
1523
+ }, workstream);
1524
+ }
1525
+
1526
+ // Step E: Find next phase — filesystem first, then ROADMAP.md fallback
1527
+ let nextPhaseNum: string | null = null;
1528
+ let nextPhaseName: string | null = null;
1529
+ let isLastPhase = true;
1530
+ // Tracks whether the completed phase belongs to the primary milestone in STATE.md.
1531
+ // When false (parallel-milestone case, Bug #2676), the milestone filter is bypassed
1532
+ // for next-phase detection so phases from the same secondary milestone are visible.
1533
+ let completedPhaseInPrimaryMilestone = true;
1534
+
1535
+ try {
1536
+ const isDirInMilestone = await getMilestonePhaseFilter(projectDir, workstream);
1537
+ const entries = await readdir(paths.phases, { withFileTypes: true });
1538
+ const allDirs = entries.filter(e => e.isDirectory()).map(e => e.name);
1539
+
1540
+ // Guard: if the completed phase's directory is not in the current-milestone filter
1541
+ // set, the filter was built from a different (primary) milestone in STATE.md.
1542
+ // In that case skip the filter so we can find the true next phase on disk.
1543
+ // This handles parallel-milestone workflows where STATE.md's `milestone:` field
1544
+ // points at the primary milestone but the phase being completed belongs to a
1545
+ // secondary in-flight milestone. (Bug #2676)
1546
+ const completedDirInFilter = allDirs.some((d) => {
1547
+ const dm = d.match(/^(\d+[A-Z]?(?:\.\d+)*)-?/i);
1548
+ return dm && comparePhaseNum(dm[1], phaseNum) === 0 && isDirInMilestone(d);
1549
+ });
1550
+ completedPhaseInPrimaryMilestone = completedDirInFilter;
1551
+ const effectiveFilter = completedDirInFilter ? isDirInMilestone : (_d: string) => true;
1552
+
1553
+ const dirs = allDirs
1554
+ .filter(effectiveFilter)
1555
+ .sort((a, b) => comparePhaseNum(a, b));
1556
+
1557
+ for (const dir of dirs) {
1558
+ const dm = dir.match(/^(\d+[A-Z]?(?:\.\d+)*)-?(.*)/i);
1559
+ if (dm) {
1560
+ // Bug #2129 parity: skip backlog phases (999.x). They are parked
1561
+ // ideas with reserved numbering, not part of the active sequence.
1562
+ // Without this, completing phase 2 in a project that has a 999.1
1563
+ // backlog directory would jump next_phase to 999.1 instead of the
1564
+ // intended Phase 3 from ROADMAP.
1565
+ if (/^999(?:\.|$)/.test(dm[1]!)) continue;
1566
+ if (comparePhaseNum(dm[1], phaseNum) > 0) {
1567
+ nextPhaseNum = dm[1];
1568
+ nextPhaseName = dm[2] || null;
1569
+ isLastPhase = false;
1570
+ break;
1571
+ }
1572
+ }
1573
+ }
1574
+ } catch { /* intentionally empty */ }
1575
+
1576
+ // Fallback: check ROADMAP.md for phases not yet scaffolded.
1577
+ // When the completed phase is from a parallel (non-primary) milestone, scan the
1578
+ // full ROADMAP rather than the primary-milestone slice so 41.3 is visible when
1579
+ // completing 41.2 for a secondary milestone. (Bug #2676)
1580
+ if (isLastPhase && existsSync(paths.roadmap)) {
1581
+ try {
1582
+ const roadmapContent = await readFile(paths.roadmap, 'utf-8');
1583
+ const roadmapForPhases = completedPhaseInPrimaryMilestone
1584
+ ? await extractCurrentMilestone(roadmapContent, projectDir)
1585
+ : roadmapContent;
1586
+ const phasePattern = /#{2,4}\s*Phase\s+(\d+[A-Z]?(?:\.\d+)*)\s*:\s*([^\n]+)/gi;
1587
+ let pm: RegExpExecArray | null;
1588
+ while ((pm = phasePattern.exec(roadmapForPhases)) !== null) {
1589
+ if (comparePhaseNum(pm[1], phaseNum) > 0) {
1590
+ nextPhaseNum = pm[1];
1591
+ nextPhaseName = pm[2].replace(/\(INSERTED\)/i, '').trim().toLowerCase().replace(/\s+/g, '-');
1592
+ isLastPhase = false;
1593
+ break;
1594
+ }
1595
+ }
1596
+ } catch { /* intentionally empty */ }
1597
+ }
1598
+
1599
+ // Step F: Update STATE.md atomically
1600
+ let stateUpdated = false;
1601
+ if (existsSync(paths.state)) {
1602
+ const lockPath = await acquireStateLock(paths.state);
1603
+ try {
1604
+ const rawState = await readFile(paths.state, 'utf-8');
1605
+
1606
+ // Split into frontmatter and body to prevent field replacement from
1607
+ // matching YAML keys (e.g., `status:` in frontmatter vs `Status:` in body).
1608
+ // Pattern 11: Strip frontmatter before modifier (from Phase 11 decisions).
1609
+ const fmMatch = rawState.match(/^(---\r?\n[\s\S]*?\r?\n---)\s*/);
1610
+ let frontmatter = fmMatch ? fmMatch[1] : '';
1611
+ let body = fmMatch ? rawState.slice(fmMatch[0].length) : rawState;
1612
+
1613
+ // Update Current Phase — preserve "X of Y (Name)" compound format
1614
+ const phaseValue = nextPhaseNum || phaseNum;
1615
+ const existingPhaseField = stateExtractField(body, 'Current Phase')
1616
+ || stateExtractField(body, 'Phase');
1617
+ let newPhaseValue = String(phaseValue);
1618
+ if (existingPhaseField) {
1619
+ const totalMatch = existingPhaseField.match(/of\s+(\d+)/);
1620
+ const nameMatch = existingPhaseField.match(/\(([^)]+)\)/);
1621
+ if (totalMatch) {
1622
+ const total = totalMatch[1];
1623
+ const nameStr = nextPhaseName
1624
+ ? ` (${nextPhaseName.replace(/-/g, ' ')})`
1625
+ : (nameMatch ? ` (${nameMatch[1]})` : '');
1626
+ newPhaseValue = `${phaseValue} of ${total}${nameStr}`;
1627
+ }
1628
+ }
1629
+ body = stateReplaceFieldWithFallback(body, 'Current Phase', 'Phase', newPhaseValue);
1630
+
1631
+ // Update Status
1632
+ body = stateReplaceFieldWithFallback(body, 'Status', null,
1633
+ isLastPhase ? 'Milestone complete' : 'Ready to plan');
1634
+
1635
+ // Update Current Plan
1636
+ body = stateReplaceFieldWithFallback(body, 'Current Plan', 'Plan', 'Not started');
1637
+
1638
+ // Update Last Activity
1639
+ body = stateReplaceFieldWithFallback(body, 'Last Activity', 'Last activity', today);
1640
+
1641
+ // Update Performance Metrics section (operates on body only)
1642
+ body = updatePerformanceMetricsSection(body, phaseNum, planCount, summaryCount);
1643
+
1644
+ // ── Root cause 1 fix: derive completed_phases from ROADMAP, not blind increment ──
1645
+ // Read the freshly-updated ROADMAP (after Step C) to count Complete rows.
1646
+ // This makes phase.complete idempotent: running it twice on the same phase
1647
+ // produces the same completed_phases value.
1648
+ let derivedCompletedPhases: number | null = null;
1649
+ let derivedTotalPhases: number | null = null;
1650
+ let derivedTotalPlans: number | null = null;
1651
+ if (existsSync(paths.roadmap)) {
1652
+ try {
1653
+ const freshRoadmap = await readFile(paths.roadmap, 'utf-8');
1654
+ // Count Complete rows in the progress table (Status column = "Complete")
1655
+ const tableCompletePattern = /\|\s*\d+[A-Z]?\S*\s*\|[^|]*\|\s*Complete\s*\|/gi;
1656
+ const completeMatches = freshRoadmap.match(tableCompletePattern);
1657
+ derivedCompletedPhases = completeMatches ? completeMatches.length : null;
1658
+
1659
+ // Count total phase rows in progress table (header + separator + data rows)
1660
+ // Identify the progress table by looking for Phase|Plans|Status|Completed header
1661
+ const progressTableMatch = freshRoadmap.match(
1662
+ /\|\s*Phase\s*\|\s*Plans\s*\|\s*Status\s*\|\s*Completed\s*\|(.*\n)*?(?:\n|$)/i,
1663
+ );
1664
+ if (progressTableMatch) {
1665
+ const tableText = progressTableMatch[0];
1666
+ const dataRowPattern = /^\|\s*\d+[A-Z]?\S*\s*\|/gm;
1667
+ const dataRows = tableText.match(dataRowPattern);
1668
+ derivedTotalPhases = dataRows ? dataRows.length : null;
1669
+ }
1670
+
1671
+ // Sum plan counts from M/N or 0/N columns in the progress table
1672
+ let totalPlansSum = 0;
1673
+ const planCellPattern = /\|\s*\d+[A-Z]?\S*\s*\|\s*(\d+)\/(\d+)\s*\|/gi;
1674
+ let pm: RegExpExecArray | null;
1675
+ while ((pm = planCellPattern.exec(freshRoadmap)) !== null) {
1676
+ totalPlansSum += parseInt(pm[2], 10);
1677
+ }
1678
+ if (totalPlansSum > 0) derivedTotalPlans = totalPlansSum;
1679
+ } catch { /* intentionally empty — fall through to existing values */ }
1680
+ }
1681
+
1682
+ // Count completed plans from all SUMMARY files across phase dirs
1683
+ let derivedCompletedPlans: number | null = null;
1684
+ try {
1685
+ const phaseEntries = await readdir(paths.phases, { withFileTypes: true });
1686
+ let summaryTotal = 0;
1687
+ for (const entry of phaseEntries) {
1688
+ if (!entry.isDirectory()) continue;
1689
+ try {
1690
+ const files = await readdir(join(paths.phases, entry.name));
1691
+ summaryTotal += files.filter(f => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md').length;
1692
+ } catch { /* intentionally empty */ }
1693
+ }
1694
+ derivedCompletedPlans = summaryTotal;
1695
+ } catch { /* intentionally empty */ }
1696
+
1697
+ // ── Root cause 2 fix: update all stale frontmatter fields ──
1698
+
1699
+ // completed_phases — derived from ROADMAP (idempotent)
1700
+ if (derivedCompletedPhases !== null && frontmatter.includes('completed_phases:')) {
1701
+ frontmatter = frontmatter.replace(
1702
+ /completed_phases:\s*\d+/,
1703
+ `completed_phases: ${derivedCompletedPhases}`,
1704
+ );
1705
+ }
1706
+
1707
+ // total_phases — keep in sync with ROADMAP
1708
+ if (derivedTotalPhases !== null && frontmatter.includes('total_phases:')) {
1709
+ frontmatter = frontmatter.replace(
1710
+ /total_phases:\s*\d+/,
1711
+ `total_phases: ${derivedTotalPhases}`,
1712
+ );
1713
+ }
1714
+
1715
+ // total_plans — derived from ROADMAP plan column sums
1716
+ if (derivedTotalPlans !== null && frontmatter.includes('total_plans:')) {
1717
+ frontmatter = frontmatter.replace(
1718
+ /total_plans:\s*\d+/,
1719
+ `total_plans: ${derivedTotalPlans}`,
1720
+ );
1721
+ }
1722
+
1723
+ // completed_plans — count of SUMMARY files on disk
1724
+ if (derivedCompletedPlans !== null && frontmatter.includes('completed_plans:')) {
1725
+ frontmatter = frontmatter.replace(
1726
+ /completed_plans:\s*\d+/,
1727
+ `completed_plans: ${derivedCompletedPlans}`,
1728
+ );
1729
+ }
1730
+
1731
+ // percent — recompute from fresh derived values
1732
+ const effectiveCompleted = derivedCompletedPhases ?? parseInt(frontmatter.match(/completed_phases:\s*(\d+)/)?.[1] ?? '0', 10);
1733
+ const effectiveTotal = derivedTotalPhases ?? parseInt(frontmatter.match(/total_phases:\s*(\d+)/)?.[1] ?? '0', 10);
1734
+ if (effectiveTotal > 0 && frontmatter.includes('percent:')) {
1735
+ const newPercent = Math.round((effectiveCompleted / effectiveTotal) * 100);
1736
+ frontmatter = frontmatter.replace(/(percent:\s*)\d+/, `$1${newPercent}`);
1737
+ }
1738
+
1739
+ // last_updated — refresh to current timestamp
1740
+ const nowIso = new Date().toISOString();
1741
+ if (frontmatter.includes('last_updated:')) {
1742
+ frontmatter = frontmatter.replace(/last_updated:\s*\S+/, `last_updated: ${nowIso}`);
1743
+ }
1744
+
1745
+ // stopped_at — set to phase completion message
1746
+ const stoppedAtValue = isLastPhase
1747
+ ? `Milestone complete (Phase ${phaseNum} was final phase)`
1748
+ : `Phase ${phaseNum} complete (${summaryCount}/${planCount}) — ready to discuss Phase ${nextPhaseNum}`;
1749
+ if (frontmatter.includes('stopped_at:')) {
1750
+ frontmatter = frontmatter.replace(/stopped_at:\s*.+/, `stopped_at: ${stoppedAtValue}`);
1751
+ } else {
1752
+ // Insert stopped_at before closing ---
1753
+ frontmatter = frontmatter.replace(/(---\s*)$/, `stopped_at: ${stoppedAtValue}\n$1`);
1754
+ }
1755
+
1756
+ // ── Root cause 2 fix: update body Current focus ──
1757
+ const focusValue = isLastPhase
1758
+ ? 'Milestone complete'
1759
+ : (nextPhaseName
1760
+ ? `Phase ${nextPhaseNum} — ${nextPhaseName.replace(/-/g, ' ')}`
1761
+ : `Phase ${nextPhaseNum}`);
1762
+ const focusPattern = /(\*\*Current focus:\*\*\s*).*/i;
1763
+ if (focusPattern.test(body)) {
1764
+ body = body.replace(focusPattern, (_m: string, prefix: string) => `${prefix}${focusValue}`);
1765
+ }
1766
+
1767
+ // Update frontmatter status field
1768
+ frontmatter = frontmatter.replace(
1769
+ /status:\s*.+/,
1770
+ `status: ${isLastPhase ? 'milestone_complete' : 'ready_to_plan'}`,
1771
+ );
1772
+
1773
+ // Reassemble and write
1774
+ const stateContent = frontmatter + '\n\n' + body;
1775
+ await writeFile(paths.state, stateContent, 'utf-8');
1776
+ stateUpdated = true;
1777
+ } finally {
1778
+ await releaseStateLock(lockPath);
1779
+ }
1780
+ }
1781
+
1782
+ // Step F2: Auto-prune STATE.md decisions when `workflow.auto_prune_state`
1783
+ // is true. Mirrors CJS cmdPhaseComplete (bin/lib/phase.cjs:1378-1390) which
1784
+ // calls cmdStatePrune({keepRecent:'3', dryRun:false, silent:true}). Without
1785
+ // this, completing phase N with auto_prune_state=true leaves stale [Phase
1786
+ // 1..N-3] decisions in STATE.md forever. (#2087)
1787
+ let autoPruned = false;
1788
+ try {
1789
+ if (existsSync(paths.config)) {
1790
+ const rawConfig = JSON.parse(await readFile(paths.config, 'utf-8')) as Record<string, unknown>;
1791
+ const wf = rawConfig.workflow as Record<string, unknown> | undefined;
1792
+ if (wf && wf.auto_prune_state === true && existsSync(paths.state)) {
1793
+ const { statePrune } = await import('./state-mutation.js');
1794
+ await statePrune(['--keep-recent', '3', '--silent'], projectDir, workstream);
1795
+ autoPruned = true;
1796
+ }
1797
+ }
1798
+ } catch { /* best-effort, matches CJS */ }
1799
+
1800
+ // Step G: Return result
1801
+ return {
1802
+ data: {
1803
+ completed_phase: phaseNum,
1804
+ phase_name: phaseInfo.phaseName,
1805
+ plans_executed: `${summaryCount}/${planCount}`,
1806
+ next_phase: nextPhaseNum,
1807
+ next_phase_name: nextPhaseName,
1808
+ is_last_phase: isLastPhase,
1809
+ date: today,
1810
+ roadmap_updated: existsSync(paths.roadmap),
1811
+ state_updated: stateUpdated,
1812
+ requirements_updated: requirementsUpdated,
1813
+ auto_pruned: autoPruned,
1814
+ warnings,
1815
+ has_warnings: warnings.length > 0,
1816
+ },
1817
+ };
1818
+ };
1819
+
1820
+ // ─── phasesClear handler ──────────────────────────────────────────────────
1821
+
1822
+ /**
1823
+ * Query handler for phases.clear.
1824
+ *
1825
+ * Port of cmdPhasesClear from milestone.cjs lines 250-277.
1826
+ * Deletes all phase directories except 999.x backlog phases.
1827
+ * Requires --confirm flag to proceed.
1828
+ *
1829
+ * @param args - args[0]: '--confirm' to proceed (optional)
1830
+ * @param projectDir - Project root directory
1831
+ * @returns QueryResult with { cleared: count }
1832
+ */
1833
+ export const phasesClear: QueryHandler = async (args, projectDir, workstream) => {
1834
+ const phasesDir = planningPaths(projectDir, workstream).phases;
1835
+ const confirm = Array.isArray(args) && args.includes('--confirm');
1836
+ let cleared = 0;
1837
+
1838
+ if (existsSync(phasesDir)) {
1839
+ const entries = await readdir(phasesDir, { withFileTypes: true });
1840
+ const dirs = entries.filter(e => e.isDirectory() && !/^999(?:\.|$)/.test(e.name));
1841
+
1842
+ if (dirs.length > 0 && !confirm) {
1843
+ throw new GSDError(
1844
+ `phases clear would delete ${dirs.length} phase director${dirs.length === 1 ? 'y' : 'ies'}. ` +
1845
+ `Pass --confirm to proceed.`,
1846
+ ErrorClassification.Validation,
1847
+ );
1848
+ }
1849
+
1850
+ for (const entry of dirs) {
1851
+ await rm(join(phasesDir, entry.name), { recursive: true, force: true });
1852
+ cleared++;
1853
+ }
1854
+ }
1855
+
1856
+ return { data: { cleared } };
1857
+ };
1858
+
1859
+ // ─── phasesArchive handler ────────────────────────────────────────────────
1860
+
1861
+ /**
1862
+ * Query handler for phases.archive.
1863
+ *
1864
+ * Extracted from cmdMilestoneComplete, milestone.cjs lines 210-227.
1865
+ * Moves milestone phase directories to milestones/{version}-phases/.
1866
+ *
1867
+ * @param args - args[0]: version string (e.g., "v3.0")
1868
+ * @param projectDir - Project root directory
1869
+ * @returns QueryResult with { archived: count, version, archive_directory }
1870
+ */
1871
+ export const phasesList: QueryHandler = async (args, projectDir, workstream) => {
1872
+ const paths = planningPaths(projectDir, workstream);
1873
+ const phasesDir = paths.phases;
1874
+
1875
+ const typeIdx = args.indexOf('--type');
1876
+ const phaseIdx = args.indexOf('--phase');
1877
+ const type = typeIdx !== -1 ? args[typeIdx + 1] : null;
1878
+ const phase = phaseIdx !== -1 ? args[phaseIdx + 1] : null;
1879
+ const includeArchived = args.includes('--include-archived');
1880
+
1881
+ if (!existsSync(phasesDir)) {
1882
+ return { data: type ? { files: [], count: 0 } : { directories: [], count: 0 } };
1883
+ }
1884
+
1885
+ const entries = await readdir(phasesDir, { withFileTypes: true });
1886
+ let dirs = entries.filter(e => e.isDirectory()).map(e => e.name);
1887
+
1888
+ if (includeArchived) {
1889
+ const milestonesDir = join(paths.planning, 'milestones');
1890
+ if (existsSync(milestonesDir)) {
1891
+ const milestoneEntries = await readdir(milestonesDir, { withFileTypes: true });
1892
+ for (const mDir of milestoneEntries.filter(e => e.isDirectory() && e.name.endsWith('-phases'))) {
1893
+ const milestone = mDir.name.replace(/-phases$/, '');
1894
+ const archivedEntries = await readdir(join(milestonesDir, mDir.name), { withFileTypes: true });
1895
+ for (const a of archivedEntries.filter(e => e.isDirectory())) {
1896
+ dirs.push(`${a.name} [${milestone}]`);
1897
+ }
1898
+ }
1899
+ }
1900
+ }
1901
+
1902
+ dirs.sort((a, b) => comparePhaseNum(a, b));
1903
+
1904
+ if (phase) {
1905
+ const normalized = normalizePhaseName(phase);
1906
+ const match = dirs.find(d => phaseTokenMatches(d, normalized));
1907
+ if (!match) {
1908
+ return { data: { files: [], count: 0, phase_dir: null, error: 'Phase not found' } };
1909
+ }
1910
+ dirs = [match];
1911
+ }
1912
+
1913
+ if (type) {
1914
+ const files: string[] = [];
1915
+ const warnings: string[] = [];
1916
+ for (const dir of dirs) {
1917
+ const dirPath = join(phasesDir, dir);
1918
+ if (!existsSync(dirPath)) continue;
1919
+ const dirFiles = await readdir(dirPath);
1920
+ let filtered: string[];
1921
+ if (type === 'plans') {
1922
+ filtered = dirFiles.filter(isCanonicalPlanFile);
1923
+ // #2893 parity — surface plan-shaped files the canonical filter
1924
+ // rejected so callers (executor init, etc.) don't silently see zero
1925
+ // plans. Per-dir prefix mirrors phase.cjs:120.
1926
+ const w = describeNonCanonicalPlans(dirFiles, filtered);
1927
+ if (w) warnings.push(`${dir}: ${w}`);
1928
+ } else if (type === 'summaries') {
1929
+ filtered = dirFiles.filter(f => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md');
1930
+ } else {
1931
+ filtered = dirFiles;
1932
+ }
1933
+ files.push(...filtered.sort());
1934
+ }
1935
+ const result: Record<string, unknown> = {
1936
+ files,
1937
+ count: files.length,
1938
+ phase_dir: phase ? dirs[0]?.replace(/^\d+(?:\.\d+)*-?/, '') : null,
1939
+ };
1940
+ if (warnings.length) result['warning'] = warnings.join(' | ');
1941
+ return { data: result };
1942
+ }
1943
+
1944
+ return { data: { directories: dirs, count: dirs.length } };
1945
+ };
1946
+
1947
+ export const phaseNextDecimal: QueryHandler = async (args, projectDir, workstream) => {
1948
+ const basePhase = args[0];
1949
+ if (!basePhase) {
1950
+ throw new GSDError('base phase number required', ErrorClassification.Validation);
1951
+ }
1952
+ assertNoNullBytes(basePhase, 'basePhase');
1953
+
1954
+ const paths = planningPaths(projectDir, workstream);
1955
+ const phasesDir = paths.phases;
1956
+ const normalized = normalizePhaseName(basePhase);
1957
+ const decimalSet = new Set<number>();
1958
+ let baseExists = false;
1959
+
1960
+ const dirNames = await listDirectories(phasesDir);
1961
+ baseExists = dirNames.some((d) => phaseTokenMatches(d, normalized));
1962
+ for (const suffix of collectDecimalSuffixesFromDirNames(normalized, dirNames)) {
1963
+ decimalSet.add(suffix);
1964
+ }
1965
+
1966
+ const roadmapPath = paths.roadmap;
1967
+ if (existsSync(roadmapPath)) {
1968
+ try {
1969
+ const roadmapContent = await readFile(roadmapPath, 'utf-8');
1970
+ for (const suffix of collectDecimalSuffixesFromRoadmap(normalized, roadmapContent)) {
1971
+ decimalSet.add(suffix);
1972
+ }
1973
+ } catch { /* ROADMAP.md read failure is non-fatal */ }
1974
+ }
1975
+
1976
+ const { next: nextDecimal, existing: existingDecimals } = computeNextDecimalPhase(normalized, decimalSet);
1977
+
1978
+ return {
1979
+ data: {
1980
+ found: baseExists,
1981
+ base_phase: normalized,
1982
+ next: nextDecimal,
1983
+ existing: existingDecimals,
1984
+ },
1985
+ };
1986
+ };
1987
+
1988
+ export const phasesArchive: QueryHandler = async (args, projectDir, workstream) => {
1989
+ const version = args[0];
1990
+ if (!version) {
1991
+ throw new GSDError('version required for phases archive', ErrorClassification.Validation);
1992
+ }
1993
+ assertNoNullBytes(version, 'version');
1994
+
1995
+ const paths = planningPaths(projectDir, workstream);
1996
+ const phasesDir = paths.phases;
1997
+ const isDirInMilestone = await getMilestonePhaseFilter(projectDir, workstream);
1998
+
1999
+ const archiveDir = join(paths.planning, 'milestones', `${version}-phases`);
2000
+ const archivedCount = await archiveDirectories(phasesDir, archiveDir, (dirName) => isDirInMilestone(dirName));
2001
+
2002
+ return {
2003
+ data: {
2004
+ archived: archivedCount,
2005
+ version,
2006
+ archive_directory: toPosixPath(relative(projectDir, archiveDir)),
2007
+ },
2008
+ };
2009
+ };
2010
+
2011
+ // ─── milestoneComplete ────────────────────────────────────────────────────
2012
+
2013
+ /**
2014
+ * Query handler for `milestone.complete` — port of `cmdMilestoneComplete` from `milestone.cjs`.
2015
+ */
2016
+ export const milestoneComplete: QueryHandler = async (args, projectDir, workstream) => {
2017
+ const version = args[0];
2018
+ if (!version) {
2019
+ throw new GSDError('version required for milestone complete (e.g., v1.0)', ErrorClassification.Validation);
2020
+ }
2021
+ // #3259: defense-in-depth — reject --help / -h as a version value before
2022
+ // any disk write, regardless of whether the dispatcher guard intercepted first.
2023
+ if (version === '--help' || version === '-h') {
2024
+ throw new GSDError(
2025
+ `"${version}" is not a valid milestone version; see \`gsd-sdk query --help\` for command list`,
2026
+ ErrorClassification.Validation,
2027
+ );
2028
+ }
2029
+ assertNoNullBytes(version, 'version');
2030
+
2031
+ const nameOpt = parseMultiwordArg(args, 'name');
2032
+ const archivePhases = args.includes('--archive-phases');
2033
+
2034
+ const paths = planningPaths(projectDir, workstream);
2035
+ const roadmapPath = paths.roadmap;
2036
+ const reqPath = paths.requirements;
2037
+ const statePath = paths.state;
2038
+ const milestonesPath = join(paths.planning, 'MILESTONES.md');
2039
+ const archiveDir = join(paths.planning, 'milestones');
2040
+ const phasesDir = paths.phases;
2041
+ const today = new Date().toISOString().split('T')[0]!;
2042
+ const milestoneName = nameOpt || version;
2043
+
2044
+ await mkdir(archiveDir, { recursive: true });
2045
+
2046
+ const isDirInMilestone = await getMilestonePhaseFilter(projectDir, workstream);
2047
+
2048
+ let phaseCount = 0;
2049
+ let totalPlans = 0;
2050
+ let totalTasks = 0;
2051
+ const accomplishments: string[] = [];
2052
+
2053
+ try {
2054
+ const dirs = (await listDirectories(phasesDir)).sort();
2055
+
2056
+ for (const dir of dirs) {
2057
+ if (!isDirInMilestone(dir)) continue;
2058
+
2059
+ phaseCount++;
2060
+ const phaseFiles = await readdir(join(phasesDir, dir));
2061
+ const plans = phaseFiles.filter((f) => f.endsWith('-PLAN.md') || f === 'PLAN.md');
2062
+ const summaries = phaseFiles.filter((f) => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md');
2063
+ totalPlans += plans.length;
2064
+
2065
+ for (const s of summaries) {
2066
+ try {
2067
+ const content = await readFile(join(phasesDir, dir, s), 'utf-8');
2068
+ const fm = extractFrontmatter(content);
2069
+ const oneLiner =
2070
+ (fm['one-liner'] as string | undefined) || extractOneLinerFromBody(content);
2071
+ if (oneLiner) {
2072
+ accomplishments.push(oneLiner);
2073
+ }
2074
+ const tasksFieldMatch = content.match(/\*\*Tasks:\*\*\s*(\d+)/);
2075
+ if (tasksFieldMatch) {
2076
+ totalTasks += parseInt(tasksFieldMatch[1]!, 10);
2077
+ } else {
2078
+ const xmlTaskMatches = content.match(/<task[\s>]/gi) || [];
2079
+ const mdTaskMatches = content.match(/##\s*Task\s*\d+/gi) || [];
2080
+ totalTasks += xmlTaskMatches.length || mdTaskMatches.length;
2081
+ }
2082
+ } catch {
2083
+ /* intentionally empty */
2084
+ }
2085
+ }
2086
+ }
2087
+ } catch {
2088
+ /* intentionally empty */
2089
+ }
2090
+
2091
+ if (existsSync(roadmapPath)) {
2092
+ const roadmapContent = await readFile(roadmapPath, 'utf-8');
2093
+ await writeFile(join(archiveDir, `${version}-ROADMAP.md`), roadmapContent, 'utf-8');
2094
+ }
2095
+
2096
+ if (existsSync(reqPath)) {
2097
+ const reqContent = await readFile(reqPath, 'utf-8');
2098
+ const archiveHeader =
2099
+ `# Requirements Archive: ${version} ${milestoneName}\n\n` +
2100
+ `**Archived:** ${today}\n**Status:** SHIPPED\n\n` +
2101
+ `For current requirements, see \`.planning/REQUIREMENTS.md\`.\n\n---\n\n`;
2102
+ await writeFile(join(archiveDir, `${version}-REQUIREMENTS.md`), archiveHeader + reqContent, 'utf-8');
2103
+ }
2104
+
2105
+ const auditFile = join(projectDir, '.planning', `${version}-MILESTONE-AUDIT.md`);
2106
+ if (existsSync(auditFile)) {
2107
+ await rename(auditFile, join(archiveDir, `${version}-MILESTONE-AUDIT.md`));
2108
+ }
2109
+
2110
+ const accomplishmentsList = accomplishments.map((a) => `- ${a}`).join('\n');
2111
+ const milestoneEntry =
2112
+ `## ${version} ${milestoneName} (Shipped: ${today})\n\n` +
2113
+ `**Phases completed:** ${phaseCount} phases, ${totalPlans} plans, ${totalTasks} tasks\n\n` +
2114
+ `**Key accomplishments:**\n${accomplishmentsList || '- (none recorded)'}\n\n---\n\n`;
2115
+
2116
+ if (existsSync(milestonesPath)) {
2117
+ const existing = await readFile(milestonesPath, 'utf-8');
2118
+ if (!existing.trim()) {
2119
+ await writeFile(milestonesPath, normalizeMd(`# Milestones\n\n${milestoneEntry}`), 'utf-8');
2120
+ } else {
2121
+ const headerMatch = existing.match(/^(#{1,3}\s+[^\n]*\n\n?)/);
2122
+ if (headerMatch) {
2123
+ const header = headerMatch[1]!;
2124
+ const rest = existing.slice(header.length);
2125
+ await writeFile(milestonesPath, normalizeMd(header + milestoneEntry + rest), 'utf-8');
2126
+ } else {
2127
+ await writeFile(milestonesPath, normalizeMd(milestoneEntry + existing), 'utf-8');
2128
+ }
2129
+ }
2130
+ } else {
2131
+ await writeFile(milestonesPath, normalizeMd(`# Milestones\n\n${milestoneEntry}`), 'utf-8');
2132
+ }
2133
+
2134
+ if (existsSync(statePath)) {
2135
+ await readModifyWriteStateMdFull(projectDir, (stateContent) => {
2136
+ let next = stateReplaceFieldWithFallback(
2137
+ stateContent,
2138
+ 'Status',
2139
+ null,
2140
+ `${version} milestone complete`,
2141
+ );
2142
+ next = stateReplaceFieldWithFallback(next, 'Last Activity', 'Last activity', today);
2143
+ next = stateReplaceFieldWithFallback(
2144
+ next,
2145
+ 'Last Activity Description',
2146
+ null,
2147
+ `${version} milestone completed and archived`,
2148
+ );
2149
+
2150
+ const positionPattern = /(##\s*Current Position\s*\n)([\s\S]*?)(?=\n##|$)/i;
2151
+ const closedPositionBody =
2152
+ `\nPhase: Milestone ${version} complete\n` +
2153
+ `Plan: —\n` +
2154
+ `Status: Awaiting next milestone\n` +
2155
+ `Last activity: ${today} — Milestone ${version} completed and archived\n\n`;
2156
+ if (positionPattern.test(next)) {
2157
+ next = next.replace(positionPattern, (_m, header) => `${header}${closedPositionBody}`);
2158
+ } else {
2159
+ next = `${next.trimEnd()}\n\n## Current Position\n${closedPositionBody}`;
2160
+ }
2161
+
2162
+ const operatorPattern = /(##\s*Operator Next Steps\s*\n)([\s\S]*?)(?=\n##|$)/i;
2163
+ if (operatorPattern.test(next)) {
2164
+ next = next.replace(
2165
+ operatorPattern,
2166
+ `$1\n- Start the next milestone with /gsd-new-milestone\n\n`,
2167
+ );
2168
+ } else {
2169
+ next = `${next.trimEnd()}\n\n## Operator Next Steps\n\n- Start the next milestone with /gsd-new-milestone\n`;
2170
+ }
2171
+
2172
+ return next;
2173
+ }, workstream);
2174
+ }
2175
+
2176
+ let phasesArchived = false;
2177
+ if (archivePhases) {
2178
+ try {
2179
+ const phaseArchiveDir = join(archiveDir, `${version}-phases`);
2180
+ const archivedCount = await archiveDirectories(
2181
+ phasesDir,
2182
+ phaseArchiveDir,
2183
+ (dirName) => isDirInMilestone(dirName),
2184
+ );
2185
+ phasesArchived = archivedCount > 0;
2186
+ } catch {
2187
+ /* intentionally empty */
2188
+ }
2189
+ }
2190
+
2191
+ return {
2192
+ data: {
2193
+ version,
2194
+ name: milestoneName,
2195
+ date: today,
2196
+ phases: phaseCount,
2197
+ plans: totalPlans,
2198
+ tasks: totalTasks,
2199
+ accomplishments,
2200
+ archived: {
2201
+ roadmap: existsSync(join(archiveDir, `${version}-ROADMAP.md`)),
2202
+ requirements: existsSync(join(archiveDir, `${version}-REQUIREMENTS.md`)),
2203
+ audit: existsSync(join(archiveDir, `${version}-MILESTONE-AUDIT.md`)),
2204
+ phases: phasesArchived,
2205
+ },
2206
+ milestones_updated: true,
2207
+ state_updated: existsSync(statePath),
2208
+ },
2209
+ };
2210
+ };