@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,326 @@
1
+ import {
2
+ existsSync,
3
+ mkdirSync,
4
+ readFileSync,
5
+ rmSync,
6
+ writeFileSync,
7
+ } from "node:fs";
8
+ import { join } from "node:path";
9
+ import {
10
+ afterAll,
11
+ afterEach,
12
+ beforeEach,
13
+ describe,
14
+ expect,
15
+ mock,
16
+ test,
17
+ } from "bun:test";
18
+
19
+ // ---------------------------------------------------------------------------
20
+ // Mocks — declared before imports that depend on platform/logger
21
+ // ---------------------------------------------------------------------------
22
+
23
+ const WORKSPACE_DIR = process.env.VELLUM_WORKSPACE_DIR!;
24
+ const CONFIG_PATH = join(WORKSPACE_DIR, "config.json");
25
+
26
+ function ensureTestDir(): void {
27
+ const dirs = [
28
+ WORKSPACE_DIR,
29
+ join(WORKSPACE_DIR, "data"),
30
+ join(WORKSPACE_DIR, "data", "memory"),
31
+ join(WORKSPACE_DIR, "data", "memory", "knowledge"),
32
+ join(WORKSPACE_DIR, "data", "logs"),
33
+ ];
34
+ for (const dir of dirs) {
35
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
36
+ }
37
+ }
38
+
39
+ function makeLoggerStub(): Record<string, unknown> {
40
+ const stub: Record<string, unknown> = {};
41
+ for (const m of [
42
+ "info",
43
+ "warn",
44
+ "error",
45
+ "debug",
46
+ "trace",
47
+ "fatal",
48
+ "silent",
49
+ "child",
50
+ ]) {
51
+ stub[m] = m === "child" ? () => makeLoggerStub() : () => {};
52
+ }
53
+ return stub;
54
+ }
55
+
56
+ mock.module("../util/logger.js", () => ({
57
+ getLogger: () => makeLoggerStub(),
58
+ }));
59
+
60
+ // ---------------------------------------------------------------------------
61
+ // Feature flag mock — controls whether managed-gemini-embeddings-enabled is on
62
+ // ---------------------------------------------------------------------------
63
+
64
+ let featureFlagEnabled = false;
65
+
66
+ mock.module("../config/assistant-feature-flags.js", () => ({
67
+ isAssistantFeatureFlagEnabled: (key: string) => {
68
+ if (key === "managed-gemini-embeddings-enabled") return featureFlagEnabled;
69
+ return true;
70
+ },
71
+ _setOverridesForTesting: () => {},
72
+ clearFeatureFlagOverridesCache: () => {},
73
+ initFeatureFlagOverrides: async () => {},
74
+ getAssistantFeatureFlagDefaults: () => ({}),
75
+ }));
76
+
77
+ // Restore all mocked modules after this file's tests complete to prevent
78
+ // cross-test contamination when running grouped with other test files.
79
+ afterAll(() => {
80
+ mock.restore();
81
+ });
82
+
83
+ import { invalidateConfigCache, loadConfig } from "../config/loader.js";
84
+ import { _setStorePath } from "../security/encrypted-store.js";
85
+
86
+ // ---------------------------------------------------------------------------
87
+ // Helpers
88
+ // ---------------------------------------------------------------------------
89
+
90
+ function writeConfig(obj: unknown): void {
91
+ writeFileSync(CONFIG_PATH, JSON.stringify(obj, null, 2) + "\n");
92
+ }
93
+
94
+ function readConfig(): Record<string, unknown> {
95
+ return JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
96
+ }
97
+
98
+ /** Stash and restore IS_PLATFORM across each test. */
99
+ let originalIsPlatform: string | undefined;
100
+
101
+ // ---------------------------------------------------------------------------
102
+ // Tests
103
+ // ---------------------------------------------------------------------------
104
+
105
+ describe("managed Gemini embedding defaults (via loadConfig)", () => {
106
+ beforeEach(() => {
107
+ ensureTestDir();
108
+ const resetPaths = [
109
+ CONFIG_PATH,
110
+ join(WORKSPACE_DIR, "keys.enc"),
111
+ join(WORKSPACE_DIR, "data"),
112
+ join(WORKSPACE_DIR, "data", "memory"),
113
+ ];
114
+ for (const path of resetPaths) {
115
+ if (existsSync(path)) {
116
+ rmSync(path, { recursive: true, force: true });
117
+ }
118
+ }
119
+ ensureTestDir();
120
+ _setStorePath(join(WORKSPACE_DIR, "keys.enc"));
121
+ invalidateConfigCache();
122
+
123
+ // Reset mock state
124
+ featureFlagEnabled = false;
125
+ originalIsPlatform = process.env.IS_PLATFORM;
126
+ delete process.env.IS_PLATFORM;
127
+ });
128
+
129
+ afterEach(() => {
130
+ _setStorePath(null);
131
+ invalidateConfigCache();
132
+
133
+ // Restore IS_PLATFORM
134
+ if (originalIsPlatform !== undefined) {
135
+ process.env.IS_PLATFORM = originalIsPlatform;
136
+ } else {
137
+ delete process.env.IS_PLATFORM;
138
+ }
139
+ });
140
+
141
+ test("applies managed Gemini defaults when FF on + IS_PLATFORM + provider auto", () => {
142
+ writeConfig({});
143
+
144
+ featureFlagEnabled = true;
145
+ process.env.IS_PLATFORM = "true";
146
+
147
+ const config = loadConfig();
148
+
149
+ // In-memory config should have managed Gemini defaults
150
+ expect(config.memory.embeddings.provider).toBe("gemini");
151
+ expect(config.memory.embeddings.geminiModel).toBe(
152
+ "gemini-embedding-2-preview",
153
+ );
154
+ expect(config.memory.embeddings.geminiDimensions).toBe(3072);
155
+ expect(config.memory.qdrant.vectorSize).toBe(3072);
156
+
157
+ // Config file on disk should also be updated
158
+ const raw = readConfig();
159
+ const memoryRaw = raw.memory as Record<string, unknown>;
160
+ const embeddingsRaw = memoryRaw.embeddings as Record<string, unknown>;
161
+ const qdrantRaw = memoryRaw.qdrant as Record<string, unknown>;
162
+ expect(embeddingsRaw.provider).toBe("gemini");
163
+ expect(embeddingsRaw.geminiModel).toBe("gemini-embedding-2-preview");
164
+ expect(embeddingsRaw.geminiDimensions).toBe(3072);
165
+ expect(qdrantRaw.vectorSize).toBe(3072);
166
+ });
167
+
168
+ test("does NOT apply when feature flag is OFF", () => {
169
+ writeConfig({});
170
+
171
+ featureFlagEnabled = false;
172
+ process.env.IS_PLATFORM = "true";
173
+
174
+ const config = loadConfig();
175
+
176
+ expect(config.memory.embeddings.provider).toBe("auto");
177
+ expect(config.memory.qdrant.vectorSize).toBe(384);
178
+ });
179
+
180
+ test("does NOT apply when IS_PLATFORM is not set", () => {
181
+ writeConfig({});
182
+
183
+ featureFlagEnabled = true;
184
+ delete process.env.IS_PLATFORM;
185
+
186
+ const config = loadConfig();
187
+
188
+ expect(config.memory.embeddings.provider).toBe("auto");
189
+ expect(config.memory.qdrant.vectorSize).toBe(384);
190
+ });
191
+
192
+ test("does NOT apply when provider is explicitly set to local", () => {
193
+ writeConfig({
194
+ memory: { embeddings: { provider: "local" } },
195
+ });
196
+
197
+ featureFlagEnabled = true;
198
+ process.env.IS_PLATFORM = "true";
199
+
200
+ const config = loadConfig();
201
+ expect(config.memory.embeddings.provider).toBe("local");
202
+ expect(config.memory.qdrant.vectorSize).toBe(384);
203
+ });
204
+
205
+ test("does NOT apply when provider is explicitly set to openai", () => {
206
+ writeConfig({
207
+ memory: { embeddings: { provider: "openai" } },
208
+ });
209
+
210
+ featureFlagEnabled = true;
211
+ process.env.IS_PLATFORM = "true";
212
+
213
+ const config = loadConfig();
214
+ expect(config.memory.embeddings.provider).toBe("openai");
215
+ });
216
+
217
+ test("does NOT apply when provider is explicitly set to gemini", () => {
218
+ writeConfig({
219
+ memory: {
220
+ embeddings: { provider: "gemini", geminiDimensions: 768 },
221
+ qdrant: { vectorSize: 768 },
222
+ },
223
+ });
224
+
225
+ featureFlagEnabled = true;
226
+ process.env.IS_PLATFORM = "true";
227
+
228
+ const config = loadConfig();
229
+
230
+ // Already gemini — should not overwrite user's custom dimensions
231
+ expect(config.memory.embeddings.provider).toBe("gemini");
232
+ expect(config.memory.embeddings.geminiDimensions).toBe(768);
233
+ expect(config.memory.qdrant.vectorSize).toBe(768);
234
+ });
235
+
236
+ test("does NOT apply when provider is explicitly set to ollama", () => {
237
+ writeConfig({
238
+ memory: { embeddings: { provider: "ollama" } },
239
+ });
240
+
241
+ featureFlagEnabled = true;
242
+ process.env.IS_PLATFORM = "true";
243
+
244
+ const config = loadConfig();
245
+ expect(config.memory.embeddings.provider).toBe("ollama");
246
+ });
247
+
248
+ test("is idempotent — second loadConfig is a no-op after migration", () => {
249
+ writeConfig({});
250
+
251
+ featureFlagEnabled = true;
252
+ process.env.IS_PLATFORM = "true";
253
+
254
+ const config = loadConfig();
255
+ expect(config.memory.embeddings.provider).toBe("gemini");
256
+
257
+ // Read file content after first migration
258
+ const contentAfterFirst = readFileSync(CONFIG_PATH, "utf-8");
259
+
260
+ // Second call — provider is now "gemini", not "auto", so migration skipped
261
+ invalidateConfigCache();
262
+ const config2 = loadConfig();
263
+ expect(config2.memory.embeddings.provider).toBe("gemini");
264
+
265
+ // File on disk should not have changed
266
+ const contentAfterSecond = readFileSync(CONFIG_PATH, "utf-8");
267
+ expect(contentAfterSecond).toBe(contentAfterFirst);
268
+ });
269
+
270
+ test("preserves existing config values while setting managed defaults", () => {
271
+ writeConfig({
272
+ provider: "anthropic",
273
+ model: "claude-opus-4-6",
274
+ memory: {
275
+ enabled: true,
276
+ qdrant: { collection: "my-collection", onDisk: false },
277
+ },
278
+ });
279
+
280
+ featureFlagEnabled = true;
281
+ process.env.IS_PLATFORM = "true";
282
+
283
+ const config = loadConfig();
284
+
285
+ // Managed defaults applied
286
+ expect(config.memory.embeddings.provider).toBe("gemini");
287
+ expect(config.memory.embeddings.geminiModel).toBe(
288
+ "gemini-embedding-2-preview",
289
+ );
290
+ expect(config.memory.qdrant.vectorSize).toBe(3072);
291
+
292
+ // Existing values preserved
293
+ const raw = readConfig();
294
+ expect(raw.provider).toBe("anthropic");
295
+ expect(raw.model).toBe("claude-opus-4-6");
296
+ const memoryRaw = raw.memory as Record<string, unknown>;
297
+ expect(memoryRaw.enabled).toBe(true);
298
+ const qdrantRaw = memoryRaw.qdrant as Record<string, unknown>;
299
+ expect(qdrantRaw.collection).toBe("my-collection");
300
+ expect(qdrantRaw.onDisk).toBe(false);
301
+ });
302
+
303
+ test("does NOT apply when both FF off and IS_PLATFORM not set", () => {
304
+ writeConfig({});
305
+
306
+ featureFlagEnabled = false;
307
+ delete process.env.IS_PLATFORM;
308
+
309
+ const config = loadConfig();
310
+
311
+ expect(config.memory.embeddings.provider).toBe("auto");
312
+ expect(config.memory.qdrant.vectorSize).toBe(384);
313
+ });
314
+
315
+ test("applies when IS_PLATFORM is '1'", () => {
316
+ writeConfig({});
317
+
318
+ featureFlagEnabled = true;
319
+ process.env.IS_PLATFORM = "1";
320
+
321
+ const config = loadConfig();
322
+
323
+ expect(config.memory.embeddings.provider).toBe("gemini");
324
+ expect(config.memory.embeddings.geminiDimensions).toBe(3072);
325
+ });
326
+ });
@@ -87,7 +87,7 @@ describe("getSchemaAtPath", () => {
87
87
  expect(result).not.toBeNull();
88
88
  // maxTokens has a default, so it should be parseable
89
89
  const parsed = (result as z.ZodType).parse(undefined);
90
- expect(parsed).toBe(16000);
90
+ expect(parsed).toBe(64000);
91
91
  });
92
92
 
93
93
  test("navigates nested paths (memory.segmentation → object schema)", () => {
@@ -188,7 +188,7 @@ describe("z.toJSONSchema integration", () => {
188
188
  expect(properties.calls).toBeDefined();
189
189
  expect(properties.memory).toBeDefined();
190
190
  expect(properties.timeouts).toBeDefined();
191
- expect(properties.sandbox).toBeDefined();
191
+ expect(properties.permissions).toBeDefined();
192
192
  });
193
193
 
194
194
  test("full schema emits real properties for transformed fields (ingress)", () => {
@@ -81,7 +81,7 @@ describe("AssistantConfigSchema", () => {
81
81
  "inference-provider-native",
82
82
  );
83
83
  expect(result.services["web-search"].mode).toBe("your-own");
84
- expect(result.maxTokens).toBe(16000);
84
+ expect(result.maxTokens).toBe(64000);
85
85
  expect(result.thinking).toEqual({
86
86
  enabled: true,
87
87
  streamThinking: true,
@@ -107,9 +107,6 @@ describe("AssistantConfigSchema", () => {
107
107
  toolExecutionTimeoutSec: 120,
108
108
  providerStreamTimeoutSec: 1800,
109
109
  });
110
- expect(result.sandbox).toEqual({
111
- enabled: false,
112
- });
113
110
  expect(result.rateLimit).toEqual({
114
111
  maxRequestsPerMinute: 0,
115
112
  });
@@ -169,7 +166,7 @@ describe("AssistantConfigSchema", () => {
169
166
  enqueueIntervalMs: 6 * 60 * 60 * 1000,
170
167
  supersededItemRetentionMs: 30 * 24 * 60 * 60 * 1000,
171
168
  conversationRetentionDays: 0,
172
- llmRequestLogRetentionMs: 7 * 24 * 60 * 60 * 1000,
169
+ llmRequestLogRetentionMs: 1 * 24 * 60 * 60 * 1000,
173
170
  });
174
171
  });
175
172
 
@@ -400,29 +397,10 @@ describe("AssistantConfigSchema", () => {
400
397
  }
401
398
  });
402
399
 
403
- test("sandbox with only enabled still parses", () => {
404
- const result = AssistantConfigSchema.parse({ sandbox: { enabled: false } });
405
- expect(result.sandbox.enabled).toBe(false);
406
- });
407
-
408
- test("rejects unknown sandbox fields", () => {
409
- const result = AssistantConfigSchema.safeParse({
410
- sandbox: { backend: "docker" },
411
- });
412
- // Unknown keys are stripped by Zod passthrough/strip, so parse should still succeed
413
- // but the unknown field should not appear in the output
414
- if (result.success) {
415
- expect(
416
- (result.data.sandbox as Record<string, unknown>)["backend"],
417
- ).toBeUndefined();
418
- }
419
- });
420
-
421
400
  test("defaults permissions.mode to workspace", () => {
422
401
  const result = AssistantConfigSchema.parse({});
423
402
  expect(result.permissions).toEqual({
424
403
  mode: "workspace",
425
- askBeforeActing: true,
426
404
  hostAccess: false,
427
405
  });
428
406
  });
@@ -861,6 +839,125 @@ describe("AssistantConfigSchema", () => {
861
839
  });
862
840
  expect(result.calls.callerIdentity.allowPerCallOverride).toBe(true);
863
841
  });
842
+
843
+ // ── hostBrowser.cdpInspect config ─────────────────────────────────
844
+
845
+ test("applies hostBrowser.cdpInspect defaults", () => {
846
+ const result = AssistantConfigSchema.parse({});
847
+ expect(result.hostBrowser).toEqual({
848
+ cdpInspect: {
849
+ enabled: false,
850
+ host: "localhost",
851
+ port: 9222,
852
+ probeTimeoutMs: 500,
853
+ },
854
+ });
855
+ });
856
+
857
+ test("accepts hostBrowser.cdpInspect enabled with custom host/port", () => {
858
+ const result = AssistantConfigSchema.parse({
859
+ hostBrowser: {
860
+ cdpInspect: {
861
+ enabled: true,
862
+ host: "127.0.0.1",
863
+ port: 9333,
864
+ },
865
+ },
866
+ });
867
+ expect(result.hostBrowser.cdpInspect.enabled).toBe(true);
868
+ expect(result.hostBrowser.cdpInspect.host).toBe("127.0.0.1");
869
+ expect(result.hostBrowser.cdpInspect.port).toBe(9333);
870
+ // Unset field should still receive its default.
871
+ expect(result.hostBrowser.cdpInspect.probeTimeoutMs).toBe(500);
872
+ });
873
+
874
+ test("accepts hostBrowser.cdpInspect custom probeTimeoutMs", () => {
875
+ const result = AssistantConfigSchema.parse({
876
+ hostBrowser: { cdpInspect: { probeTimeoutMs: 1000 } },
877
+ });
878
+ expect(result.hostBrowser.cdpInspect.probeTimeoutMs).toBe(1000);
879
+ });
880
+
881
+ test("rejects hostBrowser.cdpInspect.port below 1", () => {
882
+ const result = AssistantConfigSchema.safeParse({
883
+ hostBrowser: { cdpInspect: { port: 0 } },
884
+ });
885
+ expect(result.success).toBe(false);
886
+ if (!result.success) {
887
+ expect(
888
+ result.error.issues.some((issue) =>
889
+ issue.path.join(".").includes("hostBrowser.cdpInspect.port"),
890
+ ),
891
+ ).toBe(true);
892
+ }
893
+ });
894
+
895
+ test("rejects hostBrowser.cdpInspect.port above 65535", () => {
896
+ const result = AssistantConfigSchema.safeParse({
897
+ hostBrowser: { cdpInspect: { port: 70000 } },
898
+ });
899
+ expect(result.success).toBe(false);
900
+ if (!result.success) {
901
+ expect(
902
+ result.error.issues.some((issue) =>
903
+ issue.path.join(".").includes("hostBrowser.cdpInspect.port"),
904
+ ),
905
+ ).toBe(true);
906
+ }
907
+ });
908
+
909
+ test("rejects non-integer hostBrowser.cdpInspect.port", () => {
910
+ const result = AssistantConfigSchema.safeParse({
911
+ hostBrowser: { cdpInspect: { port: 9222.5 } },
912
+ });
913
+ expect(result.success).toBe(false);
914
+ });
915
+
916
+ test("rejects hostBrowser.cdpInspect.probeTimeoutMs below 50", () => {
917
+ const result = AssistantConfigSchema.safeParse({
918
+ hostBrowser: { cdpInspect: { probeTimeoutMs: 10 } },
919
+ });
920
+ expect(result.success).toBe(false);
921
+ if (!result.success) {
922
+ expect(
923
+ result.error.issues.some((issue) =>
924
+ issue.path
925
+ .join(".")
926
+ .includes("hostBrowser.cdpInspect.probeTimeoutMs"),
927
+ ),
928
+ ).toBe(true);
929
+ }
930
+ });
931
+
932
+ test("rejects hostBrowser.cdpInspect.probeTimeoutMs above 5000", () => {
933
+ const result = AssistantConfigSchema.safeParse({
934
+ hostBrowser: { cdpInspect: { probeTimeoutMs: 10000 } },
935
+ });
936
+ expect(result.success).toBe(false);
937
+ if (!result.success) {
938
+ expect(
939
+ result.error.issues.some((issue) =>
940
+ issue.path
941
+ .join(".")
942
+ .includes("hostBrowser.cdpInspect.probeTimeoutMs"),
943
+ ),
944
+ ).toBe(true);
945
+ }
946
+ });
947
+
948
+ test("rejects non-integer hostBrowser.cdpInspect.probeTimeoutMs", () => {
949
+ const result = AssistantConfigSchema.safeParse({
950
+ hostBrowser: { cdpInspect: { probeTimeoutMs: 500.5 } },
951
+ });
952
+ expect(result.success).toBe(false);
953
+ });
954
+
955
+ test("rejects non-boolean hostBrowser.cdpInspect.enabled", () => {
956
+ const result = AssistantConfigSchema.safeParse({
957
+ hostBrowser: { cdpInspect: { enabled: "yes" } },
958
+ });
959
+ expect(result.success).toBe(false);
960
+ });
864
961
  });
865
962
 
866
963
  // ---------------------------------------------------------------------------
@@ -1002,7 +1099,7 @@ describe("loadConfig with schema validation", () => {
1002
1099
  const config = loadConfig();
1003
1100
  expect(config.services.inference.provider).toBe("anthropic");
1004
1101
  expect(config.services.inference.model).toBe("claude-opus-4-6");
1005
- expect(config.maxTokens).toBe(16000);
1102
+ expect(config.maxTokens).toBe(64000);
1006
1103
  expect(config.thinking).toEqual({
1007
1104
  enabled: true,
1008
1105
  streamThinking: true,
@@ -1034,7 +1131,7 @@ describe("loadConfig with schema validation", () => {
1034
1131
  test("falls back to default for invalid maxTokens", () => {
1035
1132
  writeConfig({ maxTokens: -100 });
1036
1133
  const config = loadConfig();
1037
- expect(config.maxTokens).toBe(16000);
1134
+ expect(config.maxTokens).toBe(64000);
1038
1135
  });
1039
1136
 
1040
1137
  test("falls back to defaults for invalid nested values", () => {
@@ -1059,13 +1156,13 @@ describe("loadConfig with schema validation", () => {
1059
1156
  expect(config.services.inference.provider).toBe("openai");
1060
1157
  expect(config.services.inference.model).toBe("gpt-4");
1061
1158
  expect(config.thinking.enabled).toBe(true);
1062
- expect(config.maxTokens).toBe(16000);
1159
+ expect(config.maxTokens).toBe(64000);
1063
1160
  });
1064
1161
 
1065
1162
  test("handles no config file", () => {
1066
1163
  const config = loadConfig();
1067
1164
  expect(config.services.inference.provider).toBe("anthropic");
1068
- expect(config.maxTokens).toBe(16000);
1165
+ expect(config.maxTokens).toBe(64000);
1069
1166
  });
1070
1167
 
1071
1168
  test("partial nested objects get defaults for missing fields", () => {
@@ -1084,25 +1181,6 @@ describe("loadConfig with schema validation", () => {
1084
1181
  expect(config.secretDetection.action).toBe("redact");
1085
1182
  });
1086
1183
 
1087
- test("falls back for invalid sandbox.enabled", () => {
1088
- writeConfig({ sandbox: { enabled: "yes" } });
1089
- const config = loadConfig();
1090
- expect(config.sandbox.enabled).toBe(false);
1091
- });
1092
-
1093
- test("loads sandbox with only enabled field", () => {
1094
- writeConfig({ sandbox: { enabled: false } });
1095
- const config = loadConfig();
1096
- expect(config.sandbox.enabled).toBe(false);
1097
- });
1098
-
1099
- test("strips unknown sandbox fields", () => {
1100
- writeConfig({ sandbox: { enabled: true, backend: "docker" } });
1101
- const config = loadConfig();
1102
- expect(config.sandbox.enabled).toBe(true);
1103
- expect("backend" in config.sandbox).toBe(false);
1104
- });
1105
-
1106
1184
  test("falls back for invalid contextWindow relationship", () => {
1107
1185
  writeConfig({
1108
1186
  contextWindow: { targetBudgetRatio: 0.8, compactThreshold: 0.8 },
@@ -1131,7 +1209,6 @@ describe("loadConfig with schema validation", () => {
1131
1209
  const config = loadConfig();
1132
1210
  expect(config.permissions).toEqual({
1133
1211
  mode: "workspace",
1134
- askBeforeActing: true,
1135
1212
  hostAccess: false,
1136
1213
  });
1137
1214
  });
@@ -10,6 +10,8 @@
10
10
 
11
11
  import { beforeEach, describe, expect, mock, test } from "bun:test";
12
12
 
13
+ import { _setOverridesForTesting } from "../config/assistant-feature-flags.js";
14
+
13
15
  mock.module("../util/logger.js", () => ({
14
16
  getLogger: () =>
15
17
  new Proxy({} as Record<string, unknown>, {
@@ -133,6 +135,7 @@ describe("bridgeConfirmationRequestToGuardian", () => {
133
135
  resetTables();
134
136
  emittedSignals.length = 0;
135
137
  mockOnConversationCreatedCallbacks.length = 0;
138
+ _setOverridesForTesting({});
136
139
  });
137
140
 
138
141
  test("emits guardian.question for trusted-contact sessions", () => {
@@ -223,6 +226,26 @@ describe("bridgeConfirmationRequestToGuardian", () => {
223
226
  expect(emittedSignals).toHaveLength(0);
224
227
  });
225
228
 
229
+ test("skips trusted-contact bridging entirely under permission-controls-v2", () => {
230
+ _setOverridesForTesting({ "permission-controls-v2": true });
231
+
232
+ const canonicalRequest = makeCanonicalRequest();
233
+ const trustContext = makeTrustedContactContext();
234
+
235
+ const result = bridgeConfirmationRequestToGuardian({
236
+ canonicalRequest,
237
+ trustContext,
238
+ conversationId: "conv-1",
239
+ toolName: "bash",
240
+ });
241
+
242
+ expect("skipped" in result && result.skipped).toBe(true);
243
+ if ("skipped" in result) {
244
+ expect(result.reason).toBe("v2_model_mediated");
245
+ }
246
+ expect(emittedSignals).toHaveLength(0);
247
+ });
248
+
226
249
  test("skips when no guardian binding exists for channel", () => {
227
250
  const canonicalRequest = makeCanonicalRequest({ sourceChannel: "phone" });
228
251
  const trustContext = makeTrustedContactContext({
@@ -1,5 +1,6 @@
1
- import { describe, expect, mock, test } from "bun:test";
1
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
2
2
 
3
+ import { _setOverridesForTesting } from "../config/assistant-feature-flags.js";
3
4
  import {
4
5
  CONTEXT_OVERFLOW_TOOL_NAME,
5
6
  requestCompressionApproval,
@@ -20,8 +21,22 @@ function createMockPrompter(decision: UserDecision): PermissionPrompter {
20
21
  }
21
22
 
22
23
  describe("requestCompressionApproval", () => {
24
+ beforeEach(() => {
25
+ _setOverridesForTesting({});
26
+ });
27
+
23
28
  // ── Prompt shape ──
24
29
 
30
+ test("auto-approves without prompting under v2", async () => {
31
+ _setOverridesForTesting({ "permission-controls-v2": true });
32
+
33
+ const prompter = createMockPrompter("deny");
34
+ const result = await requestCompressionApproval(prompter);
35
+
36
+ expect(result).toEqual({ approved: true });
37
+ expect(prompter.prompt).not.toHaveBeenCalled();
38
+ });
39
+
25
40
  test("uses the reserved pseudo tool name", async () => {
26
41
  const prompter = createMockPrompter("allow");
27
42
  await requestCompressionApproval(prompter);
@@ -55,8 +70,8 @@ describe("requestCompressionApproval", () => {
55
70
  await requestCompressionApproval(prompter);
56
71
 
57
72
  const args = (prompter.prompt as ReturnType<typeof mock>).mock.calls[0];
58
- // persistentDecisionsAllowed is index 9
59
- expect(args[9]).toBe(false);
73
+ // persistentDecisionsAllowed is index 8
74
+ expect(args[8]).toBe(false);
60
75
  });
61
76
 
62
77
  test("includes a description in the input", async () => {
@@ -119,8 +134,8 @@ describe("requestCompressionApproval", () => {
119
134
  });
120
135
 
121
136
  const args = (prompter.prompt as ReturnType<typeof mock>).mock.calls[0];
122
- // signal is index 10
123
- expect(args[10]).toBe(controller.signal);
137
+ // signal is index 9
138
+ expect(args[9]).toBe(controller.signal);
124
139
  });
125
140
 
126
141
  test("works without signal option", async () => {
@@ -130,7 +145,7 @@ describe("requestCompressionApproval", () => {
130
145
 
131
146
  const args = (prompter.prompt as ReturnType<typeof mock>).mock.calls[0];
132
147
  // signal should be undefined when not provided
133
- expect(args[10]).toBeUndefined();
148
+ expect(args[9]).toBeUndefined();
134
149
  });
135
150
 
136
151
  // ── Tool name constant ──