@vellumai/assistant 0.6.2 → 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 (895) hide show
  1. package/ARCHITECTURE.md +273 -10
  2. package/Dockerfile +2 -3
  3. package/bun.lock +41 -49
  4. package/bunfig.toml +3 -0
  5. package/docs/architecture/memory.md +1 -1
  6. package/docs/backup-troubleshooting.md +52 -0
  7. package/docs/browser-use-architecture-phase2.md +174 -0
  8. package/docs/stt-provider-onboarding.md +120 -0
  9. package/knip.json +12 -2
  10. package/node_modules/@vellumai/ces-contracts/bun.lock +8 -6
  11. package/node_modules/@vellumai/ces-contracts/package.json +3 -3
  12. package/node_modules/@vellumai/ces-contracts/src/rpc.ts +42 -0
  13. package/openapi.yaml +1111 -86
  14. package/package.json +40 -42
  15. package/scripts/generate-openapi.ts +0 -2
  16. package/scripts/test.sh +73 -18
  17. package/src/__tests__/acp-session.test.ts +43 -0
  18. package/src/__tests__/agent-image-optimize.test.ts +28 -0
  19. package/src/__tests__/agent-loop.test.ts +123 -0
  20. package/src/__tests__/anthropic-provider.test.ts +263 -10
  21. package/src/__tests__/app-builder-tool-scripts.test.ts +1 -0
  22. package/src/__tests__/app-executors.test.ts +1 -0
  23. package/src/__tests__/app-source-watcher.test.ts +37 -11
  24. package/src/__tests__/approval-routes-http.test.ts +178 -1
  25. package/src/__tests__/auto-analysis-end-to-end.test.ts +550 -0
  26. package/src/__tests__/auto-analysis-prompt.test.ts +50 -0
  27. package/src/__tests__/browser-fill-credential.test.ts +240 -94
  28. package/src/__tests__/browser-manager.test.ts +40 -27
  29. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +2 -2
  30. package/src/__tests__/browser-skill-endstate.test.ts +31 -7
  31. package/src/__tests__/btw-routes.test.ts +7 -0
  32. package/src/__tests__/call-controller.test.ts +581 -20
  33. package/src/__tests__/catalog-files.test.ts +1000 -0
  34. package/src/__tests__/channel-approvals.test.ts +53 -0
  35. package/src/__tests__/channel-invite-transport.test.ts +2 -2
  36. package/src/__tests__/channel-readiness-routes.test.ts +16 -20
  37. package/src/__tests__/channel-readiness-service.test.ts +12 -7
  38. package/src/__tests__/checker.test.ts +157 -10
  39. package/src/__tests__/clawhub-files.test.ts +347 -0
  40. package/src/__tests__/commit-message-enrichment-service.test.ts +36 -19
  41. package/src/__tests__/config-analysis.test.ts +100 -0
  42. package/src/__tests__/config-managed-gemini-defaults.test.ts +326 -0
  43. package/src/__tests__/config-schema-cmd.test.ts +2 -2
  44. package/src/__tests__/config-schema.test.ts +1248 -224
  45. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +339 -0
  46. package/src/__tests__/config-watcher.test.ts +43 -8
  47. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +23 -0
  48. package/src/__tests__/contact-store-user-file.test.ts +512 -0
  49. package/src/__tests__/contacts-write.test.ts +197 -0
  50. package/src/__tests__/context-overflow-approval.test.ts +16 -1
  51. package/src/__tests__/context-window-manager.test.ts +88 -0
  52. package/src/__tests__/conversation-abort-tool-results.test.ts +2 -0
  53. package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -1
  54. package/src/__tests__/conversation-agent-loop.test.ts +99 -3
  55. package/src/__tests__/conversation-analysis-routes.test.ts +2 -2
  56. package/src/__tests__/conversation-attachments.test.ts +80 -4
  57. package/src/__tests__/conversation-confirmation-signals.test.ts +290 -0
  58. package/src/__tests__/conversation-error.test.ts +70 -0
  59. package/src/__tests__/conversation-fork-crud.test.ts +17 -0
  60. package/src/__tests__/conversation-history-web-search.test.ts +12 -4
  61. package/src/__tests__/conversation-host-access-routes.test.ts +229 -0
  62. package/src/__tests__/conversation-init.benchmark.test.ts +6 -1
  63. package/src/__tests__/conversation-inject-context.test.ts +103 -0
  64. package/src/__tests__/conversation-launcher-skill-regression.test.ts +51 -0
  65. package/src/__tests__/conversation-list-source.test.ts +145 -0
  66. package/src/__tests__/conversation-pre-run-repair.test.ts +2 -0
  67. package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -0
  68. package/src/__tests__/conversation-queue.test.ts +946 -62
  69. package/src/__tests__/conversation-routes-disk-view.test.ts +275 -0
  70. package/src/__tests__/conversation-routes-guardian-reply.test.ts +16 -0
  71. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  72. package/src/__tests__/conversation-runtime-assembly.test.ts +324 -46
  73. package/src/__tests__/conversation-skill-tools.test.ts +7 -4
  74. package/src/__tests__/conversation-slash-commands.test.ts +33 -0
  75. package/src/__tests__/conversation-slash-queue.test.ts +89 -18
  76. package/src/__tests__/conversation-slash-unknown.test.ts +2 -0
  77. package/src/__tests__/conversation-starter-routes.test.ts +126 -0
  78. package/src/__tests__/conversation-starters-cadence.test.ts +161 -0
  79. package/src/__tests__/conversation-store.test.ts +195 -0
  80. package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +226 -0
  81. package/src/__tests__/conversation-workspace-cache-state.test.ts +193 -0
  82. package/src/__tests__/conversation-workspace-injection.test.ts +2 -0
  83. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +2 -0
  84. package/src/__tests__/credential-execution-approval-bridge.test.ts +32 -1
  85. package/src/__tests__/credential-health-service.test.ts +352 -0
  86. package/src/__tests__/credential-security-invariants.test.ts +6 -3
  87. package/src/__tests__/credential-vault-unit.test.ts +383 -7
  88. package/src/__tests__/credential-vault.test.ts +152 -13
  89. package/src/__tests__/credentials-cli.test.ts +42 -18
  90. package/src/__tests__/cross-provider-web-search.test.ts +146 -35
  91. package/src/__tests__/date-context.test.ts +4 -4
  92. package/src/__tests__/deterministic-verification-control-plane.test.ts +10 -1
  93. package/src/__tests__/device-id.test.ts +112 -0
  94. package/src/__tests__/docker-signing-key-bootstrap.test.ts +167 -4
  95. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +1 -3
  96. package/src/__tests__/email-html-renderer.test.ts +71 -0
  97. package/src/__tests__/email-invite-adapter.test.ts +36 -32
  98. package/src/__tests__/embedding-managed-proxy-selection.test.ts +256 -0
  99. package/src/__tests__/emit-event-signal.test.ts +71 -0
  100. package/src/__tests__/extension-id-sync-guard.test.ts +222 -0
  101. package/src/__tests__/fixtures/mock-chrome-extension.ts +386 -0
  102. package/src/__tests__/gateway-only-enforcement.test.ts +206 -1
  103. package/src/__tests__/gateway-only-guard.test.ts +2 -0
  104. package/src/__tests__/gemini-provider.test.ts +66 -2
  105. package/src/__tests__/get-skill-detail-audit.test.ts +325 -0
  106. package/src/__tests__/gmail-archive-fallback.test.ts +193 -0
  107. package/src/__tests__/gmail-archive-gate.test.ts +246 -0
  108. package/src/__tests__/gmail-preferences.test.ts +117 -0
  109. package/src/__tests__/guardian-routing-invariants.test.ts +70 -2
  110. package/src/__tests__/headless-browser-interactions.test.ts +738 -359
  111. package/src/__tests__/headless-browser-mode.test.ts +614 -0
  112. package/src/__tests__/headless-browser-navigate.test.ts +528 -49
  113. package/src/__tests__/headless-browser-read-tools.test.ts +274 -100
  114. package/src/__tests__/headless-browser-snapshot.test.ts +250 -77
  115. package/src/__tests__/heartbeat-service.test.ts +70 -17
  116. package/src/__tests__/home-state-routes.test.ts +162 -0
  117. package/src/__tests__/host-bash-proxy.test.ts +145 -1
  118. package/src/__tests__/host-browser-e2e-cloud.test.ts +596 -0
  119. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +286 -0
  120. package/src/__tests__/host-browser-e2e-self-hosted.test.ts +374 -0
  121. package/src/__tests__/host-browser-event-routes.test.ts +350 -0
  122. package/src/__tests__/host-browser-proxy.test.ts +444 -0
  123. package/src/__tests__/host-browser-routes.test.ts +198 -0
  124. package/src/__tests__/host-browser-ws-events-e2e.test.ts +423 -0
  125. package/src/__tests__/host-cu-proxy.test.ts +166 -1
  126. package/src/__tests__/host-file-proxy.test.ts +185 -1
  127. package/src/__tests__/host-file-read-tool.test.ts +52 -0
  128. package/src/__tests__/host-proxy-interface.test.ts +165 -0
  129. package/src/__tests__/host-shell-tool.test.ts +1 -11
  130. package/src/__tests__/http-user-message-parity.test.ts +1 -0
  131. package/src/__tests__/identity-intro-cache.test.ts +40 -10
  132. package/src/__tests__/init-feature-flag-overrides.test.ts +38 -112
  133. package/src/__tests__/integration-status.test.ts +6 -7
  134. package/src/__tests__/jobs-store-upsert-debounced.test.ts +141 -0
  135. package/src/__tests__/list-messages-tool-merge.test.ts +37 -12
  136. package/src/__tests__/llm-context-normalization.test.ts +488 -0
  137. package/src/__tests__/llm-context-route-provider.test.ts +86 -5
  138. package/src/__tests__/llm-usage-store.test.ts +363 -0
  139. package/src/__tests__/mcp-client-auth.test.ts +40 -4
  140. package/src/__tests__/mcp-health-check.test.ts +10 -3
  141. package/src/__tests__/media-stream-output.test.ts +555 -0
  142. package/src/__tests__/media-stream-parser.test.ts +374 -0
  143. package/src/__tests__/media-stream-server-integration.test.ts +1234 -0
  144. package/src/__tests__/media-stream-stt-session.test.ts +588 -0
  145. package/src/__tests__/media-turn-detector.test.ts +440 -0
  146. package/src/__tests__/message-queue.test.ts +125 -0
  147. package/src/__tests__/migration-cross-version-compatibility.test.ts +3 -1
  148. package/src/__tests__/migration-export-http.test.ts +67 -8
  149. package/src/__tests__/migration-export-streaming.test.ts +66 -0
  150. package/src/__tests__/migration-import-commit-http.test.ts +109 -7
  151. package/src/__tests__/migration-import-preflight-http.test.ts +6 -5
  152. package/src/__tests__/migration-validate-http.test.ts +3 -3
  153. package/src/__tests__/mock-gateway-ipc.ts +151 -0
  154. package/src/__tests__/model-intents.test.ts +2 -2
  155. package/src/__tests__/native-host-marker-sync-guard.test.ts +157 -0
  156. package/src/__tests__/oauth-apps-routes.test.ts +18 -12
  157. package/src/__tests__/oauth-cli.test.ts +709 -60
  158. package/src/__tests__/oauth-connect-orchestrator.test.ts +118 -24
  159. package/src/__tests__/oauth-provider-seed-logos.test.ts +23 -0
  160. package/src/__tests__/oauth-provider-serializer.test.ts +147 -10
  161. package/src/__tests__/oauth-provider-visibility.test.ts +19 -21
  162. package/src/__tests__/oauth-providers-routes.test.ts +52 -14
  163. package/src/__tests__/oauth-store.test.ts +1465 -176
  164. package/src/__tests__/oauth2-gateway-transport.test.ts +460 -26
  165. package/src/__tests__/onboarding-template-contract.test.ts +81 -70
  166. package/src/__tests__/openai-provider.test.ts +178 -2
  167. package/src/__tests__/openai-responses-cutover-guard.test.ts +184 -0
  168. package/src/__tests__/openai-responses-provider.test.ts +1105 -0
  169. package/src/__tests__/openrouter-token-estimation.test.ts +100 -0
  170. package/src/__tests__/outlook-categories.test.ts +1 -1
  171. package/src/__tests__/outlook-client-automation.test.ts +1 -1
  172. package/src/__tests__/outlook-compose-tools.test.ts +1 -1
  173. package/src/__tests__/outlook-email-watcher.test.ts +1 -1
  174. package/src/__tests__/outlook-follow-up.test.ts +1 -1
  175. package/src/__tests__/outlook-messaging-provider.test.ts +2 -2
  176. package/src/__tests__/outlook-trash.test.ts +1 -1
  177. package/src/__tests__/outlook-unsubscribe.test.ts +32 -3
  178. package/src/__tests__/permission-checker-host-gate.test.ts +74 -14
  179. package/src/__tests__/permission-mode.test.ts +28 -56
  180. package/src/__tests__/persona-resolver.test.ts +251 -0
  181. package/src/__tests__/platform-bash-auto-approve.test.ts +4 -0
  182. package/src/__tests__/platform-callback-registration.test.ts +19 -0
  183. package/src/__tests__/platform.test.ts +92 -1
  184. package/src/__tests__/post-turn-tool-result-truncation.test.ts +343 -0
  185. package/src/__tests__/prechat-onboarding-contract.test.ts +267 -0
  186. package/src/__tests__/pricing.test.ts +174 -0
  187. package/src/__tests__/proxy-approval-callback.test.ts +18 -0
  188. package/src/__tests__/qdrant-manager.test.ts +29 -8
  189. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +194 -0
  190. package/src/__tests__/relationship-state-contract.test.ts +175 -0
  191. package/src/__tests__/relay-server.test.ts +423 -5
  192. package/src/__tests__/require-fresh-approval.test.ts +40 -1
  193. package/src/__tests__/sanitize-config-for-transfer.test.ts +132 -0
  194. package/src/__tests__/schedule-routes.test.ts +162 -0
  195. package/src/__tests__/search-skills-unified.test.ts +118 -0
  196. package/src/__tests__/secret-detection-handler.test.ts +84 -0
  197. package/src/__tests__/secret-ingress-http.test.ts +1 -0
  198. package/src/__tests__/secret-scanner-executor.test.ts +4 -0
  199. package/src/__tests__/secure-keys.test.ts +107 -0
  200. package/src/__tests__/send-endpoint-busy.test.ts +8 -1
  201. package/src/__tests__/sequence-store.test.ts +1 -1
  202. package/src/__tests__/server-history-render.test.ts +49 -0
  203. package/src/__tests__/set-permission-mode.test.ts +13 -250
  204. package/src/__tests__/settings-routes.test.ts +201 -0
  205. package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
  206. package/src/__tests__/skills-file-content-endpoint.test.ts +801 -0
  207. package/src/__tests__/skills-files-catalog-fallback.test.ts +738 -0
  208. package/src/__tests__/skills.test.ts +5 -2
  209. package/src/__tests__/skillssh-files.test.ts +446 -0
  210. package/src/__tests__/slack-block-formatting.test.ts +110 -0
  211. package/src/__tests__/slack-channel-config.test.ts +576 -16
  212. package/src/__tests__/stt-catalog-parity.test.ts +282 -0
  213. package/src/__tests__/stt-stream-session.test.ts +535 -0
  214. package/src/__tests__/subagent-detail.test.ts +44 -2
  215. package/src/__tests__/subagent-disposal.test.ts +1 -0
  216. package/src/__tests__/subagent-fork-notifications.test.ts +291 -0
  217. package/src/__tests__/subagent-fork-spawn.test.ts +384 -0
  218. package/src/__tests__/subagent-manager-notify.test.ts +1 -0
  219. package/src/__tests__/subagent-notify-parent.test.ts +1 -0
  220. package/src/__tests__/subagent-spawn-tool-fork.test.ts +411 -0
  221. package/src/__tests__/subagent-tools.test.ts +1 -0
  222. package/src/__tests__/subagent-types.test.ts +1 -0
  223. package/src/__tests__/system-prompt-ask-mode.test.ts +27 -71
  224. package/src/__tests__/system-prompt.test.ts +184 -27
  225. package/src/__tests__/task-scheduler.test.ts +32 -6
  226. package/src/__tests__/telegram-config.test.ts +10 -13
  227. package/src/__tests__/telephony-stt-routing.test.ts +329 -0
  228. package/src/__tests__/terminal-tools.test.ts +25 -5
  229. package/src/__tests__/test-preload.ts +18 -0
  230. package/src/__tests__/test-support/browser-skill-harness.ts +4 -1
  231. package/src/__tests__/tool-approval-handler.test.ts +73 -0
  232. package/src/__tests__/tool-executor-lifecycle-events.test.ts +9 -5
  233. package/src/__tests__/tool-executor-shell-integration.test.ts +4 -0
  234. package/src/__tests__/tool-executor.test.ts +33 -24
  235. package/src/__tests__/tool-result-truncation.test.ts +36 -0
  236. package/src/__tests__/tool-side-effects-slack-dm.test.ts +22 -0
  237. package/src/__tests__/top-level-renderer.test.ts +73 -1
  238. package/src/__tests__/transport-hints-queue.test.ts +14 -29
  239. package/src/__tests__/trust-store.test.ts +7 -1
  240. package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -1
  241. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +109 -0
  242. package/src/__tests__/tts-catalog-parity.test.ts +345 -0
  243. package/src/__tests__/twilio-routes-twiml.test.ts +512 -114
  244. package/src/__tests__/twilio-routes.test.ts +376 -0
  245. package/src/__tests__/unicode.test.ts +293 -0
  246. package/src/__tests__/update-bulletin-format.test.ts +59 -0
  247. package/src/__tests__/update-bulletin.test.ts +206 -5
  248. package/src/__tests__/usage-routes.test.ts +25 -4
  249. package/src/__tests__/user-reference.test.ts +46 -61
  250. package/src/__tests__/v2-consent-policy.test.ts +103 -0
  251. package/src/__tests__/verification-control-plane-policy.test.ts +4 -0
  252. package/src/__tests__/voice-config-update.test.ts +403 -0
  253. package/src/__tests__/voice-quality.test.ts +434 -19
  254. package/src/__tests__/workspace-heartbeat-service.test.ts +7 -0
  255. package/src/__tests__/workspace-migration-033-stt-service-explicit-config.test.ts +547 -0
  256. package/src/__tests__/workspace-migration-034-remove-calls-voice-transcription-provider.test.ts +596 -0
  257. package/src/__tests__/workspace-migration-drop-user-md.test.ts +368 -0
  258. package/src/__tests__/workspace-migration-meets.test.ts +244 -0
  259. package/src/__tests__/workspace-migration-seed-device-id.test.ts +14 -20
  260. package/src/__tests__/workspace-policy.test.ts +2 -0
  261. package/src/acp/client-handler.ts +30 -4
  262. package/src/agent/image-optimize.ts +24 -12
  263. package/src/agent/loop.ts +55 -9
  264. package/src/approvals/guardian-request-resolvers.ts +21 -15
  265. package/src/backup/__tests__/backup-key.test.ts +152 -0
  266. package/src/backup/__tests__/backup-worker.test.ts +767 -0
  267. package/src/backup/__tests__/list-snapshots.test.ts +87 -0
  268. package/src/backup/__tests__/local-writer.test.ts +218 -0
  269. package/src/backup/__tests__/offsite-writer.test.ts +641 -0
  270. package/src/backup/__tests__/paths.test.ts +300 -0
  271. package/src/backup/__tests__/restore.test.ts +498 -0
  272. package/src/backup/__tests__/snapshot-lock.test.ts +352 -0
  273. package/src/backup/__tests__/stream-crypt.test.ts +228 -0
  274. package/src/backup/backup-key.ts +137 -0
  275. package/src/backup/backup-worker.ts +459 -0
  276. package/src/backup/list-snapshots.ts +147 -0
  277. package/src/backup/local-writer.ts +133 -0
  278. package/src/backup/offsite-writer.ts +222 -0
  279. package/src/backup/paths.ts +226 -0
  280. package/src/backup/restore.ts +322 -0
  281. package/src/backup/snapshot-lock.ts +431 -0
  282. package/src/backup/stream-crypt.ts +263 -0
  283. package/src/browser-session/__tests__/manager.test.ts +297 -0
  284. package/src/browser-session/backends/cdp-inspect.ts +30 -0
  285. package/src/browser-session/backends/extension.ts +26 -0
  286. package/src/browser-session/backends/local.ts +24 -0
  287. package/src/browser-session/events.ts +164 -0
  288. package/src/browser-session/index.ts +27 -0
  289. package/src/browser-session/manager.ts +159 -0
  290. package/src/browser-session/types.ts +28 -0
  291. package/src/bundler/package-resolver.ts +4 -0
  292. package/src/calls/audio-store.ts +11 -5
  293. package/src/calls/call-controller.ts +226 -71
  294. package/src/calls/call-domain.ts +9 -0
  295. package/src/calls/call-speech-output.ts +190 -0
  296. package/src/calls/call-transport.ts +77 -0
  297. package/src/calls/media-stream-audio-transcode.ts +173 -0
  298. package/src/calls/media-stream-output.ts +660 -0
  299. package/src/calls/media-stream-parser.ts +300 -0
  300. package/src/calls/media-stream-protocol.ts +166 -0
  301. package/src/calls/media-stream-server.ts +592 -0
  302. package/src/calls/media-stream-stt-session.ts +460 -0
  303. package/src/calls/media-turn-detector.ts +230 -0
  304. package/src/calls/relay-server.ts +90 -75
  305. package/src/calls/resolve-call-tts-provider.ts +136 -0
  306. package/src/calls/telephony-stt-routing.ts +145 -0
  307. package/src/calls/tts-call-strategy.ts +161 -0
  308. package/src/calls/tts-text-sanitizer.ts +32 -16
  309. package/src/calls/twilio-routes.ts +281 -17
  310. package/src/calls/voice-quality.ts +78 -35
  311. package/src/calls/voice-session-bridge.ts +8 -1
  312. package/src/channels/__tests__/types.test.ts +134 -0
  313. package/src/channels/types.ts +69 -3
  314. package/src/cli/__tests__/run-assistant-command.ts +11 -1
  315. package/src/cli/commands/__tests__/backup.test.ts +1165 -0
  316. package/src/cli/commands/__tests__/domain-register.test.ts +234 -0
  317. package/src/cli/commands/__tests__/domain-status.test.ts +132 -0
  318. package/src/cli/commands/__tests__/email-attachment.test.ts +422 -0
  319. package/src/cli/commands/__tests__/email-download.test.ts +16 -1
  320. package/src/cli/commands/__tests__/email-list.test.ts +22 -4
  321. package/src/cli/commands/__tests__/email-register.test.ts +4 -4
  322. package/src/cli/commands/__tests__/email-send.test.ts +37 -4
  323. package/src/cli/commands/__tests__/email-status.test.ts +5 -1
  324. package/src/cli/commands/__tests__/email-unregister.test.ts +34 -5
  325. package/src/cli/commands/backup.ts +993 -0
  326. package/src/cli/commands/conversations.ts +77 -0
  327. package/src/cli/commands/credentials.ts +3 -4
  328. package/src/cli/commands/domain.ts +210 -0
  329. package/src/cli/commands/email.ts +273 -16
  330. package/src/cli/commands/mcp.ts +16 -4
  331. package/src/cli/commands/oauth/__tests__/connect.test.ts +56 -44
  332. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +21 -21
  333. package/src/cli/commands/oauth/__tests__/mode.test.ts +17 -17
  334. package/src/cli/commands/oauth/__tests__/ping.test.ts +16 -16
  335. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +32 -33
  336. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +330 -0
  337. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +117 -12
  338. package/src/cli/commands/oauth/__tests__/status.test.ts +10 -10
  339. package/src/cli/commands/oauth/__tests__/token.test.ts +7 -7
  340. package/src/cli/commands/oauth/apps.ts +7 -4
  341. package/src/cli/commands/oauth/connect.ts +6 -3
  342. package/src/cli/commands/oauth/disconnect.ts +1 -1
  343. package/src/cli/commands/oauth/mode.ts +12 -3
  344. package/src/cli/commands/oauth/providers.ts +215 -36
  345. package/src/cli/commands/oauth/shared.ts +7 -6
  346. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +254 -0
  347. package/src/cli/commands/platform/__tests__/connect.test.ts +6 -0
  348. package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -1
  349. package/src/cli/commands/platform/__tests__/status.test.ts +6 -0
  350. package/src/cli/commands/platform/index.ts +107 -10
  351. package/src/cli/commands/usage.ts +10 -9
  352. package/src/cli/lib/daemon-credential-client.ts +4 -0
  353. package/src/cli/program.ts +30 -4
  354. package/src/config/__tests__/backup-schema.test.ts +134 -0
  355. package/src/config/assistant-feature-flags.ts +61 -62
  356. package/src/config/bundled-skills/app-builder/SKILL.md +26 -249
  357. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +141 -0
  358. package/src/config/bundled-skills/app-builder/references/INTERACTION_HOOKS.md +56 -0
  359. package/src/config/bundled-skills/app-builder/references/WIDGETS.md +125 -0
  360. package/src/config/bundled-skills/browser/SKILL.md +30 -5
  361. package/src/config/bundled-skills/browser/TOOLS.json +123 -0
  362. package/src/config/bundled-skills/browser/tools/browser-attach.ts +12 -0
  363. package/src/config/bundled-skills/browser/tools/browser-detach.ts +12 -0
  364. package/src/config/bundled-skills/browser/tools/browser-status.ts +12 -0
  365. package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +17 -0
  366. package/src/config/bundled-skills/contacts/SKILL.md +5 -2
  367. package/src/config/bundled-skills/document/SKILL.md +4 -0
  368. package/src/config/bundled-skills/gmail/SKILL.md +54 -8
  369. package/src/config/bundled-skills/gmail/TOOLS.json +33 -3
  370. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +116 -9
  371. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +138 -11
  372. package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +59 -0
  373. package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +82 -0
  374. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +113 -17
  375. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +2 -2
  376. package/src/config/bundled-skills/media-processing/SKILL.md +3 -9
  377. package/src/config/bundled-skills/media-processing/TOOLS.json +1 -6
  378. package/src/config/bundled-skills/media-processing/__tests__/audio-transcribe.test.ts +125 -0
  379. package/src/config/bundled-skills/media-processing/__tests__/extract-keyframes.test.ts +181 -0
  380. package/src/config/bundled-skills/media-processing/__tests__/preprocess-audio.test.ts +141 -0
  381. package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +32 -87
  382. package/src/config/bundled-skills/media-processing/services/preprocess.ts +8 -4
  383. package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +0 -10
  384. package/src/config/bundled-skills/messaging/SKILL.md +3 -3
  385. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +2 -2
  386. package/src/config/bundled-skills/outlook/SKILL.md +9 -2
  387. package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +2 -2
  388. package/src/config/bundled-skills/phone-calls/SKILL.md +2 -2
  389. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +27 -18
  390. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +3 -3
  391. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  392. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +26 -22
  393. package/src/config/bundled-skills/slack/SKILL.md +1 -0
  394. package/src/config/bundled-skills/subagent/SKILL.md +21 -0
  395. package/src/config/bundled-skills/subagent/TOOLS.json +8 -4
  396. package/src/config/bundled-skills/tasks/SKILL.md +5 -0
  397. package/src/config/bundled-skills/transcribe/SKILL.md +9 -14
  398. package/src/config/bundled-skills/transcribe/TOOLS.json +2 -7
  399. package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +256 -0
  400. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +38 -188
  401. package/src/config/bundled-tool-registry.ts +8 -0
  402. package/src/config/env-registry.ts +38 -0
  403. package/src/config/env.ts +49 -4
  404. package/src/config/feature-flag-registry.json +85 -14
  405. package/src/config/loader.ts +82 -13
  406. package/src/config/sanitize-for-transfer.ts +47 -0
  407. package/src/config/schema.ts +81 -15
  408. package/src/config/schemas/__tests__/stt.test.ts +43 -0
  409. package/src/config/schemas/analysis.ts +51 -0
  410. package/src/config/schemas/backup.ts +72 -0
  411. package/src/config/schemas/calls.ts +1 -26
  412. package/src/config/schemas/elevenlabs.ts +0 -59
  413. package/src/config/schemas/filing.ts +47 -7
  414. package/src/config/schemas/heartbeat.ts +27 -5
  415. package/src/config/schemas/host-browser.ts +112 -0
  416. package/src/config/schemas/inference.ts +1 -1
  417. package/src/config/schemas/memory-lifecycle.ts +14 -2
  418. package/src/config/schemas/memory-retrieval.ts +103 -0
  419. package/src/config/schemas/security.ts +0 -6
  420. package/src/config/schemas/services.ts +52 -0
  421. package/src/config/schemas/stt.ts +59 -0
  422. package/src/config/schemas/tts.ts +230 -0
  423. package/src/config/schemas/updates.ts +14 -0
  424. package/src/config/skills.ts +4 -0
  425. package/src/config/types.ts +4 -1
  426. package/src/contacts/contact-store.ts +56 -11
  427. package/src/contacts/contacts-write.ts +38 -1
  428. package/src/context/post-turn-tool-result-truncation.ts +177 -0
  429. package/src/context/tool-result-truncation.ts +2 -1
  430. package/src/context/window-manager.ts +61 -10
  431. package/src/credential-execution/approval-bridge.ts +49 -15
  432. package/src/credential-execution/executable-discovery.ts +12 -2
  433. package/src/credential-execution/process-manager.ts +33 -2
  434. package/src/credential-health/credential-health-service.ts +366 -0
  435. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +324 -0
  436. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +497 -0
  437. package/src/daemon/__tests__/conversation-tool-setup.test.ts +195 -0
  438. package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +127 -0
  439. package/src/daemon/app-source-watcher.ts +35 -0
  440. package/src/daemon/config-watcher.ts +99 -5
  441. package/src/daemon/context-overflow-approval.ts +5 -0
  442. package/src/daemon/conversation-agent-loop-handlers.ts +23 -2
  443. package/src/daemon/conversation-agent-loop.ts +153 -42
  444. package/src/daemon/conversation-attachments.ts +40 -0
  445. package/src/daemon/conversation-error.ts +11 -0
  446. package/src/daemon/conversation-history.ts +40 -6
  447. package/src/daemon/conversation-launch.ts +220 -0
  448. package/src/daemon/conversation-lifecycle.ts +59 -9
  449. package/src/daemon/conversation-messaging.ts +37 -3
  450. package/src/daemon/conversation-notifiers.ts +5 -0
  451. package/src/daemon/conversation-process.ts +622 -13
  452. package/src/daemon/conversation-queue-manager.ts +24 -0
  453. package/src/daemon/conversation-runtime-assembly.ts +128 -36
  454. package/src/daemon/conversation-slash.ts +36 -0
  455. package/src/daemon/conversation-surfaces.ts +131 -40
  456. package/src/daemon/conversation-tool-setup.ts +99 -8
  457. package/src/daemon/conversation-usage.ts +7 -4
  458. package/src/daemon/conversation-workspace.ts +12 -0
  459. package/src/daemon/conversation.ts +292 -16
  460. package/src/daemon/date-context.ts +10 -10
  461. package/src/daemon/first-greeting.ts +3 -2
  462. package/src/daemon/handlers/config-slack-channel.ts +269 -94
  463. package/src/daemon/handlers/conversations.ts +13 -141
  464. package/src/daemon/handlers/shared.ts +80 -0
  465. package/src/daemon/handlers/skills.ts +483 -44
  466. package/src/daemon/host-bash-proxy.ts +48 -13
  467. package/src/daemon/host-browser-proxy.ts +192 -0
  468. package/src/daemon/host-cu-proxy.ts +36 -11
  469. package/src/daemon/host-file-proxy.ts +57 -9
  470. package/src/daemon/lifecycle.ts +179 -28
  471. package/src/daemon/message-protocol.ts +13 -0
  472. package/src/daemon/message-types/conversations.ts +89 -14
  473. package/src/daemon/message-types/home.ts +40 -0
  474. package/src/daemon/message-types/host-browser.ts +100 -0
  475. package/src/daemon/message-types/meet.ts +143 -0
  476. package/src/daemon/message-types/messages.ts +19 -5
  477. package/src/daemon/message-types/schedules.ts +34 -2
  478. package/src/daemon/message-types/skills.ts +26 -0
  479. package/src/daemon/message-types/subagents.ts +2 -0
  480. package/src/daemon/message-types/surfaces.ts +2 -0
  481. package/src/daemon/server.ts +439 -14
  482. package/src/daemon/shutdown-handlers.ts +32 -4
  483. package/src/daemon/shutdown-registry.ts +40 -0
  484. package/src/daemon/tool-side-effects.ts +15 -0
  485. package/src/daemon/transport-hints.ts +5 -24
  486. package/src/email/html-renderer.ts +76 -0
  487. package/src/heartbeat/heartbeat-service.ts +93 -7
  488. package/src/home/__tests__/assistant-feed-authoring.test.ts +156 -0
  489. package/src/home/__tests__/emit-feed-event.test.ts +169 -0
  490. package/src/home/__tests__/feed-scheduler.test.ts +194 -0
  491. package/src/home/__tests__/feed-types.test.ts +275 -0
  492. package/src/home/__tests__/feed-writer.test.ts +688 -0
  493. package/src/home/__tests__/phase5-exit-criteria.test.ts +212 -0
  494. package/src/home/__tests__/platform-gmail-digest.test.ts +222 -0
  495. package/src/home/__tests__/progress-formula.test.ts +213 -0
  496. package/src/home/__tests__/relationship-state-writer.test.ts +740 -0
  497. package/src/home/__tests__/rollup-producer.test.ts +398 -0
  498. package/src/home/assistant-feed-authoring.ts +124 -0
  499. package/src/home/emit-feed-event.ts +158 -0
  500. package/src/home/feed-scheduler.ts +247 -0
  501. package/src/home/feed-types.ts +181 -0
  502. package/src/home/feed-writer.ts +469 -0
  503. package/src/home/platform-gmail-digest.ts +163 -0
  504. package/src/home/progress-formula.ts +86 -0
  505. package/src/home/relationship-state-writer.ts +824 -0
  506. package/src/home/relationship-state.ts +143 -0
  507. package/src/home/rollup-producer.ts +384 -0
  508. package/src/hooks/runner.ts +7 -0
  509. package/src/inbound/platform-callback-registration.ts +30 -20
  510. package/src/inbound/public-ingress-urls.ts +12 -0
  511. package/src/instrument.ts +1 -1
  512. package/src/ipc/__tests__/cli-ipc.test.ts +200 -0
  513. package/src/ipc/cli-client.ts +151 -0
  514. package/src/ipc/cli-server.ts +234 -0
  515. package/src/ipc/gateway-client.ts +180 -0
  516. package/src/ipc/routes/index.ts +5 -0
  517. package/src/ipc/routes/wake-conversation.ts +19 -0
  518. package/src/mcp/client.ts +59 -24
  519. package/src/memory/__tests__/auto-analysis-enqueue.test.ts +356 -0
  520. package/src/memory/__tests__/auto-analysis-guard.test.ts +57 -0
  521. package/src/memory/__tests__/conversation-analyze-job.test.ts +232 -0
  522. package/src/memory/__tests__/find-analysis-conversation.test.ts +196 -0
  523. package/src/memory/app-store.ts +31 -1
  524. package/src/memory/attachments-store.ts +70 -0
  525. package/src/memory/auto-analysis-enqueue.ts +127 -0
  526. package/src/memory/auto-analysis-guard.ts +27 -0
  527. package/src/memory/cleanup-schedule-state.ts +37 -0
  528. package/src/memory/conversation-analyze-job.ts +73 -0
  529. package/src/memory/conversation-crud.ts +122 -0
  530. package/src/memory/conversation-disk-view.ts +7 -0
  531. package/src/memory/conversation-group-migration.ts +34 -2
  532. package/src/memory/conversation-queries.ts +6 -5
  533. package/src/memory/conversation-starters-cadence.ts +76 -0
  534. package/src/memory/conversation-title-service.ts +5 -2
  535. package/src/memory/db-init.ts +18 -0
  536. package/src/memory/db-maintenance.ts +108 -0
  537. package/src/memory/db.ts +1 -0
  538. package/src/memory/embedding-backend.test.ts +75 -0
  539. package/src/memory/embedding-backend.ts +131 -5
  540. package/src/memory/embedding-gemini.test.ts +54 -0
  541. package/src/memory/embedding-gemini.ts +20 -9
  542. package/src/memory/embedding-local.ts +176 -17
  543. package/src/memory/graph/consolidation.ts +10 -23
  544. package/src/memory/graph/conversation-graph-memory.ts +15 -0
  545. package/src/memory/graph/extraction-job.ts +15 -0
  546. package/src/memory/graph/extraction.test.ts +23 -0
  547. package/src/memory/graph/extraction.ts +8 -0
  548. package/src/memory/graph/retriever.ts +67 -40
  549. package/src/memory/graph/scoring.test.ts +186 -0
  550. package/src/memory/graph/scoring.ts +31 -1
  551. package/src/memory/graph/store.test.ts +7 -3
  552. package/src/memory/graph/store.ts +47 -12
  553. package/src/memory/graph/tools.ts +1 -1
  554. package/src/memory/group-crud.ts +6 -1
  555. package/src/memory/indexer.ts +95 -16
  556. package/src/memory/job-handlers/cleanup.ts +11 -8
  557. package/src/memory/job-handlers/conversation-starters.ts +16 -10
  558. package/src/memory/jobs-store.ts +64 -4
  559. package/src/memory/jobs-worker.ts +22 -9
  560. package/src/memory/llm-usage-store.ts +137 -60
  561. package/src/memory/migrations/213-oauth-providers-scope-separator.ts +13 -0
  562. package/src/memory/migrations/214-oauth-providers-refresh-url.ts +11 -0
  563. package/src/memory/migrations/215-oauth-providers-revoke.ts +14 -0
  564. package/src/memory/migrations/216-oauth-providers-token-auth-method.ts +30 -0
  565. package/src/memory/migrations/217-conversation-host-access.ts +40 -0
  566. package/src/memory/migrations/218-oauth-providers-logo-url.ts +11 -0
  567. package/src/memory/migrations/219-oauth-providers-token-exchange-body-format.ts +15 -0
  568. package/src/memory/migrations/220-normalize-user-file-by-principal.ts +190 -0
  569. package/src/memory/migrations/221-conversations-archived-at.ts +16 -0
  570. package/src/memory/migrations/index.ts +12 -0
  571. package/src/memory/migrations/registry.ts +16 -0
  572. package/src/memory/qdrant-manager.ts +43 -16
  573. package/src/memory/schema/conversations.ts +3 -0
  574. package/src/memory/schema/oauth.ts +21 -13
  575. package/src/memory/usage-buckets.ts +396 -0
  576. package/src/messaging/providers/gmail/client.ts +57 -6
  577. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +282 -0
  578. package/src/messaging/providers/slack/adapter.ts +143 -38
  579. package/src/messaging/providers/slack/client.ts +16 -0
  580. package/src/messaging/providers/slack/types.ts +4 -0
  581. package/src/notifications/decision-engine.ts +3 -3
  582. package/src/notifications/signal.ts +5 -0
  583. package/src/oauth/AGENTS.md +76 -0
  584. package/src/oauth/__tests__/identity-verifier.test.ts +25 -19
  585. package/src/oauth/__tests__/seed-providers-managed.test.ts +32 -0
  586. package/src/oauth/byo-connection.test.ts +26 -9
  587. package/src/oauth/byo-connection.ts +10 -8
  588. package/src/oauth/connect-orchestrator.ts +25 -21
  589. package/src/oauth/connect-types.ts +3 -3
  590. package/src/oauth/connection-resolver.test.ts +17 -4
  591. package/src/oauth/connection-resolver.ts +22 -18
  592. package/src/oauth/connection.ts +3 -1
  593. package/src/oauth/manual-token-connection.ts +13 -13
  594. package/src/oauth/oauth-store.ts +223 -100
  595. package/src/oauth/platform-connection.test.ts +101 -3
  596. package/src/oauth/platform-connection.ts +56 -35
  597. package/src/oauth/provider-serializer.ts +31 -5
  598. package/src/oauth/revoke.ts +76 -0
  599. package/src/oauth/seed-providers.ts +133 -87
  600. package/src/oauth/token-persistence.ts +1 -1
  601. package/src/permissions/checker.ts +16 -6
  602. package/src/permissions/defaults.ts +49 -1
  603. package/src/permissions/permission-mode.ts +4 -11
  604. package/src/permissions/prompter.ts +13 -1
  605. package/src/permissions/trust-store.ts +3 -3
  606. package/src/permissions/v2-consent-policy.ts +87 -0
  607. package/src/permissions/workspace-policy.ts +3 -0
  608. package/src/platform/client.test.ts +10 -0
  609. package/src/platform/sync-identity.ts +129 -0
  610. package/src/prompts/persona-resolver.ts +126 -2
  611. package/src/prompts/system-prompt.ts +76 -38
  612. package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +3 -65
  613. package/src/prompts/templates/BOOTSTRAP.md +59 -105
  614. package/src/prompts/templates/SOUL.md +3 -1
  615. package/src/prompts/templates/UPDATES.md +12 -0
  616. package/src/prompts/templates/channels/slack.md +20 -0
  617. package/src/prompts/update-bulletin-format.ts +26 -9
  618. package/src/prompts/update-bulletin.ts +34 -23
  619. package/src/prompts/user-reference.ts +20 -17
  620. package/src/providers/__tests__/provider-secret-catalog.test.ts +42 -0
  621. package/src/providers/anthropic/client.ts +157 -60
  622. package/src/providers/fireworks/client.ts +2 -2
  623. package/src/providers/gemini/client.ts +9 -1
  624. package/src/providers/model-catalog.ts +6 -0
  625. package/src/providers/model-intents.ts +4 -4
  626. package/src/providers/ollama/client.ts +2 -2
  627. package/src/providers/openai/chat-completions-provider.ts +474 -0
  628. package/src/providers/openai/client.ts +25 -440
  629. package/src/providers/openai/responses-provider.ts +502 -0
  630. package/src/providers/openrouter/client.ts +101 -4
  631. package/src/providers/provider-secret-catalog.ts +139 -0
  632. package/src/providers/registry.ts +2 -2
  633. package/src/providers/retry.ts +14 -3
  634. package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +251 -0
  635. package/src/providers/speech-to-text/__tests__/resolve.test.ts +828 -0
  636. package/src/providers/speech-to-text/deepgram-realtime.test.ts +980 -0
  637. package/src/providers/speech-to-text/deepgram-realtime.ts +767 -0
  638. package/src/providers/speech-to-text/deepgram.test.ts +332 -0
  639. package/src/providers/speech-to-text/deepgram.ts +115 -0
  640. package/src/providers/speech-to-text/google-gemini-live-stream.test.ts +743 -0
  641. package/src/providers/speech-to-text/google-gemini-live-stream.ts +625 -0
  642. package/src/providers/speech-to-text/google-gemini.test.ts +226 -0
  643. package/src/providers/speech-to-text/google-gemini.ts +101 -0
  644. package/src/providers/speech-to-text/openai-whisper-stream.test.ts +564 -0
  645. package/src/providers/speech-to-text/openai-whisper-stream.ts +381 -0
  646. package/src/providers/speech-to-text/openai-whisper.test.ts +1 -37
  647. package/src/providers/speech-to-text/openai-whisper.ts +63 -33
  648. package/src/providers/speech-to-text/provider-catalog.ts +306 -0
  649. package/src/providers/speech-to-text/resolve.ts +386 -6
  650. package/src/providers/types.ts +10 -1
  651. package/src/runtime/AGENTS.md +65 -0
  652. package/src/runtime/__tests__/agent-wake.test.ts +831 -0
  653. package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +715 -0
  654. package/src/runtime/__tests__/capability-tokens.test.ts +258 -0
  655. package/src/runtime/__tests__/chrome-extension-registry.test.ts +518 -0
  656. package/src/runtime/__tests__/runtime-mode.test.ts +62 -0
  657. package/src/runtime/__tests__/slack-block-formatting.test.ts +481 -0
  658. package/src/runtime/agent-wake.ts +512 -0
  659. package/src/runtime/assistant-event-hub.ts +2 -2
  660. package/src/runtime/auth/__tests__/guard-tests.test.ts +1 -0
  661. package/src/runtime/auth/__tests__/middleware.test.ts +116 -1
  662. package/src/runtime/auth/__tests__/route-policy.test.ts +48 -0
  663. package/src/runtime/auth/middleware.ts +98 -0
  664. package/src/runtime/auth/route-policy.ts +33 -9
  665. package/src/runtime/auth/token-service.ts +56 -1
  666. package/src/runtime/btw-sidechain.ts +2 -0
  667. package/src/runtime/capability-tokens.ts +414 -0
  668. package/src/runtime/channel-approvals.ts +18 -5
  669. package/src/runtime/channel-invite-transport.ts +1 -1
  670. package/src/runtime/channel-invite-transports/email.ts +14 -6
  671. package/src/runtime/channel-readiness-service.ts +12 -22
  672. package/src/runtime/chrome-extension-registry.ts +368 -0
  673. package/src/runtime/confirmation-request-guardian-bridge.ts +6 -0
  674. package/src/runtime/guardian-decision-types.ts +7 -0
  675. package/src/runtime/http-server.ts +815 -75
  676. package/src/runtime/http-types.ts +6 -2
  677. package/src/runtime/migrations/__tests__/rebind-secrets-credentials.test.ts +172 -0
  678. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +276 -0
  679. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +198 -0
  680. package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +360 -0
  681. package/src/runtime/migrations/migration-transport.ts +7 -0
  682. package/src/runtime/migrations/migration-wizard.ts +23 -2
  683. package/src/runtime/migrations/rebind-secrets-screen.ts +76 -15
  684. package/src/runtime/migrations/vbundle-builder.ts +145 -38
  685. package/src/runtime/migrations/vbundle-import-analyzer.ts +96 -1
  686. package/src/runtime/migrations/vbundle-importer.ts +89 -5
  687. package/src/runtime/pending-interactions.ts +18 -13
  688. package/src/runtime/routes/__tests__/backup-routes.test.ts +967 -0
  689. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +507 -0
  690. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +208 -0
  691. package/src/runtime/routes/__tests__/stt-routes.test.ts +406 -0
  692. package/src/runtime/routes/__tests__/tts-routes.test.ts +474 -0
  693. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +148 -17
  694. package/src/runtime/routes/app-management-routes.ts +12 -18
  695. package/src/runtime/routes/approval-routes.ts +90 -16
  696. package/src/runtime/routes/attachment-routes.test.ts +9 -3
  697. package/src/runtime/routes/attachment-routes.ts +216 -17
  698. package/src/runtime/routes/backup-routes.ts +519 -0
  699. package/src/runtime/routes/browser-extension-pair-routes.ts +556 -0
  700. package/src/runtime/routes/btw-routes.ts +8 -6
  701. package/src/runtime/routes/contact-routes.test.ts +298 -0
  702. package/src/runtime/routes/contact-routes.ts +132 -5
  703. package/src/runtime/routes/conversation-analysis-routes.ts +22 -141
  704. package/src/runtime/routes/conversation-management-routes.ts +223 -0
  705. package/src/runtime/routes/conversation-routes.ts +598 -103
  706. package/src/runtime/routes/conversation-starter-routes.ts +78 -16
  707. package/src/runtime/routes/filing-routes.ts +93 -0
  708. package/src/runtime/routes/guardian-action-routes.ts +24 -13
  709. package/src/runtime/routes/home-feed-routes.ts +334 -0
  710. package/src/runtime/routes/home-state-routes.ts +138 -0
  711. package/src/runtime/routes/host-browser-routes.ts +268 -0
  712. package/src/runtime/routes/host-file-routes.ts +9 -1
  713. package/src/runtime/routes/identity-intro-cache.ts +7 -3
  714. package/src/runtime/routes/identity-routes.ts +262 -33
  715. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +46 -39
  716. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +15 -15
  717. package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +137 -0
  718. package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +179 -0
  719. package/src/runtime/routes/integrations/slack/channel.ts +11 -3
  720. package/src/runtime/routes/integrations/slack/share.ts +45 -7
  721. package/src/runtime/routes/llm-context-normalization.ts +303 -0
  722. package/src/runtime/routes/log-export-routes.ts +42 -22
  723. package/src/runtime/routes/memory-item-routes.test.ts +3 -2
  724. package/src/runtime/routes/memory-item-routes.ts +1 -7
  725. package/src/runtime/routes/migration-routes.ts +122 -2
  726. package/src/runtime/routes/oauth-apps.ts +15 -17
  727. package/src/runtime/routes/oauth-providers.ts +4 -0
  728. package/src/runtime/routes/schedule-routes.ts +24 -11
  729. package/src/runtime/routes/settings-routes.ts +31 -102
  730. package/src/runtime/routes/skills-routes.ts +128 -9
  731. package/src/runtime/routes/stt-routes.ts +233 -0
  732. package/src/runtime/routes/subagents-routes.ts +14 -10
  733. package/src/runtime/routes/surface-action-routes.ts +41 -2
  734. package/src/runtime/routes/tts-routes.ts +108 -24
  735. package/src/runtime/routes/usage-routes.ts +38 -9
  736. package/src/runtime/routes/user-route-dispatcher.ts +50 -5
  737. package/src/runtime/routes/user-routes.ts +13 -1
  738. package/src/runtime/routes/work-items-routes.ts +8 -1
  739. package/src/runtime/routes/workspace-routes.test.ts +22 -0
  740. package/src/runtime/routes/workspace-routes.ts +8 -1
  741. package/src/runtime/routes/workspace-utils.ts +2 -0
  742. package/src/runtime/runtime-mode.ts +33 -0
  743. package/src/runtime/services/__tests__/analyze-conversation.test.ts +444 -0
  744. package/src/runtime/services/__tests__/analyze-deps-singleton.test.ts +67 -0
  745. package/src/runtime/services/__tests__/auto-analysis-prompt.test.ts +53 -0
  746. package/src/runtime/services/__tests__/manual-analysis-prompt.test.ts +41 -0
  747. package/src/runtime/services/analyze-conversation.ts +344 -0
  748. package/src/runtime/services/analyze-deps-singleton.ts +32 -0
  749. package/src/runtime/services/auto-analysis-prompt.ts +55 -0
  750. package/src/runtime/skill-route-registry.ts +49 -0
  751. package/src/runtime/slack-block-formatting.ts +437 -10
  752. package/src/schedule/scheduler.ts +57 -5
  753. package/src/security/ces-credential-client.ts +20 -0
  754. package/src/security/ces-rpc-credential-backend.ts +17 -0
  755. package/src/security/credential-backend.ts +5 -0
  756. package/src/security/oauth2.ts +68 -29
  757. package/src/security/secure-keys.ts +143 -27
  758. package/src/security/token-manager.ts +31 -10
  759. package/src/sequence/engine.ts +23 -0
  760. package/src/sequence/types.ts +1 -1
  761. package/src/skills/catalog-files.ts +554 -0
  762. package/src/skills/category-inference.ts +122 -0
  763. package/src/skills/clawhub-files.ts +213 -0
  764. package/src/skills/clawhub.ts +84 -23
  765. package/src/skills/skill-file-provider.ts +40 -0
  766. package/src/skills/skillssh-files.ts +395 -0
  767. package/src/skills/skillssh-registry.ts +4 -4
  768. package/src/stt/__tests__/daemon-batch-transcriber.test.ts +392 -0
  769. package/src/stt/__tests__/types.test.ts +89 -0
  770. package/src/stt/daemon-batch-transcriber.ts +195 -0
  771. package/src/stt/stt-stream-session.ts +499 -0
  772. package/src/stt/types.ts +330 -0
  773. package/src/stt/wav-encoder.test.ts +373 -0
  774. package/src/stt/wav-encoder.ts +175 -0
  775. package/src/subagent/manager.ts +169 -40
  776. package/src/subagent/types.ts +19 -0
  777. package/src/tools/apps/executors.ts +11 -2
  778. package/src/tools/browser/__tests__/auth-detector.test.ts +202 -108
  779. package/src/tools/browser/__tests__/browser-mode.test.ts +119 -0
  780. package/src/tools/browser/__tests__/browser-status.test.ts +123 -0
  781. package/src/tools/browser/auth-detector.ts +43 -12
  782. package/src/tools/browser/browser-execution.ts +1787 -342
  783. package/src/tools/browser/browser-manager.ts +81 -12
  784. package/src/tools/browser/browser-mode-constants.ts +12 -0
  785. package/src/tools/browser/browser-mode.ts +92 -0
  786. package/src/tools/browser/browser-status-constants.ts +33 -0
  787. package/src/tools/browser/cdp-client/__tests__/accessibility-snapshot.test.ts +318 -0
  788. package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +1175 -0
  789. package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +1263 -0
  790. package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +359 -0
  791. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +1993 -0
  792. package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-nested-frames.json +64 -0
  793. package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-simple.json +69 -0
  794. package/src/tools/browser/cdp-client/__tests__/local-cdp-client.test.ts +310 -0
  795. package/src/tools/browser/cdp-client/__tests__/types.test.ts +96 -0
  796. package/src/tools/browser/cdp-client/accessibility-snapshot.ts +387 -0
  797. package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +695 -0
  798. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +1007 -0
  799. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +580 -0
  800. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +744 -0
  801. package/src/tools/browser/cdp-client/cdp-inspect/ws-transport.ts +579 -0
  802. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +868 -0
  803. package/src/tools/browser/cdp-client/errors.ts +49 -0
  804. package/src/tools/browser/cdp-client/extension-cdp-client.ts +148 -0
  805. package/src/tools/browser/cdp-client/factory.ts +914 -0
  806. package/src/tools/browser/cdp-client/index.ts +28 -0
  807. package/src/tools/browser/cdp-client/local-cdp-client.ts +187 -0
  808. package/src/tools/browser/cdp-client/types.ts +120 -0
  809. package/src/tools/credentials/vault.ts +35 -6
  810. package/src/tools/filesystem/edit.ts +1 -1
  811. package/src/tools/filesystem/list.ts +1 -1
  812. package/src/tools/filesystem/read.ts +1 -1
  813. package/src/tools/filesystem/write.ts +2 -1
  814. package/src/tools/host-filesystem/edit.ts +1 -1
  815. package/src/tools/host-filesystem/read.ts +12 -15
  816. package/src/tools/host-filesystem/write.ts +1 -1
  817. package/src/tools/host-terminal/host-shell.ts +21 -16
  818. package/src/tools/network/web-fetch.ts +5 -2
  819. package/src/tools/network/web-search.ts +5 -2
  820. package/src/tools/permission-checker.ts +77 -82
  821. package/src/tools/registry.ts +0 -2
  822. package/src/tools/secret-detection-handler.ts +34 -0
  823. package/src/tools/shared/filesystem/image-read.ts +61 -40
  824. package/src/tools/shared/shell-output.ts +3 -1
  825. package/src/tools/side-effects.ts +2 -0
  826. package/src/tools/skills/sandbox-runner.ts +3 -2
  827. package/src/tools/subagent/spawn.ts +47 -3
  828. package/src/tools/subagent/status.ts +2 -0
  829. package/src/tools/system/register.ts +2 -16
  830. package/src/tools/terminal/safe-env.ts +15 -0
  831. package/src/tools/terminal/shell.ts +36 -20
  832. package/src/tools/tool-approval-handler.ts +48 -2
  833. package/src/tools/tool-manifest.ts +21 -0
  834. package/src/tools/types.ts +19 -0
  835. package/src/tools/ui-surface/definitions.ts +6 -1
  836. package/src/tts/__tests__/provider-adapters.test.ts +834 -0
  837. package/src/tts/__tests__/provider-catalog-consistency.test.ts +196 -0
  838. package/src/tts/__tests__/provider-catalog.test.ts +183 -0
  839. package/src/tts/__tests__/provider-registry.test.ts +90 -0
  840. package/src/tts/provider-catalog.ts +201 -0
  841. package/src/tts/provider-registry.ts +73 -0
  842. package/src/tts/providers/deepgram-provider.ts +219 -0
  843. package/src/tts/providers/elevenlabs-provider.ts +211 -0
  844. package/src/tts/providers/fish-audio-provider.ts +183 -0
  845. package/src/tts/providers/index.ts +42 -0
  846. package/src/tts/providers/register-builtins.ts +130 -0
  847. package/src/tts/synthesize-text.ts +110 -0
  848. package/src/tts/tts-config-resolver.ts +78 -0
  849. package/src/tts/types.ts +153 -0
  850. package/src/types/onboarding-context.ts +7 -0
  851. package/src/util/abort-reasons.ts +58 -0
  852. package/src/util/device-id.ts +32 -16
  853. package/src/util/errors.ts +9 -1
  854. package/src/util/platform.ts +63 -24
  855. package/src/util/pricing.ts +66 -3
  856. package/src/util/spawn.ts +1 -1
  857. package/src/util/truncate.ts +4 -2
  858. package/src/util/unicode.ts +201 -0
  859. package/src/version.ts +19 -24
  860. package/src/watcher/engine.ts +23 -0
  861. package/src/watcher/watcher-store.ts +31 -0
  862. package/src/workspace/migrations/003-seed-device-id.ts +9 -3
  863. package/src/workspace/migrations/017-seed-persona-dirs.ts +68 -4
  864. package/src/workspace/migrations/029-seed-pkb.ts +1 -1
  865. package/src/workspace/migrations/031-drop-user-md.ts +317 -0
  866. package/src/workspace/migrations/031-llm-log-retention-zero-to-null.ts +73 -0
  867. package/src/workspace/migrations/032-tts-provider-unification.ts +227 -0
  868. package/src/workspace/migrations/033-stt-service-explicit-config.ts +122 -0
  869. package/src/workspace/migrations/034-remove-calls-voice-transcription-provider.ts +215 -0
  870. package/src/workspace/migrations/035-seed-slack-channel-persona.ts +50 -0
  871. package/src/workspace/migrations/036-update-pkb-index-bar.ts +37 -0
  872. package/src/workspace/migrations/037-create-meets-dir.ts +61 -0
  873. package/src/workspace/migrations/registry.ts +16 -0
  874. package/src/workspace/top-level-renderer.ts +31 -1
  875. package/src/workspace/turn-commit.ts +31 -0
  876. package/src/__tests__/chrome-cdp.test.ts +0 -419
  877. package/src/__tests__/email-cli.test.ts +0 -297
  878. package/src/__tests__/email-service-config-fallback.test.ts +0 -102
  879. package/src/__tests__/permission-mode-sse.test.ts +0 -418
  880. package/src/__tests__/permission-mode-store.test.ts +0 -277
  881. package/src/browser-extension-relay/protocol.ts +0 -63
  882. package/src/browser-extension-relay/server.ts +0 -203
  883. package/src/cli/commands/browser-relay.ts +0 -536
  884. package/src/config/schemas/sandbox.ts +0 -14
  885. package/src/email/guardrails.ts +0 -221
  886. package/src/email/provider.ts +0 -117
  887. package/src/email/providers/agentmail.ts +0 -361
  888. package/src/email/providers/index.ts +0 -65
  889. package/src/email/service.ts +0 -384
  890. package/src/email/types.ts +0 -126
  891. package/src/permissions/permission-mode-store.ts +0 -180
  892. package/src/prompts/templates/USER.md +0 -13
  893. package/src/providers/speech-to-text/types.ts +0 -17
  894. package/src/tools/browser/chrome-cdp.ts +0 -239
  895. package/src/tools/system/set-permission-mode.ts +0 -103
@@ -1,7 +1,12 @@
1
- import { readFileSync, writeFileSync } from "node:fs";
1
+ import { createWriteStream, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { basename, join } from "node:path";
3
+ import type { Readable } from "node:stream";
4
+ import { pipeline } from "node:stream/promises";
2
5
 
3
6
  import type { Command } from "commander";
4
7
 
8
+ import { getAssistantDomain } from "../../config/env.js";
9
+ import { markdownToEmailHtml } from "../../email/html-renderer.js";
5
10
  import { VellumPlatformClient } from "../../platform/client.js";
6
11
  import { getCliLogger } from "../logger.js";
7
12
  import { shouldOutputJson, writeOutput } from "../output.js";
@@ -9,15 +14,19 @@ import { shouldOutputJson, writeOutput } from "../output.js";
9
14
  const log = getCliLogger("email");
10
15
 
11
16
  export function registerEmailCommand(program: Command): void {
17
+ const domain = getAssistantDomain();
12
18
  const email = program
13
19
  .command("email")
14
- .description("Email channel operations")
20
+ .description(
21
+ `Get your own email address (@${domain}) — register, send, receive, and manage email natively`,
22
+ )
15
23
  .option("--json", "Machine-readable compact JSON output");
16
24
 
17
25
  email.addHelpText(
18
26
  "after",
19
27
  `
20
- Manage the assistant's email channel on the Vellum platform.
28
+ Set up and manage this assistant's native email address on the Vellum
29
+ platform. No third-party email provider or browser sign-up needed.
21
30
 
22
31
  Examples:
23
32
  $ assistant email register mybot
@@ -25,17 +34,19 @@ Examples:
25
34
  $ assistant email send user@example.com -s "Hello" -b "Hi there"
26
35
  $ assistant email status
27
36
  $ assistant email list
37
+ $ assistant email attachment msg_abc1 --list
38
+ $ assistant email attachment msg_abc1 att_xyz1
28
39
  $ assistant email register mybot --json`,
29
40
  );
30
41
 
31
42
  email
32
43
  .command("register <username>")
33
- .description("Register an @vellum.me email address for this assistant")
44
+ .description(`Register an @${domain} email address for this assistant`)
34
45
  .addHelpText(
35
46
  "after",
36
47
  `
37
48
  Arguments:
38
- username The local part of the email address (e.g. "mybot" → mybot@vellum.me)
49
+ username The local part of the email address (e.g. "mybot" → mybot@${domain})
39
50
 
40
51
  Registers a new email address on the Vellum platform for the current
41
52
  assistant. Each assistant can have one email address. The address is
@@ -43,10 +54,10 @@ immediately active for receiving inbound email.
43
54
 
44
55
  Examples:
45
56
  $ assistant email register mybot
46
- ✓ Registered mybot@vellum.me
57
+ ✓ Registered mybot@${domain}
47
58
 
48
59
  $ assistant email register support --json
49
- {"address":"support@vellum.me","id":"...","created_at":"..."}`,
60
+ {"address":"support@${domain}","id":"...","created_at":"..."}`,
50
61
  )
51
62
  .action(async (username: string, _opts: unknown, cmd: Command) => {
52
63
  try {
@@ -122,14 +133,14 @@ immediately available for reuse.
122
133
 
123
134
  Examples:
124
135
  $ assistant email unregister
125
- Remove mybot@vellum.me? (y/N) y
126
- ✓ Unregistered mybot@vellum.me
136
+ Remove mybot@${domain}? (y/N) y
137
+ ✓ Unregistered mybot@${domain}
127
138
 
128
139
  $ assistant email unregister --confirm
129
- ✓ Unregistered mybot@vellum.me
140
+ ✓ Unregistered mybot@${domain}
130
141
 
131
142
  $ assistant email unregister --json
132
- {"unregistered":"mybot@vellum.me"}`,
143
+ {"unregistered":"mybot@${domain}"}`,
133
144
  )
134
145
  .action(async (_opts: { confirm?: boolean }, cmd: Command) => {
135
146
  try {
@@ -222,12 +233,12 @@ current usage and quota information from the platform.
222
233
 
223
234
  Examples:
224
235
  $ assistant email status
225
- Address: mybot@vellum.me
236
+ Address: mybot@${domain}
226
237
  Status: active
227
238
  Sent: 12 / 100 (daily)
228
239
 
229
240
  $ assistant email status --json
230
- {"address":"mybot@vellum.me","status":"active","usage":{"sent_today":12,"daily_limit":100}}`,
241
+ {"address":"mybot@${domain}","status":"active","usage":{"sent_today":12,"daily_limit":100}}`,
231
242
  )
232
243
  .action(async (_opts: unknown, cmd: Command) => {
233
244
  try {
@@ -446,7 +457,7 @@ or --format json for the full message object.
446
457
  Examples:
447
458
  $ assistant email download msg_abc123
448
459
  From: user@example.com
449
- To: mybot@vellum.me
460
+ To: mybot@${domain}
450
461
  Subject: Hello
451
462
  Date: 2026-04-05 12:00:00
452
463
 
@@ -564,6 +575,10 @@ Examples:
564
575
  .option("-b, --body <text>", "Email body (plain text)")
565
576
  .option("-f, --file <path>", "Read body from file")
566
577
  .option("--html <path>", "HTML body file (optional)")
578
+ .option(
579
+ "--reply-to <email_id>",
580
+ "Reply to an email by its ID (auto-resolves threading headers and subject)",
581
+ )
567
582
  .addHelpText(
568
583
  "after",
569
584
  `
@@ -576,13 +591,20 @@ from the assistant's registered email address.
576
591
 
577
592
  Body source priority: --body flag > --file flag > stdin (if not a TTY).
578
593
 
594
+ When --reply-to is provided, the platform auto-resolves In-Reply-To,
595
+ References, and Subject headers from the referenced email. You can
596
+ still override subject with -s.
597
+
579
598
  Examples:
580
599
  $ assistant email send user@example.com -s "Hello" -b "Hi there"
581
600
  ✓ Sent to user@example.com (delivery_id: abc123)
582
601
 
583
- $ echo "Body text" | assistant email send user@example.com -s "Hello"
602
+ $ assistant email send user@example.com -b "Thanks!" --reply-to 019d96e4-e5d2-7201-890e-04a21e8f95bb
584
603
  ✓ Sent to user@example.com (delivery_id: def456)
585
604
 
605
+ $ echo "Body text" | assistant email send user@example.com -s "Hello"
606
+ ✓ Sent to user@example.com (delivery_id: ghi789)
607
+
586
608
  $ assistant email send user@example.com -s "Hello" -b "Hi" --json
587
609
  {"delivery_id":"abc123","status":"accepted"}`,
588
610
  )
@@ -594,6 +616,7 @@ Examples:
594
616
  body?: string;
595
617
  file?: string;
596
618
  html?: string;
619
+ replyTo?: string;
597
620
  },
598
621
  cmd: Command,
599
622
  ) => {
@@ -648,10 +671,13 @@ Examples:
648
671
  );
649
672
  }
650
673
 
651
- // 3. Resolve optional HTML body from file
674
+ // 3. Resolve HTML body: explicit file > auto-generate from text
652
675
  let html: string | undefined;
653
676
  if (opts.html) {
654
677
  html = readFileSync(opts.html, "utf-8");
678
+ } else {
679
+ // Auto-generate HTML from the text body (markdown → email HTML).
680
+ html = markdownToEmailHtml(text);
655
681
  }
656
682
 
657
683
  // 4. Build payload
@@ -662,6 +688,7 @@ Examples:
662
688
  };
663
689
  if (opts.subject) payload.subject = opts.subject;
664
690
  if (html) payload.html = html;
691
+ if (opts.replyTo) payload.reply_to = opts.replyTo;
665
692
 
666
693
  // 5. Send via runtime proxy
667
694
  const response = await client.fetch("/v1/runtime-proxy/email/send/", {
@@ -700,4 +727,234 @@ Examples:
700
727
  }
701
728
  },
702
729
  );
730
+
731
+ email
732
+ .command("attachment <message-id> [attachment-id]")
733
+ .description("Download email attachments")
734
+ .option("--all", "Download all attachments for the message")
735
+ .option(
736
+ "-o, --output <dir>",
737
+ "Output directory (default: current directory)",
738
+ ".",
739
+ )
740
+ .option("--list", "List attachments without downloading")
741
+ .addHelpText(
742
+ "after",
743
+ `
744
+ Arguments:
745
+ message-id Email message ID (from \`assistant email list --json\`)
746
+ attachment-id Attachment ID (optional — required unless --all or --list)
747
+
748
+ Download one or all attachments from a specific email message. Use
749
+ --list to see available attachments without downloading.
750
+
751
+ Examples:
752
+ $ assistant email attachment msg_abc1 --list
753
+ $ assistant email attachment msg_abc1 att_xyz1
754
+ $ assistant email attachment msg_abc1 att_xyz1 -o ./downloads/
755
+ $ assistant email attachment msg_abc1 --all
756
+ $ assistant email attachment msg_abc1 --all -o ./attachments/
757
+ $ assistant email attachment msg_abc1 --list --json`,
758
+ )
759
+ .action(
760
+ async (
761
+ messageId: string,
762
+ attachmentId: string | undefined,
763
+ opts: {
764
+ all?: boolean;
765
+ output?: string;
766
+ list?: boolean;
767
+ },
768
+ cmd: Command,
769
+ ) => {
770
+ try {
771
+ const client = await VellumPlatformClient.create();
772
+ if (!client) {
773
+ throw new Error(
774
+ "Platform credentials not configured. Run: assistant platform connect",
775
+ );
776
+ }
777
+ if (!client.platformAssistantId) {
778
+ throw new Error(
779
+ "Assistant ID not configured. Set PLATFORM_ASSISTANT_ID or run: assistant platform connect",
780
+ );
781
+ }
782
+
783
+ const assistantId = client.platformAssistantId;
784
+ const basePath = `/v1/assistants/${assistantId}/emails/${messageId}/attachments`;
785
+
786
+ if (opts.list) {
787
+ // List mode — show attachment metadata without downloading
788
+ const response = await client.fetch(`${basePath}/`);
789
+ if (!response.ok) {
790
+ const body = (await response
791
+ .json()
792
+ .catch(() => ({}))) as Record<string, unknown>;
793
+ const detail = body.detail ?? `HTTP ${response.status}`;
794
+ throw new Error(String(detail));
795
+ }
796
+
797
+ const data = (await response.json()) as {
798
+ results: AttachmentMeta[];
799
+ };
800
+
801
+ if (shouldOutputJson(cmd)) {
802
+ writeOutput(cmd, data);
803
+ } else {
804
+ const attachments = data.results ?? [];
805
+ if (attachments.length === 0) {
806
+ log.info("No attachments for this message.");
807
+ } else {
808
+ for (const att of attachments) {
809
+ log.info(
810
+ ` ${att.id} ${att.filename} (${att.content_type}, ${formatBytes(att.size_bytes)})`,
811
+ );
812
+ }
813
+ log.info(`\n${attachments.length} attachment(s)`);
814
+ }
815
+ }
816
+ return;
817
+ }
818
+
819
+ if (!opts.all && !attachmentId) {
820
+ throw new Error(
821
+ "Specify an attachment ID, or use --all to download all attachments. Use --list to see available attachments.",
822
+ );
823
+ }
824
+
825
+ // Ensure output directory exists
826
+ const outDir = opts.output ?? ".";
827
+ mkdirSync(outDir, { recursive: true });
828
+
829
+ if (opts.all) {
830
+ // Download all attachments
831
+ const listResponse = await client.fetch(`${basePath}/`);
832
+ if (!listResponse.ok) {
833
+ const body = (await listResponse
834
+ .json()
835
+ .catch(() => ({}))) as Record<string, unknown>;
836
+ const detail = body.detail ?? `HTTP ${listResponse.status}`;
837
+ throw new Error(String(detail));
838
+ }
839
+
840
+ const listData = (await listResponse.json()) as {
841
+ results: AttachmentMeta[];
842
+ };
843
+
844
+ const attachments = listData.results ?? [];
845
+ if (attachments.length === 0) {
846
+ throw new Error("No attachments for this message.");
847
+ }
848
+
849
+ const downloaded: { filename: string; size_bytes: number }[] = [];
850
+ for (const att of attachments) {
851
+ const dest = join(outDir, safeFilename(att.filename));
852
+ await downloadAttachment(client, basePath, att.id, dest);
853
+ downloaded.push({
854
+ filename: att.filename,
855
+ size_bytes: att.size_bytes,
856
+ });
857
+ }
858
+
859
+ if (shouldOutputJson(cmd)) {
860
+ writeOutput(cmd, {
861
+ downloaded: downloaded.length,
862
+ directory: outDir,
863
+ files: downloaded,
864
+ });
865
+ } else {
866
+ log.info(
867
+ `✓ Downloaded ${downloaded.length} attachment(s) to ${outDir}`,
868
+ );
869
+ for (const f of downloaded) {
870
+ log.info(` - ${f.filename} (${formatBytes(f.size_bytes)})`);
871
+ }
872
+ }
873
+ } else {
874
+ // Download single attachment — first get metadata for the filename
875
+ const metaResponse = await client.fetch(
876
+ `${basePath}/${attachmentId}/`,
877
+ );
878
+ if (!metaResponse.ok) {
879
+ const body = (await metaResponse
880
+ .json()
881
+ .catch(() => ({}))) as Record<string, unknown>;
882
+ const detail = body.detail ?? `HTTP ${metaResponse.status}`;
883
+ throw new Error(String(detail));
884
+ }
885
+
886
+ const meta = (await metaResponse.json()) as AttachmentMeta;
887
+ const dest = join(outDir, safeFilename(meta.filename));
888
+ await downloadAttachment(client, basePath, meta.id, dest);
889
+
890
+ if (shouldOutputJson(cmd)) {
891
+ writeOutput(cmd, {
892
+ filename: meta.filename,
893
+ size_bytes: meta.size_bytes,
894
+ saved: dest,
895
+ });
896
+ } else {
897
+ log.info(
898
+ `✓ Downloaded ${meta.filename} (${formatBytes(meta.size_bytes)})`,
899
+ );
900
+ }
901
+ }
902
+ } catch (err) {
903
+ const message = err instanceof Error ? err.message : String(err);
904
+ if (shouldOutputJson(cmd)) {
905
+ writeOutput(cmd, { error: message });
906
+ } else {
907
+ log.error(`Error: ${message}`);
908
+ }
909
+ process.exitCode = 1;
910
+ }
911
+ },
912
+ );
913
+ }
914
+
915
+ interface AttachmentMeta {
916
+ id: string;
917
+ filename: string;
918
+ content_type: string;
919
+ size_bytes: number;
920
+ content_id: string;
921
+ created_at: string;
922
+ }
923
+
924
+ function formatBytes(bytes: number): string {
925
+ if (bytes < 1024) return `${bytes} B`;
926
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
927
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
928
+ }
929
+
930
+ function safeFilename(name: string): string {
931
+ // Strip path separators and null bytes — keep the basename only
932
+ return basename(name).replace(/[\x00/\\]/g, "_") || "attachment";
933
+ }
934
+
935
+ async function downloadAttachment(
936
+ client: VellumPlatformClient,
937
+ basePath: string,
938
+ attachmentId: string,
939
+ dest: string,
940
+ ): Promise<void> {
941
+ const response = await client.fetch(
942
+ `${basePath}/${attachmentId}/download/`,
943
+ );
944
+
945
+ if (!response.ok) {
946
+ const body = (await response.json().catch(() => ({}))) as Record<
947
+ string,
948
+ unknown
949
+ >;
950
+ const detail = body.detail ?? `HTTP ${response.status}`;
951
+ throw new Error(`Failed to download attachment: ${detail}`);
952
+ }
953
+
954
+ if (!response.body) {
955
+ throw new Error("Empty response body from download endpoint.");
956
+ }
957
+
958
+ const fileStream = createWriteStream(dest);
959
+ await pipeline(response.body as unknown as Readable, fileStream);
703
960
  }
@@ -34,13 +34,25 @@ export async function checkServerHealth(
34
34
  }),
35
35
  ]);
36
36
 
37
- if (!client.isConnected) {
38
- return "! Needs authentication";
37
+ if (client.isConnected) {
38
+ await client.disconnect();
39
+ return "\u2713 Connected";
40
+ }
41
+
42
+ // connect() swallows errors — check lastError to distinguish auth from
43
+ // transport failures (DNS, TLS, 500, stdio crash, etc.).
44
+ const err = client.lastError;
45
+ if (err) {
46
+ const message = err.message;
47
+ if (message.includes("timeout")) {
48
+ return "\u2717 Timed out";
49
+ }
50
+ return `\u2717 Error: ${message}`;
39
51
  }
40
52
 
41
- await client.disconnect();
42
- return "\u2713 Connected";
53
+ return "! Needs authentication";
43
54
  } catch (err) {
55
+ // Only the external timeout Promise can throw here (connect() never does).
44
56
  try {
45
57
  await client.disconnect();
46
58
  } catch {
@@ -264,9 +264,10 @@ describe("assistant oauth connect", () => {
264
264
 
265
265
  test("managed mode with --no-browser: prints connect URL", async () => {
266
266
  mockGetProvider = () => ({
267
- providerKey: "google",
268
- authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
269
- tokenUrl: "https://oauth2.googleapis.com/token",
267
+ provider: "google",
268
+ authorizeUrl: "https://accounts.google.com/o/oauth2/v2/auth",
269
+ tokenExchangeUrl: "https://oauth2.googleapis.com/token",
270
+ tokenExchangeBodyFormat: "form",
270
271
  managedServiceConfigKey: "google-oauth",
271
272
  });
272
273
  mockIsManagedMode = () => true;
@@ -301,9 +302,10 @@ describe("assistant oauth connect", () => {
301
302
 
302
303
  test("managed mode default: opens browser and polls for new connection", async () => {
303
304
  mockGetProvider = () => ({
304
- providerKey: "google",
305
- authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
306
- tokenUrl: "https://oauth2.googleapis.com/token",
305
+ provider: "google",
306
+ authorizeUrl: "https://accounts.google.com/o/oauth2/v2/auth",
307
+ tokenExchangeUrl: "https://oauth2.googleapis.com/token",
308
+ tokenExchangeBodyFormat: "form",
307
309
  managedServiceConfigKey: "google-oauth",
308
310
  });
309
311
  mockIsManagedMode = () => true;
@@ -357,9 +359,10 @@ describe("assistant oauth connect", () => {
357
359
 
358
360
  test("BYO mode with --no-browser: prints auth URL", async () => {
359
361
  mockGetProvider = () => ({
360
- providerKey: "google",
361
- authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
362
- tokenUrl: "https://oauth2.googleapis.com/token",
362
+ provider: "google",
363
+ authorizeUrl: "https://accounts.google.com/o/oauth2/v2/auth",
364
+ tokenExchangeUrl: "https://oauth2.googleapis.com/token",
365
+ tokenExchangeBodyFormat: "form",
363
366
  managedServiceConfigKey: null,
364
367
  });
365
368
  mockIsManagedMode = () => false;
@@ -368,7 +371,7 @@ describe("assistant oauth connect", () => {
368
371
  id: "app-1",
369
372
  clientId: "byo-client-id",
370
373
  clientSecretCredentialPath: "oauth_app/app-1/client_secret",
371
- providerKey: "google",
374
+ provider: "google",
372
375
  createdAt: 0,
373
376
  updatedAt: 0,
374
377
  });
@@ -376,7 +379,7 @@ describe("assistant oauth connect", () => {
376
379
  mockOrchestrateOAuthConnect = async () => ({
377
380
  success: true,
378
381
  deferred: true,
379
- authUrl: "https://accounts.google.com/o/oauth2/v2/auth?state=abc",
382
+ authorizeUrl: "https://accounts.google.com/o/oauth2/v2/auth?state=abc",
380
383
  state: "abc",
381
384
  service: "google",
382
385
  });
@@ -403,9 +406,10 @@ describe("assistant oauth connect", () => {
403
406
 
404
407
  test("BYO mode default calls orchestrator with isInteractive: true", async () => {
405
408
  mockGetProvider = () => ({
406
- providerKey: "google",
407
- authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
408
- tokenUrl: "https://oauth2.googleapis.com/token",
409
+ provider: "google",
410
+ authorizeUrl: "https://accounts.google.com/o/oauth2/v2/auth",
411
+ tokenExchangeUrl: "https://oauth2.googleapis.com/token",
412
+ tokenExchangeBodyFormat: "form",
409
413
  managedServiceConfigKey: null,
410
414
  });
411
415
  mockIsManagedMode = () => false;
@@ -414,7 +418,7 @@ describe("assistant oauth connect", () => {
414
418
  id: "app-1",
415
419
  clientId: "test-id",
416
420
  clientSecretCredentialPath: "oauth_app/app-1/client_secret",
417
- providerKey: "google",
421
+ provider: "google",
418
422
  createdAt: 0,
419
423
  updatedAt: 0,
420
424
  });
@@ -455,9 +459,10 @@ describe("assistant oauth connect", () => {
455
459
 
456
460
  test("BYO mode: missing app with --client-id returns error with hint", async () => {
457
461
  mockGetProvider = () => ({
458
- providerKey: "google",
459
- authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
460
- tokenUrl: "https://oauth2.googleapis.com/token",
462
+ provider: "google",
463
+ authorizeUrl: "https://accounts.google.com/o/oauth2/v2/auth",
464
+ tokenExchangeUrl: "https://oauth2.googleapis.com/token",
465
+ tokenExchangeBodyFormat: "form",
461
466
  managedServiceConfigKey: null,
462
467
  });
463
468
  mockIsManagedMode = () => false;
@@ -483,9 +488,10 @@ describe("assistant oauth connect", () => {
483
488
 
484
489
  test("BYO mode: no client_id found returns error with hint", async () => {
485
490
  mockGetProvider = () => ({
486
- providerKey: "google",
487
- authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
488
- tokenUrl: "https://oauth2.googleapis.com/token",
491
+ provider: "google",
492
+ authorizeUrl: "https://accounts.google.com/o/oauth2/v2/auth",
493
+ tokenExchangeUrl: "https://oauth2.googleapis.com/token",
494
+ tokenExchangeBodyFormat: "form",
489
495
  managedServiceConfigKey: null,
490
496
  });
491
497
  mockIsManagedMode = () => false;
@@ -509,9 +515,10 @@ describe("assistant oauth connect", () => {
509
515
 
510
516
  test("--client-id is silently ignored in managed mode", async () => {
511
517
  mockGetProvider = () => ({
512
- providerKey: "google",
513
- authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
514
- tokenUrl: "https://oauth2.googleapis.com/token",
518
+ provider: "google",
519
+ authorizeUrl: "https://accounts.google.com/o/oauth2/v2/auth",
520
+ tokenExchangeUrl: "https://oauth2.googleapis.com/token",
521
+ tokenExchangeBodyFormat: "form",
515
522
  managedServiceConfigKey: "google-oauth",
516
523
  });
517
524
  mockIsManagedMode = () => true;
@@ -547,9 +554,10 @@ describe("assistant oauth connect", () => {
547
554
 
548
555
  test("JSON output for deferred case includes ok, deferred, authUrl, service", async () => {
549
556
  mockGetProvider = () => ({
550
- providerKey: "slack",
551
- authUrl: "https://slack.com/oauth/v2/authorize",
552
- tokenUrl: "https://slack.com/api/oauth.v2.access",
557
+ provider: "slack",
558
+ authorizeUrl: "https://slack.com/oauth/v2/authorize",
559
+ tokenExchangeUrl: "https://slack.com/api/oauth.v2.access",
560
+ tokenExchangeBodyFormat: "form",
553
561
  managedServiceConfigKey: null,
554
562
  });
555
563
  mockIsManagedMode = () => false;
@@ -558,7 +566,7 @@ describe("assistant oauth connect", () => {
558
566
  id: "app-slack",
559
567
  clientId: "slack-client-id",
560
568
  clientSecretCredentialPath: "oauth_app/app-slack/client_secret",
561
- providerKey: "slack",
569
+ provider: "slack",
562
570
  createdAt: 0,
563
571
  updatedAt: 0,
564
572
  });
@@ -566,7 +574,7 @@ describe("assistant oauth connect", () => {
566
574
  mockOrchestrateOAuthConnect = async () => ({
567
575
  success: true,
568
576
  deferred: true,
569
- authUrl: "https://slack.com/oauth/v2/authorize?state=xyz",
577
+ authorizeUrl: "https://slack.com/oauth/v2/authorize?state=xyz",
570
578
  state: "xyz",
571
579
  service: "slack",
572
580
  });
@@ -591,9 +599,10 @@ describe("assistant oauth connect", () => {
591
599
 
592
600
  test("JSON output for completed case includes ok, grantedScopes, accountInfo", async () => {
593
601
  mockGetProvider = () => ({
594
- providerKey: "google",
595
- authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
596
- tokenUrl: "https://oauth2.googleapis.com/token",
602
+ provider: "google",
603
+ authorizeUrl: "https://accounts.google.com/o/oauth2/v2/auth",
604
+ tokenExchangeUrl: "https://oauth2.googleapis.com/token",
605
+ tokenExchangeBodyFormat: "form",
597
606
  managedServiceConfigKey: null,
598
607
  });
599
608
  mockIsManagedMode = () => false;
@@ -602,7 +611,7 @@ describe("assistant oauth connect", () => {
602
611
  id: "app-1",
603
612
  clientId: "completed-client-id",
604
613
  clientSecretCredentialPath: "oauth_app/app-1/client_secret",
605
- providerKey: "google",
614
+ provider: "google",
606
615
  createdAt: 0,
607
616
  updatedAt: 0,
608
617
  });
@@ -635,9 +644,10 @@ describe("assistant oauth connect", () => {
635
644
 
636
645
  test("BYO mode: client_secret required but missing returns error with hint", async () => {
637
646
  mockGetProvider = () => ({
638
- providerKey: "google",
639
- authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
640
- tokenUrl: "https://oauth2.googleapis.com/token",
647
+ provider: "google",
648
+ authorizeUrl: "https://accounts.google.com/o/oauth2/v2/auth",
649
+ tokenExchangeUrl: "https://oauth2.googleapis.com/token",
650
+ tokenExchangeBodyFormat: "form",
641
651
  tokenEndpointAuthMethod: "client_secret_post",
642
652
  managedServiceConfigKey: null,
643
653
  requiresClientSecret: 1,
@@ -648,7 +658,7 @@ describe("assistant oauth connect", () => {
648
658
  id: "app-1",
649
659
  clientId: "test-id",
650
660
  clientSecretCredentialPath: "oauth_app/app-1/client_secret",
651
- providerKey: "google",
661
+ provider: "google",
652
662
  createdAt: 0,
653
663
  updatedAt: 0,
654
664
  });
@@ -674,9 +684,10 @@ describe("assistant oauth connect", () => {
674
684
 
675
685
  test("manual-token provider returns error directing to credentials command", async () => {
676
686
  mockGetProvider = () => ({
677
- providerKey: "slack_channel",
678
- authUrl: "urn:manual-token",
679
- tokenUrl: "urn:manual-token",
687
+ provider: "slack_channel",
688
+ authorizeUrl: "urn:manual-token",
689
+ tokenExchangeUrl: "urn:manual-token",
690
+ tokenExchangeBodyFormat: "form",
680
691
  managedServiceConfigKey: null,
681
692
  });
682
693
  mockIsManagedMode = () => false;
@@ -701,9 +712,10 @@ describe("assistant oauth connect", () => {
701
712
 
702
713
  test("BYO mode: orchestrator error propagates correctly", async () => {
703
714
  mockGetProvider = () => ({
704
- providerKey: "google",
705
- authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
706
- tokenUrl: "https://oauth2.googleapis.com/token",
715
+ provider: "google",
716
+ authorizeUrl: "https://accounts.google.com/o/oauth2/v2/auth",
717
+ tokenExchangeUrl: "https://oauth2.googleapis.com/token",
718
+ tokenExchangeBodyFormat: "form",
707
719
  managedServiceConfigKey: null,
708
720
  });
709
721
  mockIsManagedMode = () => false;
@@ -712,7 +724,7 @@ describe("assistant oauth connect", () => {
712
724
  id: "app-1",
713
725
  clientId: "client-id",
714
726
  clientSecretCredentialPath: "oauth_app/app-1/client_secret",
715
- providerKey: "google",
727
+ provider: "google",
716
728
  createdAt: 0,
717
729
  updatedAt: 0,
718
730
  });