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,65 @@
1
+ // GSD Extension — Model Cost Table
2
+ // Static cost reference for known models, used by the dynamic router
3
+ // for cross-provider cost comparison.
4
+ //
5
+ // Costs are approximate per-1K-token rates in USD (input tokens).
6
+ // Updated with GSD releases. Users can override via preferences.
7
+
8
+ export interface ModelCostEntry {
9
+ /** Model ID (bare, without provider prefix) */
10
+ id: string;
11
+ /** Approximate cost per 1K input tokens in USD */
12
+ inputPer1k: number;
13
+ /** Approximate cost per 1K output tokens in USD */
14
+ outputPer1k: number;
15
+ /** Last updated date */
16
+ updatedAt: string;
17
+ }
18
+
19
+ /**
20
+ * Bundled cost table for known models.
21
+ * Updated periodically with GSD releases.
22
+ */
23
+ export const BUNDLED_COST_TABLE: ModelCostEntry[] = [
24
+ // Anthropic
25
+ { id: "claude-opus-4-6", inputPer1k: 0.015, outputPer1k: 0.075, updatedAt: "2025-03-15" },
26
+ { id: "claude-sonnet-4-6", inputPer1k: 0.003, outputPer1k: 0.015, updatedAt: "2025-03-15" },
27
+ { id: "claude-haiku-4-5", inputPer1k: 0.0008, outputPer1k: 0.004, updatedAt: "2025-03-15" },
28
+ { id: "claude-sonnet-4-5-20250514", inputPer1k: 0.003, outputPer1k: 0.015, updatedAt: "2025-03-15" },
29
+ { id: "claude-3-5-sonnet-latest", inputPer1k: 0.003, outputPer1k: 0.015, updatedAt: "2025-03-15" },
30
+ { id: "claude-3-5-haiku-latest", inputPer1k: 0.0008, outputPer1k: 0.004, updatedAt: "2025-03-15" },
31
+ { id: "claude-3-opus-latest", inputPer1k: 0.015, outputPer1k: 0.075, updatedAt: "2025-03-15" },
32
+
33
+ // OpenAI
34
+ { id: "gpt-4o", inputPer1k: 0.0025, outputPer1k: 0.01, updatedAt: "2025-03-15" },
35
+ { id: "gpt-4o-mini", inputPer1k: 0.00015, outputPer1k: 0.0006, updatedAt: "2025-03-15" },
36
+ { id: "o1", inputPer1k: 0.015, outputPer1k: 0.06, updatedAt: "2025-03-15" },
37
+ { id: "o3", inputPer1k: 0.015, outputPer1k: 0.06, updatedAt: "2025-03-15" },
38
+ { id: "gpt-4-turbo", inputPer1k: 0.01, outputPer1k: 0.03, updatedAt: "2025-03-15" },
39
+
40
+ // Google
41
+ { id: "gemini-2.0-flash", inputPer1k: 0.0001, outputPer1k: 0.0004, updatedAt: "2025-03-15" },
42
+ { id: "gemini-flash-2.0", inputPer1k: 0.0001, outputPer1k: 0.0004, updatedAt: "2025-03-15" },
43
+ { id: "gemini-2.5-pro", inputPer1k: 0.00125, outputPer1k: 0.005, updatedAt: "2025-03-15" },
44
+
45
+ // DeepSeek
46
+ { id: "deepseek-chat", inputPer1k: 0.00014, outputPer1k: 0.00028, updatedAt: "2025-03-15" },
47
+ ];
48
+
49
+ /**
50
+ * Lookup cost for a model ID. Returns undefined if not found.
51
+ */
52
+ export function lookupModelCost(modelId: string): ModelCostEntry | undefined {
53
+ const bareId = modelId.includes("/") ? modelId.split("/").pop()! : modelId;
54
+ return BUNDLED_COST_TABLE.find(e => e.id === bareId)
55
+ ?? BUNDLED_COST_TABLE.find(e => bareId.includes(e.id) || e.id.includes(bareId));
56
+ }
57
+
58
+ /**
59
+ * Compare two models by input cost. Returns negative if a is cheaper.
60
+ */
61
+ export function compareModelCost(modelIdA: string, modelIdB: string): number {
62
+ const costA = lookupModelCost(modelIdA)?.inputPer1k ?? 999;
63
+ const costB = lookupModelCost(modelIdB)?.inputPer1k ?? 999;
64
+ return costA - costB;
65
+ }
@@ -0,0 +1,256 @@
1
+ // GSD Extension — Dynamic Model Router
2
+ // Maps complexity tiers to models, enforcing downgrade-only semantics.
3
+ // The user's configured model is always the ceiling.
4
+
5
+ import type { ComplexityTier, ClassificationResult } from "./complexity-classifier.js";
6
+ import { tierOrdinal } from "./complexity-classifier.js";
7
+ import type { ResolvedModelConfig } from "./preferences.js";
8
+
9
+ // ─── Types ───────────────────────────────────────────────────────────────────
10
+
11
+ export interface DynamicRoutingConfig {
12
+ enabled?: boolean;
13
+ tier_models?: {
14
+ light?: string;
15
+ standard?: string;
16
+ heavy?: string;
17
+ };
18
+ escalate_on_failure?: boolean; // default: true
19
+ budget_pressure?: boolean; // default: true
20
+ cross_provider?: boolean; // default: true
21
+ hooks?: boolean; // default: true
22
+ }
23
+
24
+ export interface RoutingDecision {
25
+ /** The model ID to use (may be downgraded from configured) */
26
+ modelId: string;
27
+ /** Fallback chain: [selected_model, ...configured_fallbacks, configured_primary] */
28
+ fallbacks: string[];
29
+ /** The complexity tier that drove this decision */
30
+ tier: ComplexityTier;
31
+ /** True if the model was downgraded from the configured primary */
32
+ wasDowngraded: boolean;
33
+ /** Human-readable reason for this decision */
34
+ reason: string;
35
+ }
36
+
37
+ // ─── Known Model Tiers ───────────────────────────────────────────────────────
38
+ // Maps known model IDs to their capability tier. Used when tier_models is not
39
+ // explicitly configured to pick the best available model for each tier.
40
+
41
+ const MODEL_CAPABILITY_TIER: Record<string, ComplexityTier> = {
42
+ // Light-tier models (cheapest)
43
+ "claude-haiku-4-5": "light",
44
+ "claude-3-5-haiku-latest": "light",
45
+ "claude-3-haiku-20240307": "light",
46
+ "gpt-4o-mini": "light",
47
+ "gemini-2.0-flash": "light",
48
+ "gemini-flash-2.0": "light",
49
+
50
+ // Standard-tier models
51
+ "claude-sonnet-4-6": "standard",
52
+ "claude-sonnet-4-5-20250514": "standard",
53
+ "claude-3-5-sonnet-latest": "standard",
54
+ "gpt-4o": "standard",
55
+ "gemini-2.5-pro": "standard",
56
+ "deepseek-chat": "standard",
57
+
58
+ // Heavy-tier models (most capable)
59
+ "claude-opus-4-6": "heavy",
60
+ "claude-3-opus-latest": "heavy",
61
+ "gpt-4-turbo": "heavy",
62
+ "o1": "heavy",
63
+ "o3": "heavy",
64
+ };
65
+
66
+ // ─── Cost Table (per 1K input tokens, approximate USD) ───────────────────────
67
+ // Used for cross-provider cost comparison when multiple providers offer
68
+ // the same capability tier.
69
+
70
+ const MODEL_COST_PER_1K_INPUT: Record<string, number> = {
71
+ "claude-haiku-4-5": 0.0008,
72
+ "claude-3-5-haiku-latest": 0.0008,
73
+ "claude-sonnet-4-6": 0.003,
74
+ "claude-sonnet-4-5-20250514": 0.003,
75
+ "claude-opus-4-6": 0.015,
76
+ "gpt-4o-mini": 0.00015,
77
+ "gpt-4o": 0.0025,
78
+ "gemini-2.0-flash": 0.0001,
79
+ "gemini-2.5-pro": 0.00125,
80
+ "deepseek-chat": 0.00014,
81
+ };
82
+
83
+ // ─── Public API ──────────────────────────────────────────────────────────────
84
+
85
+ /**
86
+ * Resolve the model to use for a given complexity tier.
87
+ *
88
+ * Downgrade-only: the returned model is always equal to or cheaper than
89
+ * the user's configured primary model. Never upgrades beyond configuration.
90
+ *
91
+ * @param classification The complexity classification result
92
+ * @param phaseConfig The user's configured model for this phase (ceiling)
93
+ * @param routingConfig Dynamic routing configuration
94
+ * @param availableModelIds List of available model IDs (from registry)
95
+ */
96
+ export function resolveModelForComplexity(
97
+ classification: ClassificationResult,
98
+ phaseConfig: ResolvedModelConfig | undefined,
99
+ routingConfig: DynamicRoutingConfig,
100
+ availableModelIds: string[],
101
+ ): RoutingDecision {
102
+ // If no phase config or routing disabled, pass through
103
+ if (!phaseConfig || !routingConfig.enabled) {
104
+ return {
105
+ modelId: phaseConfig?.primary ?? "",
106
+ fallbacks: phaseConfig?.fallbacks ?? [],
107
+ tier: classification.tier,
108
+ wasDowngraded: false,
109
+ reason: "dynamic routing disabled or no phase config",
110
+ };
111
+ }
112
+
113
+ const configuredPrimary = phaseConfig.primary;
114
+ const configuredTier = getModelTier(configuredPrimary);
115
+ const requestedTier = classification.tier;
116
+
117
+ // Downgrade-only: if requested tier >= configured tier, no change
118
+ if (tierOrdinal(requestedTier) >= tierOrdinal(configuredTier)) {
119
+ return {
120
+ modelId: configuredPrimary,
121
+ fallbacks: phaseConfig.fallbacks,
122
+ tier: requestedTier,
123
+ wasDowngraded: false,
124
+ reason: `tier ${requestedTier} >= configured ${configuredTier}`,
125
+ };
126
+ }
127
+
128
+ // Find the best model for the requested tier
129
+ const targetModelId = findModelForTier(
130
+ requestedTier,
131
+ routingConfig,
132
+ availableModelIds,
133
+ routingConfig.cross_provider !== false,
134
+ );
135
+
136
+ if (!targetModelId) {
137
+ // No suitable model found — use configured primary
138
+ return {
139
+ modelId: configuredPrimary,
140
+ fallbacks: phaseConfig.fallbacks,
141
+ tier: requestedTier,
142
+ wasDowngraded: false,
143
+ reason: `no ${requestedTier}-tier model available`,
144
+ };
145
+ }
146
+
147
+ // Build fallback chain: [downgraded_model, ...configured_fallbacks, configured_primary]
148
+ const fallbacks = [
149
+ ...phaseConfig.fallbacks.filter(f => f !== targetModelId),
150
+ configuredPrimary,
151
+ ].filter(f => f !== targetModelId);
152
+
153
+ return {
154
+ modelId: targetModelId,
155
+ fallbacks,
156
+ tier: requestedTier,
157
+ wasDowngraded: true,
158
+ reason: classification.reason,
159
+ };
160
+ }
161
+
162
+ /**
163
+ * Escalate to the next tier after a failure.
164
+ * Returns the new tier, or null if already at heavy (max).
165
+ */
166
+ export function escalateTier(currentTier: ComplexityTier): ComplexityTier | null {
167
+ switch (currentTier) {
168
+ case "light": return "standard";
169
+ case "standard": return "heavy";
170
+ case "heavy": return null;
171
+ }
172
+ }
173
+
174
+ /**
175
+ * Get the default routing config (all features enabled).
176
+ */
177
+ export function defaultRoutingConfig(): DynamicRoutingConfig {
178
+ return {
179
+ enabled: false,
180
+ escalate_on_failure: true,
181
+ budget_pressure: true,
182
+ cross_provider: true,
183
+ hooks: true,
184
+ };
185
+ }
186
+
187
+ // ─── Internal ────────────────────────────────────────────────────────────────
188
+
189
+ function getModelTier(modelId: string): ComplexityTier {
190
+ // Strip provider prefix if present
191
+ const bareId = modelId.includes("/") ? modelId.split("/").pop()! : modelId;
192
+
193
+ // Check exact match first
194
+ if (MODEL_CAPABILITY_TIER[bareId]) return MODEL_CAPABILITY_TIER[bareId];
195
+
196
+ // Check if any known model ID is a prefix/suffix match
197
+ for (const [knownId, tier] of Object.entries(MODEL_CAPABILITY_TIER)) {
198
+ if (bareId.includes(knownId) || knownId.includes(bareId)) return tier;
199
+ }
200
+
201
+ // Unknown models are assumed heavy (safest assumption)
202
+ return "heavy";
203
+ }
204
+
205
+ function findModelForTier(
206
+ tier: ComplexityTier,
207
+ config: DynamicRoutingConfig,
208
+ availableModelIds: string[],
209
+ crossProvider: boolean,
210
+ ): string | null {
211
+ // 1. Check explicit tier_models config
212
+ const explicitModel = config.tier_models?.[tier];
213
+ if (explicitModel && availableModelIds.includes(explicitModel)) {
214
+ return explicitModel;
215
+ }
216
+ // Also check with provider prefix stripped
217
+ if (explicitModel) {
218
+ const match = availableModelIds.find(id => {
219
+ const bareAvail = id.includes("/") ? id.split("/").pop()! : id;
220
+ const bareExplicit = explicitModel.includes("/") ? explicitModel.split("/").pop()! : explicitModel;
221
+ return bareAvail === bareExplicit;
222
+ });
223
+ if (match) return match;
224
+ }
225
+
226
+ // 2. Auto-detect: find the cheapest available model in the requested tier
227
+ const candidates = availableModelIds
228
+ .filter(id => {
229
+ const modelTier = getModelTier(id);
230
+ return modelTier === tier;
231
+ })
232
+ .sort((a, b) => {
233
+ if (!crossProvider) return 0;
234
+ const costA = getModelCost(a);
235
+ const costB = getModelCost(b);
236
+ return costA - costB;
237
+ });
238
+
239
+ return candidates[0] ?? null;
240
+ }
241
+
242
+ function getModelCost(modelId: string): number {
243
+ const bareId = modelId.includes("/") ? modelId.split("/").pop()! : modelId;
244
+
245
+ if (MODEL_COST_PER_1K_INPUT[bareId] !== undefined) {
246
+ return MODEL_COST_PER_1K_INPUT[bareId];
247
+ }
248
+
249
+ // Check partial matches
250
+ for (const [knownId, cost] of Object.entries(MODEL_COST_PER_1K_INPUT)) {
251
+ if (bareId.includes(knownId) || knownId.includes(bareId)) return cost;
252
+ }
253
+
254
+ // Unknown cost — assume expensive to avoid routing to unknown cheap models
255
+ return 999;
256
+ }
@@ -1,6 +1,5 @@
1
1
  // GSD Extension — Desktop Notification Helper
2
2
  // Cross-platform desktop notifications for auto-mode events.
3
- // Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
4
3
 
5
4
  import { execFileSync } from "node:child_process";
6
5
  import type { NotificationPreferences } from "./types.js";
@@ -1,7 +1,6 @@
1
1
  // GSD Extension — Hook Engine (Post-Unit, Pre-Dispatch, State Persistence)
2
2
  // Manages hook queue, cycle tracking, artifact verification, pre-dispatch
3
3
  // interception, and durable hook state for user-configured extensibility.
4
- // Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
5
4
 
6
5
  import type {
7
6
  PostUnitHookConfig,
@@ -60,7 +59,8 @@ export function checkPostUnitHooks(
60
59
  }
61
60
 
62
61
  // Don't trigger hooks for other hook units (prevent hook-on-hook chains)
63
- if (completedUnitType.startsWith("hook/")) return null;
62
+ // Don't trigger hooks for triage units (prevent hook-on-triage chains)
63
+ if (completedUnitType.startsWith("hook/") || completedUnitType === "triage-captures") return null;
64
64
 
65
65
  // Check if any hooks are configured for this unit type
66
66
  const hooks = resolvePostUnitHooks().filter(h =>
@@ -411,6 +411,76 @@ export function getHookStatus(): HookStatusEntry[] {
411
411
  return entries;
412
412
  }
413
413
 
414
+ /**
415
+ * Manually trigger a specific hook for a unit.
416
+ * This bypasses the normal flow and forces the hook to run even if its artifact exists.
417
+ *
418
+ * @param hookName - The name of the hook to trigger (e.g., "code-review")
419
+ * @param unitType - The type of unit that triggered the hook (e.g., "execute-task")
420
+ * @param unitId - The unit ID (e.g., "M001/S01/T01")
421
+ * @param basePath - The project base path
422
+ * @returns The hook dispatch result or null if hook not found
423
+ */
424
+ export function triggerHookManually(
425
+ hookName: string,
426
+ unitType: string,
427
+ unitId: string,
428
+ basePath: string,
429
+ ): HookDispatchResult | null {
430
+ // Find the hook configuration
431
+ const hook = resolvePostUnitHooks().find(h => h.name === hookName);
432
+ if (!hook) {
433
+ console.error(`[triggerHookManually] Hook "${hookName}" not found in post_unit_hooks`);
434
+ return null;
435
+ }
436
+
437
+ if (!hook.prompt || typeof hook.prompt !== 'string' || hook.prompt.trim().length === 0) {
438
+ console.error(`[triggerHookManually] Hook "${hookName}" has empty prompt`);
439
+ return null;
440
+ }
441
+
442
+ // Reset any active hook state to allow manual triggering
443
+ activeHook = {
444
+ hookName: hook.name,
445
+ triggerUnitType: unitType,
446
+ triggerUnitId: unitId,
447
+ cycle: 1,
448
+ pendingRetry: false,
449
+ };
450
+
451
+ // Build the hook queue with just this hook
452
+ hookQueue = [{
453
+ config: hook,
454
+ triggerUnitType: unitType,
455
+ triggerUnitId: unitId,
456
+ }];
457
+
458
+ // Set the cycle count for this specific hook+trigger
459
+ const cycleKey = `${hook.name}/${unitType}/${unitId}`;
460
+ const currentCycle = (cycleCounts.get(cycleKey) ?? 0) + 1;
461
+ cycleCounts.set(cycleKey, currentCycle);
462
+
463
+ // Update active hook with the cycle count
464
+ activeHook.cycle = currentCycle;
465
+
466
+ // Build the prompt with variable substitution
467
+ const [mid, sid, tid] = unitId.split("/");
468
+ const prompt = hook.prompt
469
+ .replace(/\{milestoneId\}/g, mid ?? "")
470
+ .replace(/\{sliceId\}/g, sid ?? "")
471
+ .replace(/\{taskId\}/g, tid ?? "");
472
+
473
+ console.log(`[triggerHookManually] Built prompt for ${hookName}, length: ${prompt.length}`);
474
+
475
+ return {
476
+ hookName: hook.name,
477
+ prompt,
478
+ model: hook.model,
479
+ unitType: `hook/${hook.name}`,
480
+ unitId,
481
+ };
482
+ }
483
+
414
484
  /**
415
485
  * Format hook status for terminal display.
416
486
  */