gsd-pi 2.18.0 → 2.20.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 (289) hide show
  1. package/README.md +5 -1
  2. package/dist/cli.js +3 -3
  3. package/dist/onboarding.d.ts +3 -1
  4. package/dist/onboarding.js +77 -3
  5. package/dist/remote-questions-config.d.ts +1 -1
  6. package/dist/resources/extensions/google-search/index.ts +164 -47
  7. package/dist/resources/extensions/gsd/auto-dashboard.ts +14 -2
  8. package/dist/resources/extensions/gsd/auto-prompts.ts +148 -39
  9. package/dist/resources/extensions/gsd/auto-worktree.ts +93 -9
  10. package/dist/resources/extensions/gsd/auto.ts +690 -39
  11. package/dist/resources/extensions/gsd/captures.ts +384 -0
  12. package/dist/resources/extensions/gsd/commands.ts +654 -36
  13. package/dist/resources/extensions/gsd/complexity-classifier.ts +322 -0
  14. package/dist/resources/extensions/gsd/context-budget.ts +243 -0
  15. package/dist/resources/extensions/gsd/context-store.ts +195 -0
  16. package/dist/resources/extensions/gsd/dashboard-overlay.ts +51 -3
  17. package/dist/resources/extensions/gsd/db-writer.ts +341 -0
  18. package/dist/resources/extensions/gsd/debug-logger.ts +178 -0
  19. package/dist/resources/extensions/gsd/dispatch-guard.ts +0 -1
  20. package/dist/resources/extensions/gsd/docs/preferences-reference.md +54 -0
  21. package/dist/resources/extensions/gsd/doctor-proactive.ts +286 -0
  22. package/dist/resources/extensions/gsd/doctor.ts +283 -2
  23. package/dist/resources/extensions/gsd/export.ts +81 -2
  24. package/dist/resources/extensions/gsd/files.ts +39 -9
  25. package/dist/resources/extensions/gsd/git-service.ts +6 -0
  26. package/dist/resources/extensions/gsd/gsd-db.ts +752 -0
  27. package/dist/resources/extensions/gsd/guided-flow.ts +26 -1
  28. package/dist/resources/extensions/gsd/history.ts +0 -1
  29. package/dist/resources/extensions/gsd/index.ts +277 -1
  30. package/dist/resources/extensions/gsd/md-importer.ts +526 -0
  31. package/dist/resources/extensions/gsd/metrics.ts +84 -0
  32. package/dist/resources/extensions/gsd/model-cost-table.ts +65 -0
  33. package/dist/resources/extensions/gsd/model-router.ts +256 -0
  34. package/dist/resources/extensions/gsd/notifications.ts +0 -1
  35. package/dist/resources/extensions/gsd/post-unit-hooks.ts +72 -2
  36. package/dist/resources/extensions/gsd/preferences.ts +198 -150
  37. package/dist/resources/extensions/gsd/prompt-loader.ts +45 -9
  38. package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -5
  39. package/dist/resources/extensions/gsd/prompts/heal-skill.md +45 -0
  40. package/dist/resources/extensions/gsd/prompts/plan-slice.md +5 -1
  41. package/dist/resources/extensions/gsd/prompts/quick-task.md +48 -0
  42. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -0
  43. package/dist/resources/extensions/gsd/prompts/replan-slice.md +8 -0
  44. package/dist/resources/extensions/gsd/prompts/system.md +2 -1
  45. package/dist/resources/extensions/gsd/prompts/triage-captures.md +62 -0
  46. package/dist/resources/extensions/gsd/quick.ts +156 -0
  47. package/dist/resources/extensions/gsd/skill-discovery.ts +5 -3
  48. package/dist/resources/extensions/gsd/skill-health.ts +417 -0
  49. package/dist/resources/extensions/gsd/skill-telemetry.ts +127 -0
  50. package/dist/resources/extensions/gsd/state.ts +30 -0
  51. package/dist/resources/extensions/gsd/templates/preferences.md +1 -0
  52. package/dist/resources/extensions/gsd/tests/captures.test.ts +438 -0
  53. package/dist/resources/extensions/gsd/tests/complexity-classifier.test.ts +181 -0
  54. package/dist/resources/extensions/gsd/tests/context-budget.test.ts +283 -0
  55. package/dist/resources/extensions/gsd/tests/context-compression.test.ts +1 -1
  56. package/dist/resources/extensions/gsd/tests/context-store.test.ts +462 -0
  57. package/dist/resources/extensions/gsd/tests/continue-here.test.ts +204 -0
  58. package/dist/resources/extensions/gsd/tests/dashboard-budget.test.ts +346 -0
  59. package/dist/resources/extensions/gsd/tests/db-writer.test.ts +602 -0
  60. package/dist/resources/extensions/gsd/tests/debug-logger.test.ts +185 -0
  61. package/dist/resources/extensions/gsd/tests/derive-state-db.test.ts +406 -0
  62. package/dist/resources/extensions/gsd/tests/dispatch-guard.test.ts +0 -1
  63. package/dist/resources/extensions/gsd/tests/dist-redirect.mjs +22 -0
  64. package/dist/resources/extensions/gsd/tests/doctor-proactive.test.ts +244 -0
  65. package/dist/resources/extensions/gsd/tests/doctor-runtime.test.ts +303 -0
  66. package/dist/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +434 -0
  67. package/dist/resources/extensions/gsd/tests/gsd-db.test.ts +353 -0
  68. package/dist/resources/extensions/gsd/tests/gsd-inspect.test.ts +125 -0
  69. package/dist/resources/extensions/gsd/tests/gsd-tools.test.ts +326 -0
  70. package/dist/resources/extensions/gsd/tests/integration-edge.test.ts +228 -0
  71. package/dist/resources/extensions/gsd/tests/integration-lifecycle.test.ts +277 -0
  72. package/dist/resources/extensions/gsd/tests/md-importer.test.ts +411 -0
  73. package/dist/resources/extensions/gsd/tests/metrics.test.ts +197 -0
  74. package/dist/resources/extensions/gsd/tests/milestone-transition-worktree.test.ts +144 -0
  75. package/dist/resources/extensions/gsd/tests/model-cost-table.test.ts +69 -0
  76. package/dist/resources/extensions/gsd/tests/model-isolation.test.ts +99 -0
  77. package/dist/resources/extensions/gsd/tests/model-router.test.ts +167 -0
  78. package/dist/resources/extensions/gsd/tests/parsers.test.ts +40 -0
  79. package/dist/resources/extensions/gsd/tests/post-unit-hooks.test.ts +41 -1
  80. package/dist/resources/extensions/gsd/tests/preferences-git.test.ts +0 -1
  81. package/dist/resources/extensions/gsd/tests/preferences-hooks.test.ts +0 -1
  82. package/dist/resources/extensions/gsd/tests/preferences-mode.test.ts +110 -0
  83. package/dist/resources/extensions/gsd/tests/preferences-models.test.ts +0 -1
  84. package/dist/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +464 -0
  85. package/dist/resources/extensions/gsd/tests/prompt-db.test.ts +385 -0
  86. package/dist/resources/extensions/gsd/tests/remote-questions.test.ts +488 -1
  87. package/dist/resources/extensions/gsd/tests/resolve-ts-hooks.mjs +17 -29
  88. package/dist/resources/extensions/gsd/tests/resolve-ts.mjs +2 -8
  89. package/dist/resources/extensions/gsd/tests/routing-history.test.ts +215 -62
  90. package/dist/resources/extensions/gsd/tests/skill-lifecycle.test.ts +126 -0
  91. package/dist/resources/extensions/gsd/tests/stop-auto-remote.test.ts +31 -8
  92. package/dist/resources/extensions/gsd/tests/token-savings.test.ts +366 -0
  93. package/dist/resources/extensions/gsd/tests/triage-dispatch.test.ts +224 -0
  94. package/dist/resources/extensions/gsd/tests/triage-resolution.test.ts +215 -0
  95. package/dist/resources/extensions/gsd/tests/unit-runtime.test.ts +25 -1
  96. package/dist/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +145 -0
  97. package/dist/resources/extensions/gsd/tests/visualizer-data.test.ts +290 -0
  98. package/dist/resources/extensions/gsd/tests/visualizer-overlay.test.ts +120 -0
  99. package/dist/resources/extensions/gsd/tests/visualizer-views.test.ts +478 -0
  100. package/dist/resources/extensions/gsd/tests/worktree-db-integration.test.ts +205 -0
  101. package/dist/resources/extensions/gsd/tests/worktree-db.test.ts +442 -0
  102. package/dist/resources/extensions/gsd/tests/worktree-post-create-hook.test.ts +165 -0
  103. package/dist/resources/extensions/gsd/triage-resolution.ts +200 -0
  104. package/dist/resources/extensions/gsd/triage-ui.ts +175 -0
  105. package/dist/resources/extensions/gsd/types.ts +29 -0
  106. package/dist/resources/extensions/gsd/undo.ts +0 -1
  107. package/dist/resources/extensions/gsd/unit-runtime.ts +5 -1
  108. package/dist/resources/extensions/gsd/visualizer-data.ts +505 -0
  109. package/dist/resources/extensions/gsd/visualizer-overlay.ts +337 -0
  110. package/dist/resources/extensions/gsd/visualizer-views.ts +755 -0
  111. package/dist/resources/extensions/gsd/worktree-command.ts +18 -0
  112. package/dist/resources/extensions/gsd/worktree-manager.ts +11 -4
  113. package/dist/resources/extensions/remote-questions/config.ts +4 -2
  114. package/dist/resources/extensions/remote-questions/discord-adapter.ts +35 -4
  115. package/dist/resources/extensions/remote-questions/format.ts +166 -14
  116. package/dist/resources/extensions/remote-questions/manager.ts +14 -4
  117. package/dist/resources/extensions/remote-questions/remote-command.ts +100 -4
  118. package/dist/resources/extensions/remote-questions/slack-adapter.ts +58 -2
  119. package/dist/resources/extensions/remote-questions/telegram-adapter.ts +161 -0
  120. package/dist/resources/extensions/remote-questions/types.ts +2 -1
  121. package/dist/resources/extensions/ttsr/ttsr-manager.ts +26 -0
  122. package/dist/resources/extensions/voice/index.ts +4 -3
  123. package/package.json +1 -1
  124. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  125. package/packages/pi-coding-agent/dist/core/agent-session.js +12 -1
  126. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  127. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  128. package/packages/pi-coding-agent/dist/core/extensions/loader.js +5 -0
  129. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  130. package/packages/pi-coding-agent/dist/core/lsp/client.d.ts +6 -0
  131. package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
  132. package/packages/pi-coding-agent/dist/core/lsp/client.js +25 -0
  133. package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
  134. package/packages/pi-coding-agent/dist/core/lsp/index.d.ts +2 -0
  135. package/packages/pi-coding-agent/dist/core/lsp/index.d.ts.map +1 -1
  136. package/packages/pi-coding-agent/dist/core/lsp/index.js +106 -3
  137. package/packages/pi-coding-agent/dist/core/lsp/index.js.map +1 -1
  138. package/packages/pi-coding-agent/dist/core/lsp/lsp.md +6 -0
  139. package/packages/pi-coding-agent/dist/core/lsp/types.d.ts +35 -0
  140. package/packages/pi-coding-agent/dist/core/lsp/types.d.ts.map +1 -1
  141. package/packages/pi-coding-agent/dist/core/lsp/types.js +6 -0
  142. package/packages/pi-coding-agent/dist/core/lsp/types.js.map +1 -1
  143. package/packages/pi-coding-agent/dist/core/lsp/utils.d.ts +3 -1
  144. package/packages/pi-coding-agent/dist/core/lsp/utils.d.ts.map +1 -1
  145. package/packages/pi-coding-agent/dist/core/lsp/utils.js +45 -0
  146. package/packages/pi-coding-agent/dist/core/lsp/utils.js.map +1 -1
  147. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +6 -0
  148. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  149. package/packages/pi-coding-agent/dist/core/settings-manager.js +43 -11
  150. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  151. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  152. package/packages/pi-coding-agent/dist/core/system-prompt.js +7 -1
  153. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  154. package/packages/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
  155. package/packages/pi-coding-agent/dist/core/tools/edit.js +5 -0
  156. package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
  157. package/packages/pi-coding-agent/dist/core/tools/index.d.ts +2 -0
  158. package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
  159. package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
  160. package/packages/pi-coding-agent/dist/core/tools/write.js +5 -0
  161. package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
  162. package/packages/pi-coding-agent/src/core/agent-session.ts +13 -1
  163. package/packages/pi-coding-agent/src/core/extensions/loader.ts +6 -0
  164. package/packages/pi-coding-agent/src/core/lsp/client.ts +26 -0
  165. package/packages/pi-coding-agent/src/core/lsp/index.ts +157 -2
  166. package/packages/pi-coding-agent/src/core/lsp/lsp.md +6 -0
  167. package/packages/pi-coding-agent/src/core/lsp/types.ts +53 -0
  168. package/packages/pi-coding-agent/src/core/lsp/utils.ts +56 -0
  169. package/packages/pi-coding-agent/src/core/settings-manager.ts +41 -11
  170. package/packages/pi-coding-agent/src/core/system-prompt.ts +7 -1
  171. package/packages/pi-coding-agent/src/core/tools/edit.ts +3 -0
  172. package/packages/pi-coding-agent/src/core/tools/write.ts +3 -0
  173. package/src/resources/extensions/google-search/index.ts +164 -47
  174. package/src/resources/extensions/gsd/auto-dashboard.ts +14 -2
  175. package/src/resources/extensions/gsd/auto-prompts.ts +148 -39
  176. package/src/resources/extensions/gsd/auto-worktree.ts +93 -9
  177. package/src/resources/extensions/gsd/auto.ts +690 -39
  178. package/src/resources/extensions/gsd/captures.ts +384 -0
  179. package/src/resources/extensions/gsd/commands.ts +654 -36
  180. package/src/resources/extensions/gsd/complexity-classifier.ts +322 -0
  181. package/src/resources/extensions/gsd/context-budget.ts +243 -0
  182. package/src/resources/extensions/gsd/context-store.ts +195 -0
  183. package/src/resources/extensions/gsd/dashboard-overlay.ts +51 -3
  184. package/src/resources/extensions/gsd/db-writer.ts +341 -0
  185. package/src/resources/extensions/gsd/debug-logger.ts +178 -0
  186. package/src/resources/extensions/gsd/dispatch-guard.ts +0 -1
  187. package/src/resources/extensions/gsd/docs/preferences-reference.md +54 -0
  188. package/src/resources/extensions/gsd/doctor-proactive.ts +286 -0
  189. package/src/resources/extensions/gsd/doctor.ts +283 -2
  190. package/src/resources/extensions/gsd/export.ts +81 -2
  191. package/src/resources/extensions/gsd/files.ts +39 -9
  192. package/src/resources/extensions/gsd/git-service.ts +6 -0
  193. package/src/resources/extensions/gsd/gsd-db.ts +752 -0
  194. package/src/resources/extensions/gsd/guided-flow.ts +26 -1
  195. package/src/resources/extensions/gsd/history.ts +0 -1
  196. package/src/resources/extensions/gsd/index.ts +277 -1
  197. package/src/resources/extensions/gsd/md-importer.ts +526 -0
  198. package/src/resources/extensions/gsd/metrics.ts +84 -0
  199. package/src/resources/extensions/gsd/model-cost-table.ts +65 -0
  200. package/src/resources/extensions/gsd/model-router.ts +256 -0
  201. package/src/resources/extensions/gsd/notifications.ts +0 -1
  202. package/src/resources/extensions/gsd/post-unit-hooks.ts +72 -2
  203. package/src/resources/extensions/gsd/preferences.ts +198 -150
  204. package/src/resources/extensions/gsd/prompt-loader.ts +45 -9
  205. package/src/resources/extensions/gsd/prompts/execute-task.md +3 -5
  206. package/src/resources/extensions/gsd/prompts/heal-skill.md +45 -0
  207. package/src/resources/extensions/gsd/prompts/plan-slice.md +5 -1
  208. package/src/resources/extensions/gsd/prompts/quick-task.md +48 -0
  209. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -0
  210. package/src/resources/extensions/gsd/prompts/replan-slice.md +8 -0
  211. package/src/resources/extensions/gsd/prompts/system.md +2 -1
  212. package/src/resources/extensions/gsd/prompts/triage-captures.md +62 -0
  213. package/src/resources/extensions/gsd/quick.ts +156 -0
  214. package/src/resources/extensions/gsd/skill-discovery.ts +5 -3
  215. package/src/resources/extensions/gsd/skill-health.ts +417 -0
  216. package/src/resources/extensions/gsd/skill-telemetry.ts +127 -0
  217. package/src/resources/extensions/gsd/state.ts +30 -0
  218. package/src/resources/extensions/gsd/templates/preferences.md +1 -0
  219. package/src/resources/extensions/gsd/tests/captures.test.ts +438 -0
  220. package/src/resources/extensions/gsd/tests/complexity-classifier.test.ts +181 -0
  221. package/src/resources/extensions/gsd/tests/context-budget.test.ts +283 -0
  222. package/src/resources/extensions/gsd/tests/context-compression.test.ts +1 -1
  223. package/src/resources/extensions/gsd/tests/context-store.test.ts +462 -0
  224. package/src/resources/extensions/gsd/tests/continue-here.test.ts +204 -0
  225. package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +346 -0
  226. package/src/resources/extensions/gsd/tests/db-writer.test.ts +602 -0
  227. package/src/resources/extensions/gsd/tests/debug-logger.test.ts +185 -0
  228. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +406 -0
  229. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +0 -1
  230. package/src/resources/extensions/gsd/tests/dist-redirect.mjs +22 -0
  231. package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +244 -0
  232. package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +303 -0
  233. package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +434 -0
  234. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +353 -0
  235. package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +125 -0
  236. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +326 -0
  237. package/src/resources/extensions/gsd/tests/integration-edge.test.ts +228 -0
  238. package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +277 -0
  239. package/src/resources/extensions/gsd/tests/md-importer.test.ts +411 -0
  240. package/src/resources/extensions/gsd/tests/metrics.test.ts +197 -0
  241. package/src/resources/extensions/gsd/tests/milestone-transition-worktree.test.ts +144 -0
  242. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +69 -0
  243. package/src/resources/extensions/gsd/tests/model-isolation.test.ts +99 -0
  244. package/src/resources/extensions/gsd/tests/model-router.test.ts +167 -0
  245. package/src/resources/extensions/gsd/tests/parsers.test.ts +40 -0
  246. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +41 -1
  247. package/src/resources/extensions/gsd/tests/preferences-git.test.ts +0 -1
  248. package/src/resources/extensions/gsd/tests/preferences-hooks.test.ts +0 -1
  249. package/src/resources/extensions/gsd/tests/preferences-mode.test.ts +110 -0
  250. package/src/resources/extensions/gsd/tests/preferences-models.test.ts +0 -1
  251. package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +464 -0
  252. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +385 -0
  253. package/src/resources/extensions/gsd/tests/remote-questions.test.ts +488 -1
  254. package/src/resources/extensions/gsd/tests/resolve-ts-hooks.mjs +17 -29
  255. package/src/resources/extensions/gsd/tests/resolve-ts.mjs +2 -8
  256. package/src/resources/extensions/gsd/tests/routing-history.test.ts +215 -62
  257. package/src/resources/extensions/gsd/tests/skill-lifecycle.test.ts +126 -0
  258. package/src/resources/extensions/gsd/tests/stop-auto-remote.test.ts +31 -8
  259. package/src/resources/extensions/gsd/tests/token-savings.test.ts +366 -0
  260. package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +224 -0
  261. package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +215 -0
  262. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +25 -1
  263. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +145 -0
  264. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +290 -0
  265. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +120 -0
  266. package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +478 -0
  267. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +205 -0
  268. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +442 -0
  269. package/src/resources/extensions/gsd/tests/worktree-post-create-hook.test.ts +165 -0
  270. package/src/resources/extensions/gsd/triage-resolution.ts +200 -0
  271. package/src/resources/extensions/gsd/triage-ui.ts +175 -0
  272. package/src/resources/extensions/gsd/types.ts +29 -0
  273. package/src/resources/extensions/gsd/undo.ts +0 -1
  274. package/src/resources/extensions/gsd/unit-runtime.ts +5 -1
  275. package/src/resources/extensions/gsd/visualizer-data.ts +505 -0
  276. package/src/resources/extensions/gsd/visualizer-overlay.ts +337 -0
  277. package/src/resources/extensions/gsd/visualizer-views.ts +755 -0
  278. package/src/resources/extensions/gsd/worktree-command.ts +18 -0
  279. package/src/resources/extensions/gsd/worktree-manager.ts +11 -4
  280. package/src/resources/extensions/remote-questions/config.ts +4 -2
  281. package/src/resources/extensions/remote-questions/discord-adapter.ts +35 -4
  282. package/src/resources/extensions/remote-questions/format.ts +166 -14
  283. package/src/resources/extensions/remote-questions/manager.ts +14 -4
  284. package/src/resources/extensions/remote-questions/remote-command.ts +100 -4
  285. package/src/resources/extensions/remote-questions/slack-adapter.ts +58 -2
  286. package/src/resources/extensions/remote-questions/telegram-adapter.ts +161 -0
  287. package/src/resources/extensions/remote-questions/types.ts +2 -1
  288. package/src/resources/extensions/ttsr/ttsr-manager.ts +26 -0
  289. package/src/resources/extensions/voice/index.ts +4 -3
@@ -0,0 +1,283 @@
1
+ /**
2
+ * Unit tests for context-budget.ts — the budget engine.
3
+ * Tests pure functions with dependency-injected fakes.
4
+ * No I/O, no extension context, no global state.
5
+ */
6
+
7
+ import { describe, it } from "node:test";
8
+ import assert from "node:assert/strict";
9
+
10
+ import {
11
+ type BudgetAllocation,
12
+ type MinimalModel,
13
+ type MinimalModelRegistry,
14
+ type MinimalPreferences,
15
+ type TruncationResult,
16
+ computeBudgets,
17
+ truncateAtSectionBoundary,
18
+ resolveExecutorContextWindow,
19
+ } from "../context-budget.js";
20
+
21
+ // ─── Test helpers ─────────────────────────────────────────────────────────────
22
+
23
+ function makeRegistry(models: MinimalModel[]): MinimalModelRegistry {
24
+ return { getAll: () => models };
25
+ }
26
+
27
+ function makeModel(id: string, provider: string, contextWindow: number): MinimalModel {
28
+ return { id, provider, contextWindow };
29
+ }
30
+
31
+ // ─── computeBudgets ──────────────────────────────────────────────────────────
32
+
33
+ describe("context-budget: computeBudgets", () => {
34
+ it("returns proportional allocations for 128K context window", () => {
35
+ const b = computeBudgets(128_000);
36
+ // 128K tokens × 4 chars/token = 512K chars total
37
+ assert.equal(b.summaryBudgetChars, Math.floor(512_000 * 0.15));
38
+ assert.equal(b.inlineContextBudgetChars, Math.floor(512_000 * 0.40));
39
+ assert.equal(b.verificationBudgetChars, Math.floor(512_000 * 0.10));
40
+ assert.equal(b.continueThresholdPercent, 70);
41
+ assert.equal(b.taskCountRange.min, 2);
42
+ assert.equal(b.taskCountRange.max, 5);
43
+ });
44
+
45
+ it("returns proportional allocations for 200K context window", () => {
46
+ const b = computeBudgets(200_000);
47
+ // 200K tokens × 4 = 800K chars
48
+ assert.equal(b.summaryBudgetChars, Math.floor(800_000 * 0.15));
49
+ assert.equal(b.inlineContextBudgetChars, Math.floor(800_000 * 0.40));
50
+ assert.equal(b.verificationBudgetChars, Math.floor(800_000 * 0.10));
51
+ assert.equal(b.taskCountRange.min, 2);
52
+ assert.equal(b.taskCountRange.max, 6);
53
+ });
54
+
55
+ it("returns proportional allocations for 1M context window", () => {
56
+ const b = computeBudgets(1_000_000);
57
+ // 1M tokens × 4 = 4M chars
58
+ assert.equal(b.summaryBudgetChars, Math.floor(4_000_000 * 0.15));
59
+ assert.equal(b.inlineContextBudgetChars, Math.floor(4_000_000 * 0.40));
60
+ assert.equal(b.verificationBudgetChars, Math.floor(4_000_000 * 0.10));
61
+ assert.equal(b.taskCountRange.min, 2);
62
+ assert.equal(b.taskCountRange.max, 8);
63
+ });
64
+
65
+ it("scales proportionally — 1M > 200K > 128K for all budget fields", () => {
66
+ const b128 = computeBudgets(128_000);
67
+ const b200 = computeBudgets(200_000);
68
+ const b1M = computeBudgets(1_000_000);
69
+
70
+ assert.ok(b1M.summaryBudgetChars > b200.summaryBudgetChars);
71
+ assert.ok(b200.summaryBudgetChars > b128.summaryBudgetChars);
72
+
73
+ assert.ok(b1M.inlineContextBudgetChars > b200.inlineContextBudgetChars);
74
+ assert.ok(b200.inlineContextBudgetChars > b128.inlineContextBudgetChars);
75
+
76
+ assert.ok(b1M.verificationBudgetChars > b200.verificationBudgetChars);
77
+ assert.ok(b200.verificationBudgetChars > b128.verificationBudgetChars);
78
+
79
+ assert.ok(b1M.taskCountRange.max >= b200.taskCountRange.max);
80
+ assert.ok(b200.taskCountRange.max >= b128.taskCountRange.max);
81
+ });
82
+
83
+ it("enforces task count floor (min ≥ 2) at all sizes", () => {
84
+ for (const size of [128_000, 200_000, 1_000_000, 50_000]) {
85
+ const b = computeBudgets(size);
86
+ assert.ok(b.taskCountRange.min >= 2, `min should be ≥ 2 at ${size}, got ${b.taskCountRange.min}`);
87
+ }
88
+ });
89
+
90
+ it("task count ceiling exists and is bounded", () => {
91
+ const b = computeBudgets(10_000_000); // very large window
92
+ assert.ok(b.taskCountRange.max <= 8, `max should be capped, got ${b.taskCountRange.max}`);
93
+ assert.ok(b.taskCountRange.max >= b.taskCountRange.min);
94
+ });
95
+
96
+ it("handles zero input gracefully — defaults to 200K", () => {
97
+ const b = computeBudgets(0);
98
+ const b200 = computeBudgets(200_000);
99
+ assert.deepStrictEqual(b, b200);
100
+ });
101
+
102
+ it("handles negative input gracefully — defaults to 200K", () => {
103
+ const b = computeBudgets(-100);
104
+ const b200 = computeBudgets(200_000);
105
+ assert.deepStrictEqual(b, b200);
106
+ });
107
+ });
108
+
109
+ // ─── truncateAtSectionBoundary ───────────────────────────────────────────────
110
+
111
+ describe("context-budget: truncateAtSectionBoundary", () => {
112
+ it("returns content unchanged when under budget", () => {
113
+ const content = "### Section 1\nSome text.\n\n### Section 2\nMore text.";
114
+ const result = truncateAtSectionBoundary(content, 10_000);
115
+ assert.equal(result.content, content);
116
+ assert.equal(result.droppedSections, 0);
117
+ });
118
+
119
+ it("returns empty string unchanged", () => {
120
+ const result = truncateAtSectionBoundary("", 100);
121
+ assert.equal(result.content, "");
122
+ assert.equal(result.droppedSections, 0);
123
+ });
124
+
125
+ it("truncates at section boundary with ### markers", () => {
126
+ const content = [
127
+ "### Section A\nContent A is here.\n",
128
+ "### Section B\nContent B is here.\n",
129
+ "### Section C\nContent C is here.\n",
130
+ ].join("");
131
+
132
+ // Budget enough for section A only
133
+ const sectionALen = "### Section A\nContent A is here.\n".length;
134
+ const result = truncateAtSectionBoundary(content, sectionALen + 5);
135
+
136
+ assert.ok(result.content.includes("### Section A"), "should keep section A");
137
+ assert.ok(result.content.includes("Content A"), "should keep section A content");
138
+ assert.ok(!result.content.includes("### Section C"), "should drop section C");
139
+ assert.ok(result.content.includes("[...truncated"), "should include truncation indicator");
140
+ // Verify truncation count
141
+ assert.ok(result.content.includes("truncated 2 sections"), `should show 2 truncated, got: ${result.content}`);
142
+ assert.equal(result.droppedSections, 2);
143
+ });
144
+
145
+ it("truncates at --- divider boundaries", () => {
146
+ const content = "Intro text.\n\n---\n\nMiddle section.\n\n---\n\nFinal section.";
147
+ // Budget enough for intro only
148
+ const result = truncateAtSectionBoundary(content, 20);
149
+
150
+ assert.ok(result.content.includes("Intro text"), "should keep intro");
151
+ assert.ok(result.content.includes("[...truncated"), "should include truncation indicator");
152
+ assert.ok(result.droppedSections > 0, "should report dropped sections");
153
+ });
154
+
155
+ it("handles content with no section markers — keeps as much as fits", () => {
156
+ const content = "A".repeat(200);
157
+ const result = truncateAtSectionBoundary(content, 50);
158
+
159
+ assert.ok(result.content.length < 200, "should be shorter than original");
160
+ assert.ok(result.content.includes("[...truncated 1 sections]"), "should indicate truncation");
161
+ assert.ok(result.content.startsWith("AAAA"), "should keep content from the start");
162
+ assert.equal(result.droppedSections, 1);
163
+ });
164
+
165
+ it("handles content at exact boundary — returns unchanged", () => {
166
+ const content = "### Section 1\nText here.";
167
+ const result = truncateAtSectionBoundary(content, content.length);
168
+ assert.equal(result.content, content);
169
+ assert.equal(result.droppedSections, 0);
170
+ });
171
+
172
+ it("always keeps at least the first section even if it exceeds budget", () => {
173
+ const content = "### Long Section\n" + "X".repeat(500) + "\n\n### Short\nY";
174
+ const result = truncateAtSectionBoundary(content, 10);
175
+
176
+ // First section should be present even though it exceeds budget
177
+ assert.ok(result.content.includes("### Long Section"), "should keep first section");
178
+ assert.ok(result.content.includes("[...truncated 1 sections]"), "should indicate remaining sections dropped");
179
+ assert.equal(result.droppedSections, 1);
180
+ });
181
+ });
182
+
183
+ // ─── resolveExecutorContextWindow ────────────────────────────────────────────
184
+
185
+ describe("context-budget: resolveExecutorContextWindow", () => {
186
+ it("returns configured executor model's contextWindow when found", () => {
187
+ const registry = makeRegistry([
188
+ makeModel("claude-opus-4-6", "anthropic", 200_000),
189
+ makeModel("claude-sonnet-4-20250514", "anthropic", 200_000),
190
+ makeModel("gpt-4o", "openai", 128_000),
191
+ ]);
192
+ const prefs: MinimalPreferences = {
193
+ models: { execution: "gpt-4o" },
194
+ };
195
+
196
+ const result = resolveExecutorContextWindow(registry, prefs);
197
+ assert.equal(result, 128_000);
198
+ });
199
+
200
+ it("supports provider/model format in preferences", () => {
201
+ const registry = makeRegistry([
202
+ makeModel("gpt-4o", "openai", 128_000),
203
+ makeModel("gpt-4o", "azure", 64_000),
204
+ ]);
205
+ const prefs: MinimalPreferences = {
206
+ models: { execution: "azure/gpt-4o" },
207
+ };
208
+
209
+ const result = resolveExecutorContextWindow(registry, prefs);
210
+ assert.equal(result, 64_000);
211
+ });
212
+
213
+ it("supports object format preferences with model + fallbacks", () => {
214
+ const registry = makeRegistry([
215
+ makeModel("claude-opus-4-6", "anthropic", 200_000),
216
+ ]);
217
+ const prefs: MinimalPreferences = {
218
+ models: { execution: { model: "claude-opus-4-6", fallbacks: ["gpt-4o"] } },
219
+ };
220
+
221
+ const result = resolveExecutorContextWindow(registry, prefs);
222
+ assert.equal(result, 200_000);
223
+ });
224
+
225
+ it("falls back to sessionContextWindow when executor model not found", () => {
226
+ const registry = makeRegistry([
227
+ makeModel("claude-opus-4-6", "anthropic", 200_000),
228
+ ]);
229
+ const prefs: MinimalPreferences = {
230
+ models: { execution: "nonexistent-model" },
231
+ };
232
+
233
+ const result = resolveExecutorContextWindow(registry, prefs, 300_000);
234
+ assert.equal(result, 300_000);
235
+ });
236
+
237
+ it("falls back to sessionContextWindow when no execution preference set", () => {
238
+ const registry = makeRegistry([
239
+ makeModel("claude-opus-4-6", "anthropic", 200_000),
240
+ ]);
241
+ const prefs: MinimalPreferences = { models: {} };
242
+
243
+ const result = resolveExecutorContextWindow(registry, prefs, 128_000);
244
+ assert.equal(result, 128_000);
245
+ });
246
+
247
+ it("falls back to 200K when no session and no executor model", () => {
248
+ const registry = makeRegistry([]);
249
+ const prefs: MinimalPreferences = { models: { execution: "missing" } };
250
+
251
+ const result = resolveExecutorContextWindow(registry, prefs);
252
+ assert.equal(result, 200_000);
253
+ });
254
+
255
+ it("falls back to 200K with undefined preferences", () => {
256
+ const result = resolveExecutorContextWindow(undefined, undefined);
257
+ assert.equal(result, 200_000);
258
+ });
259
+
260
+ it("falls back to 200K with undefined registry", () => {
261
+ const prefs: MinimalPreferences = { models: { execution: "claude-opus-4-6" } };
262
+ const result = resolveExecutorContextWindow(undefined, prefs);
263
+ assert.equal(result, 200_000);
264
+ });
265
+
266
+ it("ignores models with contextWindow ≤ 0", () => {
267
+ const registry = makeRegistry([
268
+ makeModel("broken-model", "test", 0),
269
+ ]);
270
+ const prefs: MinimalPreferences = { models: { execution: "broken-model" } };
271
+
272
+ const result = resolveExecutorContextWindow(registry, prefs, 128_000);
273
+ assert.equal(result, 128_000); // falls through to session
274
+ });
275
+
276
+ it("ignores sessionContextWindow ≤ 0", () => {
277
+ const registry = makeRegistry([]);
278
+ const prefs: MinimalPreferences = {};
279
+
280
+ const result = resolveExecutorContextWindow(registry, prefs, -1);
281
+ assert.equal(result, 200_000); // falls through to default
282
+ });
283
+ });
@@ -128,7 +128,7 @@ test("compression: buildCompleteMilestonePrompt minimal drops root GSD files", (
128
128
  const block = promptsSrc.slice(completeMilestoneIdx, nextBuilder);
129
129
  assert.ok(
130
130
  block.includes('inlineLevel !== "minimal"') &&
131
- block.includes('inlineGsdRootFile(base, "requirements.md"'),
131
+ (block.includes('inlineGsdRootFile(base, "requirements.md"') || block.includes('inlineRequirementsFromDb(base')),
132
132
  "complete-milestone should gate root file inlining on level",
133
133
  );
134
134
  });