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,365 @@
1
+ /**
2
+ * Cross-module handler tests for code decomposed from the legacy `stubs.ts` module.
3
+ *
4
+ * Each suite imports real handlers from their domain modules and exercises behavior
5
+ * against temp fixtures (no standalone stubs).
6
+ */
7
+
8
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
9
+ import { mkdtemp, writeFile, mkdir, rm } from 'node:fs/promises';
10
+ import { join } from 'node:path';
11
+ import { tmpdir } from 'node:os';
12
+
13
+ import { agentSkills } from './skills.js';
14
+ import { roadmapUpdatePlanProgress } from './roadmap-update-plan-progress.js';
15
+ import { requirementsMarkComplete } from './roadmap.js';
16
+ import { statePlannedPhase } from './state-mutation.js';
17
+ import { verifySchemaDrift } from './verify.js';
18
+ import { todoMatchPhase, statsJson, progressBar } from './progress.js';
19
+ import { milestoneComplete } from './phase-lifecycle.js';
20
+ import { summaryExtract, historyDigest } from './summary.js';
21
+ import { commitToSubrepo } from './commit.js';
22
+ import {
23
+ workstreamList, workstreamCreate, workstreamSet,
24
+ workstreamStatus, workstreamComplete,
25
+ } from './workstream.js';
26
+ import { docsInit } from './docs-init.js';
27
+ import { websearch } from './websearch.js';
28
+
29
+ let tmpDir: string;
30
+
31
+ beforeEach(async () => {
32
+ tmpDir = await mkdtemp(join(tmpdir(), 'gsd-stubs-'));
33
+ await mkdir(join(tmpDir, '.planning', 'phases', '09-foundation'), { recursive: true });
34
+ await mkdir(join(tmpDir, '.planning', 'phases', '10-queries'), { recursive: true });
35
+
36
+ await writeFile(join(tmpDir, '.planning', 'config.json'), JSON.stringify({
37
+ model_profile: 'balanced',
38
+ commit_docs: false,
39
+ git: { branching_strategy: 'none' },
40
+ workflow: {},
41
+ }));
42
+ await writeFile(join(tmpDir, '.planning', 'STATE.md'), '---\nmilestone: v3.0\n---\n# State\n');
43
+ await writeFile(join(tmpDir, '.planning', 'ROADMAP.md'), [
44
+ '# Roadmap',
45
+ '## v3.0: Test',
46
+ '### Phase 9: Foundation',
47
+ '**Goal:** Build it',
48
+ '- [ ] Plan 1',
49
+ '### Phase 10: Queries',
50
+ '**Goal:** Query it',
51
+ ].join('\n'));
52
+ await writeFile(join(tmpDir, '.planning', 'REQUIREMENTS.md'), [
53
+ '# Requirements',
54
+ '- [ ] REQ-01: First requirement',
55
+ '- [ ] REQ-02: Second requirement',
56
+ '- [x] REQ-03: Already done',
57
+ ].join('\n'));
58
+
59
+ await writeFile(join(tmpDir, '.planning', 'phases', '09-foundation', '09-01-PLAN.md'), '---\nphase: 09\nplan: 01\ntype: execute\nmust_haves:\n truths: []\n---');
60
+ await writeFile(join(tmpDir, '.planning', 'phases', '09-foundation', '09-01-SUMMARY.md'), '# Done');
61
+ await writeFile(join(tmpDir, '.planning', 'phases', '10-queries', '10-01-PLAN.md'), '---\nphase: 10\nplan: 01\ntype: execute\nmust_haves:\n truths: []\n---');
62
+ });
63
+
64
+ afterEach(async () => {
65
+ await rm(tmpDir, { recursive: true, force: true });
66
+ });
67
+
68
+ // ─── skills.ts ───────────────────────────────────────────────────────────
69
+
70
+ describe('agentSkills', () => {
71
+ it('returns valid QueryResult with skills array', async () => {
72
+ const result = await agentSkills(['gsd-executor'], tmpDir);
73
+ const data = result.data as Record<string, unknown>;
74
+ expect(Array.isArray(data.skills)).toBe(true);
75
+ expect(typeof data.skill_count).toBe('number');
76
+ expect(data.agent_type).toBe('gsd-executor');
77
+ });
78
+ });
79
+
80
+ // ─── roadmap.ts ──────────────────────────────────────────────────────────
81
+
82
+ describe('roadmapUpdatePlanProgress', () => {
83
+ it('returns QueryResult without error', async () => {
84
+ const result = await roadmapUpdatePlanProgress(['9'], tmpDir);
85
+ expect(result.data).toBeDefined();
86
+ const data = result.data as Record<string, unknown>;
87
+ expect(typeof data.updated).toBe('boolean');
88
+ });
89
+
90
+ it('throws when no phase arg', async () => {
91
+ await expect(roadmapUpdatePlanProgress([], tmpDir)).rejects.toThrow();
92
+ });
93
+ });
94
+
95
+ describe('requirementsMarkComplete', () => {
96
+ it('returns QueryResult without error', async () => {
97
+ const result = await requirementsMarkComplete(['REQ-01'], tmpDir);
98
+ const data = result.data as Record<string, unknown>;
99
+ expect(typeof data.updated).toBe('boolean');
100
+ });
101
+
102
+ it('throws when no IDs provided', async () => {
103
+ await expect(requirementsMarkComplete([], tmpDir)).rejects.toThrow();
104
+ });
105
+ });
106
+
107
+ // ─── state-mutation.ts ───────────────────────────────────────────────────
108
+
109
+ describe('statePlannedPhase', () => {
110
+ it('returns cmdStatePlannedPhase-shaped data', async () => {
111
+ const result = await statePlannedPhase(['--phase', '10', '--name', 'queries', '--plans', '2'], tmpDir);
112
+ const data = result.data as Record<string, unknown>;
113
+ expect(Array.isArray(data.updated)).toBe(true);
114
+ expect(data.phase).toBe('10');
115
+ expect(data.plan_count).toBe(2);
116
+ });
117
+
118
+ it('returns error when --phase is missing', async () => {
119
+ const result = await statePlannedPhase([], tmpDir);
120
+ const data = result.data as Record<string, unknown>;
121
+ expect(data.error).toMatch(/phase required/);
122
+ });
123
+ });
124
+
125
+ // ─── verify.ts ───────────────────────────────────────────────────────────
126
+
127
+ describe('verifySchemaDrift', () => {
128
+ it('returns drift_detected shape (cmdVerifySchemaDrift parity)', async () => {
129
+ const result = await verifySchemaDrift(['9'], tmpDir);
130
+ const data = result.data as Record<string, unknown>;
131
+ expect(typeof data.drift_detected).toBe('boolean');
132
+ expect(typeof data.blocking).toBe('boolean');
133
+ expect(Array.isArray(data.schema_files)).toBe(true);
134
+ });
135
+ });
136
+
137
+ // ─── progress.ts ─────────────────────────────────────────────────────────
138
+
139
+ describe('todoMatchPhase', () => {
140
+ it('returns matches and todo_count (cmdTodoMatchPhase parity)', async () => {
141
+ const result = await todoMatchPhase(['9'], tmpDir);
142
+ const data = result.data as Record<string, unknown>;
143
+ expect(Array.isArray(data.matches)).toBe(true);
144
+ expect(data.phase).toBe('9');
145
+ expect(typeof data.todo_count).toBe('number');
146
+ });
147
+ });
148
+
149
+ describe('statsJson', () => {
150
+ it('returns cmdStats JSON shape with phases table and git fields', async () => {
151
+ const result = await statsJson([], tmpDir);
152
+ const data = result.data as Record<string, unknown>;
153
+ expect(typeof data.milestone_version).toBe('string');
154
+ expect(Array.isArray(data.phases)).toBe(true);
155
+ expect(typeof data.phases_total).toBe('number');
156
+ expect(typeof data.total_plans).toBe('number');
157
+ expect(typeof data.percent).toBe('number');
158
+ expect((data.phases_total as number)).toBeGreaterThanOrEqual(2);
159
+ expect(typeof data.git_commits).toBe('number');
160
+ });
161
+ });
162
+
163
+ describe('progressBar', () => {
164
+ it('returns bar string and percent', async () => {
165
+ const result = await progressBar([], tmpDir);
166
+ const data = result.data as Record<string, unknown>;
167
+ expect(typeof data.bar).toBe('string');
168
+ expect(typeof data.percent).toBe('number');
169
+ expect(data.bar as string).toContain('[');
170
+ });
171
+ });
172
+
173
+ // ─── summary.ts ──────────────────────────────────────────────────────────
174
+
175
+ describe('summaryExtract', () => {
176
+ it('returns error when file not found', async () => {
177
+ const result = await summaryExtract(['.planning/nonexistent.md'], tmpDir);
178
+ const data = result.data as Record<string, unknown>;
179
+ expect(data.error).toBeDefined();
180
+ });
181
+
182
+ it('extracts frontmatter fields from an existing summary file', async () => {
183
+ const summaryPath = join(tmpDir, '.planning', 'phases', '09-foundation', '09-01-SUMMARY.md');
184
+ await writeFile(
185
+ summaryPath,
186
+ ['---', 'phase: "09"', 'one-liner: Built it.', 'key-files:', ' - x.ts', '---', '', '# Summary', ''].join('\n'),
187
+ 'utf-8',
188
+ );
189
+ const result = await summaryExtract(['.planning/phases/09-foundation/09-01-SUMMARY.md'], tmpDir);
190
+ const data = result.data as Record<string, unknown>;
191
+ expect(data.one_liner).toBe('Built it.');
192
+ expect(data.key_files).toEqual(['x.ts']);
193
+ });
194
+ });
195
+
196
+ describe('historyDigest', () => {
197
+ it('returns phases object with completed summaries', async () => {
198
+ const result = await historyDigest([], tmpDir);
199
+ const data = result.data as Record<string, unknown>;
200
+ expect(typeof data.phases).toBe('object');
201
+ expect(Array.isArray(data.decisions)).toBe(true);
202
+ expect(Array.isArray(data.tech_stack)).toBe(true);
203
+ });
204
+ });
205
+
206
+ // ─── workstream.ts ───────────────────────────────────────────────────────
207
+
208
+ describe('workstream handlers', () => {
209
+ it('workstreamList returns workstreams array', async () => {
210
+ const result = await workstreamList([], tmpDir);
211
+ const data = result.data as Record<string, unknown>;
212
+ expect(Array.isArray(data.workstreams)).toBe(true);
213
+ });
214
+
215
+ it('workstreamCreate creates a directory', async () => {
216
+ const result = await workstreamCreate(['my-ws'], tmpDir);
217
+ const data = result.data as Record<string, unknown>;
218
+ expect(typeof data.created).toBe('boolean');
219
+ });
220
+
221
+ it('workstreamCreate rejects path traversal', async () => {
222
+ const result = await workstreamCreate(['../../bad'], tmpDir);
223
+ const data = result.data as Record<string, unknown>;
224
+ expect(data.created).toBe(false);
225
+ });
226
+
227
+ it('workstreamSet returns set=true for existing workstream', async () => {
228
+ await mkdir(join(tmpDir, '.planning', 'workstreams', 'backend'), { recursive: true });
229
+ const result = await workstreamSet(['backend'], tmpDir);
230
+ const data = result.data as Record<string, unknown>;
231
+ expect(data.set).toBe(true);
232
+ expect(data.active).toBe('backend');
233
+ });
234
+
235
+ it('workstreamStatus returns found boolean', async () => {
236
+ const result = await workstreamStatus(['nonexistent'], tmpDir);
237
+ const data = result.data as Record<string, unknown>;
238
+ expect(typeof data.found).toBe('boolean');
239
+ });
240
+
241
+ it('workstreamComplete archives existing workstream', async () => {
242
+ await mkdir(join(tmpDir, '.planning', 'workstreams', 'my-ws', 'phases'), { recursive: true });
243
+ await writeFile(join(tmpDir, '.planning', 'workstreams', 'my-ws', 'STATE.md'), '# State\n');
244
+ const result = await workstreamComplete(['my-ws'], tmpDir);
245
+ const data = result.data as Record<string, unknown>;
246
+ expect(data.completed).toBe(true);
247
+ expect(data.archived_to).toBeDefined();
248
+ });
249
+ });
250
+
251
+ // ─── init.ts ─────────────────────────────────────────────────────────────
252
+
253
+ describe('docsInit', () => {
254
+ it('returns docs context matching gsd-tools docs-init', async () => {
255
+ const result = await docsInit([], tmpDir);
256
+ const data = result.data as Record<string, unknown>;
257
+ expect(typeof data.planning_exists).toBe('boolean');
258
+ expect(data.project_root).toBe(tmpDir);
259
+ expect(typeof data.doc_writer_model).toBe('string');
260
+ expect(Array.isArray(data.existing_docs)).toBe(true);
261
+ expect(data.project_type).toBeDefined();
262
+ expect(data.doc_tooling).toBeDefined();
263
+ expect(Array.isArray(data.monorepo_workspaces)).toBe(true);
264
+ expect(typeof data.agents_installed).toBe('boolean');
265
+ expect(Array.isArray(data.missing_agents)).toBe(true);
266
+ });
267
+ });
268
+
269
+ // ─── websearch.ts ────────────────────────────────────────────────────────
270
+
271
+ describe('websearch', () => {
272
+ const originalEnv = process.env.BRAVE_API_KEY;
273
+
274
+ afterEach(() => {
275
+ if (originalEnv === undefined) {
276
+ delete process.env.BRAVE_API_KEY;
277
+ } else {
278
+ process.env.BRAVE_API_KEY = originalEnv;
279
+ }
280
+ vi.restoreAllMocks();
281
+ });
282
+
283
+ it('returns available:false when BRAVE_API_KEY is not set', async () => {
284
+ delete process.env.BRAVE_API_KEY;
285
+ const result = await websearch([], tmpDir);
286
+ const data = result.data as Record<string, unknown>;
287
+ expect(data.available).toBe(false);
288
+ expect(data.reason).toBe('BRAVE_API_KEY not set');
289
+ });
290
+
291
+ it('returns error when query is empty', async () => {
292
+ process.env.BRAVE_API_KEY = 'test-key';
293
+ const result = await websearch([], tmpDir);
294
+ const data = result.data as Record<string, unknown>;
295
+ expect(data.available).toBe(false);
296
+ expect(data.error).toBe('Query required');
297
+ });
298
+
299
+ it('returns results on successful API call', async () => {
300
+ process.env.BRAVE_API_KEY = 'test-key';
301
+ const mockResults = {
302
+ web: {
303
+ results: [
304
+ { title: 'Result 1', url: 'https://example.com', description: 'Desc 1', age: '2d' },
305
+ { title: 'Result 2', url: 'https://example.org', description: 'Desc 2' },
306
+ ],
307
+ },
308
+ };
309
+
310
+ vi.spyOn(globalThis, 'fetch').mockResolvedValue({
311
+ ok: true,
312
+ json: async () => mockResults,
313
+ } as Response);
314
+
315
+ const result = await websearch(['typescript generics'], tmpDir);
316
+ const data = result.data as Record<string, unknown>;
317
+ expect(data.available).toBe(true);
318
+ expect(data.query).toBe('typescript generics');
319
+ expect(data.count).toBe(2);
320
+ const results = data.results as Array<Record<string, unknown>>;
321
+ expect(results[0].title).toBe('Result 1');
322
+ expect(results[0].age).toBe('2d');
323
+ expect(results[1].age).toBeNull();
324
+ });
325
+
326
+ it('passes --limit and --freshness params to API', async () => {
327
+ process.env.BRAVE_API_KEY = 'test-key';
328
+
329
+ vi.spyOn(globalThis, 'fetch').mockResolvedValue({
330
+ ok: true,
331
+ json: async () => ({ web: { results: [] } }),
332
+ } as Response);
333
+
334
+ await websearch(['query', '--limit', '5', '--freshness', 'week'], tmpDir);
335
+
336
+ const url = new URL((globalThis.fetch as ReturnType<typeof vi.fn>).mock.calls[0][0] as string);
337
+ expect(url.searchParams.get('count')).toBe('5');
338
+ expect(url.searchParams.get('freshness')).toBe('week');
339
+ });
340
+
341
+ it('returns error on non-ok response', async () => {
342
+ process.env.BRAVE_API_KEY = 'test-key';
343
+
344
+ vi.spyOn(globalThis, 'fetch').mockResolvedValue({
345
+ ok: false,
346
+ status: 429,
347
+ } as Response);
348
+
349
+ const result = await websearch(['rate limited query'], tmpDir);
350
+ const data = result.data as Record<string, unknown>;
351
+ expect(data.available).toBe(false);
352
+ expect(data.error).toBe('API error: 429');
353
+ });
354
+
355
+ it('returns error on network failure', async () => {
356
+ process.env.BRAVE_API_KEY = 'test-key';
357
+
358
+ vi.spyOn(globalThis, 'fetch').mockRejectedValue(new Error('ECONNREFUSED'));
359
+
360
+ const result = await websearch(['network fail'], tmpDir);
361
+ const data = result.data as Record<string, unknown>;
362
+ expect(data.available).toBe(false);
363
+ expect(data.error).toBe('ECONNREFUSED');
364
+ });
365
+ });
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Detect user-added files under GSD-managed install dirs not listed in the manifest.
3
+ *
4
+ * Port of `detect-custom-files` from `get-shit-done/bin/gsd-tools.cjs` (lines 1161–1239).
5
+ */
6
+
7
+ import { existsSync, readdirSync, readFileSync } from 'node:fs';
8
+ import { join, relative, resolve } from 'node:path';
9
+
10
+ import type { QueryHandler } from './utils.js';
11
+
12
+ const GSD_MANAGED_DIRS = [
13
+ 'get-shit-done',
14
+ 'agents',
15
+ join('commands', 'gsd'),
16
+ 'hooks',
17
+ 'command',
18
+ 'skills',
19
+ ];
20
+
21
+ function walkDir(dir: string, baseDir: string): string[] {
22
+ const results: string[] = [];
23
+ if (!existsSync(dir)) return results;
24
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
25
+ const fullPath = join(dir, entry.name);
26
+ if (entry.isDirectory()) {
27
+ results.push(...walkDir(fullPath, baseDir));
28
+ } else {
29
+ const relPath = relative(baseDir, fullPath).split('\\').join('/');
30
+ results.push(relPath);
31
+ }
32
+ }
33
+ return results;
34
+ }
35
+
36
+ /**
37
+ * Args: `--config-dir <path>` (required) — runtime config directory to scan.
38
+ */
39
+ export const detectCustomFiles: QueryHandler = async (args) => {
40
+ const configDirIdx = args.indexOf('--config-dir');
41
+ const configDir = configDirIdx !== -1 ? args[configDirIdx + 1] : null;
42
+ if (!configDir) {
43
+ return { data: { error: 'Usage: detect-custom-files --config-dir <path>' } };
44
+ }
45
+
46
+ const resolvedConfigDir = resolve(configDir);
47
+ if (!existsSync(resolvedConfigDir)) {
48
+ return { data: { error: `Config directory not found: ${resolvedConfigDir}` } };
49
+ }
50
+
51
+ const manifestPath = join(resolvedConfigDir, 'gsd-file-manifest.json');
52
+ if (!existsSync(manifestPath)) {
53
+ return {
54
+ data: {
55
+ custom_files: [] as string[],
56
+ custom_count: 0,
57
+ manifest_found: false,
58
+ },
59
+ };
60
+ }
61
+
62
+ let manifest: { version?: string; files?: Record<string, unknown> };
63
+ try {
64
+ manifest = JSON.parse(readFileSync(manifestPath, 'utf8')) as { version?: string; files?: Record<string, unknown> };
65
+ } catch {
66
+ return {
67
+ data: {
68
+ custom_files: [] as string[],
69
+ custom_count: 0,
70
+ manifest_found: false,
71
+ error: 'manifest parse error',
72
+ },
73
+ };
74
+ }
75
+
76
+ const manifestKeys = new Set(Object.keys(manifest.files || {}));
77
+
78
+ const customFiles: string[] = [];
79
+ for (const managedDir of GSD_MANAGED_DIRS) {
80
+ const absDir = join(resolvedConfigDir, managedDir);
81
+ if (!existsSync(absDir)) continue;
82
+ for (const relPath of walkDir(absDir, resolvedConfigDir)) {
83
+ if (!manifestKeys.has(relPath)) {
84
+ customFiles.push(relPath);
85
+ }
86
+ }
87
+ }
88
+
89
+ return {
90
+ data: {
91
+ custom_files: customFiles,
92
+ custom_count: customFiles.length,
93
+ manifest_found: true,
94
+ manifest_version: manifest.version ?? null,
95
+ },
96
+ };
97
+ };
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Unit tests for `detect.phase-type` (decision-routing audit §3.6).
3
+ */
4
+
5
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
6
+ import { mkdir, writeFile, rm } from 'node:fs/promises';
7
+ import { join } from 'node:path';
8
+ import { tmpdir } from 'node:os';
9
+ import { detectPhaseType } from './detect-phase-type.js';
10
+
11
+ describe('detectPhaseType', () => {
12
+ let projectDir: string;
13
+
14
+ beforeEach(async () => {
15
+ projectDir = join(tmpdir(), `gsd-detect-phase-${Date.now()}-${Math.random().toString(36).slice(2)}`);
16
+ await mkdir(join(projectDir, '.planning', 'phases'), { recursive: true });
17
+ });
18
+
19
+ afterEach(async () => {
20
+ await rm(projectDir, { recursive: true, force: true });
21
+ });
22
+
23
+ it('throws when phase arg is missing', async () => {
24
+ await expect(detectPhaseType([], projectDir)).rejects.toThrow();
25
+ });
26
+
27
+ it('returns all false/null/[] when phase dir does not exist', async () => {
28
+ const { data } = await detectPhaseType(['99'], projectDir);
29
+ const d = data as Record<string, unknown>;
30
+ expect(d.has_frontend).toBe(false);
31
+ expect(d.has_schema).toBe(false);
32
+ expect(d.schema_orm).toBeNull();
33
+ expect(d.schema_files).toEqual([]);
34
+ expect(d.frontend_indicators).toEqual([]);
35
+ expect(d.has_api).toBe(false);
36
+ expect(d.has_infra).toBe(false);
37
+ });
38
+
39
+ it('sets has_frontend true when ROADMAP heading contains UI keyword', async () => {
40
+ const roadmapContent = `# Project Roadmap\n\n## Phase 01: UI Dashboard\n\nSome content\n`;
41
+ await writeFile(join(projectDir, '.planning', 'ROADMAP.md'), roadmapContent, 'utf-8');
42
+ await mkdir(join(projectDir, '.planning', 'phases', '01-ui-dashboard'), { recursive: true });
43
+
44
+ const { data } = await detectPhaseType(['1'], projectDir);
45
+ const d = data as Record<string, unknown>;
46
+ expect(d.has_frontend).toBe(true);
47
+ expect((d.frontend_indicators as string[]).length).toBeGreaterThan(0);
48
+ });
49
+
50
+ it('sets has_schema true and schema_orm prisma when prisma schema file found', async () => {
51
+ const phaseDir = join(projectDir, '.planning', 'phases', '02-database');
52
+ await mkdir(join(phaseDir, 'prisma'), { recursive: true });
53
+ await writeFile(join(phaseDir, 'prisma', 'schema.prisma'), 'model User {}', 'utf-8');
54
+
55
+ const { data } = await detectPhaseType(['2'], projectDir);
56
+ const d = data as Record<string, unknown>;
57
+ expect(d.has_schema).toBe(true);
58
+ expect(d.schema_orm).toBe('prisma');
59
+ expect((d.schema_files as string[]).length).toBeGreaterThan(0);
60
+ });
61
+
62
+ it('sets has_frontend true when UI-SPEC.md is present in phase dir', async () => {
63
+ const phaseDir = join(projectDir, '.planning', 'phases', '03-features');
64
+ await mkdir(phaseDir, { recursive: true });
65
+ await writeFile(join(phaseDir, 'UI-SPEC.md'), '# UI Spec', 'utf-8');
66
+
67
+ const { data } = await detectPhaseType(['3'], projectDir);
68
+ const d = data as Record<string, unknown>;
69
+ expect(d.has_frontend).toBe(true);
70
+ });
71
+
72
+ it('sets has_api true when route file found in phase dir', async () => {
73
+ const phaseDir = join(projectDir, '.planning', 'phases', '04-api');
74
+ await mkdir(phaseDir, { recursive: true });
75
+ await writeFile(join(phaseDir, 'user.route.ts'), 'export {}', 'utf-8');
76
+
77
+ const { data } = await detectPhaseType(['4'], projectDir);
78
+ const d = data as Record<string, unknown>;
79
+ expect(d.has_api).toBe(true);
80
+ });
81
+
82
+ it('sets has_infra true when docker file found in phase dir', async () => {
83
+ const phaseDir = join(projectDir, '.planning', 'phases', '05-infra');
84
+ await mkdir(phaseDir, { recursive: true });
85
+ await writeFile(join(phaseDir, 'dockerfile.yml'), '', 'utf-8');
86
+
87
+ const { data } = await detectPhaseType(['5'], projectDir);
88
+ const d = data as Record<string, unknown>;
89
+ expect(d.has_infra).toBe(true);
90
+ });
91
+
92
+ it('returns push_command null (reserved field)', async () => {
93
+ await mkdir(join(projectDir, '.planning', 'phases', '06-misc'), { recursive: true });
94
+ const { data } = await detectPhaseType(['6'], projectDir);
95
+ const d = data as Record<string, unknown>;
96
+ expect(d.push_command).toBeNull();
97
+ });
98
+
99
+ it('returns correct phase field in output', async () => {
100
+ await mkdir(join(projectDir, '.planning', 'phases', '07-test'), { recursive: true });
101
+ const { data } = await detectPhaseType(['7'], projectDir);
102
+ const d = data as Record<string, unknown>;
103
+ expect(d.phase).toBe('07');
104
+ });
105
+ });