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,378 @@
1
+ /**
2
+ * Learnings — Global knowledge store with CRUD operations
3
+ *
4
+ * Provides a cross-project learnings store at ~/.gsd/knowledge/.
5
+ * Each learning is stored as an individual JSON file with content-hash
6
+ * deduplication. Supports write, read, list, query, delete, copy-from-project,
7
+ * and prune operations.
8
+ *
9
+ * Storage format: { id, source_project, date, context, learning, tags, content_hash }
10
+ * File naming: {id}.json
11
+ * Deduplication: SHA-256 of learning text + source_project
12
+ */
13
+
14
+ 'use strict';
15
+
16
+ const fs = require('fs');
17
+ const path = require('path');
18
+ const crypto = require('crypto');
19
+ const os = require('os');
20
+ const { output, error: coreError } = require('./core.cjs');
21
+
22
+ // ─── Constants ───────────────────────────────────────────────────────────────
23
+
24
+ const DEFAULT_STORE_DIR = path.join(os.homedir(), '.gsd', 'knowledge');
25
+
26
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
27
+
28
+ /**
29
+ * Get the store directory, allowing override for testing.
30
+ * @param {object} [opts]
31
+ * @param {string} [opts.storeDir] - Override store directory
32
+ * @returns {string}
33
+ */
34
+ function getStoreDir(opts) {
35
+ return (opts && opts.storeDir) || DEFAULT_STORE_DIR;
36
+ }
37
+
38
+ /**
39
+ * Ensure the store directory exists. Created on first write, not on install.
40
+ * @param {string} dir
41
+ */
42
+ function ensureStoreDir(dir) {
43
+ if (!fs.existsSync(dir)) {
44
+ fs.mkdirSync(dir, { recursive: true });
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Generate a content hash for deduplication.
50
+ * Uses SHA-256 of learning text combined with source_project.
51
+ * @param {string} learning
52
+ * @param {string} sourceProject
53
+ * @returns {string}
54
+ */
55
+ function contentHash(learning, sourceProject) {
56
+ return crypto.createHash('sha256')
57
+ .update(learning + '\n' + sourceProject)
58
+ .digest('hex');
59
+ }
60
+
61
+ /**
62
+ * Generate a unique ID based on timestamp + random suffix.
63
+ * @returns {string}
64
+ */
65
+ function generateId() {
66
+ const ts = Date.now().toString(36);
67
+ const rand = crypto.randomBytes(4).toString('hex');
68
+ return `${ts}-${rand}`;
69
+ }
70
+
71
+ /**
72
+ * Read and parse a single learning JSON file.
73
+ * Returns null (with stderr warning) for malformed files.
74
+ * @param {string} filePath
75
+ * @returns {object|null}
76
+ */
77
+ function readLearningFile(filePath) {
78
+ try {
79
+ const content = fs.readFileSync(filePath, 'utf-8');
80
+ return JSON.parse(content);
81
+ } catch (err) {
82
+ process.stderr.write(`Warning: skipping malformed file ${filePath}: ${err.message}\n`);
83
+ return null;
84
+ }
85
+ }
86
+
87
+ // ─── CRUD Operations ─────────────────────────────────────────────────────────
88
+
89
+ /**
90
+ * Write a learning to the global store.
91
+ * Deduplicates by content hash — same content from same project is not stored twice.
92
+ *
93
+ * @param {object} entry
94
+ * @param {string} entry.source_project - Project name or path
95
+ * @param {string} entry.learning - The learning text
96
+ * @param {string} [entry.context] - Additional context
97
+ * @param {string[]} [entry.tags] - Tags for querying
98
+ * @param {object} [opts]
99
+ * @param {string} [opts.storeDir] - Override store directory
100
+ * @returns {{ id: string, created: boolean, content_hash: string }}
101
+ */
102
+ function learningsWrite(entry, opts) {
103
+ const dir = getStoreDir(opts);
104
+ ensureStoreDir(dir);
105
+
106
+ const hash = contentHash(entry.learning, entry.source_project);
107
+
108
+ // Check for duplicate by scanning existing files
109
+ const files = fs.readdirSync(dir).filter(f => f.endsWith('.json'));
110
+ for (const file of files) {
111
+ const existing = readLearningFile(path.join(dir, file));
112
+ if (existing && existing.content_hash === hash) {
113
+ return { id: existing.id, created: false, content_hash: hash };
114
+ }
115
+ }
116
+
117
+ const id = generateId();
118
+ const record = {
119
+ id,
120
+ source_project: entry.source_project,
121
+ date: new Date().toISOString(),
122
+ context: entry.context || '',
123
+ learning: entry.learning,
124
+ tags: entry.tags || [],
125
+ content_hash: hash,
126
+ };
127
+
128
+ fs.writeFileSync(path.join(dir, `${id}.json`), JSON.stringify(record, null, 2), 'utf-8');
129
+ return { id, created: true, content_hash: hash };
130
+ }
131
+
132
+ /**
133
+ * Read a single learning by ID.
134
+ *
135
+ * @param {string} id
136
+ * @param {object} [opts]
137
+ * @param {string} [opts.storeDir] - Override store directory
138
+ * @returns {object|null}
139
+ */
140
+ function learningsRead(id, opts) {
141
+ if (!/^[a-z0-9]+-[a-f0-9]+$/.test(id)) return null;
142
+ const dir = getStoreDir(opts);
143
+ const filePath = path.join(dir, `${id}.json`);
144
+ if (!fs.existsSync(filePath)) return null;
145
+ return readLearningFile(filePath);
146
+ }
147
+
148
+ /**
149
+ * List all learnings, sorted by date (newest first).
150
+ *
151
+ * @param {object} [opts]
152
+ * @param {string} [opts.storeDir] - Override store directory
153
+ * @returns {object[]}
154
+ */
155
+ function learningsList(opts) {
156
+ const dir = getStoreDir(opts);
157
+ if (!fs.existsSync(dir)) return [];
158
+
159
+ const files = fs.readdirSync(dir).filter(f => f.endsWith('.json'));
160
+ const results = [];
161
+ for (const file of files) {
162
+ const record = readLearningFile(path.join(dir, file));
163
+ if (record) results.push(record);
164
+ }
165
+
166
+ // Sort by date descending (newest first)
167
+ results.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
168
+ return results;
169
+ }
170
+
171
+ /**
172
+ * Query learnings by tag.
173
+ *
174
+ * @param {object} query
175
+ * @param {string} [query.tag] - Tag to filter by
176
+ * @param {object} [opts]
177
+ * @param {string} [opts.storeDir] - Override store directory
178
+ * @returns {object[]}
179
+ */
180
+ function learningsQuery(query, opts) {
181
+ const all = learningsList(opts);
182
+ if (query && query.tag) {
183
+ return all.filter(r => r.tags && r.tags.includes(query.tag));
184
+ }
185
+ return all;
186
+ }
187
+
188
+ /**
189
+ * Delete a learning by ID.
190
+ *
191
+ * @param {string} id
192
+ * @param {object} [opts]
193
+ * @param {string} [opts.storeDir] - Override store directory
194
+ * @returns {boolean} true if deleted, false if not found
195
+ */
196
+ function learningsDelete(id, opts) {
197
+ if (!/^[a-z0-9]+-[a-f0-9]+$/.test(id)) return false;
198
+ const dir = getStoreDir(opts);
199
+ const filePath = path.join(dir, `${id}.json`);
200
+ if (!fs.existsSync(filePath)) return false;
201
+ fs.unlinkSync(filePath);
202
+ return true;
203
+ }
204
+
205
+ /**
206
+ * Copy learnings from a project's LEARNINGS.md into the global store.
207
+ * Parses markdown sections as individual learnings. Deduplicates by content hash.
208
+ *
209
+ * Expected LEARNINGS.md format:
210
+ * ## Section Title
211
+ * Learning content paragraph(s)...
212
+ *
213
+ * ## Another Section
214
+ * More content...
215
+ *
216
+ * @param {string} planningDir - Path to .planning/ directory (or directory containing LEARNINGS.md)
217
+ * @param {object} [opts]
218
+ * @param {string} [opts.storeDir] - Override store directory
219
+ * @param {string} [opts.sourceProject] - Project name (defaults to directory basename)
220
+ * @returns {{ total: number, created: number, skipped: number }}
221
+ */
222
+ function learningsCopyFromProject(planningDir, opts) {
223
+ const learningsPath = path.join(planningDir, 'LEARNINGS.md');
224
+ if (!fs.existsSync(learningsPath)) {
225
+ return { total: 0, created: 0, skipped: 0 };
226
+ }
227
+
228
+ const content = fs.readFileSync(learningsPath, 'utf-8');
229
+ const sourceProject = (opts && opts.sourceProject) || path.basename(path.resolve(planningDir, '..'));
230
+
231
+ // Parse markdown: split on ## headings
232
+ const sections = content.split(/^## /m).slice(1); // skip preamble before first ##
233
+ let created = 0;
234
+ let skipped = 0;
235
+
236
+ for (const section of sections) {
237
+ const lines = section.trim().split('\n');
238
+ const title = lines[0].trim();
239
+ const body = lines.slice(1).join('\n').trim();
240
+ if (!body) continue;
241
+
242
+ // Extract tags from title (simple: use words as tags)
243
+ const tags = title.toLowerCase().split(/\s+/).filter(w => w.length > 2);
244
+
245
+ const result = learningsWrite({
246
+ source_project: sourceProject,
247
+ learning: body,
248
+ context: title,
249
+ tags,
250
+ }, opts);
251
+
252
+ if (result.created) {
253
+ created++;
254
+ } else {
255
+ skipped++;
256
+ }
257
+ }
258
+
259
+ return { total: created + skipped, created, skipped };
260
+ }
261
+
262
+ /**
263
+ * Prune learnings older than a given threshold.
264
+ *
265
+ * @param {string} olderThan - Duration string like "90d", "30d", "7d"
266
+ * @param {object} [opts]
267
+ * @param {string} [opts.storeDir] - Override store directory
268
+ * @returns {{ removed: number, kept: number }}
269
+ */
270
+ function learningsPrune(olderThan, opts) {
271
+ const match = /^(\d+)d$/.exec(olderThan);
272
+ if (!match) {
273
+ throw new Error(`Invalid duration format: "${olderThan}" — expected format like "90d"`);
274
+ }
275
+
276
+ const days = parseInt(match[1], 10);
277
+ const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000);
278
+ const dir = getStoreDir(opts);
279
+
280
+ if (!fs.existsSync(dir)) return { removed: 0, kept: 0 };
281
+
282
+ const files = fs.readdirSync(dir).filter(f => f.endsWith('.json'));
283
+ let removed = 0;
284
+ let kept = 0;
285
+
286
+ for (const file of files) {
287
+ const filePath = path.join(dir, file);
288
+ const record = readLearningFile(filePath);
289
+ if (!record) continue;
290
+
291
+ const recordDate = new Date(record.date);
292
+ if (recordDate < cutoff) {
293
+ fs.unlinkSync(filePath);
294
+ removed++;
295
+ } else {
296
+ kept++;
297
+ }
298
+ }
299
+
300
+ return { removed, kept };
301
+ }
302
+
303
+ // ─── CLI Command Handlers ────────────────────────────────────────────────────
304
+
305
+ /**
306
+ * Handle `gsd-tools learnings list`
307
+ * @param {boolean} raw - Raw output flag
308
+ */
309
+ function cmdLearningsList(raw) {
310
+ const results = learningsList();
311
+ output({ learnings: results, count: results.length }, raw);
312
+ }
313
+
314
+ /**
315
+ * Handle `gsd-tools learnings query --tag <tag>`
316
+ * @param {string} tag
317
+ * @param {boolean} raw - Raw output flag
318
+ */
319
+ function cmdLearningsQuery(tag, raw) {
320
+ const results = learningsQuery({ tag });
321
+ output({ learnings: results, count: results.length, tag }, raw);
322
+ }
323
+
324
+ /**
325
+ * Handle `gsd-tools learnings copy`
326
+ * @param {string} cwd - Current working directory
327
+ * @param {boolean} raw - Raw output flag
328
+ */
329
+ function cmdLearningsCopy(cwd, raw) {
330
+ const planningDir = path.join(cwd, '.planning');
331
+ const result = learningsCopyFromProject(planningDir);
332
+ output(result, raw);
333
+ }
334
+
335
+ /**
336
+ * Handle `gsd-tools learnings prune --older-than <duration>`
337
+ * @param {string} olderThan - Duration string like "90d"
338
+ * @param {boolean} raw - Raw output flag
339
+ */
340
+ function cmdLearningsPrune(olderThan, raw) {
341
+ try {
342
+ const result = learningsPrune(olderThan);
343
+ output(result, raw);
344
+ } catch (err) {
345
+ coreError(err.message);
346
+ }
347
+ }
348
+
349
+ /**
350
+ * Handle `gsd-tools learnings delete <id>`
351
+ * @param {string} id
352
+ * @param {boolean} raw - Raw output flag
353
+ */
354
+ function cmdLearningsDelete(id, raw) {
355
+ if (!/^[a-z0-9]+-[a-f0-9]+$/.test(id)) {
356
+ coreError(`Invalid learning ID: "${id}"`);
357
+ }
358
+ const deleted = learningsDelete(id);
359
+ output({ id, deleted }, raw);
360
+ }
361
+
362
+ // ─── Exports ─────────────────────────────────────────────────────────────────
363
+
364
+ module.exports = {
365
+ learningsWrite,
366
+ learningsRead,
367
+ learningsList,
368
+ learningsQuery,
369
+ learningsDelete,
370
+ learningsCopyFromProject,
371
+ learningsPrune,
372
+ cmdLearningsList,
373
+ cmdLearningsQuery,
374
+ cmdLearningsCopy,
375
+ cmdLearningsPrune,
376
+ cmdLearningsDelete,
377
+ DEFAULT_STORE_DIR,
378
+ };
@@ -0,0 +1,283 @@
1
+ /**
2
+ * Milestone — Milestone and requirements lifecycle operations
3
+ */
4
+
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+ const { escapeRegex, getMilestonePhaseFilter, extractOneLinerFromBody, normalizeMd, planningPaths, output, error, atomicWriteFileSync } = require('./core.cjs');
8
+ const { extractFrontmatter } = require('./frontmatter.cjs');
9
+ const { writeStateMd, stateReplaceFieldWithFallback } = require('./state.cjs');
10
+
11
+ function cmdRequirementsMarkComplete(cwd, reqIdsRaw, raw) {
12
+ if (!reqIdsRaw || reqIdsRaw.length === 0) {
13
+ error('requirement IDs required. Usage: requirements mark-complete REQ-01,REQ-02 or REQ-01 REQ-02');
14
+ }
15
+
16
+ // Accept comma-separated, space-separated, or bracket-wrapped: [REQ-01, REQ-02]
17
+ const reqIds = reqIdsRaw
18
+ .join(' ')
19
+ .replace(/[\[\]]/g, '')
20
+ .split(/[,\s]+/)
21
+ .map(r => r.trim())
22
+ .filter(Boolean);
23
+
24
+ if (reqIds.length === 0) {
25
+ error('no valid requirement IDs found');
26
+ }
27
+
28
+ const reqPath = planningPaths(cwd).requirements;
29
+ if (!fs.existsSync(reqPath)) {
30
+ output({ updated: false, reason: 'REQUIREMENTS.md not found', ids: reqIds }, raw, 'no requirements file');
31
+ return;
32
+ }
33
+
34
+ let reqContent = fs.readFileSync(reqPath, 'utf-8');
35
+ const updated = [];
36
+ const alreadyComplete = [];
37
+ const notFound = [];
38
+
39
+ for (const reqId of reqIds) {
40
+ let found = false;
41
+ const reqEscaped = escapeRegex(reqId);
42
+
43
+ // Update checkbox: - [ ] **REQ-ID** → - [x] **REQ-ID**
44
+ // Use replace() directly and compare — avoids test()+replace() global regex
45
+ // lastIndex bug where test() advances state and replace() misses matches.
46
+ const checkboxPattern = new RegExp(`(-\\s*\\[)[ ](\\]\\s*\\*\\*${reqEscaped}\\*\\*)`, 'gi');
47
+ const afterCheckbox = reqContent.replace(checkboxPattern, '$1x$2');
48
+ if (afterCheckbox !== reqContent) {
49
+ reqContent = afterCheckbox;
50
+ found = true;
51
+ }
52
+
53
+ // Update traceability table: | REQ-ID | Phase N | Pending | → | REQ-ID | Phase N | Complete |
54
+ const tablePattern = new RegExp(`(\\|\\s*${reqEscaped}\\s*\\|[^|]+\\|)\\s*Pending\\s*(\\|)`, 'gi');
55
+ const afterTable = reqContent.replace(tablePattern, '$1 Complete $2');
56
+ if (afterTable !== reqContent) {
57
+ reqContent = afterTable;
58
+ found = true;
59
+ }
60
+
61
+ if (found) {
62
+ updated.push(reqId);
63
+ } else {
64
+ // Check if already complete before declaring not_found.
65
+ // Non-global flag is fine here — we only need to know if a match exists.
66
+ const doneCheckbox = new RegExp(`-\\s*\\[x\\]\\s*\\*\\*${reqEscaped}\\*\\*`, 'i');
67
+ const doneTable = new RegExp(`\\|\\s*${reqEscaped}\\s*\\|[^|]+\\|\\s*Complete\\s*\\|`, 'i');
68
+ if (doneCheckbox.test(reqContent) || doneTable.test(reqContent)) {
69
+ alreadyComplete.push(reqId);
70
+ } else {
71
+ notFound.push(reqId);
72
+ }
73
+ }
74
+ }
75
+
76
+ if (updated.length > 0) {
77
+ atomicWriteFileSync(reqPath, reqContent);
78
+ }
79
+
80
+ output({
81
+ updated: updated.length > 0,
82
+ marked_complete: updated,
83
+ already_complete: alreadyComplete,
84
+ not_found: notFound,
85
+ total: reqIds.length,
86
+ }, raw, `${updated.length}/${reqIds.length} requirements marked complete`);
87
+ }
88
+
89
+ function cmdMilestoneComplete(cwd, version, options, raw) {
90
+ if (!version) {
91
+ error('version required for milestone complete (e.g., v1.0)');
92
+ }
93
+
94
+ const roadmapPath = planningPaths(cwd).roadmap;
95
+ const reqPath = planningPaths(cwd).requirements;
96
+ const statePath = planningPaths(cwd).state;
97
+ const milestonesPath = path.join(cwd, '.planning', 'MILESTONES.md');
98
+ const archiveDir = path.join(cwd, '.planning', 'milestones');
99
+ const phasesDir = planningPaths(cwd).phases;
100
+ const today = new Date().toISOString().split('T')[0];
101
+ const milestoneName = options.name || version;
102
+
103
+ // Ensure archive directory exists
104
+ fs.mkdirSync(archiveDir, { recursive: true });
105
+
106
+ // Scope stats and accomplishments to only the phases belonging to the
107
+ // current milestone's ROADMAP. Uses the shared filter from core.cjs
108
+ // (same logic used by cmdPhasesList and other callers).
109
+ const isDirInMilestone = getMilestonePhaseFilter(cwd);
110
+
111
+ // Gather stats from phases (scoped to current milestone only)
112
+ let phaseCount = 0;
113
+ let totalPlans = 0;
114
+ let totalTasks = 0;
115
+ const accomplishments = [];
116
+
117
+ try {
118
+ const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
119
+ const dirs = entries.filter(e => e.isDirectory()).map(e => e.name).sort();
120
+
121
+ for (const dir of dirs) {
122
+ if (!isDirInMilestone(dir)) continue;
123
+
124
+ phaseCount++;
125
+ const phaseFiles = fs.readdirSync(path.join(phasesDir, dir));
126
+ const plans = phaseFiles.filter(f => f.endsWith('-PLAN.md') || f === 'PLAN.md');
127
+ const summaries = phaseFiles.filter(f => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md');
128
+ totalPlans += plans.length;
129
+
130
+ // Extract one-liners from summaries
131
+ for (const s of summaries) {
132
+ try {
133
+ const content = fs.readFileSync(path.join(phasesDir, dir, s), 'utf-8');
134
+ const fm = extractFrontmatter(content);
135
+ const oneLiner = fm['one-liner'] || extractOneLinerFromBody(content);
136
+ if (oneLiner) {
137
+ accomplishments.push(oneLiner);
138
+ }
139
+ // Count tasks: prefer **Tasks:** N from Performance section,
140
+ // then <task XML tags, then ## Task N markdown headers
141
+ const tasksFieldMatch = content.match(/\*\*Tasks:\*\*\s*(\d+)/);
142
+ if (tasksFieldMatch) {
143
+ totalTasks += parseInt(tasksFieldMatch[1], 10);
144
+ } else {
145
+ const xmlTaskMatches = content.match(/<task[\s>]/gi) || [];
146
+ const mdTaskMatches = content.match(/##\s*Task\s*\d+/gi) || [];
147
+ totalTasks += xmlTaskMatches.length || mdTaskMatches.length;
148
+ }
149
+ } catch { /* intentionally empty */ }
150
+ }
151
+ }
152
+ } catch { /* intentionally empty */ }
153
+
154
+ // Archive ROADMAP.md
155
+ if (fs.existsSync(roadmapPath)) {
156
+ const roadmapContent = fs.readFileSync(roadmapPath, 'utf-8');
157
+ fs.writeFileSync(path.join(archiveDir, `${version}-ROADMAP.md`), roadmapContent, 'utf-8');
158
+ }
159
+
160
+ // Archive REQUIREMENTS.md
161
+ if (fs.existsSync(reqPath)) {
162
+ const reqContent = fs.readFileSync(reqPath, 'utf-8');
163
+ const archiveHeader = `# Requirements Archive: ${version} ${milestoneName}\n\n**Archived:** ${today}\n**Status:** SHIPPED\n\nFor current requirements, see \`.planning/REQUIREMENTS.md\`.\n\n---\n\n`;
164
+ fs.writeFileSync(path.join(archiveDir, `${version}-REQUIREMENTS.md`), archiveHeader + reqContent, 'utf-8');
165
+ }
166
+
167
+ // Archive audit file if exists
168
+ const auditFile = path.join(cwd, '.planning', `${version}-MILESTONE-AUDIT.md`);
169
+ if (fs.existsSync(auditFile)) {
170
+ fs.renameSync(auditFile, path.join(archiveDir, `${version}-MILESTONE-AUDIT.md`));
171
+ }
172
+
173
+ // Create/append MILESTONES.md entry
174
+ const accomplishmentsList = accomplishments.map(a => `- ${a}`).join('\n');
175
+ const milestoneEntry = `## ${version} ${milestoneName} (Shipped: ${today})\n\n**Phases completed:** ${phaseCount} phases, ${totalPlans} plans, ${totalTasks} tasks\n\n**Key accomplishments:**\n${accomplishmentsList || '- (none recorded)'}\n\n---\n\n`;
176
+
177
+ if (fs.existsSync(milestonesPath)) {
178
+ const existing = fs.readFileSync(milestonesPath, 'utf-8');
179
+ if (!existing.trim()) {
180
+ // Empty file — treat like new
181
+ atomicWriteFileSync(milestonesPath, normalizeMd(`# Milestones\n\n${milestoneEntry}`));
182
+ } else {
183
+ // Insert after the header line(s) for reverse chronological order (newest first)
184
+ const headerMatch = existing.match(/^(#{1,3}\s+[^\n]*\n\n?)/);
185
+ if (headerMatch) {
186
+ const header = headerMatch[1];
187
+ const rest = existing.slice(header.length);
188
+ atomicWriteFileSync(milestonesPath, normalizeMd(header + milestoneEntry + rest));
189
+ } else {
190
+ // No recognizable header — prepend the entry
191
+ atomicWriteFileSync(milestonesPath, normalizeMd(milestoneEntry + existing));
192
+ }
193
+ }
194
+ } else {
195
+ atomicWriteFileSync(milestonesPath, normalizeMd(`# Milestones\n\n${milestoneEntry}`));
196
+ }
197
+
198
+ // Update STATE.md — use shared helpers that handle both **bold:** and plain Field: formats
199
+ if (fs.existsSync(statePath)) {
200
+ let stateContent = fs.readFileSync(statePath, 'utf-8');
201
+
202
+ stateContent = stateReplaceFieldWithFallback(stateContent, 'Status', null, `${version} milestone complete`);
203
+ stateContent = stateReplaceFieldWithFallback(stateContent, 'Last Activity', 'Last activity', today);
204
+ stateContent = stateReplaceFieldWithFallback(stateContent, 'Last Activity Description', null,
205
+ `${version} milestone completed and archived`);
206
+
207
+ writeStateMd(statePath, stateContent, cwd);
208
+ }
209
+
210
+ // Archive phase directories if requested
211
+ let phasesArchived = false;
212
+ if (options.archivePhases) {
213
+ try {
214
+ const phaseArchiveDir = path.join(archiveDir, `${version}-phases`);
215
+ fs.mkdirSync(phaseArchiveDir, { recursive: true });
216
+
217
+ const phaseEntries = fs.readdirSync(phasesDir, { withFileTypes: true });
218
+ const phaseDirNames = phaseEntries.filter(e => e.isDirectory()).map(e => e.name);
219
+ let archivedCount = 0;
220
+ for (const dir of phaseDirNames) {
221
+ if (!isDirInMilestone(dir)) continue;
222
+ fs.renameSync(path.join(phasesDir, dir), path.join(phaseArchiveDir, dir));
223
+ archivedCount++;
224
+ }
225
+ phasesArchived = archivedCount > 0;
226
+ } catch { /* intentionally empty */ }
227
+ }
228
+
229
+ const result = {
230
+ version,
231
+ name: milestoneName,
232
+ date: today,
233
+ phases: phaseCount,
234
+ plans: totalPlans,
235
+ tasks: totalTasks,
236
+ accomplishments,
237
+ archived: {
238
+ roadmap: fs.existsSync(path.join(archiveDir, `${version}-ROADMAP.md`)),
239
+ requirements: fs.existsSync(path.join(archiveDir, `${version}-REQUIREMENTS.md`)),
240
+ audit: fs.existsSync(path.join(archiveDir, `${version}-MILESTONE-AUDIT.md`)),
241
+ phases: phasesArchived,
242
+ },
243
+ milestones_updated: true,
244
+ state_updated: fs.existsSync(statePath),
245
+ };
246
+
247
+ output(result, raw);
248
+ }
249
+
250
+ function cmdPhasesClear(cwd, raw, args) {
251
+ const phasesDir = planningPaths(cwd).phases;
252
+ const confirm = Array.isArray(args) && args.includes('--confirm');
253
+ let cleared = 0;
254
+
255
+ if (fs.existsSync(phasesDir)) {
256
+ const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
257
+ const dirs = entries.filter(e => e.isDirectory() && !/^999(?:\.|$)/.test(e.name));
258
+
259
+ if (dirs.length > 0 && !confirm) {
260
+ error(
261
+ `phases clear would delete ${dirs.length} phase director${dirs.length === 1 ? 'y' : 'ies'}. ` +
262
+ `Pass --confirm to proceed.`
263
+ );
264
+ }
265
+
266
+ try {
267
+ for (const entry of dirs) {
268
+ fs.rmSync(path.join(phasesDir, entry.name), { recursive: true, force: true });
269
+ cleared++;
270
+ }
271
+ } catch (e) {
272
+ error('Failed to clear phases directory: ' + e.message);
273
+ }
274
+ }
275
+
276
+ output({ cleared }, raw, `${cleared} phase director${cleared === 1 ? 'y' : 'ies'} cleared`);
277
+ }
278
+
279
+ module.exports = {
280
+ cmdRequirementsMarkComplete,
281
+ cmdMilestoneComplete,
282
+ cmdPhasesClear,
283
+ };