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,656 @@
1
+ /**
2
+ * Tests for validation query handlers — verifyKeyLinks, validateConsistency, validateHealth.
3
+ *
4
+ * Uses temp directories with fixture files to test verification logic.
5
+ */
6
+
7
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
8
+ import { mkdtemp, writeFile, mkdir, rm, readFile } from 'node:fs/promises';
9
+ import { join } from 'node:path';
10
+ import { tmpdir, homedir } from 'node:os';
11
+ import { GSDError } from '../errors.js';
12
+
13
+ import { verifyKeyLinks, validateConsistency, validateHealth, regexForKeyLinkPattern } from './validate.js';
14
+
15
+ // ─── regexForKeyLinkPattern ────────────────────────────────────────────────
16
+
17
+ describe('regexForKeyLinkPattern', () => {
18
+ it('preserves normal regex patterns used in key_links', () => {
19
+ const re = regexForKeyLinkPattern('import.*foo.*from.*target');
20
+ expect(re.test("import { foo } from './target.js';")).toBe(true);
21
+ });
22
+
23
+ it('falls back to literal match for nested-quantifier patterns', () => {
24
+ const re = regexForKeyLinkPattern('(a+)+');
25
+ expect(re.source).toContain('\\');
26
+ });
27
+ });
28
+
29
+ // ─── verifyKeyLinks ────────────────────────────────────────────────────────
30
+
31
+ describe('verifyKeyLinks', () => {
32
+ let tmpDir: string;
33
+
34
+ beforeEach(async () => {
35
+ tmpDir = await mkdtemp(join(tmpdir(), 'gsd-validate-'));
36
+ });
37
+
38
+ afterEach(async () => {
39
+ await rm(tmpDir, { recursive: true, force: true });
40
+ });
41
+
42
+ it('throws GSDError Validation when no args', async () => {
43
+ let caught: unknown;
44
+ try {
45
+ await verifyKeyLinks([], tmpDir);
46
+ } catch (err) {
47
+ caught = err;
48
+ }
49
+ expect(caught).toBeInstanceOf(GSDError);
50
+ expect((caught as GSDError).classification).toBe('validation');
51
+ });
52
+
53
+ it('returns all_verified true when pattern found in source', async () => {
54
+ // Create source file with an import statement
55
+ await writeFile(join(tmpDir, 'source.ts'), "import { foo } from './target.js';");
56
+ await writeFile(join(tmpDir, 'target.ts'), 'export const foo = 1;');
57
+
58
+ // Create plan with key_links
59
+ const planContent = `---
60
+ phase: 01
61
+ plan: 01
62
+ type: execute
63
+ wave: 1
64
+ depends_on: []
65
+ files_modified: []
66
+ autonomous: true
67
+
68
+ must_haves:
69
+ key_links:
70
+ - from: source.ts
71
+ to: target.ts
72
+ via: "import foo"
73
+ pattern: "import.*foo.*from.*target"
74
+ ---
75
+
76
+ # Plan
77
+ `;
78
+ await writeFile(join(tmpDir, 'plan.md'), planContent);
79
+
80
+ const result = await verifyKeyLinks(['plan.md'], tmpDir);
81
+ const data = result.data as Record<string, unknown>;
82
+ expect(data.all_verified).toBe(true);
83
+ expect(data.verified).toBe(1);
84
+ expect(data.total).toBe(1);
85
+ const links = data.links as Array<Record<string, unknown>>;
86
+ expect(links[0].detail).toBe('Pattern found in source');
87
+ });
88
+
89
+ it('returns verified true with "Pattern found in target" when not in source but in target', async () => {
90
+ await writeFile(join(tmpDir, 'source.ts'), 'const x = 1;');
91
+ await writeFile(join(tmpDir, 'target.ts'), "import { foo } from './other.js';");
92
+
93
+ const planContent = `---
94
+ phase: 01
95
+ plan: 01
96
+ type: execute
97
+ wave: 1
98
+ depends_on: []
99
+ files_modified: []
100
+ autonomous: true
101
+
102
+ must_haves:
103
+ key_links:
104
+ - from: source.ts
105
+ to: target.ts
106
+ via: "import foo"
107
+ pattern: "import.*foo"
108
+ ---
109
+
110
+ # Plan
111
+ `;
112
+ await writeFile(join(tmpDir, 'plan.md'), planContent);
113
+
114
+ const result = await verifyKeyLinks(['plan.md'], tmpDir);
115
+ const data = result.data as Record<string, unknown>;
116
+ const links = data.links as Array<Record<string, unknown>>;
117
+ expect(links[0].verified).toBe(true);
118
+ expect(links[0].detail).toBe('Pattern found in target');
119
+ });
120
+
121
+ it('returns verified false when pattern not found in source or target', async () => {
122
+ await writeFile(join(tmpDir, 'source.ts'), 'const x = 1;');
123
+ await writeFile(join(tmpDir, 'target.ts'), 'const y = 2;');
124
+
125
+ const planContent = `---
126
+ phase: 01
127
+ plan: 01
128
+ type: execute
129
+ wave: 1
130
+ depends_on: []
131
+ files_modified: []
132
+ autonomous: true
133
+
134
+ must_haves:
135
+ key_links:
136
+ - from: source.ts
137
+ to: target.ts
138
+ via: "import foo"
139
+ pattern: "import.*foo"
140
+ ---
141
+
142
+ # Plan
143
+ `;
144
+ await writeFile(join(tmpDir, 'plan.md'), planContent);
145
+
146
+ const result = await verifyKeyLinks(['plan.md'], tmpDir);
147
+ const data = result.data as Record<string, unknown>;
148
+ expect(data.all_verified).toBe(false);
149
+ const links = data.links as Array<Record<string, unknown>>;
150
+ expect(links[0].verified).toBe(false);
151
+ });
152
+
153
+ it('returns Source file not found when source missing', async () => {
154
+ await writeFile(join(tmpDir, 'target.ts'), 'export const foo = 1;');
155
+
156
+ const planContent = `---
157
+ phase: 01
158
+ plan: 01
159
+ type: execute
160
+ wave: 1
161
+ depends_on: []
162
+ files_modified: []
163
+ autonomous: true
164
+
165
+ must_haves:
166
+ key_links:
167
+ - from: missing.ts
168
+ to: target.ts
169
+ via: "import"
170
+ pattern: "import"
171
+ ---
172
+
173
+ # Plan
174
+ `;
175
+ await writeFile(join(tmpDir, 'plan.md'), planContent);
176
+
177
+ const result = await verifyKeyLinks(['plan.md'], tmpDir);
178
+ const data = result.data as Record<string, unknown>;
179
+ const links = data.links as Array<Record<string, unknown>>;
180
+ expect(links[0].detail).toBe('Source file not found');
181
+ expect(links[0].verified).toBe(false);
182
+ });
183
+
184
+ it('checks target reference in source when no pattern specified', async () => {
185
+ await writeFile(join(tmpDir, 'source.ts'), "import { foo } from './target.ts';");
186
+ await writeFile(join(tmpDir, 'target.ts'), 'export const foo = 1;');
187
+
188
+ const planContent = `---
189
+ phase: 01
190
+ plan: 01
191
+ type: execute
192
+ wave: 1
193
+ depends_on: []
194
+ files_modified: []
195
+ autonomous: true
196
+
197
+ must_haves:
198
+ key_links:
199
+ - from: source.ts
200
+ to: target.ts
201
+ via: "import"
202
+ ---
203
+
204
+ # Plan
205
+ `;
206
+ await writeFile(join(tmpDir, 'plan.md'), planContent);
207
+
208
+ const result = await verifyKeyLinks(['plan.md'], tmpDir);
209
+ const data = result.data as Record<string, unknown>;
210
+ const links = data.links as Array<Record<string, unknown>>;
211
+ expect(links[0].verified).toBe(true);
212
+ expect(links[0].detail).toBe('Target referenced in source');
213
+ });
214
+
215
+ it('reports invalid regex like gsd-tools.cjs (try/catch on new RegExp)', async () => {
216
+ await writeFile(join(tmpDir, 'source.ts'), 'const x = 1;');
217
+ await writeFile(join(tmpDir, 'target.ts'), 'const y = 2;');
218
+
219
+ const planContent = `---
220
+ phase: 01
221
+ plan: 01
222
+ type: execute
223
+ wave: 1
224
+ depends_on: []
225
+ files_modified: []
226
+ autonomous: true
227
+
228
+ must_haves:
229
+ key_links:
230
+ - from: source.ts
231
+ to: target.ts
232
+ via: "bad regex"
233
+ pattern: "[invalid"
234
+ ---
235
+
236
+ # Plan
237
+ `;
238
+ await writeFile(join(tmpDir, 'plan.md'), planContent);
239
+
240
+ const result = await verifyKeyLinks(['plan.md'], tmpDir);
241
+ const data = result.data as Record<string, unknown>;
242
+ const links = data.links as Array<Record<string, unknown>>;
243
+ expect(links[0].verified).toBe(false);
244
+ expect((links[0].detail as string)).toMatch(/Invalid regex pattern/);
245
+ });
246
+
247
+ it('returns error when no must_haves.key_links in plan', async () => {
248
+ const planContent = `---
249
+ phase: 01
250
+ plan: 01
251
+ type: execute
252
+ wave: 1
253
+ depends_on: []
254
+ files_modified: []
255
+ autonomous: true
256
+ ---
257
+
258
+ # Plan
259
+ `;
260
+ await writeFile(join(tmpDir, 'plan.md'), planContent);
261
+
262
+ const result = await verifyKeyLinks(['plan.md'], tmpDir);
263
+ const data = result.data as Record<string, unknown>;
264
+ expect(data.error).toBe('No must_haves.key_links found in frontmatter');
265
+ });
266
+ });
267
+
268
+ // ─── validateConsistency ──────────────────────────────────────────────────
269
+
270
+ describe('validateConsistency', () => {
271
+ let tmpDir: string;
272
+
273
+ beforeEach(async () => {
274
+ tmpDir = await mkdtemp(join(tmpdir(), 'gsd-consistency-'));
275
+ });
276
+
277
+ afterEach(async () => {
278
+ await rm(tmpDir, { recursive: true, force: true });
279
+ });
280
+
281
+ /** Helper: create a .planning directory structure */
282
+ async function createPlanning(opts: {
283
+ roadmap?: string;
284
+ phases?: Array<{ dir: string; plans?: string[]; summaries?: string[]; planContents?: Record<string, string> }>;
285
+ config?: Record<string, unknown>;
286
+ }): Promise<void> {
287
+ const planning = join(tmpDir, '.planning');
288
+ await mkdir(planning, { recursive: true });
289
+
290
+ if (opts.roadmap !== undefined) {
291
+ await writeFile(join(planning, 'ROADMAP.md'), opts.roadmap);
292
+ }
293
+
294
+ if (opts.config) {
295
+ await writeFile(join(planning, 'config.json'), JSON.stringify(opts.config));
296
+ }
297
+
298
+ if (opts.phases) {
299
+ const phasesDir = join(planning, 'phases');
300
+ await mkdir(phasesDir, { recursive: true });
301
+ for (const phase of opts.phases) {
302
+ const phaseDir = join(phasesDir, phase.dir);
303
+ await mkdir(phaseDir, { recursive: true });
304
+ if (phase.plans) {
305
+ for (const plan of phase.plans) {
306
+ const content = phase.planContents?.[plan] ?? `---\nphase: ${phase.dir}\nplan: 01\ntype: execute\nwave: 1\ndepends_on: []\nfiles_modified: []\nautonomous: true\n---\n\n# Plan\n`;
307
+ await writeFile(join(phaseDir, plan), content);
308
+ }
309
+ }
310
+ if (phase.summaries) {
311
+ for (const summary of phase.summaries) {
312
+ await writeFile(join(phaseDir, summary), '# Summary\n');
313
+ }
314
+ }
315
+ }
316
+ }
317
+ }
318
+
319
+ it('returns passed true when ROADMAP phases match disk', async () => {
320
+ await createPlanning({
321
+ roadmap: '# Roadmap\n\n## Phase 1: Foundation\n\nGoal here.\n\n## Phase 2: Features\n\nMore goals.\n',
322
+ phases: [
323
+ { dir: '01-foundation', plans: ['01-01-PLAN.md'], summaries: ['01-01-SUMMARY.md'] },
324
+ { dir: '02-features', plans: ['02-01-PLAN.md'], summaries: ['02-01-SUMMARY.md'] },
325
+ ],
326
+ config: { phase_naming: 'sequential' },
327
+ });
328
+
329
+ const result = await validateConsistency([], tmpDir);
330
+ const data = result.data as Record<string, unknown>;
331
+ expect(data.passed).toBe(true);
332
+ expect((data.errors as string[]).length).toBe(0);
333
+ expect((data.warnings as string[]).length).toBe(0);
334
+ });
335
+
336
+ it('warns when phase in ROADMAP but not on disk', async () => {
337
+ await createPlanning({
338
+ roadmap: '# Roadmap\n\n## Phase 1: Foundation\n\n## Phase 2: Features\n\n## Phase 3: Polish\n',
339
+ phases: [
340
+ { dir: '01-foundation', plans: ['01-01-PLAN.md'] },
341
+ { dir: '02-features', plans: ['02-01-PLAN.md'] },
342
+ ],
343
+ config: { phase_naming: 'sequential' },
344
+ });
345
+
346
+ const result = await validateConsistency([], tmpDir);
347
+ const data = result.data as Record<string, unknown>;
348
+ const warnings = data.warnings as string[];
349
+ expect(warnings.some(w => w.includes('Phase 3') && w.includes('ROADMAP') && w.includes('no directory'))).toBe(true);
350
+ });
351
+
352
+ it('warns when phase on disk but not in ROADMAP', async () => {
353
+ await createPlanning({
354
+ roadmap: '# Roadmap\n\n## Phase 1: Foundation\n',
355
+ phases: [
356
+ { dir: '01-foundation', plans: ['01-01-PLAN.md'] },
357
+ { dir: '02-features', plans: ['02-01-PLAN.md'] },
358
+ ],
359
+ config: { phase_naming: 'sequential' },
360
+ });
361
+
362
+ const result = await validateConsistency([], tmpDir);
363
+ const data = result.data as Record<string, unknown>;
364
+ const warnings = data.warnings as string[];
365
+ expect(warnings.some(w => w.includes('02') && w.includes('disk') && w.includes('not in ROADMAP'))).toBe(true);
366
+ });
367
+
368
+ it('warns on gap in sequential phase numbering', async () => {
369
+ await createPlanning({
370
+ roadmap: '# Roadmap\n\n## Phase 1: Foundation\n\n## Phase 3: Polish\n',
371
+ phases: [
372
+ { dir: '01-foundation', plans: ['01-01-PLAN.md'] },
373
+ { dir: '03-polish', plans: ['03-01-PLAN.md'] },
374
+ ],
375
+ config: { phase_naming: 'sequential' },
376
+ });
377
+
378
+ const result = await validateConsistency([], tmpDir);
379
+ const data = result.data as Record<string, unknown>;
380
+ const warnings = data.warnings as string[];
381
+ expect(warnings.some(w => w.includes('Gap in phase numbering'))).toBe(true);
382
+ });
383
+
384
+ it('warns on plan numbering gap within phase', async () => {
385
+ await createPlanning({
386
+ roadmap: '# Roadmap\n\n## Phase 1: Foundation\n',
387
+ phases: [
388
+ { dir: '01-foundation', plans: ['01-01-PLAN.md', '01-03-PLAN.md'] },
389
+ ],
390
+ config: { phase_naming: 'sequential' },
391
+ });
392
+
393
+ const result = await validateConsistency([], tmpDir);
394
+ const data = result.data as Record<string, unknown>;
395
+ const warnings = data.warnings as string[];
396
+ expect(warnings.some(w => w.includes('Gap in plan numbering'))).toBe(true);
397
+ });
398
+
399
+ it('warns on summary without matching plan', async () => {
400
+ await createPlanning({
401
+ roadmap: '# Roadmap\n\n## Phase 1: Foundation\n',
402
+ phases: [
403
+ { dir: '01-foundation', plans: ['01-01-PLAN.md'], summaries: ['01-01-SUMMARY.md', '01-02-SUMMARY.md'] },
404
+ ],
405
+ config: { phase_naming: 'sequential' },
406
+ });
407
+
408
+ const result = await validateConsistency([], tmpDir);
409
+ const data = result.data as Record<string, unknown>;
410
+ const warnings = data.warnings as string[];
411
+ expect(warnings.some(w => w.includes('Summary') && w.includes('no matching PLAN'))).toBe(true);
412
+ });
413
+
414
+ it('warns when plan missing wave in frontmatter', async () => {
415
+ const noWavePlan = `---\nphase: 01\nplan: 01\ntype: execute\ndepends_on: []\nfiles_modified: []\nautonomous: true\n---\n\n# Plan\n`;
416
+ await createPlanning({
417
+ roadmap: '# Roadmap\n\n## Phase 1: Foundation\n',
418
+ phases: [
419
+ { dir: '01-foundation', plans: ['01-01-PLAN.md'], planContents: { '01-01-PLAN.md': noWavePlan } },
420
+ ],
421
+ config: { phase_naming: 'sequential' },
422
+ });
423
+
424
+ const result = await validateConsistency([], tmpDir);
425
+ const data = result.data as Record<string, unknown>;
426
+ const warnings = data.warnings as string[];
427
+ expect(warnings.some(w => w.includes('wave') && w.includes('frontmatter'))).toBe(true);
428
+ });
429
+
430
+ it('returns passed false with error when ROADMAP.md missing', async () => {
431
+ await createPlanning({
432
+ phases: [{ dir: '01-foundation', plans: ['01-01-PLAN.md'] }],
433
+ config: { phase_naming: 'sequential' },
434
+ });
435
+
436
+ const result = await validateConsistency([], tmpDir);
437
+ const data = result.data as Record<string, unknown>;
438
+ expect(data.passed).toBe(false);
439
+ expect((data.errors as string[])).toContain('ROADMAP.md not found');
440
+ });
441
+ });
442
+
443
+ // ─── validateHealth ─────────────────────────────────────────────────────────
444
+
445
+ describe('validateHealth', () => {
446
+ let tmpDir: string;
447
+
448
+ beforeEach(async () => {
449
+ tmpDir = await mkdtemp(join(tmpdir(), 'gsd-health-'));
450
+ });
451
+
452
+ afterEach(async () => {
453
+ await rm(tmpDir, { recursive: true, force: true });
454
+ });
455
+
456
+ /** Helper: create a healthy .planning directory structure */
457
+ async function createHealthyPlanning(): Promise<void> {
458
+ const planning = join(tmpDir, '.planning');
459
+ await mkdir(join(planning, 'phases', '01-foundation'), { recursive: true });
460
+
461
+ await writeFile(join(planning, 'PROJECT.md'), '# Project\n\n## What This Is\n\nA project.\n\n## Core Value\n\nValue here.\n\n## Requirements\n\n- Req 1\n');
462
+ await writeFile(join(planning, 'ROADMAP.md'), '# Roadmap\n\n## Phase 1: Foundation\n\nGoals.\n');
463
+ await writeFile(join(planning, 'STATE.md'), '---\nstatus: executing\n---\n\n# State\n\n**Current Phase:** 1\n**Status:** executing\n');
464
+ await writeFile(join(planning, 'config.json'), JSON.stringify({
465
+ model_profile: 'balanced',
466
+ workflow: { nyquist_validation: true },
467
+ }, null, 2));
468
+
469
+ await writeFile(join(planning, 'phases', '01-foundation', '01-01-PLAN.md'), '---\nphase: 01\nplan: 01\ntype: execute\nwave: 1\ndepends_on: []\nfiles_modified: []\nautonomous: true\n---\n\n# Plan\n');
470
+ await writeFile(join(planning, 'phases', '01-foundation', '01-01-SUMMARY.md'), '# Summary\n');
471
+ }
472
+
473
+ it('returns healthy status when all files present', async () => {
474
+ await createHealthyPlanning();
475
+
476
+ const result = await validateHealth([], tmpDir);
477
+ const data = result.data as Record<string, unknown>;
478
+ expect(data.status).toBe('healthy');
479
+ expect((data.errors as unknown[]).length).toBe(0);
480
+ expect((data.warnings as unknown[]).length).toBe(0);
481
+ });
482
+
483
+ it('returns broken with E001 when no .planning/ directory', async () => {
484
+ // tmpDir has no .planning/ — already the case
485
+
486
+ const result = await validateHealth([], tmpDir);
487
+ const data = result.data as Record<string, unknown>;
488
+ expect(data.status).toBe('broken');
489
+ const errors = data.errors as Array<Record<string, unknown>>;
490
+ expect(errors.some(e => e.code === 'E001')).toBe(true);
491
+ });
492
+
493
+ it('returns error E002 when PROJECT.md missing', async () => {
494
+ await createHealthyPlanning();
495
+ const { unlink } = await import('node:fs/promises');
496
+ await unlink(join(tmpDir, '.planning', 'PROJECT.md'));
497
+
498
+ const result = await validateHealth([], tmpDir);
499
+ const data = result.data as Record<string, unknown>;
500
+ const errors = data.errors as Array<Record<string, unknown>>;
501
+ expect(errors.some(e => e.code === 'E002')).toBe(true);
502
+ });
503
+
504
+ it('returns error E003 when ROADMAP.md missing', async () => {
505
+ await createHealthyPlanning();
506
+ const { unlink } = await import('node:fs/promises');
507
+ await unlink(join(tmpDir, '.planning', 'ROADMAP.md'));
508
+
509
+ const result = await validateHealth([], tmpDir);
510
+ const data = result.data as Record<string, unknown>;
511
+ const errors = data.errors as Array<Record<string, unknown>>;
512
+ expect(errors.some(e => e.code === 'E003')).toBe(true);
513
+ });
514
+
515
+ it('returns error E004 when STATE.md missing (repairable)', async () => {
516
+ await createHealthyPlanning();
517
+ const { unlink } = await import('node:fs/promises');
518
+ await unlink(join(tmpDir, '.planning', 'STATE.md'));
519
+
520
+ const result = await validateHealth([], tmpDir);
521
+ const data = result.data as Record<string, unknown>;
522
+ const errors = data.errors as Array<Record<string, unknown>>;
523
+ const e004 = errors.find(e => e.code === 'E004');
524
+ expect(e004).toBeDefined();
525
+ expect(e004!.repairable).toBe(true);
526
+ });
527
+
528
+ it('returns error E005 when config.json has invalid JSON (repairable)', async () => {
529
+ await createHealthyPlanning();
530
+ await writeFile(join(tmpDir, '.planning', 'config.json'), '{invalid json!!!');
531
+
532
+ const result = await validateHealth([], tmpDir);
533
+ const data = result.data as Record<string, unknown>;
534
+ const errors = data.errors as Array<Record<string, unknown>>;
535
+ const e005 = errors.find(e => e.code === 'E005');
536
+ expect(e005).toBeDefined();
537
+ expect(e005!.repairable).toBe(true);
538
+ });
539
+
540
+ it('returns warning W003 when config.json missing (repairable)', async () => {
541
+ await createHealthyPlanning();
542
+ const { unlink } = await import('node:fs/promises');
543
+ await unlink(join(tmpDir, '.planning', 'config.json'));
544
+
545
+ const result = await validateHealth([], tmpDir);
546
+ const data = result.data as Record<string, unknown>;
547
+ const warnings = data.warnings as Array<Record<string, unknown>>;
548
+ const w003 = warnings.find(w => w.code === 'W003');
549
+ expect(w003).toBeDefined();
550
+ expect(w003!.repairable).toBe(true);
551
+ });
552
+
553
+ it('returns warning W005 for bad phase directory naming', async () => {
554
+ await createHealthyPlanning();
555
+ await mkdir(join(tmpDir, '.planning', 'phases', 'bad_name'), { recursive: true });
556
+
557
+ const result = await validateHealth([], tmpDir);
558
+ const data = result.data as Record<string, unknown>;
559
+ const warnings = data.warnings as Array<Record<string, unknown>>;
560
+ expect(warnings.some(w => w.code === 'W005')).toBe(true);
561
+ });
562
+
563
+ it('returns early with E010 when CWD equals home directory', async () => {
564
+ const result = await validateHealth([], homedir());
565
+ const data = result.data as Record<string, unknown>;
566
+ expect(data.status).toBe('error');
567
+ const errors = data.errors as Array<Record<string, unknown>>;
568
+ expect(errors.some(e => e.code === 'E010')).toBe(true);
569
+ });
570
+
571
+ it('returns warning W008 when config.json missing workflow.nyquist_validation', async () => {
572
+ await createHealthyPlanning();
573
+ await writeFile(join(tmpDir, '.planning', 'config.json'), JSON.stringify({
574
+ model_profile: 'balanced',
575
+ workflow: { research: true },
576
+ }, null, 2));
577
+
578
+ const result = await validateHealth([], tmpDir);
579
+ const data = result.data as Record<string, unknown>;
580
+ const warnings = data.warnings as Array<Record<string, unknown>>;
581
+ expect(warnings.some(w => w.code === 'W008')).toBe(true);
582
+ });
583
+
584
+ it('derives status from errors (broken), warnings (degraded), none (healthy)', async () => {
585
+ // broken: no .planning/
586
+ const r1 = await validateHealth([], tmpDir);
587
+ expect((r1.data as Record<string, unknown>).status).toBe('broken');
588
+
589
+ // degraded: missing config.json (warning only, not error)
590
+ await createHealthyPlanning();
591
+ const { unlink } = await import('node:fs/promises');
592
+ await unlink(join(tmpDir, '.planning', 'config.json'));
593
+ const r2 = await validateHealth([], tmpDir);
594
+ expect((r2.data as Record<string, unknown>).status).toBe('degraded');
595
+
596
+ // healthy: all present
597
+ await writeFile(join(tmpDir, '.planning', 'config.json'), JSON.stringify({
598
+ model_profile: 'balanced',
599
+ workflow: { nyquist_validation: true },
600
+ }, null, 2));
601
+ const r3 = await validateHealth([], tmpDir);
602
+ expect((r3.data as Record<string, unknown>).status).toBe('healthy');
603
+ });
604
+
605
+ // ─── Repair tests ───────────────────────────────────────────────────────
606
+
607
+ it('--repair with missing config.json creates config.json with defaults', async () => {
608
+ await createHealthyPlanning();
609
+ const { unlink } = await import('node:fs/promises');
610
+ await unlink(join(tmpDir, '.planning', 'config.json'));
611
+
612
+ const result = await validateHealth(['--repair'], tmpDir);
613
+ const data = result.data as Record<string, unknown>;
614
+ expect(data.repairs_performed).toBeDefined();
615
+ const repairs = data.repairs_performed as Array<Record<string, unknown>>;
616
+ expect(repairs.some(r => r.action === 'createConfig' && r.success === true)).toBe(true);
617
+
618
+ // Verify file was created
619
+ const config = JSON.parse(await readFile(join(tmpDir, '.planning', 'config.json'), 'utf-8'));
620
+ expect(config.model_profile).toBe('balanced');
621
+ expect(config.workflow.nyquist_validation).toBe(true);
622
+ });
623
+
624
+ it('--repair with missing STATE.md generates minimal STATE.md', async () => {
625
+ await createHealthyPlanning();
626
+ const { unlink } = await import('node:fs/promises');
627
+ await unlink(join(tmpDir, '.planning', 'STATE.md'));
628
+
629
+ const result = await validateHealth(['--repair'], tmpDir);
630
+ const data = result.data as Record<string, unknown>;
631
+ const repairs = data.repairs_performed as Array<Record<string, unknown>>;
632
+ expect(repairs.some(r => r.action === 'regenerateState' && r.success === true)).toBe(true);
633
+
634
+ // Verify file was created
635
+ const stateContent = await readFile(join(tmpDir, '.planning', 'STATE.md'), 'utf-8');
636
+ expect(stateContent).toContain('# Session State');
637
+ expect(stateContent).toContain('regenerated by');
638
+ });
639
+
640
+ it('--repair with missing nyquist key adds workflow.nyquist_validation', async () => {
641
+ await createHealthyPlanning();
642
+ await writeFile(join(tmpDir, '.planning', 'config.json'), JSON.stringify({
643
+ model_profile: 'balanced',
644
+ workflow: { research: true },
645
+ }, null, 2));
646
+
647
+ const result = await validateHealth(['--repair'], tmpDir);
648
+ const data = result.data as Record<string, unknown>;
649
+ const repairs = data.repairs_performed as Array<Record<string, unknown>>;
650
+ expect(repairs.some(r => r.action === 'addNyquistKey' && r.success === true)).toBe(true);
651
+
652
+ // Verify key was added
653
+ const config = JSON.parse(await readFile(join(tmpDir, '.planning', 'config.json'), 'utf-8'));
654
+ expect(config.workflow.nyquist_validation).toBe(true);
655
+ });
656
+ });