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,783 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import { mkdir, writeFile, rm, readFile } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { tmpdir } from 'node:os';
5
+
6
+ import { InitRunner } from './init-runner.js';
7
+ import type { InitRunnerDeps } from './init-runner.js';
8
+ import type {
9
+ PlanResult,
10
+ SessionUsage,
11
+ GSDEvent,
12
+ InitNewProjectInfo,
13
+ InitStepResult,
14
+ } from './types.js';
15
+ import { GSDEventType } from './types.js';
16
+
17
+ // ─── Mock modules ────────────────────────────────────────────────────────────
18
+
19
+ // Mock session-runner to avoid real SDK calls
20
+ vi.mock('./session-runner.js', () => ({
21
+ runPhaseStepSession: vi.fn(),
22
+ runPlanSession: vi.fn(),
23
+ }));
24
+
25
+ // Mock config loader
26
+ vi.mock('./config.js', () => ({
27
+ loadConfig: vi.fn().mockResolvedValue({
28
+ mode: 'yolo',
29
+ model_profile: 'balanced',
30
+ }),
31
+ CONFIG_DEFAULTS: {},
32
+ }));
33
+
34
+ // Mock fs/promises for template reading (InitRunner reads GSD templates)
35
+ // We partially mock — only readFile needs interception for template paths
36
+ const originalReadFile = vi.importActual('node:fs/promises').then(m => (m as typeof import('node:fs/promises')).readFile);
37
+
38
+ import { runPhaseStepSession } from './session-runner.js';
39
+
40
+ const mockRunSession = vi.mocked(runPhaseStepSession);
41
+
42
+ // ─── Factory helpers ─────────────────────────────────────────────────────────
43
+
44
+ function makeUsage(): SessionUsage {
45
+ return {
46
+ inputTokens: 1000,
47
+ outputTokens: 500,
48
+ cacheReadInputTokens: 0,
49
+ cacheCreationInputTokens: 0,
50
+ };
51
+ }
52
+
53
+ function makeSuccessResult(overrides: Partial<PlanResult> = {}): PlanResult {
54
+ return {
55
+ success: true,
56
+ sessionId: `sess-${Date.now()}`,
57
+ totalCostUsd: 0.05,
58
+ durationMs: 2000,
59
+ usage: makeUsage(),
60
+ numTurns: 10,
61
+ ...overrides,
62
+ };
63
+ }
64
+
65
+ function makeErrorResult(overrides: Partial<PlanResult> = {}): PlanResult {
66
+ return {
67
+ success: false,
68
+ sessionId: `sess-err-${Date.now()}`,
69
+ totalCostUsd: 0.01,
70
+ durationMs: 500,
71
+ usage: makeUsage(),
72
+ numTurns: 2,
73
+ error: {
74
+ subtype: 'error_during_execution',
75
+ messages: ['Session failed'],
76
+ },
77
+ ...overrides,
78
+ };
79
+ }
80
+
81
+ function makeProjectInfo(overrides: Partial<InitNewProjectInfo> = {}): InitNewProjectInfo {
82
+ return {
83
+ researcher_model: 'claude-sonnet-4-6',
84
+ synthesizer_model: 'claude-sonnet-4-6',
85
+ roadmapper_model: 'claude-sonnet-4-6',
86
+ commit_docs: false, // false for tests — no git operations
87
+ project_exists: false,
88
+ has_codebase_map: false,
89
+ planning_exists: false,
90
+ has_existing_code: false,
91
+ has_package_file: false,
92
+ is_brownfield: false,
93
+ needs_codebase_map: false,
94
+ has_git: true, // skip git init in tests
95
+ brave_search_available: false,
96
+ firecrawl_available: false,
97
+ exa_search_available: false,
98
+ project_path: '.planning/PROJECT.md',
99
+ ...overrides,
100
+ };
101
+ }
102
+
103
+ function makeTools(overrides: Record<string, unknown> = {}) {
104
+ return {
105
+ initNewProject: vi.fn().mockResolvedValue(makeProjectInfo()),
106
+ configSet: vi.fn().mockResolvedValue(undefined),
107
+ commit: vi.fn().mockResolvedValue(undefined),
108
+ exec: vi.fn(),
109
+ stateLoad: vi.fn(),
110
+ roadmapAnalyze: vi.fn(),
111
+ phaseComplete: vi.fn(),
112
+ verifySummary: vi.fn(),
113
+ initExecutePhase: vi.fn(),
114
+ initPhaseOp: vi.fn(),
115
+ configGet: vi.fn(),
116
+ stateBeginPhase: vi.fn(),
117
+ phasePlanIndex: vi.fn(),
118
+ ...overrides,
119
+ } as any;
120
+ }
121
+
122
+ function makeEventStream() {
123
+ const events: GSDEvent[] = [];
124
+ return {
125
+ emitEvent: vi.fn((event: GSDEvent) => events.push(event)),
126
+ on: vi.fn(),
127
+ emit: vi.fn(),
128
+ addTransport: vi.fn(),
129
+ events,
130
+ } as any;
131
+ }
132
+
133
+ function makeDeps(overrides: Partial<InitRunnerDeps> & { tmpDir: string }): InitRunnerDeps & { events: GSDEvent[] } {
134
+ const tools = makeTools();
135
+ const eventStream = makeEventStream();
136
+ return {
137
+ projectDir: overrides.tmpDir,
138
+ tools: overrides.tools ?? tools,
139
+ eventStream: overrides.eventStream ?? eventStream,
140
+ config: overrides.config,
141
+ events: eventStream.events,
142
+ ...(overrides.tools ? {} : {}),
143
+ };
144
+ }
145
+
146
+ // ─── Test suite ──────────────────────────────────────────────────────────────
147
+
148
+ describe('InitRunner', () => {
149
+ let tmpDir: string;
150
+
151
+ beforeEach(async () => {
152
+ tmpDir = join(tmpdir(), `init-runner-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
153
+ await mkdir(tmpDir, { recursive: true });
154
+ vi.clearAllMocks();
155
+
156
+ // Default: all sessions succeed
157
+ mockRunSession.mockResolvedValue(makeSuccessResult());
158
+ });
159
+
160
+ afterEach(async () => {
161
+ await rm(tmpDir, { recursive: true, force: true });
162
+ });
163
+
164
+ // ─── Helpers ─────────────────────────────────────────────────────────────
165
+
166
+ function createRunner(toolsOverrides: Record<string, unknown> = {}, configOverrides?: Partial<InitRunnerDeps['config']>) {
167
+ const tools = makeTools(toolsOverrides);
168
+ const eventStream = makeEventStream();
169
+ const runner = new InitRunner({
170
+ projectDir: tmpDir,
171
+ tools,
172
+ eventStream,
173
+ config: configOverrides as any,
174
+ });
175
+ return { runner, tools, eventStream, events: eventStream.events as GSDEvent[] };
176
+ }
177
+
178
+ // ─── Core workflow tests ─────────────────────────────────────────────────
179
+
180
+ it('run() calls initNewProject and validates project_exists === false', async () => {
181
+ const { runner, tools } = createRunner();
182
+
183
+ await runner.run('build a todo app');
184
+
185
+ expect(tools.initNewProject).toHaveBeenCalledOnce();
186
+ });
187
+
188
+ it('run() returns error result when initNewProject reports project_exists', async () => {
189
+ const { runner, tools } = createRunner({
190
+ initNewProject: vi.fn().mockResolvedValue(makeProjectInfo({ project_exists: true })),
191
+ });
192
+
193
+ const result = await runner.run('build a todo app');
194
+
195
+ expect(result.success).toBe(false);
196
+ // The setup step should have failed
197
+ const setupStep = result.steps.find(s => s.step === 'setup');
198
+ expect(setupStep).toBeDefined();
199
+ expect(setupStep!.success).toBe(false);
200
+ expect(setupStep!.error).toContain('already exists');
201
+ });
202
+
203
+ it('run() writes config.json with auto-mode defaults', async () => {
204
+ const { runner } = createRunner();
205
+
206
+ await runner.run('build a todo app');
207
+
208
+ // config.json should be written to .planning/config.json in tmpDir
209
+ const configPath = join(tmpDir, '.planning', 'config.json');
210
+ const content = await readFile(configPath, 'utf-8');
211
+ const parsed = JSON.parse(content);
212
+
213
+ expect(parsed.mode).toBe('yolo');
214
+ expect(parsed.parallelization).toBe(true);
215
+ expect(parsed.workflow.auto_advance).toBe(true);
216
+ });
217
+
218
+ it('run() calls configSet for auto_advance', async () => {
219
+ const { runner, tools } = createRunner();
220
+
221
+ await runner.run('build a todo app');
222
+
223
+ expect(tools.configSet).toHaveBeenCalledWith('workflow.auto_advance', 'true');
224
+ });
225
+
226
+ it('run() spawns PROJECT.md synthesis session', async () => {
227
+ const { runner } = createRunner();
228
+
229
+ await runner.run('build a todo app');
230
+
231
+ // The third session call should be the PROJECT.md synthesis
232
+ // Calls: setup (no session), config (no session), project (1st session),
233
+ // 4x research, synthesis, requirements, roadmap
234
+ // Total: 8 runPhaseStepSession calls
235
+ expect(mockRunSession).toHaveBeenCalled();
236
+
237
+ // First call should be for PROJECT.md (step 3)
238
+ const firstCall = mockRunSession.mock.calls[0];
239
+ expect(firstCall).toBeDefined();
240
+ const prompt = firstCall![0] as string;
241
+ expect(prompt).toContain('PROJECT.md');
242
+ });
243
+
244
+ it('run() spawns 4 parallel research sessions via Promise.allSettled', async () => {
245
+ const { runner } = createRunner();
246
+
247
+ await runner.run('build a todo app');
248
+
249
+ // Count calls that contain the specific "researching the X aspect" pattern
250
+ // which uniquely identifies research prompts (vs synthesis/requirements that reference research files)
251
+ const researchCalls = mockRunSession.mock.calls.filter(call => {
252
+ const prompt = call[0] as string;
253
+ return prompt.includes('You are researching the');
254
+ });
255
+
256
+ // Should be exactly 4 research sessions
257
+ expect(researchCalls.length).toBe(4);
258
+ });
259
+
260
+ it('run() spawns synthesis session after research completes', async () => {
261
+ const { runner } = createRunner();
262
+
263
+ await runner.run('build a todo app');
264
+
265
+ // Synthesis call should contain 'Synthesize' or 'SUMMARY'
266
+ const synthesisCalls = mockRunSession.mock.calls.filter(call => {
267
+ const prompt = call[0] as string;
268
+ return prompt.includes('Synthesize') || prompt.includes('SUMMARY.md');
269
+ });
270
+
271
+ expect(synthesisCalls.length).toBeGreaterThanOrEqual(1);
272
+ });
273
+
274
+ it('run() spawns requirements session', async () => {
275
+ const { runner } = createRunner();
276
+
277
+ await runner.run('build a todo app');
278
+
279
+ const reqCalls = mockRunSession.mock.calls.filter(call => {
280
+ const prompt = call[0] as string;
281
+ return prompt.includes('REQUIREMENTS.md');
282
+ });
283
+
284
+ expect(reqCalls.length).toBeGreaterThanOrEqual(1);
285
+ });
286
+
287
+ it('run() spawns roadmapper session', async () => {
288
+ const { runner } = createRunner();
289
+
290
+ await runner.run('build a todo app');
291
+
292
+ const roadmapCalls = mockRunSession.mock.calls.filter(call => {
293
+ const prompt = call[0] as string;
294
+ return prompt.includes('ROADMAP.md') || prompt.includes('STATE.md');
295
+ });
296
+
297
+ expect(roadmapCalls.length).toBeGreaterThanOrEqual(1);
298
+ });
299
+
300
+ it('run() calls commit after each major step when commit_docs is true', async () => {
301
+ const commitFn = vi.fn().mockResolvedValue(undefined);
302
+ const { runner } = createRunner({
303
+ initNewProject: vi.fn().mockResolvedValue(makeProjectInfo({ commit_docs: true })),
304
+ commit: commitFn,
305
+ });
306
+
307
+ await runner.run('build a todo app');
308
+
309
+ // Should commit: config, PROJECT.md, research, REQUIREMENTS.md, ROADMAP+STATE
310
+ expect(commitFn).toHaveBeenCalled();
311
+ expect(commitFn.mock.calls.length).toBeGreaterThanOrEqual(4);
312
+ });
313
+
314
+ it('run() does not call commit when commit_docs is false', async () => {
315
+ const commitFn = vi.fn().mockResolvedValue(undefined);
316
+ const { runner } = createRunner({
317
+ initNewProject: vi.fn().mockResolvedValue(makeProjectInfo({ commit_docs: false })),
318
+ commit: commitFn,
319
+ });
320
+
321
+ await runner.run('build a todo app');
322
+
323
+ expect(commitFn).not.toHaveBeenCalled();
324
+ });
325
+
326
+ // ─── Event emission tests ────────────────────────────────────────────────
327
+
328
+ it('run() emits InitStart and InitComplete events', async () => {
329
+ const { runner, events } = createRunner();
330
+
331
+ await runner.run('build a todo app');
332
+
333
+ const startEvents = events.filter(e => e.type === GSDEventType.InitStart);
334
+ const completeEvents = events.filter(e => e.type === GSDEventType.InitComplete);
335
+
336
+ expect(startEvents.length).toBe(1);
337
+ expect(completeEvents.length).toBe(1);
338
+
339
+ const start = startEvents[0] as any;
340
+ expect(start.projectDir).toBe(tmpDir);
341
+ expect(start.input).toBeTruthy();
342
+
343
+ const complete = completeEvents[0] as any;
344
+ expect(complete.success).toBe(true);
345
+ expect(complete.totalCostUsd).toBeTypeOf('number');
346
+ expect(complete.totalDurationMs).toBeTypeOf('number');
347
+ expect(complete.artifactCount).toBeGreaterThan(0);
348
+ });
349
+
350
+ it('run() emits InitStepStart/Complete for each step', async () => {
351
+ const { runner, events } = createRunner();
352
+
353
+ await runner.run('build a todo app');
354
+
355
+ const stepStarts = events.filter(e => e.type === GSDEventType.InitStepStart);
356
+ const stepCompletes = events.filter(e => e.type === GSDEventType.InitStepComplete);
357
+
358
+ // Steps: setup, config, project, 4x research, synthesis, requirements, roadmap = 10
359
+ expect(stepStarts.length).toBe(10);
360
+ expect(stepCompletes.length).toBe(10);
361
+
362
+ // Verify each step start has a matching complete (order may vary for parallel research)
363
+ const startSteps = stepStarts.map(e => (e as any).step).sort();
364
+ const completeSteps = stepCompletes.map(e => (e as any).step).sort();
365
+
366
+ expect(startSteps).toEqual(completeSteps);
367
+
368
+ // Verify expected step names are present
369
+ expect(startSteps).toContain('setup');
370
+ expect(startSteps).toContain('config');
371
+ expect(startSteps).toContain('project');
372
+ expect(startSteps).toContain('research-stack');
373
+ expect(startSteps).toContain('research-features');
374
+ expect(startSteps).toContain('research-architecture');
375
+ expect(startSteps).toContain('research-pitfalls');
376
+ expect(startSteps).toContain('synthesis');
377
+ expect(startSteps).toContain('requirements');
378
+ expect(startSteps).toContain('roadmap');
379
+ });
380
+
381
+ it('run() emits InitResearchSpawn before research sessions', async () => {
382
+ const { runner, events } = createRunner();
383
+
384
+ await runner.run('build a todo app');
385
+
386
+ const spawnEvents = events.filter(e => e.type === GSDEventType.InitResearchSpawn);
387
+ expect(spawnEvents.length).toBe(1);
388
+
389
+ const spawn = spawnEvents[0] as any;
390
+ expect(spawn.sessionCount).toBe(4);
391
+ expect(spawn.researchTypes).toEqual(['STACK', 'FEATURES', 'ARCHITECTURE', 'PITFALLS']);
392
+ });
393
+
394
+ // ─── Error handling tests ────────────────────────────────────────────────
395
+
396
+ it('run() returns error when a session fails (partial research success)', async () => {
397
+ // Make the STACK research session fail, others succeed
398
+ let callCount = 0;
399
+ mockRunSession.mockImplementation(async (prompt: string) => {
400
+ callCount++;
401
+ // First call is PROJECT.md, then 4 research calls
402
+ // The 2nd call overall (1st research) should fail
403
+ if (callCount === 2) {
404
+ return makeErrorResult();
405
+ }
406
+ return makeSuccessResult();
407
+ });
408
+
409
+ const { runner } = createRunner();
410
+ const result = await runner.run('build a todo app');
411
+
412
+ // Should still complete (partial success allowed for research)
413
+ // but overall result indicates research failure
414
+ expect(result.success).toBe(false);
415
+
416
+ // Steps should still exist for all phases
417
+ expect(result.steps.length).toBeGreaterThanOrEqual(7);
418
+ });
419
+
420
+ it('run() stops workflow when PROJECT.md synthesis fails', async () => {
421
+ // First session (PROJECT.md) fails
422
+ mockRunSession.mockResolvedValueOnce(makeErrorResult());
423
+
424
+ const { runner } = createRunner();
425
+ const result = await runner.run('build a todo app');
426
+
427
+ expect(result.success).toBe(false);
428
+
429
+ // Should have setup, config, and project steps only
430
+ const stepNames = result.steps.map(s => s.step);
431
+ expect(stepNames).toContain('setup');
432
+ expect(stepNames).toContain('config');
433
+ expect(stepNames).toContain('project');
434
+ // Should NOT continue to research
435
+ expect(stepNames).not.toContain('research-stack');
436
+ });
437
+
438
+ it('run() stops workflow when requirements session fails', async () => {
439
+ // Let PROJECT.md and research succeed, but make requirements fail
440
+ let sessionCallIndex = 0;
441
+ mockRunSession.mockImplementation(async () => {
442
+ sessionCallIndex++;
443
+ // Calls: 1=PROJECT.md, 2-5=research, 6=synthesis, 7=requirements
444
+ if (sessionCallIndex === 7) {
445
+ return makeErrorResult();
446
+ }
447
+ return makeSuccessResult();
448
+ });
449
+
450
+ const { runner } = createRunner();
451
+ const result = await runner.run('build a todo app');
452
+
453
+ expect(result.success).toBe(false);
454
+
455
+ const stepNames = result.steps.map(s => s.step);
456
+ expect(stepNames).toContain('requirements');
457
+ // Should NOT continue to roadmap
458
+ expect(stepNames).not.toContain('roadmap');
459
+ });
460
+
461
+ // ─── Cost aggregation tests ──────────────────────────────────────────────
462
+
463
+ it('run() aggregates costs from all sessions', async () => {
464
+ const costPerSession = 0.05;
465
+ mockRunSession.mockResolvedValue(makeSuccessResult({ totalCostUsd: costPerSession }));
466
+
467
+ const { runner } = createRunner();
468
+ const result = await runner.run('build a todo app');
469
+
470
+ // 8 total sessions: PROJECT.md + 4 research + synthesis + requirements + roadmap
471
+ // Cost from sessions extracted via extractCost, non-session steps (setup/config) are 0
472
+ expect(result.totalCostUsd).toBeGreaterThan(0);
473
+ expect(result.totalDurationMs).toBeGreaterThan(0);
474
+ });
475
+
476
+ // ─── Artifact tracking tests ─────────────────────────────────────────────
477
+
478
+ it('run() returns all expected artifacts on success', async () => {
479
+ const { runner } = createRunner();
480
+ const result = await runner.run('build a todo app');
481
+
482
+ expect(result.success).toBe(true);
483
+ expect(result.artifacts).toContain('.planning/config.json');
484
+ expect(result.artifacts).toContain('.planning/PROJECT.md');
485
+ expect(result.artifacts).toContain('.planning/research/SUMMARY.md');
486
+ expect(result.artifacts).toContain('.planning/REQUIREMENTS.md');
487
+ expect(result.artifacts).toContain('.planning/ROADMAP.md');
488
+ expect(result.artifacts).toContain('.planning/STATE.md');
489
+ });
490
+
491
+ it('run() includes research artifact paths on success', async () => {
492
+ const { runner } = createRunner();
493
+ const result = await runner.run('build a todo app');
494
+
495
+ expect(result.artifacts).toContain('.planning/research/STACK.md');
496
+ expect(result.artifacts).toContain('.planning/research/FEATURES.md');
497
+ expect(result.artifacts).toContain('.planning/research/ARCHITECTURE.md');
498
+ expect(result.artifacts).toContain('.planning/research/PITFALLS.md');
499
+ });
500
+
501
+ // ─── Git init test ─────────────────────────────────────────────────────
502
+
503
+ it('run() initializes git when has_git is false', async () => {
504
+ // We can't easily test git init without mocking execFile deeply,
505
+ // but we can verify the tools.initNewProject is called with the result
506
+ // and that the workflow continues. Since has_git=true by default in our
507
+ // mock, flip it to false and verify the config step still passes.
508
+ const { runner } = createRunner({
509
+ initNewProject: vi.fn().mockResolvedValue(makeProjectInfo({ has_git: false })),
510
+ });
511
+
512
+ // This will attempt to run `git init` which may or may not exist in test env.
513
+ // Since we're in a tmpDir, git init is safe. The test verifies the workflow proceeds.
514
+ const result = await runner.run('build a todo app');
515
+
516
+ // The config step should succeed (git init in tmpDir should work)
517
+ const configStep = result.steps.find(s => s.step === 'config');
518
+ expect(configStep).toBeDefined();
519
+ // Note: if git is not available in CI, this may fail — that's expected
520
+ });
521
+
522
+ // ─── Config passthrough test ─────────────────────────────────────────────
523
+
524
+ it('constructor accepts config overrides', async () => {
525
+ // Set projectInfo model fields to undefined so orchestratorModel is used as fallback
526
+ const { runner } = createRunner({
527
+ initNewProject: vi.fn().mockResolvedValue(makeProjectInfo({
528
+ researcher_model: undefined as any,
529
+ synthesizer_model: undefined as any,
530
+ roadmapper_model: undefined as any,
531
+ })),
532
+ }, {
533
+ maxBudgetPerSession: 10.0,
534
+ maxTurnsPerSession: 50,
535
+ orchestratorModel: 'claude-opus-4-6',
536
+ });
537
+
538
+ await runner.run('build a todo app');
539
+
540
+ // Verify the session runner was called with overridden model
541
+ const calls = mockRunSession.mock.calls;
542
+ expect(calls.length).toBeGreaterThan(0);
543
+
544
+ // Check model in options (4th argument, index 3)
545
+ const modelsUsed = calls.map(c => {
546
+ const options = c[3] as any;
547
+ return options?.model;
548
+ });
549
+ // When projectInfo model is undefined, ?? falls through to orchestratorModel
550
+ expect(modelsUsed.some(m => m === 'claude-opus-4-6')).toBe(true);
551
+ });
552
+
553
+ // ─── Session count validation ────────────────────────────────────────────
554
+
555
+ it('run() calls runPhaseStepSession exactly 8 times on full success', async () => {
556
+ const { runner } = createRunner();
557
+
558
+ await runner.run('build a todo app');
559
+
560
+ // 1 PROJECT.md + 4 research + 1 synthesis + 1 requirements + 1 roadmap = 8
561
+ expect(mockRunSession).toHaveBeenCalledTimes(8);
562
+ });
563
+
564
+ // ─── Headless prompt loading (sdkPromptsDir preference) ──────────────────
565
+
566
+ describe('sdkPromptsDir preference and sanitizer integration', () => {
567
+ let sdkPromptsDir: string;
568
+
569
+ beforeEach(async () => {
570
+ // Create a temp SDK prompts directory with test fixtures
571
+ sdkPromptsDir = join(tmpDir, 'sdk-prompts');
572
+ await mkdir(join(sdkPromptsDir, 'templates', 'research-project'), { recursive: true });
573
+ await mkdir(join(sdkPromptsDir, 'agents'), { recursive: true });
574
+
575
+ // Write headless templates (with known marker text for assertion)
576
+ await writeFile(
577
+ join(sdkPromptsDir, 'templates', 'project.md'),
578
+ '# PROJECT Template\nSDK_HEADLESS_MARKER_PROJECT\n',
579
+ );
580
+ await writeFile(
581
+ join(sdkPromptsDir, 'templates', 'requirements.md'),
582
+ '# REQUIREMENTS Template\nSDK_HEADLESS_MARKER_REQUIREMENTS\n',
583
+ );
584
+ await writeFile(
585
+ join(sdkPromptsDir, 'templates', 'roadmap.md'),
586
+ '# ROADMAP Template\nSDK_HEADLESS_MARKER_ROADMAP\n',
587
+ );
588
+ await writeFile(
589
+ join(sdkPromptsDir, 'templates', 'state.md'),
590
+ '# STATE Template\nSDK_HEADLESS_MARKER_STATE\n',
591
+ );
592
+ await writeFile(
593
+ join(sdkPromptsDir, 'templates', 'research-project', 'STACK.md'),
594
+ '# STACK Template\nSDK_HEADLESS_MARKER_STACK\n',
595
+ );
596
+
597
+ // Write headless agents (with known marker text)
598
+ await writeFile(
599
+ join(sdkPromptsDir, 'agents', 'gsd-project-researcher.md'),
600
+ '# Project Researcher Agent\nSDK_HEADLESS_MARKER_RESEARCHER\n',
601
+ );
602
+ await writeFile(
603
+ join(sdkPromptsDir, 'agents', 'gsd-research-synthesizer.md'),
604
+ '# Research Synthesizer Agent\nSDK_HEADLESS_MARKER_SYNTHESIZER\n',
605
+ );
606
+ await writeFile(
607
+ join(sdkPromptsDir, 'agents', 'gsd-roadmapper.md'),
608
+ '# Roadmapper Agent\nSDK_HEADLESS_MARKER_ROADMAPPER\n',
609
+ );
610
+ });
611
+
612
+ function createRunnerWithSdkPrompts(
613
+ toolsOverrides: Record<string, unknown> = {},
614
+ configOverrides?: Partial<InitRunnerDeps['config']>,
615
+ ) {
616
+ const tools = makeTools(toolsOverrides);
617
+ const eventStream = makeEventStream();
618
+ const runner = new InitRunner({
619
+ projectDir: tmpDir,
620
+ tools,
621
+ eventStream,
622
+ config: configOverrides as any,
623
+ sdkPromptsDir,
624
+ });
625
+ return { runner, tools, eventStream, events: eventStream.events as GSDEvent[] };
626
+ }
627
+
628
+ it('readGSDFile prefers sdk/prompts/ template over GSD-1 path', async () => {
629
+ const { runner } = createRunnerWithSdkPrompts();
630
+
631
+ await runner.run('build a todo app');
632
+
633
+ // The first session call is buildProjectPrompt → reads templates/project.md
634
+ const projectPrompt = mockRunSession.mock.calls[0]![0] as string;
635
+ expect(projectPrompt).toContain('SDK_HEADLESS_MARKER_PROJECT');
636
+ });
637
+
638
+ it('readAgentFile prefers sdk/prompts/agents/ over GSD-1 path', async () => {
639
+ const { runner } = createRunnerWithSdkPrompts();
640
+
641
+ await runner.run('build a todo app');
642
+
643
+ // Research calls (indices 1-4) use gsd-project-researcher.md agent def
644
+ const researchPrompt = mockRunSession.mock.calls[1]![0] as string;
645
+ expect(researchPrompt).toContain('SDK_HEADLESS_MARKER_RESEARCHER');
646
+ });
647
+
648
+ it('readGSDFile falls back to GSD-1 when sdk/prompts/ file does not exist', async () => {
649
+ // Create an empty sdkPromptsDir — no templates at all
650
+ const emptySdkDir = join(tmpDir, 'empty-sdk-prompts');
651
+ await mkdir(join(emptySdkDir, 'templates'), { recursive: true });
652
+ await mkdir(join(emptySdkDir, 'agents'), { recursive: true });
653
+
654
+ const tools = makeTools();
655
+ const eventStream = makeEventStream();
656
+ const runner = new InitRunner({
657
+ projectDir: tmpDir,
658
+ tools,
659
+ eventStream,
660
+ sdkPromptsDir: emptySdkDir,
661
+ });
662
+
663
+ await runner.run('build a todo app');
664
+
665
+ // buildProjectPrompt reads templates/project.md — not found in empty dir,
666
+ // falls through to GSD-1 path. If GSD-1 also missing, gets placeholder.
667
+ const projectPrompt = mockRunSession.mock.calls[0]![0] as string;
668
+
669
+ // Should NOT contain our marker (since empty dir was used)
670
+ expect(projectPrompt).not.toContain('SDK_HEADLESS_MARKER_PROJECT');
671
+ // Should still contain the PROJECT.md synthesis instruction (from the prompt builder)
672
+ expect(projectPrompt).toContain('PROJECT.md');
673
+ });
674
+
675
+ it('readAgentFile falls back to GSD-1 when sdk/prompts/agents/ file does not exist', async () => {
676
+ // Empty sdkPromptsDir — no agent files
677
+ const emptySdkDir = join(tmpDir, 'empty-sdk-agents');
678
+ await mkdir(join(emptySdkDir, 'templates', 'research-project'), { recursive: true });
679
+ await mkdir(join(emptySdkDir, 'agents'), { recursive: true });
680
+
681
+ // Write templates so we get past buildProjectPrompt
682
+ await writeFile(join(emptySdkDir, 'templates', 'project.md'), '# project\n');
683
+ await writeFile(join(emptySdkDir, 'templates', 'research-project', 'STACK.md'), '# stack\n');
684
+ await writeFile(join(emptySdkDir, 'templates', 'research-project', 'FEATURES.md'), '# features\n');
685
+ await writeFile(join(emptySdkDir, 'templates', 'research-project', 'ARCHITECTURE.md'), '# arch\n');
686
+ await writeFile(join(emptySdkDir, 'templates', 'research-project', 'PITFALLS.md'), '# pitfalls\n');
687
+
688
+ const tools = makeTools();
689
+ const eventStream = makeEventStream();
690
+ const runner = new InitRunner({
691
+ projectDir: tmpDir,
692
+ tools,
693
+ eventStream,
694
+ sdkPromptsDir: emptySdkDir,
695
+ });
696
+
697
+ await runner.run('build a todo app');
698
+
699
+ // Research prompt uses agent def — not in empty agents dir, falls to GSD-1
700
+ const researchPrompt = mockRunSession.mock.calls[1]![0] as string;
701
+ // Should NOT contain our marker
702
+ expect(researchPrompt).not.toContain('SDK_HEADLESS_MARKER_RESEARCHER');
703
+ // Should still have the "researching the" instruction
704
+ expect(researchPrompt).toContain('You are researching the');
705
+ });
706
+
707
+ it('buildProjectPrompt output passes through sanitizePrompt (no /gsd: patterns)', async () => {
708
+ // Write a template that contains an interactive pattern
709
+ await writeFile(
710
+ join(sdkPromptsDir, 'templates', 'project.md'),
711
+ '# PROJECT Template\nRun /gsd:map-codebase to analyze.\nSDK_HEADLESS_MARKER_PROJECT\n',
712
+ );
713
+
714
+ const { runner } = createRunnerWithSdkPrompts();
715
+ await runner.run('build a todo app');
716
+
717
+ const projectPrompt = mockRunSession.mock.calls[0]![0] as string;
718
+ // sanitizePrompt should have stripped the /gsd: line
719
+ expect(projectPrompt).not.toMatch(/\/gsd:\S+/);
720
+ // But the marker should still be there
721
+ expect(projectPrompt).toContain('SDK_HEADLESS_MARKER_PROJECT');
722
+ });
723
+
724
+ it('buildResearchPrompt output passes through sanitizePrompt (no /gsd: patterns)', async () => {
725
+ // Write an agent def that contains interactive patterns
726
+ await writeFile(
727
+ join(sdkPromptsDir, 'agents', 'gsd-project-researcher.md'),
728
+ '# Researcher Agent\nSpawn /gsd:something for analysis.\nSDK_HEADLESS_MARKER_RESEARCHER\n',
729
+ );
730
+
731
+ const { runner } = createRunnerWithSdkPrompts();
732
+ await runner.run('build a todo app');
733
+
734
+ const researchPrompt = mockRunSession.mock.calls[1]![0] as string;
735
+ // sanitizePrompt should have stripped the /gsd: line
736
+ expect(researchPrompt).not.toMatch(/\/gsd:\S+/);
737
+ // Marker should still be present
738
+ expect(researchPrompt).toContain('SDK_HEADLESS_MARKER_RESEARCHER');
739
+ });
740
+
741
+ it('buildRoadmapPrompt output passes through sanitizePrompt (no /gsd: patterns)', async () => {
742
+ // Write agent and templates with interactive patterns
743
+ await writeFile(
744
+ join(sdkPromptsDir, 'agents', 'gsd-roadmapper.md'),
745
+ '# Roadmapper Agent\nUse /gsd:execute to run.\nSDK_HEADLESS_MARKER_ROADMAPPER\n',
746
+ );
747
+ await writeFile(
748
+ join(sdkPromptsDir, 'templates', 'roadmap.md'),
749
+ '# ROADMAP Template\nRun /gsd:check-progress.\nSDK_HEADLESS_MARKER_ROADMAP\n',
750
+ );
751
+ await writeFile(
752
+ join(sdkPromptsDir, 'templates', 'state.md'),
753
+ '# STATE Template\nUse /gsd:add-todo for tracking.\nSDK_HEADLESS_MARKER_STATE\n',
754
+ );
755
+
756
+ // Also need research templates and synth agent for earlier steps
757
+ await writeFile(
758
+ join(sdkPromptsDir, 'templates', 'research-project', 'FEATURES.md'), '# features\n',
759
+ );
760
+ await writeFile(
761
+ join(sdkPromptsDir, 'templates', 'research-project', 'ARCHITECTURE.md'), '# arch\n',
762
+ );
763
+ await writeFile(
764
+ join(sdkPromptsDir, 'templates', 'research-project', 'PITFALLS.md'), '# pitfalls\n',
765
+ );
766
+ await writeFile(
767
+ join(sdkPromptsDir, 'templates', 'research-project', 'SUMMARY.md'), '# summary\n',
768
+ );
769
+
770
+ const { runner } = createRunnerWithSdkPrompts();
771
+ await runner.run('build a todo app');
772
+
773
+ // Roadmap prompt is the last session call (index 7)
774
+ const roadmapPrompt = mockRunSession.mock.calls[7]![0] as string;
775
+ // sanitizePrompt should have stripped all /gsd: patterns
776
+ expect(roadmapPrompt).not.toMatch(/\/gsd:\S+/);
777
+ // Markers from templates should still be present
778
+ expect(roadmapPrompt).toContain('SDK_HEADLESS_MARKER_ROADMAPPER');
779
+ expect(roadmapPrompt).toContain('SDK_HEADLESS_MARKER_ROADMAP');
780
+ expect(roadmapPrompt).toContain('SDK_HEADLESS_MARKER_STATE');
781
+ });
782
+ });
783
+ });