@vellumai/assistant 0.6.6 → 0.7.1

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 (1603) hide show
  1. package/AGENTS.md +20 -0
  2. package/ARCHITECTURE.md +46 -38
  3. package/Dockerfile +27 -6
  4. package/README.md +9 -11
  5. package/__tests__/permissions/gateway-threshold-reader.test.ts +83 -149
  6. package/bun.lock +309 -119
  7. package/docs/architecture/memory.md +1 -90
  8. package/docs/architecture/security.md +28 -41
  9. package/docs/credential-execution-service.md +7 -5
  10. package/docs/skills.md +10 -10
  11. package/docs/stt-provider-onboarding.md +17 -45
  12. package/examples/plugins/echo/bun.lock +25 -0
  13. package/knip.json +9 -22
  14. package/node_modules/@vellumai/ces-client/bun.lock +33 -0
  15. package/node_modules/@vellumai/ces-client/package.json +25 -0
  16. package/node_modules/@vellumai/ces-client/src/__tests__/ces-client.test.ts +631 -0
  17. package/node_modules/@vellumai/ces-client/src/__tests__/package-boundary.test.ts +138 -0
  18. package/node_modules/@vellumai/ces-client/src/credential-rpc.ts +13 -0
  19. package/node_modules/@vellumai/ces-client/src/http-credentials.ts +296 -0
  20. package/node_modules/@vellumai/ces-client/src/http-log-export.ts +111 -0
  21. package/node_modules/@vellumai/ces-client/src/index.ts +43 -0
  22. package/node_modules/@vellumai/ces-client/src/rpc-client.ts +445 -0
  23. package/node_modules/@vellumai/credential-storage/src/__tests__/package-boundary.test.ts +32 -6
  24. package/node_modules/@vellumai/egress-proxy/src/__tests__/package-boundary.test.ts +32 -1
  25. package/node_modules/@vellumai/gateway-client/bun.lock +39 -0
  26. package/node_modules/@vellumai/gateway-client/package.json +23 -0
  27. package/node_modules/@vellumai/gateway-client/src/__tests__/gateway-client.test.ts +343 -0
  28. package/node_modules/@vellumai/gateway-client/src/__tests__/package-boundary.test.ts +140 -0
  29. package/node_modules/@vellumai/gateway-client/src/http-delivery.ts +422 -0
  30. package/node_modules/@vellumai/gateway-client/src/index.ts +35 -0
  31. package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +331 -0
  32. package/node_modules/@vellumai/gateway-client/src/types.ts +131 -0
  33. package/node_modules/@vellumai/gateway-client/tsconfig.json +20 -0
  34. package/node_modules/@vellumai/{ces-contracts → service-contracts}/bun.lock +1 -1
  35. package/node_modules/@vellumai/{ces-contracts → service-contracts}/package.json +4 -2
  36. package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/__tests__/contracts.test.ts +5 -1
  37. package/node_modules/@vellumai/service-contracts/src/__tests__/package-boundary.test.ts +155 -0
  38. package/node_modules/@vellumai/service-contracts/src/credential-rpc.ts +23 -0
  39. package/node_modules/@vellumai/service-contracts/src/index.ts +25 -0
  40. package/node_modules/@vellumai/{ces-contracts/src/index.ts → service-contracts/src/transport.ts} +6 -28
  41. package/node_modules/@vellumai/service-contracts/src/trust-rules.ts +116 -0
  42. package/node_modules/@vellumai/service-contracts/tsconfig.json +20 -0
  43. package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +887 -0
  44. package/node_modules/@vellumai/skill-host-contracts/bun.lock +24 -0
  45. package/node_modules/@vellumai/skill-host-contracts/package.json +18 -0
  46. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +86 -0
  47. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +1342 -0
  48. package/node_modules/@vellumai/skill-host-contracts/src/index.ts +6 -0
  49. package/node_modules/@vellumai/skill-host-contracts/src/runtime-mode.ts +11 -0
  50. package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +32 -0
  51. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +325 -0
  52. package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +444 -0
  53. package/node_modules/@vellumai/skill-host-contracts/tsconfig.json +20 -0
  54. package/node_modules/@vellumai/skill-host-contracts/tsconfig.test.json +12 -0
  55. package/node_modules/@vellumai/slack-text/bun.lock +24 -0
  56. package/node_modules/@vellumai/slack-text/package.json +18 -0
  57. package/node_modules/@vellumai/slack-text/src/index.test.ts +153 -0
  58. package/node_modules/@vellumai/slack-text/src/index.ts +235 -0
  59. package/node_modules/@vellumai/slack-text/tsconfig.json +20 -0
  60. package/openapi.yaml +3136 -650
  61. package/package.json +15 -7
  62. package/scripts/check-circular-deps.ts +80 -0
  63. package/scripts/generate-openapi.ts +29 -107
  64. package/{src/memory/graph/inspect.ts → scripts/memory-inspect.ts} +27 -27
  65. package/src/__tests__/access-request-decision.test.ts +2 -11
  66. package/src/__tests__/acp-session.test.ts +4 -150
  67. package/src/__tests__/actor-token-service.test.ts +17 -678
  68. package/src/__tests__/agent-loop-callsite-precedence.test.ts +2 -6
  69. package/src/__tests__/agent-loop-override-profile.test.ts +404 -0
  70. package/src/__tests__/agent-loop-thinking.test.ts +4 -4
  71. package/src/__tests__/agent-wake-override-profile.test.ts +283 -0
  72. package/src/__tests__/always-loaded-tools-guard.test.ts +2 -1
  73. package/src/__tests__/anthropic-provider.test.ts +183 -28
  74. package/src/__tests__/app-conversation-ids-backfill.test.ts +278 -0
  75. package/src/__tests__/app-conversation-ids.test.ts +151 -0
  76. package/src/__tests__/app-routes-csp.test.ts +106 -55
  77. package/src/__tests__/approval-cascade.test.ts +3 -370
  78. package/src/__tests__/approval-conversation-turn.test.ts +3 -8
  79. package/src/__tests__/approval-hardcoded-copy-guard.test.ts +1 -1
  80. package/src/__tests__/approval-primitive.test.ts +2 -1
  81. package/src/__tests__/approval-routes-http.test.ts +36 -464
  82. package/src/__tests__/assistant-event-hub.test.ts +126 -77
  83. package/src/__tests__/assistant-event.test.ts +0 -5
  84. package/src/__tests__/assistant-events-sse-hardening.test.ts +107 -92
  85. package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -29
  86. package/src/__tests__/assistant-id-boundary-guard.test.ts +0 -3
  87. package/src/__tests__/attachment-upload-trusted-source.test.ts +139 -0
  88. package/src/__tests__/attachments-store.test.ts +46 -1
  89. package/src/__tests__/audit-log-rotation.test.ts +2 -1
  90. package/src/__tests__/auto-analysis-end-to-end.test.ts +8 -20
  91. package/src/__tests__/background-shell-bash.test.ts +227 -0
  92. package/src/__tests__/background-shell-host-bash.test.ts +465 -0
  93. package/src/__tests__/background-tool-registry.test.ts +145 -0
  94. package/src/__tests__/background-tool-routes.test.ts +175 -0
  95. package/src/__tests__/btw-routes.test.ts +147 -183
  96. package/src/__tests__/call-controller.test.ts +15 -2
  97. package/src/__tests__/call-conversation-messages.test.ts +2 -1
  98. package/src/__tests__/call-domain.test.ts +2 -2
  99. package/src/__tests__/call-pointer-messages.test.ts +11 -13
  100. package/src/__tests__/call-recovery.test.ts +2 -1
  101. package/src/__tests__/call-routes-http.test.ts +3 -14
  102. package/src/__tests__/call-site-routing-provider.test.ts +193 -0
  103. package/src/__tests__/call-store.test.ts +2 -1
  104. package/src/__tests__/cancel-resolves-conversation-key.test.ts +31 -62
  105. package/src/__tests__/canonical-guardian-store.test.ts +2 -2
  106. package/src/__tests__/catalog-files.test.ts +0 -26
  107. package/src/__tests__/ces-rpc-credential-backend.test.ts +1 -1
  108. package/src/__tests__/channel-approval-routes.test.ts +88 -344
  109. package/src/__tests__/channel-approval.test.ts +9 -7
  110. package/src/__tests__/channel-approvals.test.ts +34 -197
  111. package/src/__tests__/channel-delivery-store.test.ts +11 -10
  112. package/src/__tests__/channel-guardian.test.ts +114 -171
  113. package/src/__tests__/channel-readiness-service.test.ts +8 -6
  114. package/src/__tests__/channel-reply-delivery.test.ts +3 -19
  115. package/src/__tests__/channel-retry-sweep.test.ts +2 -5
  116. package/src/__tests__/checker.test.ts +272 -3933
  117. package/src/__tests__/circuit-breaker-pipeline.test.ts +1 -1
  118. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +208 -0
  119. package/src/__tests__/cli.test.ts +1 -38
  120. package/src/__tests__/compact-event-conversation-id-guard.test.ts +50 -0
  121. package/src/__tests__/compaction-events.test.ts +2 -1
  122. package/src/__tests__/compaction-pipeline.test.ts +1 -1
  123. package/src/__tests__/compaction-strip-metadata-clear.test.ts +2 -2
  124. package/src/__tests__/compaction-timeout-recovery.test.ts +1 -1
  125. package/src/__tests__/config-managed-gemini-defaults.test.ts +3 -7
  126. package/src/__tests__/config-model-image-provider.test.ts +0 -1
  127. package/src/__tests__/config-schema-cmd.test.ts +1 -1
  128. package/src/__tests__/config-schema.test.ts +36 -269
  129. package/src/__tests__/config-watcher.test.ts +12 -0
  130. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +4 -25
  131. package/src/__tests__/connection-policy.test.ts +1 -52
  132. package/src/__tests__/contact-store-user-file.test.ts +2 -1
  133. package/src/__tests__/contacts-tools.test.ts +56 -29
  134. package/src/__tests__/contacts-write.test.ts +8 -125
  135. package/src/__tests__/context-image-dimensions.test.ts +1 -1
  136. package/src/__tests__/context-search-agent-protocol.test.ts +230 -0
  137. package/src/__tests__/context-search-agent-runner.test.ts +998 -0
  138. package/src/__tests__/context-search-conversations-source.test.ts +320 -0
  139. package/src/__tests__/context-search-fanout.test.ts +380 -0
  140. package/src/__tests__/context-search-memory-source.test.ts +430 -0
  141. package/src/__tests__/context-search-memory-v2-source.test.ts +383 -0
  142. package/src/__tests__/context-search-pkb-source.test.ts +493 -0
  143. package/src/__tests__/context-search-types.test.ts +95 -0
  144. package/src/__tests__/context-search-workspace-source.test.ts +532 -0
  145. package/src/__tests__/context-window-manager.test.ts +71 -0
  146. package/src/__tests__/conversation-abort-tool-results.test.ts +10 -1
  147. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +633 -0
  148. package/src/__tests__/conversation-agent-loop-overflow.test.ts +117 -31
  149. package/src/__tests__/conversation-agent-loop.test.ts +1004 -15
  150. package/src/__tests__/conversation-analysis-routes.test.ts +68 -88
  151. package/src/__tests__/conversation-attachments.test.ts +9 -20
  152. package/src/__tests__/conversation-attention-store.test.ts +2 -1
  153. package/src/__tests__/conversation-attention-telegram.test.ts +15 -5
  154. package/src/__tests__/conversation-clear-safety.test.ts +53 -95
  155. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -330
  156. package/src/__tests__/conversation-crud-inference-profile.test.ts +54 -0
  157. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +63 -157
  158. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
  159. package/src/__tests__/conversation-disk-view.test.ts +5 -4
  160. package/src/__tests__/conversation-fork-crud.test.ts +26 -55
  161. package/src/__tests__/conversation-fork-route.test.ts +5 -74
  162. package/src/__tests__/conversation-history-web-search.test.ts +4 -3
  163. package/src/__tests__/conversation-inference-profile-list.test.ts +128 -0
  164. package/src/__tests__/conversation-inference-profile-route.test.ts +205 -0
  165. package/src/__tests__/conversation-init.benchmark.test.ts +4 -81
  166. package/src/__tests__/conversation-key-store-disk-view.test.ts +2 -1
  167. package/src/__tests__/conversation-lifecycle.test.ts +4 -5
  168. package/src/__tests__/conversation-list-source.test.ts +2 -2
  169. package/src/__tests__/conversation-load-history-repair.test.ts +0 -1
  170. package/src/__tests__/conversation-pairing.test.ts +0 -1
  171. package/src/__tests__/conversation-pre-run-repair.test.ts +137 -297
  172. package/src/__tests__/conversation-process-callsite.test.ts +79 -3
  173. package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -1
  174. package/src/__tests__/conversation-queue.test.ts +4 -41
  175. package/src/__tests__/conversation-routes-disk-view.test.ts +55 -188
  176. package/src/__tests__/conversation-routes-guardian-reply.test.ts +64 -71
  177. package/src/__tests__/conversation-routes-slash-commands.test.ts +144 -64
  178. package/src/__tests__/conversation-runtime-assembly.test.ts +295 -84
  179. package/src/__tests__/conversation-slash-commands.test.ts +30 -47
  180. package/src/__tests__/conversation-slash-queue.test.ts +2 -1
  181. package/src/__tests__/conversation-slash-unknown.test.ts +0 -1
  182. package/src/__tests__/conversation-speed-override.test.ts +0 -4
  183. package/src/__tests__/conversation-starter-routes.test.ts +254 -55
  184. package/src/__tests__/conversation-starters-cadence.test.ts +2 -2
  185. package/src/__tests__/conversation-store.test.ts +2 -375
  186. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -5
  187. package/src/__tests__/conversation-surfaces-standalone.test.ts +18 -14
  188. package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -2
  189. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +9 -47
  190. package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +6 -6
  191. package/src/__tests__/conversation-unread-route.test.ts +1 -1
  192. package/src/__tests__/conversation-usage.test.ts +255 -4
  193. package/src/__tests__/conversation-wipe.test.ts +2 -103
  194. package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -1
  195. package/src/__tests__/conversation-workspace-injection.test.ts +0 -1
  196. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -1
  197. package/src/__tests__/conversations-defer-cli.test.ts +150 -0
  198. package/src/__tests__/credential-execution-admin-cli.test.ts +1 -1
  199. package/src/__tests__/credential-execution-api-key-propagation.test.ts +2 -2
  200. package/src/__tests__/credential-execution-approval-bridge.test.ts +22 -289
  201. package/src/__tests__/credential-execution-client.test.ts +1 -1
  202. package/src/__tests__/credential-execution-managed-contract.test.ts +1 -1
  203. package/src/__tests__/credential-execution-shell-lockdown.test.ts +0 -39
  204. package/src/__tests__/credential-health-service.test.ts +68 -0
  205. package/src/__tests__/credential-security-e2e.test.ts +4 -3
  206. package/src/__tests__/credential-security-invariants.test.ts +15 -5
  207. package/src/__tests__/credential-token-resolver.test.ts +180 -0
  208. package/src/__tests__/credentials-cli.test.ts +45 -21
  209. package/src/__tests__/cu-unified-flow.test.ts +33 -16
  210. package/src/__tests__/daemon-assistant-events.test.ts +34 -21
  211. package/src/__tests__/daemon-credential-client.test.ts +26 -108
  212. package/src/__tests__/db-acp-history.test.ts +284 -0
  213. package/src/__tests__/db-activation-state.test.ts +240 -0
  214. package/src/__tests__/db-connection-isolation.test.ts +125 -0
  215. package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +2 -1
  216. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +248 -0
  217. package/src/__tests__/db-llm-request-log-provider-migration.test.ts +2 -1
  218. package/src/__tests__/db-memory-graph-event-date-repair.test.ts +116 -0
  219. package/src/__tests__/db-migration-rollback.test.ts +101 -0
  220. package/src/__tests__/db-rename-inference-profile-snake-case-migration.test.ts +132 -0
  221. package/src/__tests__/db-schedule-syntax-migration.test.ts +1 -0
  222. package/src/__tests__/db-slack-compaction-watermark-migration.test.ts +169 -0
  223. package/src/__tests__/delete-propagation.test.ts +3 -2
  224. package/src/__tests__/deterministic-verification-control-plane.test.ts +38 -104
  225. package/src/__tests__/dm-backfill.test.ts +3 -2
  226. package/src/__tests__/document-conversations.test.ts +332 -0
  227. package/src/__tests__/edit-propagation.test.ts +5 -7
  228. package/src/__tests__/embedding-managed-proxy-selection.test.ts +3 -3
  229. package/src/__tests__/emit-event-signal.test.ts +4 -6
  230. package/src/__tests__/empty-response-pipeline.test.ts +1 -1
  231. package/src/__tests__/events-client-registration.test.ts +441 -0
  232. package/src/__tests__/file-write-tool.test.ts +2 -4
  233. package/src/__tests__/filing-service.test.ts +197 -19
  234. package/src/__tests__/first-greeting.test.ts +156 -150
  235. package/src/__tests__/fixtures/mock-chrome-extension.ts +108 -66
  236. package/src/__tests__/followup-tools.test.ts +2 -1
  237. package/src/__tests__/gateway-client-managed-outbound.test.ts +8 -12
  238. package/src/__tests__/gateway-only-enforcement.test.ts +2 -6
  239. package/src/__tests__/gateway-only-guard.test.ts +4 -3
  240. package/src/__tests__/gemini-provider.test.ts +276 -10
  241. package/src/__tests__/get-skill-detail-audit.test.ts +3 -8
  242. package/src/__tests__/graph-extraction-event-date.test.ts +30 -0
  243. package/src/__tests__/guardian-action-conversation-turn.test.ts +2 -1
  244. package/src/__tests__/guardian-action-followup-executor.test.ts +2 -2
  245. package/src/__tests__/guardian-action-followup-store.test.ts +2 -1
  246. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +9 -9
  247. package/src/__tests__/guardian-action-late-reply.test.ts +2 -1
  248. package/src/__tests__/guardian-action-store.test.ts +2 -1
  249. package/src/__tests__/guardian-action-sweep.test.ts +9 -8
  250. package/src/__tests__/guardian-binding-drift-heal.test.ts +3 -2
  251. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +21 -118
  252. package/src/__tests__/guardian-dispatch.test.ts +14 -11
  253. package/src/__tests__/guardian-grant-minting.test.ts +16 -17
  254. package/src/__tests__/guardian-outbound-http.test.ts +71 -106
  255. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +2 -2
  256. package/src/__tests__/guardian-routing-invariants.test.ts +41 -92
  257. package/src/__tests__/guardian-routing-state.test.ts +15 -23
  258. package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -2
  259. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +274 -0
  260. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +10 -87
  261. package/src/__tests__/headless-browser-mode.test.ts +4 -9
  262. package/src/__tests__/headless-browser-navigate.test.ts +21 -20
  263. package/src/__tests__/heartbeat-service.test.ts +325 -25
  264. package/src/__tests__/helpers/call-route-handler.ts +72 -0
  265. package/src/__tests__/helpers/channel-test-adapter.ts +161 -0
  266. package/src/__tests__/helpers/create-guardian-binding.ts +91 -0
  267. package/src/__tests__/helpers/gateway-classify-mock.ts +67 -0
  268. package/src/__tests__/helpers/mock-logger.ts +36 -0
  269. package/src/__tests__/history-repair-pipeline.test.ts +1 -1
  270. package/src/__tests__/home-state-routes.test.ts +10 -31
  271. package/src/__tests__/host-bash-proxy.test.ts +46 -122
  272. package/src/__tests__/host-browser-e2e-cloud.test.ts +38 -498
  273. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +35 -95
  274. package/src/__tests__/host-browser-proxy.test.ts +111 -185
  275. package/src/__tests__/host-browser-routes.test.ts +68 -153
  276. package/src/__tests__/host-browser-ws-events-e2e.test.ts +35 -31
  277. package/src/__tests__/host-cu-proxy.test.ts +56 -111
  278. package/src/__tests__/host-file-proxy.test.ts +44 -98
  279. package/src/__tests__/host-file-read-tool.test.ts +42 -21
  280. package/src/__tests__/host-proxy-interface.test.ts +3 -3
  281. package/src/__tests__/host-shell-tool.test.ts +35 -72
  282. package/src/__tests__/host-transfer-pending-interactions.test.ts +144 -0
  283. package/src/__tests__/host-transfer-proxy.test.ts +723 -0
  284. package/src/__tests__/http-conversation-lineage.test.ts +3 -2
  285. package/src/__tests__/http-user-message-parity.test.ts +18 -15
  286. package/src/__tests__/inbound-invite-redemption.test.ts +3 -2
  287. package/src/__tests__/inbound-slack-persistence.test.ts +31 -0
  288. package/src/__tests__/injector-chain.test.ts +25 -21
  289. package/src/__tests__/injector-pkb-v2-silenced.test.ts +124 -0
  290. package/src/__tests__/inline-command-runner.test.ts +0 -66
  291. package/src/__tests__/inline-skill-load-permissions.test.ts +41 -208
  292. package/src/__tests__/install-skill-routing.test.ts +2 -14
  293. package/src/__tests__/invite-redemption-service.test.ts +2 -1
  294. package/src/__tests__/invite-routes-http.test.ts +80 -12
  295. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +2 -1
  296. package/src/__tests__/jobs-store-upsert-debounced.test.ts +2 -1
  297. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +157 -0
  298. package/src/__tests__/list-messages-attachments.test.ts +52 -55
  299. package/src/__tests__/list-messages-page-latest.test.ts +283 -0
  300. package/src/__tests__/list-messages-tool-merge.test.ts +16 -17
  301. package/src/__tests__/llm-call-pipeline.test.ts +7 -8
  302. package/src/__tests__/llm-callsite-catalog.test.ts +34 -0
  303. package/src/__tests__/llm-catalog-parity.test.ts +90 -0
  304. package/src/__tests__/llm-context-normalization.test.ts +69 -4
  305. package/src/__tests__/llm-context-resolution.test.ts +180 -0
  306. package/src/__tests__/llm-context-route-provider.test.ts +39 -113
  307. package/src/__tests__/llm-request-log-turn-query.test.ts +2 -1
  308. package/src/__tests__/llm-resolver.test.ts +279 -0
  309. package/src/__tests__/llm-schema.test.ts +57 -1
  310. package/src/__tests__/llm-usage-store.test.ts +271 -5
  311. package/src/__tests__/log-export-routes.test.ts +89 -0
  312. package/src/__tests__/log-export-workspace.test.ts +28 -17
  313. package/src/__tests__/managed-profile-guard.test.ts +225 -0
  314. package/src/__tests__/managed-skill-lifecycle.test.ts +0 -10
  315. package/src/__tests__/manual-token-reconciliation.test.ts +334 -0
  316. package/src/__tests__/mcp-abort-signal.test.ts +2 -3
  317. package/src/__tests__/mcp-client-auth.test.ts +2 -3
  318. package/src/__tests__/memory-admin-recall.test.ts +221 -0
  319. package/src/__tests__/memory-recall-log-store.test.ts +2 -1
  320. package/src/__tests__/memory-retrieval-pipeline.test.ts +6 -8
  321. package/src/__tests__/memory-upsert-concurrency.test.ts +2 -1
  322. package/src/__tests__/memory-v2-static-injector.test.ts +95 -0
  323. package/src/__tests__/migration-cross-version-compatibility.test.ts +209 -302
  324. package/src/__tests__/migration-export-http.test.ts +50 -43
  325. package/src/__tests__/migration-export-streaming.test.ts +18 -10
  326. package/src/__tests__/migration-export-to-gcs.test.ts +531 -0
  327. package/src/__tests__/migration-import-commit-http.test.ts +82 -37
  328. package/src/__tests__/migration-import-from-gcs.test.ts +574 -0
  329. package/src/__tests__/migration-import-from-url.test.ts +34 -27
  330. package/src/__tests__/migration-import-preflight-http.test.ts +108 -108
  331. package/src/__tests__/migration-jobs-status.test.ts +164 -0
  332. package/src/__tests__/migration-parity-persistence.test.ts +62 -25
  333. package/src/__tests__/migration-transport.test.ts +115 -23
  334. package/src/__tests__/migration-validate-http.test.ts +149 -159
  335. package/src/__tests__/migration-wizard.test.ts +133 -27
  336. package/src/__tests__/mock-gateway-ipc.ts +32 -62
  337. package/src/__tests__/model-intents.test.ts +15 -2
  338. package/src/__tests__/nl-approval-parser.test.ts +13 -17
  339. package/src/__tests__/non-member-access-request.test.ts +14 -6
  340. package/src/__tests__/notification-guardian-path.test.ts +15 -8
  341. package/src/__tests__/notification-schedule-notify-dedup.test.ts +2 -1
  342. package/src/__tests__/notification-telegram-adapter.test.ts +57 -55
  343. package/src/__tests__/oauth-apps-routes.test.ts +76 -122
  344. package/src/__tests__/oauth-cli.test.ts +14 -1
  345. package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
  346. package/src/__tests__/oauth-provider-visibility.test.ts +3 -1
  347. package/src/__tests__/oauth-providers-routes.test.ts +78 -101
  348. package/src/__tests__/oauth-store.test.ts +22 -1
  349. package/src/__tests__/oauth2-gateway-transport.test.ts +6 -3
  350. package/src/__tests__/openai-provider.test.ts +105 -6
  351. package/src/__tests__/openai-responses-provider.test.ts +146 -4
  352. package/src/__tests__/openrouter-provider-only.test.ts +22 -4
  353. package/src/__tests__/overflow-reduce-pipeline.test.ts +4 -9
  354. package/src/__tests__/permission-types.test.ts +3 -18
  355. package/src/__tests__/persistence-pipeline.test.ts +3 -2
  356. package/src/__tests__/pipeline-runner.test.ts +1 -1
  357. package/src/__tests__/platform-bash-auto-approve.test.ts +44 -28
  358. package/src/__tests__/platform.test.ts +11 -63
  359. package/src/__tests__/playbook-execution.test.ts +2 -1
  360. package/src/__tests__/playbook-tools.test.ts +2 -1
  361. package/src/__tests__/plugin-bootstrap.test.ts +51 -5
  362. package/src/__tests__/plugin-registry.test.ts +30 -0
  363. package/src/__tests__/plugin-route-contribution.test.ts +17 -11
  364. package/src/__tests__/plugin-skill-contribution.test.ts +3 -3
  365. package/src/__tests__/plugin-tool-contribution.test.ts +10 -4
  366. package/src/__tests__/plugin-types.test.ts +1 -1
  367. package/src/__tests__/prechat-onboarding-contract.test.ts +31 -7
  368. package/src/__tests__/pricing.test.ts +218 -5
  369. package/src/__tests__/process-message-background-slack.test.ts +331 -0
  370. package/src/__tests__/profiler-routes.test.ts +112 -177
  371. package/src/__tests__/provider-managed-proxy-integration.test.ts +153 -17
  372. package/src/__tests__/provider-send-message-override-profile.test.ts +273 -0
  373. package/src/__tests__/provider-usage-tracking.test.ts +208 -0
  374. package/src/__tests__/proxy-approval-callback.test.ts +6 -554
  375. package/src/__tests__/qdrant-collection-migration.test.ts +7 -7
  376. package/src/__tests__/reaction-persistence.test.ts +12 -8
  377. package/src/__tests__/rebind-secrets-screen.test.ts +53 -16
  378. package/src/__tests__/rebuild-index-graph-nodes.test.ts +1 -1
  379. package/src/__tests__/recording-handler.test.ts +64 -83
  380. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +4 -3
  381. package/src/__tests__/registry.test.ts +1 -0
  382. package/src/__tests__/relay-server.test.ts +37 -17
  383. package/src/__tests__/require-fresh-approval.test.ts +24 -182
  384. package/src/__tests__/resolve-trust-class.test.ts +2 -1
  385. package/src/__tests__/retry-thinking-tool-choice.test.ts +19 -7
  386. package/src/__tests__/retry-verbosity-normalization.test.ts +139 -0
  387. package/src/__tests__/runtime-attachment-metadata.test.ts +26 -6
  388. package/src/__tests__/runtime-events-sse-parity.test.ts +15 -17
  389. package/src/__tests__/runtime-events-sse.test.ts +16 -33
  390. package/src/__tests__/schedule-routes.test.ts +226 -129
  391. package/src/__tests__/schedule-store.test.ts +119 -1
  392. package/src/__tests__/schedule-tools.test.ts +2 -1
  393. package/src/__tests__/scheduler-recurrence.test.ts +2 -1
  394. package/src/__tests__/scheduler-reuse-conversation.test.ts +2 -1
  395. package/src/__tests__/scheduler-wake.test.ts +356 -0
  396. package/src/__tests__/scoped-approval-grants.test.ts +2 -1
  397. package/src/__tests__/scoped-grant-security-matrix.test.ts +2 -1
  398. package/src/__tests__/search-skills-unified.test.ts +9 -15
  399. package/src/__tests__/secret-ingress-cli.test.ts +2 -5
  400. package/src/__tests__/secret-ingress-http.test.ts +36 -23
  401. package/src/__tests__/secret-onetime-send.test.ts +4 -2
  402. package/src/__tests__/secret-prompt-log-hygiene.test.ts +24 -7
  403. package/src/__tests__/secret-prompter-channel-fallback.test.ts +42 -47
  404. package/src/__tests__/secret-response-routing.test.ts +29 -15
  405. package/src/__tests__/secret-routes-managed-proxy.test.ts +51 -103
  406. package/src/__tests__/secret-scanner.test.ts +2 -545
  407. package/src/__tests__/send-endpoint-busy.test.ts +36 -38
  408. package/src/__tests__/sequence-store.test.ts +2 -1
  409. package/src/__tests__/server-history-render.test.ts +2 -2
  410. package/src/__tests__/service-contracts-import-guard.test.ts +185 -0
  411. package/src/__tests__/set-permission-mode.test.ts +0 -10
  412. package/src/__tests__/settings-routes.test.ts +36 -69
  413. package/src/__tests__/shell-credential-ref.test.ts +0 -8
  414. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -56
  415. package/src/__tests__/skill-boundary-guard.test.ts +105 -0
  416. package/src/__tests__/skill-load-inline-command.test.ts +2 -2
  417. package/src/__tests__/skill-load-inline-includes.test.ts +2 -2
  418. package/src/__tests__/skill-runtime-path.test.ts +64 -0
  419. package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -11
  420. package/src/__tests__/skill-tool-factory.test.ts +97 -0
  421. package/src/__tests__/skills-file-content-endpoint.test.ts +9 -32
  422. package/src/__tests__/skills-files-catalog-fallback.test.ts +11 -17
  423. package/src/__tests__/slack-inbound-verification.test.ts +12 -64
  424. package/src/__tests__/slack-messaging-token-resolution.test.ts +1 -3
  425. package/src/__tests__/slack-reaction-approvals.test.ts +4 -4
  426. package/src/__tests__/slack-share-routes.test.ts +37 -72
  427. package/src/__tests__/subagent-call-site-routing.test.ts +79 -0
  428. package/src/__tests__/subagent-fork-notifications.test.ts +57 -47
  429. package/src/__tests__/subagent-fork-spawn.test.ts +20 -28
  430. package/src/__tests__/subagent-manager-notify.test.ts +70 -70
  431. package/src/__tests__/subagent-notify-parent.test.ts +83 -109
  432. package/src/__tests__/subagent-role-registry.test.ts +3 -3
  433. package/src/__tests__/subagent-spawn-tool-fork.test.ts +52 -104
  434. package/src/__tests__/subagent-tools.test.ts +0 -1
  435. package/src/__tests__/suggestion-routes.test.ts +55 -62
  436. package/src/__tests__/system-prompt.test.ts +115 -13
  437. package/src/__tests__/task-compiler.test.ts +2 -1
  438. package/src/__tests__/task-management-tools.test.ts +2 -1
  439. package/src/__tests__/task-memory-cleanup.test.ts +2 -1
  440. package/src/__tests__/task-scheduler.test.ts +2 -1
  441. package/src/__tests__/telegram-config.test.ts +0 -1
  442. package/src/__tests__/terminal-tools.test.ts +3 -401
  443. package/src/__tests__/test-preload.ts +0 -11
  444. package/src/__tests__/thread-backfill.test.ts +947 -32
  445. package/src/__tests__/token-estimate-pipeline.test.ts +68 -15
  446. package/src/__tests__/tool-approval-handler.test.ts +21 -63
  447. package/src/__tests__/tool-audit-listener.test.ts +3 -3
  448. package/src/__tests__/tool-domain-event-publisher.test.ts +3 -39
  449. package/src/__tests__/tool-error-pipeline.test.ts +6 -6
  450. package/src/__tests__/tool-execute-pipeline.test.ts +6 -14
  451. package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -16
  452. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +69 -16
  453. package/src/__tests__/tool-executor-lifecycle-events.test.ts +31 -62
  454. package/src/__tests__/tool-executor.test.ts +336 -1654
  455. package/src/__tests__/tool-grant-request-escalation.test.ts +90 -311
  456. package/src/__tests__/tool-metrics-listener.test.ts +0 -35
  457. package/src/__tests__/tool-result-truncate-pipeline.test.ts +1 -1
  458. package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
  459. package/src/__tests__/tool-trace-listener.test.ts +0 -17
  460. package/src/__tests__/transfer-progress-screen.test.ts +63 -26
  461. package/src/__tests__/trust-context-guards.test.ts +1 -1
  462. package/src/__tests__/trusted-contact-approval-notifier.test.ts +7 -15
  463. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +178 -354
  464. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +5 -151
  465. package/src/__tests__/trusted-contact-multichannel.test.ts +5 -6
  466. package/src/__tests__/trusted-contact-verification.test.ts +3 -2
  467. package/src/__tests__/tts-catalog-parity.test.ts +16 -5
  468. package/src/__tests__/turn-boundary-resolution.test.ts +2 -1
  469. package/src/__tests__/twilio-routes.test.ts +25 -66
  470. package/src/__tests__/usage-attribution.test.ts +247 -0
  471. package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -7
  472. package/src/__tests__/usage-cli.test.ts +143 -0
  473. package/src/__tests__/usage-grouped-buckets.test.ts +155 -0
  474. package/src/__tests__/usage-routes.test.ts +223 -90
  475. package/src/__tests__/user-plugin-loader.test.ts +54 -12
  476. package/src/__tests__/validation-results-screen.test.ts +39 -16
  477. package/src/__tests__/vbundle-pax-and-symlink.test.ts +12 -3
  478. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +51 -139
  479. package/src/__tests__/verification-control-plane-policy.test.ts +97 -19
  480. package/src/__tests__/voice-ingress-preflight.test.ts +5 -5
  481. package/src/__tests__/voice-invite-redemption.test.ts +2 -1
  482. package/src/__tests__/voice-scoped-grant-consumer.test.ts +3 -3
  483. package/src/__tests__/voice-session-bridge.test.ts +285 -106
  484. package/src/__tests__/volume-security-guard.test.ts +0 -2
  485. package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +2 -1
  486. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +3 -1
  487. package/src/__tests__/workspace-migration-028-recover-conversations-from-disk-view.test.ts +2 -1
  488. package/src/__tests__/workspace-migration-045-release-notes-meet-avatar.test.ts +1 -1
  489. package/src/__tests__/workspace-migration-052-seed-default-inference-profiles.test.ts +260 -0
  490. package/src/__tests__/workspace-migration-053-release-notes-acp-codex.test.ts +225 -0
  491. package/src/__tests__/workspace-migration-054-seed-recall-callsite.test.ts +235 -0
  492. package/src/__tests__/workspace-migration-055-release-notes-agentic-recall.test.ts +128 -0
  493. package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +232 -0
  494. package/src/__tests__/workspace-migration-062-drop-memory-v2-edges-json.test.ts +103 -0
  495. package/src/__tests__/workspace-migration-063-release-notes-dynamic-model-context.test.ts +77 -0
  496. package/src/__tests__/workspace-migration-064-unwind-main-agent-opus-seed.test.ts +225 -0
  497. package/src/__tests__/workspace-migration-acp-sessions-ui.test.ts +144 -0
  498. package/src/__tests__/workspace-migration-drop-user-md.test.ts +1 -1
  499. package/src/__tests__/workspace-migration-memory-v2-init.test.ts +252 -0
  500. package/src/acp/__tests__/client-handler.test.ts +64 -0
  501. package/src/acp/__tests__/helpers/acp-config-stub.ts +62 -0
  502. package/src/acp/__tests__/helpers/which-stub.ts +45 -0
  503. package/src/acp/__tests__/session-manager-persistence.test.ts +366 -0
  504. package/src/acp/__tests__/session-manager-startup.test.ts +159 -0
  505. package/src/acp/__tests__/session-manager.test.ts +83 -0
  506. package/src/acp/client-handler.ts +23 -139
  507. package/src/acp/index.ts +0 -15
  508. package/src/acp/resolve-agent.test.ts +291 -0
  509. package/src/acp/resolve-agent.ts +176 -0
  510. package/src/acp/session-manager.ts +193 -31
  511. package/src/acp/types.ts +2 -50
  512. package/src/agent/loop.ts +53 -15
  513. package/src/agent/message-types.ts +0 -2
  514. package/src/approvals/AGENTS.md +5 -1
  515. package/src/approvals/__tests__/guardian-feed-event.test.ts +11 -12
  516. package/src/approvals/approval-primitive.ts +3 -20
  517. package/src/approvals/guardian-decision-primitive.ts +37 -68
  518. package/src/approvals/guardian-request-resolvers.ts +38 -104
  519. package/src/avatar/character-components.ts +6 -6
  520. package/src/{config/bundled-skills/settings/tools → avatar}/identity-avatar.ts +1 -1
  521. package/src/backup/__tests__/backup-worker.test.ts +36 -10
  522. package/src/backup/__tests__/paths.test.ts +5 -4
  523. package/src/backup/__tests__/restore.test.ts +45 -28
  524. package/src/backup/backup-worker.ts +37 -12
  525. package/src/backup/paths.ts +11 -24
  526. package/src/backup/restore.ts +7 -11
  527. package/src/browser/__tests__/operations.test.ts +0 -35
  528. package/src/browser/operations.ts +1 -47
  529. package/src/browser-session/events.ts +0 -9
  530. package/src/bundler/package-resolver.ts +2 -6
  531. package/src/calls/active-call-lease.ts +1 -1
  532. package/src/calls/call-constants.ts +1 -1
  533. package/src/calls/call-controller.ts +1 -5
  534. package/src/calls/call-domain.ts +14 -14
  535. package/src/calls/call-pointer-messages.ts +4 -9
  536. package/src/calls/call-store.ts +2 -34
  537. package/src/calls/guardian-action-sweep.ts +9 -25
  538. package/src/calls/guardian-dispatch.ts +1 -20
  539. package/src/calls/guardian-question-copy.ts +0 -108
  540. package/src/calls/media-stream-audio-transcode.ts +2 -41
  541. package/src/calls/media-stream-server.ts +2 -3
  542. package/src/calls/media-stream-stt-session.ts +1 -3
  543. package/src/calls/relay-access-wait.ts +5 -8
  544. package/src/calls/relay-server.ts +15 -42
  545. package/src/calls/relay-setup-router.ts +2 -2
  546. package/src/calls/relay-verification.ts +4 -4
  547. package/src/calls/twilio-rest.ts +1 -39
  548. package/src/calls/twilio-routes.ts +160 -78
  549. package/src/calls/voice-control-protocol.ts +10 -10
  550. package/src/calls/voice-ingress-preflight.ts +2 -2
  551. package/src/calls/voice-session-bridge.ts +141 -77
  552. package/src/channels/__tests__/types.test.ts +25 -3
  553. package/src/channels/permission-profiles.ts +2 -72
  554. package/src/channels/types.ts +25 -44
  555. package/src/cli/AGENTS.md +1 -0
  556. package/src/cli/__tests__/notifications.test.ts +12 -10
  557. package/src/cli/commands/__tests__/attachment.test.ts +14 -8
  558. package/src/cli/commands/__tests__/backup.test.ts +3 -14
  559. package/src/cli/commands/__tests__/browser.test.ts +36 -31
  560. package/src/cli/commands/__tests__/cache.test.ts +175 -23
  561. package/src/cli/commands/__tests__/memory-v2.test.ts +382 -0
  562. package/src/cli/commands/__tests__/task.test.ts +36 -35
  563. package/src/cli/commands/__tests__/trust.test.ts +236 -0
  564. package/src/cli/commands/__tests__/ui-confirm.test.ts +14 -14
  565. package/src/cli/commands/__tests__/ui.test.ts +17 -17
  566. package/src/cli/commands/__tests__/watchers.test.ts +29 -29
  567. package/src/cli/commands/__tests__/webhooks.test.ts +544 -0
  568. package/src/cli/commands/attachment.ts +12 -8
  569. package/src/cli/commands/auth.ts +1 -1
  570. package/src/cli/commands/avatar.ts +192 -9
  571. package/src/cli/commands/backup.ts +18 -48
  572. package/src/cli/commands/browser.ts +52 -4
  573. package/src/cli/commands/cache-fs.ts +8 -0
  574. package/src/cli/commands/cache.ts +157 -84
  575. package/src/cli/commands/channel-verification-sessions.ts +6 -6
  576. package/src/cli/commands/clients.ts +74 -17
  577. package/src/cli/commands/completions.ts +3 -3
  578. package/src/cli/commands/contacts.ts +241 -86
  579. package/src/cli/commands/conversations-defer.ts +364 -0
  580. package/src/cli/commands/conversations-import.ts +2 -3
  581. package/src/cli/commands/conversations.ts +63 -53
  582. package/src/cli/commands/credential-execution.ts +1 -1
  583. package/src/cli/commands/credentials.ts +139 -5
  584. package/src/cli/commands/default-action.ts +1 -1
  585. package/src/cli/commands/domain.ts +2 -2
  586. package/src/cli/commands/email.ts +7 -7
  587. package/src/cli/commands/image-generation.ts +1 -1
  588. package/src/cli/commands/keys.ts +5 -2
  589. package/src/cli/commands/mcp.ts +1 -1
  590. package/src/cli/commands/memory-v2.ts +315 -0
  591. package/src/cli/commands/memory.ts +8 -8
  592. package/src/cli/commands/notifications.ts +21 -20
  593. package/src/cli/commands/oauth/__tests__/connect.test.ts +23 -5
  594. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +1 -1
  595. package/src/cli/commands/oauth/__tests__/mode.test.ts +1 -1
  596. package/src/cli/commands/oauth/__tests__/status.test.ts +1 -1
  597. package/src/cli/commands/oauth/__tests__/token.test.ts +1 -1
  598. package/src/cli/commands/oauth/connect.ts +2 -2
  599. package/src/cli/commands/pending.ts +102 -0
  600. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -6
  601. package/src/cli/commands/platform/__tests__/connect.test.ts +23 -11
  602. package/src/cli/commands/platform/__tests__/disconnect.test.ts +22 -10
  603. package/src/cli/commands/platform/__tests__/status.test.ts +22 -10
  604. package/src/cli/commands/platform/connect.ts +3 -3
  605. package/src/cli/commands/platform/disconnect.ts +4 -6
  606. package/src/cli/commands/platform/index.ts +12 -10
  607. package/src/cli/commands/routes.ts +7 -1
  608. package/src/cli/commands/sequence.ts +7 -7
  609. package/src/cli/commands/skills.ts +264 -116
  610. package/src/cli/commands/task.ts +12 -10
  611. package/src/cli/commands/trust.ts +105 -167
  612. package/src/cli/commands/ui.ts +3 -3
  613. package/src/cli/commands/usage.ts +29 -15
  614. package/src/cli/commands/watchers.ts +8 -8
  615. package/src/cli/commands/webhooks.ts +270 -0
  616. package/src/cli/lib/daemon-avatar-client.ts +37 -0
  617. package/src/cli/lib/daemon-credential-client.ts +41 -189
  618. package/src/cli/lib/ipc-params.ts +22 -0
  619. package/src/cli/program.ts +6 -0
  620. package/src/cli.ts +1 -82
  621. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  622. package/src/config/acp-defaults.test.ts +57 -0
  623. package/src/config/acp-defaults.ts +40 -0
  624. package/src/config/acp-schema.ts +1 -1
  625. package/src/config/assistant-feature-flags.ts +18 -142
  626. package/src/config/bundled-skills/acp/SKILL.md +44 -16
  627. package/src/config/bundled-skills/acp/TOOLS.json +45 -1
  628. package/src/config/bundled-skills/acp/tools/acp-list-agents.ts +12 -0
  629. package/src/config/bundled-skills/acp/tools/acp-steer.ts +12 -0
  630. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +14 -14
  631. package/src/config/bundled-skills/contacts/tools/contact-search.ts +1 -4
  632. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +11 -6
  633. package/src/config/bundled-skills/media-processing/__tests__/cost-tracker.test.ts +6 -6
  634. package/src/config/bundled-skills/media-processing/services/reduce.ts +0 -13
  635. package/src/config/bundled-skills/messaging/TOOLS.json +14 -4
  636. package/src/config/bundled-skills/messaging/tools/gmail-mime-helpers.ts +1 -1
  637. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +1 -1
  638. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +1 -1
  639. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +1 -1
  640. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +1 -1
  641. package/src/config/bundled-skills/settings/SKILL.md +2 -17
  642. package/src/config/bundled-skills/settings/TOOLS.json +0 -56
  643. package/src/config/bundled-skills/subagent/SKILL.md +2 -0
  644. package/src/config/bundled-tool-registry.ts +4 -6
  645. package/src/config/env-registry.ts +12 -2
  646. package/src/config/env.ts +10 -22
  647. package/src/config/feature-flag-registry.json +38 -46
  648. package/src/config/llm-callsite-catalog.ts +12 -0
  649. package/src/config/llm-context-resolution.ts +80 -0
  650. package/src/config/llm-resolver.ts +90 -36
  651. package/src/config/loader.ts +9 -12
  652. package/src/config/schema.ts +5 -228
  653. package/src/config/schemas/__tests__/filing.test.ts +58 -0
  654. package/src/config/schemas/__tests__/memory-v2.test.ts +187 -0
  655. package/src/config/schemas/call-site-catalog.ts +271 -0
  656. package/src/config/schemas/calls.ts +5 -5
  657. package/src/config/schemas/filing.ts +12 -0
  658. package/src/config/schemas/host-browser.ts +2 -2
  659. package/src/config/schemas/inference.ts +1 -3
  660. package/src/config/schemas/ingress.ts +2 -2
  661. package/src/config/schemas/llm.ts +82 -12
  662. package/src/config/schemas/memory-retrieval.ts +2 -2
  663. package/src/config/schemas/memory-storage.ts +1 -1
  664. package/src/config/schemas/memory-v2.ts +185 -0
  665. package/src/config/schemas/memory.ts +2 -0
  666. package/src/config/schemas/security.ts +1 -102
  667. package/src/config/schemas/services.ts +52 -13
  668. package/src/config/schemas/skills.ts +5 -5
  669. package/src/config/schemas/tts.ts +1 -1
  670. package/src/config/seed-inference-profiles.ts +117 -0
  671. package/src/config/skills.ts +1 -91
  672. package/src/config/types.ts +3 -47
  673. package/src/contacts/contact-store.ts +2 -19
  674. package/src/contacts/contacts-write.ts +1 -143
  675. package/src/contacts/types.ts +8 -10
  676. package/src/context/token-estimator.ts +1 -1
  677. package/src/context/tool-result-truncation.ts +1 -1
  678. package/src/context/window-manager.ts +45 -6
  679. package/src/credential-execution/approval-bridge.ts +7 -69
  680. package/src/credential-execution/client.ts +17 -422
  681. package/src/credential-execution/feature-gates.ts +1 -2
  682. package/src/credential-execution/managed-catalog.ts +1 -1
  683. package/src/credential-execution/process-manager.ts +34 -10
  684. package/src/credential-health/credential-health-service.ts +22 -17
  685. package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -13
  686. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +76 -83
  687. package/src/daemon/__tests__/daemon-skill-host.test.ts +265 -0
  688. package/src/daemon/__tests__/meet-host-supervisor.test.ts +587 -0
  689. package/src/daemon/__tests__/meet-manifest-loader.test.ts +463 -0
  690. package/src/daemon/approval-generators.ts +2 -14
  691. package/src/daemon/classifier.ts +0 -106
  692. package/src/daemon/config-watcher.ts +14 -54
  693. package/src/daemon/connection-policy.ts +1 -40
  694. package/src/daemon/conversation-agent-loop-handlers.ts +89 -9
  695. package/src/daemon/conversation-agent-loop.ts +440 -88
  696. package/src/daemon/conversation-attachments.ts +5 -81
  697. package/src/daemon/conversation-error.ts +9 -5
  698. package/src/daemon/conversation-history.ts +9 -9
  699. package/src/daemon/conversation-launch.ts +21 -136
  700. package/src/daemon/conversation-lifecycle.ts +1 -1
  701. package/src/daemon/conversation-messaging.ts +2 -1
  702. package/src/daemon/conversation-notifiers.ts +1 -1
  703. package/src/daemon/conversation-process.ts +90 -174
  704. package/src/daemon/conversation-runtime-assembly.ts +245 -164
  705. package/src/daemon/conversation-slash.ts +50 -164
  706. package/src/daemon/conversation-store.ts +344 -0
  707. package/src/daemon/conversation-surfaces.ts +27 -32
  708. package/src/daemon/conversation-tool-setup.ts +23 -202
  709. package/src/daemon/conversation-usage.ts +36 -0
  710. package/src/daemon/conversation.ts +129 -381
  711. package/src/daemon/daemon-control.ts +4 -72
  712. package/src/daemon/daemon-skill-host.ts +259 -0
  713. package/src/daemon/dictation-profile-store.ts +2 -26
  714. package/src/daemon/external-plugins-bootstrap.ts +67 -13
  715. package/src/daemon/first-greeting.ts +44 -156
  716. package/src/daemon/handlers/config-channels.ts +14 -14
  717. package/src/daemon/handlers/config-embeddings.ts +1 -1
  718. package/src/daemon/handlers/config-ingress.ts +27 -166
  719. package/src/daemon/handlers/config-model.test.ts +17 -0
  720. package/src/daemon/handlers/config-model.ts +8 -53
  721. package/src/daemon/handlers/config-telegram.ts +6 -53
  722. package/src/daemon/handlers/config-voice.ts +0 -42
  723. package/src/daemon/handlers/conversations.ts +32 -345
  724. package/src/daemon/handlers/recording.ts +27 -159
  725. package/src/daemon/handlers/shared.ts +50 -99
  726. package/src/daemon/handlers/skills.ts +55 -114
  727. package/src/daemon/host-bash-proxy.ts +67 -45
  728. package/src/daemon/host-browser-proxy.ts +65 -27
  729. package/src/daemon/host-cu-proxy.ts +40 -39
  730. package/src/daemon/host-file-proxy.ts +58 -37
  731. package/src/daemon/host-transfer-proxy.ts +538 -0
  732. package/src/daemon/lifecycle.ts +71 -272
  733. package/src/daemon/meet-host-startup.ts +51 -0
  734. package/src/daemon/meet-host-supervisor.ts +781 -0
  735. package/src/daemon/meet-manifest-loader.ts +410 -0
  736. package/src/daemon/memory-v2-startup.ts +35 -0
  737. package/src/daemon/message-protocol.ts +4 -7
  738. package/src/daemon/message-types/acp.ts +1 -0
  739. package/src/daemon/message-types/conversations.ts +23 -2
  740. package/src/daemon/message-types/host-bash.ts +1 -0
  741. package/src/daemon/message-types/host-cu.ts +1 -0
  742. package/src/daemon/message-types/host-file.ts +1 -0
  743. package/src/daemon/message-types/host-transfer.ts +42 -0
  744. package/src/daemon/message-types/integrations.ts +6 -0
  745. package/src/daemon/message-types/messages.ts +24 -23
  746. package/src/daemon/message-types/schedules.ts +1 -0
  747. package/src/daemon/message-types/settings.ts +0 -6
  748. package/src/daemon/message-types/shared.ts +5 -2
  749. package/src/daemon/message-types/subagents.ts +2 -1
  750. package/src/daemon/message-types/workspace.ts +1 -3
  751. package/src/daemon/pkb-reminder-builder.test.ts +13 -12
  752. package/src/daemon/pkb-reminder-builder.ts +8 -16
  753. package/src/daemon/process-message.ts +479 -0
  754. package/src/daemon/providers-setup.ts +14 -6
  755. package/src/daemon/server.ts +58 -1702
  756. package/src/daemon/shutdown-handlers.ts +3 -3
  757. package/src/daemon/startup-error.ts +1 -1
  758. package/src/daemon/tool-side-effects.ts +125 -107
  759. package/src/daemon/trust-context.ts +45 -0
  760. package/src/daemon/wake-target-adapter.ts +218 -0
  761. package/src/email/feature-gate.ts +1 -1
  762. package/src/events/domain-events.ts +1 -16
  763. package/src/events/tool-audit-listener.ts +5 -9
  764. package/src/events/tool-domain-event-publisher.ts +0 -10
  765. package/src/events/tool-metrics-listener.ts +1 -21
  766. package/src/events/tool-trace-listener.ts +0 -14
  767. package/src/filing/filing-service.ts +207 -55
  768. package/src/followups/followup-store.ts +3 -71
  769. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +93 -21
  770. package/src/heartbeat/heartbeat-service.ts +55 -16
  771. package/src/home/__tests__/feed-writer.test.ts +0 -4
  772. package/src/home/__tests__/phase5-exit-criteria.test.ts +18 -1
  773. package/src/home/__tests__/relationship-state-writer.test.ts +30 -0
  774. package/src/home/__tests__/rollup-producer.test.ts +67 -2
  775. package/src/home/assistant-feed-authoring.ts +8 -1
  776. package/src/home/feed-types.ts +1 -1
  777. package/src/home/feed-writer.ts +1 -2
  778. package/src/home/relationship-state-writer.ts +17 -4
  779. package/src/home/rewrite-feed-title.ts +58 -0
  780. package/src/home/rollup-producer.ts +16 -3
  781. package/src/inbound/platform-callback-registration.ts +1 -17
  782. package/src/ipc/__tests__/attachment-ipc.test.ts +128 -66
  783. package/src/ipc/__tests__/browser-ipc.test.ts +72 -58
  784. package/src/ipc/__tests__/cache-ipc.test.ts +52 -107
  785. package/src/ipc/__tests__/cli-ipc.test.ts +9 -6
  786. package/src/ipc/__tests__/skill-server-bidirectional.test.ts +253 -0
  787. package/src/ipc/__tests__/skill-server.test.ts +182 -0
  788. package/src/ipc/__tests__/socket-path.test.ts +69 -23
  789. package/src/ipc/__tests__/ui-request-route.test.ts +241 -216
  790. package/src/ipc/__tests__/watcher-ipc.test.ts +33 -33
  791. package/src/ipc/assistant-server.ts +443 -0
  792. package/src/ipc/cli-client.ts +3 -3
  793. package/src/ipc/gateway-client.test.ts +131 -0
  794. package/src/ipc/gateway-client.ts +98 -123
  795. package/src/ipc/ipc-framing.ts +281 -0
  796. package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +171 -0
  797. package/src/ipc/routes/db-proxy.ts +73 -0
  798. package/src/ipc/routes/route-adapter.ts +32 -0
  799. package/src/ipc/routes/trust-rules.test.ts +123 -0
  800. package/src/ipc/skill-ipc-types.ts +54 -0
  801. package/src/ipc/skill-routes/__tests__/config.test.ts +146 -0
  802. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +388 -0
  803. package/src/ipc/skill-routes/__tests__/identity.test.ts +62 -0
  804. package/src/ipc/skill-routes/__tests__/log.test.ts +133 -0
  805. package/src/ipc/skill-routes/__tests__/memory.test.ts +178 -0
  806. package/src/ipc/skill-routes/__tests__/platform.test.ts +111 -0
  807. package/src/ipc/skill-routes/__tests__/providers.test.ts +265 -0
  808. package/src/ipc/skill-routes/__tests__/registries.test.ts +361 -0
  809. package/src/ipc/skill-routes/config.ts +47 -0
  810. package/src/ipc/skill-routes/events.ts +120 -0
  811. package/src/ipc/skill-routes/identity.ts +21 -0
  812. package/src/ipc/skill-routes/index.ts +37 -0
  813. package/src/ipc/skill-routes/log.ts +40 -0
  814. package/src/ipc/skill-routes/memory.ts +76 -0
  815. package/src/ipc/skill-routes/platform.ts +39 -0
  816. package/src/ipc/skill-routes/providers.ts +163 -0
  817. package/src/ipc/skill-routes/registries.ts +393 -0
  818. package/src/ipc/skill-server.ts +738 -0
  819. package/src/ipc/skill-socket-path.ts +20 -0
  820. package/src/ipc/socket-cleanup.ts +92 -0
  821. package/src/ipc/socket-path.ts +63 -32
  822. package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +374 -0
  823. package/src/live-voice/__tests__/live-voice-archive.test.ts +525 -0
  824. package/src/live-voice/__tests__/live-voice-events.test.ts +473 -0
  825. package/src/live-voice/__tests__/live-voice-integration.test.ts +359 -0
  826. package/src/live-voice/__tests__/live-voice-metrics.test.ts +179 -0
  827. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +349 -0
  828. package/src/live-voice/__tests__/live-voice-stt.test.ts +244 -0
  829. package/src/live-voice/__tests__/live-voice-tts-session.test.ts +337 -0
  830. package/src/live-voice/__tests__/live-voice-tts.test.ts +337 -0
  831. package/src/live-voice/__tests__/protocol.test.ts +295 -0
  832. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +413 -0
  833. package/src/live-voice/live-voice-archive.ts +758 -0
  834. package/src/live-voice/live-voice-metrics.ts +472 -0
  835. package/src/live-voice/live-voice-session-manager.ts +222 -0
  836. package/src/live-voice/live-voice-session.ts +1144 -0
  837. package/src/live-voice/live-voice-tts.ts +260 -0
  838. package/src/live-voice/protocol.ts +515 -0
  839. package/src/mcp/client.ts +2 -2
  840. package/src/mcp/manager.ts +0 -5
  841. package/src/media/types.ts +4 -4
  842. package/src/memory/__tests__/auto-analysis-enqueue.test.ts +4 -28
  843. package/src/memory/__tests__/auto-analysis-guard.test.ts +2 -2
  844. package/src/memory/__tests__/conversation-analyze-job.test.ts +7 -62
  845. package/src/memory/__tests__/conversation-group-migration.test.ts +2 -2
  846. package/src/memory/__tests__/find-analysis-conversation.test.ts +2 -1
  847. package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +55 -0
  848. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +235 -0
  849. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +127 -0
  850. package/src/memory/admin.ts +65 -7
  851. package/src/memory/app-git-service.ts +0 -46
  852. package/src/memory/app-store.ts +154 -0
  853. package/src/memory/attachments-store.ts +20 -16
  854. package/src/memory/auto-analysis-enqueue.ts +2 -17
  855. package/src/memory/canonical-guardian-store.ts +2 -1
  856. package/src/memory/channel-verification-sessions.ts +1 -1
  857. package/src/memory/checkpoints.ts +1 -1
  858. package/src/memory/context-search/agent-protocol.ts +424 -0
  859. package/src/memory/context-search/agent-runner.ts +1295 -0
  860. package/src/memory/context-search/format.ts +160 -0
  861. package/src/memory/context-search/limits.ts +106 -0
  862. package/src/memory/context-search/search.ts +387 -0
  863. package/src/memory/context-search/sources/conversations.ts +278 -0
  864. package/src/memory/context-search/sources/memory-v2.ts +578 -0
  865. package/src/memory/context-search/sources/memory.ts +95 -0
  866. package/src/memory/context-search/sources/pkb.ts +477 -0
  867. package/src/memory/context-search/sources/workspace.ts +1256 -0
  868. package/src/memory/context-search/types.ts +49 -0
  869. package/src/memory/conversation-analyze-job.ts +3 -24
  870. package/src/memory/conversation-attention-store.ts +1 -1
  871. package/src/memory/conversation-bootstrap.ts +1 -1
  872. package/src/memory/conversation-crud.ts +86 -119
  873. package/src/memory/conversation-directories.ts +1 -11
  874. package/src/memory/conversation-disk-view.ts +1 -5
  875. package/src/memory/conversation-display-order-migration.ts +11 -2
  876. package/src/memory/conversation-group-migration.ts +20 -4
  877. package/src/memory/conversation-key-store.ts +3 -4
  878. package/src/memory/conversation-queries.ts +13 -26
  879. package/src/memory/conversation-starter-checkpoints.ts +63 -0
  880. package/src/memory/conversation-starter-validation.ts +88 -0
  881. package/src/memory/conversation-starters-cadence.ts +1 -1
  882. package/src/memory/conversation-title-service.ts +2 -1
  883. package/src/memory/db-connection.ts +62 -0
  884. package/src/memory/db-init.ts +28 -4
  885. package/src/memory/db-maintenance.ts +1 -1
  886. package/src/memory/delivery-channels.ts +1 -14
  887. package/src/memory/delivery-crud.ts +2 -32
  888. package/src/memory/delivery-status.ts +1 -1
  889. package/src/memory/embedding-backend.ts +3 -21
  890. package/src/memory/embedding-gemini.test.ts +4 -4
  891. package/src/memory/embedding-gemini.ts +0 -2
  892. package/src/memory/embedding-local.ts +6 -6
  893. package/src/memory/embedding-ollama.ts +6 -6
  894. package/src/memory/embedding-openai.ts +6 -6
  895. package/src/memory/embedding-types.ts +21 -0
  896. package/src/memory/external-conversation-store.ts +1 -1
  897. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +408 -0
  898. package/src/memory/graph/__tests__/handle-remember-v2.test.ts +225 -0
  899. package/src/memory/graph/bootstrap.test.ts +2 -7
  900. package/src/memory/graph/bootstrap.ts +2 -1
  901. package/src/memory/graph/capability-seed.ts +3 -3
  902. package/src/memory/graph/compaction.ts +1 -1
  903. package/src/memory/graph/consolidation.ts +13 -10
  904. package/src/memory/graph/conversation-graph-memory.ts +184 -12
  905. package/src/memory/graph/decay.ts +1 -1
  906. package/src/memory/graph/extraction.ts +53 -21
  907. package/src/memory/graph/graph-memory-state-store.ts +1 -1
  908. package/src/memory/graph/graph-search.test.ts +94 -2
  909. package/src/memory/graph/graph-search.ts +22 -7
  910. package/src/memory/graph/image-ref-utils.ts +1 -1
  911. package/src/memory/graph/injection.test.ts +2 -2
  912. package/src/memory/graph/injection.ts +1 -1
  913. package/src/memory/graph/retriever.test.ts +158 -4
  914. package/src/memory/graph/retriever.ts +17 -5
  915. package/src/memory/graph/store.test.ts +2 -1
  916. package/src/memory/graph/store.ts +1 -1
  917. package/src/memory/graph/tool-handlers.ts +73 -247
  918. package/src/memory/graph/tools.ts +35 -53
  919. package/src/memory/group-crud.ts +1 -2
  920. package/src/memory/guardian-action-store.ts +2 -84
  921. package/src/memory/guardian-approvals.ts +1 -49
  922. package/src/memory/guardian-rate-limits.ts +1 -1
  923. package/src/memory/indexer.ts +44 -32
  924. package/src/memory/invite-store.ts +1 -1
  925. package/src/memory/job-handlers/backfill.ts +1 -1
  926. package/src/memory/job-handlers/cleanup.ts +2 -1
  927. package/src/memory/job-handlers/conversation-starters.ts +54 -63
  928. package/src/memory/job-handlers/embedding.test.ts +2 -1
  929. package/src/memory/job-handlers/embedding.ts +1 -1
  930. package/src/memory/job-handlers/index-maintenance.ts +1 -1
  931. package/src/memory/job-handlers/summarization.ts +3 -3
  932. package/src/memory/job-utils.ts +3 -9
  933. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +362 -0
  934. package/src/memory/jobs/embed-concept-page.ts +210 -0
  935. package/src/memory/jobs/embed-pkb-file.test.ts +2 -1
  936. package/src/memory/jobs-store.ts +9 -2
  937. package/src/memory/jobs-worker.ts +56 -17
  938. package/src/memory/lifecycle-events-store.ts +1 -1
  939. package/src/memory/llm-request-log-store.ts +1 -42
  940. package/src/memory/llm-usage-store.ts +130 -44
  941. package/src/memory/media-store.ts +1 -1
  942. package/src/memory/memory-recall-log-store.ts +1 -1
  943. package/src/memory/memory-v2-activation-log-store.ts +115 -0
  944. package/src/memory/migrations/038-actor-token-records.ts +3 -0
  945. package/src/memory/migrations/039-actor-refresh-token-records.ts +3 -0
  946. package/src/memory/migrations/226-schedule-wake-conversation-id.ts +11 -0
  947. package/src/memory/migrations/227-add-conversation-inference-profile.ts +18 -0
  948. package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +27 -0
  949. package/src/memory/migrations/229-delete-private-conversations.test.ts +1087 -0
  950. package/src/memory/migrations/229-delete-private-conversations.ts +210 -0
  951. package/src/memory/migrations/230-acp-session-history.ts +41 -0
  952. package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +128 -0
  953. package/src/memory/migrations/232-activation-state.ts +38 -0
  954. package/src/memory/migrations/233-document-conversations.ts +54 -0
  955. package/src/memory/migrations/234-memory-v2-activation-logs.ts +55 -0
  956. package/src/memory/migrations/235-llm-usage-attribution.ts +31 -0
  957. package/src/memory/migrations/235-slack-compaction-watermark.ts +44 -0
  958. package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +26 -0
  959. package/src/memory/migrations/__tests__/234-memory-v2-activation-logs.test.ts +182 -0
  960. package/src/memory/migrations/index.ts +24 -0
  961. package/src/memory/migrations/registry.ts +31 -0
  962. package/src/memory/pkb/pkb-index.test.ts +4 -5
  963. package/src/memory/pkb/pkb-reconcile.test.ts +4 -5
  964. package/src/memory/pkb/pkb-search.test.ts +83 -3
  965. package/src/memory/pkb/pkb-search.ts +27 -14
  966. package/src/memory/published-pages-store.ts +1 -1
  967. package/src/memory/raw-query.ts +2 -68
  968. package/src/memory/schema/acp.ts +30 -0
  969. package/src/memory/schema/conversations.ts +8 -1
  970. package/src/memory/schema/index.ts +1 -0
  971. package/src/memory/schema/infrastructure.ts +26 -32
  972. package/src/memory/schema/memory-graph.ts +36 -14
  973. package/src/memory/scoped-approval-grants.ts +2 -1
  974. package/src/memory/search/semantic.ts +7 -18
  975. package/src/memory/shared-app-links-store.ts +2 -1
  976. package/src/memory/tool-usage-store.ts +3 -1
  977. package/src/memory/trace-event-store.ts +2 -1
  978. package/src/memory/turn-events-store.ts +1 -1
  979. package/src/memory/usage-buckets.ts +40 -1
  980. package/src/memory/usage-grouped-buckets.ts +127 -0
  981. package/src/memory/v2/__tests__/activation-store.test.ts +202 -0
  982. package/src/memory/v2/__tests__/activation.test.ts +1155 -0
  983. package/src/memory/v2/__tests__/backfill-jobs.test.ts +483 -0
  984. package/src/memory/v2/__tests__/consolidation-job.test.ts +412 -0
  985. package/src/memory/v2/__tests__/edge-index.test.ts +278 -0
  986. package/src/memory/v2/__tests__/injection.test.ts +1161 -0
  987. package/src/memory/v2/__tests__/migration.test.ts +840 -0
  988. package/src/memory/v2/__tests__/page-store.test.ts +517 -0
  989. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +181 -0
  990. package/src/memory/v2/__tests__/qdrant.test.ts +438 -0
  991. package/src/memory/v2/__tests__/sim.test.ts +549 -0
  992. package/src/memory/v2/__tests__/skill-content.test.ts +85 -0
  993. package/src/memory/v2/__tests__/skill-qdrant.test.ts +657 -0
  994. package/src/memory/v2/__tests__/skill-store.test.ts +463 -0
  995. package/src/memory/v2/__tests__/static-context.test.ts +153 -0
  996. package/src/memory/v2/__tests__/sweep-job.test.ts +441 -0
  997. package/src/memory/v2/activation-store.ts +109 -0
  998. package/src/memory/v2/activation.ts +561 -0
  999. package/src/memory/v2/backfill-jobs.ts +357 -0
  1000. package/src/memory/v2/consolidation-job.ts +306 -0
  1001. package/src/memory/v2/edge-index.ts +191 -0
  1002. package/src/memory/v2/injection.ts +431 -0
  1003. package/src/memory/v2/migration.ts +647 -0
  1004. package/src/memory/v2/now-text.ts +37 -0
  1005. package/src/memory/v2/page-store.ts +382 -0
  1006. package/src/memory/v2/prompts/consolidation.ts +261 -0
  1007. package/src/memory/v2/prompts/sweep.ts +56 -0
  1008. package/src/memory/v2/qdrant.ts +342 -0
  1009. package/src/memory/v2/sim.ts +206 -0
  1010. package/src/memory/v2/skill-content.ts +42 -0
  1011. package/src/memory/v2/skill-qdrant.ts +395 -0
  1012. package/src/memory/v2/skill-store.ts +176 -0
  1013. package/src/memory/v2/static-context.ts +62 -0
  1014. package/src/memory/v2/sweep-job.ts +298 -0
  1015. package/src/memory/v2/types.ts +106 -0
  1016. package/src/memory/validation.ts +0 -11
  1017. package/src/messaging/draft-store.ts +0 -6
  1018. package/src/messaging/provider-types.ts +8 -0
  1019. package/src/messaging/provider.ts +7 -0
  1020. package/src/messaging/providers/gmail/client.ts +1 -121
  1021. package/src/messaging/providers/index.ts +262 -0
  1022. package/src/messaging/providers/outlook/client.ts +0 -73
  1023. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +226 -0
  1024. package/src/messaging/providers/slack/adapter.ts +122 -21
  1025. package/src/messaging/providers/slack/api.ts +242 -0
  1026. package/src/messaging/providers/slack/backfill.test.ts +95 -6
  1027. package/src/messaging/providers/slack/backfill.ts +89 -11
  1028. package/src/messaging/providers/slack/client.ts +10 -124
  1029. package/src/messaging/providers/slack/message-metadata.ts +13 -3
  1030. package/src/messaging/providers/slack/render-transcript.test.ts +56 -0
  1031. package/src/messaging/providers/slack/render-transcript.ts +126 -25
  1032. package/src/messaging/providers/slack/send.ts +383 -0
  1033. package/src/messaging/providers/slack/types.ts +1 -0
  1034. package/src/messaging/providers/telegram-bot/adapter.ts +4 -42
  1035. package/src/messaging/providers/telegram-bot/api.ts +253 -0
  1036. package/src/messaging/providers/telegram-bot/client.ts +17 -58
  1037. package/src/messaging/providers/telegram-bot/send.ts +232 -0
  1038. package/src/messaging/providers/whatsapp/adapter.ts +4 -36
  1039. package/src/messaging/providers/whatsapp/api.ts +319 -0
  1040. package/src/messaging/providers/whatsapp/client.ts +4 -48
  1041. package/src/messaging/providers/whatsapp/send.ts +209 -0
  1042. package/src/notifications/adapters/slack.ts +5 -23
  1043. package/src/notifications/adapters/telegram.ts +8 -29
  1044. package/src/notifications/conversation-candidates.ts +1 -1
  1045. package/src/notifications/conversation-seed-composer.ts +12 -6
  1046. package/src/notifications/copy-composer.ts +1 -1
  1047. package/src/notifications/decision-engine.ts +1 -1
  1048. package/src/notifications/decisions-store.ts +1 -1
  1049. package/src/notifications/deliveries-store.ts +2 -1
  1050. package/src/notifications/deterministic-checks.ts +1 -1
  1051. package/src/notifications/events-store.ts +1 -13
  1052. package/src/notifications/preferences-store.ts +1 -1
  1053. package/src/notifications/signal.ts +0 -9
  1054. package/src/oauth/connection-resolver.test.ts +8 -0
  1055. package/src/oauth/connection-resolver.ts +6 -5
  1056. package/src/oauth/credential-token-resolver.ts +97 -0
  1057. package/src/oauth/manual-token-connection.ts +30 -34
  1058. package/src/oauth/oauth-store.ts +8 -5
  1059. package/src/outbound-proxy/certs.ts +0 -7
  1060. package/src/outbound-proxy/config.ts +0 -74
  1061. package/src/outbound-proxy/health.ts +0 -44
  1062. package/src/outbound-proxy/index.ts +0 -23
  1063. package/src/permissions/approval-policy.test.ts +149 -132
  1064. package/src/permissions/approval-policy.ts +65 -91
  1065. package/src/permissions/approval-provenance.test.ts +184 -0
  1066. package/src/permissions/approval-provenance.ts +70 -0
  1067. package/src/permissions/checker.test.ts +632 -0
  1068. package/src/permissions/checker.ts +270 -460
  1069. package/src/permissions/gateway-threshold-reader.ts +31 -47
  1070. package/src/permissions/ipc-risk-types.ts +95 -0
  1071. package/src/permissions/prompter.ts +13 -11
  1072. package/src/permissions/risk-types.ts +24 -210
  1073. package/src/permissions/secret-prompter.ts +21 -48
  1074. package/src/permissions/types.ts +49 -46
  1075. package/src/permissions/workspace-policy.ts +1 -8
  1076. package/src/platform/sync-identity.ts +0 -8
  1077. package/src/playbooks/playbook-compiler.ts +1 -1
  1078. package/src/plugins/defaults/index.ts +1 -1
  1079. package/src/plugins/defaults/injectors.ts +87 -23
  1080. package/src/plugins/defaults/llm-call.ts +6 -9
  1081. package/src/plugins/defaults/memory-retrieval.ts +1 -6
  1082. package/src/plugins/defaults/overflow-reduce.ts +12 -7
  1083. package/src/plugins/defaults/token-estimate.ts +2 -3
  1084. package/src/plugins/registry.ts +61 -1
  1085. package/src/plugins/types.ts +14 -7
  1086. package/src/plugins/user-loader.ts +36 -10
  1087. package/src/prompts/persona-resolver.ts +2 -4
  1088. package/src/prompts/system-prompt.ts +34 -31
  1089. package/src/prompts/templates/BOOTSTRAP.md +52 -6
  1090. package/src/prompts/templates/SOUL.md +3 -1
  1091. package/src/prompts/update-bulletin-job.ts +2 -0
  1092. package/src/providers/__tests__/provider-env-vars.test.ts +0 -21
  1093. package/src/providers/__tests__/retry-callsite.test.ts +141 -7
  1094. package/src/providers/anthropic/client.ts +143 -52
  1095. package/src/providers/call-site-routing.ts +49 -6
  1096. package/src/providers/fireworks/client.ts +3 -0
  1097. package/src/providers/gemini/client.ts +113 -23
  1098. package/src/providers/managed-proxy/context.ts +0 -17
  1099. package/src/providers/model-catalog.ts +188 -27
  1100. package/src/providers/model-intents.ts +7 -8
  1101. package/src/providers/openai/chat-completions-provider.ts +43 -7
  1102. package/src/providers/openai/responses-provider.ts +46 -5
  1103. package/src/providers/openrouter/client.ts +4 -5
  1104. package/src/providers/provider-env-vars.ts +4 -12
  1105. package/src/providers/provider-send-message.ts +61 -13
  1106. package/src/providers/ratelimit.ts +7 -2
  1107. package/src/providers/registry.ts +15 -10
  1108. package/src/providers/retry.ts +148 -31
  1109. package/src/providers/speech-to-text/openai-whisper-stream.ts +1 -1
  1110. package/src/providers/speech-to-text/openai-whisper.ts +3 -6
  1111. package/src/providers/speech-to-text/provider-catalog.ts +75 -0
  1112. package/src/providers/speech-to-text/xai.ts +5 -5
  1113. package/src/providers/thinking-config.ts +34 -0
  1114. package/src/providers/types.ts +35 -10
  1115. package/src/providers/usage-tracking.ts +96 -0
  1116. package/src/runtime/AGENTS.md +16 -11
  1117. package/src/runtime/__tests__/agent-wake.test.ts +122 -9
  1118. package/src/runtime/__tests__/interactive-ui.test.ts +157 -246
  1119. package/src/runtime/access-request-helper.ts +9 -20
  1120. package/src/runtime/actor-trust-resolver.ts +2 -2
  1121. package/src/runtime/agent-wake.ts +211 -68
  1122. package/src/runtime/approval-conversation-turn.ts +2 -15
  1123. package/src/runtime/approval-message-composer.ts +11 -60
  1124. package/src/runtime/assistant-event-hub.ts +541 -45
  1125. package/src/runtime/assistant-event.ts +16 -69
  1126. package/src/runtime/auth/__tests__/guard-tests.test.ts +6 -30
  1127. package/src/runtime/auth/__tests__/middleware.test.ts +10 -10
  1128. package/src/runtime/auth/__tests__/route-policy.test.ts +0 -8
  1129. package/src/runtime/auth/middleware.ts +5 -5
  1130. package/src/runtime/auth/route-policy.ts +205 -12
  1131. package/src/runtime/auth/token-service.ts +1 -111
  1132. package/src/runtime/capability-tokens.ts +89 -313
  1133. package/src/runtime/channel-approval-types.ts +1 -6
  1134. package/src/runtime/channel-approvals.ts +13 -81
  1135. package/src/runtime/channel-readiness-service.ts +2 -2
  1136. package/src/runtime/channel-reply-delivery.ts +2 -8
  1137. package/src/runtime/channel-retry-sweep.ts +20 -17
  1138. package/src/runtime/channel-verification-service.ts +3 -5
  1139. package/src/runtime/confirmation-request-guardian-bridge.ts +2 -7
  1140. package/src/runtime/gateway-client.ts +37 -378
  1141. package/src/runtime/guardian-action-grant-minter.ts +2 -3
  1142. package/src/runtime/guardian-action-message-composer.ts +11 -52
  1143. package/src/runtime/guardian-action-service.ts +19 -7
  1144. package/src/runtime/guardian-decision-types.ts +4 -65
  1145. package/src/runtime/guardian-reply-router.ts +10 -19
  1146. package/src/runtime/guardian-vellum-migration.ts +5 -64
  1147. package/src/runtime/http-errors.ts +1 -32
  1148. package/src/runtime/http-router.ts +54 -8
  1149. package/src/runtime/http-server.ts +362 -1187
  1150. package/src/runtime/http-types.ts +20 -98
  1151. package/src/runtime/interactive-ui-types.ts +145 -0
  1152. package/src/runtime/interactive-ui.ts +37 -196
  1153. package/src/runtime/invite-redemption-service.ts +1 -1
  1154. package/src/runtime/invite-redemption-templates.ts +1 -1
  1155. package/src/runtime/local-actor-identity.ts +13 -43
  1156. package/src/runtime/message-composer-types.ts +134 -0
  1157. package/src/runtime/middleware/auth.ts +0 -20
  1158. package/src/runtime/middleware/rate-limiter.ts +1 -1
  1159. package/src/runtime/middleware/request-logger.ts +5 -2
  1160. package/src/runtime/migrations/__tests__/job-registry.test.ts +346 -0
  1161. package/src/runtime/migrations/__tests__/v1-test-helpers.ts +112 -0
  1162. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +11 -4
  1163. package/src/runtime/migrations/__tests__/vbundle-builder-v1-shape.test.ts +253 -0
  1164. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +19 -6
  1165. package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +71 -27
  1166. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +41 -2
  1167. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +143 -79
  1168. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +143 -23
  1169. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +18 -2
  1170. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +371 -0
  1171. package/src/runtime/migrations/job-registry.ts +281 -0
  1172. package/src/runtime/migrations/migration-transport.ts +46 -13
  1173. package/src/runtime/migrations/migration-wizard.ts +2 -2
  1174. package/src/runtime/migrations/origin-mode.ts +40 -0
  1175. package/src/runtime/migrations/vbundle-builder.ts +133 -80
  1176. package/src/runtime/migrations/vbundle-import-analyzer.ts +9 -7
  1177. package/src/runtime/migrations/vbundle-importer.ts +8 -8
  1178. package/src/runtime/migrations/vbundle-metadata-merge.ts +1 -1
  1179. package/src/runtime/migrations/vbundle-streaming-importer.ts +3 -16
  1180. package/src/runtime/migrations/vbundle-streaming-validator.ts +48 -26
  1181. package/src/runtime/migrations/vbundle-tar-stream.ts +11 -3
  1182. package/src/runtime/migrations/vbundle-validator.ts +214 -41
  1183. package/src/runtime/nl-approval-parser.ts +16 -21
  1184. package/src/runtime/pending-interactions.ts +42 -16
  1185. package/src/runtime/routes/__tests__/acp-routes.test.ts +394 -0
  1186. package/src/runtime/routes/__tests__/backup-routes.test.ts +232 -339
  1187. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +235 -0
  1188. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +72 -4
  1189. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +58 -0
  1190. package/src/runtime/routes/__tests__/migration-export-secrets-redacted.test.ts +54 -0
  1191. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +19 -6
  1192. package/src/runtime/routes/__tests__/stt-routes.test.ts +182 -223
  1193. package/src/runtime/routes/__tests__/suggest-trust-rule-routes.test.ts +230 -0
  1194. package/src/{ipc/__tests__/task-ipc.test.ts → runtime/routes/__tests__/task-routes.test.ts} +116 -96
  1195. package/src/runtime/routes/__tests__/tts-routes.test.ts +185 -289
  1196. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +7 -7
  1197. package/src/runtime/routes/access-request-decision.ts +25 -50
  1198. package/src/runtime/routes/acp-routes.test.ts +368 -0
  1199. package/src/runtime/routes/acp-routes.ts +392 -170
  1200. package/src/runtime/routes/app-management-routes.ts +475 -662
  1201. package/src/runtime/routes/app-routes.ts +192 -177
  1202. package/src/runtime/routes/approval-routes.ts +163 -440
  1203. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +24 -84
  1204. package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +3 -10
  1205. package/src/runtime/routes/attachment-routes.ts +409 -253
  1206. package/src/runtime/routes/audio-routes.ts +51 -18
  1207. package/src/runtime/routes/avatar-routes.ts +81 -76
  1208. package/src/runtime/routes/background-tool-routes.ts +94 -0
  1209. package/src/runtime/routes/backup-routes.ts +154 -336
  1210. package/src/runtime/routes/brain-graph-routes.ts +83 -110
  1211. package/src/runtime/routes/browser-routes.ts +127 -0
  1212. package/src/runtime/routes/btw-routes.ts +62 -106
  1213. package/src/runtime/routes/cache-routes.ts +96 -0
  1214. package/src/runtime/routes/call-routes.ts +208 -247
  1215. package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +1 -1
  1216. package/src/runtime/routes/channel-delivery-routes.ts +25 -27
  1217. package/src/runtime/routes/channel-guardian-routes.ts +1 -5
  1218. package/src/runtime/routes/channel-readiness-routes.ts +79 -120
  1219. package/src/runtime/routes/channel-route-definitions.ts +62 -0
  1220. package/src/runtime/routes/channel-route-shared.ts +15 -45
  1221. package/src/runtime/routes/channel-verification-routes.ts +207 -187
  1222. package/src/runtime/routes/client-routes.ts +81 -0
  1223. package/src/runtime/routes/consolidation-routes.ts +115 -0
  1224. package/src/runtime/routes/contact-routes.ts +533 -407
  1225. package/src/runtime/routes/conversation-analysis-routes.ts +48 -49
  1226. package/src/runtime/routes/conversation-attention-routes.ts +55 -67
  1227. package/src/runtime/routes/conversation-list-routes.ts +248 -0
  1228. package/src/runtime/routes/conversation-management-routes.ts +591 -717
  1229. package/src/runtime/routes/conversation-query-routes.ts +621 -459
  1230. package/src/runtime/routes/conversation-routes.ts +396 -792
  1231. package/src/runtime/routes/conversation-starter-routes.ts +137 -108
  1232. package/src/runtime/routes/credential-prompt-routes.ts +124 -0
  1233. package/src/runtime/routes/debug-routes.ts +34 -39
  1234. package/src/runtime/routes/defer-routes.ts +230 -0
  1235. package/src/runtime/routes/diagnostics-routes.ts +79 -70
  1236. package/src/runtime/routes/documents-routes.ts +163 -117
  1237. package/src/runtime/routes/errors.ts +132 -0
  1238. package/src/runtime/routes/events-routes.ts +126 -119
  1239. package/src/runtime/routes/filing-routes.ts +80 -76
  1240. package/src/runtime/routes/global-search-routes.ts +51 -57
  1241. package/src/runtime/routes/group-routes.ts +199 -181
  1242. package/src/runtime/routes/guardian-action-routes.ts +100 -171
  1243. package/src/runtime/routes/guardian-approval-interception.ts +27 -58
  1244. package/src/runtime/routes/guardian-approval-prompt.ts +10 -21
  1245. package/src/runtime/routes/guardian-approval-reply-helpers.ts +2 -6
  1246. package/src/runtime/routes/guardian-expiry-sweep.ts +19 -36
  1247. package/src/runtime/routes/heartbeat-routes.ts +194 -209
  1248. package/src/runtime/routes/home-feed-routes.ts +85 -187
  1249. package/src/runtime/routes/home-state-routes.ts +27 -24
  1250. package/src/runtime/routes/host-bash-routes.ts +45 -54
  1251. package/src/runtime/routes/host-browser-routes.ts +44 -99
  1252. package/src/runtime/routes/host-cu-routes.ts +80 -71
  1253. package/src/runtime/routes/host-file-routes.ts +53 -62
  1254. package/src/runtime/routes/host-transfer-routes.ts +216 -0
  1255. package/src/runtime/routes/http-adapter.ts +172 -0
  1256. package/src/runtime/routes/identity-routes.ts +161 -85
  1257. package/src/runtime/routes/inbound-conversation.ts +11 -18
  1258. package/src/runtime/routes/inbound-message-handler.ts +639 -232
  1259. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +81 -226
  1260. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +2 -3
  1261. package/src/runtime/routes/inbound-stages/background-dispatch.ts +57 -90
  1262. package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +25 -50
  1263. package/src/runtime/routes/inbound-stages/edit-intercept.ts +7 -7
  1264. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +5 -5
  1265. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +5 -6
  1266. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -24
  1267. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +3 -10
  1268. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +4 -4
  1269. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +3 -3
  1270. package/src/runtime/routes/index.ts +201 -0
  1271. package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +25 -32
  1272. package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +22 -31
  1273. package/src/runtime/routes/integrations/slack/channel.ts +50 -71
  1274. package/src/runtime/routes/integrations/slack/share.ts +49 -58
  1275. package/src/runtime/routes/integrations/telegram.ts +91 -74
  1276. package/src/runtime/routes/integrations/twilio.ts +163 -240
  1277. package/src/runtime/routes/integrations/vercel.ts +57 -54
  1278. package/src/runtime/routes/interface-routes.ts +43 -0
  1279. package/src/runtime/routes/internal-oauth-routes.ts +56 -0
  1280. package/src/runtime/routes/internal-twilio-routes.ts +46 -0
  1281. package/src/runtime/routes/llm-call-sites-routes.ts +22 -0
  1282. package/src/runtime/routes/llm-context-normalization.ts +4 -2
  1283. package/src/runtime/routes/log-export/workspace-allowlist.ts +1 -1
  1284. package/src/runtime/routes/log-export-routes.ts +90 -100
  1285. package/src/runtime/routes/memory-item-routes.test.ts +152 -175
  1286. package/src/runtime/routes/memory-item-routes.ts +243 -323
  1287. package/src/runtime/routes/memory-v2-routes.ts +188 -0
  1288. package/src/runtime/routes/migration-rollback-routes.ts +167 -212
  1289. package/src/runtime/routes/migration-routes.ts +1037 -377
  1290. package/src/runtime/routes/notification-routes.ts +199 -70
  1291. package/src/runtime/routes/oauth-apps.ts +254 -251
  1292. package/src/runtime/routes/oauth-providers.ts +66 -57
  1293. package/src/runtime/routes/playground/__tests__/force-compact.test.ts +60 -120
  1294. package/src/runtime/routes/playground/__tests__/guard.test.ts +34 -54
  1295. package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +107 -151
  1296. package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +41 -117
  1297. package/src/runtime/routes/playground/__tests__/seed-conversation.test.ts +95 -138
  1298. package/src/runtime/routes/playground/__tests__/seeded-conversations.test.ts +115 -217
  1299. package/src/runtime/routes/playground/__tests__/state.test.ts +41 -90
  1300. package/src/runtime/routes/playground/conversation-not-found.ts +9 -11
  1301. package/src/runtime/routes/playground/force-compact.ts +41 -54
  1302. package/src/runtime/routes/playground/guard.ts +18 -19
  1303. package/src/runtime/routes/playground/helpers.ts +103 -0
  1304. package/src/runtime/routes/playground/index.ts +15 -27
  1305. package/src/runtime/routes/playground/inject-failures.ts +48 -64
  1306. package/src/runtime/routes/playground/reset-circuit.ts +31 -57
  1307. package/src/runtime/routes/playground/seed-conversation.ts +66 -92
  1308. package/src/runtime/routes/playground/seeded-conversations.ts +60 -64
  1309. package/src/runtime/routes/playground/state.ts +23 -24
  1310. package/src/runtime/routes/profiler-routes.ts +132 -167
  1311. package/src/runtime/routes/ps-routes.ts +120 -0
  1312. package/src/runtime/routes/recording-routes.ts +189 -270
  1313. package/src/runtime/routes/rename-conversation-routes.ts +85 -0
  1314. package/src/runtime/routes/schedule-routes.ts +239 -246
  1315. package/src/runtime/routes/secret-routes.ts +305 -282
  1316. package/src/runtime/routes/secrets-deps.ts +24 -0
  1317. package/src/runtime/routes/settings-routes.ts +370 -449
  1318. package/src/runtime/routes/skills-routes.ts +417 -471
  1319. package/src/runtime/routes/stt-routes.ts +196 -206
  1320. package/src/runtime/routes/subagents-routes.ts +125 -141
  1321. package/src/runtime/routes/suggest-trust-rule-routes.ts +275 -0
  1322. package/src/runtime/routes/surface-action-routes.ts +135 -190
  1323. package/src/runtime/routes/surface-content-routes.ts +84 -118
  1324. package/src/runtime/routes/task-routes.ts +354 -0
  1325. package/src/runtime/routes/telemetry-routes.ts +33 -49
  1326. package/src/runtime/routes/trace-event-routes.ts +55 -74
  1327. package/src/runtime/routes/trust-rules-routes.ts +61 -244
  1328. package/src/runtime/routes/tts-routes.ts +187 -169
  1329. package/src/runtime/routes/types.ts +139 -0
  1330. package/src/{ipc/routes/ui-request.ts → runtime/routes/ui-request-routes.ts} +23 -17
  1331. package/src/runtime/routes/upgrade-broadcast-routes.ts +150 -198
  1332. package/src/runtime/routes/usage-routes.ts +222 -171
  1333. package/src/runtime/routes/user-routes.ts +88 -18
  1334. package/src/runtime/routes/wake-conversation-routes.ts +49 -0
  1335. package/src/{ipc/routes/watcher.ts → runtime/routes/watcher-routes.ts} +84 -39
  1336. package/src/runtime/routes/wipe-conversation-routes.ts +89 -0
  1337. package/src/runtime/routes/work-items-routes.test.ts +10 -20
  1338. package/src/runtime/routes/work-items-routes.ts +419 -437
  1339. package/src/runtime/routes/workspace-commit-routes.ts +30 -61
  1340. package/src/runtime/routes/workspace-routes.test.ts +254 -381
  1341. package/src/runtime/routes/workspace-routes.ts +238 -246
  1342. package/src/runtime/runtime-mode.ts +8 -1
  1343. package/src/runtime/services/__tests__/analyze-conversation.test.ts +82 -120
  1344. package/src/runtime/services/analyze-conversation.ts +18 -55
  1345. package/src/runtime/services/conversation-serializer.ts +179 -0
  1346. package/src/runtime/trust-context-resolver.ts +3 -2
  1347. package/src/runtime/verification-outbound-actions.ts +14 -50
  1348. package/src/runtime/verification-rate-limiter.ts +1 -1
  1349. package/src/schedule/schedule-store.ts +64 -18
  1350. package/src/schedule/scheduler.ts +101 -0
  1351. package/src/security/ces-credential-client.ts +32 -169
  1352. package/src/security/ces-rpc-credential-backend.ts +1 -1
  1353. package/src/security/credential-backend.ts +6 -6
  1354. package/src/security/oauth-completion-page.ts +1 -1
  1355. package/src/security/oauth2.ts +3 -6
  1356. package/src/security/secret-scanner.ts +14 -547
  1357. package/src/security/secure-keys.ts +31 -11
  1358. package/src/security/token-manager.ts +7 -3
  1359. package/src/sequence/analytics.ts +1 -1
  1360. package/src/sequence/guardrails.ts +3 -3
  1361. package/src/sequence/store.ts +2 -1
  1362. package/src/signals/bash.ts +1 -1
  1363. package/src/signals/cancel.ts +16 -25
  1364. package/src/signals/conversation-undo.ts +2 -27
  1365. package/src/signals/emit-event.ts +1 -2
  1366. package/src/signals/event-stream.ts +1 -1
  1367. package/src/signals/user-message.ts +108 -22
  1368. package/src/skills/catalog-cache.ts +7 -0
  1369. package/src/skills/catalog-files.ts +0 -5
  1370. package/src/skills/catalog-install.ts +29 -18
  1371. package/src/skills/category-inference.ts +0 -11
  1372. package/src/skills/clawhub.ts +4 -4
  1373. package/src/skills/inline-command-runner.ts +1 -7
  1374. package/src/skills/managed-store.ts +2 -2
  1375. package/src/skills/remote-skill-policy.ts +6 -7
  1376. package/src/subagent/index.ts +2 -6
  1377. package/src/subagent/manager.ts +94 -107
  1378. package/src/subagent/types.ts +9 -0
  1379. package/src/tasks/SPEC.md +2 -2
  1380. package/src/tasks/task-compiler.ts +1 -1
  1381. package/src/tasks/task-runner.ts +2 -22
  1382. package/src/tasks/task-store.ts +2 -29
  1383. package/src/telemetry/types.ts +6 -0
  1384. package/src/telemetry/usage-telemetry-reporter.test.ts +38 -15
  1385. package/src/telemetry/usage-telemetry-reporter.ts +3 -5
  1386. package/src/tools/acp/list-agents.test.ts +115 -0
  1387. package/src/tools/acp/list-agents.ts +31 -0
  1388. package/src/tools/acp/spawn.test.ts +378 -0
  1389. package/src/tools/acp/spawn.ts +142 -62
  1390. package/src/tools/acp/steer.test.ts +100 -0
  1391. package/src/tools/acp/steer.ts +38 -0
  1392. package/src/tools/background-tool-registry.ts +98 -0
  1393. package/src/tools/browser/__tests__/browser-status.test.ts +44 -127
  1394. package/src/tools/browser/browser-execution.ts +38 -127
  1395. package/src/tools/browser/browser-manager.ts +1 -8
  1396. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +92 -68
  1397. package/src/tools/browser/cdp-client/accessibility-snapshot.ts +1 -1
  1398. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +3 -1
  1399. package/src/tools/browser/cdp-client/factory.ts +48 -76
  1400. package/src/tools/browser/cdp-client/index.ts +1 -14
  1401. package/src/tools/browser/cdp-client/types.ts +4 -1
  1402. package/src/tools/computer-use/definitions.ts +1 -1
  1403. package/src/tools/credential-execution/make-authenticated-request.ts +2 -2
  1404. package/src/tools/credential-execution/manage-secure-command-tool.ts +1 -1
  1405. package/src/tools/credential-execution/run-authenticated-command.ts +2 -2
  1406. package/src/tools/credentials/broker-types.ts +2 -1
  1407. package/src/tools/document/editor-template.ts +1 -1
  1408. package/src/tools/execution-timeout.ts +1 -1
  1409. package/src/tools/executor.ts +53 -45
  1410. package/src/tools/host-filesystem/edit.ts +3 -2
  1411. package/src/tools/host-filesystem/read.ts +3 -2
  1412. package/src/tools/host-filesystem/transfer.test.ts +271 -0
  1413. package/src/tools/host-filesystem/transfer.ts +235 -0
  1414. package/src/tools/host-filesystem/write.ts +3 -2
  1415. package/src/tools/host-terminal/host-shell.ts +192 -13
  1416. package/src/tools/mcp/mcp-tool-factory.ts +1 -1
  1417. package/src/tools/memory/register.test.ts +161 -1
  1418. package/src/tools/memory/register.ts +19 -34
  1419. package/src/tools/network/script-proxy/index.ts +1 -10
  1420. package/src/tools/permission-checker.ts +84 -220
  1421. package/src/tools/policy-context.ts +1 -8
  1422. package/src/tools/registry.ts +16 -1
  1423. package/src/tools/shared/shell-output.ts +4 -1
  1424. package/src/tools/side-effects.ts +2 -2
  1425. package/src/tools/skills/execute.ts +1 -1
  1426. package/src/tools/skills/sandbox-runner.ts +1 -6
  1427. package/src/tools/skills/skill-tool-factory.ts +32 -0
  1428. package/src/tools/subagent/spawn.ts +35 -11
  1429. package/src/tools/terminal/safe-env.ts +10 -1
  1430. package/src/tools/terminal/shell.ts +142 -88
  1431. package/src/tools/tool-approval-handler.ts +4 -70
  1432. package/src/tools/tool-input-summary.ts +10 -0
  1433. package/src/tools/types.ts +136 -183
  1434. package/src/tools/ui-surface/definitions.ts +2 -2
  1435. package/src/tts/__tests__/provider-catalog.test.ts +2 -2
  1436. package/src/tts/provider-catalog.ts +1 -1
  1437. package/src/usage/actors.ts +2 -1
  1438. package/src/usage/attribution.ts +185 -0
  1439. package/src/usage/pricing.ts +166 -0
  1440. package/src/usage/types.ts +14 -0
  1441. package/src/util/debounce.ts +0 -21
  1442. package/src/util/errors.ts +0 -8
  1443. package/src/util/json.ts +13 -0
  1444. package/src/util/log-redact.ts +0 -1
  1445. package/src/util/logger.ts +3 -3
  1446. package/src/util/platform.ts +85 -124
  1447. package/src/util/pricing.ts +158 -8
  1448. package/src/watcher/engine.ts +42 -20
  1449. package/src/watcher/watcher-store.ts +2 -1
  1450. package/src/work-items/work-item-runner.ts +15 -42
  1451. package/src/work-items/work-item-store.ts +1 -1
  1452. package/src/workspace/git-service.ts +1 -6
  1453. package/src/workspace/migrations/006-services-config.ts +10 -1
  1454. package/src/workspace/migrations/017-seed-persona-dirs.ts +1 -1
  1455. package/src/workspace/migrations/019-scope-journal-to-guardian.ts +1 -1
  1456. package/src/workspace/migrations/028-recover-conversations-from-disk-view.ts +1 -1
  1457. package/src/workspace/migrations/031-drop-user-md.ts +1 -1
  1458. package/src/workspace/migrations/045-release-notes-meet-avatar.ts +3 -4
  1459. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +4 -3
  1460. package/src/workspace/migrations/052-seed-default-inference-profiles.ts +150 -0
  1461. package/src/workspace/migrations/053-release-notes-acp-codex.ts +107 -0
  1462. package/src/workspace/migrations/054-seed-recall-callsite.ts +102 -0
  1463. package/src/workspace/migrations/055-release-notes-agentic-recall.ts +63 -0
  1464. package/src/workspace/migrations/056-release-notes-inference-profile-reordering.ts +65 -0
  1465. package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +98 -0
  1466. package/src/workspace/migrations/058-release-notes-acp-sessions-ui.ts +71 -0
  1467. package/src/workspace/migrations/059-move-pid-to-workspace.ts +53 -0
  1468. package/src/workspace/migrations/060-memory-v2-init.ts +37 -0
  1469. package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +59 -0
  1470. package/src/workspace/migrations/062-drop-memory-v2-edges-json.ts +27 -0
  1471. package/src/workspace/migrations/063-release-notes-dynamic-model-context.ts +70 -0
  1472. package/src/workspace/migrations/064-unwind-main-agent-opus-seed.ts +64 -0
  1473. package/src/workspace/migrations/rebuild-conversation-disk-view.ts +1 -1
  1474. package/src/workspace/migrations/registry.ts +26 -0
  1475. package/src/workspace/migrations/runner.ts +2 -2
  1476. package/src/workspace/provider-commit-message-generator.ts +4 -4
  1477. package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +0 -471
  1478. package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +0 -436
  1479. package/src/__tests__/cli-command-risk-guard.test.ts +0 -368
  1480. package/src/__tests__/config-watcher-feature-flags.test.ts +0 -211
  1481. package/src/__tests__/conversation-approval-overrides.test.ts +0 -207
  1482. package/src/__tests__/conversation-host-access-routes.test.ts +0 -229
  1483. package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +0 -226
  1484. package/src/__tests__/conversation-tool-setup-side-effect-flag.test.ts +0 -167
  1485. package/src/__tests__/ephemeral-permissions.test.ts +0 -474
  1486. package/src/__tests__/extension-id-sync-guard.test.ts +0 -241
  1487. package/src/__tests__/host-browser-e2e-self-hosted.test.ts +0 -374
  1488. package/src/__tests__/native-host-marker-sync-guard.test.ts +0 -157
  1489. package/src/__tests__/pairing-concurrent.test.ts +0 -84
  1490. package/src/__tests__/pairing-routes.test.ts +0 -181
  1491. package/src/__tests__/parser.test.ts +0 -595
  1492. package/src/__tests__/permission-checker-host-gate.test.ts +0 -488
  1493. package/src/__tests__/permission-controls-v2-flag.test.ts +0 -55
  1494. package/src/__tests__/permission-mode.test.ts +0 -89
  1495. package/src/__tests__/provider-env-vars-scope.test.ts +0 -52
  1496. package/src/__tests__/risk-classifier-parity.test.ts +0 -230
  1497. package/src/__tests__/sandbox-diagnostics.test.ts +0 -138
  1498. package/src/__tests__/sandbox-host-parity.test.ts +0 -1024
  1499. package/src/__tests__/secret-detection-handler.test.ts +0 -74
  1500. package/src/__tests__/secret-scanner-executor.test.ts +0 -451
  1501. package/src/__tests__/shell-identity.test.ts +0 -236
  1502. package/src/__tests__/shell-parser-fuzz.test.ts +0 -629
  1503. package/src/__tests__/shell-parser-property.test.ts +0 -936
  1504. package/src/__tests__/starter-bundle.test.ts +0 -173
  1505. package/src/__tests__/stt-catalog-parity.test.ts +0 -282
  1506. package/src/__tests__/task-runner.test.ts +0 -224
  1507. package/src/__tests__/tcc-sandbox-deny.test.ts +0 -198
  1508. package/src/__tests__/terminal-sandbox.test.ts +0 -374
  1509. package/src/__tests__/tool-executor-shell-integration.test.ts +0 -354
  1510. package/src/__tests__/tool-notification-listener.test.ts +0 -65
  1511. package/src/__tests__/trust-store-pattern-matches.test.ts +0 -29
  1512. package/src/__tests__/trust-store.test.ts +0 -2013
  1513. package/src/__tests__/v2-consent-policy.test.ts +0 -103
  1514. package/src/browser/identifiers.ts +0 -51
  1515. package/src/cli/db.ts +0 -1
  1516. package/src/config/bundled-skills/settings/tools/avatar-get.ts +0 -40
  1517. package/src/config/bundled-skills/settings/tools/avatar-remove.ts +0 -64
  1518. package/src/config/bundled-skills/settings/tools/avatar-update.ts +0 -88
  1519. package/src/context/__tests__/microcompact.test.ts +0 -805
  1520. package/src/context/microcompact.ts +0 -443
  1521. package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +0 -127
  1522. package/src/daemon/approved-devices-store.ts +0 -110
  1523. package/src/daemon/external-skills-bootstrap.ts +0 -41
  1524. package/src/daemon/handlers/slack-channel-oauth-install.ts +0 -197
  1525. package/src/daemon/message-types/trust.ts +0 -71
  1526. package/src/daemon/pairing-store.ts +0 -229
  1527. package/src/events/tool-notification-listener.ts +0 -17
  1528. package/src/ipc/cli-server.ts +0 -252
  1529. package/src/ipc/routes/attachment.ts +0 -114
  1530. package/src/ipc/routes/browser-context.ts +0 -63
  1531. package/src/ipc/routes/browser.ts +0 -97
  1532. package/src/ipc/routes/cache.ts +0 -96
  1533. package/src/ipc/routes/get-contact.ts +0 -16
  1534. package/src/ipc/routes/index.ts +0 -35
  1535. package/src/ipc/routes/list-clients.ts +0 -31
  1536. package/src/ipc/routes/merge-contacts.ts +0 -17
  1537. package/src/ipc/routes/notification.ts +0 -133
  1538. package/src/ipc/routes/rename-conversation.ts +0 -59
  1539. package/src/ipc/routes/search-contacts.ts +0 -19
  1540. package/src/ipc/routes/task-queue.ts +0 -226
  1541. package/src/ipc/routes/task.ts +0 -173
  1542. package/src/ipc/routes/upsert-contact.ts +0 -25
  1543. package/src/ipc/routes/wake-conversation.ts +0 -19
  1544. package/src/memory/db.ts +0 -23
  1545. package/src/permissions/arg-parser.test.ts +0 -161
  1546. package/src/permissions/arg-parser.ts +0 -141
  1547. package/src/permissions/bash-risk-classifier.test.ts +0 -1620
  1548. package/src/permissions/bash-risk-classifier.ts +0 -950
  1549. package/src/permissions/command-registry.test.ts +0 -774
  1550. package/src/permissions/command-registry.ts +0 -1005
  1551. package/src/permissions/defaults.ts +0 -314
  1552. package/src/permissions/file-risk-classifier.test.ts +0 -535
  1553. package/src/permissions/file-risk-classifier.ts +0 -274
  1554. package/src/permissions/permission-mode.ts +0 -24
  1555. package/src/permissions/schedule-risk-classifier.test.ts +0 -129
  1556. package/src/permissions/schedule-risk-classifier.ts +0 -85
  1557. package/src/permissions/shell-identity.ts +0 -297
  1558. package/src/permissions/skill-risk-classifier.test.ts +0 -311
  1559. package/src/permissions/skill-risk-classifier.ts +0 -214
  1560. package/src/permissions/trust-client.ts +0 -359
  1561. package/src/permissions/trust-store-interface.ts +0 -100
  1562. package/src/permissions/trust-store.ts +0 -1330
  1563. package/src/permissions/v2-consent-policy.ts +0 -87
  1564. package/src/permissions/web-risk-classifier.test.ts +0 -170
  1565. package/src/permissions/web-risk-classifier.ts +0 -89
  1566. package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +0 -715
  1567. package/src/runtime/__tests__/capability-tokens.test.ts +0 -258
  1568. package/src/runtime/__tests__/chrome-extension-registry.test.ts +0 -518
  1569. package/src/runtime/__tests__/client-registry.test.ts +0 -293
  1570. package/src/runtime/actor-refresh-token-store.ts +0 -156
  1571. package/src/runtime/actor-token-store.ts +0 -207
  1572. package/src/runtime/auth/__tests__/credential-service.test.ts +0 -264
  1573. package/src/runtime/auth/credential-service.ts +0 -352
  1574. package/src/runtime/chrome-extension-registry.ts +0 -368
  1575. package/src/runtime/client-registry.ts +0 -261
  1576. package/src/runtime/conversation-approval-overrides.ts +0 -86
  1577. package/src/runtime/routes/browser-extension-pair-routes.ts +0 -575
  1578. package/src/runtime/routes/channel-routes.ts +0 -112
  1579. package/src/runtime/routes/contact-routes.test.ts +0 -298
  1580. package/src/runtime/routes/guardian-bootstrap-routes.ts +0 -175
  1581. package/src/runtime/routes/guardian-refresh-routes.ts +0 -79
  1582. package/src/runtime/routes/inbound-stages/verification-intercept.ts +0 -336
  1583. package/src/runtime/routes/invite-routes.ts +0 -280
  1584. package/src/runtime/routes/pairing-routes.ts +0 -431
  1585. package/src/runtime/routes/playground/deps.ts +0 -56
  1586. package/src/runtime/services/__tests__/analyze-deps-singleton.test.ts +0 -67
  1587. package/src/runtime/services/analyze-deps-singleton.ts +0 -32
  1588. package/src/tasks/ephemeral-permissions.ts +0 -55
  1589. package/src/tools/secret-detection-handler.ts +0 -359
  1590. package/src/tools/terminal/backends/native.ts +0 -327
  1591. package/src/tools/terminal/backends/types.ts +0 -37
  1592. package/src/tools/terminal/parser.ts +0 -623
  1593. package/src/tools/terminal/sandbox-diagnostics.ts +0 -87
  1594. package/src/tools/terminal/sandbox.ts +0 -40
  1595. package/src/types/qrcode.d.ts +0 -13
  1596. package/src/util/network-info.ts +0 -55
  1597. /package/node_modules/@vellumai/{ces-contracts → ces-client}/tsconfig.json +0 -0
  1598. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/__tests__/grants.test.ts +0 -0
  1599. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/error.ts +0 -0
  1600. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/grants.ts +0 -0
  1601. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/handles.ts +0 -0
  1602. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/rendering.ts +0 -0
  1603. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/rpc.ts +0 -0
@@ -15,15 +15,17 @@
15
15
  */
16
16
 
17
17
  import { createReadStream } from "node:fs";
18
+ import { hostname } from "node:os";
18
19
  import { PassThrough, Readable } from "node:stream";
19
20
  import { Database } from "bun:sqlite";
20
21
 
21
22
  import { z } from "zod";
22
23
 
24
+ import { getPlatformAssistantId } from "../../config/env.js";
23
25
  import { invalidateConfigCache } from "../../config/loader.js";
26
+ import { getAssistantName } from "../../daemon/identity-helpers.js";
24
27
  import { getDb, resetDb } from "../../memory/db-connection.js";
25
28
  import { validateMigrationState } from "../../memory/migrations/validate-migration-state.js";
26
- import { clearCache as clearTrustCache } from "../../permissions/trust-store.js";
27
29
  import { credentialKey } from "../../security/credential-key.js";
28
30
  import {
29
31
  bulkSetSecureKeysAsync,
@@ -41,12 +43,23 @@ import {
41
43
  getWorkspaceDir,
42
44
  getWorkspaceHooksDir,
43
45
  } from "../../util/platform.js";
44
- import { httpError } from "../http-errors.js";
45
- import type { RouteDefinition } from "../http-router.js";
46
+ import { APP_VERSION } from "../../version.js";
47
+ import { DAEMON_INTERNAL_ASSISTANT_ID } from "../assistant-scope.js";
46
48
  import {
47
49
  validateGcsSignedUrl,
48
50
  type ValidateGcsSignedUrlOptions,
49
51
  } from "../migrations/gcs-signed-url.js";
52
+ import {
53
+ JobAlreadyInProgressError,
54
+ migrationJobs,
55
+ } from "../migrations/job-registry.js";
56
+ import { getOriginMode } from "../migrations/origin-mode.js";
57
+ import type {
58
+ VBundleAssistantInfo,
59
+ VBundleCompatibility,
60
+ VBundleExportOptions,
61
+ VBundleOriginInfo,
62
+ } from "../migrations/vbundle-builder.js";
50
63
  import { streamExportVBundle } from "../migrations/vbundle-builder.js";
51
64
  import {
52
65
  analyzeImport,
@@ -60,6 +73,15 @@ import {
60
73
  } from "../migrations/vbundle-importer.js";
61
74
  import { streamCommitImport } from "../migrations/vbundle-streaming-importer.js";
62
75
  import { validateVBundle } from "../migrations/vbundle-validator.js";
76
+ import {
77
+ BadGatewayError,
78
+ BadRequestError,
79
+ InternalError,
80
+ NotFoundError,
81
+ RouteError,
82
+ } from "./errors.js";
83
+ import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
84
+ import { RouteResponse } from "./types.js";
63
85
 
64
86
  /**
65
87
  * CES account prefix for platform-identity (`vellum:*`) credentials. Entries
@@ -126,6 +148,110 @@ export async function reconcileVellumMetadataFromCes(warningSink: {
126
148
 
127
149
  const log = getLogger("migration-routes");
128
150
 
151
+ /**
152
+ * Fields the export pipeline must populate on the v1 manifest.
153
+ *
154
+ * Centralized so both the synchronous-bytes and async-to-gcs handlers
155
+ * compute the same values (and a future caller doesn't accidentally drift).
156
+ */
157
+ interface ExportManifestInputs {
158
+ assistant: VBundleAssistantInfo;
159
+ origin: VBundleOriginInfo;
160
+ compatibility: VBundleCompatibility;
161
+ exportOptions: VBundleExportOptions;
162
+ }
163
+
164
+ /**
165
+ * Resolve the `assistant.id` for an export.
166
+ *
167
+ * Mirrors `platform/client.ts`'s precedence: in-memory override (set at
168
+ * daemon startup or by secret-routes) → credential store → daemon-internal
169
+ * fallback. The schema requires `id` to be non-empty, so we fall back to
170
+ * `DAEMON_INTERNAL_ASSISTANT_ID` rather than the empty string.
171
+ */
172
+ async function resolveAssistantId(): Promise<string> {
173
+ const inMemory = getPlatformAssistantId();
174
+ if (inMemory) return inMemory;
175
+ try {
176
+ const stored = await getSecureKeyAsync(
177
+ credentialKey("vellum", "platform_assistant_id"),
178
+ );
179
+ if (stored) return stored;
180
+ } catch (err) {
181
+ log.warn(
182
+ { err },
183
+ "Failed to read platform_assistant_id from credential store; falling back to daemon-internal id",
184
+ );
185
+ }
186
+ return DAEMON_INTERNAL_ASSISTANT_ID;
187
+ }
188
+
189
+ /**
190
+ * Decide the truthful `secrets_redacted` flag for an export.
191
+ *
192
+ * The export entry points pass every collected credential through to the
193
+ * builder unfiltered, so the bundle is NOT redacted whenever any
194
+ * credentials made it in. Only flip to true when the credential list is
195
+ * empty AND every credential read succeeded — i.e. there genuinely are
196
+ * no secrets in the bundle.
197
+ *
198
+ * Two failure modes both force `false`:
199
+ * - `storeUnreachable`: the top-level `listSecureKeysAsync()` call
200
+ * failed, so we never even discovered which accounts exist.
201
+ * - `perAccountUnreachable`: the LIST call succeeded but one or more
202
+ * individual `getSecureKeyResultAsync(account)` reads returned
203
+ * `unreachable: true`. Those accounts were silently skipped from the
204
+ * `credentials` array, so a `credentialCount === 0` outcome could
205
+ * reflect "we couldn't read them" rather than "no secrets exist".
206
+ * Claiming a clean redaction in that case would be a lie.
207
+ *
208
+ * NOTE: a managed-mode bundle with `secrets_redacted: false` will fail
209
+ * the validator's cross-field refine. That surfaces an existing
210
+ * platform-side enforcement gap — the runtime emits the truthful value
211
+ * and lets the schema flag it.
212
+ */
213
+ export function computeSecretsRedacted(
214
+ credentialCount: number,
215
+ storeUnreachable: boolean,
216
+ perAccountUnreachable: boolean,
217
+ ): boolean {
218
+ return credentialCount === 0 && !storeUnreachable && !perAccountUnreachable;
219
+ }
220
+
221
+ /**
222
+ * Compute the v1 manifest inputs that aren't tied to per-call options.
223
+ *
224
+ * `walkDirectoryForMetadata` skips `embedding-models`, `data/qdrant`,
225
+ * `signals`, and `deprecated` — `logs` is NOT in the skip list, so log
226
+ * files end up in `manifest.contents`. Browser state and memory vectors
227
+ * (qdrant) are skipped, so those flags are false.
228
+ */
229
+ async function buildExportManifestInputs(): Promise<ExportManifestInputs> {
230
+ const assistantId = await resolveAssistantId();
231
+ const assistantName = getAssistantName() ?? "Assistant";
232
+ const originMode = await getOriginMode();
233
+ return {
234
+ assistant: {
235
+ id: assistantId,
236
+ name: assistantName,
237
+ runtime_version: APP_VERSION,
238
+ },
239
+ origin: {
240
+ mode: originMode,
241
+ hostname: hostname(),
242
+ },
243
+ compatibility: {
244
+ min_runtime_version: APP_VERSION,
245
+ max_runtime_version: null,
246
+ },
247
+ exportOptions: {
248
+ include_logs: true,
249
+ include_browser_state: false,
250
+ include_memory_vectors: false,
251
+ },
252
+ };
253
+ }
254
+
129
255
  /**
130
256
  * POST /v1/migrations/validate
131
257
  *
@@ -139,60 +265,24 @@ const log = getLogger("migration-routes");
139
265
  * 400: Standard error envelope for missing/empty body
140
266
  * 422: Standard error envelope for completely unparseable input
141
267
  */
142
- export async function handleMigrationValidate(req: Request): Promise<Response> {
143
- let fileData: Uint8Array | null = null;
144
-
145
- const contentType = req.headers.get("content-type") ?? "";
146
-
147
- if (contentType.includes("multipart/form-data")) {
148
- try {
149
- const formData = await req.formData();
150
- const file = formData.get("file");
151
- if (!file || !(file instanceof Blob)) {
152
- return httpError(
153
- "BAD_REQUEST",
154
- 'Multipart upload requires a "file" field',
155
- 400,
156
- );
157
- }
158
- fileData = new Uint8Array(await file.arrayBuffer());
159
- } catch (err) {
160
- log.error({ err }, "Failed to parse multipart form data");
161
- return httpError("BAD_REQUEST", "Invalid multipart form data", 400);
162
- }
163
- } else {
164
- // Treat as raw binary body
165
- try {
166
- const arrayBuffer = await req.arrayBuffer();
167
- fileData = new Uint8Array(arrayBuffer);
168
- } catch (err) {
169
- log.error({ err }, "Failed to read request body");
170
- return httpError("BAD_REQUEST", "Failed to read request body", 400);
171
- }
172
- }
173
-
174
- if (!fileData || fileData.length === 0) {
175
- return httpError(
176
- "BAD_REQUEST",
177
- "Request body is empty — a .vbundle file is required",
178
- 400,
179
- );
180
- }
268
+ export async function handleMigrationValidate({
269
+ rawBody,
270
+ headers,
271
+ }: RouteHandlerArgs) {
272
+ const fileData = await extractFileData(rawBody, headers);
181
273
 
182
274
  try {
183
275
  const result = validateVBundle(fileData);
184
276
 
185
- return Response.json({
277
+ return {
186
278
  is_valid: result.is_valid,
187
279
  errors: result.errors,
188
280
  ...(result.manifest ? { manifest: result.manifest } : {}),
189
- });
281
+ };
190
282
  } catch (err) {
191
283
  log.error({ err }, "Unexpected error during vbundle validation");
192
- return httpError(
193
- "INTERNAL_ERROR",
284
+ throw new InternalError(
194
285
  err instanceof Error ? err.message : "Unexpected validation error",
195
- 500,
196
286
  );
197
287
  }
198
288
  }
@@ -214,28 +304,21 @@ export async function handleMigrationValidate(req: Request): Promise<Response> {
214
304
  *
215
305
  * Auth: Requires settings.write scope. Allowed for actor, svc_gateway, svc_daemon, local.
216
306
  */
217
- export async function handleMigrationExport(req: Request): Promise<Response> {
218
- let description: string | undefined;
219
-
220
- // Parse optional JSON body for export metadata
221
- const contentType = req.headers.get("content-type") ?? "";
222
- if (contentType.includes("application/json")) {
223
- try {
224
- const body = (await req.json()) as Record<string, unknown>;
225
- if (typeof body.description === "string") {
226
- description = body.description;
227
- }
228
- } catch (err) {
229
- log.warn({ err }, "Failed to parse export request body — using defaults");
230
- }
231
- }
232
-
307
+ export async function handleMigrationExport(
308
+ _args: RouteHandlerArgs,
309
+ ): Promise<RouteResponse> {
310
+ // The legacy `description` field is no longer carried on the v1
311
+ // manifest. Older clients still POST it; we silently ignore it.
233
312
  let cleanup: (() => Promise<void>) | undefined;
234
313
 
235
314
  try {
236
315
  // Read all stored credentials to include in the export bundle
237
316
  const credentialList = await listSecureKeysAsync();
238
317
  const credentials: Array<{ account: string; value: string }> = [];
318
+ // Track per-account read failures separately from the top-level LIST
319
+ // failure. A single skipped account means we cannot truthfully claim
320
+ // the bundle is fully redacted — we don't know what we missed.
321
+ let perAccountUnreachable = false;
239
322
  if (credentialList.unreachable) {
240
323
  log.warn(
241
324
  "Credential store is unreachable — export will not include credentials",
@@ -244,6 +327,7 @@ export async function handleMigrationExport(req: Request): Promise<Response> {
244
327
  for (const account of credentialList.accounts) {
245
328
  const result = await getSecureKeyResultAsync(account);
246
329
  if (result.unreachable) {
330
+ perAccountUnreachable = true;
247
331
  log.warn(
248
332
  { account },
249
333
  "Credential store unreachable when reading credential — skipping",
@@ -254,10 +338,17 @@ export async function handleMigrationExport(req: Request): Promise<Response> {
254
338
  }
255
339
  }
256
340
 
341
+ const manifestInputs = await buildExportManifestInputs();
342
+ const secretsRedacted = computeSecretsRedacted(
343
+ credentials.length,
344
+ credentialList.unreachable,
345
+ perAccountUnreachable,
346
+ );
347
+
257
348
  const result = await streamExportVBundle({
258
349
  workspaceDir: getWorkspaceDir(),
259
- source: "runtime-export",
260
- description,
350
+ ...manifestInputs,
351
+ secretsRedacted,
261
352
  credentials,
262
353
  checkpoint: () => {
263
354
  const dbPath = getDbPath();
@@ -292,30 +383,318 @@ export async function handleMigrationExport(req: Request): Promise<Response> {
292
383
  cleanup = undefined;
293
384
  });
294
385
 
295
- const body = Readable.toWeb(fileStream) as unknown as ReadableStream;
296
-
297
- return new Response(body, {
298
- status: 200,
299
- headers: {
300
- "Content-Type": "application/octet-stream",
301
- "Content-Disposition": `attachment; filename="${filename}"`,
302
- "Content-Length": String(size),
303
- "X-Vbundle-Schema-Version": manifest.schema_version,
304
- "X-Vbundle-Manifest-Sha256": manifest.manifest_sha256,
305
- "X-Vbundle-Credentials-Included": String(credentials.length),
306
- },
386
+ const streamBody = Readable.toWeb(fileStream) as unknown as ReadableStream;
387
+
388
+ return new RouteResponse(streamBody, {
389
+ "Content-Type": "application/octet-stream",
390
+ "Content-Disposition": `attachment; filename="${filename}"`,
391
+ "Content-Length": String(size),
392
+ // `schema_version` is now an integer; clients that parse this header
393
+ // continue to work, but the value flips from "1.0" to "1".
394
+ "X-Vbundle-Schema-Version": String(manifest.schema_version),
395
+ // Header name preserved for cross-version client compat; populated
396
+ // from the renamed manifest `checksum` field.
397
+ "X-Vbundle-Manifest-Sha256": manifest.checksum,
398
+ "X-Vbundle-Credentials-Included": String(credentials.length),
307
399
  });
308
400
  } catch (err) {
309
401
  await cleanup?.();
310
402
  log.error({ err }, "Failed to build export bundle");
311
- return httpError(
312
- "INTERNAL_ERROR",
403
+ throw new InternalError(
313
404
  err instanceof Error ? err.message : "Unexpected export error",
314
- 500,
315
405
  );
316
406
  }
317
407
  }
318
408
 
409
+ // ---------------------------------------------------------------------------
410
+ // POST /v1/migrations/export-to-gcs — async export streamed to a signed URL
411
+ // ---------------------------------------------------------------------------
412
+
413
+ /** 60 minutes — matches the URL-body import fetch deadline. */
414
+ const EXPORT_TO_GCS_PUT_TIMEOUT_MS = 60 * 60 * 1000;
415
+
416
+ const MigrationExportToGcsBody = z.object({
417
+ upload_url: z.string().url(),
418
+ description: z.string().optional(),
419
+ });
420
+
421
+ /**
422
+ * Collected credentials plus warning markers if the credential store was
423
+ * unreachable. The caller surfaces the warning in logs; production callers
424
+ * fail closed on errors (a thrown exception → 500) to avoid shipping a
425
+ * bundle with partial credentials. An unreachable store is NOT an error —
426
+ * `handleMigrationExport` treats that case as "export without credentials".
427
+ *
428
+ * - `unreachable`: the top-level `listSecureKeysAsync()` call failed.
429
+ * - `perAccountUnreachable`: the LIST succeeded but one or more individual
430
+ * `getSecureKeyResultAsync(account)` calls returned `unreachable: true`.
431
+ * Those accounts were silently skipped from `credentials`, so the count
432
+ * here understates reality. The flag is what tells `computeSecretsRedacted`
433
+ * it cannot claim a clean redaction.
434
+ */
435
+ interface CollectedCredentials {
436
+ credentials: Array<{ account: string; value: string }>;
437
+ unreachable: boolean;
438
+ perAccountUnreachable: boolean;
439
+ }
440
+
441
+ /**
442
+ * Mirror of the credential-collection block inside `handleMigrationExport`.
443
+ * Factored out so the new async export-to-gcs handler can share the exact
444
+ * same behavior. Throws if the credential store raises an unexpected error —
445
+ * the caller translates that into a 500 (fail closed on credential errors).
446
+ */
447
+ async function collectExportCredentials(): Promise<CollectedCredentials> {
448
+ const credentialList = await listSecureKeysAsync();
449
+ if (credentialList.unreachable) {
450
+ log.warn(
451
+ "Credential store is unreachable — export will not include credentials",
452
+ );
453
+ return {
454
+ credentials: [],
455
+ unreachable: true,
456
+ perAccountUnreachable: false,
457
+ };
458
+ }
459
+ const credentials: Array<{ account: string; value: string }> = [];
460
+ let perAccountUnreachable = false;
461
+ for (const account of credentialList.accounts) {
462
+ const result = await getSecureKeyResultAsync(account);
463
+ if (result.unreachable) {
464
+ perAccountUnreachable = true;
465
+ log.warn(
466
+ { account },
467
+ "Credential store unreachable when reading credential — skipping",
468
+ );
469
+ } else if (result.value != null) {
470
+ credentials.push({ account, value: result.value });
471
+ }
472
+ }
473
+ return { credentials, unreachable: false, perAccountUnreachable };
474
+ }
475
+
476
+ /**
477
+ * POST /v1/migrations/export-to-gcs
478
+ *
479
+ * Starts an async export job that streams a freshly-built .vbundle archive
480
+ * to a GCS signed PUT URL. Returns `202 Accepted` with a `job_id` the caller
481
+ * can poll via the job-status endpoint; the bundle upload runs in the
482
+ * background via `migrationJobs`.
483
+ *
484
+ * Request body (JSON):
485
+ * { upload_url: string, description?: string }
486
+ *
487
+ * Responses:
488
+ * 202: { job_id, status: "pending", type: "export" }
489
+ * 400: { error: { code: "invalid_upload_url", reason } } — URL failed
490
+ * `validateGcsSignedUrl` (scheme/host/signature/traversal).
491
+ * 409: { error: { code: "export_in_progress", job_id } } — another export
492
+ * job is already pending or running.
493
+ * 500: Standard error envelope for credential-collection failures or
494
+ * other unexpected errors before the job is enqueued.
495
+ *
496
+ * Terminal job state (surfaced via the job-status endpoint once poll lands):
497
+ * result: { size, sha256, schemaVersion, credentialsIncluded }
498
+ * error.code = "upload_failed" with `upstreamStatus` on non-2xx PUT
499
+ * error.code = "fetch_failed" on transport errors from the PUT itself.
500
+ *
501
+ * Auth: settings.write scope (matches `migrations/export`).
502
+ */
503
+ export async function handleMigrationExportToGcs({ body }: RouteHandlerArgs) {
504
+ // ── 1. Parse JSON body ────────────────────────────────────────────────
505
+ const parsed = MigrationExportToGcsBody.safeParse(body);
506
+ if (!parsed.success) {
507
+ throw new BadRequestError(
508
+ "Request body must be { upload_url: string, description?: string } with a valid URL",
509
+ );
510
+ }
511
+
512
+ // ── 2. Validate the upload URL. Never log `parsed.data.upload_url`.
513
+ const validated = validateGcsSignedUrl(
514
+ parsed.data.upload_url,
515
+ urlValidatorOptions,
516
+ );
517
+ if (!validated.ok) {
518
+ log.warn(
519
+ { reason: validated.reason },
520
+ "Rejected migration export-to-gcs upload URL",
521
+ );
522
+ throw new RouteError(
523
+ `Invalid upload URL: ${validated.reason}`,
524
+ "invalid_upload_url",
525
+ 400,
526
+ );
527
+ }
528
+
529
+ log.info(
530
+ { host: validated.host, path: validated.path },
531
+ "migration export to GCS starting",
532
+ );
533
+
534
+ // ── 3. Collect credentials up front. Fail closed → 500.
535
+ let collected: CollectedCredentials;
536
+ try {
537
+ collected = await collectExportCredentials();
538
+ } catch (err) {
539
+ log.error({ err }, "Failed to collect credentials for export-to-gcs");
540
+ throw new InternalError(
541
+ err instanceof Error ? err.message : "Failed to collect credentials",
542
+ );
543
+ }
544
+
545
+ const uploadUrl = parsed.data.upload_url;
546
+
547
+ // Compute the v1 manifest inputs once outside the async job runner so we
548
+ // surface failures (e.g. credential-store probe) as a synchronous 500
549
+ // before the caller starts polling.
550
+ let manifestInputs: ExportManifestInputs;
551
+ try {
552
+ manifestInputs = await buildExportManifestInputs();
553
+ } catch (err) {
554
+ log.error({ err }, "Failed to assemble export manifest inputs");
555
+ throw new InternalError(
556
+ err instanceof Error
557
+ ? err.message
558
+ : "Failed to assemble export manifest inputs",
559
+ );
560
+ }
561
+
562
+ const secretsRedacted = computeSecretsRedacted(
563
+ collected.credentials.length,
564
+ collected.unreachable,
565
+ collected.perAccountUnreachable,
566
+ );
567
+
568
+ // ── 4. Enqueue the job. The runner captures the collected credentials.
569
+ let job;
570
+ try {
571
+ job = migrationJobs.startJob("export", async () => {
572
+ let cleanup: (() => Promise<void>) | undefined;
573
+ try {
574
+ const result = await streamExportVBundle({
575
+ workspaceDir: getWorkspaceDir(),
576
+ ...manifestInputs,
577
+ secretsRedacted,
578
+ credentials: collected.credentials,
579
+ checkpoint: () => {
580
+ const dbPath = getDbPath();
581
+ try {
582
+ const db = new Database(dbPath);
583
+ try {
584
+ db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
585
+ } finally {
586
+ db.close();
587
+ }
588
+ } catch (err) {
589
+ log.warn(
590
+ { err },
591
+ "WAL checkpoint failed — exporting without checkpoint",
592
+ );
593
+ }
594
+ },
595
+ });
596
+
597
+ cleanup = result.cleanup;
598
+ const { tempPath, size, manifest } = result;
599
+
600
+ // Stream the temp file to GCS via PUT. Using Node's ReadableStream
601
+ // bridge keeps peak memory bounded — we do NOT load the archive
602
+ // into memory.
603
+ const fileStream = createReadStream(tempPath);
604
+ const webBody = Readable.toWeb(
605
+ fileStream,
606
+ ) as unknown as ReadableStream<Uint8Array>;
607
+
608
+ let response: Response;
609
+ try {
610
+ response = await fetch(uploadUrl, {
611
+ method: "PUT",
612
+ body: webBody,
613
+ // `duplex: "half"` is required when sending a streaming body
614
+ // via fetch in Node/Bun — without it the platform rejects the
615
+ // request as "duplex option is required when body is a
616
+ // ReadableStream".
617
+ duplex: "half",
618
+ // `validateGcsSignedUrl` only vets the initial URL. If the
619
+ // upstream responds with a 3xx, default fetch would follow
620
+ // the redirect and PUT bytes to an attacker-controlled host.
621
+ // Refuse redirects so the signed URL's origin is the only
622
+ // destination for the export archive.
623
+ redirect: "error",
624
+ headers: {
625
+ "Content-Type": "application/octet-stream",
626
+ "Content-Length": String(size),
627
+ },
628
+ signal: AbortSignal.timeout(EXPORT_TO_GCS_PUT_TIMEOUT_MS),
629
+ } as RequestInit & { duplex: "half" });
630
+ } catch (err) {
631
+ // Transport-level fetch failures (DNS, reset, abort) — tag them
632
+ // with the fetch-body marker so the registry maps them to
633
+ // `error.code = "fetch_failed"` and logs stay consistent with
634
+ // the import URL path.
635
+ const wrapped = err instanceof Error ? err : new Error(String(err));
636
+ tagFetchBodyError(wrapped as NodeJS.ErrnoException);
637
+ (wrapped as { code?: string }).code = "fetch_failed";
638
+ throw wrapped;
639
+ }
640
+
641
+ if (!response.ok) {
642
+ // Drain so the socket is released promptly. Ignore drain errors.
643
+ try {
644
+ await response.body?.cancel();
645
+ } catch {
646
+ /* best-effort */
647
+ }
648
+ const uploadErr = new Error(
649
+ `Upload to GCS failed with status ${response.status}`,
650
+ );
651
+ (uploadErr as { code?: string }).code = "upload_failed";
652
+ (uploadErr as { upstreamStatus?: number }).upstreamStatus =
653
+ response.status;
654
+ throw uploadErr;
655
+ }
656
+
657
+ return {
658
+ size,
659
+ sha256: manifest.checksum,
660
+ schemaVersion: manifest.schema_version,
661
+ credentialsIncluded: collected.credentials.length,
662
+ };
663
+ } finally {
664
+ // Mirror the raw-bytes export cleanup pattern: the stream's
665
+ // `close` listener is the happy-path cleanup in that handler, but
666
+ // here we keep everything in the async block, so a finally is the
667
+ // right place to evict the temp file regardless of outcome.
668
+ if (cleanup) {
669
+ try {
670
+ await cleanup();
671
+ } catch (err) {
672
+ log.warn({ err }, "Failed to clean up export-to-gcs temp file");
673
+ }
674
+ }
675
+ }
676
+ });
677
+ } catch (err) {
678
+ if (err instanceof JobAlreadyInProgressError) {
679
+ throw new RouteError(
680
+ `Export already in progress: ${err.existingJobId}`,
681
+ "export_in_progress",
682
+ 409,
683
+ );
684
+ }
685
+ log.error({ err }, "Unexpected error while enqueueing export-to-gcs job");
686
+ throw new InternalError(
687
+ err instanceof Error ? err.message : "Unexpected export-to-gcs error",
688
+ );
689
+ }
690
+
691
+ return {
692
+ job_id: job.id,
693
+ status: "pending" as const,
694
+ type: "export" as const,
695
+ };
696
+ }
697
+
319
698
  /**
320
699
  * Extract file data from a request body, supporting both raw binary
321
700
  * and multipart form data uploads.
@@ -323,42 +702,41 @@ export async function handleMigrationExport(req: Request): Promise<Response> {
323
702
  * Shared between validate and import-preflight handlers.
324
703
  */
325
704
  async function extractFileData(
326
- req: Request,
327
- ): Promise<{ data: Uint8Array } | { error: Response }> {
328
- const contentType = req.headers.get("content-type") ?? "";
705
+ rawBody: Uint8Array | undefined,
706
+ headers: Record<string, string> | undefined,
707
+ ): Promise<Uint8Array> {
708
+ const contentType = headers?.["content-type"] ?? "";
329
709
 
330
710
  if (contentType.includes("multipart/form-data")) {
711
+ if (!rawBody) {
712
+ throw new BadRequestError("Request body is empty");
713
+ }
331
714
  try {
332
- const formData = await req.formData();
715
+ const syntheticReq = new Request("http://localhost", {
716
+ method: "POST",
717
+ headers: { "content-type": contentType },
718
+ body: rawBody.buffer as ArrayBuffer,
719
+ });
720
+ const formData = await syntheticReq.formData();
333
721
  const file = formData.get("file");
334
722
  if (!file || !(file instanceof Blob)) {
335
- return {
336
- error: httpError(
337
- "BAD_REQUEST",
338
- 'Multipart upload requires a "file" field',
339
- 400,
340
- ),
341
- };
723
+ throw new BadRequestError('Multipart upload requires a "file" field');
342
724
  }
343
- return { data: new Uint8Array(await file.arrayBuffer()) };
725
+ return new Uint8Array(await file.arrayBuffer());
344
726
  } catch (err) {
727
+ if (err instanceof BadRequestError) throw err;
345
728
  log.error({ err }, "Failed to parse multipart form data");
346
- return {
347
- error: httpError("BAD_REQUEST", "Invalid multipart form data", 400),
348
- };
729
+ throw new BadRequestError("Invalid multipart form data");
349
730
  }
350
731
  }
351
732
 
352
- // Treat as raw binary body
353
- try {
354
- const arrayBuffer = await req.arrayBuffer();
355
- return { data: new Uint8Array(arrayBuffer) };
356
- } catch (err) {
357
- log.error({ err }, "Failed to read request body");
358
- return {
359
- error: httpError("BAD_REQUEST", "Failed to read request body", 400),
360
- };
733
+ // Raw binary body — already provided as rawBody by the adapter
734
+ if (!rawBody || rawBody.length === 0) {
735
+ throw new BadRequestError(
736
+ "Request body is empty a .vbundle file is required",
737
+ );
361
738
  }
739
+ return rawBody;
362
740
  }
363
741
 
364
742
  /**
@@ -387,35 +765,23 @@ async function extractFileData(
387
765
  *
388
766
  * Auth: Requires settings.write scope. Allowed for actor, svc_gateway, svc_daemon, local.
389
767
  */
390
- export async function handleMigrationImportPreflight(
391
- req: Request,
392
- ): Promise<Response> {
393
- const extracted = await extractFileData(req);
394
- if ("error" in extracted) {
395
- return extracted.error;
396
- }
397
-
398
- const fileData = extracted.data;
399
- if (fileData.length === 0) {
400
- return httpError(
401
- "BAD_REQUEST",
402
- "Request body is empty — a .vbundle file is required",
403
- 400,
404
- );
405
- }
768
+ export async function handleMigrationImportPreflight({
769
+ rawBody,
770
+ headers,
771
+ }: RouteHandlerArgs) {
772
+ const fileData = await extractFileData(rawBody, headers);
406
773
 
407
774
  try {
408
- // Step 1: Validate the bundle
409
775
  const validationResult = validateVBundle(fileData);
410
776
 
411
777
  if (!validationResult.is_valid || !validationResult.manifest) {
412
- return Response.json({
778
+ return {
413
779
  can_import: false,
414
780
  validation: {
415
781
  is_valid: false,
416
782
  errors: validationResult.errors,
417
783
  },
418
- });
784
+ };
419
785
  }
420
786
 
421
787
  const pathResolver = new DefaultPathResolver(
@@ -423,18 +789,14 @@ export async function handleMigrationImportPreflight(
423
789
  getWorkspaceHooksDir(),
424
790
  );
425
791
 
426
- const report = analyzeImport({
792
+ return analyzeImport({
427
793
  manifest: validationResult.manifest,
428
794
  pathResolver,
429
795
  });
430
-
431
- return Response.json(report);
432
796
  } catch (err) {
433
797
  log.error({ err }, "Unexpected error during import preflight analysis");
434
- return httpError(
435
- "INTERNAL_ERROR",
798
+ throw new InternalError(
436
799
  err instanceof Error ? err.message : "Unexpected import preflight error",
437
- 500,
438
800
  );
439
801
  }
440
802
  }
@@ -477,31 +839,18 @@ export async function handleMigrationImportPreflight(
477
839
  *
478
840
  * Auth: Requires settings.write scope. Allowed for actor, svc_gateway, svc_daemon, local.
479
841
  */
480
- export async function handleMigrationImport(req: Request): Promise<Response> {
842
+ export async function handleMigrationImport(
843
+ args: RouteHandlerArgs,
844
+ ): Promise<unknown> {
845
+ const { body, rawBody, headers } = args;
481
846
  // JSON body means the caller is asking us to fetch the bundle from a
482
- // signed URL and stream it through the importer. This keeps the daemon's
483
- // peak memory bounded by one tar entry instead of bundle size, which is
484
- // the whole point of supporting URL-based imports for large bundles.
485
- //
486
- // Raw-bytes path (octet-stream / multipart) is untouched below.
487
- const contentType = req.headers.get("content-type") ?? "";
847
+ // signed URL and stream it through the importer.
848
+ const contentType = headers?.["content-type"] ?? "";
488
849
  if (contentType.includes("application/json")) {
489
- return handleMigrationImportFromUrl(req);
850
+ return handleMigrationImportFromUrl(body);
490
851
  }
491
852
 
492
- const extracted = await extractFileData(req);
493
- if ("error" in extracted) {
494
- return extracted.error;
495
- }
496
-
497
- const fileData = extracted.data;
498
- if (fileData.length === 0) {
499
- return httpError(
500
- "BAD_REQUEST",
501
- "Request body is empty — a .vbundle file is required",
502
- 400,
503
- );
504
- }
853
+ const fileData = await extractFileData(rawBody, headers);
505
854
 
506
855
  try {
507
856
  // Validate the bundle before closing the DB to avoid an unnecessary
@@ -510,11 +859,11 @@ export async function handleMigrationImport(req: Request): Promise<Response> {
510
859
  // (avoids holding two copies of decompressed data in memory).
511
860
  const validation = validateVBundle(fileData);
512
861
  if (!validation.is_valid) {
513
- return Response.json({
862
+ return {
514
863
  success: false,
515
864
  reason: "validation_failed",
516
865
  errors: validation.errors,
517
- });
866
+ };
518
867
  }
519
868
 
520
869
  const pathResolver = new DefaultPathResolver(
@@ -535,7 +884,7 @@ export async function handleMigrationImport(req: Request): Promise<Response> {
535
884
  });
536
885
 
537
886
  if (!result.ok) {
538
- return importCommitFailureResponse(result);
887
+ throwImportCommitFailure(result);
539
888
  }
540
889
 
541
890
  // Import credentials from the bundle into CES (non-blocking — failures
@@ -558,9 +907,8 @@ export async function handleMigrationImport(req: Request): Promise<Response> {
558
907
  // if Django's post-hatch provisioning raced with the import.
559
908
  await reconcileVellumMetadataFromCes(result.report);
560
909
 
561
- // Invalidate in-process caches so imported settings.json and trust.json take effect
910
+ // Invalidate in-process config cache so imported settings.json takes effect
562
911
  invalidateConfigCache();
563
- clearTrustCache();
564
912
 
565
913
  // Check whether the imported database contains migration checkpoints from
566
914
  // a newer version. This is non-blocking — the import has already
@@ -568,19 +916,18 @@ export async function handleMigrationImport(req: Request): Promise<Response> {
568
916
  // not be fully compatible with this daemon's schema.
569
917
  appendNewerMigrationWarningsIfAny(result.report);
570
918
 
571
- return importCommitSuccessResponse(result.report, credentialsImported);
919
+ return importCommitSuccessResult(result.report, credentialsImported);
572
920
  } catch (err) {
573
921
  log.error({ err }, "Unexpected error during import commit");
574
- return httpError(
575
- "INTERNAL_ERROR",
922
+ throw new InternalError(
576
923
  err instanceof Error ? err.message : "Unexpected import error",
577
- 500,
578
924
  );
579
925
  }
580
926
  }
581
927
 
582
928
  // ---------------------------------------------------------------------------
583
- // URL-body variant of POST /v1/migrations/import
929
+ // GCS URL import pipeline — shared by the URL-body branch of
930
+ // POST /v1/migrations/import and POST /v1/migrations/import-from-gcs.
584
931
  // ---------------------------------------------------------------------------
585
932
 
586
933
  /** 60 minutes — matches the gateway's upstream fetch deadline. */
@@ -588,6 +935,8 @@ const URL_FETCH_TIMEOUT_MS = 60 * 60 * 1000;
588
935
 
589
936
  const MigrationImportUrlBody = z.object({ url: z.string().min(1) });
590
937
 
938
+ const MigrationImportFromGcsBody = z.object({ bundle_url: z.string().url() });
939
+
591
940
  /**
592
941
  * Marker attached to errors that originate from the upstream HTTP body
593
942
  * stream (peer reset, abort mid-stream, DNS/transport failure after
@@ -643,43 +992,98 @@ export function _setUrlImportValidatorOptionsForTests(
643
992
  }
644
993
 
645
994
  /**
646
- * Handle a JSON `{ "url": "..." }` body on POST /v1/migrations/import.
647
- *
648
- * Fetches the signed URL, pipes the response body through the streaming
649
- * importer, and returns the same response shapes as the raw-bytes path.
650
- * The signed URL is never logged or included in error responses — only the
651
- * extracted host and path make it into logs.
995
+ * Successful outcome of `runGcsImport`. Mirrors the wire shape produced by
996
+ * `importCommitSuccessResponse` (report fields spread at the top level, with
997
+ * an optional `credentialsImported` summary alongside) so the same value can
998
+ * be serialized directly as a Response body OR stashed as an async-job
999
+ * `result` both the sync endpoint and the async job-status endpoint then
1000
+ * hand the CLI a single, identical `ImportResponse`-compatible shape.
652
1001
  */
653
- async function handleMigrationImportFromUrl(req: Request): Promise<Response> {
654
- // ── 1. Parse JSON body ────────────────────────────────────────────────
655
- let rawBody: unknown;
656
- try {
657
- rawBody = await req.json();
658
- } catch (err) {
659
- log.warn(
660
- { err: err instanceof Error ? err.message : String(err) },
661
- "Failed to parse JSON body on migration import URL request",
662
- );
663
- return httpError("BAD_REQUEST", "Invalid JSON body", 400);
664
- }
1002
+ export interface ImportSummary extends ImportCommitReport {
1003
+ credentialsImported?: CredentialImportSummary;
1004
+ }
665
1005
 
666
- const parsed = MigrationImportUrlBody.safeParse(rawBody);
667
- if (!parsed.success) {
668
- return httpError(
669
- "BAD_REQUEST",
670
- "Request body must be { url: string } with a non-empty url",
671
- 400,
672
- );
1006
+ /**
1007
+ * Structured error thrown by `runGcsImport`. Carries the information needed
1008
+ * to reconstruct the URL-body handler's legacy Response shapes and for the
1009
+ * async-job registry to map to `error.code`/`upstreamStatus`.
1010
+ */
1011
+ interface GcsImportErrorInit {
1012
+ code:
1013
+ | "invalid_url"
1014
+ | "fetch_failed"
1015
+ | "validation_failed"
1016
+ | "extraction_failed"
1017
+ | "write_failed";
1018
+ message: string;
1019
+ upstreamStatus?: number;
1020
+ reason?: string;
1021
+ errors?: Array<{ code: string; message: string; path?: string }>;
1022
+ partial_report?: ImportCommitReport;
1023
+ }
1024
+
1025
+ class GcsImportError extends Error {
1026
+ public readonly code: GcsImportErrorInit["code"];
1027
+ public readonly upstreamStatus?: number;
1028
+ public readonly reason?: string;
1029
+ public readonly errors?: GcsImportErrorInit["errors"];
1030
+ public readonly partial_report?: ImportCommitReport;
1031
+
1032
+ constructor(init: GcsImportErrorInit) {
1033
+ super(init.message);
1034
+ this.name = "GcsImportError";
1035
+ this.code = init.code;
1036
+ if (init.upstreamStatus !== undefined) {
1037
+ this.upstreamStatus = init.upstreamStatus;
1038
+ }
1039
+ if (init.reason !== undefined) {
1040
+ this.reason = init.reason;
1041
+ }
1042
+ if (init.errors !== undefined) {
1043
+ this.errors = init.errors;
1044
+ }
1045
+ if (init.partial_report !== undefined) {
1046
+ this.partial_report = init.partial_report;
1047
+ }
673
1048
  }
1049
+ }
674
1050
 
675
- // ── 2. Validate the URL (defense-in-depth; never log `parsed.data.url`).
676
- const validated = validateGcsSignedUrl(parsed.data.url, urlValidatorOptions);
1051
+ /**
1052
+ * Fetch a .vbundle from a signed GCS URL and commit it via the streaming
1053
+ * importer. On success, returns an `ImportSummary` the caller can serialize
1054
+ * into a Response or stash as an async-job `result`. On failure, throws a
1055
+ * `GcsImportError`:
1056
+ *
1057
+ * - `invalid_url` → URL failed `validateGcsSignedUrl` (pre-fetch).
1058
+ * - `fetch_failed` → upstream fetch error, non-2xx response, missing
1059
+ * body, OR a mid-stream body teardown tagged via
1060
+ * `kFetchBodyError`. `upstreamStatus` is populated
1061
+ * for non-2xx responses.
1062
+ * - `validation_failed` → the bundle failed schema/structural validation
1063
+ * inside `streamCommitImport`; `errors` carries
1064
+ * the per-issue list.
1065
+ * - `extraction_failed` → bundle extraction threw (malformed archive, hash
1066
+ * mismatch, etc.) that was NOT an upstream tear-
1067
+ * down. `reason` carries the importer's string.
1068
+ * - `write_failed` → post-extraction disk write error; `partial_report`
1069
+ * is attached when the importer produced one.
1070
+ *
1071
+ * The signed URL is never echoed into errors or logs — only the extracted
1072
+ * `host`/`path` are.
1073
+ */
1074
+ async function runGcsImport(
1075
+ url: string,
1076
+ _correlationId?: string,
1077
+ ): Promise<ImportSummary> {
1078
+ // ── 1. Validate the URL (defense-in-depth; never log the raw URL).
1079
+ const validated = validateGcsSignedUrl(url, urlValidatorOptions);
677
1080
  if (!validated.ok) {
678
- // `reason` is a stable enum string and safe to include. The raw URL is
679
- // not — it may contain a live signature. Callers get the reason so they
680
- // can correct the URL without leaking anything into observability.
681
1081
  log.warn({ reason: validated.reason }, "Rejected migration import URL");
682
- return httpError("BAD_REQUEST", `Invalid URL: ${validated.reason}`, 400);
1082
+ throw new GcsImportError({
1083
+ code: "invalid_url",
1084
+ message: `Invalid URL: ${validated.reason}`,
1085
+ reason: validated.reason,
1086
+ });
683
1087
  }
684
1088
 
685
1089
  log.info(
@@ -689,10 +1093,10 @@ async function handleMigrationImportFromUrl(req: Request): Promise<Response> {
689
1093
 
690
1094
  const startedAt = Date.now();
691
1095
 
692
- // ── 3. Fetch the URL ──────────────────────────────────────────────────
1096
+ // ── 2. Fetch the URL ──────────────────────────────────────────────────
693
1097
  let upstream: Response;
694
1098
  try {
695
- upstream = await fetch(parsed.data.url, {
1099
+ upstream = await fetch(url, {
696
1100
  signal: AbortSignal.timeout(URL_FETCH_TIMEOUT_MS),
697
1101
  // SSRF guard: `validateGcsSignedUrl` only vetted the initial URL.
698
1102
  // Default fetch behavior follows 3xx responses, which would let a
@@ -710,10 +1114,10 @@ async function handleMigrationImportFromUrl(req: Request): Promise<Response> {
710
1114
  },
711
1115
  "Failed to fetch migration import URL",
712
1116
  );
713
- return Response.json(
714
- { success: false, reason: "fetch_failed" },
715
- { status: 502 },
716
- );
1117
+ throw new GcsImportError({
1118
+ code: "fetch_failed",
1119
+ message: err instanceof Error ? err.message : String(err),
1120
+ });
717
1121
  }
718
1122
 
719
1123
  if (!upstream.ok) {
@@ -731,14 +1135,11 @@ async function handleMigrationImportFromUrl(req: Request): Promise<Response> {
731
1135
  } catch {
732
1136
  /* best effort */
733
1137
  }
734
- return Response.json(
735
- {
736
- success: false,
737
- reason: "fetch_failed",
738
- upstream_status: upstream.status,
739
- },
740
- { status: 502 },
741
- );
1138
+ throw new GcsImportError({
1139
+ code: "fetch_failed",
1140
+ message: `Upstream fetch returned ${upstream.status}`,
1141
+ upstreamStatus: upstream.status,
1142
+ });
742
1143
  }
743
1144
 
744
1145
  if (!upstream.body) {
@@ -746,13 +1147,13 @@ async function handleMigrationImportFromUrl(req: Request): Promise<Response> {
746
1147
  { host: validated.host, path: validated.path },
747
1148
  "Migration import URL fetch returned no body",
748
1149
  );
749
- return Response.json(
750
- { success: false, reason: "fetch_failed" },
751
- { status: 502 },
752
- );
1150
+ throw new GcsImportError({
1151
+ code: "fetch_failed",
1152
+ message: "Upstream fetch returned no body",
1153
+ });
753
1154
  }
754
1155
 
755
- // ── 4. Stream the response through the importer ──────────────────────
1156
+ // ── 3. Stream the response through the importer ──────────────────────
756
1157
  // Convert the WHATWG ReadableStream from fetch() into a Node Readable so
757
1158
  // the tar-stream / gunzip / hash-verifier pipeline inside
758
1159
  // streamCommitImport can consume it via `.pipe()`.
@@ -764,8 +1165,8 @@ async function handleMigrationImportFromUrl(req: Request): Promise<Response> {
764
1165
  // from the upstream HTTP body (peer reset, abort mid-stream, etc.) with a
765
1166
  // known symbol. When that tagged error surfaces out of
766
1167
  // streamCommitImport's gunzip/tar pipeline, we can distinguish it from a
767
- // legitimate bundle-format failure and map it to 502 fetch_failed instead
768
- // of 500 extraction_failed — matching the OpenAPI contract for the URL
1168
+ // legitimate bundle-format failure and map it to `fetch_failed` instead
1169
+ // of `extraction_failed` — matching the OpenAPI contract for the URL
769
1170
  // body shape. We also propagate errors from the wrapper back to the
770
1171
  // upstream stream so its underlying connection is torn down cleanly.
771
1172
  //
@@ -781,7 +1182,7 @@ async function handleMigrationImportFromUrl(req: Request): Promise<Response> {
781
1182
  // `taggedSource`. The subsequent `close` on `upstreamNodeStream` is then a
782
1183
  // cascaded effect of our own teardown, NOT a real upstream failure — so
783
1184
  // we must NOT tag it as a fetch-body error, or local validation /
784
- // extraction errors would be masked as 502 fetch_failed.
1185
+ // extraction errors would be masked as fetch_failed.
785
1186
  let localTeardownInitiated = false;
786
1187
  upstreamNodeStream.on("end", () => {
787
1188
  upstreamEnded = true;
@@ -808,6 +1209,19 @@ async function handleMigrationImportFromUrl(req: Request): Promise<Response> {
808
1209
  taggedSource.destroy(err);
809
1210
  });
810
1211
  upstreamNodeStream.pipe(taggedSource);
1212
+ // Absorb stream errors on `taggedSource`. `streamCommitImport` does
1213
+ // several `await`s (workspace recovery, temp-dir mkdir) before
1214
+ // `parseVBundleStream(source)` attaches its own `source.on('error')`
1215
+ // listener. If the upstream socket is destroyed during that window,
1216
+ // the `upstreamNodeStream.on('close')` handler above calls
1217
+ // `taggedSource.destroy(err)` with no listener attached yet and the
1218
+ // error surfaces as unhandled. We don't need to act on it here — the
1219
+ // `kFetchBodyTornDown` flag has already been latched on the stream,
1220
+ // and the post-import branch below (`wasFetchBodyTornDown(taggedSource)`)
1221
+ // maps the failure to `fetch_failed`. Register this absorber
1222
+ // unconditionally so there is always at least one `'error'` listener
1223
+ // on the wrapper for the lifetime of the stream.
1224
+ taggedSource.on("error", () => {});
811
1225
  // Propagate wrapper teardown back to the upstream fetch body. When the
812
1226
  // streaming importer hits a validation/extraction error, it destroys
813
1227
  // `source` (which is `taggedSource`). Without this listener the
@@ -817,8 +1231,8 @@ async function handleMigrationImportFromUrl(req: Request): Promise<Response> {
817
1231
  // (malformed bundle, hash mismatch, size cap, etc.). We set
818
1232
  // `localTeardownInitiated` BEFORE destroying upstream so the resulting
819
1233
  // cascaded `close` on `upstreamNodeStream` isn't misclassified as a real
820
- // upstream failure (which would return 502 fetch_failed and mask the
821
- // actual validation error).
1234
+ // upstream failure (which would return fetch_failed and mask the actual
1235
+ // validation error).
822
1236
  taggedSource.on("close", () => {
823
1237
  if (!upstreamNodeStream.destroyed) {
824
1238
  localTeardownInitiated = true;
@@ -867,10 +1281,10 @@ async function handleMigrationImportFromUrl(req: Request): Promise<Response> {
867
1281
  },
868
1282
  "Upstream body stream failed mid-import",
869
1283
  );
870
- return Response.json(
871
- { success: false, reason: "fetch_failed" },
872
- { status: 502 },
873
- );
1284
+ throw new GcsImportError({
1285
+ code: "fetch_failed",
1286
+ message: err instanceof Error ? err.message : String(err),
1287
+ });
874
1288
  }
875
1289
  log.error(
876
1290
  {
@@ -880,11 +1294,10 @@ async function handleMigrationImportFromUrl(req: Request): Promise<Response> {
880
1294
  },
881
1295
  "streamCommitImport threw during URL-body import",
882
1296
  );
883
- return httpError(
884
- "INTERNAL_ERROR",
885
- err instanceof Error ? err.message : "Unexpected import error",
886
- 500,
887
- );
1297
+ throw new GcsImportError({
1298
+ code: "extraction_failed",
1299
+ message: err instanceof Error ? err.message : "Unexpected import error",
1300
+ });
888
1301
  }
889
1302
 
890
1303
  if (!result.ok) {
@@ -902,10 +1315,10 @@ async function handleMigrationImportFromUrl(req: Request): Promise<Response> {
902
1315
  },
903
1316
  "Upstream body stream failed mid-import (detected via result)",
904
1317
  );
905
- return Response.json(
906
- { success: false, reason: "fetch_failed" },
907
- { status: 502 },
908
- );
1318
+ throw new GcsImportError({
1319
+ code: "fetch_failed",
1320
+ message: "Upstream body stream failed mid-import",
1321
+ });
909
1322
  }
910
1323
  log.warn(
911
1324
  {
@@ -915,7 +1328,28 @@ async function handleMigrationImportFromUrl(req: Request): Promise<Response> {
915
1328
  },
916
1329
  "streamCommitImport returned failure during URL-body import",
917
1330
  );
918
- return importCommitFailureResponse(result);
1331
+ if (result.reason === "validation_failed") {
1332
+ throw new GcsImportError({
1333
+ code: "validation_failed",
1334
+ message: "Bundle validation failed",
1335
+ reason: result.reason,
1336
+ errors: result.errors,
1337
+ });
1338
+ }
1339
+ if (result.reason === "extraction_failed") {
1340
+ throw new GcsImportError({
1341
+ code: "extraction_failed",
1342
+ message: result.message,
1343
+ reason: result.reason,
1344
+ });
1345
+ }
1346
+ // write_failed
1347
+ throw new GcsImportError({
1348
+ code: "write_failed",
1349
+ message: result.message,
1350
+ reason: result.reason,
1351
+ partial_report: result.partial_report,
1352
+ });
919
1353
  }
920
1354
 
921
1355
  // Merge any warnings accumulated by the credential-import callback into
@@ -949,7 +1383,134 @@ async function handleMigrationImportFromUrl(req: Request): Promise<Response> {
949
1383
  "Migration import from URL complete",
950
1384
  );
951
1385
 
952
- return importCommitSuccessResponse(result.report, credentialsImported);
1386
+ return credentialsImported
1387
+ ? { ...result.report, credentialsImported }
1388
+ : { ...result.report };
1389
+ }
1390
+
1391
+ /**
1392
+ * Handle a JSON `{ "url": "..." }` body on POST /v1/migrations/import.
1393
+ *
1394
+ * Thin wrapper around `runGcsImport` that preserves the legacy synchronous
1395
+ * Response shapes. `handleMigrationImportFromGcs` below uses the same helper
1396
+ * asynchronously via the migration-job registry.
1397
+ */
1398
+ async function handleMigrationImportFromUrl(
1399
+ body: Record<string, unknown> | undefined,
1400
+ ): Promise<unknown> {
1401
+ const parsed = MigrationImportUrlBody.safeParse(body);
1402
+ if (!parsed.success) {
1403
+ throw new BadRequestError(
1404
+ "Request body must be { url: string } with a non-empty url",
1405
+ );
1406
+ }
1407
+
1408
+ try {
1409
+ const summary = await runGcsImport(parsed.data.url);
1410
+ const { credentialsImported, ...report } = summary;
1411
+ return importCommitSuccessResult(report, credentialsImported);
1412
+ } catch (err) {
1413
+ throwGcsImportError(err);
1414
+ }
1415
+ }
1416
+
1417
+ /**
1418
+ * Map a `runGcsImport` error (or any other thrown value) to a thrown
1419
+ * RouteError subclass or a plain-object error body. Always throws —
1420
+ * callers should invoke this in a catch block.
1421
+ */
1422
+ function throwGcsImportError(err: unknown): never {
1423
+ if (err instanceof GcsImportError) {
1424
+ if (err.code === "invalid_url") {
1425
+ throw new BadRequestError(err.message);
1426
+ }
1427
+ if (err.code === "fetch_failed") {
1428
+ throw new BadGatewayError(
1429
+ err.upstreamStatus
1430
+ ? `Upstream fetch returned ${err.upstreamStatus}`
1431
+ : err.message,
1432
+ );
1433
+ }
1434
+ if (err.code === "validation_failed") {
1435
+ // Validation failure is not an HTTP error — return structured body
1436
+ // with 200 (same as raw-bytes validate path).
1437
+ throw new BadRequestError(
1438
+ JSON.stringify({
1439
+ success: false,
1440
+ reason: "validation_failed",
1441
+ errors: err.errors ?? [],
1442
+ }),
1443
+ );
1444
+ }
1445
+ if (err.code === "extraction_failed") {
1446
+ throw new InternalError(err.message);
1447
+ }
1448
+ // write_failed
1449
+ throw new InternalError(err.message);
1450
+ }
1451
+
1452
+ log.error({ err }, "Unexpected error from runGcsImport");
1453
+ throw new InternalError(
1454
+ err instanceof Error ? err.message : "Unexpected import error",
1455
+ );
1456
+ }
1457
+
1458
+ /**
1459
+ * POST /v1/migrations/import-from-gcs
1460
+ *
1461
+ * Kick off an async bundle import from a signed GCS URL. Returns 202 with a
1462
+ * `job_id` the caller can poll via `GET /v1/migrations/jobs/:job_id`
1463
+ * (PR 4). 409 if another import is already pending or running.
1464
+ *
1465
+ * Auth: Requires settings.write scope. Allowed for actor, svc_gateway, svc_daemon, local.
1466
+ */
1467
+ export async function handleMigrationImportFromGcs({ body }: RouteHandlerArgs) {
1468
+ const parsed = MigrationImportFromGcsBody.safeParse(body);
1469
+ if (!parsed.success) {
1470
+ throw new BadRequestError(
1471
+ "Request body must be { bundle_url: string } with a valid URL",
1472
+ );
1473
+ }
1474
+
1475
+ const { bundle_url } = parsed.data;
1476
+
1477
+ // Synchronously validate the GCS URL before consuming the single
1478
+ // in-flight import slot.
1479
+ const validated = validateGcsSignedUrl(bundle_url, urlValidatorOptions);
1480
+ if (!validated.ok) {
1481
+ log.warn(
1482
+ { reason: validated.reason },
1483
+ "Rejected migration import-from-gcs bundle URL",
1484
+ );
1485
+ throw new RouteError(
1486
+ `Invalid bundle URL: ${validated.reason}`,
1487
+ "invalid_bundle_url",
1488
+ 400,
1489
+ );
1490
+ }
1491
+
1492
+ try {
1493
+ const job = migrationJobs.startJob("import", async (jobRecord) =>
1494
+ runGcsImport(bundle_url, jobRecord.id),
1495
+ );
1496
+ return {
1497
+ job_id: job.id,
1498
+ status: "pending" as const,
1499
+ type: "import" as const,
1500
+ };
1501
+ } catch (err) {
1502
+ if (err instanceof JobAlreadyInProgressError) {
1503
+ throw new RouteError(
1504
+ `Import already in progress: ${err.existingJobId}`,
1505
+ "import_in_progress",
1506
+ 409,
1507
+ );
1508
+ }
1509
+ log.error({ err }, "Unexpected error scheduling import-from-gcs job");
1510
+ throw new InternalError(
1511
+ err instanceof Error ? err.message : "Unexpected import error",
1512
+ );
1513
+ }
953
1514
  }
954
1515
 
955
1516
  // ---------------------------------------------------------------------------
@@ -1078,178 +1639,277 @@ function appendNewerMigrationWarningsIfAny(report: ImportCommitReport): void {
1078
1639
  }
1079
1640
 
1080
1641
  /**
1081
- * Build a success Response from an ImportCommitReport. The report fields
1082
- * are spread at the top level, with an optional `credentialsImported`
1083
- * summary alongside.
1642
+ * Build a success result from an ImportCommitReport.
1084
1643
  */
1085
- function importCommitSuccessResponse(
1644
+ function importCommitSuccessResult(
1086
1645
  report: ImportCommitReport,
1087
1646
  credentialsImported: CredentialImportSummary | undefined,
1088
- ): Response {
1089
- return Response.json({
1647
+ ): unknown {
1648
+ return {
1090
1649
  ...report,
1091
1650
  ...(credentialsImported ? { credentialsImported } : {}),
1092
- });
1651
+ };
1093
1652
  }
1094
1653
 
1095
1654
  /**
1096
- * Map an `ImportCommitResult` failure to the Response shape callers of
1097
- * `POST /v1/migrations/import` depend on. Status codes and body shapes
1098
- * are part of the public contract and must remain stable.
1655
+ * Map an `ImportCommitResult` failure to a thrown error or a plain-object
1656
+ * error body. Status codes and body shapes are part of the public contract
1657
+ * and must remain stable.
1099
1658
  */
1100
- function importCommitFailureResponse(
1659
+ function throwImportCommitFailure(
1101
1660
  result: Extract<ImportCommitResult, { ok: false }>,
1102
- ): Response {
1661
+ ): never {
1103
1662
  if (result.reason === "validation_failed") {
1104
- return Response.json({
1105
- success: false,
1106
- reason: "validation_failed",
1107
- errors: result.errors,
1108
- });
1663
+ // Validation failure uses 400 — structured body with error details
1664
+ throw new BadRequestError(
1665
+ JSON.stringify({
1666
+ success: false,
1667
+ reason: "validation_failed",
1668
+ errors: result.errors,
1669
+ }),
1670
+ );
1109
1671
  }
1110
1672
 
1111
1673
  if (result.reason === "extraction_failed") {
1112
- return Response.json(
1113
- {
1114
- success: false,
1115
- reason: "extraction_failed",
1116
- message: result.message,
1117
- },
1118
- { status: 500 },
1119
- );
1674
+ throw new InternalError(result.message);
1120
1675
  }
1121
1676
 
1122
1677
  // write_failed
1123
- return Response.json(
1124
- {
1125
- success: false,
1126
- reason: "write_failed",
1127
- message: result.message,
1128
- ...(result.partial_report
1129
- ? { partial_report: result.partial_report }
1130
- : {}),
1131
- },
1132
- { status: 500 },
1133
- );
1678
+ throw new InternalError(result.message);
1679
+ }
1680
+
1681
+ // ---------------------------------------------------------------------------
1682
+ // GET /v1/migrations/jobs/:job_id
1683
+ // ---------------------------------------------------------------------------
1684
+
1685
+ /**
1686
+ * GET /v1/migrations/jobs/:job_id
1687
+ *
1688
+ * Returns the current status of a migration job tracked by
1689
+ * `MigrationJobRegistry`. The response shape is a discriminated union on
1690
+ * `status`:
1691
+ *
1692
+ * - `{ job_id, type, status: "processing" }`
1693
+ * Covers both the internal `pending` and `running` states — collapsed
1694
+ * into a single wire value to match the platform's transport shape used
1695
+ * by `ExportStatusProcessingSerializer` / `ImportStatusProcessingSerializer`.
1696
+ * - `{ job_id, type, status: "complete", result }`
1697
+ * - `{ job_id, type, status: "failed", error, error_code, upstream_status? }`
1698
+ *
1699
+ * 404 `{ error: { code: "job_not_found" } }` when no job matches the id.
1700
+ */
1701
+ export async function handleMigrationJobStatus({
1702
+ pathParams,
1703
+ }: RouteHandlerArgs) {
1704
+ const jobId = pathParams?.job_id;
1705
+ if (!jobId) {
1706
+ throw new BadRequestError("Missing job_id path parameter");
1707
+ }
1708
+
1709
+ const job = migrationJobs.getJob(jobId);
1710
+ if (job === null) {
1711
+ throw new NotFoundError("Job not found");
1712
+ }
1713
+
1714
+ if (job.status === "complete") {
1715
+ return {
1716
+ job_id: job.id,
1717
+ type: job.type,
1718
+ status: "complete",
1719
+ result: job.result,
1720
+ };
1721
+ }
1722
+
1723
+ if (job.status === "failed") {
1724
+ const error = job.error;
1725
+ const result: Record<string, unknown> = {
1726
+ job_id: job.id,
1727
+ type: job.type,
1728
+ status: "failed",
1729
+ error: error?.message ?? "unknown",
1730
+ error_code: error?.code ?? "unknown",
1731
+ };
1732
+ if (error?.upstreamStatus !== undefined) {
1733
+ result.upstream_status = error.upstreamStatus;
1734
+ }
1735
+ return result;
1736
+ }
1737
+
1738
+ // pending or running — collapse to the platform's "processing" wire value.
1739
+ return {
1740
+ job_id: job.id,
1741
+ type: job.type,
1742
+ status: "processing",
1743
+ };
1134
1744
  }
1135
1745
 
1136
1746
  // ---------------------------------------------------------------------------
1137
1747
  // Route definitions
1138
1748
  // ---------------------------------------------------------------------------
1139
1749
 
1140
- export function migrationRouteDefinitions(): RouteDefinition[] {
1141
- return [
1142
- {
1143
- endpoint: "migrations/validate",
1144
- method: "POST",
1145
- summary: "Validate a .vbundle archive",
1146
- description:
1147
- "Upload a .vbundle archive for validation. Accepts raw binary or multipart form data.",
1148
- tags: ["migrations"],
1149
- responseBody: z.object({
1150
- is_valid: z.boolean(),
1151
- errors: z.array(z.unknown()),
1152
- manifest: z.object({}).passthrough(),
1153
- }),
1154
- handler: async ({ req }) => handleMigrationValidate(req),
1750
+ export const ROUTES: RouteDefinition[] = [
1751
+ {
1752
+ operationId: "migrations_validate_post",
1753
+ endpoint: "migrations/validate",
1754
+ method: "POST",
1755
+ summary: "Validate a .vbundle archive",
1756
+ description:
1757
+ "Upload a .vbundle archive for validation. Accepts raw binary or multipart form data.",
1758
+ tags: ["migrations"],
1759
+ responseBody: z.object({
1760
+ is_valid: z.boolean(),
1761
+ errors: z.array(z.unknown()),
1762
+ manifest: z.object({}).passthrough(),
1763
+ }),
1764
+ handler: handleMigrationValidate,
1765
+ },
1766
+ {
1767
+ operationId: "migrations_export_post",
1768
+ endpoint: "migrations/export",
1769
+ method: "POST",
1770
+ summary: "Export a .vbundle archive",
1771
+ description:
1772
+ "Generate and download a .vbundle archive of the assistant's data. Optional JSON body for metadata.",
1773
+ tags: ["migrations"],
1774
+ requestBody: z.object({
1775
+ description: z.string().describe("Human-readable export description"),
1776
+ }),
1777
+ handler: handleMigrationExport,
1778
+ },
1779
+ {
1780
+ operationId: "migrations_importpreflight_post",
1781
+ endpoint: "migrations/import-preflight",
1782
+ method: "POST",
1783
+ summary: "Dry-run import analysis",
1784
+ description:
1785
+ "Validate a .vbundle archive and return a report of what would change on import without modifying data.",
1786
+ tags: ["migrations"],
1787
+ responseBody: z.object({
1788
+ can_import: z.boolean(),
1789
+ summary: z.object({}).passthrough(),
1790
+ files: z.array(z.unknown()),
1791
+ conflicts: z.array(z.unknown()),
1792
+ manifest: z.object({}).passthrough(),
1793
+ }),
1794
+ handler: handleMigrationImportPreflight,
1795
+ },
1796
+ {
1797
+ operationId: "migrations_import_post",
1798
+ endpoint: "migrations/import",
1799
+ method: "POST",
1800
+ summary: "Import a .vbundle archive",
1801
+ description:
1802
+ "Commit a .vbundle archive import to disk — destructive. Accepts the bundle as raw bytes (application/octet-stream), multipart/form-data, or a JSON body with `{ url }` carrying a signed URL the daemon fetches.",
1803
+ tags: ["migrations"],
1804
+ requestBody: z.object({
1805
+ url: z
1806
+ .string()
1807
+ .url()
1808
+ .describe(
1809
+ "A signed GCS URL pointing to the .vbundle archive (JSON body path only).",
1810
+ ),
1811
+ }),
1812
+ additionalResponses: {
1813
+ "502": {
1814
+ description: "Upstream fetch failed (URL body only).",
1815
+ },
1155
1816
  },
1156
- {
1157
- endpoint: "migrations/export",
1158
- method: "POST",
1159
- summary: "Export a .vbundle archive",
1160
- description:
1161
- "Generate and download a .vbundle archive of the assistant's data. Optional JSON body for metadata.",
1162
- tags: ["migrations"],
1163
- requestBody: z.object({
1164
- description: z.string().describe("Human-readable export description"),
1165
- }),
1166
- handler: async ({ req }) => handleMigrationExport(req),
1817
+ responseBody: z.object({
1818
+ success: z.boolean(),
1819
+ summary: z.object({}).passthrough(),
1820
+ files: z.array(z.unknown()),
1821
+ manifest: z.object({}).passthrough(),
1822
+ warnings: z.array(z.unknown()),
1823
+ }),
1824
+ handler: handleMigrationImport,
1825
+ },
1826
+ {
1827
+ operationId: "migrations_exporttogcs_post",
1828
+ endpoint: "migrations/export-to-gcs",
1829
+ method: "POST",
1830
+ summary: "Start an async export streamed to a GCS signed URL",
1831
+ description:
1832
+ "Kick off a background export job that PUTs a freshly-built .vbundle archive to the supplied GCS signed URL. Returns 202 with a job_id the caller can poll via the job-status endpoint. Fails fast with 409 if another export job is already pending or running.",
1833
+ tags: ["migrations"],
1834
+ requestBody: z.object({
1835
+ upload_url: z
1836
+ .string()
1837
+ .url()
1838
+ .describe("Signed GCS PUT URL that receives the exported bundle."),
1839
+ description: z
1840
+ .string()
1841
+ .optional()
1842
+ .describe("Human-readable export description."),
1843
+ }),
1844
+ responseStatus: "202",
1845
+ responseBody: z.object({
1846
+ job_id: z.string(),
1847
+ status: z.literal("pending"),
1848
+ type: z.literal("export"),
1849
+ }),
1850
+ handler: handleMigrationExportToGcs,
1851
+ },
1852
+ {
1853
+ operationId: "migrations_importfromgcs_post",
1854
+ endpoint: "migrations/import-from-gcs",
1855
+ method: "POST",
1856
+ summary: "Start an async .vbundle import from a signed GCS URL",
1857
+ description:
1858
+ "Schedule a background import job that fetches the bundle at `bundle_url` and streams it through the importer. Returns 202 with a `job_id`; poll `GET /v1/migrations/jobs/{job_id}` for status. 409 if another import is already in flight.",
1859
+ tags: ["migrations"],
1860
+ requestBody: z.object({
1861
+ bundle_url: z.string().url(),
1862
+ }),
1863
+ responseStatus: "202",
1864
+ responseBody: z.object({
1865
+ job_id: z.string(),
1866
+ status: z.literal("pending"),
1867
+ type: z.literal("import"),
1868
+ }),
1869
+ additionalResponses: {
1870
+ "409": {
1871
+ description: "Another import job is already pending or running.",
1872
+ },
1167
1873
  },
1168
- {
1169
- endpoint: "migrations/import-preflight",
1170
- method: "POST",
1171
- summary: "Dry-run import analysis",
1172
- description:
1173
- "Validate a .vbundle archive and return a report of what would change on import without modifying data.",
1174
- tags: ["migrations"],
1175
- responseBody: z.object({
1176
- can_import: z.boolean(),
1177
- summary: z.object({}).passthrough(),
1178
- files: z.array(z.unknown()),
1179
- conflicts: z.array(z.unknown()),
1180
- manifest: z.object({}).passthrough(),
1874
+ handler: handleMigrationImportFromGcs,
1875
+ },
1876
+ {
1877
+ operationId: "migrations_jobs_by_job_id_get",
1878
+ endpoint: "migrations/jobs/:job_id",
1879
+ method: "GET",
1880
+ summary: "Get migration job status",
1881
+ description:
1882
+ "Return the current status of an async migration job (export or import). The response discriminates on `status`: `processing` (pending or running), `complete` (with `result`), or `failed` (with `error`, `error_code`, optional `upstream_status`).",
1883
+ tags: ["migrations"],
1884
+ pathParams: [
1885
+ { name: "job_id", description: "The migration job ID to query." },
1886
+ ],
1887
+ responseBody: z.discriminatedUnion("status", [
1888
+ z.object({
1889
+ job_id: z.string(),
1890
+ type: z.enum(["export", "import"]),
1891
+ status: z.literal("processing"),
1181
1892
  }),
1182
- handler: async ({ req }) => handleMigrationImportPreflight(req),
1183
- },
1184
- {
1185
- endpoint: "migrations/import",
1186
- method: "POST",
1187
- summary: "Import a .vbundle archive",
1188
- description:
1189
- "Commit a .vbundle archive import to disk — destructive. Accepts the bundle as raw bytes (application/octet-stream), multipart/form-data, or a JSON body carrying a signed URL the daemon fetches and streams through the importer.",
1190
- tags: ["migrations"],
1191
- requestBodies: [
1192
- {
1193
- contentType: "application/octet-stream",
1194
- schema: {
1195
- type: "string",
1196
- format: "binary",
1197
- description: "Raw .vbundle archive bytes.",
1198
- },
1199
- },
1200
- {
1201
- contentType: "multipart/form-data",
1202
- schema: {
1203
- type: "object",
1204
- properties: {
1205
- file: {
1206
- type: "string",
1207
- format: "binary",
1208
- description: "The .vbundle archive uploaded as a file field.",
1209
- },
1210
- },
1211
- required: ["file"],
1212
- },
1213
- },
1214
- {
1215
- contentType: "application/json",
1216
- schema: {
1217
- type: "object",
1218
- properties: {
1219
- url: {
1220
- type: "string",
1221
- format: "uri",
1222
- description:
1223
- "A signed GCS URL pointing to the .vbundle archive. The daemon fetches the URL and streams the body through the importer.",
1224
- },
1225
- },
1226
- required: ["url"],
1227
- },
1228
- },
1229
- ],
1230
- additionalResponses: {
1231
- "502": {
1232
- description:
1233
- "Upstream fetch failed (URL body only). Body shape: { success: false, reason: 'fetch_failed', upstream_status?: number }.",
1234
- schema: {
1235
- type: "object",
1236
- properties: {
1237
- success: { type: "boolean" },
1238
- reason: { type: "string", enum: ["fetch_failed"] },
1239
- upstream_status: { type: "integer" },
1240
- },
1241
- required: ["success", "reason"],
1242
- },
1243
- },
1244
- },
1245
- responseBody: z.object({
1246
- success: z.boolean(),
1247
- summary: z.object({}).passthrough(),
1248
- files: z.array(z.unknown()),
1249
- manifest: z.object({}).passthrough(),
1250
- warnings: z.array(z.unknown()),
1893
+ z.object({
1894
+ job_id: z.string(),
1895
+ type: z.enum(["export", "import"]),
1896
+ status: z.literal("complete"),
1897
+ result: z.unknown(),
1898
+ }),
1899
+ z.object({
1900
+ job_id: z.string(),
1901
+ type: z.enum(["export", "import"]),
1902
+ status: z.literal("failed"),
1903
+ error: z.string(),
1904
+ error_code: z.string(),
1905
+ upstream_status: z.number().int().optional(),
1251
1906
  }),
1252
- handler: async ({ req }) => handleMigrationImport(req),
1907
+ ]),
1908
+ additionalResponses: {
1909
+ "404": {
1910
+ description: "No job matches the given id.",
1911
+ },
1253
1912
  },
1254
- ];
1255
- }
1913
+ handler: handleMigrationJobStatus,
1914
+ },
1915
+ ];