@vellumai/assistant 0.6.1 → 0.6.3

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 (463) hide show
  1. package/bun.lock +40 -40
  2. package/bunfig.toml +3 -0
  3. package/docker-entrypoint.sh +12 -2
  4. package/docs/architecture/memory.md +1 -1
  5. package/node_modules/@vellumai/ces-contracts/src/handles.ts +7 -9
  6. package/node_modules/@vellumai/ces-contracts/src/rpc.ts +42 -0
  7. package/openapi.yaml +184 -69
  8. package/package.json +41 -41
  9. package/scripts/generate-openapi.ts +1 -2
  10. package/src/__tests__/acp-session.test.ts +43 -0
  11. package/src/__tests__/app-builder-tool-scripts.test.ts +1 -0
  12. package/src/__tests__/app-executors.test.ts +1 -0
  13. package/src/__tests__/app-source-watcher.test.ts +37 -11
  14. package/src/__tests__/approval-routes-http.test.ts +178 -1
  15. package/src/__tests__/assistant-event-hub.test.ts +30 -0
  16. package/src/__tests__/browser-fill-credential.test.ts +229 -94
  17. package/src/__tests__/browser-manager.test.ts +40 -27
  18. package/src/__tests__/catalog-files.test.ts +862 -0
  19. package/src/__tests__/channel-approvals.test.ts +53 -0
  20. package/src/__tests__/checker.test.ts +104 -170
  21. package/src/__tests__/cli-command-risk-guard.test.ts +1 -1
  22. package/src/__tests__/config-managed-gemini-defaults.test.ts +326 -0
  23. package/src/__tests__/config-schema-cmd.test.ts +2 -2
  24. package/src/__tests__/config-schema.test.ts +125 -48
  25. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +23 -0
  26. package/src/__tests__/context-overflow-approval.test.ts +21 -6
  27. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -1
  28. package/src/__tests__/conversation-agent-loop.test.ts +1 -1
  29. package/src/__tests__/conversation-analysis-routes.test.ts +169 -0
  30. package/src/__tests__/conversation-attachments.test.ts +80 -4
  31. package/src/__tests__/conversation-confirmation-signals.test.ts +155 -0
  32. package/src/__tests__/conversation-directories-parse.test.ts +105 -0
  33. package/src/__tests__/conversation-fork-crud.test.ts +17 -0
  34. package/src/__tests__/conversation-history-web-search.test.ts +1 -0
  35. package/src/__tests__/conversation-host-access-routes.test.ts +229 -0
  36. package/src/__tests__/conversation-inject-context.test.ts +103 -0
  37. package/src/__tests__/conversation-queue.test.ts +45 -2
  38. package/src/__tests__/conversation-routes-disk-view.test.ts +5 -0
  39. package/src/__tests__/conversation-routes-guardian-reply.test.ts +16 -0
  40. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  41. package/src/__tests__/conversation-runtime-assembly.test.ts +269 -46
  42. package/src/__tests__/conversation-starter-routes.test.ts +126 -0
  43. package/src/__tests__/conversation-starters-cadence.test.ts +161 -0
  44. package/src/__tests__/conversation-store.test.ts +195 -0
  45. package/src/__tests__/conversation-workspace-cache-state.test.ts +193 -0
  46. package/src/__tests__/credential-execution-approval-bridge.test.ts +32 -3
  47. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  48. package/src/__tests__/credential-vault-unit.test.ts +4 -4
  49. package/src/__tests__/credential-vault.test.ts +152 -13
  50. package/src/__tests__/credentials-cli.test.ts +2 -2
  51. package/src/__tests__/date-context.test.ts +4 -4
  52. package/src/__tests__/embedding-managed-proxy-selection.test.ts +256 -0
  53. package/src/__tests__/extension-id-sync-guard.test.ts +155 -0
  54. package/src/__tests__/fixtures/mock-chrome-extension.ts +375 -0
  55. package/src/__tests__/gateway-only-guard.test.ts +3 -0
  56. package/src/__tests__/gemini-provider.test.ts +2 -2
  57. package/src/__tests__/guardian-routing-invariants.test.ts +70 -2
  58. package/src/__tests__/headless-browser-interactions.test.ts +707 -371
  59. package/src/__tests__/headless-browser-navigate.test.ts +389 -47
  60. package/src/__tests__/headless-browser-read-tools.test.ts +266 -103
  61. package/src/__tests__/headless-browser-snapshot.test.ts +240 -77
  62. package/src/__tests__/host-bash-proxy.test.ts +150 -1
  63. package/src/__tests__/host-browser-e2e-cloud.test.ts +462 -0
  64. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +286 -0
  65. package/src/__tests__/host-browser-e2e-self-hosted.test.ts +374 -0
  66. package/src/__tests__/host-browser-event-routes.test.ts +350 -0
  67. package/src/__tests__/host-browser-proxy.test.ts +444 -0
  68. package/src/__tests__/host-browser-routes.test.ts +198 -0
  69. package/src/__tests__/host-browser-ws-events-e2e.test.ts +320 -0
  70. package/src/__tests__/host-cu-proxy.test.ts +171 -1
  71. package/src/__tests__/host-file-proxy.test.ts +185 -1
  72. package/src/__tests__/host-file-read-tool.test.ts +52 -0
  73. package/src/__tests__/host-proxy-interface.test.ts +165 -0
  74. package/src/__tests__/host-shell-tool.test.ts +1 -11
  75. package/src/__tests__/http-user-message-parity.test.ts +1 -0
  76. package/src/__tests__/init-feature-flag-overrides.test.ts +167 -0
  77. package/src/__tests__/inline-command-runner.test.ts +7 -5
  78. package/src/__tests__/integration-status.test.ts +6 -7
  79. package/src/__tests__/list-messages-tool-merge.test.ts +37 -12
  80. package/src/__tests__/log-export-workspace.test.ts +190 -0
  81. package/src/__tests__/managed-credential-catalog-cli.test.ts +12 -14
  82. package/src/__tests__/mcp-client-auth.test.ts +40 -4
  83. package/src/__tests__/mcp-health-check.test.ts +10 -3
  84. package/src/__tests__/migration-cross-version-compatibility.test.ts +3 -1
  85. package/src/__tests__/migration-export-http.test.ts +61 -2
  86. package/src/__tests__/migration-export-streaming.test.ts +66 -0
  87. package/src/__tests__/migration-import-commit-http.test.ts +101 -1
  88. package/src/__tests__/native-host-marker-sync-guard.test.ts +157 -0
  89. package/src/__tests__/navigate-settings-tab.test.ts +14 -1
  90. package/src/__tests__/notification-broadcaster.test.ts +65 -0
  91. package/src/__tests__/oauth-apps-routes.test.ts +17 -12
  92. package/src/__tests__/oauth-cli.test.ts +707 -60
  93. package/src/__tests__/oauth-connect-orchestrator.test.ts +116 -24
  94. package/src/__tests__/oauth-provider-seed-logos.test.ts +23 -0
  95. package/src/__tests__/oauth-provider-serializer.test.ts +146 -10
  96. package/src/__tests__/oauth-provider-visibility.test.ts +19 -21
  97. package/src/__tests__/oauth-providers-routes.test.ts +50 -14
  98. package/src/__tests__/oauth-store.test.ts +1386 -182
  99. package/src/__tests__/oauth2-gateway-transport.test.ts +211 -20
  100. package/src/__tests__/onboarding-template-contract.test.ts +74 -55
  101. package/src/__tests__/openai-provider.test.ts +2 -2
  102. package/src/__tests__/outlook-categories.test.ts +1 -1
  103. package/src/__tests__/outlook-client-automation.test.ts +1 -1
  104. package/src/__tests__/outlook-compose-tools.test.ts +1 -1
  105. package/src/__tests__/outlook-email-watcher.test.ts +1 -1
  106. package/src/__tests__/outlook-follow-up.test.ts +1 -1
  107. package/src/__tests__/outlook-messaging-provider.test.ts +2 -2
  108. package/src/__tests__/outlook-trash.test.ts +1 -1
  109. package/src/__tests__/outlook-unsubscribe.test.ts +1 -1
  110. package/src/__tests__/permission-checker-host-gate.test.ts +74 -14
  111. package/src/__tests__/permission-mode.test.ts +28 -56
  112. package/src/__tests__/pkb-autoinject.test.ts +96 -0
  113. package/src/__tests__/platform-callback-registration.test.ts +19 -0
  114. package/src/__tests__/post-turn-tool-result-truncation.test.ts +296 -0
  115. package/src/__tests__/proxy-approval-callback.test.ts +18 -0
  116. package/src/__tests__/require-fresh-approval.test.ts +40 -3
  117. package/src/__tests__/sandbox-diagnostics.test.ts +1 -32
  118. package/src/__tests__/sanitize-config-for-transfer.test.ts +132 -0
  119. package/src/__tests__/schedule-routes.test.ts +162 -0
  120. package/src/__tests__/secret-detection-handler.test.ts +84 -0
  121. package/src/__tests__/secret-ingress-http.test.ts +1 -0
  122. package/src/__tests__/send-endpoint-busy.test.ts +3 -0
  123. package/src/__tests__/set-permission-mode.test.ts +13 -250
  124. package/src/__tests__/skills-file-content-endpoint.test.ts +670 -0
  125. package/src/__tests__/skills-files-catalog-fallback.test.ts +450 -0
  126. package/src/__tests__/slack-channel-config.test.ts +12 -15
  127. package/src/__tests__/subagent-detail.test.ts +44 -2
  128. package/src/__tests__/subagent-disposal.test.ts +1 -0
  129. package/src/__tests__/subagent-fork-notifications.test.ts +291 -0
  130. package/src/__tests__/subagent-fork-spawn.test.ts +384 -0
  131. package/src/__tests__/subagent-manager-notify.test.ts +1 -0
  132. package/src/__tests__/subagent-notify-parent.test.ts +1 -0
  133. package/src/__tests__/subagent-spawn-tool-fork.test.ts +411 -0
  134. package/src/__tests__/subagent-tools.test.ts +1 -0
  135. package/src/__tests__/subagent-types.test.ts +1 -0
  136. package/src/__tests__/system-prompt-ask-mode.test.ts +27 -71
  137. package/src/__tests__/system-prompt.test.ts +72 -1
  138. package/src/__tests__/task-scheduler.test.ts +32 -6
  139. package/src/__tests__/telegram-config.test.ts +10 -13
  140. package/src/__tests__/terminal-sandbox.test.ts +1 -1
  141. package/src/__tests__/terminal-tools.test.ts +11 -5
  142. package/src/__tests__/test-preload.ts +14 -0
  143. package/src/__tests__/tool-approval-handler.test.ts +73 -0
  144. package/src/__tests__/tool-domain-event-publisher.test.ts +0 -1
  145. package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -8
  146. package/src/__tests__/tool-executor.test.ts +0 -1
  147. package/src/__tests__/tool-side-effects-slack-dm.test.ts +22 -0
  148. package/src/__tests__/top-level-renderer.test.ts +73 -1
  149. package/src/__tests__/transport-hints-queue.test.ts +62 -0
  150. package/src/__tests__/trust-store.test.ts +4 -4
  151. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +109 -0
  152. package/src/__tests__/v2-consent-policy.test.ts +103 -0
  153. package/src/__tests__/workspace-migration-030-seed-pkb-autoinject.test.ts +168 -0
  154. package/src/__tests__/workspace-policy.test.ts +2 -7
  155. package/src/acp/client-handler.ts +30 -4
  156. package/src/agent/loop.ts +12 -35
  157. package/src/approvals/guardian-request-resolvers.ts +21 -15
  158. package/src/browser-session/__tests__/manager.test.ts +297 -0
  159. package/src/browser-session/backends/cdp-inspect.ts +30 -0
  160. package/src/browser-session/backends/extension.ts +26 -0
  161. package/src/browser-session/backends/local.ts +24 -0
  162. package/src/browser-session/events.ts +164 -0
  163. package/src/browser-session/index.ts +27 -0
  164. package/src/browser-session/manager.ts +159 -0
  165. package/src/browser-session/types.ts +28 -0
  166. package/src/channels/__tests__/types.test.ts +134 -0
  167. package/src/channels/types.ts +55 -0
  168. package/src/cli/__tests__/run-assistant-command.ts +34 -7
  169. package/src/cli/__tests__/unknown-command.test.ts +33 -0
  170. package/src/cli/commands/browser-relay.ts +339 -409
  171. package/src/cli/commands/credentials.ts +3 -3
  172. package/src/cli/commands/default-action.ts +68 -1
  173. package/src/cli/commands/email.ts +18 -13
  174. package/src/cli/commands/mcp.ts +16 -4
  175. package/src/cli/commands/oauth/__tests__/connect.test.ts +68 -41
  176. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +21 -21
  177. package/src/cli/commands/oauth/__tests__/mode.test.ts +17 -17
  178. package/src/cli/commands/oauth/__tests__/ping.test.ts +16 -16
  179. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +31 -33
  180. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +329 -0
  181. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +116 -12
  182. package/src/cli/commands/oauth/__tests__/status.test.ts +10 -10
  183. package/src/cli/commands/oauth/__tests__/token.test.ts +7 -7
  184. package/src/cli/commands/oauth/apps.ts +7 -4
  185. package/src/cli/commands/oauth/connect.ts +16 -2
  186. package/src/cli/commands/oauth/disconnect.ts +1 -1
  187. package/src/cli/commands/oauth/providers.ts +200 -36
  188. package/src/cli/commands/oauth/shared.ts +5 -5
  189. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +259 -0
  190. package/src/cli/commands/platform/__tests__/connect.test.ts +1 -1
  191. package/src/cli/commands/platform/__tests__/disconnect.test.ts +1 -1
  192. package/src/cli/commands/platform/__tests__/status.test.ts +1 -1
  193. package/src/cli/commands/platform/index.ts +107 -10
  194. package/src/cli/commands/usage.ts +10 -9
  195. package/src/cli/lib/daemon-credential-client.ts +4 -0
  196. package/src/cli/program.ts +10 -3
  197. package/src/config/assistant-feature-flags.ts +59 -55
  198. package/src/config/bundled-skills/app-builder/SKILL.md +33 -173
  199. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +105 -0
  200. package/src/config/bundled-skills/app-builder/references/INTERACTION_HOOKS.md +56 -0
  201. package/src/config/bundled-skills/app-builder/references/WIDGETS.md +125 -0
  202. package/src/config/bundled-skills/contacts/SKILL.md +3 -0
  203. package/src/config/bundled-skills/document/SKILL.md +4 -0
  204. package/src/config/bundled-skills/gmail/SKILL.md +12 -7
  205. package/src/config/bundled-skills/gmail/TOOLS.json +1 -1
  206. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +2 -1
  207. package/src/config/bundled-skills/outlook/SKILL.md +7 -0
  208. package/src/config/bundled-skills/settings/TOOLS.json +1 -1
  209. package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +8 -3
  210. package/src/config/bundled-skills/subagent/SKILL.md +21 -0
  211. package/src/config/bundled-skills/subagent/TOOLS.json +8 -4
  212. package/src/config/bundled-skills/tasks/SKILL.md +5 -0
  213. package/src/config/env-registry.ts +14 -0
  214. package/src/config/env.ts +21 -0
  215. package/src/config/feature-flag-registry.json +46 -7
  216. package/src/config/loader.ts +56 -1
  217. package/src/config/sanitize-for-transfer.ts +47 -0
  218. package/src/config/schema.ts +46 -5
  219. package/src/config/schemas/host-browser.ts +66 -0
  220. package/src/config/schemas/memory-lifecycle.ts +1 -1
  221. package/src/config/schemas/memory-retrieval.ts +103 -0
  222. package/src/config/schemas/security.ts +0 -6
  223. package/src/config/schemas/services.ts +16 -0
  224. package/src/config/types.ts +0 -1
  225. package/src/context/post-turn-tool-result-truncation.ts +176 -0
  226. package/src/context/window-manager.ts +19 -1
  227. package/src/credential-execution/approval-bridge.ts +49 -16
  228. package/src/credential-execution/managed-catalog.ts +3 -7
  229. package/src/daemon/__tests__/conversation-tool-setup.test.ts +186 -0
  230. package/src/daemon/app-source-watcher.ts +35 -0
  231. package/src/daemon/config-watcher.ts +6 -2
  232. package/src/daemon/context-overflow-approval.ts +5 -1
  233. package/src/daemon/conversation-agent-loop-handlers.ts +17 -2
  234. package/src/daemon/conversation-agent-loop.ts +74 -19
  235. package/src/daemon/conversation-attachments.ts +40 -1
  236. package/src/daemon/conversation-messaging.ts +3 -0
  237. package/src/daemon/conversation-process.ts +66 -3
  238. package/src/daemon/conversation-queue-manager.ts +8 -0
  239. package/src/daemon/conversation-runtime-assembly.ts +159 -20
  240. package/src/daemon/conversation-surfaces.ts +78 -12
  241. package/src/daemon/conversation-tool-setup.ts +74 -11
  242. package/src/daemon/conversation-workspace.ts +12 -0
  243. package/src/daemon/conversation.ts +227 -11
  244. package/src/daemon/date-context.ts +10 -10
  245. package/src/daemon/first-greeting.ts +3 -2
  246. package/src/daemon/handlers/conversations.ts +9 -139
  247. package/src/daemon/handlers/shared.ts +65 -0
  248. package/src/daemon/handlers/skills.ts +232 -37
  249. package/src/daemon/host-bash-proxy.ts +48 -13
  250. package/src/daemon/host-browser-proxy.ts +191 -0
  251. package/src/daemon/host-cu-proxy.ts +36 -11
  252. package/src/daemon/host-file-proxy.ts +57 -9
  253. package/src/daemon/lifecycle.ts +86 -12
  254. package/src/daemon/message-protocol.ts +7 -0
  255. package/src/daemon/message-types/conversations.ts +59 -13
  256. package/src/daemon/message-types/host-browser.ts +100 -0
  257. package/src/daemon/message-types/messages.ts +5 -6
  258. package/src/daemon/message-types/notifications.ts +12 -0
  259. package/src/daemon/message-types/settings.ts +12 -0
  260. package/src/daemon/message-types/skills.ts +10 -0
  261. package/src/daemon/message-types/subagents.ts +2 -0
  262. package/src/daemon/server.ts +112 -35
  263. package/src/daemon/tool-side-effects.ts +6 -0
  264. package/src/daemon/transport-hints.ts +14 -0
  265. package/src/inbound/platform-callback-registration.ts +18 -17
  266. package/src/index.ts +1 -1
  267. package/src/mcp/client.ts +59 -24
  268. package/src/memory/app-store.ts +31 -1
  269. package/src/memory/conversation-crud.ts +38 -10
  270. package/src/memory/conversation-directories.ts +39 -0
  271. package/src/memory/conversation-group-migration.ts +65 -5
  272. package/src/memory/conversation-starters-cadence.ts +76 -0
  273. package/src/memory/conversation-title-service.ts +5 -2
  274. package/src/memory/db-init.ts +12 -0
  275. package/src/memory/embedding-backend.test.ts +75 -0
  276. package/src/memory/embedding-backend.ts +131 -5
  277. package/src/memory/embedding-gemini.test.ts +54 -0
  278. package/src/memory/embedding-gemini.ts +20 -9
  279. package/src/memory/embedding-local.ts +177 -18
  280. package/src/memory/graph/capability-seed.ts +3 -5
  281. package/src/memory/graph/consolidation.ts +10 -23
  282. package/src/memory/graph/extraction-job.ts +15 -0
  283. package/src/memory/graph/retriever.ts +40 -22
  284. package/src/memory/graph/store.test.ts +7 -3
  285. package/src/memory/graph/store.ts +47 -12
  286. package/src/memory/group-crud.ts +25 -9
  287. package/src/memory/llm-usage-store.ts +45 -4
  288. package/src/memory/migrations/213-oauth-providers-scope-separator.ts +13 -0
  289. package/src/memory/migrations/214-oauth-providers-refresh-url.ts +11 -0
  290. package/src/memory/migrations/215-oauth-providers-revoke.ts +14 -0
  291. package/src/memory/migrations/216-oauth-providers-token-auth-method.ts +30 -0
  292. package/src/memory/migrations/217-conversation-host-access.ts +40 -0
  293. package/src/memory/migrations/218-oauth-providers-logo-url.ts +11 -0
  294. package/src/memory/migrations/index.ts +6 -0
  295. package/src/memory/migrations/registry.ts +8 -0
  296. package/src/memory/schema/conversations.ts +1 -0
  297. package/src/memory/schema/oauth.ts +18 -13
  298. package/src/messaging/provider.ts +1 -1
  299. package/src/notifications/broadcaster.ts +6 -0
  300. package/src/notifications/conversation-pairing.ts +12 -4
  301. package/src/notifications/emit-signal.ts +14 -0
  302. package/src/notifications/signal.ts +11 -0
  303. package/src/oauth/AGENTS.md +76 -0
  304. package/src/oauth/__tests__/identity-verifier.test.ts +24 -19
  305. package/src/oauth/__tests__/seed-providers-managed.test.ts +32 -0
  306. package/src/oauth/byo-connection.test.ts +8 -8
  307. package/src/oauth/byo-connection.ts +7 -7
  308. package/src/oauth/connect-orchestrator.ts +23 -21
  309. package/src/oauth/connect-types.ts +3 -3
  310. package/src/oauth/connection-resolver.test.ts +17 -4
  311. package/src/oauth/connection-resolver.ts +16 -16
  312. package/src/oauth/connection.ts +1 -1
  313. package/src/oauth/manual-token-connection.ts +13 -13
  314. package/src/oauth/oauth-store.ts +214 -100
  315. package/src/oauth/platform-connection.test.ts +5 -5
  316. package/src/oauth/platform-connection.ts +4 -4
  317. package/src/oauth/provider-serializer.ts +31 -5
  318. package/src/oauth/revoke.ts +76 -0
  319. package/src/oauth/seed-providers.ts +127 -87
  320. package/src/oauth/token-persistence.ts +1 -1
  321. package/src/permissions/checker.ts +3 -3
  322. package/src/permissions/defaults.ts +7 -8
  323. package/src/permissions/permission-mode.ts +4 -11
  324. package/src/permissions/prompter.ts +13 -3
  325. package/src/permissions/v2-consent-policy.ts +87 -0
  326. package/src/platform/client.ts +1 -1
  327. package/src/prompts/system-prompt.ts +18 -21
  328. package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +3 -65
  329. package/src/prompts/templates/BOOTSTRAP.md +59 -96
  330. package/src/prompts/templates/SOUL.md +11 -11
  331. package/src/providers/anthropic/client.ts +1 -0
  332. package/src/providers/types.ts +1 -1
  333. package/src/runtime/AGENTS.md +23 -0
  334. package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +715 -0
  335. package/src/runtime/__tests__/capability-tokens.test.ts +258 -0
  336. package/src/runtime/__tests__/chrome-extension-registry.test.ts +518 -0
  337. package/src/runtime/assistant-event-hub.ts +24 -2
  338. package/src/runtime/auth/__tests__/guard-tests.test.ts +1 -0
  339. package/src/runtime/auth/__tests__/middleware.test.ts +116 -1
  340. package/src/runtime/auth/__tests__/route-policy.test.ts +8 -0
  341. package/src/runtime/auth/middleware.ts +98 -0
  342. package/src/runtime/auth/route-policy.ts +6 -7
  343. package/src/runtime/auth/token-service.ts +8 -0
  344. package/src/runtime/capability-tokens.ts +414 -0
  345. package/src/runtime/channel-approvals.ts +18 -5
  346. package/src/runtime/chrome-extension-registry.ts +332 -0
  347. package/src/runtime/confirmation-request-guardian-bridge.ts +6 -0
  348. package/src/runtime/guardian-decision-types.ts +7 -0
  349. package/src/runtime/http-server.ts +425 -70
  350. package/src/runtime/migrations/__tests__/rebind-secrets-credentials.test.ts +172 -0
  351. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +276 -0
  352. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +162 -0
  353. package/src/runtime/migrations/migration-transport.ts +6 -0
  354. package/src/runtime/migrations/migration-wizard.ts +22 -2
  355. package/src/runtime/migrations/rebind-secrets-screen.ts +76 -15
  356. package/src/runtime/migrations/vbundle-builder.ts +145 -38
  357. package/src/runtime/migrations/vbundle-import-analyzer.ts +19 -0
  358. package/src/runtime/migrations/vbundle-importer.ts +55 -5
  359. package/src/runtime/pending-interactions.ts +29 -13
  360. package/src/runtime/routes/approval-routes.ts +90 -16
  361. package/src/runtime/routes/browser-cdp-routes.ts +229 -0
  362. package/src/runtime/routes/browser-extension-pair-routes.ts +497 -0
  363. package/src/runtime/routes/conversation-analysis-routes.ts +18 -5
  364. package/src/runtime/routes/conversation-management-routes.ts +108 -0
  365. package/src/runtime/routes/conversation-routes.ts +308 -28
  366. package/src/runtime/routes/conversation-starter-routes.ts +78 -16
  367. package/src/runtime/routes/group-routes.ts +22 -8
  368. package/src/runtime/routes/guardian-action-routes.ts +24 -13
  369. package/src/runtime/routes/host-browser-routes.ts +279 -0
  370. package/src/runtime/routes/host-file-routes.ts +9 -1
  371. package/src/runtime/routes/identity-routes.ts +259 -16
  372. package/src/runtime/routes/log-export/AGENTS.md +104 -0
  373. package/src/runtime/routes/log-export/__tests__/workspace-allowlist-error-contract.test.ts +103 -0
  374. package/src/runtime/routes/log-export/__tests__/workspace-allowlist.test.ts +716 -0
  375. package/src/runtime/routes/log-export/workspace-allowlist.ts +458 -0
  376. package/src/runtime/routes/log-export-routes.ts +60 -25
  377. package/src/runtime/routes/memory-item-routes.ts +1 -7
  378. package/src/runtime/routes/migration-routes.ts +87 -2
  379. package/src/runtime/routes/oauth-apps.ts +15 -17
  380. package/src/runtime/routes/oauth-providers.ts +4 -0
  381. package/src/runtime/routes/schedule-routes.ts +24 -11
  382. package/src/runtime/routes/settings-routes.ts +9 -97
  383. package/src/runtime/routes/skills-routes.ts +52 -2
  384. package/src/runtime/routes/subagents-routes.ts +14 -10
  385. package/src/runtime/routes/usage-routes.ts +8 -7
  386. package/src/runtime/routes/workspace-routes.test.ts +22 -0
  387. package/src/runtime/routes/workspace-routes.ts +8 -1
  388. package/src/runtime/routes/workspace-utils.ts +2 -0
  389. package/src/schedule/scheduler.ts +7 -5
  390. package/src/security/ces-credential-client.ts +20 -0
  391. package/src/security/ces-rpc-credential-backend.ts +17 -0
  392. package/src/security/credential-backend.ts +5 -0
  393. package/src/security/oauth2.ts +42 -25
  394. package/src/security/secure-keys.ts +118 -25
  395. package/src/security/token-manager.ts +23 -10
  396. package/src/skills/catalog-files.ts +492 -0
  397. package/src/skills/inline-command-runner.ts +12 -14
  398. package/src/subagent/manager.ts +131 -26
  399. package/src/subagent/types.ts +19 -0
  400. package/src/tools/apps/executors.ts +11 -2
  401. package/src/tools/browser/__tests__/auth-detector.test.ts +202 -108
  402. package/src/tools/browser/auth-detector.ts +43 -12
  403. package/src/tools/browser/browser-execution.ts +645 -340
  404. package/src/tools/browser/browser-manager.ts +36 -12
  405. package/src/tools/browser/cdp-client/__tests__/accessibility-snapshot.test.ts +318 -0
  406. package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +1175 -0
  407. package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +870 -0
  408. package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +330 -0
  409. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +377 -0
  410. package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-nested-frames.json +64 -0
  411. package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-simple.json +69 -0
  412. package/src/tools/browser/cdp-client/__tests__/local-cdp-client.test.ts +310 -0
  413. package/src/tools/browser/cdp-client/__tests__/types.test.ts +96 -0
  414. package/src/tools/browser/cdp-client/accessibility-snapshot.ts +387 -0
  415. package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +695 -0
  416. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +743 -0
  417. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +580 -0
  418. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +578 -0
  419. package/src/tools/browser/cdp-client/cdp-inspect/ws-transport.ts +579 -0
  420. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +635 -0
  421. package/src/tools/browser/cdp-client/errors.ts +34 -0
  422. package/src/tools/browser/cdp-client/extension-cdp-client.ts +125 -0
  423. package/src/tools/browser/cdp-client/factory.ts +204 -0
  424. package/src/tools/browser/cdp-client/index.ts +14 -0
  425. package/src/tools/browser/cdp-client/local-cdp-client.ts +187 -0
  426. package/src/tools/browser/cdp-client/types.ts +52 -0
  427. package/src/tools/filesystem/edit.ts +1 -1
  428. package/src/tools/filesystem/list.ts +1 -1
  429. package/src/tools/filesystem/read.ts +1 -1
  430. package/src/tools/filesystem/write.ts +2 -1
  431. package/src/tools/host-filesystem/edit.ts +1 -1
  432. package/src/tools/host-filesystem/read.ts +12 -15
  433. package/src/tools/host-filesystem/write.ts +1 -1
  434. package/src/tools/host-terminal/host-shell.ts +21 -16
  435. package/src/tools/permission-checker.ts +77 -100
  436. package/src/tools/registry.ts +0 -2
  437. package/src/tools/secret-detection-handler.ts +34 -1
  438. package/src/tools/shared/filesystem/image-read.ts +61 -40
  439. package/src/tools/skills/sandbox-runner.ts +3 -6
  440. package/src/tools/subagent/spawn.ts +47 -3
  441. package/src/tools/subagent/status.ts +2 -0
  442. package/src/tools/system/register.ts +2 -16
  443. package/src/tools/terminal/safe-env.ts +7 -0
  444. package/src/tools/terminal/sandbox-diagnostics.ts +4 -4
  445. package/src/tools/terminal/sandbox.ts +4 -1
  446. package/src/tools/terminal/shell.ts +24 -21
  447. package/src/tools/tool-approval-handler.ts +48 -2
  448. package/src/tools/types.ts +2 -3
  449. package/src/util/platform.ts +14 -19
  450. package/src/watcher/provider-types.ts +1 -1
  451. package/src/workspace/migrations/029-seed-pkb.ts +1 -0
  452. package/src/workspace/migrations/030-seed-pkb-autoinject.ts +73 -0
  453. package/src/workspace/migrations/registry.ts +2 -0
  454. package/src/workspace/top-level-renderer.ts +19 -1
  455. package/src/__tests__/chrome-cdp.test.ts +0 -419
  456. package/src/__tests__/permission-mode-sse.test.ts +0 -418
  457. package/src/__tests__/permission-mode-store.test.ts +0 -277
  458. package/src/browser-extension-relay/protocol.ts +0 -63
  459. package/src/browser-extension-relay/server.ts +0 -203
  460. package/src/config/schemas/sandbox.ts +0 -14
  461. package/src/permissions/permission-mode-store.ts +0 -180
  462. package/src/tools/browser/chrome-cdp.ts +0 -239
  463. package/src/tools/system/set-permission-mode.ts +0 -103
@@ -1,6 +1,11 @@
1
1
  // Conversation lifecycle, auth, model config, and history types.
2
2
 
3
- import type { ChannelId, InterfaceId } from "../../channels/types.js";
3
+ import type {
4
+ ChannelId,
5
+ HostProxyInterfaceId,
6
+ InterfaceId,
7
+ } from "../../channels/types.js";
8
+ import { supportsHostProxy } from "../../channels/types.js";
4
9
  import type { ConversationType } from "./shared.js";
5
10
  import type { UserMessageAttachment } from "./shared.js";
6
11
 
@@ -26,26 +31,61 @@ interface BaseTransportMetadata {
26
31
  chatType?: string;
27
32
  }
28
33
 
29
- /** Transport metadata for macOS desktop clients, including host environment fields. */
30
- export interface MacosTransportMetadata extends BaseTransportMetadata {
31
- /** Interface identifier for macOS transport. */
32
- interfaceId: "macos";
33
- /** Home directory of the host macOS user. */
34
+ /**
35
+ * Transport metadata for interfaces that support the full desktop host-proxy
36
+ * set (see `HostProxyInterfaceId` / `supportsHostProxy`). Carries the host
37
+ * environment fields the client reports so the `<workspace>` block renders
38
+ * the user's actual machine rather than a containerized daemon's own OS.
39
+ *
40
+ * Today this variant is populated only by the macOS client, but the shape
41
+ * is capability-keyed (not interface-name-keyed) so future host-capable
42
+ * clients (e.g. a native Linux or Windows desktop) get the same treatment
43
+ * automatically when added to `HostProxyInterfaceId`.
44
+ */
45
+ export interface HostProxyTransportMetadata extends BaseTransportMetadata {
46
+ /** Interface identifier — restricted to interfaces that support host proxies. */
47
+ interfaceId: HostProxyInterfaceId;
48
+ /** Home directory of the user on the host machine (e.g. `NSHomeDirectory()`). */
34
49
  hostHomeDir?: string;
35
- /** Username of the host macOS user. */
50
+ /** Username of the user on the host machine (e.g. `NSUserName()`). */
36
51
  hostUsername?: string;
37
52
  }
38
53
 
39
- /** Transport metadata for non-macOS transports. */
40
- export interface NonMacosTransportMetadata extends BaseTransportMetadata {
54
+ /**
55
+ * Transport metadata for interfaces that do NOT support host-proxy tools
56
+ * (iOS, CLI, channel ingress, chrome-extension, etc.). No host environment
57
+ * because the assistant has no local filesystem to address on the client.
58
+ */
59
+ export interface NonHostProxyTransportMetadata extends BaseTransportMetadata {
41
60
  /** Interface identifier for this transport (e.g. "ios", "cli"). */
42
- interfaceId?: Exclude<InterfaceId, "macos">;
61
+ interfaceId?: Exclude<InterfaceId, HostProxyInterfaceId>;
43
62
  }
44
63
 
45
- /** Lightweight conversation transport metadata for channel identity and natural-language guidance. */
64
+ /**
65
+ * Discriminated union of transport metadata variants, keyed on whether the
66
+ * interface supports host-proxy tools (`supportsHostProxy`). The daemon uses
67
+ * that same predicate at runtime to decide whether to populate / read host
68
+ * environment fields on the conversation, so the type system and the runtime
69
+ * gate stay in lock-step as new host-capable interfaces are added.
70
+ */
46
71
  export type ConversationTransportMetadata =
47
- | MacosTransportMetadata
48
- | NonMacosTransportMetadata;
72
+ | HostProxyTransportMetadata
73
+ | NonHostProxyTransportMetadata;
74
+
75
+ /**
76
+ * Type guard: does this transport belong to an interface that supports the
77
+ * full host-proxy set? Wraps `supportsHostProxy` so the capability logic
78
+ * stays in one place (channels/types.ts) and narrows the discriminated
79
+ * union to `HostProxyTransportMetadata` for safe field access.
80
+ */
81
+ export function isHostProxyTransport(
82
+ transport: ConversationTransportMetadata,
83
+ ): transport is HostProxyTransportMetadata {
84
+ return (
85
+ transport.interfaceId !== undefined &&
86
+ supportsHostProxy(transport.interfaceId)
87
+ );
88
+ }
49
89
 
50
90
  export interface ConversationCreateRequest {
51
91
  type: "conversation_create";
@@ -171,6 +211,7 @@ export interface ConversationInfo {
171
211
  title: string;
172
212
  correlationId?: string;
173
213
  conversationType?: ConversationType;
214
+ hostAccess: boolean;
174
215
  }
175
216
 
176
217
  export interface ConversationTitleUpdated {
@@ -212,6 +253,7 @@ export interface ConversationListResponse {
212
253
  updatedAt: number;
213
254
  conversationType?: ConversationType;
214
255
  source?: string;
256
+ hostAccess: boolean;
215
257
  scheduleJobId?: string;
216
258
  channelBinding?: ChannelBinding;
217
259
  conversationOriginChannel?: ChannelId;
@@ -309,6 +351,10 @@ export interface HistoryResponseSurface {
309
351
  data?: Record<string, unknown>;
310
352
  }>;
311
353
  display?: string;
354
+ /** True when the surface was completed (e.g. form submitted, action taken). */
355
+ completed?: boolean;
356
+ /** Human-readable summary shown in the completion chip. */
357
+ completionSummary?: string;
312
358
  }
313
359
 
314
360
  export interface HistoryResponse {
@@ -0,0 +1,100 @@
1
+ // Host browser proxy types.
2
+ // Enables proxying CDP commands to the desktop client (host machine)
3
+ // when running as a managed assistant.
4
+
5
+ // === Server → Client ===
6
+
7
+ export interface HostBrowserRequest {
8
+ type: "host_browser_request";
9
+ requestId: string;
10
+ conversationId: string;
11
+ /** CDP method name, e.g. "Page.navigate", "Runtime.evaluate", "Accessibility.getFullAXTree". */
12
+ cdpMethod: string;
13
+ /** Opaque JSON params object forwarded verbatim to CDP. */
14
+ cdpParams?: Record<string, unknown>;
15
+ /** Optional CDP target/session ID; omitted = "most-recently-active tab". */
16
+ cdpSessionId?: string;
17
+ /** Client-side timeout hint; defaults to 30s in the proxy. */
18
+ timeout_seconds?: number;
19
+ }
20
+
21
+ export interface HostBrowserCancelRequest {
22
+ type: "host_browser_cancel";
23
+ requestId: string;
24
+ }
25
+
26
+ // === Client → Server ===
27
+
28
+ /**
29
+ * Unsolicited CDP event forwarded from the chrome extension to the
30
+ * runtime. The extension subscribes to `chrome.debugger.onEvent` and
31
+ * pushes each event here so the runtime can observe lifecycle signals
32
+ * (e.g. `Target.targetDestroyed`, `Page.frameNavigated`,
33
+ * `Network.requestWillBeSent`) without having to round-trip a CDP
34
+ * command. Events are routed through the relay WebSocket using the
35
+ * same envelope vocabulary as `host_browser_result`.
36
+ *
37
+ * The envelope is transport-level only — the runtime dispatcher in
38
+ * `resolveHostBrowserEvent` fans out into a module-level event bus
39
+ * that tool-side consumers (currently just the
40
+ * BrowserSessionRegistry) subscribe to by method name. No request/
41
+ * response contract is implied; events can arrive at any time while
42
+ * a chrome extension is attached and there is no ordering guarantee
43
+ * relative to `host_browser_result` frames.
44
+ */
45
+ export interface HostBrowserEvent {
46
+ type: "host_browser_event";
47
+ /** CDP event method name, e.g. "Page.frameNavigated", "Target.targetDestroyed". */
48
+ method: string;
49
+ /** CDP event params forwarded verbatim. Opaque to the runtime. */
50
+ params?: unknown;
51
+ /**
52
+ * Optional CDP session id — populated for flat child sessions
53
+ * routed through `Target.attachToTarget` with `flatten: true`.
54
+ * Matches the `source.sessionId` field surfaced by Chrome 125+ in
55
+ * its `chrome.debugger.onEvent` callback.
56
+ */
57
+ cdpSessionId?: string;
58
+ }
59
+
60
+ /**
61
+ * Notification that the chrome extension has lost its debugger
62
+ * attachment to a target (tab closed, user clicked Cancel on the
63
+ * infobar, navigation across origins, another debugger took over
64
+ * via `Target.attachToTarget`, or the extension itself tore the
65
+ * session down on worker shutdown).
66
+ *
67
+ * The runtime dispatcher evicts any in-memory session state that
68
+ * references the invalidated target so the next CDP command from a
69
+ * tool force a fresh attach on the extension side. The extension's
70
+ * `host-browser-dispatcher` clears its local attach cache in the
71
+ * same way — the two signals are symmetric and together make
72
+ * reattach deterministic across the round-trip.
73
+ */
74
+ export interface HostBrowserSessionInvalidated {
75
+ type: "host_browser_session_invalidated";
76
+ /**
77
+ * Opaque target identifier. When the extension detached from a
78
+ * top-level tab target, this is the tab's id as a string. For a
79
+ * flat child session it is the CDP sessionId. Matches the shape
80
+ * used on the `cdpSessionId` field of outbound
81
+ * `host_browser_request` frames so runtime-side session lookups
82
+ * can use either field interchangeably.
83
+ */
84
+ targetId?: string;
85
+ /**
86
+ * Free-form human-readable reason surfaced by Chrome via
87
+ * `chrome.debugger.onDetach`. Used only for logging.
88
+ */
89
+ reason?: string;
90
+ }
91
+
92
+ // --- Domain-level union aliases (consumed by the barrel file) ---
93
+
94
+ export type _HostBrowserServerMessages =
95
+ | HostBrowserRequest
96
+ | HostBrowserCancelRequest;
97
+
98
+ export type _HostBrowserClientMessages =
99
+ | HostBrowserEvent
100
+ | HostBrowserSessionInvalidated;
@@ -151,7 +151,6 @@ export interface ConfirmationRequest {
151
151
  newContent: string;
152
152
  isNewFile: boolean;
153
153
  };
154
- sandboxed?: boolean;
155
154
  conversationId?: string;
156
155
  /** When false, the client should hide "always allow" / trust-rule persistence affordances. */
157
156
  persistentDecisionsAllowed?: boolean;
@@ -308,10 +307,10 @@ export interface AssistantActivityState {
308
307
  statusText?: string;
309
308
  }
310
309
 
311
- /** Broadcast to clients when the two-axis permission mode changes. */
312
- export interface PermissionModeUpdate {
313
- type: "permission_mode_update";
314
- askBeforeActing: boolean;
310
+ /** Broadcast to clients when a conversation's host-access setting changes. */
311
+ export interface ConversationHostAccessUpdated {
312
+ type: "conversation_host_access_updated";
313
+ conversationId: string;
315
314
  hostAccess: boolean;
316
315
  }
317
316
 
@@ -377,4 +376,4 @@ export type _MessagesServerMessages =
377
376
  | TraceEvent
378
377
  | ConfirmationStateChanged
379
378
  | AssistantActivityState
380
- | PermissionModeUpdate;
379
+ | ConversationHostAccessUpdated;
@@ -27,6 +27,18 @@ export interface NotificationConversationCreated {
27
27
  * and should only be surfaced by clients bound to this guardian identity.
28
28
  */
29
29
  targetGuardianPrincipalId?: string;
30
+ /**
31
+ * Conversation group identifier propagated from the signal producer.
32
+ * Clients use this to place the conversation in the correct sidebar folder
33
+ * (e.g. "system:scheduled" for schedule completion threads).
34
+ */
35
+ groupId?: string;
36
+ /**
37
+ * Semantic source of the conversation (e.g. "schedule", "reminder").
38
+ * Allows clients to override the default "notification" source so the
39
+ * conversation is attributed correctly.
40
+ */
41
+ source?: string;
30
42
  }
31
43
 
32
44
  /** Client ack sent after UNUserNotificationCenter.add() completes (or fails). */
@@ -34,11 +34,21 @@ export interface AvatarUpdated {
34
34
  avatarPath: string;
35
35
  }
36
36
 
37
+ /** Sent by the daemon when workspace config.json changes on disk. */
38
+ export interface ConfigChanged {
39
+ type: "config_changed";
40
+ }
41
+
37
42
  /** Sent by the daemon when sounds config or sound files change on disk. */
38
43
  export interface SoundsConfigUpdated {
39
44
  type: "sounds_config_updated";
40
45
  }
41
46
 
47
+ /** Sent by the daemon when feature flag files change on disk. */
48
+ export interface FeatureFlagsChanged {
49
+ type: "feature_flags_changed";
50
+ }
51
+
42
52
  /** Response to a generate_avatar request indicating success or failure. */
43
53
  export interface GenerateAvatarResponse {
44
54
  type: "generate_avatar_response";
@@ -56,5 +66,7 @@ export type _SettingsClientMessages =
56
66
  export type _SettingsServerMessages =
57
67
  | ClientSettingsUpdate
58
68
  | AvatarUpdated
69
+ | ConfigChanged
59
70
  | SoundsConfigUpdated
71
+ | FeatureFlagsChanged
60
72
  | GenerateAvatarResponse;
@@ -189,6 +189,16 @@ export type SkillDetailResponse =
189
189
  | SkillsshSkillDetail
190
190
  | CustomSkillDetail;
191
191
 
192
+ // ─── Single-file content response (HTTP API) ─────────────────────────────
193
+ export interface SkillFileContentResponse {
194
+ path: string;
195
+ name: string;
196
+ size: number;
197
+ mimeType: string;
198
+ isBinary: boolean;
199
+ content: string | null;
200
+ }
201
+
192
202
  export interface SkillsDraftResponse {
193
203
  type: "skills_draft_response";
194
204
  success: boolean;
@@ -10,6 +10,7 @@ export interface SubagentSpawned {
10
10
  parentConversationId: string;
11
11
  label: string;
12
12
  objective: string;
13
+ isFork?: boolean;
13
14
  }
14
15
 
15
16
  export interface SubagentStatusChanged {
@@ -29,6 +30,7 @@ export interface SubagentDetailResponse {
29
30
  content: string;
30
31
  toolName?: string;
31
32
  isError?: boolean;
33
+ messageId?: string;
32
34
  }>;
33
35
  }
34
36
 
@@ -17,6 +17,7 @@ import {
17
17
  type InterfaceId,
18
18
  parseChannelId,
19
19
  parseInterfaceId,
20
+ supportsHostProxy,
20
21
  } from "../channels/types.js";
21
22
  import { getConfig } from "../config/loader.js";
22
23
  import { onContactChange } from "../contacts/contact-events.js";
@@ -65,7 +66,10 @@ import {
65
66
  getWorkspacePromptPath,
66
67
  } from "../util/platform.js";
67
68
  import { registerDaemonCallbacks } from "../work-items/work-item-runner.js";
68
- import { AppSourceWatcher } from "./app-source-watcher.js";
69
+ import {
70
+ AppSourceWatcher,
71
+ setEnsureAppSourceWatcher,
72
+ } from "./app-source-watcher.js";
69
73
  import { ConfigWatcher } from "./config-watcher.js";
70
74
  import {
71
75
  Conversation,
@@ -85,12 +89,14 @@ import type {
85
89
  } from "./handlers/shared.js";
86
90
  import type { SkillOperationContext } from "./handlers/skills.js";
87
91
  import { HostBashProxy } from "./host-bash-proxy.js";
92
+ import { HostBrowserProxy } from "./host-browser-proxy.js";
88
93
  import { HostCuProxy } from "./host-cu-proxy.js";
89
94
  import { HostFileProxy } from "./host-file-proxy.js";
90
95
  import type {
91
96
  ServerMessage,
92
97
  UserMessageAttachment,
93
98
  } from "./message-protocol.js";
99
+ import { buildTransportHints } from "./transport-hints.js";
94
100
 
95
101
  const log = getLogger("server");
96
102
 
@@ -156,9 +162,10 @@ function resolveCanonicalRequestSourceType(
156
162
 
157
163
  /**
158
164
  * Build an onEvent callback that registers pending interactions when the agent
159
- * loop emits confirmation_request, secret_request, host_bash_request, or
160
- * host_file_request events. This ensures that channel approval interception
161
- * can look up the conversation by requestId.
165
+ * loop emits confirmation_request, secret_request, host_bash_request,
166
+ * host_browser_request, host_file_request, or host_cu_request events. This
167
+ * ensures that channel approval interception can look up the conversation by
168
+ * requestId.
162
169
  */
163
170
  function makePendingInteractionRegistrar(
164
171
  conversation: Conversation,
@@ -247,6 +254,12 @@ function makePendingInteractionRegistrar(
247
254
  conversationId,
248
255
  kind: "host_bash",
249
256
  });
257
+ } else if (msg.type === "host_browser_request") {
258
+ pendingInteractions.register(msg.requestId, {
259
+ conversation,
260
+ conversationId,
261
+ kind: "host_browser",
262
+ });
250
263
  } else if (msg.type === "host_file_request") {
251
264
  pendingInteractions.register(msg.requestId, {
252
265
  conversation,
@@ -373,35 +386,24 @@ export class DaemonServer {
373
386
  { channelId: transport.channelId },
374
387
  "Transport metadata received",
375
388
  );
376
-
377
- // Build enriched hints: interface ID first, then host environment (macOS
378
- // only), then any client-provided hints.
379
- const enrichedHints: string[] = [];
380
-
381
- const interfaceLabel = parseInterfaceId(transport.interfaceId) ?? "vellum";
382
- enrichedHints.push(`User is messaging from interface: ${interfaceLabel}`);
383
-
384
- if (transport.interfaceId === "macos") {
385
- if (transport.hostHomeDir) {
386
- enrichedHints.push(`Host home directory: ${transport.hostHomeDir}`);
387
- }
388
- if (transport.hostUsername) {
389
- enrichedHints.push(`Host username: ${transport.hostUsername}`);
390
- }
391
- }
392
-
393
- if (transport.hints) {
394
- enrichedHints.push(...transport.hints);
395
- }
396
-
397
- conversation.setTransportHints(enrichedHints);
389
+ conversation.setTransportHints(buildTransportHints(transport));
390
+ // Route client-reported host env through the capability-gated setter on
391
+ // Conversation so both the create/reuse path here and the queue-drain
392
+ // path in conversation-process share one implementation. The method
393
+ // gates on `supportsHostProxy` (not a specific interface name), so any
394
+ // new host-capable client added to `HostProxyInterfaceId` will flow its
395
+ // host env through automatically.
396
+ conversation.applyHostEnvFromTransport(transport);
398
397
  }
399
398
 
400
399
  constructor() {
401
400
  this.evictor = new ConversationEvictor(this.conversations);
402
401
  getSubagentManager().sharedRequestTimestamps = this.sharedRequestTimestamps;
403
402
  getSubagentManager().broadcastToAllClients = (msg) => this.broadcast(msg);
403
+ getSubagentManager().resolveParentConversation = (id) =>
404
+ this.conversations.get(id);
404
405
  setBroadcastToAllClients((msg) => this.broadcast(msg));
406
+ setEnsureAppSourceWatcher(() => this.appSourceWatcher.ensureStarted());
405
407
  this.evictor.onEvict = (conversationId: string) => {
406
408
  getSubagentManager().abortAllForParent(conversationId);
407
409
  };
@@ -548,10 +550,18 @@ export class DaemonServer {
548
550
  }
549
551
  }
550
552
 
553
+ private broadcastConfigChanged(): void {
554
+ this.broadcast({ type: "config_changed" });
555
+ }
556
+
551
557
  private broadcastSoundsConfigUpdated(): void {
552
558
  this.broadcast({ type: "sounds_config_updated" });
553
559
  }
554
560
 
561
+ private broadcastFeatureFlagsChanged(): void {
562
+ this.broadcast({ type: "feature_flags_changed" });
563
+ }
564
+
555
565
  private broadcastAvatarUpdated(): void {
556
566
  this.broadcast({
557
567
  type: "avatar_updated",
@@ -748,6 +758,8 @@ export class DaemonServer {
748
758
  () => this.broadcastIdentityChanged(),
749
759
  () => this.broadcastSoundsConfigUpdated(),
750
760
  () => this.broadcastAvatarUpdated(),
761
+ () => this.broadcastConfigChanged(),
762
+ () => this.broadcastFeatureFlagsChanged(),
751
763
  );
752
764
 
753
765
  this.appSourceWatcher.start((appId) => this.handleAppSourceChange(appId));
@@ -889,10 +901,11 @@ export class DaemonServer {
889
901
  let conversation = this.conversations.get(conversationId);
890
902
  const sendToClient = () => {};
891
903
 
892
- if (options && Object.values(options).some((v) => v !== undefined)) {
904
+ const { taskRunId: _taskRunId, ...persistentOptions } = options ?? {};
905
+ if (Object.values(persistentOptions).some((v) => v !== undefined)) {
893
906
  this.conversationOptions.set(conversationId, {
894
907
  ...this.conversationOptions.get(conversationId),
895
- ...options,
908
+ ...persistentOptions,
896
909
  });
897
910
  }
898
911
 
@@ -978,7 +991,13 @@ export class DaemonServer {
978
991
  }
979
992
  this.evictor.touch(conversationId);
980
993
  } else {
981
- this.applyTransportMetadata(conversation, options);
994
+ // Only apply transport metadata when the conversation is idle.
995
+ // When processing, the hints are stored on the queued message and
996
+ // will be applied at dequeue time — applying them here would
997
+ // overwrite the in-flight conversation's transportHints.
998
+ if (!conversation.isProcessing()) {
999
+ this.applyTransportMetadata(conversation, options);
1000
+ }
982
1001
  this.evictor.touch(conversationId);
983
1002
  }
984
1003
  return conversation;
@@ -1058,6 +1077,7 @@ export class DaemonServer {
1058
1077
  conversation.setAssistantId(
1059
1078
  options?.assistantId ?? DAEMON_INTERNAL_ASSISTANT_ID,
1060
1079
  );
1080
+ conversation.taskRunId = options?.taskRunId;
1061
1081
  // Only overwrite trust/auth context when explicitly provided. Callers that
1062
1082
  // don't supply a trust context (e.g. signal-injected messages) should
1063
1083
  // inherit whatever the conversation already has from a prior session.
@@ -1085,13 +1105,36 @@ export class DaemonServer {
1085
1105
  options?.transport?.chatType,
1086
1106
  ),
1087
1107
  );
1088
- // Only create the host bash proxy for desktop client interfaces that can
1089
- // execute commands on the user's machine. Non-desktop conversations (CLI,
1090
- // channels, headless) fall back to local execution.
1108
+ // Chrome-extension host_browser wiring is intentionally not supported
1109
+ // through this entry point. `prepareConversationForMessage` constructs
1110
+ // host_browser proxies that capture `conversation.getCurrentSender()`
1111
+ // directly, which would route browser frames through the daemon SSE
1112
+ // channel instead of the `ChromeExtensionRegistry`. Chrome-extension
1113
+ // flows reach host_browser exclusively through the
1114
+ // `/v1/messages` flow in `conversation-routes.ts`, which wires a
1115
+ // registry-aware sender and sets `hostBrowserSenderOverride`.
1116
+ //
1117
+ // Fail loudly rather than silently returning a mis-wired proxy so that
1118
+ // any future caller that tries to route chrome-extension through this
1119
+ // path discovers the gap immediately. When the time comes, factor the
1120
+ // wiring in conversation-routes.ts (registry lookup + override) into a
1121
+ // shared helper and call it from both sites.
1122
+ if (resolvedInterface === "chrome-extension") {
1123
+ throw new Error(
1124
+ "prepareConversationForMessage does not yet support chrome-extension transport — " +
1125
+ "use the conversation-routes.ts /v1/messages flow which routes host_browser through " +
1126
+ "the ChromeExtensionRegistry. If you need chrome-extension here, factor out the " +
1127
+ "wiring in conversation-routes.ts into a shared helper.",
1128
+ );
1129
+ }
1130
+ // Only create each host proxy for interfaces that support the matching
1131
+ // capability. macOS supports all four; the chrome-extension interface only
1132
+ // supports host_browser. Non-desktop conversations (CLI, channels, headless)
1133
+ // fall back to local execution.
1091
1134
  // Guard: don't replace an active proxy during concurrent turn races —
1092
1135
  // another request may have started processing between the isProcessing()
1093
1136
  // check above and the await on ensureActorScopedHistory().
1094
- if (resolvedInterface === "macos") {
1137
+ if (supportsHostProxy(resolvedInterface, "host_bash")) {
1095
1138
  if (!conversation.isProcessing() || !conversation.hostBashProxy) {
1096
1139
  conversation.setHostBashProxy(
1097
1140
  new HostBashProxy(conversation.getCurrentSender(), (requestId) => {
@@ -1099,6 +1142,21 @@ export class DaemonServer {
1099
1142
  }),
1100
1143
  );
1101
1144
  }
1145
+ } else if (!conversation.isProcessing()) {
1146
+ conversation.setHostBashProxy(undefined);
1147
+ }
1148
+ if (supportsHostProxy(resolvedInterface, "host_browser")) {
1149
+ if (!conversation.isProcessing() || !conversation.hostBrowserProxy) {
1150
+ conversation.setHostBrowserProxy(
1151
+ new HostBrowserProxy(conversation.getCurrentSender(), (requestId) => {
1152
+ pendingInteractions.resolve(requestId);
1153
+ }),
1154
+ );
1155
+ }
1156
+ } else if (!conversation.isProcessing()) {
1157
+ conversation.setHostBrowserProxy(undefined);
1158
+ }
1159
+ if (supportsHostProxy(resolvedInterface, "host_file")) {
1102
1160
  if (!conversation.isProcessing() || !conversation.hostFileProxy) {
1103
1161
  conversation.setHostFileProxy(
1104
1162
  new HostFileProxy(conversation.getCurrentSender(), (requestId) => {
@@ -1106,6 +1164,10 @@ export class DaemonServer {
1106
1164
  }),
1107
1165
  );
1108
1166
  }
1167
+ } else if (!conversation.isProcessing()) {
1168
+ conversation.setHostFileProxy(undefined);
1169
+ }
1170
+ if (supportsHostProxy(resolvedInterface, "host_cu")) {
1109
1171
  if (!conversation.isProcessing() || !conversation.hostCuProxy) {
1110
1172
  conversation.setHostCuProxy(
1111
1173
  new HostCuProxy(conversation.getCurrentSender(), (requestId) => {
@@ -1115,8 +1177,6 @@ export class DaemonServer {
1115
1177
  }
1116
1178
  conversation.addPreactivatedSkillId("computer-use");
1117
1179
  } else if (!conversation.isProcessing()) {
1118
- conversation.setHostBashProxy(undefined);
1119
- conversation.setHostFileProxy(undefined);
1120
1180
  conversation.setHostCuProxy(undefined);
1121
1181
  }
1122
1182
  conversation.setCommandIntent(options?.commandIntent ?? null);
@@ -1195,8 +1255,25 @@ export class DaemonServer {
1195
1255
  }
1196
1256
  }
1197
1257
  : registrar;
1258
+ // Non-interactive interfaces that still have a connected client capable
1259
+ // of handling host_browser_request events (e.g. chrome-extension) need
1260
+ // their hostBrowserProxy explicitly marked connected. The proxy
1261
+ // constructor defaults clientConnected = false, so without an explicit
1262
+ // sender update the chrome-extension proxy would be created and
1263
+ // immediately unavailable. We do NOT call updateClient(onEvent, false)
1264
+ // for that case, because flipping hasNoClient false would also enable
1265
+ // host_bash/host_file/host_cu tool gating for an interface that can't
1266
+ // service them. Instead, provision just the browser proxy's sender.
1267
+ const persistInterfaceCtx = conversation.getTurnInterfaceContext();
1268
+ const persistInterface = persistInterfaceCtx?.userMessageInterface;
1198
1269
  if (options?.isInteractive === true) {
1199
1270
  conversation.updateClient(onEvent, false);
1271
+ } else if (
1272
+ persistInterface &&
1273
+ !supportsHostProxy(persistInterface) &&
1274
+ supportsHostProxy(persistInterface, "host_browser")
1275
+ ) {
1276
+ conversation.hostBrowserProxy?.updateSender(onEvent, true);
1200
1277
  }
1201
1278
 
1202
1279
  conversation
@@ -15,6 +15,7 @@ import { deliverVerificationSlack } from "../runtime/verification-outbound-actio
15
15
  import { updatePublishedAppDeployment } from "../services/published-app-updater.js";
16
16
  import type { ToolExecutionResult } from "../tools/types.js";
17
17
  import { getLogger } from "../util/logger.js";
18
+ import { ensureAppSourceWatcher } from "./app-source-watcher.js";
18
19
  import { refreshSurfacesForApp } from "./conversation-surfaces.js";
19
20
  import type { ToolSetupContext } from "./conversation-tool-setup.js";
20
21
  import { isDoordashCommand, updateDoordashProgress } from "./doordash-steps.js";
@@ -109,6 +110,11 @@ registerHook(
109
110
  description?: string;
110
111
  };
111
112
  if (parsed.id) {
113
+ // The apps directory may have just been created — ensure the
114
+ // filesystem watcher is running so subsequent file edits
115
+ // trigger live reload.
116
+ ensureAppSourceWatcher();
117
+
112
118
  handleAppChange(ctx, parsed.id, broadcastToAllClients);
113
119
 
114
120
  // Fire-and-forget: generate an app icon in the background.
@@ -0,0 +1,14 @@
1
+ import type { ConversationTransportMetadata } from "./message-types/conversations.js";
2
+
3
+ /**
4
+ * Build transport hints from conversation transport metadata.
5
+ *
6
+ * Only forwards client-provided hints. Interface identity is already
7
+ * covered by `<turn_context>`, and host environment fields (home dir,
8
+ * username) are rendered in the `<workspace>` block.
9
+ */
10
+ export function buildTransportHints(
11
+ transport: ConversationTransportMetadata,
12
+ ): string[] {
13
+ return transport.hints ? [...transport.hints] : [];
14
+ }