@gajae-code/coding-agent 0.10.1 → 0.11.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 (474) hide show
  1. package/CHANGELOG.md +70 -2
  2. package/dist/types/append-only-mode.d.ts +1 -1
  3. package/dist/types/cli/args.d.ts +4 -5
  4. package/dist/types/cli/daemon-cli.d.ts +12 -1
  5. package/dist/types/cli/notify-cli.d.ts +21 -1
  6. package/dist/types/cli.d.ts +3 -0
  7. package/dist/types/commands/daemon.d.ts +39 -0
  8. package/dist/types/commands/launch.d.ts +3 -0
  9. package/dist/types/commands/notify.d.ts +28 -1
  10. package/dist/types/commands/sdk.d.ts +33 -0
  11. package/dist/types/config/atomic-yaml-patch.d.ts +85 -0
  12. package/dist/types/config/model-profile-activation.d.ts +35 -15
  13. package/dist/types/config/model-profiles.d.ts +11 -5
  14. package/dist/types/config/model-registry.d.ts +3 -3
  15. package/dist/types/config/model-resolver.d.ts +39 -6
  16. package/dist/types/config/model-selector-value.d.ts +17 -0
  17. package/dist/types/config/models-config-schema.d.ts +10 -6
  18. package/dist/types/config/settings-schema.d.ts +133 -6
  19. package/dist/types/config/settings.d.ts +63 -35
  20. package/dist/types/coordinator-mcp/model-preset.d.ts +7 -6
  21. package/dist/types/coordinator-mcp/server.d.ts +6 -49
  22. package/dist/types/daemon/builtin.d.ts +6 -5
  23. package/dist/types/daemon/control-types.d.ts +1 -1
  24. package/dist/types/discovery/mcp-json.d.ts +12 -1
  25. package/dist/types/extensibility/custom-tools/types.d.ts +1 -1
  26. package/dist/types/extensibility/extensions/compact-handler.d.ts +4 -2
  27. package/dist/types/extensibility/extensions/get-commands-handler.d.ts +2 -2
  28. package/dist/types/extensibility/extensions/loader.d.ts +10 -1
  29. package/dist/types/extensibility/extensions/runner.d.ts +3 -3
  30. package/dist/types/extensibility/extensions/types.d.ts +141 -16
  31. package/dist/types/extensibility/hooks/types.d.ts +1 -1
  32. package/dist/types/gjc-runtime/launch-tmux.d.ts +3 -2
  33. package/dist/types/gjc-runtime/psmux-detect.d.ts +3 -0
  34. package/dist/types/gjc-runtime/session-state-sidecar.d.ts +3 -0
  35. package/dist/types/gjc-runtime/team-runtime.d.ts +3 -4
  36. package/dist/types/gjc-runtime/tmux-owner-isolation-cli.d.ts +13 -0
  37. package/dist/types/gjc-runtime/tmux-sessions.d.ts +4 -1
  38. package/dist/types/gjc-runtime/windows-powershell-command.d.ts +9 -0
  39. package/dist/types/harness-control-plane/operate.d.ts +5 -5
  40. package/dist/types/harness-control-plane/owner.d.ts +18 -4
  41. package/dist/types/harness-control-plane/receipts.d.ts +0 -1
  42. package/dist/types/harness-control-plane/sdk-transport.d.ts +43 -0
  43. package/dist/types/harness-control-plane/session-transport.d.ts +48 -0
  44. package/dist/types/harness-control-plane/types.d.ts +3 -4
  45. package/dist/types/lsp/index.d.ts +1 -1
  46. package/dist/types/main.d.ts +32 -38
  47. package/dist/types/modes/acp/acp-agent.d.ts +224 -53
  48. package/dist/types/modes/acp/acp-client-bridge.d.ts +1 -0
  49. package/dist/types/modes/acp/acp-mode.d.ts +6 -15
  50. package/dist/types/modes/acp/permission-mode.d.ts +4 -0
  51. package/dist/types/modes/acp/startup-options.d.ts +6 -0
  52. package/dist/types/modes/components/agent-dashboard.d.ts +3 -0
  53. package/dist/types/modes/components/gajae-pet-widget.d.ts +1 -0
  54. package/dist/types/modes/components/model-selector.d.ts +1 -0
  55. package/dist/types/modes/components/notifications-settings-editor.d.ts +135 -0
  56. package/dist/types/modes/components/pet-capability.d.ts +37 -0
  57. package/dist/types/modes/components/pet-selector.d.ts +1 -1
  58. package/dist/types/modes/components/settings-selector.d.ts +15 -4
  59. package/dist/types/modes/components/welcome.d.ts +1 -1
  60. package/dist/types/modes/controllers/selector-controller.d.ts +35 -1
  61. package/dist/types/modes/index.d.ts +0 -4
  62. package/dist/types/modes/interactive-mode.d.ts +5 -1
  63. package/dist/types/modes/runtime-init.d.ts +2 -2
  64. package/dist/types/modes/shared/agent-wire/approval-gate.d.ts +6 -9
  65. package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +4 -6
  66. package/dist/types/modes/shared/agent-wire/event-contract.d.ts +6 -6
  67. package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +4 -9
  68. package/dist/types/modes/shared/agent-wire/event-observation.d.ts +1 -1
  69. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +169 -30
  70. package/dist/types/modes/shared/agent-wire/workflow-gate-schema.d.ts +7 -7
  71. package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +105 -0
  72. package/dist/types/modes/types.d.ts +16 -1
  73. package/dist/types/runtime-mcp/client.d.ts +2 -0
  74. package/dist/types/runtime-mcp/config.d.ts +5 -1
  75. package/dist/types/runtime-mcp/manager.d.ts +8 -1
  76. package/dist/types/runtime-mcp/types.d.ts +4 -0
  77. package/dist/types/sdk/acp/adapter.d.ts +67 -0
  78. package/dist/types/sdk/acp/index.d.ts +2 -0
  79. package/dist/types/sdk/broker/broker.d.ts +53 -0
  80. package/dist/types/sdk/broker/discovery.d.ts +30 -0
  81. package/dist/types/sdk/broker/ensure.d.ts +33 -0
  82. package/dist/types/sdk/broker/identity.d.ts +3 -0
  83. package/dist/types/sdk/broker/index.d.ts +8 -0
  84. package/dist/types/sdk/broker/lifecycle-ledger.d.ts +95 -0
  85. package/dist/types/sdk/broker/lifecycle.d.ts +85 -0
  86. package/dist/types/sdk/broker/process-incarnation.d.ts +14 -0
  87. package/dist/types/sdk/broker/runtime.d.ts +33 -0
  88. package/dist/types/sdk/broker/session-index.d.ts +57 -0
  89. package/dist/types/sdk/broker/state-version.d.ts +8 -0
  90. package/dist/types/sdk/broker/transport.d.ts +9 -0
  91. package/dist/types/sdk/bus/chat-command-policy.d.ts +49 -0
  92. package/dist/types/sdk/bus/chat-daemon-cli.d.ts +21 -0
  93. package/dist/types/sdk/bus/chat-daemon-control.d.ts +111 -0
  94. package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +77 -0
  95. package/dist/types/sdk/bus/chat-effect-journal.d.ts +84 -0
  96. package/dist/types/{notifications → sdk/bus}/config-commands.d.ts +7 -2
  97. package/dist/types/sdk/bus/config.d.ts +274 -0
  98. package/dist/types/sdk/bus/conversation-store.d.ts +72 -0
  99. package/dist/types/sdk/bus/discord-conversation.d.ts +58 -0
  100. package/dist/types/sdk/bus/discord-daemon.d.ts +45 -0
  101. package/dist/types/sdk/bus/discord-live-provider.d.ts +70 -0
  102. package/dist/types/sdk/bus/discord-provider.d.ts +85 -0
  103. package/dist/types/{notifications → sdk/bus}/html-format.d.ts +2 -2
  104. package/dist/types/{notifications → sdk/bus}/index.d.ts +113 -13
  105. package/dist/types/{notifications → sdk/bus}/lifecycle-control-runtime.d.ts +4 -2
  106. package/dist/types/{notifications → sdk/bus}/lifecycle-orchestrator.d.ts +18 -21
  107. package/dist/types/{notifications → sdk/bus}/managed-daemon.d.ts +1 -1
  108. package/dist/types/sdk/bus/native-runtime-compatibility.d.ts +13 -0
  109. package/dist/types/sdk/bus/notification-orchestration.d.ts +170 -0
  110. package/dist/types/{notifications → sdk/bus}/notification-service.d.ts +7 -1
  111. package/dist/types/sdk/bus/session-control.d.ts +83 -0
  112. package/dist/types/sdk/bus/slack-conversation.d.ts +56 -0
  113. package/dist/types/sdk/bus/slack-daemon.d.ts +60 -0
  114. package/dist/types/sdk/bus/slack-live-provider.d.ts +59 -0
  115. package/dist/types/sdk/bus/slack-provider.d.ts +55 -0
  116. package/dist/types/{notifications → sdk/bus}/telegram-cli.d.ts +4 -4
  117. package/dist/types/{notifications → sdk/bus}/telegram-daemon-cli.d.ts +14 -5
  118. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +12 -0
  119. package/dist/types/{notifications → sdk/bus}/telegram-daemon-control.d.ts +2 -2
  120. package/dist/types/{notifications → sdk/bus}/telegram-daemon.d.ts +55 -17
  121. package/dist/types/{notifications → sdk/bus}/telegram-reference.d.ts +2 -2
  122. package/dist/types/sdk/bus/telegram-setup.d.ts +128 -0
  123. package/dist/types/{notifications → sdk/bus}/topic-registry.d.ts +11 -0
  124. package/dist/types/sdk/cli/index.d.ts +1 -0
  125. package/dist/types/sdk/cli/session-cli.d.ts +19 -0
  126. package/dist/types/sdk/client/client.d.ts +1 -0
  127. package/dist/types/sdk/client/discovery.d.ts +27 -0
  128. package/dist/types/sdk/client/index.d.ts +2 -0
  129. package/dist/types/sdk/host/control/dispatch.d.ts +34 -0
  130. package/dist/types/sdk/host/control/index.d.ts +2 -0
  131. package/dist/types/sdk/host/control/operations.d.ts +65 -0
  132. package/dist/types/sdk/host/events.d.ts +35 -0
  133. package/dist/types/sdk/host/host.d.ts +35 -0
  134. package/dist/types/sdk/host/index.d.ts +4 -0
  135. package/dist/types/sdk/host/query/cursor.d.ts +62 -0
  136. package/dist/types/sdk/host/query/handlers.d.ts +70 -0
  137. package/dist/types/sdk/host/query/index.d.ts +3 -0
  138. package/dist/types/sdk/host/query/revision-store.d.ts +60 -0
  139. package/dist/types/sdk/host/reverse-leases.d.ts +45 -0
  140. package/dist/types/sdk/host/types.d.ts +32 -0
  141. package/dist/types/sdk/index.d.ts +6 -0
  142. package/dist/types/sdk/lifecycle-session.d.ts +14 -0
  143. package/dist/types/sdk/mcp/index.d.ts +1 -0
  144. package/dist/types/sdk/mcp/server.d.ts +37 -0
  145. package/dist/types/sdk/models.d.ts +44 -0
  146. package/dist/types/sdk/protocol/adapter-validation.d.ts +14 -0
  147. package/dist/types/sdk/protocol/operation-registry.d.ts +24 -0
  148. package/dist/types/{sdk.d.ts → sdk/session.d.ts} +44 -38
  149. package/dist/types/sdk/startup-capability.d.ts +50 -0
  150. package/dist/types/session/agent-session.d.ts +114 -21
  151. package/dist/types/session/default-model-selection.d.ts +25 -0
  152. package/dist/types/session/fallback-chain-controller.d.ts +52 -0
  153. package/dist/types/session/session-manager.d.ts +58 -1
  154. package/dist/types/setup/credential-auto-import.d.ts +36 -6
  155. package/dist/types/tools/ask-answer-registry.d.ts +1 -1
  156. package/dist/types/tools/browser/benchmark/detector-report.d.ts +63 -0
  157. package/dist/types/tools/browser/benchmark/run-suite.d.ts +18 -0
  158. package/dist/types/tools/browser/launch.d.ts +22 -0
  159. package/dist/types/tools/browser/profile-discovery.d.ts +31 -0
  160. package/dist/types/tools/browser/profile-posture.d.ts +37 -0
  161. package/dist/types/tools/browser/profile-reuse.d.ts +39 -0
  162. package/dist/types/tools/browser/profile-warmup.d.ts +39 -0
  163. package/dist/types/tools/browser/registry.d.ts +19 -0
  164. package/dist/types/tools/browser/tab-protocol.d.ts +4 -0
  165. package/dist/types/tools/index.d.ts +8 -8
  166. package/package.json +34 -13
  167. package/scripts/build-sdk-package-smoke.ts +94 -0
  168. package/scripts/capture-notifications-settings-showcase.ts +435 -0
  169. package/scripts/compile-args.ts +4 -2
  170. package/scripts/g005-daemon-smoke.ts +4 -5
  171. package/scripts/g011-daemon-path-smoke.ts +5 -5
  172. package/scripts/generate-sdk-adapter-parity-manifest.ts +163 -0
  173. package/scripts/generate-sdk-operation-inventory.ts +867 -0
  174. package/scripts/generate-telegram-baseline-manifest.ts +128 -0
  175. package/scripts/manifest-schema.ts +124 -0
  176. package/scripts/run-test-manifest.ts +153 -0
  177. package/scripts/run-threat-model-check.ts +157 -0
  178. package/scripts/verify-gjc-sdk-canonicalization.ts +3467 -0
  179. package/scripts/verify-gjc-sdk-rename.ts +90 -0
  180. package/src/append-only-mode.ts +1 -1
  181. package/src/cli/args.ts +43 -12
  182. package/src/cli/auth-gateway-cli.ts +2 -2
  183. package/src/cli/config-cli.ts +2 -1
  184. package/src/cli/daemon-cli.ts +63 -14
  185. package/src/cli/list-models.ts +1 -1
  186. package/src/cli/notify-cli.ts +288 -286
  187. package/src/cli.ts +21 -2
  188. package/src/commands/daemon.ts +50 -6
  189. package/src/commands/harness.ts +93 -36
  190. package/src/commands/launch.ts +5 -2
  191. package/src/commands/mcp-serve.ts +19 -12
  192. package/src/commands/notify.ts +36 -3
  193. package/src/commands/sdk.ts +426 -0
  194. package/src/commit/agentic/agent.ts +1 -0
  195. package/src/config/atomic-yaml-patch.ts +423 -0
  196. package/src/config/model-profile-activation.ts +240 -89
  197. package/src/config/model-profiles.ts +37 -34
  198. package/src/config/model-registry.ts +51 -26
  199. package/src/config/model-resolver.ts +138 -51
  200. package/src/config/model-selector-value.ts +50 -0
  201. package/src/config/models-config-schema.ts +14 -21
  202. package/src/config/settings-schema.ts +128 -10
  203. package/src/config/settings.ts +1120 -158
  204. package/src/coordinator-mcp/model-preset.ts +74 -20
  205. package/src/coordinator-mcp/server.ts +1597 -3052
  206. package/src/daemon/builtin.ts +8 -5
  207. package/src/daemon/control-types.ts +1 -1
  208. package/src/defaults/gjc/skills/team/SKILL.md +4 -4
  209. package/src/discovery/mcp-json.ts +327 -20
  210. package/src/extensibility/custom-tools/types.ts +1 -1
  211. package/src/extensibility/extensions/compact-handler.ts +3 -3
  212. package/src/extensibility/extensions/get-commands-handler.ts +2 -2
  213. package/src/extensibility/extensions/loader.ts +69 -5
  214. package/src/extensibility/extensions/runner.ts +112 -4
  215. package/src/extensibility/extensions/types.ts +176 -17
  216. package/src/extensibility/hooks/types.ts +1 -1
  217. package/src/extensibility/slash-commands.ts +3 -3
  218. package/src/gjc-runtime/launch-tmux.ts +170 -86
  219. package/src/gjc-runtime/psmux-detect.ts +82 -4
  220. package/src/gjc-runtime/session-state-sidecar.ts +41 -31
  221. package/src/gjc-runtime/team-runtime.ts +54 -35
  222. package/src/gjc-runtime/tmux-owner-isolation-cli.ts +53 -17
  223. package/src/gjc-runtime/tmux-owner-isolation.ts +5 -2
  224. package/src/gjc-runtime/tmux-sessions.ts +19 -13
  225. package/src/gjc-runtime/ultragoal-guard.ts +53 -6
  226. package/src/gjc-runtime/ultragoal-runtime.ts +155 -3
  227. package/src/gjc-runtime/windows-powershell-command.ts +58 -0
  228. package/src/harness-control-plane/operate.ts +9 -9
  229. package/src/harness-control-plane/owner.ts +283 -39
  230. package/src/harness-control-plane/receipts.ts +0 -1
  231. package/src/harness-control-plane/sdk-transport.ts +395 -0
  232. package/src/harness-control-plane/session-transport.ts +94 -0
  233. package/src/harness-control-plane/types.ts +1 -1
  234. package/src/internal-urls/docs-index.generated.ts +36 -37
  235. package/src/lsp/client.ts +42 -6
  236. package/src/lsp/index.ts +2 -2
  237. package/src/main.ts +299 -204
  238. package/src/modes/DESIGN.md +258 -0
  239. package/src/modes/acp/acp-agent.ts +1228 -2612
  240. package/src/modes/acp/acp-client-bridge.ts +2 -20
  241. package/src/modes/acp/acp-event-mapper.ts +18 -2
  242. package/src/modes/acp/acp-mode.ts +8 -36
  243. package/src/modes/acp/permission-mode.ts +25 -0
  244. package/src/modes/acp/startup-options.ts +6 -0
  245. package/src/modes/components/agent-dashboard.ts +37 -17
  246. package/src/modes/components/custom-editor.ts +1 -0
  247. package/src/modes/components/gajae-pet-widget.ts +169 -20
  248. package/src/modes/components/model-selector.ts +93 -35
  249. package/src/modes/components/notifications-settings-editor.ts +1379 -0
  250. package/src/modes/components/pet-capability.ts +115 -0
  251. package/src/modes/components/pet-selector.ts +4 -6
  252. package/src/modes/components/settings-selector.ts +86 -11
  253. package/src/modes/components/welcome.ts +4 -4
  254. package/src/modes/controllers/command-controller.ts +1 -2
  255. package/src/modes/controllers/event-controller.ts +11 -16
  256. package/src/modes/controllers/extension-ui-controller.ts +357 -12
  257. package/src/modes/controllers/input-controller.ts +43 -13
  258. package/src/modes/controllers/selector-controller.ts +671 -44
  259. package/src/modes/index.ts +0 -22
  260. package/src/modes/interactive-mode.ts +108 -24
  261. package/src/modes/runtime-init.ts +298 -6
  262. package/src/modes/shared/agent-wire/approval-gate.ts +9 -11
  263. package/src/modes/shared/agent-wire/deep-interview-gate.ts +10 -11
  264. package/src/modes/shared/agent-wire/event-contract.ts +7 -8
  265. package/src/modes/shared/agent-wire/event-envelope.ts +9 -17
  266. package/src/modes/shared/agent-wire/event-observation.ts +16 -7
  267. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +1254 -87
  268. package/src/modes/shared/agent-wire/workflow-gate-schema.ts +15 -15
  269. package/src/modes/shared/agent-wire/workflow-gate-types.ts +113 -0
  270. package/src/modes/types.ts +16 -1
  271. package/src/runtime-mcp/client.ts +94 -19
  272. package/src/runtime-mcp/config.ts +27 -15
  273. package/src/runtime-mcp/manager.ts +343 -105
  274. package/src/runtime-mcp/oauth-flow.ts +42 -12
  275. package/src/runtime-mcp/transports/http.ts +49 -19
  276. package/src/runtime-mcp/transports/stdio.ts +47 -28
  277. package/src/runtime-mcp/types.ts +10 -0
  278. package/src/sdk/acp/adapter.ts +418 -0
  279. package/src/sdk/acp/index.ts +2 -0
  280. package/src/sdk/broker/broker.ts +642 -0
  281. package/src/sdk/broker/discovery.ts +94 -0
  282. package/src/sdk/broker/ensure.ts +249 -0
  283. package/src/sdk/broker/identity.ts +42 -0
  284. package/src/sdk/broker/index.ts +8 -0
  285. package/src/sdk/broker/internal-source-marker-2178.txt +1 -0
  286. package/src/sdk/broker/internal-source.bunfig.toml +1 -0
  287. package/src/sdk/broker/lifecycle-ledger.ts +286 -0
  288. package/src/sdk/broker/lifecycle.ts +2157 -0
  289. package/src/sdk/broker/process-incarnation.ts +159 -0
  290. package/src/sdk/broker/runtime.ts +164 -0
  291. package/src/sdk/broker/session-index.ts +318 -0
  292. package/src/sdk/broker/state-version.ts +23 -0
  293. package/src/sdk/broker/transport.ts +125 -0
  294. package/src/sdk/bus/chat-command-policy.ts +107 -0
  295. package/src/sdk/bus/chat-daemon-cli.ts +214 -0
  296. package/src/sdk/bus/chat-daemon-control.ts +713 -0
  297. package/src/sdk/bus/chat-daemon-runtime.ts +526 -0
  298. package/src/sdk/bus/chat-effect-journal.ts +353 -0
  299. package/src/{notifications → sdk/bus}/config-commands.ts +39 -10
  300. package/src/sdk/bus/config.ts +433 -0
  301. package/src/sdk/bus/conversation-store.ts +391 -0
  302. package/src/sdk/bus/discord-conversation.ts +85 -0
  303. package/src/sdk/bus/discord-daemon.ts +2275 -0
  304. package/src/sdk/bus/discord-live-provider.ts +521 -0
  305. package/src/sdk/bus/discord-provider.ts +56 -0
  306. package/src/{notifications → sdk/bus}/html-format.ts +2 -2
  307. package/src/sdk/bus/index.ts +3943 -0
  308. package/src/{notifications → sdk/bus}/lifecycle-commands.ts +2 -0
  309. package/src/{notifications → sdk/bus}/lifecycle-control-runtime.ts +225 -196
  310. package/src/{notifications → sdk/bus}/lifecycle-orchestrator.ts +161 -74
  311. package/src/{notifications → sdk/bus}/managed-daemon.ts +2 -2
  312. package/src/sdk/bus/native-runtime-compatibility.ts +42 -0
  313. package/src/sdk/bus/natives-augment.d.ts +38 -0
  314. package/src/sdk/bus/notification-orchestration.ts +535 -0
  315. package/src/{notifications → sdk/bus}/notification-service.ts +106 -12
  316. package/src/sdk/bus/session-control.ts +333 -0
  317. package/src/sdk/bus/slack-conversation.ts +74 -0
  318. package/src/sdk/bus/slack-daemon.ts +2144 -0
  319. package/src/sdk/bus/slack-live-provider.ts +380 -0
  320. package/src/sdk/bus/slack-provider.ts +76 -0
  321. package/src/{notifications → sdk/bus}/telegram-cli.ts +8 -8
  322. package/src/sdk/bus/telegram-daemon-cli.ts +330 -0
  323. package/src/sdk/bus/telegram-daemon-contract.ts +14 -0
  324. package/src/{notifications → sdk/bus}/telegram-daemon-control.ts +4 -4
  325. package/src/{notifications → sdk/bus}/telegram-daemon.ts +502 -54
  326. package/src/{notifications → sdk/bus}/telegram-reference.ts +2 -2
  327. package/src/sdk/bus/telegram-setup.ts +663 -0
  328. package/src/{notifications → sdk/bus}/topic-registry.ts +32 -0
  329. package/src/sdk/cli/index.ts +1 -0
  330. package/src/sdk/cli/session-cli.ts +275 -0
  331. package/src/sdk/client/client.ts +1 -0
  332. package/src/sdk/client/discovery.ts +108 -0
  333. package/src/sdk/client/index.ts +2 -0
  334. package/src/sdk/host/control/dispatch.ts +367 -0
  335. package/src/sdk/host/control/index.ts +10 -0
  336. package/src/sdk/host/control/operations.ts +63 -0
  337. package/src/sdk/host/events.ts +91 -0
  338. package/src/sdk/host/host.ts +296 -0
  339. package/src/sdk/host/index.ts +4 -0
  340. package/src/sdk/host/query/cursor.ts +189 -0
  341. package/src/sdk/host/query/handlers.ts +533 -0
  342. package/src/sdk/host/query/index.ts +3 -0
  343. package/src/sdk/host/query/revision-store.ts +1126 -0
  344. package/src/sdk/host/reverse-leases.ts +325 -0
  345. package/src/sdk/host/types.ts +29 -0
  346. package/src/sdk/index.ts +13 -0
  347. package/src/sdk/lifecycle-session.ts +39 -0
  348. package/src/sdk/mcp/index.ts +1 -0
  349. package/src/sdk/mcp/server.ts +332 -0
  350. package/src/sdk/models.ts +168 -0
  351. package/src/sdk/protocol/adapter-validation.ts +48 -0
  352. package/src/sdk/protocol/operation-inventory.generated.json +5654 -0
  353. package/src/sdk/protocol/operation-registry.ts +312 -0
  354. package/src/{sdk.ts → sdk/session.ts} +339 -212
  355. package/src/sdk/startup-capability.ts +189 -0
  356. package/src/session/agent-session.ts +2470 -866
  357. package/src/session/default-model-selection.ts +93 -0
  358. package/src/session/fallback-chain-controller.ts +136 -0
  359. package/src/session/session-manager.ts +447 -13
  360. package/src/session/session-storage.ts +8 -1
  361. package/src/setup/credential-auto-import.ts +290 -35
  362. package/src/setup/hermes/templates/operator-instructions.v1.md +3 -5
  363. package/src/slash-commands/builtin-registry.ts +33 -30
  364. package/src/task/executor.ts +62 -13
  365. package/src/tools/ask-answer-registry.ts +1 -1
  366. package/src/tools/ask.ts +13 -8
  367. package/src/tools/browser/STEALTH-THIRD-PARTY-NOTICES.md +26 -0
  368. package/src/tools/browser/benchmark/detector-report.ts +157 -0
  369. package/src/tools/browser/benchmark/run-suite.ts +39 -0
  370. package/src/tools/browser/launch.ts +124 -19
  371. package/src/tools/browser/profile-discovery.ts +63 -0
  372. package/src/tools/browser/profile-posture.ts +59 -0
  373. package/src/tools/browser/profile-reuse.ts +102 -0
  374. package/src/tools/browser/profile-warmup.ts +109 -0
  375. package/src/tools/browser/registry.ts +87 -11
  376. package/src/tools/browser/tab-protocol.ts +1 -0
  377. package/src/tools/browser/tab-supervisor.ts +1 -0
  378. package/src/tools/browser/tab-worker.ts +1 -1
  379. package/src/tools/browser.ts +6 -0
  380. package/src/tools/index.ts +8 -8
  381. package/src/tools/puppeteer/14_stealth_permissions.txt +57 -0
  382. package/src/tools/puppeteer/15_stealth_webrtc.txt +60 -0
  383. package/src/tools/telegram-send.ts +2 -2
  384. package/vendor/insane-search/MANIFEST.json +2 -1
  385. package/vendor/insane-search/engine/bias_check.py +4 -1
  386. package/vendor/insane-search/engine/phase0.py +26 -1
  387. package/dist/types/harness-control-plane/rpc-adapter.d.ts +0 -69
  388. package/dist/types/modes/bridge/auth.d.ts +0 -12
  389. package/dist/types/modes/bridge/bridge-client-bridge.d.ts +0 -9
  390. package/dist/types/modes/bridge/bridge-mode.d.ts +0 -47
  391. package/dist/types/modes/bridge/bridge-ui-context.d.ts +0 -88
  392. package/dist/types/modes/bridge/event-stream.d.ts +0 -8
  393. package/dist/types/modes/rpc/host-tools.d.ts +0 -1
  394. package/dist/types/modes/rpc/host-uris.d.ts +0 -1
  395. package/dist/types/modes/rpc/rpc-client.d.ts +0 -299
  396. package/dist/types/modes/rpc/rpc-mode.d.ts +0 -86
  397. package/dist/types/modes/rpc/rpc-socket-security.d.ts +0 -10
  398. package/dist/types/modes/rpc/rpc-types.d.ts +0 -810
  399. package/dist/types/modes/shared/agent-wire/command-contract.d.ts +0 -18
  400. package/dist/types/modes/shared/agent-wire/command-dispatch.d.ts +0 -37
  401. package/dist/types/modes/shared/agent-wire/command-validation.d.ts +0 -2
  402. package/dist/types/modes/shared/agent-wire/handshake.d.ts +0 -56
  403. package/dist/types/modes/shared/agent-wire/host-tool-bridge.d.ts +0 -16
  404. package/dist/types/modes/shared/agent-wire/host-uri-bridge.d.ts +0 -17
  405. package/dist/types/modes/shared/agent-wire/protocol.d.ts +0 -25
  406. package/dist/types/modes/shared/agent-wire/responses.d.ts +0 -4
  407. package/dist/types/modes/shared/agent-wire/scopes.d.ts +0 -18
  408. package/dist/types/modes/shared/agent-wire/session-registry.d.ts +0 -25
  409. package/dist/types/modes/shared/agent-wire/ui-request-broker.d.ts +0 -42
  410. package/dist/types/modes/shared/agent-wire/ui-result.d.ts +0 -27
  411. package/dist/types/modes/shared/agent-wire/unattended-action-policy.d.ts +0 -29
  412. package/dist/types/modes/shared/agent-wire/unattended-audit.d.ts +0 -68
  413. package/dist/types/modes/shared/agent-wire/unattended-run-controller.d.ts +0 -166
  414. package/dist/types/modes/shared/agent-wire/unattended-session.d.ts +0 -127
  415. package/dist/types/notifications/config.d.ts +0 -132
  416. package/src/harness-control-plane/rpc-adapter.ts +0 -290
  417. package/src/modes/bridge/auth.ts +0 -41
  418. package/src/modes/bridge/bridge-client-bridge.ts +0 -47
  419. package/src/modes/bridge/bridge-mode.ts +0 -675
  420. package/src/modes/bridge/bridge-ui-context.ts +0 -200
  421. package/src/modes/bridge/event-stream.ts +0 -70
  422. package/src/modes/rpc/host-tools.ts +0 -1
  423. package/src/modes/rpc/host-uris.ts +0 -1
  424. package/src/modes/rpc/rpc-client.ts +0 -1166
  425. package/src/modes/rpc/rpc-mode.ts +0 -1029
  426. package/src/modes/rpc/rpc-socket-security.ts +0 -115
  427. package/src/modes/rpc/rpc-types.ts +0 -637
  428. package/src/modes/shared/agent-wire/command-contract.ts +0 -18
  429. package/src/modes/shared/agent-wire/command-dispatch.ts +0 -498
  430. package/src/modes/shared/agent-wire/command-validation.ts +0 -181
  431. package/src/modes/shared/agent-wire/handshake.ts +0 -157
  432. package/src/modes/shared/agent-wire/host-tool-bridge.ts +0 -197
  433. package/src/modes/shared/agent-wire/host-uri-bridge.ts +0 -236
  434. package/src/modes/shared/agent-wire/protocol.ts +0 -46
  435. package/src/modes/shared/agent-wire/responses.ts +0 -17
  436. package/src/modes/shared/agent-wire/scopes.ts +0 -94
  437. package/src/modes/shared/agent-wire/session-registry.ts +0 -109
  438. package/src/modes/shared/agent-wire/ui-request-broker.ts +0 -150
  439. package/src/modes/shared/agent-wire/ui-result.ts +0 -48
  440. package/src/modes/shared/agent-wire/unattended-action-policy.ts +0 -365
  441. package/src/modes/shared/agent-wire/unattended-audit.ts +0 -176
  442. package/src/modes/shared/agent-wire/unattended-run-controller.ts +0 -426
  443. package/src/modes/shared/agent-wire/unattended-session.ts +0 -528
  444. package/src/notifications/config.ts +0 -219
  445. package/src/notifications/index.ts +0 -1835
  446. package/src/notifications/telegram-daemon-cli.ts +0 -243
  447. package/src/tools/puppeteer/09_stealth_locale.txt +0 -46
  448. /package/dist/types/{notifications → sdk/bus}/attachment-registry.d.ts +0 -0
  449. /package/dist/types/{notifications → sdk/bus}/chat-adapters.d.ts +0 -0
  450. /package/dist/types/{notifications → sdk/bus}/daemon-paths.d.ts +0 -0
  451. /package/dist/types/{notifications → sdk/bus}/engine.d.ts +0 -0
  452. /package/dist/types/{notifications → sdk/bus}/helpers.d.ts +0 -0
  453. /package/dist/types/{notifications → sdk/bus}/lifecycle-commands.d.ts +0 -0
  454. /package/dist/types/{notifications → sdk/bus}/operator-runtime.d.ts +0 -0
  455. /package/dist/types/{notifications → sdk/bus}/rate-limit-pool.d.ts +0 -0
  456. /package/dist/types/{notifications → sdk/bus}/recent-activity.d.ts +0 -0
  457. /package/dist/types/{notifications → sdk/bus}/reply-sent-store.d.ts +0 -0
  458. /package/dist/types/{notifications → sdk/bus}/rich-draft.d.ts +0 -0
  459. /package/dist/types/{notifications → sdk/bus}/rich-render.d.ts +0 -0
  460. /package/dist/types/{notifications → sdk/bus}/threaded-inbound.d.ts +0 -0
  461. /package/dist/types/{notifications → sdk/bus}/threaded-render.d.ts +0 -0
  462. /package/src/{notifications → sdk/bus}/attachment-registry.ts +0 -0
  463. /package/src/{notifications → sdk/bus}/chat-adapters.ts +0 -0
  464. /package/src/{notifications → sdk/bus}/daemon-paths.ts +0 -0
  465. /package/src/{notifications → sdk/bus}/engine.ts +0 -0
  466. /package/src/{notifications → sdk/bus}/helpers.ts +0 -0
  467. /package/src/{notifications → sdk/bus}/operator-runtime.ts +0 -0
  468. /package/src/{notifications → sdk/bus}/rate-limit-pool.ts +0 -0
  469. /package/src/{notifications → sdk/bus}/recent-activity.ts +0 -0
  470. /package/src/{notifications → sdk/bus}/reply-sent-store.ts +0 -0
  471. /package/src/{notifications → sdk/bus}/rich-draft.ts +0 -0
  472. /package/src/{notifications → sdk/bus}/rich-render.ts +0 -0
  473. /package/src/{notifications → sdk/bus}/threaded-inbound.ts +0 -0
  474. /package/src/{notifications → sdk/bus}/threaded-render.ts +0 -0
@@ -1,3 +1,4 @@
1
+ import { ThinkingLevel } from "@gajae-code/agent-core";
1
2
  import type { Component, OverlayHandle, TUI } from "@gajae-code/tui";
2
3
  import { Container, Spacer, Text } from "@gajae-code/tui";
3
4
  import { logger } from "@gajae-code/utils";
@@ -22,6 +23,8 @@ import { HookInputComponent } from "../../modes/components/hook-input";
22
23
  import { HookSelectorComponent } from "../../modes/components/hook-selector";
23
24
  import { getAvailableThemesWithPaths, getThemeByName, setTheme, type Theme, theme } from "../../modes/theme/theme";
24
25
  import type { InteractiveModeContext } from "../../modes/types";
26
+ import { parseThinkingLevel } from "../../thinking";
27
+ import type { TodoPhase } from "../../tools/todo-write";
25
28
  import { setSessionTerminalTitle, setTerminalTitle } from "../../utils/title-generator";
26
29
  import { applyInjectedUserSubmission } from "../utils/injected-user-submission";
27
30
  import { classifyHookSelectorBellEvent, ringTerminalBell } from "../utils/terminal-bell";
@@ -50,6 +53,206 @@ export class ExtensionUiController {
50
53
  overlay?.hide();
51
54
  }
52
55
 
56
+ #sdkControl = async (operation: string, input: Record<string, unknown>): Promise<unknown> => {
57
+ const session = this.ctx.session;
58
+ switch (operation) {
59
+ case "model.set": {
60
+ const selector = typeof input.id === "string" ? input.id : "";
61
+ const slashIndex = selector.indexOf("/");
62
+ const model =
63
+ slashIndex > 0
64
+ ? session.modelRegistry.find(selector.slice(0, slashIndex), selector.slice(slashIndex + 1))
65
+ : undefined;
66
+ const thinkingLevel =
67
+ typeof input.thinkingLevel === "string" ? parseThinkingLevel(input.thinkingLevel) : undefined;
68
+ if (!model || !thinkingLevel || thinkingLevel === ThinkingLevel.Inherit)
69
+ throw Object.assign(new Error("model.set requires a valid model id and concrete thinkingLevel."), {
70
+ code: "invalid_input",
71
+ });
72
+ return await session.setDefaultModelSelection(model, thinkingLevel);
73
+ }
74
+ case "todo.replace": {
75
+ const phases = input.items;
76
+ if (
77
+ !Array.isArray(phases) ||
78
+ !phases.every(phase => {
79
+ if (!phase || typeof phase !== "object") return false;
80
+ const candidate = phase as { name?: unknown; tasks?: unknown };
81
+ return (
82
+ typeof candidate.name === "string" &&
83
+ Array.isArray(candidate.tasks) &&
84
+ candidate.tasks.every(task => {
85
+ if (!task || typeof task !== "object") return false;
86
+ const item = task as { content?: unknown; status?: unknown };
87
+ return (
88
+ typeof item.content === "string" &&
89
+ ["pending", "in_progress", "completed", "abandoned"].includes(String(item.status))
90
+ );
91
+ })
92
+ );
93
+ })
94
+ )
95
+ throw Object.assign(new Error("todo.replace requires TodoPhase items."), { code: "invalid_input" });
96
+ session.setTodoPhases(phases as TodoPhase[]);
97
+ return { replaced: session.getTodoPhases() };
98
+ }
99
+ case "permission_mode.set": {
100
+ const requested = input.mode;
101
+ const mode =
102
+ requested === "allow" || requested === "always-allow"
103
+ ? "allow"
104
+ : requested === "deny" || requested === "always-deny"
105
+ ? "deny"
106
+ : requested === "prompt"
107
+ ? "prompt"
108
+ : undefined;
109
+ if (!mode)
110
+ throw Object.assign(new Error("permission_mode.set requires prompt, allow, or deny."), {
111
+ code: "invalid_input",
112
+ });
113
+ session.setSdkPermissionMode(mode);
114
+ return { changed: true, mode: session.sdkPermissionMode };
115
+ }
116
+ case "bash.execute": {
117
+ if (typeof input.cmd !== "string" || input.cmd.trim() === "")
118
+ throw Object.assign(new Error("bash.execute requires a command."), { code: "invalid_input" });
119
+ const result = await session.executeBash(input.cmd, undefined, { excludeFromContext: true });
120
+ return {
121
+ exitCode: result.exitCode,
122
+ cancelled: result.cancelled,
123
+ output: result.output,
124
+ truncated: result.truncated,
125
+ };
126
+ }
127
+ case "bash.abort":
128
+ if (!session.isBashRunning) return { aborted: false };
129
+ session.abortBash();
130
+ return { aborted: true };
131
+ case "retry.last":
132
+ if (!(await session.retry()))
133
+ throw Object.assign(new Error("There is no failed or interrupted turn to retry."), {
134
+ code: "nothing_to_retry",
135
+ });
136
+ return { retried: true };
137
+ case "retry.now":
138
+ if (!session.isRetrying)
139
+ throw Object.assign(new Error("No retry backoff is pending."), { code: "retry_not_pending" });
140
+ session.retryNow();
141
+ return { retried: true, immediate: true };
142
+ case "bash.background":
143
+ if (!session.requestForegroundBashBackground())
144
+ throw Object.assign(new Error("The active bash command cannot be moved to a managed background job."), {
145
+ code: "not_foldable",
146
+ });
147
+ return { backgrounded: true };
148
+ case "compaction.auto.set":
149
+ session.setAutoCompactionEnabled(input.on === true);
150
+ return { changed: true };
151
+ case "retry.auto.set":
152
+ session.setAutoRetryEnabled(input.on === true);
153
+ return { changed: true };
154
+ case "retry.abort":
155
+ session.abortRetry();
156
+ return { aborted: true };
157
+ case "session.new":
158
+ return { created: await session.newSession() };
159
+ case "session.fork":
160
+ return { session: await session.fork() };
161
+ case "session.resume":
162
+ return { resumed: await session.switchSession(String(input.id)) };
163
+ case "session.close":
164
+ await session.sessionManager.flush();
165
+ return { closed: true };
166
+ case "session.switch":
167
+ return { switched: await session.switchSession(String(input.id)) };
168
+ case "session.branch":
169
+ try {
170
+ return await session.branch(String(input.entryId));
171
+ } catch (error) {
172
+ throw Object.assign(new Error(error instanceof Error ? error.message : "Branch entry was not found."), {
173
+ code: "resource_gone",
174
+ });
175
+ }
176
+ case "session.rename":
177
+ return { renamed: await session.setSessionName(String(input.name), "user") };
178
+ case "session.handoff":
179
+ try {
180
+ return {
181
+ handoff: await session.handoff(
182
+ typeof input.instructions === "string" ? input.instructions : undefined,
183
+ ),
184
+ };
185
+ } catch (error) {
186
+ throw Object.assign(
187
+ new Error(error instanceof Error ? error.message : "Handoff is unavailable for the current state."),
188
+ { code: "invalid_request" },
189
+ );
190
+ }
191
+ case "session.export_html":
192
+ try {
193
+ return { path: await session.exportToHtml(typeof input.path === "string" ? input.path : undefined) };
194
+ } catch (error) {
195
+ throw Object.assign(
196
+ new Error(
197
+ error instanceof Error ? error.message : "Session export is unavailable for the current state.",
198
+ ),
199
+ { code: "invalid_request" },
200
+ );
201
+ }
202
+ case "runtime.reload":
203
+ await session.reload();
204
+ return { reloaded: true };
205
+ case "service_tier.set":
206
+ session.setServiceTier(input.tier as never);
207
+ return { changed: true };
208
+ case "queue.message.remove": {
209
+ const removed = session.removeQueuedMessageForEditing(String(input.id));
210
+ if (removed === undefined)
211
+ throw Object.assign(new Error("Queued message was not found."), { code: "resource_gone" });
212
+ return { removed };
213
+ }
214
+ case "queue.message.move": {
215
+ const id = String(input.id);
216
+ const moved =
217
+ input.before !== undefined
218
+ ? session.moveQueuedMessageForEditing(id, "up")
219
+ : session.moveQueuedMessageForEditing(id, "down");
220
+ if (!moved) throw Object.assign(new Error("Queue position is invalid."), { code: "invalid_position" });
221
+ return { moved };
222
+ }
223
+ case "queue.message.update": {
224
+ const id = String(input.id);
225
+ const old = session.removeQueuedMessageForEditing(id);
226
+ const patch = input.patch as { text?: unknown };
227
+ if (old === undefined || typeof patch?.text !== "string")
228
+ throw Object.assign(new Error("Queued message update is invalid."), { code: "invalid_message" });
229
+ await session.sendUserMessage(patch.text, { deliverAs: id.startsWith("steer:") ? "steer" : "followUp" });
230
+ return { updated: true };
231
+ }
232
+ case "extension.set_enabled": {
233
+ const id = String(input.id);
234
+ const disabled = [...(session.settings.get("disabledExtensions") ?? [])];
235
+ const on = input.on === true;
236
+ const next = on ? disabled.filter(value => value !== id) : [...new Set([...disabled, id])];
237
+ session.settings.set("disabledExtensions", next);
238
+ return { changed: true, enabled: on };
239
+ }
240
+ case "session.delete":
241
+ await session.sessionManager.dropSession(String(input.id));
242
+ return { deleted: true };
243
+ case "session.cwd.move":
244
+ await session.sessionManager.moveTo(String(input.path));
245
+ return { moved: true, cwd: session.sessionManager.getCwd() };
246
+ default:
247
+ throw Object.assign(new Error(`${operation} has no AgentSession implementation.`), { code: "unavailable" });
248
+ }
249
+ };
250
+
251
+ /** Re-mount the pet-aware composer after a transient hook UI closes. */
252
+ #restoreComposerEditor(): void {
253
+ this.ctx.restoreComposer();
254
+ }
255
+
53
256
  /**
54
257
  * Initialize the hook system with TUI-based UI context.
55
258
  */
@@ -123,11 +326,21 @@ export class ExtensionUiController {
123
326
  setModel: async model => {
124
327
  const key = await this.ctx.session.modelRegistry.getApiKey(model);
125
328
  if (!key) return false;
126
- await this.ctx.session.setModel(model);
329
+ await this.ctx.session.setModel(model, "default", { cause: "user-selection" });
127
330
  return true;
128
331
  },
129
332
  getThinkingLevel: () => this.ctx.session.thinkingLevel,
130
- setThinkingLevel: level => this.ctx.session.setThinkingLevel(level),
333
+ setThinkingLevel: (level, persist) => this.ctx.session.setThinkingLevel(level, persist),
334
+ getThinkingVisibility: () => this.ctx.session.getThinkingVisibility(),
335
+ setThinkingVisibility: (visibility, persist) => this.ctx.session.setThinkingVisibility(visibility, persist),
336
+ cycleThinkingLevel: () => this.ctx.session.cycleThinkingLevel(),
337
+ setThinkingLevelForControl: (level, persist) => this.ctx.session.setThinkingLevelForControl(level, persist),
338
+ setThinkingVisibilityForControl: (visibility, persist) =>
339
+ this.ctx.session.setThinkingVisibilityForControl(visibility, persist),
340
+ setModelTemporaryForControl: (model, expectedSessionId) =>
341
+ this.ctx.session.setModelTemporaryForControl(model, expectedSessionId),
342
+ fetchUsageReportsForControl: () => this.ctx.session.fetchUsageReportsForControl(),
343
+ getThinkingScopeForControl: () => this.ctx.session.getThinkingScopeForControl(),
131
344
  getCommands: () => getSessionSlashCommands(this.ctx.session),
132
345
  getSessionName: () => this.ctx.sessionManager.getSessionName(),
133
346
  setSessionName: name => this.#updateSessionName(name),
@@ -137,6 +350,15 @@ export class ExtensionUiController {
137
350
  isIdle: () => !this.ctx.session.isStreaming,
138
351
  abort: () => this.ctx.session.abort(),
139
352
  hasPendingMessages: () => this.ctx.session.queuedMessageCount > 0,
353
+ getPendingMessageCounts: () => this.ctx.session.pendingMessageCounts,
354
+ getTranscript: () => this.ctx.session.getTranscript(),
355
+ getTranscriptBody: entryId => this.ctx.session.getTranscriptBody(entryId),
356
+ getGoalState: () => this.ctx.session.getGoalModeState(),
357
+ getTodoState: () => this.ctx.session.getTodoPhases(),
358
+ getQueuedMessages: () => this.ctx.session.getQueuedMessageEntries(),
359
+ getActiveTools: () => this.ctx.session.getActiveToolNames(),
360
+ getAllTools: () => this.ctx.session.getAllToolNames(),
361
+
140
362
  shutdown: () => {
141
363
  // Defer the actual teardown to the main loop, which calls
142
364
  // `checkShutdownRequested()` at idle boundaries so any queued
@@ -146,6 +368,38 @@ export class ExtensionUiController {
146
368
  getContextUsage: () => this.ctx.session.getContextUsage(),
147
369
  compact: instructionsOrOptions => this.#compactSession(instructionsOrOptions),
148
370
  getSystemPrompt: () => this.ctx.session.systemPrompt,
371
+ clearContext: () => this.ctx.session.clearContext(),
372
+ cycleModel: () => this.ctx.session.cycleModel(),
373
+ cycleThinkingLevel: () => this.ctx.session.cycleThinkingLevel(),
374
+ setQueueMode: (kind, mode) => {
375
+ if (kind === "steering" && (mode === "all" || mode === "one-at-a-time")) {
376
+ this.ctx.session.setSteeringMode(mode);
377
+ return true;
378
+ }
379
+ if (kind === "follow_up" && (mode === "all" || mode === "one-at-a-time")) {
380
+ this.ctx.session.setFollowUpMode(mode);
381
+ return true;
382
+ }
383
+ if (kind === "interrupt" && (mode === "immediate" || mode === "wait")) {
384
+ this.ctx.session.setInterruptMode(mode);
385
+ return true;
386
+ }
387
+ return false;
388
+ },
389
+ invokeSkill: (name, args) => this.ctx.session.invokeSkill(name, args),
390
+ setPlanMode: on => this.ctx.session.setSdkPlanMode(on),
391
+ operateGoal: (op, objective) => this.ctx.session.operateGoal(op, objective),
392
+ getSkillState: () =>
393
+ this.ctx.session.skills.map(skill => ({ name: skill.name, description: skill.description })),
394
+ getConfigItems: () => ({
395
+ steeringMode: this.ctx.session.steeringMode,
396
+ followUpMode: this.ctx.session.followUpMode,
397
+ interruptMode: this.ctx.session.interruptMode,
398
+ }),
399
+ getBranchCandidates: () => this.ctx.sessionManager.getTree(),
400
+ getExtensions: () => this.ctx.session.extensionRunner?.getExtensionPaths() ?? [],
401
+ setSdkPermissionProvider: provider => this.ctx.session.setSdkPermissionProvider(provider),
402
+ sdkControl: this.#sdkControl,
149
403
  };
150
404
  const commandActions: ExtensionCommandContextActions = {
151
405
  getContextUsage: () => this.ctx.session.getContextUsage(),
@@ -372,11 +626,21 @@ export class ExtensionUiController {
372
626
  setModel: async model => {
373
627
  const key = await this.ctx.session.modelRegistry.getApiKey(model);
374
628
  if (!key) return false;
375
- await this.ctx.session.setModel(model);
629
+ await this.ctx.session.setModel(model, "default", { cause: "user-selection" });
376
630
  return true;
377
631
  },
378
632
  getThinkingLevel: () => this.ctx.session.thinkingLevel,
379
633
  setThinkingLevel: (level, persist) => this.ctx.session.setThinkingLevel(level, persist),
634
+ getThinkingVisibility: () => this.ctx.session.getThinkingVisibility(),
635
+ setThinkingVisibility: (visibility, persist) => this.ctx.session.setThinkingVisibility(visibility, persist),
636
+ cycleThinkingLevel: () => this.ctx.session.cycleThinkingLevel(),
637
+ setThinkingLevelForControl: (level, persist) => this.ctx.session.setThinkingLevelForControl(level, persist),
638
+ setThinkingVisibilityForControl: (visibility, persist) =>
639
+ this.ctx.session.setThinkingVisibilityForControl(visibility, persist),
640
+ setModelTemporaryForControl: (model, expectedSessionId) =>
641
+ this.ctx.session.setModelTemporaryForControl(model, expectedSessionId),
642
+ fetchUsageReportsForControl: () => this.ctx.session.fetchUsageReportsForControl(),
643
+ getThinkingScopeForControl: () => this.ctx.session.getThinkingScopeForControl(),
380
644
  getCommands: () => getSessionSlashCommands(this.ctx.session),
381
645
  getSessionName: () => this.ctx.sessionManager.getSessionName(),
382
646
  setSessionName: name => this.#updateSessionName(name),
@@ -386,6 +650,15 @@ export class ExtensionUiController {
386
650
  isIdle: () => !this.ctx.session.isStreaming,
387
651
  abort: () => this.ctx.session.abort(),
388
652
  hasPendingMessages: () => this.ctx.session.queuedMessageCount > 0,
653
+ getPendingMessageCounts: () => this.ctx.session.pendingMessageCounts,
654
+ getTranscript: () => this.ctx.session.getTranscript(),
655
+ getTranscriptBody: entryId => this.ctx.session.getTranscriptBody(entryId),
656
+ getGoalState: () => this.ctx.session.getGoalModeState(),
657
+ getTodoState: () => this.ctx.session.getTodoPhases(),
658
+ getQueuedMessages: () => this.ctx.session.getQueuedMessageEntries(),
659
+ getActiveTools: () => this.ctx.session.getActiveToolNames(),
660
+ getAllTools: () => this.ctx.session.getAllToolNames(),
661
+
389
662
  shutdown: () => {
390
663
  // Defer the actual teardown to the main loop, which calls
391
664
  // `checkShutdownRequested()` at idle boundaries so any queued
@@ -395,6 +668,35 @@ export class ExtensionUiController {
395
668
  getContextUsage: () => this.ctx.session.getContextUsage(),
396
669
  compact: instructionsOrOptions => this.#compactSession(instructionsOrOptions),
397
670
  getSystemPrompt: () => this.ctx.session.systemPrompt,
671
+ clearContext: () => this.ctx.session.clearContext(),
672
+ cycleModel: () => this.ctx.session.cycleModel(),
673
+ cycleThinkingLevel: () => this.ctx.session.cycleThinkingLevel(),
674
+ setQueueMode: (kind, mode) => {
675
+ if (kind === "steering" && (mode === "all" || mode === "one-at-a-time")) {
676
+ this.ctx.session.setSteeringMode(mode);
677
+ return true;
678
+ }
679
+ if (kind === "follow_up" && (mode === "all" || mode === "one-at-a-time")) {
680
+ this.ctx.session.setFollowUpMode(mode);
681
+ return true;
682
+ }
683
+ if (kind === "interrupt" && (mode === "immediate" || mode === "wait")) {
684
+ this.ctx.session.setInterruptMode(mode);
685
+ return true;
686
+ }
687
+ return false;
688
+ },
689
+ getSkillState: () =>
690
+ this.ctx.session.skills.map(skill => ({ name: skill.name, description: skill.description })),
691
+ getConfigItems: () => ({
692
+ steeringMode: this.ctx.session.steeringMode,
693
+ followUpMode: this.ctx.session.followUpMode,
694
+ interruptMode: this.ctx.session.interruptMode,
695
+ }),
696
+ getBranchCandidates: () => this.ctx.sessionManager.getTree(),
697
+ getExtensions: () => this.ctx.session.extensionRunner?.getExtensionPaths() ?? [],
698
+ setSdkPermissionProvider: provider => this.ctx.session.setSdkPermissionProvider(provider),
699
+ sdkControl: this.#sdkControl,
398
700
  };
399
701
  const commandActions: ExtensionCommandContextActions = {
400
702
  getContextUsage: () => this.ctx.session.getContextUsage(),
@@ -571,6 +873,14 @@ export class ExtensionUiController {
571
873
  model: this.ctx.session.model,
572
874
  isIdle: () => !this.ctx.session.isStreaming,
573
875
  hasPendingMessages: () => this.ctx.session.queuedMessageCount > 0,
876
+ getPendingMessageCounts: () => this.ctx.session.pendingMessageCounts,
877
+ getTranscript: () => this.ctx.session.getTranscript(),
878
+ getTranscriptBody: entryId => this.ctx.session.getTranscriptBody(entryId),
879
+ getGoalState: () => this.ctx.session.getGoalModeState(),
880
+ getTodoState: () => this.ctx.session.getTodoPhases(),
881
+ getQueuedMessages: () => this.ctx.session.getQueuedMessageEntries(),
882
+ getActiveTools: () => this.ctx.session.getActiveToolNames(),
883
+ getAllTools: () => this.ctx.session.getAllToolNames(),
574
884
  hasQueuedMessages: () => this.ctx.session.queuedMessageCount > 0,
575
885
  abort: () => {
576
886
  this.ctx.session.abort();
@@ -579,6 +889,44 @@ export class ExtensionUiController {
579
889
  // Signal shutdown request
580
890
  },
581
891
  getSystemPrompt: () => [...this.ctx.session.systemPrompt],
892
+ cycleModel: () => this.ctx.session.cycleModel(),
893
+ cycleThinkingLevel: () => this.ctx.session.cycleThinkingLevel(),
894
+ setQueueMode: (kind, mode) => {
895
+ if (kind === "steering" && (mode === "all" || mode === "one-at-a-time")) {
896
+ this.ctx.session.setSteeringMode(mode);
897
+ return true;
898
+ }
899
+ if (kind === "follow_up" && (mode === "all" || mode === "one-at-a-time")) {
900
+ this.ctx.session.setFollowUpMode(mode);
901
+ return true;
902
+ }
903
+ if (kind === "interrupt" && (mode === "immediate" || mode === "wait")) {
904
+ this.ctx.session.setInterruptMode(mode);
905
+ return true;
906
+ }
907
+ return false;
908
+ },
909
+ getSkillState: () =>
910
+ this.ctx.session.skills.map(skill => ({ name: skill.name, description: skill.description })),
911
+ getConfigItems: () => ({
912
+ steeringMode: this.ctx.session.steeringMode,
913
+ followUpMode: this.ctx.session.followUpMode,
914
+ interruptMode: this.ctx.session.interruptMode,
915
+ }),
916
+ getBranchCandidates: () => this.ctx.sessionManager.getTree(),
917
+ getExtensions: () => this.ctx.session.extensionRunner?.getExtensionPaths() ?? [],
918
+ getArtifact: () => undefined,
919
+ getJobs: () => undefined,
920
+ sdkBindings: () => [
921
+ "cycleModel",
922
+ "cycleThinkingLevel",
923
+ "setQueueMode",
924
+ "getSkillState",
925
+ "getConfigItems",
926
+ "getBranchCandidates",
927
+ "getExtensions",
928
+ ],
929
+ clearContext: () => this.ctx.session.clearContext(),
582
930
  });
583
931
  } catch (err) {
584
932
  this.showToolError(registeredTool.definition.name, err instanceof Error ? err.message : String(err));
@@ -723,8 +1071,7 @@ export class ExtensionUiController {
723
1071
  */
724
1072
  hideHookSelector(): void {
725
1073
  this.ctx.hookSelector?.dispose();
726
- this.ctx.editorContainer.clear();
727
- this.ctx.editorContainer.addChild(this.ctx.editor);
1074
+ this.#restoreComposerEditor();
728
1075
  this.ctx.hookSelector = undefined;
729
1076
  this.ctx.ui.setFocus(this.ctx.editor);
730
1077
  this.ctx.ui.requestRender();
@@ -785,8 +1132,7 @@ export class ExtensionUiController {
785
1132
  */
786
1133
  hideHookInput(): void {
787
1134
  this.ctx.hookInput?.dispose();
788
- this.ctx.editorContainer.clear();
789
- this.ctx.editorContainer.addChild(this.ctx.editor);
1135
+ this.#restoreComposerEditor();
790
1136
  this.ctx.hookInput = undefined;
791
1137
  this.ctx.ui.setFocus(this.ctx.editor);
792
1138
  this.ctx.ui.requestRender();
@@ -835,8 +1181,7 @@ export class ExtensionUiController {
835
1181
  * Hide the hook editor.
836
1182
  */
837
1183
  hideHookEditor(): void {
838
- this.ctx.editorContainer.clear();
839
- this.ctx.editorContainer.addChild(this.ctx.editor);
1184
+ this.#restoreComposerEditor();
840
1185
  this.ctx.hookEditor = undefined;
841
1186
  this.ctx.ui.setFocus(this.ctx.editor);
842
1187
  this.ctx.ui.requestRender();
@@ -879,8 +1224,7 @@ export class ExtensionUiController {
879
1224
  closed = true;
880
1225
  this.#clearActiveHookCustom();
881
1226
  if (!options?.overlay) {
882
- this.ctx.editorContainer.clear();
883
- this.ctx.editorContainer.addChild(this.ctx.editor);
1227
+ this.#restoreComposerEditor();
884
1228
  this.ctx.editor.setText(savedText);
885
1229
  }
886
1230
  this.ctx.ui.setFocus(this.ctx.editor);
@@ -980,9 +1324,10 @@ export class ExtensionUiController {
980
1324
  // (queueSteer/queueFollowUp push synchronously) before refreshing pending display.
981
1325
  const send = this.ctx.session.sendUserMessage(content, options);
982
1326
  applyInjectedUserSubmission(this.ctx, { content, queued });
983
- send.catch((err: unknown) => {
1327
+ void send.catch((err: unknown) => {
984
1328
  this.ctx.showError(`Extension sendUserMessage failed: ${err instanceof Error ? err.message : String(err)}`);
985
1329
  });
1330
+ return send;
986
1331
  };
987
1332
 
988
1333
  #applyCustomMessageDisplay(wasStreaming: boolean, shouldDisplay: boolean | undefined): void {
@@ -434,13 +434,14 @@ export class InputController {
434
434
  }
435
435
 
436
436
  const runner = this.ctx.session.extensionRunner;
437
+ const pendingImages = this.ctx.pendingImages;
437
438
  let inputImages = this.#visiblePendingImagesForText(text);
438
439
 
439
440
  if (runner?.hasHandlers("input")) {
440
441
  const result = await runner.emitInput(text, inputImages, "interactive");
441
442
  if (result?.handled) {
442
443
  this.ctx.editor.setText("");
443
- this.ctx.pendingImages = [];
444
+ this.#clearPendingImagesIfOwnedBy(pendingImages);
444
445
  return;
445
446
  }
446
447
  if (result?.text !== undefined) {
@@ -530,7 +531,7 @@ export class InputController {
530
531
  this.ctx.editor.addToHistory(text);
531
532
  this.ctx.editor.setText("");
532
533
  const images = inputImages && inputImages.length > 0 ? [...inputImages] : undefined;
533
- this.ctx.pendingImages = [];
534
+ this.#clearPendingImagesIfOwnedBy(pendingImages);
534
535
  // Record the signature so the queued message's eventual delivery
535
536
  // (a user-role `message_start` event) leaves any draft the user has
536
537
  // typed since queuing intact. Same protection as #783, applied to
@@ -582,7 +583,7 @@ export class InputController {
582
583
  if (this.ctx.onInputCallback) {
583
584
  // Include any pending images from clipboard paste
584
585
  const images = inputImages && inputImages.length > 0 ? [...inputImages] : undefined;
585
- this.ctx.pendingImages = [];
586
+ this.#clearPendingImagesIfOwnedBy(pendingImages);
586
587
 
587
588
  // Render user message immediately, then let session events catch up
588
589
  const submission = this.ctx.startPendingSubmission({ text, images });
@@ -1104,11 +1105,14 @@ export class InputController {
1104
1105
  return false;
1105
1106
  }
1106
1107
 
1107
- this.ctx.pendingImages.push({
1108
- type: "image",
1109
- data: image.data,
1110
- mimeType: image.mimeType,
1111
- });
1108
+ this.ctx.pendingImages = [
1109
+ ...this.ctx.pendingImages,
1110
+ {
1111
+ type: "image",
1112
+ data: image.data,
1113
+ mimeType: image.mimeType,
1114
+ },
1115
+ ];
1112
1116
  this.ctx.editor.insertText(`${formatPastedImageReference(this.#nextImagePlaceholder(), image.resolvedPath)} `);
1113
1117
  this.ctx.showStatus(`Attached image: ${path.basename(image.resolvedPath)}`, { dim: true });
1114
1118
  this.ctx.ui.requestRender();
@@ -1151,10 +1155,33 @@ export class InputController {
1151
1155
  return images.length > 0 ? images : undefined;
1152
1156
  }
1153
1157
 
1158
+ #clearPendingImagesIfOwnedBy(pendingImages: InteractiveModeContext["pendingImages"]): void {
1159
+ if (this.ctx.pendingImages === pendingImages) {
1160
+ this.ctx.pendingImages = [];
1161
+ }
1162
+ }
1163
+
1154
1164
  #clearPendingImagesIfPlaceholdersRemoved(text: string): void {
1155
1165
  if (this.ctx.pendingImages.length === 0 || IMAGE_PLACEHOLDER_PRESENT_PATTERN.test(text)) {
1156
1166
  return;
1157
1167
  }
1168
+ // Editor submit resets the composer and emits onChange("") before onSubmit(result).
1169
+ // Defer the empty-buffer clear so the submit handler can still resolve image
1170
+ // placeholders against pendingImages, while manual clears still drop stale images.
1171
+ if (text.length === 0) {
1172
+ const pendingImages = this.ctx.pendingImages;
1173
+ const pendingImageCount = pendingImages.length;
1174
+ queueMicrotask(() => {
1175
+ if (
1176
+ this.ctx.pendingImages === pendingImages &&
1177
+ pendingImages.length === pendingImageCount &&
1178
+ this.ctx.editor.getText().length === 0
1179
+ ) {
1180
+ this.ctx.pendingImages = [];
1181
+ }
1182
+ });
1183
+ return;
1184
+ }
1158
1185
  this.ctx.pendingImages = [];
1159
1186
  }
1160
1187
 
@@ -1185,11 +1212,14 @@ export class InputController {
1185
1212
  }
1186
1213
  }
1187
1214
 
1188
- this.ctx.pendingImages.push({
1189
- type: "image",
1190
- data: imageData.data,
1191
- mimeType: imageData.mimeType,
1192
- });
1215
+ this.ctx.pendingImages = [
1216
+ ...this.ctx.pendingImages,
1217
+ {
1218
+ type: "image",
1219
+ data: imageData.data,
1220
+ mimeType: imageData.mimeType,
1221
+ },
1222
+ ];
1193
1223
  this.ctx.editor.insertText(`${this.#nextImagePlaceholder()} `);
1194
1224
  this.ctx.ui.requestRender();
1195
1225
  return true;