@gajae-code/coding-agent 0.13.3 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (599) hide show
  1. package/CHANGELOG.md +184 -2
  2. package/README.md +2 -0
  3. package/bin/gajaessi.js +4 -0
  4. package/dist/types/async/job-manager.d.ts +55 -2
  5. package/dist/types/async/support.d.ts +14 -0
  6. package/dist/types/capability/mcp.d.ts +6 -0
  7. package/dist/types/capability/types.d.ts +6 -0
  8. package/dist/types/cli/accounts-cli.d.ts +19 -0
  9. package/dist/types/cli/args.d.ts +3 -0
  10. package/dist/types/cli/config-cli.d.ts +6 -0
  11. package/dist/types/cli/crash-cli.d.ts +10 -0
  12. package/dist/types/cli/customize-doctor.d.ts +145 -0
  13. package/dist/types/cli/daemon-cli.d.ts +3 -1
  14. package/dist/types/cli/mcp-cli.d.ts +11 -0
  15. package/dist/types/cli/notify-cli.d.ts +1 -1
  16. package/dist/types/cli/root-flags.d.ts +12 -0
  17. package/dist/types/cli/setup-cli.d.ts +3 -1
  18. package/dist/types/cli/skills-cli.d.ts +2 -1
  19. package/dist/types/cli/update-cli.d.ts +19 -1
  20. package/dist/types/cli.d.ts +6 -0
  21. package/dist/types/commands/accounts.d.ts +40 -0
  22. package/dist/types/commands/crash.d.ts +24 -0
  23. package/dist/types/commands/customize.d.ts +22 -0
  24. package/dist/types/commands/daemon.d.ts +1 -1
  25. package/dist/types/commands/launch.d.ts +6 -0
  26. package/dist/types/commands/setup.d.ts +6 -0
  27. package/dist/types/commands/skills.d.ts +6 -1
  28. package/dist/types/commands/update.d.ts +7 -0
  29. package/dist/types/config/atomic-yaml-patch-worker.d.ts +25 -0
  30. package/dist/types/config/atomic-yaml-patch.d.ts +62 -2
  31. package/dist/types/config/config-schema-version.d.ts +10 -0
  32. package/dist/types/config/file-lock.d.ts +18 -0
  33. package/dist/types/config/model-profile-activation.d.ts +3 -1
  34. package/dist/types/config/model-registry.d.ts +9 -1
  35. package/dist/types/config/models-config-schema.d.ts +2 -0
  36. package/dist/types/config/settings-schema.d.ts +70 -6
  37. package/dist/types/config/settings.d.ts +63 -0
  38. package/dist/types/config/skill-settings-defaults.d.ts +26 -0
  39. package/dist/types/config/task-delegation.d.ts +39 -0
  40. package/dist/types/config/update-channel.d.ts +10 -0
  41. package/dist/types/coordinator-mcp/server.d.ts +5 -1
  42. package/dist/types/crash/index-store.d.ts +87 -0
  43. package/dist/types/crash/nudge.d.ts +50 -0
  44. package/dist/types/crash/record-loader.d.ts +17 -0
  45. package/dist/types/crash/report.d.ts +134 -0
  46. package/dist/types/crash/sanitize.d.ts +25 -0
  47. package/dist/types/cursor.d.ts +13 -2
  48. package/dist/types/customization/import.d.ts +37 -0
  49. package/dist/types/customization/index.d.ts +4 -0
  50. package/dist/types/customization/inventory.d.ts +25 -0
  51. package/dist/types/customization/mutations.d.ts +32 -0
  52. package/dist/types/customization/types.d.ts +115 -0
  53. package/dist/types/daemon/control-types.d.ts +8 -1
  54. package/dist/types/daemon/operator-contract.d.ts +4 -4
  55. package/dist/types/discovery/claude.d.ts +39 -1
  56. package/dist/types/discovery/codex.d.ts +39 -1
  57. package/dist/types/discovery/index.d.ts +2 -0
  58. package/dist/types/discovery/mcp-compat.d.ts +30 -0
  59. package/dist/types/edit/renderer.d.ts +23 -0
  60. package/dist/types/extensibility/extensions/runner.d.ts +3 -0
  61. package/dist/types/extensibility/extensions/types.d.ts +21 -4
  62. package/dist/types/extensibility/gjc-plugins/observability.d.ts +6 -1
  63. package/dist/types/extensibility/gjc-plugins/registry.d.ts +8 -1
  64. package/dist/types/extensibility/hooks/loader.d.ts +19 -5
  65. package/dist/types/extensibility/runtime-skill-discovery.d.ts +22 -1
  66. package/dist/types/extensibility/skill-management.d.ts +107 -0
  67. package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +3 -1
  68. package/dist/types/gjc-runtime/launch-worktree.d.ts +8 -0
  69. package/dist/types/gjc-runtime/linux-proc.d.ts +3 -0
  70. package/dist/types/gjc-runtime/ralplan-runtime.d.ts +10 -6
  71. package/dist/types/gjc-runtime/session-state-lock.d.ts +104 -0
  72. package/dist/types/gjc-runtime/session-state-sidecar.d.ts +120 -2
  73. package/dist/types/gjc-runtime/state-writer.d.ts +10 -1
  74. package/dist/types/gjc-runtime/ultragoal-guard.d.ts +4 -2
  75. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +8 -6
  76. package/dist/types/gjc-runtime/workflow-settings.d.ts +109 -0
  77. package/dist/types/hooks/events.d.ts +60 -0
  78. package/dist/types/hooks/normalize.d.ts +83 -0
  79. package/dist/types/hooks/skill-state.d.ts +9 -2
  80. package/dist/types/main.d.ts +1 -1
  81. package/dist/types/modes/acp/abort-scope.d.ts +13 -0
  82. package/dist/types/modes/acp/acp-agent.d.ts +7 -4
  83. package/dist/types/modes/components/customization/customization-dashboard.d.ts +44 -0
  84. package/dist/types/modes/components/customization/import-wizard.d.ts +21 -0
  85. package/dist/types/modes/components/customization/index.d.ts +1 -0
  86. package/dist/types/modes/components/gajae-pet-widget.d.ts +8 -30
  87. package/dist/types/modes/components/irc-sidebar.d.ts +1 -0
  88. package/dist/types/modes/components/iterm-pet-transport.d.ts +122 -0
  89. package/dist/types/modes/components/oauth-selector.d.ts +10 -4
  90. package/dist/types/modes/components/pet-capability.d.ts +11 -25
  91. package/dist/types/modes/components/status-line/gh.d.ts +6 -2
  92. package/dist/types/modes/controllers/extension-ui-controller.d.ts +1 -1
  93. package/dist/types/modes/controllers/selector-controller.d.ts +7 -8
  94. package/dist/types/modes/controllers/stt-controller.d.ts +1 -1
  95. package/dist/types/modes/interactive-mode.d.ts +1 -0
  96. package/dist/types/modes/types.d.ts +1 -0
  97. package/dist/types/modes/utils/injected-user-submission.d.ts +10 -0
  98. package/dist/types/runtime-mcp/config.d.ts +9 -0
  99. package/dist/types/runtime-mcp/manager.d.ts +26 -1
  100. package/dist/types/runtime-mcp/oauth-discovery.d.ts +4 -0
  101. package/dist/types/runtime-mcp/oauth-flow.d.ts +24 -1
  102. package/dist/types/runtime-mcp/pool-key.d.ts +2 -0
  103. package/dist/types/runtime-mcp/protocol.d.ts +278 -0
  104. package/dist/types/runtime-mcp/scope-config.d.ts +29 -0
  105. package/dist/types/runtime-mcp/tool-bridge.d.ts +15 -13
  106. package/dist/types/runtime-mcp/transports/http.d.ts +9 -0
  107. package/dist/types/runtime-mcp/types.d.ts +102 -10
  108. package/dist/types/sdk/acp/adapter.d.ts +26 -5
  109. package/dist/types/sdk/broker/broker.d.ts +3 -55
  110. package/dist/types/sdk/broker/lifecycle.d.ts +18 -12
  111. package/dist/types/sdk/broker/session-index.d.ts +14 -5
  112. package/dist/types/sdk/broker/startup-failure.d.ts +16 -1
  113. package/dist/types/sdk/bus/chat-daemon-control.d.ts +51 -1
  114. package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +4 -41
  115. package/dist/types/sdk/bus/config.d.ts +11 -0
  116. package/dist/types/sdk/bus/conversation-store.d.ts +0 -1
  117. package/dist/types/sdk/bus/daemon-paths.d.ts +6 -0
  118. package/dist/types/sdk/bus/discord-conversation.d.ts +2 -0
  119. package/dist/types/sdk/bus/discord-daemon.d.ts +17 -12
  120. package/dist/types/sdk/bus/existing-thread-readiness.d.ts +4 -34
  121. package/dist/types/sdk/bus/inbound-reaction-ordering.d.ts +61 -0
  122. package/dist/types/sdk/bus/index.d.ts +85 -99
  123. package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +29 -7
  124. package/dist/types/sdk/bus/managed-daemon.d.ts +2 -32
  125. package/dist/types/sdk/bus/notification-service.d.ts +52 -0
  126. package/dist/types/sdk/bus/operator-runtime.d.ts +1 -1
  127. package/dist/types/sdk/bus/prompt-reconciliation.d.ts +16 -5
  128. package/dist/types/sdk/bus/reconciliation-store.d.ts +113 -5
  129. package/dist/types/sdk/bus/session-control.d.ts +25 -1
  130. package/dist/types/sdk/bus/slack-conversation.d.ts +4 -0
  131. package/dist/types/sdk/bus/slack-daemon.d.ts +9 -17
  132. package/dist/types/sdk/bus/slack-live-provider.d.ts +3 -1
  133. package/dist/types/sdk/bus/slack-provider.d.ts +4 -0
  134. package/dist/types/sdk/bus/slack-thread-binding.d.ts +6 -40
  135. package/dist/types/sdk/bus/telegram-adoption-intent.d.ts +30 -104
  136. package/dist/types/sdk/bus/telegram-daemon-cli.d.ts +10 -0
  137. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +262 -19
  138. package/dist/types/sdk/bus/telegram-daemon-orphan-reap.d.ts +125 -0
  139. package/dist/types/sdk/bus/telegram-daemon-owner-registry.d.ts +22 -0
  140. package/dist/types/sdk/bus/telegram-daemon.d.ts +119 -310
  141. package/dist/types/sdk/bus/telegram-reference.d.ts +1 -47
  142. package/dist/types/sdk/bus/threaded-render.d.ts +1 -0
  143. package/dist/types/sdk/bus/topic-registry.d.ts +33 -17
  144. package/dist/types/sdk/cli/rows.d.ts +2 -11
  145. package/dist/types/sdk/cli/session-cli.d.ts +15 -25
  146. package/dist/types/sdk/client/client.d.ts +97 -1
  147. package/dist/types/sdk/host/control/dispatch.d.ts +0 -7
  148. package/dist/types/sdk/host/control/index.d.ts +1 -1
  149. package/dist/types/sdk/host/control/operations.d.ts +18 -5
  150. package/dist/types/sdk/host/control/runtime-gate.d.ts +19 -0
  151. package/dist/types/sdk/host/host.d.ts +15 -1
  152. package/dist/types/sdk/host/query/handlers.d.ts +5 -0
  153. package/dist/types/sdk/host/reverse-leases.d.ts +1 -1
  154. package/dist/types/sdk/host/session-runtime.d.ts +127 -7
  155. package/dist/types/sdk/host/types.d.ts +1 -1
  156. package/dist/types/sdk/host/websocket-transport.d.ts +1 -1
  157. package/dist/types/sdk/index.d.ts +2 -1
  158. package/dist/types/sdk/lifecycle/broker-client.d.ts +8 -0
  159. package/dist/types/sdk/lifecycle/client.d.ts +59 -0
  160. package/dist/types/sdk/lifecycle/index.d.ts +3 -0
  161. package/dist/types/sdk/lifecycle/service.d.ts +232 -0
  162. package/dist/types/sdk/mcp/server.d.ts +9 -6
  163. package/dist/types/sdk/prompt-deadline-lease.d.ts +43 -0
  164. package/dist/types/sdk/prompt-deadline-manager.d.ts +28 -0
  165. package/dist/types/sdk/prompt-status.d.ts +10 -3
  166. package/dist/types/sdk/protocol/operation-registry.d.ts +5 -0
  167. package/dist/types/sdk/receipt-state.d.ts +17 -0
  168. package/dist/types/sdk/reconciliation-extensions.d.ts +2 -0
  169. package/dist/types/sdk/router/index.d.ts +1 -0
  170. package/dist/types/sdk/router/session-router.d.ts +152 -0
  171. package/dist/types/sdk/session-list.d.ts +22 -0
  172. package/dist/types/sdk/session-reconnect.d.ts +43 -1
  173. package/dist/types/sdk/session.d.ts +34 -1
  174. package/dist/types/sdk/transport/serve-cli.d.ts +1 -4
  175. package/dist/types/session/account-inventory.d.ts +86 -0
  176. package/dist/types/session/agent-session.d.ts +145 -6
  177. package/dist/types/session/agent-storage.d.ts +10 -0
  178. package/dist/types/session/coordinator-tool-label.d.ts +28 -0
  179. package/dist/types/session/internal/managed-session-storage.d.ts +23 -4
  180. package/dist/types/session/messages.d.ts +1 -1
  181. package/dist/types/session/secure-token-file.d.ts +3 -0
  182. package/dist/types/session/session-manager.d.ts +40 -1
  183. package/dist/types/session/startup-auth-config.d.ts +44 -0
  184. package/dist/types/session/terminal-abort.d.ts +378 -0
  185. package/dist/types/session/yield-queue.d.ts +7 -0
  186. package/dist/types/session-import/claude.d.ts +26 -0
  187. package/dist/types/session-import/codex.d.ts +88 -0
  188. package/dist/types/session-import/command.d.ts +35 -0
  189. package/dist/types/session-import/detect.d.ts +22 -0
  190. package/dist/types/session-import/index.d.ts +7 -0
  191. package/dist/types/session-import/provider-codex.d.ts +22 -0
  192. package/dist/types/session-import/provider-service.d.ts +38 -0
  193. package/dist/types/session-import/redact.d.ts +23 -0
  194. package/dist/types/session-import/service.d.ts +47 -0
  195. package/dist/types/session-import/types.d.ts +120 -0
  196. package/dist/types/setup/paseo/check.d.ts +16 -0
  197. package/dist/types/setup/paseo/install-saga.d.ts +115 -0
  198. package/dist/types/setup/paseo/json-publisher.d.ts +76 -0
  199. package/dist/types/setup/paseo/orchestration-preferences.d.ts +24 -0
  200. package/dist/types/setup/paseo/paseo-ownership.d.ts +87 -0
  201. package/dist/types/setup/paseo/paseo-setup.d.ts +29 -0
  202. package/dist/types/setup/paseo/provider-config.d.ts +35 -0
  203. package/dist/types/setup/paseo/remove.d.ts +14 -0
  204. package/dist/types/setup/paseo/result-types.d.ts +59 -0
  205. package/dist/types/setup/paseo/setup-deps.d.ts +73 -0
  206. package/dist/types/setup/paseo/skills-bridge.d.ts +44 -0
  207. package/dist/types/skill-state/active-state.d.ts +5 -1
  208. package/dist/types/slash-commands/acp-builtins.d.ts +5 -1
  209. package/dist/types/slash-commands/builtin-registry.d.ts +2 -0
  210. package/dist/types/slash-commands/helpers/credential-switch.d.ts +12 -0
  211. package/dist/types/slash-commands/helpers/usage-report.d.ts +5 -6
  212. package/dist/types/slash-commands/types.d.ts +7 -1
  213. package/dist/types/task/executor.d.ts +10 -0
  214. package/dist/types/task/index.d.ts +3 -1
  215. package/dist/types/tools/ask-answer-registry.d.ts +6 -3
  216. package/dist/types/tools/bash-sleep-advisory.d.ts +14 -0
  217. package/dist/types/tools/bash.d.ts +2 -6
  218. package/dist/types/tools/browser/attach.d.ts +11 -0
  219. package/dist/types/tools/browser/launch.d.ts +20 -0
  220. package/dist/types/tools/browser/profile-discovery.d.ts +6 -0
  221. package/dist/types/tools/browser/render.d.ts +1 -0
  222. package/dist/types/tools/browser.d.ts +3 -1
  223. package/dist/types/tools/image-gen.d.ts +9 -2
  224. package/dist/types/tools/index.d.ts +8 -0
  225. package/dist/types/tools/monitor.d.ts +1 -1
  226. package/dist/types/tools/skill-discovery.d.ts +8 -1
  227. package/dist/types/tools/subagent.d.ts +2 -0
  228. package/dist/types/tools/ultragoal-ask-guard.d.ts +2 -2
  229. package/dist/types/utils/herdr-pane.d.ts +76 -0
  230. package/package.json +19 -9
  231. package/scripts/build-binary.ts +2 -1
  232. package/scripts/build-sdk-package-smoke.ts +2 -13
  233. package/scripts/capture-sticky-viewport-showcase.ts +0 -1
  234. package/scripts/compile-args.ts +2 -0
  235. package/scripts/generate-sdk-adapter-parity-manifest.ts +31 -16
  236. package/scripts/generate-sdk-operation-inventory.ts +28 -0
  237. package/scripts/generate-telegram-baseline-manifest.ts +1 -0
  238. package/scripts/generate-tool-catalog.ts +6 -4
  239. package/scripts/verify-gjc-sdk-canonicalization.ts +5 -39
  240. package/src/async/job-manager.ts +352 -17
  241. package/src/async/support.ts +25 -0
  242. package/src/autoresearch/dashboard.ts +28 -13
  243. package/src/capability/index.ts +3 -1
  244. package/src/capability/mcp.ts +6 -0
  245. package/src/capability/types.ts +6 -0
  246. package/src/cli/accounts-cli.ts +395 -0
  247. package/src/cli/args.ts +23 -0
  248. package/src/cli/auth-broker-cli.ts +136 -66
  249. package/src/cli/auth-gateway-cli.ts +94 -70
  250. package/src/cli/config-cli.ts +27 -2
  251. package/src/cli/crash-cli.ts +78 -0
  252. package/src/cli/customize-doctor.ts +1605 -0
  253. package/src/cli/daemon-cli.ts +12 -3
  254. package/src/cli/fast-help.ts +1 -0
  255. package/src/cli/mcp-cli.ts +128 -60
  256. package/src/cli/notify-cli.ts +8 -14
  257. package/src/cli/root-flags.ts +8 -0
  258. package/src/cli/setup-cli.ts +145 -0
  259. package/src/cli/skills-cli.ts +38 -2
  260. package/src/cli/update-cli.ts +167 -12
  261. package/src/cli.ts +4 -0
  262. package/src/commands/accounts.ts +71 -0
  263. package/src/commands/crash.ts +35 -0
  264. package/src/commands/customize.ts +84 -0
  265. package/src/commands/daemon.ts +2 -2
  266. package/src/commands/deep-interview.ts +2 -0
  267. package/src/commands/launch.ts +1 -0
  268. package/src/commands/mcp.ts +12 -7
  269. package/src/commands/ralplan.ts +2 -0
  270. package/src/commands/sdk.ts +65 -32
  271. package/src/commands/setup.ts +5 -0
  272. package/src/commands/skills.ts +14 -4
  273. package/src/commands/ultragoal.ts +10 -1
  274. package/src/commands/update.ts +26 -15
  275. package/src/config/atomic-yaml-patch-worker.ts +57 -0
  276. package/src/config/atomic-yaml-patch.ts +769 -29
  277. package/src/config/config-schema-version.ts +10 -0
  278. package/src/config/file-lock.ts +70 -1
  279. package/src/config/mcp-schema.json +52 -14
  280. package/src/config/model-profile-activation.ts +20 -1
  281. package/src/config/model-profiles.ts +29 -19
  282. package/src/config/model-registry.ts +132 -21
  283. package/src/config/models-config-schema.ts +1 -1
  284. package/src/config/settings-schema.ts +76 -6
  285. package/src/config/settings.ts +4038 -199
  286. package/src/config/skill-settings-defaults.ts +41 -3
  287. package/src/config/task-delegation.ts +87 -0
  288. package/src/config/update-channel.ts +23 -0
  289. package/src/coordinator-mcp/server.ts +377 -308
  290. package/src/crash/index-store.ts +723 -0
  291. package/src/crash/nudge.ts +89 -0
  292. package/src/crash/record-loader.ts +149 -0
  293. package/src/crash/report.ts +551 -0
  294. package/src/crash/sanitize.ts +129 -0
  295. package/src/cursor.ts +36 -10
  296. package/src/customization/import.ts +946 -0
  297. package/src/customization/index.ts +4 -0
  298. package/src/customization/inventory.ts +335 -0
  299. package/src/customization/mutations.ts +141 -0
  300. package/src/customization/types.ts +223 -0
  301. package/src/daemon/control-types.ts +8 -1
  302. package/src/daemon/operator-contract.ts +6 -6
  303. package/src/defaults/gjc/skills/deep-interview/SKILL.md +11 -22
  304. package/src/defaults/gjc/skills/ralplan/SKILL.md +36 -23
  305. package/src/defaults/gjc/skills/ultragoal/SKILL.md +16 -0
  306. package/src/discovery/claude-hooks.ts +38 -0
  307. package/src/discovery/claude.ts +142 -209
  308. package/src/discovery/codex-hooks.ts +38 -0
  309. package/src/discovery/codex.ts +132 -198
  310. package/src/discovery/helpers.ts +8 -1
  311. package/src/discovery/index.ts +2 -0
  312. package/src/discovery/mcp-compat.ts +234 -0
  313. package/src/discovery/mcp-json.ts +6 -0
  314. package/src/edit/renderer.ts +40 -0
  315. package/src/edit/streaming.ts +4 -2
  316. package/src/exec/bash-executor.ts +24 -20
  317. package/src/export/html/index.ts +51 -2
  318. package/src/extensibility/extensions/loader.ts +9 -1
  319. package/src/extensibility/extensions/runner.ts +17 -4
  320. package/src/extensibility/extensions/types.ts +31 -6
  321. package/src/extensibility/gjc-plugins/constrained-hooks.ts +33 -0
  322. package/src/extensibility/gjc-plugins/installer.ts +9 -5
  323. package/src/extensibility/gjc-plugins/observability.ts +8 -2
  324. package/src/extensibility/gjc-plugins/registry.ts +13 -2
  325. package/src/extensibility/gjc-plugins/runtime-adapters.ts +3 -1
  326. package/src/extensibility/gjc-plugins/schema.ts +222 -39
  327. package/src/extensibility/hooks/loader.ts +154 -10
  328. package/src/extensibility/runtime-skill-discovery.ts +257 -60
  329. package/src/extensibility/skill-management.ts +368 -0
  330. package/src/extensibility/skills.ts +52 -16
  331. package/src/gjc-runtime/deep-interview-runtime.ts +45 -61
  332. package/src/gjc-runtime/launch-worktree.ts +56 -2
  333. package/src/gjc-runtime/linux-proc.ts +7 -1
  334. package/src/gjc-runtime/ralplan-runtime.ts +100 -164
  335. package/src/gjc-runtime/session-state-lock.ts +992 -0
  336. package/src/gjc-runtime/session-state-sidecar.ts +644 -142
  337. package/src/gjc-runtime/state-writer.ts +39 -14
  338. package/src/gjc-runtime/tmux-owner-isolation.ts +5 -4
  339. package/src/gjc-runtime/ultragoal-guard.ts +11 -4
  340. package/src/gjc-runtime/ultragoal-runtime.ts +44 -41
  341. package/src/gjc-runtime/workflow-settings.ts +596 -0
  342. package/src/goals/tools/goal-tool.ts +6 -1
  343. package/src/hooks/events.ts +291 -0
  344. package/src/hooks/native-skill-hook.ts +4 -0
  345. package/src/hooks/normalize.ts +369 -0
  346. package/src/hooks/skill-state.ts +165 -46
  347. package/src/internal-urls/docs-index.generated.ts +40 -32
  348. package/src/main.ts +32 -5
  349. package/src/migrate/mcp-mapper.ts +25 -2
  350. package/src/modes/acp/abort-scope.ts +29 -0
  351. package/src/modes/acp/acp-agent.ts +423 -98
  352. package/src/modes/components/assistant-message.ts +6 -1
  353. package/src/modes/components/customization/customization-dashboard.ts +443 -0
  354. package/src/modes/components/customization/import-wizard.ts +372 -0
  355. package/src/modes/components/customization/index.ts +1 -0
  356. package/src/modes/components/gajae-pet-widget.ts +539 -213
  357. package/src/modes/components/irc-sidebar.ts +11 -0
  358. package/src/modes/components/iterm-pet-transport.ts +585 -0
  359. package/src/modes/components/oauth-selector.ts +277 -86
  360. package/src/modes/components/pet-capability.ts +39 -40
  361. package/src/modes/components/settings-selector.ts +9 -0
  362. package/src/modes/components/status-line/gh.ts +45 -1
  363. package/src/modes/components/status-line/segments.ts +16 -1
  364. package/src/modes/components/tool-status-header.ts +13 -3
  365. package/src/modes/controllers/command-controller.ts +20 -8
  366. package/src/modes/controllers/extension-ui-controller.ts +56 -257
  367. package/src/modes/controllers/input-controller.ts +10 -0
  368. package/src/modes/controllers/runtime-mcp-command-controller.ts +16 -3
  369. package/src/modes/controllers/selector-controller.ts +177 -72
  370. package/src/modes/controllers/stt-controller.ts +3 -3
  371. package/src/modes/interactive-mode.ts +88 -16
  372. package/src/modes/print-mode.ts +35 -6
  373. package/src/modes/runtime-init.ts +21 -68
  374. package/src/modes/types.ts +1 -0
  375. package/src/modes/utils/injected-user-submission.ts +25 -0
  376. package/src/modes/utils/terminal-bell.ts +15 -1
  377. package/src/prompts/agent-fragments/ralplan-persistence.md +1 -1
  378. package/src/prompts/agent-fragments/restricted-bash.md +1 -1
  379. package/src/prompts/agents/critic.md +1 -1
  380. package/src/prompts/system/rlm-research.md +1 -1
  381. package/src/prompts/system/system-prompt.md +0 -2
  382. package/src/prompts/tools/bash.md +7 -1
  383. package/src/prompts/tools/browser.md +1 -1
  384. package/src/prompts/tools/cron.md +6 -6
  385. package/src/prompts/tools/read.md +0 -2
  386. package/src/prompts/tools/skill-discovery.md +4 -2
  387. package/src/runtime-mcp/client.ts +427 -23
  388. package/src/runtime-mcp/config.ts +37 -5
  389. package/src/runtime-mcp/manager-pool.test.ts +56 -0
  390. package/src/runtime-mcp/manager.ts +52 -2
  391. package/src/runtime-mcp/oauth-discovery.ts +13 -0
  392. package/src/runtime-mcp/oauth-flow.ts +46 -1
  393. package/src/runtime-mcp/pool-key.ts +5 -1
  394. package/src/runtime-mcp/pool.test.ts +9 -0
  395. package/src/runtime-mcp/protocol.test.ts +353 -0
  396. package/src/runtime-mcp/protocol.ts +624 -0
  397. package/src/runtime-mcp/scope-config.ts +78 -0
  398. package/src/runtime-mcp/tool-bridge.ts +44 -10
  399. package/src/runtime-mcp/transports/http.ts +84 -13
  400. package/src/runtime-mcp/types.ts +123 -12
  401. package/src/sdk/acp/adapter.ts +328 -97
  402. package/src/sdk/broker/broker.ts +160 -741
  403. package/src/sdk/broker/ensure.ts +9 -1
  404. package/src/sdk/broker/lifecycle.ts +510 -116
  405. package/src/sdk/broker/operation-receipt-ledger.ts +11 -2
  406. package/src/sdk/broker/process-incarnation.ts +19 -0
  407. package/src/sdk/broker/session-index.ts +516 -117
  408. package/src/sdk/broker/startup-failure.ts +28 -5
  409. package/src/sdk/broker/transport.ts +1 -13
  410. package/src/sdk/bus/chat-daemon-cli.ts +4 -2
  411. package/src/sdk/bus/chat-daemon-control.ts +67 -6
  412. package/src/sdk/bus/chat-daemon-runtime.ts +183 -859
  413. package/src/sdk/bus/config.ts +13 -0
  414. package/src/sdk/bus/conversation-store.ts +59 -171
  415. package/src/sdk/bus/daemon-paths.ts +20 -0
  416. package/src/sdk/bus/discord-conversation.ts +2 -0
  417. package/src/sdk/bus/discord-daemon.ts +524 -126
  418. package/src/sdk/bus/discord-live-provider.ts +206 -79
  419. package/src/sdk/bus/existing-thread-readiness.ts +4 -97
  420. package/src/sdk/bus/inbound-reaction-ordering.ts +122 -0
  421. package/src/sdk/bus/index.ts +2480 -456
  422. package/src/sdk/bus/kind-aware-reconciliation.ts +204 -34
  423. package/src/sdk/bus/lifecycle-commands.ts +2 -2
  424. package/src/sdk/bus/managed-daemon.ts +2 -145
  425. package/src/sdk/bus/notification-service.ts +196 -0
  426. package/src/sdk/bus/operator-runtime.ts +1 -1
  427. package/src/sdk/bus/prompt-reconciliation.ts +24 -15
  428. package/src/sdk/bus/reconciliation-store.ts +553 -24
  429. package/src/sdk/bus/session-control.ts +49 -3
  430. package/src/sdk/bus/slack-conversation.ts +4 -0
  431. package/src/sdk/bus/slack-daemon.ts +733 -134
  432. package/src/sdk/bus/slack-live-provider.ts +65 -15
  433. package/src/sdk/bus/slack-provider.ts +4 -0
  434. package/src/sdk/bus/slack-thread-binding.ts +9 -104
  435. package/src/sdk/bus/telegram-adoption-intent.ts +299 -209
  436. package/src/sdk/bus/telegram-daemon-cli.ts +194 -7
  437. package/src/sdk/bus/telegram-daemon-contract.ts +265 -19
  438. package/src/sdk/bus/telegram-daemon-control.ts +3 -13
  439. package/src/sdk/bus/telegram-daemon-orphan-reap.ts +498 -0
  440. package/src/sdk/bus/telegram-daemon-owner-registry.ts +176 -0
  441. package/src/sdk/bus/telegram-daemon.ts +2552 -2280
  442. package/src/sdk/bus/telegram-reference.ts +1 -226
  443. package/src/sdk/bus/telegram-setup.ts +2 -2
  444. package/src/sdk/bus/threaded-render.ts +1 -0
  445. package/src/sdk/bus/topic-registry.ts +279 -146
  446. package/src/sdk/cli/rows.ts +2 -35
  447. package/src/sdk/cli/session-cli.ts +776 -700
  448. package/src/sdk/client/client.ts +892 -1
  449. package/src/sdk/host/control/dispatch.ts +93 -58
  450. package/src/sdk/host/control/index.ts +1 -1
  451. package/src/sdk/host/control/operations.ts +18 -10
  452. package/src/sdk/host/control/runtime-gate.ts +40 -0
  453. package/src/sdk/host/host.ts +63 -12
  454. package/src/sdk/host/query/handlers.ts +66 -7
  455. package/src/sdk/host/reverse-leases.ts +2 -2
  456. package/src/sdk/host/sdk-surface-parity.test.ts +1 -1
  457. package/src/sdk/host/session-runtime.test.ts +2787 -34
  458. package/src/sdk/host/session-runtime.ts +1489 -101
  459. package/src/sdk/host/surface-policy.ts +12 -8
  460. package/src/sdk/host/types.ts +1 -1
  461. package/src/sdk/host/websocket-transport.lifecycle.test.ts +31 -59
  462. package/src/sdk/host/websocket-transport.ts +85 -50
  463. package/src/sdk/index.ts +2 -1
  464. package/src/sdk/lifecycle/broker-client.ts +53 -0
  465. package/src/sdk/lifecycle/client.ts +234 -0
  466. package/src/sdk/lifecycle/index.ts +3 -0
  467. package/src/sdk/{bus/recent-activity.ts → lifecycle/recent-sessions.ts} +5 -2
  468. package/src/sdk/lifecycle/service.ts +720 -0
  469. package/src/sdk/mcp/server.ts +226 -188
  470. package/src/sdk/prompt-deadline-lease.ts +55 -0
  471. package/src/sdk/prompt-deadline-manager.ts +148 -0
  472. package/src/sdk/prompt-status.ts +11 -3
  473. package/src/sdk/protocol/operation-inventory.generated.json +272 -129
  474. package/src/sdk/protocol/operation-registry.ts +71 -8
  475. package/src/sdk/receipt-state.ts +43 -0
  476. package/src/sdk/reconciliation-extensions.ts +14 -0
  477. package/src/sdk/router/index.ts +1 -0
  478. package/src/sdk/router/session-router.ts +1658 -0
  479. package/src/sdk/session-list.ts +93 -0
  480. package/src/sdk/session-reconnect.ts +45 -1
  481. package/src/sdk/session.ts +716 -120
  482. package/src/sdk/transport/serve-cli.ts +18 -34
  483. package/src/session/account-inventory.ts +603 -0
  484. package/src/session/agent-session.ts +2857 -582
  485. package/src/session/agent-storage.ts +35 -0
  486. package/src/session/blob-store.ts +32 -1
  487. package/src/session/coordinator-tool-label.ts +40 -0
  488. package/src/session/internal/managed-session-scope.ts +4 -0
  489. package/src/session/internal/managed-session-storage.ts +173 -12
  490. package/src/session/messages.ts +1 -1
  491. package/src/session/secure-token-file.ts +80 -0
  492. package/src/session/session-manager.ts +730 -58
  493. package/src/session/session-storage.ts +25 -16
  494. package/src/session/startup-auth-config.ts +297 -0
  495. package/src/session/terminal-abort.ts +1253 -0
  496. package/src/session/yield-queue.ts +57 -15
  497. package/src/session-import/claude.ts +334 -0
  498. package/src/session-import/codex.ts +1033 -0
  499. package/src/session-import/command.ts +77 -0
  500. package/src/session-import/detect.ts +133 -0
  501. package/src/session-import/index.ts +7 -0
  502. package/src/session-import/provider-codex.ts +327 -0
  503. package/src/session-import/provider-service.ts +457 -0
  504. package/src/session-import/redact.ts +128 -0
  505. package/src/session-import/service.ts +1264 -0
  506. package/src/session-import/types.ts +148 -0
  507. package/src/setup/paseo/check.ts +213 -0
  508. package/src/setup/paseo/install-saga.ts +293 -0
  509. package/src/setup/paseo/json-publisher.ts +263 -0
  510. package/src/setup/paseo/orchestration-preferences.ts +86 -0
  511. package/src/setup/paseo/paseo-ownership.ts +224 -0
  512. package/src/setup/paseo/paseo-setup.ts +253 -0
  513. package/src/setup/paseo/provider-config.ts +139 -0
  514. package/src/setup/paseo/remove.ts +183 -0
  515. package/src/setup/paseo/result-types.ts +79 -0
  516. package/src/setup/paseo/setup-deps.ts +175 -0
  517. package/src/setup/paseo/skills-bridge.ts +260 -0
  518. package/src/skill-state/active-state.ts +21 -11
  519. package/src/slash-commands/acp-builtins.ts +9 -1
  520. package/src/slash-commands/builtin-registry.ts +98 -16
  521. package/src/slash-commands/helpers/credential-switch.ts +143 -0
  522. package/src/slash-commands/helpers/mcp.ts +9 -3
  523. package/src/slash-commands/helpers/usage-report.ts +61 -56
  524. package/src/slash-commands/types.ts +7 -2
  525. package/src/task/executor.ts +30 -11
  526. package/src/task/index.ts +66 -7
  527. package/src/task/render.ts +23 -9
  528. package/src/tools/ask-answer-registry.ts +23 -7
  529. package/src/tools/ask.ts +8 -4
  530. package/src/tools/bash-sleep-advisory.ts +115 -0
  531. package/src/tools/bash.ts +98 -18
  532. package/src/tools/browser/attach.ts +71 -3
  533. package/src/tools/browser/launch.ts +86 -13
  534. package/src/tools/browser/profile-discovery.ts +57 -7
  535. package/src/tools/browser/render.ts +8 -1
  536. package/src/tools/browser.ts +130 -21
  537. package/src/tools/computer.enforcement.test.ts +1 -1
  538. package/src/tools/computer.ts +3 -2
  539. package/src/tools/cron.ts +12 -1
  540. package/src/tools/image-gen.ts +27 -16
  541. package/src/tools/index.ts +8 -0
  542. package/src/tools/job.ts +33 -6
  543. package/src/tools/monitor.ts +41 -2
  544. package/src/tools/skill-discovery.ts +21 -29
  545. package/src/tools/subagent.ts +142 -24
  546. package/src/tools/tool-catalog.generated.ts +6 -6
  547. package/src/tools/ultragoal-ask-guard.ts +10 -3
  548. package/src/utils/herdr-pane.ts +345 -0
  549. package/src/utils/title-generator.ts +2 -0
  550. package/src/web/scrapers/index.ts +6 -4
  551. package/dist/types/cli/malloc-env-guard.test.d.ts +0 -1
  552. package/dist/types/defaults/gjc-defaults.test.d.ts +0 -1
  553. package/dist/types/memory-backend/lazy-loading.test.d.ts +0 -1
  554. package/dist/types/runtime/boot-ordering.test.d.ts +0 -1
  555. package/dist/types/runtime/lazy-service.test.d.ts +0 -1
  556. package/dist/types/runtime/network-prewarm-service.test.d.ts +0 -1
  557. package/dist/types/runtime/workspace-tree-service.test.d.ts +0 -1
  558. package/dist/types/runtime-mcp/config.test.d.ts +0 -1
  559. package/dist/types/runtime-mcp/http.test.d.ts +0 -1
  560. package/dist/types/runtime-mcp/manager-pool.test.d.ts +0 -1
  561. package/dist/types/runtime-mcp/pool-key.test.d.ts +0 -1
  562. package/dist/types/runtime-mcp/pool.test.d.ts +0 -1
  563. package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +0 -117
  564. package/dist/types/sdk/bus/lifecycle-orchestrator.d.ts +0 -141
  565. package/dist/types/sdk/bus/telegram-cli.d.ts +0 -31
  566. package/dist/types/sdk/elevation/allowlist.d.ts +0 -20
  567. package/dist/types/sdk/elevation/audit.d.ts +0 -93
  568. package/dist/types/sdk/elevation/capability.d.ts +0 -3
  569. package/dist/types/sdk/elevation/digest.d.ts +0 -72
  570. package/dist/types/sdk/elevation/dispatch-receipt.d.ts +0 -85
  571. package/dist/types/sdk/elevation/grant-ledger.d.ts +0 -163
  572. package/dist/types/sdk/elevation/owner.d.ts +0 -48
  573. package/dist/types/sdk/host/import-graph.test.d.ts +0 -1
  574. package/dist/types/sdk/host/sdk-surface-parity.test.d.ts +0 -1
  575. package/dist/types/sdk/host/session-runtime.test.d.ts +0 -1
  576. package/dist/types/sdk/host/websocket-transport.lifecycle.test.d.ts +0 -1
  577. package/dist/types/session/auth-broker-config.d.ts +0 -13
  578. package/dist/types/session/heap-eviction-artifacts.test.d.ts +0 -1
  579. package/dist/types/skills/skills.test.d.ts +0 -1
  580. package/dist/types/slash-commands/notify-command.test.d.ts +0 -1
  581. package/dist/types/task/token-log.test.d.ts +0 -1
  582. package/dist/types/tools/computer.enforcement.test.d.ts +0 -1
  583. package/dist/types/tools/descriptors.test.d.ts +0 -1
  584. package/scripts/g005-daemon-smoke.ts +0 -180
  585. package/scripts/g011-daemon-path-smoke.ts +0 -153
  586. package/src/sdk/bus/lifecycle-control-runtime.ts +0 -1733
  587. package/src/sdk/bus/lifecycle-orchestrator.ts +0 -489
  588. package/src/sdk/bus/telegram-cli.ts +0 -212
  589. package/src/sdk/elevation/allowlist.ts +0 -54
  590. package/src/sdk/elevation/audit.ts +0 -208
  591. package/src/sdk/elevation/capability.ts +0 -41
  592. package/src/sdk/elevation/digest.ts +0 -129
  593. package/src/sdk/elevation/dispatch-receipt.ts +0 -184
  594. package/src/sdk/elevation/grant-ledger.ts +0 -1142
  595. package/src/sdk/elevation/owner.ts +0 -109
  596. package/src/session/auth-broker-config.ts +0 -109
  597. /package/dist/types/{ai-core-import-gate.test.d.ts → discovery/claude-hooks.d.ts} +0 -0
  598. /package/dist/types/{cli/fixture-report.test.d.ts → discovery/codex-hooks.d.ts} +0 -0
  599. /package/dist/types/sdk/{bus/recent-activity.d.ts → lifecycle/recent-sessions.d.ts} +0 -0
@@ -1,7 +1,17 @@
1
1
  import { type RunGh, runGhDefault } from "../../../utils/gh";
2
2
 
3
3
  const STATUS_LINE_GH_TIMEOUT_MS = 5_000;
4
+ const STATUS_LINE_PR_CACHE_TTL_MS = 60_000;
4
5
  const C0_C1_CONTROL_CHARACTERS = /[\u0000-\u001f\u007f-\u009f]/;
6
+ type CurrentPr = { number: number; url: string } | null;
7
+
8
+ interface PrCacheEntry {
9
+ value: CurrentPr;
10
+ expiresAt: number;
11
+ }
12
+
13
+ const prCache = new Map<string, PrCacheEntry>();
14
+ const prLookupsInFlight = new Map<string, Promise<CurrentPr>>();
5
15
 
6
16
  function canonicalPrUrl(value: unknown, number: number): string | null {
7
17
  if (typeof value !== "string" || C0_C1_CONTROL_CHARACTERS.test(value)) return null;
@@ -22,7 +32,7 @@ function canonicalPrUrl(value: unknown, number: number): string | null {
22
32
  }
23
33
  }
24
34
 
25
- export async function lookupCurrentPr(runGh: RunGh = runGhDefault): Promise<{ number: number; url: string } | null> {
35
+ export async function lookupCurrentPr(runGh: RunGh = runGhDefault): Promise<CurrentPr> {
26
36
  try {
27
37
  const result = await runGh(["pr", "view", "--json", "number,url"], { timeoutMs: STATUS_LINE_GH_TIMEOUT_MS });
28
38
  if (result.exitCode !== 0 || result.timedOut) return null;
@@ -35,3 +45,37 @@ export async function lookupCurrentPr(runGh: RunGh = runGhDefault): Promise<{ nu
35
45
  return null;
36
46
  }
37
47
  }
48
+
49
+ export function lookupCurrentPrCached(
50
+ cacheKey: string,
51
+ runGh: RunGh = runGhDefault,
52
+ now: () => number = Date.now,
53
+ ): Promise<CurrentPr> {
54
+ const cached = prCache.get(cacheKey);
55
+ if (cached && cached.expiresAt > now()) return Promise.resolve(cached.value);
56
+
57
+ const inFlight = prLookupsInFlight.get(cacheKey);
58
+ if (inFlight) return inFlight;
59
+
60
+ const lookup = lookupCurrentPr(runGh)
61
+ .then(value => {
62
+ // Bound process-lifetime memory: drop every expired entry on insert so
63
+ // the map holds only keys seen within one TTL window.
64
+ const timestamp = now();
65
+ for (const [key, entry] of prCache) {
66
+ if (entry.expiresAt <= timestamp) prCache.delete(key);
67
+ }
68
+ prCache.set(cacheKey, { value, expiresAt: timestamp + STATUS_LINE_PR_CACHE_TTL_MS });
69
+ return value;
70
+ })
71
+ .finally(() => {
72
+ if (prLookupsInFlight.get(cacheKey) === lookup) prLookupsInFlight.delete(cacheKey);
73
+ });
74
+ prLookupsInFlight.set(cacheKey, lookup);
75
+ return lookup;
76
+ }
77
+
78
+ export function clearCurrentPrCache(): void {
79
+ prCache.clear();
80
+ prLookupsInFlight.clear();
81
+ }
@@ -21,7 +21,7 @@ function withIcon(icon: string, text: string): string {
21
21
  }
22
22
 
23
23
  function stripDisplayRoot(pwd: string): string {
24
- for (const root of ["/work", path.join(os.homedir(), "Projects")]) {
24
+ for (const root of displayRoots()) {
25
25
  const relative = relativePathWithinRoot(root, pwd);
26
26
  if (relative) return relative;
27
27
  }
@@ -32,6 +32,14 @@ function normalizePremiumRequests(value: number): number {
32
32
  return Math.round((value + Number.EPSILON) * 100) / 100;
33
33
  }
34
34
 
35
+ // Display roots take precedence over scratch classification: ~/Projects and
36
+ // /work are deliberate workspaces, never scratch, even when the home directory
37
+ // itself sits under a temp/scratch root (CI harnesses and containers redirect
38
+ // HOME beneath the OS temp dir). Resolved at render time so a preload-rewritten
39
+ // HOME is honored, matching scratchRoots().
40
+ function displayRoots(): readonly string[] {
41
+ return ["/work", path.join(os.homedir(), "Projects")];
42
+ }
35
43
  function scratchRoots(): readonly string[] {
36
44
  const roots = new Set<string>([os.tmpdir(), path.join(os.homedir(), "tmp")]);
37
45
  if (process.platform === "win32") {
@@ -51,6 +59,13 @@ function scratchRoots(): readonly string[] {
51
59
  }
52
60
 
53
61
  function classifyProjectDir(pwd: string): { scratch: boolean; relative: string | null } {
62
+ // A deliberate display root wins over scratch ancestry: ~/Projects is a
63
+ // workspace even when HOME itself sits under the OS temp dir (CI and test
64
+ // harnesses redirect HOME beneath the scratch root). This is more precise
65
+ // than exempting all of HOME: ~/tmp stays scratch (it is in scratchRoots).
66
+ for (const root of displayRoots()) {
67
+ if (pathIsWithin(root, pwd)) return { scratch: false, relative: null };
68
+ }
54
69
  for (const root of scratchRoots()) {
55
70
  if (pathIsWithin(root, pwd)) {
56
71
  return { scratch: true, relative: relativePathWithinRoot(root, pwd) };
@@ -19,7 +19,7 @@ import type { ActionRegistry, FocusDomain } from "../action-registry";
19
19
  import { EMPTY_JOBS_SNAPSHOT, type JobsSnapshot } from "../jobs-observer";
20
20
  import { sanitizeStatusText } from "../shared";
21
21
  import { renderSkillHudBar } from "./skill-hud/render";
22
- import { lookupCurrentPr } from "./status-line/gh";
22
+ import { lookupCurrentPrCached } from "./status-line/gh";
23
23
  import {
24
24
  canReuseCachedPr,
25
25
  createPrCacheContext,
@@ -399,6 +399,10 @@ export class StatusLineComponent implements Component {
399
399
 
400
400
  this.#prLookupInFlight = true;
401
401
  const lookupContext = currentContext;
402
+ if (!lookupContext) {
403
+ this.#prLookupInFlight = false;
404
+ return stalePr ?? null;
405
+ }
402
406
 
403
407
  // Fire async lookup, keep stale value visible until resolved
404
408
  (async () => {
@@ -415,7 +419,7 @@ export class StatusLineComponent implements Component {
415
419
  };
416
420
  try {
417
421
  // Requires `gh repo set-default` to be configured; fails gracefully if not
418
- const pr = await lookupCurrentPr();
422
+ const pr = await lookupCurrentPrCached(`${lookupContext.repoId ?? ""}\0${lookupContext.branch}`);
419
423
  setCachedPr(pr);
420
424
  } finally {
421
425
  this.#prLookupInFlight = false;
@@ -579,6 +583,8 @@ export class StatusLineComponent implements Component {
579
583
  pushWindow(`${providerId ?? "provider"}:5h`, "5h", fraction, resetsAt, "m");
580
584
  } else if (windowId === "7d" && !tier) {
581
585
  pushWindow(`${providerId ?? "provider"}:7d`, "7d", fraction, resetsAt, "h");
586
+ } else if (providerId === "grok-build" && windowId === "weekly" && !tier) {
587
+ pushWindow("grok-build:weekly", "weekly", fraction, resetsAt, "h");
582
588
  }
583
589
  }
584
590
  }
@@ -620,6 +626,10 @@ export class StatusLineComponent implements Component {
620
626
  const contextPctSegmentActive =
621
627
  effectiveSettings.leftSegments.includes("context_pct") ||
622
628
  effectiveSettings.rightSegments.includes("context_pct");
629
+ // Never spawn a gh lookup when no pr segment is rendered; the pr segment
630
+ // treats a null value as hidden, so gating here is behavior-identical.
631
+ const prSegmentActive =
632
+ effectiveSettings.leftSegments.includes("pr") || effectiveSettings.rightSegments.includes("pr");
623
633
 
624
634
  return {
625
635
  session: this.session,
@@ -638,7 +648,7 @@ export class StatusLineComponent implements Component {
638
648
  git: {
639
649
  branch: this.#getCurrentBranch(),
640
650
  status: this.#getGitStatus(),
641
- pr: this.#lookupPr(),
651
+ pr: prSegmentActive ? this.#lookupPr() : null,
642
652
  },
643
653
  usage: this.#cachedUsage,
644
654
  };
@@ -1588,20 +1588,20 @@ function formatWindowSuffix(label: string, windowLabel: string, uiTheme: typeof
1588
1588
  return uiTheme.fg("dim", `(${windowLabel})`);
1589
1589
  }
1590
1590
 
1591
- function formatAccountLabel(limit: UsageLimit, report: UsageReport, index: number): string {
1591
+ function formatAccountLabel(limit: UsageLimit, report: UsageReport, reportIndex: number): string {
1592
1592
  const email = (report.metadata?.email as string | undefined) ?? limit.scope.accountId;
1593
1593
  if (email) return email;
1594
1594
  const accountId = (report.metadata?.accountId as string | undefined) ?? limit.scope.accountId;
1595
1595
  if (accountId) return accountId;
1596
- return `account ${index + 1}`;
1596
+ return `account ${reportIndex + 1}`;
1597
1597
  }
1598
1598
 
1599
- function formatUnlimitedReportLabel(report: UsageReport, index: number): string {
1599
+ function formatUnlimitedReportLabel(report: UsageReport, reportIndex: number): string {
1600
1600
  const email = report.metadata?.email as string | undefined;
1601
1601
  if (email) return email;
1602
1602
  const accountId = report.metadata?.accountId as string | undefined;
1603
1603
  if (accountId) return accountId;
1604
- return `account ${index + 1}`;
1604
+ return `account ${reportIndex + 1}`;
1605
1605
  }
1606
1606
 
1607
1607
  function formatResetShort(limit: UsageLimit, nowMs: number): string | undefined {
@@ -1614,6 +1614,7 @@ function formatResetShort(limit: UsageLimit, nowMs: number): string | undefined
1614
1614
  function formatAccountHeaderRow(
1615
1615
  limits: UsageLimit[],
1616
1616
  reports: UsageReport[],
1617
+ reportIndexes: ReadonlyMap<UsageReport, number>,
1617
1618
  nowMs: number,
1618
1619
  columnWidth: number,
1619
1620
  uiTheme: typeof theme,
@@ -1621,7 +1622,7 @@ function formatAccountHeaderRow(
1621
1622
  const parts = limits.map((limit, index) => {
1622
1623
  const reset = formatResetShort(limit, nowMs);
1623
1624
  return {
1624
- label: formatAccountLabel(limit, reports[index], index),
1625
+ label: formatAccountLabel(limit, reports[index], reportIndexes.get(reports[index]) ?? index),
1625
1626
  suffix: reset ? `(${reset})` : "",
1626
1627
  };
1627
1628
  });
@@ -1780,6 +1781,7 @@ export function renderUsageReports(
1780
1781
  for (const { provider, providerReports } of providerEntries) {
1781
1782
  lines.push("");
1782
1783
  const providerName = formatProviderName(provider);
1784
+ const reportIndexes = new Map(providerReports.map((report, index) => [report, index]));
1783
1785
 
1784
1786
  const limitGroups = new Map<
1785
1787
  string,
@@ -1811,10 +1813,13 @@ export function renderUsageReports(
1811
1813
  const rankedAccounts = providerReports
1812
1814
  .map(report => {
1813
1815
  const [firstLimit] = report.limits;
1816
+ const reportIndex = reportIndexes.get(report) ?? 0;
1814
1817
  return {
1815
1818
  report,
1816
1819
  total: report.limits.reduce((sum, limit) => sum + (resolveFraction(limit) ?? 0), 0),
1817
- label: firstLimit ? formatAccountLabel(firstLimit, report, 0) : formatUnlimitedReportLabel(report, 0),
1820
+ label: firstLimit
1821
+ ? formatAccountLabel(firstLimit, report, reportIndex)
1822
+ : formatUnlimitedReportLabel(report, reportIndex),
1818
1823
  };
1819
1824
  })
1820
1825
  .sort((a, b) => (a.total !== b.total ? b.total - a.total : a.label.localeCompare(b.label)));
@@ -1850,7 +1855,14 @@ export function renderUsageReports(
1850
1855
 
1851
1856
  const windowSuffix = formatWindowSuffix(group.label, group.windowLabel, uiTheme);
1852
1857
  lines.push(`${statusIcon} ${uiTheme.bold(group.label)} ${windowSuffix}`.trim());
1853
- const accountLabels = formatAccountHeaderRow(sortedLimits, sortedReports, nowMs, sectionColumnWidth, uiTheme);
1858
+ const accountLabels = formatAccountHeaderRow(
1859
+ sortedLimits,
1860
+ sortedReports,
1861
+ reportIndexes,
1862
+ nowMs,
1863
+ sectionColumnWidth,
1864
+ uiTheme,
1865
+ );
1854
1866
  lines.push(` ${accountLabels.join(" ")}`.trimEnd());
1855
1867
  const bars = sortedLimits.map(limit =>
1856
1868
  padColumn(renderUsageBar(limit, uiTheme, sectionColumnWidth), sectionColumnWidth),
@@ -1869,7 +1881,7 @@ export function renderUsageReports(
1869
1881
  // Render accounts with no rate limits (e.g. business/enterprise plans).
1870
1882
  const unlimitedReports = providerReports.filter(report => report.limits.length === 0);
1871
1883
  for (const report of unlimitedReports) {
1872
- const label = formatUnlimitedReportLabel(report, 0);
1884
+ const label = formatUnlimitedReportLabel(report, reportIndexes.get(report) ?? 0);
1873
1885
  const tier = report.metadata?.planType as string | undefined;
1874
1886
  const tierSuffix = tier ? ` ${uiTheme.fg("dim", `(${tier})`)}` : "";
1875
1887
  lines.push(
@@ -31,12 +31,7 @@ import { HookEditorComponent } from "../../modes/components/hook-editor";
31
31
  import { HookInputComponent } from "../../modes/components/hook-input";
32
32
  import { HookSelectorComponent } from "../../modes/components/hook-selector";
33
33
  import { getAvailableThemesWithPaths, getThemeByName, setTheme, type Theme, theme } from "../../modes/theme/theme";
34
- import {
35
- clearInteractiveActivityLoaders,
36
- type InteractiveModeContext,
37
- stopInteractiveActivityIndicator,
38
- syncInteractiveActivityIndicator,
39
- } from "../../modes/types";
34
+ import type { InteractiveModeContext } from "../../modes/types";
40
35
  import {
41
36
  parseSyntheticModelId,
42
37
  resolveSyntheticModelSelection,
@@ -48,9 +43,8 @@ import { parseThinkingLevel } from "../../thinking";
48
43
  import type { TodoPhase } from "../../tools/todo-write";
49
44
  import { setSessionTerminalTitle, setTerminalTitle } from "../../utils/title-generator";
50
45
  import { emitHostStatus } from "../utils/host-status";
51
- import { applyInjectedUserSubmission } from "../utils/injected-user-submission";
46
+ import { applyInjectedUserSubmission, extensionUserMessageContentError } from "../utils/injected-user-submission";
52
47
  import { classifyHookSelectorBellEvent, ringTerminalBell } from "../utils/terminal-bell";
53
- import { prepareTranscriptRebuild } from "../utils/ui-helpers";
54
48
 
55
49
  const MAX_WIDGET_LINES = 10;
56
50
  const HOOK_SELECTOR_CHROME_ROWS = 7;
@@ -106,6 +100,23 @@ const EXTENSION_COMMAND_MUTATIONS: ReadonlySet<PropertyKey> = new Set([
106
100
  "switchSession",
107
101
  ]);
108
102
 
103
+ const BROKER_LIFECYCLE_OPERATIONS = new Set([
104
+ "session.new",
105
+ "session.fork",
106
+ "session.resume",
107
+ "session.close",
108
+ "session.switch",
109
+ "session.branch",
110
+ "session.handoff",
111
+ "session.delete",
112
+ ]);
113
+
114
+ function prohibitBrokerLifecycleOperation(operation: string): never {
115
+ throw Object.assign(new Error(`${operation} is available only through the Broker lifecycle service.`), {
116
+ code: "operation_prohibited",
117
+ });
118
+ }
119
+
109
120
  export class ExtensionUiController {
110
121
  #extensionTerminalInputUnsubscribers = new Set<() => void>();
111
122
  #extensionErrorUnsubscribe?: () => void;
@@ -314,52 +325,8 @@ export class ExtensionUiController {
314
325
  case "retry.abort":
315
326
  session.abortRetry();
316
327
  return { aborted: true };
317
- case "session.new":
318
- return { created: await session.newSession() };
319
- case "session.fork":
320
- return { session: await session.fork() };
321
- case "session.resume":
322
- return { resumed: await session.switchSession(String(input.id)) };
323
- case "session.close":
324
- await session.sessionManager.flush();
325
- return { closed: true };
326
- case "session.switch":
327
- return { switched: await session.switchSession(String(input.id)) };
328
- case "session.branch":
329
- try {
330
- return await session.branch(String(input.entryId));
331
- } catch (error) {
332
- throw Object.assign(new Error(error instanceof Error ? error.message : "Branch entry was not found."), {
333
- code: "resource_gone",
334
- });
335
- }
336
328
  case "session.rename":
337
329
  return { renamed: await session.setSessionName(String(input.name), "user") };
338
- case "session.handoff":
339
- try {
340
- return {
341
- handoff: await session.handoff(
342
- typeof input.target === "string"
343
- ? input.target
344
- : typeof input.instructions === "string"
345
- ? input.instructions
346
- : undefined,
347
- ),
348
- };
349
- } catch (error) {
350
- const typed = error as { code?: unknown; handoffDocument?: unknown };
351
- const handoffDocument =
352
- typeof typed?.handoffDocument === "string" ? { handoffDocument: typed.handoffDocument } : undefined;
353
- // Preserve a safe typed code (e.g. transient `busy`) so clients keep
354
- // correct retry/backoff semantics; only synthesize invalid_request for
355
- // otherwise-untyped failures.
356
- const code = typed?.code === "busy" ? "busy" : "invalid_request";
357
- throw Object.assign(
358
- new Error(error instanceof Error ? error.message : "Handoff is unavailable for the current state."),
359
- { code },
360
- handoffDocument,
361
- );
362
- }
363
330
  case "session.export_html":
364
331
  try {
365
332
  return { path: await session.exportToHtml(typeof input.path === "string" ? input.path : undefined) };
@@ -426,13 +393,11 @@ export class ExtensionUiController {
426
393
  }
427
394
  return { changed: true, enabled: on };
428
395
  }
429
- case "session.delete":
430
- await session.sessionManager.dropSession(String(input.id));
431
- return { deleted: true };
432
396
  case "session.cwd.move":
433
397
  await session.sessionManager.moveTo(String(input.path));
434
398
  return { moved: true, cwd: session.sessionManager.getCwd() };
435
399
  default:
400
+ if (BROKER_LIFECYCLE_OPERATIONS.has(operation)) prohibitBrokerLifecycleOperation(operation);
436
401
  throw Object.assign(new Error(`${operation} has no AgentSession implementation.`), { code: "unavailable" });
437
402
  }
438
403
  };
@@ -531,7 +496,13 @@ export class ExtensionUiController {
531
496
  sendMessage: (message, options) => {
532
497
  const wasStreaming = this.ctx.session.isStreaming;
533
498
  this.ctx.session
534
- .sendCustomMessage(message, options)
499
+ // The extension seam is the trusted runtime boundary: extension
500
+ // producers are external to the turn's model/tool runtime, so
501
+ // nextTurn messages are classified "external" here (survive a
502
+ // terminal abort) instead of letting the extension label its
503
+ // own origin — caller-controlled origin defeats source-based
504
+ // continuation fencing (review thread P2).
505
+ .sendCustomMessage(message, { ...options, origin: "external" })
535
506
  .then(() => {
536
507
  if (!this.#isStopped()) this.#applyCustomMessageDisplay(wasStreaming, message.display);
537
508
  })
@@ -640,6 +611,13 @@ export class ExtensionUiController {
640
611
  const commandActions: ExtensionCommandContextActions = {
641
612
  getContextUsage: () => this.ctx.session.getContextUsage(),
642
613
  waitForIdle: () => this.ctx.session.agent.waitForIdle(),
614
+ newSession: async () => prohibitBrokerLifecycleOperation("session.new"),
615
+ branch: async () => prohibitBrokerLifecycleOperation("session.branch"),
616
+ navigateTree: async (targetId, navOptions) => {
617
+ const result = await this.ctx.session.navigateTree(targetId, { summarize: navOptions?.summarize });
618
+ return { cancelled: result.cancelled };
619
+ },
620
+ switchSession: async () => prohibitBrokerLifecycleOperation("session.switch"),
643
621
  reload: async () => {
644
622
  const previousSessionId = this.ctx.sessionManager.getSessionId();
645
623
  await this.ctx.session.reload();
@@ -651,105 +629,7 @@ export class ExtensionUiController {
651
629
  if (this.#isStopped()) return;
652
630
  this.ctx.showStatus("Reloaded session");
653
631
  },
654
- newSession: async options => {
655
- const cleanupPreviousSessionUi = this.captureSessionUiCleanup();
656
- const success = await this.ctx.session.newSession({ parentSession: options?.parentSession });
657
- if (!success) {
658
- return { cancelled: true };
659
- }
660
- if (this.#isStopped()) return { cancelled: true };
661
- clearInteractiveActivityLoaders(this.ctx);
662
- cleanupPreviousSessionUi();
663
-
664
- stopInteractiveActivityIndicator(this.ctx);
665
- this.ctx.resetIrcSidebarSession();
666
- setSessionTerminalTitle(this.ctx.sessionManager.getSessionName(), this.ctx.sessionManager.getCwd());
667
-
668
- if (options?.setup) {
669
- await options.setup(this.ctx.sessionManager);
670
- if (this.#isStopped()) return { cancelled: true };
671
- }
672
-
673
- this.ctx.statusLine.invalidate();
674
- this.ctx.statusLine.setSessionStartTime(Date.now());
675
- this.ctx.updateEditorTopBorder();
676
- this.ctx.ui.requestRender();
677
-
678
- prepareTranscriptRebuild(this.ctx.ui, "replace-identity");
679
- this.ctx.chatContainer.clear();
680
- this.ctx.pendingMessagesContainer.clear();
681
- this.ctx.compactionQueuedMessages = [];
682
- this.ctx.streamingComponent = undefined;
683
- this.ctx.streamingMessage = undefined;
684
- this.ctx.pendingTools.clear();
685
-
686
- this.ctx.chatContainer.addChild(
687
- new Text(`${theme.fg("accent", `${theme.status.success} New session started`)}`, 1, 0),
688
- );
689
- await this.ctx.reloadTodos();
690
- if (this.#isStopped()) return { cancelled: true };
691
- this.ctx.ui.requestRender();
692
-
693
- return { cancelled: false };
694
- },
695
- branch: async entryId => {
696
- const result = await this.ctx.session.branch(entryId);
697
- if (this.#isStopped()) return { cancelled: true };
698
- if (result.cancelled) {
699
- return { cancelled: true };
700
- }
701
- this.ctx.resetIrcSidebarSession();
702
-
703
- // Update UI
704
- this.ctx.rebuildInitialMessages("replace-identity");
705
- await this.ctx.reloadTodos();
706
- if (this.#isStopped()) return { cancelled: true };
707
- this.ctx.editor.setText(result.selectedText);
708
- this.ctx.showStatus("Branched to new session");
709
-
710
- return { cancelled: false };
711
- },
712
- navigateTree: async (targetId, options) => {
713
- const result = await this.ctx.session.navigateTree(targetId, { summarize: options?.summarize });
714
- if (this.#isStopped()) return { cancelled: true };
715
- if (result.cancelled) {
716
- return { cancelled: true };
717
- }
718
-
719
- // Update UI
720
- this.ctx.rebuildInitialMessages("reconcile-same-transcript");
721
- await this.ctx.reloadTodos();
722
- if (this.#isStopped()) return { cancelled: true };
723
- if (result.editorText && !this.ctx.editor.getText().trim()) {
724
- this.ctx.editor.setText(result.editorText);
725
- }
726
- this.ctx.showStatus("Navigated to selected point");
727
-
728
- return { cancelled: false };
729
- },
730
632
  compact: async instructionsOrOptions => this.#handleInteractiveCompact(instructionsOrOptions),
731
- switchSession: async sessionPath => {
732
- const previousSessionId = this.ctx.sessionManager.getSessionId();
733
-
734
- this.clearHookWidgets();
735
- const result = await this.ctx.session.switchSession(sessionPath);
736
- if (this.#isStopped()) return { cancelled: true };
737
- if (!result) {
738
- return { cancelled: true };
739
- }
740
- clearInteractiveActivityLoaders(this.ctx);
741
- const switchingToDifferentSession = previousSessionId !== this.ctx.sessionManager.getSessionId();
742
- if (switchingToDifferentSession) this.ctx.resetIrcSidebarSession();
743
-
744
- setSessionTerminalTitle(this.ctx.sessionManager.getSessionName(), this.ctx.sessionManager.getCwd());
745
- this.ctx.rebuildInitialMessages(
746
- switchingToDifferentSession ? "replace-identity" : "reconcile-same-transcript",
747
- );
748
- await this.ctx.reloadTodos();
749
- if (this.#isStopped()) return { cancelled: true };
750
- syncInteractiveActivityIndicator(this.ctx);
751
- return { cancelled: false };
752
- },
753
633
  };
754
634
 
755
635
  extensionRunner.initialize(
@@ -849,7 +729,10 @@ export class ExtensionUiController {
849
729
  sendMessage: (message, options) => {
850
730
  const wasStreaming = this.ctx.session.isStreaming;
851
731
  this.ctx.session
852
- .sendCustomMessage(message, options)
732
+ // Trusted seam: extension producers are external to the turn
733
+ // runtime, so classify nextTurn messages "external" here
734
+ // instead of accepting a caller-supplied origin (review P2).
735
+ .sendCustomMessage(message, { ...options, origin: "external" })
853
736
  .then(() => this.#applyCustomMessageDisplay(wasStreaming, message.display))
854
737
  .catch((err: unknown) => {
855
738
  const errorText = `Extension sendMessage failed: ${err instanceof Error ? err.message : String(err)}`;
@@ -955,6 +838,13 @@ export class ExtensionUiController {
955
838
  const commandActions: ExtensionCommandContextActions = {
956
839
  getContextUsage: () => this.ctx.session.getContextUsage(),
957
840
  waitForIdle: () => this.ctx.session.agent.waitForIdle(),
841
+ newSession: async () => prohibitBrokerLifecycleOperation("session.new"),
842
+ branch: async () => prohibitBrokerLifecycleOperation("session.branch"),
843
+ navigateTree: async (targetId, navOptions) => {
844
+ const result = await this.ctx.session.navigateTree(targetId, { summarize: navOptions?.summarize });
845
+ return { cancelled: result.cancelled };
846
+ },
847
+ switchSession: async () => prohibitBrokerLifecycleOperation("session.switch"),
958
848
  reload: async () => {
959
849
  if (this.ctx.isBackgrounded) {
960
850
  return;
@@ -969,109 +859,7 @@ export class ExtensionUiController {
969
859
  if (this.#isStopped()) return;
970
860
  this.ctx.showStatus("Reloaded session");
971
861
  },
972
- newSession: async options => {
973
- if (this.ctx.isBackgrounded) {
974
- return { cancelled: true };
975
- }
976
- const cleanupPreviousSessionUi = this.captureSessionUiCleanup();
977
- const success = await this.ctx.session.newSession({ parentSession: options?.parentSession });
978
- if (!success) {
979
- return { cancelled: true };
980
- }
981
- if (this.#isStopped()) return { cancelled: true };
982
- clearInteractiveActivityLoaders(this.ctx);
983
- cleanupPreviousSessionUi();
984
-
985
- stopInteractiveActivityIndicator(this.ctx);
986
- this.ctx.resetIrcSidebarSession();
987
-
988
- if (options?.setup) {
989
- await options.setup(this.ctx.sessionManager);
990
- if (this.#isStopped()) return { cancelled: true };
991
- }
992
-
993
- prepareTranscriptRebuild(this.ctx.ui, "replace-identity");
994
- this.ctx.chatContainer.clear();
995
- this.ctx.pendingMessagesContainer.clear();
996
- this.ctx.compactionQueuedMessages = [];
997
- this.ctx.streamingComponent = undefined;
998
- this.ctx.streamingMessage = undefined;
999
- this.ctx.pendingTools.clear();
1000
-
1001
- this.ctx.chatContainer.addChild(
1002
- new Text(`${theme.fg("accent", `${theme.status.success} New session started`)}`, 1, 0),
1003
- );
1004
- await this.ctx.reloadTodos();
1005
- if (this.#isStopped()) return { cancelled: true };
1006
- this.ctx.ui.requestRender();
1007
-
1008
- return { cancelled: false };
1009
- },
1010
- branch: async entryId => {
1011
- if (this.ctx.isBackgrounded) {
1012
- return { cancelled: true };
1013
- }
1014
- const result = await this.ctx.session.branch(entryId);
1015
- if (this.#isStopped()) return { cancelled: true };
1016
- if (result.cancelled) {
1017
- return { cancelled: true };
1018
- }
1019
- this.ctx.resetIrcSidebarSession();
1020
-
1021
- // Update UI
1022
- this.ctx.rebuildInitialMessages("replace-identity");
1023
- await this.ctx.reloadTodos();
1024
- if (this.#isStopped()) return { cancelled: true };
1025
- this.ctx.editor.setText(result.selectedText);
1026
- this.ctx.showStatus("Branched to new session");
1027
-
1028
- return { cancelled: false };
1029
- },
1030
- navigateTree: async (targetId, options) => {
1031
- if (this.ctx.isBackgrounded) {
1032
- return { cancelled: true };
1033
- }
1034
- const result = await this.ctx.session.navigateTree(targetId, { summarize: options?.summarize });
1035
- if (this.#isStopped()) return { cancelled: true };
1036
- if (result.cancelled) {
1037
- return { cancelled: true };
1038
- }
1039
-
1040
- // Update UI
1041
- this.ctx.rebuildInitialMessages("reconcile-same-transcript");
1042
- await this.ctx.reloadTodos();
1043
- if (this.#isStopped()) return { cancelled: true };
1044
- if (result.editorText && !this.ctx.editor.getText().trim()) {
1045
- this.ctx.editor.setText(result.editorText);
1046
- }
1047
- this.ctx.showStatus("Navigated to selected point");
1048
-
1049
- return { cancelled: false };
1050
- },
1051
862
  compact: async instructionsOrOptions => this.#handleInteractiveCompact(instructionsOrOptions),
1052
- switchSession: async sessionPath => {
1053
- if (this.ctx.isBackgrounded) {
1054
- return { cancelled: true };
1055
- }
1056
- const previousSessionId = this.ctx.sessionManager.getSessionId();
1057
-
1058
- this.clearHookWidgets();
1059
- const result = await this.ctx.session.switchSession(sessionPath);
1060
- if (this.#isStopped()) return { cancelled: true };
1061
- if (!result) {
1062
- return { cancelled: true };
1063
- }
1064
- clearInteractiveActivityLoaders(this.ctx);
1065
- const switchingToDifferentSession = previousSessionId !== this.ctx.sessionManager.getSessionId();
1066
- if (switchingToDifferentSession) this.ctx.resetIrcSidebarSession();
1067
- this.ctx.rebuildInitialMessages(
1068
- switchingToDifferentSession ? "replace-identity" : "reconcile-same-transcript",
1069
- );
1070
- await this.ctx.reloadTodos();
1071
- if (this.#isStopped()) return { cancelled: true };
1072
- syncInteractiveActivityIndicator(this.ctx);
1073
- return { cancelled: false };
1074
- },
1075
863
  };
1076
864
 
1077
865
  extensionRunner.initialize(
@@ -1703,6 +1491,17 @@ export class ExtensionUiController {
1703
1491
 
1704
1492
  #sendExtensionUserMessage: SendUserMessageHandler = (content, options) => {
1705
1493
  if (this.#isStopped()) return Promise.resolve();
1494
+ // Validate at the owning boundary BEFORE session delivery and UI bookkeeping:
1495
+ // applyInjectedUserSubmission → normalizeInjectedUserContent iterates content
1496
+ // and dereferences part.type synchronously. Absent/null content (the
1497
+ // container) OR null/undefined/non-object array elements throw an untyped
1498
+ // TypeError synchronously — before the send.catch handler below is attached,
1499
+ // leaving the typed invalid_input rejection from AgentSession unobserved
1500
+ // (unhandled rejection) and crashing the resident process. Reject as a typed
1501
+ // nonfatal control error so callers can surface it without losing session
1502
+ // continuity.
1503
+ const invalidContentError = extensionUserMessageContentError(content);
1504
+ if (invalidContentError) return Promise.reject(invalidContentError);
1706
1505
  // Compute queued BEFORE send: prompt() may flip session.isStreaming synchronously.
1707
1506
  const queued = Boolean(options?.deliverAs) || this.ctx.session.isStreaming;
1708
1507
  // Call send first so the busy/queued path finds the session queue populated
@@ -26,6 +26,7 @@ import { ensureSupportedImageInput, ImageInputTooLargeError } from "../../utils/
26
26
  import { resizeImage } from "../../utils/image-resize";
27
27
  import { loadPastedImageBatch, PastedImageBatchError } from "../../utils/pasted-image-loading";
28
28
  import {
29
+ decodePastedPathCandidate,
29
30
  formatPastedImageReference,
30
31
  locatePastedImageReferenceAroundCursor,
31
32
  parsePastedImagePaths,
@@ -55,8 +56,13 @@ export const BACKGROUND_FOLD_DOUBLE_PRESS_MS = 750;
55
56
  const DRAFT_CLEAR_DOUBLE_ESCAPE_WINDOW_MS = 800;
56
57
  const EMPTY_EDITOR_DOUBLE_ESCAPE_WINDOW_MS = 500;
57
58
  const IMAGE_PLACEHOLDER_PATTERN = /\[image ([1-9]\d*)\]/g;
59
+ const ITERM_PET_DRAG_PATH_PATTERN = /^\/var\/folders\/[^/]+\/[^/]+\/T\/iTerm2\.[A-Za-z0-9]+\.gajae-pet\.(?:png|gif)$/;
58
60
  const IMAGE_PLACEHOLDER_PRESENT_PATTERN = /\[image [1-9]\d*\]/;
59
61
 
62
+ function isItermPetDragPaste(text: string): boolean {
63
+ return ITERM_PET_DRAG_PATH_PATTERN.test(decodePastedPathCandidate(text) ?? "");
64
+ }
65
+
60
66
  interface InputControllerDependencies {
61
67
  loadPastedImageBatch?: typeof loadPastedImageBatch;
62
68
  }
@@ -1675,6 +1681,10 @@ export class InputController {
1675
1681
  }
1676
1682
 
1677
1683
  handleTextPaste(text: string, context: PasteTextContext): boolean | Promise<boolean> {
1684
+ if (isItermPetDragPaste(text)) {
1685
+ this.ctx.showStatus("Ignored dragged Gajae Pet image.", { dim: true });
1686
+ return true;
1687
+ }
1678
1688
  if (this.ctx.isBashMode || this.ctx.isPythonMode) return false;
1679
1689
  const parsed = parsePastedImagePaths(text, { cwd: this.ctx.sessionManager.getCwd() });
1680
1690
  if (!parsed) return false;