gsd-remix 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 (554) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +939 -0
  3. package/README.zh-CN.md +876 -0
  4. package/agents/gsd-advisor-researcher.md +127 -0
  5. package/agents/gsd-ai-researcher.md +133 -0
  6. package/agents/gsd-assumptions-analyzer.md +105 -0
  7. package/agents/gsd-code-fixer.md +517 -0
  8. package/agents/gsd-code-reviewer.md +371 -0
  9. package/agents/gsd-codebase-mapper.md +781 -0
  10. package/agents/gsd-debug-session-manager.md +314 -0
  11. package/agents/gsd-debugger.md +1452 -0
  12. package/agents/gsd-doc-classifier.md +168 -0
  13. package/agents/gsd-doc-synthesizer.md +204 -0
  14. package/agents/gsd-doc-verifier.md +217 -0
  15. package/agents/gsd-doc-writer.md +615 -0
  16. package/agents/gsd-domain-researcher.md +153 -0
  17. package/agents/gsd-eval-auditor.md +191 -0
  18. package/agents/gsd-eval-planner.md +154 -0
  19. package/agents/gsd-executor.md +603 -0
  20. package/agents/gsd-framework-selector.md +160 -0
  21. package/agents/gsd-integration-checker.md +470 -0
  22. package/agents/gsd-intel-updater.md +334 -0
  23. package/agents/gsd-nyquist-auditor.md +203 -0
  24. package/agents/gsd-pattern-mapper.md +335 -0
  25. package/agents/gsd-phase-researcher.md +841 -0
  26. package/agents/gsd-plan-checker.md +978 -0
  27. package/agents/gsd-planner.md +1251 -0
  28. package/agents/gsd-project-researcher.md +677 -0
  29. package/agents/gsd-research-synthesizer.md +247 -0
  30. package/agents/gsd-roadmapper.md +688 -0
  31. package/agents/gsd-security-auditor.md +155 -0
  32. package/agents/gsd-ui-auditor.md +495 -0
  33. package/agents/gsd-ui-checker.md +309 -0
  34. package/agents/gsd-ui-researcher.md +380 -0
  35. package/agents/gsd-user-profiler.md +171 -0
  36. package/agents/gsd-verifier.md +830 -0
  37. package/bin/install.js +7062 -0
  38. package/commands/gsd/add-backlog.md +79 -0
  39. package/commands/gsd/add-phase.md +43 -0
  40. package/commands/gsd/add-tests.md +41 -0
  41. package/commands/gsd/add-todo.md +47 -0
  42. package/commands/gsd/ai-integration-phase.md +36 -0
  43. package/commands/gsd/analyze-dependencies.md +34 -0
  44. package/commands/gsd/audit-fix.md +33 -0
  45. package/commands/gsd/audit-milestone.md +36 -0
  46. package/commands/gsd/audit-uat.md +24 -0
  47. package/commands/gsd/autonomous.md +46 -0
  48. package/commands/gsd/check-todos.md +45 -0
  49. package/commands/gsd/cleanup.md +23 -0
  50. package/commands/gsd/code-review-fix.md +52 -0
  51. package/commands/gsd/code-review.md +55 -0
  52. package/commands/gsd/complete-milestone.md +136 -0
  53. package/commands/gsd/debug.md +263 -0
  54. package/commands/gsd/discuss-phase.md +69 -0
  55. package/commands/gsd/do.md +30 -0
  56. package/commands/gsd/docs-update.md +48 -0
  57. package/commands/gsd/eval-review.md +32 -0
  58. package/commands/gsd/execute-phase.md +63 -0
  59. package/commands/gsd/explore.md +27 -0
  60. package/commands/gsd/extract_learnings.md +22 -0
  61. package/commands/gsd/fast.md +30 -0
  62. package/commands/gsd/forensics.md +56 -0
  63. package/commands/gsd/from-gsd2.md +47 -0
  64. package/commands/gsd/graphify.md +201 -0
  65. package/commands/gsd/health.md +22 -0
  66. package/commands/gsd/help.md +24 -0
  67. package/commands/gsd/import.md +37 -0
  68. package/commands/gsd/inbox.md +38 -0
  69. package/commands/gsd/ingest-docs.md +42 -0
  70. package/commands/gsd/insert-phase.md +32 -0
  71. package/commands/gsd/intel.md +179 -0
  72. package/commands/gsd/join-discord.md +19 -0
  73. package/commands/gsd/list-phase-assumptions.md +46 -0
  74. package/commands/gsd/list-workspaces.md +19 -0
  75. package/commands/gsd/manager.md +40 -0
  76. package/commands/gsd/map-codebase.md +71 -0
  77. package/commands/gsd/milestone-summary.md +51 -0
  78. package/commands/gsd/new-milestone.md +44 -0
  79. package/commands/gsd/new-project.md +46 -0
  80. package/commands/gsd/new-workspace.md +44 -0
  81. package/commands/gsd/next.md +28 -0
  82. package/commands/gsd/note.md +34 -0
  83. package/commands/gsd/pause-work.md +38 -0
  84. package/commands/gsd/plan-milestone-gaps.md +34 -0
  85. package/commands/gsd/plan-phase.md +52 -0
  86. package/commands/gsd/plan-review-convergence.md +52 -0
  87. package/commands/gsd/plant-seed.md +28 -0
  88. package/commands/gsd/pr-branch.md +25 -0
  89. package/commands/gsd/profile-user.md +46 -0
  90. package/commands/gsd/progress.md +25 -0
  91. package/commands/gsd/quick.md +173 -0
  92. package/commands/gsd/reapply-patches.md +331 -0
  93. package/commands/gsd/remove-phase.md +31 -0
  94. package/commands/gsd/remove-workspace.md +26 -0
  95. package/commands/gsd/research-phase.md +195 -0
  96. package/commands/gsd/resume-work.md +40 -0
  97. package/commands/gsd/review-backlog.md +62 -0
  98. package/commands/gsd/review.md +40 -0
  99. package/commands/gsd/scan.md +26 -0
  100. package/commands/gsd/secure-phase.md +35 -0
  101. package/commands/gsd/session-report.md +19 -0
  102. package/commands/gsd/set-profile.md +12 -0
  103. package/commands/gsd/settings.md +36 -0
  104. package/commands/gsd/ship.md +23 -0
  105. package/commands/gsd/sketch-wrap-up.md +31 -0
  106. package/commands/gsd/sketch.md +49 -0
  107. package/commands/gsd/spec-phase.md +62 -0
  108. package/commands/gsd/spike-wrap-up.md +31 -0
  109. package/commands/gsd/spike.md +46 -0
  110. package/commands/gsd/stats.md +18 -0
  111. package/commands/gsd/sync-skills.md +19 -0
  112. package/commands/gsd/thread.md +227 -0
  113. package/commands/gsd/ui-phase.md +34 -0
  114. package/commands/gsd/ui-review.md +32 -0
  115. package/commands/gsd/ultraplan-phase.md +33 -0
  116. package/commands/gsd/undo.md +34 -0
  117. package/commands/gsd/update.md +37 -0
  118. package/commands/gsd/validate-phase.md +35 -0
  119. package/commands/gsd/verify-work.md +38 -0
  120. package/commands/gsd/workstreams.md +69 -0
  121. package/get-shit-done/bin/gsd-tools.cjs +1263 -0
  122. package/get-shit-done/bin/lib/artifacts.cjs +52 -0
  123. package/get-shit-done/bin/lib/audit.cjs +757 -0
  124. package/get-shit-done/bin/lib/commands.cjs +1023 -0
  125. package/get-shit-done/bin/lib/config-schema.cjs +79 -0
  126. package/get-shit-done/bin/lib/config.cjs +463 -0
  127. package/get-shit-done/bin/lib/core.cjs +1794 -0
  128. package/get-shit-done/bin/lib/docs.cjs +267 -0
  129. package/get-shit-done/bin/lib/frontmatter.cjs +379 -0
  130. package/get-shit-done/bin/lib/graphify.cjs +494 -0
  131. package/get-shit-done/bin/lib/gsd2-import.cjs +511 -0
  132. package/get-shit-done/bin/lib/init.cjs +1878 -0
  133. package/get-shit-done/bin/lib/intel.cjs +639 -0
  134. package/get-shit-done/bin/lib/learnings.cjs +378 -0
  135. package/get-shit-done/bin/lib/milestone.cjs +283 -0
  136. package/get-shit-done/bin/lib/model-profiles.cjs +71 -0
  137. package/get-shit-done/bin/lib/phase.cjs +1058 -0
  138. package/get-shit-done/bin/lib/profile-output.cjs +1080 -0
  139. package/get-shit-done/bin/lib/profile-pipeline.cjs +539 -0
  140. package/get-shit-done/bin/lib/roadmap.cjs +523 -0
  141. package/get-shit-done/bin/lib/schema-detect.cjs +238 -0
  142. package/get-shit-done/bin/lib/security.cjs +504 -0
  143. package/get-shit-done/bin/lib/state.cjs +1649 -0
  144. package/get-shit-done/bin/lib/template.cjs +226 -0
  145. package/get-shit-done/bin/lib/uat.cjs +288 -0
  146. package/get-shit-done/bin/lib/verify.cjs +1184 -0
  147. package/get-shit-done/bin/lib/workstream.cjs +495 -0
  148. package/get-shit-done/bin/repair-sdk.cjs +177 -0
  149. package/get-shit-done/contexts/dev.md +21 -0
  150. package/get-shit-done/contexts/research.md +22 -0
  151. package/get-shit-done/contexts/review.md +22 -0
  152. package/get-shit-done/references/agent-contracts.md +79 -0
  153. package/get-shit-done/references/ai-evals.md +156 -0
  154. package/get-shit-done/references/ai-frameworks.md +186 -0
  155. package/get-shit-done/references/artifact-types.md +131 -0
  156. package/get-shit-done/references/autonomous-smart-discuss.md +277 -0
  157. package/get-shit-done/references/checkpoints.md +808 -0
  158. package/get-shit-done/references/common-bug-patterns.md +114 -0
  159. package/get-shit-done/references/context-budget.md +49 -0
  160. package/get-shit-done/references/continuation-format.md +253 -0
  161. package/get-shit-done/references/debugger-philosophy.md +76 -0
  162. package/get-shit-done/references/decimal-phase-calculation.md +64 -0
  163. package/get-shit-done/references/doc-conflict-engine.md +91 -0
  164. package/get-shit-done/references/domain-probes.md +125 -0
  165. package/get-shit-done/references/executor-examples.md +110 -0
  166. package/get-shit-done/references/few-shot-examples/plan-checker.md +73 -0
  167. package/get-shit-done/references/few-shot-examples/verifier.md +109 -0
  168. package/get-shit-done/references/gate-prompts.md +100 -0
  169. package/get-shit-done/references/gates.md +70 -0
  170. package/get-shit-done/references/git-integration.md +295 -0
  171. package/get-shit-done/references/git-planning-commit.md +40 -0
  172. package/get-shit-done/references/ios-scaffold.md +123 -0
  173. package/get-shit-done/references/mandatory-initial-read.md +2 -0
  174. package/get-shit-done/references/model-profile-resolution.md +38 -0
  175. package/get-shit-done/references/model-profiles.md +145 -0
  176. package/get-shit-done/references/phase-argument-parsing.md +61 -0
  177. package/get-shit-done/references/planner-antipatterns.md +89 -0
  178. package/get-shit-done/references/planner-gap-closure.md +62 -0
  179. package/get-shit-done/references/planner-reviews.md +39 -0
  180. package/get-shit-done/references/planner-revision.md +87 -0
  181. package/get-shit-done/references/planner-source-audit.md +73 -0
  182. package/get-shit-done/references/planning-config.md +460 -0
  183. package/get-shit-done/references/project-skills-discovery.md +19 -0
  184. package/get-shit-done/references/questioning.md +162 -0
  185. package/get-shit-done/references/revision-loop.md +97 -0
  186. package/get-shit-done/references/sketch-interactivity.md +41 -0
  187. package/get-shit-done/references/sketch-theme-system.md +94 -0
  188. package/get-shit-done/references/sketch-tooling.md +45 -0
  189. package/get-shit-done/references/sketch-variant-patterns.md +81 -0
  190. package/get-shit-done/references/tdd.md +330 -0
  191. package/get-shit-done/references/thinking-models-debug.md +44 -0
  192. package/get-shit-done/references/thinking-models-execution.md +50 -0
  193. package/get-shit-done/references/thinking-models-planning.md +62 -0
  194. package/get-shit-done/references/thinking-models-research.md +50 -0
  195. package/get-shit-done/references/thinking-models-verification.md +55 -0
  196. package/get-shit-done/references/thinking-partner.md +96 -0
  197. package/get-shit-done/references/ui-brand.md +160 -0
  198. package/get-shit-done/references/universal-anti-patterns.md +63 -0
  199. package/get-shit-done/references/user-profiling.md +681 -0
  200. package/get-shit-done/references/verification-overrides.md +227 -0
  201. package/get-shit-done/references/verification-patterns.md +612 -0
  202. package/get-shit-done/references/workstream-flag.md +111 -0
  203. package/get-shit-done/templates/AI-SPEC.md +246 -0
  204. package/get-shit-done/templates/DEBUG.md +169 -0
  205. package/get-shit-done/templates/README.md +76 -0
  206. package/get-shit-done/templates/SECURITY.md +61 -0
  207. package/get-shit-done/templates/UAT.md +265 -0
  208. package/get-shit-done/templates/UI-SPEC.md +100 -0
  209. package/get-shit-done/templates/VALIDATION.md +76 -0
  210. package/get-shit-done/templates/claude-md.md +145 -0
  211. package/get-shit-done/templates/codebase/architecture.md +255 -0
  212. package/get-shit-done/templates/codebase/concerns.md +310 -0
  213. package/get-shit-done/templates/codebase/conventions.md +307 -0
  214. package/get-shit-done/templates/codebase/integrations.md +280 -0
  215. package/get-shit-done/templates/codebase/stack.md +186 -0
  216. package/get-shit-done/templates/codebase/structure.md +285 -0
  217. package/get-shit-done/templates/codebase/testing.md +480 -0
  218. package/get-shit-done/templates/config.json +56 -0
  219. package/get-shit-done/templates/context.md +352 -0
  220. package/get-shit-done/templates/continue-here.md +78 -0
  221. package/get-shit-done/templates/copilot-instructions.md +7 -0
  222. package/get-shit-done/templates/debug-subagent-prompt.md +91 -0
  223. package/get-shit-done/templates/dev-preferences.md +21 -0
  224. package/get-shit-done/templates/discovery.md +146 -0
  225. package/get-shit-done/templates/discussion-log.md +63 -0
  226. package/get-shit-done/templates/milestone-archive.md +123 -0
  227. package/get-shit-done/templates/milestone.md +115 -0
  228. package/get-shit-done/templates/phase-prompt.md +610 -0
  229. package/get-shit-done/templates/planner-subagent-prompt.md +117 -0
  230. package/get-shit-done/templates/project.md +186 -0
  231. package/get-shit-done/templates/requirements.md +231 -0
  232. package/get-shit-done/templates/research-project/ARCHITECTURE.md +204 -0
  233. package/get-shit-done/templates/research-project/FEATURES.md +147 -0
  234. package/get-shit-done/templates/research-project/PITFALLS.md +200 -0
  235. package/get-shit-done/templates/research-project/STACK.md +120 -0
  236. package/get-shit-done/templates/research-project/SUMMARY.md +170 -0
  237. package/get-shit-done/templates/research.md +592 -0
  238. package/get-shit-done/templates/retrospective.md +54 -0
  239. package/get-shit-done/templates/roadmap.md +202 -0
  240. package/get-shit-done/templates/spec.md +307 -0
  241. package/get-shit-done/templates/state.md +184 -0
  242. package/get-shit-done/templates/summary-complex.md +59 -0
  243. package/get-shit-done/templates/summary-minimal.md +41 -0
  244. package/get-shit-done/templates/summary-standard.md +48 -0
  245. package/get-shit-done/templates/summary.md +248 -0
  246. package/get-shit-done/templates/user-profile.md +146 -0
  247. package/get-shit-done/templates/user-setup.md +311 -0
  248. package/get-shit-done/templates/verification-report.md +322 -0
  249. package/get-shit-done/workflows/add-phase.md +112 -0
  250. package/get-shit-done/workflows/add-tests.md +354 -0
  251. package/get-shit-done/workflows/add-todo.md +160 -0
  252. package/get-shit-done/workflows/ai-integration-phase.md +284 -0
  253. package/get-shit-done/workflows/analyze-dependencies.md +96 -0
  254. package/get-shit-done/workflows/audit-fix.md +175 -0
  255. package/get-shit-done/workflows/audit-milestone.md +340 -0
  256. package/get-shit-done/workflows/audit-uat.md +109 -0
  257. package/get-shit-done/workflows/autonomous.md +789 -0
  258. package/get-shit-done/workflows/check-todos.md +179 -0
  259. package/get-shit-done/workflows/cleanup.md +154 -0
  260. package/get-shit-done/workflows/code-review-fix.md +497 -0
  261. package/get-shit-done/workflows/code-review.md +515 -0
  262. package/get-shit-done/workflows/complete-milestone.md +847 -0
  263. package/get-shit-done/workflows/diagnose-issues.md +238 -0
  264. package/get-shit-done/workflows/discovery-phase.md +291 -0
  265. package/get-shit-done/workflows/discuss-phase-assumptions.md +670 -0
  266. package/get-shit-done/workflows/discuss-phase-power.md +308 -0
  267. package/get-shit-done/workflows/discuss-phase.md +1378 -0
  268. package/get-shit-done/workflows/do.md +110 -0
  269. package/get-shit-done/workflows/docs-update.md +1155 -0
  270. package/get-shit-done/workflows/eval-review.md +155 -0
  271. package/get-shit-done/workflows/execute-phase.md +1677 -0
  272. package/get-shit-done/workflows/execute-plan.md +533 -0
  273. package/get-shit-done/workflows/explore.md +141 -0
  274. package/get-shit-done/workflows/extract_learnings.md +242 -0
  275. package/get-shit-done/workflows/fast.md +105 -0
  276. package/get-shit-done/workflows/forensics.md +265 -0
  277. package/get-shit-done/workflows/graduation.md +195 -0
  278. package/get-shit-done/workflows/health.md +314 -0
  279. package/get-shit-done/workflows/help.md +667 -0
  280. package/get-shit-done/workflows/import.md +246 -0
  281. package/get-shit-done/workflows/inbox.md +387 -0
  282. package/get-shit-done/workflows/ingest-docs.md +328 -0
  283. package/get-shit-done/workflows/insert-phase.md +130 -0
  284. package/get-shit-done/workflows/list-phase-assumptions.md +178 -0
  285. package/get-shit-done/workflows/list-workspaces.md +56 -0
  286. package/get-shit-done/workflows/manager.md +365 -0
  287. package/get-shit-done/workflows/map-codebase.md +393 -0
  288. package/get-shit-done/workflows/milestone-summary.md +223 -0
  289. package/get-shit-done/workflows/new-milestone.md +611 -0
  290. package/get-shit-done/workflows/new-project.md +1391 -0
  291. package/get-shit-done/workflows/new-workspace.md +239 -0
  292. package/get-shit-done/workflows/next.md +220 -0
  293. package/get-shit-done/workflows/node-repair.md +92 -0
  294. package/get-shit-done/workflows/note.md +158 -0
  295. package/get-shit-done/workflows/pause-work.md +243 -0
  296. package/get-shit-done/workflows/plan-milestone-gaps.md +273 -0
  297. package/get-shit-done/workflows/plan-phase.md +1349 -0
  298. package/get-shit-done/workflows/plan-review-convergence.md +254 -0
  299. package/get-shit-done/workflows/plant-seed.md +172 -0
  300. package/get-shit-done/workflows/pr-branch.md +157 -0
  301. package/get-shit-done/workflows/profile-user.md +452 -0
  302. package/get-shit-done/workflows/progress.md +619 -0
  303. package/get-shit-done/workflows/quick.md +970 -0
  304. package/get-shit-done/workflows/remove-phase.md +155 -0
  305. package/get-shit-done/workflows/remove-workspace.md +92 -0
  306. package/get-shit-done/workflows/research-phase.md +89 -0
  307. package/get-shit-done/workflows/resume-project.md +326 -0
  308. package/get-shit-done/workflows/review.md +344 -0
  309. package/get-shit-done/workflows/scan.md +102 -0
  310. package/get-shit-done/workflows/secure-phase.md +166 -0
  311. package/get-shit-done/workflows/session-report.md +146 -0
  312. package/get-shit-done/workflows/settings.md +319 -0
  313. package/get-shit-done/workflows/ship.md +302 -0
  314. package/get-shit-done/workflows/sketch-wrap-up.md +283 -0
  315. package/get-shit-done/workflows/sketch.md +286 -0
  316. package/get-shit-done/workflows/spec-phase.md +262 -0
  317. package/get-shit-done/workflows/spike-wrap-up.md +281 -0
  318. package/get-shit-done/workflows/spike.md +362 -0
  319. package/get-shit-done/workflows/stats.md +60 -0
  320. package/get-shit-done/workflows/sync-skills.md +182 -0
  321. package/get-shit-done/workflows/transition.md +693 -0
  322. package/get-shit-done/workflows/ui-phase.md +323 -0
  323. package/get-shit-done/workflows/ui-review.md +190 -0
  324. package/get-shit-done/workflows/ultraplan-phase.md +189 -0
  325. package/get-shit-done/workflows/undo.md +314 -0
  326. package/get-shit-done/workflows/update.md +587 -0
  327. package/get-shit-done/workflows/validate-phase.md +176 -0
  328. package/get-shit-done/workflows/verify-phase.md +465 -0
  329. package/get-shit-done/workflows/verify-work.md +740 -0
  330. package/hooks/dist/gsd-check-update-worker.js +108 -0
  331. package/hooks/dist/gsd-check-update.js +64 -0
  332. package/hooks/dist/gsd-context-monitor.js +192 -0
  333. package/hooks/dist/gsd-phase-boundary.sh +28 -0
  334. package/hooks/dist/gsd-prompt-guard.js +97 -0
  335. package/hooks/dist/gsd-read-guard.js +82 -0
  336. package/hooks/dist/gsd-read-injection-scanner.js +152 -0
  337. package/hooks/dist/gsd-session-state.sh +34 -0
  338. package/hooks/dist/gsd-statusline.js +293 -0
  339. package/hooks/dist/gsd-validate-commit.sh +48 -0
  340. package/hooks/dist/gsd-workflow-guard.js +94 -0
  341. package/hooks/gsd-check-update-worker.js +108 -0
  342. package/hooks/gsd-check-update.js +64 -0
  343. package/hooks/gsd-context-monitor.js +192 -0
  344. package/hooks/gsd-phase-boundary.sh +28 -0
  345. package/hooks/gsd-prompt-guard.js +97 -0
  346. package/hooks/gsd-read-guard.js +82 -0
  347. package/hooks/gsd-read-injection-scanner.js +152 -0
  348. package/hooks/gsd-session-state.sh +34 -0
  349. package/hooks/gsd-statusline.js +293 -0
  350. package/hooks/gsd-validate-commit.sh +48 -0
  351. package/hooks/gsd-workflow-guard.js +94 -0
  352. package/package.json +59 -0
  353. package/scripts/base64-scan.sh +262 -0
  354. package/scripts/build-hooks.js +95 -0
  355. package/scripts/gen-inventory-manifest.cjs +109 -0
  356. package/scripts/prompt-injection-scan.sh +201 -0
  357. package/scripts/run-tests.cjs +33 -0
  358. package/scripts/secret-scan.sh +227 -0
  359. package/sdk/package-lock.json +1998 -0
  360. package/sdk/package.json +52 -0
  361. package/sdk/prompts/agents/gsd-executor.md +110 -0
  362. package/sdk/prompts/agents/gsd-phase-researcher.md +158 -0
  363. package/sdk/prompts/agents/gsd-plan-checker.md +160 -0
  364. package/sdk/prompts/agents/gsd-planner.md +214 -0
  365. package/sdk/prompts/agents/gsd-project-researcher.md +323 -0
  366. package/sdk/prompts/agents/gsd-research-synthesizer.md +237 -0
  367. package/sdk/prompts/agents/gsd-roadmapper.md +670 -0
  368. package/sdk/prompts/agents/gsd-verifier.md +159 -0
  369. package/sdk/prompts/templates/project.md +186 -0
  370. package/sdk/prompts/templates/requirements.md +231 -0
  371. package/sdk/prompts/templates/research-project/ARCHITECTURE.md +204 -0
  372. package/sdk/prompts/templates/research-project/FEATURES.md +147 -0
  373. package/sdk/prompts/templates/research-project/PITFALLS.md +200 -0
  374. package/sdk/prompts/templates/research-project/STACK.md +120 -0
  375. package/sdk/prompts/templates/research-project/SUMMARY.md +170 -0
  376. package/sdk/prompts/templates/roadmap.md +202 -0
  377. package/sdk/prompts/templates/state.md +175 -0
  378. package/sdk/prompts/workflows/discuss-phase.md +126 -0
  379. package/sdk/prompts/workflows/execute-plan.md +106 -0
  380. package/sdk/prompts/workflows/plan-phase.md +84 -0
  381. package/sdk/prompts/workflows/research-phase.md +45 -0
  382. package/sdk/prompts/workflows/verify-phase.md +142 -0
  383. package/sdk/src/assembled-prompts.test.ts +349 -0
  384. package/sdk/src/cli-transport.test.ts +388 -0
  385. package/sdk/src/cli-transport.ts +130 -0
  386. package/sdk/src/cli.test.ts +383 -0
  387. package/sdk/src/cli.ts +670 -0
  388. package/sdk/src/config.test.ts +168 -0
  389. package/sdk/src/config.ts +177 -0
  390. package/sdk/src/context-engine.test.ts +295 -0
  391. package/sdk/src/context-engine.ts +170 -0
  392. package/sdk/src/context-truncation.test.ts +163 -0
  393. package/sdk/src/context-truncation.ts +233 -0
  394. package/sdk/src/e2e.integration.test.ts +178 -0
  395. package/sdk/src/errors.ts +72 -0
  396. package/sdk/src/event-stream.test.ts +661 -0
  397. package/sdk/src/event-stream.ts +441 -0
  398. package/sdk/src/failure-memory.test.ts +457 -0
  399. package/sdk/src/failure-memory.ts +1324 -0
  400. package/sdk/src/golden/capture.ts +95 -0
  401. package/sdk/src/golden/fixtures/generate-slug.golden.json +1 -0
  402. package/sdk/src/golden/fixtures/profile-sample-sessions/demo-project/sample.jsonl +3 -0
  403. package/sdk/src/golden/fixtures/summary-extract-sample.md +26 -0
  404. package/sdk/src/golden/fixtures/uat-render-checkpoint-sample.md +15 -0
  405. package/sdk/src/golden/golden-integration-covered.ts +30 -0
  406. package/sdk/src/golden/golden-mutation-covered.ts +7 -0
  407. package/sdk/src/golden/golden-policy.test.ts +8 -0
  408. package/sdk/src/golden/golden-policy.ts +112 -0
  409. package/sdk/src/golden/golden.integration.test.ts +373 -0
  410. package/sdk/src/golden/init-golden-normalize.ts +15 -0
  411. package/sdk/src/golden/read-only-golden-rows.ts +77 -0
  412. package/sdk/src/golden/read-only-parity.integration.test.ts +125 -0
  413. package/sdk/src/golden/registry-canonical-commands.ts +31 -0
  414. package/sdk/src/gsd-tools.test.ts +409 -0
  415. package/sdk/src/gsd-tools.ts +595 -0
  416. package/sdk/src/headless-prompts.test.ts +159 -0
  417. package/sdk/src/index.ts +333 -0
  418. package/sdk/src/init-e2e.integration.test.ts +136 -0
  419. package/sdk/src/init-runner.test.ts +783 -0
  420. package/sdk/src/init-runner.ts +735 -0
  421. package/sdk/src/lifecycle-e2e.integration.test.ts +258 -0
  422. package/sdk/src/logger.test.ts +149 -0
  423. package/sdk/src/logger.ts +113 -0
  424. package/sdk/src/milestone-runner.test.ts +421 -0
  425. package/sdk/src/phase-prompt.test.ts +538 -0
  426. package/sdk/src/phase-prompt.ts +264 -0
  427. package/sdk/src/phase-runner-types.test.ts +421 -0
  428. package/sdk/src/phase-runner.integration.test.ts +377 -0
  429. package/sdk/src/phase-runner.test.ts +2333 -0
  430. package/sdk/src/phase-runner.ts +1203 -0
  431. package/sdk/src/plan-parser.test.ts +528 -0
  432. package/sdk/src/plan-parser.ts +427 -0
  433. package/sdk/src/prompt-builder.test.ts +306 -0
  434. package/sdk/src/prompt-builder.ts +193 -0
  435. package/sdk/src/prompt-sanitizer.test.ts +260 -0
  436. package/sdk/src/prompt-sanitizer.ts +71 -0
  437. package/sdk/src/query/QUERY-HANDLERS.md +317 -0
  438. package/sdk/src/query/audit-open.ts +722 -0
  439. package/sdk/src/query/check-auto-mode.test.ts +77 -0
  440. package/sdk/src/query/check-auto-mode.ts +50 -0
  441. package/sdk/src/query/check-completion.test.ts +113 -0
  442. package/sdk/src/query/check-completion.ts +182 -0
  443. package/sdk/src/query/check-gates.test.ts +103 -0
  444. package/sdk/src/query/check-gates.ts +112 -0
  445. package/sdk/src/query/check-ship-ready.test.ts +77 -0
  446. package/sdk/src/query/check-ship-ready.ts +103 -0
  447. package/sdk/src/query/check-verification-status.test.ts +143 -0
  448. package/sdk/src/query/check-verification-status.ts +160 -0
  449. package/sdk/src/query/commit.test.ts +202 -0
  450. package/sdk/src/query/commit.ts +301 -0
  451. package/sdk/src/query/config-gates.test.ts +89 -0
  452. package/sdk/src/query/config-gates.ts +69 -0
  453. package/sdk/src/query/config-mutation.test.ts +365 -0
  454. package/sdk/src/query/config-mutation.ts +497 -0
  455. package/sdk/src/query/config-query.test.ts +161 -0
  456. package/sdk/src/query/config-query.ts +190 -0
  457. package/sdk/src/query/context-history.test.ts +165 -0
  458. package/sdk/src/query/context-history.ts +467 -0
  459. package/sdk/src/query/decomposed-handlers.test.ts +365 -0
  460. package/sdk/src/query/detect-custom-files.ts +97 -0
  461. package/sdk/src/query/detect-phase-type.test.ts +105 -0
  462. package/sdk/src/query/detect-phase-type.ts +141 -0
  463. package/sdk/src/query/docs-init.ts +257 -0
  464. package/sdk/src/query/failure-capture.ts +58 -0
  465. package/sdk/src/query/frontmatter-array.test.ts +14 -0
  466. package/sdk/src/query/frontmatter-mutation.test.ts +259 -0
  467. package/sdk/src/query/frontmatter-mutation.ts +343 -0
  468. package/sdk/src/query/frontmatter.test.ts +281 -0
  469. package/sdk/src/query/frontmatter.ts +397 -0
  470. package/sdk/src/query/helpers.test.ts +426 -0
  471. package/sdk/src/query/helpers.ts +482 -0
  472. package/sdk/src/query/index.ts +586 -0
  473. package/sdk/src/query/init-complex.test.ts +232 -0
  474. package/sdk/src/query/init-complex.ts +578 -0
  475. package/sdk/src/query/init.test.ts +522 -0
  476. package/sdk/src/query/init.ts +1046 -0
  477. package/sdk/src/query/intel.test.ts +90 -0
  478. package/sdk/src/query/intel.ts +404 -0
  479. package/sdk/src/query/normalize-query-command.test.ts +50 -0
  480. package/sdk/src/query/normalize-query-command.ts +56 -0
  481. package/sdk/src/query/phase-lifecycle.test.ts +1126 -0
  482. package/sdk/src/query/phase-lifecycle.ts +1799 -0
  483. package/sdk/src/query/phase-list-queries.test.ts +88 -0
  484. package/sdk/src/query/phase-list-queries.ts +152 -0
  485. package/sdk/src/query/phase-ready.test.ts +65 -0
  486. package/sdk/src/query/phase-ready.ts +158 -0
  487. package/sdk/src/query/phase.test.ts +307 -0
  488. package/sdk/src/query/phase.ts +340 -0
  489. package/sdk/src/query/pipeline.test.ts +169 -0
  490. package/sdk/src/query/pipeline.ts +243 -0
  491. package/sdk/src/query/plan-execution-route.test.ts +166 -0
  492. package/sdk/src/query/plan-execution-route.ts +209 -0
  493. package/sdk/src/query/plan-task-structure.test.ts +65 -0
  494. package/sdk/src/query/plan-task-structure.ts +63 -0
  495. package/sdk/src/query/profile-extract-messages.ts +247 -0
  496. package/sdk/src/query/profile-output.ts +908 -0
  497. package/sdk/src/query/profile-questionnaire-data.ts +181 -0
  498. package/sdk/src/query/profile-sample.ts +184 -0
  499. package/sdk/src/query/profile-scan-sessions.ts +174 -0
  500. package/sdk/src/query/profile.test.ts +74 -0
  501. package/sdk/src/query/profile.ts +337 -0
  502. package/sdk/src/query/progress.test.ts +156 -0
  503. package/sdk/src/query/progress.ts +566 -0
  504. package/sdk/src/query/registry.test.ts +216 -0
  505. package/sdk/src/query/registry.ts +174 -0
  506. package/sdk/src/query/requirements-extract-from-plans.test.ts +58 -0
  507. package/sdk/src/query/requirements-extract-from-plans.ts +86 -0
  508. package/sdk/src/query/roadmap-update-plan-progress.ts +132 -0
  509. package/sdk/src/query/roadmap.test.ts +359 -0
  510. package/sdk/src/query/roadmap.ts +591 -0
  511. package/sdk/src/query/route-next-action.test.ts +61 -0
  512. package/sdk/src/query/route-next-action.ts +345 -0
  513. package/sdk/src/query/runtime-health.ts +7 -0
  514. package/sdk/src/query/schema-detect.ts +189 -0
  515. package/sdk/src/query/skill-manifest.ts +214 -0
  516. package/sdk/src/query/skills.test.ts +80 -0
  517. package/sdk/src/query/skills.ts +62 -0
  518. package/sdk/src/query/state-mutation.test.ts +450 -0
  519. package/sdk/src/query/state-mutation.ts +1444 -0
  520. package/sdk/src/query/state-project-load.ts +109 -0
  521. package/sdk/src/query/state.test.ts +347 -0
  522. package/sdk/src/query/state.ts +397 -0
  523. package/sdk/src/query/summary.test.ts +95 -0
  524. package/sdk/src/query/summary.ts +296 -0
  525. package/sdk/src/query/template.test.ts +180 -0
  526. package/sdk/src/query/template.ts +242 -0
  527. package/sdk/src/query/uat.test.ts +77 -0
  528. package/sdk/src/query/uat.ts +314 -0
  529. package/sdk/src/query/utils.test.ts +82 -0
  530. package/sdk/src/query/utils.ts +92 -0
  531. package/sdk/src/query/validate.test.ts +656 -0
  532. package/sdk/src/query/validate.ts +807 -0
  533. package/sdk/src/query/verify.test.ts +414 -0
  534. package/sdk/src/query/verify.ts +645 -0
  535. package/sdk/src/query/websearch.test.ts +31 -0
  536. package/sdk/src/query/websearch.ts +82 -0
  537. package/sdk/src/query/workspace.test.ts +119 -0
  538. package/sdk/src/query/workspace.ts +131 -0
  539. package/sdk/src/query/workstream.test.ts +51 -0
  540. package/sdk/src/query/workstream.ts +434 -0
  541. package/sdk/src/research-gate.test.ts +190 -0
  542. package/sdk/src/research-gate.ts +94 -0
  543. package/sdk/src/runtime-health.test.ts +176 -0
  544. package/sdk/src/runtime-health.ts +387 -0
  545. package/sdk/src/session-runner.test.ts +98 -0
  546. package/sdk/src/session-runner.ts +299 -0
  547. package/sdk/src/tool-scoping.test.ts +160 -0
  548. package/sdk/src/tool-scoping.ts +61 -0
  549. package/sdk/src/types.ts +917 -0
  550. package/sdk/src/workstream-utils.ts +33 -0
  551. package/sdk/src/ws-flag.test.ts +285 -0
  552. package/sdk/src/ws-transport.test.ts +161 -0
  553. package/sdk/src/ws-transport.ts +93 -0
  554. package/sdk/tsconfig.json +20 -0
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Unit tests for `check.auto-mode` (decision-routing audit §3.5).
3
+ */
4
+
5
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
6
+ import { mkdir, writeFile, rm } from 'node:fs/promises';
7
+ import { join } from 'node:path';
8
+ import { tmpdir } from 'node:os';
9
+ import { checkAutoMode } from './check-auto-mode.js';
10
+
11
+ describe('checkAutoMode', () => {
12
+ let projectDir: string;
13
+
14
+ beforeEach(async () => {
15
+ projectDir = join(tmpdir(), `gsd-auto-mode-${Date.now()}-${Math.random().toString(36).slice(2)}`);
16
+ await mkdir(join(projectDir, '.planning'), { recursive: true });
17
+ });
18
+
19
+ afterEach(async () => {
20
+ await rm(projectDir, { recursive: true, force: true });
21
+ });
22
+
23
+ it('returns defaults when config.json is missing', async () => {
24
+ const { data } = await checkAutoMode([], projectDir);
25
+ expect(data).toEqual({
26
+ active: false,
27
+ source: 'none',
28
+ auto_chain_active: false,
29
+ auto_advance: false,
30
+ });
31
+ });
32
+
33
+ it('active true when only auto_advance is set', async () => {
34
+ await writeFile(
35
+ join(projectDir, '.planning', 'config.json'),
36
+ JSON.stringify({ workflow: { auto_advance: true } }),
37
+ 'utf-8',
38
+ );
39
+ const { data } = await checkAutoMode([], projectDir);
40
+ expect(data).toMatchObject({
41
+ active: true,
42
+ source: 'auto_advance',
43
+ auto_advance: true,
44
+ auto_chain_active: false,
45
+ });
46
+ });
47
+
48
+ it('active true when only _auto_chain_active is set', async () => {
49
+ await writeFile(
50
+ join(projectDir, '.planning', 'config.json'),
51
+ JSON.stringify({ workflow: { _auto_chain_active: true } }),
52
+ 'utf-8',
53
+ );
54
+ const { data } = await checkAutoMode([], projectDir);
55
+ expect(data).toMatchObject({
56
+ active: true,
57
+ source: 'auto_chain',
58
+ auto_advance: false,
59
+ auto_chain_active: true,
60
+ });
61
+ });
62
+
63
+ it('uses source both when both flags are true', async () => {
64
+ await writeFile(
65
+ join(projectDir, '.planning', 'config.json'),
66
+ JSON.stringify({ workflow: { auto_advance: true, _auto_chain_active: true } }),
67
+ 'utf-8',
68
+ );
69
+ const { data } = await checkAutoMode([], projectDir);
70
+ expect(data).toMatchObject({
71
+ active: true,
72
+ source: 'both',
73
+ auto_advance: true,
74
+ auto_chain_active: true,
75
+ });
76
+ });
77
+ });
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Consolidated auto-advance flags (`check.auto-mode`).
3
+ *
4
+ * Replaces paired `config-get workflow.auto_advance` + `config-get workflow._auto_chain_active`
5
+ * for checkpoint and auto-advance gates. See `.planning/research/decision-routing-audit.md` §3.5.
6
+ *
7
+ * Semantics match `execute-phase.md`: automation applies when **either** the ephemeral chain flag
8
+ * or the persistent user preference is true (`active === true`).
9
+ */
10
+
11
+ import { CONFIG_DEFAULTS, loadConfig } from '../config.js';
12
+ import type { QueryHandler } from './utils.js';
13
+
14
+ export type AutoModeSource = 'auto_chain' | 'auto_advance' | 'both' | 'none';
15
+
16
+ function resolveSource(
17
+ autoChainActive: boolean,
18
+ autoAdvance: boolean,
19
+ ): { active: boolean; source: AutoModeSource } {
20
+ if (autoChainActive && autoAdvance) {
21
+ return { active: true, source: 'both' };
22
+ }
23
+ if (autoChainActive) {
24
+ return { active: true, source: 'auto_chain' };
25
+ }
26
+ if (autoAdvance) {
27
+ return { active: true, source: 'auto_advance' };
28
+ }
29
+ return { active: false, source: 'none' };
30
+ }
31
+
32
+ export const checkAutoMode: QueryHandler = async (_args, projectDir) => {
33
+ const config = await loadConfig(projectDir);
34
+ const wf: Record<string, unknown> = {
35
+ ...CONFIG_DEFAULTS.workflow,
36
+ ...(config.workflow as unknown as Record<string, unknown>),
37
+ };
38
+ const autoAdvance = Boolean(wf.auto_advance ?? false);
39
+ const autoChainActive = Boolean(wf._auto_chain_active ?? false);
40
+ const { active, source } = resolveSource(autoChainActive, autoAdvance);
41
+
42
+ return {
43
+ data: {
44
+ active,
45
+ source,
46
+ auto_chain_active: autoChainActive,
47
+ auto_advance: autoAdvance,
48
+ },
49
+ };
50
+ };
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Unit tests for `check.completion` (decision-routing audit §3.7).
3
+ */
4
+
5
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
6
+ import { mkdir, writeFile, rm } from 'node:fs/promises';
7
+ import { join } from 'node:path';
8
+ import { tmpdir } from 'node:os';
9
+ import { checkCompletion } from './check-completion.js';
10
+
11
+ describe('checkCompletion', () => {
12
+ let projectDir: string;
13
+
14
+ beforeEach(async () => {
15
+ projectDir = join(tmpdir(), `gsd-check-completion-${Date.now()}-${Math.random().toString(36).slice(2)}`);
16
+ await mkdir(join(projectDir, '.planning', 'phases'), { recursive: true });
17
+ });
18
+
19
+ afterEach(async () => {
20
+ await rm(projectDir, { recursive: true, force: true });
21
+ });
22
+
23
+ it('throws when scope arg is missing', async () => {
24
+ await expect(checkCompletion([], projectDir)).rejects.toThrow();
25
+ });
26
+
27
+ it('throws when scope is invalid', async () => {
28
+ await expect(checkCompletion(['invalid', '1'], projectDir)).rejects.toThrow();
29
+ });
30
+
31
+ it('throws when phase number is missing for phase scope', async () => {
32
+ await expect(checkCompletion(['phase'], projectDir)).rejects.toThrow();
33
+ });
34
+
35
+ describe('phase scope', () => {
36
+ it('returns complete true when all plans have summaries', async () => {
37
+ const phaseDir = join(projectDir, '.planning', 'phases', '01-foundation');
38
+ await mkdir(phaseDir, { recursive: true });
39
+ await writeFile(join(phaseDir, '01-01-PLAN.md'), '---\nphase: 1\n---\n', 'utf-8');
40
+ await writeFile(join(phaseDir, '01-02-PLAN.md'), '---\nphase: 1\n---\n', 'utf-8');
41
+ await writeFile(join(phaseDir, '01-01-SUMMARY.md'), '# Summary', 'utf-8');
42
+ await writeFile(join(phaseDir, '01-02-SUMMARY.md'), '# Summary', 'utf-8');
43
+
44
+ const { data } = await checkCompletion(['phase', '1'], projectDir);
45
+ const d = data as Record<string, unknown>;
46
+ expect(d.complete).toBe(true);
47
+ expect(d.plans_total).toBe(2);
48
+ expect(d.plans_with_summaries).toBe(2);
49
+ expect((d.missing_summaries as string[]).length).toBe(0);
50
+ });
51
+
52
+ it('returns complete false when not all plans have summaries', async () => {
53
+ const phaseDir = join(projectDir, '.planning', 'phases', '02-core');
54
+ await mkdir(phaseDir, { recursive: true });
55
+ await writeFile(join(phaseDir, '02-01-PLAN.md'), '---\nphase: 2\n---\n', 'utf-8');
56
+ await writeFile(join(phaseDir, '02-02-PLAN.md'), '---\nphase: 2\n---\n', 'utf-8');
57
+ await writeFile(join(phaseDir, '02-01-SUMMARY.md'), '# Summary', 'utf-8');
58
+
59
+ const { data } = await checkCompletion(['phase', '2'], projectDir);
60
+ const d = data as Record<string, unknown>;
61
+ expect(d.complete).toBe(false);
62
+ expect(d.plans_total).toBe(2);
63
+ expect(d.plans_with_summaries).toBe(1);
64
+ expect((d.missing_summaries as string[]).length).toBe(1);
65
+ });
66
+
67
+ it('includes debt rollup fields', async () => {
68
+ const phaseDir = join(projectDir, '.planning', 'phases', '03-api');
69
+ await mkdir(phaseDir, { recursive: true });
70
+
71
+ const { data } = await checkCompletion(['phase', '3'], projectDir);
72
+ const d = data as Record<string, unknown>;
73
+ const debt = d.debt as Record<string, unknown>;
74
+ expect(debt).toBeDefined();
75
+ expect(typeof debt.uat_gaps).toBe('number');
76
+ expect(typeof debt.verification_failures).toBe('number');
77
+ expect(typeof debt.human_needed).toBe('boolean');
78
+ });
79
+
80
+ it('returns verification_status from VERIFICATION.md when present', async () => {
81
+ const phaseDir = join(projectDir, '.planning', 'phases', '04-ui');
82
+ await mkdir(phaseDir, { recursive: true });
83
+ await writeFile(join(phaseDir, '04-01-PLAN.md'), '---\nphase: 4\n---\n', 'utf-8');
84
+ await writeFile(join(phaseDir, '04-01-SUMMARY.md'), '# Summary', 'utf-8');
85
+ await writeFile(
86
+ join(phaseDir, 'VERIFICATION.md'),
87
+ '---\nstatus: passed\n---\n\n| ID | Description | Status |\n|---|---|---|\n| T-01 | Auth works | PASS |',
88
+ 'utf-8',
89
+ );
90
+
91
+ const { data } = await checkCompletion(['phase', '4'], projectDir);
92
+ const d = data as Record<string, unknown>;
93
+ expect(d.verification_status).not.toBeNull();
94
+ });
95
+ });
96
+
97
+ describe('milestone scope', () => {
98
+ it('returns milestone completion fields', async () => {
99
+ await writeFile(
100
+ join(projectDir, '.planning', 'ROADMAP.md'),
101
+ '# Roadmap\n\n## Phase 01: Foundation\n\n## Phase 02: Core\n',
102
+ 'utf-8',
103
+ );
104
+
105
+ const { data } = await checkCompletion(['milestone', 'v1.0'], projectDir);
106
+ const d = data as Record<string, unknown>;
107
+ expect(typeof d.complete).toBe('boolean');
108
+ expect(typeof d.phase_count).toBe('number');
109
+ expect(typeof d.phases_complete).toBe('number');
110
+ expect(Array.isArray(d.phases_incomplete)).toBe(true);
111
+ });
112
+ });
113
+ });
@@ -0,0 +1,182 @@
1
+ /**
2
+ * Phase or milestone completion rollup (`check.completion`).
3
+ *
4
+ * Replaces repeated PLAN/SUMMARY counting and verification checks in
5
+ * `transition.md`, `complete-milestone.md`, `execute-phase.md`.
6
+ * See `.planning/research/decision-routing-audit.md` §3.7.
7
+ */
8
+
9
+ import { existsSync } from 'node:fs';
10
+ import { readFile, readdir } from 'node:fs/promises';
11
+ import { join } from 'node:path';
12
+ import { GSDError, ErrorClassification } from '../errors.js';
13
+ import { normalizePhaseName, planningPaths } from './helpers.js';
14
+ import { findPhase } from './phase.js';
15
+ import { roadmapAnalyze } from './roadmap.js';
16
+ import type { QueryHandler } from './utils.js';
17
+
18
+ const VALID_SCOPES = new Set(['phase', 'milestone']);
19
+
20
+ // ─── Helpers ───────────────────────────────────────────────────────────────
21
+
22
+ function countFailLines(content: string): number {
23
+ return (content.match(/\|\s*FAIL\s*\|/gi) || []).length;
24
+ }
25
+
26
+ async function readFileSafe(filePath: string): Promise<string | null> {
27
+ try {
28
+ return await readFile(filePath, 'utf-8');
29
+ } catch {
30
+ return null;
31
+ }
32
+ }
33
+
34
+ function deriveVerificationStatus(content: string | null): string | null {
35
+ if (!content) return null;
36
+ const failCount = countFailLines(content);
37
+ if (failCount > 0) return 'fail';
38
+ const passMatch = content.match(/\|\s*PASS\s*\|/gi);
39
+ if (passMatch && passMatch.length > 0) return 'pass';
40
+ // Frontmatter status field fallback
41
+ const statusMatch = content.match(/^status:\s*(\S+)/im);
42
+ if (statusMatch) return statusMatch[1].toLowerCase();
43
+ return 'missing';
44
+ }
45
+
46
+ function deriveUatStatus(content: string | null): string | null {
47
+ if (!content) return null;
48
+ const failCount = (content.match(/\|\s*FAIL\s*\|/gi) || []).length;
49
+ if (failCount > 0) return 'fail';
50
+ return 'pass';
51
+ }
52
+
53
+ // ─── Phase scope ───────────────────────────────────────────────────────────
54
+
55
+ async function checkPhaseCompletion(phaseArg: string, projectDir: string): Promise<Record<string, unknown>> {
56
+ const phaseRes = await findPhase([phaseArg], projectDir);
57
+ const pdata = phaseRes.data as Record<string, unknown>;
58
+ const found = Boolean(pdata.found);
59
+
60
+ const plans = (pdata.plans as string[] | undefined) ?? [];
61
+ const summaries = (pdata.summaries as string[] | undefined) ?? [];
62
+ const plans_total = plans.length;
63
+
64
+ // Derive which plans are missing a summary
65
+ const summaryIds = new Set(
66
+ summaries
67
+ .map(s => s.replace('-SUMMARY.md', '').replace('SUMMARY.md', ''))
68
+ .filter(Boolean),
69
+ );
70
+ const plans_with_summaries = plans.filter(p => {
71
+ const planId = p.replace('-PLAN.md', '').replace('PLAN.md', '');
72
+ return summaryIds.has(planId);
73
+ }).length;
74
+ const missing_summaries = plans
75
+ .filter(p => {
76
+ const planId = p.replace('-PLAN.md', '').replace('PLAN.md', '');
77
+ return !summaryIds.has(planId);
78
+ });
79
+
80
+ // Read VERIFICATION.md and UAT.md if phase was found
81
+ let verificationContent: string | null = null;
82
+ let uatContent: string | null = null;
83
+
84
+ if (found && pdata.directory) {
85
+ const phaseDirFull = join(projectDir, pdata.directory as string);
86
+ if (existsSync(phaseDirFull)) {
87
+ try {
88
+ const files = (await readdir(phaseDirFull)).sort((a, b) => a.localeCompare(b));
89
+ const verFile = files.includes('VERIFICATION.md')
90
+ ? 'VERIFICATION.md'
91
+ : files.find(f => f.endsWith('-VERIFICATION.md'));
92
+ const uatFile = files.includes('UAT.md') ? 'UAT.md' : files.find(f => f.endsWith('-UAT.md'));
93
+ if (verFile) verificationContent = await readFileSafe(join(phaseDirFull, verFile));
94
+ if (uatFile) uatContent = await readFileSafe(join(phaseDirFull, uatFile));
95
+ } catch {
96
+ // Phase dir unreadable — treat as no files
97
+ }
98
+ }
99
+ }
100
+
101
+ const verification_status = deriveVerificationStatus(verificationContent);
102
+ const uat_status = deriveUatStatus(uatContent);
103
+
104
+ const uat_gaps = uatContent ? countFailLines(uatContent) : 0;
105
+ const verification_failures = verificationContent ? countFailLines(verificationContent) : 0;
106
+
107
+ const complete =
108
+ plans_total > 0 &&
109
+ missing_summaries.length === 0 &&
110
+ verification_status !== 'fail';
111
+
112
+ return {
113
+ complete,
114
+ plans_total,
115
+ plans_with_summaries,
116
+ missing_summaries,
117
+ verification_status,
118
+ uat_status,
119
+ debt: {
120
+ uat_gaps,
121
+ verification_failures,
122
+ human_needed: false,
123
+ },
124
+ };
125
+ }
126
+
127
+ // ─── Milestone scope ───────────────────────────────────────────────────────
128
+
129
+ async function checkMilestoneCompletion(projectDir: string): Promise<Record<string, unknown>> {
130
+ const analysis = await roadmapAnalyze([], projectDir);
131
+ const adata = analysis.data as { phases?: Array<Record<string, unknown>> };
132
+ const phases = adata.phases ?? [];
133
+
134
+ const phase_count = phases.length;
135
+ const completePhases = phases.filter(
136
+ p => p.roadmap_complete === true || p.disk_status === 'complete',
137
+ );
138
+ const phases_complete = completePhases.length;
139
+ const phases_incomplete = phases
140
+ .filter(p => p.roadmap_complete !== true && p.disk_status !== 'complete')
141
+ .map(p => String(normalizePhaseName(String(p.number))));
142
+
143
+ const blockers: string[] = [];
144
+
145
+ const complete = phase_count > 0 && phases_complete === phase_count;
146
+
147
+ return {
148
+ complete,
149
+ phase_count,
150
+ phases_complete,
151
+ phases_incomplete,
152
+ blockers,
153
+ };
154
+ }
155
+
156
+ // ─── Handler ───────────────────────────────────────────────────────────────
157
+
158
+ export const checkCompletion: QueryHandler = async (args, projectDir) => {
159
+ const scope = args[0];
160
+ if (!scope) {
161
+ throw new GSDError('scope required for check completion (phase|milestone)', ErrorClassification.Validation);
162
+ }
163
+ if (!VALID_SCOPES.has(scope)) {
164
+ throw new GSDError(
165
+ `invalid scope "${scope}" — must be "phase" or "milestone"`,
166
+ ErrorClassification.Validation,
167
+ );
168
+ }
169
+
170
+ if (scope === 'phase') {
171
+ const phaseNum = args[1];
172
+ if (!phaseNum) {
173
+ throw new GSDError('phase number required for check completion phase', ErrorClassification.Validation);
174
+ }
175
+ const result = await checkPhaseCompletion(phaseNum, projectDir);
176
+ return { data: result };
177
+ }
178
+
179
+ // milestone scope
180
+ const result = await checkMilestoneCompletion(projectDir);
181
+ return { data: result };
182
+ };
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Unit tests for `check.gates` (decision-routing audit §3.2).
3
+ */
4
+
5
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
6
+ import { mkdir, writeFile, rm } from 'node:fs/promises';
7
+ import { join } from 'node:path';
8
+ import { tmpdir } from 'node:os';
9
+ import { checkGates } from './check-gates.js';
10
+
11
+ describe('checkGates', () => {
12
+ let projectDir: string;
13
+
14
+ beforeEach(async () => {
15
+ projectDir = join(tmpdir(), `gsd-check-gates-${Date.now()}-${Math.random().toString(36).slice(2)}`);
16
+ await mkdir(join(projectDir, '.planning', 'phases'), { recursive: true });
17
+ // Write a clean STATE.md
18
+ await writeFile(
19
+ join(projectDir, '.planning', 'STATE.md'),
20
+ '---\nstatus: active\n---\n\n# Project State\n\nStatus: active\n',
21
+ 'utf-8',
22
+ );
23
+ });
24
+
25
+ afterEach(async () => {
26
+ await rm(projectDir, { recursive: true, force: true });
27
+ });
28
+
29
+ it('throws when workflow name arg is missing', async () => {
30
+ await expect(checkGates([], projectDir)).rejects.toThrow();
31
+ });
32
+
33
+ it('returns passed true when no blockers exist', async () => {
34
+ const { data } = await checkGates(['execute-phase'], projectDir);
35
+ const d = data as Record<string, unknown>;
36
+ expect(d.passed).toBe(true);
37
+ expect(d.blockers).toEqual([]);
38
+ });
39
+
40
+ it('returns blocker when .continue-here.md is present in root', async () => {
41
+ await writeFile(join(projectDir, '.continue-here.md'), '# Continue here', 'utf-8');
42
+
43
+ const { data } = await checkGates(['execute-phase'], projectDir);
44
+ const d = data as Record<string, unknown>;
45
+ expect(d.passed).toBe(false);
46
+ const blockers = d.blockers as Array<Record<string, unknown>>;
47
+ expect(blockers.length).toBeGreaterThan(0);
48
+ expect(blockers[0].gate).toBe('continue-here');
49
+ expect(blockers[0].severity).toBe('blocking');
50
+ });
51
+
52
+ it('returns blocker when STATE.md has status: failed', async () => {
53
+ await writeFile(
54
+ join(projectDir, '.planning', 'STATE.md'),
55
+ '---\nstatus: failed\n---\n\n# Project State\n',
56
+ 'utf-8',
57
+ );
58
+
59
+ const { data } = await checkGates(['execute-phase'], projectDir);
60
+ const d = data as Record<string, unknown>;
61
+ expect(d.passed).toBe(false);
62
+ const blockers = d.blockers as Array<Record<string, unknown>>;
63
+ const stateBlocker = blockers.find(b => b.gate === 'state-error');
64
+ expect(stateBlocker).toBeDefined();
65
+ });
66
+
67
+ it('returns blocker when STATE.md has status: error', async () => {
68
+ await writeFile(
69
+ join(projectDir, '.planning', 'STATE.md'),
70
+ '---\nstatus: error\n---\n\n# Project State\n',
71
+ 'utf-8',
72
+ );
73
+
74
+ const { data } = await checkGates(['execute-phase'], projectDir);
75
+ const d = data as Record<string, unknown>;
76
+ expect(d.passed).toBe(false);
77
+ const blockers = d.blockers as Array<Record<string, unknown>>;
78
+ const stateBlocker = blockers.find(b => b.gate === 'state-error');
79
+ expect(stateBlocker).toBeDefined();
80
+ });
81
+
82
+ it('includes warnings shape in result', async () => {
83
+ const { data } = await checkGates(['execute-phase'], projectDir);
84
+ const d = data as Record<string, unknown>;
85
+ expect(Array.isArray(d.warnings)).toBe(true);
86
+ });
87
+
88
+ it('returns verification-debt warning when phase VERIFICATION.md has FAIL rows', async () => {
89
+ const phaseDir = join(projectDir, '.planning', 'phases', '01-foundation');
90
+ await mkdir(phaseDir, { recursive: true });
91
+ await writeFile(
92
+ join(phaseDir, 'VERIFICATION.md'),
93
+ '| T-01 | Auth works | FAIL |\n| T-02 | User model | PASS |\n',
94
+ 'utf-8',
95
+ );
96
+
97
+ const { data } = await checkGates(['execute-phase', '--phase', '1'], projectDir);
98
+ const d = data as Record<string, unknown>;
99
+ const warnings = d.warnings as Array<Record<string, unknown>>;
100
+ const debtWarning = warnings.find(w => w.gate === 'verification-debt');
101
+ expect(debtWarning).toBeDefined();
102
+ });
103
+ });
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Safety gate consolidation (`check.gates`).
3
+ *
4
+ * Checks blocking conditions before proceeding with a workflow — replaces
5
+ * per-workflow gate logic in `next.md`, `execute-phase.md`, `discuss-phase.md`.
6
+ * See `.planning/research/decision-routing-audit.md` §3.2.
7
+ */
8
+
9
+ import { readFile } from 'node:fs/promises';
10
+ import { existsSync } from 'node:fs';
11
+ import { join } from 'node:path';
12
+ import { GSDError, ErrorClassification } from '../errors.js';
13
+ import { normalizePhaseName, planningPaths } from './helpers.js';
14
+ import { findPhase } from './phase.js';
15
+ import type { QueryHandler } from './utils.js';
16
+
17
+ interface Blocker {
18
+ gate: string;
19
+ file: string;
20
+ severity: 'blocking';
21
+ anti_patterns: string[];
22
+ }
23
+
24
+ interface Warning {
25
+ gate: string;
26
+ phase: string;
27
+ items: string[];
28
+ message: string;
29
+ }
30
+
31
+ async function readFileSafe(filePath: string): Promise<string | null> {
32
+ try {
33
+ return await readFile(filePath, 'utf-8');
34
+ } catch {
35
+ return null;
36
+ }
37
+ }
38
+
39
+ export const checkGates: QueryHandler = async (args, projectDir) => {
40
+ const workflow = args[0];
41
+ if (!workflow) {
42
+ throw new GSDError('workflow name required for check gates', ErrorClassification.Validation);
43
+ }
44
+
45
+ // Parse optional --phase flag
46
+ let phaseNum: string | null = null;
47
+ const phaseIdx = args.indexOf('--phase');
48
+ if (phaseIdx !== -1 && args[phaseIdx + 1]) {
49
+ phaseNum = args[phaseIdx + 1];
50
+ }
51
+
52
+ const blockers: Blocker[] = [];
53
+ const warnings: Warning[] = [];
54
+ const paths = planningPaths(projectDir);
55
+
56
+ // Gate 1: .continue-here.md in project root
57
+ const continueHerePath = join(projectDir, '.continue-here.md');
58
+ if (existsSync(continueHerePath)) {
59
+ blockers.push({
60
+ gate: 'continue-here',
61
+ file: '.continue-here.md',
62
+ severity: 'blocking',
63
+ anti_patterns: ['continue-here.md present — another session may be in progress'],
64
+ });
65
+ }
66
+
67
+ // Gate 2: STATE.md error/failed status
68
+ const stateContent = await readFileSafe(paths.state);
69
+ if (stateContent) {
70
+ const hasErrorStatus =
71
+ /^status:\s*(error|failed)/im.test(stateContent) ||
72
+ /##\s*Error/i.test(stateContent);
73
+ if (hasErrorStatus) {
74
+ blockers.push({
75
+ gate: 'state-error',
76
+ file: '.planning/STATE.md',
77
+ severity: 'blocking',
78
+ anti_patterns: ['STATE.md status is error/failed'],
79
+ });
80
+ }
81
+ }
82
+
83
+ // Gate 3: Verification debt — check VERIFICATION.md in phase dir if phase provided
84
+ if (phaseNum) {
85
+ const phaseRes = await findPhase([phaseNum], projectDir);
86
+ const pdata = phaseRes.data as Record<string, unknown>;
87
+ if (pdata.found && pdata.directory) {
88
+ const phaseDirFull = join(projectDir, pdata.directory as string);
89
+ const verPath = join(phaseDirFull, 'VERIFICATION.md');
90
+ const verContent = await readFileSafe(verPath);
91
+ if (verContent) {
92
+ const failLines = verContent.match(/\|\s*FAIL\s*\|[^\n]*/gi) || [];
93
+ if (failLines.length > 0) {
94
+ warnings.push({
95
+ gate: 'verification-debt',
96
+ phase: normalizePhaseName(phaseNum),
97
+ items: failLines.map(l => `FAIL: ${l.trim()}`),
98
+ message: `${failLines.length} FAIL row(s) in VERIFICATION.md`,
99
+ });
100
+ }
101
+ }
102
+ }
103
+ }
104
+
105
+ return {
106
+ data: {
107
+ passed: blockers.length === 0,
108
+ blockers,
109
+ warnings,
110
+ },
111
+ };
112
+ };