gsd-pi 2.77.0-dev.eaa4973bc → 2.78.0-dev.aeeb2ca00

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 (545) hide show
  1. package/README.md +53 -17
  2. package/dist/claude-cli-check.js +46 -10
  3. package/dist/headless.js +49 -4
  4. package/dist/resource-loader.d.ts +40 -0
  5. package/dist/resource-loader.js +32 -13
  6. package/dist/resources/extensions/browser-tools/capture.js +9 -0
  7. package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  8. package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  9. package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  10. package/dist/resources/extensions/browser-tools/tools/forms.js +5 -1
  11. package/dist/resources/extensions/browser-tools/tools/intent.js +5 -1
  12. package/dist/resources/extensions/claude-code-cli/readiness.js +72 -16
  13. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +481 -17
  14. package/dist/resources/extensions/github-sync/templates.js +103 -0
  15. package/dist/resources/extensions/google-search/index.js +3 -2
  16. package/dist/resources/extensions/gsd/auto/loop.js +124 -2
  17. package/dist/resources/extensions/gsd/auto/phases.js +57 -39
  18. package/dist/resources/extensions/gsd/auto/session.js +6 -2
  19. package/dist/resources/extensions/gsd/auto-dispatch.js +142 -29
  20. package/dist/resources/extensions/gsd/auto-model-selection.js +124 -4
  21. package/dist/resources/extensions/gsd/auto-post-unit.js +150 -64
  22. package/dist/resources/extensions/gsd/auto-prompts.js +372 -104
  23. package/dist/resources/extensions/gsd/auto-recovery.js +197 -48
  24. package/dist/resources/extensions/gsd/auto-start.js +107 -29
  25. package/dist/resources/extensions/gsd/auto-tool-tracking.js +47 -7
  26. package/dist/resources/extensions/gsd/auto-worktree.js +122 -26
  27. package/dist/resources/extensions/gsd/auto.js +76 -21
  28. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +19 -1
  29. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +209 -0
  30. package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +3 -6
  31. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -3
  32. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +127 -9
  33. package/dist/resources/extensions/gsd/component-loader.js +447 -0
  34. package/dist/resources/extensions/gsd/component-types.js +69 -0
  35. package/dist/resources/extensions/gsd/context-store.js +23 -7
  36. package/dist/resources/extensions/gsd/detection.js +49 -1
  37. package/dist/resources/extensions/gsd/dispatch-guard.js +2 -17
  38. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  39. package/dist/resources/extensions/gsd/forensics.js +106 -0
  40. package/dist/resources/extensions/gsd/gate-registry.js +2 -2
  41. package/dist/resources/extensions/gsd/git-constants.js +28 -1
  42. package/dist/resources/extensions/gsd/git-self-heal.js +27 -0
  43. package/dist/resources/extensions/gsd/git-service.js +126 -2
  44. package/dist/resources/extensions/gsd/gsd-db.js +6 -3
  45. package/dist/resources/extensions/gsd/guided-flow.js +39 -13
  46. package/dist/resources/extensions/gsd/memory-extractor.js +7 -1
  47. package/dist/resources/extensions/gsd/milestone-scope-classifier.js +299 -0
  48. package/dist/resources/extensions/gsd/milestone-summary-classifier.js +37 -0
  49. package/dist/resources/extensions/gsd/model-cost-table.js +3 -0
  50. package/dist/resources/extensions/gsd/model-router.js +6 -0
  51. package/dist/resources/extensions/gsd/native-git-bridge.js +34 -4
  52. package/dist/resources/extensions/gsd/preferences-validation.js +23 -0
  53. package/dist/resources/extensions/gsd/prompt-cache-optimizer.js +4 -0
  54. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
  55. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +23 -4
  56. package/dist/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
  57. package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  58. package/dist/resources/extensions/gsd/safety/git-checkpoint.js +11 -0
  59. package/dist/resources/extensions/gsd/service-tier.js +5 -2
  60. package/dist/resources/extensions/gsd/session-lock.js +19 -10
  61. package/dist/resources/extensions/gsd/skill-manifest.js +168 -0
  62. package/dist/resources/extensions/gsd/slice-cadence.js +238 -0
  63. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +278 -8
  64. package/dist/resources/extensions/gsd/state-transition-matrix.js +118 -0
  65. package/dist/resources/extensions/gsd/state.js +69 -58
  66. package/dist/resources/extensions/gsd/sync-lock.js +98 -42
  67. package/dist/resources/extensions/gsd/tools/validate-milestone.js +7 -2
  68. package/dist/resources/extensions/gsd/unit-context-composer.js +147 -0
  69. package/dist/resources/extensions/gsd/unit-context-manifest.js +370 -0
  70. package/dist/resources/extensions/gsd/uok/dispatch-envelope.js +33 -0
  71. package/dist/resources/extensions/gsd/uok/execution-graph.js +10 -0
  72. package/dist/resources/extensions/gsd/uok/gate-runner.js +53 -5
  73. package/dist/resources/extensions/gsd/uok/gitops.js +2 -1
  74. package/dist/resources/extensions/gsd/uok/loop-adapter.js +37 -10
  75. package/dist/resources/extensions/gsd/uok/parity-report.js +58 -0
  76. package/dist/resources/extensions/gsd/uok/plan-v2.js +10 -4
  77. package/dist/resources/extensions/gsd/uok/writer.js +82 -0
  78. package/dist/resources/extensions/gsd/workflow-mcp.js +6 -0
  79. package/dist/resources/extensions/gsd/worktree-manager.js +85 -8
  80. package/dist/resources/extensions/gsd/worktree-resolver.js +86 -7
  81. package/dist/resources/extensions/gsd/worktree-telemetry.js +198 -0
  82. package/dist/resources/extensions/mcp-client/index.js +3 -1
  83. package/dist/resources/extensions/ollama/index.js +5 -1
  84. package/dist/resources/extensions/remote-questions/manager.js +11 -5
  85. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  86. package/dist/web/standalone/.next/BUILD_ID +1 -1
  87. package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
  88. package/dist/web/standalone/.next/build-manifest.json +2 -2
  89. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  90. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  91. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  99. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  107. package/dist/web/standalone/.next/server/app/index.html +1 -1
  108. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
  115. package/dist/web/standalone/.next/server/chunks/1926.js +1 -1
  116. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  117. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  119. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  120. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  121. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  122. package/package.json +2 -3
  123. package/packages/daemon/package.json +2 -2
  124. package/packages/daemon/src/logger.ts +4 -3
  125. package/packages/mcp-server/dist/server.d.ts +24 -0
  126. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  127. package/packages/mcp-server/dist/server.js +88 -87
  128. package/packages/mcp-server/dist/server.js.map +1 -1
  129. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  130. package/packages/mcp-server/dist/workflow-tools.js +15 -6
  131. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  132. package/packages/mcp-server/package.json +2 -2
  133. package/packages/mcp-server/src/mcp-server.test.ts +25 -3
  134. package/packages/mcp-server/src/readers/graph.test.ts +87 -15
  135. package/packages/mcp-server/src/secure-env-collect.test.ts +232 -237
  136. package/packages/mcp-server/src/server.ts +131 -105
  137. package/packages/mcp-server/src/workflow-tools.test.ts +85 -0
  138. package/packages/mcp-server/src/workflow-tools.ts +19 -6
  139. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  140. package/packages/native/package.json +2 -2
  141. package/packages/native/src/__tests__/_test-coverage-guard.test.mjs +98 -0
  142. package/packages/native/src/__tests__/module-compat.test.mjs +59 -27
  143. package/packages/native/src/__tests__/ps.test.mjs +14 -8
  144. package/packages/native/src/__tests__/stream-process.test.mjs +23 -2
  145. package/packages/native/src/__tests__/truncate.test.mjs +17 -2
  146. package/packages/pi-agent-core/package.json +1 -1
  147. package/packages/pi-agent-core/src/agent-loop.test.ts +5 -15
  148. package/packages/pi-agent-core/src/agent.test.ts +96 -102
  149. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  150. package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -1
  151. package/packages/pi-ai/dist/models/capability-patches.js +9 -2
  152. package/packages/pi-ai/dist/models/capability-patches.js.map +1 -1
  153. package/packages/pi-ai/dist/models/generated/index.d.ts +34 -0
  154. package/packages/pi-ai/dist/models/generated/index.d.ts.map +1 -1
  155. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +17 -0
  156. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -1
  157. package/packages/pi-ai/dist/models/generated/openai-codex.js +17 -0
  158. package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -1
  159. package/packages/pi-ai/dist/models/generated/openai.d.ts +17 -0
  160. package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -1
  161. package/packages/pi-ai/dist/models/generated/openai.js +17 -0
  162. package/packages/pi-ai/dist/models/generated/openai.js.map +1 -1
  163. package/packages/pi-ai/dist/models.generated.test.js +43 -70
  164. package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
  165. package/packages/pi-ai/dist/models.test.js +36 -11
  166. package/packages/pi-ai/dist/models.test.js.map +1 -1
  167. package/packages/pi-ai/package.json +1 -1
  168. package/packages/pi-ai/scripts/generate-models.ts +44 -0
  169. package/packages/pi-ai/src/models/capability-patches.ts +10 -2
  170. package/packages/pi-ai/src/models/generated/openai-codex.ts +17 -0
  171. package/packages/pi-ai/src/models/generated/openai.ts +17 -0
  172. package/packages/pi-ai/src/models.generated.test.ts +46 -73
  173. package/packages/pi-ai/src/models.test.ts +48 -11
  174. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  175. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +96 -32
  176. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  177. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js +75 -12
  178. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js.map +1 -1
  179. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +99 -31
  180. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
  181. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +5 -0
  182. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  183. package/packages/pi-coding-agent/dist/core/extensions/loader.js +61 -0
  184. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  185. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js +30 -4
  186. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js.map +1 -1
  187. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +17 -0
  188. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  189. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js +76 -18
  190. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js.map +1 -1
  191. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
  192. package/packages/pi-coding-agent/dist/core/retry-handler.js +2 -6
  193. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
  194. package/packages/pi-coding-agent/dist/core/retry-handler.test.js +5 -1
  195. package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
  196. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts +18 -0
  197. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts.map +1 -0
  198. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js +18 -0
  199. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js.map +1 -0
  200. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +20 -0
  201. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  202. package/packages/pi-coding-agent/dist/core/system-prompt.js +16 -2
  203. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  204. package/packages/pi-coding-agent/dist/index.d.ts +1 -0
  205. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  206. package/packages/pi-coding-agent/dist/index.js +1 -0
  207. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  208. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +36 -5
  209. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  210. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +20 -13
  211. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -1
  212. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  213. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +30 -12
  214. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  215. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  216. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +18 -3
  217. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  218. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +125 -0
  219. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  220. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +2 -0
  221. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  222. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  223. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +4 -0
  224. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  225. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +105 -13
  226. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  227. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts +2 -0
  228. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts.map +1 -0
  229. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js +130 -0
  230. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js.map +1 -0
  231. package/packages/pi-coding-agent/package.json +1 -1
  232. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +113 -37
  233. package/packages/pi-coding-agent/src/core/agent-session-model-switch.test.ts +89 -17
  234. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +112 -43
  235. package/packages/pi-coding-agent/src/core/extensions/loader.ts +58 -0
  236. package/packages/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +35 -4
  237. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +20 -0
  238. package/packages/pi-coding-agent/src/core/resource-loader-cache-reset.test.ts +93 -28
  239. package/packages/pi-coding-agent/src/core/retry-handler.test.ts +5 -1
  240. package/packages/pi-coding-agent/src/core/retry-handler.ts +2 -8
  241. package/packages/pi-coding-agent/src/core/retryable-error-regex.ts +18 -0
  242. package/packages/pi-coding-agent/src/core/system-prompt.ts +35 -1
  243. package/packages/pi-coding-agent/src/index.ts +1 -0
  244. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +49 -3
  245. package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +26 -20
  246. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +48 -9
  247. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +146 -1
  248. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +20 -3
  249. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +2 -0
  250. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +119 -13
  251. package/packages/pi-coding-agent/src/tests/system-prompt-skill-filter.test.ts +157 -0
  252. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  253. package/packages/pi-tui/dist/__tests__/autocomplete.test.js +18 -8
  254. package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
  255. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +128 -17
  256. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
  257. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +37 -11
  258. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -1
  259. package/packages/pi-tui/dist/__tests__/tui.test.js +18 -30
  260. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
  261. package/packages/pi-tui/dist/components/__tests__/input.test.js +10 -3
  262. package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
  263. package/packages/pi-tui/dist/components/__tests__/loader.test.js +53 -9
  264. package/packages/pi-tui/dist/components/__tests__/loader.test.js.map +1 -1
  265. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +6 -2
  266. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -1
  267. package/packages/pi-tui/dist/components/editor.d.ts +14 -0
  268. package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
  269. package/packages/pi-tui/dist/components/editor.js +19 -0
  270. package/packages/pi-tui/dist/components/editor.js.map +1 -1
  271. package/packages/pi-tui/dist/components/image.test.js +6 -5
  272. package/packages/pi-tui/dist/components/image.test.js.map +1 -1
  273. package/packages/pi-tui/dist/editor-component.d.ts +2 -0
  274. package/packages/pi-tui/dist/editor-component.d.ts.map +1 -1
  275. package/packages/pi-tui/dist/editor-component.js.map +1 -1
  276. package/packages/pi-tui/package.json +1 -1
  277. package/packages/pi-tui/src/__tests__/autocomplete.test.ts +24 -8
  278. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +140 -17
  279. package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +42 -11
  280. package/packages/pi-tui/src/__tests__/tui.test.ts +18 -37
  281. package/packages/pi-tui/src/components/__tests__/input.test.ts +19 -3
  282. package/packages/pi-tui/src/components/__tests__/loader.test.ts +112 -35
  283. package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +9 -2
  284. package/packages/pi-tui/src/components/editor.ts +22 -0
  285. package/packages/pi-tui/src/components/image.test.ts +10 -5
  286. package/packages/pi-tui/src/editor-component.ts +3 -0
  287. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  288. package/packages/rpc-client/dist/rpc-client.test.js +101 -51
  289. package/packages/rpc-client/dist/rpc-client.test.js.map +1 -1
  290. package/packages/rpc-client/package.json +1 -1
  291. package/packages/rpc-client/src/rpc-client.test.ts +109 -52
  292. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  293. package/pkg/package.json +1 -1
  294. package/scripts/install.js +15 -1
  295. package/src/resources/extensions/browser-tools/capture.ts +12 -0
  296. package/src/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  297. package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  298. package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  299. package/src/resources/extensions/browser-tools/tools/forms.ts +5 -1
  300. package/src/resources/extensions/browser-tools/tools/intent.ts +5 -1
  301. package/src/resources/extensions/claude-code-cli/readiness.ts +75 -16
  302. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +518 -19
  303. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +919 -75
  304. package/src/resources/extensions/github-sync/templates.ts +151 -0
  305. package/src/resources/extensions/github-sync/tests/cli.test.ts +76 -7
  306. package/src/resources/extensions/github-sync/tests/templates.test.ts +92 -1
  307. package/src/resources/extensions/google-search/index.ts +3 -2
  308. package/src/resources/extensions/gsd/auto/loop.ts +142 -2
  309. package/src/resources/extensions/gsd/auto/phases.ts +62 -38
  310. package/src/resources/extensions/gsd/auto/session.ts +7 -2
  311. package/src/resources/extensions/gsd/auto-dispatch.ts +156 -29
  312. package/src/resources/extensions/gsd/auto-model-selection.ts +131 -4
  313. package/src/resources/extensions/gsd/auto-post-unit.ts +163 -73
  314. package/src/resources/extensions/gsd/auto-prompts.ts +385 -93
  315. package/src/resources/extensions/gsd/auto-recovery.ts +230 -51
  316. package/src/resources/extensions/gsd/auto-start.ts +127 -9
  317. package/src/resources/extensions/gsd/auto-tool-tracking.ts +51 -7
  318. package/src/resources/extensions/gsd/auto-worktree.ts +130 -26
  319. package/src/resources/extensions/gsd/auto.ts +90 -23
  320. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +20 -1
  321. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +221 -0
  322. package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +3 -7
  323. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +7 -3
  324. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +158 -9
  325. package/src/resources/extensions/gsd/component-loader.ts +598 -0
  326. package/src/resources/extensions/gsd/component-types.ts +362 -0
  327. package/src/resources/extensions/gsd/context-store.ts +25 -8
  328. package/src/resources/extensions/gsd/detection.ts +58 -1
  329. package/src/resources/extensions/gsd/dispatch-guard.ts +2 -20
  330. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  331. package/src/resources/extensions/gsd/forensics.ts +118 -1
  332. package/src/resources/extensions/gsd/gate-registry.ts +2 -2
  333. package/src/resources/extensions/gsd/git-constants.ts +30 -1
  334. package/src/resources/extensions/gsd/git-self-heal.ts +31 -0
  335. package/src/resources/extensions/gsd/git-service.ts +149 -2
  336. package/src/resources/extensions/gsd/gsd-db.ts +6 -3
  337. package/src/resources/extensions/gsd/guided-flow.ts +57 -14
  338. package/src/resources/extensions/gsd/journal.ts +11 -1
  339. package/src/resources/extensions/gsd/memory-extractor.ts +11 -3
  340. package/src/resources/extensions/gsd/milestone-scope-classifier.ts +366 -0
  341. package/src/resources/extensions/gsd/milestone-summary-classifier.ts +42 -0
  342. package/src/resources/extensions/gsd/model-cost-table.ts +3 -0
  343. package/src/resources/extensions/gsd/model-router.ts +6 -0
  344. package/src/resources/extensions/gsd/native-git-bridge.ts +34 -4
  345. package/src/resources/extensions/gsd/preferences-validation.ts +21 -0
  346. package/src/resources/extensions/gsd/prompt-cache-optimizer.ts +4 -0
  347. package/src/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
  348. package/src/resources/extensions/gsd/prompts/discuss-headless.md +23 -4
  349. package/src/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
  350. package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  351. package/src/resources/extensions/gsd/safety/git-checkpoint.ts +15 -0
  352. package/src/resources/extensions/gsd/service-tier.ts +5 -2
  353. package/src/resources/extensions/gsd/session-lock.ts +20 -10
  354. package/src/resources/extensions/gsd/skill-manifest.ts +175 -0
  355. package/src/resources/extensions/gsd/slice-cadence.ts +299 -0
  356. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +309 -8
  357. package/src/resources/extensions/gsd/state-transition-matrix.ts +152 -0
  358. package/src/resources/extensions/gsd/state.ts +76 -66
  359. package/src/resources/extensions/gsd/sync-lock.ts +97 -39
  360. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +270 -0
  361. package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +2 -1
  362. package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +341 -0
  363. package/src/resources/extensions/gsd/tests/auto-discuss-milestone-deadlock-4973.test.ts +264 -0
  364. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +133 -292
  365. package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +742 -0
  366. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +78 -0
  367. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +61 -0
  368. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +93 -0
  369. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +4 -1
  370. package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +8 -194
  371. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +3 -2
  372. package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +2 -2
  373. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +15 -58
  374. package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +2 -2
  375. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +3 -2
  376. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +3 -2
  377. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +2 -1
  378. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +17 -21
  379. package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +108 -0
  380. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +263 -0
  381. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +25 -0
  382. package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +192 -0
  383. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +2 -1
  384. package/src/resources/extensions/gsd/tests/complete-task.test.ts +16 -8
  385. package/src/resources/extensions/gsd/tests/component-loader.test.ts +589 -0
  386. package/src/resources/extensions/gsd/tests/component-types.test.ts +127 -0
  387. package/src/resources/extensions/gsd/tests/context-store.test.ts +79 -0
  388. package/src/resources/extensions/gsd/tests/copy-planning-artifacts-samepath.test.ts +2 -1
  389. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +50 -1
  390. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +159 -0
  391. package/src/resources/extensions/gsd/tests/db-access-guardrails.test.ts +1 -0
  392. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +3 -3
  393. package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +40 -0
  394. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +91 -3
  395. package/src/resources/extensions/gsd/tests/derive-state.test.ts +4 -4
  396. package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +2 -1
  397. package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +2 -1
  398. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +5 -0
  399. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +25 -0
  400. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +14 -0
  401. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +3 -2
  402. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +4 -3
  403. package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +4 -3
  404. package/src/resources/extensions/gsd/tests/execution-entry-missing-context-4671.test.ts +173 -0
  405. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +139 -129
  406. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +8 -104
  407. package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +102 -0
  408. package/src/resources/extensions/gsd/tests/gate-storage.test.ts +1 -1
  409. package/src/resources/extensions/gsd/tests/google-search-stub.test.ts +14 -4
  410. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +117 -0
  411. package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +4 -55
  412. package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +7 -56
  413. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +20 -0
  414. package/src/resources/extensions/gsd/tests/integration/doctor-proactive.test.ts +18 -2
  415. package/src/resources/extensions/gsd/tests/integration/queue-completed-milestone-perf.test.ts +10 -4
  416. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +144 -7
  417. package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +4 -0
  418. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +2 -16
  419. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +9 -3
  420. package/src/resources/extensions/gsd/tests/interrupted-session-ui.test.ts +6 -9
  421. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +64 -0
  422. package/src/resources/extensions/gsd/tests/knowledge.test.ts +93 -1
  423. package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +8 -37
  424. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +5 -15
  425. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +227 -55
  426. package/src/resources/extensions/gsd/tests/milestone-scope-classifier.test.ts +187 -0
  427. package/src/resources/extensions/gsd/tests/milestone-summary-classifier.test.ts +30 -0
  428. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
  429. package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
  430. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +6 -48
  431. package/src/resources/extensions/gsd/tests/notification-widget.test.ts +6 -3
  432. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +59 -2
  433. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +273 -130
  434. package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +301 -0
  435. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +32 -1
  436. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +2 -1
  437. package/src/resources/extensions/gsd/tests/prompt-cache-optimizer.test.ts +12 -0
  438. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +15 -4
  439. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +23 -24
  440. package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +32 -0
  441. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +3 -2
  442. package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +4 -5
  443. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +75 -2
  444. package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +132 -0
  445. package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +8 -40
  446. package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +136 -256
  447. package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +114 -0
  448. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +6 -3
  449. package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +148 -0
  450. package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
  451. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +29 -0
  452. package/src/resources/extensions/gsd/tests/sidecar-queue.test.ts +3 -2
  453. package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +55 -95
  454. package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +158 -0
  455. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +120 -1
  456. package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +112 -0
  457. package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +242 -0
  458. package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +3 -2
  459. package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +164 -1
  460. package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +2 -1
  461. package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +112 -0
  462. package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +29 -5
  463. package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +44 -0
  464. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +3 -3
  465. package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +11 -92
  466. package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +7 -6
  467. package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +102 -101
  468. package/src/resources/extensions/gsd/tests/sync-lock.test.ts +31 -0
  469. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +4 -3
  470. package/src/resources/extensions/gsd/tests/test-helpers.test.ts +98 -0
  471. package/src/resources/extensions/gsd/tests/test-helpers.ts +153 -0
  472. package/src/resources/extensions/gsd/tests/token-profile.test.ts +8 -1
  473. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +61 -1
  474. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -1
  475. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +355 -0
  476. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +258 -0
  477. package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +51 -0
  478. package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +16 -0
  479. package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +75 -0
  480. package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +49 -26
  481. package/src/resources/extensions/gsd/tests/uok-loop-adapter-writer.test.ts +65 -0
  482. package/src/resources/extensions/gsd/tests/uok-parity-report.test.ts +42 -0
  483. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +19 -2
  484. package/src/resources/extensions/gsd/tests/uok-writer.test.ts +75 -0
  485. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +12 -0
  486. package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +144 -80
  487. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -54
  488. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +342 -277
  489. package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +37 -29
  490. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +226 -266
  491. package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +103 -67
  492. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +92 -90
  493. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +238 -59
  494. package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +113 -161
  495. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +210 -0
  496. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +262 -0
  497. package/src/resources/extensions/gsd/tests/write-gate-predicates.test.ts +186 -0
  498. package/src/resources/extensions/gsd/tests/write-gate.test.ts +7 -5
  499. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +80 -96
  500. package/src/resources/extensions/gsd/tools/validate-milestone.ts +8 -2
  501. package/src/resources/extensions/gsd/types.ts +3 -3
  502. package/src/resources/extensions/gsd/unit-context-composer.ts +218 -0
  503. package/src/resources/extensions/gsd/unit-context-manifest.ts +574 -0
  504. package/src/resources/extensions/gsd/uok/contracts.ts +65 -0
  505. package/src/resources/extensions/gsd/uok/dispatch-envelope.ts +56 -0
  506. package/src/resources/extensions/gsd/uok/execution-graph.ts +22 -0
  507. package/src/resources/extensions/gsd/uok/gate-runner.ts +65 -5
  508. package/src/resources/extensions/gsd/uok/gitops.ts +6 -1
  509. package/src/resources/extensions/gsd/uok/loop-adapter.ts +45 -10
  510. package/src/resources/extensions/gsd/uok/parity-report.ts +84 -0
  511. package/src/resources/extensions/gsd/uok/plan-v2.ts +13 -5
  512. package/src/resources/extensions/gsd/uok/writer.ts +113 -0
  513. package/src/resources/extensions/gsd/workflow-mcp.ts +6 -0
  514. package/src/resources/extensions/gsd/worktree-manager.ts +108 -7
  515. package/src/resources/extensions/gsd/worktree-resolver.ts +96 -9
  516. package/src/resources/extensions/gsd/worktree-telemetry.ts +322 -0
  517. package/src/resources/extensions/mcp-client/index.ts +3 -1
  518. package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +70 -36
  519. package/src/resources/extensions/ollama/index.ts +5 -1
  520. package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +123 -15
  521. package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +206 -19
  522. package/src/resources/extensions/remote-questions/manager.ts +36 -4
  523. package/src/resources/extensions/remote-questions/tests/command-polling.test.ts +200 -190
  524. package/src/resources/extensions/shared/tests/interview-preview.test.ts +11 -3
  525. package/src/resources/extensions/voice/tests/linux-ready.test.ts +129 -113
  526. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +0 -2
  527. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +0 -1
  528. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +0 -289
  529. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +0 -1
  530. package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +0 -363
  531. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +0 -143
  532. package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +0 -157
  533. package/src/resources/extensions/gsd/tests/dashboard-model-label-ordering.test.ts +0 -107
  534. package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +0 -48
  535. package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +0 -159
  536. package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +0 -96
  537. package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +0 -79
  538. package/src/resources/extensions/gsd/tests/forensics-hook-key-parse.test.ts +0 -74
  539. package/src/resources/extensions/gsd/tests/forensics-journal.test.ts +0 -162
  540. package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +0 -38
  541. package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +0 -73
  542. package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +0 -125
  543. package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +0 -42
  544. /package/dist/web/standalone/.next/static/{5wbu35_C2_MQ3Jj1lEVDx → cAJH99yNS1UPbeSEiNRrV}/_buildManifest.js +0 -0
  545. /package/dist/web/standalone/.next/static/{5wbu35_C2_MQ3Jj1lEVDx → cAJH99yNS1UPbeSEiNRrV}/_ssgManifest.js +0 -0
@@ -66,6 +66,21 @@ function parseMcpToolName(name: string): { server: string; tool: string } | null
66
66
  return { server: rest.slice(0, delim), tool: rest.slice(delim + 2) };
67
67
  }
68
68
 
69
+ /**
70
+ * Prettify a raw tool name for display. Prefers the registered `label`
71
+ * ("Complete Slice") when available; otherwise strips a leading `gsd_`
72
+ * prefix and converts snake_case to Title Case.
73
+ */
74
+ function prettifyToolName(name: string, label?: string): string {
75
+ if (label && label.trim().length > 0) return label;
76
+ const stripped = name.replace(/^gsd_/, "");
77
+ if (stripped.length === 0) return name;
78
+ return stripped
79
+ .split("_")
80
+ .map((word) => (word.length === 0 ? word : word[0].toUpperCase() + word.slice(1)))
81
+ .join(" ");
82
+ }
83
+
69
84
  type ToolFrameTone = "pending" | "success" | "error";
70
85
 
71
86
  function trimOuterBlankLines(lines: string[]): string[] {
@@ -131,15 +146,19 @@ function formatCompactArgs(args: unknown, expanded: boolean): string {
131
146
 
132
147
  const allPrimitive = entries.every(([, value]) => {
133
148
  const t = typeof value;
134
- if (t === "number" || t === "boolean") return true;
135
- if (t === "string") return (value as string).length <= COMPACT_ARG_VALUE_LIMIT;
136
- return value == null;
149
+ return t === "number" || t === "boolean" || t === "string" || value == null;
137
150
  });
138
151
 
139
152
  if (allPrimitive) {
140
153
  return entries
141
154
  .map(([key, value]) => {
142
- if (typeof value === "string") return `${key}=${JSON.stringify(value)}`;
155
+ if (typeof value === "string") {
156
+ const truncated =
157
+ !expanded && value.length > COMPACT_ARG_VALUE_LIMIT
158
+ ? `${value.slice(0, COMPACT_ARG_VALUE_LIMIT - 1)}…`
159
+ : value;
160
+ return `${key}=${JSON.stringify(truncated)}`;
161
+ }
143
162
  if (value == null) return `${key}=null`;
144
163
  return `${key}=${String(value)}`;
145
164
  })
@@ -526,7 +545,7 @@ export class ToolExecutionComponent extends Container {
526
545
  const parsed = parseMcpToolName(this.toolName);
527
546
  const frameLabel = parsed
528
547
  ? `Tool ${parsed.server}·${parsed.tool}`
529
- : `Tool ${this.normalizedToolName || this.toolName || "unknown"}`;
548
+ : `Tool ${prettifyToolName(this.toolName, this.toolDefinition?.label) || "unknown"}`;
530
549
  const framed = renderToolFrame(lines, frameWidth, {
531
550
  label: frameLabel,
532
551
  status: frameStatus,
@@ -570,12 +589,30 @@ export class ToolExecutionComponent extends Container {
570
589
  }
571
590
  } catch {
572
591
  // Fall back to default on error
573
- this.contentBox.addChild(new Text(theme.fg("toolTitle", theme.bold(this.toolName)), 0, 0));
592
+ this.contentBox.addChild(
593
+ new Text(
594
+ theme.fg(
595
+ "toolTitle",
596
+ theme.bold(prettifyToolName(this.toolName, this.toolDefinition?.label)),
597
+ ),
598
+ 0,
599
+ 0,
600
+ ),
601
+ );
574
602
  customRendererHasContent = true;
575
603
  }
576
604
  } else {
577
- // No custom renderCall, show tool name
578
- this.contentBox.addChild(new Text(theme.fg("toolTitle", theme.bold(this.toolName)), 0, 0));
605
+ // No custom renderCall, show prettified tool name
606
+ this.contentBox.addChild(
607
+ new Text(
608
+ theme.fg(
609
+ "toolTitle",
610
+ theme.bold(prettifyToolName(this.toolName, this.toolDefinition?.label)),
611
+ ),
612
+ 0,
613
+ 0,
614
+ ),
615
+ );
579
616
  customRendererHasContent = true;
580
617
  }
581
618
 
@@ -1126,7 +1163,9 @@ export class ToolExecutionComponent extends Container {
1126
1163
  // cleanly. GSD-registered MCP tools have already had their prefix
1127
1164
  // stripped upstream in partial-builder.ts and won't reach this branch.
1128
1165
  const parsed = parseMcpToolName(this.toolName);
1129
- const displayName = parsed ? parsed.tool : this.toolName;
1166
+ const displayName = parsed
1167
+ ? parsed.tool
1168
+ : prettifyToolName(this.toolName, this.toolDefinition?.label);
1130
1169
  const serverPrefix = parsed ? theme.fg("muted", `${parsed.server}\u00b7`) : "";
1131
1170
  text = serverPrefix + theme.fg("toolTitle", theme.bold(displayName));
1132
1171
 
@@ -1,7 +1,151 @@
1
+ // GSD2 — Tests for input-controller image pasting behavior
2
+ // Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
3
+
4
+ import { describe, it, beforeEach } from "node:test";
1
5
  import assert from "node:assert/strict";
2
6
  import test from "node:test";
3
-
4
7
  import { setupEditorSubmitHandler } from "./input-controller.js";
8
+ import { ContextualTips } from "../../../core/contextual-tips.js";
9
+ import type { InteractiveModeStateHost } from "../interactive-mode-state.js";
10
+ import type { ImageContent } from "@gsd/pi-ai";
11
+
12
+ /** Minimal mock host satisfying InteractiveModeStateHost + setupEditorSubmitHandler extras. */
13
+ function createMockHost() {
14
+ const promptCalls: Array<{ text: string; options?: any }> = [];
15
+ const historyCalls: string[] = [];
16
+ let editorText = "";
17
+
18
+ const host = {
19
+ defaultEditor: {
20
+ onSubmit: undefined as ((text: string) => Promise<void>) | undefined,
21
+ addToHistory: (text: string) => { historyCalls.push(text); },
22
+ setText: (text: string) => { editorText = text; },
23
+ getText: () => editorText,
24
+ },
25
+ editor: {
26
+ setText: (text: string) => { editorText = text; },
27
+ getText: () => editorText,
28
+ addToHistory: (text: string) => { historyCalls.push(text); },
29
+ },
30
+ session: {
31
+ isStreaming: false,
32
+ isCompacting: false,
33
+ isBashRunning: false,
34
+ thinkingLevel: undefined,
35
+ prompt: async (text: string, options?: any) => { promptCalls.push({ text, options }); },
36
+ },
37
+ ui: { requestRender: () => {} },
38
+ footer: {},
39
+ keybindings: {},
40
+ statusContainer: {},
41
+ chatContainer: {},
42
+ pinnedMessageContainer: {},
43
+ settingsManager: {},
44
+ pendingTools: new Map(),
45
+ toolOutputExpanded: false,
46
+ hideThinkingBlock: false,
47
+ isBashMode: false,
48
+ onInputCallback: undefined,
49
+ isInitialized: true,
50
+ loadingAnimation: undefined,
51
+ pendingWorkingMessage: undefined,
52
+ defaultWorkingMessage: "Working...",
53
+ streamingComponent: undefined,
54
+ streamingMessage: undefined,
55
+ retryEscapeHandler: undefined,
56
+ retryLoader: undefined,
57
+ autoCompactionLoader: undefined,
58
+ autoCompactionEscapeHandler: undefined,
59
+ compactionQueuedMessages: [] as Array<{ text: string; mode: "steer" | "followUp" }>,
60
+ extensionSelector: undefined,
61
+ extensionInput: undefined,
62
+ extensionEditor: undefined,
63
+ editorContainer: {},
64
+ keybindingsManager: undefined,
65
+ pendingImages: [] as ImageContent[],
66
+
67
+ // Extra methods required by setupEditorSubmitHandler
68
+ getSlashCommandContext: () => ({}),
69
+ handleBashCommand: async (_command: string, _excludeFromContext?: boolean) => {},
70
+ showWarning: (_message: string) => {},
71
+ showError: (_message: string) => {},
72
+ showTip: (_message: string) => {},
73
+ updateEditorBorderColor: () => {},
74
+ isExtensionCommand: (_text: string) => false,
75
+ isKnownSlashCommand: (_text: string) => false,
76
+ queueCompactionMessage: (_text: string, _mode: "steer" | "followUp") => {},
77
+ updatePendingMessagesDisplay: () => {},
78
+ flushPendingBashComponents: () => {},
79
+ contextualTips: new ContextualTips(),
80
+ getContextPercent: () => undefined,
81
+ options: { submitPromptsDirectly: true },
82
+ } satisfies InteractiveModeStateHost & Parameters<typeof setupEditorSubmitHandler>[0];
83
+
84
+ return { host, promptCalls, historyCalls };
85
+ }
86
+
87
+ const TEST_IMAGE: ImageContent = {
88
+ type: "image",
89
+ data: "iVBORw0KGgo=",
90
+ mimeType: "image/png",
91
+ };
92
+
93
+ describe("input-controller pending images", () => {
94
+ let host: ReturnType<typeof createMockHost>["host"];
95
+ let promptCalls: ReturnType<typeof createMockHost>["promptCalls"];
96
+
97
+ beforeEach(() => {
98
+ const mock = createMockHost();
99
+ host = mock.host;
100
+ promptCalls = mock.promptCalls;
101
+ setupEditorSubmitHandler(host);
102
+ });
103
+
104
+ it("passes pending images to session.prompt on submit", async () => {
105
+ host.pendingImages.push({ ...TEST_IMAGE });
106
+ await host.defaultEditor.onSubmit!("describe this image");
107
+
108
+ assert.equal(promptCalls.length, 1);
109
+ assert.equal(promptCalls[0].text, "describe this image");
110
+ assert.ok(promptCalls[0].options?.images);
111
+ assert.equal(promptCalls[0].options.images.length, 1);
112
+ assert.equal(promptCalls[0].options.images[0].mimeType, "image/png");
113
+ });
114
+
115
+ it("clears pending images after submit", async () => {
116
+ host.pendingImages.push({ ...TEST_IMAGE });
117
+ await host.defaultEditor.onSubmit!("describe this image");
118
+
119
+ assert.equal(host.pendingImages.length, 0);
120
+ });
121
+
122
+ it("passes undefined images when no images are pending", async () => {
123
+ await host.defaultEditor.onSubmit!("hello");
124
+
125
+ assert.equal(promptCalls.length, 1);
126
+ assert.equal(promptCalls[0].options?.images, undefined);
127
+ });
128
+
129
+ it("passes multiple images in order", async () => {
130
+ const img1: ImageContent = { type: "image", data: "aaa=", mimeType: "image/png" };
131
+ const img2: ImageContent = { type: "image", data: "bbb=", mimeType: "image/jpeg" };
132
+ host.pendingImages.push(img1, img2);
133
+
134
+ await host.defaultEditor.onSubmit!("describe these images");
135
+
136
+ assert.equal(promptCalls[0].options.images.length, 2);
137
+ assert.equal(promptCalls[0].options.images[0].data, "aaa=");
138
+ assert.equal(promptCalls[0].options.images[1].data, "bbb=");
139
+ });
140
+
141
+ it("discards pending images on bash command", async () => {
142
+ host.pendingImages.push({ ...TEST_IMAGE });
143
+ await host.defaultEditor.onSubmit!("! ls -la");
144
+
145
+ assert.equal(host.pendingImages.length, 0);
146
+ assert.equal(promptCalls.length, 0); // bash commands don't go through prompt
147
+ });
148
+ });
5
149
 
6
150
  type HostOptions = {
7
151
  knownSlashCommands?: string[];
@@ -49,6 +193,7 @@ function createHost(options: HostOptions = {}) {
49
193
  ui: {
50
194
  requestRender() {},
51
195
  },
196
+ pendingImages: [] as ImageContent[],
52
197
  getSlashCommandContext: () => ({
53
198
  showSettingsSelector: () => {
54
199
  settingsOpened += 1;
@@ -1,7 +1,19 @@
1
+ import type { ImageContent } from "@gsd/pi-ai";
1
2
  import { dispatchSlashCommand } from "../slash-command-handlers.js";
2
3
  import type { InteractiveModeStateHost } from "../interactive-mode-state.js";
3
4
  import type { ContextualTips } from "../../../core/contextual-tips.js";
4
5
 
6
+ /**
7
+ * Consume and clear any pending pasted images from the host.
8
+ * Returns undefined if there are no pending images.
9
+ */
10
+ function consumePendingImages(host: InteractiveModeStateHost): ImageContent[] | undefined {
11
+ if (host.pendingImages.length === 0) return undefined;
12
+ const images = [...host.pendingImages];
13
+ host.pendingImages.length = 0;
14
+ return images;
15
+ }
16
+
5
17
  export function setupEditorSubmitHandler(host: InteractiveModeStateHost & {
6
18
  getSlashCommandContext: () => any;
7
19
  handleBashCommand: (command: string, excludeFromContext?: boolean) => Promise<void>;
@@ -26,6 +38,7 @@ export function setupEditorSubmitHandler(host: InteractiveModeStateHost & {
26
38
  const handled = await dispatchSlashCommand(text, host.getSlashCommandContext());
27
39
  if (handled) {
28
40
  host.editor.setText("");
41
+ consumePendingImages(host); // discard images on slash command
29
42
  return;
30
43
  }
31
44
  if (!host.isKnownSlashCommand(text)) {
@@ -53,10 +66,14 @@ export function setupEditorSubmitHandler(host: InteractiveModeStateHost & {
53
66
  await host.handleBashCommand(command, isExcluded);
54
67
  host.isBashMode = false;
55
68
  host.updateEditorBorderColor();
69
+ consumePendingImages(host); // discard images on bash command
56
70
  return;
57
71
  }
58
72
  }
59
73
 
74
+ // Consume pending images for prompt submissions
75
+ const images = consumePendingImages(host);
76
+
60
77
  // Evaluate contextual tips before sending to agent
61
78
  const tip = host.contextualTips.evaluate({
62
79
  input: text,
@@ -73,7 +90,7 @@ export function setupEditorSubmitHandler(host: InteractiveModeStateHost & {
73
90
  host.editor.addToHistory?.(text);
74
91
  host.editor.setText("");
75
92
  try {
76
- await host.session.prompt(text);
93
+ await host.session.prompt(text, { images });
77
94
  } catch (error: unknown) {
78
95
  const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
79
96
  host.showError(errorMessage);
@@ -87,7 +104,7 @@ export function setupEditorSubmitHandler(host: InteractiveModeStateHost & {
87
104
  if (host.session.isStreaming) {
88
105
  host.editor.addToHistory?.(text);
89
106
  host.editor.setText("");
90
- await host.session.prompt(text, { streamingBehavior: "steer" });
107
+ await host.session.prompt(text, { streamingBehavior: "steer", images });
91
108
  host.updatePendingMessagesDisplay();
92
109
  host.ui.requestRender();
93
110
  return;
@@ -104,7 +121,7 @@ export function setupEditorSubmitHandler(host: InteractiveModeStateHost & {
104
121
  if (host.options?.submitPromptsDirectly) {
105
122
  host.editor.addToHistory?.(text);
106
123
  try {
107
- await host.session.prompt(text);
124
+ await host.session.prompt(text, { images });
108
125
  } catch (error: unknown) {
109
126
  const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
110
127
  host.showError(errorMessage);
@@ -1,3 +1,4 @@
1
+ import type { ImageContent } from "@gsd/pi-ai";
1
2
  import type { AgentSessionEvent } from "../../core/agent-session.js";
2
3
 
3
4
  export interface InteractiveModeStateHost {
@@ -32,6 +33,7 @@ export interface InteractiveModeStateHost {
32
33
  extensionEditor?: any;
33
34
  editorContainer: any;
34
35
  keybindingsManager?: any;
36
+ pendingImages: ImageContent[];
35
37
  }
36
38
 
37
39
  export type InteractiveModeEvent = AgentSessionEvent;
@@ -3,7 +3,6 @@
3
3
  * Handles TUI rendering and user interaction, delegating business logic to AgentSession.
4
4
  */
5
5
 
6
- import * as crypto from "node:crypto";
7
6
  import * as fs from "node:fs";
8
7
  import * as os from "node:os";
9
8
  import * as path from "node:path";
@@ -62,7 +61,7 @@ import { type SessionContext, SessionManager } from "../../core/session-manager.
62
61
  import { BUILTIN_SLASH_COMMANDS } from "../../core/slash-commands.js";
63
62
  import type { TruncationResult } from "../../core/tools/truncate.js";
64
63
  import { getChangelogPath, getNewEntries, parseChangelog } from "../../utils/changelog.js";
65
- import { extensionForImageMimeType, readClipboardImage } from "../../utils/clipboard-image.js";
64
+ import { readClipboardImage } from "../../utils/clipboard-image.js";
66
65
  import { ensureTool } from "../../utils/tools-manager.js";
67
66
  import { AssistantMessageComponent } from "./components/assistant-message.js";
68
67
  import { BashExecutionComponent } from "./components/bash-execution.js";
@@ -240,6 +239,9 @@ export class InteractiveMode {
240
239
  // Tool output expansion state
241
240
  private toolOutputExpanded = false;
242
241
 
242
+ // Pasted image tracking
243
+ private pendingImages: ImageContent[] = [];
244
+
243
245
  // Thinking block visibility state
244
246
  private hideThinkingBlock = false;
245
247
 
@@ -648,8 +650,10 @@ export class InteractiveMode {
648
650
  // Main interactive loop
649
651
  while (true) {
650
652
  const userInput = await this.getUserInput();
653
+ const images = this.pendingImages.length > 0 ? [...this.pendingImages] : undefined;
654
+ this.pendingImages.length = 0;
651
655
  try {
652
- await this.session.prompt(userInput);
656
+ await this.session.prompt(userInput, { images });
653
657
  } catch (error: unknown) {
654
658
  const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
655
659
  this.showError(errorMessage);
@@ -1814,6 +1818,13 @@ export class InteractiveMode {
1814
1818
  this.editor = this.defaultEditor;
1815
1819
  }
1816
1820
 
1821
+ // Ensure pasted image path handler is set on the active editor
1822
+ if (!this.editor.onPasteImagePath) {
1823
+ this.editor.onPasteImagePath = (filePath: string) => {
1824
+ this.handlePastedImagePath(filePath);
1825
+ };
1826
+ }
1827
+
1817
1828
  this.editorContainer.addChild(this.editor as Component);
1818
1829
  this.ui.setFocus(this.editor as Component);
1819
1830
  this.ui.requestRender();
@@ -1948,6 +1959,7 @@ export class InteractiveMode {
1948
1959
  this.session.abortBash();
1949
1960
  } else if (this.isBashMode) {
1950
1961
  this.editor.setText("");
1962
+ this.pendingImages.length = 0;
1951
1963
  this.isBashMode = false;
1952
1964
  this.updateEditorBorderColor();
1953
1965
  } else if (!this.editor.getText().trim()) {
@@ -2002,6 +2014,12 @@ export class InteractiveMode {
2002
2014
  this.defaultEditor.onPasteImage = () => {
2003
2015
  this.handleClipboardImagePaste();
2004
2016
  };
2017
+
2018
+ // Handle image file paths pasted via terminal emulator (e.g. iTerm2).
2019
+ // Set on defaultEditor here; setCustomEditorComponent guards re-assignment for custom editors.
2020
+ this.defaultEditor.onPasteImagePath = (filePath: string) => {
2021
+ this.handlePastedImagePath(filePath);
2022
+ };
2005
2023
  }
2006
2024
 
2007
2025
  private async handleClipboardImagePaste(): Promise<void> {
@@ -2011,21 +2029,104 @@ export class InteractiveMode {
2011
2029
  return;
2012
2030
  }
2013
2031
 
2014
- // Write to temp file
2015
- const tmpDir = os.tmpdir();
2016
- const ext = extensionForImageMimeType(image.mimeType) ?? "png";
2017
- const fileName = `pi-clipboard-${crypto.randomUUID()}.${ext}`;
2018
- const filePath = path.join(tmpDir, fileName);
2019
- fs.writeFileSync(filePath, Buffer.from(image.bytes));
2032
+ // Store image as base64 ImageContent for sending with the prompt
2033
+ const imageContent: ImageContent = {
2034
+ type: "image",
2035
+ data: Buffer.from(image.bytes).toString("base64"),
2036
+ mimeType: image.mimeType,
2037
+ };
2038
+ this.pendingImages.push(imageContent);
2020
2039
 
2021
- // Insert file path directly
2022
- this.editor.insertTextAtCursor?.(filePath);
2040
+ // Insert friendly placeholder instead of file path
2041
+ const imageNum = this.pendingImages.length;
2042
+ this.editor.insertTextAtCursor?.(`[Image #${imageNum}]`);
2023
2043
  this.ui.requestRender();
2024
2044
  } catch {
2025
2045
  // Silently ignore clipboard errors (may not have permission, etc.)
2026
2046
  }
2027
2047
  }
2028
2048
 
2049
+ // MIME types restricted to formats commonly accepted by AI vision APIs.
2050
+ // SVG is excluded — it is XML/JS-bearing and not safe to forward as image content.
2051
+ // TIFF/HEIC/HEIF/AVIF are excluded for compatibility; users can convert before pasting.
2052
+ private static readonly MIME_BY_EXT: Record<string, string> = {
2053
+ png: "image/png",
2054
+ jpg: "image/jpeg",
2055
+ jpeg: "image/jpeg",
2056
+ gif: "image/gif",
2057
+ webp: "image/webp",
2058
+ };
2059
+
2060
+ // Magic-byte signatures used to verify file content matches its extension,
2061
+ // preventing arbitrary-file-read via crafted paste of e.g. "/etc/passwd.png".
2062
+ private static matchesImageSignature(buf: Buffer, mimeType: string): boolean {
2063
+ if (buf.length < 12) return false;
2064
+ switch (mimeType) {
2065
+ case "image/png":
2066
+ return buf[0] === 0x89 && buf[1] === 0x50 && buf[2] === 0x4e && buf[3] === 0x47;
2067
+ case "image/jpeg":
2068
+ return buf[0] === 0xff && buf[1] === 0xd8 && buf[2] === 0xff;
2069
+ case "image/gif":
2070
+ return (
2071
+ buf[0] === 0x47 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x38 &&
2072
+ (buf[4] === 0x37 || buf[4] === 0x39) && buf[5] === 0x61
2073
+ );
2074
+ case "image/webp":
2075
+ return (
2076
+ buf[0] === 0x52 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x46 &&
2077
+ buf[8] === 0x57 && buf[9] === 0x45 && buf[10] === 0x42 && buf[11] === 0x50
2078
+ );
2079
+ default:
2080
+ return false;
2081
+ }
2082
+ }
2083
+
2084
+ private handlePastedImagePath(filePath: string): void {
2085
+ try {
2086
+ const ext = path.extname(filePath).slice(1).toLowerCase();
2087
+ const mimeType = InteractiveMode.MIME_BY_EXT[ext];
2088
+ if (!mimeType) {
2089
+ // Unsupported / unsafe extension — fall back to inserting raw path.
2090
+ this.editor.insertTextAtCursor?.(filePath);
2091
+ this.ui.requestRender();
2092
+ return;
2093
+ }
2094
+
2095
+ // Reject symlinks to prevent reading sensitive files via a symlinked
2096
+ // `.png` that points at e.g. ~/.ssh/id_rsa.
2097
+ const lst = fs.lstatSync(filePath);
2098
+ if (!lst.isFile()) {
2099
+ this.editor.insertTextAtCursor?.(filePath);
2100
+ this.ui.requestRender();
2101
+ return;
2102
+ }
2103
+
2104
+ const data = fs.readFileSync(filePath);
2105
+
2106
+ // Magic-byte check — confirms file content actually matches the
2107
+ // extension before we forward bytes to a model.
2108
+ if (!InteractiveMode.matchesImageSignature(data, mimeType)) {
2109
+ this.editor.insertTextAtCursor?.(filePath);
2110
+ this.ui.requestRender();
2111
+ return;
2112
+ }
2113
+
2114
+ this.pendingImages.push({
2115
+ type: "image",
2116
+ data: data.toString("base64"),
2117
+ mimeType,
2118
+ });
2119
+
2120
+ const imageNum = this.pendingImages.length;
2121
+ this.editor.insertTextAtCursor?.(`[Image #${imageNum}]`);
2122
+ this.ui.requestRender();
2123
+ } catch {
2124
+ // Fall back to inserting the raw path if file can't be read
2125
+ this.editor.insertTextAtCursor?.(filePath);
2126
+ this.ui.requestRender();
2127
+ }
2128
+ }
2129
+
2029
2130
  private getSlashCommandContext(): SlashCommandContext {
2030
2131
  return {
2031
2132
  session: this.session,
@@ -2562,12 +2663,16 @@ export class InteractiveMode {
2562
2663
  return;
2563
2664
  }
2564
2665
 
2666
+ // Consume pending images
2667
+ const images = this.pendingImages.length > 0 ? [...this.pendingImages] : undefined;
2668
+ this.pendingImages.length = 0;
2669
+
2565
2670
  // Queue input during compaction (extension commands execute immediately)
2566
2671
  if (this.session.isCompacting) {
2567
2672
  if (this.isExtensionCommand(text)) {
2568
2673
  this.editor.addToHistory?.(text);
2569
2674
  this.editor.setText("");
2570
- await this.session.prompt(text);
2675
+ await this.session.prompt(text, { images });
2571
2676
  } else {
2572
2677
  this.queueCompactionMessage(text, "followUp");
2573
2678
  }
@@ -2579,7 +2684,7 @@ export class InteractiveMode {
2579
2684
  if (this.session.isStreaming) {
2580
2685
  this.editor.addToHistory?.(text);
2581
2686
  this.editor.setText("");
2582
- await this.session.prompt(text, { streamingBehavior: "followUp" });
2687
+ await this.session.prompt(text, { streamingBehavior: "followUp", images });
2583
2688
  this.updatePendingMessagesDisplay();
2584
2689
  this.ui.requestRender();
2585
2690
  }
@@ -3863,6 +3968,7 @@ export class InteractiveMode {
3863
3968
  this.streamingComponent = undefined;
3864
3969
  this.streamingMessage = undefined;
3865
3970
  this.pendingTools.clear();
3971
+ this.pendingImages.length = 0;
3866
3972
 
3867
3973
  // Reset contextual tips for the new session
3868
3974
  this.contextualTips.reset();