@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,1940 @@
1
+ /**
2
+ * State — STATE.md operations and progression engine
3
+ */
4
+
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+ const { escapeRegex, loadConfig, getMilestoneInfo, getMilestonePhaseFilter, output, error } = require('./core.cjs');
8
+ const { platformWriteSync, platformReadSync, platformEnsureDir } = require('./shell-command-projection.cjs');
9
+ const { planningDir, planningPaths } = require('./planning-workspace.cjs');
10
+ const { extractFrontmatter, reconstructFrontmatter } = require('./frontmatter.cjs');
11
+ const scanPhasePlans = require('./plan-scan.cjs');
12
+ const {
13
+ computeProgressPercent,
14
+ normalizeProgressNumbers,
15
+ normalizeStateStatus,
16
+ shouldPreserveExistingProgress,
17
+ stateExtractField,
18
+ stateReplaceField,
19
+ } = require('./state-document.cjs');
20
+
21
+ // Cache disk scan results from buildStateFrontmatter per cwd per process (#1967).
22
+ // Avoids re-reading N+1 directories on every state write when the phase structure
23
+ // hasn't changed within the same gsd-tools invocation.
24
+ const _diskScanCache = new Map();
25
+
26
+ /** Shorthand — every state command needs this path */
27
+ function getStatePath(cwd) {
28
+ return planningPaths(cwd).state;
29
+ }
30
+
31
+ // Track all lock files held by this process so they can be removed on exit.
32
+ // process.on('exit') fires even on process.exit(1), unlike try/finally which is
33
+ // skipped when error() calls process.exit(1) inside a locked region (#1916).
34
+ const _heldStateLocks = new Set();
35
+ process.on('exit', () => {
36
+ for (const lockPath of _heldStateLocks) {
37
+ try { require('fs').unlinkSync(lockPath); } catch { /* already gone */ }
38
+ }
39
+ });
40
+
41
+ function cmdStateLoad(cwd, raw) {
42
+ const config = loadConfig(cwd);
43
+ const planDir = planningPaths(cwd).planning;
44
+
45
+ const stateRaw = platformReadSync(path.join(planDir, 'STATE.md')) || '';
46
+
47
+ const configExists = fs.existsSync(path.join(planDir, 'config.json'));
48
+ const roadmapExists = fs.existsSync(path.join(planDir, 'ROADMAP.md'));
49
+ const stateExists = stateRaw.length > 0;
50
+
51
+ const result = {
52
+ config,
53
+ state_raw: stateRaw,
54
+ state_exists: stateExists,
55
+ roadmap_exists: roadmapExists,
56
+ config_exists: configExists,
57
+ };
58
+
59
+ // For --raw, output a condensed key=value format
60
+ if (raw) {
61
+ const c = config;
62
+ const lines = [
63
+ `model_profile=${c.model_profile}`,
64
+ `commit_docs=${c.commit_docs}`,
65
+ `branching_strategy=${c.branching_strategy}`,
66
+ `phase_branch_template=${c.phase_branch_template}`,
67
+ `milestone_branch_template=${c.milestone_branch_template}`,
68
+ `parallelization=${c.parallelization}`,
69
+ `research=${c.research}`,
70
+ `plan_checker=${c.plan_checker}`,
71
+ `verifier=${c.verifier}`,
72
+ `config_exists=${configExists}`,
73
+ `roadmap_exists=${roadmapExists}`,
74
+ `state_exists=${stateExists}`,
75
+ ];
76
+ process.stdout.write(lines.join('\n'));
77
+ process.exit(0);
78
+ }
79
+
80
+ output(result);
81
+ }
82
+
83
+ function cmdStateGet(cwd, section, raw) {
84
+ const statePath = planningPaths(cwd).state;
85
+ const content = platformReadSync(statePath);
86
+ if (content === null) {
87
+ error('STATE.md not found');
88
+ return;
89
+ }
90
+ {
91
+
92
+ if (!section) {
93
+ output({ content }, raw, content);
94
+ return;
95
+ }
96
+
97
+ // Try to find markdown section or field
98
+ const fieldEscaped = escapeRegex(section);
99
+
100
+ // Check for **field:** value (bold format)
101
+ const boldPattern = new RegExp(`\\*\\*${fieldEscaped}:\\*\\*\\s*(.*)`, 'i');
102
+ const boldMatch = content.match(boldPattern);
103
+ if (boldMatch) {
104
+ output({ [section]: boldMatch[1].trim() }, raw, boldMatch[1].trim());
105
+ return;
106
+ }
107
+
108
+ // Check for field: value (plain format)
109
+ const plainPattern = new RegExp(`^${fieldEscaped}:\\s*(.*)`, 'im');
110
+ const plainMatch = content.match(plainPattern);
111
+ if (plainMatch) {
112
+ output({ [section]: plainMatch[1].trim() }, raw, plainMatch[1].trim());
113
+ return;
114
+ }
115
+
116
+ // Check for ## Section
117
+ const sectionPattern = new RegExp(`##\\s*${fieldEscaped}\\s*\n([\\s\\S]*?)(?=\\n##|$)`, 'i');
118
+ const sectionMatch = content.match(sectionPattern);
119
+ if (sectionMatch) {
120
+ output({ [section]: sectionMatch[1].trim() }, raw, sectionMatch[1].trim());
121
+ return;
122
+ }
123
+
124
+ output({ error: `Section or field "${section}" not found` }, raw, '');
125
+ }
126
+ }
127
+
128
+ function readTextArgOrFile(cwd, value, filePath, label) {
129
+ if (!filePath) return value;
130
+
131
+ // Path traversal guard: ensure file resolves within project directory
132
+ const { validatePath } = require('./security.cjs');
133
+ const pathCheck = validatePath(filePath, cwd, { allowAbsolute: true });
134
+ if (!pathCheck.safe) {
135
+ throw new Error(`${label} path rejected: ${pathCheck.error}`);
136
+ }
137
+
138
+ try {
139
+ return fs.readFileSync(pathCheck.resolved, 'utf-8').trimEnd();
140
+ } catch {
141
+ throw new Error(`${label} file not found: ${filePath}`);
142
+ }
143
+ }
144
+
145
+ function cmdStatePatch(cwd, patches, raw) {
146
+ // Validate all field names before processing
147
+ const { validateFieldName } = require('./security.cjs');
148
+ for (const field of Object.keys(patches)) {
149
+ const fieldCheck = validateFieldName(field);
150
+ if (!fieldCheck.valid) {
151
+ error(`state patch: ${fieldCheck.error}`);
152
+ }
153
+ }
154
+
155
+ const statePath = planningPaths(cwd).state;
156
+ try {
157
+ const results = { updated: [], failed: [] };
158
+
159
+ // Use atomic read-modify-write to prevent lost updates from concurrent agents
160
+ readModifyWriteStateMd(statePath, (content) => {
161
+ for (const [field, value] of Object.entries(patches)) {
162
+ const result = stateReplaceField(content, field, value);
163
+ if (result) {
164
+ content = result;
165
+ results.updated.push(field);
166
+ } else {
167
+ results.failed.push(field);
168
+ }
169
+ }
170
+ return content;
171
+ }, cwd);
172
+
173
+ output(results, raw, results.updated.length > 0 ? 'true' : 'false');
174
+ } catch {
175
+ error('STATE.md not found');
176
+ }
177
+ }
178
+
179
+ function cmdStateUpdate(cwd, field, value) {
180
+ if (!field || value === undefined) {
181
+ error('field and value required for state update');
182
+ }
183
+
184
+ // Validate field name to prevent regex injection via crafted field names
185
+ const { validateFieldName } = require('./security.cjs');
186
+ const fieldCheck = validateFieldName(field);
187
+ if (!fieldCheck.valid) {
188
+ error(`state update: ${fieldCheck.error}`);
189
+ }
190
+
191
+ const statePath = planningPaths(cwd).state;
192
+ try {
193
+ let updated = false;
194
+ const shouldResync = ['Progress', 'Total Plans in Phase', 'Total Phases'].includes(field);
195
+ // Preserve curated progress for body-only updates, but allow fields that
196
+ // directly project into progress.* frontmatter to rebuild after mutation.
197
+ readModifyWriteStateMd(statePath, (content) => {
198
+ const body = stripFrontmatter(content);
199
+ const result = stateReplaceField(body, field, value);
200
+ if (result) {
201
+ updated = true;
202
+ const existingFm = extractFrontmatter(content);
203
+ if (Object.keys(existingFm).length > 0) {
204
+ return `---\n${reconstructFrontmatter(existingFm)}\n---\n\n${result}`;
205
+ }
206
+ return result;
207
+ }
208
+ return content;
209
+ }, cwd, { resync: shouldResync });
210
+ if (updated) {
211
+ output({ updated: true });
212
+ } else {
213
+ output({ updated: false, reason: `Field "${field}" not found in STATE.md` });
214
+ }
215
+ } catch {
216
+ output({ updated: false, reason: 'STATE.md not found' });
217
+ }
218
+ }
219
+
220
+ // ─── State Progression Engine ────────────────────────────────────────────────
221
+
222
+ /**
223
+ * Replace a STATE.md field with fallback field name support.
224
+ * Tries `primary` first, then `fallback` (if provided), returns content unchanged
225
+ * if neither matches. This consolidates the replaceWithFallback pattern that was
226
+ * previously duplicated inline across phase.cjs, milestone.cjs, and state.cjs.
227
+ */
228
+ function stateReplaceFieldWithFallback(content, primary, fallback, value) {
229
+ let result = stateReplaceField(content, primary, value);
230
+ if (result) return result;
231
+ if (fallback) {
232
+ result = stateReplaceField(content, fallback, value);
233
+ if (result) return result;
234
+ }
235
+ // Neither pattern matched — field may have been reformatted or removed.
236
+ // Log diagnostic so template drift is detected early rather than silently swallowed.
237
+ process.stderr.write(
238
+ `[gsd-tools] WARNING: STATE.md field "${primary}"${fallback ? ` (fallback: "${fallback}")` : ''} not found — update skipped. ` +
239
+ `This may indicate STATE.md was externally modified or uses an unexpected format.\n`
240
+ );
241
+ return content;
242
+ }
243
+
244
+ /**
245
+ * Update fields within the ## Current Position section of STATE.md.
246
+ * This keeps the Current Position body in sync with the bold frontmatter fields.
247
+ * Only updates fields that already exist in the section; does not add new lines.
248
+ * Fixes #1365: advance-plan could not update Status/Last activity after begin-phase.
249
+ */
250
+ function updateCurrentPositionFields(content, fields) {
251
+ const posPattern = /(##\s*Current Position\s*\n)([\s\S]*?)(?=\n##|$)/i;
252
+ const posMatch = content.match(posPattern);
253
+ if (!posMatch) return content;
254
+
255
+ let posBody = posMatch[2];
256
+
257
+ if (fields.status && /^Status:/m.test(posBody)) {
258
+ posBody = posBody.replace(/^Status:.*$/m, `Status: ${fields.status}`);
259
+ }
260
+ if (fields.lastActivity && /^Last activity:/im.test(posBody)) {
261
+ posBody = posBody.replace(/^Last activity:.*$/im, `Last activity: ${fields.lastActivity}`);
262
+ }
263
+ if (fields.plan && /^Plan:/m.test(posBody)) {
264
+ posBody = posBody.replace(/^Plan:.*$/m, `Plan: ${fields.plan}`);
265
+ }
266
+
267
+ return content.replace(posPattern, () => `${posMatch[1]}${posBody}`);
268
+ }
269
+
270
+ function cmdStateAdvancePlan(cwd, raw) {
271
+ const statePath = planningPaths(cwd).state;
272
+ if (!fs.existsSync(statePath)) { output({ error: 'STATE.md not found' }, raw); return; }
273
+
274
+ const today = new Date().toISOString().split('T')[0];
275
+ let result = null;
276
+
277
+ readModifyWriteStateMd(statePath, (content) => {
278
+ // Try legacy separate fields first, then compound "Plan: X of Y" format
279
+ const legacyPlan = stateExtractField(content, 'Current Plan');
280
+ const legacyTotal = stateExtractField(content, 'Total Plans in Phase');
281
+ const planField = stateExtractField(content, 'Plan');
282
+
283
+ let currentPlan, totalPlans;
284
+ let useCompoundFormat = false;
285
+
286
+ if (legacyPlan && legacyTotal) {
287
+ currentPlan = parseInt(legacyPlan, 10);
288
+ totalPlans = parseInt(legacyTotal, 10);
289
+ } else if (planField) {
290
+ // Compound format: "2 of 6 in current phase" or "2 of 6"
291
+ currentPlan = parseInt(planField, 10);
292
+ const ofMatch = planField.match(/of\s+(\d+)/);
293
+ totalPlans = ofMatch ? parseInt(ofMatch[1], 10) : NaN;
294
+ useCompoundFormat = true;
295
+ }
296
+
297
+ if (isNaN(currentPlan) || isNaN(totalPlans)) {
298
+ result = { error: true };
299
+ return content;
300
+ }
301
+
302
+ if (currentPlan >= totalPlans) {
303
+ content = stateReplaceFieldWithFallback(content, 'Status', null, 'Phase complete — ready for verification');
304
+ content = stateReplaceFieldWithFallback(content, 'Last Activity', 'Last activity', today);
305
+ content = updateCurrentPositionFields(content, { status: 'Phase complete — ready for verification', lastActivity: today });
306
+ result = { advanced: false, reason: 'last_plan', current_plan: currentPlan, total_plans: totalPlans, status: 'ready_for_verification' };
307
+ } else {
308
+ const newPlan = currentPlan + 1;
309
+ let planDisplayValue;
310
+ if (useCompoundFormat) {
311
+ // Preserve compound format: "X of Y in current phase" → replace X only
312
+ planDisplayValue = planField.replace(/^\d+/, String(newPlan));
313
+ content = stateReplaceField(content, 'Plan', planDisplayValue) || content;
314
+ } else {
315
+ planDisplayValue = `${newPlan} of ${totalPlans}`;
316
+ content = stateReplaceField(content, 'Current Plan', String(newPlan)) || content;
317
+ }
318
+ content = stateReplaceFieldWithFallback(content, 'Status', null, 'Ready to execute');
319
+ content = stateReplaceFieldWithFallback(content, 'Last Activity', 'Last activity', today);
320
+ content = updateCurrentPositionFields(content, { status: 'Ready to execute', lastActivity: today, plan: planDisplayValue });
321
+ result = { advanced: true, previous_plan: currentPlan, current_plan: newPlan, total_plans: totalPlans };
322
+ }
323
+ return content;
324
+ }, cwd);
325
+
326
+ if (!result || result.error) {
327
+ output({ error: 'Cannot parse Current Plan or Total Plans in Phase from STATE.md' }, raw);
328
+ return;
329
+ }
330
+
331
+ if (result.advanced === false) {
332
+ output(result, raw, 'false');
333
+ } else {
334
+ output(result, raw, 'true');
335
+ }
336
+ }
337
+
338
+ function cmdStateRecordMetric(cwd, options, raw) {
339
+ const statePath = planningPaths(cwd).state;
340
+ if (!fs.existsSync(statePath)) { output({ error: 'STATE.md not found' }, raw); return; }
341
+
342
+ const { phase, plan, duration, tasks, files } = options;
343
+
344
+ if (!phase || !plan || !duration) {
345
+ output({ error: 'phase, plan, and duration required' }, raw);
346
+ return;
347
+ }
348
+
349
+ let recorded = false;
350
+ let created = false;
351
+ readModifyWriteStateMd(statePath, (content) => {
352
+ // Find Performance Metrics section and its table
353
+ const metricsPattern = /(##\s*Performance Metrics[\s\S]*?\n\|[^\n]+\n\|[-|\s]+\n)([\s\S]*?)(?=\n##|\n$|$)/i;
354
+ const metricsMatch = content.match(metricsPattern);
355
+
356
+ const newRow = `| Phase ${phase} P${plan} | ${duration} | ${tasks || '-'} tasks | ${files || '-'} files |`;
357
+
358
+ if (metricsMatch) {
359
+ let tableBody = metricsMatch[2].trimEnd();
360
+
361
+ if (tableBody.trim() === '' || tableBody.includes('None yet')) {
362
+ tableBody = newRow;
363
+ } else {
364
+ tableBody = tableBody + '\n' + newRow;
365
+ }
366
+
367
+ recorded = true;
368
+ return content.replace(metricsPattern, (_match, header) => `${header}${tableBody}\n`);
369
+ }
370
+
371
+ // Section absent — DWIM: auto-create canonical ## Performance Metrics scaffold,
372
+ // then append the row. Matches state begin-phase / advance-plan DWIM behavior.
373
+ const scaffold = [
374
+ '',
375
+ '## Performance Metrics',
376
+ '',
377
+ '| Phase | Plan | Duration | Notes |',
378
+ '|-------|------|----------|-------|',
379
+ newRow,
380
+ '',
381
+ ].join('\n');
382
+ recorded = true;
383
+ created = true;
384
+ return content.trimEnd() + '\n' + scaffold;
385
+ }, cwd);
386
+
387
+ // Auto-create fallback guarantees recorded === true; no else branch needed.
388
+ const result = { recorded: true, phase, plan, duration };
389
+ if (created) result.created = true;
390
+ output(result, raw, 'true');
391
+ }
392
+
393
+ function cmdStateUpdateProgress(cwd, raw) {
394
+ const statePath = planningPaths(cwd).state;
395
+ if (!fs.existsSync(statePath)) { output({ error: 'STATE.md not found' }, raw); return; }
396
+
397
+ // Count summaries across current milestone phases only (outside lock — read-only)
398
+ const phasesDir = planningPaths(cwd).phases;
399
+ let totalPlans = 0;
400
+ let totalSummaries = 0;
401
+
402
+ if (fs.existsSync(phasesDir)) {
403
+ const isDirInMilestone = getMilestonePhaseFilter(cwd);
404
+ const phaseDirs = fs.readdirSync(phasesDir, { withFileTypes: true })
405
+ .filter(e => e.isDirectory()).map(e => e.name)
406
+ .filter(isDirInMilestone);
407
+ for (const dir of phaseDirs) {
408
+ const { planCount, summaryCount } = scanPhasePlans(path.join(phasesDir, dir));
409
+ totalPlans += planCount;
410
+ totalSummaries += summaryCount;
411
+ }
412
+ }
413
+
414
+ const percent = totalPlans > 0 ? Math.min(100, Math.round(totalSummaries / totalPlans * 100)) : 0;
415
+ const barWidth = 10;
416
+ const filled = Math.round(percent / 100 * barWidth);
417
+ const bar = '\u2588'.repeat(filled) + '\u2591'.repeat(barWidth - filled);
418
+ const progressStr = `[${bar}] ${percent}%`;
419
+
420
+ let updated = false;
421
+ const _totalPlans = totalPlans;
422
+ const _totalSummaries = totalSummaries;
423
+
424
+ readModifyWriteStateMd(statePath, (content) => {
425
+ // Try **Progress:** bold format first, then plain Progress: format
426
+ const boldProgressPattern = /(\*\*Progress:\*\*\s*).*/i;
427
+ const plainProgressPattern = /^(Progress:\s*).*/im;
428
+ if (boldProgressPattern.test(content)) {
429
+ updated = true;
430
+ return content.replace(boldProgressPattern, (_match, prefix) => `${prefix}${progressStr}`);
431
+ } else if (plainProgressPattern.test(content)) {
432
+ updated = true;
433
+ return content.replace(plainProgressPattern, (_match, prefix) => `${prefix}${progressStr}`);
434
+ }
435
+ return content;
436
+ }, cwd);
437
+
438
+ if (updated) {
439
+ output({ updated: true, percent, completed: _totalSummaries, total: _totalPlans, bar: progressStr }, raw, progressStr);
440
+ } else {
441
+ output({ updated: false, reason: 'Progress field not found in STATE.md' }, raw, 'false');
442
+ }
443
+ }
444
+
445
+ function cmdStateAddDecision(cwd, options, raw) {
446
+ const statePath = planningPaths(cwd).state;
447
+ if (!fs.existsSync(statePath)) { output({ error: 'STATE.md not found' }, raw); return; }
448
+
449
+ const { phase, summary, summary_file, rationale, rationale_file } = options;
450
+ let summaryText = null;
451
+ let rationaleText = '';
452
+
453
+ try {
454
+ summaryText = readTextArgOrFile(cwd, summary, summary_file, 'summary');
455
+ rationaleText = readTextArgOrFile(cwd, rationale || '', rationale_file, 'rationale');
456
+ } catch (err) {
457
+ output({ added: false, reason: err.message }, raw, 'false');
458
+ return;
459
+ }
460
+
461
+ if (!summaryText) { output({ error: 'summary required' }, raw); return; }
462
+
463
+ const entry = `- [Phase ${phase || '?'}]: ${summaryText}${rationaleText ? ` — ${rationaleText}` : ''}`;
464
+ let added = false;
465
+ let created = false;
466
+
467
+ readModifyWriteStateMd(statePath, (content) => {
468
+ // Find Decisions section (various heading patterns)
469
+ const sectionPattern = /(###?\s*(?:Decisions|Decisions Made|Accumulated.*Decisions)\s*\n)([\s\S]*?)(?=\n###?|\n##[^#]|$)/i;
470
+ const match = content.match(sectionPattern);
471
+
472
+ if (match) {
473
+ let sectionBody = match[2];
474
+ // Remove placeholders
475
+ sectionBody = sectionBody.replace(/None yet\.?\s*\n?/gi, '').replace(/No decisions yet\.?\s*\n?/gi, '');
476
+ sectionBody = sectionBody.trimEnd() + '\n' + entry + '\n';
477
+ added = true;
478
+ return content.replace(sectionPattern, (_match, header) => `${header}${sectionBody}`);
479
+ }
480
+
481
+ // Section absent — DWIM: auto-create canonical ## Decisions scaffold,
482
+ // then append the entry. Matches state begin-phase / advance-plan DWIM behavior.
483
+ const scaffold = [
484
+ '',
485
+ '## Decisions',
486
+ '',
487
+ entry,
488
+ '',
489
+ ].join('\n');
490
+ added = true;
491
+ created = true;
492
+ return content.trimEnd() + '\n' + scaffold;
493
+ }, cwd);
494
+
495
+ // Auto-create fallback guarantees added === true; no else branch needed.
496
+ const result = { added: true, decision: entry };
497
+ if (created) result.created = true;
498
+ output(result, raw, 'true');
499
+ }
500
+
501
+ function cmdStateAddBlocker(cwd, text, raw) {
502
+ const statePath = planningPaths(cwd).state;
503
+ if (!fs.existsSync(statePath)) { output({ error: 'STATE.md not found' }, raw); return; }
504
+ const blockerOptions = typeof text === 'object' && text !== null ? text : { text };
505
+ let blockerText = null;
506
+
507
+ try {
508
+ blockerText = readTextArgOrFile(cwd, blockerOptions.text, blockerOptions.text_file, 'blocker');
509
+ } catch (err) {
510
+ output({ added: false, reason: err.message }, raw, 'false');
511
+ return;
512
+ }
513
+
514
+ if (!blockerText) { output({ error: 'text required' }, raw); return; }
515
+
516
+ const entry = `- ${blockerText}`;
517
+ let added = false;
518
+ let created = false;
519
+
520
+ readModifyWriteStateMd(statePath, (content) => {
521
+ const sectionPattern = /(###?\s*(?:Blockers|Blockers\/Concerns|Concerns)\s*\n)([\s\S]*?)(?=\n###?|\n##[^#]|$)/i;
522
+ const match = content.match(sectionPattern);
523
+
524
+ if (match) {
525
+ let sectionBody = match[2];
526
+ sectionBody = sectionBody.replace(/None\.?\s*\n?/gi, '').replace(/None yet\.?\s*\n?/gi, '');
527
+ sectionBody = sectionBody.trimEnd() + '\n' + entry + '\n';
528
+ added = true;
529
+ return content.replace(sectionPattern, (_match, header) => `${header}${sectionBody}`);
530
+ }
531
+
532
+ // Section absent — DWIM: auto-create canonical ### Blockers scaffold.
533
+ const scaffold = [
534
+ '',
535
+ '### Blockers',
536
+ '',
537
+ entry,
538
+ '',
539
+ ].join('\n');
540
+ added = true;
541
+ created = true;
542
+ return content.trimEnd() + '\n' + scaffold;
543
+ }, cwd);
544
+
545
+ // Auto-create fallback guarantees added === true; no else branch needed.
546
+ const result = { added: true, blocker: blockerText };
547
+ if (created) result.created = true;
548
+ output(result, raw, 'true');
549
+ }
550
+
551
+ function cmdStateResolveBlocker(cwd, text, raw) {
552
+ const statePath = planningPaths(cwd).state;
553
+ if (!fs.existsSync(statePath)) { output({ error: 'STATE.md not found' }, raw); return; }
554
+ if (!text) { output({ error: 'text required' }, raw); return; }
555
+
556
+ let resolved = false;
557
+
558
+ readModifyWriteStateMd(statePath, (content) => {
559
+ const sectionPattern = /(###?\s*(?:Blockers|Blockers\/Concerns|Concerns)\s*\n)([\s\S]*?)(?=\n###?|\n##[^#]|$)/i;
560
+ const match = content.match(sectionPattern);
561
+
562
+ if (match) {
563
+ const sectionBody = match[2];
564
+ const lines = sectionBody.split('\n');
565
+ const filtered = lines.filter(line => {
566
+ if (!line.startsWith('- ')) return true;
567
+ return !line.toLowerCase().includes(text.toLowerCase());
568
+ });
569
+
570
+ let newBody = filtered.join('\n');
571
+ // If section is now empty, add placeholder
572
+ if (!newBody.trim() || !newBody.includes('- ')) {
573
+ newBody = 'None\n';
574
+ }
575
+
576
+ resolved = true;
577
+ return content.replace(sectionPattern, (_match, header) => `${header}${newBody}`);
578
+ }
579
+ return content;
580
+ }, cwd);
581
+
582
+ if (resolved) {
583
+ output({ resolved: true, blocker: text }, raw, 'true');
584
+ } else {
585
+ output({ resolved: false, reason: 'Blockers section not found in STATE.md' }, raw, 'false');
586
+ }
587
+ }
588
+
589
+ function cmdStateRecordSession(cwd, options, raw) {
590
+ const statePath = planningPaths(cwd).state;
591
+ if (!fs.existsSync(statePath)) { output({ error: 'STATE.md not found' }, raw); return; }
592
+
593
+ const now = new Date().toISOString();
594
+ const updated = [];
595
+
596
+ readModifyWriteStateMd(statePath, (content) => {
597
+ // Update Last session / Last Date
598
+ let result = stateReplaceField(content, 'Last session', now);
599
+ if (result) { content = result; updated.push('Last session'); }
600
+ result = stateReplaceField(content, 'Last Date', now);
601
+ if (result) { content = result; updated.push('Last Date'); }
602
+
603
+ // Update Stopped at
604
+ if (options.stopped_at) {
605
+ result = stateReplaceField(content, 'Stopped At', options.stopped_at);
606
+ if (!result) result = stateReplaceField(content, 'Stopped at', options.stopped_at);
607
+ if (result) { content = result; updated.push('Stopped At'); }
608
+ }
609
+
610
+ // Update Resume file
611
+ const resumeFile = options.resume_file || 'None';
612
+ result = stateReplaceField(content, 'Resume File', resumeFile);
613
+ if (!result) result = stateReplaceField(content, 'Resume file', resumeFile);
614
+ if (result) { content = result; updated.push('Resume File'); }
615
+
616
+ return content;
617
+ }, cwd);
618
+
619
+ if (updated.length > 0) {
620
+ output({ recorded: true, updated }, raw, 'true');
621
+ } else {
622
+ output({ recorded: false, reason: 'No session fields found in STATE.md' }, raw, 'false');
623
+ }
624
+ }
625
+
626
+ function cmdStateSnapshot(cwd, raw) {
627
+ const statePath = planningPaths(cwd).state;
628
+
629
+ if (!fs.existsSync(statePath)) {
630
+ output({ error: 'STATE.md not found' }, raw);
631
+ return;
632
+ }
633
+
634
+ const content = fs.readFileSync(statePath, 'utf-8');
635
+
636
+ // Bug #3265: prefer YAML frontmatter for canonical scalar fields so that a
637
+ // body table cell containing **Status:** Y cannot shadow the authoritative
638
+ // frontmatter value. Mirrors the fix in sdk/src/query/state.ts.
639
+ const fm = extractFrontmatter(content);
640
+ const body = stripFrontmatter(content);
641
+
642
+ // Helper: return frontmatter scalar value when present and non-empty.
643
+ // Accepts strings, numbers, and booleans — coercing non-string primitives to
644
+ // their string representation so callers always receive string | null.
645
+ // Returns null for missing, null/undefined, or empty-after-trim values so
646
+ // the caller falls back to body extraction.
647
+ const fmScalar = (key) => {
648
+ const v = fm[key];
649
+ if (v === null || v === undefined) return null;
650
+ if (typeof v === 'string') return v.trim() || null;
651
+ if (typeof v === 'number' || typeof v === 'boolean') return String(v);
652
+ return null;
653
+ };
654
+
655
+ // Extract basic fields — frontmatter keys take precedence over body
656
+ const currentPhase = fmScalar('current_phase') ?? stateExtractField(body, 'Current Phase');
657
+ const currentPhaseName = fmScalar('current_phase_name') ?? stateExtractField(body, 'Current Phase Name');
658
+ const totalPhasesRaw = fmScalar('total_phases') ?? stateExtractField(body, 'Total Phases');
659
+ const currentPlan = fmScalar('current_plan') ?? stateExtractField(body, 'Current Plan');
660
+ const totalPlansRaw = fmScalar('total_plans_in_phase') ?? stateExtractField(body, 'Total Plans in Phase');
661
+ const status = fmScalar('status') ?? stateExtractField(body, 'Status');
662
+ const progressRaw = fmScalar('progress') ?? stateExtractField(body, 'Progress');
663
+ const lastActivity = fmScalar('last_activity') ?? stateExtractField(body, 'Last Activity');
664
+ const lastActivityDesc = fmScalar('last_activity_desc') ?? stateExtractField(body, 'Last Activity Description');
665
+ const pausedAt = fmScalar('paused_at') ?? stateExtractField(body, 'Paused At');
666
+
667
+ // Parse numeric fields
668
+ const totalPhases = totalPhasesRaw ? parseInt(totalPhasesRaw, 10) : null;
669
+ const totalPlansInPhase = totalPlansRaw ? parseInt(totalPlansRaw, 10) : null;
670
+ const progressPercent = progressRaw ? parseInt(progressRaw.replace('%', ''), 10) : null;
671
+
672
+ // Extract decisions table
673
+ const decisions = [];
674
+ const decisionsMatch = body.match(/##\s*Decisions Made[\s\S]*?\n\|[^\n]+\n\|[-|\s]+\n([\s\S]*?)(?=\n##|\n$|$)/i);
675
+ if (decisionsMatch) {
676
+ const tableBody = decisionsMatch[1];
677
+ const rows = tableBody.trim().split('\n').filter(r => r.includes('|'));
678
+ for (const row of rows) {
679
+ const cells = row.split('|').map(c => c.trim()).filter(Boolean);
680
+ if (cells.length >= 3) {
681
+ decisions.push({
682
+ phase: cells[0],
683
+ summary: cells[1],
684
+ rationale: cells[2],
685
+ });
686
+ }
687
+ }
688
+ }
689
+
690
+ // Extract blockers list
691
+ const blockers = [];
692
+ const blockersMatch = body.match(/##\s*Blockers\s*\n([\s\S]*?)(?=\n##|$)/i);
693
+ if (blockersMatch) {
694
+ const blockersSection = blockersMatch[1];
695
+ const items = blockersSection.match(/^-\s+(.+)$/gm) || [];
696
+ for (const item of items) {
697
+ blockers.push(item.replace(/^-\s+/, '').trim());
698
+ }
699
+ }
700
+
701
+ // Extract session info
702
+ const session = {
703
+ last_date: null,
704
+ stopped_at: null,
705
+ resume_file: null,
706
+ };
707
+
708
+ const sessionMatch = body.match(/##\s*Session\s*\n([\s\S]*?)(?=\n##|$)/i);
709
+ if (sessionMatch) {
710
+ const sessionSection = sessionMatch[1];
711
+ const lastDateMatch = sessionSection.match(/\*\*Last Date:\*\*\s*(.+)/i)
712
+ || sessionSection.match(/^Last Date:\s*(.+)/im);
713
+ const stoppedAtMatch = sessionSection.match(/\*\*Stopped At:\*\*\s*(.+)/i)
714
+ || sessionSection.match(/^Stopped At:\s*(.+)/im);
715
+ const resumeFileMatch = sessionSection.match(/\*\*Resume File:\*\*\s*(.+)/i)
716
+ || sessionSection.match(/^Resume File:\s*(.+)/im);
717
+
718
+ if (lastDateMatch) session.last_date = lastDateMatch[1].trim();
719
+ if (stoppedAtMatch) session.stopped_at = stoppedAtMatch[1].trim();
720
+ if (resumeFileMatch) session.resume_file = resumeFileMatch[1].trim();
721
+ }
722
+
723
+ const result = {
724
+ current_phase: currentPhase,
725
+ current_phase_name: currentPhaseName,
726
+ total_phases: totalPhases,
727
+ current_plan: currentPlan,
728
+ total_plans_in_phase: totalPlansInPhase,
729
+ status,
730
+ progress_percent: progressPercent,
731
+ last_activity: lastActivity,
732
+ last_activity_desc: lastActivityDesc,
733
+ decisions,
734
+ blockers,
735
+ paused_at: pausedAt,
736
+ session,
737
+ };
738
+
739
+ output(result, raw);
740
+ }
741
+
742
+ // ─── State Frontmatter Sync ──────────────────────────────────────────────────
743
+
744
+ /**
745
+ * Extract machine-readable fields from STATE.md markdown body and build
746
+ * a YAML frontmatter object. Allows hooks and scripts to read state
747
+ * reliably via `state json` instead of fragile regex parsing.
748
+ */
749
+ function buildStateFrontmatter(bodyContent, cwd) {
750
+ const currentPhase = stateExtractField(bodyContent, 'Current Phase');
751
+ const currentPhaseName = stateExtractField(bodyContent, 'Current Phase Name');
752
+ const currentPlan = stateExtractField(bodyContent, 'Current Plan');
753
+ const totalPhasesRaw = stateExtractField(bodyContent, 'Total Phases');
754
+ const totalPlansRaw = stateExtractField(bodyContent, 'Total Plans in Phase');
755
+ const status = stateExtractField(bodyContent, 'Status');
756
+ const progressRaw = stateExtractField(bodyContent, 'Progress');
757
+ const lastActivity = stateExtractField(bodyContent, 'Last Activity');
758
+ // Bug #2444: scope Stopped At extraction to the ## Session section so that
759
+ // historical "Stopped at:" prose elsewhere in the body (e.g. in a
760
+ // Session Continuity Archive section) never overwrites the current value.
761
+ // Fall back to full-body search only when no ## Session section exists.
762
+ const sessionSectionMatch = bodyContent.match(/##\s*Session\s*\n([\s\S]*?)(?=\n##|$)/i);
763
+ const sessionBodyScope = sessionSectionMatch ? sessionSectionMatch[1] : bodyContent;
764
+ const stoppedAt = stateExtractField(sessionBodyScope, 'Stopped At') || stateExtractField(sessionBodyScope, 'Stopped at');
765
+ const pausedAt = stateExtractField(bodyContent, 'Paused At');
766
+
767
+ let milestone = null;
768
+ let milestoneName = null;
769
+ if (cwd) {
770
+ try {
771
+ const info = getMilestoneInfo(cwd);
772
+ milestone = info.version;
773
+ milestoneName = info.name;
774
+ } catch { /* intentionally empty */ }
775
+ }
776
+
777
+ let totalPhases = totalPhasesRaw ? parseInt(totalPhasesRaw, 10) : null;
778
+ let completedPhases = null;
779
+ let totalPlans = totalPlansRaw ? parseInt(totalPlansRaw, 10) : null;
780
+ let completedPlans = null;
781
+
782
+ if (cwd) {
783
+ try {
784
+ const phasesDir = planningPaths(cwd).phases;
785
+ if (fs.existsSync(phasesDir)) {
786
+ // Use cached disk scan when available — avoids N+1 readdirSync calls
787
+ // on repeated buildStateFrontmatter invocations within the same process (#1967)
788
+ let cached = _diskScanCache.get(cwd);
789
+ if (!cached) {
790
+ const isDirInMilestone = getMilestonePhaseFilter(cwd);
791
+ const allMatchingDirs = fs.readdirSync(phasesDir, { withFileTypes: true })
792
+ .filter(e => e.isDirectory()).map(e => e.name)
793
+ .filter(isDirInMilestone);
794
+
795
+ // Bug #2445: when stale phase dirs from a prior milestone remain in
796
+ // .planning/phases/ alongside new dirs with the same phase number,
797
+ // de-duplicate by normalized phase number keeping the most recently
798
+ // modified dir. This prevents double-counting (e.g. two "Phase 1" dirs).
799
+ const seenPhaseNums = new Map(); // normalizedNum -> dirName
800
+ for (const dir of allMatchingDirs) {
801
+ const m = dir.match(/^0*(\d+[A-Za-z]?(?:\.\d+)*)/);
802
+ const key = m ? m[1].toLowerCase() : dir;
803
+ if (!seenPhaseNums.has(key)) {
804
+ seenPhaseNums.set(key, dir);
805
+ } else {
806
+ // Keep the dir that is newer on disk (more likely current milestone)
807
+ try {
808
+ const existing = path.join(phasesDir, seenPhaseNums.get(key));
809
+ const candidate = path.join(phasesDir, dir);
810
+ if (fs.statSync(candidate).mtimeMs > fs.statSync(existing).mtimeMs) {
811
+ seenPhaseNums.set(key, dir);
812
+ }
813
+ } catch { /* keep existing on stat error */ }
814
+ }
815
+ }
816
+ const phaseDirs = [...seenPhaseNums.values()];
817
+
818
+ let diskTotalPlans = 0;
819
+ let diskTotalSummaries = 0;
820
+ let diskCompletedPhases = 0;
821
+
822
+ for (const dir of phaseDirs) {
823
+ const phaseDir = path.join(phasesDir, dir);
824
+ const { planCount, summaryCount, completed } = scanPhasePlans(phaseDir);
825
+ diskTotalPlans += planCount;
826
+ diskTotalSummaries += summaryCount;
827
+ if (completed) diskCompletedPhases++;
828
+ }
829
+ cached = {
830
+ totalPhases: isDirInMilestone.phaseCount > 0
831
+ ? Math.max(phaseDirs.length, isDirInMilestone.phaseCount)
832
+ : phaseDirs.length,
833
+ completedPhases: diskCompletedPhases,
834
+ totalPlans: diskTotalPlans,
835
+ completedPlans: diskTotalSummaries,
836
+ };
837
+ _diskScanCache.set(cwd, cached);
838
+ }
839
+ totalPhases = cached.totalPhases;
840
+ completedPhases = cached.completedPhases;
841
+ totalPlans = cached.totalPlans;
842
+ completedPlans = cached.completedPlans;
843
+ }
844
+ } catch { /* intentionally empty */ }
845
+ }
846
+
847
+ // Derive percent from disk counts when available (ground truth).
848
+ // Uses min(plan_fraction, phase_fraction) via computeProgressPercent so that
849
+ // ROADMAP-declared-but-unrealized future phases cap the reported completion
850
+ // instead of a false 100% from plan-only coverage (#3242 Bug B).
851
+ // Falls back to the body Progress: field only when no plan files exist on disk.
852
+ let progressPercent = computeProgressPercent(completedPlans, totalPlans, completedPhases, totalPhases);
853
+ if (progressPercent === null && progressRaw) {
854
+ const pctMatch = progressRaw.match(/(\d+)%/);
855
+ if (pctMatch) progressPercent = parseInt(pctMatch[1], 10);
856
+ }
857
+
858
+ const normalizedStatus = normalizeStateStatus(status, pausedAt);
859
+
860
+ const fm = { gsd_state_version: '1.0' };
861
+
862
+ if (milestone) fm.milestone = milestone;
863
+ if (milestoneName) fm.milestone_name = milestoneName;
864
+ if (currentPhase) fm.current_phase = currentPhase;
865
+ if (currentPhaseName) fm.current_phase_name = currentPhaseName;
866
+ if (currentPlan) fm.current_plan = currentPlan;
867
+ fm.status = normalizedStatus;
868
+ if (stoppedAt) fm.stopped_at = stoppedAt;
869
+ if (pausedAt) fm.paused_at = pausedAt;
870
+ fm.last_updated = new Date().toISOString();
871
+ if (lastActivity) fm.last_activity = lastActivity;
872
+
873
+ const progress = {};
874
+ if (totalPhases !== null) progress.total_phases = totalPhases;
875
+ if (completedPhases !== null) progress.completed_phases = completedPhases;
876
+ if (totalPlans !== null) progress.total_plans = totalPlans;
877
+ if (completedPlans !== null) progress.completed_plans = completedPlans;
878
+ if (progressPercent !== null) progress.percent = progressPercent;
879
+ if (Object.keys(progress).length > 0) fm.progress = progress;
880
+
881
+ return fm;
882
+ }
883
+
884
+ function stripFrontmatter(content) {
885
+ // Strip ALL frontmatter blocks at the start of the file.
886
+ // Handles CRLF line endings and multiple stacked blocks (corruption recovery).
887
+ // Greedy: keeps stripping ---...--- blocks separated by optional whitespace.
888
+ let result = content;
889
+ // eslint-disable-next-line no-constant-condition
890
+ while (true) {
891
+ const stripped = result.replace(/^\s*---\r?\n[\s\S]*?\r?\n---\s*/, '');
892
+ if (stripped === result) break;
893
+ result = stripped;
894
+ }
895
+ return result;
896
+ }
897
+
898
+ function syncStateFrontmatter(content, cwd) {
899
+ // Read existing frontmatter BEFORE stripping — it may contain values
900
+ // that the body no longer has (e.g., Status field removed by an agent).
901
+ const existingFm = extractFrontmatter(content);
902
+ const body = stripFrontmatter(content);
903
+ const derivedFm = buildStateFrontmatter(body, cwd);
904
+
905
+ // Preserve existing frontmatter status when body-derived status is 'unknown'.
906
+ // This prevents a missing Status: field in the body from overwriting a
907
+ // previously valid status (e.g., 'executing' → 'unknown').
908
+ if (derivedFm.status === 'unknown' && existingFm.status && existingFm.status !== 'unknown') {
909
+ derivedFm.status = existingFm.status;
910
+ }
911
+
912
+ const yamlStr = reconstructFrontmatter(derivedFm);
913
+ return `---\n${yamlStr}\n---\n\n${body}`;
914
+ }
915
+
916
+ // Transient errno codes that indicate a temporary filesystem condition under
917
+ // concurrent O_EXCL races — Docker overlay-fs (ENOENT/EINVAL/EIO), NFS
918
+ // (ESTALE), and OS-level interrupt/retry signals (EAGAIN/EINTR). These are
919
+ // recoverable; acquireStateLock retries instead of propagating them.
920
+ // Truly fatal codes (EMFILE, ENOSPC, EROFS, EACCES) are NOT in this set and
921
+ // will still throw immediately.
922
+ const ACQUIRE_LOCK_RETRY_ERRNOS = new Set([
923
+ 'EPERM', // Windows / macOS AV scanner holds the file open during delete
924
+ 'EBUSY', // Windows: file in use by another process
925
+ 'EAGAIN', // POSIX: resource temporarily unavailable
926
+ 'EINTR', // POSIX: syscall interrupted by signal
927
+ 'EINVAL', // Docker overlay-fs: transient during concurrent O_EXCL creation
928
+ 'EIO', // Docker overlay-fs / NFS: transient I/O error
929
+ 'ENOENT', // Docker overlay-fs: parent dir transiently missing during race
930
+ 'ESTALE', // NFS: stale file handle (self-resolves on retry)
931
+ ]);
932
+
933
+ /**
934
+ * Acquire a lockfile for STATE.md operations.
935
+ * Returns the lock path for later release.
936
+ */
937
+ function acquireStateLock(statePath) {
938
+ const lockPath = statePath + '.lock';
939
+ const retryDelay = 200; // ms
940
+ const staleThresholdMs = 10000;
941
+ const maxWaitMs = 30000;
942
+ const startedAt = Date.now();
943
+
944
+ // eslint-disable-next-line no-constant-condition
945
+ while (true) {
946
+ try {
947
+ const fd = fs.openSync(lockPath, fs.constants.O_CREAT | fs.constants.O_EXCL | fs.constants.O_WRONLY);
948
+ fs.writeSync(fd, String(process.pid));
949
+ fs.closeSync(fd);
950
+ // Exit-time cleanup keeps a crashed locked region from leaving a stale file (#1916).
951
+ _heldStateLocks.add(lockPath);
952
+ return lockPath;
953
+ } catch (err) {
954
+ // Transient filesystem errors (Docker overlay-fs, NFS, OS signals, AV scanners)
955
+ // are recoverable — retry the acquisition loop rather than propagating.
956
+ // See ACQUIRE_LOCK_RETRY_ERRNOS for the full list and rationale.
957
+ if (ACQUIRE_LOCK_RETRY_ERRNOS.has(err.code)) { continue; }
958
+ if (err.code !== 'EEXIST') throw err; // propagate — silent bypass causes lost updates
959
+ // Only unlink a lock we did not place when it has crossed the staleness
960
+ // threshold (crashed holder). Nuking a fresh lock held by a slow-but-live
961
+ // writer causes lost updates (#3711 regression).
962
+ try {
963
+ const stat = fs.statSync(lockPath);
964
+ if (Date.now() - stat.mtimeMs > staleThresholdMs) {
965
+ try { fs.unlinkSync(lockPath); } catch { /* already gone */ }
966
+ continue;
967
+ }
968
+ } catch { continue; /* released between EEXIST and stat */ }
969
+ if (Date.now() - startedAt >= maxWaitMs) {
970
+ throw new Error(
971
+ 'acquireStateLock: ' + lockPath + ' held by live process for ' +
972
+ (Date.now() - startedAt) + 'ms (exceeded ' + maxWaitMs + 'ms budget)'
973
+ );
974
+ }
975
+ const jitter = Math.floor(Math.random() * 50);
976
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, retryDelay + jitter);
977
+ }
978
+ }
979
+ }
980
+
981
+ function releaseStateLock(lockPath) {
982
+ _heldStateLocks.delete(lockPath);
983
+ try { fs.unlinkSync(lockPath); } catch { /* lock already gone */ }
984
+ }
985
+
986
+ /**
987
+ * Write STATE.md with synchronized YAML frontmatter.
988
+ * All STATE.md writes should use this instead of raw writeFileSync.
989
+ * Uses a simple lockfile to prevent parallel agents from overwriting
990
+ * each other's changes (race condition with read-modify-write cycle).
991
+ */
992
+ function writeStateMd(statePath, content, cwd) {
993
+ // Invalidate disk scan cache before computing new frontmatter — the write
994
+ // may create new PLAN/SUMMARY files that buildStateFrontmatter must see.
995
+ // Safe for any calling pattern, not just short-lived CLI processes (#1967).
996
+ if (cwd) _diskScanCache.delete(cwd);
997
+ const synced = syncStateFrontmatter(content, cwd);
998
+ const lockPath = acquireStateLock(statePath);
999
+ try {
1000
+ platformWriteSync(statePath, synced);
1001
+ } finally {
1002
+ releaseStateLock(lockPath);
1003
+ }
1004
+ }
1005
+
1006
+ /**
1007
+ * Atomic read-modify-write for STATE.md.
1008
+ * Holds the lock across the entire read -> transform -> write cycle,
1009
+ * preventing the lost-update problem where two agents read the same
1010
+ * content and the second write clobbers the first.
1011
+ *
1012
+ * @param {string} statePath
1013
+ * @param {function} transformFn - (content: string) => string
1014
+ * @param {string} cwd
1015
+ * @param {{ resync?: boolean }} [options]
1016
+ * resync: when true (default) rebuilds the entire frontmatter from disk after
1017
+ * the transform. Pass { resync: false } for body-only updates (e.g. state.update
1018
+ * on a single field) that must not trample manually-curated cross-milestone
1019
+ * progress.* counters in the frontmatter (#3242 Bug A).
1020
+ * When resync is false, syncStateFrontmatter still runs to maintain/create the
1021
+ * frontmatter block, but any existing progress.* sub-keys are preserved from
1022
+ * the pre-transform file rather than being rebuilt from disk.
1023
+ */
1024
+ function readModifyWriteStateMd(statePath, transformFn, cwd, options) {
1025
+ const resync = !options || options.resync !== false;
1026
+ const lockPath = acquireStateLock(statePath);
1027
+ try {
1028
+ const content = platformReadSync(statePath) || '';
1029
+ // Snapshot the existing progress block BEFORE the transform so we can
1030
+ // restore it when resync is false.
1031
+ const preFm = resync ? null : extractFrontmatter(content);
1032
+ const modified = transformFn(content);
1033
+ let synced = syncStateFrontmatter(modified, cwd);
1034
+
1035
+ if (!resync && preFm && preFm.progress) {
1036
+ // Re-apply the curated progress block that syncStateFrontmatter just
1037
+ // overwrote with disk-derived values. Only restore keys that were present
1038
+ // in the snapshot — this preserves any new non-progress frontmatter fields
1039
+ // (e.g., status, current_phase) that syncStateFrontmatter legitimately
1040
+ // derived from the updated body.
1041
+ const postFm = extractFrontmatter(synced);
1042
+ postFm.progress = preFm.progress;
1043
+ const yamlStr = reconstructFrontmatter(postFm);
1044
+ const body = stripFrontmatter(synced);
1045
+ synced = `---\n${yamlStr}\n---\n\n${body}`;
1046
+ }
1047
+
1048
+ platformWriteSync(statePath, synced);
1049
+ } finally {
1050
+ releaseStateLock(lockPath);
1051
+ }
1052
+ }
1053
+
1054
+ function cmdStateJson(cwd, raw) {
1055
+ const statePath = planningPaths(cwd).state;
1056
+ if (!fs.existsSync(statePath)) {
1057
+ output({ error: 'STATE.md not found' }, raw, 'STATE.md not found');
1058
+ return;
1059
+ }
1060
+
1061
+ const content = fs.readFileSync(statePath, 'utf-8');
1062
+ const existingFm = extractFrontmatter(content);
1063
+ const body = stripFrontmatter(content);
1064
+
1065
+ // Always rebuild from body + disk so progress counters reflect current state.
1066
+ // Returning cached frontmatter directly causes stale percent/completed_plans
1067
+ // when SUMMARY files were added after the last STATE.md write (#1589).
1068
+ const built = buildStateFrontmatter(body, cwd);
1069
+
1070
+ // Preserve frontmatter-only fields that cannot be recovered from the body.
1071
+ if (existingFm && existingFm.stopped_at && !built.stopped_at) {
1072
+ built.stopped_at = existingFm.stopped_at;
1073
+ }
1074
+ if (existingFm && existingFm.paused_at && !built.paused_at) {
1075
+ built.paused_at = existingFm.paused_at;
1076
+ }
1077
+ // Preserve existing status when body-derived status is 'unknown' (same logic as syncStateFrontmatter).
1078
+ if (built.status === 'unknown' && existingFm && existingFm.status && existingFm.status !== 'unknown') {
1079
+ built.status = existingFm.status;
1080
+ }
1081
+ // Preserve curated cross-milestone aggregates when local disk scanning sees
1082
+ // only a narrower realized subset (#3242 Bug A). Stale lower counters still
1083
+ // rebuild from disk because they do not exceed the derived scan.
1084
+ if (existingFm && shouldPreserveExistingProgress(existingFm.progress, built.progress)) {
1085
+ built.progress = normalizeProgressNumbers(existingFm.progress);
1086
+ }
1087
+
1088
+ output(built, raw, JSON.stringify(built, null, 2));
1089
+ }
1090
+
1091
+ /**
1092
+ * Update STATE.md when a new phase begins execution.
1093
+ * Updates body text fields (Current focus, Status, Last Activity, Current Position)
1094
+ * and synchronizes frontmatter via writeStateMd.
1095
+ * Fixes: #1102 (plan counts), #1103 (status/last_activity), #1104 (body text).
1096
+ */
1097
+ function cmdStateBeginPhase(cwd, phaseNumber, phaseName, planCount, raw) {
1098
+ const statePath = planningPaths(cwd).state;
1099
+ if (!fs.existsSync(statePath)) {
1100
+ output({ error: 'STATE.md not found' }, raw);
1101
+ return;
1102
+ }
1103
+
1104
+ const today = new Date().toISOString().split('T')[0];
1105
+ const updated = [];
1106
+
1107
+ readModifyWriteStateMd(statePath, (content) => {
1108
+ // Idempotency guard (#3127): if the phase is already mid-flight, do NOT
1109
+ // overwrite execution-progress fields (Current Plan, plan body line,
1110
+ // Last Activity Description). Only update fields that are safe to
1111
+ // refresh on resume (Last Activity date, Status if inconsistent).
1112
+ // A phase is considered mid-flight when Status contains 'Executing Phase N'
1113
+ // for the current phase number.
1114
+ const currentStatus = stateExtractField(content, 'Status') || '';
1115
+ const isAlreadyExecuting = new RegExp(`Executing Phase\\s+${escapeRegex(String(phaseNumber))}\\b`, 'i').test(currentStatus);
1116
+
1117
+ // Update Status field
1118
+ const statusValue = `Executing Phase ${phaseNumber}`;
1119
+ let result = stateReplaceField(content, 'Status', statusValue);
1120
+ if (result) { content = result; updated.push('Status'); }
1121
+
1122
+ // Update Last Activity (safe to update on resume — tracks when execute-phase ran)
1123
+ result = stateReplaceField(content, 'Last Activity', today);
1124
+ if (result) { content = result; updated.push('Last Activity'); }
1125
+
1126
+ if (!isAlreadyExecuting) {
1127
+ // First-time execution: set all progress fields
1128
+
1129
+ // Update Last Activity Description
1130
+ const activityDesc = `Phase ${phaseNumber} execution started`;
1131
+ result = stateReplaceField(content, 'Last Activity Description', activityDesc);
1132
+ if (result) { content = result; updated.push('Last Activity Description'); }
1133
+
1134
+ // Update Current Phase
1135
+ result = stateReplaceField(content, 'Current Phase', String(phaseNumber));
1136
+ if (result) { content = result; updated.push('Current Phase'); }
1137
+
1138
+ // Update Current Phase Name
1139
+ if (phaseName) {
1140
+ result = stateReplaceField(content, 'Current Phase Name', phaseName);
1141
+ if (result) { content = result; updated.push('Current Phase Name'); }
1142
+ }
1143
+
1144
+ // Update Current Plan to 1 (starting from the first plan)
1145
+ result = stateReplaceField(content, 'Current Plan', '1');
1146
+ if (result) { content = result; updated.push('Current Plan'); }
1147
+
1148
+ // Update Total Plans in Phase
1149
+ if (planCount) {
1150
+ result = stateReplaceField(content, 'Total Plans in Phase', String(planCount));
1151
+ if (result) { content = result; updated.push('Total Plans in Phase'); }
1152
+ }
1153
+
1154
+ // Update **Current focus:** body text line (#1104)
1155
+ const focusLabel = phaseName ? `Phase ${phaseNumber} — ${phaseName}` : `Phase ${phaseNumber}`;
1156
+ const focusPattern = /(\*\*Current focus:\*\*\s*).*/i;
1157
+ if (focusPattern.test(content)) {
1158
+ content = content.replace(focusPattern, (_match, prefix) => `${prefix}${focusLabel}`);
1159
+ updated.push('Current focus');
1160
+ }
1161
+
1162
+ // Update ## Current Position section (#1104, #1365)
1163
+ const positionPattern = /(##\s*Current Position\s*\n)([\s\S]*?)(?=\n##|$)/i;
1164
+ const positionMatch = content.match(positionPattern);
1165
+ if (positionMatch) {
1166
+ const header = positionMatch[1];
1167
+ let posBody = positionMatch[2];
1168
+
1169
+ // Update or insert Phase line
1170
+ const newPhase = `Phase: ${phaseNumber}${phaseName ? ` (${phaseName})` : ''} — EXECUTING`;
1171
+ if (/^Phase:/m.test(posBody)) {
1172
+ posBody = posBody.replace(/^Phase:.*$/m, newPhase);
1173
+ } else {
1174
+ posBody = newPhase + '\n' + posBody;
1175
+ }
1176
+
1177
+ // Update or insert Plan line
1178
+ const newPlan = `Plan: 1 of ${planCount || '?'}`;
1179
+ if (/^Plan:/m.test(posBody)) {
1180
+ posBody = posBody.replace(/^Plan:.*$/m, newPlan);
1181
+ } else {
1182
+ posBody = posBody.replace(/^(Phase:.*$)/m, `$1\n${newPlan}`);
1183
+ }
1184
+
1185
+ // Update Status line if present
1186
+ const newStatus = `Status: Executing Phase ${phaseNumber}`;
1187
+ if (/^Status:/m.test(posBody)) {
1188
+ posBody = posBody.replace(/^Status:.*$/m, newStatus);
1189
+ }
1190
+
1191
+ // Update Last activity line if present
1192
+ const newActivity = `Last activity: ${today} -- Phase ${phaseNumber} execution started`;
1193
+ if (/^Last activity:/im.test(posBody)) {
1194
+ posBody = posBody.replace(/^Last activity:.*$/im, newActivity);
1195
+ }
1196
+
1197
+ content = content.replace(positionPattern, () => `${header}${posBody}`);
1198
+ updated.push('Current Position');
1199
+ }
1200
+ } else {
1201
+ // Resume path: only update Last activity timestamp in Current Position
1202
+ // (do not touch Plan:, stopped_at, progress.percent, or plan counter)
1203
+ const positionPattern = /(##\s*Current Position\s*\n)([\s\S]*?)(?=\n##|$)/i;
1204
+ const positionMatch = content.match(positionPattern);
1205
+ if (positionMatch) {
1206
+ const header = positionMatch[1];
1207
+ let posBody = positionMatch[2];
1208
+ const resumeActivity = `Last activity: ${today} -- Phase ${phaseNumber} execution resumed (wave continue)`;
1209
+ if (/^Last activity:/im.test(posBody)) {
1210
+ posBody = posBody.replace(/^Last activity:.*$/im, resumeActivity);
1211
+ content = content.replace(positionPattern, () => `${header}${posBody}`);
1212
+ updated.push('Last activity (resume)');
1213
+ }
1214
+ }
1215
+ }
1216
+
1217
+ return content;
1218
+ }, cwd);
1219
+
1220
+ output({ updated, phase: phaseNumber, phase_name: phaseName || null, plan_count: planCount || null }, raw, updated.length > 0 ? 'true' : 'false');
1221
+ }
1222
+
1223
+ /**
1224
+ * Write a WAITING.json signal file when GSD hits a decision point.
1225
+ * External watchers (fswatch, polling, orchestrators) can detect this.
1226
+ * File is written to .planning/WAITING.json (or .gsd/WAITING.json if .gsd exists).
1227
+ * Fixes #1034.
1228
+ */
1229
+ function cmdSignalWaiting(cwd, type, question, options, phase, raw) {
1230
+ const gsdDir = fs.existsSync(path.join(cwd, '.gsd')) ? path.join(cwd, '.gsd') : planningDir(cwd);
1231
+ const waitingPath = path.join(gsdDir, 'WAITING.json');
1232
+
1233
+ const signal = {
1234
+ status: 'waiting',
1235
+ type: type || 'decision_point',
1236
+ question: question || null,
1237
+ options: options ? options.split('|').map(o => o.trim()) : [],
1238
+ since: new Date().toISOString(),
1239
+ phase: phase || null,
1240
+ };
1241
+
1242
+ try {
1243
+ platformEnsureDir(gsdDir);
1244
+ platformWriteSync(waitingPath, JSON.stringify(signal, null, 2));
1245
+ output({ signaled: true, path: waitingPath }, raw, 'true');
1246
+ } catch (e) {
1247
+ output({ signaled: false, error: e.message }, raw, 'false');
1248
+ }
1249
+ }
1250
+
1251
+ /**
1252
+ * Remove the WAITING.json signal file when user answers and agent resumes.
1253
+ */
1254
+ function cmdSignalResume(cwd, raw) {
1255
+ const paths = [
1256
+ path.join(cwd, '.gsd', 'WAITING.json'),
1257
+ path.join(planningDir(cwd), 'WAITING.json'),
1258
+ ];
1259
+
1260
+ let removed = false;
1261
+ for (const p of paths) {
1262
+ if (fs.existsSync(p)) {
1263
+ try { fs.unlinkSync(p); removed = true; } catch {}
1264
+ }
1265
+ }
1266
+
1267
+ output({ resumed: true, removed }, raw, removed ? 'true' : 'false');
1268
+ }
1269
+
1270
+ // ─── Gate Functions (STATE.md consistency enforcement) ────────────────────────
1271
+
1272
+ /**
1273
+ * Update the ## Performance Metrics section in STATE.md content.
1274
+ * Increments Velocity totals and upserts a By Phase table row.
1275
+ * Returns modified content string.
1276
+ */
1277
+ function updatePerformanceMetricsSection(content, cwd, phaseNum, planCount, summaryCount) {
1278
+ // Update Velocity: Total plans completed
1279
+ const totalMatch = content.match(/Total plans completed:\s*(\d+|\[N\])/);
1280
+ const prevTotal = totalMatch && totalMatch[1] !== '[N]' ? parseInt(totalMatch[1], 10) : 0;
1281
+ const newTotal = prevTotal + summaryCount;
1282
+ content = content.replace(
1283
+ /Total plans completed:\s*(\d+|\[N\])/,
1284
+ `Total plans completed: ${newTotal}`
1285
+ );
1286
+
1287
+ // Update By Phase table — upsert row for this phase
1288
+ const byPhaseTablePattern = /(\|\s*Phase\s*\|\s*Plans\s*\|\s*Total\s*\|\s*Avg\/Plan\s*\|[ \t]*\n\|(?:[- :\t]+\|)+[ \t]*\n)((?:[ \t]*\|[^\n]*\n)*)(?=\n|$)/i;
1289
+ const byPhaseMatch = content.match(byPhaseTablePattern);
1290
+ if (byPhaseMatch) {
1291
+ let tableBody = byPhaseMatch[2].trim();
1292
+ const phaseRowPattern = new RegExp(`^\\|\\s*${escapeRegex(String(phaseNum))}\\s*\\|.*$`, 'm');
1293
+ const newRow = `| ${phaseNum} | ${summaryCount} | - | - |`;
1294
+
1295
+ if (phaseRowPattern.test(tableBody)) {
1296
+ // Update existing row
1297
+ tableBody = tableBody.replace(phaseRowPattern, newRow);
1298
+ } else {
1299
+ // Remove placeholder row and add new row
1300
+ tableBody = tableBody.replace(/^\|\s*-\s*\|\s*-\s*\|\s*-\s*\|\s*-\s*\|$/m, '').trim();
1301
+ tableBody = tableBody ? tableBody + '\n' + newRow : newRow;
1302
+ }
1303
+
1304
+ content = content.replace(byPhaseTablePattern, (_match, tableHeader) => `${tableHeader}${tableBody}\n`);
1305
+ }
1306
+
1307
+ return content;
1308
+ }
1309
+
1310
+ /**
1311
+ * Gate 3a: Record state after plan-phase completes.
1312
+ * Updates Status to "Ready to execute", Total Plans, Last Activity.
1313
+ */
1314
+ function cmdStatePlannedPhase(cwd, phaseNumber, planCount, raw) {
1315
+ const statePath = planningPaths(cwd).state;
1316
+ if (!fs.existsSync(statePath)) {
1317
+ output({ error: 'STATE.md not found' }, raw);
1318
+ return;
1319
+ }
1320
+
1321
+ let content = fs.readFileSync(statePath, 'utf-8');
1322
+ const today = new Date().toISOString().split('T')[0];
1323
+ const updated = [];
1324
+
1325
+ // Update Status
1326
+ let result = stateReplaceField(content, 'Status', 'Ready to execute');
1327
+ if (result) { content = result; updated.push('Status'); }
1328
+
1329
+ // Update Total Plans in Phase
1330
+ if (planCount !== null && planCount !== undefined) {
1331
+ result = stateReplaceField(content, 'Total Plans in Phase', String(planCount));
1332
+ if (result) { content = result; updated.push('Total Plans in Phase'); }
1333
+ }
1334
+
1335
+ // Update Last Activity
1336
+ result = stateReplaceField(content, 'Last Activity', today);
1337
+ if (result) { content = result; updated.push('Last Activity'); }
1338
+
1339
+ // Update Last Activity Description
1340
+ result = stateReplaceField(content, 'Last Activity Description', `Phase ${phaseNumber} planning complete — ${planCount || '?'} plans ready`);
1341
+ if (result) { content = result; updated.push('Last Activity Description'); }
1342
+
1343
+ // Update Current Position section
1344
+ content = updateCurrentPositionFields(content, {
1345
+ status: 'Ready to execute',
1346
+ lastActivity: `${today} -- Phase ${phaseNumber} planning complete`,
1347
+ });
1348
+
1349
+ if (updated.length > 0) {
1350
+ writeStateMd(statePath, content, cwd);
1351
+ }
1352
+
1353
+ output({ updated, phase: phaseNumber, plan_count: planCount }, raw, updated.length > 0 ? 'true' : 'false');
1354
+ }
1355
+
1356
+ /**
1357
+ * Bug #2630: reset STATE.md for a new milestone cycle.
1358
+ * Stomps frontmatter milestone/milestone_name/status/progress AND rewrites
1359
+ * the Current Position body. Preserves Accumulated Context.
1360
+ * Symmetric with the SDK `stateMilestoneSwitch` handler.
1361
+ */
1362
+ function cmdStateMilestoneSwitch(cwd, version, name, raw) {
1363
+ if (!version || !String(version).trim()) {
1364
+ output({ error: 'milestone required (--milestone <vX.Y>)' }, raw);
1365
+ return;
1366
+ }
1367
+ const resolvedName = (name && String(name).trim()) || 'milestone';
1368
+ const statePath = planningPaths(cwd).state;
1369
+ const today = new Date().toISOString().split('T')[0];
1370
+
1371
+ const lockPath = acquireStateLock(statePath);
1372
+ try {
1373
+ const content = platformReadSync(statePath) || '';
1374
+ const existingFm = extractFrontmatter(content);
1375
+ const body = stripFrontmatter(content);
1376
+
1377
+ const positionPattern = /(##\s*Current Position\s*\n)([\s\S]*?)(?=\n##|$)/i;
1378
+ const resetPositionBody =
1379
+ `\nPhase: Not started (defining requirements)\n` +
1380
+ `Plan: —\n` +
1381
+ `Status: Defining requirements\n` +
1382
+ `Last activity: ${today} — Milestone ${version} started\n\n`;
1383
+ let newBody;
1384
+ if (positionPattern.test(body)) {
1385
+ newBody = body.replace(positionPattern, (_m, header) => `${header}${resetPositionBody}`);
1386
+ } else {
1387
+ const preface = body.trim().length > 0 ? body : '# Project State\n';
1388
+ newBody = `${preface.trimEnd()}\n\n## Current Position\n${resetPositionBody}`;
1389
+ }
1390
+
1391
+ const fm = {
1392
+ gsd_state_version: existingFm.gsd_state_version || '1.0',
1393
+ milestone: version,
1394
+ milestone_name: resolvedName,
1395
+ status: 'planning',
1396
+ last_updated: new Date().toISOString(),
1397
+ last_activity: today,
1398
+ progress: {
1399
+ total_phases: 0,
1400
+ completed_phases: 0,
1401
+ total_plans: 0,
1402
+ completed_plans: 0,
1403
+ percent: 0,
1404
+ },
1405
+ };
1406
+
1407
+ const yamlStr = reconstructFrontmatter(fm);
1408
+ const assembled = `---\n${yamlStr}\n---\n\n${newBody.replace(/^\n+/, '')}`;
1409
+ platformWriteSync(statePath, assembled);
1410
+ output(
1411
+ { switched: true, version, name: resolvedName, status: 'planning' },
1412
+ raw,
1413
+ 'true',
1414
+ );
1415
+ } finally {
1416
+ releaseStateLock(lockPath);
1417
+ }
1418
+ }
1419
+
1420
+ /**
1421
+ * Gate 1: Validate STATE.md against filesystem.
1422
+ * Returns { valid, warnings, drift } JSON.
1423
+ */
1424
+ function cmdStateValidate(cwd, raw) {
1425
+ const statePath = planningPaths(cwd).state;
1426
+ if (!fs.existsSync(statePath)) {
1427
+ output({ error: 'STATE.md not found' }, raw);
1428
+ return;
1429
+ }
1430
+
1431
+ const content = fs.readFileSync(statePath, 'utf-8');
1432
+ const warnings = [];
1433
+ const drift = {};
1434
+
1435
+ const status = stateExtractField(content, 'Status') || '';
1436
+ const currentPhase = stateExtractField(content, 'Current Phase');
1437
+ const totalPlansRaw = stateExtractField(content, 'Total Plans in Phase');
1438
+ const totalPlansInPhase = totalPlansRaw ? parseInt(totalPlansRaw, 10) : null;
1439
+
1440
+ const phasesDir = planningPaths(cwd).phases;
1441
+
1442
+ // Scan disk for current phase
1443
+ if (currentPhase && fs.existsSync(phasesDir)) {
1444
+ const normalized = currentPhase.replace(/\s+of\s+\d+.*/, '').trim();
1445
+ try {
1446
+ const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
1447
+ const phaseDir = entries.find(e => e.isDirectory() && e.name.startsWith(normalized.replace(/^0+/, '').padStart(2, '0')));
1448
+ if (phaseDir) {
1449
+ const phaseDirPath = path.join(phasesDir, phaseDir.name);
1450
+ const { planCount: diskPlans, summaryCount: diskSummaries } = scanPhasePlans(phaseDirPath);
1451
+
1452
+ // Check plan count mismatch
1453
+ if (totalPlansInPhase !== null && diskPlans !== totalPlansInPhase) {
1454
+ warnings.push(`Plan count mismatch: STATE.md says ${totalPlansInPhase} plans, disk has ${diskPlans}`);
1455
+ drift.plan_count = { state: totalPlansInPhase, disk: diskPlans };
1456
+ }
1457
+
1458
+ // Check for VERIFICATION.md
1459
+ const files = fs.readdirSync(phaseDirPath);
1460
+ const verificationFiles = files.filter(f => f.includes('VERIFICATION') && f.endsWith('.md'));
1461
+ for (const vf of verificationFiles) {
1462
+ try {
1463
+ const vContent = fs.readFileSync(path.join(phaseDirPath, vf), 'utf-8');
1464
+ if (/status:\s*passed/i.test(vContent) && /executing/i.test(status)) {
1465
+ warnings.push(`Status drift: STATE.md says "${status}" but ${vf} shows verification passed — phase may be complete`);
1466
+ drift.verification_status = { state_status: status, verification: 'passed' };
1467
+ }
1468
+ } catch { /* intentionally empty */ }
1469
+ }
1470
+
1471
+ // Check if all plans have summaries but status still says executing
1472
+ if (diskPlans > 0 && diskSummaries >= diskPlans && /executing/i.test(status)) {
1473
+ // Only warn if no verification exists (if verification passed, the above warning covers it)
1474
+ if (verificationFiles.length === 0) {
1475
+ warnings.push(`All ${diskPlans} plans have summaries but status is still "${status}" — phase may be ready for verification`);
1476
+ }
1477
+ }
1478
+ }
1479
+ } catch { /* intentionally empty */ }
1480
+ }
1481
+
1482
+ const valid = warnings.length === 0;
1483
+ output({ valid, warnings, drift }, raw);
1484
+ }
1485
+
1486
+ /**
1487
+ * Gate 2: Sync STATE.md from filesystem ground truth.
1488
+ * Scans phase dirs, reconstructs counters, progress, metrics.
1489
+ * Supports --verify for dry-run mode.
1490
+ */
1491
+ function cmdStateSync(cwd, options, raw) {
1492
+ const statePath = planningPaths(cwd).state;
1493
+ if (!fs.existsSync(statePath)) {
1494
+ output({ error: 'STATE.md not found' }, raw);
1495
+ return;
1496
+ }
1497
+
1498
+ const verify = options && options.verify;
1499
+ const content = fs.readFileSync(statePath, 'utf-8');
1500
+ const changes = [];
1501
+ let modified = content;
1502
+ const today = new Date().toISOString().split('T')[0];
1503
+
1504
+ const phasesDir = planningPaths(cwd).phases;
1505
+ if (!fs.existsSync(phasesDir)) {
1506
+ output({ synced: true, changes: [], dry_run: !!verify }, raw);
1507
+ return;
1508
+ }
1509
+
1510
+ // Scan all phases
1511
+ let entries;
1512
+ try {
1513
+ entries = fs.readdirSync(phasesDir, { withFileTypes: true })
1514
+ .filter(e => e.isDirectory())
1515
+ .map(e => e.name)
1516
+ .sort();
1517
+ } catch {
1518
+ output({ synced: true, changes: [], dry_run: !!verify }, raw);
1519
+ return;
1520
+ }
1521
+
1522
+ let totalDiskPlans = 0;
1523
+ let totalDiskSummaries = 0;
1524
+ let diskCompletedPhases = 0;
1525
+ let highestIncompletePhase = null;
1526
+ let highestIncompletePhaseNum = null;
1527
+ let highestIncompletePhaseplanCount = 0;
1528
+ let highestIncompletePhaseSummaryCount = 0;
1529
+
1530
+ for (const dir of entries) {
1531
+ const dirPath = path.join(phasesDir, dir);
1532
+ const { planCount: plans, summaryCount: summaries, completed } = scanPhasePlans(dirPath);
1533
+ totalDiskPlans += plans;
1534
+ totalDiskSummaries += summaries;
1535
+ if (completed) diskCompletedPhases++;
1536
+
1537
+ // Track the highest phase with incomplete plans (or any plans)
1538
+ const phaseMatch = dir.match(/^(\d+[A-Z]?(?:\.\d+)*)/i);
1539
+ if (phaseMatch && plans > 0) {
1540
+ if (summaries < plans) {
1541
+ // Incomplete phase — this is likely the current one
1542
+ highestIncompletePhase = dir;
1543
+ highestIncompletePhaseNum = phaseMatch[1];
1544
+ highestIncompletePhaseplanCount = plans;
1545
+ highestIncompletePhaseSummaryCount = summaries;
1546
+ } else if (!highestIncompletePhase) {
1547
+ // All complete, track as potential current
1548
+ highestIncompletePhase = dir;
1549
+ highestIncompletePhaseNum = phaseMatch[1];
1550
+ highestIncompletePhaseplanCount = plans;
1551
+ highestIncompletePhaseSummaryCount = summaries;
1552
+ }
1553
+ }
1554
+ }
1555
+
1556
+ // Determine total phases from ROADMAP (may be larger than realized disk dirs).
1557
+ // Mirrors the logic in buildStateFrontmatter so both report consistent percents (#3242 Bug B).
1558
+ let syncTotalPhases = null;
1559
+ try {
1560
+ const isDirInMilestone = getMilestonePhaseFilter(cwd);
1561
+ if (isDirInMilestone.phaseCount > 0) {
1562
+ syncTotalPhases = Math.max(entries.length, isDirInMilestone.phaseCount);
1563
+ } else {
1564
+ syncTotalPhases = entries.length;
1565
+ }
1566
+ } catch { /* intentionally empty */ }
1567
+
1568
+ // Sync Total Plans in Phase
1569
+ if (highestIncompletePhase) {
1570
+ const currentPlansField = stateExtractField(modified, 'Total Plans in Phase');
1571
+ if (currentPlansField && parseInt(currentPlansField, 10) !== highestIncompletePhaseplanCount) {
1572
+ changes.push(`Total Plans in Phase: ${currentPlansField} -> ${highestIncompletePhaseplanCount}`);
1573
+ const result = stateReplaceField(modified, 'Total Plans in Phase', String(highestIncompletePhaseplanCount));
1574
+ if (result) modified = result;
1575
+ }
1576
+ }
1577
+
1578
+ // Sync Progress — use shared helper so formula stays in one place (#3242 Bug B).
1579
+ // computeProgressPercent applies min(plan_fraction, phase_fraction) so unrealised
1580
+ // ROADMAP phases cap the reported percent rather than allowing a false 100%.
1581
+ const percent = (() => {
1582
+ const p = computeProgressPercent(totalDiskSummaries, totalDiskPlans, diskCompletedPhases, syncTotalPhases);
1583
+ return p !== null ? p : 0;
1584
+ })();
1585
+ const currentProgress = stateExtractField(modified, 'Progress');
1586
+ if (currentProgress) {
1587
+ const currentPercent = parseInt(currentProgress.replace(/[^\d]/g, ''), 10);
1588
+ if (currentPercent !== percent) {
1589
+ const barWidth = 10;
1590
+ const filled = Math.round(percent / 100 * barWidth);
1591
+ const bar = '\u2588'.repeat(filled) + '\u2591'.repeat(barWidth - filled);
1592
+ const progressStr = `[${bar}] ${percent}%`;
1593
+ changes.push(`Progress: ${currentProgress} -> ${progressStr}`);
1594
+ const result = stateReplaceField(modified, 'Progress', progressStr);
1595
+ if (result) modified = result;
1596
+ }
1597
+ }
1598
+
1599
+ // Sync Last Activity
1600
+ const result = stateReplaceField(modified, 'Last Activity', today);
1601
+ if (result) {
1602
+ const oldActivity = stateExtractField(modified, 'Last Activity');
1603
+ if (oldActivity !== today) {
1604
+ changes.push(`Last Activity: ${oldActivity} -> ${today}`);
1605
+ }
1606
+ modified = result;
1607
+ }
1608
+
1609
+ if (verify) {
1610
+ output({ synced: false, changes, dry_run: true }, raw);
1611
+ return;
1612
+ }
1613
+
1614
+ if (changes.length > 0 || modified !== content) {
1615
+ writeStateMd(statePath, modified, cwd);
1616
+ }
1617
+
1618
+ output({ synced: true, changes, dry_run: false }, raw);
1619
+ }
1620
+
1621
+ /**
1622
+ * Prune old entries from STATE.md sections that grow unboundedly (#1970).
1623
+ * Moves decisions, recently-completed summaries, and resolved blockers
1624
+ * older than keepRecent phases to STATE-ARCHIVE.md.
1625
+ *
1626
+ * Options:
1627
+ * keepRecent: number of recent phases to retain (default: 3)
1628
+ * dryRun: if true, return what would be pruned without modifying STATE.md
1629
+ */
1630
+ function cmdStatePrune(cwd, options, raw) {
1631
+ const silent = !!options.silent;
1632
+ const emit = silent ? () => {} : (result, r, v) => output(result, r, v);
1633
+ const statePath = planningPaths(cwd).state;
1634
+ if (!fs.existsSync(statePath)) { emit({ error: 'STATE.md not found' }, raw); return; }
1635
+
1636
+ const keepRecent = parseInt(options.keepRecent, 10) || 3;
1637
+ const dryRun = !!options.dryRun;
1638
+ const currentPhaseRaw = stateExtractField(fs.readFileSync(statePath, 'utf-8'), 'Current Phase');
1639
+ const currentPhase = parseInt(currentPhaseRaw, 10) || 0;
1640
+ const cutoff = currentPhase - keepRecent;
1641
+
1642
+ if (cutoff <= 0) {
1643
+ emit({ pruned: false, reason: `Only ${currentPhase} phases — nothing to prune with --keep-recent ${keepRecent}` }, raw, 'false');
1644
+ return;
1645
+ }
1646
+
1647
+ const archivePath = path.join(path.dirname(statePath), 'STATE-ARCHIVE.md');
1648
+ const archived = [];
1649
+
1650
+ // Shared pruning logic applied to both dry-run and real passes.
1651
+ // Returns { newContent, archivedSections }.
1652
+ function prunePass(content) {
1653
+ const sections = [];
1654
+
1655
+ // Prune Decisions section: entries like "- [Phase N]: ..."
1656
+ const decisionPattern = /(###?\s*(?:Decisions|Decisions Made|Accumulated.*Decisions)\s*\n)([\s\S]*?)(?=\n###?|\n##[^#]|$)/i;
1657
+ const decMatch = content.match(decisionPattern);
1658
+ if (decMatch) {
1659
+ const lines = decMatch[2].split('\n');
1660
+ const keep = [];
1661
+ const archive = [];
1662
+ for (const line of lines) {
1663
+ const phaseMatch = line.match(/^\s*-\s*\[Phase\s+(\d+)/i);
1664
+ if (phaseMatch && parseInt(phaseMatch[1], 10) <= cutoff) {
1665
+ archive.push(line);
1666
+ } else {
1667
+ keep.push(line);
1668
+ }
1669
+ }
1670
+ if (archive.length > 0) {
1671
+ sections.push({ section: 'Decisions', count: archive.length, lines: archive });
1672
+ content = content.replace(decisionPattern, (_m, header) => `${header}${keep.join('\n')}`);
1673
+ }
1674
+ }
1675
+
1676
+ // Prune Recently Completed section: entries mentioning phase numbers
1677
+ const recentPattern = /(###?\s*Recently Completed\s*\n)([\s\S]*?)(?=\n###?|\n##[^#]|$)/i;
1678
+ const recMatch = content.match(recentPattern);
1679
+ if (recMatch) {
1680
+ const lines = recMatch[2].split('\n');
1681
+ const keep = [];
1682
+ const archive = [];
1683
+ for (const line of lines) {
1684
+ const phaseMatch = line.match(/Phase\s+(\d+)/i);
1685
+ if (phaseMatch && parseInt(phaseMatch[1], 10) <= cutoff) {
1686
+ archive.push(line);
1687
+ } else {
1688
+ keep.push(line);
1689
+ }
1690
+ }
1691
+ if (archive.length > 0) {
1692
+ sections.push({ section: 'Recently Completed', count: archive.length, lines: archive });
1693
+ content = content.replace(recentPattern, (_m, header) => `${header}${keep.join('\n')}`);
1694
+ }
1695
+ }
1696
+
1697
+ // Prune resolved blockers: lines marked as resolved (strikethrough ~~text~~
1698
+ // or "[RESOLVED]" prefix) with a phase reference older than cutoff
1699
+ const blockersPattern = /(###?\s*(?:Blockers|Blockers\/Concerns|Blockers\s*&\s*Concerns)\s*\n)([\s\S]*?)(?=\n###?|\n##[^#]|$)/i;
1700
+ const blockersMatch = content.match(blockersPattern);
1701
+ if (blockersMatch) {
1702
+ const lines = blockersMatch[2].split('\n');
1703
+ const keep = [];
1704
+ const archive = [];
1705
+ for (const line of lines) {
1706
+ const isResolved = /~~.*~~|\[RESOLVED\]/i.test(line);
1707
+ const phaseMatch = line.match(/Phase\s+(\d+)/i);
1708
+ if (isResolved && phaseMatch && parseInt(phaseMatch[1], 10) <= cutoff) {
1709
+ archive.push(line);
1710
+ } else {
1711
+ keep.push(line);
1712
+ }
1713
+ }
1714
+ if (archive.length > 0) {
1715
+ sections.push({ section: 'Blockers (resolved)', count: archive.length, lines: archive });
1716
+ content = content.replace(blockersPattern, (_m, header) => `${header}${keep.join('\n')}`);
1717
+ }
1718
+ }
1719
+
1720
+ // Prune Performance Metrics table rows: keep only rows for phases > cutoff.
1721
+ // Preserves header rows (| Phase | ... and |---|...) and any prose around the table.
1722
+ const metricsPattern = /(###?\s*Performance Metrics\s*\n)([\s\S]*?)(?=\n###?|\n##[^#]|$)/i;
1723
+ const metricsMatch = content.match(metricsPattern);
1724
+ if (metricsMatch) {
1725
+ const sectionLines = metricsMatch[2].split('\n');
1726
+ const keep = [];
1727
+ const archive = [];
1728
+ for (const line of sectionLines) {
1729
+ // Table data row: starts with | followed by a number (phase)
1730
+ const tableRowMatch = line.match(/^\|\s*(\d+)\s*\|/);
1731
+ if (tableRowMatch) {
1732
+ const rowPhase = parseInt(tableRowMatch[1], 10);
1733
+ if (rowPhase <= cutoff) {
1734
+ archive.push(line);
1735
+ } else {
1736
+ keep.push(line);
1737
+ }
1738
+ } else {
1739
+ // Header row, separator row, or prose — always keep
1740
+ keep.push(line);
1741
+ }
1742
+ }
1743
+ if (archive.length > 0) {
1744
+ sections.push({ section: 'Performance Metrics', count: archive.length, lines: archive });
1745
+ content = content.replace(metricsPattern, (_m, header) => `${header}${keep.join('\n')}`);
1746
+ }
1747
+ }
1748
+
1749
+ return { newContent: content, archivedSections: sections };
1750
+ }
1751
+
1752
+ if (dryRun) {
1753
+ // Dry-run: compute what would be pruned without writing anything
1754
+ const content = fs.readFileSync(statePath, 'utf-8');
1755
+ const result = prunePass(content);
1756
+ const totalPruned = result.archivedSections.reduce((sum, s) => sum + s.count, 0);
1757
+ emit({
1758
+ pruned: false,
1759
+ dry_run: true,
1760
+ cutoff_phase: cutoff,
1761
+ keep_recent: keepRecent,
1762
+ sections: result.archivedSections.map(s => ({ section: s.section, entries_would_archive: s.count })),
1763
+ total_would_archive: totalPruned,
1764
+ note: totalPruned > 0 ? 'Run without --dry-run to actually prune' : 'Nothing to prune',
1765
+ }, raw, totalPruned > 0 ? 'true' : 'false');
1766
+ return;
1767
+ }
1768
+
1769
+ readModifyWriteStateMd(statePath, (content) => {
1770
+ const result = prunePass(content);
1771
+ archived.push(...result.archivedSections);
1772
+ return result.newContent;
1773
+ }, cwd);
1774
+
1775
+ // Write archived entries to STATE-ARCHIVE.md
1776
+ if (archived.length > 0) {
1777
+ const timestamp = new Date().toISOString().split('T')[0];
1778
+ let archiveContent = platformReadSync(archivePath);
1779
+ if (archiveContent === null) {
1780
+ archiveContent = '# STATE Archive\n\nPruned entries from STATE.md. Recoverable but no longer loaded into agent context.\n\n';
1781
+ }
1782
+ archiveContent += `## Pruned ${timestamp} (phases 1-${cutoff}, kept recent ${keepRecent})\n\n`;
1783
+ for (const section of archived) {
1784
+ archiveContent += `### ${section.section}\n\n${section.lines.join('\n')}\n\n`;
1785
+ }
1786
+ platformWriteSync(archivePath, archiveContent);
1787
+ }
1788
+
1789
+ const totalPruned = archived.reduce((sum, s) => sum + s.count, 0);
1790
+ emit({
1791
+ pruned: totalPruned > 0,
1792
+ cutoff_phase: cutoff,
1793
+ keep_recent: keepRecent,
1794
+ sections: archived.map(s => ({ section: s.section, entries_archived: s.count })),
1795
+ total_archived: totalPruned,
1796
+ archive_file: totalPruned > 0 ? 'STATE-ARCHIVE.md' : null,
1797
+ }, raw, totalPruned > 0 ? 'true' : 'false');
1798
+ }
1799
+
1800
+ /**
1801
+ * Mark the current phase as COMPLETE in STATE.md.
1802
+ * Updates Status, Last Activity, and the Current Position section to reflect
1803
+ * that the phase execution is finished and the project is ready for the next phase.
1804
+ * Implements the `gsd state complete-phase` subcommand (issue #2735).
1805
+ */
1806
+ function resolvePhaseIdForCompletePhase(content, overridePhase) {
1807
+ const candidate = overridePhase ||
1808
+ stateExtractField(content, 'Current Phase') ||
1809
+ stateExtractField(content, 'Phase') ||
1810
+ '';
1811
+
1812
+ // Accept canonical phase token only (e.g. 3, 03, 3A, 3.3, 10.2)
1813
+ const phaseMatch = String(candidate).match(/(\d+[A-Z]?(?:\.\d+)*)/i);
1814
+ return phaseMatch ? phaseMatch[1] : null;
1815
+ }
1816
+
1817
+ function cmdStateCompletePhase(cwd, raw, overridePhase) {
1818
+ const statePath = planningPaths(cwd).state;
1819
+ if (!fs.existsSync(statePath)) {
1820
+ output({ error: 'STATE.md not found' }, raw);
1821
+ return;
1822
+ }
1823
+
1824
+ const content = fs.readFileSync(statePath, 'utf-8');
1825
+ const resolvedPhase = resolvePhaseIdForCompletePhase(content, overridePhase);
1826
+ if (!resolvedPhase || /^phase$/i.test(resolvedPhase)) {
1827
+ output({ error: 'Unable to resolve current phase. Pass an explicit phase: state complete-phase --phase <N>' }, raw);
1828
+ return;
1829
+ }
1830
+
1831
+ // Idempotency guard (#3489). If STATE.md's canonical `Current Phase` field
1832
+ // already names a phase distinct from the one we are being asked to mark
1833
+ // complete, the project has advanced past the requested phase (e.g. a
1834
+ // follow-up phase was inserted, or the next phase began). Re-running
1835
+ // `state complete-phase --phase <N>` in that situation previously rolled
1836
+ // STATE.md back to <N>'s moment-of-completion — silently clobbering Status,
1837
+ // Last Activity, Last Activity Description, and the Current Position body.
1838
+ // The handler is now a no-op in that case so re-invocation from downstream
1839
+ // workflows cannot regress the project state.
1840
+ const existingCurrentPhaseRaw = stateExtractField(content, 'Current Phase') || '';
1841
+ const existingCurrentPhaseMatch = String(existingCurrentPhaseRaw).match(/(\d+[A-Z]?(?:\.\d+)*)/i);
1842
+ const existingCurrentPhase = existingCurrentPhaseMatch ? existingCurrentPhaseMatch[1] : null;
1843
+ if (existingCurrentPhase && existingCurrentPhase !== resolvedPhase) {
1844
+ output(
1845
+ { updated: [], phase: resolvedPhase, idempotent: true, note: 'phase already superseded; no-op' },
1846
+ raw,
1847
+ 'false',
1848
+ );
1849
+ return;
1850
+ }
1851
+
1852
+ const today = new Date().toISOString().split('T')[0];
1853
+ const updated = [];
1854
+
1855
+ readModifyWriteStateMd(statePath, (content) => {
1856
+ const currentPhase = resolvedPhase;
1857
+
1858
+ // Update Status field
1859
+ const statusValue = `Phase ${currentPhase} complete`;
1860
+ let result = stateReplaceField(content, 'Status', statusValue);
1861
+ if (result) { content = result; updated.push('Status'); }
1862
+
1863
+ // Update Last Activity date
1864
+ result = stateReplaceField(content, 'Last Activity', today);
1865
+ if (result) { content = result; updated.push('Last Activity'); }
1866
+
1867
+ // Update Last Activity Description
1868
+ const activityDesc = `Phase ${currentPhase} marked complete`;
1869
+ result = stateReplaceField(content, 'Last Activity Description', activityDesc);
1870
+ if (result) { content = result; updated.push('Last Activity Description'); }
1871
+
1872
+ // Update ## Current Position section
1873
+ const positionPattern = /(##\s*Current Position\s*\n)([\s\S]*?)(?=\n##|$)/i;
1874
+ const positionMatch = content.match(positionPattern);
1875
+ if (positionMatch) {
1876
+ const header = positionMatch[1];
1877
+ let posBody = positionMatch[2];
1878
+
1879
+ // Update Phase line to show COMPLETE
1880
+ const newPhase = `Phase: ${currentPhase} — COMPLETE`;
1881
+ if (/^Phase:/m.test(posBody)) {
1882
+ posBody = posBody.replace(/^Phase:.*$/m, newPhase);
1883
+ }
1884
+
1885
+ // Update Status line if present
1886
+ const newStatus = `Status: Phase ${currentPhase} complete`;
1887
+ if (/^Status:/m.test(posBody)) {
1888
+ posBody = posBody.replace(/^Status:.*$/m, newStatus);
1889
+ }
1890
+
1891
+ // Update Last activity line if present
1892
+ const newActivity = `Last activity: ${today} -- Phase ${currentPhase} marked complete`;
1893
+ if (/^Last activity:/im.test(posBody)) {
1894
+ posBody = posBody.replace(/^Last activity:.*$/im, newActivity);
1895
+ }
1896
+
1897
+ content = content.replace(positionPattern, () => `${header}${posBody}`);
1898
+ updated.push('Current Position');
1899
+ }
1900
+
1901
+ return content;
1902
+ }, cwd);
1903
+
1904
+ output(
1905
+ { updated, phase: resolvedPhase },
1906
+ raw,
1907
+ updated.length > 0 ? 'true' : 'false',
1908
+ );
1909
+ }
1910
+
1911
+ module.exports = {
1912
+ stateExtractField,
1913
+ stateReplaceField,
1914
+ stateReplaceFieldWithFallback,
1915
+ writeStateMd,
1916
+ readModifyWriteStateMd,
1917
+ updatePerformanceMetricsSection,
1918
+ cmdStateLoad,
1919
+ cmdStateGet,
1920
+ cmdStatePatch,
1921
+ cmdStateUpdate,
1922
+ cmdStateAdvancePlan,
1923
+ cmdStateRecordMetric,
1924
+ cmdStateUpdateProgress,
1925
+ cmdStateAddDecision,
1926
+ cmdStateAddBlocker,
1927
+ cmdStateResolveBlocker,
1928
+ cmdStateRecordSession,
1929
+ cmdStateSnapshot,
1930
+ cmdStateJson,
1931
+ cmdStateBeginPhase,
1932
+ cmdStatePlannedPhase,
1933
+ cmdStateCompletePhase,
1934
+ cmdStateValidate,
1935
+ cmdStateSync,
1936
+ cmdStatePrune,
1937
+ cmdStateMilestoneSwitch,
1938
+ cmdSignalWaiting,
1939
+ cmdSignalResume,
1940
+ };