@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
@@ -45,6 +45,7 @@ let mockRepoSkillsDir: string | undefined = undefined;
45
45
 
46
46
  mock.module("../skills/catalog-cache.js", () => ({
47
47
  getCatalog: async () => mockCatalog,
48
+ getCachedCatalogSync: () => mockCatalog,
48
49
  }));
49
50
 
50
51
  mock.module("../skills/catalog-install.js", () => ({
@@ -72,6 +73,8 @@ mock.module("../config/env.js", () => ({
72
73
  // ---------------------------------------------------------------------------
73
74
 
74
75
  import {
76
+ catalogSkillToSlim,
77
+ createVellumCatalogProvider,
75
78
  readCatalogSkillFileContent,
76
79
  readCatalogSkillFiles,
77
80
  sanitizeRelativePath,
@@ -860,3 +863,138 @@ describe("readCatalogSkillFileContent (platform mode)", () => {
860
863
  expect(fetchCalls.length).toBe(0);
861
864
  });
862
865
  });
866
+
867
+ // ---------------------------------------------------------------------------
868
+ // catalogSkillToSlim
869
+ // ---------------------------------------------------------------------------
870
+
871
+ describe("catalogSkillToSlim", () => {
872
+ test("maps CatalogSkill to SlimSkillResponse with vellum origin", () => {
873
+ const cs: CatalogSkill = {
874
+ id: "test-skill",
875
+ name: "test-skill",
876
+ description: "A test skill",
877
+ emoji: "🧪",
878
+ };
879
+ const slim = catalogSkillToSlim(cs);
880
+ expect(slim.id).toBe("test-skill");
881
+ expect(slim.name).toBe("test-skill");
882
+ expect(slim.description).toBe("A test skill");
883
+ expect(slim.emoji).toBe("🧪");
884
+ expect(slim.kind).toBe("catalog");
885
+ expect(slim.origin).toBe("vellum");
886
+ expect(slim.status).toBe("available");
887
+ });
888
+
889
+ test("uses display-name from metadata when available", () => {
890
+ const cs: CatalogSkill = {
891
+ id: "test-skill",
892
+ name: "test-skill",
893
+ description: "A test skill",
894
+ metadata: { vellum: { "display-name": "Pretty Name" } },
895
+ };
896
+ const slim = catalogSkillToSlim(cs);
897
+ expect(slim.name).toBe("Pretty Name");
898
+ });
899
+ });
900
+
901
+ // ---------------------------------------------------------------------------
902
+ // createVellumCatalogProvider
903
+ // ---------------------------------------------------------------------------
904
+
905
+ describe("createVellumCatalogProvider", () => {
906
+ test("canHandle returns true when skill is in the cached catalog", () => {
907
+ mockCatalog = [skill("my-skill"), skill("other-skill")];
908
+ const provider = createVellumCatalogProvider();
909
+ expect(provider.canHandle("my-skill")).toBe(true);
910
+ expect(provider.canHandle("other-skill")).toBe(true);
911
+ });
912
+
913
+ test("canHandle returns false when skill is NOT in the cached catalog", () => {
914
+ mockCatalog = [skill("my-skill")];
915
+ const provider = createVellumCatalogProvider();
916
+ expect(provider.canHandle("unknown-skill")).toBe(false);
917
+ });
918
+
919
+ test("canHandle returns false when catalog cache is empty", () => {
920
+ mockCatalog = [];
921
+ const provider = createVellumCatalogProvider();
922
+ expect(provider.canHandle("any-skill")).toBe(false);
923
+ });
924
+
925
+ test("listFiles delegates to readCatalogSkillFiles", async () => {
926
+ const root = makeTempSkillsDir();
927
+ writeSkill(root, "my-skill", {
928
+ "SKILL.md": "# hello",
929
+ "tools/run.sh": "#!/bin/sh\necho hi\n",
930
+ });
931
+ mockRepoSkillsDir = root;
932
+ mockCatalog = [skill("my-skill")];
933
+ installFetchForbidden();
934
+
935
+ const provider = createVellumCatalogProvider();
936
+ const entries = await provider.listFiles("my-skill");
937
+ expect(entries).not.toBeNull();
938
+ const paths = entries!.map((e) => e.path).sort();
939
+ expect(paths).toEqual(["SKILL.md", "tools/run.sh"]);
940
+ });
941
+
942
+ test("listFiles returns null for unknown skill", async () => {
943
+ mockCatalog = [];
944
+ installFetchForbidden();
945
+
946
+ const provider = createVellumCatalogProvider();
947
+ expect(await provider.listFiles("unknown")).toBeNull();
948
+ });
949
+
950
+ test("readFileContent delegates to readCatalogSkillFileContent", async () => {
951
+ const root = makeTempSkillsDir();
952
+ writeSkill(root, "my-skill", { "SKILL.md": "# hello world\n" });
953
+ mockRepoSkillsDir = root;
954
+ mockCatalog = [skill("my-skill")];
955
+ installFetchForbidden();
956
+
957
+ const provider = createVellumCatalogProvider();
958
+ const entry = await provider.readFileContent("my-skill", "SKILL.md");
959
+ expect(entry).not.toBeNull();
960
+ expect(entry!.content).toBe("# hello world\n");
961
+ expect(entry!.path).toBe("SKILL.md");
962
+ });
963
+
964
+ test("readFileContent returns null for unknown skill", async () => {
965
+ mockCatalog = [];
966
+ installFetchForbidden();
967
+
968
+ const provider = createVellumCatalogProvider();
969
+ expect(await provider.readFileContent("unknown", "SKILL.md")).toBeNull();
970
+ });
971
+
972
+ test("toSlimSkill returns SlimSkillResponse for catalog skill", async () => {
973
+ mockCatalog = [
974
+ {
975
+ id: "my-skill",
976
+ name: "my-skill",
977
+ description: "A skill",
978
+ emoji: "🔧",
979
+ metadata: { vellum: { "display-name": "My Skill" } },
980
+ },
981
+ ];
982
+
983
+ const provider = createVellumCatalogProvider();
984
+ const slim = await provider.toSlimSkill("my-skill");
985
+ expect(slim).not.toBeNull();
986
+ expect(slim!.id).toBe("my-skill");
987
+ expect(slim!.name).toBe("My Skill");
988
+ expect(slim!.description).toBe("A skill");
989
+ expect(slim!.kind).toBe("catalog");
990
+ expect(slim!.origin).toBe("vellum");
991
+ expect(slim!.status).toBe("available");
992
+ });
993
+
994
+ test("toSlimSkill returns null for unknown skill", async () => {
995
+ mockCatalog = [];
996
+
997
+ const provider = createVellumCatalogProvider();
998
+ expect(await provider.toSlimSkill("unknown")).toBeNull();
999
+ });
1000
+ });
@@ -54,11 +54,11 @@ describe("resolveAdapterHandle", () => {
54
54
  test("returns async handle when only resolveChannelHandleAsync is defined", async () => {
55
55
  const adapter: ChannelInviteAdapter = {
56
56
  channel: "email",
57
- resolveChannelHandleAsync: async () => "hello@assistant.agentmail.to",
57
+ resolveChannelHandleAsync: async () => "hello@vellum.me",
58
58
  };
59
59
 
60
60
  const handle = await resolveAdapterHandle(adapter);
61
- expect(handle).toBe("hello@assistant.agentmail.to");
61
+ expect(handle).toBe("hello@vellum.me");
62
62
  });
63
63
 
64
64
  test("prefers async over sync when both are defined", async () => {
@@ -14,7 +14,6 @@ import { beforeEach, describe, expect, mock, test } from "bun:test";
14
14
  let mockRawConfig: Record<string, unknown> | undefined;
15
15
  let mockSecureKeys: Record<string, string>;
16
16
  let mockHasTwilioCredentials: boolean;
17
- let mockPrimaryInboxAddress: string | undefined;
18
17
 
19
18
  mock.module("../calls/twilio-rest.js", () => ({
20
19
  hasTwilioCredentials: () => mockHasTwilioCredentials,
@@ -24,7 +23,7 @@ mock.module("../calls/twilio-rest.js", () => ({
24
23
  mock.module("../config/env.js", () => ({}));
25
24
 
26
25
  mock.module("../config/loader.js", () => ({
27
- loadRawConfig: () => mockRawConfig,
26
+ loadRawConfig: () => mockRawConfig ?? {},
28
27
  loadConfig: () => {
29
28
  const raw = mockRawConfig ?? {};
30
29
  const wa = (raw.whatsapp ?? {}) as Record<string, unknown>;
@@ -43,6 +42,15 @@ mock.module("../config/loader.js", () => ({
43
42
  whatsapp: { phoneNumber: (wa.phoneNumber as string) ?? "" },
44
43
  };
45
44
  },
45
+ getNestedValue: (obj: Record<string, unknown>, path: string) => {
46
+ const keys = path.split(".");
47
+ let current: unknown = obj;
48
+ for (const key of keys) {
49
+ if (current == null || typeof current !== "object") return undefined;
50
+ current = (current as Record<string, unknown>)[key];
51
+ }
52
+ return current;
53
+ },
46
54
  invalidateConfigCache: () => {},
47
55
  }));
48
56
 
@@ -50,12 +58,6 @@ mock.module("../security/secure-keys.js", () => ({
50
58
  getSecureKeyAsync: async (key: string) => mockSecureKeys[key] ?? null,
51
59
  }));
52
60
 
53
- mock.module("../email/service.js", () => ({
54
- getEmailService: () => ({
55
- getPrimaryInboxAddress: async () => mockPrimaryInboxAddress,
56
- }),
57
- }));
58
-
59
61
  mock.module("../email/feature-gate.js", () => ({
60
62
  isEmailEnabled: () => true,
61
63
  }));
@@ -76,7 +78,6 @@ describe("channel readiness routes — email and WhatsApp probes", () => {
76
78
  mockRawConfig = undefined;
77
79
  mockSecureKeys = {};
78
80
  mockHasTwilioCredentials = false;
79
- mockPrimaryInboxAddress = undefined;
80
81
  });
81
82
 
82
83
  // -------------------------------------------------------------------------
@@ -96,19 +97,19 @@ describe("channel readiness routes — email and WhatsApp probes", () => {
96
97
  ).toBe(false);
97
98
  });
98
99
 
99
- test("reports not ready when AgentMail API key is missing", async () => {
100
+ test("reports platform email check as passing", async () => {
100
101
  mockRawConfig = {};
101
102
  const service = createReadinessService();
102
103
  const [snapshot] = await service.getReadiness("email");
103
104
 
104
- expect(snapshot.ready).toBe(false);
105
- expect(snapshot.reasons.some((r) => r.code === "agentmail_api_key")).toBe(
106
- true,
105
+ const platformCheck = snapshot.localChecks.find(
106
+ (c) => c.name === "platform_email",
107
107
  );
108
+ expect(platformCheck).toBeDefined();
109
+ expect(platformCheck!.passed).toBe(true);
108
110
  });
109
111
 
110
112
  test("checks invite policy", async () => {
111
- mockSecureKeys = { agentmail: "test-key" };
112
113
  mockRawConfig = {
113
114
  ingress: { publicBaseUrl: "https://example.com", enabled: true },
114
115
  };
@@ -124,7 +125,6 @@ describe("channel readiness routes — email and WhatsApp probes", () => {
124
125
  });
125
126
 
126
127
  test("checks ingress configuration", async () => {
127
- mockSecureKeys = { agentmail: "test-key" };
128
128
  mockRawConfig = {};
129
129
  const service = createReadinessService();
130
130
  const [snapshot] = await service.getReadiness("email");
@@ -137,11 +137,10 @@ describe("channel readiness routes — email and WhatsApp probes", () => {
137
137
  });
138
138
 
139
139
  test("ready when all prerequisites are met (including inbox)", async () => {
140
- mockSecureKeys = { agentmail: "test-key" };
141
140
  mockRawConfig = {
142
141
  ingress: { publicBaseUrl: "https://example.com", enabled: true },
142
+ email: { address: "hello@vellum.me" },
143
143
  };
144
- mockPrimaryInboxAddress = "hello@example.agentmail.to";
145
144
  const service = createReadinessService();
146
145
  const [snapshot] = await service.getReadiness("email", true);
147
146
 
@@ -150,11 +149,9 @@ describe("channel readiness routes — email and WhatsApp probes", () => {
150
149
  });
151
150
 
152
151
  test("not ready when inbox is missing (remote check)", async () => {
153
- mockSecureKeys = { agentmail: "test-key" };
154
152
  mockRawConfig = {
155
153
  ingress: { publicBaseUrl: "https://example.com", enabled: true },
156
154
  };
157
- mockPrimaryInboxAddress = undefined;
158
155
  const service = createReadinessService();
159
156
  const [snapshot] = await service.getReadiness("email", true);
160
157
 
@@ -165,7 +162,6 @@ describe("channel readiness routes — email and WhatsApp probes", () => {
165
162
  });
166
163
 
167
164
  test("local-only readiness still passes without inbox check", async () => {
168
- mockSecureKeys = { agentmail: "test-key" };
169
165
  mockRawConfig = {
170
166
  ingress: { publicBaseUrl: "https://example.com", enabled: true },
171
167
  };
@@ -26,7 +26,7 @@ mock.module("../channels/config.js", () => ({
26
26
  mock.module("../config/env.js", () => ({}));
27
27
 
28
28
  mock.module("../config/loader.js", () => ({
29
- loadRawConfig: () => mockRawConfig,
29
+ loadRawConfig: () => mockRawConfig ?? {},
30
30
  loadConfig: () => ({
31
31
  twilio: { phoneNumber: mockTwilioPhoneNumber ?? "" },
32
32
  whatsapp: { phoneNumber: "" },
@@ -35,12 +35,17 @@ mock.module("../config/loader.js", () => ({
35
35
  twilio: { phoneNumber: mockTwilioPhoneNumber ?? "" },
36
36
  whatsapp: { phoneNumber: "" },
37
37
  }),
38
- }));
39
-
40
- mock.module("../email/service.js", () => ({
41
- getEmailService: () => ({
42
- getPrimaryInboxAddress: async () => undefined,
43
- }),
38
+ getNestedValue: (obj: Record<string, unknown>, path: string) => {
39
+ const keys = path.split(".");
40
+ let current: unknown = obj;
41
+ for (const key of keys) {
42
+ if (current == null || typeof current !== "object") return undefined;
43
+ current = (current as Record<string, unknown>)[key];
44
+ }
45
+ return current;
46
+ },
47
+ saveRawConfig: () => {},
48
+ setNestedValue: () => {},
44
49
  }));
45
50
 
46
51
  mock.module("../inbound/platform-callback-registration.js", () => ({
@@ -12,12 +12,14 @@ import {
12
12
  import { homedir, tmpdir } from "node:os";
13
13
  import { join, resolve } from "node:path";
14
14
  import {
15
+ afterAll,
15
16
  afterEach,
16
17
  beforeAll,
17
18
  beforeEach,
18
19
  describe,
19
20
  expect,
20
21
  mock,
22
+ spyOn,
21
23
  test,
22
24
  } from "bun:test";
23
25
 
@@ -67,6 +69,25 @@ mock.module("../config/loader.js", () => ({
67
69
  setNestedValue: () => {},
68
70
  }));
69
71
 
72
+ // Mutable guardian persona path so tests can toggle whether
73
+ // getDefaultRuleTemplates emits the dynamic guardian-persona allow rules.
74
+ // Defaults to null so existing tests see no extra rules, matching the
75
+ // behaviour on a fresh install without a resolved guardian.
76
+ let mockGuardianPersonaPath: string | null = null;
77
+
78
+ // Spy on the namespace import rather than using `mock.module`. Bun's
79
+ // `mock.module` is a persistent process-wide override that would clobber
80
+ // every other export (e.g. `ensureGuardianPersonaFile`,
81
+ // `isGuardianPersonaCustomized`) and break unrelated test files
82
+ // (persona-resolver.test.ts) when run in the same bun test invocation.
83
+ // `spyOn` with `mockRestore()` in afterAll restores the original
84
+ // implementation so other test files see the real exports.
85
+ import * as personaResolver from "../prompts/persona-resolver.js";
86
+ const guardianPathSpy = spyOn(
87
+ personaResolver,
88
+ "resolveGuardianPersonaPath",
89
+ ).mockImplementation(() => mockGuardianPersonaPath);
90
+
70
91
  import {
71
92
  check,
72
93
  classifyRisk,
@@ -140,6 +161,13 @@ function writeSkill(
140
161
  );
141
162
  }
142
163
 
164
+ // Restore the guardian persona spy at the end of this file's run so
165
+ // subsequent test files (e.g. persona-resolver.test.ts) see the real
166
+ // implementation when they import from the module namespace.
167
+ afterAll(() => {
168
+ guardianPathSpy.mockRestore();
169
+ });
170
+
143
171
  describe("Permission Checker", () => {
144
172
  beforeAll(async () => {
145
173
  // Warm up the shell parser (loads WASM)
@@ -152,6 +180,8 @@ describe("Permission Checker", () => {
152
180
  // Reset permissions mode to workspace (default) so existing tests are not affected
153
181
  testConfig.permissions = { mode: "workspace" };
154
182
  testConfig.skills = { load: { extraDirs: [] } };
183
+ // Reset guardian persona mock so each test opts in explicitly
184
+ mockGuardianPersonaPath = null;
155
185
  loggerWarnCalls.length = 0;
156
186
  try {
157
187
  rmSync(join(checkerTestDir, "protected", "trust.json"));
@@ -201,6 +231,25 @@ describe("Permission Checker", () => {
201
231
  });
202
232
  expect(risk).toBe(RiskLevel.High);
203
233
  });
234
+
235
+ test("file_read of legacy signing key is high risk even when BASE_DATA_DIR relocates getProtectedDir()", async () => {
236
+ const savedBaseDataDir = process.env.BASE_DATA_DIR;
237
+ process.env.BASE_DATA_DIR = "/tmp/fake-instance-signing-key-test";
238
+ try {
239
+ const risk = await classifyRisk("file_read", {
240
+ path: join(
241
+ homedir(),
242
+ ".vellum",
243
+ "protected",
244
+ "actor-token-signing-key",
245
+ ),
246
+ });
247
+ expect(risk).toBe(RiskLevel.High);
248
+ } finally {
249
+ if (savedBaseDataDir === undefined) delete process.env.BASE_DATA_DIR;
250
+ else process.env.BASE_DATA_DIR = savedBaseDataDir;
251
+ }
252
+ });
204
253
  });
205
254
 
206
255
  // file_write is always low (sandboxed)
@@ -1473,14 +1522,6 @@ describe("Permission Checker", () => {
1473
1522
  expect(result.matchedRule!.id).toBe("default:allow-file_edit-identity");
1474
1523
  });
1475
1524
 
1476
- test("file_read of workspace USER.md is auto-allowed", async () => {
1477
- const userPath = join(checkerTestDir, "USER.md");
1478
- const result = await check("file_read", { path: userPath }, "/tmp");
1479
- expect(result.decision).toBe("allow");
1480
- expect(result.matchedRule).toBeDefined();
1481
- expect(result.matchedRule!.id).toBe("default:allow-file_read-user");
1482
- });
1483
-
1484
1525
  test("file_write of workspace SOUL.md is auto-allowed", async () => {
1485
1526
  const soulPath = join(checkerTestDir, "SOUL.md");
1486
1527
  const result = await check("file_write", { path: soulPath }, "/tmp");
@@ -1528,6 +1569,106 @@ describe("Permission Checker", () => {
1528
1569
  // Low risk → auto-allowed even outside workspace
1529
1570
  expect(result.decision).toBe("allow");
1530
1571
  });
1572
+
1573
+ // ── guardian persona file (users/<slug>.md) ──────────────────
1574
+ // The per-user persona file lives at `users/<guardian-slug>.md`.
1575
+ // Dynamic guardian-persona default rules auto-allow reads and
1576
+ // edits of this file.
1577
+
1578
+ test("file_edit of guardian users/<slug>.md is auto-allowed", async () => {
1579
+ const guardianPath = join(checkerTestDir, "users", "alice.md");
1580
+ mockGuardianPersonaPath = guardianPath;
1581
+ const result = await check("file_edit", { path: guardianPath }, "/tmp");
1582
+ expect(result.decision).toBe("allow");
1583
+ expect(result.matchedRule).toBeDefined();
1584
+ expect(result.matchedRule!.id).toBe(
1585
+ "default:allow-file_edit-guardian-persona",
1586
+ );
1587
+ });
1588
+
1589
+ test("file_read of guardian users/<slug>.md is auto-allowed", async () => {
1590
+ const guardianPath = join(checkerTestDir, "users", "alice.md");
1591
+ mockGuardianPersonaPath = guardianPath;
1592
+ const result = await check("file_read", { path: guardianPath }, "/tmp");
1593
+ expect(result.decision).toBe("allow");
1594
+ expect(result.matchedRule).toBeDefined();
1595
+ expect(result.matchedRule!.id).toBe(
1596
+ "default:allow-file_read-guardian-persona",
1597
+ );
1598
+ });
1599
+
1600
+ test("file_write of guardian users/<slug>.md is auto-allowed", async () => {
1601
+ const guardianPath = join(checkerTestDir, "users", "alice.md");
1602
+ mockGuardianPersonaPath = guardianPath;
1603
+ const result = await check("file_write", { path: guardianPath }, "/tmp");
1604
+ expect(result.decision).toBe("allow");
1605
+ expect(result.matchedRule).toBeDefined();
1606
+ expect(result.matchedRule!.id).toBe(
1607
+ "default:allow-file_write-guardian-persona",
1608
+ );
1609
+ });
1610
+
1611
+ test("getDefaultRuleTemplates emits guardian persona rules when guardian is resolved", () => {
1612
+ const guardianPath = join(checkerTestDir, "users", "alice.md");
1613
+ mockGuardianPersonaPath = guardianPath;
1614
+ const templates = getDefaultRuleTemplates();
1615
+ const guardianRules = templates.filter((t) =>
1616
+ t.id.endsWith("-guardian-persona"),
1617
+ );
1618
+ // One rule each for file_read, file_write, file_edit.
1619
+ expect(guardianRules).toHaveLength(3);
1620
+ for (const rule of guardianRules) {
1621
+ expect(rule.decision).toBe("allow");
1622
+ expect(rule.priority).toBe(100);
1623
+ expect(rule.scope).toBe("everywhere");
1624
+ expect(rule.pattern).toBe(`${rule.tool}:${guardianPath}`);
1625
+ }
1626
+ });
1627
+
1628
+ test("getDefaultRuleTemplates emits no guardian persona rules when unresolved", () => {
1629
+ mockGuardianPersonaPath = null;
1630
+ const templates = getDefaultRuleTemplates();
1631
+ const guardianRules = templates.filter((t) =>
1632
+ t.id.endsWith("-guardian-persona"),
1633
+ );
1634
+ expect(guardianRules).toHaveLength(0);
1635
+ });
1636
+
1637
+ test("glob metacharacters in guardian path are escaped and match only the literal file", async () => {
1638
+ // A legacy/imported contact whose userFile contains glob metacharacters
1639
+ // must not broaden the auto-allow rule into a wildcard match.
1640
+ const weirdDir = join(checkerTestDir, "users");
1641
+ const guardianPath = join(weirdDir, "weird[slug]*.md");
1642
+ const siblingPath = join(weirdDir, "weirdX.md");
1643
+ mockGuardianPersonaPath = guardianPath;
1644
+
1645
+ const templates = getDefaultRuleTemplates();
1646
+ const guardianRules = templates.filter((t) =>
1647
+ t.id.endsWith("-guardian-persona"),
1648
+ );
1649
+ expect(guardianRules).toHaveLength(3);
1650
+ for (const rule of guardianRules) {
1651
+ // Pattern must contain escaped metacharacters, not bare wildcards.
1652
+ expect(rule.pattern).not.toBe(`${rule.tool}:${guardianPath}`);
1653
+ expect(rule.pattern).toContain("\\[");
1654
+ expect(rule.pattern).toContain("\\]");
1655
+ expect(rule.pattern).toContain("\\*");
1656
+ }
1657
+
1658
+ // Literal guardian path is auto-allowed.
1659
+ const literal = await check("file_edit", { path: guardianPath }, "/tmp");
1660
+ expect(literal.decision).toBe("allow");
1661
+ expect(literal.matchedRule?.id).toBe(
1662
+ "default:allow-file_edit-guardian-persona",
1663
+ );
1664
+
1665
+ // A sibling file that would match if `*` / `[...]` were treated as
1666
+ // wildcards must NOT match the dynamic guardian-persona rule.
1667
+ const sibling = await check("file_edit", { path: siblingPath }, "/tmp");
1668
+ expect(sibling.matchedRule?.id).not.toBe(
1669
+ "default:allow-file_edit-guardian-persona",
1670
+ );
1671
+ });
1531
1672
  });
1532
1673
 
1533
1674
  // ── generateAllowlistOptions ───────────────────────────────────
@@ -4252,8 +4393,8 @@ describe("Permission Checker", () => {
4252
4393
  });
4253
4394
 
4254
4395
  // ── browser tool permission baselines ─────────────────────────────
4255
- // All 10 browser tools are core-registered and RiskLevel.Low by default.
4256
- // These tests lock that baseline so the migration can verify it's preserved.
4396
+ // Representative browser tools are RiskLevel.Low and auto-allowed by
4397
+ // default rules in strict mode.
4257
4398
 
4258
4399
  describe("browser tool permission baselines", () => {
4259
4400
  const browserToolNames = [
@@ -4261,12 +4402,15 @@ describe("Permission Checker", () => {
4261
4402
  "browser_snapshot",
4262
4403
  "browser_screenshot",
4263
4404
  "browser_close",
4405
+ "browser_attach",
4406
+ "browser_detach",
4264
4407
  "browser_click",
4265
4408
  "browser_type",
4266
4409
  "browser_press_key",
4267
4410
  "browser_wait_for",
4268
4411
  "browser_extract",
4269
4412
  "browser_fill_credential",
4413
+ "browser_status",
4270
4414
  ] as const;
4271
4415
 
4272
4416
  // Register mock browser tools with the correct metadata so classifyRisk
@@ -4357,12 +4501,15 @@ describe("Permission Checker", () => {
4357
4501
  "browser_snapshot",
4358
4502
  "browser_screenshot",
4359
4503
  "browser_close",
4504
+ "browser_attach",
4505
+ "browser_detach",
4360
4506
  "browser_click",
4361
4507
  "browser_type",
4362
4508
  "browser_press_key",
4363
4509
  "browser_wait_for",
4364
4510
  "browser_extract",
4365
4511
  "browser_fill_credential",
4512
+ "browser_status",
4366
4513
  ];
4367
4514
 
4368
4515
  for (const tool of browserTools) {