@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,1971 @@
1
+ /**
2
+ * Unit tests for phase lifecycle handlers.
3
+ *
4
+ * Tests phaseAdd, phaseAddBatch, phaseInsert, phaseScaffold, replaceInCurrentMilestone,
5
+ * and readModifyWriteRoadmapMd.
6
+ */
7
+
8
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
9
+ import { mkdtemp, writeFile, readFile, rm, mkdir, readdir } from 'node:fs/promises';
10
+ import { join } from 'node:path';
11
+ import { tmpdir } from 'node:os';
12
+ import { existsSync } from 'node:fs';
13
+
14
+ // ─── Fixtures ─────────────────────────────────────────────────────────────
15
+
16
+ const MINIMAL_ROADMAP = `# Roadmap
17
+
18
+ ## Current Milestone: v3.0 SDK-First Migration
19
+
20
+ ### Phase 9: Foundation
21
+
22
+ **Goal:** Build foundation
23
+ **Requirements**: TBD
24
+ **Depends on:** Phase 8
25
+ **Plans:** 3 plans
26
+
27
+ Plans:
28
+ - [x] 09-01 (Foundation setup)
29
+
30
+ ### Phase 10: Read-Only Queries
31
+
32
+ **Goal:** Port queries.
33
+ **Requirements**: TBD
34
+ **Depends on:** Phase 9
35
+ **Plans:** 3 plans
36
+
37
+ Plans:
38
+ - [x] 10-01 (Query setup)
39
+
40
+ ---
41
+ *Last updated: 2026-04-08*
42
+ `;
43
+
44
+ const ROADMAP_WITH_DETAILS = `# Roadmap
45
+
46
+ <details>
47
+ <summary>v1.0 (shipped)</summary>
48
+
49
+ ### Phase 1: Old Phase
50
+
51
+ **Goal:** Shipped already
52
+ **Plans:** 2 plans
53
+
54
+ </details>
55
+
56
+ ## Current Milestone: v3.0 SDK-First Migration
57
+
58
+ ### Phase 9: Foundation
59
+
60
+ **Goal:** Build foundation
61
+ **Requirements**: TBD
62
+ **Plans:** 3 plans
63
+
64
+ ### Phase 10: Read-Only Queries
65
+
66
+ **Goal:** Port queries.
67
+ **Requirements**: TBD
68
+ **Plans:** 3 plans
69
+
70
+ ---
71
+ *Last updated: 2026-04-08*
72
+ `;
73
+
74
+ const MINIMAL_STATE = `---
75
+ gsd_state_version: 1.0
76
+ milestone: v3.0
77
+ milestone_name: SDK-First Migration
78
+ status: executing
79
+ ---
80
+
81
+ # Project State
82
+
83
+ ## Current Position
84
+
85
+ Phase: 10 (Read-Only Queries) — EXECUTING
86
+ Plan: 2 of 3
87
+ Status: Executing Phase 10
88
+
89
+ ## Session Continuity
90
+
91
+ Last session: 2026-04-07T10:00:00.000Z
92
+ Stopped at: Completed 10-02-PLAN.md
93
+ `;
94
+
95
+ /** Create a test project with .planning structure. */
96
+ async function setupTestProject(
97
+ tmpDir: string,
98
+ opts?: { roadmap?: string; state?: string; config?: Record<string, unknown>; phases?: string[] }
99
+ ): Promise<string> {
100
+ const planningDir = join(tmpDir, '.planning');
101
+ await mkdir(planningDir, { recursive: true });
102
+ const phasesDir = join(planningDir, 'phases');
103
+ await mkdir(phasesDir, { recursive: true });
104
+ await writeFile(join(planningDir, 'ROADMAP.md'), opts?.roadmap || MINIMAL_ROADMAP, 'utf-8');
105
+ await writeFile(join(planningDir, 'STATE.md'), opts?.state || MINIMAL_STATE, 'utf-8');
106
+ await writeFile(
107
+ join(planningDir, 'config.json'),
108
+ JSON.stringify(opts?.config || { model_profile: 'balanced', phase_naming: 'sequential' }),
109
+ 'utf-8'
110
+ );
111
+ // Create phase directories if requested
112
+ if (opts?.phases) {
113
+ for (const phase of opts.phases) {
114
+ await mkdir(join(phasesDir, phase), { recursive: true });
115
+ await writeFile(join(phasesDir, phase, '.gitkeep'), '', 'utf-8');
116
+ }
117
+ }
118
+ return tmpDir;
119
+ }
120
+
121
+ // ─── Tests ────────────────────────────────────────────────────────────────
122
+
123
+ let tmpDir: string;
124
+
125
+ beforeEach(async () => {
126
+ tmpDir = await mkdtemp(join(tmpdir(), 'gsd-lifecycle-'));
127
+ });
128
+
129
+ afterEach(async () => {
130
+ await rm(tmpDir, { recursive: true, force: true });
131
+ });
132
+
133
+ // ─── replaceInCurrentMilestone ──────────────────────────────────────────
134
+
135
+ describe('replaceInCurrentMilestone', () => {
136
+ it('replaces in full content when no details blocks', async () => {
137
+ const { replaceInCurrentMilestone } = await import('./phase-lifecycle.js');
138
+ const content = '### Phase 9: Foundation\n**Plans:** 3 plans\n';
139
+ const result = replaceInCurrentMilestone(content, /3 plans/, '4 plans');
140
+ expect(result).toContain('4 plans');
141
+ });
142
+
143
+ it('only replaces after last </details> block', async () => {
144
+ const { replaceInCurrentMilestone } = await import('./phase-lifecycle.js');
145
+ const content = '<details>\n### Phase 1: Old\n**Plans:** 3 plans\n</details>\n\n### Phase 9: Current\n**Plans:** 3 plans\n';
146
+ const result = replaceInCurrentMilestone(content, /3 plans/, '4 plans');
147
+ // Should only replace in the current milestone section (after </details>)
148
+ const before = result.slice(0, result.indexOf('</details>') + '</details>'.length);
149
+ const after = result.slice(result.indexOf('</details>') + '</details>'.length);
150
+ expect(before).toContain('3 plans'); // old milestone untouched
151
+ expect(after).toContain('4 plans'); // current milestone updated
152
+ });
153
+
154
+ it('replaces only in current milestone when older milestones are wrapped in <details>', async () => {
155
+ const { replaceInCurrentMilestone } = await import('./phase-lifecycle.js');
156
+ const content = [
157
+ '# Roadmap',
158
+ '',
159
+ '<details>',
160
+ '<summary>✅ v1.18 (shipped)</summary>',
161
+ '',
162
+ '### Phase 1: Old Phase',
163
+ '',
164
+ '- [ ] Phase 1: Old Phase',
165
+ '',
166
+ '</details>',
167
+ '',
168
+ '<details>',
169
+ '<summary>✅ v1.19 (shipped)</summary>',
170
+ '',
171
+ '### Phase 2: Another Old Phase',
172
+ '',
173
+ '</details>',
174
+ '',
175
+ '## Current Milestone: v1.20',
176
+ '',
177
+ '- [ ] Phase 3: Current work',
178
+ '',
179
+ '### Phase 3: Current work',
180
+ '',
181
+ '**Plans:** 0/2 plans',
182
+ '',
183
+ ].join('\n');
184
+
185
+ const pattern = /\*\*Plans:\*\* [^\n]+/;
186
+ const result = replaceInCurrentMilestone(content, pattern, '**Plans:** 2/2 plans complete');
187
+
188
+ // Should update Phase 3's Plans line (current milestone)
189
+ expect(result).toContain('**Plans:** 2/2 plans complete');
190
+ // Should NOT touch v1.18 or v1.19 sections
191
+ expect(result).toContain('✅ v1.18');
192
+ expect(result).toContain('✅ v1.19');
193
+ });
194
+
195
+ it('replaces inside active milestone when it is wrapped in a <details> block', async () => {
196
+ const { replaceInCurrentMilestone } = await import('./phase-lifecycle.js');
197
+ // Scenario: active milestone is collapsed in <details> (e.g. user collapsed it)
198
+ const content = [
199
+ '# Roadmap',
200
+ '',
201
+ '<details>',
202
+ '<summary>✅ v1.18 (shipped)</summary>',
203
+ '',
204
+ '### Phase 1: Old Phase',
205
+ '',
206
+ '**Plans:** 1/1 plans',
207
+ '',
208
+ '</details>',
209
+ '',
210
+ '<details>',
211
+ '<summary>🚧 v1.19 in-progress</summary>',
212
+ '',
213
+ '### Phase 2: Current Work',
214
+ '',
215
+ '**Plans:** 1/2 plans',
216
+ '',
217
+ '</details>',
218
+ '',
219
+ ].join('\n');
220
+
221
+ const pattern = /\*\*Plans:\*\* [^\n]+/g;
222
+ const result = replaceInCurrentMilestone(content, pattern, '**Plans:** 2/2 plans complete');
223
+
224
+ // The replacement should happen somewhere in the content (not silently dropped)
225
+ expect(result).toContain('**Plans:** 2/2 plans complete');
226
+ // v1.18 old plans line should remain untouched
227
+ expect(result).toContain('**Plans:** 1/1 plans');
228
+ });
229
+
230
+ it('replaces inside active <details> even when footer text exists after </details>', async () => {
231
+ const { replaceInCurrentMilestone } = await import('./phase-lifecycle.js');
232
+ // Scenario: active milestone is the last <details> block, but a footer
233
+ // (e.g. "---\n*Last updated*") follows it. The fast-path sees after.trim()
234
+ // non-empty and replaces in the footer instead of inside the active block.
235
+ const content = [
236
+ '# Roadmap',
237
+ '',
238
+ '<details>',
239
+ '<summary>v1.0 (Archived)</summary>',
240
+ '',
241
+ '**Plans:** 1/1 plans',
242
+ '',
243
+ '</details>',
244
+ '',
245
+ '<details>',
246
+ '<summary>v2.0 (Active)</summary>',
247
+ '',
248
+ '**Plans:** 1/2 plans',
249
+ '',
250
+ '</details>',
251
+ '',
252
+ '---',
253
+ '*Last updated: 2026-01-01*',
254
+ ].join('\n');
255
+
256
+ const pattern = /\*\*Plans:\*\* [^\n]+/g;
257
+ const result = replaceInCurrentMilestone(content, pattern, '**Plans:** 2/2 plans complete');
258
+
259
+ // Active milestone inside last <details> should be updated
260
+ expect(result).toContain('**Plans:** 2/2 plans complete');
261
+ // Archived milestone should remain untouched
262
+ expect(result).toContain('**Plans:** 1/1 plans');
263
+ // Footer should be preserved verbatim
264
+ expect(result).toContain('---');
265
+ expect(result).toContain('*Last updated: 2026-01-01*');
266
+ });
267
+ });
268
+
269
+ // ─── readModifyWriteRoadmapMd ───────────────────────────────────────────
270
+
271
+ describe('readModifyWriteRoadmapMd', () => {
272
+ it('reads, modifies, and writes ROADMAP.md atomically', async () => {
273
+ const { readModifyWriteRoadmapMd } = await import('./phase-lifecycle.js');
274
+ await setupTestProject(tmpDir);
275
+ const result = await readModifyWriteRoadmapMd(tmpDir, (content) => {
276
+ return content.replace('Port queries.', 'Port all queries.');
277
+ });
278
+ expect(result).toContain('Port all queries.');
279
+ const ondisk = await readFile(join(tmpDir, '.planning', 'ROADMAP.md'), 'utf-8');
280
+ expect(ondisk).toContain('Port all queries.');
281
+ });
282
+
283
+ it('creates and releases lockfile', async () => {
284
+ const { readModifyWriteRoadmapMd } = await import('./phase-lifecycle.js');
285
+ await setupTestProject(tmpDir);
286
+ await readModifyWriteRoadmapMd(tmpDir, (c) => c);
287
+ // Lock should be released after operation
288
+ const lockPath = join(tmpDir, '.planning', 'ROADMAP.md.lock');
289
+ expect(existsSync(lockPath)).toBe(false);
290
+ });
291
+ });
292
+
293
+ // ─── phaseAdd ──────────────────────────────────────────────────────────
294
+
295
+ describe('phaseAdd', () => {
296
+ it('creates directory and updates ROADMAP.md for sequential phase', async () => {
297
+ const { phaseAdd } = await import('./phase-lifecycle.js');
298
+ await setupTestProject(tmpDir, {
299
+ phases: ['09-foundation', '10-read-only-queries'],
300
+ });
301
+
302
+ const result = await phaseAdd(['New Feature'], tmpDir);
303
+ const data = result.data as Record<string, unknown>;
304
+
305
+ expect(data.phase_number).toBe(11);
306
+ expect(data.padded).toBe('11');
307
+ expect(data.name).toBe('New Feature');
308
+ expect(data.slug).toBe('new-feature');
309
+ expect(data.naming_mode).toBe('sequential');
310
+
311
+ // Verify directory was created
312
+ const dir = data.directory as string;
313
+ expect(dir).toContain('11-new-feature');
314
+ const phasesDir = join(tmpDir, '.planning', 'phases');
315
+ const entries = await readdir(phasesDir, { withFileTypes: true });
316
+ const newDir = entries.find(e => e.isDirectory() && e.name.includes('11-new-feature'));
317
+ expect(newDir).toBeTruthy();
318
+
319
+ // Verify .gitkeep
320
+ expect(existsSync(join(phasesDir, newDir!.name, '.gitkeep'))).toBe(true);
321
+
322
+ // Verify ROADMAP.md updated
323
+ const roadmap = await readFile(join(tmpDir, '.planning', 'ROADMAP.md'), 'utf-8');
324
+ expect(roadmap).toContain('### Phase 11: New Feature');
325
+ expect(roadmap).toContain('**Goal:** [To be planned]');
326
+ });
327
+
328
+ it('skips exactly phase 999 (backlog sentinel) when calculating next number', async () => {
329
+ const { phaseAdd } = await import('./phase-lifecycle.js');
330
+ const roadmapWith999 = MINIMAL_ROADMAP.replace(
331
+ '---\n*Last updated',
332
+ '### Phase 999: Backlog\n\n**Goal:** Backlog items\n**Plans:** 0 plans\n\n---\n*Last updated'
333
+ );
334
+ await setupTestProject(tmpDir, { roadmap: roadmapWith999 });
335
+
336
+ const result = await phaseAdd(['After Ten'], tmpDir);
337
+ const data = result.data as Record<string, unknown>;
338
+ // Should be 11, not 1000
339
+ expect(data.phase_number).toBe(11);
340
+ });
341
+
342
+ it('returns correct next phase id for projects using 1000+ canonical phase numbers (regression #3774)', async () => {
343
+ // Bug: scanSequentialMaxPhaseFromMilestone and scanSequentialMaxPhaseFromDirs
344
+ // used `num >= 999` instead of `num === 999`, causing every phase ≥ 1000 to be
345
+ // excluded from the max-scan. computeNextSequentialPhaseId returned 1 (0+1)
346
+ // instead of 1501 for a project whose highest phase is 1500.
347
+ const { phaseAdd } = await import('./phase-lifecycle.js');
348
+
349
+ const roadmapWith1000Plus = [
350
+ '# Roadmap',
351
+ '',
352
+ '## Current Milestone: v10.0 Large Project',
353
+ '',
354
+ '### Phase 1000: Foundation',
355
+ '',
356
+ '**Goal:** Foundation',
357
+ '**Requirements**: TBD',
358
+ '**Plans:** 1 plans',
359
+ '',
360
+ 'Plans:',
361
+ '- [x] 1000-01 (Foundation setup)',
362
+ '',
363
+ '### Phase 1500: Latest',
364
+ '',
365
+ '**Goal:** Latest',
366
+ '**Requirements**: TBD',
367
+ '**Depends on:** Phase 1499',
368
+ '**Plans:** 1 plans',
369
+ '',
370
+ 'Plans:',
371
+ '- [x] 1500-01 (Latest step)',
372
+ '',
373
+ '---',
374
+ '*Last updated: 2026-05-20*',
375
+ '',
376
+ ].join('\n');
377
+
378
+ const phases = [
379
+ '1000-foundation',
380
+ '1100-alpha',
381
+ '1200-beta',
382
+ '1300-gamma',
383
+ '1400-delta',
384
+ '1500-latest',
385
+ ];
386
+
387
+ await setupTestProject(tmpDir, { roadmap: roadmapWith1000Plus, phases });
388
+
389
+ const result = await phaseAdd(['Next After 1500'], tmpDir);
390
+ const data = result.data as Record<string, unknown>;
391
+ // Must be 1501, not 1 (the pre-fix bug value)
392
+ expect(data.phase_number).toBe(1501);
393
+ });
394
+
395
+ it('distinguishes === 999 guard from === 1000 off-by-one: [999, 1000] fixture must yield 1001 (regression #3774)', async () => {
396
+ // Distinguishing fixture: phases [999, 1000] on disk + in ROADMAP.
397
+ // With correct guard (=== 999): skips 999, keeps 1000 as max → next = 1001 ✓
398
+ // With off-by-one guard (=== 1000): skips 1000, keeps 999 → max = 999 but
399
+ // 999 is itself skipped by the equality guard (999 === 999 is true when
400
+ // the guard fires), so actually keeps nothing → max = 0 → next = 1 ✗.
401
+ // Either way, the result diverges from 1001, catching the regression.
402
+ const { phaseAdd } = await import('./phase-lifecycle.js');
403
+
404
+ const roadmapWith999and1000 = [
405
+ '# Roadmap',
406
+ '',
407
+ '## Current Milestone: v1.0',
408
+ '',
409
+ '### Phase 999: Backlog',
410
+ '',
411
+ '**Goal:** Backlog sentinel',
412
+ '**Plans:** 0 plans',
413
+ '',
414
+ '### Phase 1000: First Four-Digit Phase',
415
+ '',
416
+ '**Goal:** First canonical phase above backlog sentinel',
417
+ '**Requirements**: TBD',
418
+ '**Plans:** 1 plans',
419
+ '',
420
+ 'Plans:',
421
+ '- [x] 1000-01 (initial work)',
422
+ '',
423
+ '---',
424
+ '*Last updated: 2026-05-21*',
425
+ '',
426
+ ].join('\n');
427
+
428
+ const phases = [
429
+ '999-backlog',
430
+ '1000-first-four-digit',
431
+ ];
432
+
433
+ await setupTestProject(tmpDir, { roadmap: roadmapWith999and1000, phases });
434
+
435
+ const result = await phaseAdd(['After One Thousand'], tmpDir);
436
+ const data = result.data as Record<string, unknown>;
437
+ // Must be 1001: skips 999 (backlog sentinel), keeps 1000 as max, adds 1
438
+ expect(data.phase_number).toBe(1001);
439
+ });
440
+
441
+ it('throws GSDError with Validation for empty description', async () => {
442
+ const { phaseAdd } = await import('./phase-lifecycle.js');
443
+ await setupTestProject(tmpDir);
444
+
445
+ await expect(phaseAdd([], tmpDir)).rejects.toThrow('description required');
446
+ });
447
+
448
+ it('inserts phase entry before last --- separator', async () => {
449
+ const { phaseAdd } = await import('./phase-lifecycle.js');
450
+ await setupTestProject(tmpDir);
451
+
452
+ await phaseAdd(['Inserted Phase'], tmpDir);
453
+ const roadmap = await readFile(join(tmpDir, '.planning', 'ROADMAP.md'), 'utf-8');
454
+
455
+ // The new phase should appear before the trailing ---
456
+ const phaseIdx = roadmap.indexOf('### Phase 11: Inserted Phase');
457
+ const sepIdx = roadmap.lastIndexOf('\n---');
458
+ expect(phaseIdx).toBeLessThan(sepIdx);
459
+ expect(phaseIdx).toBeGreaterThan(0);
460
+ });
461
+
462
+ it('detects max phase from bullet checklist format (regression #2726)', async () => {
463
+ const { phaseAdd } = await import('./phase-lifecycle.js');
464
+
465
+ const roadmap = [
466
+ '# Roadmap',
467
+ '',
468
+ '## Current Milestone: v5.0',
469
+ '',
470
+ '- [x] Phase 76: Data Import',
471
+ '- [x] Phase 77: Data Transform',
472
+ '- [ ] Phase 88: Final Cleanup',
473
+ '',
474
+ ].join('\n');
475
+
476
+ await setupTestProject(tmpDir, {
477
+ roadmap,
478
+ state: MINIMAL_STATE,
479
+ phases: [],
480
+ });
481
+
482
+ const result = await phaseAdd(['new-feature'], tmpDir);
483
+ const data = result.data as Record<string, unknown>;
484
+
485
+ expect(data.phase_number).toBe(89);
486
+ expect(data.padded).toBe('89');
487
+ });
488
+
489
+ it('detects max phase from bold inline format (regression #2726)', async () => {
490
+ const { phaseAdd } = await import('./phase-lifecycle.js');
491
+
492
+ const roadmap = [
493
+ '# Roadmap',
494
+ '',
495
+ '## Current Milestone: v5.0',
496
+ '',
497
+ '**Phase 50: Core Infrastructure**',
498
+ '**Phase 51: API Layer**',
499
+ '',
500
+ ].join('\n');
501
+
502
+ await setupTestProject(tmpDir, {
503
+ roadmap,
504
+ state: MINIMAL_STATE,
505
+ phases: [],
506
+ });
507
+
508
+ const result = await phaseAdd(['new-feature'], tmpDir);
509
+ const data = result.data as Record<string, unknown>;
510
+
511
+ expect(data.phase_number).toBe(52);
512
+ });
513
+
514
+ it('falls back to filesystem scan when no phase matches in ROADMAP (regression #2726)', async () => {
515
+ const { phaseAdd } = await import('./phase-lifecycle.js');
516
+
517
+ // ROADMAP with no recognizable phase entries
518
+ const roadmap = '# Roadmap\n\n## Current Milestone: v5.0\n\nSome content without phases\n';
519
+
520
+ await setupTestProject(tmpDir, {
521
+ roadmap,
522
+ state: MINIMAL_STATE,
523
+ phases: ['45-legacy-phase', '46-another-phase'],
524
+ });
525
+
526
+ const result = await phaseAdd(['new-feature'], tmpDir);
527
+ const data = result.data as Record<string, unknown>;
528
+
529
+ // Should detect phases 45 and 46 on disk, so new phase = 47
530
+ expect(data.phase_number).toBe(47);
531
+ });
532
+
533
+ it('filesystem fallback handles project-code-prefixed phase directories (regression coderabbit)', async () => {
534
+ const { phaseAdd } = await import('./phase-lifecycle.js');
535
+
536
+ const roadmap = '# Roadmap\n\n## Current Milestone: v5.0\n\nSome content\n';
537
+
538
+ await setupTestProject(tmpDir, {
539
+ roadmap,
540
+ state: MINIMAL_STATE,
541
+ phases: [],
542
+ });
543
+
544
+ // Create prefixed directories manually (project_code = "CK" scenario)
545
+ const phasesDir = join(tmpDir, '.planning', 'phases');
546
+ await mkdir(join(phasesDir, 'CK-45-legacy-phase'), { recursive: true });
547
+ await mkdir(join(phasesDir, 'CK-46-another-phase'), { recursive: true });
548
+
549
+ const result = await phaseAdd(['new-feature'], tmpDir);
550
+ const data = result.data as Record<string, unknown>;
551
+
552
+ // Should detect CK-45 and CK-46, so new phase = 47
553
+ expect(data.phase_number).toBe(47);
554
+ });
555
+
556
+ // ── Symptom A: --dry-run flag (#3226) ─────────────────────────────────
557
+
558
+ it('--dry-run returns JSON result without creating any files or modifying ROADMAP', async () => {
559
+ const { phaseAdd } = await import('./phase-lifecycle.js');
560
+ await setupTestProject(tmpDir, {
561
+ phases: ['09-foundation', '10-read-only-queries'],
562
+ });
563
+
564
+ const roadmapBefore = await readFile(join(tmpDir, '.planning', 'ROADMAP.md'), 'utf-8');
565
+ const result = await phaseAdd(['Dry Run Phase', '--dry-run'], tmpDir);
566
+ const data = result.data as Record<string, unknown>;
567
+
568
+ // Result must include the computed fields
569
+ expect(data.phase_number).toBe(11);
570
+ expect(data.padded).toBe('11');
571
+ expect(data.name).toBe('Dry Run Phase');
572
+ expect(data.slug).toBe('dry-run-phase');
573
+ expect(data.dry_run).toBe(true);
574
+ expect(typeof data.roadmap_entry).toBe('string');
575
+ expect((data.roadmap_entry as string)).toContain('### Phase 11: Dry Run Phase');
576
+
577
+ // ROADMAP.md must be unchanged
578
+ const roadmapAfter = await readFile(join(tmpDir, '.planning', 'ROADMAP.md'), 'utf-8');
579
+ expect(roadmapAfter).toBe(roadmapBefore);
580
+
581
+ // No new phase directory must have been created
582
+ const phasesDir = join(tmpDir, '.planning', 'phases');
583
+ const entries = await readdir(phasesDir, { withFileTypes: true });
584
+ const newDir = entries.find(e => e.isDirectory() && e.name.includes('11-dry-run-phase'));
585
+ expect(newDir).toBeUndefined();
586
+ });
587
+
588
+ it('--dry-run works when flag appears after customId position', async () => {
589
+ const { phaseAdd } = await import('./phase-lifecycle.js');
590
+ await setupTestProject(tmpDir, {
591
+ phases: ['09-foundation', '10-read-only-queries'],
592
+ });
593
+
594
+ const roadmapBefore = await readFile(join(tmpDir, '.planning', 'ROADMAP.md'), 'utf-8');
595
+ // description + --dry-run — no customId; flag must not be mistaken for customId
596
+ const result = await phaseAdd(['My Feature', '--dry-run'], tmpDir);
597
+ const data = result.data as Record<string, unknown>;
598
+
599
+ expect(data.dry_run).toBe(true);
600
+ expect(data.phase_number).toBe(11);
601
+
602
+ // ROADMAP must still be untouched
603
+ const roadmapAfter = await readFile(join(tmpDir, '.planning', 'ROADMAP.md'), 'utf-8');
604
+ expect(roadmapAfter).toBe(roadmapBefore);
605
+ });
606
+
607
+ // ── Symptom C: unknown flag rejection (#3226) ──────────────────────────
608
+
609
+ it('rejects unknown --flags with a validation error naming the flag', async () => {
610
+ const { phaseAdd } = await import('./phase-lifecycle.js');
611
+ await setupTestProject(tmpDir);
612
+
613
+ await expect(phaseAdd(['My Feature', '--bogus-flag'], tmpDir)).rejects.toThrow('--bogus-flag');
614
+ });
615
+
616
+ it('rejects any unknown --flag even when mixed with dry-run', async () => {
617
+ const { phaseAdd } = await import('./phase-lifecycle.js');
618
+ await setupTestProject(tmpDir);
619
+
620
+ await expect(phaseAdd(['Desc', '--dry-run', '--unknown'], tmpDir)).rejects.toThrow('--unknown');
621
+ });
622
+
623
+ // ── Symptom B: ROADMAP heading scan counts ### Phase N: (#3226 verify) ─
624
+
625
+ it('scans ### Phase N: headings in ROADMAP when no on-disk dirs exist (B already fixed)', async () => {
626
+ const { phaseAdd } = await import('./phase-lifecycle.js');
627
+
628
+ const roadmap = [
629
+ '# Roadmap',
630
+ '',
631
+ '## Current Milestone: v5.0',
632
+ '',
633
+ '### Phase 5: Foundation',
634
+ '',
635
+ '**Goal:** Build foundation',
636
+ '**Plans:** 0 plans',
637
+ '',
638
+ ].join('\n');
639
+
640
+ await setupTestProject(tmpDir, {
641
+ roadmap,
642
+ state: MINIMAL_STATE,
643
+ phases: [], // no on-disk dirs — must rely on ROADMAP scan
644
+ });
645
+
646
+ const result = await phaseAdd(['Next Phase'], tmpDir);
647
+ const data = result.data as Record<string, unknown>;
648
+
649
+ // Must detect Phase 5 from ### heading → next = 6, not 1
650
+ expect(data.phase_number).toBe(6);
651
+ });
652
+
653
+ // ── Concurrent phase.add: no duplicate IDs (CR finding) ────────────────
654
+ it('concurrent phase.add calls produce distinct sequential phase numbers', async () => {
655
+ const { phaseAdd } = await import('./phase-lifecycle.js');
656
+ await setupTestProject(tmpDir, {
657
+ phases: ['09-foundation', '10-read-only-queries'],
658
+ });
659
+
660
+ // Fire two phase.add calls simultaneously. If computation happens outside
661
+ // the lock both will observe maxPhase=10 and claim newPhaseId=11 — collision.
662
+ const [r1, r2] = await Promise.all([
663
+ phaseAdd(['Concurrent Alpha'], tmpDir),
664
+ phaseAdd(['Concurrent Beta'], tmpDir),
665
+ ]);
666
+
667
+ const n1 = (r1.data as Record<string, unknown>).phase_number as number;
668
+ const n2 = (r2.data as Record<string, unknown>).phase_number as number;
669
+
670
+ // Both must succeed and produce DIFFERENT numbers
671
+ expect(n1).not.toBe(n2);
672
+
673
+ // The pair must be {11, 12} — no gaps, no duplicates
674
+ const sorted = [n1, n2].sort((a, b) => a - b);
675
+ expect(sorted).toEqual([11, 12]);
676
+
677
+ // ROADMAP.md must contain exactly one entry for each phase
678
+ const roadmap = await readFile(join(tmpDir, '.planning', 'ROADMAP.md'), 'utf-8');
679
+ const phase11Count = (roadmap.match(/### Phase 11:/g) || []).length;
680
+ const phase12Count = (roadmap.match(/### Phase 12:/g) || []).length;
681
+ expect(phase11Count).toBe(1);
682
+ expect(phase12Count).toBe(1);
683
+
684
+ // Both phase directories must exist on disk
685
+ const phasesDir = join(tmpDir, '.planning', 'phases');
686
+ const entries = await readdir(phasesDir, { withFileTypes: true });
687
+ const dirs = entries.filter(e => e.isDirectory()).map(e => e.name);
688
+ const has11 = dirs.some(d => d.startsWith('11-'));
689
+ const has12 = dirs.some(d => d.startsWith('12-'));
690
+ expect(has11).toBe(true);
691
+ expect(has12).toBe(true);
692
+ });
693
+ });
694
+
695
+ // ─── phaseAddBatch ─────────────────────────────────────────────────────
696
+
697
+ describe('phaseAddBatch', () => {
698
+ it('adds multiple sequential phases in one pass', async () => {
699
+ const { phaseAddBatch } = await import('./phase-lifecycle.js');
700
+ await setupTestProject(tmpDir, {
701
+ phases: ['09-foundation', '10-read-only-queries'],
702
+ });
703
+
704
+ const result = await phaseAddBatch(['Alpha', 'Beta'], tmpDir);
705
+ const data = result.data as { phases: Array<Record<string, unknown>>; count: number };
706
+
707
+ expect(data.count).toBe(2);
708
+ expect(data.phases[0].phase_number).toBe(11);
709
+ expect(data.phases[0].name).toBe('Alpha');
710
+ expect(data.phases[1].phase_number).toBe(12);
711
+ expect(data.phases[1].name).toBe('Beta');
712
+
713
+ const roadmap = await readFile(join(tmpDir, '.planning', 'ROADMAP.md'), 'utf-8');
714
+ expect(roadmap).toContain('### Phase 11: Alpha');
715
+ expect(roadmap).toContain('### Phase 12: Beta');
716
+
717
+ const phasesDir = join(tmpDir, '.planning', 'phases');
718
+ expect(existsSync(join(phasesDir, '11-alpha', '.gitkeep'))).toBe(true);
719
+ expect(existsSync(join(phasesDir, '12-beta', '.gitkeep'))).toBe(true);
720
+ });
721
+
722
+ it('accepts --descriptions JSON array', async () => {
723
+ const { phaseAddBatch } = await import('./phase-lifecycle.js');
724
+ await setupTestProject(tmpDir, { phases: ['09-foundation', '10-read-only-queries'] });
725
+
726
+ const result = await phaseAddBatch(
727
+ ['--descriptions', JSON.stringify(['One', 'Two'])],
728
+ tmpDir,
729
+ );
730
+ const data = result.data as { count: number };
731
+ expect(data.count).toBe(2);
732
+ });
733
+
734
+ it('throws when no descriptions', async () => {
735
+ const { phaseAddBatch } = await import('./phase-lifecycle.js');
736
+ await setupTestProject(tmpDir);
737
+
738
+ await expect(phaseAddBatch([], tmpDir)).rejects.toThrow('descriptions array required');
739
+ });
740
+ });
741
+
742
+ // ─── phaseInsert ────────────────────────────────────────────────────────
743
+
744
+ describe('phaseInsert', () => {
745
+ it('creates decimal phase directory after target phase', async () => {
746
+ const { phaseInsert } = await import('./phase-lifecycle.js');
747
+ await setupTestProject(tmpDir, {
748
+ phases: ['09-foundation', '10-read-only-queries'],
749
+ });
750
+
751
+ const result = await phaseInsert(['10', 'Urgent Fix'], tmpDir);
752
+ const data = result.data as Record<string, unknown>;
753
+
754
+ expect(data.phase_number).toBe('10.1');
755
+ expect(data.after_phase).toBe('10');
756
+ expect(data.name).toBe('Urgent Fix');
757
+ expect(data.slug).toBe('urgent-fix');
758
+
759
+ // Verify directory created
760
+ const dir = data.directory as string;
761
+ expect(dir).toContain('10.1-urgent-fix');
762
+ const phasesDir = join(tmpDir, '.planning', 'phases');
763
+ const entries = await readdir(phasesDir, { withFileTypes: true });
764
+ const newDir = entries.find(e => e.isDirectory() && e.name.includes('10.1-urgent-fix'));
765
+ expect(newDir).toBeTruthy();
766
+ });
767
+
768
+ it('scans both directories and ROADMAP.md for existing decimals to avoid collisions', async () => {
769
+ const { phaseInsert } = await import('./phase-lifecycle.js');
770
+ await setupTestProject(tmpDir, {
771
+ phases: ['09-foundation', '10-read-only-queries', '10.1-hotfix'],
772
+ });
773
+
774
+ const result = await phaseInsert(['10', 'Another Fix'], tmpDir);
775
+ const data = result.data as Record<string, unknown>;
776
+ // Should be 10.2 since 10.1 already exists on disk
777
+ expect(data.phase_number).toBe('10.2');
778
+ });
779
+
780
+ it('inserts section in ROADMAP.md after target phase', async () => {
781
+ const { phaseInsert } = await import('./phase-lifecycle.js');
782
+ await setupTestProject(tmpDir);
783
+
784
+ await phaseInsert(['10', 'Urgent Fix'], tmpDir);
785
+ const roadmap = await readFile(join(tmpDir, '.planning', 'ROADMAP.md'), 'utf-8');
786
+
787
+ expect(roadmap).toContain('### Phase 10.1: Urgent Fix (INSERTED)');
788
+ // Should appear after Phase 10 section
789
+ const phase10Idx = roadmap.indexOf('### Phase 10:');
790
+ const insertedIdx = roadmap.indexOf('### Phase 10.1:');
791
+ expect(insertedIdx).toBeGreaterThan(phase10Idx);
792
+ });
793
+
794
+ it('throws GSDError for missing target phase', async () => {
795
+ const { phaseInsert } = await import('./phase-lifecycle.js');
796
+ await setupTestProject(tmpDir);
797
+
798
+ await expect(phaseInsert(['99', 'Missing'], tmpDir)).rejects.toThrow('Phase 99 not found');
799
+ });
800
+
801
+ it('throws GSDError with Validation for missing args', async () => {
802
+ const { phaseInsert } = await import('./phase-lifecycle.js');
803
+ await setupTestProject(tmpDir);
804
+
805
+ await expect(phaseInsert([], tmpDir)).rejects.toThrow('after-phase and description required');
806
+ });
807
+
808
+ it('#3098 preserved: throws when bullet-only entry in a heading-style ROADMAP (hybrid = missing detail section)', async () => {
809
+ // A hybrid ROADMAP: phase 9 has a heading but phase 10 only has a bullet
810
+ // summary entry. Insert must still reject with "missing a detail section"
811
+ // because the surrounding ROADMAP uses heading-style phases.
812
+ const { phaseInsert } = await import('./phase-lifecycle.js');
813
+ const hybridRoadmap = `# Roadmap\n\n## Current Milestone\n\n### Phase 9: Foundation\n\n- [ ] **Phase 10: Queries**\n`;
814
+ await setupTestProject(tmpDir, {
815
+ roadmap: hybridRoadmap,
816
+ phases: ['09-foundation'],
817
+ });
818
+
819
+ await expect(phaseInsert(['10', 'Hotfix'], tmpDir)).rejects.toThrow('missing a detail section');
820
+ });
821
+
822
+ // ─── #3815: checked-bullet ROADMAP format ─────────────────────────────
823
+
824
+ const BULLET_ONLY_ROADMAP = `# Roadmap
825
+
826
+ ## Current Milestone: v2.0 Agent Skills
827
+
828
+ - [x] **Phase 01: bootstrap** — completed 2026-04-01
829
+ - [ ] **Phase 02: core-loop**
830
+ - [ ] **Phase 03: persistence**
831
+
832
+ ---
833
+ *Last updated: 2026-05-01*
834
+ `;
835
+
836
+ it('#3815: inserts decimal phase between bullets in a checked-bullet ROADMAP', async () => {
837
+ const { phaseInsert } = await import('./phase-lifecycle.js');
838
+ await setupTestProject(tmpDir, {
839
+ roadmap: BULLET_ONLY_ROADMAP,
840
+ phases: ['01-bootstrap', '02-core-loop', '03-persistence'],
841
+ });
842
+
843
+ const result = await phaseInsert(['02', 'hot patch'], tmpDir);
844
+ const data = result.data as Record<string, unknown>;
845
+
846
+ expect(data.phase_number).toBe('02.1');
847
+ expect(data.after_phase).toBe('02');
848
+ expect(data.name).toBe('hot patch');
849
+
850
+ const roadmap = await readFile(join(tmpDir, '.planning', 'ROADMAP.md'), 'utf-8');
851
+
852
+ // New bullet must be present
853
+ expect(roadmap).toMatch(/- \[ \].*Phase 02\.1:.*hot patch/i);
854
+
855
+ // New bullet must appear AFTER the Phase 02 bullet
856
+ const phase02Idx = roadmap.indexOf('Phase 02: core-loop');
857
+ const insertedIdx = roadmap.search(/Phase 02\.1:/i);
858
+ expect(phase02Idx).toBeGreaterThanOrEqual(0);
859
+ expect(insertedIdx).toBeGreaterThan(phase02Idx);
860
+
861
+ // New bullet must appear BEFORE the Phase 03 bullet (positional assertion)
862
+ const phase03Idx = roadmap.indexOf('Phase 03: persistence');
863
+ expect(insertedIdx).toBeLessThan(phase03Idx);
864
+
865
+ // Must NOT corrupt the surrounding bullet structure
866
+ expect(roadmap).toContain('- [x] **Phase 01: bootstrap**');
867
+ expect(roadmap).toContain('- [ ] **Phase 02: core-loop**');
868
+ expect(roadmap).toContain('- [ ] **Phase 03: persistence**');
869
+ });
870
+
871
+ it('#3815: inserts at end of bullet list when target is the last phase', async () => {
872
+ const { phaseInsert } = await import('./phase-lifecycle.js');
873
+ await setupTestProject(tmpDir, {
874
+ roadmap: BULLET_ONLY_ROADMAP,
875
+ phases: ['01-bootstrap', '02-core-loop', '03-persistence'],
876
+ });
877
+
878
+ const result = await phaseInsert(['03', 'final extra'], tmpDir);
879
+ const data = result.data as Record<string, unknown>;
880
+
881
+ expect(data.phase_number).toBe('03.1');
882
+
883
+ const roadmap = await readFile(join(tmpDir, '.planning', 'ROADMAP.md'), 'utf-8');
884
+ expect(roadmap).toMatch(/- \[ \].*Phase 03\.1:.*final extra/i);
885
+
886
+ // Must appear after Phase 03 bullet
887
+ const phase03Idx = roadmap.indexOf('Phase 03: persistence');
888
+ const insertedIdx = roadmap.search(/Phase 03\.1:/i);
889
+ expect(insertedIdx).toBeGreaterThan(phase03Idx);
890
+ });
891
+
892
+ it('#3815: plain bullet format (no bold) also works', async () => {
893
+ const { phaseInsert } = await import('./phase-lifecycle.js');
894
+ const PLAIN_BULLET_ROADMAP = `# Roadmap
895
+
896
+ ## Current Milestone: v2.0
897
+
898
+ - [ ] Phase 01: foo
899
+ - [ ] Phase 02: bar
900
+ - [ ] Phase 03: baz
901
+
902
+ ---
903
+ *Last updated: 2026-05-01*
904
+ `;
905
+ await setupTestProject(tmpDir, {
906
+ roadmap: PLAIN_BULLET_ROADMAP,
907
+ phases: ['01-foo', '02-bar', '03-baz'],
908
+ });
909
+
910
+ const result = await phaseInsert(['02', 'inserted'], tmpDir);
911
+ const data = result.data as Record<string, unknown>;
912
+
913
+ expect(data.phase_number).toBe('02.1');
914
+
915
+ const roadmap = await readFile(join(tmpDir, '.planning', 'ROADMAP.md'), 'utf-8');
916
+ expect(roadmap).toMatch(/- \[ \].*Phase 02\.1:.*inserted/i);
917
+
918
+ const phase02Idx = roadmap.indexOf('Phase 02: bar');
919
+ const insertedIdx = roadmap.search(/Phase 02\.1:/i);
920
+ const phase03Idx = roadmap.indexOf('Phase 03: baz');
921
+ expect(insertedIdx).toBeGreaterThan(phase02Idx);
922
+ expect(insertedIdx).toBeLessThan(phase03Idx);
923
+ });
924
+ });
925
+
926
+ // ─── phaseScaffold ──────────────────────────────────────────────────────
927
+
928
+ describe('phaseScaffold', () => {
929
+ it('creates context template for a phase', async () => {
930
+ const { phaseScaffold } = await import('./phase-lifecycle.js');
931
+ await setupTestProject(tmpDir, {
932
+ phases: ['09-foundation'],
933
+ });
934
+
935
+ const result = await phaseScaffold(['context', '9'], tmpDir);
936
+ const data = result.data as Record<string, unknown>;
937
+
938
+ expect(data.created).toBe(true);
939
+ const filePath = data.path as string;
940
+ expect(filePath).toContain('09-CONTEXT.md');
941
+
942
+ // Check content
943
+ const fullPath = join(tmpDir, '.planning', 'phases', '09-foundation', '09-CONTEXT.md');
944
+ expect(existsSync(fullPath)).toBe(true);
945
+ const content = await readFile(fullPath, 'utf-8');
946
+ expect(content).toContain('phase: "09"');
947
+ expect(content).toContain('Context');
948
+ });
949
+
950
+ it('creates uat template', async () => {
951
+ const { phaseScaffold } = await import('./phase-lifecycle.js');
952
+ await setupTestProject(tmpDir, {
953
+ phases: ['09-foundation'],
954
+ });
955
+
956
+ const result = await phaseScaffold(['uat', '9'], tmpDir);
957
+ const data = result.data as Record<string, unknown>;
958
+
959
+ expect(data.created).toBe(true);
960
+ const fullPath = join(tmpDir, '.planning', 'phases', '09-foundation', '09-UAT.md');
961
+ expect(existsSync(fullPath)).toBe(true);
962
+ const content = await readFile(fullPath, 'utf-8');
963
+ expect(content).toContain('User Acceptance Testing');
964
+ });
965
+
966
+ it('creates verification template', async () => {
967
+ const { phaseScaffold } = await import('./phase-lifecycle.js');
968
+ await setupTestProject(tmpDir, {
969
+ phases: ['09-foundation'],
970
+ });
971
+
972
+ const result = await phaseScaffold(['verification', '9'], tmpDir);
973
+ const data = result.data as Record<string, unknown>;
974
+
975
+ expect(data.created).toBe(true);
976
+ const fullPath = join(tmpDir, '.planning', 'phases', '09-foundation', '09-VERIFICATION.md');
977
+ expect(existsSync(fullPath)).toBe(true);
978
+ const content = await readFile(fullPath, 'utf-8');
979
+ expect(content).toContain('Verification');
980
+ });
981
+
982
+ it('creates phase-dir under phases/', async () => {
983
+ const { phaseScaffold } = await import('./phase-lifecycle.js');
984
+ await setupTestProject(tmpDir);
985
+
986
+ const result = await phaseScaffold(['phase-dir', '15', 'New Module'], tmpDir);
987
+ const data = result.data as Record<string, unknown>;
988
+
989
+ expect(data.created).toBe(true);
990
+ const dir = data.directory as string;
991
+ expect(dir).toContain('15-new-module');
992
+ });
993
+
994
+ it('returns already_exists for existing file', async () => {
995
+ const { phaseScaffold } = await import('./phase-lifecycle.js');
996
+ await setupTestProject(tmpDir, {
997
+ phases: ['09-foundation'],
998
+ });
999
+
1000
+ // Create first
1001
+ await phaseScaffold(['context', '9'], tmpDir);
1002
+ // Second call should return already_exists
1003
+ const result = await phaseScaffold(['context', '9'], tmpDir);
1004
+ const data = result.data as Record<string, unknown>;
1005
+ expect(data.created).toBe(false);
1006
+ expect(data.reason).toBe('already_exists');
1007
+ });
1008
+
1009
+ it('throws GSDError for unknown type', async () => {
1010
+ const { phaseScaffold } = await import('./phase-lifecycle.js');
1011
+ await setupTestProject(tmpDir, {
1012
+ phases: ['09-foundation'],
1013
+ });
1014
+
1015
+ await expect(phaseScaffold(['badtype', '9'], tmpDir)).rejects.toThrow('Unknown scaffold type');
1016
+ });
1017
+ });
1018
+
1019
+ // ─── phaseRemove ─────────────────────────────────────────────────────────
1020
+
1021
+ const ROADMAP_FOR_REMOVE = `# Roadmap
1022
+
1023
+ ## Current Milestone: v3.0 SDK-First Migration
1024
+
1025
+ ### Phase 5: Auth
1026
+
1027
+ **Goal:** Build authentication
1028
+ **Requirements**: TBD
1029
+ **Depends on:** Phase 4
1030
+ **Plans:** 2 plans
1031
+
1032
+ Plans:
1033
+ - [x] 05-01 (Auth setup)
1034
+ - [x] 05-02 (Auth complete)
1035
+
1036
+ ### Phase 6: Dashboard
1037
+
1038
+ **Goal:** Build dashboard
1039
+ **Requirements**: TBD
1040
+ **Depends on:** Phase 5
1041
+ **Plans:** 3 plans
1042
+
1043
+ Plans:
1044
+ - [ ] 06-01 (Dashboard setup)
1045
+
1046
+ ### Phase 7: API
1047
+
1048
+ **Goal:** Build API layer
1049
+ **Requirements**: TBD
1050
+ **Depends on:** Phase 6
1051
+ **Plans:** 2 plans
1052
+
1053
+ Plans:
1054
+ - [ ] 07-01 (API setup)
1055
+
1056
+ ---
1057
+ *Last updated: 2026-04-08*
1058
+ `;
1059
+
1060
+ const STATE_FOR_REMOVE = `---
1061
+ gsd_state_version: 1.0
1062
+ milestone: v3.0
1063
+ milestone_name: SDK-First Migration
1064
+ status: executing
1065
+ progress:
1066
+ total_phases: 7
1067
+ completed_phases: 4
1068
+ total_plans: 15
1069
+ completed_plans: 12
1070
+ percent: 80
1071
+ ---
1072
+
1073
+ # Project State
1074
+
1075
+ ## Current Position
1076
+
1077
+ Phase: 6 (Dashboard) — EXECUTING
1078
+ Plan: 1 of 3
1079
+ Status: Executing Phase 6
1080
+
1081
+ ## Session Continuity
1082
+
1083
+ Last session: 2026-04-08T10:00:00.000Z
1084
+ Stopped at: Started
1085
+ `;
1086
+
1087
+ describe('phaseRemove', () => {
1088
+ it('removes integer phase directory and renumbers subsequent phases', async () => {
1089
+ const { phaseRemove } = await import('./phase-lifecycle.js');
1090
+ const phasesDir = join(tmpDir, '.planning', 'phases');
1091
+ await setupTestProject(tmpDir, {
1092
+ roadmap: ROADMAP_FOR_REMOVE,
1093
+ state: STATE_FOR_REMOVE,
1094
+ phases: ['05-auth', '06-dashboard', '07-api'],
1095
+ });
1096
+ // Create files inside directories to verify file renaming
1097
+ await writeFile(join(phasesDir, '06-dashboard', '06-01-PLAN.md'), 'plan', 'utf-8');
1098
+ await writeFile(join(phasesDir, '07-api', '07-01-PLAN.md'), 'plan', 'utf-8');
1099
+
1100
+ const result = await phaseRemove(['6'], tmpDir);
1101
+ const data = result.data as Record<string, unknown>;
1102
+
1103
+ expect(data.removed).toBe('6');
1104
+ expect(data.directory_deleted).toBeTruthy();
1105
+ expect(data.roadmap_updated).toBe(true);
1106
+ expect(data.state_updated).toBe(true);
1107
+
1108
+ // Phase 6 dir should be gone
1109
+ const entries = await readdir(phasesDir, { withFileTypes: true });
1110
+ const dirNames = entries.filter(e => e.isDirectory()).map(e => e.name);
1111
+ expect(dirNames.find(d => d.includes('06-dashboard'))).toBeUndefined();
1112
+
1113
+ // Phase 7 should have been renamed to 06
1114
+ const renamedDir = dirNames.find(d => d.includes('06-api'));
1115
+ expect(renamedDir).toBeTruthy();
1116
+
1117
+ // Files inside renamed dir should also be renamed
1118
+ const files = await readdir(join(phasesDir, renamedDir!));
1119
+ expect(files.some(f => f.includes('06-01'))).toBe(true);
1120
+ expect(files.some(f => f.includes('07-01'))).toBe(false);
1121
+ });
1122
+
1123
+ it('removes decimal phase and renumbers sibling decimals', async () => {
1124
+ const { phaseRemove } = await import('./phase-lifecycle.js');
1125
+ const decimalRoadmap = ROADMAP_FOR_REMOVE.replace(
1126
+ '### Phase 7: API',
1127
+ '### Phase 6.1: Hotfix A\n\n**Goal:** Fix A\n**Plans:** 1 plans\n\n### Phase 6.2: Hotfix B\n\n**Goal:** Fix B\n**Plans:** 1 plans\n\n### Phase 6.3: Hotfix C\n\n**Goal:** Fix C\n**Plans:** 1 plans\n\n### Phase 7: API'
1128
+ );
1129
+ const phasesDir = join(tmpDir, '.planning', 'phases');
1130
+ await setupTestProject(tmpDir, {
1131
+ roadmap: decimalRoadmap,
1132
+ state: STATE_FOR_REMOVE,
1133
+ phases: ['05-auth', '06-dashboard', '06.1-hotfix-a', '06.2-hotfix-b', '06.3-hotfix-c', '07-api'],
1134
+ });
1135
+ // Create files with phase ID in name
1136
+ await writeFile(join(phasesDir, '06.2-hotfix-b', '06.2-01-PLAN.md'), 'plan', 'utf-8');
1137
+ await writeFile(join(phasesDir, '06.3-hotfix-c', '06.3-01-PLAN.md'), 'plan', 'utf-8');
1138
+
1139
+ const result = await phaseRemove(['6.1'], tmpDir);
1140
+ const data = result.data as Record<string, unknown>;
1141
+
1142
+ expect(data.removed).toBe('6.1');
1143
+
1144
+ // 06.1 should be gone
1145
+ const entries = await readdir(phasesDir, { withFileTypes: true });
1146
+ const dirNames = entries.filter(e => e.isDirectory()).map(e => e.name);
1147
+ expect(dirNames.find(d => d.includes('06.1-hotfix-a'))).toBeUndefined();
1148
+
1149
+ // 06.2 should become 06.1, 06.3 should become 06.2
1150
+ expect(dirNames.find(d => d.includes('06.1-hotfix-b'))).toBeTruthy();
1151
+ expect(dirNames.find(d => d.includes('06.2-hotfix-c'))).toBeTruthy();
1152
+ expect(dirNames.find(d => d.includes('06.3'))).toBeUndefined();
1153
+
1154
+ // Files inside renamed dirs should be renamed
1155
+ const dir1Files = await readdir(join(phasesDir, '06.1-hotfix-b'));
1156
+ expect(dir1Files.some(f => f.includes('06.1-01'))).toBe(true);
1157
+ const dir2Files = await readdir(join(phasesDir, '06.2-hotfix-c'));
1158
+ expect(dir2Files.some(f => f.includes('06.2-01'))).toBe(true);
1159
+ });
1160
+
1161
+ it('requires --force to remove phase with SUMMARY files', async () => {
1162
+ const { phaseRemove } = await import('./phase-lifecycle.js');
1163
+ const phasesDir = join(tmpDir, '.planning', 'phases');
1164
+ await setupTestProject(tmpDir, {
1165
+ roadmap: ROADMAP_FOR_REMOVE,
1166
+ state: STATE_FOR_REMOVE,
1167
+ phases: ['05-auth', '06-dashboard', '07-api'],
1168
+ });
1169
+ // Create a SUMMARY file to simulate executed work
1170
+ await writeFile(join(phasesDir, '06-dashboard', '06-01-SUMMARY.md'), 'summary', 'utf-8');
1171
+
1172
+ await expect(phaseRemove(['6'], tmpDir)).rejects.toThrow('--force');
1173
+ });
1174
+
1175
+ it('allows removal with --force even when SUMMARY files exist', async () => {
1176
+ const { phaseRemove } = await import('./phase-lifecycle.js');
1177
+ const phasesDir = join(tmpDir, '.planning', 'phases');
1178
+ await setupTestProject(tmpDir, {
1179
+ roadmap: ROADMAP_FOR_REMOVE,
1180
+ state: STATE_FOR_REMOVE,
1181
+ phases: ['05-auth', '06-dashboard', '07-api'],
1182
+ });
1183
+ await writeFile(join(phasesDir, '06-dashboard', '06-01-SUMMARY.md'), 'summary', 'utf-8');
1184
+
1185
+ const result = await phaseRemove(['6', '--force'], tmpDir);
1186
+ const data = result.data as Record<string, unknown>;
1187
+ expect(data.removed).toBe('6');
1188
+ expect(data.directory_deleted).toBeTruthy();
1189
+ });
1190
+
1191
+ it('bug-3409: accepts --force before phase id', async () => {
1192
+ const { phaseRemove } = await import('./phase-lifecycle.js');
1193
+ const phasesDir = join(tmpDir, '.planning', 'phases');
1194
+ await setupTestProject(tmpDir, {
1195
+ roadmap: ROADMAP_FOR_REMOVE,
1196
+ state: STATE_FOR_REMOVE,
1197
+ phases: ['05-auth', '06-dashboard', '07-api'],
1198
+ });
1199
+ await writeFile(join(phasesDir, '06-dashboard', '06-01-SUMMARY.md'), 'summary', 'utf-8');
1200
+
1201
+ const result = await phaseRemove(['--force', '6'], tmpDir);
1202
+ const data = result.data as Record<string, unknown>;
1203
+ expect(data.removed).toBe('6');
1204
+ expect(data.directory_deleted).toBeTruthy();
1205
+ });
1206
+
1207
+ it('throws GSDError when ROADMAP.md is missing', async () => {
1208
+ const { phaseRemove } = await import('./phase-lifecycle.js');
1209
+ // Set up without ROADMAP.md
1210
+ const planningDir = join(tmpDir, '.planning');
1211
+ await mkdir(planningDir, { recursive: true });
1212
+ const phasesDir = join(planningDir, 'phases');
1213
+ await mkdir(phasesDir, { recursive: true });
1214
+ await writeFile(join(planningDir, 'STATE.md'), STATE_FOR_REMOVE, 'utf-8');
1215
+
1216
+ await expect(phaseRemove(['6'], tmpDir)).rejects.toThrow('ROADMAP.md not found');
1217
+ });
1218
+
1219
+ it('throws GSDError when phase number is missing', async () => {
1220
+ const { phaseRemove } = await import('./phase-lifecycle.js');
1221
+ await setupTestProject(tmpDir, {
1222
+ roadmap: ROADMAP_FOR_REMOVE,
1223
+ state: STATE_FOR_REMOVE,
1224
+ });
1225
+
1226
+ await expect(phaseRemove([], tmpDir)).rejects.toThrow('phase number required');
1227
+ });
1228
+
1229
+ it('throws GSDError when target phase does not exist and does not mutate STATE.md', async () => {
1230
+ const { phaseRemove } = await import('./phase-lifecycle.js');
1231
+ await setupTestProject(tmpDir, {
1232
+ roadmap: ROADMAP_FOR_REMOVE,
1233
+ state: STATE_FOR_REMOVE,
1234
+ phases: ['05-auth', '06-dashboard', '07-api'],
1235
+ });
1236
+
1237
+ await expect(phaseRemove(['99'], tmpDir)).rejects.toThrow('Phase 99 not found');
1238
+ const stateContent = await readFile(join(tmpDir, '.planning', 'STATE.md'), 'utf-8');
1239
+ expect(stateContent).toMatch(/total_phases:\s*7/);
1240
+ });
1241
+
1242
+ it('updates ROADMAP.md by removing phase section and renumbering', async () => {
1243
+ const { phaseRemove } = await import('./phase-lifecycle.js');
1244
+ await setupTestProject(tmpDir, {
1245
+ roadmap: ROADMAP_FOR_REMOVE,
1246
+ state: STATE_FOR_REMOVE,
1247
+ phases: ['05-auth', '06-dashboard', '07-api'],
1248
+ });
1249
+
1250
+ await phaseRemove(['6'], tmpDir);
1251
+
1252
+ const roadmap = await readFile(join(tmpDir, '.planning', 'ROADMAP.md'), 'utf-8');
1253
+ // Phase 6 section should be removed
1254
+ expect(roadmap).not.toContain('### Phase 6: Dashboard');
1255
+ // Phase 7 should be renumbered to 6
1256
+ expect(roadmap).toContain('### Phase 6: API');
1257
+ // Plan references should be renumbered
1258
+ expect(roadmap).toContain('06-01');
1259
+ expect(roadmap).not.toContain('07-01');
1260
+ });
1261
+
1262
+ it('decrements total_phases in STATE.md frontmatter', async () => {
1263
+ const { phaseRemove } = await import('./phase-lifecycle.js');
1264
+ await setupTestProject(tmpDir, {
1265
+ roadmap: ROADMAP_FOR_REMOVE,
1266
+ state: STATE_FOR_REMOVE,
1267
+ phases: ['05-auth', '06-dashboard', '07-api'],
1268
+ });
1269
+
1270
+ await phaseRemove(['6'], tmpDir);
1271
+
1272
+ const stateContent = await readFile(join(tmpDir, '.planning', 'STATE.md'), 'utf-8');
1273
+ // total_phases should be decremented from 7 to 6
1274
+ expect(stateContent).toMatch(/total_phases:\s*6/);
1275
+ });
1276
+ });
1277
+
1278
+ // ─── phaseComplete ─────────────────────────────────────────────────────────
1279
+
1280
+ const ROADMAP_FOR_COMPLETE = `# Roadmap
1281
+
1282
+ <details>
1283
+ <summary>v1.0 (shipped)</summary>
1284
+
1285
+ ### Phase 1: Old Phase
1286
+
1287
+ **Goal:** Shipped already
1288
+ **Plans:** 2 plans
1289
+
1290
+ </details>
1291
+
1292
+ ## Current Milestone: v3.0 SDK-First Migration
1293
+
1294
+ | Phase | Plans | Status | Completed |
1295
+ |-------|-------|--------|-----------|
1296
+ | 9. | 3/3 | Complete | 2026-04-01 |
1297
+ | 10. | 0/3 | In Progress | |
1298
+ | 11. | 0/2 | Not Started | |
1299
+
1300
+ - [x] Phase 9: Foundation (completed 2026-04-01)
1301
+ - [ ] Phase 10: Read-Only Queries
1302
+ - [ ] Phase 11: Final Phase
1303
+
1304
+ ### Phase 9: Foundation
1305
+
1306
+ **Goal:** Build foundation
1307
+ **Requirements**: FOUND-01, FOUND-02
1308
+ **Depends on:** Phase 8
1309
+ **Plans:** 3/3 plans complete
1310
+
1311
+ Plans:
1312
+ - [x] 09-01 (Foundation setup)
1313
+ - [x] 09-02 (Foundation core)
1314
+ - [x] 09-03 (Foundation tests)
1315
+
1316
+ ### Phase 10: Read-Only Queries
1317
+
1318
+ **Goal:** Port queries
1319
+ **Requirements**: QUERY-01
1320
+ **Depends on:** Phase 9
1321
+ **Plans:** 3 plans
1322
+
1323
+ Plans:
1324
+ - [x] 10-01 (Query setup)
1325
+ - [x] 10-02 (Query core)
1326
+ - [ ] 10-03 (Query tests)
1327
+
1328
+ ### Phase 11: Final Phase
1329
+
1330
+ **Goal:** Final work
1331
+ **Requirements**: FINAL-01
1332
+ **Depends on:** Phase 10
1333
+ **Plans:** 2 plans
1334
+
1335
+ Plans:
1336
+ - [ ] 11-01 (Final setup)
1337
+ - [ ] 11-02 (Final complete)
1338
+
1339
+ ---
1340
+ *Last updated: 2026-04-08*
1341
+ `;
1342
+
1343
+ const STATE_FOR_COMPLETE = `---
1344
+ gsd_state_version: 1.0
1345
+ milestone: v3.0
1346
+ milestone_name: SDK-First Migration
1347
+ status: executing
1348
+ progress:
1349
+ total_phases: 3
1350
+ completed_phases: 1
1351
+ total_plans: 8
1352
+ completed_plans: 5
1353
+ percent: 33
1354
+ ---
1355
+
1356
+ # Project State
1357
+
1358
+ ## Current Position
1359
+
1360
+ Phase: 10 of 3 (Read-Only Queries) — EXECUTING
1361
+ Plan: 3 of 3
1362
+ Status: Executing Phase 10
1363
+ Last activity: 2026-04-08
1364
+
1365
+ ## Performance Metrics
1366
+
1367
+ **Velocity:**
1368
+
1369
+ - Total plans completed: 3
1370
+ - Average duration: --
1371
+ - Total execution time: 0 hours
1372
+
1373
+ **By Phase:**
1374
+
1375
+ | Phase | Plans | Total | Avg/Plan |
1376
+ |-------|-------|-------|----------|
1377
+ | 9 | 3 | - | - |
1378
+
1379
+ ## Session Continuity
1380
+
1381
+ Last session: 2026-04-08T10:00:00.000Z
1382
+ Stopped at: Completed 10-03-PLAN.md
1383
+ `;
1384
+
1385
+ const REQUIREMENTS_FOR_COMPLETE = `# Requirements
1386
+
1387
+ ## Checklist
1388
+
1389
+ - [x] **FOUND-01** Foundation setup
1390
+ - [x] **FOUND-02** Foundation core
1391
+ - [ ] **QUERY-01** Query implementation
1392
+ - [ ] **FINAL-01** Final work
1393
+
1394
+ ## Traceability
1395
+
1396
+ | Requirement | Phase | Status |
1397
+ |-------------|-------|--------|
1398
+ | FOUND-01 | Phase 9 | Complete |
1399
+ | FOUND-02 | Phase 9 | Complete |
1400
+ | QUERY-01 | Phase 10 | In Progress |
1401
+ | FINAL-01 | Phase 11 | Pending |
1402
+ `;
1403
+
1404
+ describe('phaseComplete', () => {
1405
+ it('marks phase checkbox, updates progress table, and plan count in ROADMAP.md', async () => {
1406
+ const { phaseComplete } = await import('./phase-lifecycle.js');
1407
+ await setupTestProject(tmpDir, {
1408
+ roadmap: ROADMAP_FOR_COMPLETE,
1409
+ state: STATE_FOR_COMPLETE,
1410
+ phases: ['09-foundation', '10-read-only-queries', '11-final-phase'],
1411
+ });
1412
+ // Create PLAN and SUMMARY files for phase 10
1413
+ const p10Dir = join(tmpDir, '.planning', 'phases', '10-read-only-queries');
1414
+ await writeFile(join(p10Dir, '10-01-PLAN.md'), 'plan1', 'utf-8');
1415
+ await writeFile(join(p10Dir, '10-02-PLAN.md'), 'plan2', 'utf-8');
1416
+ await writeFile(join(p10Dir, '10-03-PLAN.md'), 'plan3', 'utf-8');
1417
+ await writeFile(join(p10Dir, '10-01-SUMMARY.md'), 'summary1', 'utf-8');
1418
+ await writeFile(join(p10Dir, '10-02-SUMMARY.md'), 'summary2', 'utf-8');
1419
+ await writeFile(join(p10Dir, '10-03-SUMMARY.md'), 'summary3', 'utf-8');
1420
+ // Create REQUIREMENTS.md
1421
+ await writeFile(join(tmpDir, '.planning', 'REQUIREMENTS.md'), REQUIREMENTS_FOR_COMPLETE, 'utf-8');
1422
+
1423
+ const result = await phaseComplete(['10'], tmpDir);
1424
+ const data = result.data as Record<string, unknown>;
1425
+
1426
+ expect(data.completed_phase).toBe('10');
1427
+ expect(data.plans_executed).toBe('3/3');
1428
+ expect(data.is_last_phase).toBe(false);
1429
+ expect(data.next_phase).toBeTruthy();
1430
+ expect(data.roadmap_updated).toBe(true);
1431
+
1432
+ // Check ROADMAP.md updates
1433
+ const roadmap = await readFile(join(tmpDir, '.planning', 'ROADMAP.md'), 'utf-8');
1434
+ // Checkbox should be marked
1435
+ expect(roadmap).toMatch(/\[x\].*Phase 10/);
1436
+ // Progress table should show Complete
1437
+ expect(roadmap).toMatch(/10\.?\s*\|.*3\/3.*\|.*Complete/i);
1438
+ // Plan count in section should be updated
1439
+ expect(roadmap).toContain('3/3 plans complete');
1440
+ // Plan checkboxes should be [x]
1441
+ expect(roadmap).toMatch(/\[x\] 10-01/);
1442
+ expect(roadmap).toMatch(/\[x\] 10-02/);
1443
+ expect(roadmap).toMatch(/\[x\] 10-03/);
1444
+ });
1445
+
1446
+ it('updates REQUIREMENTS.md checkboxes and traceability table', async () => {
1447
+ const { phaseComplete } = await import('./phase-lifecycle.js');
1448
+ await setupTestProject(tmpDir, {
1449
+ roadmap: ROADMAP_FOR_COMPLETE,
1450
+ state: STATE_FOR_COMPLETE,
1451
+ phases: ['09-foundation', '10-read-only-queries', '11-final-phase'],
1452
+ });
1453
+ const p10Dir = join(tmpDir, '.planning', 'phases', '10-read-only-queries');
1454
+ await writeFile(join(p10Dir, '10-01-PLAN.md'), 'plan1', 'utf-8');
1455
+ await writeFile(join(p10Dir, '10-02-PLAN.md'), 'plan2', 'utf-8');
1456
+ await writeFile(join(p10Dir, '10-03-PLAN.md'), 'plan3', 'utf-8');
1457
+ await writeFile(join(p10Dir, '10-01-SUMMARY.md'), 'summary1', 'utf-8');
1458
+ await writeFile(join(p10Dir, '10-02-SUMMARY.md'), 'summary2', 'utf-8');
1459
+ await writeFile(join(p10Dir, '10-03-SUMMARY.md'), 'summary3', 'utf-8');
1460
+ await writeFile(join(tmpDir, '.planning', 'REQUIREMENTS.md'), REQUIREMENTS_FOR_COMPLETE, 'utf-8');
1461
+
1462
+ await phaseComplete(['10'], tmpDir);
1463
+
1464
+ const req = await readFile(join(tmpDir, '.planning', 'REQUIREMENTS.md'), 'utf-8');
1465
+ // QUERY-01 checkbox should be marked
1466
+ expect(req).toMatch(/\[x\].*\*\*QUERY-01\*\*/);
1467
+ // Traceability should show Complete for QUERY-01
1468
+ expect(req).toMatch(/QUERY-01\s*\|.*\|\s*Complete\s*\|/);
1469
+ // FINAL-01 should remain Pending
1470
+ expect(req).toMatch(/FINAL-01\s*\|.*\|\s*Pending\s*\|/);
1471
+ });
1472
+
1473
+ it('updates STATE.md fields: current phase, status, completed phases, percent', async () => {
1474
+ const { phaseComplete } = await import('./phase-lifecycle.js');
1475
+ await setupTestProject(tmpDir, {
1476
+ roadmap: ROADMAP_FOR_COMPLETE,
1477
+ state: STATE_FOR_COMPLETE,
1478
+ phases: ['09-foundation', '10-read-only-queries', '11-final-phase'],
1479
+ });
1480
+ const p10Dir = join(tmpDir, '.planning', 'phases', '10-read-only-queries');
1481
+ await writeFile(join(p10Dir, '10-01-PLAN.md'), 'plan', 'utf-8');
1482
+ await writeFile(join(p10Dir, '10-02-PLAN.md'), 'plan', 'utf-8');
1483
+ await writeFile(join(p10Dir, '10-03-PLAN.md'), 'plan', 'utf-8');
1484
+ await writeFile(join(p10Dir, '10-01-SUMMARY.md'), 'summary', 'utf-8');
1485
+ await writeFile(join(p10Dir, '10-02-SUMMARY.md'), 'summary', 'utf-8');
1486
+ await writeFile(join(p10Dir, '10-03-SUMMARY.md'), 'summary', 'utf-8');
1487
+ await writeFile(join(tmpDir, '.planning', 'REQUIREMENTS.md'), REQUIREMENTS_FOR_COMPLETE, 'utf-8');
1488
+
1489
+ await phaseComplete(['10'], tmpDir);
1490
+
1491
+ const state = await readFile(join(tmpDir, '.planning', 'STATE.md'), 'utf-8');
1492
+ // Phase should advance to 11
1493
+ expect(state).toMatch(/Phase:\s*11/);
1494
+ // Status should indicate ready to plan
1495
+ expect(state).toMatch(/Status:\s*Ready to plan/);
1496
+ // Completed phases should be incremented from 1 to 2
1497
+ expect(state).toMatch(/completed_phases:\s*2/);
1498
+ // Percent should be recalculated (2/3 = 67%)
1499
+ expect(state).toMatch(/percent:\s*67/);
1500
+ });
1501
+
1502
+ it('detects next phase from filesystem, falls back to ROADMAP.md', async () => {
1503
+ const { phaseComplete } = await import('./phase-lifecycle.js');
1504
+ await setupTestProject(tmpDir, {
1505
+ roadmap: ROADMAP_FOR_COMPLETE,
1506
+ state: STATE_FOR_COMPLETE,
1507
+ phases: ['09-foundation', '10-read-only-queries', '11-final-phase'],
1508
+ });
1509
+ const p10Dir = join(tmpDir, '.planning', 'phases', '10-read-only-queries');
1510
+ await writeFile(join(p10Dir, '10-01-PLAN.md'), 'plan', 'utf-8');
1511
+ await writeFile(join(p10Dir, '10-01-SUMMARY.md'), 'summary', 'utf-8');
1512
+ await writeFile(join(tmpDir, '.planning', 'REQUIREMENTS.md'), REQUIREMENTS_FOR_COMPLETE, 'utf-8');
1513
+
1514
+ const result = await phaseComplete(['10'], tmpDir);
1515
+ const data = result.data as Record<string, unknown>;
1516
+
1517
+ // Next phase should be 11 (from filesystem)
1518
+ expect(data.next_phase).toBe('11');
1519
+ expect(data.is_last_phase).toBe(false);
1520
+ });
1521
+
1522
+ it('sets is_last_phase when completing the final phase', async () => {
1523
+ const { phaseComplete } = await import('./phase-lifecycle.js');
1524
+ await setupTestProject(tmpDir, {
1525
+ roadmap: ROADMAP_FOR_COMPLETE,
1526
+ state: STATE_FOR_COMPLETE,
1527
+ phases: ['09-foundation', '10-read-only-queries', '11-final-phase'],
1528
+ });
1529
+ const p11Dir = join(tmpDir, '.planning', 'phases', '11-final-phase');
1530
+ await writeFile(join(p11Dir, '11-01-PLAN.md'), 'plan', 'utf-8');
1531
+ await writeFile(join(p11Dir, '11-01-SUMMARY.md'), 'summary', 'utf-8');
1532
+ await writeFile(join(tmpDir, '.planning', 'REQUIREMENTS.md'), REQUIREMENTS_FOR_COMPLETE, 'utf-8');
1533
+
1534
+ const result = await phaseComplete(['11'], tmpDir);
1535
+ const data = result.data as Record<string, unknown>;
1536
+
1537
+ expect(data.is_last_phase).toBe(true);
1538
+ expect(data.next_phase).toBeNull();
1539
+
1540
+ // State should show milestone complete
1541
+ const state = await readFile(join(tmpDir, '.planning', 'STATE.md'), 'utf-8');
1542
+ expect(state).toMatch(/Status:\s*Milestone complete/);
1543
+ });
1544
+
1545
+ it('collects UAT/VERIFICATION warnings without blocking', async () => {
1546
+ const { phaseComplete } = await import('./phase-lifecycle.js');
1547
+ await setupTestProject(tmpDir, {
1548
+ roadmap: ROADMAP_FOR_COMPLETE,
1549
+ state: STATE_FOR_COMPLETE,
1550
+ phases: ['09-foundation', '10-read-only-queries', '11-final-phase'],
1551
+ });
1552
+ const p10Dir = join(tmpDir, '.planning', 'phases', '10-read-only-queries');
1553
+ await writeFile(join(p10Dir, '10-01-PLAN.md'), 'plan', 'utf-8');
1554
+ await writeFile(join(p10Dir, '10-01-SUMMARY.md'), 'summary', 'utf-8');
1555
+ // Create UAT file with pending status
1556
+ await writeFile(join(p10Dir, '10-UAT.md'), '---\nresult: pending\n---\nPending tests', 'utf-8');
1557
+ // Create VERIFICATION file with gaps
1558
+ await writeFile(join(p10Dir, '10-VERIFICATION.md'), '---\nstatus: gaps_found\n---\nGaps', 'utf-8');
1559
+ await writeFile(join(tmpDir, '.planning', 'REQUIREMENTS.md'), REQUIREMENTS_FOR_COMPLETE, 'utf-8');
1560
+
1561
+ const result = await phaseComplete(['10'], tmpDir);
1562
+ const data = result.data as Record<string, unknown>;
1563
+
1564
+ // Should complete despite warnings
1565
+ expect(data.completed_phase).toBe('10');
1566
+ expect(data.has_warnings).toBe(true);
1567
+ const warnings = data.warnings as string[];
1568
+ expect(warnings.length).toBeGreaterThan(0);
1569
+ expect(warnings.some(w => w.includes('pending'))).toBe(true);
1570
+ expect(warnings.some(w => w.includes('gaps'))).toBe(true);
1571
+ });
1572
+
1573
+ it('throws GSDError for missing phase', async () => {
1574
+ const { phaseComplete } = await import('./phase-lifecycle.js');
1575
+ await setupTestProject(tmpDir, {
1576
+ roadmap: ROADMAP_FOR_COMPLETE,
1577
+ state: STATE_FOR_COMPLETE,
1578
+ phases: ['09-foundation'],
1579
+ });
1580
+ await writeFile(join(tmpDir, '.planning', 'REQUIREMENTS.md'), REQUIREMENTS_FOR_COMPLETE, 'utf-8');
1581
+
1582
+ await expect(phaseComplete(['99'], tmpDir)).rejects.toThrow('Phase 99 not found');
1583
+ });
1584
+
1585
+ it('updates performance metrics table in STATE.md', async () => {
1586
+ const { phaseComplete } = await import('./phase-lifecycle.js');
1587
+ await setupTestProject(tmpDir, {
1588
+ roadmap: ROADMAP_FOR_COMPLETE,
1589
+ state: STATE_FOR_COMPLETE,
1590
+ phases: ['09-foundation', '10-read-only-queries', '11-final-phase'],
1591
+ });
1592
+ const p10Dir = join(tmpDir, '.planning', 'phases', '10-read-only-queries');
1593
+ await writeFile(join(p10Dir, '10-01-PLAN.md'), 'plan', 'utf-8');
1594
+ await writeFile(join(p10Dir, '10-02-PLAN.md'), 'plan', 'utf-8');
1595
+ await writeFile(join(p10Dir, '10-03-PLAN.md'), 'plan', 'utf-8');
1596
+ await writeFile(join(p10Dir, '10-01-SUMMARY.md'), 'summary', 'utf-8');
1597
+ await writeFile(join(p10Dir, '10-02-SUMMARY.md'), 'summary', 'utf-8');
1598
+ await writeFile(join(p10Dir, '10-03-SUMMARY.md'), 'summary', 'utf-8');
1599
+ await writeFile(join(tmpDir, '.planning', 'REQUIREMENTS.md'), REQUIREMENTS_FOR_COMPLETE, 'utf-8');
1600
+
1601
+ await phaseComplete(['10'], tmpDir);
1602
+
1603
+ const state = await readFile(join(tmpDir, '.planning', 'STATE.md'), 'utf-8');
1604
+ // Total plans completed should be incremented: 3 + 3 = 6
1605
+ expect(state).toContain('Total plans completed: 6');
1606
+ // By Phase table should have a row for phase 10
1607
+ expect(state).toMatch(/\|\s*10\s*\|\s*3\s*\|/);
1608
+ });
1609
+
1610
+ it('does not overwrite plan checkbox when **Plans:** is on its own line (regression #2728)', async () => {
1611
+ const { phaseComplete } = await import('./phase-lifecycle.js');
1612
+
1613
+ const roadmap = [
1614
+ '# Roadmap',
1615
+ '',
1616
+ '## Current Milestone: v3.0',
1617
+ '',
1618
+ '- [ ] Phase 7: marketing-landing-v2',
1619
+ '',
1620
+ '### Phase 7: marketing-landing-v2',
1621
+ '',
1622
+ '**Goal:** Landing page',
1623
+ '**Plans:**',
1624
+ '- [x] 07-01-cherry-pick-foundation-PLAN.md — Wave 1',
1625
+ '- [x] 07-02-routing-auth-seo-PLAN.md — Wave 2',
1626
+ '',
1627
+ '### Phase 8: p3-nice-to-haves',
1628
+ '',
1629
+ '**Goal:** Nice to haves',
1630
+ '**Plans:** 3 plans',
1631
+ '',
1632
+ ].join('\n');
1633
+
1634
+ const state = [
1635
+ '---',
1636
+ 'gsd_state_version: 1.0',
1637
+ 'milestone: v3.0',
1638
+ 'status: executing',
1639
+ 'progress:',
1640
+ ' total_phases: 2',
1641
+ ' completed_phases: 0',
1642
+ ' total_plans: 4',
1643
+ ' completed_plans: 2',
1644
+ ' percent: 50',
1645
+ '---',
1646
+ '',
1647
+ '# Project State',
1648
+ '',
1649
+ 'Phase: 7 of 2 — EXECUTING',
1650
+ 'Status: Executing Phase 7',
1651
+ ].join('\n');
1652
+
1653
+ await setupTestProject(tmpDir, {
1654
+ roadmap,
1655
+ state,
1656
+ phases: ['07-marketing-landing-v2', '08-p3-nice-to-haves'],
1657
+ });
1658
+
1659
+ const p7Dir = join(tmpDir, '.planning', 'phases', '07-marketing-landing-v2');
1660
+ await writeFile(join(p7Dir, '07-01-PLAN.md'), 'plan1', 'utf-8');
1661
+ await writeFile(join(p7Dir, '07-02-PLAN.md'), 'plan2', 'utf-8');
1662
+ await writeFile(join(p7Dir, '07-01-SUMMARY.md'), 'summary1', 'utf-8');
1663
+ await writeFile(join(p7Dir, '07-02-SUMMARY.md'), 'summary2', 'utf-8');
1664
+
1665
+ await phaseComplete(['7'], tmpDir);
1666
+
1667
+ const updated = await readFile(join(tmpDir, '.planning', 'ROADMAP.md'), 'utf-8');
1668
+
1669
+ // The plan lines must NOT be replaced with "N/N plans complete"
1670
+ expect(updated).toContain('07-01-cherry-pick-foundation-PLAN.md');
1671
+ expect(updated).toContain('07-02-routing-auth-seo-PLAN.md');
1672
+ expect(updated).not.toMatch(/^2\/2 plans complete/m);
1673
+
1674
+ // Phase 8's **Plans:** line must NOT be touched
1675
+ expect(updated).toContain('**Plans:** 3 plans');
1676
+ });
1677
+ });
1678
+
1679
+ // ─── phasesClear ────────────────────────────────────────────────────────────
1680
+
1681
+ describe('phasesClear', () => {
1682
+ it('throws GSDError without --confirm flag, showing count', async () => {
1683
+ const { phasesClear } = await import('./phase-lifecycle.js');
1684
+ await setupTestProject(tmpDir, {
1685
+ phases: ['09-foundation', '10-read-only-queries', '999.1-backlog'],
1686
+ });
1687
+
1688
+ // Should throw with count of dirs to delete (2, not 3 since 999.1 is excluded)
1689
+ await expect(phasesClear([], tmpDir)).rejects.toThrow(/2 phase director/);
1690
+ });
1691
+
1692
+ it('deletes all dirs except 999.x with --confirm', async () => {
1693
+ const { phasesClear } = await import('./phase-lifecycle.js');
1694
+ await setupTestProject(tmpDir, {
1695
+ phases: ['09-foundation', '10-read-only-queries', '999.1-backlog'],
1696
+ });
1697
+
1698
+ const result = await phasesClear(['--confirm'], tmpDir);
1699
+ const data = result.data as Record<string, unknown>;
1700
+
1701
+ expect(data.cleared).toBe(2);
1702
+
1703
+ // Verify filesystem
1704
+ const phasesDir = join(tmpDir, '.planning', 'phases');
1705
+ const entries = await readdir(phasesDir, { withFileTypes: true });
1706
+ const dirNames = entries.filter(e => e.isDirectory()).map(e => e.name);
1707
+ expect(dirNames.length).toBe(1);
1708
+ expect(dirNames[0]).toContain('999');
1709
+ });
1710
+
1711
+ it('returns 0 cleared when phases dir is empty', async () => {
1712
+ const { phasesClear } = await import('./phase-lifecycle.js');
1713
+ await setupTestProject(tmpDir, { phases: [] });
1714
+
1715
+ const result = await phasesClear(['--confirm'], tmpDir);
1716
+ const data = result.data as Record<string, unknown>;
1717
+ expect(data.cleared).toBe(0);
1718
+ });
1719
+ });
1720
+
1721
+ // ─── phasesArchive ──────────────────────────────────────────────────────────
1722
+
1723
+ describe('phasesArchive', () => {
1724
+ it('moves milestone phase dirs to milestones/{version}-phases/', async () => {
1725
+ const { phasesArchive } = await import('./phase-lifecycle.js');
1726
+ await setupTestProject(tmpDir, {
1727
+ phases: ['09-foundation', '10-read-only-queries'],
1728
+ });
1729
+
1730
+ const result = await phasesArchive(['v3.0'], tmpDir);
1731
+ const data = result.data as Record<string, unknown>;
1732
+
1733
+ expect(data.version).toBe('v3.0');
1734
+ expect((data.archived as number)).toBeGreaterThan(0);
1735
+
1736
+ // Verify archive directory exists
1737
+ const archiveDir = join(tmpDir, '.planning', 'milestones', 'v3.0-phases');
1738
+ expect(existsSync(archiveDir)).toBe(true);
1739
+
1740
+ // Verify dirs were moved
1741
+ const archivedEntries = await readdir(archiveDir, { withFileTypes: true });
1742
+ const archivedDirs = archivedEntries.filter(e => e.isDirectory()).map(e => e.name);
1743
+ expect(archivedDirs.length).toBeGreaterThan(0);
1744
+
1745
+ // Original dirs should be gone
1746
+ const phasesDir = join(tmpDir, '.planning', 'phases');
1747
+ const remaining = await readdir(phasesDir, { withFileTypes: true });
1748
+ const remainingDirs = remaining.filter(e => e.isDirectory()).map(e => e.name);
1749
+ expect(remainingDirs.length).toBe(0);
1750
+ });
1751
+ });
1752
+
1753
+ // ─── milestoneComplete help-flag defense (#3259) ────────────────────────────
1754
+
1755
+ describe('milestoneComplete help-flag defense', () => {
1756
+ it('rejects --help as a version value with GSDError before any disk write', async () => {
1757
+ const { milestoneComplete } = await import('./phase-lifecycle.js');
1758
+ const { GSDError, ErrorClassification } = await import('../errors.js');
1759
+ await setupTestProject(tmpDir);
1760
+
1761
+ // Capture pre-invocation filesystem state
1762
+ const planningDir = join(tmpDir, '.planning');
1763
+ const milestonesPath = join(planningDir, 'MILESTONES.md');
1764
+ const statePath = join(planningDir, 'STATE.md');
1765
+ const preStateStat = await import('node:fs').then((m) => m.statSync(statePath));
1766
+ const milestonesExistedBefore = existsSync(milestonesPath);
1767
+
1768
+ let thrown: unknown;
1769
+ try {
1770
+ await milestoneComplete(['--help'], tmpDir);
1771
+ } catch (e) {
1772
+ thrown = e;
1773
+ }
1774
+
1775
+ expect(thrown).toBeInstanceOf(GSDError);
1776
+ const err = thrown as InstanceType<typeof GSDError>;
1777
+ expect(err.classification).toBe(ErrorClassification.Validation);
1778
+ expect(err.message).toContain('--help');
1779
+
1780
+ // Assert no files were written
1781
+ const postStateStat = await import('node:fs').then((m) => m.statSync(statePath));
1782
+ expect(postStateStat.mtimeMs).toBe(preStateStat.mtimeMs);
1783
+ expect(existsSync(milestonesPath)).toBe(milestonesExistedBefore);
1784
+ });
1785
+
1786
+ it('rejects -h as a version value with GSDError before any disk write', async () => {
1787
+ const { milestoneComplete } = await import('./phase-lifecycle.js');
1788
+ const { GSDError, ErrorClassification } = await import('../errors.js');
1789
+ await setupTestProject(tmpDir);
1790
+
1791
+ const statePath = join(tmpDir, '.planning', 'STATE.md');
1792
+ const preStateStat = await import('node:fs').then((m) => m.statSync(statePath));
1793
+ const milestonesPath = join(tmpDir, '.planning', 'MILESTONES.md');
1794
+ const milestonesExistedBefore = existsSync(milestonesPath);
1795
+
1796
+ let thrown: unknown;
1797
+ try {
1798
+ await milestoneComplete(['-h'], tmpDir);
1799
+ } catch (e) {
1800
+ thrown = e;
1801
+ }
1802
+
1803
+ expect(thrown).toBeInstanceOf(GSDError);
1804
+ const err = thrown as InstanceType<typeof GSDError>;
1805
+ expect(err.classification).toBe(ErrorClassification.Validation);
1806
+ expect(err.message).toContain('-h');
1807
+
1808
+ // Assert no files were written
1809
+ const postStateStat = await import('node:fs').then((m) => m.statSync(statePath));
1810
+ expect(postStateStat.mtimeMs).toBe(preStateStat.mtimeMs);
1811
+ expect(existsSync(milestonesPath)).toBe(milestonesExistedBefore);
1812
+ });
1813
+ });
1814
+
1815
+ // ─── Registry integration ──────────────────────────────────────────────────
1816
+
1817
+ describe('lifecycle handlers in registry', () => {
1818
+ // Registry assembly (invariant checks + large handler map) routinely takes
1819
+ // 5–10 s on a cold ESM module cache. The second test below reuses the
1820
+ // cached import and completes instantly, but the first import is the cold
1821
+ // path. Raise the per-test timeout so the warm-up doesn't surface as a
1822
+ // spurious "Test timed out" failure (pre-existing: STACK_TRACE_ERROR mask).
1823
+ it('registers all 7 lifecycle handlers with dot notation', async () => {
1824
+ const { createRegistry } = await import('./index.js');
1825
+ const registry = createRegistry();
1826
+
1827
+ const commands = [
1828
+ 'phase.add', 'phase.insert', 'phase.remove', 'phase.complete',
1829
+ 'phase.scaffold', 'phases.clear', 'phases.archive',
1830
+ ];
1831
+
1832
+ for (const cmd of commands) {
1833
+ const handler = registry.getHandler(cmd);
1834
+ expect(handler, `${cmd} should be registered`).toBeDefined();
1835
+ }
1836
+ }, 30_000);
1837
+
1838
+ it('registers space-delimited aliases', async () => {
1839
+ const { createRegistry } = await import('./index.js');
1840
+ const registry = createRegistry();
1841
+
1842
+ const commands = [
1843
+ 'phase add', 'phase insert', 'phase remove', 'phase complete',
1844
+ 'phase scaffold', 'phases clear', 'phases archive',
1845
+ ];
1846
+
1847
+ for (const cmd of commands) {
1848
+ const handler = registry.getHandler(cmd);
1849
+ expect(handler, `${cmd} should be registered`).toBeDefined();
1850
+ }
1851
+ });
1852
+ });
1853
+
1854
+ // ─── CR-3267 regression: error-propagation in listDirectories ─────────────
1855
+
1856
+ describe('listDirectories — CR-3267 finding 1: non-ENOENT errors propagate', () => {
1857
+ it('propagates EACCES from readdir instead of returning []', async () => {
1858
+ const { listDirectories } = await import('./phase-filesystem-adapter.js');
1859
+ // Create a real directory then remove read permission
1860
+ const dir = await mkdtemp(join(tmpdir(), 'gsd-fs-acl-'));
1861
+ const inner = join(dir, 'phases');
1862
+ await mkdir(inner);
1863
+ try {
1864
+ await import('node:fs/promises').then(m => m.chmod(inner, 0o000));
1865
+ await expect(listDirectories(inner)).rejects.toThrow();
1866
+ } finally {
1867
+ // Restore so cleanup can delete
1868
+ await import('node:fs/promises').then(m => m.chmod(inner, 0o755));
1869
+ await rm(dir, { recursive: true, force: true });
1870
+ }
1871
+ });
1872
+
1873
+ it('returns [] for ENOENT (directory gone between existsSync and readdir)', async () => {
1874
+ // existsSync passes, but the directory has been removed before readdir —
1875
+ // the ENOENT branch must still return [].
1876
+ const { listDirectories } = await import('./phase-filesystem-adapter.js');
1877
+ // We can't easily race the real FS, but we can verify the function tolerates
1878
+ // a path that truly does not exist (existsSync returns false → early []).
1879
+ const nonExistent = join(tmpdir(), 'gsd-does-not-exist-' + Date.now());
1880
+ const result = await listDirectories(nonExistent);
1881
+ expect(result).toEqual([]);
1882
+ });
1883
+ });
1884
+
1885
+ // ─── CR-3267 regression: error-propagation in readModifyWriteRoadmapMd ─────
1886
+
1887
+ describe('readModifyWriteRoadmapMd — CR-3267 finding 4: non-ENOENT errors propagate', () => {
1888
+ it('propagates EACCES on ROADMAP.md readFile instead of treating as empty', async () => {
1889
+ const { readModifyWriteRoadmapMd } = await import('./phase-lifecycle.js');
1890
+ const dir = await mkdtemp(join(tmpdir(), 'gsd-roadmap-acl-'));
1891
+ const planningDir = join(dir, '.planning');
1892
+ await mkdir(planningDir, { recursive: true });
1893
+ const roadmapPath = join(planningDir, 'ROADMAP.md');
1894
+ await writeFile(roadmapPath, '# Roadmap\n', 'utf-8');
1895
+ try {
1896
+ await import('node:fs/promises').then(m => m.chmod(roadmapPath, 0o000));
1897
+ await expect(
1898
+ readModifyWriteRoadmapMd(dir, (c) => c)
1899
+ ).rejects.toThrow();
1900
+ } finally {
1901
+ await import('node:fs/promises').then(m => m.chmod(roadmapPath, 0o644));
1902
+ await rm(dir, { recursive: true, force: true });
1903
+ }
1904
+ });
1905
+
1906
+ it('starts with empty content when ROADMAP.md is absent (ENOENT)', async () => {
1907
+ const { readModifyWriteRoadmapMd } = await import('./phase-lifecycle.js');
1908
+ const dir = await mkdtemp(join(tmpdir(), 'gsd-roadmap-noent-'));
1909
+ const planningDir = join(dir, '.planning');
1910
+ await mkdir(planningDir, { recursive: true });
1911
+ // No ROADMAP.md written — must default to '' and create it
1912
+ try {
1913
+ const result = await readModifyWriteRoadmapMd(dir, (c) => c + 'NEW');
1914
+ expect(result).toBe('NEW');
1915
+ } finally {
1916
+ await rm(dir, { recursive: true, force: true });
1917
+ }
1918
+ });
1919
+ });
1920
+
1921
+ // ─── CR-3267 regression: buildPhaseRoadmapEntry — no "Phase 0" dependency ──
1922
+
1923
+ describe('buildPhaseRoadmapEntry — CR-3267 finding 2: first sequential phase has no predecessor', () => {
1924
+ it('omits Depends on line when phaseId is 1', async () => {
1925
+ const { buildPhaseRoadmapEntry } = await import('./phase-lifecycle-policy.js');
1926
+ const entry = buildPhaseRoadmapEntry(1, 'Bootstrap', 'sequential');
1927
+ expect(entry).not.toContain('Depends on');
1928
+ expect(entry).not.toContain('Phase 0');
1929
+ });
1930
+
1931
+ it('includes Depends on line when phaseId is 2', async () => {
1932
+ const { buildPhaseRoadmapEntry } = await import('./phase-lifecycle-policy.js');
1933
+ const entry = buildPhaseRoadmapEntry(2, 'Second Phase', 'sequential');
1934
+ expect(entry).toContain('**Depends on:** Phase 1');
1935
+ });
1936
+
1937
+ it('omits Depends on line for custom naming mode regardless of id', async () => {
1938
+ const { buildPhaseRoadmapEntry } = await import('./phase-lifecycle-policy.js');
1939
+ const entry = buildPhaseRoadmapEntry('ALPHA', 'Custom', 'custom');
1940
+ expect(entry).not.toContain('Depends on');
1941
+ });
1942
+ });
1943
+
1944
+ // ─── CR-3267 regression: collectDecimalSuffixesFromDirNames prefix grammar ─
1945
+
1946
+ describe('collectDecimalSuffixesFromDirNames — CR-3267 finding 3: alphanumeric prefixes accepted', () => {
1947
+ it('matches directories with long alphanumeric project-code prefix', async () => {
1948
+ const { collectDecimalSuffixesFromDirNames } = await import('./phase-lifecycle-policy.js');
1949
+ // Prefix "MYAPP01" is longer than 6 chars and contains digits — was rejected before fix
1950
+ const dirs = ['MYAPP01-3.1-some-work', 'MYAPP01-3.2-other-work', 'unrelated-dir'];
1951
+ const result = collectDecimalSuffixesFromDirNames('3', dirs);
1952
+ expect(result.has(1)).toBe(true);
1953
+ expect(result.has(2)).toBe(true);
1954
+ });
1955
+
1956
+ it('still matches directories with short uppercase-only prefix', async () => {
1957
+ const { collectDecimalSuffixesFromDirNames } = await import('./phase-lifecycle-policy.js');
1958
+ const dirs = ['AB-5.1-task', 'AB-5.3-other'];
1959
+ const result = collectDecimalSuffixesFromDirNames('5', dirs);
1960
+ expect(result.has(1)).toBe(true);
1961
+ expect(result.has(3)).toBe(true);
1962
+ });
1963
+
1964
+ it('matches directories with no prefix', async () => {
1965
+ const { collectDecimalSuffixesFromDirNames } = await import('./phase-lifecycle-policy.js');
1966
+ const dirs = ['3.1-plain', '3.2-also-plain'];
1967
+ const result = collectDecimalSuffixesFromDirNames('3', dirs);
1968
+ expect(result.has(1)).toBe(true);
1969
+ expect(result.has(2)).toBe(true);
1970
+ });
1971
+ });