gsd-pi 2.38.0-dev.eeb3520 → 2.39.0-dev.38f11d1

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 (335) hide show
  1. package/README.md +15 -11
  2. package/dist/app-paths.js +1 -1
  3. package/dist/cli.js +9 -0
  4. package/dist/extension-discovery.d.ts +5 -3
  5. package/dist/extension-discovery.js +14 -9
  6. package/dist/extension-registry.js +2 -2
  7. package/dist/remote-questions-config.js +2 -2
  8. package/dist/resource-loader.js +34 -1
  9. package/dist/resources/extensions/async-jobs/index.js +10 -0
  10. package/dist/resources/extensions/browser-tools/index.js +3 -1
  11. package/dist/resources/extensions/browser-tools/package.json +3 -1
  12. package/dist/resources/extensions/browser-tools/tools/verify.js +97 -0
  13. package/dist/resources/extensions/cmux/index.js +55 -1
  14. package/dist/resources/extensions/context7/package.json +1 -1
  15. package/dist/resources/extensions/env-utils.js +29 -0
  16. package/dist/resources/extensions/get-secrets-from-user.js +5 -24
  17. package/dist/resources/extensions/github-sync/cli.js +284 -0
  18. package/dist/resources/extensions/github-sync/index.js +73 -0
  19. package/dist/resources/extensions/github-sync/mapping.js +67 -0
  20. package/dist/resources/extensions/github-sync/sync.js +424 -0
  21. package/dist/resources/extensions/github-sync/templates.js +118 -0
  22. package/dist/resources/extensions/github-sync/types.js +7 -0
  23. package/dist/resources/extensions/google-search/package.json +3 -1
  24. package/dist/resources/extensions/gsd/auto/session.js +6 -23
  25. package/dist/resources/extensions/gsd/auto-dashboard.js +7 -0
  26. package/dist/resources/extensions/gsd/auto-dispatch.js +8 -9
  27. package/dist/resources/extensions/gsd/auto-loop.js +923 -787
  28. package/dist/resources/extensions/gsd/auto-post-unit.js +107 -70
  29. package/dist/resources/extensions/gsd/auto-prompts.js +205 -51
  30. package/dist/resources/extensions/gsd/auto-start.js +19 -3
  31. package/dist/resources/extensions/gsd/auto-worktree-sync.js +13 -5
  32. package/dist/resources/extensions/gsd/auto-worktree.js +3 -3
  33. package/dist/resources/extensions/gsd/auto.js +147 -98
  34. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +126 -0
  35. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +233 -0
  36. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +59 -0
  37. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +38 -0
  38. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +156 -0
  39. package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +46 -0
  40. package/dist/resources/extensions/gsd/bootstrap/system-context.js +300 -0
  41. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +38 -0
  42. package/dist/resources/extensions/gsd/captures.js +9 -1
  43. package/dist/resources/extensions/gsd/commands/catalog.js +278 -0
  44. package/dist/resources/extensions/gsd/commands/context.js +84 -0
  45. package/dist/resources/extensions/gsd/commands/dispatcher.js +21 -0
  46. package/dist/resources/extensions/gsd/commands/handlers/auto.js +72 -0
  47. package/dist/resources/extensions/gsd/commands/handlers/core.js +246 -0
  48. package/dist/resources/extensions/gsd/commands/handlers/ops.js +166 -0
  49. package/dist/resources/extensions/gsd/commands/handlers/parallel.js +94 -0
  50. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +102 -0
  51. package/dist/resources/extensions/gsd/commands/index.js +11 -0
  52. package/dist/resources/extensions/gsd/commands-extensions.js +3 -2
  53. package/dist/resources/extensions/gsd/commands-handlers.js +17 -4
  54. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
  55. package/dist/resources/extensions/gsd/commands.js +8 -1169
  56. package/dist/resources/extensions/gsd/context-budget.js +2 -10
  57. package/dist/resources/extensions/gsd/dashboard-overlay.js +9 -0
  58. package/dist/resources/extensions/gsd/detection.js +1 -2
  59. package/dist/resources/extensions/gsd/docs/preferences-reference.md +0 -2
  60. package/dist/resources/extensions/gsd/doctor-checks.js +82 -0
  61. package/dist/resources/extensions/gsd/doctor-environment.js +78 -0
  62. package/dist/resources/extensions/gsd/doctor-format.js +15 -0
  63. package/dist/resources/extensions/gsd/doctor-proactive.js +80 -10
  64. package/dist/resources/extensions/gsd/doctor-providers.js +30 -11
  65. package/dist/resources/extensions/gsd/doctor.js +234 -12
  66. package/dist/resources/extensions/gsd/exit-command.js +2 -1
  67. package/dist/resources/extensions/gsd/export-html.js +46 -0
  68. package/dist/resources/extensions/gsd/export.js +1 -1
  69. package/dist/resources/extensions/gsd/files.js +48 -9
  70. package/dist/resources/extensions/gsd/forensics.js +1 -1
  71. package/dist/resources/extensions/gsd/git-service.js +30 -12
  72. package/dist/resources/extensions/gsd/gitignore.js +16 -3
  73. package/dist/resources/extensions/gsd/guided-flow.js +149 -38
  74. package/dist/resources/extensions/gsd/health-widget-core.js +32 -70
  75. package/dist/resources/extensions/gsd/health-widget.js +4 -87
  76. package/dist/resources/extensions/gsd/index.js +4 -1111
  77. package/dist/resources/extensions/gsd/migrate/parsers.js +1 -1
  78. package/dist/resources/extensions/gsd/migrate-external.js +18 -1
  79. package/dist/resources/extensions/gsd/native-git-bridge.js +37 -0
  80. package/dist/resources/extensions/gsd/package.json +1 -1
  81. package/dist/resources/extensions/gsd/paths.js +3 -0
  82. package/dist/resources/extensions/gsd/preferences-models.js +0 -12
  83. package/dist/resources/extensions/gsd/preferences-types.js +1 -1
  84. package/dist/resources/extensions/gsd/preferences-validation.js +59 -11
  85. package/dist/resources/extensions/gsd/preferences.js +22 -11
  86. package/dist/resources/extensions/gsd/progress-score.js +20 -1
  87. package/dist/resources/extensions/gsd/prompt-loader.js +6 -2
  88. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  89. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  90. package/dist/resources/extensions/gsd/prompts/discuss.md +11 -14
  91. package/dist/resources/extensions/gsd/prompts/execute-task.md +5 -3
  92. package/dist/resources/extensions/gsd/prompts/forensics.md +121 -46
  93. package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
  94. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +11 -12
  95. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -10
  96. package/dist/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
  97. package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
  98. package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
  99. package/dist/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
  100. package/dist/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
  101. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  102. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  103. package/dist/resources/extensions/gsd/prompts/queue.md +4 -8
  104. package/dist/resources/extensions/gsd/prompts/reactive-execute.md +11 -8
  105. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
  106. package/dist/resources/extensions/gsd/prompts/research-milestone.md +1 -1
  107. package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
  108. package/dist/resources/extensions/gsd/prompts/run-uat.md +28 -11
  109. package/dist/resources/extensions/gsd/prompts/workflow-start.md +2 -2
  110. package/dist/resources/extensions/gsd/repo-identity.js +21 -4
  111. package/dist/resources/extensions/gsd/resource-version.js +2 -1
  112. package/dist/resources/extensions/gsd/roadmap-mutations.js +24 -0
  113. package/dist/resources/extensions/gsd/state.js +42 -23
  114. package/dist/resources/extensions/gsd/templates/runtime.md +21 -0
  115. package/dist/resources/extensions/gsd/templates/task-plan.md +3 -0
  116. package/dist/resources/extensions/gsd/visualizer-data.js +27 -2
  117. package/dist/resources/extensions/gsd/visualizer-views.js +52 -0
  118. package/dist/resources/extensions/gsd/worktree.js +35 -16
  119. package/dist/resources/extensions/mcp-client/index.js +14 -1
  120. package/dist/resources/extensions/remote-questions/status.js +4 -1
  121. package/dist/resources/extensions/remote-questions/store.js +4 -1
  122. package/dist/resources/extensions/search-the-web/provider.js +2 -1
  123. package/dist/resources/extensions/shared/frontmatter.js +1 -1
  124. package/dist/resources/extensions/subagent/index.js +12 -3
  125. package/dist/resources/extensions/subagent/isolation.js +2 -1
  126. package/dist/resources/extensions/ttsr/rule-loader.js +2 -1
  127. package/dist/resources/extensions/universal-config/package.json +1 -1
  128. package/dist/welcome-screen.d.ts +12 -0
  129. package/dist/welcome-screen.js +53 -0
  130. package/package.json +1 -1
  131. package/packages/pi-ai/dist/utils/oauth/anthropic.js +2 -2
  132. package/packages/pi-ai/dist/utils/oauth/anthropic.js.map +1 -1
  133. package/packages/pi-ai/src/utils/oauth/anthropic.ts +2 -2
  134. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  135. package/packages/pi-coding-agent/dist/core/extensions/loader.js +205 -7
  136. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  137. package/packages/pi-coding-agent/dist/core/package-manager.d.ts.map +1 -1
  138. package/packages/pi-coding-agent/dist/core/package-manager.js +8 -4
  139. package/packages/pi-coding-agent/dist/core/package-manager.js.map +1 -1
  140. package/packages/pi-coding-agent/dist/core/skills.d.ts +1 -0
  141. package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
  142. package/packages/pi-coding-agent/dist/core/skills.js +6 -1
  143. package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
  144. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  145. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  146. package/packages/pi-coding-agent/dist/index.js +1 -1
  147. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  148. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts +17 -0
  149. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -0
  150. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +244 -0
  151. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -0
  152. package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.d.ts +3 -0
  153. package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.d.ts.map +1 -0
  154. package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js +58 -0
  155. package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js.map +1 -0
  156. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts +12 -0
  157. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -0
  158. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +54 -0
  159. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -0
  160. package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.d.ts +6 -0
  161. package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.d.ts.map +1 -0
  162. package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.js +63 -0
  163. package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.js.map +1 -0
  164. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +38 -0
  165. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -0
  166. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js +2 -0
  167. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -0
  168. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  169. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +13 -453
  170. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  171. package/packages/pi-coding-agent/package.json +1 -1
  172. package/packages/pi-coding-agent/src/core/extensions/loader.ts +223 -7
  173. package/packages/pi-coding-agent/src/core/package-manager.ts +8 -4
  174. package/packages/pi-coding-agent/src/core/skills.ts +9 -1
  175. package/packages/pi-coding-agent/src/index.ts +1 -0
  176. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +302 -0
  177. package/packages/pi-coding-agent/src/modes/interactive/controllers/extension-ui-controller.ts +59 -0
  178. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +68 -0
  179. package/packages/pi-coding-agent/src/modes/interactive/controllers/model-controller.ts +71 -0
  180. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +37 -0
  181. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +16 -506
  182. package/pkg/package.json +1 -1
  183. package/src/resources/extensions/async-jobs/index.ts +11 -0
  184. package/src/resources/extensions/browser-tools/index.ts +3 -0
  185. package/src/resources/extensions/browser-tools/tools/verify.ts +117 -0
  186. package/src/resources/extensions/cmux/index.ts +57 -1
  187. package/src/resources/extensions/env-utils.ts +31 -0
  188. package/src/resources/extensions/get-secrets-from-user.ts +5 -24
  189. package/src/resources/extensions/github-sync/cli.ts +364 -0
  190. package/src/resources/extensions/github-sync/index.ts +93 -0
  191. package/src/resources/extensions/github-sync/mapping.ts +81 -0
  192. package/src/resources/extensions/github-sync/sync.ts +556 -0
  193. package/src/resources/extensions/github-sync/templates.ts +183 -0
  194. package/src/resources/extensions/github-sync/tests/cli.test.ts +20 -0
  195. package/src/resources/extensions/github-sync/tests/commit-linking.test.ts +39 -0
  196. package/src/resources/extensions/github-sync/tests/mapping.test.ts +104 -0
  197. package/src/resources/extensions/github-sync/tests/templates.test.ts +110 -0
  198. package/src/resources/extensions/github-sync/types.ts +47 -0
  199. package/src/resources/extensions/gsd/auto/session.ts +7 -25
  200. package/src/resources/extensions/gsd/auto-dashboard.ts +10 -0
  201. package/src/resources/extensions/gsd/auto-dispatch.ts +7 -9
  202. package/src/resources/extensions/gsd/auto-loop.ts +1285 -1138
  203. package/src/resources/extensions/gsd/auto-post-unit.ts +90 -46
  204. package/src/resources/extensions/gsd/auto-prompts.ts +250 -53
  205. package/src/resources/extensions/gsd/auto-start.ts +24 -3
  206. package/src/resources/extensions/gsd/auto-worktree-sync.ts +15 -4
  207. package/src/resources/extensions/gsd/auto-worktree.ts +3 -3
  208. package/src/resources/extensions/gsd/auto.ts +143 -102
  209. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +142 -0
  210. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +238 -0
  211. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +90 -0
  212. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +46 -0
  213. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +167 -0
  214. package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +55 -0
  215. package/src/resources/extensions/gsd/bootstrap/system-context.ts +340 -0
  216. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +51 -0
  217. package/src/resources/extensions/gsd/captures.ts +10 -1
  218. package/src/resources/extensions/gsd/commands/catalog.ts +301 -0
  219. package/src/resources/extensions/gsd/commands/context.ts +101 -0
  220. package/src/resources/extensions/gsd/commands/dispatcher.ts +32 -0
  221. package/src/resources/extensions/gsd/commands/handlers/auto.ts +74 -0
  222. package/src/resources/extensions/gsd/commands/handlers/core.ts +274 -0
  223. package/src/resources/extensions/gsd/commands/handlers/ops.ts +169 -0
  224. package/src/resources/extensions/gsd/commands/handlers/parallel.ts +118 -0
  225. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +109 -0
  226. package/src/resources/extensions/gsd/commands/index.ts +14 -0
  227. package/src/resources/extensions/gsd/commands-extensions.ts +4 -2
  228. package/src/resources/extensions/gsd/commands-handlers.ts +18 -3
  229. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
  230. package/src/resources/extensions/gsd/commands.ts +10 -1307
  231. package/src/resources/extensions/gsd/context-budget.ts +2 -12
  232. package/src/resources/extensions/gsd/dashboard-overlay.ts +10 -0
  233. package/src/resources/extensions/gsd/detection.ts +2 -2
  234. package/src/resources/extensions/gsd/docs/preferences-reference.md +0 -2
  235. package/src/resources/extensions/gsd/doctor-checks.ts +75 -0
  236. package/src/resources/extensions/gsd/doctor-environment.ts +82 -1
  237. package/src/resources/extensions/gsd/doctor-format.ts +20 -0
  238. package/src/resources/extensions/gsd/doctor-proactive.ts +106 -10
  239. package/src/resources/extensions/gsd/doctor-providers.ts +30 -9
  240. package/src/resources/extensions/gsd/doctor-types.ts +16 -1
  241. package/src/resources/extensions/gsd/doctor.ts +243 -14
  242. package/src/resources/extensions/gsd/exit-command.ts +2 -2
  243. package/src/resources/extensions/gsd/export-html.ts +51 -0
  244. package/src/resources/extensions/gsd/export.ts +1 -1
  245. package/src/resources/extensions/gsd/files.ts +51 -11
  246. package/src/resources/extensions/gsd/forensics.ts +1 -1
  247. package/src/resources/extensions/gsd/git-service.ts +44 -10
  248. package/src/resources/extensions/gsd/gitignore.ts +17 -3
  249. package/src/resources/extensions/gsd/guided-flow.ts +177 -44
  250. package/src/resources/extensions/gsd/health-widget-core.ts +28 -80
  251. package/src/resources/extensions/gsd/health-widget.ts +4 -89
  252. package/src/resources/extensions/gsd/index.ts +12 -1307
  253. package/src/resources/extensions/gsd/migrate/parsers.ts +1 -1
  254. package/src/resources/extensions/gsd/migrate-external.ts +18 -1
  255. package/src/resources/extensions/gsd/native-git-bridge.ts +37 -0
  256. package/src/resources/extensions/gsd/paths.ts +4 -0
  257. package/src/resources/extensions/gsd/preferences-models.ts +0 -12
  258. package/src/resources/extensions/gsd/preferences-types.ts +4 -4
  259. package/src/resources/extensions/gsd/preferences-validation.ts +51 -11
  260. package/src/resources/extensions/gsd/preferences.ts +25 -11
  261. package/src/resources/extensions/gsd/progress-score.ts +23 -0
  262. package/src/resources/extensions/gsd/prompt-loader.ts +7 -2
  263. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  264. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  265. package/src/resources/extensions/gsd/prompts/discuss.md +11 -14
  266. package/src/resources/extensions/gsd/prompts/execute-task.md +5 -3
  267. package/src/resources/extensions/gsd/prompts/forensics.md +121 -46
  268. package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
  269. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +11 -12
  270. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -10
  271. package/src/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
  272. package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
  273. package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
  274. package/src/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
  275. package/src/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
  276. package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  277. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  278. package/src/resources/extensions/gsd/prompts/queue.md +4 -8
  279. package/src/resources/extensions/gsd/prompts/reactive-execute.md +11 -8
  280. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
  281. package/src/resources/extensions/gsd/prompts/research-milestone.md +1 -1
  282. package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
  283. package/src/resources/extensions/gsd/prompts/run-uat.md +28 -11
  284. package/src/resources/extensions/gsd/prompts/workflow-start.md +2 -2
  285. package/src/resources/extensions/gsd/repo-identity.ts +23 -4
  286. package/src/resources/extensions/gsd/resource-version.ts +3 -1
  287. package/src/resources/extensions/gsd/roadmap-mutations.ts +29 -0
  288. package/src/resources/extensions/gsd/state.ts +39 -21
  289. package/src/resources/extensions/gsd/templates/runtime.md +21 -0
  290. package/src/resources/extensions/gsd/templates/task-plan.md +3 -0
  291. package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +21 -18
  292. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +135 -77
  293. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +4 -3
  294. package/src/resources/extensions/gsd/tests/cmux.test.ts +93 -0
  295. package/src/resources/extensions/gsd/tests/derive-state.test.ts +43 -0
  296. package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +266 -0
  297. package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +3 -3
  298. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +86 -3
  299. package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +50 -0
  300. package/src/resources/extensions/gsd/tests/health-widget.test.ts +16 -54
  301. package/src/resources/extensions/gsd/tests/parsers.test.ts +131 -14
  302. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +209 -0
  303. package/src/resources/extensions/gsd/tests/preferences.test.ts +2 -7
  304. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +59 -0
  305. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +16 -16
  306. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +21 -1
  307. package/src/resources/extensions/gsd/tests/run-uat.test.ts +16 -4
  308. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +140 -0
  309. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +10 -10
  310. package/src/resources/extensions/gsd/tests/worktree.test.ts +47 -0
  311. package/src/resources/extensions/gsd/types.ts +18 -1
  312. package/src/resources/extensions/gsd/verification-evidence.ts +16 -0
  313. package/src/resources/extensions/gsd/visualizer-data.ts +52 -2
  314. package/src/resources/extensions/gsd/visualizer-views.ts +58 -0
  315. package/src/resources/extensions/gsd/worktree.ts +35 -15
  316. package/src/resources/extensions/mcp-client/index.ts +17 -1
  317. package/src/resources/extensions/remote-questions/status.ts +5 -1
  318. package/src/resources/extensions/remote-questions/store.ts +5 -1
  319. package/src/resources/extensions/search-the-web/provider.ts +2 -1
  320. package/src/resources/extensions/shared/frontmatter.ts +1 -1
  321. package/src/resources/extensions/subagent/index.ts +12 -3
  322. package/src/resources/extensions/subagent/isolation.ts +3 -1
  323. package/src/resources/extensions/ttsr/rule-loader.ts +3 -1
  324. package/dist/resources/extensions/gsd/prompt-compressor.js +0 -393
  325. package/dist/resources/extensions/gsd/semantic-chunker.js +0 -254
  326. package/dist/resources/extensions/gsd/summary-distiller.js +0 -212
  327. package/src/resources/extensions/gsd/prompt-compressor.ts +0 -508
  328. package/src/resources/extensions/gsd/semantic-chunker.ts +0 -336
  329. package/src/resources/extensions/gsd/summary-distiller.ts +0 -258
  330. package/src/resources/extensions/gsd/tests/context-compression.test.ts +0 -193
  331. package/src/resources/extensions/gsd/tests/prompt-compressor.test.ts +0 -529
  332. package/src/resources/extensions/gsd/tests/semantic-chunker.test.ts +0 -426
  333. package/src/resources/extensions/gsd/tests/summary-distiller.test.ts +0 -323
  334. package/src/resources/extensions/gsd/tests/token-optimization-benchmark.test.ts +0 -1272
  335. package/src/resources/extensions/gsd/tests/token-optimization-prefs.test.ts +0 -164
@@ -89,6 +89,15 @@ import { TreeSelectorComponent } from "./components/tree-selector.js";
89
89
  import { UserMessageComponent } from "./components/user-message.js";
90
90
  import { UserMessageSelectorComponent } from "./components/user-message-selector.js";
91
91
  import { type SlashCommandContext, dispatchSlashCommand, getAppKeyDisplay } from "./slash-command-handlers.js";
92
+ import { handleAgentEvent } from "./controllers/chat-controller.js";
93
+ import { createExtensionUIContext as buildExtensionUIContext } from "./controllers/extension-ui-controller.js";
94
+ import { setupEditorSubmitHandler as setupEditorSubmitHandlerController } from "./controllers/input-controller.js";
95
+ import {
96
+ findExactModelMatch as findExactModelMatchController,
97
+ getModelCandidates as getModelCandidatesController,
98
+ handleModelCommand as handleModelCommandController,
99
+ updateAvailableProviderCount as updateAvailableProviderCountController,
100
+ } from "./controllers/model-controller.js";
92
101
  import {
93
102
  getAvailableThemes,
94
103
  getAvailableThemesWithPaths,
@@ -1486,60 +1495,7 @@ export class InteractiveMode {
1486
1495
  * Create the ExtensionUIContext for extensions.
1487
1496
  */
1488
1497
  private createExtensionUIContext(): ExtensionUIContext {
1489
- return {
1490
- select: (title, options, opts) => this.showExtensionSelector(title, options, opts),
1491
- confirm: (title, message, opts) => this.showExtensionConfirm(title, message, opts),
1492
- input: (title, placeholder, opts) => this.showExtensionInput(title, placeholder, opts),
1493
- notify: (message, type) => this.showExtensionNotify(message, type),
1494
- onTerminalInput: (handler) => this.addExtensionTerminalInputListener(handler),
1495
- setStatus: (key, text) => this.setExtensionStatus(key, text),
1496
- setWorkingMessage: (message) => {
1497
- if (this.loadingAnimation) {
1498
- if (message) {
1499
- this.loadingAnimation.setMessage(message);
1500
- } else {
1501
- this.loadingAnimation.setMessage(
1502
- `${this.defaultWorkingMessage} (${appKey(this.keybindings, "interrupt")} to interrupt)`,
1503
- );
1504
- }
1505
- } else {
1506
- // Queue message for when loadingAnimation is created (handles agent_start race)
1507
- this.pendingWorkingMessage = message;
1508
- }
1509
- },
1510
- setWidget: (key, content, options) => this.setExtensionWidget(key, content, options),
1511
- setFooter: (factory) => this.setExtensionFooter(factory),
1512
- setHeader: (factory) => this.setExtensionHeader(factory),
1513
- setTitle: (title) => this.ui.terminal.setTitle(title),
1514
- custom: (factory, options) => this.showExtensionCustom(factory, options),
1515
- pasteToEditor: (text) => this.editor.handleInput(`\x1b[200~${text}\x1b[201~`),
1516
- setEditorText: (text) => this.editor.setText(text),
1517
- getEditorText: () => this.editor.getText(),
1518
- editor: (title, prefill) => this.showExtensionEditor(title, prefill),
1519
- setEditorComponent: (factory) => this.setCustomEditorComponent(factory),
1520
- get theme() {
1521
- return theme;
1522
- },
1523
- getAllThemes: () => getAvailableThemesWithPaths(),
1524
- getTheme: (name) => getThemeByName(name),
1525
- setTheme: (themeOrName) => {
1526
- if (themeOrName instanceof Theme) {
1527
- setThemeInstance(themeOrName);
1528
- this.ui.requestRender();
1529
- return { success: true };
1530
- }
1531
- const result = setTheme(themeOrName, true);
1532
- if (result.success) {
1533
- if (this.settingsManager.getTheme() !== themeOrName) {
1534
- this.settingsManager.setTheme(themeOrName);
1535
- }
1536
- this.ui.requestRender();
1537
- }
1538
- return result;
1539
- },
1540
- getToolsExpanded: () => this.toolOutputExpanded,
1541
- setToolsExpanded: (expanded) => this.setToolsExpanded(expanded),
1542
- };
1498
+ return buildExtensionUIContext(this);
1543
1499
  }
1544
1500
 
1545
1501
  /**
@@ -2017,69 +1973,7 @@ export class InteractiveMode {
2017
1973
  }
2018
1974
 
2019
1975
  private setupEditorSubmitHandler(): void {
2020
- this.defaultEditor.onSubmit = async (text: string) => {
2021
- text = text.trim();
2022
- if (!text) return;
2023
-
2024
- // Handle slash commands
2025
- if (text.startsWith("/")) {
2026
- const handled = await dispatchSlashCommand(text, this.getSlashCommandContext());
2027
- if (handled) {
2028
- this.editor.setText("");
2029
- return;
2030
- }
2031
- }
2032
-
2033
- // Handle bash command (! for normal, !! for excluded from context)
2034
- if (text.startsWith("!")) {
2035
- const isExcluded = text.startsWith("!!");
2036
- const command = isExcluded ? text.slice(2).trim() : text.slice(1).trim();
2037
- if (command) {
2038
- if (this.session.isBashRunning) {
2039
- this.showWarning("A bash command is already running. Press Esc to cancel it first.");
2040
- this.editor.setText(text);
2041
- return;
2042
- }
2043
- this.editor.addToHistory?.(text);
2044
- await this.handleBashCommand(command, isExcluded);
2045
- this.isBashMode = false;
2046
- this.updateEditorBorderColor();
2047
- return;
2048
- }
2049
- }
2050
-
2051
- // Queue input during compaction (extension commands execute immediately)
2052
- if (this.session.isCompacting) {
2053
- if (this.isExtensionCommand(text)) {
2054
- this.editor.addToHistory?.(text);
2055
- this.editor.setText("");
2056
- await this.session.prompt(text);
2057
- } else {
2058
- this.queueCompactionMessage(text, "steer");
2059
- }
2060
- return;
2061
- }
2062
-
2063
- // If streaming, use prompt() with steer behavior
2064
- // This handles extension commands (execute immediately), prompt template expansion, and queueing
2065
- if (this.session.isStreaming) {
2066
- this.editor.addToHistory?.(text);
2067
- this.editor.setText("");
2068
- await this.session.prompt(text, { streamingBehavior: "steer" });
2069
- this.updatePendingMessagesDisplay();
2070
- this.ui.requestRender();
2071
- return;
2072
- }
2073
-
2074
- // Normal message submission
2075
- // First, move any pending bash components to chat
2076
- this.flushPendingBashComponents();
2077
-
2078
- if (this.onInputCallback) {
2079
- this.onInputCallback(text);
2080
- }
2081
- this.editor.addToHistory?.(text);
2082
- };
1976
+ setupEditorSubmitHandlerController(this as any);
2083
1977
  }
2084
1978
 
2085
1979
  private subscribeToAgent(): void {
@@ -2089,338 +1983,7 @@ export class InteractiveMode {
2089
1983
  }
2090
1984
 
2091
1985
  private async handleEvent(event: AgentSessionEvent): Promise<void> {
2092
- if (!this.isInitialized) {
2093
- await this.init();
2094
- }
2095
-
2096
- this.footer.invalidate();
2097
-
2098
- switch (event.type) {
2099
- case "agent_start":
2100
- // Restore main escape handler if retry handler is still active
2101
- // (retry success event fires later, but we need main handler now)
2102
- if (this.retryEscapeHandler) {
2103
- this.defaultEditor.onEscape = this.retryEscapeHandler;
2104
- this.retryEscapeHandler = undefined;
2105
- }
2106
- if (this.retryLoader) {
2107
- this.retryLoader.stop();
2108
- this.retryLoader = undefined;
2109
- }
2110
- if (this.loadingAnimation) {
2111
- this.loadingAnimation.stop();
2112
- }
2113
- this.statusContainer.clear();
2114
- this.loadingAnimation = new Loader(
2115
- this.ui,
2116
- (spinner) => theme.fg("accent", spinner),
2117
- (text) => theme.fg("muted", text),
2118
- this.defaultWorkingMessage,
2119
- );
2120
- this.statusContainer.addChild(this.loadingAnimation);
2121
- // Apply any pending working message queued before loader existed
2122
- if (this.pendingWorkingMessage !== undefined) {
2123
- if (this.pendingWorkingMessage) {
2124
- this.loadingAnimation.setMessage(this.pendingWorkingMessage);
2125
- }
2126
- this.pendingWorkingMessage = undefined;
2127
- }
2128
- this.ui.requestRender();
2129
- break;
2130
-
2131
- case "message_start":
2132
- if (event.message.role === "custom") {
2133
- this.addMessageToChat(event.message);
2134
- this.ui.requestRender();
2135
- } else if (event.message.role === "user") {
2136
- this.addMessageToChat(event.message);
2137
- this.updatePendingMessagesDisplay();
2138
- this.ui.requestRender();
2139
- } else if (event.message.role === "assistant") {
2140
- this.streamingComponent = new AssistantMessageComponent(
2141
- undefined,
2142
- this.hideThinkingBlock,
2143
- this.getMarkdownThemeWithSettings(),
2144
- );
2145
- this.streamingMessage = event.message;
2146
- this.chatContainer.addChild(this.streamingComponent);
2147
- this.streamingComponent.updateContent(this.streamingMessage);
2148
- this.ui.requestRender();
2149
- }
2150
- break;
2151
-
2152
- case "message_update":
2153
- if (this.streamingComponent && event.message.role === "assistant") {
2154
- this.streamingMessage = event.message;
2155
- this.streamingComponent.updateContent(this.streamingMessage);
2156
-
2157
- for (const content of this.streamingMessage.content) {
2158
- if (content.type === "toolCall") {
2159
- if (!this.pendingTools.has(content.id)) {
2160
- const component = new ToolExecutionComponent(
2161
- content.name,
2162
- content.arguments,
2163
- {
2164
- showImages: this.settingsManager.getShowImages(),
2165
- },
2166
- this.getRegisteredToolDefinition(content.name),
2167
- this.ui,
2168
- );
2169
- component.setExpanded(this.toolOutputExpanded);
2170
- this.chatContainer.addChild(component);
2171
- this.pendingTools.set(content.id, component);
2172
- } else {
2173
- const component = this.pendingTools.get(content.id);
2174
- if (component) {
2175
- component.updateArgs(content.arguments);
2176
- }
2177
- }
2178
- } else if (content.type === "serverToolUse") {
2179
- // Server-side tool (e.g., native web search) — show as pending tool execution
2180
- if (!this.pendingTools.has(content.id)) {
2181
- const component = new ToolExecutionComponent(
2182
- content.name,
2183
- content.input ?? {},
2184
- {
2185
- showImages: this.settingsManager.getShowImages(),
2186
- },
2187
- undefined,
2188
- this.ui,
2189
- );
2190
- component.setExpanded(this.toolOutputExpanded);
2191
- this.chatContainer.addChild(component);
2192
- this.pendingTools.set(content.id, component);
2193
- }
2194
- } else if (content.type === "webSearchResult") {
2195
- // Server-side tool result — resolve the pending server tool execution
2196
- const component = this.pendingTools.get(content.toolUseId);
2197
- if (component) {
2198
- const searchContent = content.content;
2199
- const isError = searchContent && typeof searchContent === "object" && "type" in (searchContent as any) && (searchContent as any).type === "web_search_tool_result_error";
2200
- const resultText = this.formatWebSearchResult(searchContent);
2201
- component.updateResult({
2202
- content: [{ type: "text", text: resultText }],
2203
- isError: !!isError,
2204
- });
2205
- this.pendingTools.delete(content.toolUseId);
2206
- }
2207
- }
2208
- }
2209
- this.ui.requestRender();
2210
- }
2211
- break;
2212
-
2213
- case "message_end":
2214
- if (event.message.role === "user") break;
2215
- if (this.streamingComponent && event.message.role === "assistant") {
2216
- this.streamingMessage = event.message;
2217
- let errorMessage: string | undefined;
2218
- if (this.streamingMessage.stopReason === "aborted") {
2219
- const retryAttempt = this.session.retryAttempt;
2220
- errorMessage =
2221
- retryAttempt > 0
2222
- ? `Aborted after ${retryAttempt} retry attempt${retryAttempt > 1 ? "s" : ""}`
2223
- : "Operation aborted";
2224
- this.streamingMessage.errorMessage = errorMessage;
2225
- }
2226
- this.streamingComponent.updateContent(this.streamingMessage);
2227
-
2228
- if (this.streamingMessage.stopReason === "aborted" || this.streamingMessage.stopReason === "error") {
2229
- if (!errorMessage) {
2230
- errorMessage = this.streamingMessage.errorMessage || "Error";
2231
- }
2232
- for (const [, component] of this.pendingTools.entries()) {
2233
- component.updateResult({
2234
- content: [{ type: "text", text: errorMessage }],
2235
- isError: true,
2236
- });
2237
- }
2238
- this.pendingTools.clear();
2239
- } else {
2240
- // Args are now complete - trigger diff computation for edit tools
2241
- for (const [, component] of this.pendingTools.entries()) {
2242
- component.setArgsComplete();
2243
- }
2244
- }
2245
- this.streamingComponent = undefined;
2246
- this.streamingMessage = undefined;
2247
- this.footer.invalidate();
2248
- }
2249
- this.ui.requestRender();
2250
- break;
2251
-
2252
- case "tool_execution_start": {
2253
- if (!this.pendingTools.has(event.toolCallId)) {
2254
- const component = new ToolExecutionComponent(
2255
- event.toolName,
2256
- event.args,
2257
- {
2258
- showImages: this.settingsManager.getShowImages(),
2259
- },
2260
- this.getRegisteredToolDefinition(event.toolName),
2261
- this.ui,
2262
- );
2263
- component.setExpanded(this.toolOutputExpanded);
2264
- this.chatContainer.addChild(component);
2265
- this.pendingTools.set(event.toolCallId, component);
2266
- this.ui.requestRender();
2267
- }
2268
- break;
2269
- }
2270
-
2271
- case "tool_execution_update": {
2272
- const component = this.pendingTools.get(event.toolCallId);
2273
- if (component) {
2274
- component.updateResult({ ...event.partialResult, isError: false }, true);
2275
- this.ui.requestRender();
2276
- }
2277
- break;
2278
- }
2279
-
2280
- case "tool_execution_end": {
2281
- const component = this.pendingTools.get(event.toolCallId);
2282
- if (component) {
2283
- component.updateResult({ ...event.result, isError: event.isError });
2284
- this.pendingTools.delete(event.toolCallId);
2285
- this.ui.requestRender();
2286
- }
2287
- break;
2288
- }
2289
-
2290
- case "agent_end":
2291
- if (this.loadingAnimation) {
2292
- this.loadingAnimation.stop();
2293
- this.loadingAnimation = undefined;
2294
- this.statusContainer.clear();
2295
- }
2296
- if (this.streamingComponent) {
2297
- this.chatContainer.removeChild(this.streamingComponent);
2298
- this.streamingComponent = undefined;
2299
- this.streamingMessage = undefined;
2300
- }
2301
- this.pendingTools.clear();
2302
-
2303
- await this.checkShutdownRequested();
2304
-
2305
- this.ui.requestRender();
2306
- break;
2307
-
2308
- case "auto_compaction_start": {
2309
- // Keep editor active; submissions are queued during compaction.
2310
- // Set up escape to abort auto-compaction
2311
- this.autoCompactionEscapeHandler = this.defaultEditor.onEscape;
2312
- this.defaultEditor.onEscape = () => {
2313
- this.session.abortCompaction();
2314
- };
2315
- // Show compacting indicator with reason
2316
- this.statusContainer.clear();
2317
- const reasonText = event.reason === "overflow" ? "Context overflow detected, " : "";
2318
- this.autoCompactionLoader = new Loader(
2319
- this.ui,
2320
- (spinner) => theme.fg("accent", spinner),
2321
- (text) => theme.fg("muted", text),
2322
- `${reasonText}Auto-compacting... (${appKey(this.keybindings, "interrupt")} to cancel)`,
2323
- );
2324
- this.statusContainer.addChild(this.autoCompactionLoader);
2325
- this.ui.requestRender();
2326
- break;
2327
- }
2328
-
2329
- case "auto_compaction_end": {
2330
- // Restore escape handler
2331
- if (this.autoCompactionEscapeHandler) {
2332
- this.defaultEditor.onEscape = this.autoCompactionEscapeHandler;
2333
- this.autoCompactionEscapeHandler = undefined;
2334
- }
2335
- // Stop loader
2336
- if (this.autoCompactionLoader) {
2337
- this.autoCompactionLoader.stop();
2338
- this.autoCompactionLoader = undefined;
2339
- this.statusContainer.clear();
2340
- }
2341
- // Handle result
2342
- if (event.aborted) {
2343
- this.showStatus("Auto-compaction cancelled");
2344
- } else if (event.result) {
2345
- // Rebuild chat to show compacted state
2346
- this.chatContainer.clear();
2347
- this.rebuildChatFromMessages();
2348
- // Add compaction component at bottom so user sees it without scrolling
2349
- this.addMessageToChat({
2350
- role: "compactionSummary",
2351
- tokensBefore: event.result.tokensBefore,
2352
- summary: event.result.summary,
2353
- timestamp: Date.now(),
2354
- });
2355
- this.footer.invalidate();
2356
- } else if (event.errorMessage) {
2357
- // Compaction failed (e.g., quota exceeded, API error)
2358
- this.chatContainer.addChild(new Spacer(1));
2359
- this.chatContainer.addChild(new Text(theme.fg("error", event.errorMessage), 1, 0));
2360
- }
2361
- void this.flushCompactionQueue({ willRetry: event.willRetry });
2362
- this.ui.requestRender();
2363
- break;
2364
- }
2365
-
2366
- case "auto_retry_start": {
2367
- // Set up escape to abort retry
2368
- this.retryEscapeHandler = this.defaultEditor.onEscape;
2369
- this.defaultEditor.onEscape = () => {
2370
- this.session.abortRetry();
2371
- };
2372
- // Show retry indicator
2373
- this.statusContainer.clear();
2374
- const delaySeconds = Math.round(event.delayMs / 1000);
2375
- this.retryLoader = new Loader(
2376
- this.ui,
2377
- (spinner) => theme.fg("warning", spinner),
2378
- (text) => theme.fg("muted", text),
2379
- `Retrying (${event.attempt}/${event.maxAttempts}) in ${delaySeconds}s... (${appKey(this.keybindings, "interrupt")} to cancel)`,
2380
- );
2381
- this.statusContainer.addChild(this.retryLoader);
2382
- this.ui.requestRender();
2383
- break;
2384
- }
2385
-
2386
- case "auto_retry_end": {
2387
- // Restore escape handler
2388
- if (this.retryEscapeHandler) {
2389
- this.defaultEditor.onEscape = this.retryEscapeHandler;
2390
- this.retryEscapeHandler = undefined;
2391
- }
2392
- // Stop loader
2393
- if (this.retryLoader) {
2394
- this.retryLoader.stop();
2395
- this.retryLoader = undefined;
2396
- this.statusContainer.clear();
2397
- }
2398
- // Show error only on final failure (success shows normal response)
2399
- if (!event.success) {
2400
- this.showError(`Retry failed after ${event.attempt} attempts: ${event.finalError || "Unknown error"}`);
2401
- }
2402
- this.ui.requestRender();
2403
- break;
2404
- }
2405
-
2406
- case "fallback_provider_switch": {
2407
- this.showStatus(`Switched from ${event.from} → ${event.to} (${event.reason})`);
2408
- this.ui.requestRender();
2409
- break;
2410
- }
2411
-
2412
- case "fallback_provider_restored": {
2413
- this.showStatus(`Restored to ${event.provider}`);
2414
- this.ui.requestRender();
2415
- break;
2416
- }
2417
-
2418
- case "fallback_chain_exhausted": {
2419
- this.showError(event.reason);
2420
- this.ui.requestRender();
2421
- break;
2422
- }
2423
- }
1986
+ await handleAgentEvent(this as any, event);
2424
1987
  }
2425
1988
 
2426
1989
  /** Extract text content from a user message */
@@ -3299,73 +2862,20 @@ export class InteractiveMode {
3299
2862
  }
3300
2863
 
3301
2864
  private async handleModelCommand(searchTerm?: string): Promise<void> {
3302
- if (!searchTerm) {
3303
- this.showModelSelector();
3304
- return;
3305
- }
3306
-
3307
- const model = await this.findExactModelMatch(searchTerm);
3308
- if (model) {
3309
- try {
3310
- await this.session.setModel(model);
3311
- this.footer.invalidate();
3312
- this.updateEditorBorderColor();
3313
- this.showStatus(`Model: ${model.id}`);
3314
- this.checkDaxnutsEasterEgg(model);
3315
- } catch (error) {
3316
- this.showError(error instanceof Error ? error.message : String(error));
3317
- }
3318
- return;
3319
- }
3320
-
3321
- this.showModelSelector(searchTerm);
2865
+ await handleModelCommandController(this, searchTerm);
3322
2866
  }
3323
2867
 
3324
2868
  private async findExactModelMatch(searchTerm: string): Promise<Model<any> | undefined> {
3325
- const term = searchTerm.trim();
3326
- if (!term) return undefined;
3327
-
3328
- let targetProvider: string | undefined;
3329
- let targetModelId = "";
3330
-
3331
- if (term.includes("/")) {
3332
- const parts = term.split("/", 2);
3333
- targetProvider = parts[0]?.trim().toLowerCase();
3334
- targetModelId = parts[1]?.trim().toLowerCase() ?? "";
3335
- } else {
3336
- targetModelId = term.toLowerCase();
3337
- }
3338
-
3339
- if (!targetModelId) return undefined;
3340
-
3341
- const models = await this.getModelCandidates();
3342
- const exactMatches = models.filter((item) => {
3343
- const idMatch = item.id.toLowerCase() === targetModelId;
3344
- const providerMatch = !targetProvider || item.provider.toLowerCase() === targetProvider;
3345
- return idMatch && providerMatch;
3346
- });
3347
-
3348
- return exactMatches.length === 1 ? exactMatches[0] : undefined;
2869
+ return findExactModelMatchController(this, searchTerm);
3349
2870
  }
3350
2871
 
3351
2872
  private async getModelCandidates(): Promise<Model<any>[]> {
3352
- if (this.session.scopedModels.length > 0) {
3353
- return this.session.scopedModels.map((scoped) => scoped.model);
3354
- }
3355
-
3356
- this.session.modelRegistry.refresh();
3357
- try {
3358
- return await this.session.modelRegistry.getAvailable();
3359
- } catch {
3360
- return [];
3361
- }
2873
+ return getModelCandidatesController(this);
3362
2874
  }
3363
2875
 
3364
2876
  /** Update the footer's available provider count from current model candidates */
3365
2877
  private async updateAvailableProviderCount(): Promise<void> {
3366
- const models = await this.getModelCandidates();
3367
- const uniqueProviders = new Set(models.map((m) => m.provider));
3368
- this.footerDataProvider.setAvailableProviderCount(uniqueProviders.size);
2878
+ await updateAvailableProviderCountController(this);
3369
2879
  }
3370
2880
 
3371
2881
  private showModelSelector(initialSearchInput?: string): void {
package/pkg/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glittercowboy/gsd",
3
- "version": "2.38.0",
3
+ "version": "2.39.0",
4
4
  "piConfig": {
5
5
  "name": "gsd",
6
6
  "configDir": ".gsd"
@@ -78,6 +78,17 @@ export default function AsyncJobs(pi: ExtensionAPI) {
78
78
  });
79
79
  });
80
80
 
81
+ pi.on("session_before_switch", async () => {
82
+ if (manager) {
83
+ // Cancel all running background jobs — their results are no longer
84
+ // relevant to the new session and would produce wasteful follow-up
85
+ // notifications that trigger empty LLM turns (#1642).
86
+ for (const job of manager.getRunningJobs()) {
87
+ manager.cancel(job.id);
88
+ }
89
+ }
90
+ });
91
+
81
92
  pi.on("session_shutdown", async () => {
82
93
  if (manager) {
83
94
  manager.shutdown();
@@ -33,6 +33,7 @@ async function registerBrowserTools(pi: ExtensionAPI): Promise<void> {
33
33
  codegen,
34
34
  actionCache,
35
35
  injectionDetection,
36
+ verify,
36
37
  ] = await Promise.all([
37
38
  importExtensionModule<typeof import("./lifecycle.js")>(import.meta.url, "./lifecycle.js"),
38
39
  importExtensionModule<typeof import("./capture.js")>(import.meta.url, "./capture.js"),
@@ -60,6 +61,7 @@ async function registerBrowserTools(pi: ExtensionAPI): Promise<void> {
60
61
  importExtensionModule<typeof import("./tools/codegen.js")>(import.meta.url, "./tools/codegen.js"),
61
62
  importExtensionModule<typeof import("./tools/action-cache.js")>(import.meta.url, "./tools/action-cache.js"),
62
63
  importExtensionModule<typeof import("./tools/injection-detect.js")>(import.meta.url, "./tools/injection-detect.js"),
64
+ importExtensionModule<typeof import("./tools/verify.js")>(import.meta.url, "./tools/verify.js"),
63
65
  ]);
64
66
 
65
67
  const deps = {
@@ -132,6 +134,7 @@ async function registerBrowserTools(pi: ExtensionAPI): Promise<void> {
132
134
  codegen.registerCodegenTools(pi, deps);
133
135
  actionCache.registerActionCacheTools(pi, deps);
134
136
  injectionDetection.registerInjectionDetectionTools(pi, deps);
137
+ verify.registerVerifyTools(pi, deps);
135
138
  })().catch((error) => {
136
139
  registrationPromise = null;
137
140
  throw error;