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,522 @@
1
+ /**
2
+ * Unit tests for init composition handlers.
3
+ *
4
+ * Tests all 13 init handlers plus the withProjectRoot helper.
5
+ * Uses mkdtemp temp directories to simulate .planning/ layout.
6
+ */
7
+
8
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
9
+ import { mkdtemp, writeFile, mkdir, rm, readdir } from 'node:fs/promises';
10
+ import { join } from 'node:path';
11
+ import { tmpdir } from 'node:os';
12
+ import {
13
+ withProjectRoot,
14
+ initExecutePhase,
15
+ initPlanPhase,
16
+ initNewMilestone,
17
+ initQuick,
18
+ initResume,
19
+ initVerifyWork,
20
+ initPhaseOp,
21
+ initTodos,
22
+ initMilestoneOp,
23
+ initMapCodebase,
24
+ initNewWorkspace,
25
+ initListWorkspaces,
26
+ initRemoveWorkspace,
27
+ initIngestDocs,
28
+ } from './init.js';
29
+
30
+ let tmpDir: string;
31
+
32
+ beforeEach(async () => {
33
+ tmpDir = await mkdtemp(join(tmpdir(), 'gsd-init-'));
34
+ // Create minimal .planning structure
35
+ await mkdir(join(tmpDir, '.planning', 'phases', '09-foundation'), { recursive: true });
36
+ await mkdir(join(tmpDir, '.planning', 'phases', '10-read-only-queries'), { recursive: true });
37
+ // Create config.json
38
+ await writeFile(join(tmpDir, '.planning', 'config.json'), JSON.stringify({
39
+ model_profile: 'balanced',
40
+ commit_docs: false,
41
+ git: {
42
+ branching_strategy: 'none',
43
+ phase_branch_template: 'gsd/phase-{phase}-{slug}',
44
+ milestone_branch_template: 'gsd/{milestone}-{slug}',
45
+ quick_branch_template: null,
46
+ },
47
+ workflow: { research: true, plan_check: true, verifier: true, nyquist_validation: true },
48
+ }));
49
+ // Create STATE.md
50
+ await writeFile(join(tmpDir, '.planning', 'STATE.md'), [
51
+ '---',
52
+ 'milestone: v3.0',
53
+ 'status: executing',
54
+ '---',
55
+ '',
56
+ '# Project State',
57
+ '',
58
+ '## Current Position',
59
+ '',
60
+ 'Phase: 9 (foundation)',
61
+ 'Plan: 1 of 3',
62
+ 'Status: Executing',
63
+ '',
64
+ ].join('\n'));
65
+ // Create ROADMAP.md with phase sections
66
+ await writeFile(join(tmpDir, '.planning', 'ROADMAP.md'), [
67
+ '# Roadmap',
68
+ '',
69
+ '## v3.0: SDK-First Migration',
70
+ '',
71
+ '### Phase 9: Foundation',
72
+ '',
73
+ '**Goal:** Build foundation',
74
+ '',
75
+ '### Phase 10: Read-Only Queries',
76
+ '',
77
+ '**Goal:** Implement queries',
78
+ '',
79
+ ].join('\n'));
80
+ // Create plan and summary files in phase 09
81
+ await writeFile(join(tmpDir, '.planning', 'phases', '09-foundation', '09-01-PLAN.md'), [
82
+ '---',
83
+ 'phase: 09-foundation',
84
+ 'plan: 01',
85
+ 'wave: 1',
86
+ '---',
87
+ '<objective>Test plan</objective>',
88
+ ].join('\n'));
89
+ await writeFile(join(tmpDir, '.planning', 'phases', '09-foundation', '09-01-SUMMARY.md'), '# Summary');
90
+ await writeFile(join(tmpDir, '.planning', 'phases', '09-foundation', '09-CONTEXT.md'), '# Context');
91
+ await writeFile(join(tmpDir, '.planning', 'phases', '09-foundation', '09-RESEARCH.md'), '# Research');
92
+ });
93
+
94
+ afterEach(async () => {
95
+ await rm(tmpDir, { recursive: true, force: true });
96
+ });
97
+
98
+ describe('withProjectRoot', () => {
99
+ it('injects project_root, agents_installed, missing_agents into result', () => {
100
+ const result: Record<string, unknown> = { foo: 'bar' };
101
+ const enriched = withProjectRoot(tmpDir, result);
102
+ expect(enriched.project_root).toBe(tmpDir);
103
+ expect(typeof enriched.agents_installed).toBe('boolean');
104
+ expect(Array.isArray(enriched.missing_agents)).toBe(true);
105
+ // Original field preserved
106
+ expect(enriched.foo).toBe('bar');
107
+ });
108
+
109
+ it('injects response_language when config has it', () => {
110
+ const result: Record<string, unknown> = {};
111
+ const enriched = withProjectRoot(tmpDir, result, { response_language: 'ja' });
112
+ expect(enriched.response_language).toBe('ja');
113
+ });
114
+
115
+ it('does not inject response_language when not in config', () => {
116
+ const result: Record<string, unknown> = {};
117
+ const enriched = withProjectRoot(tmpDir, result, {});
118
+ expect(enriched.response_language).toBeUndefined();
119
+ });
120
+
121
+ // Regression: #2400 — checkAgentsInstalled was looking at the wrong default
122
+ // directory (~/.claude/get-shit-done/agents) while the installer writes to
123
+ // ~/.claude/agents, causing agents_installed: false even on clean installs.
124
+ it('reports agents_installed: true when all expected agents exist in GSD_AGENTS_DIR', async () => {
125
+ const { MODEL_PROFILES } = await import('./config-query.js');
126
+ const agentsDir = join(tmpDir, 'fake-agents');
127
+ await mkdir(agentsDir, { recursive: true });
128
+ for (const name of Object.keys(MODEL_PROFILES)) {
129
+ await writeFile(join(agentsDir, `${name}.md`), '# stub');
130
+ }
131
+ const prev = process.env.GSD_AGENTS_DIR;
132
+ process.env.GSD_AGENTS_DIR = agentsDir;
133
+ try {
134
+ const enriched = withProjectRoot(tmpDir, {});
135
+ expect(enriched.agents_installed).toBe(true);
136
+ expect(enriched.missing_agents).toEqual([]);
137
+ } finally {
138
+ if (prev === undefined) delete process.env.GSD_AGENTS_DIR;
139
+ else process.env.GSD_AGENTS_DIR = prev;
140
+ }
141
+ });
142
+
143
+ it('reports missing agents when GSD_AGENTS_DIR is empty', async () => {
144
+ const agentsDir = join(tmpDir, 'empty-agents');
145
+ await mkdir(agentsDir, { recursive: true });
146
+ const prev = process.env.GSD_AGENTS_DIR;
147
+ process.env.GSD_AGENTS_DIR = agentsDir;
148
+ try {
149
+ const enriched = withProjectRoot(tmpDir, {}) as Record<string, unknown>;
150
+ expect(enriched.agents_installed).toBe(false);
151
+ expect((enriched.missing_agents as string[]).length).toBeGreaterThan(0);
152
+ } finally {
153
+ if (prev === undefined) delete process.env.GSD_AGENTS_DIR;
154
+ else process.env.GSD_AGENTS_DIR = prev;
155
+ }
156
+ });
157
+
158
+ // Regression: #2400 follow-up — installer honors CLAUDE_CONFIG_DIR for custom
159
+ // Claude install roots. The SDK check must follow the same precedence or it
160
+ // false-negatives agent presence on non-default installs.
161
+ it('honors CLAUDE_CONFIG_DIR when GSD_AGENTS_DIR is unset', async () => {
162
+ const { MODEL_PROFILES } = await import('./config-query.js');
163
+ const configDir = join(tmpDir, 'custom-claude');
164
+ const agentsDir = join(configDir, 'agents');
165
+ await mkdir(agentsDir, { recursive: true });
166
+ for (const name of Object.keys(MODEL_PROFILES)) {
167
+ await writeFile(join(agentsDir, `${name}.md`), '# stub');
168
+ }
169
+ const prevAgents = process.env.GSD_AGENTS_DIR;
170
+ const prevClaude = process.env.CLAUDE_CONFIG_DIR;
171
+ delete process.env.GSD_AGENTS_DIR;
172
+ process.env.CLAUDE_CONFIG_DIR = configDir;
173
+ try {
174
+ const enriched = withProjectRoot(tmpDir, {}) as Record<string, unknown>;
175
+ expect(enriched.agents_installed).toBe(true);
176
+ expect(enriched.missing_agents).toEqual([]);
177
+ } finally {
178
+ if (prevAgents === undefined) delete process.env.GSD_AGENTS_DIR;
179
+ else process.env.GSD_AGENTS_DIR = prevAgents;
180
+ if (prevClaude === undefined) delete process.env.CLAUDE_CONFIG_DIR;
181
+ else process.env.CLAUDE_CONFIG_DIR = prevClaude;
182
+ }
183
+ });
184
+
185
+ // #2402 — runtime-aware resolution: GSD_RUNTIME selects which runtime's
186
+ // config-dir env chain to consult, so non-Claude installs stop
187
+ // false-negating.
188
+ it('GSD_RUNTIME=codex resolves agents under CODEX_HOME/agents', async () => {
189
+ const { MODEL_PROFILES } = await import('./config-query.js');
190
+ const codexHome = join(tmpDir, 'codex-home');
191
+ const agentsDir = join(codexHome, 'agents');
192
+ await mkdir(agentsDir, { recursive: true });
193
+ for (const name of Object.keys(MODEL_PROFILES)) {
194
+ await writeFile(join(agentsDir, `${name}.md`), '# stub');
195
+ }
196
+ const prevAgents = process.env.GSD_AGENTS_DIR;
197
+ const prevRuntime = process.env.GSD_RUNTIME;
198
+ const prevCodex = process.env.CODEX_HOME;
199
+ delete process.env.GSD_AGENTS_DIR;
200
+ process.env.GSD_RUNTIME = 'codex';
201
+ process.env.CODEX_HOME = codexHome;
202
+ try {
203
+ const enriched = withProjectRoot(tmpDir, {}) as Record<string, unknown>;
204
+ expect(enriched.agents_installed).toBe(true);
205
+ expect(enriched.missing_agents).toEqual([]);
206
+ } finally {
207
+ if (prevAgents === undefined) delete process.env.GSD_AGENTS_DIR;
208
+ else process.env.GSD_AGENTS_DIR = prevAgents;
209
+ if (prevRuntime === undefined) delete process.env.GSD_RUNTIME;
210
+ else process.env.GSD_RUNTIME = prevRuntime;
211
+ if (prevCodex === undefined) delete process.env.CODEX_HOME;
212
+ else process.env.CODEX_HOME = prevCodex;
213
+ }
214
+ });
215
+
216
+ it('config.runtime drives detection when GSD_RUNTIME is unset', async () => {
217
+ const { MODEL_PROFILES } = await import('./config-query.js');
218
+ const geminiHome = join(tmpDir, 'gemini-home');
219
+ const agentsDir = join(geminiHome, 'agents');
220
+ await mkdir(agentsDir, { recursive: true });
221
+ for (const name of Object.keys(MODEL_PROFILES)) {
222
+ await writeFile(join(agentsDir, `${name}.md`), '# stub');
223
+ }
224
+ const prevAgents = process.env.GSD_AGENTS_DIR;
225
+ const prevRuntime = process.env.GSD_RUNTIME;
226
+ const prevGemini = process.env.GEMINI_CONFIG_DIR;
227
+ delete process.env.GSD_AGENTS_DIR;
228
+ delete process.env.GSD_RUNTIME;
229
+ process.env.GEMINI_CONFIG_DIR = geminiHome;
230
+ try {
231
+ const enriched = withProjectRoot(tmpDir, {}, { runtime: 'gemini' }) as Record<string, unknown>;
232
+ expect(enriched.agents_installed).toBe(true);
233
+ } finally {
234
+ if (prevAgents === undefined) delete process.env.GSD_AGENTS_DIR;
235
+ else process.env.GSD_AGENTS_DIR = prevAgents;
236
+ if (prevRuntime === undefined) delete process.env.GSD_RUNTIME;
237
+ else process.env.GSD_RUNTIME = prevRuntime;
238
+ if (prevGemini === undefined) delete process.env.GEMINI_CONFIG_DIR;
239
+ else process.env.GEMINI_CONFIG_DIR = prevGemini;
240
+ }
241
+ });
242
+
243
+ it('GSD_RUNTIME wins over config.runtime', async () => {
244
+ const { MODEL_PROFILES } = await import('./config-query.js');
245
+ const codexHome = join(tmpDir, 'codex-win');
246
+ const agentsDir = join(codexHome, 'agents');
247
+ await mkdir(agentsDir, { recursive: true });
248
+ for (const name of Object.keys(MODEL_PROFILES)) {
249
+ await writeFile(join(agentsDir, `${name}.md`), '# stub');
250
+ }
251
+ const prevAgents = process.env.GSD_AGENTS_DIR;
252
+ const prevRuntime = process.env.GSD_RUNTIME;
253
+ const prevCodex = process.env.CODEX_HOME;
254
+ delete process.env.GSD_AGENTS_DIR;
255
+ process.env.GSD_RUNTIME = 'codex';
256
+ process.env.CODEX_HOME = codexHome;
257
+ try {
258
+ // config says gemini, env says codex — codex should win and find agents.
259
+ const enriched = withProjectRoot(tmpDir, {}, { runtime: 'gemini' }) as Record<string, unknown>;
260
+ expect(enriched.agents_installed).toBe(true);
261
+ } finally {
262
+ if (prevAgents === undefined) delete process.env.GSD_AGENTS_DIR;
263
+ else process.env.GSD_AGENTS_DIR = prevAgents;
264
+ if (prevRuntime === undefined) delete process.env.GSD_RUNTIME;
265
+ else process.env.GSD_RUNTIME = prevRuntime;
266
+ if (prevCodex === undefined) delete process.env.CODEX_HOME;
267
+ else process.env.CODEX_HOME = prevCodex;
268
+ }
269
+ });
270
+
271
+ it('unknown GSD_RUNTIME falls through to config/Claude default', () => {
272
+ const prevAgents = process.env.GSD_AGENTS_DIR;
273
+ const prevRuntime = process.env.GSD_RUNTIME;
274
+ delete process.env.GSD_AGENTS_DIR;
275
+ process.env.GSD_RUNTIME = 'not-a-runtime';
276
+ try {
277
+ // Should not throw; falls back to Claude — missing_agents on a blank tmpDir.
278
+ const enriched = withProjectRoot(tmpDir, {}) as Record<string, unknown>;
279
+ expect(typeof enriched.agents_installed).toBe('boolean');
280
+ } finally {
281
+ if (prevAgents === undefined) delete process.env.GSD_AGENTS_DIR;
282
+ else process.env.GSD_AGENTS_DIR = prevAgents;
283
+ if (prevRuntime === undefined) delete process.env.GSD_RUNTIME;
284
+ else process.env.GSD_RUNTIME = prevRuntime;
285
+ }
286
+ });
287
+
288
+ it('GSD_AGENTS_DIR takes precedence over CLAUDE_CONFIG_DIR', async () => {
289
+ const { MODEL_PROFILES } = await import('./config-query.js');
290
+ const winningDir = join(tmpDir, 'winning-agents');
291
+ const losingDir = join(tmpDir, 'losing-config', 'agents');
292
+ await mkdir(winningDir, { recursive: true });
293
+ await mkdir(losingDir, { recursive: true });
294
+ // Only populate the winning dir.
295
+ for (const name of Object.keys(MODEL_PROFILES)) {
296
+ await writeFile(join(winningDir, `${name}.md`), '# stub');
297
+ }
298
+ const prevAgents = process.env.GSD_AGENTS_DIR;
299
+ const prevClaude = process.env.CLAUDE_CONFIG_DIR;
300
+ process.env.GSD_AGENTS_DIR = winningDir;
301
+ process.env.CLAUDE_CONFIG_DIR = join(tmpDir, 'losing-config');
302
+ try {
303
+ const enriched = withProjectRoot(tmpDir, {}) as Record<string, unknown>;
304
+ expect(enriched.agents_installed).toBe(true);
305
+ } finally {
306
+ if (prevAgents === undefined) delete process.env.GSD_AGENTS_DIR;
307
+ else process.env.GSD_AGENTS_DIR = prevAgents;
308
+ if (prevClaude === undefined) delete process.env.CLAUDE_CONFIG_DIR;
309
+ else process.env.CLAUDE_CONFIG_DIR = prevClaude;
310
+ }
311
+ });
312
+ });
313
+
314
+ describe('initExecutePhase', () => {
315
+ it('returns flat JSON with expected keys for existing phase', async () => {
316
+ const result = await initExecutePhase(['9'], tmpDir);
317
+ const data = result.data as Record<string, unknown>;
318
+ expect(data.phase_found).toBe(true);
319
+ expect(data.phase_number).toBe('09');
320
+ expect(data.executor_model).toBeDefined();
321
+ expect(data.commit_docs).toBeDefined();
322
+ expect(data.project_root).toBe(tmpDir);
323
+ expect(data.plans).toBeDefined();
324
+ expect(data.summaries).toBeDefined();
325
+ expect(data.milestone_version).toBeDefined();
326
+ });
327
+
328
+ it('returns error when phase arg missing', async () => {
329
+ const result = await initExecutePhase([], tmpDir);
330
+ const data = result.data as Record<string, unknown>;
331
+ expect(data.error).toBeDefined();
332
+ });
333
+ });
334
+
335
+ describe('initPlanPhase', () => {
336
+ it('returns flat JSON with expected keys', async () => {
337
+ const result = await initPlanPhase(['9'], tmpDir);
338
+ const data = result.data as Record<string, unknown>;
339
+ expect(data.phase_found).toBe(true);
340
+ expect(data.researcher_model).toBeDefined();
341
+ expect(data.planner_model).toBeDefined();
342
+ expect(data.checker_model).toBeDefined();
343
+ expect(data.research_enabled).toBeDefined();
344
+ expect(data.has_research).toBe(true);
345
+ expect(data.has_context).toBe(true);
346
+ expect(data.project_root).toBe(tmpDir);
347
+ });
348
+
349
+ it('returns error when phase arg missing', async () => {
350
+ const result = await initPlanPhase([], tmpDir);
351
+ const data = result.data as Record<string, unknown>;
352
+ expect(data.error).toBeDefined();
353
+ });
354
+ });
355
+
356
+ describe('initNewMilestone', () => {
357
+ it('returns flat JSON with milestone info', async () => {
358
+ const result = await initNewMilestone([], tmpDir);
359
+ const data = result.data as Record<string, unknown>;
360
+ expect(data.current_milestone).toBeDefined();
361
+ expect(data.current_milestone_name).toBeDefined();
362
+ expect(data.phase_dir_count).toBeGreaterThanOrEqual(0);
363
+ expect(data.project_root).toBe(tmpDir);
364
+ });
365
+ });
366
+
367
+ describe('initQuick', () => {
368
+ it('returns flat JSON with task info', async () => {
369
+ const result = await initQuick(['my-task'], tmpDir);
370
+ const data = result.data as Record<string, unknown>;
371
+ expect(data.quick_id).toBeDefined();
372
+ expect(data.slug).toBe('my-task');
373
+ expect(data.description).toBe('my-task');
374
+ expect(data.planner_model).toBeDefined();
375
+ expect(data.executor_model).toBeDefined();
376
+ expect(data.quick_dir).toBe('.planning/quick');
377
+ expect(data.project_root).toBe(tmpDir);
378
+ });
379
+ });
380
+
381
+ describe('initResume', () => {
382
+ it('returns flat JSON with state info', async () => {
383
+ const result = await initResume([], tmpDir);
384
+ const data = result.data as Record<string, unknown>;
385
+ expect(data.state_exists).toBe(true);
386
+ expect(data.roadmap_exists).toBe(true);
387
+ expect(data.project_root).toBe(tmpDir);
388
+ expect(data.commit_docs).toBeDefined();
389
+ });
390
+ });
391
+
392
+ describe('initVerifyWork', () => {
393
+ it('returns flat JSON with expected keys', async () => {
394
+ const result = await initVerifyWork(['9'], tmpDir);
395
+ const data = result.data as Record<string, unknown>;
396
+ expect(data.phase_found).toBe(true);
397
+ expect(data.phase_number).toBe('09');
398
+ expect(data.planner_model).toBeDefined();
399
+ expect(data.checker_model).toBeDefined();
400
+ expect(data.project_root).toBe(tmpDir);
401
+ });
402
+
403
+ it('returns error when phase arg missing', async () => {
404
+ const result = await initVerifyWork([], tmpDir);
405
+ const data = result.data as Record<string, unknown>;
406
+ expect(data.error).toBeDefined();
407
+ });
408
+ });
409
+
410
+ describe('initPhaseOp', () => {
411
+ it('returns flat JSON with phase artifacts', async () => {
412
+ const result = await initPhaseOp(['9'], tmpDir);
413
+ const data = result.data as Record<string, unknown>;
414
+ expect(data.phase_found).toBe(true);
415
+ expect(data.phase_number).toBe('09');
416
+ expect(data.has_research).toBe(true);
417
+ expect(data.has_context).toBe(true);
418
+ expect(data.plan_count).toBeGreaterThanOrEqual(1);
419
+ expect(data.project_root).toBe(tmpDir);
420
+ });
421
+ });
422
+
423
+ describe('initTodos', () => {
424
+ it('returns flat JSON with todo inventory', async () => {
425
+ const result = await initTodos([], tmpDir);
426
+ const data = result.data as Record<string, unknown>;
427
+ expect(data.todo_count).toBe(0);
428
+ expect(Array.isArray(data.todos)).toBe(true);
429
+ expect(data.area_filter).toBeNull();
430
+ expect(data.project_root).toBe(tmpDir);
431
+ });
432
+
433
+ it('filters by area when provided', async () => {
434
+ const result = await initTodos(['code'], tmpDir);
435
+ const data = result.data as Record<string, unknown>;
436
+ expect(data.area_filter).toBe('code');
437
+ });
438
+ });
439
+
440
+ describe('initMilestoneOp', () => {
441
+ it('returns flat JSON with milestone info', async () => {
442
+ const result = await initMilestoneOp([], tmpDir);
443
+ const data = result.data as Record<string, unknown>;
444
+ expect(data.milestone_version).toBeDefined();
445
+ expect(data.milestone_name).toBeDefined();
446
+ expect(data.phase_count).toBeGreaterThanOrEqual(0);
447
+ expect(data.completed_phases).toBeGreaterThanOrEqual(0);
448
+ expect(data.project_root).toBe(tmpDir);
449
+ });
450
+ });
451
+
452
+ describe('initMapCodebase', () => {
453
+ it('returns flat JSON with mapper info', async () => {
454
+ const result = await initMapCodebase([], tmpDir);
455
+ const data = result.data as Record<string, unknown>;
456
+ expect(data.mapper_model).toBeDefined();
457
+ expect(Array.isArray(data.existing_maps)).toBe(true);
458
+ expect(data.codebase_dir).toBe('.planning/codebase');
459
+ expect(data.project_root).toBe(tmpDir);
460
+ });
461
+ });
462
+
463
+ describe('initNewWorkspace', () => {
464
+ it('returns flat JSON with workspace info', async () => {
465
+ const result = await initNewWorkspace([], tmpDir);
466
+ const data = result.data as Record<string, unknown>;
467
+ expect(data.default_workspace_base).toBeDefined();
468
+ expect(typeof data.worktree_available).toBe('boolean');
469
+ expect(data.project_root).toBe(tmpDir);
470
+ });
471
+
472
+ it('detects git availability', async () => {
473
+ const result = await initNewWorkspace([], tmpDir);
474
+ const data = result.data as Record<string, unknown>;
475
+ // worktree_available depends on whether git is installed
476
+ expect(typeof data.worktree_available).toBe('boolean');
477
+ });
478
+ });
479
+
480
+ describe('initListWorkspaces', () => {
481
+ it('returns flat JSON with workspaces array', async () => {
482
+ const result = await initListWorkspaces([], tmpDir);
483
+ const data = result.data as Record<string, unknown>;
484
+ expect(Array.isArray(data.workspaces)).toBe(true);
485
+ expect(data.workspace_count).toBeGreaterThanOrEqual(0);
486
+ });
487
+ });
488
+
489
+ describe('initRemoveWorkspace', () => {
490
+ it('returns error when name arg missing', async () => {
491
+ const result = await initRemoveWorkspace([], tmpDir);
492
+ const data = result.data as Record<string, unknown>;
493
+ expect(data.error).toBeDefined();
494
+ });
495
+
496
+ it('rejects path separator in workspace name (T-14-01)', async () => {
497
+ const result = await initRemoveWorkspace(['../../bad'], tmpDir);
498
+ const data = result.data as Record<string, unknown>;
499
+ expect(data.error).toBeDefined();
500
+ });
501
+ });
502
+
503
+ describe('initIngestDocs', () => {
504
+ it('returns flat JSON with ingest-docs branching fields', async () => {
505
+ const result = await initIngestDocs([], tmpDir);
506
+ const data = result.data as Record<string, unknown>;
507
+ expect(data.project_exists).toBe(false);
508
+ expect(data.planning_exists).toBe(true);
509
+ expect(typeof data.has_git).toBe('boolean');
510
+ expect(data.project_path).toBe('.planning/PROJECT.md');
511
+ expect(data.commit_docs).toBeDefined();
512
+ expect(data.project_root).toBe(tmpDir);
513
+ });
514
+
515
+ it('reports project_exists true when PROJECT.md is present', async () => {
516
+ await writeFile(join(tmpDir, '.planning', 'PROJECT.md'), '# project');
517
+ const result = await initIngestDocs([], tmpDir);
518
+ const data = result.data as Record<string, unknown>;
519
+ expect(data.project_exists).toBe(true);
520
+ expect(data.planning_exists).toBe(true);
521
+ });
522
+ });