@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
@@ -6,6 +6,15 @@
6
6
  * config handler. Uses fetch() directly — no twilio npm package.
7
7
  */
8
8
 
9
+ import {
10
+ lookupIncomingPhoneNumberSid,
11
+ twilioAuthHeader,
12
+ twilioBaseUrl,
13
+ TwilioRestError,
14
+ type TwilioWebhookUrls,
15
+ updatePhoneNumberWebhooks as updateTwilioPhoneNumberWebhooks,
16
+ } from "@vellumai/twilio-client";
17
+
9
18
  import { loadConfig } from "../config/loader.js";
10
19
  import { credentialKey } from "../security/credential-key.js";
11
20
  import { getSecureKeyAsync } from "../security/secure-keys.js";
@@ -56,20 +65,7 @@ export async function hasTwilioCredentials(): Promise<boolean> {
56
65
  }
57
66
  }
58
67
 
59
- /** Build the HTTP Basic auth header for Twilio API requests. */
60
- export function twilioAuthHeader(
61
- accountSid: string,
62
- authToken: string,
63
- ): string {
64
- return (
65
- "Basic " + Buffer.from(`${accountSid}:${authToken}`).toString("base64")
66
- );
67
- }
68
-
69
- /** Build the Twilio REST API base URL for a given account. */
70
- export function twilioBaseUrl(accountSid: string): string {
71
- return `https://api.twilio.com/2010-04-01/Accounts/${accountSid}`;
72
- }
68
+ export { twilioAuthHeader, twilioBaseUrl };
73
69
 
74
70
  export interface TwilioPhoneNumber {
75
71
  phoneNumber: string;
@@ -210,9 +206,13 @@ export async function provisionPhoneNumber(
210
206
  };
211
207
  }
212
208
 
213
- export interface WebhookUrls {
214
- voiceUrl: string;
215
- statusCallbackUrl: string;
209
+ export type WebhookUrls = TwilioWebhookUrls;
210
+
211
+ function rethrowAsProviderError(err: unknown): never {
212
+ if (err instanceof TwilioRestError) {
213
+ throw new ProviderError(err.message, "twilio", err.status);
214
+ }
215
+ throw err;
216
216
  }
217
217
 
218
218
  /**
@@ -227,69 +227,15 @@ export async function updatePhoneNumberWebhooks(
227
227
  phoneNumber: string,
228
228
  webhooks: WebhookUrls,
229
229
  ): Promise<void> {
230
- // First, find the SID for this phone number
231
- const listRes = await fetch(
232
- `${twilioBaseUrl(
230
+ try {
231
+ await updateTwilioPhoneNumberWebhooks({
233
232
  accountSid,
234
- )}/IncomingPhoneNumbers.json?PhoneNumber=${encodeURIComponent(
233
+ authToken,
235
234
  phoneNumber,
236
- )}`,
237
- {
238
- method: "GET",
239
- headers: { Authorization: twilioAuthHeader(accountSid, authToken) },
240
- },
241
- );
242
-
243
- if (!listRes.ok) {
244
- const text = await listRes.text();
245
- throw new ProviderError(
246
- `Twilio API error ${listRes.status} looking up phone number: ${text}`,
247
- "twilio",
248
- listRes.status,
249
- );
250
- }
251
-
252
- const listData = (await listRes.json()) as {
253
- incoming_phone_numbers: Array<{ sid: string; phone_number: string }>;
254
- };
255
-
256
- const match = listData.incoming_phone_numbers.find(
257
- (n) => n.phone_number === phoneNumber,
258
- );
259
- if (!match) {
260
- throw new ProviderError(
261
- `Phone number ${phoneNumber} not found on Twilio account ${accountSid}`,
262
- "twilio",
263
- );
264
- }
265
-
266
- // Update the phone number's webhook configuration
267
- const body = new URLSearchParams({
268
- VoiceUrl: webhooks.voiceUrl,
269
- VoiceMethod: "POST",
270
- StatusCallback: webhooks.statusCallbackUrl,
271
- StatusCallbackMethod: "POST",
272
- });
273
-
274
- const updateRes = await fetch(
275
- `${twilioBaseUrl(accountSid)}/IncomingPhoneNumbers/${match.sid}.json`,
276
- {
277
- method: "POST",
278
- headers: {
279
- Authorization: twilioAuthHeader(accountSid, authToken),
280
- "Content-Type": "application/x-www-form-urlencoded",
281
- },
282
- body: body.toString(),
283
- },
284
- );
285
-
286
- if (!updateRes.ok) {
287
- const text = await updateRes.text();
288
- throw new ProviderError(
289
- `Twilio API error ${updateRes.status} updating webhooks: ${text}`,
290
- "twilio",
291
- updateRes.status,
292
- );
235
+ webhooks,
236
+ });
237
+ } catch (err) {
238
+ rethrowAsProviderError(err);
293
239
  }
294
240
  }
295
241
 
@@ -302,35 +248,17 @@ async function getPhoneNumberSid(
302
248
  authToken: string,
303
249
  phoneNumber: string,
304
250
  ): Promise<string | null> {
305
- const res = await fetch(
306
- `${twilioBaseUrl(
307
- accountSid,
308
- )}/IncomingPhoneNumbers.json?PhoneNumber=${encodeURIComponent(
309
- phoneNumber,
310
- )}`,
311
- {
312
- method: "GET",
313
- headers: { Authorization: twilioAuthHeader(accountSid, authToken) },
314
- },
315
- );
316
-
317
- if (!res.ok) {
318
- const text = await res.text();
319
- throw new ProviderError(
320
- `Twilio API error ${res.status} looking up phone number SID: ${text}`,
321
- "twilio",
322
- res.status,
251
+ try {
252
+ return (
253
+ (await lookupIncomingPhoneNumberSid({
254
+ accountSid,
255
+ authToken,
256
+ phoneNumber,
257
+ })) ?? null
323
258
  );
259
+ } catch (err) {
260
+ rethrowAsProviderError(err);
324
261
  }
325
-
326
- const data = (await res.json()) as {
327
- incoming_phone_numbers: Array<{ sid: string; phone_number: string }>;
328
- };
329
-
330
- const match = data.incoming_phone_numbers.find(
331
- (n) => n.phone_number === phoneNumber,
332
- );
333
- return match?.sid ?? null;
334
262
  }
335
263
 
336
264
  /**
@@ -21,11 +21,13 @@
21
21
  * server-side.
22
22
  */
23
23
 
24
- import { loadConfig } from "../config/loader.js";
25
24
  import {
26
- getTwilioMediaStreamUrl,
27
- getTwilioRelayUrl,
28
- } from "../inbound/public-ingress-urls.js";
25
+ buildTwilioMediaStreamUrl,
26
+ buildTwilioRelayUrl,
27
+ TWILIO_PUBLIC_BASE_URL_PLACEHOLDER,
28
+ } from "@vellumai/service-contracts/twilio-ingress";
29
+
30
+ import { loadConfig } from "../config/loader.js";
29
31
  import { getProviderEntry } from "../providers/speech-to-text/provider-catalog.js";
30
32
  import {
31
33
  BadRequestError,
@@ -444,7 +446,6 @@ function buildVoiceWebhookTwiml(
444
446
  // calls don't fail entirely on a misconfigured provider.
445
447
  return buildConversationRelayTwiml(
446
448
  callSessionId,
447
- cfg,
448
449
  profile,
449
450
  sessionContext,
450
451
  verificationSessionId,
@@ -457,7 +458,6 @@ function buildVoiceWebhookTwiml(
457
458
  if (strategy.strategy === "conversation-relay-native") {
458
459
  return buildConversationRelayTwiml(
459
460
  callSessionId,
460
- cfg,
461
461
  profile,
462
462
  sessionContext,
463
463
  verificationSessionId,
@@ -500,7 +500,6 @@ function buildVoiceWebhookTwiml(
500
500
  // through the relay server which supports it natively.
501
501
  return buildConversationRelayTwiml(
502
502
  callSessionId,
503
- cfg,
504
503
  profile,
505
504
  sessionContext,
506
505
  verificationSessionId,
@@ -508,7 +507,7 @@ function buildVoiceWebhookTwiml(
508
507
  );
509
508
  }
510
509
 
511
- return buildMediaStreamTwiml(callSessionId, cfg, verificationSessionId);
510
+ return buildMediaStreamTwiml(callSessionId, verificationSessionId);
512
511
  }
513
512
 
514
513
  /**
@@ -516,7 +515,6 @@ function buildVoiceWebhookTwiml(
516
515
  */
517
516
  function buildConversationRelayTwiml(
518
517
  callSessionId: string,
519
- cfg: ReturnType<typeof loadConfig>,
520
518
  profile: ReturnType<typeof resolveVoiceQualityProfile>,
521
519
  sessionContext: {
522
520
  task: string | null;
@@ -538,7 +536,7 @@ function buildConversationRelayTwiml(
538
536
  interruptSensitivity: profile.interruptSensitivity,
539
537
  };
540
538
 
541
- const relayUrl = getTwilioRelayUrl(cfg);
539
+ const relayUrl = buildTwilioRelayUrl(TWILIO_PUBLIC_BASE_URL_PLACEHOLDER);
542
540
  const welcomeGreeting = buildWelcomeGreeting(sessionContext?.task ?? null);
543
541
  const relayToken = TWILIO_RELAY_TOKEN_PLACEHOLDER;
544
542
 
@@ -572,10 +570,11 @@ function buildConversationRelayTwiml(
572
570
  */
573
571
  function buildMediaStreamTwiml(
574
572
  callSessionId: string,
575
- cfg: ReturnType<typeof loadConfig>,
576
573
  verificationSessionId: string | null | undefined,
577
574
  ): string {
578
- const streamUrl = getTwilioMediaStreamUrl(cfg);
575
+ const streamUrl = buildTwilioMediaStreamUrl(
576
+ TWILIO_PUBLIC_BASE_URL_PLACEHOLDER,
577
+ );
579
578
  const relayToken = TWILIO_RELAY_TOKEN_PLACEHOLDER;
580
579
 
581
580
  const customParameters: Record<string, string> | undefined =
@@ -91,17 +91,18 @@ export function isInteractiveInterface(id: InterfaceId): boolean {
91
91
 
92
92
  /**
93
93
  * Host proxy capabilities that an interface can support. The macOS client
94
- * supports all four; the chrome-extension interface only supports
94
+ * supports all five; the chrome-extension interface only supports
95
95
  * host_browser (via the Chrome DevTools Protocol proxy).
96
96
  */
97
97
  export type HostProxyCapability =
98
98
  | "host_bash"
99
99
  | "host_file"
100
100
  | "host_cu"
101
- | "host_browser";
101
+ | "host_browser"
102
+ | "host_app_control";
102
103
 
103
104
  /**
104
- * Interfaces that support the full desktop host-proxy set (all four
105
+ * Interfaces that support the full desktop host-proxy set (all five
105
106
  * `HostProxyCapability` values). This is the capability-level identity used
106
107
  * by the discriminated transport metadata union and by the
107
108
  * `supportsHostProxy(id)` type predicate.
@@ -135,10 +136,10 @@ export function supportsHostProxy(
135
136
  id: InterfaceId,
136
137
  capability?: HostProxyCapability,
137
138
  ): boolean {
138
- // macOS supports all four host proxy capabilities including host_browser.
139
- // The host_browser proxy is provisioned via the assistant event hub. When no
140
- // extension is connected, browser tools fall through to cdp-inspect/local
141
- // via the CDP factory's candidate chain.
139
+ // macOS supports all five host proxy capabilities including host_browser
140
+ // and host_app_control. The host_browser proxy is provisioned via the
141
+ // assistant event hub. When no extension is connected, browser tools fall
142
+ // through to cdp-inspect/local via the CDP factory's candidate chain.
142
143
  if (id === "macos") return true;
143
144
  if (id === "chrome-extension" && capability === "host_browser") return true;
144
145
  return false;
@@ -9,7 +9,6 @@
9
9
  * or via a commander program (for end-to-end arg parsing).
10
10
  */
11
11
 
12
- import { Readable } from "node:stream";
13
12
  import {
14
13
  afterEach,
15
14
  beforeEach,
@@ -130,8 +129,8 @@ let mockDaemonRunning = false;
130
129
  const recoveryCallOrder: string[] = [];
131
130
 
132
131
  /** Number of times each recovery helper was invoked. */
133
- let mockResetDbCalls = 0;
134
- let mockInvalidateConfigCacheCalls = 0;
132
+ let _mockResetDbCalls = 0;
133
+ let _mockInvalidateConfigCacheCalls = 0;
135
134
 
136
135
  /** Log calls captured by the mocked logger. */
137
136
  let mockLogInfo: string[] = [];
@@ -167,7 +166,7 @@ mock.module("../../../config/loader.js", () => ({
167
166
  backup: getComputedBackupConfig(),
168
167
  }),
169
168
  invalidateConfigCache: () => {
170
- mockInvalidateConfigCacheCalls += 1;
169
+ _mockInvalidateConfigCacheCalls += 1;
171
170
  recoveryCallOrder.push("invalidateConfigCache");
172
171
  },
173
172
  }));
@@ -178,7 +177,7 @@ mock.module("../../../daemon/daemon-control.js", () => ({
178
177
 
179
178
  mock.module("../../../memory/db-connection.js", () => ({
180
179
  resetDb: () => {
181
- mockResetDbCalls += 1;
180
+ _mockResetDbCalls += 1;
182
181
  recoveryCallOrder.push("resetDb");
183
182
  },
184
183
  }));
@@ -323,9 +322,6 @@ const {
323
322
  handleDestinationsList,
324
323
  handleStatus,
325
324
  handleList,
326
- handleCreate,
327
- handleVerify,
328
- handleRestore,
329
325
  registerBackupCommand,
330
326
  } = backupMod;
331
327
 
@@ -342,8 +338,8 @@ beforeEach(() => {
342
338
  mockLogError = [];
343
339
  mockCreateShouldThrow = null;
344
340
  mockDaemonRunning = false;
345
- mockResetDbCalls = 0;
346
- mockInvalidateConfigCacheCalls = 0;
341
+ _mockResetDbCalls = 0;
342
+ _mockInvalidateConfigCacheCalls = 0;
347
343
  recoveryCallOrder.length = 0;
348
344
  process.exitCode = 0;
349
345
  mockVerifyResult = { valid: true };
@@ -768,273 +764,6 @@ describe("handleList", () => {
768
764
  // create
769
765
  // ---------------------------------------------------------------------------
770
766
 
771
- describe("handleCreate", () => {
772
- test("renders successful snapshot result with empty offsite", async () => {
773
- await handleCreate();
774
- const out = mockLogInfo.join("\n");
775
- expect(out).toContain("Created snapshot:");
776
- expect(out).toContain("backup-20260411-093000.vbundle");
777
- expect(out).toContain("offsite: (none)");
778
- });
779
-
780
- test("renders per-destination outcome mix (ok, skipped, error)", async () => {
781
- mockCreateSnapshotResult = {
782
- ...mockCreateSnapshotResult,
783
- offsite: [
784
- {
785
- destination: { path: "/ok", encrypt: true },
786
- entry: {
787
- path: "/ok/f.vbundle.enc",
788
- filename: "f.vbundle.enc",
789
- createdAt: new Date(),
790
- sizeBytes: 100,
791
- encrypted: true,
792
- },
793
- },
794
- {
795
- destination: { path: "/skipped", encrypt: true },
796
- entry: null,
797
- skipped: "parent-missing",
798
- },
799
- {
800
- destination: { path: "/broken", encrypt: false },
801
- entry: null,
802
- error: "disk full",
803
- },
804
- ],
805
- };
806
- await handleCreate();
807
- const out = mockLogInfo.join("\n");
808
- expect(out).toContain("ok /ok");
809
- expect(out).toContain("skipped /skipped");
810
- expect(out).toContain("error /broken");
811
- expect(out).toContain("disk full");
812
- });
813
-
814
- test("concurrency error prints clear message", async () => {
815
- mockCreateShouldThrow = new Error("snapshot in progress");
816
- await handleCreate();
817
- expect(process.exitCode).toBe(1);
818
- expect(
819
- mockLogError.some((m) =>
820
- m.toLowerCase().includes("already running"),
821
- ),
822
- ).toBe(true);
823
- });
824
- });
825
-
826
- // ---------------------------------------------------------------------------
827
- // verify
828
- // ---------------------------------------------------------------------------
829
-
830
- describe("handleVerify", () => {
831
- test("returns valid result from verifySnapshot", async () => {
832
- mockVerifyResult = {
833
- valid: true,
834
- manifest: {
835
- schema_version: "1.0.0",
836
- created_at: "2026-04-11T09:30:00Z",
837
- source: "backup-worker",
838
- files: [],
839
- manifest_sha256: "abc",
840
- },
841
- };
842
- await handleVerify("/tmp/local/backup.vbundle");
843
- const out = mockLogInfo.join("\n");
844
- expect(out).toContain("OK:");
845
- expect(out).toContain("1.0.0");
846
- expect(process.exitCode).toBe(0);
847
- });
848
-
849
- test("propagates invalid result with error details", async () => {
850
- mockVerifyResult = { valid: false, error: "bad checksum" };
851
- await handleVerify("/tmp/local/backup.vbundle");
852
- expect(process.exitCode).toBe(1);
853
- expect(
854
- mockLogError.some((m) => m.includes("Invalid:")),
855
- ).toBe(true);
856
- expect(
857
- mockLogError.some((m) => m.includes("bad checksum")),
858
- ).toBe(true);
859
- });
860
- });
861
-
862
- // ---------------------------------------------------------------------------
863
- // restore
864
- // ---------------------------------------------------------------------------
865
-
866
- /**
867
- * Replace `process.stdin` with a readable stream that emits the given line.
868
- * `readline.createInterface` consumes this as a single line so prompt-based
869
- * confirmation tests stay deterministic.
870
- */
871
- function stubStdin(input: string): () => void {
872
- const original = process.stdin;
873
- const stream = Readable.from([input + "\n"]) as NodeJS.ReadableStream;
874
- Object.defineProperty(process, "stdin", {
875
- value: stream,
876
- writable: true,
877
- configurable: true,
878
- });
879
- return () => {
880
- Object.defineProperty(process, "stdin", {
881
- value: original,
882
- writable: true,
883
- configurable: true,
884
- });
885
- };
886
- }
887
-
888
- describe("handleRestore", () => {
889
- test("--yes flag bypasses confirmation and calls restoreFromSnapshot", async () => {
890
- await handleRestore({
891
- path: "/tmp/local/backup-20260411-093000.vbundle",
892
- yes: true,
893
- });
894
- expect(process.exitCode).toBe(0);
895
- const out = mockLogInfo.join("\n");
896
- expect(out).toContain("Restored from");
897
- expect(out).toContain("files restored: 42");
898
- });
899
-
900
- test("without --yes and 'n' answer aborts", async () => {
901
- const restore = stubStdin("n");
902
- try {
903
- await handleRestore({
904
- path: "/tmp/local/backup-20260411-093000.vbundle",
905
- });
906
- } finally {
907
- restore();
908
- }
909
- expect(process.exitCode).toBe(0);
910
- const out = mockLogInfo.join("\n");
911
- expect(out).toContain("Restore cancelled");
912
- });
913
-
914
- test("without --path and without --latest errors", async () => {
915
- await handleRestore({});
916
- expect(process.exitCode).toBe(1);
917
- expect(
918
- mockLogError.some((m) => m.includes("--path")),
919
- ).toBe(true);
920
- });
921
-
922
- test("both --path and --latest errors", async () => {
923
- await handleRestore({
924
- path: "/tmp/x.vbundle",
925
- latest: true,
926
- yes: true,
927
- });
928
- expect(process.exitCode).toBe(1);
929
- expect(
930
- mockLogError.some((m) => m.includes("Cannot combine")),
931
- ).toBe(true);
932
- });
933
-
934
- test("--latest with no local snapshots errors", async () => {
935
- mockSnapshots["/tmp/local"] = [];
936
- await handleRestore({ latest: true, yes: true });
937
- expect(process.exitCode).toBe(1);
938
- expect(
939
- mockLogError.some((m) => m.includes("No local snapshots")),
940
- ).toBe(true);
941
- });
942
-
943
- test("--latest picks newest local snapshot", async () => {
944
- mockSnapshots["/tmp/local"] = [
945
- {
946
- path: "/tmp/local/newest.vbundle",
947
- filename: "newest.vbundle",
948
- createdAt: new Date("2026-04-11T12:00:00Z"),
949
- sizeBytes: 1024,
950
- encrypted: false,
951
- },
952
- {
953
- path: "/tmp/local/older.vbundle",
954
- filename: "older.vbundle",
955
- createdAt: new Date("2026-04-10T12:00:00Z"),
956
- sizeBytes: 1024,
957
- encrypted: false,
958
- },
959
- ];
960
- await handleRestore({ latest: true, yes: true });
961
- expect(process.exitCode).toBe(0);
962
- expect(mockLogInfo.some((m) => m.includes("newest.vbundle"))).toBe(
963
- true,
964
- );
965
- });
966
-
967
- test("refuses to run while the assistant is running (no --force)", async () => {
968
- // Safety gate: the CLI must refuse to restore against a live assistant
969
- // unless --force is passed. Restoring under a running assistant is
970
- // dangerous — the open SQLite handle, cached config, and cached trust
971
- // rules all contradict the on-disk state after the bundle is written.
972
- mockDaemonRunning = true;
973
-
974
- await handleRestore({
975
- path: "/tmp/local/backup-20260411-093000.vbundle",
976
- yes: true,
977
- });
978
-
979
- expect(process.exitCode).toBe(1);
980
- expect(
981
- mockLogError.some((m) =>
982
- m.toLowerCase().includes("assistant is running"),
983
- ),
984
- ).toBe(true);
985
- // restoreFromSnapshot must not have been called — the safety gate
986
- // bails before reaching the recovery sequence.
987
- expect(mockResetDbCalls).toBe(0);
988
- expect(recoveryCallOrder).toEqual([]);
989
- });
990
-
991
- test("--force overrides the daemon-running refusal and still runs recovery sequence", async () => {
992
- mockDaemonRunning = true;
993
-
994
- await handleRestore({
995
- path: "/tmp/local/backup-20260411-093000.vbundle",
996
- yes: true,
997
- force: true,
998
- });
999
-
1000
- expect(process.exitCode).toBe(0);
1001
- // Recovery sequence must still run even with --force — the flag only
1002
- // overrides the running-assistant refusal, not the DB reset or cache
1003
- // invalidation.
1004
- expect(mockResetDbCalls).toBe(1);
1005
- expect(mockInvalidateConfigCacheCalls).toBe(1);
1006
- expect(recoveryCallOrder).toEqual([
1007
- "resetDb",
1008
- "restoreFromSnapshot",
1009
- "invalidateConfigCache", ]);
1010
- });
1011
-
1012
- test("successful restore runs resetDb, restore, then cache invalidation in order", async () => {
1013
- // Regression test for the restore-corrupts-daemon-state gap. The CLI
1014
- // handler must mirror the HTTP handler's recovery sequence so an
1015
- // in-process CLI invocation leaves the shared runtime in a consistent
1016
- // state.
1017
- mockDaemonRunning = false;
1018
-
1019
- await handleRestore({
1020
- path: "/tmp/local/backup-20260411-093000.vbundle",
1021
- yes: true,
1022
- });
1023
-
1024
- expect(process.exitCode).toBe(0);
1025
- expect(mockResetDbCalls).toBe(1);
1026
- expect(mockInvalidateConfigCacheCalls).toBe(1);
1027
- expect(recoveryCallOrder).toEqual([
1028
- "resetDb",
1029
- "restoreFromSnapshot",
1030
- "invalidateConfigCache", ]);
1031
- });
1032
- });
1033
-
1034
- // ---------------------------------------------------------------------------
1035
- // End-to-end: via Commander program
1036
- // ---------------------------------------------------------------------------
1037
-
1038
767
  async function runProgram(
1039
768
  args: string[],
1040
769
  ): Promise<{ exitCode: number }> {