@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
@@ -0,0 +1,191 @@
1
+ import { v4 as uuid } from "uuid";
2
+
3
+ import type { ToolExecutionResult } from "../tools/types.js";
4
+ import { AssistantError, ErrorCode } from "../util/errors.js";
5
+ import { getLogger } from "../util/logger.js";
6
+ import type { ServerMessage } from "./message-protocol.js";
7
+ import type { HostBrowserRequest } from "./message-types/host-browser.js";
8
+
9
+ /** Distributive omit that preserves union variant fields. */
10
+ type DistributiveOmit<T, K extends PropertyKey> = T extends unknown
11
+ ? Omit<T, K>
12
+ : never;
13
+
14
+ /** Clean input type for callers — transport envelope fields are added by the proxy. */
15
+ export type HostBrowserInput = DistributiveOmit<
16
+ HostBrowserRequest,
17
+ "type" | "requestId" | "conversationId"
18
+ >;
19
+
20
+ const log = getLogger("host-browser-proxy");
21
+
22
+ interface PendingRequest {
23
+ resolve: (result: ToolExecutionResult) => void;
24
+ reject: (err: Error) => void;
25
+ timer: ReturnType<typeof setTimeout>;
26
+ /** Detach the abort listener from the caller's signal. No-op when no signal was passed. */
27
+ detachAbort: () => void;
28
+ }
29
+
30
+ export class HostBrowserProxy {
31
+ private pending = new Map<string, PendingRequest>();
32
+ private sendToClient: (msg: ServerMessage) => void;
33
+ private onInternalResolve?: (requestId: string) => void;
34
+ private clientConnected = false;
35
+
36
+ constructor(
37
+ sendToClient: (msg: ServerMessage) => void,
38
+ onInternalResolve?: (requestId: string) => void,
39
+ ) {
40
+ this.sendToClient = sendToClient;
41
+ this.onInternalResolve = onInternalResolve;
42
+ }
43
+
44
+ updateSender(
45
+ sendToClient: (msg: ServerMessage) => void,
46
+ clientConnected: boolean,
47
+ ): void {
48
+ this.sendToClient = sendToClient;
49
+ this.clientConnected = clientConnected;
50
+ }
51
+
52
+ request(
53
+ input: HostBrowserInput,
54
+ conversationId: string,
55
+ signal?: AbortSignal,
56
+ ): Promise<ToolExecutionResult> {
57
+ if (signal?.aborted) {
58
+ return Promise.resolve({ content: "Aborted", isError: true });
59
+ }
60
+
61
+ const requestId = uuid();
62
+
63
+ return new Promise<ToolExecutionResult>((resolve, reject) => {
64
+ // CDP operations should be fast — 30 second default timeout matches host_file.
65
+ const timeoutSec = input.timeout_seconds ?? 30;
66
+
67
+ // Declared up-front so onAbort (defined before detachAbort is assigned)
68
+ // can close over a stable reference once it's wired below.
69
+ let detachAbort: () => void = () => {};
70
+
71
+ const timer = setTimeout(() => {
72
+ this.pending.delete(requestId);
73
+ detachAbort();
74
+ this.onInternalResolve?.(requestId);
75
+ log.warn(
76
+ { requestId, cdpMethod: input.cdpMethod },
77
+ "Host browser proxy request timed out",
78
+ );
79
+ resolve({
80
+ content: "Host browser proxy timed out waiting for client response",
81
+ isError: true,
82
+ });
83
+ }, timeoutSec * 1000);
84
+
85
+ if (signal) {
86
+ const onAbort = () => {
87
+ if (this.pending.has(requestId)) {
88
+ clearTimeout(timer);
89
+ this.pending.delete(requestId);
90
+ // Abort fired — nothing to detach, but call the no-op for symmetry
91
+ // so callers can rely on detachAbort being idempotent.
92
+ detachAbort();
93
+ this.onInternalResolve?.(requestId);
94
+ try {
95
+ this.sendToClient({
96
+ type: "host_browser_cancel",
97
+ requestId,
98
+ } as ServerMessage);
99
+ } catch {
100
+ // Best-effort cancel notification — connection may already be closed.
101
+ }
102
+ resolve({ content: "Aborted", isError: true });
103
+ }
104
+ };
105
+ signal.addEventListener("abort", onAbort, { once: true });
106
+ detachAbort = () => signal.removeEventListener("abort", onAbort);
107
+ }
108
+
109
+ this.pending.set(requestId, { resolve, reject, timer, detachAbort });
110
+
111
+ try {
112
+ this.sendToClient({
113
+ ...input,
114
+ type: "host_browser_request",
115
+ requestId,
116
+ conversationId,
117
+ } as ServerMessage);
118
+ } catch (err) {
119
+ // Sender threw synchronously (e.g. client transport error during
120
+ // event emission). Clean up pending state and timer so we don't
121
+ // leak an in-flight entry that nothing will ever resolve.
122
+ clearTimeout(timer);
123
+ this.pending.delete(requestId);
124
+ detachAbort();
125
+ this.onInternalResolve?.(requestId);
126
+ log.warn(
127
+ { requestId, cdpMethod: input.cdpMethod, err },
128
+ "Host browser proxy send failed",
129
+ );
130
+ reject(err instanceof Error ? err : new Error(String(err)));
131
+ }
132
+ });
133
+ }
134
+
135
+ resolve(
136
+ requestId: string,
137
+ response: { content: string; isError: boolean },
138
+ ): void {
139
+ const entry = this.pending.get(requestId);
140
+ if (!entry) {
141
+ // Benign race, not an error. A late result frame with no matching
142
+ // pending entry means one of:
143
+ // - the proxy-side setTimeout has already resolved the caller;
144
+ // - the caller's AbortSignal fired and the entry was torn down;
145
+ // - a duplicate result frame was delivered (e.g. retry after a
146
+ // transient WS drop).
147
+ // Log at debug so operators don't chase false-positive "timeout"
148
+ // alerts on what is actually a cleanly-handled race.
149
+ log.debug(
150
+ { requestId },
151
+ "Ignoring host_browser_result for unknown or already-resolved request",
152
+ );
153
+ return;
154
+ }
155
+ clearTimeout(entry.timer);
156
+ entry.detachAbort();
157
+ this.pending.delete(requestId);
158
+ entry.resolve({ content: response.content, isError: response.isError });
159
+ }
160
+
161
+ hasPendingRequest(requestId: string): boolean {
162
+ return this.pending.has(requestId);
163
+ }
164
+
165
+ isAvailable(): boolean {
166
+ return this.clientConnected;
167
+ }
168
+
169
+ dispose(): void {
170
+ for (const [requestId, entry] of this.pending) {
171
+ clearTimeout(entry.timer);
172
+ entry.detachAbort();
173
+ this.onInternalResolve?.(requestId);
174
+ try {
175
+ this.sendToClient({
176
+ type: "host_browser_cancel",
177
+ requestId,
178
+ } as ServerMessage);
179
+ } catch {
180
+ // Best-effort cancel notification — connection may already be closed.
181
+ }
182
+ entry.reject(
183
+ new AssistantError(
184
+ "Host browser proxy disposed",
185
+ ErrorCode.INTERNAL_ERROR,
186
+ ),
187
+ );
188
+ }
189
+ this.pending.clear();
190
+ }
191
+ }
@@ -57,6 +57,8 @@ interface PendingRequest {
57
57
  resolve: (result: ToolExecutionResult) => void;
58
58
  reject: (err: Error) => void;
59
59
  timer: ReturnType<typeof setTimeout>;
60
+ /** Detach the abort listener from the caller's signal. No-op when no signal was passed. */
61
+ detachAbort: () => void;
60
62
  }
61
63
 
62
64
  // ---------------------------------------------------------------------------
@@ -152,8 +154,13 @@ export class HostCuProxy {
152
154
  const requestId = uuid();
153
155
 
154
156
  return new Promise<ToolExecutionResult>((resolve, reject) => {
157
+ // Declared up-front so onAbort (defined before detachAbort is assigned)
158
+ // can close over a stable reference once it's wired below.
159
+ let detachAbort: () => void = () => {};
160
+
155
161
  const timer = setTimeout(() => {
156
162
  this.pending.delete(requestId);
163
+ detachAbort();
157
164
  this.onInternalResolve?.(requestId);
158
165
  log.warn({ requestId, toolName }, "Host CU proxy request timed out");
159
166
  resolve({
@@ -162,13 +169,14 @@ export class HostCuProxy {
162
169
  });
163
170
  }, REQUEST_TIMEOUT_SEC * 1000);
164
171
 
165
- this.pending.set(requestId, { resolve, reject, timer });
166
-
167
172
  if (signal) {
168
173
  const onAbort = () => {
169
174
  if (this.pending.has(requestId)) {
170
175
  clearTimeout(timer);
171
176
  this.pending.delete(requestId);
177
+ // Abort fired — nothing to detach, but call the no-op for symmetry
178
+ // so callers can rely on detachAbort being idempotent.
179
+ detachAbort();
172
180
  this.onInternalResolve?.(requestId);
173
181
  try {
174
182
  this.sendToClient({
@@ -182,17 +190,32 @@ export class HostCuProxy {
182
190
  }
183
191
  };
184
192
  signal.addEventListener("abort", onAbort, { once: true });
193
+ detachAbort = () => signal.removeEventListener("abort", onAbort);
185
194
  }
186
195
 
187
- this.sendToClient({
188
- type: "host_cu_request",
189
- requestId,
190
- conversationId,
191
- toolName,
192
- input,
193
- stepNumber,
194
- reasoning,
195
- } as ServerMessage);
196
+ this.pending.set(requestId, { resolve, reject, timer, detachAbort });
197
+
198
+ try {
199
+ this.sendToClient({
200
+ type: "host_cu_request",
201
+ requestId,
202
+ conversationId,
203
+ toolName,
204
+ input,
205
+ stepNumber,
206
+ reasoning,
207
+ } as ServerMessage);
208
+ } catch (err) {
209
+ // Sender threw synchronously (e.g. client transport error during
210
+ // event emission). Clean up pending state and timer so we don't
211
+ // leak an in-flight entry that nothing will ever resolve.
212
+ clearTimeout(timer);
213
+ this.pending.delete(requestId);
214
+ detachAbort();
215
+ this.onInternalResolve?.(requestId);
216
+ log.warn({ requestId, toolName, err }, "Host CU proxy send failed");
217
+ reject(err instanceof Error ? err : new Error(String(err)));
218
+ }
196
219
  });
197
220
  }
198
221
 
@@ -203,6 +226,7 @@ export class HostCuProxy {
203
226
  return;
204
227
  }
205
228
  clearTimeout(entry.timer);
229
+ entry.detachAbort();
206
230
  this.pending.delete(requestId);
207
231
 
208
232
  // Capture pre-update state so formatObservation sees the correct previous AX tree
@@ -388,6 +412,7 @@ export class HostCuProxy {
388
412
  dispose(): void {
389
413
  for (const [requestId, entry] of this.pending) {
390
414
  clearTimeout(entry.timer);
415
+ entry.detachAbort();
391
416
  this.onInternalResolve?.(requestId);
392
417
  try {
393
418
  this.sendToClient({
@@ -1,5 +1,6 @@
1
1
  import { v4 as uuid } from "uuid";
2
2
 
3
+ import { readImageBase64 } from "../tools/shared/filesystem/image-read.js";
3
4
  import type { ToolExecutionResult } from "../tools/types.js";
4
5
  import { AssistantError, ErrorCode } from "../util/errors.js";
5
6
  import { getLogger } from "../util/logger.js";
@@ -23,6 +24,10 @@ interface PendingRequest {
23
24
  resolve: (result: ToolExecutionResult) => void;
24
25
  reject: (err: Error) => void;
25
26
  timer: ReturnType<typeof setTimeout>;
27
+ operation: HostFileInput["operation"];
28
+ path: string;
29
+ /** Detach the abort listener from the caller's signal. No-op when no signal was passed. */
30
+ detachAbort: () => void;
26
31
  }
27
32
 
28
33
  export class HostFileProxy {
@@ -61,8 +66,14 @@ export class HostFileProxy {
61
66
  return new Promise<ToolExecutionResult>((resolve, reject) => {
62
67
  // File operations should be fast — 30 second timeout.
63
68
  const timeoutSec = 30;
69
+
70
+ // Declared up-front so onAbort (defined before detachAbort is assigned)
71
+ // can close over a stable reference once it's wired below.
72
+ let detachAbort: () => void = () => {};
73
+
64
74
  const timer = setTimeout(() => {
65
75
  this.pending.delete(requestId);
76
+ detachAbort();
66
77
  this.onInternalResolve?.(requestId);
67
78
  log.warn(
68
79
  { requestId, operation: input.operation },
@@ -74,13 +85,14 @@ export class HostFileProxy {
74
85
  });
75
86
  }, timeoutSec * 1000);
76
87
 
77
- this.pending.set(requestId, { resolve, reject, timer });
78
-
79
88
  if (signal) {
80
89
  const onAbort = () => {
81
90
  if (this.pending.has(requestId)) {
82
91
  clearTimeout(timer);
83
92
  this.pending.delete(requestId);
93
+ // Abort fired — nothing to detach, but call the no-op for symmetry
94
+ // so callers can rely on detachAbort being idempotent.
95
+ detachAbort();
84
96
  this.onInternalResolve?.(requestId);
85
97
  try {
86
98
  this.sendToClient({
@@ -94,20 +106,45 @@ export class HostFileProxy {
94
106
  }
95
107
  };
96
108
  signal.addEventListener("abort", onAbort, { once: true });
109
+ detachAbort = () => signal.removeEventListener("abort", onAbort);
97
110
  }
98
111
 
99
- this.sendToClient({
100
- ...input,
101
- type: "host_file_request",
102
- requestId,
103
- conversationId,
104
- } as ServerMessage);
112
+ this.pending.set(requestId, {
113
+ resolve,
114
+ reject,
115
+ timer,
116
+ operation: input.operation,
117
+ path: input.path,
118
+ detachAbort,
119
+ });
120
+
121
+ try {
122
+ this.sendToClient({
123
+ ...input,
124
+ type: "host_file_request",
125
+ requestId,
126
+ conversationId,
127
+ } as ServerMessage);
128
+ } catch (err) {
129
+ // Sender threw synchronously (e.g. client transport error during
130
+ // event emission). Clean up pending state and timer so we don't
131
+ // leak an in-flight entry that nothing will ever resolve.
132
+ clearTimeout(timer);
133
+ this.pending.delete(requestId);
134
+ detachAbort();
135
+ this.onInternalResolve?.(requestId);
136
+ log.warn(
137
+ { requestId, operation: input.operation, err },
138
+ "Host file proxy send failed",
139
+ );
140
+ reject(err instanceof Error ? err : new Error(String(err)));
141
+ }
105
142
  });
106
143
  }
107
144
 
108
145
  resolve(
109
146
  requestId: string,
110
- response: { content: string; isError: boolean },
147
+ response: { content: string; isError: boolean; imageData?: string },
111
148
  ): void {
112
149
  const entry = this.pending.get(requestId);
113
150
  if (!entry) {
@@ -115,7 +152,17 @@ export class HostFileProxy {
115
152
  return;
116
153
  }
117
154
  clearTimeout(entry.timer);
155
+ entry.detachAbort();
118
156
  this.pending.delete(requestId);
157
+ if (
158
+ entry.operation === "read" &&
159
+ !response.isError &&
160
+ typeof response.imageData === "string" &&
161
+ response.imageData.length > 0
162
+ ) {
163
+ entry.resolve(readImageBase64(response.imageData, entry.path));
164
+ return;
165
+ }
119
166
  entry.resolve({ content: response.content, isError: response.isError });
120
167
  }
121
168
 
@@ -130,6 +177,7 @@ export class HostFileProxy {
130
177
  dispose(): void {
131
178
  for (const [requestId, entry] of this.pending) {
132
179
  clearTimeout(entry.timer);
180
+ entry.detachAbort();
133
181
  this.onInternalResolve?.(requestId);
134
182
  try {
135
183
  this.sendToClient({
@@ -5,6 +5,7 @@ import { reconcileCallsOnStartup } from "../calls/call-recovery.js";
5
5
  import { setRelayBroadcast } from "../calls/relay-server.js";
6
6
  import { TwilioConversationRelayProvider } from "../calls/twilio-provider.js";
7
7
  import { setVoiceBridgeDeps } from "../calls/voice-session-bridge.js";
8
+ import { initFeatureFlagOverrides } from "../config/assistant-feature-flags.js";
8
9
  import {
9
10
  getPlatformAssistantId,
10
11
  getQdrantHttpPortEnv,
@@ -74,6 +75,11 @@ import {
74
75
  mintPairingBearerToken,
75
76
  resolveSigningKey,
76
77
  } from "../runtime/auth/token-service.js";
78
+ import {
79
+ initCapabilityTokenSecret,
80
+ loadOrCreateCapabilityTokenSecret,
81
+ writeDaemonTokenFallback,
82
+ } from "../runtime/capability-tokens.js";
77
83
  import { ensureVellumGuardianBinding } from "../runtime/guardian-vellum-migration.js";
78
84
  import { RuntimeHttpServer } from "../runtime/http-server.js";
79
85
  import { startScheduler } from "../schedule/scheduler.js";
@@ -269,6 +275,29 @@ export async function runDaemon(): Promise<void> {
269
275
  const signingKey = resolveSigningKey();
270
276
  initAuthSigningKey(signingKey);
271
277
 
278
+ // Load (or generate + persist) the capability-token HMAC secret used
279
+ // to mint scoped tokens for the chrome extension pair endpoint.
280
+ // Wrapped in try/catch so a disk failure here never blocks startup —
281
+ // tokens can still be minted using a lazy on-demand load inside the
282
+ // capability-tokens module.
283
+ try {
284
+ initCapabilityTokenSecret(loadOrCreateCapabilityTokenSecret());
285
+ } catch (err) {
286
+ log.warn(
287
+ { err },
288
+ "Failed to pre-load capability token secret — continuing startup (lazy load will handle subsequent calls)",
289
+ );
290
+ }
291
+
292
+ // Pre-populate the feature flag cache from the gateway so all
293
+ // subsequent sync isAssistantFeatureFlagEnabled() calls have data.
294
+ // Fired non-blocking so a slow or unreachable gateway doesn't delay
295
+ // daemon startup (the fetch has a 10s timeout that would otherwise
296
+ // stall the critical path).
297
+ void initFeatureFlagOverrides().catch((err) =>
298
+ log.warn({ err }, "Background feature flag init failed"),
299
+ );
300
+
272
301
  seedInterfaceFiles();
273
302
 
274
303
  log.info("Daemon startup: installing templates and initializing DB");
@@ -422,8 +451,11 @@ export async function runDaemon(): Promise<void> {
422
451
 
423
452
  // Ensure a vellum guardian binding exists so the identity system works
424
453
  // without requiring a manual bootstrap step.
454
+ let localGuardianPrincipalId = "local";
425
455
  try {
426
- ensureVellumGuardianBinding(DAEMON_INTERNAL_ASSISTANT_ID);
456
+ localGuardianPrincipalId = ensureVellumGuardianBinding(
457
+ DAEMON_INTERNAL_ASSISTANT_ID,
458
+ );
427
459
  } catch (err) {
428
460
  log.warn(
429
461
  { err },
@@ -431,6 +463,19 @@ export async function runDaemon(): Promise<void> {
431
463
  );
432
464
  }
433
465
 
466
+ // Write a dev-only fallback capability token to `~/.vellum/daemon-token`
467
+ // so developers can manually pair the chrome extension without the
468
+ // native messaging helper. Production pairing goes through
469
+ // `POST /v1/browser-extension-pair` via the native helper.
470
+ try {
471
+ writeDaemonTokenFallback(localGuardianPrincipalId);
472
+ } catch (err) {
473
+ log.warn(
474
+ { err },
475
+ "Failed to write dev daemon-token fallback — continuing startup",
476
+ );
477
+ }
478
+
434
479
  try {
435
480
  syncUpdateBulletinOnStartup();
436
481
  } catch (err) {
@@ -579,8 +624,6 @@ export async function runDaemon(): Promise<void> {
579
624
  }
580
625
  }
581
626
 
582
- await initializeProvidersAndTools(config);
583
-
584
627
  // Start the DaemonServer (conversation manager) before Qdrant so HTTP
585
628
  // routes can begin accepting requests while Qdrant initializes.
586
629
  log.info("Daemon startup: starting DaemonServer");
@@ -690,7 +733,7 @@ export async function runDaemon(): Promise<void> {
690
733
  seedUninstalledCatalogSkillMemories,
691
734
  } = await import("../memory/graph/capability-seed.js");
692
735
  seedSkillGraphNodes();
693
- seedCliGraphNodes();
736
+ await seedCliGraphNodes();
694
737
  void seedUninstalledCatalogSkillMemories().catch((err) =>
695
738
  log.warn(
696
739
  { err },
@@ -735,12 +778,17 @@ export async function runDaemon(): Promise<void> {
735
778
  conversationId,
736
779
  message,
737
780
  undefined,
738
- options?.trustClass
781
+ options
739
782
  ? {
740
- trustContext: {
741
- sourceChannel: "vellum",
742
- trustClass: options.trustClass,
743
- },
783
+ ...(options.trustClass
784
+ ? {
785
+ trustContext: {
786
+ sourceChannel: "vellum",
787
+ trustClass: options.trustClass,
788
+ },
789
+ }
790
+ : {}),
791
+ ...(options.taskRunId ? { taskRunId: options.taskRunId } : {}),
744
792
  }
745
793
  : undefined,
746
794
  );
@@ -763,6 +811,11 @@ export async function runDaemon(): Promise<void> {
763
811
  },
764
812
  routingIntent: schedule.routingIntent,
765
813
  routingHints: schedule.routingHints,
814
+ conversationMetadata: {
815
+ groupId: "system:scheduled",
816
+ scheduleJobId: schedule.id,
817
+ source: "schedule",
818
+ },
766
819
  dedupeKey: `schedule:notify:${schedule.id}:${Date.now()}`,
767
820
  throwOnError: true,
768
821
  });
@@ -782,6 +835,11 @@ export async function runDaemon(): Promise<void> {
782
835
  scheduleId: schedule.id,
783
836
  name: schedule.name,
784
837
  },
838
+ conversationMetadata: {
839
+ groupId: "system:scheduled",
840
+ scheduleJobId: schedule.id,
841
+ source: "schedule",
842
+ },
785
843
  dedupeKey: `schedule:complete:${schedule.id}:${Date.now()}`,
786
844
  });
787
845
  },
@@ -1150,6 +1208,21 @@ export async function runDaemon(): Promise<void> {
1150
1208
  runtimeHttp = null;
1151
1209
  }
1152
1210
 
1211
+ // Initialize providers and tools after the HTTP server is listening so
1212
+ // health-check and pairing requests can be served immediately. Wrapped in
1213
+ // its own try/catch so a failure here doesn't tear down the running HTTP
1214
+ // server (DaemonServer.start() already calls initializeProviders internally
1215
+ // and tools are resolved lazily at conversation creation time).
1216
+ try {
1217
+ log.info("Daemon startup: initializing providers and tools");
1218
+ await initializeProvidersAndTools(config);
1219
+ } catch (err) {
1220
+ log.warn(
1221
+ { err },
1222
+ "Provider/tool initialization failed — continuing with degraded functionality",
1223
+ );
1224
+ }
1225
+
1153
1226
  writePid(process.pid);
1154
1227
  log.info({ pid: process.pid }, "Daemon started");
1155
1228
 
@@ -1178,10 +1251,11 @@ export async function runDaemon(): Promise<void> {
1178
1251
  if (!runtimeManager.isReady()) {
1179
1252
  log.info("Downloading embedding runtime in background...");
1180
1253
  await runtimeManager.ensureInstalled();
1181
- // Reset the localBackendBroken flag so auto mode retries local embeddings
1182
- const { clearEmbeddingBackendCache } =
1254
+ // Reset the sticky local-backend failure flag so auto mode retries
1255
+ // local embeddings without evicting a worker that may already be live.
1256
+ const { resetLocalEmbeddingFailureState } =
1183
1257
  await import("../memory/embedding-backend.js");
1184
- clearEmbeddingBackendCache();
1258
+ resetLocalEmbeddingFailureState();
1185
1259
  log.info("Embedding runtime download complete");
1186
1260
  }
1187
1261
  } catch (err) {
@@ -23,6 +23,7 @@ export * from "./message-types/diagnostics.js";
23
23
  export * from "./message-types/documents.js";
24
24
  export * from "./message-types/guardian-actions.js";
25
25
  export * from "./message-types/host-bash.js";
26
+ export * from "./message-types/host-browser.js";
26
27
  export * from "./message-types/host-cu.js";
27
28
  export * from "./message-types/host-file.js";
28
29
  export * from "./message-types/inbox.js";
@@ -77,6 +78,10 @@ import type {
77
78
  _GuardianActionsServerMessages,
78
79
  } from "./message-types/guardian-actions.js";
79
80
  import type { _HostBashServerMessages } from "./message-types/host-bash.js";
81
+ import type {
82
+ _HostBrowserClientMessages,
83
+ _HostBrowserServerMessages,
84
+ } from "./message-types/host-browser.js";
80
85
  import type { _HostCuServerMessages } from "./message-types/host-cu.js";
81
86
  import type { _HostFileServerMessages } from "./message-types/host-file.js";
82
87
  import type {
@@ -157,6 +162,7 @@ export type ClientMessage =
157
162
  | _ContactsClientMessages
158
163
  | _WorkItemsClientMessages
159
164
  | _BrowserClientMessages
165
+ | _HostBrowserClientMessages
160
166
  | _SubagentsClientMessages
161
167
  | _DocumentsClientMessages
162
168
  | _GuardianActionsClientMessages
@@ -186,6 +192,7 @@ export type ServerMessage =
186
192
  | _DocumentsServerMessages
187
193
  | _GuardianActionsServerMessages
188
194
  | _HostBashServerMessages
195
+ | _HostBrowserServerMessages
189
196
  | _HostCuServerMessages
190
197
  | _HostFileServerMessages
191
198
  | _MemoryServerMessages