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,645 @@
1
+ /**
2
+ * Verification query handlers — plan structure, phase completeness, artifact checks.
3
+ *
4
+ * Ported from get-shit-done/bin/lib/verify.cjs.
5
+ * Provides plan validation, phase completeness checking, and artifact verification
6
+ * as native TypeScript query handlers registered in the SDK query registry.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import { verifyPlanStructure, verifyPhaseCompleteness, verifyArtifacts } from './verify.js';
11
+ *
12
+ * const result = await verifyPlanStructure(['path/to/plan.md'], '/project');
13
+ * // { data: { valid: true, errors: [], warnings: [], task_count: 2, ... } }
14
+ * ```
15
+ */
16
+
17
+ import { readFile, readdir } from 'node:fs/promises';
18
+ import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
19
+ import { join, isAbsolute } from 'node:path';
20
+ import { GSDError, ErrorClassification } from '../errors.js';
21
+ import { extractFrontmatter, parseMustHavesBlock } from './frontmatter.js';
22
+ import {
23
+ comparePhaseNum,
24
+ normalizePhaseName,
25
+ phaseTokenMatches,
26
+ planningPaths,
27
+ } from './helpers.js';
28
+ import type { QueryHandler } from './utils.js';
29
+
30
+ // ─── verifyPlanStructure ───────────────────────────────────────────────────
31
+
32
+ /**
33
+ * Validate plan structure against required schema.
34
+ *
35
+ * Port of `cmdVerifyPlanStructure` from `verify.cjs` lines 108-167.
36
+ * Checks required frontmatter fields, task XML elements, wave/depends_on
37
+ * consistency, and autonomous/checkpoint consistency.
38
+ *
39
+ * @param args - args[0]: file path (required)
40
+ * @param projectDir - Project root directory
41
+ * @returns QueryResult with { valid, errors, warnings, task_count, tasks, frontmatter_fields }
42
+ * @throws GSDError with Validation classification if file path missing
43
+ */
44
+ export const verifyPlanStructure: QueryHandler = async (args, projectDir) => {
45
+ const filePath = args[0];
46
+ if (!filePath) {
47
+ throw new GSDError('file path required', ErrorClassification.Validation);
48
+ }
49
+
50
+ // T-12-01: Null byte rejection on file paths
51
+ if (filePath.includes('\0')) {
52
+ throw new GSDError('file path contains null bytes', ErrorClassification.Validation);
53
+ }
54
+
55
+ const fullPath = isAbsolute(filePath) ? filePath : join(projectDir, filePath);
56
+
57
+ let content: string;
58
+ try {
59
+ content = await readFile(fullPath, 'utf-8');
60
+ } catch {
61
+ return { data: { error: 'File not found', path: filePath } };
62
+ }
63
+
64
+ const fm = extractFrontmatter(content);
65
+ const errors: string[] = [];
66
+ const warnings: string[] = [];
67
+
68
+ // Check required frontmatter fields
69
+ const required = ['phase', 'plan', 'type', 'wave', 'depends_on', 'files_modified', 'autonomous', 'must_haves'];
70
+ for (const field of required) {
71
+ if (fm[field] === undefined) errors.push(`Missing required frontmatter field: ${field}`);
72
+ }
73
+
74
+ // Parse and check task elements
75
+ // T-12-03: Use non-greedy [\s\S]*? to avoid catastrophic backtracking
76
+ const taskPattern = /<task[^>]*>([\s\S]*?)<\/task>/g;
77
+ const tasks: Array<{ name: string; hasFiles: boolean; hasAction: boolean; hasVerify: boolean; hasDone: boolean }> = [];
78
+ let taskMatch: RegExpExecArray | null;
79
+ while ((taskMatch = taskPattern.exec(content)) !== null) {
80
+ const taskContent = taskMatch[1];
81
+ const nameMatch = taskContent.match(/<name>([\s\S]*?)<\/name>/);
82
+ const taskName = nameMatch ? nameMatch[1].trim() : 'unnamed';
83
+ const hasFiles = /<files>/.test(taskContent);
84
+ const hasAction = /<action>/.test(taskContent);
85
+ const hasVerify = /<verify>/.test(taskContent);
86
+ const hasDone = /<done>/.test(taskContent);
87
+
88
+ if (!nameMatch) errors.push('Task missing <name> element');
89
+ if (!hasAction) errors.push(`Task '${taskName}' missing <action>`);
90
+ if (!hasVerify) warnings.push(`Task '${taskName}' missing <verify>`);
91
+ if (!hasDone) warnings.push(`Task '${taskName}' missing <done>`);
92
+ if (!hasFiles) warnings.push(`Task '${taskName}' missing <files>`);
93
+
94
+ tasks.push({ name: taskName, hasFiles, hasAction, hasVerify, hasDone });
95
+ }
96
+
97
+ if (tasks.length === 0) warnings.push('No <task> elements found');
98
+
99
+ // Wave/depends_on consistency
100
+ if (fm.wave && parseInt(String(fm.wave), 10) > 1 && (!fm.depends_on || (Array.isArray(fm.depends_on) && fm.depends_on.length === 0))) {
101
+ warnings.push('Wave > 1 but depends_on is empty');
102
+ }
103
+
104
+ // Autonomous/checkpoint consistency
105
+ const hasCheckpoints = /<task\s+type=["']?checkpoint/.test(content);
106
+ if (hasCheckpoints && fm.autonomous !== 'false' && fm.autonomous !== false) {
107
+ errors.push('Has checkpoint tasks but autonomous is not false');
108
+ }
109
+
110
+ return {
111
+ data: {
112
+ valid: errors.length === 0,
113
+ errors,
114
+ warnings,
115
+ task_count: tasks.length,
116
+ tasks,
117
+ frontmatter_fields: Object.keys(fm),
118
+ },
119
+ };
120
+ };
121
+
122
+ // ─── verifyPhaseCompleteness ───────────────────────────────────────────────
123
+
124
+ /**
125
+ * Check phase completeness by matching PLAN files to SUMMARY files.
126
+ *
127
+ * Port of `cmdVerifyPhaseCompleteness` from `verify.cjs` lines 169-213.
128
+ * Scans a phase directory for PLAN and SUMMARY files, identifies incomplete
129
+ * plans (no summary) and orphan summaries (no plan).
130
+ *
131
+ * @param args - args[0]: phase number (required)
132
+ * @param projectDir - Project root directory
133
+ * @returns QueryResult with { complete, phase, plan_count, summary_count, incomplete_plans, orphan_summaries, errors, warnings }
134
+ * @throws GSDError with Validation classification if phase number missing
135
+ */
136
+ export const verifyPhaseCompleteness: QueryHandler = async (args, projectDir) => {
137
+ const phase = args[0];
138
+ if (!phase) {
139
+ throw new GSDError('phase required', ErrorClassification.Validation);
140
+ }
141
+
142
+ const phasesDir = planningPaths(projectDir).phases;
143
+ const normalized = normalizePhaseName(phase);
144
+
145
+ // Find phase directory (mirror findPhase pattern from phase.ts)
146
+ let phaseDir: string | null = null;
147
+ let phaseNumber: string = normalized;
148
+ try {
149
+ const entries = await readdir(phasesDir, { withFileTypes: true });
150
+ const dirs = entries
151
+ .filter(e => e.isDirectory())
152
+ .map(e => e.name)
153
+ .sort();
154
+ const match = dirs.find(d => phaseTokenMatches(d, normalized));
155
+ if (match) {
156
+ phaseDir = join(phasesDir, match);
157
+ // Extract phase number from directory name
158
+ const numMatch = match.match(/^(\d+[A-Z]?(?:\.\d+)*)/i);
159
+ if (numMatch) phaseNumber = numMatch[1];
160
+ }
161
+ } catch { /* phases dir doesn't exist */ }
162
+
163
+ if (!phaseDir) {
164
+ return { data: { error: 'Phase not found', phase } };
165
+ }
166
+
167
+ const errors: string[] = [];
168
+ const warnings: string[] = [];
169
+
170
+ // List plans and summaries
171
+ let files: string[];
172
+ try {
173
+ files = await readdir(phaseDir);
174
+ } catch {
175
+ return { data: { error: 'Cannot read phase directory' } };
176
+ }
177
+
178
+ const plans = files.filter(f => /-PLAN\.md$/i.test(f));
179
+ const summaries = files.filter(f => /-SUMMARY\.md$/i.test(f));
180
+
181
+ // Extract plan IDs (everything before -PLAN.md / -SUMMARY.md)
182
+ const planIds = new Set(plans.map(p => p.replace(/-PLAN\.md$/i, '')));
183
+ const summaryIds = new Set(summaries.map(s => s.replace(/-SUMMARY\.md$/i, '')));
184
+
185
+ // Plans without summaries
186
+ const incompletePlans = [...planIds].filter(id => !summaryIds.has(id));
187
+ if (incompletePlans.length > 0) {
188
+ errors.push(`Plans without summaries: ${incompletePlans.join(', ')}`);
189
+ }
190
+
191
+ // Summaries without plans (orphans)
192
+ const orphanSummaries = [...summaryIds].filter(id => !planIds.has(id));
193
+ if (orphanSummaries.length > 0) {
194
+ warnings.push(`Summaries without plans: ${orphanSummaries.join(', ')}`);
195
+ }
196
+
197
+ return {
198
+ data: {
199
+ complete: errors.length === 0,
200
+ phase: phaseNumber,
201
+ plan_count: plans.length,
202
+ summary_count: summaries.length,
203
+ incomplete_plans: incompletePlans,
204
+ orphan_summaries: orphanSummaries,
205
+ errors,
206
+ warnings,
207
+ },
208
+ };
209
+ };
210
+
211
+ // ─── verifyArtifacts ───────────────────────────────────────────────────────
212
+
213
+ /**
214
+ * Verify artifact file existence and content from must_haves.artifacts.
215
+ *
216
+ * Port of `cmdVerifyArtifacts` from `verify.cjs` lines 283-336.
217
+ * Reads must_haves.artifacts from plan frontmatter and checks each artifact
218
+ * for file existence, min_lines, contains, and exports.
219
+ *
220
+ * @param args - args[0]: plan file path (required)
221
+ * @param projectDir - Project root directory
222
+ * @returns QueryResult with { all_passed, passed, total, artifacts }
223
+ * @throws GSDError with Validation classification if file path missing
224
+ */
225
+ export const verifyArtifacts: QueryHandler = async (args, projectDir) => {
226
+ const planFilePath = args[0];
227
+ if (!planFilePath) {
228
+ throw new GSDError('plan file path required', ErrorClassification.Validation);
229
+ }
230
+
231
+ // T-12-01: Null byte rejection on file paths
232
+ if (planFilePath.includes('\0')) {
233
+ throw new GSDError('file path contains null bytes', ErrorClassification.Validation);
234
+ }
235
+
236
+ const fullPath = isAbsolute(planFilePath) ? planFilePath : join(projectDir, planFilePath);
237
+
238
+ let content: string;
239
+ try {
240
+ content = await readFile(fullPath, 'utf-8');
241
+ } catch {
242
+ return { data: { error: 'File not found', path: planFilePath } };
243
+ }
244
+
245
+ const { items: artifacts } = parseMustHavesBlock(content, 'artifacts');
246
+ if (artifacts.length === 0) {
247
+ return { data: { error: 'No must_haves.artifacts found in frontmatter', path: planFilePath } };
248
+ }
249
+
250
+ const results: Array<{ path: string; exists: boolean; issues: string[]; passed: boolean }> = [];
251
+
252
+ for (const artifact of artifacts) {
253
+ if (typeof artifact === 'string') continue; // skip simple string items
254
+ const artObj = artifact as Record<string, unknown>;
255
+ const artPath = artObj.path as string | undefined;
256
+ if (!artPath) continue;
257
+
258
+ const artFullPath = join(projectDir, artPath);
259
+ let exists = false;
260
+ let fileContent = '';
261
+
262
+ try {
263
+ fileContent = await readFile(artFullPath, 'utf-8');
264
+ exists = true;
265
+ } catch {
266
+ // File doesn't exist
267
+ }
268
+
269
+ const check: { path: string; exists: boolean; issues: string[]; passed: boolean } = {
270
+ path: artPath,
271
+ exists,
272
+ issues: [],
273
+ passed: false,
274
+ };
275
+
276
+ if (exists) {
277
+ const lineCount = fileContent.split('\n').length;
278
+
279
+ if (artObj.min_lines && lineCount < (artObj.min_lines as number)) {
280
+ check.issues.push(`Only ${lineCount} lines, need ${artObj.min_lines}`);
281
+ }
282
+ if (artObj.contains && !fileContent.includes(artObj.contains as string)) {
283
+ check.issues.push(`Missing pattern: ${artObj.contains}`);
284
+ }
285
+ if (artObj.exports) {
286
+ const exports = Array.isArray(artObj.exports) ? artObj.exports : [artObj.exports];
287
+ for (const exp of exports) {
288
+ if (!fileContent.includes(String(exp))) {
289
+ check.issues.push(`Missing export: ${exp}`);
290
+ }
291
+ }
292
+ }
293
+ check.passed = check.issues.length === 0;
294
+ } else {
295
+ check.issues.push('File not found');
296
+ }
297
+
298
+ results.push(check);
299
+ }
300
+
301
+ const passed = results.filter(r => r.passed).length;
302
+ return {
303
+ data: {
304
+ all_passed: results.length > 0 && passed === results.length,
305
+ passed,
306
+ total: results.length,
307
+ artifacts: results,
308
+ },
309
+ };
310
+ };
311
+
312
+ // ─── verifyCommits ────────────────────────────────────────────────────────
313
+
314
+ /**
315
+ * Verify that commit hashes referenced in SUMMARY.md files actually exist.
316
+ *
317
+ * Port of `cmdVerifyCommits` from `verify.cjs` lines 262-282.
318
+ * Used by gsd-verifier agent to confirm commits mentioned in summaries
319
+ * are real commits in the git history.
320
+ *
321
+ * @param args - One or more commit hashes
322
+ * @param projectDir - Project root directory
323
+ * @returns QueryResult with { all_valid, valid, invalid, total }
324
+ */
325
+ export const verifyCommits: QueryHandler = async (args, projectDir) => {
326
+ if (args.length === 0) {
327
+ throw new GSDError('At least one commit hash required', ErrorClassification.Validation);
328
+ }
329
+
330
+ const { execGit } = await import('./commit.js');
331
+ const valid: string[] = [];
332
+ const invalid: string[] = [];
333
+
334
+ for (const hash of args) {
335
+ const result = execGit(projectDir, ['cat-file', '-t', hash]);
336
+ if (result.exitCode === 0 && result.stdout.trim() === 'commit') {
337
+ valid.push(hash);
338
+ } else {
339
+ invalid.push(hash);
340
+ }
341
+ }
342
+
343
+ return {
344
+ data: {
345
+ all_valid: invalid.length === 0,
346
+ valid,
347
+ invalid,
348
+ total: args.length,
349
+ },
350
+ };
351
+ };
352
+
353
+ // ─── verifyReferences ─────────────────────────────────────────────────────
354
+
355
+ /**
356
+ * Verify that @-references and backtick file paths in a document resolve.
357
+ *
358
+ * Port of `cmdVerifyReferences` from `verify.cjs` lines 217-260.
359
+ *
360
+ * @param args - args[0]: file path (required)
361
+ * @param projectDir - Project root directory
362
+ * @returns QueryResult with { valid, found, missing }
363
+ */
364
+ export const verifyReferences: QueryHandler = async (args, projectDir) => {
365
+ const filePath = args[0];
366
+ if (!filePath) {
367
+ throw new GSDError('file path required', ErrorClassification.Validation);
368
+ }
369
+
370
+ const fullPath = isAbsolute(filePath) ? filePath : join(projectDir, filePath);
371
+
372
+ let content: string;
373
+ try {
374
+ content = await readFile(fullPath, 'utf-8');
375
+ } catch {
376
+ return { data: { error: 'File not found', path: filePath } };
377
+ }
378
+
379
+ const found: string[] = [];
380
+ const missing: string[] = [];
381
+
382
+ const atRefs = content.match(/@([^\s\n,)]+\/[^\s\n,)]+)/g) || [];
383
+ for (const ref of atRefs) {
384
+ const cleanRef = ref.slice(1);
385
+ const resolved = cleanRef.startsWith('~/')
386
+ ? join(process.env.HOME || '', cleanRef.slice(2))
387
+ : join(projectDir, cleanRef);
388
+ if (existsSync(resolved)) {
389
+ found.push(cleanRef);
390
+ } else {
391
+ missing.push(cleanRef);
392
+ }
393
+ }
394
+
395
+ const backtickRefs = content.match(/`([^`]+\/[^`]+\.[a-zA-Z]{1,10})`/g) || [];
396
+ for (const ref of backtickRefs) {
397
+ const cleanRef = ref.slice(1, -1);
398
+ if (cleanRef.startsWith('http') || cleanRef.includes('${') || cleanRef.includes('{{')) continue;
399
+ if (found.includes(cleanRef) || missing.includes(cleanRef)) continue;
400
+ const resolved = join(projectDir, cleanRef);
401
+ if (existsSync(resolved)) {
402
+ found.push(cleanRef);
403
+ } else {
404
+ missing.push(cleanRef);
405
+ }
406
+ }
407
+
408
+ return {
409
+ data: {
410
+ valid: missing.length === 0,
411
+ found: found.length,
412
+ missing,
413
+ total: found.length + missing.length,
414
+ },
415
+ };
416
+ };
417
+
418
+ // ─── verifySummary ────────────────────────────────────────────────────────
419
+
420
+ /**
421
+ * Verify a SUMMARY.md file: existence, file spot-checks, commit refs, self-check section.
422
+ *
423
+ * Port of `cmdVerifySummary` from verify.cjs lines 13-107.
424
+ *
425
+ * @param args - args[0]: summary path (required), args[1]: optional --check-count N
426
+ */
427
+ export const verifySummary: QueryHandler = async (args, projectDir) => {
428
+ const summaryPath = args[0];
429
+ if (!summaryPath) {
430
+ throw new GSDError('summary-path required', ErrorClassification.Validation);
431
+ }
432
+
433
+ const checkCountIdx = args.indexOf('--check-count');
434
+ const checkCount = checkCountIdx !== -1 ? parseInt(args[checkCountIdx + 1], 10) || 2 : 2;
435
+
436
+ const fullPath = join(projectDir, summaryPath);
437
+
438
+ if (!existsSync(fullPath)) {
439
+ return {
440
+ data: {
441
+ passed: false,
442
+ checks: {
443
+ summary_exists: false,
444
+ files_created: { checked: 0, found: 0, missing: [] },
445
+ commits_exist: false,
446
+ self_check: 'not_found',
447
+ },
448
+ errors: ['SUMMARY.md not found'],
449
+ },
450
+ };
451
+ }
452
+
453
+ const content = readFileSync(fullPath, 'utf-8');
454
+ const errors: string[] = [];
455
+
456
+ const mentionedFiles = new Set<string>();
457
+ const patterns = [
458
+ /`([^`]+\.[a-zA-Z]+)`/g,
459
+ /(?:Created|Modified|Added|Updated|Edited):\s*`?([^\s`]+\.[a-zA-Z]+)`?/gi,
460
+ ];
461
+ for (const pattern of patterns) {
462
+ let m;
463
+ while ((m = pattern.exec(content)) !== null) {
464
+ const filePath = m[1];
465
+ if (filePath && !filePath.startsWith('http') && filePath.includes('/')) {
466
+ mentionedFiles.add(filePath);
467
+ }
468
+ }
469
+ }
470
+
471
+ const filesToCheck = Array.from(mentionedFiles).slice(0, checkCount);
472
+ const missing: string[] = [];
473
+ for (const file of filesToCheck) {
474
+ if (!existsSync(join(projectDir, file))) {
475
+ missing.push(file);
476
+ }
477
+ }
478
+
479
+ const { execGit } = await import('./commit.js');
480
+ const commitHashPattern = /\b[0-9a-f]{7,40}\b/g;
481
+ const hashes = content.match(commitHashPattern) || [];
482
+ let commitsExist = false;
483
+ for (const hash of hashes.slice(0, 3)) {
484
+ const result = execGit(projectDir, ['cat-file', '-t', hash]);
485
+ if (result.exitCode === 0 && result.stdout.trim() === 'commit') {
486
+ commitsExist = true;
487
+ break;
488
+ }
489
+ }
490
+
491
+ let selfCheck = 'not_found';
492
+ const selfCheckPattern = /##\s*(?:Self[- ]?Check|Verification|Quality Check)/i;
493
+ if (selfCheckPattern.test(content)) {
494
+ const passPattern = /(?:all\s+)?(?:pass|✓|✅|complete|succeeded)/i;
495
+ const failPattern = /(?:fail|✗|❌|incomplete|blocked)/i;
496
+ const checkSection = content.slice(content.search(selfCheckPattern));
497
+ if (failPattern.test(checkSection)) {
498
+ selfCheck = 'failed';
499
+ } else if (passPattern.test(checkSection)) {
500
+ selfCheck = 'passed';
501
+ }
502
+ }
503
+
504
+ if (missing.length > 0) errors.push('Missing files: ' + missing.join(', '));
505
+ if (!commitsExist && hashes.length > 0) errors.push('Referenced commit hashes not found in git history');
506
+ if (selfCheck === 'failed') errors.push('Self-check section indicates failure');
507
+
508
+ const passed = missing.length === 0 && selfCheck !== 'failed';
509
+ return {
510
+ data: {
511
+ passed,
512
+ checks: {
513
+ summary_exists: true,
514
+ files_created: { checked: filesToCheck.length, found: filesToCheck.length - missing.length, missing },
515
+ commits_exist: commitsExist,
516
+ self_check: selfCheck,
517
+ },
518
+ errors,
519
+ },
520
+ };
521
+ };
522
+
523
+ // ─── verifyPathExists ─────────────────────────────────────────────────────
524
+
525
+ /**
526
+ * Check file/directory existence and return type.
527
+ *
528
+ * Port of `cmdVerifyPathExists` from commands.cjs lines 111-132.
529
+ *
530
+ * @param args - args[0]: path to check (required)
531
+ */
532
+ export const verifyPathExists: QueryHandler = async (args, projectDir) => {
533
+ const targetPath = args[0];
534
+ if (!targetPath) {
535
+ throw new GSDError('path required for verification', ErrorClassification.Validation);
536
+ }
537
+ if (targetPath.includes('\0')) {
538
+ throw new GSDError('path contains null bytes', ErrorClassification.Validation);
539
+ }
540
+
541
+ const fullPath = isAbsolute(targetPath) ? targetPath : join(projectDir, targetPath);
542
+
543
+ try {
544
+ const stats = statSync(fullPath);
545
+ const type = stats.isDirectory() ? 'directory' : stats.isFile() ? 'file' : 'other';
546
+ return { data: { exists: true, type } };
547
+ } catch {
548
+ return { data: { exists: false, type: null } };
549
+ }
550
+ };
551
+
552
+ // ─── verifySchemaDrift ────────────────────────────────────────────────────
553
+
554
+ /**
555
+ * Detect schema drift for a phase — port of `cmdVerifySchemaDrift` from verify.cjs lines 1013–1086.
556
+ */
557
+ export const verifySchemaDrift: QueryHandler = async (args, projectDir) => {
558
+ const phaseArg = args[0];
559
+ const skipFlag = args.includes('--skip');
560
+
561
+ if (!phaseArg) {
562
+ throw new GSDError('Usage: verify schema-drift <phase> [--skip]', ErrorClassification.Validation);
563
+ }
564
+
565
+ const { checkSchemaDrift } = await import('./schema-detect.js');
566
+ const { execGit } = await import('./commit.js');
567
+
568
+ const phasesDir = planningPaths(projectDir).phases;
569
+ if (!existsSync(phasesDir)) {
570
+ return {
571
+ data: {
572
+ drift_detected: false,
573
+ blocking: false,
574
+ message: 'No phases directory',
575
+ },
576
+ };
577
+ }
578
+
579
+ const normalized = normalizePhaseName(phaseArg);
580
+ const dirNames = readdirSync(phasesDir, { withFileTypes: true })
581
+ .filter(e => e.isDirectory())
582
+ .map(e => e.name)
583
+ .sort((a, b) => comparePhaseNum(a, b));
584
+
585
+ let phaseDirName = dirNames.find(d => phaseTokenMatches(d, normalized)) ?? null;
586
+ if (!phaseDirName && /^[\d.]+/.test(phaseArg)) {
587
+ const exact = join(phasesDir, phaseArg);
588
+ if (existsSync(exact)) phaseDirName = phaseArg;
589
+ }
590
+
591
+ if (!phaseDirName) {
592
+ return {
593
+ data: {
594
+ drift_detected: false,
595
+ blocking: false,
596
+ message: `Phase directory not found: ${phaseArg}`,
597
+ },
598
+ };
599
+ }
600
+
601
+ const phaseDir = join(phasesDir, phaseDirName);
602
+
603
+ function filesModifiedFromFrontmatter(fm: Record<string, unknown>): string[] {
604
+ const v = fm.files_modified;
605
+ if (Array.isArray(v)) return v.map(x => String(x).trim()).filter(Boolean);
606
+ if (typeof v === 'string') {
607
+ const t = v.trim();
608
+ return t ? [t] : [];
609
+ }
610
+ return [];
611
+ }
612
+
613
+ const allFiles: string[] = [];
614
+ const planFiles = readdirSync(phaseDir).filter(f => f.endsWith('-PLAN.md') || f === 'PLAN.md');
615
+ for (const pf of planFiles) {
616
+ const content = readFileSync(join(phaseDir, pf), 'utf-8');
617
+ const fm = extractFrontmatter(content) as Record<string, unknown>;
618
+ allFiles.push(...filesModifiedFromFrontmatter(fm));
619
+ }
620
+
621
+ let executionLog = '';
622
+ const summaryFiles = readdirSync(phaseDir).filter(f => f.endsWith('-SUMMARY.md'));
623
+ for (const sf of summaryFiles) {
624
+ executionLog += readFileSync(join(phaseDir, sf), 'utf-8') + '\n';
625
+ }
626
+
627
+ const gitLog = execGit(projectDir, ['log', '--oneline', '--all', '-50']);
628
+ if (gitLog.exitCode === 0) {
629
+ executionLog += '\n' + gitLog.stdout;
630
+ }
631
+
632
+ const result = checkSchemaDrift(allFiles, executionLog, { skipCheck: !!skipFlag });
633
+
634
+ return {
635
+ data: {
636
+ drift_detected: result.driftDetected,
637
+ blocking: result.blocking,
638
+ schema_files: result.schemaFiles,
639
+ orms: result.orms,
640
+ unpushed_orms: result.unpushedOrms,
641
+ message: result.message,
642
+ skipped: result.skipped || false,
643
+ },
644
+ };
645
+ };
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Tests for websearch handler (no network when API key unset).
3
+ */
4
+
5
+ import { describe, it, expect } from 'vitest';
6
+ import { websearch } from './websearch.js';
7
+
8
+ describe('websearch', () => {
9
+ it('returns available:false when BRAVE_API_KEY is not set', async () => {
10
+ const prev = process.env.BRAVE_API_KEY;
11
+ delete process.env.BRAVE_API_KEY;
12
+ const r = await websearch(['test query'], '/tmp');
13
+ const data = r.data as Record<string, unknown>;
14
+ expect(data.available).toBe(false);
15
+ if (prev !== undefined) process.env.BRAVE_API_KEY = prev;
16
+ });
17
+
18
+ it('returns error when query is missing and BRAVE_API_KEY is set', async () => {
19
+ const prev = process.env.BRAVE_API_KEY;
20
+ process.env.BRAVE_API_KEY = 'test-dummy-key';
21
+ try {
22
+ const r = await websearch([], '/tmp');
23
+ const data = r.data as Record<string, unknown>;
24
+ expect(data.available).toBe(false);
25
+ expect(data.error).toBe('Query required');
26
+ } finally {
27
+ if (prev !== undefined) process.env.BRAVE_API_KEY = prev;
28
+ else delete process.env.BRAVE_API_KEY;
29
+ }
30
+ });
31
+ });