@vellumai/assistant 0.6.3 → 0.6.4

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 (667) hide show
  1. package/ARCHITECTURE.md +273 -10
  2. package/Dockerfile +2 -3
  3. package/bun.lock +5 -13
  4. package/docs/backup-troubleshooting.md +52 -0
  5. package/docs/browser-use-architecture-phase2.md +174 -0
  6. package/docs/stt-provider-onboarding.md +120 -0
  7. package/knip.json +12 -2
  8. package/node_modules/@vellumai/ces-contracts/bun.lock +8 -6
  9. package/node_modules/@vellumai/ces-contracts/package.json +3 -3
  10. package/openapi.yaml +982 -72
  11. package/package.json +4 -6
  12. package/scripts/generate-openapi.ts +0 -1
  13. package/scripts/test.sh +73 -18
  14. package/src/__tests__/agent-image-optimize.test.ts +28 -0
  15. package/src/__tests__/agent-loop.test.ts +123 -0
  16. package/src/__tests__/anthropic-provider.test.ts +263 -10
  17. package/src/__tests__/auto-analysis-end-to-end.test.ts +550 -0
  18. package/src/__tests__/auto-analysis-prompt.test.ts +50 -0
  19. package/src/__tests__/browser-fill-credential.test.ts +11 -0
  20. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +2 -2
  21. package/src/__tests__/browser-skill-endstate.test.ts +31 -7
  22. package/src/__tests__/btw-routes.test.ts +7 -0
  23. package/src/__tests__/call-controller.test.ts +581 -20
  24. package/src/__tests__/catalog-files.test.ts +138 -0
  25. package/src/__tests__/channel-invite-transport.test.ts +2 -2
  26. package/src/__tests__/channel-readiness-routes.test.ts +16 -20
  27. package/src/__tests__/channel-readiness-service.test.ts +12 -7
  28. package/src/__tests__/checker.test.ts +157 -10
  29. package/src/__tests__/clawhub-files.test.ts +347 -0
  30. package/src/__tests__/commit-message-enrichment-service.test.ts +36 -19
  31. package/src/__tests__/config-analysis.test.ts +100 -0
  32. package/src/__tests__/config-schema.test.ts +1013 -66
  33. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +339 -0
  34. package/src/__tests__/config-watcher.test.ts +43 -8
  35. package/src/__tests__/contact-store-user-file.test.ts +512 -0
  36. package/src/__tests__/contacts-write.test.ts +197 -0
  37. package/src/__tests__/context-window-manager.test.ts +88 -0
  38. package/src/__tests__/conversation-abort-tool-results.test.ts +2 -0
  39. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
  40. package/src/__tests__/conversation-agent-loop.test.ts +98 -2
  41. package/src/__tests__/conversation-confirmation-signals.test.ts +135 -0
  42. package/src/__tests__/conversation-error.test.ts +70 -0
  43. package/src/__tests__/conversation-history-web-search.test.ts +11 -4
  44. package/src/__tests__/conversation-init.benchmark.test.ts +6 -1
  45. package/src/__tests__/conversation-launcher-skill-regression.test.ts +51 -0
  46. package/src/__tests__/conversation-list-source.test.ts +145 -0
  47. package/src/__tests__/conversation-pre-run-repair.test.ts +2 -0
  48. package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -0
  49. package/src/__tests__/conversation-queue.test.ts +901 -60
  50. package/src/__tests__/conversation-routes-disk-view.test.ts +270 -0
  51. package/src/__tests__/conversation-runtime-assembly.test.ts +55 -0
  52. package/src/__tests__/conversation-skill-tools.test.ts +7 -4
  53. package/src/__tests__/conversation-slash-commands.test.ts +33 -0
  54. package/src/__tests__/conversation-slash-queue.test.ts +89 -18
  55. package/src/__tests__/conversation-slash-unknown.test.ts +2 -0
  56. package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +226 -0
  57. package/src/__tests__/conversation-workspace-injection.test.ts +2 -0
  58. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +2 -0
  59. package/src/__tests__/credential-health-service.test.ts +352 -0
  60. package/src/__tests__/credential-security-invariants.test.ts +5 -3
  61. package/src/__tests__/credential-vault-unit.test.ts +379 -3
  62. package/src/__tests__/credentials-cli.test.ts +40 -16
  63. package/src/__tests__/cross-provider-web-search.test.ts +146 -35
  64. package/src/__tests__/deterministic-verification-control-plane.test.ts +10 -1
  65. package/src/__tests__/device-id.test.ts +112 -0
  66. package/src/__tests__/docker-signing-key-bootstrap.test.ts +167 -4
  67. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +1 -3
  68. package/src/__tests__/email-html-renderer.test.ts +71 -0
  69. package/src/__tests__/email-invite-adapter.test.ts +36 -32
  70. package/src/__tests__/emit-event-signal.test.ts +71 -0
  71. package/src/__tests__/extension-id-sync-guard.test.ts +75 -8
  72. package/src/__tests__/fixtures/mock-chrome-extension.ts +11 -0
  73. package/src/__tests__/gateway-only-enforcement.test.ts +206 -1
  74. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  75. package/src/__tests__/gemini-provider.test.ts +64 -0
  76. package/src/__tests__/get-skill-detail-audit.test.ts +325 -0
  77. package/src/__tests__/gmail-archive-fallback.test.ts +193 -0
  78. package/src/__tests__/gmail-archive-gate.test.ts +246 -0
  79. package/src/__tests__/gmail-preferences.test.ts +117 -0
  80. package/src/__tests__/headless-browser-interactions.test.ts +43 -0
  81. package/src/__tests__/headless-browser-mode.test.ts +614 -0
  82. package/src/__tests__/headless-browser-navigate.test.ts +142 -5
  83. package/src/__tests__/headless-browser-read-tools.test.ts +11 -0
  84. package/src/__tests__/headless-browser-snapshot.test.ts +10 -0
  85. package/src/__tests__/heartbeat-service.test.ts +70 -17
  86. package/src/__tests__/home-state-routes.test.ts +162 -0
  87. package/src/__tests__/host-bash-proxy.test.ts +0 -5
  88. package/src/__tests__/host-browser-e2e-cloud.test.ts +138 -4
  89. package/src/__tests__/host-browser-e2e-self-hosted.test.ts +4 -4
  90. package/src/__tests__/host-browser-ws-events-e2e.test.ts +103 -0
  91. package/src/__tests__/host-cu-proxy.test.ts +0 -5
  92. package/src/__tests__/identity-intro-cache.test.ts +40 -10
  93. package/src/__tests__/init-feature-flag-overrides.test.ts +38 -112
  94. package/src/__tests__/jobs-store-upsert-debounced.test.ts +141 -0
  95. package/src/__tests__/llm-context-normalization.test.ts +488 -0
  96. package/src/__tests__/llm-context-route-provider.test.ts +86 -5
  97. package/src/__tests__/llm-usage-store.test.ts +363 -0
  98. package/src/__tests__/media-stream-output.test.ts +555 -0
  99. package/src/__tests__/media-stream-parser.test.ts +374 -0
  100. package/src/__tests__/media-stream-server-integration.test.ts +1234 -0
  101. package/src/__tests__/media-stream-stt-session.test.ts +588 -0
  102. package/src/__tests__/media-turn-detector.test.ts +440 -0
  103. package/src/__tests__/message-queue.test.ts +125 -0
  104. package/src/__tests__/migration-export-http.test.ts +6 -6
  105. package/src/__tests__/migration-import-commit-http.test.ts +8 -6
  106. package/src/__tests__/migration-import-preflight-http.test.ts +6 -5
  107. package/src/__tests__/migration-validate-http.test.ts +3 -3
  108. package/src/__tests__/mock-gateway-ipc.ts +151 -0
  109. package/src/__tests__/model-intents.test.ts +2 -2
  110. package/src/__tests__/oauth-apps-routes.test.ts +1 -0
  111. package/src/__tests__/oauth-cli.test.ts +2 -0
  112. package/src/__tests__/oauth-connect-orchestrator.test.ts +2 -0
  113. package/src/__tests__/oauth-provider-serializer.test.ts +1 -0
  114. package/src/__tests__/oauth-providers-routes.test.ts +2 -0
  115. package/src/__tests__/oauth-store.test.ts +85 -0
  116. package/src/__tests__/oauth2-gateway-transport.test.ts +249 -6
  117. package/src/__tests__/onboarding-template-contract.test.ts +6 -13
  118. package/src/__tests__/openai-provider.test.ts +176 -0
  119. package/src/__tests__/openai-responses-cutover-guard.test.ts +184 -0
  120. package/src/__tests__/openai-responses-provider.test.ts +1105 -0
  121. package/src/__tests__/openrouter-token-estimation.test.ts +100 -0
  122. package/src/__tests__/outlook-unsubscribe.test.ts +31 -2
  123. package/src/__tests__/persona-resolver.test.ts +251 -0
  124. package/src/__tests__/platform-bash-auto-approve.test.ts +4 -0
  125. package/src/__tests__/platform.test.ts +92 -1
  126. package/src/__tests__/post-turn-tool-result-truncation.test.ts +47 -0
  127. package/src/__tests__/prechat-onboarding-contract.test.ts +267 -0
  128. package/src/__tests__/pricing.test.ts +174 -0
  129. package/src/__tests__/qdrant-manager.test.ts +29 -8
  130. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +194 -0
  131. package/src/__tests__/relationship-state-contract.test.ts +175 -0
  132. package/src/__tests__/relay-server.test.ts +423 -5
  133. package/src/__tests__/search-skills-unified.test.ts +118 -0
  134. package/src/__tests__/secret-scanner-executor.test.ts +4 -0
  135. package/src/__tests__/secure-keys.test.ts +107 -0
  136. package/src/__tests__/send-endpoint-busy.test.ts +5 -1
  137. package/src/__tests__/sequence-store.test.ts +1 -1
  138. package/src/__tests__/server-history-render.test.ts +49 -0
  139. package/src/__tests__/settings-routes.test.ts +201 -0
  140. package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
  141. package/src/__tests__/skills-file-content-endpoint.test.ts +276 -145
  142. package/src/__tests__/skills-files-catalog-fallback.test.ts +381 -93
  143. package/src/__tests__/skills.test.ts +5 -2
  144. package/src/__tests__/skillssh-files.test.ts +446 -0
  145. package/src/__tests__/slack-block-formatting.test.ts +110 -0
  146. package/src/__tests__/slack-channel-config.test.ts +564 -1
  147. package/src/__tests__/stt-catalog-parity.test.ts +282 -0
  148. package/src/__tests__/stt-stream-session.test.ts +535 -0
  149. package/src/__tests__/system-prompt.test.ts +112 -26
  150. package/src/__tests__/telephony-stt-routing.test.ts +329 -0
  151. package/src/__tests__/terminal-tools.test.ts +18 -7
  152. package/src/__tests__/test-preload.ts +18 -0
  153. package/src/__tests__/test-support/browser-skill-harness.ts +4 -1
  154. package/src/__tests__/tool-executor-lifecycle-events.test.ts +9 -5
  155. package/src/__tests__/tool-executor-shell-integration.test.ts +4 -0
  156. package/src/__tests__/tool-executor.test.ts +33 -24
  157. package/src/__tests__/tool-result-truncation.test.ts +36 -0
  158. package/src/__tests__/trust-store.test.ts +7 -1
  159. package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -1
  160. package/src/__tests__/tts-catalog-parity.test.ts +345 -0
  161. package/src/__tests__/twilio-routes-twiml.test.ts +512 -114
  162. package/src/__tests__/twilio-routes.test.ts +376 -0
  163. package/src/__tests__/unicode.test.ts +293 -0
  164. package/src/__tests__/update-bulletin-format.test.ts +59 -0
  165. package/src/__tests__/update-bulletin.test.ts +206 -5
  166. package/src/__tests__/usage-routes.test.ts +25 -4
  167. package/src/__tests__/user-reference.test.ts +46 -61
  168. package/src/__tests__/verification-control-plane-policy.test.ts +4 -0
  169. package/src/__tests__/voice-config-update.test.ts +403 -0
  170. package/src/__tests__/voice-quality.test.ts +434 -19
  171. package/src/__tests__/workspace-heartbeat-service.test.ts +7 -0
  172. package/src/__tests__/workspace-migration-033-stt-service-explicit-config.test.ts +547 -0
  173. package/src/__tests__/workspace-migration-034-remove-calls-voice-transcription-provider.test.ts +596 -0
  174. package/src/__tests__/workspace-migration-drop-user-md.test.ts +368 -0
  175. package/src/__tests__/workspace-migration-meets.test.ts +244 -0
  176. package/src/__tests__/workspace-migration-seed-device-id.test.ts +14 -20
  177. package/src/__tests__/workspace-policy.test.ts +2 -0
  178. package/src/agent/image-optimize.ts +24 -12
  179. package/src/agent/loop.ts +43 -3
  180. package/src/backup/__tests__/backup-key.test.ts +152 -0
  181. package/src/backup/__tests__/backup-worker.test.ts +767 -0
  182. package/src/backup/__tests__/list-snapshots.test.ts +87 -0
  183. package/src/backup/__tests__/local-writer.test.ts +218 -0
  184. package/src/backup/__tests__/offsite-writer.test.ts +641 -0
  185. package/src/backup/__tests__/paths.test.ts +300 -0
  186. package/src/backup/__tests__/restore.test.ts +498 -0
  187. package/src/backup/__tests__/snapshot-lock.test.ts +352 -0
  188. package/src/backup/__tests__/stream-crypt.test.ts +228 -0
  189. package/src/backup/backup-key.ts +137 -0
  190. package/src/backup/backup-worker.ts +459 -0
  191. package/src/backup/list-snapshots.ts +147 -0
  192. package/src/backup/local-writer.ts +133 -0
  193. package/src/backup/offsite-writer.ts +222 -0
  194. package/src/backup/paths.ts +226 -0
  195. package/src/backup/restore.ts +322 -0
  196. package/src/backup/snapshot-lock.ts +431 -0
  197. package/src/backup/stream-crypt.ts +263 -0
  198. package/src/bundler/package-resolver.ts +4 -0
  199. package/src/calls/audio-store.ts +11 -5
  200. package/src/calls/call-controller.ts +226 -71
  201. package/src/calls/call-domain.ts +9 -0
  202. package/src/calls/call-speech-output.ts +190 -0
  203. package/src/calls/call-transport.ts +77 -0
  204. package/src/calls/media-stream-audio-transcode.ts +173 -0
  205. package/src/calls/media-stream-output.ts +660 -0
  206. package/src/calls/media-stream-parser.ts +300 -0
  207. package/src/calls/media-stream-protocol.ts +166 -0
  208. package/src/calls/media-stream-server.ts +592 -0
  209. package/src/calls/media-stream-stt-session.ts +460 -0
  210. package/src/calls/media-turn-detector.ts +230 -0
  211. package/src/calls/relay-server.ts +90 -75
  212. package/src/calls/resolve-call-tts-provider.ts +136 -0
  213. package/src/calls/telephony-stt-routing.ts +145 -0
  214. package/src/calls/tts-call-strategy.ts +161 -0
  215. package/src/calls/tts-text-sanitizer.ts +32 -16
  216. package/src/calls/twilio-routes.ts +281 -17
  217. package/src/calls/voice-quality.ts +78 -35
  218. package/src/calls/voice-session-bridge.ts +8 -1
  219. package/src/channels/types.ts +16 -0
  220. package/src/cli/__tests__/run-assistant-command.ts +11 -1
  221. package/src/cli/commands/__tests__/backup.test.ts +1165 -0
  222. package/src/cli/commands/__tests__/domain-register.test.ts +234 -0
  223. package/src/cli/commands/__tests__/domain-status.test.ts +132 -0
  224. package/src/cli/commands/__tests__/email-attachment.test.ts +422 -0
  225. package/src/cli/commands/__tests__/email-download.test.ts +16 -1
  226. package/src/cli/commands/__tests__/email-list.test.ts +22 -4
  227. package/src/cli/commands/__tests__/email-register.test.ts +4 -4
  228. package/src/cli/commands/__tests__/email-send.test.ts +37 -4
  229. package/src/cli/commands/__tests__/email-status.test.ts +5 -1
  230. package/src/cli/commands/__tests__/email-unregister.test.ts +34 -5
  231. package/src/cli/commands/backup.ts +993 -0
  232. package/src/cli/commands/conversations.ts +77 -0
  233. package/src/cli/commands/credentials.ts +0 -1
  234. package/src/cli/commands/domain.ts +210 -0
  235. package/src/cli/commands/email.ts +255 -3
  236. package/src/cli/commands/oauth/__tests__/connect.test.ts +12 -0
  237. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +1 -0
  238. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -0
  239. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -0
  240. package/src/cli/commands/oauth/mode.ts +12 -3
  241. package/src/cli/commands/oauth/providers.ts +15 -0
  242. package/src/cli/commands/oauth/shared.ts +2 -1
  243. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +4 -9
  244. package/src/cli/commands/platform/__tests__/connect.test.ts +6 -0
  245. package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -1
  246. package/src/cli/commands/platform/__tests__/status.test.ts +6 -0
  247. package/src/cli/program.ts +30 -4
  248. package/src/config/__tests__/backup-schema.test.ts +134 -0
  249. package/src/config/assistant-feature-flags.ts +61 -62
  250. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +37 -1
  251. package/src/config/bundled-skills/browser/SKILL.md +30 -5
  252. package/src/config/bundled-skills/browser/TOOLS.json +123 -0
  253. package/src/config/bundled-skills/browser/tools/browser-attach.ts +12 -0
  254. package/src/config/bundled-skills/browser/tools/browser-detach.ts +12 -0
  255. package/src/config/bundled-skills/browser/tools/browser-status.ts +12 -0
  256. package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +17 -0
  257. package/src/config/bundled-skills/contacts/SKILL.md +2 -2
  258. package/src/config/bundled-skills/gmail/SKILL.md +53 -7
  259. package/src/config/bundled-skills/gmail/TOOLS.json +33 -3
  260. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +116 -9
  261. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +138 -11
  262. package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +59 -0
  263. package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +82 -0
  264. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +113 -17
  265. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +2 -2
  266. package/src/config/bundled-skills/media-processing/SKILL.md +3 -9
  267. package/src/config/bundled-skills/media-processing/TOOLS.json +1 -6
  268. package/src/config/bundled-skills/media-processing/__tests__/audio-transcribe.test.ts +125 -0
  269. package/src/config/bundled-skills/media-processing/__tests__/extract-keyframes.test.ts +181 -0
  270. package/src/config/bundled-skills/media-processing/__tests__/preprocess-audio.test.ts +141 -0
  271. package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +32 -87
  272. package/src/config/bundled-skills/media-processing/services/preprocess.ts +8 -4
  273. package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +0 -10
  274. package/src/config/bundled-skills/messaging/SKILL.md +3 -3
  275. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +2 -2
  276. package/src/config/bundled-skills/outlook/SKILL.md +2 -2
  277. package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +2 -2
  278. package/src/config/bundled-skills/phone-calls/SKILL.md +2 -2
  279. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +27 -18
  280. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +3 -3
  281. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  282. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +26 -22
  283. package/src/config/bundled-skills/slack/SKILL.md +1 -0
  284. package/src/config/bundled-skills/transcribe/SKILL.md +9 -14
  285. package/src/config/bundled-skills/transcribe/TOOLS.json +2 -7
  286. package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +256 -0
  287. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +38 -188
  288. package/src/config/bundled-tool-registry.ts +8 -0
  289. package/src/config/env-registry.ts +24 -0
  290. package/src/config/env.ts +34 -10
  291. package/src/config/feature-flag-registry.json +46 -14
  292. package/src/config/loader.ts +26 -12
  293. package/src/config/schema.ts +35 -10
  294. package/src/config/schemas/__tests__/stt.test.ts +43 -0
  295. package/src/config/schemas/analysis.ts +51 -0
  296. package/src/config/schemas/backup.ts +72 -0
  297. package/src/config/schemas/calls.ts +1 -26
  298. package/src/config/schemas/elevenlabs.ts +0 -59
  299. package/src/config/schemas/filing.ts +47 -7
  300. package/src/config/schemas/heartbeat.ts +27 -5
  301. package/src/config/schemas/host-browser.ts +47 -1
  302. package/src/config/schemas/inference.ts +1 -1
  303. package/src/config/schemas/memory-lifecycle.ts +14 -2
  304. package/src/config/schemas/services.ts +44 -0
  305. package/src/config/schemas/stt.ts +59 -0
  306. package/src/config/schemas/tts.ts +230 -0
  307. package/src/config/schemas/updates.ts +14 -0
  308. package/src/config/skills.ts +4 -0
  309. package/src/config/types.ts +4 -0
  310. package/src/contacts/contact-store.ts +56 -11
  311. package/src/contacts/contacts-write.ts +38 -1
  312. package/src/context/post-turn-tool-result-truncation.ts +3 -2
  313. package/src/context/tool-result-truncation.ts +2 -1
  314. package/src/context/window-manager.ts +45 -12
  315. package/src/credential-execution/executable-discovery.ts +12 -2
  316. package/src/credential-execution/process-manager.ts +33 -2
  317. package/src/credential-health/credential-health-service.ts +366 -0
  318. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +324 -0
  319. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +497 -0
  320. package/src/daemon/__tests__/conversation-tool-setup.test.ts +17 -8
  321. package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +127 -0
  322. package/src/daemon/config-watcher.ts +99 -5
  323. package/src/daemon/conversation-agent-loop-handlers.ts +6 -0
  324. package/src/daemon/conversation-agent-loop.ts +101 -24
  325. package/src/daemon/conversation-error.ts +11 -0
  326. package/src/daemon/conversation-history.ts +40 -6
  327. package/src/daemon/conversation-launch.ts +220 -0
  328. package/src/daemon/conversation-lifecycle.ts +59 -9
  329. package/src/daemon/conversation-messaging.ts +37 -3
  330. package/src/daemon/conversation-notifiers.ts +5 -0
  331. package/src/daemon/conversation-process.ts +581 -19
  332. package/src/daemon/conversation-queue-manager.ts +24 -0
  333. package/src/daemon/conversation-runtime-assembly.ts +11 -1
  334. package/src/daemon/conversation-slash.ts +36 -0
  335. package/src/daemon/conversation-surfaces.ts +94 -4
  336. package/src/daemon/conversation-tool-setup.ts +25 -0
  337. package/src/daemon/conversation-usage.ts +7 -4
  338. package/src/daemon/conversation.ts +86 -28
  339. package/src/daemon/handlers/config-slack-channel.ts +269 -94
  340. package/src/daemon/handlers/conversations.ts +4 -1
  341. package/src/daemon/handlers/shared.ts +22 -0
  342. package/src/daemon/handlers/skills.ts +321 -77
  343. package/src/daemon/host-browser-proxy.ts +2 -1
  344. package/src/daemon/lifecycle.ts +122 -25
  345. package/src/daemon/message-protocol.ts +6 -0
  346. package/src/daemon/message-types/conversations.ts +34 -1
  347. package/src/daemon/message-types/home.ts +40 -0
  348. package/src/daemon/message-types/meet.ts +143 -0
  349. package/src/daemon/message-types/messages.ts +14 -0
  350. package/src/daemon/message-types/schedules.ts +34 -2
  351. package/src/daemon/message-types/skills.ts +16 -0
  352. package/src/daemon/message-types/surfaces.ts +2 -0
  353. package/src/daemon/server.ts +347 -2
  354. package/src/daemon/shutdown-handlers.ts +32 -4
  355. package/src/daemon/shutdown-registry.ts +40 -0
  356. package/src/daemon/tool-side-effects.ts +9 -0
  357. package/src/email/html-renderer.ts +76 -0
  358. package/src/heartbeat/heartbeat-service.ts +93 -7
  359. package/src/home/__tests__/assistant-feed-authoring.test.ts +156 -0
  360. package/src/home/__tests__/emit-feed-event.test.ts +169 -0
  361. package/src/home/__tests__/feed-scheduler.test.ts +194 -0
  362. package/src/home/__tests__/feed-types.test.ts +275 -0
  363. package/src/home/__tests__/feed-writer.test.ts +688 -0
  364. package/src/home/__tests__/phase5-exit-criteria.test.ts +212 -0
  365. package/src/home/__tests__/platform-gmail-digest.test.ts +222 -0
  366. package/src/home/__tests__/progress-formula.test.ts +213 -0
  367. package/src/home/__tests__/relationship-state-writer.test.ts +740 -0
  368. package/src/home/__tests__/rollup-producer.test.ts +398 -0
  369. package/src/home/assistant-feed-authoring.ts +124 -0
  370. package/src/home/emit-feed-event.ts +158 -0
  371. package/src/home/feed-scheduler.ts +247 -0
  372. package/src/home/feed-types.ts +181 -0
  373. package/src/home/feed-writer.ts +469 -0
  374. package/src/home/platform-gmail-digest.ts +163 -0
  375. package/src/home/progress-formula.ts +86 -0
  376. package/src/home/relationship-state-writer.ts +824 -0
  377. package/src/home/relationship-state.ts +143 -0
  378. package/src/home/rollup-producer.ts +384 -0
  379. package/src/hooks/runner.ts +7 -0
  380. package/src/inbound/platform-callback-registration.ts +12 -3
  381. package/src/inbound/public-ingress-urls.ts +12 -0
  382. package/src/instrument.ts +1 -1
  383. package/src/ipc/__tests__/cli-ipc.test.ts +200 -0
  384. package/src/ipc/cli-client.ts +151 -0
  385. package/src/ipc/cli-server.ts +234 -0
  386. package/src/ipc/gateway-client.ts +180 -0
  387. package/src/ipc/routes/index.ts +5 -0
  388. package/src/ipc/routes/wake-conversation.ts +19 -0
  389. package/src/memory/__tests__/auto-analysis-enqueue.test.ts +356 -0
  390. package/src/memory/__tests__/auto-analysis-guard.test.ts +57 -0
  391. package/src/memory/__tests__/conversation-analyze-job.test.ts +232 -0
  392. package/src/memory/__tests__/find-analysis-conversation.test.ts +196 -0
  393. package/src/memory/app-store.ts +1 -1
  394. package/src/memory/attachments-store.ts +70 -0
  395. package/src/memory/auto-analysis-enqueue.ts +127 -0
  396. package/src/memory/auto-analysis-guard.ts +27 -0
  397. package/src/memory/cleanup-schedule-state.ts +37 -0
  398. package/src/memory/conversation-analyze-job.ts +73 -0
  399. package/src/memory/conversation-crud.ts +99 -0
  400. package/src/memory/conversation-disk-view.ts +7 -0
  401. package/src/memory/conversation-group-migration.ts +34 -2
  402. package/src/memory/conversation-queries.ts +6 -5
  403. package/src/memory/db-init.ts +6 -0
  404. package/src/memory/db-maintenance.ts +108 -0
  405. package/src/memory/db.ts +1 -0
  406. package/src/memory/graph/conversation-graph-memory.ts +15 -0
  407. package/src/memory/graph/extraction.test.ts +23 -0
  408. package/src/memory/graph/extraction.ts +8 -0
  409. package/src/memory/graph/retriever.ts +27 -18
  410. package/src/memory/graph/scoring.test.ts +186 -0
  411. package/src/memory/graph/scoring.ts +31 -1
  412. package/src/memory/graph/tools.ts +1 -1
  413. package/src/memory/group-crud.ts +6 -1
  414. package/src/memory/indexer.ts +95 -16
  415. package/src/memory/job-handlers/cleanup.ts +11 -8
  416. package/src/memory/job-handlers/conversation-starters.ts +16 -10
  417. package/src/memory/jobs-store.ts +64 -4
  418. package/src/memory/jobs-worker.ts +22 -9
  419. package/src/memory/llm-usage-store.ts +92 -56
  420. package/src/memory/migrations/219-oauth-providers-token-exchange-body-format.ts +15 -0
  421. package/src/memory/migrations/220-normalize-user-file-by-principal.ts +190 -0
  422. package/src/memory/migrations/221-conversations-archived-at.ts +16 -0
  423. package/src/memory/migrations/index.ts +6 -0
  424. package/src/memory/migrations/registry.ts +8 -0
  425. package/src/memory/qdrant-manager.ts +43 -16
  426. package/src/memory/schema/conversations.ts +2 -0
  427. package/src/memory/schema/oauth.ts +3 -0
  428. package/src/memory/usage-buckets.ts +396 -0
  429. package/src/messaging/providers/gmail/client.ts +57 -6
  430. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +282 -0
  431. package/src/messaging/providers/slack/adapter.ts +143 -38
  432. package/src/messaging/providers/slack/client.ts +16 -0
  433. package/src/messaging/providers/slack/types.ts +4 -0
  434. package/src/notifications/decision-engine.ts +3 -3
  435. package/src/notifications/signal.ts +5 -0
  436. package/src/oauth/__tests__/identity-verifier.test.ts +1 -0
  437. package/src/oauth/byo-connection.test.ts +18 -1
  438. package/src/oauth/byo-connection.ts +3 -1
  439. package/src/oauth/connect-orchestrator.ts +2 -0
  440. package/src/oauth/connection-resolver.ts +6 -2
  441. package/src/oauth/connection.ts +2 -0
  442. package/src/oauth/oauth-store.ts +9 -0
  443. package/src/oauth/platform-connection.test.ts +98 -0
  444. package/src/oauth/platform-connection.ts +52 -31
  445. package/src/oauth/seed-providers.ts +7 -0
  446. package/src/permissions/checker.ts +16 -6
  447. package/src/permissions/defaults.ts +49 -1
  448. package/src/permissions/trust-store.ts +3 -3
  449. package/src/permissions/workspace-policy.ts +3 -0
  450. package/src/platform/client.test.ts +10 -0
  451. package/src/platform/sync-identity.ts +129 -0
  452. package/src/prompts/persona-resolver.ts +126 -2
  453. package/src/prompts/system-prompt.ts +59 -18
  454. package/src/prompts/templates/BOOTSTRAP.md +5 -5
  455. package/src/prompts/templates/SOUL.md +3 -1
  456. package/src/prompts/templates/UPDATES.md +12 -0
  457. package/src/prompts/templates/channels/slack.md +20 -0
  458. package/src/prompts/update-bulletin-format.ts +26 -9
  459. package/src/prompts/update-bulletin.ts +34 -23
  460. package/src/prompts/user-reference.ts +20 -17
  461. package/src/providers/__tests__/provider-secret-catalog.test.ts +42 -0
  462. package/src/providers/anthropic/client.ts +157 -61
  463. package/src/providers/fireworks/client.ts +2 -2
  464. package/src/providers/gemini/client.ts +9 -1
  465. package/src/providers/model-catalog.ts +6 -0
  466. package/src/providers/model-intents.ts +4 -4
  467. package/src/providers/ollama/client.ts +2 -2
  468. package/src/providers/openai/chat-completions-provider.ts +474 -0
  469. package/src/providers/openai/client.ts +25 -440
  470. package/src/providers/openai/responses-provider.ts +502 -0
  471. package/src/providers/openrouter/client.ts +101 -4
  472. package/src/providers/provider-secret-catalog.ts +139 -0
  473. package/src/providers/registry.ts +2 -2
  474. package/src/providers/retry.ts +14 -3
  475. package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +251 -0
  476. package/src/providers/speech-to-text/__tests__/resolve.test.ts +828 -0
  477. package/src/providers/speech-to-text/deepgram-realtime.test.ts +980 -0
  478. package/src/providers/speech-to-text/deepgram-realtime.ts +767 -0
  479. package/src/providers/speech-to-text/deepgram.test.ts +332 -0
  480. package/src/providers/speech-to-text/deepgram.ts +115 -0
  481. package/src/providers/speech-to-text/google-gemini-live-stream.test.ts +743 -0
  482. package/src/providers/speech-to-text/google-gemini-live-stream.ts +625 -0
  483. package/src/providers/speech-to-text/google-gemini.test.ts +226 -0
  484. package/src/providers/speech-to-text/google-gemini.ts +101 -0
  485. package/src/providers/speech-to-text/openai-whisper-stream.test.ts +564 -0
  486. package/src/providers/speech-to-text/openai-whisper-stream.ts +381 -0
  487. package/src/providers/speech-to-text/openai-whisper.test.ts +1 -37
  488. package/src/providers/speech-to-text/openai-whisper.ts +63 -33
  489. package/src/providers/speech-to-text/provider-catalog.ts +306 -0
  490. package/src/providers/speech-to-text/resolve.ts +386 -6
  491. package/src/providers/types.ts +9 -0
  492. package/src/runtime/AGENTS.md +43 -1
  493. package/src/runtime/__tests__/agent-wake.test.ts +831 -0
  494. package/src/runtime/__tests__/runtime-mode.test.ts +62 -0
  495. package/src/runtime/__tests__/slack-block-formatting.test.ts +481 -0
  496. package/src/runtime/agent-wake.ts +512 -0
  497. package/src/runtime/auth/__tests__/route-policy.test.ts +40 -0
  498. package/src/runtime/auth/route-policy.ts +30 -5
  499. package/src/runtime/auth/token-service.ts +56 -1
  500. package/src/runtime/btw-sidechain.ts +2 -0
  501. package/src/runtime/capability-tokens.ts +10 -10
  502. package/src/runtime/channel-invite-transport.ts +1 -1
  503. package/src/runtime/channel-invite-transports/email.ts +14 -6
  504. package/src/runtime/channel-readiness-service.ts +12 -22
  505. package/src/runtime/chrome-extension-registry.ts +38 -2
  506. package/src/runtime/http-server.ts +395 -10
  507. package/src/runtime/http-types.ts +6 -2
  508. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +36 -0
  509. package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +360 -0
  510. package/src/runtime/migrations/migration-transport.ts +1 -0
  511. package/src/runtime/migrations/migration-wizard.ts +1 -0
  512. package/src/runtime/migrations/vbundle-import-analyzer.ts +77 -1
  513. package/src/runtime/migrations/vbundle-importer.ts +34 -0
  514. package/src/runtime/pending-interactions.ts +0 -11
  515. package/src/runtime/routes/__tests__/backup-routes.test.ts +967 -0
  516. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +507 -0
  517. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +208 -0
  518. package/src/runtime/routes/__tests__/stt-routes.test.ts +406 -0
  519. package/src/runtime/routes/__tests__/tts-routes.test.ts +474 -0
  520. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +148 -17
  521. package/src/runtime/routes/app-management-routes.ts +12 -18
  522. package/src/runtime/routes/attachment-routes.test.ts +9 -3
  523. package/src/runtime/routes/attachment-routes.ts +216 -17
  524. package/src/runtime/routes/backup-routes.ts +519 -0
  525. package/src/runtime/routes/browser-extension-pair-routes.ts +82 -23
  526. package/src/runtime/routes/btw-routes.ts +8 -6
  527. package/src/runtime/routes/contact-routes.test.ts +298 -0
  528. package/src/runtime/routes/contact-routes.ts +132 -5
  529. package/src/runtime/routes/conversation-analysis-routes.ts +22 -142
  530. package/src/runtime/routes/conversation-management-routes.ts +115 -0
  531. package/src/runtime/routes/conversation-routes.ts +367 -146
  532. package/src/runtime/routes/filing-routes.ts +93 -0
  533. package/src/runtime/routes/home-feed-routes.ts +334 -0
  534. package/src/runtime/routes/home-state-routes.ts +138 -0
  535. package/src/runtime/routes/host-browser-routes.ts +3 -14
  536. package/src/runtime/routes/identity-intro-cache.ts +7 -3
  537. package/src/runtime/routes/identity-routes.ts +3 -17
  538. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +46 -39
  539. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +15 -15
  540. package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +137 -0
  541. package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +179 -0
  542. package/src/runtime/routes/integrations/slack/channel.ts +11 -3
  543. package/src/runtime/routes/integrations/slack/share.ts +45 -7
  544. package/src/runtime/routes/llm-context-normalization.ts +303 -0
  545. package/src/runtime/routes/memory-item-routes.test.ts +3 -2
  546. package/src/runtime/routes/migration-routes.ts +40 -5
  547. package/src/runtime/routes/settings-routes.ts +22 -5
  548. package/src/runtime/routes/skills-routes.ts +76 -7
  549. package/src/runtime/routes/stt-routes.ts +233 -0
  550. package/src/runtime/routes/surface-action-routes.ts +41 -2
  551. package/src/runtime/routes/tts-routes.ts +108 -24
  552. package/src/runtime/routes/usage-routes.ts +30 -2
  553. package/src/runtime/routes/user-route-dispatcher.ts +50 -5
  554. package/src/runtime/routes/user-routes.ts +13 -1
  555. package/src/runtime/routes/work-items-routes.ts +8 -1
  556. package/src/runtime/runtime-mode.ts +33 -0
  557. package/src/runtime/services/__tests__/analyze-conversation.test.ts +444 -0
  558. package/src/runtime/services/__tests__/analyze-deps-singleton.test.ts +67 -0
  559. package/src/runtime/services/__tests__/auto-analysis-prompt.test.ts +53 -0
  560. package/src/runtime/services/__tests__/manual-analysis-prompt.test.ts +41 -0
  561. package/src/runtime/services/analyze-conversation.ts +344 -0
  562. package/src/runtime/services/analyze-deps-singleton.ts +32 -0
  563. package/src/runtime/services/auto-analysis-prompt.ts +55 -0
  564. package/src/runtime/skill-route-registry.ts +49 -0
  565. package/src/runtime/slack-block-formatting.ts +437 -10
  566. package/src/schedule/scheduler.ts +50 -0
  567. package/src/security/oauth2.ts +26 -4
  568. package/src/security/secure-keys.ts +25 -2
  569. package/src/security/token-manager.ts +8 -0
  570. package/src/sequence/engine.ts +23 -0
  571. package/src/sequence/types.ts +1 -1
  572. package/src/skills/catalog-files.ts +64 -2
  573. package/src/skills/category-inference.ts +122 -0
  574. package/src/skills/clawhub-files.ts +213 -0
  575. package/src/skills/clawhub.ts +84 -23
  576. package/src/skills/skill-file-provider.ts +40 -0
  577. package/src/skills/skillssh-files.ts +395 -0
  578. package/src/skills/skillssh-registry.ts +4 -4
  579. package/src/stt/__tests__/daemon-batch-transcriber.test.ts +392 -0
  580. package/src/stt/__tests__/types.test.ts +89 -0
  581. package/src/stt/daemon-batch-transcriber.ts +195 -0
  582. package/src/stt/stt-stream-session.ts +499 -0
  583. package/src/stt/types.ts +330 -0
  584. package/src/stt/wav-encoder.test.ts +373 -0
  585. package/src/stt/wav-encoder.ts +175 -0
  586. package/src/subagent/manager.ts +38 -14
  587. package/src/tools/browser/__tests__/browser-mode.test.ts +119 -0
  588. package/src/tools/browser/__tests__/browser-status.test.ts +123 -0
  589. package/src/tools/browser/browser-execution.ts +1163 -23
  590. package/src/tools/browser/browser-manager.ts +45 -0
  591. package/src/tools/browser/browser-mode-constants.ts +12 -0
  592. package/src/tools/browser/browser-mode.ts +92 -0
  593. package/src/tools/browser/browser-status-constants.ts +33 -0
  594. package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +393 -0
  595. package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +29 -0
  596. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +1648 -32
  597. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +264 -0
  598. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +183 -17
  599. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +254 -21
  600. package/src/tools/browser/cdp-client/errors.ts +15 -0
  601. package/src/tools/browser/cdp-client/extension-cdp-client.ts +39 -16
  602. package/src/tools/browser/cdp-client/factory.ts +797 -87
  603. package/src/tools/browser/cdp-client/index.ts +16 -2
  604. package/src/tools/browser/cdp-client/types.ts +68 -0
  605. package/src/tools/credentials/vault.ts +35 -6
  606. package/src/tools/network/web-fetch.ts +5 -2
  607. package/src/tools/network/web-search.ts +5 -2
  608. package/src/tools/shared/shell-output.ts +3 -1
  609. package/src/tools/side-effects.ts +2 -0
  610. package/src/tools/skills/sandbox-runner.ts +3 -2
  611. package/src/tools/terminal/safe-env.ts +10 -2
  612. package/src/tools/terminal/shell.ts +15 -4
  613. package/src/tools/tool-manifest.ts +21 -0
  614. package/src/tools/types.ts +17 -0
  615. package/src/tools/ui-surface/definitions.ts +6 -1
  616. package/src/tts/__tests__/provider-adapters.test.ts +834 -0
  617. package/src/tts/__tests__/provider-catalog-consistency.test.ts +196 -0
  618. package/src/tts/__tests__/provider-catalog.test.ts +183 -0
  619. package/src/tts/__tests__/provider-registry.test.ts +90 -0
  620. package/src/tts/provider-catalog.ts +201 -0
  621. package/src/tts/provider-registry.ts +73 -0
  622. package/src/tts/providers/deepgram-provider.ts +219 -0
  623. package/src/tts/providers/elevenlabs-provider.ts +211 -0
  624. package/src/tts/providers/fish-audio-provider.ts +183 -0
  625. package/src/tts/providers/index.ts +42 -0
  626. package/src/tts/providers/register-builtins.ts +130 -0
  627. package/src/tts/synthesize-text.ts +110 -0
  628. package/src/tts/tts-config-resolver.ts +78 -0
  629. package/src/tts/types.ts +153 -0
  630. package/src/types/onboarding-context.ts +7 -0
  631. package/src/util/abort-reasons.ts +58 -0
  632. package/src/util/device-id.ts +32 -16
  633. package/src/util/errors.ts +9 -1
  634. package/src/util/platform.ts +54 -10
  635. package/src/util/pricing.ts +66 -3
  636. package/src/util/spawn.ts +1 -1
  637. package/src/util/truncate.ts +4 -2
  638. package/src/util/unicode.ts +201 -0
  639. package/src/version.ts +19 -24
  640. package/src/watcher/engine.ts +23 -0
  641. package/src/watcher/watcher-store.ts +31 -0
  642. package/src/workspace/migrations/003-seed-device-id.ts +9 -3
  643. package/src/workspace/migrations/017-seed-persona-dirs.ts +68 -4
  644. package/src/workspace/migrations/029-seed-pkb.ts +1 -1
  645. package/src/workspace/migrations/031-drop-user-md.ts +317 -0
  646. package/src/workspace/migrations/031-llm-log-retention-zero-to-null.ts +73 -0
  647. package/src/workspace/migrations/032-tts-provider-unification.ts +227 -0
  648. package/src/workspace/migrations/033-stt-service-explicit-config.ts +122 -0
  649. package/src/workspace/migrations/034-remove-calls-voice-transcription-provider.ts +215 -0
  650. package/src/workspace/migrations/035-seed-slack-channel-persona.ts +50 -0
  651. package/src/workspace/migrations/036-update-pkb-index-bar.ts +37 -0
  652. package/src/workspace/migrations/037-create-meets-dir.ts +61 -0
  653. package/src/workspace/migrations/registry.ts +16 -0
  654. package/src/workspace/top-level-renderer.ts +13 -1
  655. package/src/workspace/turn-commit.ts +31 -0
  656. package/src/__tests__/email-cli.test.ts +0 -297
  657. package/src/__tests__/email-service-config-fallback.test.ts +0 -102
  658. package/src/cli/commands/browser-relay.ts +0 -466
  659. package/src/email/guardrails.ts +0 -221
  660. package/src/email/provider.ts +0 -117
  661. package/src/email/providers/agentmail.ts +0 -361
  662. package/src/email/providers/index.ts +0 -65
  663. package/src/email/service.ts +0 -384
  664. package/src/email/types.ts +0 -126
  665. package/src/prompts/templates/USER.md +0 -13
  666. package/src/providers/speech-to-text/types.ts +0 -17
  667. package/src/runtime/routes/browser-cdp-routes.ts +0 -229
@@ -77,6 +77,7 @@ const mockConnections = new Map<
77
77
  expiresAt: number | null;
78
78
  grantedScopes?: string;
79
79
  accountInfo?: string | null;
80
+ status?: string;
80
81
  }
81
82
  >();
82
83
  const mockApps = new Map<
@@ -92,14 +93,26 @@ const mockProviders = new Map<
92
93
  string,
93
94
  {
94
95
  key: string;
96
+ provider: string;
95
97
  tokenExchangeUrl: string;
96
98
  tokenEndpointAuthMethod?: string;
99
+ tokenExchangeBodyFormat?: string;
97
100
  baseUrl?: string;
101
+ managedServiceConfigKey?: string | null;
98
102
  }
99
103
  >();
100
104
 
101
105
  mock.module("./oauth-store.js", () => ({
102
106
  getConnectionByProvider: (service: string) => mockConnections.get(service),
107
+ getActiveConnection: (
108
+ service: string,
109
+ opts?: { clientId?: string; account?: string },
110
+ ) => {
111
+ const conn = mockConnections.get(service);
112
+ if (!conn) return undefined;
113
+ if (opts?.account && conn.accountInfo !== opts.account) return undefined;
114
+ return conn;
115
+ },
103
116
  getConnection: (id: string) => {
104
117
  for (const conn of mockConnections.values()) {
105
118
  if (conn.id === id) return conn;
@@ -192,12 +205,15 @@ async function setupCredential(
192
205
  const connId = `conn-${service}`;
193
206
  mockProviders.set(service, {
194
207
  key: service,
208
+ provider: service,
195
209
  tokenExchangeUrl: "https://oauth2.googleapis.com/token",
210
+ tokenExchangeBodyFormat: "form",
196
211
  // Only well-known providers (gmail) have a baseUrl; custom services don't
197
212
  baseUrl:
198
213
  service === "google"
199
214
  ? "https://gmail.googleapis.com/gmail/v1/users/me"
200
215
  : undefined,
216
+ managedServiceConfigKey: null,
201
217
  });
202
218
  mockApps.set(appId, {
203
219
  id: appId,
@@ -212,6 +228,7 @@ async function setupCredential(
212
228
  expiresAt: opts?.expiresAt ?? Date.now() + 3600 * 1000,
213
229
  grantedScopes: JSON.stringify(opts?.grantedScopes ?? ["read", "write"]),
214
230
  accountInfo: null,
231
+ status: "active",
215
232
  });
216
233
  // Store access token in oauth-store key format
217
234
  await setSecureKeyAsync(
@@ -509,7 +526,7 @@ describe("resolveOAuthConnection", () => {
509
526
  test("throws when no base URL configured", async () => {
510
527
  await setupCredential("custom-service");
511
528
  await expect(resolveOAuthConnection("custom-service")).rejects.toThrow(
512
- /No base URL configured for "custom-service"/,
529
+ /OAuth provider "custom-service" has no base URL configured/,
513
530
  );
514
531
  });
515
532
  });
@@ -82,7 +82,9 @@ export class BYOOAuthConnection implements OAuthConnection {
82
82
  method: req.method,
83
83
  headers,
84
84
  body: req.body ? JSON.stringify(req.body) : undefined,
85
- signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
85
+ signal: req.signal
86
+ ? AbortSignal.any([req.signal, AbortSignal.timeout(REQUEST_TIMEOUT_MS)])
87
+ : AbortSignal.timeout(REQUEST_TIMEOUT_MS),
86
88
  });
87
89
 
88
90
  if (resp.status === 401) {
@@ -209,6 +209,8 @@ export async function orchestrateOAuthConnect(
209
209
  authorizeParams,
210
210
  userinfoUrl,
211
211
  tokenEndpointAuthMethod,
212
+ tokenExchangeBodyFormat:
213
+ (providerRow.tokenExchangeBodyFormat as "form" | "json") ?? "form",
212
214
  };
213
215
 
214
216
  const storageParams = {
@@ -1,5 +1,9 @@
1
1
  import { getConfig } from "../config/loader.js";
2
- import { type Services, ServicesSchema } from "../config/schemas/services.js";
2
+ import {
3
+ getServiceMode,
4
+ type Services,
5
+ ServicesSchema,
6
+ } from "../config/schemas/services.js";
3
7
  import { VellumPlatformClient } from "../platform/client.js";
4
8
  import { getSecureKeyAsync } from "../security/secure-keys.js";
5
9
  import { getLogger } from "../util/logger.js";
@@ -47,7 +51,7 @@ export async function resolveOAuthConnection(
47
51
 
48
52
  if (managedKey && managedKey in ServicesSchema.shape) {
49
53
  const services: Services = getConfig().services;
50
- if (services[managedKey as keyof Services].mode === "managed") {
54
+ if (getServiceMode(services, managedKey as keyof Services) === "managed") {
51
55
  const client = await VellumPlatformClient.create();
52
56
  if (!client || !client.platformAssistantId) {
53
57
  const detail = !client
@@ -11,6 +11,8 @@ export interface OAuthConnectionRequest {
11
11
  * use the same credential but different base URLs).
12
12
  */
13
13
  baseUrl?: string;
14
+ /** Optional abort signal to cancel the request. */
15
+ signal?: AbortSignal;
14
16
  }
15
17
 
16
18
  export interface OAuthConnectionResponse {
@@ -72,6 +72,7 @@ export function seedProviders(
72
72
  tokenExchangeUrl: string;
73
73
  refreshUrl?: string;
74
74
  tokenEndpointAuthMethod?: string;
75
+ tokenExchangeBodyFormat?: string;
75
76
  userinfoUrl?: string;
76
77
  pingUrl?: string;
77
78
  pingMethod?: string;
@@ -122,6 +123,7 @@ export function seedProviders(
122
123
  // token endpoint auth method.
123
124
  const tokenEndpointAuthMethod =
124
125
  p.tokenEndpointAuthMethod || "client_secret_post";
126
+ const tokenExchangeBodyFormat = p.tokenExchangeBodyFormat || "form";
125
127
  const userinfoUrl = p.userinfoUrl ?? null;
126
128
  const pingUrl = p.pingUrl ?? null;
127
129
  const pingMethod = p.pingMethod ?? null;
@@ -176,6 +178,7 @@ export function seedProviders(
176
178
  tokenExchangeUrl,
177
179
  refreshUrl,
178
180
  tokenEndpointAuthMethod,
181
+ tokenExchangeBodyFormat,
179
182
  userinfoUrl,
180
183
  baseUrl,
181
184
  defaultScopes,
@@ -217,6 +220,7 @@ export function seedProviders(
217
220
  tokenExchangeUrl,
218
221
  refreshUrl,
219
222
  tokenEndpointAuthMethod,
223
+ tokenExchangeBodyFormat,
220
224
  userinfoUrl,
221
225
  baseUrl: sql`COALESCE(${oauthProviders.baseUrl}, ${baseUrl})`,
222
226
  scopeSeparator,
@@ -279,6 +283,7 @@ export function registerProvider(params: {
279
283
  tokenExchangeUrl: string;
280
284
  refreshUrl?: string;
281
285
  tokenEndpointAuthMethod?: string;
286
+ tokenExchangeBodyFormat?: string;
282
287
  userinfoUrl?: string;
283
288
  pingUrl?: string;
284
289
  pingMethod?: string;
@@ -331,6 +336,7 @@ export function registerProvider(params: {
331
336
  refreshUrl: params.refreshUrl ?? null,
332
337
  tokenEndpointAuthMethod:
333
338
  params.tokenEndpointAuthMethod || "client_secret_post",
339
+ tokenExchangeBodyFormat: params.tokenExchangeBodyFormat || "form",
334
340
  userinfoUrl: params.userinfoUrl ?? null,
335
341
  baseUrl: params.baseUrl ?? null,
336
342
  defaultScopes: JSON.stringify(params.defaultScopes),
@@ -402,6 +408,7 @@ export function updateProvider(
402
408
  tokenExchangeUrl: string;
403
409
  refreshUrl: string;
404
410
  tokenEndpointAuthMethod: string;
411
+ tokenExchangeBodyFormat: string;
405
412
  userinfoUrl: string;
406
413
  pingUrl: string;
407
414
  pingMethod: string;
@@ -452,6 +459,8 @@ export function updateProvider(
452
459
  if (params.tokenEndpointAuthMethod !== undefined)
453
460
  set.tokenEndpointAuthMethod =
454
461
  params.tokenEndpointAuthMethod || "client_secret_post";
462
+ if (params.tokenExchangeBodyFormat !== undefined)
463
+ set.tokenExchangeBodyFormat = params.tokenExchangeBodyFormat || "form";
455
464
  if (params.userinfoUrl !== undefined) set.userinfoUrl = params.userinfoUrl;
456
465
  if (params.pingUrl !== undefined) set.pingUrl = params.pingUrl;
457
466
  if (params.pingMethod !== undefined) set.pingMethod = params.pingMethod;
@@ -1,5 +1,13 @@
1
1
  import { describe, expect, mock, test } from "bun:test";
2
2
 
3
+ import * as actualRetry from "../util/retry.js";
4
+
5
+ // Stub out sleep so retry tests don't wait for real delays.
6
+ mock.module("../util/retry.js", () => ({
7
+ ...actualRetry,
8
+ sleep: () => Promise.resolve(),
9
+ }));
10
+
3
11
  import type { VellumPlatformClient } from "../platform/client.js";
4
12
  import { BackendError, VellumError } from "../util/errors.js";
5
13
  import {
@@ -226,6 +234,96 @@ describe("PlatformOAuthConnection", () => {
226
234
  );
227
235
  });
228
236
 
237
+ test("retries on 429 and succeeds", async () => {
238
+ let callCount = 0;
239
+ const client = makeMockClient(
240
+ mock(async () => {
241
+ callCount++;
242
+ if (callCount <= 2) {
243
+ return new Response("", { status: 429 });
244
+ }
245
+ return new Response(
246
+ JSON.stringify({ status: 200, headers: {}, body: { ok: true } }),
247
+ { status: 200 },
248
+ );
249
+ }) as unknown as typeof globalThis.fetch,
250
+ );
251
+
252
+ const conn = new PlatformOAuthConnection({ ...DEFAULT_OPTIONS, client });
253
+ const result = await conn.request({ method: "GET", path: "/test" });
254
+
255
+ expect(result.status).toBe(200);
256
+ expect(result.body).toEqual({ ok: true });
257
+ expect(callCount).toBe(3);
258
+ });
259
+
260
+ test("throws after exhausting retries on 429", async () => {
261
+ const client = makeMockClient(
262
+ mock(
263
+ async () => new Response("", { status: 429 }),
264
+ ) as unknown as typeof globalThis.fetch,
265
+ );
266
+
267
+ const conn = new PlatformOAuthConnection({ ...DEFAULT_OPTIONS, client });
268
+ await expect(
269
+ conn.request({ method: "GET", path: "/test" }),
270
+ ).rejects.toThrow("Platform proxy returned unexpected status 429");
271
+ });
272
+
273
+ test("retries on 500 and succeeds", async () => {
274
+ let callCount = 0;
275
+ const client = makeMockClient(
276
+ mock(async () => {
277
+ callCount++;
278
+ if (callCount === 1) {
279
+ return new Response("", { status: 500 });
280
+ }
281
+ return new Response(
282
+ JSON.stringify({ status: 200, headers: {}, body: null }),
283
+ { status: 200 },
284
+ );
285
+ }) as unknown as typeof globalThis.fetch,
286
+ );
287
+
288
+ const conn = new PlatformOAuthConnection({ ...DEFAULT_OPTIONS, client });
289
+ const result = await conn.request({ method: "GET", path: "/test" });
290
+
291
+ expect(result.status).toBe(200);
292
+ expect(callCount).toBe(2);
293
+ });
294
+
295
+ test("does not retry on 424", async () => {
296
+ let callCount = 0;
297
+ const client = makeMockClient(
298
+ mock(async () => {
299
+ callCount++;
300
+ return new Response("", { status: 424 });
301
+ }) as unknown as typeof globalThis.fetch,
302
+ );
303
+
304
+ const conn = new PlatformOAuthConnection({ ...DEFAULT_OPTIONS, client });
305
+ await expect(
306
+ conn.request({ method: "GET", path: "/test" }),
307
+ ).rejects.toThrow(CredentialRequiredError);
308
+ expect(callCount).toBe(1);
309
+ });
310
+
311
+ test("does not retry on 403", async () => {
312
+ let callCount = 0;
313
+ const client = makeMockClient(
314
+ mock(async () => {
315
+ callCount++;
316
+ return new Response("", { status: 403 });
317
+ }) as unknown as typeof globalThis.fetch,
318
+ );
319
+
320
+ const conn = new PlatformOAuthConnection({ ...DEFAULT_OPTIONS, client });
321
+ await expect(
322
+ conn.request({ method: "GET", path: "/test" }),
323
+ ).rejects.toThrow("Platform proxy returned unexpected status 403");
324
+ expect(callCount).toBe(1);
325
+ });
326
+
229
327
  test("uses connectionId in proxy URL regardless of provider format", async () => {
230
328
  const client = makeMockClient(
231
329
  mock(async (url: string | URL | Request) => {
@@ -1,11 +1,18 @@
1
1
  import type { VellumPlatformClient } from "../platform/client.js";
2
2
  import { BackendError } from "../util/errors.js";
3
+ import {
4
+ getHttpRetryDelay,
5
+ isRetryableStatus,
6
+ sleep,
7
+ } from "../util/retry.js";
3
8
  import type {
4
9
  OAuthConnection,
5
10
  OAuthConnectionRequest,
6
11
  OAuthConnectionResponse,
7
12
  } from "./connection.js";
8
13
 
14
+ const MAX_RETRIES = 3;
15
+
9
16
  export class CredentialRequiredError extends BackendError {
10
17
  constructor(message = "Connection not set up on platform") {
11
18
  super(message);
@@ -76,39 +83,53 @@ export class PlatformOAuthConnection implements OAuthConnection {
76
83
  },
77
84
  };
78
85
 
79
- const response = await this.client.fetch(proxyPath, {
80
- method: "POST",
81
- headers: {
82
- "Content-Type": "application/json",
83
- },
84
- body: JSON.stringify(body),
85
- });
86
-
87
- if (response.status === 424) {
88
- throw new CredentialRequiredError();
89
- }
90
-
91
- if (response.status === 502) {
92
- throw new ProviderUnreachableError();
93
- }
94
-
95
- if (!response.ok) {
96
- throw new BackendError(
97
- `Platform proxy returned unexpected status ${response.status}`,
98
- );
86
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
87
+ const response = await this.client.fetch(proxyPath, {
88
+ method: "POST",
89
+ headers: {
90
+ "Content-Type": "application/json",
91
+ },
92
+ body: JSON.stringify(body),
93
+ signal: req.signal,
94
+ });
95
+
96
+ if (response.status === 424) {
97
+ throw new CredentialRequiredError();
98
+ }
99
+
100
+ if (response.status === 502) {
101
+ throw new ProviderUnreachableError();
102
+ }
103
+
104
+ if (
105
+ !response.ok &&
106
+ isRetryableStatus(response.status) &&
107
+ attempt < MAX_RETRIES
108
+ ) {
109
+ await sleep(getHttpRetryDelay(response, attempt));
110
+ continue;
111
+ }
112
+
113
+ if (!response.ok) {
114
+ throw new BackendError(
115
+ `Platform proxy returned unexpected status ${response.status}`,
116
+ );
117
+ }
118
+
119
+ const json = (await response.json()) as {
120
+ status: number;
121
+ headers: Record<string, string>;
122
+ body: unknown;
123
+ };
124
+
125
+ return {
126
+ status: json.status,
127
+ headers: json.headers,
128
+ body: json.body,
129
+ };
99
130
  }
100
131
 
101
- const json = (await response.json()) as {
102
- status: number;
103
- headers: Record<string, string>;
104
- body: unknown;
105
- };
106
-
107
- return {
108
- status: json.status,
109
- headers: json.headers,
110
- body: json.body,
111
- };
132
+ throw new BackendError("Platform proxy request failed after retries");
112
133
  }
113
134
 
114
135
  async withToken<T>(_fn: (token: string) => Promise<T>): Promise<T> {
@@ -27,6 +27,7 @@ export const PROVIDER_SEED_DATA: Record<
27
27
  tokenExchangeUrl: string;
28
28
  refreshUrl?: string;
29
29
  tokenEndpointAuthMethod?: string;
30
+ tokenExchangeBodyFormat?: string;
30
31
  userinfoUrl?: string;
31
32
  pingUrl?: string;
32
33
  pingMethod?: string;
@@ -85,6 +86,7 @@ export const PROVIDER_SEED_DATA: Record<
85
86
  "https://www.googleapis.com/auth/gmail.readonly",
86
87
  "https://www.googleapis.com/auth/gmail.modify",
87
88
  "https://www.googleapis.com/auth/gmail.send",
89
+ "https://www.googleapis.com/auth/gmail.settings.basic",
88
90
  "https://www.googleapis.com/auth/calendar.readonly",
89
91
  "https://www.googleapis.com/auth/calendar.events",
90
92
  "https://www.googleapis.com/auth/userinfo.email",
@@ -140,6 +142,7 @@ export const PROVIDER_SEED_DATA: Record<
140
142
  clientIdPlaceholder: null,
141
143
  logoUrl: "https://cdn.simpleicons.org/slack",
142
144
  defaultScopes: [
145
+ "channels:join",
143
146
  "channels:read",
144
147
  "channels:history",
145
148
  "groups:read",
@@ -199,6 +202,8 @@ export const PROVIDER_SEED_DATA: Record<
199
202
  },
200
203
  authorizeParams: { owner: "user" },
201
204
  tokenEndpointAuthMethod: "client_secret_basic",
205
+ tokenExchangeBodyFormat: "json",
206
+ managedServiceConfigKey: "notion-oauth",
202
207
  loopbackPort: 17323,
203
208
  injectionTemplates: [
204
209
  {
@@ -238,6 +243,8 @@ export const PROVIDER_SEED_DATA: Record<
238
243
  },
239
244
  tokenEndpointAuthMethod: "client_secret_basic",
240
245
  loopbackPort: 17335,
246
+ managedServiceConfigKey: "twitter-oauth",
247
+ featureFlag: "managed-x-oauth-integration",
241
248
  injectionTemplates: [
242
249
  {
243
250
  hostPattern: "api.x.com",
@@ -20,7 +20,11 @@ import {
20
20
  looksLikePathOnlyInput,
21
21
  } from "../tools/network/url-safety.js";
22
22
  import { getTool } from "../tools/registry.js";
23
- import { getDeprecatedDir, getWorkspaceHooksDir } from "../util/platform.js";
23
+ import {
24
+ getDeprecatedDir,
25
+ getProtectedDir,
26
+ getWorkspaceHooksDir,
27
+ } from "../util/platform.js";
24
28
  import {
25
29
  buildShellAllowlistOptions,
26
30
  buildShellCommandCandidates,
@@ -962,11 +966,17 @@ function isActorTokenSigningKeyPath(
962
966
  if (!filePath) return false;
963
967
  const cwd = workingDir ?? process.cwd();
964
968
  const resolvedPath = resolve(cwd, filePath);
965
- const signingKeyPaths = [
966
- join(homedir(), ".vellum", "protected", "actor-token-signing-key"),
967
- join(getDeprecatedDir(), "actor-token-signing-key"),
968
- resolve(cwd, "deprecated", "actor-token-signing-key"),
969
- ];
969
+ // Include both the per-instance protected dir AND the legacy global
970
+ // ~/.vellum/protected path so upgraded machines with a host-wide signing
971
+ // key still classify reads as High risk.
972
+ const signingKeyPaths = Array.from(
973
+ new Set([
974
+ join(homedir(), ".vellum", "protected", "actor-token-signing-key"),
975
+ join(getProtectedDir(), "actor-token-signing-key"),
976
+ join(getDeprecatedDir(), "actor-token-signing-key"),
977
+ resolve(cwd, "deprecated", "actor-token-signing-key"),
978
+ ]),
979
+ );
970
980
  return signingKeyPaths.includes(resolvedPath);
971
981
  }
972
982
 
@@ -3,6 +3,7 @@ import { join } from "node:path";
3
3
  import { getIsContainerized } from "../config/env-registry.js";
4
4
  import { getConfig } from "../config/loader.js";
5
5
  import { getBundledSkillsDir } from "../config/skills.js";
6
+ import { resolveGuardianPersonaPath } from "../prompts/persona-resolver.js";
6
7
  import { getWorkspaceDir } from "../util/platform.js";
7
8
 
8
9
  export interface DefaultRuleTemplate {
@@ -15,6 +16,16 @@ export interface DefaultRuleTemplate {
15
16
  allowHighRisk?: boolean;
16
17
  }
17
18
 
19
+ /**
20
+ * Escape minimatch metacharacters so a literal path is matched literally when
21
+ * interpolated into a rule pattern. Without this, characters like `*`, `?`,
22
+ * `[`, `]`, `{`, `}` in a filename would be treated as wildcards and broaden
23
+ * the resulting allow rule beyond the intended file.
24
+ */
25
+ function escapeMinimatchPath(p: string): string {
26
+ return p.replace(/[?*[\]{}()!|\\]/g, "\\$&");
27
+ }
28
+
18
29
  const HOST_FILE_TOOLS = [
19
30
  "host_file_read",
20
31
  "host_file_write",
@@ -118,7 +129,6 @@ export function getDefaultRuleTemplates(): DefaultRuleTemplate[] {
118
129
  const workspaceDir = getWorkspaceDir().replaceAll("\\", "/");
119
130
  const WORKSPACE_PROMPT_FILES = [
120
131
  "IDENTITY.md",
121
- "USER.md",
122
132
  "SOUL.md",
123
133
  "BOOTSTRAP.md",
124
134
  "UPDATES.md",
@@ -139,6 +149,40 @@ export function getDefaultRuleTemplates(): DefaultRuleTemplate[] {
139
149
  })),
140
150
  );
141
151
 
152
+ // Guardian persona file — the contact-store-resolved `users/<slug>.md`
153
+ // for the current guardian. Once the workspace has a guardian contact,
154
+ // their per-user persona file should be readable/editable without a
155
+ // prompt.
156
+ //
157
+ // Resolved dynamically at template-build time (rather than hardcoded
158
+ // like WORKSPACE_PROMPT_FILES) because the slug depends on the
159
+ // installed guardian. The try/catch protects against early-boot paths
160
+ // where the DB may not yet be initialized — in that case no guardian
161
+ // persona rules are emitted and the agent will be prompted on first
162
+ // edit until the guardian contact is created.
163
+ let guardianPersonaRules: DefaultRuleTemplate[] = [];
164
+ try {
165
+ const guardianPath = resolveGuardianPersonaPath();
166
+ if (guardianPath) {
167
+ const posixPath = guardianPath.replaceAll("\\", "/");
168
+ const escapedPath = escapeMinimatchPath(posixPath);
169
+ guardianPersonaRules = WORKSPACE_FILE_TOOLS.map((tool) => ({
170
+ id: `default:allow-${tool}-guardian-persona`,
171
+ tool,
172
+ pattern: `${tool}:${escapedPath}`,
173
+ scope: "everywhere",
174
+ decision: "allow" as const,
175
+ priority: 100,
176
+ }));
177
+ }
178
+ } catch {
179
+ // If guardian resolution fails at default-rule computation, the rule
180
+ // will be missing until the trust cache is invalidated and rebuilt.
181
+ // Runtime guardian-creation paths invalidate the cache via
182
+ // `clearTrustCache()` in `contacts-write.createGuardianBinding` so
183
+ // that the next `getRules()` call picks up the new auto-allow rule.
184
+ }
185
+
142
186
  const bootstrapDeleteRule: DefaultRuleTemplate = {
143
187
  id: "default:allow-bash-rm-bootstrap",
144
188
  tool: "bash",
@@ -248,6 +292,8 @@ export function getDefaultRuleTemplates(): DefaultRuleTemplate[] {
248
292
  "browser_snapshot",
249
293
  "browser_screenshot",
250
294
  "browser_close",
295
+ "browser_attach",
296
+ "browser_detach",
251
297
  "browser_click",
252
298
  "browser_type",
253
299
  "browser_press_key",
@@ -258,6 +304,7 @@ export function getDefaultRuleTemplates(): DefaultRuleTemplate[] {
258
304
  "browser_extract",
259
305
  "browser_wait_for_download",
260
306
  "browser_fill_credential",
307
+ "browser_status",
261
308
  ] as const;
262
309
 
263
310
  const browserToolRules: DefaultRuleTemplate[] = BROWSER_TOOLS_NO_SLASH.map(
@@ -303,6 +350,7 @@ export function getDefaultRuleTemplates(): DefaultRuleTemplate[] {
303
350
  ...computerUseRules,
304
351
  ...managedSkillRules,
305
352
  ...workspacePromptRules,
353
+ ...guardianPersonaRules,
306
354
  bootstrapDeleteRule,
307
355
  updatesDeleteRule,
308
356
  ...skillSourceMutationRules,
@@ -6,7 +6,6 @@ import {
6
6
  renameSync,
7
7
  writeFileSync,
8
8
  } from "node:fs";
9
- import { homedir } from "node:os";
10
9
  import { dirname, join } from "node:path";
11
10
 
12
11
  import { Minimatch } from "minimatch";
@@ -14,6 +13,7 @@ import { v4 as uuid } from "uuid";
14
13
 
15
14
  import { getIsContainerized } from "../config/env-registry.js";
16
15
  import { getLogger } from "../util/logger.js";
16
+ import { getProtectedDir } from "../util/platform.js";
17
17
  import { getDefaultRuleTemplates } from "./defaults.js";
18
18
  import * as trustClient from "./trust-client.js";
19
19
  import type {
@@ -135,12 +135,12 @@ function getTrustPath(): string {
135
135
  * Resolve the gateway security directory.
136
136
  *
137
137
  * Docker: `GATEWAY_SECURITY_DIR` env var.
138
- * Local: falls back to `~/.vellum/` + `protected/`.
138
+ * Local: the per-instance protected directory resolved by `getProtectedDir()`.
139
139
  */
140
140
  function getGatewaySecurityDir(): string {
141
141
  const securityDir = process.env.GATEWAY_SECURITY_DIR;
142
142
  if (securityDir) return securityDir;
143
- return join(homedir(), ".vellum", "protected");
143
+ return getProtectedDir();
144
144
  }
145
145
 
146
146
  /**
@@ -65,6 +65,9 @@ const NETWORK_TOOLS = new Set([
65
65
  "browser_hover",
66
66
  "browser_screenshot",
67
67
  "browser_close",
68
+ "browser_attach",
69
+ "browser_detach",
70
+ "browser_status",
68
71
  "network_request",
69
72
  ]);
70
73
 
@@ -23,6 +23,16 @@ mock.module("../config/env.js", () => ({
23
23
  getPlatformAssistantId: () => mockAssistantId,
24
24
  }));
25
25
 
26
+ // Stub the credential-store fallback so tests stay hermetic and do not
27
+ // read real values from the host credential backend.
28
+ mock.module("../security/secure-keys.js", () => ({
29
+ getSecureKeyAsync: async () => null,
30
+ }));
31
+
32
+ mock.module("../security/credential-key.js", () => ({
33
+ credentialKey: (namespace: string, key: string) => `${namespace}:${key}`,
34
+ }));
35
+
26
36
  // ---------------------------------------------------------------------------
27
37
  // Import under test (after mocks)
28
38
  // ---------------------------------------------------------------------------