@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,6 +1,11 @@
1
1
  import type { Command } from "commander";
2
2
 
3
- import { getAssistantDomain } from "../../config/env.js";
3
+ import { getApexDomain, getAssistantDomain } from "../../config/env.js";
4
+ import {
5
+ loadRawConfig,
6
+ saveRawConfig,
7
+ setNestedValue,
8
+ } from "../../config/loader.js";
4
9
  import { VellumPlatformClient } from "../../platform/client.js";
5
10
  import { getCliLogger } from "../logger.js";
6
11
  import { shouldOutputJson, writeOutput } from "../output.js";
@@ -8,6 +13,7 @@ import { shouldOutputJson, writeOutput } from "../output.js";
8
13
  const log = getCliLogger("domain");
9
14
 
10
15
  export function registerDomainCommand(program: Command): void {
16
+ const apexDomain = getApexDomain();
11
17
  const baseDomain = getAssistantDomain();
12
18
  const domain = program
13
19
  .command("domain")
@@ -97,17 +103,36 @@ Examples:
97
103
 
98
104
  const data = (await response.json()) as {
99
105
  id: string;
100
- domain: string;
101
- status: string;
102
- verified: boolean;
103
- created_at: string;
106
+ subdomain?: string;
107
+ domain?: string;
108
+ status?: string;
109
+ verified?: boolean;
110
+ created_at?: string;
111
+ created?: string;
104
112
  };
105
113
 
114
+ // Persist the subdomain to config so getAssistantDomain() can use it
115
+ const registeredSubdomain =
116
+ data.subdomain ??
117
+ data.domain?.replace(`.${apexDomain}`, "") ??
118
+ subdomain;
119
+ if (registeredSubdomain) {
120
+ const raw = loadRawConfig();
121
+ setNestedValue(raw, "platform.subdomain", registeredSubdomain);
122
+ saveRawConfig(raw);
123
+ }
124
+
125
+ const displayDomain =
126
+ data.domain ??
127
+ (registeredSubdomain
128
+ ? `${registeredSubdomain}.${apexDomain}`
129
+ : "unknown");
130
+
106
131
  if (shouldOutputJson(cmd)) {
107
132
  writeOutput(cmd, data);
108
133
  } else {
109
- log.info(`✓ Registered ${data.domain}`);
110
- if (!data.verified) {
134
+ log.info(`✓ Registered ${displayDomain}`);
135
+ if (data.verified === false) {
111
136
  log.info(
112
137
  " ⚠ Domain verification pending — this usually resolves within a few seconds.",
113
138
  );
@@ -174,15 +199,33 @@ Examples:
174
199
  const data = (await response.json()) as {
175
200
  results: {
176
201
  id: string;
177
- domain: string;
178
- status: string;
179
- verified: boolean;
180
- created_at: string;
202
+ subdomain?: string;
203
+ domain?: string;
204
+ status?: string;
205
+ verified?: boolean;
206
+ created_at?: string;
207
+ created?: string;
181
208
  }[];
182
209
  };
183
210
 
184
211
  const domains = data.results ?? [];
185
212
 
213
+ // Sync subdomain to config if not already cached
214
+ if (domains.length > 0) {
215
+ const first = domains[0];
216
+ const sub =
217
+ first.subdomain ?? first.domain?.replace(`.${apexDomain}`, "");
218
+ if (sub) {
219
+ const raw = loadRawConfig();
220
+ const existing = (raw as Record<string, Record<string, unknown>>)
221
+ .platform?.subdomain;
222
+ if (existing !== sub) {
223
+ setNestedValue(raw, "platform.subdomain", sub);
224
+ saveRawConfig(raw);
225
+ }
226
+ }
227
+ }
228
+
186
229
  if (shouldOutputJson(cmd)) {
187
230
  writeOutput(cmd, data);
188
231
  } else if (domains.length === 0) {
@@ -191,10 +234,18 @@ Examples:
191
234
  );
192
235
  } else {
193
236
  for (const d of domains) {
194
- log.info(`Domain: ${d.domain}`);
195
- log.info(`Status: ${d.status}`);
196
- log.info(`Verified: ${d.verified ? "yes" : "no"}`);
197
- log.info(`Created: ${d.created_at.split("T")[0]}`);
237
+ const displayDomain =
238
+ d.domain ??
239
+ (d.subdomain ? `${d.subdomain}.${apexDomain}` : "unknown");
240
+ const createdRaw = d.created_at ?? d.created;
241
+ const createdDate = createdRaw
242
+ ? createdRaw.split("T")[0]
243
+ : "unknown";
244
+ log.info(`Domain: ${displayDomain}`);
245
+ if (d.status != null) log.info(`Status: ${d.status}`);
246
+ if (d.verified != null)
247
+ log.info(`Verified: ${d.verified ? "yes" : "no"}`);
248
+ log.info(`Created: ${createdDate}`);
198
249
  }
199
250
  }
200
251
  } catch (err) {
@@ -0,0 +1,183 @@
1
+ /**
2
+ * `assistant gateway` CLI namespace.
3
+ *
4
+ * Subcommands:
5
+ * logs tail — Show the last N gateway log entries via the daemon IPC proxy.
6
+ */
7
+
8
+ import type { Command } from "commander";
9
+
10
+ import { cliIpcCall } from "../../ipc/cli-client.js";
11
+ import { log } from "../logger.js";
12
+
13
+ // -- Types --------------------------------------------------------------------
14
+
15
+ interface PinoEntry {
16
+ time: number; // Unix ms timestamp
17
+ level: number; // pino numeric level
18
+ module?: string;
19
+ msg?: string;
20
+ [key: string]: unknown;
21
+ }
22
+
23
+ // -- Helpers ------------------------------------------------------------------
24
+
25
+ function formatTime(ms: number): string {
26
+ const d = new Date(ms);
27
+ const pad = (n: number, w = 2) => String(n).padStart(w, "0");
28
+ const centis = String(Math.floor((ms % 1000) / 10)).padStart(2, "0");
29
+ return (
30
+ `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ` +
31
+ `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}.${centis}`
32
+ );
33
+ }
34
+
35
+ const LEVEL_NAMES: Record<number, string> = {
36
+ 10: "TRACE",
37
+ 20: "DEBUG",
38
+ 30: "INFO",
39
+ 40: "WARN",
40
+ 50: "ERROR",
41
+ 60: "FATAL",
42
+ };
43
+
44
+ function levelName(n: number): string {
45
+ return LEVEL_NAMES[n] ?? String(n);
46
+ }
47
+
48
+ function colorLevel(name: string, levelNum: number): string {
49
+ if (!process.stdout.isTTY) return name;
50
+ if (levelNum >= 50) return `\x1b[31m${name}\x1b[0m`; // red: error/fatal
51
+ if (levelNum === 40) return `\x1b[33m${name}\x1b[0m`; // yellow: warn
52
+ if (levelNum <= 20) return `\x1b[2m${name}\x1b[0m`; // dim: debug/trace
53
+ return name;
54
+ }
55
+
56
+ // -- Registration -------------------------------------------------------------
57
+
58
+ export function registerGatewayCommand(program: Command): void {
59
+ const gateway = program.command("gateway").description("Gateway management");
60
+
61
+ gateway.addHelpText(
62
+ "after",
63
+ `
64
+ The gateway is the channel ingress layer — it handles inbound HTTP requests,
65
+ manages trust rules, routes traffic to the assistant, and records
66
+ structured logs for all inbound activity.
67
+
68
+ Examples:
69
+ $ assistant gateway logs tail
70
+ $ assistant gateway logs tail -n 50
71
+ $ assistant gateway logs tail --level warn
72
+ $ assistant gateway logs tail --module cors`,
73
+ );
74
+
75
+ const logs = gateway.command("logs").description("Gateway log operations");
76
+
77
+ logs.addHelpText(
78
+ "after",
79
+ `
80
+ Gateway logs are structured JSON (ndjson) entries emitted by the gateway
81
+ process. Each entry carries a timestamp, numeric pino log level, optional
82
+ module tag, and a message. Use 'tail' to inspect recent entries.
83
+
84
+ Examples:
85
+ $ assistant gateway logs tail
86
+ $ assistant gateway logs tail --level error --module cors`,
87
+ );
88
+
89
+ logs
90
+ .command("tail")
91
+ .description("Show last N gateway log entries")
92
+ .option("-n <number>", "Number of lines (default: 10)")
93
+ .option("-q, --quiet", "Suppress column headers")
94
+ .option(
95
+ "--level <level>",
96
+ "Minimum log level (trace|debug|info|warn|error|fatal)",
97
+ "info",
98
+ )
99
+ .option("--module <name>", "Filter to exact module name")
100
+ .option("--raw", "Output raw ndjson (one JSON object per line)")
101
+ .addHelpText(
102
+ "after",
103
+ `
104
+ Arguments:
105
+ -n <number> Number of entries to return, clamped to 1–1000 (default: 10).
106
+ --level <level> Minimum log level to include. One of:
107
+ trace | debug | info | warn | error | fatal
108
+ Defaults to "info". Use "trace" or "debug" for verbose output.
109
+ --module <name> Filter to entries whose module tag exactly matches <name>.
110
+ Useful for isolating a specific subsystem (e.g. "cors", "trust").
111
+ --raw Emit raw ndjson — one JSON object per line — instead of the
112
+ formatted table. Useful for piping to jq or other JSON tools.
113
+ -q, --quiet Suppress the column-header line in table output.
114
+
115
+ Output format (default table):
116
+ TIME (24 chars) LEVEL (5 chars) MODULE (up to 12 chars) MESSAGE (truncated at 120 chars)
117
+
118
+ Truncation:
119
+ When more matching entries exist beyond the requested -n window, a dim
120
+ "(showing last N matching entries — earlier entries exist)" footer is printed.
121
+
122
+ Examples:
123
+ $ assistant gateway logs tail
124
+ $ assistant gateway logs tail -n 50 --level warn
125
+ $ assistant gateway logs tail --module cors --raw | jq .msg`,
126
+ )
127
+ .action(async (opts) => {
128
+ const n = Math.max(1, Math.min(1000, parseInt(opts.n ?? "10", 10) || 10));
129
+ const params: Record<string, unknown> = { n };
130
+ if (opts.level && opts.level !== "info") params.level = opts.level;
131
+ if (opts.module) params.module = opts.module;
132
+
133
+ const result = await cliIpcCall<{ lines: PinoEntry[]; truncated: boolean }>(
134
+ "gateway_logs_tail",
135
+ { body: params },
136
+ );
137
+
138
+ if (!result.ok) {
139
+ log.error(result.error ?? "Failed to fetch gateway logs");
140
+ process.exitCode = 1;
141
+ return;
142
+ }
143
+
144
+ const { lines, truncated } = result.result!;
145
+
146
+ if (opts.raw) {
147
+ for (const entry of lines) process.stdout.write(JSON.stringify(entry) + "\n");
148
+ return;
149
+ }
150
+
151
+ if (lines.length === 0) {
152
+ if (!opts.quiet) process.stdout.write("No log entries found.\n");
153
+ return;
154
+ }
155
+
156
+ const moduleWidth = Math.min(
157
+ 12,
158
+ Math.max(6, ...lines.map((l) => l.module?.length ?? 0)),
159
+ );
160
+
161
+ if (!opts.quiet) {
162
+ process.stdout.write(
163
+ `${"TIME".padEnd(24)} ${"LEVEL".padEnd(5)} ${"MODULE".padEnd(moduleWidth)} MESSAGE\n`,
164
+ );
165
+ }
166
+
167
+ for (const entry of lines) {
168
+ const time = formatTime(entry.time).padEnd(24);
169
+ const lvlName = levelName(entry.level).padEnd(5);
170
+ const lvlColored = colorLevel(lvlName, entry.level);
171
+ const mod = (entry.module ?? "").padEnd(moduleWidth);
172
+ const msg = entry.msg ?? "";
173
+ const msgTrunc = msg.length > 120 ? msg.slice(0, 120) + "…" : msg;
174
+ process.stdout.write(`${time} ${lvlColored} ${mod} ${msgTrunc}\n`);
175
+ }
176
+
177
+ if (truncated) {
178
+ const footer = `(showing last ${n} matching entries — earlier entries exist)`;
179
+ const dim = process.stdout.isTTY ? `\x1b[2m${footer}\x1b[0m` : footer;
180
+ process.stdout.write(dim + "\n");
181
+ }
182
+ });
183
+ }
@@ -102,10 +102,12 @@ Examples:
102
102
  process.exit(1);
103
103
  }
104
104
 
105
- if (await setSecureKeyViaDaemon("api_key", provider, key)) {
105
+ const setResult = await setSecureKeyViaDaemon("api_key", provider, key);
106
+ if (setResult.ok) {
106
107
  log.info(`Stored API key for "${provider}"`);
107
108
  } else {
108
- log.error(`Failed to store API key for "${provider}"`);
109
+ const detail = setResult.error ? `: ${setResult.error}` : "";
110
+ log.error(`Failed to store API key for "${provider}"${detail}`);
109
111
  process.exit(1);
110
112
  }
111
113
  });
@@ -133,11 +135,12 @@ Examples:
133
135
  process.exit(1);
134
136
  }
135
137
 
136
- const result = await deleteSecureKeyViaDaemon("api_key", provider);
137
- if (result === "deleted") {
138
+ const delResult = await deleteSecureKeyViaDaemon("api_key", provider);
139
+ if (delResult.result === "deleted") {
138
140
  log.info(`Deleted API key for "${provider}"`);
139
- } else if (result === "error") {
140
- log.error(`Failed to delete API key for "${provider}": storage error`);
141
+ } else if (delResult.result === "error") {
142
+ const detail = delResult.error ? `: ${delResult.error}` : "";
143
+ log.error(`Failed to delete API key for "${provider}"${detail}`);
141
144
  process.exit(1);
142
145
  } else {
143
146
  log.error(`No API key found for "${provider}"`);
@@ -1,24 +1,59 @@
1
- import { mkdirSync, writeFileSync } from "node:fs";
2
- import { join } from "node:path";
3
-
4
- import { UnauthorizedError } from "@modelcontextprotocol/sdk/client/auth.js";
5
- import { Client } from "@modelcontextprotocol/sdk/client/index.js";
6
- import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
7
- import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
8
1
  import type { Command } from "commander";
9
2
 
10
3
  import { loadRawConfig, saveRawConfig } from "../../config/loader.js";
11
4
  import type { McpConfig, McpServerConfig } from "../../config/schemas/mcp.js";
5
+ import { cliIpcCall } from "../../ipc/cli-client.js";
12
6
  import { McpClient } from "../../mcp/client.js";
13
- import {
14
- deleteMcpOAuthCredentials,
15
- McpOAuthProvider,
16
- } from "../../mcp/mcp-oauth-provider.js";
17
- import { getSignalsDir } from "../../util/platform.js";
7
+ import { deleteMcpOAuthCredentials } from "../../mcp/mcp-oauth-provider.js";
8
+ import { openInHostBrowser } from "../../util/browser.js";
18
9
  import { log } from "../logger.js";
19
10
 
20
11
  const HEALTH_CHECK_TIMEOUT_MS = 10_000;
21
12
 
13
+ async function pollMcpAuthStatus(
14
+ serverId: string,
15
+ options: { intervalMs: number; timeoutMs: number },
16
+ ): Promise<{ status: "complete" | "error"; error?: string }> {
17
+ const deadline = Date.now() + options.timeoutMs;
18
+ while (Date.now() < deadline) {
19
+ await new Promise<void>((resolve) =>
20
+ setTimeout(resolve, options.intervalMs),
21
+ );
22
+ const result = await cliIpcCall<{ status: string; error?: string }>(
23
+ "internal_mcp_auth_status",
24
+ { pathParams: { serverId } },
25
+ );
26
+ if (result.ok && result.result?.status === "complete") {
27
+ return { status: "complete" };
28
+ }
29
+ if (result.ok && result.result?.status === "error") {
30
+ return { status: "error", error: result.result.error };
31
+ }
32
+ // The daemon returned an IPC-level error (ok: false) indicating the flow
33
+ // was not found — most likely because the daemon restarted mid-poll and
34
+ // lost the in-memory state. Surface this immediately instead of looping
35
+ // for the full 2.5 minutes and then reporting a generic timeout.
36
+ if (
37
+ !result.ok &&
38
+ result.error &&
39
+ result.error.includes("No active OAuth flow")
40
+ ) {
41
+ return {
42
+ status: "error",
43
+ error: `OAuth flow was lost (assistant may have restarted). Run 'assistant mcp auth ${serverId}' to retry.`,
44
+ };
45
+ }
46
+ // Fail fast on any other real IPC error instead of looping for 2.5 minutes
47
+ if (!result.ok && result.error) {
48
+ return { status: "error", error: result.error };
49
+ }
50
+ }
51
+ return {
52
+ status: "error",
53
+ error: "OAuth authorization timed out after 2.5 minutes",
54
+ };
55
+ }
56
+
22
57
  export async function checkServerHealth(
23
58
  serverId: string,
24
59
  config: McpServerConfig,
@@ -66,21 +101,6 @@ export async function checkServerHealth(
66
101
  }
67
102
  }
68
103
 
69
- /**
70
- * Write a signal file so the daemon's ConfigWatcher triggers an MCP reload.
71
- * Used by `mcp reload`, `mcp auth`, and any operation that needs the daemon
72
- * to reconnect MCP servers.
73
- */
74
- function signalMcpReload(): void {
75
- try {
76
- const signalsDir = getSignalsDir();
77
- mkdirSync(signalsDir, { recursive: true });
78
- writeFileSync(join(signalsDir, "mcp-reload"), "");
79
- } catch {
80
- // Best-effort — the daemon may not be running or the directory may not exist.
81
- }
82
- }
83
-
84
104
  export function registerMcpCommand(program: Command): void {
85
105
  const mcp = program
86
106
  .command("mcp")
@@ -290,11 +310,18 @@ Examples:
290
310
  $ vellum mcp reload # after editing config.json to add a new server
291
311
  $ vellum mcp reload # after running "vellum mcp auth <server>"`,
292
312
  )
293
- .action(() => {
294
- signalMcpReload();
295
- log.info(
296
- "MCP reload signal sent. The running assistant will reconnect servers shortly.",
297
- );
313
+ .action(async () => {
314
+ const result = await cliIpcCall("internal_mcp_reload", { body: {} });
315
+ if (!result.ok) {
316
+ log.warn(
317
+ `Could not signal reload: ${result.error}. ` +
318
+ `Run 'assistant mcp reload' once the assistant is up.`,
319
+ );
320
+ } else {
321
+ log.info(
322
+ "MCP reload signal sent. The running assistant will reconnect servers shortly.",
323
+ );
324
+ }
298
325
  });
299
326
 
300
327
  mcp
@@ -337,7 +364,7 @@ Examples:
337
364
  $ assistant mcp add legacy-sse -t sse -u https://old.example.com/events --disabled`,
338
365
  )
339
366
  .action(
340
- (
367
+ async (
341
368
  name: string,
342
369
  opts: {
343
370
  transportType: string;
@@ -411,10 +438,15 @@ Examples:
411
438
 
412
439
  saveRawConfig(raw);
413
440
  log.info(`Added MCP server "${name}" (${opts.transportType})`);
414
- log.info(
415
- "The running assistant will pick up this change automatically. " +
416
- "Or run 'vellum mcp reload' to apply now.",
417
- );
441
+ const reloadResult = await cliIpcCall("internal_mcp_reload", { body: {} });
442
+ if (!reloadResult.ok) {
443
+ log.warn(
444
+ `Could not signal reload: ${reloadResult.error}. ` +
445
+ `Run 'assistant mcp reload' once the assistant is up.`,
446
+ );
447
+ } else {
448
+ log.info("The running assistant is reloading MCP servers now.");
449
+ }
418
450
  },
419
451
  );
420
452
 
@@ -428,8 +460,8 @@ Arguments:
428
460
  name Name of a configured MCP server to authenticate with
429
461
 
430
462
  Only works with sse or streamable-http transports (stdio servers do not use
431
- OAuth). Opens a browser for OAuth authorization with the remote server and
432
- starts a local callback server to receive the authorization code.
463
+ OAuth). Opens a browser for OAuth authorization with the remote server. The
464
+ running assistant handles the OAuth callback and token exchange.
433
465
 
434
466
  The command waits up to 2.5 minutes for the user to complete the browser-based
435
467
  OAuth flow. If the server already has valid cached tokens, the command succeeds
@@ -466,141 +498,69 @@ Examples:
466
498
  return;
467
499
  }
468
500
 
469
- // Validate URL early so we fail fast before starting the callback server
470
- let serverUrl: URL;
471
- try {
472
- serverUrl = new URL(transport.url);
473
- } catch {
474
- log.error(`Invalid URL for MCP server "${name}": ${transport.url}`);
475
- process.exitCode = 1;
476
- return;
477
- }
501
+ // IPC-first path attempt daemon-orchestrated flow (works on hosted assistants)
502
+ const startResult = await cliIpcCall<{
503
+ auth_url: string;
504
+ state: string;
505
+ already_authenticated?: boolean;
506
+ }>("internal_mcp_auth_start", { body: { serverId: name } });
478
507
 
479
- const provider = new McpOAuthProvider(
480
- name,
481
- transport.url,
482
- /* interactive */ true,
483
- );
484
- // Clear stale client_info and discovery — the callback server uses a random port,
485
- // so any previously cached client_info has a mismatched redirect_uri.
486
- // Preserve tokens so they survive if this auth attempt fails.
487
- await provider.invalidateCredentials("client");
488
- await provider.invalidateCredentials("discovery");
489
- const { codePromise } = await provider.startCallbackServer();
490
-
491
- const OAUTH_TIMEOUT_MS = 150_000; // 2.5 min for browser interaction
492
- const TransportClass =
493
- transport.type === "sse"
494
- ? SSEClientTransport
495
- : StreamableHTTPClientTransport;
496
- const mcpTransport = new TransportClass(serverUrl, {
497
- authProvider: provider,
498
- requestInit: transport.headers
499
- ? { headers: transport.headers }
500
- : undefined,
501
- });
502
-
503
- const client = new Client({ name: "vellum-assistant", version: "1.0.0" });
504
-
505
- try {
506
- // Try connecting — if tokens are already cached, this succeeds immediately
507
- await client.connect(mcpTransport);
508
- provider.stopCallbackServer();
509
- await client.close();
508
+ if (startResult.ok && startResult.result?.already_authenticated) {
510
509
  log.info(`Server "${name}" is already authenticated.`);
510
+ process.exit(0);
511
511
  return;
512
- } catch (err) {
513
- if (!(err instanceof UnauthorizedError)) {
514
- provider.stopCallbackServer();
515
- try {
516
- await client.close();
517
- } catch {
518
- /* ignore */
519
- }
520
- log.error(`Failed to connect to "${name}": ${err}`);
521
- process.exitCode = 1;
522
- return;
523
- }
524
512
  }
525
513
 
526
- // UnauthorizedError browser was opened by redirectToAuthorization().
527
- // Wait for the user to complete the OAuth flow.
528
- log.info(
529
- "Waiting for authorization in browser... (press Ctrl+C to cancel)",
530
- );
514
+ if (startResult.ok && startResult.result?.auth_url) {
515
+ const authUrl = startResult.result.auth_url;
516
+ log.info(`Opening browser for "${name}" OAuth authorization...`);
517
+ await openInHostBrowser(authUrl);
518
+ log.info(`If the browser did not open, visit:\n${authUrl}`);
519
+ log.info(
520
+ "Waiting for authorization in browser... (press Ctrl+C to cancel)",
521
+ );
531
522
 
532
- let code: string;
533
- let oauthTimer: ReturnType<typeof setTimeout> | undefined;
534
- try {
535
- code = await Promise.race([
536
- codePromise,
537
- new Promise<never>((_, reject) => {
538
- oauthTimer = setTimeout(
539
- () =>
540
- reject(
541
- new Error("OAuth authorization timed out after 2.5 minutes"),
542
- ),
543
- OAUTH_TIMEOUT_MS,
544
- );
545
- if (typeof oauthTimer === "object" && "unref" in oauthTimer)
546
- oauthTimer.unref();
547
- }),
548
- ]);
549
- clearTimeout(oauthTimer);
550
- } catch (err) {
551
- clearTimeout(oauthTimer);
552
- provider.stopCallbackServer();
553
- try {
554
- await client.close();
555
- } catch {
556
- /* ignore */
523
+ const finalStatus = await pollMcpAuthStatus(name, {
524
+ intervalMs: 2_000,
525
+ timeoutMs: 150_000, // matches existing OAUTH_TIMEOUT_MS
526
+ });
527
+
528
+ if (finalStatus.status === "complete") {
529
+ log.info(`Authentication successful for "${name}".`);
530
+ log.info(
531
+ "The running assistant has picked up this change automatically.",
532
+ );
533
+ process.exit(0);
534
+ return;
557
535
  }
558
- const message = err instanceof Error ? err.message : String(err);
559
- if (message.includes("denied") || message.includes("cancelled")) {
536
+
537
+ const errMsg = finalStatus.error ?? "Unknown error";
538
+ if (errMsg.includes("denied") || errMsg.includes("cancelled")) {
560
539
  log.error(`Authorization cancelled for "${name}".`);
561
- } else if (message.includes("timed out")) {
540
+ } else if (errMsg.includes("timed out")) {
562
541
  log.error(
563
542
  `Authorization timed out for "${name}". Try again with: assistant mcp auth ${name}`,
564
543
  );
565
544
  } else {
566
- log.error(`Authorization failed for "${name}": ${message}`);
567
- }
568
- process.exitCode = 1;
569
- return;
570
- }
571
-
572
- log.info("Authorization received. Exchanging token...");
573
-
574
- // Exchange auth code for tokens
575
- try {
576
- await mcpTransport.finishAuth(code);
577
- } catch (err) {
578
- provider.stopCallbackServer();
579
- try {
580
- await client.close();
581
- } catch {
582
- /* ignore */
545
+ log.error(`OAuth failed for "${name}": ${errMsg}`);
583
546
  }
584
- log.error(`Token exchange failed for "${name}": ${err}`);
585
547
  process.exitCode = 1;
586
548
  return;
587
549
  }
588
550
 
589
- // Clean up transport/client so the process can exit
590
- try {
591
- await client.close();
592
- } catch {
593
- /* ignore */
551
+ // Any !startResult.ok case: surface error and exit 1
552
+ const ipcErrMsg = startResult.error ?? "Unknown error";
553
+ if (
554
+ ipcErrMsg.startsWith("Could not connect to assistant daemon") ||
555
+ ipcErrMsg.startsWith("Unknown method:")
556
+ ) {
557
+ log.error(
558
+ `MCP OAuth requires the assistant to be running. Is it running?`,
559
+ );
560
+ } else {
561
+ log.error(`MCP OAuth failed via assistant: ${ipcErrMsg}`);
594
562
  }
595
- provider.stopCallbackServer();
596
-
597
- log.info(`Authentication successful for "${name}".`);
598
- log.info(
599
- "The running assistant will pick up this change automatically. " +
600
- "Or run 'vellum mcp reload' to apply now.",
601
- );
602
- signalMcpReload();
603
- process.exit(0);
563
+ process.exitCode = 1;
604
564
  });
605
565
 
606
566
  mcp