@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,5 +1,5 @@
1
1
  /**
2
- * `vellum backup` — manage automated backups, on-demand snapshots, restore, and verify.
2
+ * `vellum backup` — manage automated backup configuration and list snapshots.
3
3
  *
4
4
  * All subcommands run in-process (they do not call the daemon HTTP port).
5
5
  * Config mutations go through `loadRawConfig` / `setNestedValue` / `saveRawConfig`
@@ -12,31 +12,22 @@ import { dirname } from "node:path";
12
12
 
13
13
  import type { Command } from "commander";
14
14
 
15
- import { readBackupKey } from "../../backup/backup-key.js";
16
- import { createSnapshotNow } from "../../backup/backup-worker.js";
17
15
  import {
18
16
  listSnapshotsInDir,
19
17
  type SnapshotEntry,
20
18
  } from "../../backup/list-snapshots.js";
21
19
  import {
22
- getBackupKeyPath,
23
20
  getLocalBackupsDir,
24
21
  resolveOffsiteDestinations,
25
22
  } from "../../backup/paths.js";
26
- import { restoreFromSnapshot, verifySnapshot } from "../../backup/restore.js";
27
23
  import {
28
24
  getConfig,
29
- invalidateConfigCache,
30
25
  loadRawConfig,
31
26
  saveRawConfig,
32
27
  setNestedValue,
33
28
  } from "../../config/loader.js";
34
29
  import type { BackupDestination } from "../../config/schema.js";
35
- import { isDaemonRunning } from "../../daemon/daemon-control.js";
36
30
  import { getMemoryCheckpoint } from "../../memory/checkpoints.js";
37
- import { resetDb } from "../../memory/db-connection.js";
38
- import { DefaultPathResolver } from "../../runtime/migrations/vbundle-import-analyzer.js";
39
- import { getWorkspaceDir, getWorkspaceHooksDir } from "../../util/platform.js";
40
31
  import { log } from "../logger.js";
41
32
 
42
33
  // ---------------------------------------------------------------------------
@@ -87,7 +78,7 @@ function formatDurationShort(ms: number): string {
87
78
 
88
79
  /**
89
80
  * Check whether an offsite destination's parent directory exists. Mirrors the
90
- * reachability check in `offsite-writer.ts` — if the parent is missing (e.g.
81
+ * reachability check in the backup worker — if the parent is missing (e.g.
91
82
  * iCloud Drive not enabled, external SSD unplugged) the destination is
92
83
  * considered unreachable and we skip it at runtime.
93
84
  */
@@ -405,242 +396,9 @@ export async function handleList(): Promise<void> {
405
396
  }
406
397
 
407
398
  // ---------------------------------------------------------------------------
408
- // create
409
399
  // ---------------------------------------------------------------------------
410
400
 
411
- export async function handleCreate(): Promise<void> {
412
- const cfg = getConfig().backup;
413
- try {
414
- const result = await createSnapshotNow(cfg, new Date());
415
- log.info(`Created snapshot: ${result.local.path}`);
416
- log.info(` size: ${formatBytes(result.local.sizeBytes)}`);
417
- log.info(` duration: ${result.durationMs}ms`);
418
- if (result.offsite.length === 0) {
419
- log.info(` offsite: (none)`);
420
- } else {
421
- log.info(` offsite:`);
422
- for (const r of result.offsite) {
423
- if (r.entry) {
424
- log.info(
425
- ` ok ${r.destination.path} -> ${r.entry.filename}`,
426
- );
427
- } else if (r.skipped) {
428
- log.info(` skipped ${r.destination.path} (${r.skipped})`);
429
- } else {
430
- log.info(
431
- ` error ${r.destination.path} (${r.error ?? "unknown"})`,
432
- );
433
- }
434
- }
435
- }
436
- } catch (err) {
437
- const message = err instanceof Error ? err.message : String(err);
438
- if (message.toLowerCase().includes("snapshot in progress")) {
439
- log.error(
440
- "Another snapshot is already running. Wait for it to finish, then retry.",
441
- );
442
- } else {
443
- log.error(`Snapshot failed: ${message}`);
444
- }
445
- process.exitCode = 1;
446
- }
447
- }
448
-
449
- // ---------------------------------------------------------------------------
450
- // restore / verify helpers
451
- // ---------------------------------------------------------------------------
452
401
 
453
- /** True when a snapshot path ends in `.vbundle.enc`. */
454
- function isEncryptedPath(path: string): boolean {
455
- return path.endsWith(".vbundle.enc");
456
- }
457
-
458
- /**
459
- * Load the backup key when the snapshot is encrypted. Throws a user-facing
460
- * error when the key file is missing or corrupt.
461
- */
462
- async function loadKeyForEncryptedSnapshot(
463
- snapshotPath: string,
464
- ): Promise<Buffer | undefined> {
465
- if (!isEncryptedPath(snapshotPath)) return undefined;
466
- const keyPath = getBackupKeyPath();
467
- const key = await readBackupKey(keyPath);
468
- if (!key) {
469
- throw new Error(
470
- `Encrypted snapshot requires backup key at ${keyPath}, but none was found. ` +
471
- `The key is generated the first time automatic backup runs against an encrypted ` +
472
- `destination.`,
473
- );
474
- }
475
- return key;
476
- }
477
-
478
- /**
479
- * Prompt for y/N confirmation. Defaults to `false` on empty input, EOF, or
480
- * anything other than `y` / `yes` (case-insensitive).
481
- */
482
- async function promptConfirm(question: string): Promise<boolean> {
483
- const readline = await import("node:readline");
484
- const rl = readline.createInterface({
485
- input: process.stdin,
486
- output: process.stdout,
487
- });
488
- const answer = await new Promise<string>((resolve) => {
489
- rl.question(question, resolve);
490
- });
491
- rl.close();
492
- const normalized = answer.trim().toLowerCase();
493
- return normalized === "y" || normalized === "yes";
494
- }
495
-
496
- // ---------------------------------------------------------------------------
497
- // restore
498
- // ---------------------------------------------------------------------------
499
-
500
- export interface RestoreOptions {
501
- path?: string;
502
- latest?: boolean;
503
- yes?: boolean;
504
- force?: boolean;
505
- }
506
-
507
- export async function handleRestore(opts: RestoreOptions): Promise<void> {
508
- if (!opts.path && !opts.latest) {
509
- log.error(
510
- "Must specify --path <snapshot> or --latest. " +
511
- "Run 'vellum backup list' to see available snapshots.",
512
- );
513
- process.exitCode = 1;
514
- return;
515
- }
516
- if (opts.path && opts.latest) {
517
- log.error("Cannot combine --path and --latest. Drop one.");
518
- process.exitCode = 1;
519
- return;
520
- }
521
-
522
- // Safety gate: a restore while the assistant is running is dangerous.
523
- // The assistant holds an open SQLite handle (referencing the old inode on
524
- // Unix), a cached config, and cached trust rules. Overwriting the files
525
- // under a running process corrupts state. Refuse unless `--force` says the
526
- // caller knows what they're doing.
527
- if (!opts.force && isDaemonRunning()) {
528
- log.error(
529
- "Assistant is running — stop it first with 'vellum sleep' before restoring " +
530
- "(safe restore requires an idle assistant). Pass --force to override.",
531
- );
532
- process.exitCode = 1;
533
- return;
534
- }
535
-
536
- let snapshotPath: string;
537
- if (opts.path) {
538
- snapshotPath = opts.path;
539
- } else {
540
- // `--latest` is explicitly scoped to local snapshots — offsite files may
541
- // not exist after a machine swap (per the plan), so we keep the selection
542
- // rule predictable.
543
- const cfg = getConfig().backup;
544
- const localDir = getLocalBackupsDir(cfg.localDirectory);
545
- const entries = await listSnapshotsInDir(localDir);
546
- if (entries.length === 0) {
547
- log.error(
548
- `No local snapshots found in ${localDir}. ` +
549
- `Run 'vellum backup create' to make one, or pass --path with an explicit file.`,
550
- );
551
- process.exitCode = 1;
552
- return;
553
- }
554
- snapshotPath = entries[0]!.path;
555
- }
556
-
557
- if (!opts.yes) {
558
- const confirmed = await promptConfirm(
559
- `Restore from ${snapshotPath}? This will overwrite workspace files. (y/N) `,
560
- );
561
- if (!confirmed) {
562
- log.info("Restore cancelled");
563
- return;
564
- }
565
- }
566
-
567
- let key: Buffer | undefined;
568
- try {
569
- key = await loadKeyForEncryptedSnapshot(snapshotPath);
570
- } catch (err) {
571
- log.error(err instanceof Error ? err.message : String(err));
572
- process.exitCode = 1;
573
- return;
574
- }
575
-
576
- try {
577
- const workspaceDir = getWorkspaceDir();
578
- const hooksDir = getWorkspaceHooksDir();
579
- const pathResolver = new DefaultPathResolver(workspaceDir, hooksDir);
580
-
581
- // Close the SQLite singleton before the bundle is written. If the
582
- // assistant process was running in-process (tests, `--force`) the
583
- // singleton may still reference the old file; resetting closes the
584
- // handle so the restored DB file is picked up cleanly on the next
585
- // getDb() call.
586
- resetDb();
587
-
588
- const result = await restoreFromSnapshot(snapshotPath, {
589
- key,
590
- pathResolver,
591
- workspaceDir,
592
- });
593
-
594
- // Invalidate the in-process config cache so the restored settings.json
595
- // takes effect without requiring a daemon restart.
596
- invalidateConfigCache();
597
-
598
- log.info(`Restored from ${snapshotPath}`);
599
- log.info(` bundle_id: ${result.manifest.bundle_id}`);
600
- log.info(` schema_version: ${result.manifest.schema_version}`);
601
- log.info(` files restored: ${result.restoredFiles}`);
602
- } catch (err) {
603
- log.error(
604
- `Restore failed: ${err instanceof Error ? err.message : String(err)}`,
605
- );
606
- process.exitCode = 1;
607
- }
608
- }
609
-
610
- // ---------------------------------------------------------------------------
611
- // verify
612
- // ---------------------------------------------------------------------------
613
-
614
- export async function handleVerify(path: string): Promise<void> {
615
- let key: Buffer | undefined;
616
- try {
617
- key = await loadKeyForEncryptedSnapshot(path);
618
- } catch (err) {
619
- log.error(err instanceof Error ? err.message : String(err));
620
- process.exitCode = 1;
621
- return;
622
- }
623
-
624
- try {
625
- const result = await verifySnapshot(path, { key });
626
- if (result.valid) {
627
- log.info(`OK: ${path}`);
628
- if (result.manifest) {
629
- log.info(` schema_version: ${result.manifest.schema_version}`);
630
- log.info(` bundle_id: ${result.manifest.bundle_id}`);
631
- }
632
- } else {
633
- log.error(`Invalid: ${path}`);
634
- if (result.error) log.error(` ${result.error}`);
635
- process.exitCode = 1;
636
- }
637
- } catch (err) {
638
- log.error(
639
- `Verify failed: ${err instanceof Error ? err.message : String(err)}`,
640
- );
641
- process.exitCode = 1;
642
- }
643
- }
644
402
 
645
403
  // ---------------------------------------------------------------------------
646
404
  // Command wiring
@@ -650,7 +408,7 @@ export function registerBackupCommand(program: Command): void {
650
408
  const backup = program
651
409
  .command("backup")
652
410
  .description(
653
- "Manage automated backups, on-demand snapshots, restore, and verify",
411
+ "Manage automated backup configuration and list snapshots",
654
412
  );
655
413
 
656
414
  backup.addHelpText(
@@ -659,7 +417,7 @@ export function registerBackupCommand(program: Command): void {
659
417
  Backups capture a snapshot of the assistant workspace (config, conversations,
660
418
  trust rules, hooks, the SQLite database) as a .vbundle file. Credentials are
661
419
  NOT included — they live in the OS keychain / CES and users re-authenticate
662
- integrations after a restore. The automated worker runs on a configurable
420
+ integrations after a restore (via the gateway). The automated worker runs on a configurable
663
421
  interval and writes to a local pool under ~/.vellum/backups/local/, optionally
664
422
  mirroring each snapshot to one or more offsite destinations (iCloud Drive by
665
423
  default).
@@ -672,10 +430,7 @@ Examples:
672
430
  $ vellum backup enable --interval 6 --retention 3
673
431
  $ vellum backup destinations add /Volumes/BackupSSD/vellum --plaintext
674
432
  $ vellum backup status
675
- $ vellum backup list
676
- $ vellum backup create
677
- $ vellum backup restore --latest --yes
678
- $ vellum backup verify ~/.vellum/backups/local/backup-20260411-093000.vbundle`,
433
+ $ vellum backup list`,
679
434
  );
680
435
 
681
436
  backup
@@ -841,7 +596,7 @@ Examples:
841
596
  });
842
597
 
843
598
  // ---------------------------------------------------------------------------
844
- // status / list / create / restore / verify
599
+ // status / list
845
600
  // ---------------------------------------------------------------------------
846
601
 
847
602
  backup
@@ -880,84 +635,4 @@ Examples:
880
635
  await handleList();
881
636
  });
882
637
 
883
- backup
884
- .command("create")
885
- .description("Create a backup snapshot immediately (ignores interval)")
886
- .addHelpText(
887
- "after",
888
- `
889
- Triggers an on-demand snapshot. Bypasses the interval gate so it will run even
890
- if the automated worker just ran, but still honours the concurrency mutex --
891
- a second concurrent caller errors with "snapshot in progress". Does NOT update
892
- the last-run checkpoint (manual snapshots should not reset the cadence).
893
-
894
- Examples:
895
- $ vellum backup create`,
896
- )
897
- .action(async () => {
898
- await handleCreate();
899
- });
900
-
901
- backup
902
- .command("restore")
903
- .description("Restore a backup snapshot into the workspace")
904
- .option(
905
- "--path <path>",
906
- "Absolute path to the .vbundle or .vbundle.enc file to restore",
907
- )
908
- .option(
909
- "--latest",
910
- "Restore the newest local snapshot (offsite files are not considered)",
911
- )
912
- .option("--yes", "Skip the confirmation prompt")
913
- .option(
914
- "--force",
915
- "Restore even when the assistant is running (unsafe — only use if you know what you're doing)",
916
- )
917
- .addHelpText(
918
- "after",
919
- `
920
- Restores a snapshot by writing its contents back into the workspace.
921
- Encryption is auto-detected from the file extension; encrypted snapshots
922
- (.vbundle.enc) require the backup key at ~/.vellum/workspace/.backup.key.
923
-
924
- Prompts for confirmation unless --yes is passed.
925
-
926
- --latest selects the newest local snapshot only. Offsite files may not exist
927
- on a new machine after a workspace migration, so --latest refuses to dig into
928
- them on purpose.
929
-
930
- Safety: refuses to run while the assistant is running, because the live
931
- SQLite handle and cached config/trust rules can corrupt the restored state.
932
- Stop the assistant first with 'vellum sleep'. Pass --force to override (only
933
- use this if you understand the risk).
934
-
935
- Examples:
936
- $ vellum backup restore --latest --yes
937
- $ vellum backup restore --path ~/.vellum/backups/local/backup-20260411-093000.vbundle`,
938
- )
939
- .action(async (opts: RestoreOptions) => {
940
- await handleRestore(opts);
941
- });
942
-
943
- backup
944
- .command("verify <path>")
945
- .description("Verify a backup snapshot without restoring it")
946
- .addHelpText(
947
- "after",
948
- `
949
- Arguments:
950
- path Absolute path to a .vbundle or .vbundle.enc snapshot file.
951
-
952
- Runs the same validation the importer would run but never touches the
953
- workspace. Encryption is auto-detected from the file extension; encrypted
954
- snapshots require the backup key at ~/.vellum/workspace/.backup.key.
955
-
956
- Examples:
957
- $ vellum backup verify ~/.vellum/backups/local/backup-20260411-093000.vbundle
958
- $ vellum backup verify /Volumes/BackupSSD/vellum/backup-20260411-093000.vbundle.enc`,
959
- )
960
- .action(async (path: string) => {
961
- await handleVerify(path);
962
- });
963
638
  }
@@ -9,6 +9,7 @@ interface ClientEntryJSON {
9
9
  clientId: string;
10
10
  interfaceId: string;
11
11
  capabilities: string[];
12
+ machineName?: string;
12
13
  connectedAt: string;
13
14
  lastActiveAt: string;
14
15
  }
@@ -47,7 +48,7 @@ Examples:
47
48
  .option("--json", "Machine-readable compact JSON output")
48
49
  .option(
49
50
  "--capability <name>",
50
- "Filter to clients supporting this capability (e.g. host_bash, host_file, host_cu, host_browser)",
51
+ "Filter to clients supporting this capability (e.g. host_bash, host_file, host_cu, host_browser, host_app_control)",
51
52
  )
52
53
  .addHelpText(
53
54
  "after",
@@ -55,7 +56,7 @@ Examples:
55
56
  Options:
56
57
  --json Output as compact JSON instead of a table.
57
58
  --capability <name> Only show clients that support the named capability.
58
- Valid values: host_bash, host_file, host_cu, host_browser.
59
+ Valid values: host_bash, host_file, host_cu, host_browser, host_app_control.
59
60
 
60
61
  The table shows each client's ID, interface type, capabilities,
61
62
  connection timestamps, and host environment (when available).
@@ -104,6 +105,7 @@ Examples:
104
105
  "CLIENT ID",
105
106
  "INTERFACE",
106
107
  "CAPABILITIES",
108
+ "LABEL",
107
109
  "CONNECTED",
108
110
  "LAST ACTIVE",
109
111
  ];
@@ -111,6 +113,7 @@ Examples:
111
113
  e.clientId,
112
114
  e.interfaceId,
113
115
  e.capabilities.length > 0 ? e.capabilities.join(", ") : "—",
116
+ e.machineName ?? "—",
114
117
  formatRelativeTime(e.connectedAt),
115
118
  formatRelativeTime(e.lastActiveAt),
116
119
  ]);
@@ -134,13 +137,13 @@ Examples:
134
137
  },
135
138
  );
136
139
 
137
- clients
138
- .command("disconnect <clientId>")
139
- .description("Force-disconnect a client by its ID")
140
- .option("--json", "Machine-readable compact JSON output")
141
- .addHelpText(
142
- "after",
143
- `
140
+ clients
141
+ .command("disconnect <clientId>")
142
+ .description("Force-disconnect a client by its ID")
143
+ .option("--json", "Machine-readable compact JSON output")
144
+ .addHelpText(
145
+ "after",
146
+ `
144
147
  Arguments:
145
148
  clientId The UUID of the client to disconnect (from \`clients list\`).
146
149
 
@@ -151,34 +154,30 @@ reconnect automatically depending on its implementation.
151
154
  Examples:
152
155
  $ assistant clients disconnect a1a30bde-6679-406c-bc32-d5a0d2a7a99e
153
156
  $ assistant clients disconnect a1a30bde-6679-406c-bc32-d5a0d2a7a99e --json`,
154
- )
155
- .action(
156
- async (
157
- clientId: string,
158
- opts: { json?: boolean },
159
- cmd: Command,
160
- ) => {
161
- const result = await cliIpcCall<DisconnectClientResponse>(
162
- "disconnect_client",
163
- { body: { clientId } },
164
- );
165
-
166
- if (!result.ok) {
167
- log.error(result.error ?? "Failed to disconnect client");
168
- process.exitCode = 1;
169
- return;
170
- }
171
-
172
- if (opts.json) {
173
- writeOutput(cmd, result.result!);
174
- return;
175
- }
176
-
177
- log.info(
178
- `Disconnected client ${clientId} (${result.result!.disconnected} subscriber${result.result!.disconnected === 1 ? "" : "s"} disposed)`,
179
- );
180
- },
181
- );
157
+ )
158
+ .action(
159
+ async (clientId: string, opts: { json?: boolean }, cmd: Command) => {
160
+ const result = await cliIpcCall<DisconnectClientResponse>(
161
+ "disconnect_client",
162
+ { body: { clientId } },
163
+ );
164
+
165
+ if (!result.ok) {
166
+ log.error(result.error ?? "Failed to disconnect client");
167
+ process.exitCode = 1;
168
+ return;
169
+ }
170
+
171
+ if (opts.json) {
172
+ writeOutput(cmd, result.result!);
173
+ return;
174
+ }
175
+
176
+ log.info(
177
+ `Disconnected client ${clientId} (${result.result!.disconnected} subscriber${result.result!.disconnected === 1 ? "" : "s"} disposed)`,
178
+ );
179
+ },
180
+ );
182
181
  }
183
182
 
184
183
  function formatRelativeTime(iso: string): string {
@@ -19,6 +19,7 @@ import type {
19
19
  ContactType,
20
20
  ContactWithChannels,
21
21
  } from "../../contacts/types.js";
22
+ import { cliIpcCall } from "../../ipc/cli-client.js";
22
23
  import { getDb } from "../../memory/db-connection.js";
23
24
  import {
24
25
  createIngressInvite,
@@ -27,6 +28,7 @@ import {
27
28
  redeemVoiceInviteCode,
28
29
  revokeIngressInvite,
29
30
  } from "../../runtime/invite-service.js";
31
+ import type { ContactPromptResult } from "../../runtime/routes/contact-prompt-routes.js";
30
32
  import { shouldOutputJson, writeOutput } from "../output.js";
31
33
 
32
34
  // ---------------------------------------------------------------------------
@@ -407,6 +409,77 @@ Examples:
407
409
  },
408
410
  );
409
411
 
412
+ contacts
413
+ .command("prompt")
414
+ .description("Prompt user to register a contact channel via the app UI")
415
+ .option("--channel <channel>", "Suggested channel type hint (e.g. phone, email, telegram)")
416
+ .option("--placeholder <placeholder>", "Placeholder text for the address input field")
417
+ .option("--role <role>", "Intended role: guardian, trusted-contact, or unknown (default: unknown)")
418
+ .option("--label <label>", "Display label shown in the prompt UI")
419
+ .option("--description <description>", "Longer description shown in the prompt UI")
420
+ .option("--timeout <ms>", "How long to wait for the user to submit (ms). Defaults to match the server-side prompt timeout.", String(310_000))
421
+ .addHelpText(
422
+ "after",
423
+ `
424
+ Opens a contact address prompt in the user's app. The user enters a channel
425
+ address (phone number, email, Telegram ID, etc.). The address is saved with
426
+ status "unverified". Verification is a separate step.
427
+
428
+ Run \`assistant contacts prompt --help\` for full option details.`,
429
+ )
430
+ .action(
431
+ async (
432
+ opts: {
433
+ channel?: string;
434
+ placeholder?: string;
435
+ role?: string;
436
+ label?: string;
437
+ description?: string;
438
+ timeout?: string;
439
+ },
440
+ cmd: Command,
441
+ ) => {
442
+ try {
443
+ const timeoutMs = opts.timeout ? parseInt(opts.timeout, 10) : 310_000;
444
+ const ipc = await cliIpcCall<ContactPromptResult>(
445
+ "contacts_prompt",
446
+ {
447
+ body: {
448
+ channel: opts.channel,
449
+ placeholder: opts.placeholder,
450
+ role: opts.role ?? "unknown",
451
+ label: opts.label,
452
+ description: opts.description,
453
+ },
454
+ },
455
+ { timeoutMs },
456
+ );
457
+
458
+ if (!ipc.ok || !ipc.result?.ok) {
459
+ writeError(cmd, ipc.error ?? ipc.result?.error ?? "Contact prompt failed");
460
+ process.exitCode = 1;
461
+ return;
462
+ }
463
+
464
+ const result = ipc.result;
465
+ if (shouldOutputJson(cmd)) {
466
+ writeOutput(cmd, result);
467
+ } else {
468
+ process.stdout.write(
469
+ `Registered ${result.channelType} channel: ${result.address}\n` +
470
+ ` Channel ID: ${result.channelId}\n` +
471
+ ` Contact ID: ${result.contactId}\n` +
472
+ ` Status: unverified\n`,
473
+ );
474
+ }
475
+ } catch (err) {
476
+ const message = err instanceof Error ? err.message : String(err);
477
+ writeError(cmd, message);
478
+ process.exitCode = 1;
479
+ }
480
+ },
481
+ );
482
+
410
483
  const channelsCmds = contacts
411
484
  .command("channels")
412
485
  .description("Manage contact channels");
@@ -15,10 +15,7 @@ import {
15
15
  } from "../../memory/conversation-crud.js";
16
16
  import { listConversations } from "../../memory/conversation-queries.js";
17
17
  import { getDb } from "../../memory/db-connection.js";
18
- import {
19
- selectEmbeddingBackend,
20
- SPARSE_EMBEDDING_VERSION,
21
- } from "../../memory/embedding-backend.js";
18
+ import { selectEmbeddingBackend } from "../../memory/embedding-backend.js";
22
19
  import { enqueueMemoryJob } from "../../memory/jobs-store.js";
23
20
  import {
24
21
  initQdrantClient,
@@ -307,7 +304,7 @@ Examples:
307
304
  const qdrantUrl = resolveQdrantUrl(config);
308
305
  const embeddingSelection = await selectEmbeddingBackend(config);
309
306
  const embeddingModel = embeddingSelection.backend
310
- ? `${embeddingSelection.backend.provider}:${embeddingSelection.backend.model}:sparse-v${SPARSE_EMBEDDING_VERSION}`
307
+ ? `${embeddingSelection.backend.provider}:${embeddingSelection.backend.model}`
311
308
  : undefined;
312
309
  const qdrant = initQdrantClient({
313
310
  url: qdrantUrl,
@@ -439,13 +439,17 @@ Examples:
439
439
 
440
440
  assertMetadataWritable();
441
441
 
442
- const stored = await setSecureKeyViaDaemon(
442
+ const setResult = await setSecureKeyViaDaemon(
443
443
  "credential",
444
444
  `${service}:${field}`,
445
445
  value,
446
446
  );
447
- if (!stored) {
448
- writeError(cmd, `Failed to store secret for ${service}:${field}`);
447
+ if (!setResult.ok) {
448
+ const detail = setResult.error ? `: ${setResult.error}` : "";
449
+ writeError(
450
+ cmd,
451
+ `Failed to store credential ${service}:${field}${detail}`,
452
+ );
449
453
  process.exitCode = 1;
450
454
  return;
451
455
  }
@@ -506,12 +510,16 @@ Examples:
506
510
 
507
511
  assertMetadataWritable();
508
512
 
509
- const secretResult = await deleteSecureKeyViaDaemon(
513
+ const deleteResult = await deleteSecureKeyViaDaemon(
510
514
  "credential",
511
515
  `${service}:${field}`,
512
516
  );
513
- if (secretResult === "error") {
514
- writeError(cmd, "Failed to delete credential from secure storage");
517
+ if (deleteResult.result === "error") {
518
+ const detail = deleteResult.error ? `: ${deleteResult.error}` : "";
519
+ writeError(
520
+ cmd,
521
+ `Failed to delete credential ${service}:${field}${detail}`,
522
+ );
515
523
  process.exitCode = 1;
516
524
  return;
517
525
  }
@@ -537,7 +545,7 @@ Examples:
537
545
  }
538
546
 
539
547
  if (
540
- secretResult !== "deleted" &&
548
+ deleteResult.result !== "deleted" &&
541
549
  !metadataDeleted &&
542
550
  oauthResult !== "disconnected"
543
551
  ) {