@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
@@ -0,0 +1,242 @@
1
+ /**
2
+ * Unit tests for the gateway_logs_tail IPC route handler.
3
+ *
4
+ * Covers:
5
+ * - Happy path: all params → correct URL with querystring
6
+ * - All params absent → URL with no querystring
7
+ * - Only n provided → querystring has only n
8
+ * - Gateway returns 500 with error body → Error thrown with error message
9
+ * - level: "INVALID" → ZodError (no gateway call)
10
+ * - n: 0 → ZodError (min 1 violation)
11
+ * - n: 1001 → ZodError (max 1000 violation)
12
+ * - module: "" → accepted (empty string passes zod string validation)
13
+ */
14
+
15
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
16
+
17
+ import { ZodError } from "zod";
18
+
19
+ // ---------------------------------------------------------------------------
20
+ // Mocks — must be defined before importing the module under test
21
+ // ---------------------------------------------------------------------------
22
+
23
+ mock.module("../../../util/logger.js", () => ({
24
+ getLogger: () =>
25
+ new Proxy({} as Record<string, unknown>, {
26
+ get: () => () => {},
27
+ }),
28
+ }));
29
+
30
+ mock.module("../../../config/env.js", () => ({
31
+ getGatewayInternalBaseUrl: () => "http://localhost:9999",
32
+ }));
33
+
34
+ // ---------------------------------------------------------------------------
35
+ // Import the module under test AFTER mocks are set up
36
+ // ---------------------------------------------------------------------------
37
+
38
+ import { ROUTES } from "../gateway-log-routes.js";
39
+
40
+ const gatewayLogsTailRoute = ROUTES.find(
41
+ (r) => r.operationId === "gateway_logs_tail",
42
+ )!;
43
+
44
+ // ---------------------------------------------------------------------------
45
+ // Helpers
46
+ // ---------------------------------------------------------------------------
47
+
48
+ function makeFetchMock(
49
+ status: number,
50
+ body: unknown,
51
+ ): ReturnType<typeof mock> {
52
+ return mock(async () => ({
53
+ ok: status >= 200 && status < 300,
54
+ status,
55
+ json: async () => body,
56
+ }));
57
+ }
58
+
59
+ // ---------------------------------------------------------------------------
60
+ // Tests
61
+ // ---------------------------------------------------------------------------
62
+
63
+ describe("gateway_logs_tail route", () => {
64
+ beforeEach(() => {
65
+ // Reset global fetch to avoid cross-test contamination
66
+ globalThis.fetch = undefined as unknown as typeof fetch;
67
+ });
68
+
69
+ test("route is registered with correct operationId, method, and endpoint", () => {
70
+ expect(gatewayLogsTailRoute).toBeDefined();
71
+ expect(gatewayLogsTailRoute.operationId).toBe("gateway_logs_tail");
72
+ expect(gatewayLogsTailRoute.method).toBe("GET");
73
+ expect(gatewayLogsTailRoute.endpoint).toBe("gateway/logs/tail");
74
+ });
75
+
76
+ describe("happy path — all params provided via body", () => {
77
+ test("calls gateway with correct URL including all query params", async () => {
78
+ const mockFetch = makeFetchMock(200, { entries: [] });
79
+ globalThis.fetch = mockFetch as unknown as typeof fetch;
80
+
81
+ await gatewayLogsTailRoute.handler({
82
+ body: { n: 5, level: "warn", module: "mcp" },
83
+ });
84
+
85
+ expect(mockFetch).toHaveBeenCalledTimes(1);
86
+ const calledUrl = (mockFetch.mock.calls[0] as [string])[0];
87
+ expect(calledUrl).toBe(
88
+ "http://localhost:9999/v1/logs/tail?n=5&level=warn&module=mcp",
89
+ );
90
+ });
91
+
92
+ test("returns the parsed response body", async () => {
93
+ const responseBody = { entries: [{ msg: "hello", level: 40 }] };
94
+ globalThis.fetch = makeFetchMock(200, responseBody) as unknown as typeof fetch;
95
+
96
+ const result = await gatewayLogsTailRoute.handler({
97
+ body: { n: 5, level: "warn", module: "mcp" },
98
+ });
99
+
100
+ expect(result).toEqual(responseBody);
101
+ });
102
+ });
103
+
104
+ describe("all params absent", () => {
105
+ test("calls gateway URL with no querystring when body is empty", async () => {
106
+ const mockFetch = makeFetchMock(200, { entries: [] });
107
+ globalThis.fetch = mockFetch as unknown as typeof fetch;
108
+
109
+ await gatewayLogsTailRoute.handler({ body: {} });
110
+
111
+ const calledUrl = (mockFetch.mock.calls[0] as [string])[0];
112
+ expect(calledUrl).toBe("http://localhost:9999/v1/logs/tail");
113
+ });
114
+
115
+ test("calls gateway URL with no querystring when no args provided", async () => {
116
+ const mockFetch = makeFetchMock(200, { entries: [] });
117
+ globalThis.fetch = mockFetch as unknown as typeof fetch;
118
+
119
+ await gatewayLogsTailRoute.handler({});
120
+
121
+ const calledUrl = (mockFetch.mock.calls[0] as [string])[0];
122
+ expect(calledUrl).toBe("http://localhost:9999/v1/logs/tail");
123
+ });
124
+ });
125
+
126
+ describe("only n provided", () => {
127
+ test("querystring contains only n — no spurious level or module keys", async () => {
128
+ const mockFetch = makeFetchMock(200, { entries: [] });
129
+ globalThis.fetch = mockFetch as unknown as typeof fetch;
130
+
131
+ await gatewayLogsTailRoute.handler({ body: { n: 5 } });
132
+
133
+ const calledUrl = (mockFetch.mock.calls[0] as [string])[0];
134
+ expect(calledUrl).toBe("http://localhost:9999/v1/logs/tail?n=5");
135
+ expect(calledUrl).not.toContain("level");
136
+ expect(calledUrl).not.toContain("module");
137
+ });
138
+ });
139
+
140
+ describe("gateway error handling", () => {
141
+ test("gateway 500 with { error: 'disk error' } throws Error with that message", async () => {
142
+ globalThis.fetch = makeFetchMock(500, {
143
+ error: "disk error",
144
+ }) as unknown as typeof fetch;
145
+
146
+ await expect(
147
+ gatewayLogsTailRoute.handler({ body: {} }),
148
+ ).rejects.toThrow("disk error");
149
+ });
150
+
151
+ test("gateway 500 with non-string error falls back to generic message", async () => {
152
+ globalThis.fetch = makeFetchMock(500, {
153
+ error: { nested: true },
154
+ }) as unknown as typeof fetch;
155
+
156
+ await expect(
157
+ gatewayLogsTailRoute.handler({ body: {} }),
158
+ ).rejects.toThrow("Gateway request failed (500)");
159
+ });
160
+
161
+ test("gateway 500 with unparseable JSON falls back to generic message", async () => {
162
+ globalThis.fetch = mock(async () => ({
163
+ ok: false,
164
+ status: 500,
165
+ json: async () => {
166
+ throw new SyntaxError("Unexpected token");
167
+ },
168
+ })) as unknown as typeof fetch;
169
+
170
+ await expect(
171
+ gatewayLogsTailRoute.handler({ body: {} }),
172
+ ).rejects.toThrow("Gateway request failed (500)");
173
+ });
174
+ });
175
+
176
+ describe("zod validation", () => {
177
+ test("level: 'INVALID' is rejected with ZodError before calling gateway", async () => {
178
+ const mockFetch = makeFetchMock(200, {});
179
+ globalThis.fetch = mockFetch as unknown as typeof fetch;
180
+
181
+ await expect(
182
+ gatewayLogsTailRoute.handler({
183
+ body: { level: "INVALID" },
184
+ }),
185
+ ).rejects.toBeInstanceOf(ZodError);
186
+
187
+ expect(mockFetch).not.toHaveBeenCalled();
188
+ });
189
+
190
+ test("n: 0 is rejected with ZodError (min 1 violation)", async () => {
191
+ const mockFetch = makeFetchMock(200, {});
192
+ globalThis.fetch = mockFetch as unknown as typeof fetch;
193
+
194
+ await expect(
195
+ gatewayLogsTailRoute.handler({ body: { n: 0 } }),
196
+ ).rejects.toBeInstanceOf(ZodError);
197
+
198
+ expect(mockFetch).not.toHaveBeenCalled();
199
+ });
200
+
201
+ test("n: 1001 is rejected with ZodError (max 1000 violation)", async () => {
202
+ const mockFetch = makeFetchMock(200, {});
203
+ globalThis.fetch = mockFetch as unknown as typeof fetch;
204
+
205
+ await expect(
206
+ gatewayLogsTailRoute.handler({ body: { n: 1001 } }),
207
+ ).rejects.toBeInstanceOf(ZodError);
208
+
209
+ expect(mockFetch).not.toHaveBeenCalled();
210
+ });
211
+
212
+ test("module: '' is accepted (empty string passes zod string validation)", async () => {
213
+ const mockFetch = makeFetchMock(200, { entries: [] });
214
+ globalThis.fetch = mockFetch as unknown as typeof fetch;
215
+
216
+ await expect(
217
+ gatewayLogsTailRoute.handler({ body: { module: "" } }),
218
+ ).resolves.toBeDefined();
219
+
220
+ expect(mockFetch).toHaveBeenCalledTimes(1);
221
+ });
222
+ });
223
+
224
+ describe("queryParams source (HTTP GET path)", () => {
225
+ test("uses queryParams when provided (HTTP GET path) — string params", async () => {
226
+ const mockFetch = makeFetchMock(200, { entries: [] });
227
+ globalThis.fetch = mockFetch as unknown as typeof fetch;
228
+
229
+ // When queryParams has values, those take precedence over body.
230
+ // Only string-valued params (level, module) are valid from the HTTP layer;
231
+ // n is numeric and must come via IPC body.
232
+ await gatewayLogsTailRoute.handler({
233
+ queryParams: { level: "info", module: "cors" },
234
+ body: {},
235
+ });
236
+
237
+ const calledUrl = (mockFetch.mock.calls[0] as [string])[0];
238
+ expect(calledUrl).toContain("level=info");
239
+ expect(calledUrl).toContain("module=cors");
240
+ });
241
+ });
242
+ });
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Asserts `setHeartbeatConfig` persists only user-set heartbeat fields to
3
+ * `config.json` and surfaces the resolved (post-default) values via the
4
+ * response payload.
5
+ */
6
+
7
+ import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
8
+ import { tmpdir } from "node:os";
9
+ import { join } from "node:path";
10
+ import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
11
+
12
+ import { invalidateConfigCache } from "../../../config/loader.js";
13
+ import { ROUTES } from "../heartbeat-routes.js";
14
+ import type { RouteDefinition } from "../types.js";
15
+
16
+ // ─── Module mocks ──────────────────────────────────────────────────────────
17
+
18
+ // Stub the heartbeat service so the response-path's getInstance() returns
19
+ // undefined (no scheduler running in tests).
20
+ mock.module("../../../heartbeat/heartbeat-service.js", () => ({
21
+ HeartbeatService: {
22
+ getInstance: () => undefined,
23
+ },
24
+ }));
25
+
26
+ // ─── Setup ─────────────────────────────────────────────────────────────────
27
+
28
+ let workspaceDir: string;
29
+ let origWorkspaceDir: string | undefined;
30
+ let configPath: string;
31
+
32
+ function findHandler(operationId: string): RouteDefinition["handler"] {
33
+ const route = ROUTES.find((r) => r.operationId === operationId);
34
+ if (!route) throw new Error(`Route ${operationId} not found`);
35
+ return route.handler;
36
+ }
37
+
38
+ function readConfig(): Record<string, unknown> {
39
+ return JSON.parse(readFileSync(configPath, "utf-8"));
40
+ }
41
+
42
+ beforeEach(() => {
43
+ workspaceDir = mkdtempSync(join(tmpdir(), "vellum-hbr-"));
44
+ origWorkspaceDir = process.env.VELLUM_WORKSPACE_DIR;
45
+ process.env.VELLUM_WORKSPACE_DIR = workspaceDir;
46
+ configPath = join(workspaceDir, "config.json");
47
+ invalidateConfigCache();
48
+ });
49
+
50
+ afterEach(() => {
51
+ if (origWorkspaceDir === undefined) {
52
+ delete process.env.VELLUM_WORKSPACE_DIR;
53
+ } else {
54
+ process.env.VELLUM_WORKSPACE_DIR = origWorkspaceDir;
55
+ }
56
+ invalidateConfigCache();
57
+ try {
58
+ rmSync(workspaceDir, { recursive: true, force: true });
59
+ } catch {
60
+ // best-effort cleanup
61
+ }
62
+ });
63
+
64
+ // ─── Tests ─────────────────────────────────────────────────────────────────
65
+
66
+ describe("setHeartbeatConfig handler", () => {
67
+ test("persists only user-set fields when starting from a config with no heartbeat block", async () => {
68
+ writeFileSync(
69
+ configPath,
70
+ JSON.stringify({ provider: "anthropic" }, null, 2) + "\n",
71
+ );
72
+
73
+ const handler = findHandler("updateHeartbeatConfig");
74
+ const result = (await handler({ body: { enabled: true } })) as {
75
+ enabled: boolean;
76
+ intervalMs: number;
77
+ activeHoursStart: number | null;
78
+ activeHoursEnd: number | null;
79
+ success: boolean;
80
+ };
81
+
82
+ // On-disk: only user-set heartbeat fields, no schema defaults baked in.
83
+ const onDisk = readConfig();
84
+ expect(onDisk).toEqual({
85
+ provider: "anthropic",
86
+ heartbeat: { enabled: true },
87
+ });
88
+
89
+ // Response: schema-default intervalMs surfaces, proving cache
90
+ // invalidation + getConfig() read picked up the new on-disk state.
91
+ expect(result.success).toBe(true);
92
+ expect(result.enabled).toBe(true);
93
+ expect(result.intervalMs).toBe(6 * 3_600_000);
94
+ expect(result.activeHoursStart).toBe(8);
95
+ expect(result.activeHoursEnd).toBe(22);
96
+ });
97
+
98
+ test("merges patch into existing heartbeat block instead of overwriting", async () => {
99
+ writeFileSync(
100
+ configPath,
101
+ JSON.stringify({ heartbeat: { intervalMs: 60000 } }, null, 2) + "\n",
102
+ );
103
+
104
+ const handler = findHandler("updateHeartbeatConfig");
105
+ await handler({ body: { enabled: true } });
106
+
107
+ const onDisk = readConfig();
108
+ expect(onDisk).toEqual({
109
+ heartbeat: { intervalMs: 60000, enabled: true },
110
+ });
111
+ });
112
+ });
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Types extracted from guardian-approval-interception.ts to break the
3
+ * interception ↔ guardian-text-engine-strategy cycle.
4
+ */
5
+
6
+ export interface ApprovalInterceptionResult {
7
+ handled: boolean;
8
+ type?:
9
+ | "decision_applied"
10
+ | "assistant_turn"
11
+ | "guardian_decision_applied"
12
+ | "stale_ignored";
13
+ }
@@ -17,7 +17,7 @@ import type {
17
17
  ApprovalConversationGenerator,
18
18
  ApprovalCopyGenerator,
19
19
  } from "../../http-types.js";
20
- import type { ApprovalInterceptionResult } from "../guardian-approval-interception.js";
20
+ import type { ApprovalInterceptionResult } from "../approval-interception-types.js";
21
21
  import { deliverStaleApprovalReply } from "../guardian-approval-reply-helpers.js";
22
22
 
23
23
  const log = getLogger("runtime-http");
@@ -26,17 +26,11 @@ import { dirname, sep } from "node:path";
26
26
 
27
27
  import { z } from "zod";
28
28
 
29
- import { readBackupKey } from "../../backup/backup-key.js";
30
- import {
31
- type BackupRunResult,
32
- createSnapshotNow,
33
- } from "../../backup/backup-worker.js";
34
29
  import {
35
30
  listSnapshotsInDir,
36
31
  type SnapshotEntry,
37
32
  } from "../../backup/list-snapshots.js";
38
33
  import {
39
- getBackupKeyPath,
40
34
  getLocalBackupsDir,
41
35
  resolveOffsiteDestinations,
42
36
  } from "../../backup/paths.js";
@@ -47,7 +41,7 @@ import { getMemoryCheckpoint } from "../../memory/checkpoints.js";
47
41
  import { getLogger } from "../../util/logger.js";
48
42
  import { getWorkspaceDir, getWorkspaceHooksDir } from "../../util/platform.js";
49
43
  import { DefaultPathResolver } from "../migrations/vbundle-import-analyzer.js";
50
- import { BadRequestError, ConflictError, RouteError } from "./errors.js";
44
+ import { BadRequestError, RouteError } from "./errors.js";
51
45
  import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
52
46
 
53
47
  const log = getLogger("backup-routes");
@@ -115,23 +109,16 @@ async function validateSnapshotPath(rawPath: unknown): Promise<string> {
115
109
  }
116
110
 
117
111
  /**
118
- * Load the backup decryption key iff the target snapshot is encrypted.
119
- * Returns null for plaintext bundles. Throws BadRequestError when an
120
- * encrypted bundle is supplied but no key file exists.
112
+ * Reject encrypted snapshots decryption has moved to the gateway (ATL-397).
113
+ * The assistant daemon no longer has access to the backup key.
121
114
  */
122
- async function loadKeyIfEncrypted(
123
- snapshotPath: string,
124
- ): Promise<Buffer | null> {
125
- if (!snapshotPath.endsWith(".vbundle.enc")) {
126
- return null;
127
- }
128
- const key = await readBackupKey(getBackupKeyPath());
129
- if (key == null) {
115
+ function rejectIfEncrypted(snapshotPath: string): void {
116
+ if (snapshotPath.endsWith(".vbundle.enc")) {
130
117
  throw new BadRequestError(
131
- "Encrypted snapshot requires a backup key, but backup.key is missing",
118
+ "Encrypted snapshot restore/verify must go through the gateway, " +
119
+ "which owns the backup key. Use the gateway's backup endpoints instead.",
132
120
  );
133
121
  }
134
- return key;
135
122
  }
136
123
 
137
124
  // ---------------------------------------------------------------------------
@@ -189,24 +176,17 @@ export async function handleBackupList(): Promise<BackupListResponse> {
189
176
  return { local, offsite, offsiteEnabled, nextRunAt };
190
177
  }
191
178
 
192
- export async function handleBackupCreate(): Promise<BackupRunResult> {
193
- try {
194
- const config = getConfig();
195
- return await createSnapshotNow(config.backup, new Date());
196
- } catch (err) {
197
- const message = err instanceof Error ? err.message : String(err);
198
- if (message.startsWith("snapshot in progress")) {
199
- throw new ConflictError("A snapshot is already in progress");
200
- }
201
- log.error({ err }, "Manual backup snapshot failed");
202
- throw new RouteError(message, "INTERNAL_ERROR", 500);
203
- }
179
+ export async function handleBackupCreate(): Promise<never> {
180
+ throw new BadRequestError(
181
+ "Backup snapshot creation has moved to the gateway. " +
182
+ "Use the gateway's POST /v1/backups/create endpoint instead.",
183
+ );
204
184
  }
205
185
 
206
186
  export async function handleBackupRestore({ body }: RouteHandlerArgs) {
207
187
  const path = body?.path;
208
188
  const snapshotPath = await validateSnapshotPath(path);
209
- const key = await loadKeyIfEncrypted(snapshotPath);
189
+ rejectIfEncrypted(snapshotPath);
210
190
 
211
191
  try {
212
192
  const pathResolver = new DefaultPathResolver(
@@ -215,7 +195,6 @@ export async function handleBackupRestore({ body }: RouteHandlerArgs) {
215
195
  );
216
196
 
217
197
  const result = await restoreFromSnapshot(snapshotPath, {
218
- key: key ?? undefined,
219
198
  pathResolver,
220
199
  workspaceDir: getWorkspaceDir(),
221
200
  });
@@ -239,12 +218,10 @@ export async function handleBackupRestore({ body }: RouteHandlerArgs) {
239
218
  export async function handleBackupVerify({ body }: RouteHandlerArgs) {
240
219
  const path = body?.path;
241
220
  const snapshotPath = await validateSnapshotPath(path);
242
- const key = await loadKeyIfEncrypted(snapshotPath);
221
+ rejectIfEncrypted(snapshotPath);
243
222
 
244
223
  try {
245
- return await verifySnapshot(snapshotPath, {
246
- key: key ?? undefined,
247
- });
224
+ return await verifySnapshot(snapshotPath);
248
225
  } catch (err) {
249
226
  log.error({ err, snapshotPath }, "Snapshot verification failed");
250
227
  throw new RouteError(
@@ -18,6 +18,8 @@ import { z } from "zod";
18
18
 
19
19
  import { readNowScratchpad } from "../../daemon/conversation-runtime-assembly.js";
20
20
  import { getOrCreateConversation } from "../../daemon/conversation-store.js";
21
+ import { buildToolDefinitions } from "../../daemon/conversation-tool-setup.js";
22
+ import { parseIdentityFields } from "../../daemon/handlers/identity.js";
21
23
  import { getConversationByKey } from "../../memory/conversation-key-store.js";
22
24
  import { resolvePersonaContext } from "../../prompts/persona-resolver.js";
23
25
  import { getLogger } from "../../util/logger.js";
@@ -35,33 +37,6 @@ const IDENTITY_INTRO_KEY = "identity-intro";
35
37
  /** Conversation key used by the client for empty-state greeting generation. */
36
38
  const GREETING_KEY = "greeting";
37
39
 
38
- /**
39
- * Parse the `## Identity Intro` section from SOUL.md.
40
- * Returns the first non-empty line under that heading, or null.
41
- */
42
- function readSoulIdentityIntro(): string | null {
43
- try {
44
- const soulPath = getWorkspacePromptPath("SOUL.md");
45
- if (!existsSync(soulPath)) return null;
46
- const content = readFileSync(soulPath, "utf-8");
47
-
48
- let inSection = false;
49
- for (const line of content.split("\n")) {
50
- const trimmed = line.trim();
51
- if (/^#+\s/.test(trimmed)) {
52
- inSection = trimmed.toLowerCase().includes("identity intro");
53
- continue;
54
- }
55
- if (inSection && trimmed.length > 0) {
56
- return trimmed;
57
- }
58
- }
59
- } catch {
60
- // Fall through — no SOUL.md intro available
61
- }
62
- return null;
63
- }
64
-
65
40
  // ---------------------------------------------------------------------------
66
41
  // SSE helpers
67
42
  // ---------------------------------------------------------------------------
@@ -94,14 +69,17 @@ async function handleBtw({
94
69
 
95
70
  // ----- Identity intro fast-path -----
96
71
  if (conversationKey === IDENTITY_INTRO_KEY) {
97
- const soulIntro = readSoulIdentityIntro();
98
- const fastText = soulIntro ?? getCachedIntro()?.text;
72
+ let fastText: string | undefined;
73
+ const identityPath = getWorkspacePromptPath("IDENTITY.md");
74
+ if (existsSync(identityPath)) {
75
+ const fields = parseIdentityFields(readFileSync(identityPath, "utf-8"));
76
+ if (fields.name) {
77
+ fastText = `Hi, I'm ${fields.name}!`;
78
+ }
79
+ }
80
+ fastText ??= getCachedIntro()?.text;
99
81
  if (fastText) {
100
- log.debug(
101
- soulIntro
102
- ? "Returning SOUL.md identity intro"
103
- : "Returning cached identity intro",
104
- );
82
+ log.debug("Returning identity intro fast-path");
105
83
  return new ReadableStream({
106
84
  start(controller) {
107
85
  controller.enqueue(sseEvent("btw_text_delta", { text: fastText }));
@@ -129,9 +107,7 @@ async function handleBtw({
129
107
  try {
130
108
  conversation = await getOrCreateConversation(conversationId);
131
109
  } catch {
132
- throw new ServiceUnavailableError(
133
- "Message processing is not available",
134
- );
110
+ throw new ServiceUnavailableError("Message processing is not available");
135
111
  }
136
112
 
137
113
  return new ReadableStream({
@@ -145,6 +121,7 @@ async function handleBtw({
145
121
  const result = await runBtwSidechain({
146
122
  content: effectiveContent,
147
123
  conversation,
124
+ tools: buildToolDefinitions(),
148
125
  signal: abortSignal,
149
126
  userPersona,
150
127
  channelPersona,
@@ -48,6 +48,7 @@ export const ROUTES: RouteDefinition[] = [
48
48
  clientId: c.clientId,
49
49
  interfaceId: c.interfaceId,
50
50
  capabilities: c.capabilities,
51
+ machineName: c.machineName,
51
52
  connectedAt: c.connectedAt,
52
53
  lastActiveAt: c.lastActiveAt,
53
54
  }),