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,170 @@
1
+ /**
2
+ * Context engine — resolves which .planning/ state files exist per phase type.
3
+ *
4
+ * Different phases need different subsets of context files. The execute phase
5
+ * only needs STATE.md + config.json (minimal). Research needs STATE.md +
6
+ * ROADMAP.md + CONTEXT.md. Plan needs all files. Verify needs STATE.md +
7
+ * ROADMAP.md + REQUIREMENTS.md + PLAN/SUMMARY files.
8
+ *
9
+ * Context reduction (issue #1614):
10
+ * - Large files are truncated to keep prompts cache-friendly
11
+ * - ROADMAP.md is narrowed to the current milestone when possible
12
+ * - Truncation preserves headings + first paragraph per section
13
+ */
14
+
15
+ import { readFile, access } from 'node:fs/promises';
16
+ import { join } from 'node:path';
17
+ import { constants } from 'node:fs';
18
+
19
+ import type { ContextFiles } from './types.js';
20
+ import { PhaseType } from './types.js';
21
+ import type { GSDLogger } from './logger.js';
22
+ import {
23
+ truncateMarkdown,
24
+ extractCurrentMilestone,
25
+ DEFAULT_TRUNCATION_OPTIONS,
26
+ type TruncationOptions,
27
+ } from './context-truncation.js';
28
+ import { relPlanningPath } from './workstream-utils.js';
29
+
30
+ // ─── File manifest per phase ─────────────────────────────────────────────────
31
+
32
+ interface FileSpec {
33
+ key: keyof ContextFiles;
34
+ filename: string;
35
+ required: boolean;
36
+ }
37
+
38
+ /**
39
+ * Define which files each phase needs. Required files emit warnings when missing;
40
+ * optional files silently return undefined.
41
+ */
42
+ const PHASE_FILE_MANIFEST: Record<PhaseType, FileSpec[]> = {
43
+ [PhaseType.Execute]: [
44
+ { key: 'state', filename: 'STATE.md', required: true },
45
+ { key: 'config', filename: 'config.json', required: false },
46
+ ],
47
+ [PhaseType.Research]: [
48
+ { key: 'state', filename: 'STATE.md', required: true },
49
+ { key: 'roadmap', filename: 'ROADMAP.md', required: true },
50
+ { key: 'context', filename: 'CONTEXT.md', required: true },
51
+ { key: 'requirements', filename: 'REQUIREMENTS.md', required: false },
52
+ ],
53
+ [PhaseType.Plan]: [
54
+ { key: 'state', filename: 'STATE.md', required: true },
55
+ { key: 'roadmap', filename: 'ROADMAP.md', required: true },
56
+ { key: 'context', filename: 'CONTEXT.md', required: true },
57
+ { key: 'research', filename: 'RESEARCH.md', required: false },
58
+ { key: 'requirements', filename: 'REQUIREMENTS.md', required: false },
59
+ ],
60
+ [PhaseType.Verify]: [
61
+ { key: 'state', filename: 'STATE.md', required: true },
62
+ { key: 'roadmap', filename: 'ROADMAP.md', required: true },
63
+ { key: 'requirements', filename: 'REQUIREMENTS.md', required: false },
64
+ { key: 'plan', filename: 'PLAN.md', required: false },
65
+ { key: 'summary', filename: 'SUMMARY.md', required: false },
66
+ ],
67
+ [PhaseType.Repair]: [
68
+ { key: 'state', filename: 'STATE.md', required: true },
69
+ { key: 'config', filename: 'config.json', required: false },
70
+ { key: 'plan', filename: 'PLAN.md', required: false },
71
+ ],
72
+ [PhaseType.Discuss]: [
73
+ { key: 'state', filename: 'STATE.md', required: true },
74
+ { key: 'roadmap', filename: 'ROADMAP.md', required: false },
75
+ { key: 'context', filename: 'CONTEXT.md', required: false },
76
+ ],
77
+ };
78
+
79
+ // ─── ContextEngine class ─────────────────────────────────────────────────────
80
+
81
+ export class ContextEngine {
82
+ private readonly planningDir: string;
83
+ private readonly logger?: GSDLogger;
84
+ private readonly truncation: TruncationOptions;
85
+
86
+ constructor(projectDir: string, logger?: GSDLogger, truncation?: Partial<TruncationOptions>, workstream?: string) {
87
+ this.planningDir = join(projectDir, relPlanningPath(workstream));
88
+ this.logger = logger;
89
+ this.truncation = { ...DEFAULT_TRUNCATION_OPTIONS, ...truncation };
90
+ }
91
+
92
+ /**
93
+ * Resolve context files appropriate for the given phase type.
94
+ * Reads each file defined in the phase manifest, returning undefined
95
+ * for missing optional files and warning for missing required files.
96
+ *
97
+ * Files exceeding the truncation threshold are reduced to headings +
98
+ * first paragraphs. ROADMAP.md is narrowed to the current milestone.
99
+ */
100
+ async resolveContextFiles(phaseType: PhaseType): Promise<ContextFiles> {
101
+ const manifest = PHASE_FILE_MANIFEST[phaseType];
102
+ const result: ContextFiles = {};
103
+
104
+ for (const spec of manifest) {
105
+ const filePath = join(this.planningDir, spec.filename);
106
+ const content = await this.readFileIfExists(filePath);
107
+
108
+ if (content !== undefined) {
109
+ result[spec.key] = content;
110
+ } else if (spec.required) {
111
+ this.logger?.warn(`Required context file missing for ${phaseType} phase: ${spec.filename}`, {
112
+ phase: phaseType,
113
+ file: spec.filename,
114
+ path: filePath,
115
+ });
116
+ }
117
+ }
118
+
119
+ // Apply context reduction: milestone extraction then truncation
120
+ if (result.roadmap && result.state) {
121
+ const before = result.roadmap.length;
122
+ result.roadmap = extractCurrentMilestone(result.roadmap, result.state);
123
+ if (result.roadmap.length < before) {
124
+ this.logger?.debug?.('ROADMAP.md narrowed to current milestone', {
125
+ before,
126
+ after: result.roadmap.length,
127
+ });
128
+ }
129
+ }
130
+
131
+ // Truncate oversized files (skip config.json — structured data, not markdown)
132
+ const truncatable: Array<{ key: keyof ContextFiles; filename: string }> = [
133
+ { key: 'roadmap', filename: 'ROADMAP.md' },
134
+ { key: 'context', filename: 'CONTEXT.md' },
135
+ { key: 'research', filename: 'RESEARCH.md' },
136
+ { key: 'requirements', filename: 'REQUIREMENTS.md' },
137
+ { key: 'plan', filename: 'PLAN.md' },
138
+ { key: 'summary', filename: 'SUMMARY.md' },
139
+ ];
140
+
141
+ for (const { key, filename } of truncatable) {
142
+ const raw = result[key];
143
+ if (raw && raw.length > this.truncation.maxContentLength) {
144
+ const before = raw.length;
145
+ result[key] = truncateMarkdown(raw, filename, this.truncation);
146
+ this.logger?.debug?.(`${filename} truncated`, {
147
+ before,
148
+ after: result[key]!.length,
149
+ });
150
+ }
151
+ }
152
+
153
+ return result;
154
+ }
155
+
156
+ /**
157
+ * Check if a file exists and read it. Returns undefined if not found.
158
+ */
159
+ private async readFileIfExists(filePath: string): Promise<string | undefined> {
160
+ try {
161
+ await access(filePath, constants.R_OK);
162
+ return await readFile(filePath, 'utf-8');
163
+ } catch {
164
+ return undefined;
165
+ }
166
+ }
167
+ }
168
+
169
+ export { PHASE_FILE_MANIFEST };
170
+ export type { FileSpec };
@@ -0,0 +1,163 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import {
3
+ truncateMarkdown,
4
+ extractCurrentMilestone,
5
+ DEFAULT_TRUNCATION_OPTIONS,
6
+ } from './context-truncation.js';
7
+
8
+ // ─── truncateMarkdown ───────────────────────────────────────────────────────
9
+
10
+ describe('truncateMarkdown', () => {
11
+ it('returns content unchanged when below threshold', () => {
12
+ const content = '# Title\n\nShort content.';
13
+ const result = truncateMarkdown(content, 'TEST.md');
14
+ expect(result).toBe(content);
15
+ });
16
+
17
+ it('truncates content above threshold, keeping headings and first paragraphs', () => {
18
+ const sections = [];
19
+ for (let i = 0; i < 20; i++) {
20
+ sections.push(`## Section ${i}\n\nFirst paragraph of section ${i}.\n\nSecond paragraph with lots of detail.\nMore detail here.\nEven more detail.`);
21
+ }
22
+ const content = `# Title\n\n${sections.join('\n\n')}`;
23
+ const result = truncateMarkdown(content, 'BIG.md', { maxContentLength: 100 });
24
+
25
+ // Headings preserved
26
+ expect(result).toContain('# Title');
27
+ expect(result).toContain('## Section 0');
28
+ expect(result).toContain('## Section 19');
29
+
30
+ // First paragraphs preserved
31
+ expect(result).toContain('First paragraph of section 0.');
32
+ expect(result).toContain('First paragraph of section 19.');
33
+
34
+ // Second paragraphs omitted
35
+ expect(result).not.toContain('Second paragraph');
36
+ expect(result).not.toContain('More detail here.');
37
+
38
+ // Truncation markers present
39
+ expect(result).toContain('[...');
40
+ expect(result).toContain('lines omitted]');
41
+ expect(result).toContain('[Truncated: read .planning/BIG.md for full content]');
42
+ });
43
+
44
+ it('preserves YAML frontmatter entirely', () => {
45
+ const content = `---\nphase: "01"\nstatus: active\n---\n\n# Title\n\nParagraph 1.\n\nParagraph 2.\n${'x'.repeat(10000)}`;
46
+ const result = truncateMarkdown(content, 'STATE.md', { maxContentLength: 100 });
47
+
48
+ expect(result).toContain('---\nphase: "01"\nstatus: active\n---');
49
+ expect(result).toContain('# Title');
50
+ expect(result).toContain('Paragraph 1.');
51
+ });
52
+
53
+ it('is smaller than original when truncated', () => {
54
+ const longContent = Array.from({ length: 200 }, (_, i) =>
55
+ `## Section ${i}\n\nFirst paragraph.\n\nLong detail paragraph ${'x'.repeat(100)}.`
56
+ ).join('\n\n');
57
+
58
+ const result = truncateMarkdown(longContent, 'HUGE.md', { maxContentLength: 100 });
59
+ expect(result.length).toBeLessThan(longContent.length);
60
+ });
61
+
62
+ it('handles content with no headings', () => {
63
+ const content = `First line.\n\nSecond paragraph.\n\nThird paragraph.\n${'x'.repeat(10000)}`;
64
+ const result = truncateMarkdown(content, 'FLAT.md', { maxContentLength: 100 });
65
+
66
+ // Should still truncate — first paragraph kept
67
+ expect(result).toContain('First line.');
68
+ expect(result.length).toBeLessThan(content.length);
69
+ });
70
+
71
+ it('default threshold is 8192 characters', () => {
72
+ expect(DEFAULT_TRUNCATION_OPTIONS.maxContentLength).toBe(8192);
73
+ });
74
+ });
75
+
76
+ // ─── extractCurrentMilestone ────────────────────────────────────────────────
77
+
78
+ describe('extractCurrentMilestone', () => {
79
+ const makeRoadmap = () => `# Project Roadmap
80
+
81
+ ## Milestone 1: Foundation
82
+ ### Phase 01: Setup
83
+ Requirements for setup.
84
+ ### Phase 02: Core
85
+ Requirements for core.
86
+
87
+ ## Milestone 2: Features
88
+ ### Phase 03: Auth
89
+ Requirements for auth.
90
+ ### Phase 04: API
91
+ Requirements for API.
92
+
93
+ ## Milestone 3: Polish
94
+ ### Phase 05: UI
95
+ Requirements for UI.`;
96
+
97
+ it('returns full roadmap when no state provided', () => {
98
+ const roadmap = makeRoadmap();
99
+ expect(extractCurrentMilestone(roadmap)).toBe(roadmap);
100
+ });
101
+
102
+ it('returns full roadmap when milestone not found in state', () => {
103
+ const roadmap = makeRoadmap();
104
+ const state = '# State\nstatus: active';
105
+ expect(extractCurrentMilestone(roadmap, state)).toBe(roadmap);
106
+ });
107
+
108
+ it('extracts current milestone section by name', () => {
109
+ const roadmap = makeRoadmap();
110
+ const state = 'Current Milestone: Features';
111
+ const result = extractCurrentMilestone(roadmap, state);
112
+
113
+ expect(result).toContain('## Milestone 2: Features');
114
+ expect(result).toContain('### Phase 03: Auth');
115
+ expect(result).toContain('### Phase 04: API');
116
+
117
+ // Other milestones omitted
118
+ expect(result).not.toContain('### Phase 01: Setup');
119
+ expect(result).not.toContain('### Phase 05: UI');
120
+ expect(result).toContain('other milestone(s) omitted');
121
+ });
122
+
123
+ it('matches milestone name case-insensitively', () => {
124
+ const roadmap = makeRoadmap();
125
+ const state = 'current milestone: features';
126
+ const result = extractCurrentMilestone(roadmap, state);
127
+
128
+ expect(result).toContain('## Milestone 2: Features');
129
+ expect(result).not.toContain('### Phase 01: Setup');
130
+ });
131
+
132
+ it('matches milestone from "milestone:" field in state', () => {
133
+ const roadmap = makeRoadmap();
134
+ const state = '# State\nmilestone: Foundation\nphase: 01';
135
+ const result = extractCurrentMilestone(roadmap, state);
136
+
137
+ expect(result).toContain('## Milestone 1: Foundation');
138
+ expect(result).toContain('### Phase 01: Setup');
139
+ expect(result).not.toContain('### Phase 03: Auth');
140
+ });
141
+
142
+ it('matches milestone from Current Position block', () => {
143
+ const roadmap = makeRoadmap();
144
+ const state = `# State
145
+
146
+ ## Current Position
147
+ milestone: Polish
148
+ phase: 05`;
149
+ const result = extractCurrentMilestone(roadmap, state);
150
+
151
+ expect(result).toContain('## Milestone 3: Polish');
152
+ expect(result).toContain('### Phase 05: UI');
153
+ expect(result).not.toContain('### Phase 01: Setup');
154
+ });
155
+
156
+ it('preserves roadmap title in output', () => {
157
+ const roadmap = makeRoadmap();
158
+ const state = 'Current Milestone: Features';
159
+ const result = extractCurrentMilestone(roadmap, state);
160
+
161
+ expect(result).toContain('# Project Roadmap');
162
+ });
163
+ });
@@ -0,0 +1,233 @@
1
+ /**
2
+ * Context truncation — reduces large .planning/ files to cache-friendly sizes.
3
+ *
4
+ * Two strategies:
5
+ * 1. Markdown-aware truncation: keeps headings + first paragraph per section,
6
+ * replaces the rest with a pointer to the full file.
7
+ * 2. Milestone extraction: pulls only the current milestone from ROADMAP.md.
8
+ *
9
+ * All functions are pure — no I/O, no side effects.
10
+ */
11
+
12
+ // ─── Types ──────────────────────────────────────────────────────────────────
13
+
14
+ export interface TruncationOptions {
15
+ /** Max content length in characters before truncation kicks in. Default: 8192 */
16
+ maxContentLength: number;
17
+ }
18
+
19
+ export const DEFAULT_TRUNCATION_OPTIONS: TruncationOptions = {
20
+ maxContentLength: 8192,
21
+ };
22
+
23
+ // ─── Markdown-aware truncation ──────────────────────────────────────────────
24
+
25
+ /**
26
+ * Truncate markdown content while preserving structure.
27
+ *
28
+ * Strategy: keep YAML frontmatter, all headings, and the first paragraph under
29
+ * each heading. Collapse everything else with a line count summary.
30
+ *
31
+ * Returns the original content unchanged if below maxContentLength.
32
+ */
33
+ export function truncateMarkdown(
34
+ content: string,
35
+ filename: string,
36
+ options: TruncationOptions = DEFAULT_TRUNCATION_OPTIONS,
37
+ ): string {
38
+ if (content.length <= options.maxContentLength) return content;
39
+
40
+ const lines = content.split('\n');
41
+ const kept: string[] = [];
42
+ let inFrontmatter = false;
43
+ let frontmatterDone = false;
44
+ let currentSectionLines = 0;
45
+ let paragraphKept = false;
46
+ let omittedLines = 0;
47
+ let inParagraph = false;
48
+
49
+ for (let i = 0; i < lines.length; i++) {
50
+ const line = lines[i];
51
+
52
+ // Handle YAML frontmatter (preserve entirely)
53
+ if (i === 0 && line.trim() === '---') {
54
+ inFrontmatter = true;
55
+ kept.push(line);
56
+ continue;
57
+ }
58
+ if (inFrontmatter) {
59
+ kept.push(line);
60
+ if (line.trim() === '---') {
61
+ inFrontmatter = false;
62
+ frontmatterDone = true;
63
+ }
64
+ continue;
65
+ }
66
+
67
+ // Heading — always keep, reset paragraph tracking
68
+ if (/^#{1,6}\s/.test(line)) {
69
+ if (omittedLines > 0) {
70
+ kept.push(`[... ${omittedLines} lines omitted]`);
71
+ omittedLines = 0;
72
+ }
73
+ kept.push(line);
74
+ currentSectionLines = 0;
75
+ paragraphKept = false;
76
+ inParagraph = false;
77
+ continue;
78
+ }
79
+
80
+ // Empty line — paragraph boundary
81
+ if (line.trim() === '') {
82
+ if (inParagraph && !paragraphKept) {
83
+ // End of first paragraph — mark it kept
84
+ paragraphKept = true;
85
+ }
86
+ if (!paragraphKept || currentSectionLines === 0) {
87
+ kept.push(line);
88
+ } else {
89
+ omittedLines++;
90
+ }
91
+ inParagraph = false;
92
+ continue;
93
+ }
94
+
95
+ // Content line
96
+ currentSectionLines++;
97
+ if (!paragraphKept) {
98
+ // Still in the first paragraph — keep it
99
+ kept.push(line);
100
+ inParagraph = true;
101
+ } else {
102
+ omittedLines++;
103
+ }
104
+ }
105
+
106
+ if (omittedLines > 0) {
107
+ kept.push(`[... ${omittedLines} lines omitted]`);
108
+ }
109
+
110
+ const totalOmitted = lines.length - kept.length;
111
+ if (totalOmitted > 0) {
112
+ kept.push('');
113
+ kept.push(`[Truncated: read .planning/${filename} for full content]`);
114
+ }
115
+
116
+ return kept.join('\n');
117
+ }
118
+
119
+ // ─── Milestone extraction ───────────────────────────────────────────────────
120
+
121
+ /**
122
+ * Extract the current milestone section from a ROADMAP.md.
123
+ *
124
+ * Parses STATE.md to find the current milestone name, then extracts only
125
+ * that milestone's section from the roadmap. Falls back to full content
126
+ * if the milestone can't be identified or found.
127
+ */
128
+ export function extractCurrentMilestone(
129
+ roadmapContent: string,
130
+ stateContent?: string,
131
+ ): string {
132
+ if (!stateContent) return roadmapContent;
133
+
134
+ // Find current milestone from STATE.md
135
+ // Patterns: "Current Milestone: X", "milestone: X", "## Current Position" block
136
+ const milestonePatterns = [
137
+ /current\s*milestone\s*:\s*(.+)/i,
138
+ /^milestone\s*:\s*(.+)/im,
139
+ /##\s*current\s*position[\s\S]*?milestone\s*:\s*(.+)/i,
140
+ ];
141
+
142
+ let milestoneName: string | undefined;
143
+ for (const pattern of milestonePatterns) {
144
+ const match = stateContent.match(pattern);
145
+ if (match) {
146
+ milestoneName = match[1].trim();
147
+ break;
148
+ }
149
+ }
150
+
151
+ if (!milestoneName) return roadmapContent;
152
+
153
+ // Find the milestone section in roadmap
154
+ // Look for heading containing the milestone name
155
+ const lines = roadmapContent.split('\n');
156
+ let sectionStart = -1;
157
+ let sectionEnd = lines.length;
158
+ let sectionHeadingLevel = 0;
159
+
160
+ for (let i = 0; i < lines.length; i++) {
161
+ const headingMatch = lines[i].match(/^(#{1,6})\s+(.+)/);
162
+ if (!headingMatch) continue;
163
+
164
+ const level = headingMatch[1].length;
165
+ const title = headingMatch[2];
166
+
167
+ if (sectionStart === -1) {
168
+ // Looking for the milestone heading
169
+ if (title.toLowerCase().includes(milestoneName.toLowerCase())) {
170
+ sectionStart = i;
171
+ sectionHeadingLevel = level;
172
+ }
173
+ } else {
174
+ // Found start — look for next heading at same or higher level
175
+ if (level <= sectionHeadingLevel) {
176
+ sectionEnd = i;
177
+ break;
178
+ }
179
+ }
180
+ }
181
+
182
+ if (sectionStart === -1) return roadmapContent;
183
+
184
+ // Extract preamble (everything before first milestone heading at the same level)
185
+ const preamble: string[] = [];
186
+ for (let i = 0; i < lines.length; i++) {
187
+ const headingMatch = lines[i].match(/^(#{1,6})\s/);
188
+ if (headingMatch && headingMatch[1].length === sectionHeadingLevel && i !== sectionStart) {
189
+ // Hit another milestone-level heading before our section
190
+ if (i < sectionStart) {
191
+ break; // preamble ends at first milestone heading
192
+ }
193
+ }
194
+ if (i < sectionStart) {
195
+ // Keep top-level title and intro
196
+ if (i === 0 || lines[i].match(/^#\s/) || !lines[i].match(/^#{1,6}\s/)) {
197
+ preamble.push(lines[i]);
198
+ }
199
+ }
200
+ }
201
+
202
+ const milestoneSection = lines.slice(sectionStart, sectionEnd).join('\n');
203
+ const otherMilestones = countOtherMilestones(lines, sectionHeadingLevel, sectionStart);
204
+
205
+ const result = [
206
+ ...preamble,
207
+ '',
208
+ milestoneSection,
209
+ ];
210
+
211
+ if (otherMilestones > 0) {
212
+ result.push('');
213
+ result.push(`[${otherMilestones} other milestone(s) omitted — read .planning/ROADMAP.md for full roadmap]`);
214
+ }
215
+
216
+ return result.join('\n').trim();
217
+ }
218
+
219
+ function countOtherMilestones(
220
+ lines: string[],
221
+ headingLevel: number,
222
+ excludeIndex: number,
223
+ ): number {
224
+ let count = 0;
225
+ for (let i = 0; i < lines.length; i++) {
226
+ if (i === excludeIndex) continue;
227
+ const match = lines[i].match(/^(#{1,6})\s/);
228
+ if (match && match[1].length === headingLevel) {
229
+ count++;
230
+ }
231
+ }
232
+ return count;
233
+ }