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,33 @@
1
+ /**
2
+ * Workstream utility functions for multi-workstream project support.
3
+ *
4
+ * When --ws <name> is provided, all .planning/ paths are routed to
5
+ * .planning/workstreams/<name>/ instead.
6
+ */
7
+
8
+ import { posix } from 'node:path';
9
+
10
+ /**
11
+ * Validate a workstream name.
12
+ * Allowed: alphanumeric, hyphens, underscores, dots.
13
+ * Disallowed: empty, spaces, slashes, special chars, path traversal.
14
+ */
15
+ export function validateWorkstreamName(name: string): boolean {
16
+ if (!name || name.length === 0) return false;
17
+ // Only allow alphanumeric, hyphens, underscores, dots
18
+ // Must not be ".." or start with ".." (path traversal)
19
+ if (name === '..' || name.startsWith('../')) return false;
20
+ return /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(name);
21
+ }
22
+
23
+ /**
24
+ * Return the relative planning directory path.
25
+ *
26
+ * - Without workstream: `.planning`
27
+ * - With workstream: `.planning/workstreams/<name>`
28
+ */
29
+ export function relPlanningPath(workstream?: string): string {
30
+ if (!workstream) return '.planning';
31
+ // Use POSIX segments so the same logical path string is used on all platforms (Windows included).
32
+ return posix.join('.planning', 'workstreams', workstream);
33
+ }
@@ -0,0 +1,285 @@
1
+ /**
2
+ * Tests for --ws (workstream) flag support.
3
+ *
4
+ * Validates:
5
+ * - CLI parsing of --ws flag
6
+ * - Workstream name validation
7
+ * - GSDOptions.workstream propagation
8
+ * - GSDTools workstream-aware invocation
9
+ * - Config path resolution with workstream
10
+ * - ContextEngine workstream-aware planning dir
11
+ */
12
+
13
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
14
+ import { mkdir, writeFile, rm } from 'node:fs/promises';
15
+ import { join } from 'node:path';
16
+ import { tmpdir } from 'node:os';
17
+
18
+ // ─── Workstream name validation ─────────────────────────────────────────────
19
+
20
+ import { validateWorkstreamName } from './workstream-utils.js';
21
+
22
+ describe('validateWorkstreamName', () => {
23
+ it('accepts alphanumeric names', () => {
24
+ expect(validateWorkstreamName('frontend')).toBe(true);
25
+ expect(validateWorkstreamName('backend2')).toBe(true);
26
+ });
27
+
28
+ it('accepts names with hyphens', () => {
29
+ expect(validateWorkstreamName('my-feature')).toBe(true);
30
+ });
31
+
32
+ it('accepts names with underscores', () => {
33
+ expect(validateWorkstreamName('my_feature')).toBe(true);
34
+ });
35
+
36
+ it('accepts names with dots', () => {
37
+ expect(validateWorkstreamName('v1.0')).toBe(true);
38
+ });
39
+
40
+ it('rejects empty strings', () => {
41
+ expect(validateWorkstreamName('')).toBe(false);
42
+ });
43
+
44
+ it('rejects names with spaces', () => {
45
+ expect(validateWorkstreamName('my feature')).toBe(false);
46
+ });
47
+
48
+ it('rejects names with slashes', () => {
49
+ expect(validateWorkstreamName('my/feature')).toBe(false);
50
+ });
51
+
52
+ it('rejects names with special characters', () => {
53
+ expect(validateWorkstreamName('feat@ure')).toBe(false);
54
+ expect(validateWorkstreamName('feat!ure')).toBe(false);
55
+ expect(validateWorkstreamName('feat#ure')).toBe(false);
56
+ });
57
+
58
+ it('rejects path traversal attempts', () => {
59
+ expect(validateWorkstreamName('..')).toBe(false);
60
+ expect(validateWorkstreamName('../etc')).toBe(false);
61
+ });
62
+ });
63
+
64
+ // ─── relPlanningPath helper ─────────────────────────────────────────────────
65
+
66
+ import { relPlanningPath } from './workstream-utils.js';
67
+
68
+ describe('relPlanningPath', () => {
69
+ it('returns .planning/ in flat mode (no workstream)', () => {
70
+ expect(relPlanningPath()).toBe('.planning');
71
+ expect(relPlanningPath(undefined)).toBe('.planning');
72
+ });
73
+
74
+ it('returns .planning/workstreams/<name>/ with workstream', () => {
75
+ expect(relPlanningPath('frontend')).toBe('.planning/workstreams/frontend');
76
+ expect(relPlanningPath('api-v2')).toBe('.planning/workstreams/api-v2');
77
+ });
78
+ });
79
+
80
+ // ─── CLI --ws flag parsing ──────────────────────────────────────────────────
81
+
82
+ import { parseCliArgs } from './cli.js';
83
+
84
+ describe('parseCliArgs --ws flag', () => {
85
+ it('parses --ws flag', () => {
86
+ const result = parseCliArgs(['run', 'build auth', '--ws', 'frontend']);
87
+
88
+ expect(result.ws).toBe('frontend');
89
+ });
90
+
91
+ it('ws is undefined when not provided', () => {
92
+ const result = parseCliArgs(['run', 'build auth']);
93
+
94
+ expect(result.ws).toBeUndefined();
95
+ });
96
+
97
+ it('works with other flags', () => {
98
+ const result = parseCliArgs([
99
+ 'run', 'build auth',
100
+ '--ws', 'backend',
101
+ '--model', 'claude-sonnet-4-6',
102
+ '--project-dir', '/tmp/test',
103
+ ]);
104
+
105
+ expect(result.ws).toBe('backend');
106
+ expect(result.model).toBe('claude-sonnet-4-6');
107
+ expect(result.projectDir).toBe('/tmp/test');
108
+ });
109
+ });
110
+
111
+ // ─── GSDOptions.workstream ──────────────────────────────────────────────────
112
+
113
+ describe('GSDOptions.workstream', () => {
114
+ it('GSD class accepts workstream option', async () => {
115
+ // This is a compile-time check -- if the type is wrong, TS will fail
116
+ const { GSD } = await import('./index.js');
117
+ const gsd = new GSD({
118
+ projectDir: '/tmp/test-ws',
119
+ workstream: 'frontend',
120
+ });
121
+ // If we get here without a type error, the option is accepted
122
+ expect(gsd).toBeDefined();
123
+ });
124
+ });
125
+
126
+ // ─── GSDTools workstream injection ──────────────────────────────────────────
127
+
128
+ describe('GSDTools workstream injection', () => {
129
+ let tmpDir: string;
130
+ let fixtureDir: string;
131
+
132
+ beforeEach(async () => {
133
+ tmpDir = join(tmpdir(), `gsd-ws-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
134
+ fixtureDir = join(tmpDir, 'fixtures');
135
+ await mkdir(fixtureDir, { recursive: true });
136
+ await mkdir(join(tmpDir, '.planning'), { recursive: true });
137
+ });
138
+
139
+ afterEach(async () => {
140
+ await rm(tmpDir, { recursive: true, force: true });
141
+ });
142
+
143
+ async function createScript(name: string, code: string): Promise<string> {
144
+ const scriptPath = join(fixtureDir, name);
145
+ await writeFile(scriptPath, code, { mode: 0o755 });
146
+ return scriptPath;
147
+ }
148
+
149
+ it('passes --ws flag to gsd-tools.cjs when workstream is set', async () => {
150
+ const { GSDTools } = await import('./gsd-tools.js');
151
+
152
+ // Script echoes its arguments as JSON
153
+ const scriptPath = await createScript(
154
+ 'echo-args.cjs',
155
+ 'process.stdout.write(JSON.stringify(process.argv.slice(2)));',
156
+ );
157
+
158
+ const tools = new GSDTools({
159
+ projectDir: tmpDir,
160
+ gsdToolsPath: scriptPath,
161
+ workstream: 'frontend',
162
+ });
163
+
164
+ const result = await tools.exec('state', ['load']) as string[];
165
+
166
+ // Should contain --ws frontend in the arguments
167
+ expect(result).toContain('--ws');
168
+ expect(result).toContain('frontend');
169
+ });
170
+
171
+ it('does not pass --ws when workstream is undefined', async () => {
172
+ const { GSDTools } = await import('./gsd-tools.js');
173
+
174
+ const scriptPath = await createScript(
175
+ 'echo-args-no-ws.cjs',
176
+ 'process.stdout.write(JSON.stringify(process.argv.slice(2)));',
177
+ );
178
+
179
+ const tools = new GSDTools({
180
+ projectDir: tmpDir,
181
+ gsdToolsPath: scriptPath,
182
+ });
183
+
184
+ const result = await tools.exec('state', ['load']) as string[];
185
+
186
+ expect(result).not.toContain('--ws');
187
+ });
188
+ });
189
+
190
+ // ─── Config workstream-aware path ───────────────────────────────────────────
191
+
192
+ import { loadConfig } from './config.js';
193
+
194
+ describe('loadConfig with workstream', () => {
195
+ let tmpDir: string;
196
+
197
+ beforeEach(async () => {
198
+ tmpDir = join(tmpdir(), `gsd-config-ws-${Date.now()}-${Math.random().toString(36).slice(2)}`);
199
+ await mkdir(tmpDir, { recursive: true });
200
+ });
201
+
202
+ afterEach(async () => {
203
+ await rm(tmpDir, { recursive: true, force: true });
204
+ });
205
+
206
+ it('loads config from workstream path when workstream is provided', async () => {
207
+ const wsDir = join(tmpDir, '.planning', 'workstreams', 'frontend');
208
+ await mkdir(wsDir, { recursive: true });
209
+ await writeFile(
210
+ join(wsDir, 'config.json'),
211
+ JSON.stringify({ model_profile: 'performance' }),
212
+ );
213
+
214
+ const config = await loadConfig(tmpDir, 'frontend');
215
+
216
+ expect(config.model_profile).toBe('performance');
217
+ });
218
+
219
+ it('falls back to root config when workstream config is missing', async () => {
220
+ // Create root config but no workstream config
221
+ await mkdir(join(tmpDir, '.planning'), { recursive: true });
222
+ await writeFile(
223
+ join(tmpDir, '.planning', 'config.json'),
224
+ JSON.stringify({ model_profile: 'balanced' }),
225
+ );
226
+
227
+ const config = await loadConfig(tmpDir, 'frontend');
228
+
229
+ expect(config.model_profile).toBe('balanced');
230
+ });
231
+
232
+ it('loads from root .planning/ when workstream is undefined', async () => {
233
+ await mkdir(join(tmpDir, '.planning'), { recursive: true });
234
+ await writeFile(
235
+ join(tmpDir, '.planning', 'config.json'),
236
+ JSON.stringify({ model_profile: 'economy' }),
237
+ );
238
+
239
+ const config = await loadConfig(tmpDir);
240
+
241
+ expect(config.model_profile).toBe('economy');
242
+ });
243
+ });
244
+
245
+ // ─── ContextEngine workstream-aware planning dir ────────────────────────────
246
+
247
+ describe('ContextEngine with workstream', () => {
248
+ let tmpDir: string;
249
+
250
+ beforeEach(async () => {
251
+ tmpDir = join(tmpdir(), `gsd-ctx-ws-${Date.now()}-${Math.random().toString(36).slice(2)}`);
252
+ await mkdir(tmpDir, { recursive: true });
253
+ });
254
+
255
+ afterEach(async () => {
256
+ await rm(tmpDir, { recursive: true, force: true });
257
+ });
258
+
259
+ it('resolves files from workstream planning dir', async () => {
260
+ const { ContextEngine } = await import('./context-engine.js');
261
+ const { PhaseType } = await import('./types.js');
262
+
263
+ const wsDir = join(tmpDir, '.planning', 'workstreams', 'backend');
264
+ await mkdir(wsDir, { recursive: true });
265
+ await writeFile(join(wsDir, 'STATE.md'), '# State\nPhase: 01');
266
+
267
+ const engine = new ContextEngine(tmpDir, undefined, undefined, 'backend');
268
+ const files = await engine.resolveContextFiles(PhaseType.Execute);
269
+
270
+ expect(files.state).toContain('Phase: 01');
271
+ });
272
+
273
+ it('resolves files from root .planning/ without workstream', async () => {
274
+ const { ContextEngine } = await import('./context-engine.js');
275
+ const { PhaseType } = await import('./types.js');
276
+
277
+ await mkdir(join(tmpDir, '.planning'), { recursive: true });
278
+ await writeFile(join(tmpDir, '.planning', 'STATE.md'), '# State\nPhase: 02');
279
+
280
+ const engine = new ContextEngine(tmpDir);
281
+ const files = await engine.resolveContextFiles(PhaseType.Execute);
282
+
283
+ expect(files.state).toContain('Phase: 02');
284
+ });
285
+ });
@@ -0,0 +1,161 @@
1
+ import { describe, it, expect, afterEach } from 'vitest';
2
+ import { WebSocket } from 'ws';
3
+ import { WSTransport } from './ws-transport.js';
4
+ import { GSDEventType, type GSDEvent, type GSDEventBase } from './types.js';
5
+
6
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
7
+
8
+ function makeBase(overrides: Partial<GSDEventBase> = {}): Omit<GSDEventBase, 'type'> {
9
+ return {
10
+ timestamp: '2025-06-15T14:30:45.123Z',
11
+ sessionId: 'test-session',
12
+ ...overrides,
13
+ };
14
+ }
15
+
16
+ /** Connect a WS client and resolve once open. */
17
+ function connectClient(port: number): Promise<WebSocket> {
18
+ return new Promise((resolve, reject) => {
19
+ const ws = new WebSocket(`ws://127.0.0.1:${port}`);
20
+ ws.on('open', () => resolve(ws));
21
+ ws.on('error', reject);
22
+ });
23
+ }
24
+
25
+ /** Wait for the next message on a WS client. */
26
+ function waitForMessage(ws: WebSocket): Promise<string> {
27
+ return new Promise((resolve, reject) => {
28
+ const timeout = setTimeout(() => reject(new Error('message timeout')), 5000);
29
+ ws.once('message', (data) => {
30
+ clearTimeout(timeout);
31
+ resolve(data.toString());
32
+ });
33
+ });
34
+ }
35
+
36
+ // Track transports for cleanup
37
+ const activeTransports: WSTransport[] = [];
38
+
39
+ afterEach(() => {
40
+ for (const t of activeTransports) {
41
+ try { t.close(); } catch { /* ignore */ }
42
+ }
43
+ activeTransports.length = 0;
44
+ });
45
+
46
+ // ─── Tests ───────────────────────────────────────────────────────────────────
47
+
48
+ describe('WSTransport', () => {
49
+ it('start() creates a server on the specified port', async () => {
50
+ const transport = new WSTransport({ port: 0 }); // dynamic port
51
+ activeTransports.push(transport);
52
+
53
+ await transport.start();
54
+
55
+ // Server is listening — we can connect a client
56
+ const address = (transport as any).server?.address();
57
+ expect(address).toBeTruthy();
58
+ expect(typeof address.port).toBe('number');
59
+ expect(address.port).toBeGreaterThan(0);
60
+ });
61
+
62
+ it('onEvent broadcasts JSON to connected client', async () => {
63
+ const transport = new WSTransport({ port: 0 });
64
+ activeTransports.push(transport);
65
+ await transport.start();
66
+
67
+ const address = (transport as any).server?.address();
68
+ const client = await connectClient(address.port);
69
+
70
+ const event: GSDEvent = {
71
+ ...makeBase(),
72
+ type: GSDEventType.SessionInit,
73
+ model: 'claude-sonnet-4-20250514',
74
+ tools: ['Read', 'Write'],
75
+ cwd: '/tmp/test',
76
+ } as GSDEvent;
77
+
78
+ const msgPromise = waitForMessage(client);
79
+ transport.onEvent(event);
80
+
81
+ const received = await msgPromise;
82
+ const parsed = JSON.parse(received);
83
+
84
+ expect(parsed.type).toBe('session_init');
85
+ expect(parsed.model).toBe('claude-sonnet-4-20250514');
86
+ expect(parsed.tools).toEqual(['Read', 'Write']);
87
+
88
+ client.close();
89
+ });
90
+
91
+ it('onEvent handles no connected clients without error', async () => {
92
+ const transport = new WSTransport({ port: 0 });
93
+ activeTransports.push(transport);
94
+ await transport.start();
95
+
96
+ // No clients connected — should not throw
97
+ expect(() => {
98
+ transport.onEvent({
99
+ ...makeBase(),
100
+ type: GSDEventType.MilestoneStart,
101
+ phaseCount: 2,
102
+ prompt: 'test',
103
+ } as GSDEvent);
104
+ }).not.toThrow();
105
+ });
106
+
107
+ it('close() shuts down the server', async () => {
108
+ const transport = new WSTransport({ port: 0 });
109
+ // Don't push to activeTransports — we close manually
110
+
111
+ await transport.start();
112
+ const address = (transport as any).server?.address();
113
+ expect(address).toBeTruthy();
114
+
115
+ transport.close();
116
+
117
+ // Server should be null after close
118
+ expect((transport as any).server).toBeNull();
119
+
120
+ // Connecting should fail
121
+ await expect(connectClient(address.port)).rejects.toThrow();
122
+ });
123
+
124
+ it('close() before start() does not throw', () => {
125
+ const transport = new WSTransport({ port: 0 });
126
+ expect(() => transport.close()).not.toThrow();
127
+ });
128
+
129
+ it('broadcasts to multiple connected clients', async () => {
130
+ const transport = new WSTransport({ port: 0 });
131
+ activeTransports.push(transport);
132
+ await transport.start();
133
+
134
+ const address = (transport as any).server?.address();
135
+ const client1 = await connectClient(address.port);
136
+ const client2 = await connectClient(address.port);
137
+
138
+ const event: GSDEvent = {
139
+ ...makeBase(),
140
+ type: GSDEventType.MilestoneComplete,
141
+ success: true,
142
+ totalCostUsd: 5.0,
143
+ totalDurationMs: 120000,
144
+ phasesCompleted: 3,
145
+ } as GSDEvent;
146
+
147
+ const msg1Promise = waitForMessage(client1);
148
+ const msg2Promise = waitForMessage(client2);
149
+
150
+ transport.onEvent(event);
151
+
152
+ const [msg1, msg2] = await Promise.all([msg1Promise, msg2Promise]);
153
+
154
+ expect(JSON.parse(msg1).type).toBe('milestone_complete');
155
+ expect(JSON.parse(msg2).type).toBe('milestone_complete');
156
+ expect(JSON.parse(msg1).success).toBe(true);
157
+
158
+ client1.close();
159
+ client2.close();
160
+ });
161
+ });
@@ -0,0 +1,93 @@
1
+ /**
2
+ * WebSocket Transport — broadcasts GSD events as JSON over WebSocket.
3
+ *
4
+ * Implements TransportHandler. Starts a WebSocketServer on a given port
5
+ * and JSON-serializes each event to all connected clients.
6
+ */
7
+
8
+ import { WebSocketServer, WebSocket } from 'ws';
9
+ import type { GSDEvent, TransportHandler } from './types.js';
10
+
11
+ export interface WSTransportOptions {
12
+ port: number;
13
+ }
14
+
15
+ export class WSTransport implements TransportHandler {
16
+ private readonly port: number;
17
+ private server: WebSocketServer | null = null;
18
+ private closing = false;
19
+
20
+ constructor(options: WSTransportOptions) {
21
+ this.port = options.port;
22
+ }
23
+
24
+ /**
25
+ * Start the WebSocket server on the configured port.
26
+ * Resolves once the server is listening.
27
+ */
28
+ async start(): Promise<void> {
29
+ if (this.closing) return;
30
+
31
+ return new Promise<void>((resolve, reject) => {
32
+ try {
33
+ this.server = new WebSocketServer({ port: this.port });
34
+ this.server.on('listening', () => resolve());
35
+ this.server.on('error', (err) => reject(err));
36
+ } catch (err) {
37
+ reject(err);
38
+ }
39
+ });
40
+ }
41
+
42
+ /**
43
+ * Broadcast a GSD event as JSON to all connected clients.
44
+ * Never throws — wraps each client.send in try/catch.
45
+ */
46
+ onEvent(event: GSDEvent): void {
47
+ try {
48
+ if (!this.server) return;
49
+
50
+ const payload = JSON.stringify(event);
51
+
52
+ for (const client of this.server.clients) {
53
+ if (client.readyState === WebSocket.OPEN) {
54
+ try {
55
+ client.send(payload);
56
+ } catch {
57
+ // Ignore individual client send errors
58
+ }
59
+ }
60
+ }
61
+ } catch {
62
+ // TransportHandler contract: onEvent must never throw
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Close all client connections and shut down the server.
68
+ * Safe to call before start() — sets a closing flag.
69
+ */
70
+ close(): void {
71
+ this.closing = true;
72
+
73
+ if (!this.server) return;
74
+
75
+ // Terminate all clients
76
+ for (const client of this.server.clients) {
77
+ try {
78
+ client.terminate();
79
+ } catch {
80
+ // Ignore client close errors
81
+ }
82
+ }
83
+
84
+ // Close the server
85
+ try {
86
+ this.server.close();
87
+ } catch {
88
+ // Ignore server close errors
89
+ }
90
+
91
+ this.server = null;
92
+ }
93
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "strict": true,
7
+ "outDir": "dist",
8
+ "rootDir": "src",
9
+ "declaration": true,
10
+ "declarationMap": true,
11
+ "sourceMap": true,
12
+ "esModuleInterop": true,
13
+ "skipLibCheck": true,
14
+ "forceConsistentCasingInFileNames": true,
15
+ "resolveJsonModule": true,
16
+ "isolatedModules": true
17
+ },
18
+ "include": ["src/**/*.ts"],
19
+ "exclude": ["src/**/*.test.ts", "src/**/*.integration.test.ts", "dist", "node_modules"]
20
+ }