@vellumai/assistant 0.7.1 → 0.7.2

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 (535) hide show
  1. package/ARCHITECTURE.md +32 -49
  2. package/Dockerfile +1 -0
  3. package/README.md +1 -2
  4. package/__tests__/permissions/gateway-threshold-reader.test.ts +9 -3
  5. package/bun.lock +26 -26
  6. package/docs/architecture/security.md +20 -0
  7. package/docs/plugins.md +7 -9
  8. package/knip.json +1 -0
  9. package/node_modules/@vellumai/gateway-client/src/index.ts +1 -0
  10. package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +39 -1
  11. package/node_modules/@vellumai/gateway-client/src/types.ts +11 -0
  12. package/node_modules/@vellumai/service-contracts/package.json +2 -0
  13. package/node_modules/@vellumai/service-contracts/src/__tests__/contracts.test.ts +4 -0
  14. package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +107 -0
  15. package/node_modules/@vellumai/service-contracts/src/index.ts +5 -1
  16. package/node_modules/@vellumai/service-contracts/src/ingress.ts +24 -0
  17. package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +84 -0
  18. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +9 -0
  19. package/node_modules/@vellumai/twilio-client/bun.lock +24 -0
  20. package/node_modules/@vellumai/twilio-client/package.json +18 -0
  21. package/node_modules/@vellumai/twilio-client/src/__tests__/twilio-client.test.ts +128 -0
  22. package/node_modules/@vellumai/twilio-client/src/index.ts +179 -0
  23. package/node_modules/@vellumai/twilio-client/tsconfig.json +20 -0
  24. package/openapi.yaml +565 -12
  25. package/package.json +6 -3
  26. package/src/__tests__/app-builder-tool-scripts.test.ts +3 -3
  27. package/src/__tests__/app-bundler.test.ts +170 -1
  28. package/src/__tests__/app-control-flow.test.ts +374 -0
  29. package/src/__tests__/app-control-no-global-cgevent.test.ts +98 -0
  30. package/src/__tests__/app-control-tool-schemas.test.ts +621 -0
  31. package/src/__tests__/app-executors.test.ts +30 -43
  32. package/src/__tests__/approval-routes-http.test.ts +23 -6
  33. package/src/__tests__/assistant-event-hub-machine-name.test.ts +146 -0
  34. package/src/__tests__/assistant-event-hub-targeted.test.ts +257 -0
  35. package/src/__tests__/assistant-event-hub.test.ts +109 -2
  36. package/src/__tests__/assistant-event.test.ts +10 -0
  37. package/src/__tests__/assistant-events-sse-hardening.test.ts +7 -2
  38. package/src/__tests__/assistant-feature-flags-integration.test.ts +11 -7
  39. package/src/__tests__/background-shell-host-bash.test.ts +14 -15
  40. package/src/__tests__/bootstrap-turn-cleanup.test.ts +44 -0
  41. package/src/__tests__/btw-routes.test.ts +13 -4
  42. package/src/__tests__/call-controller.test.ts +49 -1
  43. package/src/__tests__/call-domain.test.ts +0 -2
  44. package/src/__tests__/call-routes-http.test.ts +0 -2
  45. package/src/__tests__/channel-readiness-service.test.ts +59 -1
  46. package/src/__tests__/checker.test.ts +3 -4
  47. package/src/__tests__/config-loader-backfill.test.ts +90 -155
  48. package/src/__tests__/config-loader-platform-defaults.test.ts +196 -0
  49. package/src/__tests__/config-schema-cmd.test.ts +0 -1
  50. package/src/__tests__/config-set-platform-guard.test.ts +48 -4
  51. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +2 -2
  52. package/src/__tests__/config-watcher.test.ts +2 -2
  53. package/src/__tests__/conversation-app-control-instantiation.test.ts +392 -0
  54. package/src/__tests__/conversation-app-control-lifecycle.test.ts +237 -0
  55. package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
  56. package/src/__tests__/conversation-lifecycle.test.ts +36 -0
  57. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +283 -0
  58. package/src/__tests__/conversation-routes-disk-view.test.ts +6 -0
  59. package/src/__tests__/conversation-routes-guardian-reply.test.ts +120 -72
  60. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  61. package/src/__tests__/conversation-slash-commands.test.ts +0 -4
  62. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +202 -0
  63. package/src/__tests__/conversation-surfaces-app-control.test.ts +317 -0
  64. package/src/__tests__/credential-execution-feature-gates.test.ts +5 -12
  65. package/src/__tests__/credential-execution-managed-contract.test.ts +3 -131
  66. package/src/__tests__/credentials-cli.test.ts +5 -12
  67. package/src/__tests__/cu-unified-flow.test.ts +185 -23
  68. package/src/__tests__/daemon-credential-client.test.ts +101 -19
  69. package/src/__tests__/db-schedule-syntax-migration.test.ts +2 -0
  70. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
  71. package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
  72. package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -2
  73. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -2
  74. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -1
  75. package/src/__tests__/heartbeat-service.test.ts +718 -1
  76. package/src/__tests__/helpers/call-route-handler.ts +7 -1
  77. package/src/__tests__/host-app-control-proxy.test.ts +602 -0
  78. package/src/__tests__/host-app-control-routes.test.ts +263 -0
  79. package/src/__tests__/host-bash-proxy.test.ts +246 -47
  80. package/src/__tests__/host-bash-routes.test.ts +294 -0
  81. package/src/__tests__/host-browser-proxy.test.ts +24 -22
  82. package/src/__tests__/host-browser-routes.test.ts +39 -13
  83. package/src/__tests__/host-cu-proxy.test.ts +41 -52
  84. package/src/__tests__/host-cu-routes-targeted.test.ts +300 -0
  85. package/src/__tests__/host-file-edit-tool.test.ts +47 -1
  86. package/src/__tests__/host-file-proxy-targeted.test.ts +339 -0
  87. package/src/__tests__/host-file-proxy.test.ts +37 -43
  88. package/src/__tests__/host-file-read-tool.test.ts +17 -0
  89. package/src/__tests__/host-file-routes-targeted.test.ts +262 -0
  90. package/src/__tests__/host-file-write-tool.test.ts +42 -1
  91. package/src/__tests__/host-proxy-base.test.ts +312 -0
  92. package/src/__tests__/host-shell-tool.test.ts +22 -4
  93. package/src/__tests__/host-transfer-proxy-targeted.test.ts +583 -0
  94. package/src/__tests__/host-transfer-proxy.test.ts +121 -22
  95. package/src/__tests__/host-transfer-routes-targeted.test.ts +447 -0
  96. package/src/__tests__/http-user-message-parity.test.ts +1 -0
  97. package/src/__tests__/identity-intro-cache.test.ts +29 -0
  98. package/src/__tests__/identity-routes.test.ts +103 -1
  99. package/src/__tests__/init-feature-flag-overrides.test.ts +26 -3
  100. package/src/__tests__/inline-command-runner.test.ts +0 -1
  101. package/src/__tests__/inline-skill-load-permissions.test.ts +5 -11
  102. package/src/__tests__/integration-status.test.ts +85 -5
  103. package/src/__tests__/intent-routing.test.ts +0 -1
  104. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +95 -5
  105. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +17 -0
  106. package/src/__tests__/managed-skill-lifecycle.test.ts +0 -1
  107. package/src/__tests__/mcp-auth-routes.test.ts +197 -0
  108. package/src/__tests__/mcp-cli.test.ts +338 -2
  109. package/src/__tests__/memory-jobs-worker-lanes.test.ts +188 -0
  110. package/src/__tests__/migration-import-commit-http.test.ts +108 -2
  111. package/src/__tests__/mock-gateway-ipc.ts +1 -0
  112. package/src/__tests__/oauth-cli.test.ts +0 -2
  113. package/src/__tests__/oauth2-gateway-transport.test.ts +0 -1
  114. package/src/__tests__/persistence-secret-redaction.test.ts +299 -0
  115. package/src/__tests__/platform-bash-auto-approve.test.ts +5 -9
  116. package/src/__tests__/prechat-onboarding-contract.test.ts +3 -1
  117. package/src/__tests__/process-message-background-slack.test.ts +2 -0
  118. package/src/__tests__/provider-commit-message-generator.test.ts +0 -1
  119. package/src/__tests__/public-ingress-urls.test.ts +97 -0
  120. package/src/__tests__/require-fresh-approval.test.ts +0 -1
  121. package/src/__tests__/retry-backoff.test.ts +87 -0
  122. package/src/__tests__/runtime-events-sse.test.ts +10 -6
  123. package/src/__tests__/sanitize-config-for-transfer.test.ts +24 -2
  124. package/src/__tests__/schedule-retry.test.ts +715 -0
  125. package/src/__tests__/script-proxy-mitm-handler.test.ts +1 -1
  126. package/src/__tests__/secret-ingress-http.test.ts +1 -0
  127. package/src/__tests__/send-endpoint-busy.test.ts +3 -0
  128. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -1
  129. package/src/__tests__/skill-feature-flags.test.ts +43 -41
  130. package/src/__tests__/skill-load-feature-flag.test.ts +13 -14
  131. package/src/__tests__/skill-load-inline-command.test.ts +0 -51
  132. package/src/__tests__/skill-load-inline-includes.test.ts +0 -43
  133. package/src/__tests__/skill-projection.benchmark.test.ts +0 -1
  134. package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -1
  135. package/src/__tests__/slack-channel-config.test.ts +9 -14
  136. package/src/__tests__/system-prompt-ask-mode.test.ts +0 -1
  137. package/src/__tests__/system-prompt.test.ts +0 -1
  138. package/src/__tests__/telegram-config.test.ts +0 -1
  139. package/src/__tests__/test-preload.ts +8 -0
  140. package/src/__tests__/tool-approval-handler.test.ts +3 -4
  141. package/src/__tests__/tool-audit-listener.test.ts +48 -0
  142. package/src/__tests__/tool-execute-pipeline.test.ts +0 -1
  143. package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -1
  144. package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
  145. package/src/__tests__/tool-executor.test.ts +0 -1
  146. package/src/__tests__/twilio-config.test.ts +3 -16
  147. package/src/__tests__/twilio-routes.test.ts +3 -5
  148. package/src/__tests__/twilio-validation.test.ts +93 -0
  149. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +1 -4
  150. package/src/__tests__/verification-control-plane-policy.test.ts +2 -4
  151. package/src/__tests__/voice-ingress-preflight.test.ts +19 -0
  152. package/src/__tests__/workspace-migration-006-services-config.test.ts +3 -2
  153. package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +1 -5
  154. package/src/__tests__/workspace-migration-down-functions.test.ts +8 -8
  155. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +10 -6
  156. package/src/backup/__tests__/paths.test.ts +0 -22
  157. package/src/backup/__tests__/restore.test.ts +51 -151
  158. package/src/backup/paths.ts +2 -18
  159. package/src/backup/restore.ts +107 -231
  160. package/src/bundler/app-bundler.ts +51 -3
  161. package/src/calls/relay-server.ts +4 -44
  162. package/src/calls/twilio-config.ts +2 -17
  163. package/src/calls/twilio-rest.ts +33 -105
  164. package/src/calls/twilio-routes.ts +11 -12
  165. package/src/channels/types.ts +8 -7
  166. package/src/cli/commands/__tests__/backup.test.ts +6 -277
  167. package/src/cli/commands/__tests__/gateway.test.ts +288 -0
  168. package/src/cli/commands/__tests__/memory-v2.test.ts +4 -0
  169. package/src/cli/commands/__tests__/webhooks.test.ts +0 -1
  170. package/src/cli/commands/backup.ts +6 -331
  171. package/src/cli/commands/clients.ts +36 -37
  172. package/src/cli/commands/contacts.ts +73 -0
  173. package/src/cli/commands/conversations.ts +2 -5
  174. package/src/cli/commands/credentials.ts +15 -7
  175. package/src/cli/commands/domain.ts +66 -15
  176. package/src/cli/commands/gateway.ts +183 -0
  177. package/src/cli/commands/keys.ts +9 -6
  178. package/src/cli/commands/mcp.ts +116 -156
  179. package/src/cli/commands/memory-v2.ts +296 -1
  180. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -1
  181. package/src/cli/commands/platform/__tests__/connect.test.ts +0 -2
  182. package/src/cli/commands/platform/__tests__/disconnect.test.ts +0 -2
  183. package/src/cli/commands/platform/__tests__/status.test.ts +13 -15
  184. package/src/cli/commands/platform/disconnect.ts +5 -4
  185. package/src/cli/commands/platform/index.ts +0 -18
  186. package/src/cli/lib/daemon-credential-client.ts +110 -28
  187. package/src/cli/program.ts +2 -0
  188. package/src/config/assistant-feature-flags.ts +67 -10
  189. package/src/config/bundled-skills/acp/SKILL.md +6 -0
  190. package/src/config/bundled-skills/acp/TOOLS.json +1 -22
  191. package/src/config/bundled-skills/app-builder/SKILL.md +14 -109
  192. package/src/config/bundled-skills/app-builder/TOOLS.json +1 -28
  193. package/src/config/bundled-skills/app-builder/tools/app-create.ts +1 -10
  194. package/src/config/bundled-skills/app-control/SKILL.md +75 -0
  195. package/src/config/bundled-skills/app-control/TOOLS.json +299 -0
  196. package/src/config/bundled-skills/app-control/tools/app-control-click.ts +12 -0
  197. package/src/config/bundled-skills/app-control/tools/app-control-combo.ts +12 -0
  198. package/src/config/bundled-skills/app-control/tools/app-control-drag.ts +12 -0
  199. package/src/config/bundled-skills/app-control/tools/app-control-observe.ts +12 -0
  200. package/src/config/bundled-skills/app-control/tools/app-control-press.ts +12 -0
  201. package/src/config/bundled-skills/app-control/tools/app-control-sequence.ts +12 -0
  202. package/src/config/bundled-skills/app-control/tools/app-control-start.ts +12 -0
  203. package/src/config/bundled-skills/app-control/tools/app-control-stop.ts +12 -0
  204. package/src/config/bundled-skills/app-control/tools/app-control-type.ts +12 -0
  205. package/src/config/bundled-skills/computer-use/SKILL.md +6 -0
  206. package/src/config/bundled-skills/computer-use/TOOLS.json +67 -43
  207. package/src/config/bundled-skills/contacts/TOOLS.json +0 -16
  208. package/src/config/bundled-skills/document/TOOLS.json +0 -8
  209. package/src/config/bundled-skills/followups/TOOLS.json +0 -12
  210. package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
  211. package/src/config/bundled-skills/image-studio/TOOLS.json +0 -4
  212. package/src/config/bundled-skills/media-processing/TOOLS.json +0 -24
  213. package/src/config/bundled-skills/messaging/TOOLS.json +0 -40
  214. package/src/config/bundled-skills/phone-calls/TOOLS.json +0 -12
  215. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +19 -4
  216. package/src/config/bundled-skills/playbooks/TOOLS.json +0 -16
  217. package/src/config/bundled-skills/schedule/TOOLS.json +14 -14
  218. package/src/config/bundled-skills/sequences/TOOLS.json +0 -36
  219. package/src/config/bundled-skills/settings/SKILL.md +4 -0
  220. package/src/config/bundled-skills/settings/TOOLS.json +0 -12
  221. package/src/config/bundled-skills/skill-management/SKILL.md +6 -0
  222. package/src/config/bundled-skills/skill-management/TOOLS.json +0 -8
  223. package/src/config/bundled-skills/subagent/SKILL.md +6 -2
  224. package/src/config/bundled-skills/subagent/TOOLS.json +0 -20
  225. package/src/config/bundled-skills/transcribe/SKILL.md +4 -0
  226. package/src/config/bundled-skills/transcribe/TOOLS.json +0 -4
  227. package/src/config/bundled-tool-registry.ts +21 -0
  228. package/src/config/env-registry.ts +0 -2
  229. package/src/config/env.ts +19 -12
  230. package/src/config/feature-flag-registry.json +21 -133
  231. package/src/config/loader.ts +73 -99
  232. package/src/config/sanitize-for-transfer.ts +2 -0
  233. package/src/config/schemas/__tests__/memory-lifecycle.test.ts +80 -0
  234. package/src/config/schemas/__tests__/memory-v2.test.ts +7 -4
  235. package/src/config/schemas/calls.ts +0 -9
  236. package/src/config/schemas/heartbeat.ts +63 -0
  237. package/src/config/schemas/ingress.ts +10 -6
  238. package/src/config/schemas/llm.ts +5 -10
  239. package/src/config/schemas/memory-lifecycle.ts +77 -24
  240. package/src/config/schemas/memory-v2.ts +48 -4
  241. package/src/config/schemas/platform.ts +6 -0
  242. package/src/config/schemas/services.ts +1 -15
  243. package/src/config/schemas/skills.ts +0 -6
  244. package/src/config/seed-inference-profiles.ts +1 -1
  245. package/src/contacts/contact-store.ts +0 -30
  246. package/src/contacts/contacts-write.ts +0 -27
  247. package/src/context/window-manager.ts +1 -2
  248. package/src/credential-execution/feature-gates.ts +10 -10
  249. package/src/credential-execution/process-manager.ts +12 -41
  250. package/src/daemon/__tests__/conversation-tool-setup.test.ts +126 -5
  251. package/src/daemon/bootstrap-turn-cleanup.ts +45 -0
  252. package/src/daemon/config-watcher.ts +4 -3
  253. package/src/daemon/conversation-agent-loop-handlers.ts +21 -3
  254. package/src/daemon/conversation-agent-loop.ts +32 -28
  255. package/src/daemon/conversation-lifecycle.ts +8 -1
  256. package/src/daemon/conversation-process.ts +16 -11
  257. package/src/daemon/conversation-runtime-assembly.ts +2 -2
  258. package/src/daemon/conversation-surfaces.ts +125 -4
  259. package/src/daemon/conversation-tool-setup.ts +16 -55
  260. package/src/daemon/conversation.ts +21 -2
  261. package/src/daemon/doordash-steps.ts +1 -1
  262. package/src/daemon/handlers/shared.ts +4 -1
  263. package/src/daemon/host-app-control-proxy.ts +293 -0
  264. package/src/daemon/host-bash-proxy.ts +84 -74
  265. package/src/daemon/host-browser-proxy.ts +67 -82
  266. package/src/daemon/host-cu-proxy.ts +81 -86
  267. package/src/daemon/host-file-proxy.ts +93 -69
  268. package/src/daemon/host-proxy-base.ts +294 -0
  269. package/src/daemon/host-proxy-preactivation.ts +82 -0
  270. package/src/daemon/host-transfer-proxy.ts +247 -129
  271. package/src/daemon/lifecycle.ts +115 -117
  272. package/src/daemon/message-protocol.ts +3 -8
  273. package/src/daemon/message-types/contacts.ts +23 -1
  274. package/src/daemon/message-types/conversations.ts +11 -8
  275. package/src/daemon/message-types/host-app-control.ts +150 -0
  276. package/src/daemon/message-types/host-bash.ts +4 -0
  277. package/src/daemon/message-types/host-cu.ts +2 -0
  278. package/src/daemon/message-types/host-file.ts +4 -0
  279. package/src/daemon/message-types/host-transfer.ts +3 -0
  280. package/src/daemon/message-types/schedules.ts +8 -3
  281. package/src/daemon/message-types/skills.ts +2 -2
  282. package/src/daemon/process-message.ts +18 -1
  283. package/src/daemon/shutdown-handlers.ts +0 -3
  284. package/src/daemon/tool-setup-types.ts +51 -0
  285. package/src/daemon/tool-side-effects.ts +1 -1
  286. package/src/events/tool-audit-listener.ts +2 -1
  287. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +15 -7
  288. package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +216 -0
  289. package/src/heartbeat/heartbeat-run-store.ts +236 -0
  290. package/src/heartbeat/heartbeat-service.ts +280 -49
  291. package/src/home/__tests__/post-connect-feed.test.ts +99 -0
  292. package/src/home/__tests__/relationship-state-writer.test.ts +11 -9
  293. package/src/home/__tests__/suggested-prompts.test.ts +89 -0
  294. package/src/home/post-connect-feed.ts +68 -0
  295. package/src/home/relationship-state-writer.ts +17 -92
  296. package/src/home/suggested-prompts.ts +46 -10
  297. package/src/inbound/public-ingress-urls.ts +32 -34
  298. package/src/ipc/__tests__/route-error-envelope.test.ts +80 -0
  299. package/src/ipc/assistant-server.ts +14 -1
  300. package/src/ipc/cli-client.ts +32 -1
  301. package/src/live-voice/live-voice-metrics.ts +10 -10
  302. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +304 -0
  303. package/src/mcp/mcp-auth-orchestrator.ts +213 -0
  304. package/src/mcp/mcp-auth-state.ts +133 -0
  305. package/src/mcp/mcp-oauth-provider.ts +19 -0
  306. package/src/memory/__tests__/jobs-store-job-classes.test.ts +24 -0
  307. package/src/memory/__tests__/qdrant-client-sentinel.test.ts +49 -0
  308. package/src/memory/__tests__/sparse-tokenize.test.ts +66 -0
  309. package/src/memory/anisotropy.test.ts +247 -0
  310. package/src/memory/anisotropy.ts +443 -0
  311. package/src/memory/auto-analysis-constants.ts +17 -0
  312. package/src/memory/auto-analysis-guard.ts +5 -15
  313. package/src/memory/canonical-guardian-store.ts +7 -7
  314. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +122 -0
  315. package/src/memory/context-search/agent-protocol.ts +6 -6
  316. package/src/memory/context-search/agent-runner.ts +32 -7
  317. package/src/memory/context-search/sources/memory-v2.ts +17 -5
  318. package/src/memory/conversation-crud.ts +1 -1
  319. package/src/memory/conversation-key-store.ts +2 -15
  320. package/src/memory/db-init.ts +4 -0
  321. package/src/memory/embedding-backend.ts +9 -21
  322. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +49 -4
  323. package/src/memory/graph/conversation-graph-memory.ts +1 -24
  324. package/src/memory/graph/graph-search.ts +8 -0
  325. package/src/memory/graph/retriever.ts +28 -0
  326. package/src/memory/graph/tools.ts +1 -1
  327. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +8 -2
  328. package/src/memory/jobs/embed-concept-page.ts +28 -2
  329. package/src/memory/jobs/embed-pkb-file.test.ts +2 -2
  330. package/src/memory/jobs-store.ts +66 -22
  331. package/src/memory/jobs-worker.ts +112 -63
  332. package/src/memory/memory-v2-activation-log-store.ts +1 -1
  333. package/src/memory/migrations/237-heartbeat-runs.ts +45 -0
  334. package/src/memory/migrations/238-schedule-retry-policy.ts +20 -0
  335. package/src/memory/migrations/index.ts +5 -0
  336. package/src/memory/migrations/registry.ts +8 -0
  337. package/src/memory/pkb/pkb-search.ts +7 -0
  338. package/src/memory/qdrant-client.ts +50 -20
  339. package/src/memory/schema/infrastructure.ts +15 -0
  340. package/src/memory/search/semantic.ts +7 -0
  341. package/src/memory/sparse-tokenize.ts +49 -0
  342. package/src/memory/v2/__tests__/activation.test.ts +77 -95
  343. package/src/memory/v2/__tests__/injection.test.ts +43 -21
  344. package/src/memory/v2/__tests__/sim.test.ts +166 -6
  345. package/src/memory/v2/__tests__/sparse-bm25.test.ts +292 -0
  346. package/src/memory/v2/__tests__/static-context.test.ts +0 -1
  347. package/src/memory/v2/activation.ts +69 -88
  348. package/src/memory/v2/consolidation-job.ts +3 -5
  349. package/src/memory/v2/constants.ts +7 -0
  350. package/src/memory/v2/injection.ts +86 -53
  351. package/src/memory/v2/prompts/consolidation.ts +312 -91
  352. package/src/memory/v2/qdrant.ts +99 -1
  353. package/src/memory/v2/sim.ts +126 -16
  354. package/src/memory/v2/skill-qdrant.ts +12 -3
  355. package/src/memory/v2/skill-store.ts +16 -1
  356. package/src/memory/v2/sparse-bm25.ts +245 -0
  357. package/src/memory/v2/static-context.ts +6 -5
  358. package/src/messaging/providers/gmail/types.ts +0 -49
  359. package/src/messaging/providers/slack/adapter.ts +1 -31
  360. package/src/messaging/providers/slack/types.ts +0 -32
  361. package/src/notifications/README.md +10 -10
  362. package/src/notifications/broadcaster.ts +1 -1
  363. package/src/notifications/guardian-question-mode.ts +5 -5
  364. package/src/oauth/connect-orchestrator.ts +4 -0
  365. package/src/oauth/credential-token-resolver.ts +1 -3
  366. package/src/oauth/manual-token-connection.ts +0 -4
  367. package/src/outbound-proxy/index.ts +1 -37
  368. package/src/outbound-proxy/logging.ts +1 -1
  369. package/src/outbound-proxy/policy.ts +6 -5
  370. package/src/outbound-proxy/router.ts +2 -1
  371. package/src/permissions/approval-policy.test.ts +6 -275
  372. package/src/permissions/approval-policy.ts +0 -51
  373. package/src/permissions/checker.test.ts +0 -1
  374. package/src/permissions/checker.ts +3 -17
  375. package/src/permissions/gateway-threshold-reader.ts +2 -0
  376. package/src/permissions/prompter.ts +34 -1
  377. package/src/permissions/secret-prompter.ts +6 -2
  378. package/src/prompts/bootstrap-cleanup.ts +27 -0
  379. package/src/prompts/system-prompt.ts +3 -18
  380. package/src/prompts/templates/SOUL.md +13 -1
  381. package/src/providers/speech-to-text/provider-catalog.ts +7 -8
  382. package/src/runtime/assistant-event-hub.ts +118 -96
  383. package/src/runtime/assistant-event.ts +1 -0
  384. package/src/runtime/auth/__tests__/middleware.test.ts +11 -56
  385. package/src/runtime/auth/middleware.ts +0 -96
  386. package/src/runtime/auth/route-policy.ts +19 -0
  387. package/src/runtime/btw-sidechain.ts +2 -3
  388. package/src/runtime/channel-invite-transport.ts +2 -48
  389. package/src/runtime/channel-invite-transports/email.ts +1 -1
  390. package/src/runtime/channel-invite-transports/slack.ts +1 -1
  391. package/src/runtime/channel-invite-transports/telegram.ts +1 -1
  392. package/src/runtime/channel-invite-transports/voice.ts +1 -1
  393. package/src/runtime/channel-invite-transports/whatsapp.ts +1 -1
  394. package/src/runtime/channel-invite-types.ts +54 -0
  395. package/src/runtime/channel-readiness-service.ts +32 -13
  396. package/src/runtime/http-server.ts +3 -329
  397. package/src/runtime/http-types.ts +0 -5
  398. package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +413 -0
  399. package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +260 -0
  400. package/src/runtime/migrations/__tests__/vbundle-import-version-compat.test.ts +189 -0
  401. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +153 -1
  402. package/src/runtime/migrations/__tests__/vbundle-symlink-importer.test.ts +451 -0
  403. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
  404. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming.test.ts +515 -0
  405. package/src/runtime/migrations/__tests__/vbundle-symlink-tar.test.ts +437 -0
  406. package/src/runtime/migrations/__tests__/vbundle-symlink-walker.test.ts +319 -0
  407. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +51 -1
  408. package/src/runtime/migrations/migration-transport.ts +7 -7
  409. package/src/runtime/migrations/vbundle-builder.ts +327 -60
  410. package/src/runtime/migrations/vbundle-import-analyzer.ts +4 -4
  411. package/src/runtime/migrations/vbundle-import-policy.ts +172 -0
  412. package/src/runtime/migrations/vbundle-importer.ts +245 -68
  413. package/src/runtime/migrations/vbundle-streaming-importer.ts +326 -35
  414. package/src/runtime/migrations/vbundle-streaming-validator.ts +157 -4
  415. package/src/runtime/migrations/vbundle-tar-stream.ts +15 -6
  416. package/src/runtime/migrations/vbundle-validator.ts +114 -0
  417. package/src/runtime/pending-interactions.ts +35 -9
  418. package/src/runtime/routes/__tests__/backup-routes.test.ts +22 -150
  419. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -0
  420. package/src/runtime/routes/__tests__/gateway-log-routes.test.ts +242 -0
  421. package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +112 -0
  422. package/src/runtime/routes/approval-interception-types.ts +13 -0
  423. package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +1 -1
  424. package/src/runtime/routes/backup-routes.ts +15 -38
  425. package/src/runtime/routes/btw-routes.ts +14 -37
  426. package/src/runtime/routes/client-routes.ts +1 -0
  427. package/src/runtime/routes/contact-prompt-routes.ts +183 -0
  428. package/src/runtime/routes/conversation-query-routes.ts +36 -1
  429. package/src/runtime/routes/conversation-routes.ts +30 -13
  430. package/src/runtime/routes/document-pdf-renderer.ts +165 -0
  431. package/src/runtime/routes/documents-routes.ts +30 -0
  432. package/src/runtime/routes/errors.ts +19 -4
  433. package/src/runtime/routes/events-routes.ts +12 -6
  434. package/src/runtime/routes/gateway-log-routes.ts +79 -0
  435. package/src/runtime/routes/guardian-approval-interception.ts +2 -8
  436. package/src/runtime/routes/heartbeat-routes.ts +103 -38
  437. package/src/runtime/routes/host-app-control-routes.ts +134 -0
  438. package/src/runtime/routes/host-bash-routes.ts +36 -6
  439. package/src/runtime/routes/host-browser-routes.ts +108 -13
  440. package/src/runtime/routes/host-cu-routes.ts +44 -14
  441. package/src/runtime/routes/host-file-routes.ts +33 -10
  442. package/src/runtime/routes/host-transfer-routes.ts +64 -24
  443. package/src/runtime/routes/http-adapter.ts +1 -0
  444. package/src/runtime/routes/identity-intro-cache.ts +30 -0
  445. package/src/runtime/routes/identity-routes.ts +15 -43
  446. package/src/runtime/routes/inbound-message-handler.ts +1 -9
  447. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -7
  448. package/src/runtime/routes/inbound-stages/edit-intercept.ts +0 -8
  449. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +0 -20
  450. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +5 -13
  451. package/src/runtime/routes/index.ts +8 -0
  452. package/src/runtime/routes/mcp-auth-routes.ts +132 -0
  453. package/src/runtime/routes/memory-item-routes.ts +10 -12
  454. package/src/runtime/routes/memory-v2-routes.ts +441 -1
  455. package/src/runtime/routes/migration-routes.ts +96 -0
  456. package/src/runtime/routes/schedule-routes.ts +7 -0
  457. package/src/runtime/verification-templates.ts +4 -7
  458. package/src/schedule/integration-status.ts +66 -2
  459. package/src/schedule/recurrence-engine.ts +4 -1
  460. package/src/schedule/retry-backoff.ts +18 -0
  461. package/src/schedule/retry-policy.ts +82 -0
  462. package/src/schedule/schedule-recovery.ts +64 -0
  463. package/src/schedule/schedule-store.ts +106 -2
  464. package/src/schedule/scheduler-types.ts +25 -0
  465. package/src/schedule/scheduler.ts +63 -38
  466. package/src/security/oauth-callback-registry.ts +8 -0
  467. package/src/sequence/analytics.ts +5 -5
  468. package/src/sequence/engine.ts +1 -1
  469. package/src/skills/catalog-files.ts +2 -8
  470. package/src/skills/include-graph.ts +5 -5
  471. package/src/skills/remote-skill-policy.ts +5 -5
  472. package/src/skills/skill-file-provider.ts +1 -1
  473. package/src/skills/skill-file-types.ts +13 -0
  474. package/src/skills/skillssh-audit-types.ts +28 -0
  475. package/src/skills/skillssh-registry.ts +8 -21
  476. package/src/telemetry/types.ts +2 -0
  477. package/src/telemetry/usage-telemetry-reporter.test.ts +21 -0
  478. package/src/telemetry/usage-telemetry-reporter.ts +1 -0
  479. package/src/tools/app-control/skill-proxy-bridge.ts +28 -0
  480. package/src/tools/apps/executors.ts +56 -69
  481. package/src/tools/browser/__tests__/browser-status.test.ts +21 -18
  482. package/src/tools/browser/browser-execution.ts +2 -2
  483. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +55 -4
  484. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +12 -6
  485. package/src/tools/browser/cdp-client/factory.ts +23 -24
  486. package/src/tools/browser/cdp-client/index.ts +1 -14
  487. package/src/tools/computer-use/definitions.ts +42 -20
  488. package/src/tools/executor.ts +2 -0
  489. package/src/tools/host-filesystem/edit.ts +26 -0
  490. package/src/tools/host-filesystem/read.ts +26 -0
  491. package/src/tools/host-filesystem/transfer.ts +31 -1
  492. package/src/tools/host-filesystem/write.ts +26 -0
  493. package/src/tools/host-terminal/host-shell.ts +58 -0
  494. package/src/tools/schedule/create.ts +6 -0
  495. package/src/tools/schedule/list.ts +2 -0
  496. package/src/tools/schedule/update.ts +10 -0
  497. package/src/tools/shared/filesystem/file-ops-service.ts +2 -0
  498. package/src/tools/shared/filesystem/path-policy.ts +25 -1
  499. package/src/tools/skills/load.ts +0 -32
  500. package/src/tools/tool-approval-handler.ts +1 -5
  501. package/src/tools/types.ts +4 -0
  502. package/src/usage/pricing.ts +1 -1
  503. package/src/workspace/hatched-date.ts +86 -0
  504. package/src/workspace/migrations/003-seed-device-id.ts +1 -1
  505. package/src/workspace/migrations/006-services-config.ts +8 -5
  506. package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +3 -9
  507. package/src/workspace/migrations/021-move-signals-to-workspace.ts +4 -10
  508. package/src/workspace/migrations/022-move-hooks-to-workspace.ts +4 -10
  509. package/src/workspace/migrations/023-move-config-files-to-workspace.ts +4 -11
  510. package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +3 -10
  511. package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +3 -2
  512. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +2 -1
  513. package/src/workspace/migrations/059-move-pid-to-workspace.ts +3 -8
  514. package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +3 -8
  515. package/src/workspace/migrations/AGENTS.md +1 -1
  516. package/src/workspace/migrations/migrate-to-workspace-volume.ts +4 -10
  517. package/src/workspace/migrations/utils.ts +21 -0
  518. package/src/__tests__/host-browser-e2e-cloud.test.ts +0 -443
  519. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +0 -226
  520. package/src/__tests__/host-browser-ws-events-e2e.test.ts +0 -427
  521. package/src/__tests__/twilio-rest.test.ts +0 -34
  522. package/src/backup/__tests__/backup-key.test.ts +0 -152
  523. package/src/backup/__tests__/backup-worker.test.ts +0 -782
  524. package/src/backup/__tests__/offsite-writer.test.ts +0 -641
  525. package/src/backup/__tests__/stream-crypt.test.ts +0 -228
  526. package/src/backup/backup-key.ts +0 -137
  527. package/src/backup/backup-worker.ts +0 -472
  528. package/src/backup/offsite-writer.ts +0 -222
  529. package/src/backup/stream-crypt.ts +0 -263
  530. package/src/daemon/message-types/pairing.ts +0 -58
  531. package/src/outbound-proxy/config.ts +0 -20
  532. package/src/outbound-proxy/health.ts +0 -18
  533. package/src/outbound-proxy/types.ts +0 -150
  534. package/src/runtime/capability-tokens.ts +0 -190
  535. package/src/signals/mcp-reload.ts +0 -18
@@ -1,116 +1,56 @@
1
1
  /**
2
- * High-level helpers for restoring and verifying backup snapshots produced
3
- * by the backup pipeline.
2
+ * High-level helpers for restoring and verifying backup snapshots.
4
3
  *
5
- * A snapshot is one of:
6
- * - A plaintext `.vbundle` file (gzipped tar see `vbundle-builder.ts`).
7
- * - An encrypted `.vbundle.enc` file produced by `stream-crypt.encryptFile`.
4
+ * Only plaintext `.vbundle` files are supported directly. Encrypted
5
+ * `.vbundle.enc` files must be restored through the gateway, which owns the
6
+ * backup encryption key (ATL-397).
8
7
  *
9
- * The encryption status is detected purely from the file extension:
10
- * - `.vbundle.enc` encrypted (decryption key required)
11
- * - `.vbundle` → plaintext
12
- *
13
- * For encrypted snapshots, this module decrypts to a temporary file under the
14
- * OS temp directory, runs validation, and then either commits the import or
15
- * just reports validation status. The temp file is always cleaned up — on
16
- * success and on failure — via a `try { ... } finally { unlink }` block.
17
- *
18
- * Restore is intentionally a thin wrapper around the existing
19
- * `commitImport` flow in `runtime/migrations/vbundle-importer.ts`. That
20
- * function handles bundle validation, workspace clearing, per-file
21
- * backup-before-overwrite, and writing files to disk.
8
+ * Restore is a thin wrapper around `commitImport` in
9
+ * `runtime/migrations/vbundle-importer.ts`, which handles bundle validation,
10
+ * workspace clearing, per-file backup-before-overwrite, and writing files.
22
11
  *
23
12
  * `restoreFromSnapshot` closes the live SQLite singleton via `resetDb()`
24
- * immediately before the commit step so the daemon's DB handle is released
25
- * before `assistant.db` is overwritten on disk. This mirrors the pattern in
26
- * `handleMigrationImport` and ensures both the HTTP restore path and any
27
- * in-process CLI caller get the reset for free. Tests can inject a fake via
28
- * `opts.resetDbImpl`.
29
- *
30
- * `commitImport` does NOT invalidate cached config. Callers are responsible
31
- * for calling `invalidateConfigCache()` AFTER a successful restore so the
32
- * daemon re-reads the restored `config.json` instead of serving stale
33
- * in-process caches. A daemon restart is the simplest recovery path.
13
+ * before the commit step so the daemon's DB handle is released before
14
+ * `assistant.db` is overwritten on disk.
34
15
  *
35
16
  * Credentials are intentionally excluded from backups — they live in the OS
36
- * keychain / CES and are not restored by this path. Users re-authenticate
37
- * integrations after a restore.
17
+ * keychain / CES and are not restored by this path.
38
18
  */
39
19
 
40
- import { randomUUID } from "node:crypto";
41
- import { readFile, unlink } from "node:fs/promises";
42
- import { tmpdir } from "node:os";
43
- import { join } from "node:path";
20
+ import { readFile } from "node:fs/promises";
44
21
 
45
22
  import { resetDb } from "../memory/db-connection.js";
46
23
  import type { PathResolver } from "../runtime/migrations/vbundle-import-analyzer.js";
24
+ import {
25
+ evaluateRuntimeCompatibility,
26
+ formatRuntimeCompatibilityMessage,
27
+ } from "../runtime/migrations/vbundle-import-policy.js";
47
28
  import { commitImport } from "../runtime/migrations/vbundle-importer.js";
48
29
  import type { ManifestType } from "../runtime/migrations/vbundle-validator.js";
49
30
  import { validateVBundle } from "../runtime/migrations/vbundle-validator.js";
50
- import { decryptFile } from "./stream-crypt.js";
31
+ import { APP_VERSION } from "../version.js";
51
32
 
52
33
  // ---------------------------------------------------------------------------
53
34
  // Public types
54
35
  // ---------------------------------------------------------------------------
55
36
 
56
- /**
57
- * Optional injection point for the underlying commit function. Tests pass a
58
- * fake here to avoid running the destructive `commitImport` flow against the
59
- * live workspace. Production callers should leave this unset so the real
60
- * importer is used.
61
- */
62
37
  type CommitImpl = typeof commitImport;
63
38
 
64
39
  interface RestoreOptions {
65
- /** AES-256 decryption key. Required for `.vbundle.enc` snapshots. */
66
- key?: Buffer;
67
- /**
68
- * Resolver that maps archive paths (e.g. `workspace/config.json`) to
69
- * absolute disk paths. Required by the underlying `commitImport` flow.
70
- */
71
40
  pathResolver: PathResolver;
72
- /**
73
- * Absolute path to the workspace directory. When set and the bundle
74
- * contains `workspace/` entries, `commitImport` clears the workspace
75
- * before writing to ensure an exact-match restore.
76
- */
77
41
  workspaceDir?: string;
78
- /**
79
- * Optional override for the underlying commit function. Tests inject a
80
- * fake to avoid mutating disk; production callers should leave this unset.
81
- */
82
42
  commitImpl?: CommitImpl;
83
- /**
84
- * Optional override for the DB-reset hook. Invoked immediately before
85
- * `commitImpl` so the live SQLite singleton is closed before
86
- * `assistant.db` is overwritten. Tests inject a spy; production callers
87
- * should leave this unset so the real `resetDb` is used.
88
- */
89
43
  resetDbImpl?: () => void;
90
44
  }
91
45
 
92
46
  export interface RestoreResult {
93
- /** Manifest from the bundle that was restored. */
94
47
  manifest: ManifestType;
95
- /** Number of files written (or skipped) by the underlying commit. */
96
48
  restoredFiles: number;
97
49
  }
98
50
 
99
- interface VerifyOptions {
100
- /** AES-256 decryption key. Required for `.vbundle.enc` snapshots. */
101
- key?: Buffer;
102
- }
103
-
104
51
  export interface VerifyResult {
105
- /** True iff the bundle decrypts (when applicable) and validates. */
106
52
  valid: boolean;
107
- /** Manifest from the bundle when `valid` is true. */
108
53
  manifest?: ManifestType;
109
- /**
110
- * Human-readable error message when `valid` is false. Populated for
111
- * validation failures, decryption failures, and missing-file errors.
112
- * Always undefined when `valid` is true.
113
- */
114
54
  error?: string;
115
55
  }
116
56
 
@@ -118,201 +58,137 @@ export interface VerifyResult {
118
58
  // Internal helpers
119
59
  // ---------------------------------------------------------------------------
120
60
 
121
- /** Returns true if the snapshot path indicates an encrypted bundle. */
122
61
  function isEncryptedSnapshot(snapshotPath: string): boolean {
123
62
  return snapshotPath.endsWith(".vbundle.enc");
124
63
  }
125
64
 
126
- /** Build a unique temp path for a decrypted bundle. */
127
- function makeDecryptedTempPath(): string {
128
- return join(tmpdir(), `vellum-restore-${randomUUID()}.vbundle`);
129
- }
130
-
131
- /**
132
- * Resolve `snapshotPath` to a path that holds plaintext `.vbundle` bytes.
133
- *
134
- * For plaintext snapshots, this just returns `{ path: snapshotPath }`. For
135
- * encrypted snapshots, it decrypts to a fresh temp file and returns
136
- * `{ path: tmpPath, tmpPath }` so the caller can clean up afterwards.
137
- *
138
- * Throws when an encrypted bundle has no key, when `decryptFile` fails
139
- * (bad key, tampered ciphertext, truncated file), or on any I/O error.
140
- */
141
- async function materializePlaintext(
142
- snapshotPath: string,
143
- key: Buffer | undefined,
144
- ): Promise<{ path: string; tmpPath: string | null }> {
145
- if (!isEncryptedSnapshot(snapshotPath)) {
146
- return { path: snapshotPath, tmpPath: null };
147
- }
148
-
149
- if (!key) {
150
- throw new Error("Encrypted snapshot requires a decryption key");
151
- }
152
-
153
- const tmpPath = makeDecryptedTempPath();
154
- await decryptFile(snapshotPath, tmpPath, key);
155
- return { path: tmpPath, tmpPath };
156
- }
157
-
158
- /** Best-effort temp file cleanup — swallows ENOENT and other errors. */
159
- async function safeUnlink(path: string | null): Promise<void> {
160
- if (!path) return;
161
- try {
162
- await unlink(path);
163
- } catch {
164
- // Best-effort — temp file may already be gone.
165
- }
166
- }
167
-
168
65
  // ---------------------------------------------------------------------------
169
66
  // Public API
170
67
  // ---------------------------------------------------------------------------
171
68
 
172
69
  /**
173
- * Restore a backup snapshot into the workspace.
174
- *
175
- * Auto-detects encryption from the file extension. Encrypted snapshots
176
- * (`.vbundle.enc`) decrypt to a temp file under `tmpdir()` before
177
- * validation; the temp file is unlinked in a `finally` block so it never
178
- * lingers, even on validation or commit failure.
70
+ * Restore a plaintext backup snapshot into the workspace.
179
71
  *
180
- * The actual restore is delegated to `commitImport`, which owns the
181
- * backup-before-overwrite, workspace-clearing, and integrity-check logic.
182
- * Tests can pass `opts.commitImpl` to substitute a fake without mutating
183
- * the live workspace.
72
+ * Encrypted `.vbundle.enc` snapshots are rejected use the gateway's
73
+ * restore endpoint for those.
184
74
  */
185
75
  export async function restoreFromSnapshot(
186
76
  snapshotPath: string,
187
77
  opts: RestoreOptions,
188
78
  ): Promise<RestoreResult> {
79
+ if (isEncryptedSnapshot(snapshotPath)) {
80
+ throw new Error(
81
+ "Encrypted snapshot restore must go through the gateway, which owns the backup key. " +
82
+ "Use the gateway's restore endpoint instead.",
83
+ );
84
+ }
85
+
189
86
  const {
190
- key,
191
87
  pathResolver,
192
88
  workspaceDir,
193
89
  commitImpl = commitImport,
194
90
  resetDbImpl = resetDb,
195
91
  } = opts;
196
92
 
197
- let tmpPath: string | null = null;
198
- try {
199
- const materialized = await materializePlaintext(snapshotPath, key);
200
- tmpPath = materialized.tmpPath;
201
-
202
- // Read plaintext bytes for validation + commit. validateVBundle takes
203
- // raw bytes (Uint8Array) — file paths are not part of its API.
204
- const fileData = await readFile(materialized.path);
93
+ const fileData = await readFile(snapshotPath);
205
94
 
206
- const validation = validateVBundle(fileData);
207
- if (!validation.is_valid || !validation.manifest || !validation.entries) {
208
- const summary = validation.errors
209
- .map((e) => `${e.code}: ${e.message}`)
210
- .join("; ");
211
- throw new Error(`Snapshot failed validation: ${summary}`);
212
- }
95
+ const validation = validateVBundle(fileData);
96
+ if (!validation.is_valid || !validation.manifest || !validation.entries) {
97
+ const summary = validation.errors
98
+ .map((e) => `${e.code}: ${e.message}`)
99
+ .join("; ");
100
+ throw new Error(`Snapshot failed validation: ${summary}`);
101
+ }
213
102
 
214
- // Close the live SQLite singleton before overwriting assistant.db on
215
- // disk otherwise the daemon keeps a handle to the old inode and
216
- // subsequent writes can corrupt the restored state. Mirrors the
217
- // pattern in `handleMigrationImport`. The singleton will be lazily
218
- // reopened on the next getDb() call.
219
- resetDbImpl();
103
+ // Pre-check runtime-version compat before the DB close/reopen cycle.
104
+ // commitImport runs the same gate as defense-in-depth for callers that
105
+ // don't pre-check; we run it here too so an incompatible bundle short-
106
+ // circuits before resetDbImpl().
107
+ const compatResult = evaluateRuntimeCompatibility(
108
+ validation.manifest.compatibility,
109
+ APP_VERSION,
110
+ );
111
+ if (!compatResult.ok) {
112
+ throw new Error(
113
+ `Snapshot restore failed: ${formatRuntimeCompatibilityMessage(
114
+ compatResult.bundle_compat,
115
+ compatResult.runtime_version,
116
+ )}`,
117
+ );
118
+ }
220
119
 
221
- const commitResult = commitImpl({
222
- archiveData: fileData,
223
- pathResolver,
224
- preValidatedManifest: validation.manifest,
225
- preValidatedEntries: validation.entries,
226
- workspaceDir,
227
- });
120
+ resetDbImpl();
228
121
 
229
- if (!commitResult.ok) {
230
- // Surface a single error message regardless of which discriminated
231
- // branch failed — callers in the backup CLI just want a message.
232
- let message: string;
233
- switch (commitResult.reason) {
234
- case "validation_failed":
235
- message = commitResult.errors
236
- .map((e) => `${e.code}: ${e.message}`)
237
- .join("; ");
238
- break;
239
- case "extraction_failed":
240
- case "write_failed":
241
- message = commitResult.message;
242
- break;
243
- }
244
- throw new Error(`Snapshot restore failed: ${message}`);
122
+ const commitResult = commitImpl({
123
+ archiveData: fileData,
124
+ pathResolver,
125
+ preValidatedManifest: validation.manifest,
126
+ preValidatedEntries: validation.entries,
127
+ workspaceDir,
128
+ });
129
+
130
+ if (!commitResult.ok) {
131
+ let message: string;
132
+ switch (commitResult.reason) {
133
+ case "validation_failed":
134
+ message = commitResult.errors
135
+ .map((e) => `${e.code}: ${e.message}`)
136
+ .join("; ");
137
+ break;
138
+ case "extraction_failed":
139
+ case "write_failed":
140
+ message = commitResult.message;
141
+ break;
142
+ case "version_incompatible":
143
+ message = formatRuntimeCompatibilityMessage(
144
+ commitResult.bundle_compat,
145
+ commitResult.runtime_version,
146
+ );
147
+ break;
245
148
  }
246
-
247
- return {
248
- manifest: commitResult.report.manifest,
249
- restoredFiles: commitResult.report.summary.total_files,
250
- };
251
- } finally {
252
- await safeUnlink(tmpPath);
149
+ throw new Error(`Snapshot restore failed: ${message}`);
253
150
  }
151
+
152
+ return {
153
+ manifest: commitResult.report.manifest,
154
+ restoredFiles: commitResult.report.summary.total_files,
155
+ };
254
156
  }
255
157
 
256
158
  /**
257
159
  * Verify a backup snapshot without restoring it.
258
160
  *
259
- * Auto-detects encryption from the file extension and decrypts to a temp
260
- * file when needed (cleaned up in a `finally` block). Runs the same
261
- * `validateVBundle` checks the importer would run, but never touches the
262
- * workspace.
263
- *
264
- * Does NOT throw on validation or decryption failure — those are returned
265
- * as `{ valid: false, error: ... }`. Only the missing-key precondition
266
- * for encrypted bundles throws, since that is a programmer error.
161
+ * Only plaintext `.vbundle` files are supported. Encrypted snapshots must be
162
+ * verified through the gateway.
267
163
  */
268
164
  export async function verifySnapshot(
269
165
  snapshotPath: string,
270
- opts: VerifyOptions,
271
166
  ): Promise<VerifyResult> {
272
- const { key } = opts;
273
-
274
- // Encrypted bundles must have a key — this is a precondition error,
275
- // not a validation failure, so we throw rather than return.
276
- if (isEncryptedSnapshot(snapshotPath) && !key) {
277
- throw new Error("Encrypted snapshot requires a decryption key");
167
+ if (isEncryptedSnapshot(snapshotPath)) {
168
+ return {
169
+ valid: false,
170
+ error:
171
+ "Encrypted snapshot verification must go through the gateway, which owns the backup key.",
172
+ };
278
173
  }
279
174
 
280
- let tmpPath: string | null = null;
175
+ let fileData: Uint8Array;
281
176
  try {
282
- let plaintextPath: string;
283
- try {
284
- const materialized = await materializePlaintext(snapshotPath, key);
285
- tmpPath = materialized.tmpPath;
286
- plaintextPath = materialized.path;
287
- } catch (err) {
288
- // Decryption / I/O failure — surface as a soft error so verification
289
- // callers (e.g. snapshot list health checks) get a uniform shape.
290
- return {
291
- valid: false,
292
- error: err instanceof Error ? err.message : String(err),
293
- };
294
- }
295
-
296
- let fileData: Uint8Array;
297
- try {
298
- fileData = await readFile(plaintextPath);
299
- } catch (err) {
300
- return {
301
- valid: false,
302
- error: err instanceof Error ? err.message : String(err),
303
- };
304
- }
305
-
306
- const validation = validateVBundle(fileData);
307
- if (!validation.is_valid || !validation.manifest) {
308
- const summary = validation.errors
309
- .map((e) => `${e.code}: ${e.message}`)
310
- .join("; ");
311
- return { valid: false, error: summary };
312
- }
177
+ fileData = await readFile(snapshotPath);
178
+ } catch (err) {
179
+ return {
180
+ valid: false,
181
+ error: err instanceof Error ? err.message : String(err),
182
+ };
183
+ }
313
184
 
314
- return { valid: true, manifest: validation.manifest };
315
- } finally {
316
- await safeUnlink(tmpPath);
185
+ const validation = validateVBundle(fileData);
186
+ if (!validation.is_valid || !validation.manifest) {
187
+ const summary = validation.errors
188
+ .map((e) => `${e.code}: ${e.message}`)
189
+ .join("; ");
190
+ return { valid: false, error: summary };
317
191
  }
192
+
193
+ return { valid: true, manifest: validation.manifest };
318
194
  }
@@ -17,6 +17,7 @@ import JSZip from "jszip";
17
17
  import { getApp, getAppDirPath, isMultifileApp } from "../memory/app-store.js";
18
18
  import { computeContentId } from "../util/content-id.js";
19
19
  import { getLogger } from "../util/logger.js";
20
+ import { APP_VERSION } from "../version.js";
20
21
  import { compileApp } from "./app-compiler.js";
21
22
  import type { SigningCallback } from "./bundle-signer.js";
22
23
  import { signBundle } from "./bundle-signer.js";
@@ -25,7 +26,6 @@ import { serializeManifest } from "./manifest.js";
25
26
 
26
27
  const bundlerLog = getLogger("app-bundler");
27
28
 
28
- import { APP_VERSION } from "../version.js";
29
29
  const PACKAGE_VERSION = APP_VERSION;
30
30
 
31
31
  const MAX_BUNDLE_SIZE_BYTES = 25 * 1024 * 1024; // 25 MB
@@ -37,6 +37,45 @@ export interface BundleResult {
37
37
  iconImageBase64?: string;
38
38
  }
39
39
 
40
+ function isDefaultMainScaffold(source: string): boolean {
41
+ const normalized = source.replace(/\s+/g, " ").trim();
42
+ return (
43
+ normalized.startsWith(
44
+ `import { render } from 'preact'; function App() { return <div>{"Hello, `,
45
+ ) &&
46
+ normalized.endsWith(
47
+ `!"}</div>; } render(<App />, document.getElementById('app')!);`,
48
+ )
49
+ );
50
+ }
51
+
52
+ function assertMultifileSourceReady(
53
+ app: { name: string },
54
+ appDir: string,
55
+ ): void {
56
+ const srcIndexPath = join(appDir, "src", "index.html");
57
+ const srcMainPath = join(appDir, "src", "main.tsx");
58
+ const missing = [
59
+ !existsSync(srcIndexPath) ? "src/index.html" : null,
60
+ !existsSync(srcMainPath) ? "src/main.tsx" : null,
61
+ ].filter((value): value is string => value !== null);
62
+
63
+ if (missing.length > 0) {
64
+ throw new Error(
65
+ `App "${app.name}" is a multi-file TSX app but is missing ${missing.join(
66
+ " and ",
67
+ )}. Write source files under src/ and call app_refresh before sharing.`,
68
+ );
69
+ }
70
+
71
+ const mainSource = readFileSync(srcMainPath, "utf-8");
72
+ if (isDefaultMainScaffold(mainSource)) {
73
+ throw new Error(
74
+ `App "${app.name}" still has the default src/main.tsx scaffold. Write the real multi-file TSX source and call app_refresh before sharing.`,
75
+ );
76
+ }
77
+ }
78
+
40
79
  /**
41
80
  * Package an app into a .vellum zip archive.
42
81
  *
@@ -82,6 +121,8 @@ export async function packageApp(
82
121
  const appDir = getAppDirPath(appId);
83
122
 
84
123
  if (multifile) {
124
+ assertMultifileSourceReady(app, appDir);
125
+
85
126
  // Multi-file TSX app: compile src/ -> dist/
86
127
  const compileResult = await compileApp(appDir);
87
128
  if (!compileResult.ok) {
@@ -97,8 +138,15 @@ export async function packageApp(
97
138
  }
98
139
 
99
140
  const distDir = join(appDir, "dist");
100
- const indexHtml = await readFile(join(distDir, "index.html"), "utf-8");
101
- const mainJs = await readFile(join(distDir, "main.js"));
141
+ const distIndexPath = join(distDir, "index.html");
142
+ const distMainPath = join(distDir, "main.js");
143
+ if (!existsSync(distIndexPath) || !existsSync(distMainPath)) {
144
+ throw new Error(
145
+ `Compilation for app "${app.name}" did not produce dist/index.html and dist/main.js. Check src/index.html and src/main.tsx, then call app_refresh.`,
146
+ );
147
+ }
148
+ const indexHtml = await readFile(distIndexPath, "utf-8");
149
+ const mainJs = await readFile(distMainPath);
102
150
 
103
151
  compiledFiles.push({ name: "index.html", data: Buffer.from(indexHtml) });
104
152
  compiledFiles.push({ name: "main.js", data: mainJs });
@@ -14,10 +14,6 @@ import {
14
14
  findGuardianForChannel,
15
15
  listGuardianChannels,
16
16
  } from "../contacts/contact-store.js";
17
- import {
18
- touchContactInteraction,
19
- upsertContactChannel,
20
- } from "../contacts/contacts-write.js";
21
17
  import { getAssistantName } from "../daemon/identity-helpers.js";
22
18
  import type { ServerMessage } from "../daemon/message-protocol.js";
23
19
  import { getCanonicalGuardianRequest } from "../memory/canonical-guardian-store.js";
@@ -615,13 +611,6 @@ export class RelayConnection {
615
611
  this.startNameCapture(outcome.assistantId, outcome.fromNumber);
616
612
  return;
617
613
  case "verification":
618
- if (
619
- resolved.actorTrust.memberRecord &&
620
- (resolved.actorTrust.trustClass === "guardian" ||
621
- resolved.actorTrust.trustClass === "trusted_contact")
622
- ) {
623
- touchContactInteraction(resolved.actorTrust.memberRecord.channel.id);
624
- }
625
614
  if (this.controller && resolved.actorTrust.trustClass !== "unknown") {
626
615
  this.controller.setTrustContext(
627
616
  toTrustContext(resolved.actorTrust, msg.from),
@@ -631,15 +620,6 @@ export class RelayConnection {
631
620
  return;
632
621
  case "normal_call":
633
622
  if (outcome.isInbound) {
634
- if (
635
- resolved.actorTrust.memberRecord &&
636
- (resolved.actorTrust.trustClass === "guardian" ||
637
- resolved.actorTrust.trustClass === "trusted_contact")
638
- ) {
639
- touchContactInteraction(
640
- resolved.actorTrust.memberRecord.channel.id,
641
- );
642
- }
643
623
  if (this.controller && resolved.actorTrust.trustClass !== "unknown") {
644
624
  this.controller.setTrustContext(
645
625
  toTrustContext(resolved.actorTrust, msg.from),
@@ -796,8 +776,6 @@ export class RelayConnection {
796
776
  private continueCallAfterTrustedContactActivation(params: {
797
777
  assistantId: string;
798
778
  fromNumber: string;
799
- callerName?: string;
800
- skipMemberActivation?: boolean;
801
779
  activationReason?:
802
780
  | "invite_redeemed"
803
781
  | "access_approved"
@@ -805,25 +783,10 @@ export class RelayConnection {
805
783
  friendName?: string;
806
784
  guardianName?: string;
807
785
  }): void {
808
- const { assistantId, fromNumber, callerName } = params;
809
-
810
- if (!params.skipMemberActivation) {
811
- try {
812
- upsertContactChannel({
813
- sourceChannel: "phone",
814
- externalUserId: fromNumber,
815
- externalChatId: fromNumber,
816
- displayName: callerName,
817
- status: "active",
818
- policy: "allow",
819
- });
820
- } catch (err) {
821
- log.error(
822
- { err, callSessionId: this.callSessionId },
823
- "Failed to activate voice caller as trusted contact",
824
- );
825
- }
826
- }
786
+ const { assistantId, fromNumber } = params;
787
+
788
+ // Contact activation is handled by the gateway — the assistant no
789
+ // longer writes contact/channel records on inbound voice calls.
827
790
 
828
791
  const updatedTrust = resolveActorTrust({
829
792
  assistantId,
@@ -1411,7 +1374,6 @@ export class RelayConnection {
1411
1374
  this.continueCallAfterTrustedContactActivation({
1412
1375
  assistantId,
1413
1376
  fromNumber,
1414
- callerName: callerName ?? undefined,
1415
1377
  activationReason: "access_approved",
1416
1378
  });
1417
1379
 
@@ -1594,8 +1556,6 @@ export class RelayConnection {
1594
1556
  this.continueCallAfterTrustedContactActivation({
1595
1557
  assistantId: this.inviteRedemptionAssistantId,
1596
1558
  fromNumber: this.inviteRedemptionFromNumber,
1597
- callerName: this.inviteRedemptionFriendName ?? undefined,
1598
- skipMemberActivation: true,
1599
1559
  activationReason: "invite_redeemed",
1600
1560
  friendName: this.inviteRedemptionFriendName ?? undefined,
1601
1561
  guardianName: this.inviteRedemptionGuardianName ?? undefined,
@@ -1,8 +1,4 @@
1
1
  import { loadConfig } from "../config/loader.js";
2
- import {
3
- getPublicBaseUrl,
4
- getTwilioRelayUrl,
5
- } from "../inbound/public-ingress-urls.js";
6
2
  import { credentialKey } from "../security/credential-key.js";
7
3
  import { getSecureKeyAsync } from "../security/secure-keys.js";
8
4
  import { ConfigError } from "../util/errors.js";
@@ -14,8 +10,6 @@ export interface TwilioConfig {
14
10
  accountSid: string;
15
11
  authToken: string;
16
12
  phoneNumber: string;
17
- webhookBaseUrl: string;
18
- wssBaseUrl: string;
19
13
  }
20
14
 
21
15
  /**
@@ -39,19 +33,10 @@ export function resolveTwilioPhoneNumber(): string {
39
33
  }
40
34
 
41
35
  export async function getTwilioConfig(): Promise<TwilioConfig> {
42
- const config = loadConfig();
43
- const accountSid = config.twilio?.accountSid || "";
36
+ const accountSid = loadConfig().twilio?.accountSid || "";
44
37
  const authToken =
45
38
  (await getSecureKeyAsync(credentialKey("twilio", "auth_token"))) || "";
46
39
  const phoneNumber = resolveTwilioPhoneNumber();
47
- const webhookBaseUrl = getPublicBaseUrl(config);
48
-
49
- let wssBaseUrl: string;
50
- try {
51
- wssBaseUrl = getTwilioRelayUrl(config);
52
- } catch {
53
- wssBaseUrl = "";
54
- }
55
40
 
56
41
  if (!accountSid || !authToken) {
57
42
  throw new ConfigError(
@@ -64,5 +49,5 @@ export async function getTwilioConfig(): Promise<TwilioConfig> {
64
49
 
65
50
  log.debug("Twilio config loaded successfully");
66
51
 
67
- return { accountSid, authToken, phoneNumber, webhookBaseUrl, wssBaseUrl };
52
+ return { accountSid, authToken, phoneNumber };
68
53
  }