@vellumai/assistant 0.4.26 → 0.4.29

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 (1301) hide show
  1. package/.env.example +2 -2
  2. package/AGENTS.md +5 -0
  3. package/ARCHITECTURE.md +169 -69
  4. package/Dockerfile +1 -1
  5. package/README.md +111 -112
  6. package/bun.lock +0 -3
  7. package/docs/architecture/integrations.md +0 -1
  8. package/docs/architecture/memory.md +100 -63
  9. package/docs/error-handling.md +71 -0
  10. package/docs/runbook-trusted-contacts.md +10 -9
  11. package/docs/trusted-contact-access.md +48 -46
  12. package/package.json +3 -3
  13. package/scripts/compare-benchmarks.sh +12 -5
  14. package/scripts/ipc/check-swift-decoder-drift.ts +3 -0
  15. package/scripts/test.sh +89 -5
  16. package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +46 -0
  17. package/src/__tests__/access-request-decision.test.ts +0 -1
  18. package/src/__tests__/account-registry.test.ts +1 -1
  19. package/src/__tests__/actor-token-service.test.ts +36 -23
  20. package/src/__tests__/agent-loop-thinking.test.ts +29 -13
  21. package/src/__tests__/agent-loop.test.ts +2 -1
  22. package/src/__tests__/app-builder-tool-scripts.test.ts +1 -1
  23. package/src/__tests__/approval-routes-http.test.ts +2 -2
  24. package/src/__tests__/asset-materialize-tool.test.ts +7 -7
  25. package/src/__tests__/asset-search-tool.test.ts +7 -7
  26. package/src/__tests__/browser-fill-credential.test.ts +1 -1
  27. package/src/__tests__/bundled-skill-retrieval-guard.test.ts +217 -0
  28. package/src/__tests__/call-controller.test.ts +99 -69
  29. package/src/__tests__/call-start-guardian-guard.test.ts +1 -1
  30. package/src/__tests__/channel-approval-routes.test.ts +113 -70
  31. package/src/__tests__/channel-guardian.test.ts +173 -282
  32. package/src/__tests__/channel-readiness-service.test.ts +6 -2
  33. package/src/__tests__/channel-reply-delivery.test.ts +2 -2
  34. package/src/__tests__/channel-retry-sweep.test.ts +14 -14
  35. package/src/__tests__/checker.test.ts +12 -31
  36. package/src/__tests__/claude-code-tool-profiles.test.ts +1 -1
  37. package/src/__tests__/commit-message-enrichment-service.test.ts +67 -59
  38. package/src/__tests__/compaction.benchmark.test.ts +6 -2
  39. package/src/__tests__/computer-use-tools.test.ts +1 -1
  40. package/src/__tests__/config-schema.test.ts +66 -7
  41. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +29 -29
  42. package/src/__tests__/contacts-tools.test.ts +63 -2
  43. package/src/__tests__/context-overflow-approval.test.ts +141 -0
  44. package/src/__tests__/context-overflow-policy.test.ts +171 -0
  45. package/src/__tests__/context-overflow-reducer.test.ts +533 -0
  46. package/src/__tests__/context-window-manager.test.ts +97 -0
  47. package/src/__tests__/conversation-attention-telegram.test.ts +38 -46
  48. package/src/__tests__/conversation-pairing.test.ts +2 -2
  49. package/src/__tests__/conversation-routes-guardian-reply.test.ts +214 -10
  50. package/src/__tests__/conversation-routes.test.ts +4 -7
  51. package/src/__tests__/credential-broker-browser-fill.test.ts +13 -2
  52. package/src/__tests__/credential-security-e2e.test.ts +1 -1
  53. package/src/__tests__/credential-security-invariants.test.ts +1 -1
  54. package/src/__tests__/credential-vault-unit.test.ts +1 -1
  55. package/src/__tests__/credential-vault.test.ts +11 -8
  56. package/src/__tests__/daemon-lifecycle.test.ts +2 -2
  57. package/src/__tests__/daemon-server-session-init.test.ts +6 -6
  58. package/src/__tests__/delete-managed-skill-tool.test.ts +1 -1
  59. package/src/__tests__/deterministic-verification-control-plane.test.ts +2 -2
  60. package/src/__tests__/emit-signal-routing-intent.test.ts +4 -0
  61. package/src/__tests__/encrypted-store.test.ts +10 -7
  62. package/src/__tests__/ephemeral-permissions.test.ts +3 -3
  63. package/src/__tests__/file-edit-tool.test.ts +1 -1
  64. package/src/__tests__/file-read-tool.test.ts +1 -1
  65. package/src/__tests__/file-write-tool.test.ts +1 -1
  66. package/src/__tests__/fixtures/credential-security-fixtures.ts +87 -64
  67. package/src/__tests__/fixtures/media-reuse-fixtures.ts +37 -31
  68. package/src/__tests__/fixtures/mock-signup-server.ts +171 -115
  69. package/src/__tests__/fixtures/proxy-fixtures.ts +39 -39
  70. package/src/__tests__/followup-tools.test.ts +1 -1
  71. package/src/__tests__/gateway-only-guard.test.ts +3 -0
  72. package/src/__tests__/guardian-actions-endpoint.test.ts +543 -1
  73. package/src/__tests__/guardian-control-plane-policy.test.ts +15 -15
  74. package/src/__tests__/guardian-dispatch.test.ts +79 -1
  75. package/src/__tests__/guardian-grant-minting.test.ts +14 -14
  76. package/src/__tests__/guardian-outbound-http.test.ts +1 -2
  77. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +0 -41
  78. package/src/__tests__/guardian-routing-invariants.test.ts +2 -5
  79. package/src/__tests__/guardian-routing-state.test.ts +36 -52
  80. package/src/__tests__/guardian-verification-intent-routing.test.ts +4 -6
  81. package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +2 -2
  82. package/src/__tests__/handle-user-message-secret-resume.test.ts +39 -1
  83. package/src/__tests__/handlers-cu-observation-blob.test.ts +21 -10
  84. package/src/__tests__/handlers-telegram-config.test.ts +14 -14
  85. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +23 -2
  86. package/src/__tests__/headless-browser-interactions.test.ts +1 -1
  87. package/src/__tests__/headless-browser-navigate.test.ts +1 -1
  88. package/src/__tests__/headless-browser-read-tools.test.ts +1 -1
  89. package/src/__tests__/headless-browser-snapshot.test.ts +1 -1
  90. package/src/__tests__/heartbeat-service.test.ts +45 -2
  91. package/src/__tests__/host-file-edit-tool.test.ts +1 -1
  92. package/src/__tests__/host-file-read-tool.test.ts +1 -1
  93. package/src/__tests__/host-file-write-tool.test.ts +1 -1
  94. package/src/__tests__/host-shell-tool.test.ts +1 -1
  95. package/src/__tests__/inbound-invite-redemption.test.ts +16 -18
  96. package/src/__tests__/ingress-reconcile.test.ts +2 -2
  97. package/src/__tests__/ingress-routes-http.test.ts +2 -1
  98. package/src/__tests__/integrations-cli.test.ts +256 -0
  99. package/src/__tests__/intent-routing.test.ts +4 -5
  100. package/src/__tests__/invite-redemption-service.test.ts +4 -3
  101. package/src/__tests__/ipc-snapshot.test.ts +28 -0
  102. package/src/__tests__/managed-skill-lifecycle.test.ts +1 -1
  103. package/src/__tests__/mcp-cli.test.ts +136 -57
  104. package/src/__tests__/mcp-client-auth.test.ts +95 -0
  105. package/src/__tests__/media-generate-image.test.ts +2 -2
  106. package/src/__tests__/media-reuse-story.e2e.test.ts +8 -8
  107. package/src/__tests__/memory-regressions.test.ts +6 -6
  108. package/src/__tests__/messaging-send-tool.test.ts +1 -1
  109. package/src/__tests__/migration-cross-version-compatibility.test.ts +1855 -0
  110. package/src/__tests__/migration-export-http.test.ts +540 -0
  111. package/src/__tests__/migration-import-commit-http.test.ts +823 -0
  112. package/src/__tests__/migration-import-preflight-http.test.ts +755 -0
  113. package/src/__tests__/migration-parity-persistence.test.ts +1854 -0
  114. package/src/__tests__/migration-transport.test.ts +904 -0
  115. package/src/__tests__/migration-validate-http.test.ts +698 -0
  116. package/src/__tests__/migration-wizard.test.ts +1289 -0
  117. package/src/__tests__/non-member-access-request.test.ts +17 -17
  118. package/src/__tests__/notification-decision-strategy.test.ts +110 -2
  119. package/src/__tests__/notification-deep-link.test.ts +18 -0
  120. package/src/__tests__/notification-guardian-path.test.ts +0 -1
  121. package/src/__tests__/oauth2-gateway-transport.test.ts +1 -1
  122. package/src/__tests__/playbook-execution.test.ts +1 -1
  123. package/src/__tests__/playbook-tools.test.ts +1 -1
  124. package/src/__tests__/provider-streaming.benchmark.test.ts +3 -1
  125. package/src/__tests__/proxy-approval-callback.test.ts +1 -1
  126. package/src/__tests__/qdrant-manager.test.ts +40 -11
  127. package/src/__tests__/rebind-secrets-screen.test.ts +839 -0
  128. package/src/__tests__/recording-handler.test.ts +2 -2
  129. package/src/__tests__/recording-intent-handler.test.ts +3 -3
  130. package/src/__tests__/recording-state-machine.test.ts +2 -2
  131. package/src/__tests__/relay-server.test.ts +506 -227
  132. package/src/__tests__/reminder-store.test.ts +8 -0
  133. package/src/__tests__/reminder.test.ts +8 -0
  134. package/src/__tests__/{resolve-guardian-trust-class.test.ts → resolve-trust-class.test.ts} +11 -17
  135. package/src/__tests__/scaffold-managed-skill-tool.test.ts +1 -1
  136. package/src/__tests__/schedule-tools.test.ts +1 -1
  137. package/src/__tests__/script-proxy-certs.test.ts +1 -1
  138. package/src/__tests__/script-proxy-connect-tunnel.test.ts +2 -3
  139. package/src/__tests__/script-proxy-decision-trace.test.ts +2 -2
  140. package/src/__tests__/script-proxy-http-forwarder.test.ts +1 -1
  141. package/src/__tests__/script-proxy-injection-runtime.test.ts +5 -5
  142. package/src/__tests__/script-proxy-mitm-handler.test.ts +4 -4
  143. package/src/__tests__/script-proxy-policy-runtime.test.ts +2 -2
  144. package/src/__tests__/script-proxy-policy.test.ts +2 -2
  145. package/src/__tests__/script-proxy-session-manager.test.ts +4 -7
  146. package/src/__tests__/script-proxy-session-runtime.test.ts +1 -6
  147. package/src/__tests__/secret-onetime-send.test.ts +4 -4
  148. package/src/__tests__/secret-scanner-executor.test.ts +2 -2
  149. package/src/__tests__/send-endpoint-busy.test.ts +11 -9
  150. package/src/__tests__/send-notification-tool.test.ts +2 -2
  151. package/src/__tests__/session-abort-tool-results.test.ts +17 -2
  152. package/src/__tests__/session-agent-loop.test.ts +456 -35
  153. package/src/__tests__/session-confirmation-signals.test.ts +3 -2
  154. package/src/__tests__/session-conflict-gate.test.ts +20 -3
  155. package/src/__tests__/session-init.benchmark.test.ts +2 -2
  156. package/src/__tests__/session-load-history-repair.test.ts +7 -7
  157. package/src/__tests__/session-pre-run-repair.test.ts +17 -2
  158. package/src/__tests__/session-profile-injection.test.ts +20 -3
  159. package/src/__tests__/session-provider-retry-repair.test.ts +86 -6
  160. package/src/__tests__/session-queue.test.ts +33 -18
  161. package/src/__tests__/session-runtime-assembly.test.ts +147 -1
  162. package/src/__tests__/session-runtime-workspace.test.ts +40 -0
  163. package/src/__tests__/session-slash-known.test.ts +21 -3
  164. package/src/__tests__/session-slash-queue.test.ts +17 -2
  165. package/src/__tests__/session-slash-unknown.test.ts +17 -2
  166. package/src/__tests__/session-surfaces-deselection.test.ts +208 -0
  167. package/src/__tests__/session-workspace-cache-state.test.ts +2 -2
  168. package/src/__tests__/session-workspace-injection.test.ts +17 -2
  169. package/src/__tests__/session-workspace-tool-tracking.test.ts +17 -2
  170. package/src/__tests__/shell-credential-ref.test.ts +1 -1
  171. package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -1
  172. package/src/__tests__/skill-load-feature-flag.test.ts +1 -1
  173. package/src/__tests__/skill-load-tool.test.ts +1 -1
  174. package/src/__tests__/skill-script-runner-host.test.ts +1 -1
  175. package/src/__tests__/skill-script-runner-sandbox.test.ts +1 -1
  176. package/src/__tests__/skill-script-runner.test.ts +1 -1
  177. package/src/__tests__/skill-tool-factory.test.ts +1 -1
  178. package/src/__tests__/slack-skill.test.ts +3 -2
  179. package/src/__tests__/subagent-tools.test.ts +3 -3
  180. package/src/__tests__/swarm-recursion.test.ts +1 -1
  181. package/src/__tests__/swarm-session-integration.test.ts +1 -1
  182. package/src/__tests__/swarm-tool.test.ts +1 -1
  183. package/src/__tests__/task-management-tools.test.ts +1 -1
  184. package/src/__tests__/task-tools.test.ts +1 -1
  185. package/src/__tests__/terminal-tools.test.ts +1 -1
  186. package/src/__tests__/test-support/browser-skill-harness.ts +39 -27
  187. package/src/__tests__/test-support/computer-use-skill-harness.ts +14 -14
  188. package/src/__tests__/tool-approval-handler.test.ts +15 -15
  189. package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -1
  190. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
  191. package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -2
  192. package/src/__tests__/tool-executor-shell-integration.test.ts +1 -1
  193. package/src/__tests__/tool-executor.test.ts +23 -182
  194. package/src/__tests__/tool-grant-request-escalation.test.ts +11 -11
  195. package/src/__tests__/tool-permission-simulate-handler.test.ts +4 -4
  196. package/src/__tests__/transfer-progress-screen.test.ts +1180 -0
  197. package/src/__tests__/trust-context-guards.test.ts +25 -29
  198. package/src/__tests__/trusted-contact-approval-notifier.test.ts +23 -21
  199. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +37 -40
  200. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +29 -25
  201. package/src/__tests__/trusted-contact-multichannel.test.ts +25 -24
  202. package/src/__tests__/trusted-contact-verification.test.ts +63 -77
  203. package/src/__tests__/turn-commit.test.ts +18 -18
  204. package/src/__tests__/twilio-provider.test.ts +7 -7
  205. package/src/__tests__/validation-results-screen.test.ts +1107 -0
  206. package/src/__tests__/view-image-tool.test.ts +1 -1
  207. package/src/__tests__/voice-invite-redemption.test.ts +3 -2
  208. package/src/__tests__/voice-scoped-grant-consumer.test.ts +12 -12
  209. package/src/__tests__/voice-session-bridge.test.ts +24 -24
  210. package/src/agent/attachments.ts +3 -1
  211. package/src/agent/loop.ts +13 -13
  212. package/src/agent/message-types.ts +13 -7
  213. package/src/amazon/cart.ts +59 -32
  214. package/src/amazon/checkout.ts +25 -14
  215. package/src/amazon/client.ts +68 -48
  216. package/src/amazon/product-details.ts +3 -3
  217. package/src/amazon/request-extractor.ts +46 -31
  218. package/src/amazon/search.ts +6 -4
  219. package/src/amazon/session.ts +33 -24
  220. package/src/approvals/AGENTS.md +26 -0
  221. package/src/approvals/approval-primitive.ts +87 -64
  222. package/src/approvals/guardian-decision-primitive.ts +172 -81
  223. package/src/approvals/guardian-request-resolvers.ts +262 -155
  224. package/src/autonomy/autonomy-resolver.ts +7 -5
  225. package/src/autonomy/autonomy-store.ts +34 -19
  226. package/src/autonomy/disposition-mapper.ts +5 -5
  227. package/src/autonomy/index.ts +6 -6
  228. package/src/autonomy/types.ts +7 -3
  229. package/src/browser-extension-relay/client.ts +50 -19
  230. package/src/browser-extension-relay/protocol.ts +11 -11
  231. package/src/browser-extension-relay/server.ts +45 -20
  232. package/src/bundler/app-bundler.ts +75 -50
  233. package/src/bundler/bundle-scanner.ts +145 -41
  234. package/src/bundler/bundle-signer.ts +16 -14
  235. package/src/bundler/signature-verifier.ts +36 -33
  236. package/src/calls/call-constants.ts +10 -3
  237. package/src/calls/call-controller.ts +473 -214
  238. package/src/calls/call-conversation-messages.ts +25 -15
  239. package/src/calls/call-domain.ts +401 -148
  240. package/src/calls/call-pointer-message-composer.ts +26 -21
  241. package/src/calls/call-pointer-messages.ts +52 -28
  242. package/src/calls/call-recovery.ts +53 -37
  243. package/src/calls/call-state-machine.ts +37 -7
  244. package/src/calls/call-state.ts +35 -13
  245. package/src/calls/call-store.ts +165 -77
  246. package/src/calls/elevenlabs-client.ts +39 -20
  247. package/src/calls/guardian-action-sweep.ts +42 -24
  248. package/src/calls/guardian-dispatch.ts +79 -56
  249. package/src/calls/guardian-question-copy.ts +28 -23
  250. package/src/calls/relay-server.ts +1121 -532
  251. package/src/calls/speaker-identification.ts +21 -15
  252. package/src/calls/twilio-config.ts +34 -17
  253. package/src/calls/twilio-provider.ts +108 -55
  254. package/src/calls/twilio-rest.ts +212 -100
  255. package/src/calls/twilio-routes.ts +165 -92
  256. package/src/calls/types.ts +55 -7
  257. package/src/calls/voice-quality.ts +6 -4
  258. package/src/calls/voice-session-bridge.ts +181 -133
  259. package/src/channels/config.ts +17 -13
  260. package/src/channels/types.ts +38 -10
  261. package/src/cli/amazon.ts +333 -227
  262. package/src/cli/config-commands.ts +236 -146
  263. package/src/cli/core-commands.ts +403 -329
  264. package/src/cli/email-guardrails.ts +38 -19
  265. package/src/cli/email.ts +207 -153
  266. package/src/cli/influencer.ts +58 -56
  267. package/src/cli/integrations.ts +362 -0
  268. package/src/cli/ipc-client.ts +24 -19
  269. package/src/cli/map.ts +176 -129
  270. package/src/cli/mcp.ts +260 -152
  271. package/src/cli/sequence.ts +165 -107
  272. package/src/cli/twitter.ts +302 -218
  273. package/src/cli.ts +418 -279
  274. package/src/commands/cc-command-registry.ts +52 -27
  275. package/src/config/agent-schema.ts +217 -134
  276. package/src/config/assistant-feature-flags.ts +23 -18
  277. package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +19 -0
  278. package/src/config/bundled-skills/app-builder/tools/app-create.ts +7 -4
  279. package/src/config/bundled-skills/app-builder/tools/app-delete.ts +6 -3
  280. package/src/config/bundled-skills/app-builder/tools/app-file-edit.ts +7 -4
  281. package/src/config/bundled-skills/app-builder/tools/app-file-list.ts +6 -3
  282. package/src/config/bundled-skills/app-builder/tools/app-file-read.ts +6 -3
  283. package/src/config/bundled-skills/app-builder/tools/app-file-write.ts +7 -4
  284. package/src/config/bundled-skills/app-builder/tools/app-list.ts +6 -3
  285. package/src/config/bundled-skills/app-builder/tools/app-query.ts +6 -3
  286. package/src/config/bundled-skills/app-builder/tools/app-update.ts +6 -3
  287. package/src/config/bundled-skills/browser/tools/browser-click.ts +5 -2
  288. package/src/config/bundled-skills/browser/tools/browser-close.ts +5 -2
  289. package/src/config/bundled-skills/browser/tools/browser-extract.ts +5 -2
  290. package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +5 -2
  291. package/src/config/bundled-skills/browser/tools/browser-hover.ts +5 -2
  292. package/src/config/bundled-skills/browser/tools/browser-navigate.ts +5 -2
  293. package/src/config/bundled-skills/browser/tools/browser-press-key.ts +5 -2
  294. package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +5 -2
  295. package/src/config/bundled-skills/browser/tools/browser-scroll.ts +5 -2
  296. package/src/config/bundled-skills/browser/tools/browser-select-option.ts +5 -2
  297. package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +5 -2
  298. package/src/config/bundled-skills/browser/tools/browser-type.ts +5 -2
  299. package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +13 -6
  300. package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +5 -2
  301. package/src/config/bundled-skills/claude-code/TOOLS.json +4 -0
  302. package/src/config/bundled-skills/claude-code/tools/claude-code.ts +5 -2
  303. package/src/config/bundled-skills/computer-use/SKILL.md +2 -2
  304. package/src/config/bundled-skills/computer-use/tools/computer-use-click.ts +6 -3
  305. package/src/config/bundled-skills/computer-use/tools/computer-use-done.ts +6 -3
  306. package/src/config/bundled-skills/computer-use/tools/computer-use-double-click.ts +10 -3
  307. package/src/config/bundled-skills/computer-use/tools/computer-use-drag.ts +6 -3
  308. package/src/config/bundled-skills/computer-use/tools/computer-use-key.ts +6 -3
  309. package/src/config/bundled-skills/computer-use/tools/computer-use-open-app.ts +6 -3
  310. package/src/config/bundled-skills/computer-use/tools/computer-use-request-control.ts +10 -3
  311. package/src/config/bundled-skills/computer-use/tools/computer-use-respond.ts +6 -3
  312. package/src/config/bundled-skills/computer-use/tools/computer-use-right-click.ts +10 -3
  313. package/src/config/bundled-skills/computer-use/tools/computer-use-run-applescript.ts +10 -3
  314. package/src/config/bundled-skills/computer-use/tools/computer-use-scroll.ts +6 -3
  315. package/src/config/bundled-skills/computer-use/tools/computer-use-type-text.ts +6 -3
  316. package/src/config/bundled-skills/computer-use/tools/computer-use-wait.ts +6 -3
  317. package/src/config/bundled-skills/configure-settings/SKILL.md +28 -14
  318. package/src/config/bundled-skills/contacts/SKILL.md +446 -15
  319. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +99 -20
  320. package/src/config/bundled-skills/contacts/tools/contact-search.ts +74 -17
  321. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +89 -26
  322. package/src/config/bundled-skills/document/tools/document-create.ts +5 -2
  323. package/src/config/bundled-skills/document/tools/document-update.ts +5 -2
  324. package/src/config/bundled-skills/doordash/doordash-cli.ts +17 -7
  325. package/src/config/bundled-skills/email-setup/SKILL.md +9 -9
  326. package/src/config/bundled-skills/followups/tools/followup-create.ts +5 -2
  327. package/src/config/bundled-skills/followups/tools/followup-list.ts +5 -2
  328. package/src/config/bundled-skills/followups/tools/followup-resolve.ts +5 -2
  329. package/src/config/bundled-skills/google-calendar/calendar-client.ts +44 -32
  330. package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +11 -5
  331. package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +13 -7
  332. package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +11 -5
  333. package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +13 -7
  334. package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +28 -12
  335. package/src/config/bundled-skills/google-calendar/tools/shared.ts +6 -4
  336. package/src/config/bundled-skills/google-calendar/types.ts +3 -3
  337. package/src/config/bundled-skills/guardian-verify-setup/SKILL.md +46 -24
  338. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +36 -19
  339. package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +60 -35
  340. package/src/config/bundled-skills/mcp-setup/SKILL.md +75 -0
  341. package/src/config/bundled-skills/media-processing/SKILL.md +55 -15
  342. package/src/config/bundled-skills/media-processing/TOOLS.json +20 -2
  343. package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +12 -10
  344. package/src/config/bundled-skills/media-processing/__tests__/cost-tracker.test.ts +34 -19
  345. package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +82 -66
  346. package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +148 -0
  347. package/src/config/bundled-skills/media-processing/services/concurrency-pool.ts +1 -1
  348. package/src/config/bundled-skills/media-processing/services/cost-tracker.ts +8 -3
  349. package/src/config/bundled-skills/media-processing/services/gemini-map.ts +117 -53
  350. package/src/config/bundled-skills/media-processing/services/gemini-video.ts +273 -0
  351. package/src/config/bundled-skills/media-processing/services/preprocess.ts +185 -97
  352. package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +32 -27
  353. package/src/config/bundled-skills/media-processing/services/reduce.ts +101 -24
  354. package/src/config/bundled-skills/media-processing/tools/analyze-keyframes.ts +121 -55
  355. package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +58 -24
  356. package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +177 -91
  357. package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +98 -70
  358. package/src/config/bundled-skills/media-processing/tools/media-diagnostics.ts +59 -19
  359. package/src/config/bundled-skills/media-processing/tools/media-status.ts +26 -10
  360. package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +29 -14
  361. package/src/config/bundled-skills/messaging/SKILL.md +7 -5
  362. package/src/config/bundled-skills/messaging/TOOLS.json +7 -7
  363. package/src/config/bundled-skills/messaging/tools/gmail-archive-by-query.ts +31 -13
  364. package/src/config/bundled-skills/messaging/tools/gmail-archive.ts +16 -10
  365. package/src/config/bundled-skills/messaging/tools/gmail-batch-label.ts +18 -9
  366. package/src/config/bundled-skills/messaging/tools/gmail-download-attachment.ts +23 -16
  367. package/src/config/bundled-skills/messaging/tools/gmail-draft.ts +28 -12
  368. package/src/config/bundled-skills/messaging/tools/gmail-filters.ts +41 -21
  369. package/src/config/bundled-skills/messaging/tools/gmail-follow-up.ts +44 -23
  370. package/src/config/bundled-skills/messaging/tools/gmail-forward.ts +73 -33
  371. package/src/config/bundled-skills/messaging/tools/gmail-label.ts +15 -9
  372. package/src/config/bundled-skills/messaging/tools/gmail-list-attachments.ts +22 -14
  373. package/src/config/bundled-skills/messaging/tools/gmail-outreach-scan.ts +99 -50
  374. package/src/config/bundled-skills/messaging/tools/gmail-send-draft.ts +14 -8
  375. package/src/config/bundled-skills/messaging/tools/gmail-send-with-attachments.ts +63 -44
  376. package/src/config/bundled-skills/messaging/tools/gmail-sender-digest.ts +90 -46
  377. package/src/config/bundled-skills/messaging/tools/gmail-summarize-thread.ts +43 -22
  378. package/src/config/bundled-skills/messaging/tools/gmail-trash.ts +15 -9
  379. package/src/config/bundled-skills/messaging/tools/gmail-triage.ts +51 -22
  380. package/src/config/bundled-skills/messaging/tools/gmail-unsubscribe.ts +62 -26
  381. package/src/config/bundled-skills/messaging/tools/gmail-vacation.ts +34 -19
  382. package/src/config/bundled-skills/messaging/tools/google-contacts.ts +32 -16
  383. package/src/config/bundled-skills/messaging/tools/messaging-analyze-activity.ts +10 -4
  384. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +91 -47
  385. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +21 -9
  386. package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +9 -3
  387. package/src/config/bundled-skills/messaging/tools/messaging-draft.ts +30 -17
  388. package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +10 -4
  389. package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +14 -6
  390. package/src/config/bundled-skills/messaging/tools/messaging-read.ts +16 -5
  391. package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +63 -36
  392. package/src/config/bundled-skills/messaging/tools/messaging-search.ts +10 -4
  393. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +30 -12
  394. package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +48 -29
  395. package/src/config/bundled-skills/messaging/tools/scan-result-store.ts +20 -6
  396. package/src/config/bundled-skills/messaging/tools/send-notification.ts +1 -1
  397. package/src/config/bundled-skills/messaging/tools/sequence-analytics.ts +59 -22
  398. package/src/config/bundled-skills/messaging/tools/sequence-cancel.ts +13 -7
  399. package/src/config/bundled-skills/messaging/tools/sequence-create.ts +27 -12
  400. package/src/config/bundled-skills/messaging/tools/sequence-delete.ts +14 -6
  401. package/src/config/bundled-skills/messaging/tools/sequence-enroll.ts +30 -11
  402. package/src/config/bundled-skills/messaging/tools/sequence-enrollment-list.ts +16 -8
  403. package/src/config/bundled-skills/messaging/tools/sequence-get.ts +31 -13
  404. package/src/config/bundled-skills/messaging/tools/sequence-import.ts +38 -22
  405. package/src/config/bundled-skills/messaging/tools/sequence-list.ts +16 -7
  406. package/src/config/bundled-skills/messaging/tools/sequence-pause.ts +29 -10
  407. package/src/config/bundled-skills/messaging/tools/sequence-resume.ts +16 -8
  408. package/src/config/bundled-skills/messaging/tools/sequence-update.ts +35 -16
  409. package/src/config/bundled-skills/messaging/tools/shared.ts +26 -12
  410. package/src/config/bundled-skills/notifications/tools/send-notification.ts +69 -34
  411. package/src/config/bundled-skills/notifications/tools/shared.ts +1 -1
  412. package/src/config/bundled-skills/phone-calls/SKILL.md +46 -48
  413. package/src/config/bundled-skills/phone-calls/tools/call-end.ts +1 -1
  414. package/src/config/bundled-skills/phone-calls/tools/call-start.ts +1 -1
  415. package/src/config/bundled-skills/phone-calls/tools/call-status.ts +1 -1
  416. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +91 -51
  417. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +30 -16
  418. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +66 -27
  419. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +89 -42
  420. package/src/config/bundled-skills/public-ingress/SKILL.md +26 -19
  421. package/src/config/bundled-skills/reminder/tools/reminder-cancel.ts +5 -2
  422. package/src/config/bundled-skills/reminder/tools/reminder-create.ts +5 -2
  423. package/src/config/bundled-skills/reminder/tools/reminder-list.ts +5 -2
  424. package/src/config/bundled-skills/schedule/tools/schedule-create.ts +5 -2
  425. package/src/config/bundled-skills/schedule/tools/schedule-delete.ts +5 -2
  426. package/src/config/bundled-skills/schedule/tools/schedule-list.ts +5 -2
  427. package/src/config/bundled-skills/schedule/tools/schedule-update.ts +5 -2
  428. package/src/config/bundled-skills/screen-recording/SKILL.md +11 -3
  429. package/src/config/bundled-skills/self-upgrade/SKILL.md +9 -8
  430. package/src/config/bundled-skills/slack/TOOLS.json +33 -15
  431. package/src/config/bundled-skills/slack/tools/shared.ts +7 -5
  432. package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +11 -5
  433. package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +11 -5
  434. package/src/config/bundled-skills/slack/tools/slack-configure-channels.ts +46 -16
  435. package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +11 -5
  436. package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +28 -0
  437. package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +12 -6
  438. package/src/config/bundled-skills/sms-setup/SKILL.md +5 -8
  439. package/src/config/bundled-skills/subagent/tools/subagent-abort.ts +5 -2
  440. package/src/config/bundled-skills/subagent/tools/subagent-message.ts +5 -2
  441. package/src/config/bundled-skills/subagent/tools/subagent-read.ts +5 -2
  442. package/src/config/bundled-skills/subagent/tools/subagent-spawn.ts +5 -2
  443. package/src/config/bundled-skills/subagent/tools/subagent-status.ts +5 -2
  444. package/src/config/bundled-skills/tasks/tools/task-delete.ts +5 -2
  445. package/src/config/bundled-skills/tasks/tools/task-list-add.ts +5 -2
  446. package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +5 -2
  447. package/src/config/bundled-skills/tasks/tools/task-list-show.ts +5 -2
  448. package/src/config/bundled-skills/tasks/tools/task-list-update.ts +5 -2
  449. package/src/config/bundled-skills/tasks/tools/task-list.ts +5 -2
  450. package/src/config/bundled-skills/tasks/tools/task-queue-run.ts +5 -2
  451. package/src/config/bundled-skills/tasks/tools/task-run.ts +5 -2
  452. package/src/config/bundled-skills/tasks/tools/task-save.ts +5 -2
  453. package/src/config/bundled-skills/telegram-setup/SKILL.md +7 -8
  454. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +232 -127
  455. package/src/config/bundled-skills/twilio-setup/SKILL.md +7 -12
  456. package/src/config/bundled-skills/twitter/SKILL.md +19 -2
  457. package/src/config/bundled-skills/voice-setup/SKILL.md +5 -5
  458. package/src/config/bundled-skills/watcher/tools/watcher-create.ts +5 -2
  459. package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +5 -2
  460. package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +5 -2
  461. package/src/config/bundled-skills/watcher/tools/watcher-list.ts +5 -2
  462. package/src/config/bundled-skills/watcher/tools/watcher-update.ts +5 -2
  463. package/src/config/bundled-skills/weather/tools/get-weather.ts +5 -2
  464. package/src/config/calls-schema.ts +108 -63
  465. package/src/config/computer-use-prompt.ts +7 -7
  466. package/src/config/core-schema.ts +239 -155
  467. package/src/config/defaults.ts +2 -2
  468. package/src/config/elevenlabs-schema.ts +15 -15
  469. package/src/config/env-registry.ts +33 -33
  470. package/src/config/feature-flag-registry.json +31 -7
  471. package/src/config/loader.ts +118 -58
  472. package/src/config/mcp-schema.ts +29 -15
  473. package/src/config/memory-schema.ts +434 -229
  474. package/src/config/notifications-schema.ts +4 -4
  475. package/src/config/sandbox-schema.ts +2 -2
  476. package/src/config/schema.ts +12 -2
  477. package/src/config/skill-state.ts +27 -15
  478. package/src/config/skills-schema.ts +72 -23
  479. package/src/config/skills.ts +303 -143
  480. package/src/config/system-prompt.ts +25 -6
  481. package/src/config/types.ts +1 -1
  482. package/src/config/update-bulletin-format.ts +3 -3
  483. package/src/config/update-bulletin-state.ts +15 -6
  484. package/src/config/update-bulletin-template-path.ts +8 -4
  485. package/src/config/update-bulletin.ts +33 -14
  486. package/src/config/user-reference.ts +8 -8
  487. package/src/contacts/contact-events.ts +21 -0
  488. package/src/contacts/contact-store.ts +622 -100
  489. package/src/contacts/contacts-write.ts +287 -0
  490. package/src/contacts/index.ts +13 -4
  491. package/src/contacts/startup-migration.ts +21 -0
  492. package/src/contacts/types.ts +47 -2
  493. package/src/context/token-estimator.ts +54 -31
  494. package/src/context/tool-result-truncation.ts +41 -7
  495. package/src/context/window-manager.ts +225 -120
  496. package/src/daemon/approval-generators.ts +83 -55
  497. package/src/daemon/approved-devices-store.ts +33 -20
  498. package/src/daemon/assistant-attachments.ts +134 -98
  499. package/src/daemon/auth-manager.ts +17 -15
  500. package/src/daemon/classifier.ts +117 -46
  501. package/src/daemon/computer-use-session.ts +316 -187
  502. package/src/daemon/config-watcher.ts +91 -44
  503. package/src/daemon/connection-policy.ts +18 -10
  504. package/src/daemon/context-overflow-approval.ts +48 -0
  505. package/src/daemon/context-overflow-policy.ts +50 -0
  506. package/src/daemon/context-overflow-reducer.ts +300 -0
  507. package/src/daemon/daemon-control.ts +79 -51
  508. package/src/daemon/date-context.ts +119 -69
  509. package/src/daemon/dictation-profile-store.ts +94 -48
  510. package/src/daemon/dictation-text-processing.ts +33 -12
  511. package/src/daemon/doordash-steps.ts +92 -49
  512. package/src/daemon/guardian-action-generators.ts +62 -46
  513. package/src/daemon/guardian-verification-intent.ts +31 -18
  514. package/src/daemon/handlers/apps.ts +257 -111
  515. package/src/daemon/handlers/avatar.ts +20 -15
  516. package/src/daemon/handlers/computer-use.ts +82 -39
  517. package/src/daemon/handlers/config-channels.ts +146 -69
  518. package/src/daemon/handlers/config-heartbeat.ts +114 -59
  519. package/src/daemon/handlers/config-inbox.ts +277 -106
  520. package/src/daemon/handlers/config-ingress.ts +127 -55
  521. package/src/daemon/handlers/config-integrations.ts +145 -88
  522. package/src/daemon/handlers/config-model.ts +58 -22
  523. package/src/daemon/handlers/config-platform.ts +40 -16
  524. package/src/daemon/handlers/config-scheduling.ts +109 -48
  525. package/src/daemon/handlers/config-slack-channel.ts +67 -35
  526. package/src/daemon/handlers/config-slack.ts +21 -20
  527. package/src/daemon/handlers/config-telegram.ts +100 -70
  528. package/src/daemon/handlers/config-tools.ts +103 -55
  529. package/src/daemon/handlers/config-trust.ts +50 -20
  530. package/src/daemon/handlers/config.ts +72 -24
  531. package/src/daemon/handlers/contacts.ts +163 -0
  532. package/src/daemon/handlers/diagnostics.ts +90 -48
  533. package/src/daemon/handlers/documents.ts +74 -46
  534. package/src/daemon/handlers/guardian-actions.ts +118 -71
  535. package/src/daemon/handlers/home-base.ts +19 -16
  536. package/src/daemon/handlers/identity.ts +65 -45
  537. package/src/daemon/handlers/index.ts +78 -54
  538. package/src/daemon/handlers/misc.ts +664 -234
  539. package/src/daemon/handlers/navigate-settings.ts +14 -11
  540. package/src/daemon/handlers/oauth-connect.ts +48 -35
  541. package/src/daemon/handlers/open-bundle-handler.ts +31 -24
  542. package/src/daemon/handlers/pairing.ts +51 -25
  543. package/src/daemon/handlers/publish.ts +55 -33
  544. package/src/daemon/handlers/recording.ts +378 -162
  545. package/src/daemon/handlers/sessions.ts +923 -423
  546. package/src/daemon/handlers/shared.ts +202 -117
  547. package/src/daemon/handlers/signing.ts +25 -6
  548. package/src/daemon/handlers/subagents.ts +117 -56
  549. package/src/daemon/handlers/twitter-auth.ts +70 -49
  550. package/src/daemon/handlers/work-items.ts +264 -112
  551. package/src/daemon/handlers/workspace-files.ts +27 -20
  552. package/src/daemon/handlers.ts +2 -2
  553. package/src/daemon/history-repair.ts +16 -15
  554. package/src/daemon/identity-helpers.ts +4 -4
  555. package/src/daemon/install-cli-launchers.ts +33 -22
  556. package/src/daemon/ipc-blob-store.ts +38 -24
  557. package/src/daemon/ipc-contract/apps.ts +61 -49
  558. package/src/daemon/ipc-contract/computer-use.ts +47 -37
  559. package/src/daemon/ipc-contract/contacts.ts +69 -0
  560. package/src/daemon/ipc-contract/diagnostics.ts +14 -14
  561. package/src/daemon/ipc-contract/documents.ts +8 -8
  562. package/src/daemon/ipc-contract/guardian-actions.ts +4 -4
  563. package/src/daemon/ipc-contract/inbox.ts +16 -16
  564. package/src/daemon/ipc-contract/integrations.ts +57 -44
  565. package/src/daemon/ipc-contract/memory.ts +3 -5
  566. package/src/daemon/ipc-contract/messages.ts +95 -69
  567. package/src/daemon/ipc-contract/notifications.ts +10 -6
  568. package/src/daemon/ipc-contract/pairing.ts +8 -8
  569. package/src/daemon/ipc-contract/schedules.ts +20 -20
  570. package/src/daemon/ipc-contract/sessions.ts +88 -57
  571. package/src/daemon/ipc-contract/settings.ts +12 -7
  572. package/src/daemon/ipc-contract/shared.ts +9 -7
  573. package/src/daemon/ipc-contract/skills.ts +46 -26
  574. package/src/daemon/ipc-contract/subagents.ts +9 -9
  575. package/src/daemon/ipc-contract/trust.ts +11 -11
  576. package/src/daemon/ipc-contract/work-items.ts +33 -28
  577. package/src/daemon/ipc-contract/workspace.ts +28 -21
  578. package/src/daemon/ipc-contract-inventory.json +8 -0
  579. package/src/daemon/ipc-contract-inventory.ts +29 -26
  580. package/src/daemon/ipc-contract.ts +111 -44
  581. package/src/daemon/ipc-handler.ts +27 -19
  582. package/src/daemon/ipc-protocol.ts +22 -12
  583. package/src/daemon/ipc-validate.ts +91 -46
  584. package/src/daemon/lifecycle.ts +25 -1
  585. package/src/daemon/main.ts +10 -8
  586. package/src/daemon/media-visibility-policy.ts +3 -1
  587. package/src/daemon/pairing-store.ts +72 -40
  588. package/src/daemon/providers-setup.ts +35 -25
  589. package/src/daemon/recording-executor.ts +37 -30
  590. package/src/daemon/recording-intent-fallback.ts +58 -28
  591. package/src/daemon/recording-intent.ts +71 -61
  592. package/src/daemon/ride-shotgun-handler.ts +201 -121
  593. package/src/daemon/seed-files.ts +28 -17
  594. package/src/daemon/server.ts +23 -14
  595. package/src/daemon/session-agent-loop-handlers.ts +261 -135
  596. package/src/daemon/session-agent-loop.ts +795 -253
  597. package/src/daemon/session-attachments.ts +104 -39
  598. package/src/daemon/session-conflict-gate.ts +72 -28
  599. package/src/daemon/session-dynamic-profile.ts +36 -22
  600. package/src/daemon/session-error.ts +50 -45
  601. package/src/daemon/session-evictor.ts +17 -10
  602. package/src/daemon/session-history.ts +201 -89
  603. package/src/daemon/session-lifecycle.ts +79 -42
  604. package/src/daemon/session-media-retry.ts +89 -41
  605. package/src/daemon/session-memory.ts +77 -55
  606. package/src/daemon/session-messaging.ts +261 -111
  607. package/src/daemon/session-notifiers.ts +57 -45
  608. package/src/daemon/session-process.ts +370 -154
  609. package/src/daemon/session-queue-manager.ts +30 -13
  610. package/src/daemon/session-runtime-assembly.ts +61 -15
  611. package/src/daemon/session-skill-tools.ts +84 -36
  612. package/src/daemon/session-slash.ts +178 -113
  613. package/src/daemon/session-surfaces.ts +498 -211
  614. package/src/daemon/session-tool-setup.ts +22 -17
  615. package/src/daemon/session-usage.ts +26 -13
  616. package/src/daemon/session-workspace.ts +7 -4
  617. package/src/daemon/session.ts +18 -19
  618. package/src/daemon/shutdown-handlers.ts +36 -33
  619. package/src/daemon/tls-certs.ts +90 -57
  620. package/src/daemon/tool-side-effects.ts +97 -65
  621. package/src/daemon/trace-emitter.ts +8 -7
  622. package/src/daemon/video-thumbnail.ts +55 -25
  623. package/src/daemon/watch-handler.ts +164 -86
  624. package/src/email/provider.ts +1 -1
  625. package/src/email/providers/agentmail.ts +87 -45
  626. package/src/email/providers/index.ts +19 -14
  627. package/src/email/service.ts +52 -24
  628. package/src/email/types.ts +2 -2
  629. package/src/errors.ts +1 -1
  630. package/src/events/bus.ts +30 -10
  631. package/src/events/domain-events.ts +19 -13
  632. package/src/events/index.ts +6 -6
  633. package/src/events/tool-audit-listener.ts +34 -20
  634. package/src/events/tool-domain-event-publisher.ts +22 -20
  635. package/src/events/tool-metrics-listener.ts +26 -21
  636. package/src/events/tool-notification-listener.ts +5 -5
  637. package/src/events/tool-profiling-listener.ts +33 -23
  638. package/src/events/tool-trace-listener.ts +70 -46
  639. package/src/export/formatter.ts +38 -32
  640. package/src/followups/followup-store.ts +43 -36
  641. package/src/followups/index.ts +2 -2
  642. package/src/followups/types.ts +1 -1
  643. package/src/gallery/default-gallery.ts +37 -34
  644. package/src/gallery/gallery-manifest.ts +9 -9
  645. package/src/heartbeat/heartbeat-service.ts +59 -37
  646. package/src/home-base/app-link-store.ts +14 -12
  647. package/src/home-base/bootstrap.ts +14 -8
  648. package/src/home-base/prebuilt/seed.ts +35 -26
  649. package/src/home-base/prebuilt-home-base-updater.ts +14 -8
  650. package/src/hooks/cli.ts +56 -43
  651. package/src/hooks/config.ts +27 -14
  652. package/src/hooks/discovery.ts +53 -33
  653. package/src/hooks/manager.ts +50 -26
  654. package/src/hooks/runner.ts +35 -29
  655. package/src/hooks/templates.ts +38 -15
  656. package/src/hooks/types.ts +13 -13
  657. package/src/inbound/platform-callback-registration.ts +21 -15
  658. package/src/inbound/public-ingress-urls.ts +9 -6
  659. package/src/index.ts +20 -19
  660. package/src/influencer/client.ts +269 -108
  661. package/src/instrument.ts +3 -1
  662. package/src/logfire.ts +64 -39
  663. package/src/mcp/client.ts +107 -55
  664. package/src/mcp/manager.ts +45 -18
  665. package/src/mcp/mcp-oauth-provider.ts +114 -62
  666. package/src/media/gemini-image-service.ts +28 -21
  667. package/src/memory/account-store.ts +16 -9
  668. package/src/memory/admin.ts +87 -57
  669. package/src/memory/app-git-service.ts +77 -47
  670. package/src/memory/app-store.ts +151 -77
  671. package/src/memory/attachments-store.ts +123 -53
  672. package/src/memory/canonical-guardian-store.ts +190 -48
  673. package/src/memory/channel-delivery-store.ts +5 -5
  674. package/src/memory/channel-guardian-store.ts +31 -16
  675. package/src/memory/checkpoints.ts +14 -7
  676. package/src/memory/clarification-resolver.ts +219 -104
  677. package/src/memory/conflict-intent.ts +74 -23
  678. package/src/memory/conflict-policy.ts +20 -7
  679. package/src/memory/conflict-store.ts +144 -94
  680. package/src/memory/contradiction-checker.ts +257 -132
  681. package/src/memory/conversation-attention-store.ts +72 -32
  682. package/src/memory/conversation-bootstrap.ts +28 -0
  683. package/src/memory/conversation-crud.ts +12 -5
  684. package/src/memory/conversation-display-order-migration.ts +7 -7
  685. package/src/memory/conversation-key-store.ts +18 -13
  686. package/src/memory/conversation-queries.ts +130 -52
  687. package/src/memory/conversation-store.ts +43 -26
  688. package/src/memory/conversation-title-service.ts +89 -66
  689. package/src/memory/db-init.ts +90 -2
  690. package/src/memory/db.ts +10 -3
  691. package/src/memory/delivery-channels.ts +12 -6
  692. package/src/memory/delivery-crud.ts +26 -12
  693. package/src/memory/delivery-status.ts +19 -16
  694. package/src/memory/embedding-backend.ts +205 -77
  695. package/src/memory/embedding-gemini.ts +23 -10
  696. package/src/memory/embedding-local.ts +89 -44
  697. package/src/memory/embedding-ollama.ts +25 -13
  698. package/src/memory/embedding-openai.ts +20 -11
  699. package/src/memory/embedding-runtime-manager.ts +163 -90
  700. package/src/memory/entity-extractor.ts +185 -123
  701. package/src/memory/external-conversation-store.ts +30 -12
  702. package/src/memory/fingerprint.ts +2 -2
  703. package/src/memory/fts-reconciler.ts +57 -28
  704. package/src/memory/guardian-action-store.ts +162 -100
  705. package/src/memory/guardian-approvals.ts +63 -129
  706. package/src/memory/guardian-rate-limits.ts +20 -9
  707. package/src/memory/guardian-verification.ts +82 -35
  708. package/src/memory/indexer.ts +96 -55
  709. package/src/memory/ingress-invite-store.ts +28 -169
  710. package/src/memory/items-extractor.ts +313 -157
  711. package/src/memory/job-handlers/backfill.ts +116 -63
  712. package/src/memory/job-handlers/cleanup.ts +64 -41
  713. package/src/memory/job-handlers/conflict.ts +90 -49
  714. package/src/memory/job-handlers/embedding.ts +32 -17
  715. package/src/memory/job-handlers/extraction.ts +58 -33
  716. package/src/memory/job-handlers/index-maintenance.ts +31 -17
  717. package/src/memory/job-handlers/media-processing.ts +65 -24
  718. package/src/memory/job-handlers/summarization.ts +186 -128
  719. package/src/memory/job-utils.ts +100 -57
  720. package/src/memory/jobs-store.ts +235 -142
  721. package/src/memory/jobs-worker.ts +167 -83
  722. package/src/memory/llm-request-log-store.ts +13 -11
  723. package/src/memory/llm-usage-store.ts +35 -26
  724. package/src/memory/media-store.ts +151 -44
  725. package/src/memory/message-content.ts +28 -18
  726. package/src/memory/migrations/001-job-deferrals.ts +11 -5
  727. package/src/memory/migrations/002-tool-invocations-fk.ts +14 -6
  728. package/src/memory/migrations/003-memory-fts-backfill.ts +11 -5
  729. package/src/memory/migrations/004-entity-relation-dedup.ts +17 -11
  730. package/src/memory/migrations/005-fingerprint-scope-unique.ts +36 -21
  731. package/src/memory/migrations/006-scope-salted-fingerprints.ts +35 -20
  732. package/src/memory/migrations/007-assistant-id-to-self.ts +40 -27
  733. package/src/memory/migrations/008-remove-assistant-id-columns.ts +58 -36
  734. package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +36 -22
  735. package/src/memory/migrations/010-ext-conv-bindings-channel-chat-unique.ts +21 -11
  736. package/src/memory/migrations/011-call-sessions-provider-sid-dedup.ts +30 -15
  737. package/src/memory/migrations/012-call-sessions-add-initiated-from.ts +4 -2
  738. package/src/memory/migrations/013-guardian-action-tables.ts +29 -11
  739. package/src/memory/migrations/014-backfill-inbox-thread-state.ts +35 -21
  740. package/src/memory/migrations/015-drop-active-search-index.ts +17 -11
  741. package/src/memory/migrations/016-memory-segments-indexes.ts +7 -3
  742. package/src/memory/migrations/017-memory-items-indexes.ts +4 -2
  743. package/src/memory/migrations/018-remaining-table-indexes.ts +13 -5
  744. package/src/memory/migrations/019-notification-tables-schema-migration.ts +34 -20
  745. package/src/memory/migrations/020-rename-macos-ios-channel-to-vellum.ts +87 -53
  746. package/src/memory/migrations/021-conversation-status-indexes.ts +7 -3
  747. package/src/memory/migrations/022-add-origin-interface.ts +4 -2
  748. package/src/memory/migrations/023-memory-item-sources-indexes.ts +4 -2
  749. package/src/memory/migrations/024-embedding-vector-blob.ts +34 -18
  750. package/src/memory/migrations/025-messages-fts-backfill.ts +11 -5
  751. package/src/memory/migrations/026-guardian-verification-sessions.ts +80 -14
  752. package/src/memory/migrations/026a-embeddings-nullable-vector-json.ts +42 -26
  753. package/src/memory/migrations/027-notification-delivery-pairing-columns.ts +22 -8
  754. package/src/memory/migrations/027a-guardian-bootstrap-token.ts +11 -3
  755. package/src/memory/migrations/028-call-session-mode.ts +13 -3
  756. package/src/memory/migrations/028-notification-delivery-client-ack.ts +22 -8
  757. package/src/memory/migrations/029-channel-inbound-delivered-segments.ts +7 -3
  758. package/src/memory/migrations/030-guardian-action-followup.ts +46 -8
  759. package/src/memory/migrations/030-guardian-verification-purpose.ts +4 -2
  760. package/src/memory/migrations/031-conversations-thread-type-index.ts +4 -2
  761. package/src/memory/migrations/032-guardian-delivery-conversation-index.ts +4 -2
  762. package/src/memory/migrations/032-notification-delivery-thread-decision.ts +22 -8
  763. package/src/memory/migrations/033-scoped-approval-grants.ts +1 -1
  764. package/src/memory/migrations/034-guardian-action-tool-metadata.ts +15 -3
  765. package/src/memory/migrations/035-guardian-action-supersession.ts +15 -3
  766. package/src/memory/migrations/036-normalize-phone-identities.ts +101 -87
  767. package/src/memory/migrations/037-voice-invite-columns.ts +22 -4
  768. package/src/memory/migrations/038-actor-token-records.ts +5 -9
  769. package/src/memory/migrations/039-actor-refresh-token-records.ts +7 -13
  770. package/src/memory/migrations/100-core-tables.ts +1 -1
  771. package/src/memory/migrations/101-watchers-and-logs.ts +1 -1
  772. package/src/memory/migrations/103-complex-migrations.ts +9 -9
  773. package/src/memory/migrations/104-core-indexes.ts +188 -64
  774. package/src/memory/migrations/105-contacts-and-triage.ts +28 -10
  775. package/src/memory/migrations/106-call-sessions.ts +58 -16
  776. package/src/memory/migrations/107-followups.ts +16 -6
  777. package/src/memory/migrations/108-tasks-and-work-items.ts +43 -11
  778. package/src/memory/migrations/109-external-conversation-bindings.ts +11 -5
  779. package/src/memory/migrations/110-channel-guardian.ts +48 -10
  780. package/src/memory/migrations/111-media-assets.ts +52 -18
  781. package/src/memory/migrations/112-assistant-inbox.ts +32 -12
  782. package/src/memory/migrations/113-late-migrations.ts +12 -12
  783. package/src/memory/migrations/114-notifications.ts +28 -12
  784. package/src/memory/migrations/115-sequences.ts +10 -4
  785. package/src/memory/migrations/116-messages-fts.ts +1 -1
  786. package/src/memory/migrations/117-conversation-attention.ts +16 -6
  787. package/src/memory/migrations/118-reminder-routing-intent.ts +7 -3
  788. package/src/memory/migrations/119-schema-indexes-and-columns.ts +35 -15
  789. package/src/memory/migrations/120-fk-cascade-rebuilds.ts +36 -17
  790. package/src/memory/migrations/121-canonical-guardian-requests.ts +25 -9
  791. package/src/memory/migrations/122-canonical-guardian-requester-chat-id.ts +11 -3
  792. package/src/memory/migrations/123-canonical-guardian-deliveries-destination-index.ts +4 -2
  793. package/src/memory/migrations/124-voice-invite-display-metadata.ts +15 -3
  794. package/src/memory/migrations/125-guardian-principal-id-columns.ts +22 -4
  795. package/src/memory/migrations/126-backfill-guardian-principal-id.ts +174 -126
  796. package/src/memory/migrations/127-guardian-principal-id-not-null.ts +58 -42
  797. package/src/memory/migrations/128-contacts-role-principal.ts +26 -0
  798. package/src/memory/migrations/129-contact-channels-access-fields.ts +105 -0
  799. package/src/memory/migrations/130-contact-channels-type-ext-chat-id-index.ts +15 -0
  800. package/src/memory/migrations/131-drop-legacy-member-guardian-tables.ts +134 -0
  801. package/src/memory/migrations/132-contacts-assistant-id.ts +21 -0
  802. package/src/memory/migrations/index.ts +82 -73
  803. package/src/memory/migrations/registry.ts +53 -37
  804. package/src/memory/migrations/validate-migration-state.ts +73 -46
  805. package/src/memory/profile-compiler.ts +58 -24
  806. package/src/memory/published-pages-store.ts +12 -16
  807. package/src/memory/qdrant-circuit-breaker.ts +28 -20
  808. package/src/memory/qdrant-client.ts +99 -63
  809. package/src/memory/qdrant-manager.ts +89 -57
  810. package/src/memory/query-builder.ts +9 -7
  811. package/src/memory/raw-query.ts +63 -14
  812. package/src/memory/recall-cache.ts +15 -8
  813. package/src/memory/retrieval-budget.ts +0 -1
  814. package/src/memory/retriever.ts +385 -192
  815. package/src/memory/schema-migration.ts +1 -1
  816. package/src/memory/schema.ts +44 -56
  817. package/src/memory/scoped-approval-grants.ts +99 -45
  818. package/src/memory/search/entity.ts +102 -40
  819. package/src/memory/search/formatting.ts +70 -52
  820. package/src/memory/search/lexical.ts +82 -43
  821. package/src/memory/search/ranking.ts +103 -39
  822. package/src/memory/search/semantic.ts +59 -35
  823. package/src/memory/search/types.ts +8 -8
  824. package/src/memory/segmenter.ts +20 -12
  825. package/src/memory/shared-app-links-store.ts +21 -16
  826. package/src/memory/task-memory-cleanup.ts +18 -8
  827. package/src/memory/tool-usage-store.ts +27 -19
  828. package/src/memory/validation.ts +4 -2
  829. package/src/messaging/activity-analyzer.ts +7 -7
  830. package/src/messaging/draft-store.ts +13 -10
  831. package/src/messaging/email-classifier.ts +73 -37
  832. package/src/messaging/index.ts +3 -3
  833. package/src/messaging/outreach-classifier.ts +76 -38
  834. package/src/messaging/provider-types.ts +2 -4
  835. package/src/messaging/provider.ts +37 -8
  836. package/src/messaging/providers/gmail/adapter.ts +183 -66
  837. package/src/messaging/providers/gmail/client.ts +3 -1
  838. package/src/messaging/providers/gmail/mime-builder.ts +21 -19
  839. package/src/messaging/providers/gmail/people-client.ts +22 -9
  840. package/src/messaging/providers/gmail/types.ts +6 -6
  841. package/src/messaging/providers/slack/adapter.ts +93 -43
  842. package/src/messaging/providers/slack/client.ts +100 -41
  843. package/src/messaging/providers/slack/types.ts +6 -0
  844. package/src/messaging/providers/sms/adapter.ts +76 -40
  845. package/src/messaging/providers/sms/client.ts +4 -4
  846. package/src/messaging/providers/telegram-bot/adapter.ts +52 -30
  847. package/src/messaging/providers/telegram-bot/client.ts +7 -7
  848. package/src/messaging/providers/whatsapp/adapter.ts +58 -31
  849. package/src/messaging/providers/whatsapp/client.ts +4 -4
  850. package/src/messaging/registry.ts +9 -5
  851. package/src/messaging/style-analyzer.ts +69 -39
  852. package/src/messaging/thread-summarizer.ts +101 -53
  853. package/src/messaging/triage-engine.ts +111 -82
  854. package/src/messaging/types.ts +10 -10
  855. package/src/migrations/config-merge.ts +18 -10
  856. package/src/migrations/data-layout.ts +35 -22
  857. package/src/migrations/data-merge.ts +17 -7
  858. package/src/migrations/hooks-merge.ts +43 -16
  859. package/src/migrations/index.ts +6 -6
  860. package/src/migrations/log.ts +9 -5
  861. package/src/migrations/skills-merge.ts +17 -7
  862. package/src/migrations/workspace-layout.ts +39 -25
  863. package/src/notifications/AGENTS.md +5 -0
  864. package/src/notifications/adapters/macos.ts +21 -14
  865. package/src/notifications/adapters/sms.ts +28 -15
  866. package/src/notifications/adapters/telegram.ts +24 -15
  867. package/src/notifications/broadcaster.ts +108 -52
  868. package/src/notifications/conversation-pairing.ts +64 -29
  869. package/src/notifications/copy-composer.ts +165 -95
  870. package/src/notifications/decision-engine.ts +353 -147
  871. package/src/notifications/decisions-store.ts +26 -10
  872. package/src/notifications/deliveries-store.ts +23 -13
  873. package/src/notifications/destination-resolver.ts +42 -24
  874. package/src/notifications/deterministic-checks.ts +78 -27
  875. package/src/notifications/emit-signal.ts +83 -45
  876. package/src/notifications/events-store.ts +13 -7
  877. package/src/notifications/guardian-question-mode.ts +125 -75
  878. package/src/notifications/preference-extractor.ts +85 -53
  879. package/src/notifications/preference-summary.ts +31 -18
  880. package/src/notifications/preferences-store.ts +29 -18
  881. package/src/notifications/runtime-dispatch.ts +22 -12
  882. package/src/notifications/signal.ts +4 -4
  883. package/src/notifications/thread-candidates.ts +59 -23
  884. package/src/notifications/thread-seed-composer.ts +45 -27
  885. package/src/notifications/types.ts +19 -10
  886. package/src/oauth/connect-orchestrator.ts +105 -54
  887. package/src/oauth/connect-types.ts +3 -3
  888. package/src/oauth/provider-profiles.ts +80 -59
  889. package/src/oauth/scope-policy.ts +5 -2
  890. package/src/oauth/token-persistence.ts +58 -24
  891. package/src/outbound-proxy/certs.ts +284 -0
  892. package/src/outbound-proxy/config.ts +94 -0
  893. package/src/outbound-proxy/connect-tunnel.ts +84 -0
  894. package/src/outbound-proxy/health.ts +62 -0
  895. package/src/outbound-proxy/host-pattern-match.ts +67 -0
  896. package/src/outbound-proxy/http-forwarder.ts +162 -0
  897. package/src/outbound-proxy/index.ts +80 -0
  898. package/src/outbound-proxy/logging.ts +193 -0
  899. package/src/outbound-proxy/mitm-handler.ts +292 -0
  900. package/src/outbound-proxy/policy.ts +172 -0
  901. package/src/outbound-proxy/router.ts +64 -0
  902. package/src/outbound-proxy/server.ts +145 -0
  903. package/src/outbound-proxy/types.ts +150 -0
  904. package/src/permissions/checker.ts +481 -189
  905. package/src/permissions/defaults.ts +135 -108
  906. package/src/permissions/prompter.ts +53 -27
  907. package/src/permissions/secret-prompter.ts +21 -15
  908. package/src/permissions/shell-identity.ts +47 -16
  909. package/src/permissions/trust-store.ts +185 -73
  910. package/src/permissions/types.ts +22 -12
  911. package/src/permissions/workspace-policy.ts +47 -38
  912. package/src/playbooks/index.ts +10 -2
  913. package/src/playbooks/playbook-compiler.ts +30 -24
  914. package/src/playbooks/types.ts +11 -8
  915. package/src/providers/anthropic/client.ts +325 -168
  916. package/src/providers/failover.ts +57 -22
  917. package/src/providers/fireworks/client.ts +9 -5
  918. package/src/providers/gemini/client.ts +61 -39
  919. package/src/providers/model-intents.ts +40 -33
  920. package/src/providers/ollama/client.ts +7 -7
  921. package/src/providers/openai/client.ts +106 -68
  922. package/src/providers/openrouter/client.ts +9 -5
  923. package/src/providers/provider-send-message.ts +59 -27
  924. package/src/providers/ratelimit.ts +25 -8
  925. package/src/providers/registry.ts +86 -38
  926. package/src/providers/retry.ts +84 -36
  927. package/src/providers/stream-timeout.ts +5 -3
  928. package/src/providers/types.ts +7 -6
  929. package/src/runtime/AGENTS.md +42 -0
  930. package/src/runtime/access-request-helper.ts +118 -68
  931. package/src/runtime/actor-refresh-token-store.ts +21 -16
  932. package/src/runtime/actor-token-store.ts +25 -18
  933. package/src/runtime/actor-trust-resolver.ts +183 -80
  934. package/src/runtime/approval-conversation-turn.ts +39 -26
  935. package/src/runtime/approval-message-composer.ts +116 -84
  936. package/src/runtime/assistant-event-hub.ts +25 -6
  937. package/src/runtime/assistant-event.ts +4 -4
  938. package/src/runtime/assistant-scope.ts +1 -1
  939. package/src/runtime/auth/__tests__/guard-tests.test.ts +36 -14
  940. package/src/runtime/auth/context.ts +8 -7
  941. package/src/runtime/auth/credential-service.ts +60 -38
  942. package/src/runtime/auth/external-assistant-id.ts +16 -8
  943. package/src/runtime/auth/index.ts +23 -16
  944. package/src/runtime/auth/route-policy.ts +170 -104
  945. package/src/runtime/auth/scopes.ts +22 -29
  946. package/src/runtime/auth/subject.ts +19 -13
  947. package/src/runtime/auth/token-service.ts +3 -3
  948. package/src/runtime/auth/types.ts +23 -23
  949. package/src/runtime/channel-approval-parser.ts +37 -14
  950. package/src/runtime/channel-approval-types.ts +12 -4
  951. package/src/runtime/channel-approvals.ts +41 -23
  952. package/src/runtime/channel-guardian-service.ts +144 -103
  953. package/src/runtime/channel-invite-transport.ts +4 -2
  954. package/src/runtime/channel-invite-transports/telegram.ts +16 -10
  955. package/src/runtime/channel-invite-transports/voice.ts +7 -7
  956. package/src/runtime/channel-readiness-service.ts +139 -90
  957. package/src/runtime/channel-readiness-types.ts +4 -2
  958. package/src/runtime/channel-reply-delivery.ts +21 -11
  959. package/src/runtime/channel-retry-sweep.ts +111 -62
  960. package/src/runtime/confirmation-request-guardian-bridge.ts +73 -54
  961. package/src/runtime/gateway-client.ts +86 -53
  962. package/src/runtime/guardian-action-conversation-turn.ts +34 -18
  963. package/src/runtime/guardian-action-followup-executor.ts +115 -45
  964. package/src/runtime/guardian-action-grant-minter.ts +40 -24
  965. package/src/runtime/guardian-action-message-composer.ts +105 -84
  966. package/src/runtime/guardian-decision-types.ts +28 -13
  967. package/src/runtime/guardian-outbound-actions.ts +9 -0
  968. package/src/runtime/guardian-reply-router.ts +274 -145
  969. package/src/runtime/guardian-vellum-migration.ts +38 -24
  970. package/src/runtime/guardian-verification-templates.ts +8 -11
  971. package/src/runtime/http-router.ts +175 -0
  972. package/src/runtime/http-server.ts +931 -669
  973. package/src/runtime/http-types.ts +2 -2
  974. package/src/runtime/ingress-service.ts +182 -89
  975. package/src/runtime/invite-redemption-service.ts +211 -134
  976. package/src/runtime/invite-redemption-templates.ts +18 -11
  977. package/src/runtime/local-actor-identity.ts +73 -55
  978. package/src/runtime/middleware/auth.ts +25 -14
  979. package/src/runtime/middleware/error-handler.ts +15 -11
  980. package/src/runtime/middleware/rate-limiter.ts +23 -17
  981. package/src/runtime/middleware/request-logger.ts +4 -4
  982. package/src/runtime/middleware/twilio-validation.ts +29 -20
  983. package/src/runtime/migrations/migration-transport.ts +575 -0
  984. package/src/runtime/migrations/migration-wizard.ts +715 -0
  985. package/src/runtime/migrations/rebind-secrets-screen.ts +351 -0
  986. package/src/runtime/migrations/transfer-progress-screen.ts +321 -0
  987. package/src/runtime/migrations/validation-results-screen.ts +467 -0
  988. package/src/runtime/migrations/vbundle-builder.ts +295 -0
  989. package/src/runtime/migrations/vbundle-import-analyzer.ts +212 -0
  990. package/src/runtime/migrations/vbundle-importer.ts +339 -0
  991. package/src/runtime/migrations/vbundle-validator.ts +356 -0
  992. package/src/runtime/pending-interactions.ts +16 -7
  993. package/src/runtime/routes/access-request-decision.ts +73 -52
  994. package/src/runtime/routes/app-routes.ts +56 -38
  995. package/src/runtime/routes/approval-routes.ts +165 -74
  996. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +930 -0
  997. package/src/runtime/routes/approval-strategies/guardian-legacy-fallback-strategy.ts +82 -0
  998. package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +151 -0
  999. package/src/runtime/routes/attachment-routes.ts +59 -48
  1000. package/src/runtime/routes/brain-graph-routes.ts +85 -69
  1001. package/src/runtime/routes/call-routes.ts +79 -38
  1002. package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +10 -10
  1003. package/src/runtime/routes/channel-delivery-routes.ts +19 -14
  1004. package/src/runtime/routes/channel-guardian-routes.ts +3 -3
  1005. package/src/runtime/routes/channel-inbound-routes.ts +2 -2
  1006. package/src/runtime/routes/channel-readiness-routes.ts +12 -6
  1007. package/src/runtime/routes/channel-route-shared.ts +33 -25
  1008. package/src/runtime/routes/channel-routes.ts +4 -6
  1009. package/src/runtime/routes/contact-routes.ts +205 -16
  1010. package/src/runtime/routes/conversation-attention-routes.ts +57 -28
  1011. package/src/runtime/routes/conversation-routes.ts +321 -174
  1012. package/src/runtime/routes/debug-routes.ts +14 -10
  1013. package/src/runtime/routes/events-routes.ts +90 -57
  1014. package/src/runtime/routes/global-search-routes.ts +266 -0
  1015. package/src/runtime/routes/guardian-action-routes.ts +147 -56
  1016. package/src/runtime/routes/guardian-approval-interception.ts +255 -880
  1017. package/src/runtime/routes/guardian-approval-prompt.ts +40 -24
  1018. package/src/runtime/routes/guardian-approval-reply-helpers.ts +135 -0
  1019. package/src/runtime/routes/guardian-bootstrap-routes.ts +55 -36
  1020. package/src/runtime/routes/guardian-expiry-sweep.ts +63 -37
  1021. package/src/runtime/routes/guardian-refresh-routes.ts +40 -19
  1022. package/src/runtime/routes/identity-routes.ts +71 -42
  1023. package/src/runtime/routes/inbound-conversation.ts +17 -11
  1024. package/src/runtime/routes/inbound-message-handler.ts +278 -1460
  1025. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +658 -0
  1026. package/src/runtime/routes/inbound-stages/background-dispatch.ts +492 -0
  1027. package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +214 -0
  1028. package/src/runtime/routes/inbound-stages/edit-intercept.ts +116 -0
  1029. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +167 -0
  1030. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +185 -0
  1031. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +132 -0
  1032. package/src/runtime/routes/inbound-stages/verification-intercept.ts +340 -0
  1033. package/src/runtime/routes/ingress-routes.ts +34 -23
  1034. package/src/runtime/routes/integration-routes.ts +60 -21
  1035. package/src/runtime/routes/migration-routes.ts +434 -0
  1036. package/src/runtime/routes/pairing-routes.ts +157 -79
  1037. package/src/runtime/routes/secret-routes.ts +6 -2
  1038. package/src/runtime/routes/twilio-routes.ts +443 -249
  1039. package/src/runtime/tool-grant-request-helper.ts +36 -27
  1040. package/src/runtime/{guardian-context-resolver.ts → trust-context-resolver.ts} +29 -41
  1041. package/src/schedule/integration-status.ts +44 -9
  1042. package/src/schedule/recurrence-engine.ts +47 -24
  1043. package/src/schedule/recurrence-types.ts +12 -7
  1044. package/src/schedule/schedule-store.ts +166 -83
  1045. package/src/schedule/scheduler.ts +26 -22
  1046. package/src/security/encrypted-store.ts +68 -38
  1047. package/src/security/keychain.ts +183 -120
  1048. package/src/security/oauth-callback-registry.ts +3 -3
  1049. package/src/security/oauth2.ts +226 -138
  1050. package/src/security/redaction.ts +24 -24
  1051. package/src/security/secret-allowlist.ts +46 -21
  1052. package/src/security/secret-ingress.ts +15 -7
  1053. package/src/security/secret-scanner.ts +193 -104
  1054. package/src/security/secure-keys.ts +9 -3
  1055. package/src/security/token-manager.ts +99 -40
  1056. package/src/security/tool-approval-digest.ts +3 -3
  1057. package/src/sequence/analytics.ts +52 -27
  1058. package/src/sequence/engine.ts +135 -72
  1059. package/src/sequence/guardrails.ts +32 -20
  1060. package/src/sequence/importer.ts +75 -37
  1061. package/src/sequence/reply-matcher.ts +36 -18
  1062. package/src/sequence/store.ts +137 -75
  1063. package/src/sequence/types.ts +30 -16
  1064. package/src/services/published-app-updater.ts +26 -16
  1065. package/src/services/vercel-deploy.ts +19 -15
  1066. package/src/skills/active-skill-tools.ts +3 -3
  1067. package/src/skills/clawhub.ts +178 -90
  1068. package/src/skills/include-graph.ts +24 -17
  1069. package/src/skills/managed-store.ts +89 -42
  1070. package/src/skills/path-classifier.ts +10 -10
  1071. package/src/skills/remote-skill-policy.ts +31 -22
  1072. package/src/skills/slash-commands.ts +36 -30
  1073. package/src/skills/tool-manifest.ts +60 -31
  1074. package/src/skills/version-hash.ts +25 -15
  1075. package/src/slack/slack-webhook.ts +19 -15
  1076. package/src/subagent/index.ts +4 -8
  1077. package/src/subagent/manager.ts +119 -69
  1078. package/src/subagent/types.ts +9 -12
  1079. package/src/swarm/backend-claude-code.ts +124 -45
  1080. package/src/swarm/checkpoint.ts +36 -16
  1081. package/src/swarm/graph-utils.ts +1 -3
  1082. package/src/swarm/index.ts +38 -19
  1083. package/src/swarm/limits.ts +13 -4
  1084. package/src/swarm/orchestrator.ts +108 -57
  1085. package/src/swarm/plan-validator.ts +23 -17
  1086. package/src/swarm/router-planner.ts +51 -22
  1087. package/src/swarm/router-prompts.ts +4 -1
  1088. package/src/swarm/synthesizer.ts +26 -18
  1089. package/src/swarm/types.ts +14 -4
  1090. package/src/swarm/worker-backend.ts +36 -26
  1091. package/src/swarm/worker-prompts.ts +13 -9
  1092. package/src/swarm/worker-runner.ts +40 -34
  1093. package/src/tasks/candidate-store.ts +14 -6
  1094. package/src/tasks/ephemeral-permissions.ts +9 -5
  1095. package/src/tasks/task-compiler.ts +41 -38
  1096. package/src/tasks/task-runner.ts +54 -26
  1097. package/src/tasks/task-scheduler.ts +1 -1
  1098. package/src/tasks/task-store.ts +20 -7
  1099. package/src/tasks/tool-sanitizer.ts +3 -3
  1100. package/src/tools/apps/definitions.ts +23 -15
  1101. package/src/tools/apps/executors.ts +118 -37
  1102. package/src/tools/apps/open-proxy.ts +5 -5
  1103. package/src/tools/apps/registry.ts +2 -2
  1104. package/src/tools/assets/materialize.ts +59 -41
  1105. package/src/tools/assets/search.ts +86 -48
  1106. package/src/tools/browser/api-map.ts +52 -36
  1107. package/src/tools/browser/auth-cache.ts +21 -18
  1108. package/src/tools/browser/auth-detector.ts +43 -28
  1109. package/src/tools/browser/auto-navigate.ts +149 -68
  1110. package/src/tools/browser/browser-execution.ts +9 -3
  1111. package/src/tools/browser/headless-browser.ts +287 -150
  1112. package/src/tools/browser/jit-auth.ts +37 -21
  1113. package/src/tools/browser/network-recorder.ts +138 -56
  1114. package/src/tools/browser/recording-store.ts +22 -15
  1115. package/src/tools/browser/runtime-check.ts +8 -5
  1116. package/src/tools/browser/x-auto-navigate.ts +88 -47
  1117. package/src/tools/calls/call-end.ts +9 -6
  1118. package/src/tools/calls/call-start.ts +30 -20
  1119. package/src/tools/calls/call-status.ts +8 -5
  1120. package/src/tools/claude-code/claude-code.ts +301 -165
  1121. package/src/tools/computer-use/definitions.ts +159 -130
  1122. package/src/tools/computer-use/registry.ts +2 -2
  1123. package/src/tools/computer-use/request-computer-control.ts +21 -13
  1124. package/src/tools/computer-use/skill-proxy-bridge.ts +1 -1
  1125. package/src/tools/credentials/account-registry.ts +52 -35
  1126. package/src/tools/credentials/broker-types.ts +1 -1
  1127. package/src/tools/credentials/broker.ts +97 -55
  1128. package/src/tools/credentials/domain-policy.ts +5 -2
  1129. package/src/tools/credentials/host-pattern-match.ts +15 -8
  1130. package/src/tools/credentials/metadata-store.ts +93 -43
  1131. package/src/tools/credentials/policy-types.ts +5 -2
  1132. package/src/tools/credentials/policy-validate.ts +21 -14
  1133. package/src/tools/credentials/post-connect-hooks.ts +18 -7
  1134. package/src/tools/credentials/resolve.ts +11 -10
  1135. package/src/tools/credentials/selection.ts +30 -25
  1136. package/src/tools/credentials/tool-policy.ts +5 -2
  1137. package/src/tools/credentials/vault.ts +452 -183
  1138. package/src/tools/document/document-tool.ts +23 -17
  1139. package/src/tools/document/editor-template.ts +12 -7
  1140. package/src/tools/execution-target.ts +13 -10
  1141. package/src/tools/execution-timeout.ts +6 -5
  1142. package/src/tools/executor.ts +141 -74
  1143. package/src/tools/filesystem/edit.ts +82 -45
  1144. package/src/tools/filesystem/fuzzy-match.ts +70 -32
  1145. package/src/tools/filesystem/read.ts +46 -28
  1146. package/src/tools/filesystem/view-image.ts +86 -42
  1147. package/src/tools/filesystem/write.ts +53 -32
  1148. package/src/tools/followups/followup_create.ts +43 -17
  1149. package/src/tools/followups/followup_list.ts +28 -13
  1150. package/src/tools/followups/followup_resolve.ts +9 -6
  1151. package/src/tools/guardian-control-plane-policy.ts +15 -14
  1152. package/src/tools/host-filesystem/edit.ts +77 -42
  1153. package/src/tools/host-filesystem/read.ts +52 -33
  1154. package/src/tools/host-filesystem/write.ts +50 -29
  1155. package/src/tools/host-terminal/host-shell.ts +97 -61
  1156. package/src/tools/mcp/mcp-tool-factory.ts +21 -14
  1157. package/src/tools/memory/definitions.ts +60 -28
  1158. package/src/tools/memory/handlers.ts +149 -77
  1159. package/src/tools/memory/register.ts +39 -16
  1160. package/src/tools/network/__tests__/web-search.test.ts +236 -177
  1161. package/src/tools/network/domain-normalize.ts +13 -9
  1162. package/src/tools/network/script-proxy/__tests__/logging.test.ts +193 -123
  1163. package/src/tools/network/script-proxy/__tests__/policy.test.ts +225 -127
  1164. package/src/tools/network/script-proxy/index.ts +1 -17
  1165. package/src/tools/network/script-proxy/session-manager.ts +151 -84
  1166. package/src/tools/network/url-safety.ts +56 -34
  1167. package/src/tools/network/web-fetch.ts +273 -155
  1168. package/src/tools/network/web-search.ts +166 -81
  1169. package/src/tools/permission-checker.ts +6 -25
  1170. package/src/tools/policy-context.ts +8 -5
  1171. package/src/tools/registry.ts +73 -46
  1172. package/src/tools/reminder/reminder-store.ts +65 -44
  1173. package/src/tools/reminder/reminder.ts +76 -35
  1174. package/src/tools/schedule/create.ts +44 -21
  1175. package/src/tools/schedule/delete.ts +8 -5
  1176. package/src/tools/schedule/list.ts +39 -19
  1177. package/src/tools/schedule/update.ts +49 -26
  1178. package/src/tools/secret-detection-handler.ts +130 -49
  1179. package/src/tools/sensitive-output-placeholders.ts +15 -8
  1180. package/src/tools/shared/filesystem/edit-engine.ts +45 -14
  1181. package/src/tools/shared/filesystem/errors.ts +18 -18
  1182. package/src/tools/shared/filesystem/file-ops-service.ts +59 -32
  1183. package/src/tools/shared/filesystem/format-diff.ts +21 -11
  1184. package/src/tools/shared/filesystem/path-policy.ts +17 -13
  1185. package/src/tools/shared/filesystem/size-guard.ts +8 -4
  1186. package/src/tools/shared/filesystem/types.ts +2 -2
  1187. package/src/tools/shared/shell-output.ts +4 -3
  1188. package/src/tools/side-effects.ts +36 -28
  1189. package/src/tools/skills/delete-managed.ts +30 -17
  1190. package/src/tools/skills/load.ts +88 -46
  1191. package/src/tools/skills/sandbox-runner.ts +62 -46
  1192. package/src/tools/skills/scaffold-managed.ts +98 -48
  1193. package/src/tools/skills/script-contract.ts +5 -2
  1194. package/src/tools/skills/skill-script-runner.ts +29 -13
  1195. package/src/tools/skills/skill-tool-factory.ts +20 -10
  1196. package/src/tools/subagent/abort.ts +10 -4
  1197. package/src/tools/subagent/message.ts +14 -8
  1198. package/src/tools/subagent/read.ts +20 -11
  1199. package/src/tools/subagent/spawn.ts +14 -6
  1200. package/src/tools/subagent/status.ts +7 -4
  1201. package/src/tools/swarm/delegate.ts +75 -49
  1202. package/src/tools/system/avatar-generator.ts +46 -33
  1203. package/src/tools/system/navigate-settings.ts +29 -19
  1204. package/src/tools/system/open-system-settings.ts +30 -20
  1205. package/src/tools/system/request-permission.ts +59 -44
  1206. package/src/tools/system/version.ts +27 -16
  1207. package/src/tools/system/voice-config.ts +116 -53
  1208. package/src/tools/tasks/index.ts +8 -8
  1209. package/src/tools/tasks/task-delete.ts +61 -22
  1210. package/src/tools/tasks/task-list.ts +23 -11
  1211. package/src/tools/tasks/task-run.ts +41 -16
  1212. package/src/tools/tasks/task-save.ts +27 -10
  1213. package/src/tools/tasks/work-item-enqueue.ts +114 -48
  1214. package/src/tools/tasks/work-item-list.ts +20 -10
  1215. package/src/tools/tasks/work-item-remove.ts +49 -15
  1216. package/src/tools/tasks/work-item-run.ts +34 -13
  1217. package/src/tools/tasks/work-item-update.ts +84 -31
  1218. package/src/tools/terminal/backends/native.ts +64 -35
  1219. package/src/tools/terminal/backends/types.ts +6 -2
  1220. package/src/tools/terminal/parser.ts +200 -125
  1221. package/src/tools/terminal/safe-env.ts +27 -21
  1222. package/src/tools/terminal/sandbox-diagnostics.ts +31 -13
  1223. package/src/tools/terminal/sandbox.ts +10 -6
  1224. package/src/tools/terminal/shell.ts +124 -68
  1225. package/src/tools/tool-approval-handler.ts +193 -138
  1226. package/src/tools/types.ts +43 -23
  1227. package/src/tools/ui-surface/definitions.ts +124 -89
  1228. package/src/tools/ui-surface/registry.ts +2 -2
  1229. package/src/tools/watch/screen-watch.ts +50 -32
  1230. package/src/tools/watch/watch-state.ts +41 -15
  1231. package/src/tools/watcher/create.ts +37 -15
  1232. package/src/tools/watcher/delete.ts +9 -6
  1233. package/src/tools/watcher/digest.ts +10 -6
  1234. package/src/tools/watcher/list.ts +37 -14
  1235. package/src/tools/watcher/update.ts +33 -18
  1236. package/src/tools/weather/service.ts +331 -174
  1237. package/src/twitter/client.ts +261 -138
  1238. package/src/twitter/oauth-client.ts +17 -13
  1239. package/src/twitter/router.ts +51 -23
  1240. package/src/twitter/session.ts +27 -18
  1241. package/src/types/qrcode.d.ts +6 -3
  1242. package/src/usage/actors.ts +16 -16
  1243. package/src/usage/types.ts +3 -3
  1244. package/src/util/bundled-asset.ts +10 -6
  1245. package/src/util/canonicalize-identity.ts +11 -4
  1246. package/src/util/clipboard.ts +7 -7
  1247. package/src/util/content-id.ts +3 -3
  1248. package/src/util/debounce.ts +3 -2
  1249. package/src/util/diff.ts +55 -33
  1250. package/src/util/errors.ts +26 -26
  1251. package/src/util/fs.ts +8 -2
  1252. package/src/util/log-redact.ts +12 -12
  1253. package/src/util/logger.ts +112 -51
  1254. package/src/util/network-info.ts +13 -5
  1255. package/src/util/object.ts +4 -2
  1256. package/src/util/phone.ts +4 -4
  1257. package/src/util/platform.ts +80 -58
  1258. package/src/util/pricing.ts +49 -31
  1259. package/src/util/retry.ts +18 -7
  1260. package/src/util/row-mapper.ts +7 -4
  1261. package/src/util/silently.ts +7 -4
  1262. package/src/util/spawn.ts +48 -0
  1263. package/src/util/spinner.ts +9 -7
  1264. package/src/util/time.ts +16 -3
  1265. package/src/util/truncate.ts +1 -1
  1266. package/src/util/voice-code.ts +6 -4
  1267. package/src/util/xml.ts +5 -1
  1268. package/src/version.ts +12 -8
  1269. package/src/watcher/engine.ts +71 -44
  1270. package/src/watcher/provider-registry.ts +1 -1
  1271. package/src/watcher/providers/github.ts +40 -23
  1272. package/src/watcher/providers/gmail.ts +59 -38
  1273. package/src/watcher/providers/google-calendar.ts +62 -48
  1274. package/src/watcher/providers/linear.ts +219 -150
  1275. package/src/watcher/providers/slack.ts +93 -27
  1276. package/src/watcher/watcher-store.ts +75 -55
  1277. package/src/work-items/work-item-runner.ts +62 -29
  1278. package/src/work-items/work-item-store.ts +137 -47
  1279. package/src/workspace/commit-message-enrichment-service.ts +65 -25
  1280. package/src/workspace/commit-message-provider.ts +14 -12
  1281. package/src/workspace/git-service.ts +355 -239
  1282. package/src/workspace/heartbeat-service.ts +74 -37
  1283. package/src/workspace/provider-commit-message-generator.ts +95 -70
  1284. package/src/workspace/top-level-renderer.ts +10 -8
  1285. package/src/workspace/top-level-scanner.ts +9 -3
  1286. package/src/workspace/turn-commit.ts +63 -36
  1287. package/src/__tests__/ingress-member-store.test.ts +0 -294
  1288. package/src/__tests__/script-proxy-router.test.ts +0 -215
  1289. package/src/config/bundled-skills/trusted-contacts/SKILL.md +0 -372
  1290. package/src/memory/guardian-bindings.ts +0 -158
  1291. package/src/memory/ingress-member-store.ts +0 -352
  1292. package/src/tools/network/script-proxy/__tests__/router.test.ts +0 -77
  1293. package/src/tools/network/script-proxy/certs.ts +0 -7
  1294. package/src/tools/network/script-proxy/connect-tunnel.ts +0 -1
  1295. package/src/tools/network/script-proxy/http-forwarder.ts +0 -2
  1296. package/src/tools/network/script-proxy/logging.ts +0 -12
  1297. package/src/tools/network/script-proxy/mitm-handler.ts +0 -2
  1298. package/src/tools/network/script-proxy/policy.ts +0 -4
  1299. package/src/tools/network/script-proxy/router.ts +0 -2
  1300. package/src/tools/network/script-proxy/server.ts +0 -5
  1301. package/src/tools/network/script-proxy/types.ts +0 -19
@@ -32,32 +32,44 @@ import {
32
32
  getGatewayInternalBaseUrl,
33
33
  hasUngatedHttpAuthDisabled,
34
34
  isHttpAuthDisabled,
35
- } from '../config/env.js';
36
- import type { ServerMessage } from '../daemon/ipc-contract.js';
37
- import { PairingStore } from '../daemon/pairing-store.js';
38
- import { type Confidence, getAttentionStateByConversationIds, recordConversationSeenSignal, type SignalType } from '../memory/conversation-attention-store.js';
39
- import * as conversationStore from '../memory/conversation-store.js';
40
- import * as externalConversationStore from '../memory/external-conversation-store.js';
41
- import { consumeCallback, consumeCallbackError } from '../security/oauth-callback-registry.js';
42
- import { getLogger } from '../util/logger.js';
43
- import { buildAssistantEvent } from './assistant-event.js';
44
- import { assistantEventHub } from './assistant-event-hub.js';
45
- import { DAEMON_INTERNAL_ASSISTANT_ID } from './assistant-scope.js';
35
+ } from "../config/env.js";
36
+ import type { ServerMessage } from "../daemon/ipc-contract.js";
37
+ import { PairingStore } from "../daemon/pairing-store.js";
38
+ import {
39
+ type Confidence,
40
+ getAttentionStateByConversationIds,
41
+ recordConversationSeenSignal,
42
+ type SignalType,
43
+ } from "../memory/conversation-attention-store.js";
44
+ import * as conversationStore from "../memory/conversation-store.js";
45
+ import * as externalConversationStore from "../memory/external-conversation-store.js";
46
+ import {
47
+ consumeCallback,
48
+ consumeCallbackError,
49
+ } from "../security/oauth-callback-registry.js";
50
+ import { getLogger } from "../util/logger.js";
51
+ import { buildAssistantEvent } from "./assistant-event.js";
52
+ import { assistantEventHub } from "./assistant-event-hub.js";
53
+ import { DAEMON_INTERNAL_ASSISTANT_ID } from "./assistant-scope.js";
46
54
  // Auth
47
- import { authenticateRequest } from './auth/middleware.js';
48
- import { enforcePolicy, getPolicy } from './auth/route-policy.js';
49
- import { mintDaemonDeliveryToken, mintUiPageToken, verifyToken } from './auth/token-service.js';
50
- import type { AuthContext } from './auth/types.js';
51
- import { sweepFailedEvents } from './channel-retry-sweep.js';
52
- import { httpError } from './http-errors.js';
55
+ import { authenticateRequest } from "./auth/middleware.js";
56
+ import {
57
+ mintDaemonDeliveryToken,
58
+ mintUiPageToken,
59
+ verifyToken,
60
+ } from "./auth/token-service.js";
61
+ import { sweepFailedEvents } from "./channel-retry-sweep.js";
62
+ import { httpError } from "./http-errors.js";
63
+ import type { RouteDefinition } from "./http-router.js";
64
+ import { HttpRouter } from "./http-router.js";
53
65
  // Middleware
54
66
  import {
55
67
  extractBearerToken,
56
68
  isLoopbackHost,
57
69
  isPrivateNetworkOrigin,
58
70
  isPrivateNetworkPeer,
59
- } from './middleware/auth.js';
60
- import { withErrorHandling } from './middleware/error-handler.js';
71
+ } from "./middleware/auth.js";
72
+ import { withErrorHandling } from "./middleware/error-handler.js";
61
73
  import {
62
74
  apiRateLimiter,
63
75
  extractClientIp,
@@ -126,6 +138,8 @@ import {
126
138
  handleGetContact,
127
139
  handleListContacts,
128
140
  handleMergeContacts,
141
+ handleUpdateContactChannel,
142
+ handleUpsertContact,
129
143
  } from "./routes/contact-routes.js";
130
144
  import { handleListConversationAttention } from "./routes/conversation-attention-routes.js";
131
145
  // Route handlers — grouped by domain
@@ -137,6 +151,7 @@ import {
137
151
  } from "./routes/conversation-routes.js";
138
152
  import { handleDebug } from "./routes/debug-routes.js";
139
153
  import { handleSubscribeAssistantEvents } from "./routes/events-routes.js";
154
+ import { handleGlobalSearch } from "./routes/global-search-routes.js";
140
155
  import {
141
156
  handleGuardianActionDecision,
142
157
  handleGuardianActionsPending,
@@ -163,12 +178,19 @@ import {
163
178
  handleGetSlackChannelConfig,
164
179
  handleGetTelegramConfig,
165
180
  handleResendOutbound,
181
+ handleRevokeGuardian,
166
182
  handleSetSlackChannelConfig,
167
183
  handleSetTelegramCommands,
168
184
  handleSetTelegramConfig,
169
185
  handleSetupTelegram,
170
186
  handleStartOutbound,
171
187
  } from "./routes/integration-routes.js";
188
+ import {
189
+ handleMigrationExport,
190
+ handleMigrationImport,
191
+ handleMigrationImportPreflight,
192
+ handleMigrationValidate,
193
+ } from "./routes/migration-routes.js";
172
194
  import type { PairingHandlerContext } from "./routes/pairing-routes.js";
173
195
  // Extracted route handlers
174
196
  import {
@@ -236,68 +258,6 @@ const DEFAULT_HOSTNAME = "127.0.0.1";
236
258
  /** Global hard cap on request body size (50 MB). */
237
259
  const MAX_REQUEST_BODY_BYTES = 50 * 1024 * 1024;
238
260
 
239
- // ---------------------------------------------------------------------------
240
- // Parameterized endpoint normalization for policy lookup
241
- // ---------------------------------------------------------------------------
242
-
243
- /**
244
- * Patterns that map parameterized URLs back to their policy registry keys.
245
- * Order matters: more specific patterns must come before general ones so
246
- * that e.g. `attachments/{id}/content` matches before `attachments/{id}`.
247
- */
248
- const PARAMETERIZED_ROUTE_PATTERNS: Array<{ re: RegExp; policyBase: string }> = [
249
- // calls/{id}/cancel, calls/{id}/answer, calls/{id}/instruction
250
- { re: /^calls\/[^/]+\/(cancel|answer|instruction)$/, policyBase: 'calls/$1' },
251
- // calls/{id} (GET status)
252
- { re: /^calls\/[^/]+$/, policyBase: 'calls' },
253
- // contacts/{id}
254
- { re: /^contacts\/[^/]+$/, policyBase: 'contacts' },
255
- // ingress/members/{id}/block
256
- { re: /^ingress\/members\/[^/]+\/block$/, policyBase: 'ingress/members/block' },
257
- // ingress/members/{id}
258
- { re: /^ingress\/members\/[^/]+$/, policyBase: 'ingress/members' },
259
- // ingress/invites/{id}
260
- { re: /^ingress\/invites\/[^/]+$/, policyBase: 'ingress/invites' },
261
- // integrations/twilio/sms/compliance/tollfree/{sid}
262
- { re: /^integrations\/twilio\/sms\/compliance\/tollfree\/[^/]+$/, policyBase: 'integrations/twilio/sms/compliance/tollfree' },
263
- // attachments/{id}/content
264
- { re: /^attachments\/[^/]+\/content$/, policyBase: 'attachments/content' },
265
- // attachments/{id}
266
- { re: /^attachments\/[^/]+$/, policyBase: 'attachments' },
267
- // trust-rules/manage/{id}
268
- { re: /^trust-rules\/manage\/[^/]+$/, policyBase: 'trust-rules/manage' },
269
- // interfaces/{path}
270
- { re: /^interfaces\/.+$/, policyBase: 'interfaces' },
271
- ];
272
-
273
- /**
274
- * Strip parameterized segments from an endpoint string so it matches
275
- * the base route name used in the policy registry.
276
- *
277
- * For example, `calls/abc123` becomes `calls`, and
278
- * `attachments/abc123/content` becomes `attachments/content`.
279
- *
280
- * If the raw endpoint already has a direct policy registered (either
281
- * bare or with a method qualifier), normalization is skipped. This
282
- * prevents literal sub-routes like `calls/start` from being
283
- * incorrectly collapsed to `calls`.
284
- */
285
- function normalizeEndpointForPolicy(endpoint: string, method: string): string {
286
- // If the exact endpoint (with or without method) has a direct policy, don't normalize
287
- if (getPolicy(`${endpoint}:${method}`) || getPolicy(endpoint)) {
288
- return endpoint;
289
- }
290
-
291
- for (const { re, policyBase } of PARAMETERIZED_ROUTE_PATTERNS) {
292
- const match = endpoint.match(re);
293
- if (match) {
294
- // Support capture-group substitution (e.g. calls/$1 -> calls/cancel)
295
- return policyBase.replace(/\$(\d+)/g, (_, idx) => match[Number(idx)] ?? '');
296
- }
297
- }
298
- return endpoint;
299
- }
300
-
301
261
  export class RuntimeHttpServer {
302
262
  private server: ReturnType<typeof Bun.serve> | null = null;
303
263
  private port: number;
@@ -327,6 +287,7 @@ export class RuntimeHttpServer {
327
287
  ): void;
328
288
  }
329
289
  | undefined;
290
+ private router: HttpRouter;
330
291
 
331
292
  constructor(options: RuntimeHttpServerOptions = {}) {
332
293
  this.port = options.port ?? DEFAULT_PORT;
@@ -342,6 +303,7 @@ export class RuntimeHttpServer {
342
303
  this.interfacesDir = options.interfacesDir ?? null;
343
304
  this.sendMessageDeps = options.sendMessageDeps;
344
305
  this.findSession = options.findSession;
306
+ this.router = new HttpRouter(this.buildRouteTable());
345
307
  }
346
308
 
347
309
  /** The port the server is actually listening on (resolved after start). */
@@ -597,10 +559,16 @@ export class RuntimeHttpServer {
597
559
  // needs to work when the access token is expired. Bootstrap has its
598
560
  // own loopback IP validation; refresh is secured by the refresh token
599
561
  // in the request body (32 random bytes, hash-only storage).
600
- if (path === '/v1/integrations/guardian/vellum/bootstrap' && req.method === 'POST') {
562
+ if (
563
+ path === "/v1/integrations/guardian/vellum/bootstrap" &&
564
+ req.method === "POST"
565
+ ) {
601
566
  return await handleGuardianBootstrap(req, server);
602
567
  }
603
- if (path === '/v1/integrations/guardian/vellum/refresh' && req.method === 'POST') {
568
+ if (
569
+ path === "/v1/integrations/guardian/vellum/refresh" &&
570
+ req.method === "POST"
571
+ ) {
604
572
  return await handleGuardianRefresh(req);
605
573
  }
606
574
 
@@ -612,13 +580,27 @@ export class RuntimeHttpServer {
612
580
  }
613
581
  const authContext = authResult.context;
614
582
 
583
+ // Serve shareable app pages (outside /v1/ namespace, no rate limiting)
584
+ const pagesMatch = path.match(/^\/pages\/([^/]+)$/);
585
+ if (pagesMatch && req.method === "GET") {
586
+ return withErrorHandling("pages", async () =>
587
+ handleServePage(pagesMatch[1]),
588
+ );
589
+ }
590
+
615
591
  // Per-client-IP rate limiting for /v1/* endpoints. Authenticated requests
616
592
  // get a higher limit; unauthenticated requests get a lower limit to reduce
617
593
  // abuse surface. We key on IP rather than bearer token because the gateway
618
594
  // uses a single shared token for all proxied requests, which would collapse
619
595
  // all users into one bucket.
620
596
  // Skip rate limiting entirely when HTTP auth is disabled (local Docker dev).
621
- if (path.startsWith("/v1/") && !isHttpAuthDisabled()) {
597
+ if (!path.startsWith("/v1/")) {
598
+ return httpError("NOT_FOUND", "Not found", 404);
599
+ }
600
+
601
+ const endpoint = path.slice("/v1/".length);
602
+
603
+ if (!isHttpAuthDisabled()) {
622
604
  const clientIp = extractClientIp(req, server);
623
605
  const token = extractBearerToken(req);
624
606
  const result = token
@@ -627,113 +609,34 @@ export class RuntimeHttpServer {
627
609
  if (!result.allowed) {
628
610
  return rateLimitResponse(result);
629
611
  }
630
- // Attach rate limit headers to the eventual response
631
- const originalResponse = await this.handleAuthenticatedRequest(req, url, path, server, authContext);
632
- const headers = new Headers(originalResponse.headers);
612
+ const routerResponse = await this.router.dispatch(
613
+ endpoint,
614
+ req,
615
+ url,
616
+ server,
617
+ authContext,
618
+ );
619
+ const response =
620
+ routerResponse ?? httpError("NOT_FOUND", "Not found", 404);
621
+ const headers = new Headers(response.headers);
633
622
  for (const [k, v] of Object.entries(rateLimitHeaders(result))) {
634
623
  headers.set(k, v);
635
624
  }
636
- return new Response(originalResponse.body, {
637
- status: originalResponse.status,
638
- statusText: originalResponse.statusText,
625
+ return new Response(response.body, {
626
+ status: response.status,
627
+ statusText: response.statusText,
639
628
  headers,
640
629
  });
641
630
  }
642
631
 
643
- return this.handleAuthenticatedRequest(req, url, path, server, authContext);
644
- }
645
-
646
- /**
647
- * Handle requests that have already passed auth and rate limiting.
648
- */
649
- private async handleAuthenticatedRequest(req: Request, url: URL, path: string, server: ReturnType<typeof Bun.serve>, authContext: AuthContext): Promise<Response> {
650
- // Pairing registration (bearer-authenticated)
651
- if (path === '/v1/pairing/register' && req.method === 'POST') {
652
- const policyDenied = enforcePolicy('pairing/register', authContext);
653
- if (policyDenied) return policyDenied;
654
- return await handlePairingRegister(req, this.pairingContext);
655
- }
656
-
657
- // Serve shareable app pages
658
- const pagesMatch = path.match(/^\/pages\/([^/]+)$/);
659
- if (pagesMatch && req.method === "GET") {
660
- try {
661
- return handleServePage(pagesMatch[1]);
662
- } catch (err) {
663
- log.error(
664
- { err, appId: pagesMatch[1] },
665
- "Runtime HTTP handler error serving page",
666
- );
667
- return httpError("INTERNAL_ERROR", "Internal server error", 500);
668
- }
669
- }
670
-
671
- // Cloud sharing endpoints
672
- if (path === '/v1/apps/share' && req.method === 'POST') {
673
- const policyDenied = enforcePolicy('apps/share', authContext);
674
- if (policyDenied) return policyDenied;
675
- try { return await handleShareApp(req); } catch (err) {
676
- log.error({ err }, 'Runtime HTTP handler error sharing app');
677
- return httpError('INTERNAL_ERROR', 'Internal server error', 500);
678
- }
679
- }
680
-
681
- const sharedTokenMatch = path.match(/^\/v1\/apps\/shared\/([^/]+)$/);
682
- if (sharedTokenMatch) {
683
- const shareToken = sharedTokenMatch[1];
684
- if (req.method === 'GET') {
685
- const policyDenied = enforcePolicy('apps/shared:GET', authContext);
686
- if (policyDenied) return policyDenied;
687
- try { return handleDownloadSharedApp(shareToken); } catch (err) {
688
- log.error({ err, shareToken }, 'Runtime HTTP handler error downloading shared app');
689
- return httpError('INTERNAL_ERROR', 'Internal server error', 500);
690
- }
691
- }
692
- if (req.method === 'DELETE') {
693
- const policyDenied = enforcePolicy('apps/shared:DELETE', authContext);
694
- if (policyDenied) return policyDenied;
695
- try { return handleDeleteSharedApp(shareToken); } catch (err) {
696
- log.error({ err, shareToken }, 'Runtime HTTP handler error deleting shared app');
697
- return httpError('INTERNAL_ERROR', 'Internal server error', 500);
698
- }
699
- }
700
- }
701
-
702
- const sharedMetadataMatch = path.match(/^\/v1\/apps\/shared\/([^/]+)\/metadata$/);
703
- if (sharedMetadataMatch && req.method === 'GET') {
704
- const policyDenied = enforcePolicy('apps/shared/metadata', authContext);
705
- if (policyDenied) return policyDenied;
706
- try { return handleGetSharedAppMetadata(sharedMetadataMatch[1]); } catch (err) {
707
- log.error({ err, shareToken: sharedMetadataMatch[1] }, 'Runtime HTTP handler error getting shared app metadata');
708
- return httpError('INTERNAL_ERROR', 'Internal server error', 500);
709
- }
710
- }
711
-
712
- // Secret management endpoint
713
- if (path === '/v1/secrets' && req.method === 'POST') {
714
- const policyDenied = enforcePolicy('secrets', authContext);
715
- if (policyDenied) return policyDenied;
716
- try { return await handleAddSecret(req); } catch (err) {
717
- log.error({ err }, 'Runtime HTTP handler error adding secret');
718
- return httpError('INTERNAL_ERROR', 'Internal server error', 500);
719
- }
720
- }
721
- if (path === '/v1/secrets' && req.method === 'DELETE') {
722
- const policyDenied = enforcePolicy('secrets', authContext);
723
- if (policyDenied) return policyDenied;
724
- try { return await handleDeleteSecret(req); } catch (err) {
725
- log.error({ err }, 'Runtime HTTP handler error deleting secret');
726
- return httpError('INTERNAL_ERROR', 'Internal server error', 500);
727
- }
728
- }
729
-
730
- // Runtime routes: /v1/<endpoint>
731
- const routeMatch = path.match(/^\/v1\/(.+)$/);
732
- if (routeMatch) {
733
- return this.dispatchEndpoint(routeMatch[1], req, url, server, authContext);
734
- }
735
-
736
- return httpError("NOT_FOUND", "Not found", 404);
632
+ const routerResponse = await this.router.dispatch(
633
+ endpoint,
634
+ req,
635
+ url,
636
+ server,
637
+ authContext,
638
+ );
639
+ return routerResponse ?? httpError("NOT_FOUND", "Not found", 404);
737
640
  }
738
641
 
739
642
  private handleBrowserRelayUpgrade(
@@ -753,13 +656,13 @@ export class RuntimeHttpServer {
753
656
 
754
657
  if (!isHttpAuthDisabled()) {
755
658
  const wsUrl = new URL(req.url);
756
- const token = wsUrl.searchParams.get('token');
659
+ const token = wsUrl.searchParams.get("token");
757
660
  if (!token) {
758
- return httpError('UNAUTHORIZED', 'Unauthorized', 401);
661
+ return httpError("UNAUTHORIZED", "Unauthorized", 401);
759
662
  }
760
- const jwtResult = verifyToken(token, 'vellum-daemon');
663
+ const jwtResult = verifyToken(token, "vellum-daemon");
761
664
  if (!jwtResult.ok) {
762
- return httpError('UNAUTHORIZED', 'Unauthorized', 401);
665
+ return httpError("UNAUTHORIZED", "Unauthorized", 401);
763
666
  }
764
667
  }
765
668
 
@@ -842,41 +745,110 @@ export class RuntimeHttpServer {
842
745
  return null;
843
746
  }
844
747
 
748
+ private handleGetInterface(interfacePath: string): Response {
749
+ if (!this.interfacesDir) {
750
+ return httpError("NOT_FOUND", "Interface not found", 404);
751
+ }
752
+ const fullPath = resolve(this.interfacesDir, interfacePath);
753
+ if (
754
+ (fullPath !== this.interfacesDir &&
755
+ !fullPath.startsWith(this.interfacesDir + "/")) ||
756
+ !existsSync(fullPath)
757
+ ) {
758
+ return httpError("NOT_FOUND", "Interface not found", 404);
759
+ }
760
+ const source = readFileSync(fullPath, "utf-8");
761
+ return new Response(source, {
762
+ headers: { "Content-Type": "text/plain; charset=utf-8" },
763
+ });
764
+ }
765
+
766
+ // ---------------------------------------------------------------------------
767
+ // Declarative route table
768
+ // ---------------------------------------------------------------------------
769
+
845
770
  /**
846
- * Dispatch a request to the appropriate endpoint handler.
771
+ * Build the full set of route definitions. Routes are matched in order,
772
+ * so more specific patterns (e.g. `calls/:id/cancel`) must precede
773
+ * more general ones (e.g. `calls/:id`).
847
774
  */
848
- private async dispatchEndpoint(
849
- endpoint: string,
850
- req: Request,
851
- url: URL,
852
- server: ReturnType<typeof Bun.serve>,
853
- authContext: AuthContext,
854
- ): Promise<Response> {
775
+ private buildRouteTable(): RouteDefinition[] {
855
776
  const assistantId = DAEMON_INTERNAL_ASSISTANT_ID;
856
777
 
857
- // Normalize parameterized endpoints to their base policy key so that
858
- // routes like `calls/abc123` match the registered key `calls` and
859
- // `attachments/abc123/content` matches `attachments/content`.
860
- const normalizedEndpoint = normalizeEndpointForPolicy(endpoint, req.method);
861
-
862
- // Enforce route-level scope/principal policy before invoking any handler.
863
- // Try method-specific key first (e.g. "messages:POST"); fall back to the
864
- // plain endpoint key only when no method-specific policy is registered.
865
- const methodKey = `${normalizedEndpoint}:${req.method}`;
866
- const policyKey = getPolicy(methodKey) ? methodKey : normalizedEndpoint;
867
- const policyDenied = enforcePolicy(policyKey, authContext);
868
- if (policyDenied) return policyDenied;
869
-
870
- return withErrorHandling(endpoint, async () => {
871
- if (endpoint === "health" && req.method === "GET") return handleHealth();
872
- if (endpoint === "debug" && req.method === "GET") return handleDebug();
873
-
874
- if (endpoint === "browser-relay/status" && req.method === "GET") {
875
- return Response.json(extensionRelayServer.getStatus());
876
- }
778
+ return [
779
+ // ------------------------------------------------------------------
780
+ // Pairing (authenticated)
781
+ // ------------------------------------------------------------------
782
+ {
783
+ endpoint: "pairing/register",
784
+ method: "POST",
785
+ handler: async ({ req }) =>
786
+ handlePairingRegister(req, this.pairingContext),
787
+ },
788
+
789
+ // ------------------------------------------------------------------
790
+ // Apps — cloud sharing
791
+ // ------------------------------------------------------------------
792
+ {
793
+ endpoint: "apps/share",
794
+ method: "POST",
795
+ handler: async ({ req }) => handleShareApp(req),
796
+ },
797
+ {
798
+ endpoint: "apps/shared/:token/metadata",
799
+ method: "GET",
800
+ policyKey: "apps/shared/metadata",
801
+ handler: ({ params }) => handleGetSharedAppMetadata(params.token),
802
+ },
803
+ {
804
+ endpoint: "apps/shared/:token",
805
+ method: "GET",
806
+ policyKey: "apps/shared",
807
+ handler: ({ params }) => handleDownloadSharedApp(params.token),
808
+ },
809
+ {
810
+ endpoint: "apps/shared/:token",
811
+ method: "DELETE",
812
+ policyKey: "apps/shared",
813
+ handler: ({ params }) => handleDeleteSharedApp(params.token),
814
+ },
815
+
816
+ // ------------------------------------------------------------------
817
+ // Secrets
818
+ // ------------------------------------------------------------------
819
+ {
820
+ endpoint: "secrets",
821
+ method: "POST",
822
+ handler: async ({ req }) => handleAddSecret(req),
823
+ },
824
+ {
825
+ endpoint: "secrets",
826
+ method: "DELETE",
827
+ handler: async ({ req }) => handleDeleteSecret(req),
828
+ },
877
829
 
878
- if (endpoint === "browser-relay/command" && req.method === "POST") {
879
- try {
830
+ // ------------------------------------------------------------------
831
+ // Health / debug / browser relay
832
+ // ------------------------------------------------------------------
833
+ {
834
+ endpoint: "health",
835
+ method: "GET",
836
+ handler: () => handleHealth(),
837
+ },
838
+ {
839
+ endpoint: "debug",
840
+ method: "GET",
841
+ handler: () => handleDebug(),
842
+ },
843
+ {
844
+ endpoint: "browser-relay/status",
845
+ method: "GET",
846
+ handler: () => Response.json(extensionRelayServer.getStatus()),
847
+ },
848
+ {
849
+ endpoint: "browser-relay/command",
850
+ method: "POST",
851
+ handler: async ({ req }) => {
880
852
  const body = (await req.json()) as Record<string, unknown>;
881
853
  const resp = await extensionRelayServer.sendCommand(
882
854
  body as Omit<
@@ -885,482 +857,772 @@ export class RuntimeHttpServer {
885
857
  >,
886
858
  );
887
859
  return Response.json(resp);
888
- } catch (err) {
889
- return httpError(
890
- "INTERNAL_ERROR",
891
- err instanceof Error ? err.message : String(err),
892
- 500,
893
- );
894
- }
895
- }
860
+ },
861
+ },
896
862
 
897
- if (endpoint === "conversations" && req.method === "GET") {
898
- const limit = Number(url.searchParams.get("limit") ?? 50);
899
- const offset = Number(url.searchParams.get("offset") ?? 0);
900
- const conversations = conversationStore.listConversations(
901
- limit,
902
- false,
903
- offset,
904
- );
905
- const totalCount = conversationStore.countConversations();
906
- const conversationIds = conversations.map((c) => c.id);
907
- const bindings =
908
- externalConversationStore.getBindingsForConversations(
909
- conversationIds,
863
+ // ------------------------------------------------------------------
864
+ // Conversations
865
+ // ------------------------------------------------------------------
866
+ {
867
+ endpoint: "conversations",
868
+ method: "GET",
869
+ handler: ({ url }) => {
870
+ const limit = Number(url.searchParams.get("limit") ?? 50);
871
+ const offset = Number(url.searchParams.get("offset") ?? 0);
872
+ const conversations = conversationStore.listConversations(
873
+ limit,
874
+ false,
875
+ offset,
910
876
  );
911
- const attentionStates =
912
- getAttentionStateByConversationIds(conversationIds);
913
- return Response.json({
914
- sessions: conversations.map((c) => {
915
- const binding = bindings.get(c.id);
916
- const originChannel = parseChannelId(c.originChannel);
917
- const attn = attentionStates.get(c.id);
918
- const assistantAttention = attn
919
- ? {
920
- hasUnseenLatestAssistantMessage:
921
- attn.latestAssistantMessageAt != null &&
922
- (attn.lastSeenAssistantMessageAt == null ||
923
- attn.lastSeenAssistantMessageAt <
924
- attn.latestAssistantMessageAt),
925
- ...(attn.latestAssistantMessageAt != null
926
- ? {
927
- latestAssistantMessageAt: attn.latestAssistantMessageAt,
928
- }
929
- : {}),
930
- ...(attn.lastSeenAssistantMessageAt != null
931
- ? {
932
- lastSeenAssistantMessageAt:
933
- attn.lastSeenAssistantMessageAt,
934
- }
935
- : {}),
936
- ...(attn.lastSeenConfidence != null
937
- ? { lastSeenConfidence: attn.lastSeenConfidence }
938
- : {}),
939
- ...(attn.lastSeenSignalType != null
940
- ? { lastSeenSignalType: attn.lastSeenSignalType }
941
- : {}),
942
- }
943
- : undefined;
944
- return {
945
- id: c.id,
946
- title: c.title ?? "Untitled",
947
- createdAt: c.createdAt,
948
- updatedAt: c.updatedAt,
949
- threadType: c.threadType === "private" ? "private" : "standard",
950
- source: c.source ?? "user",
951
- ...(binding
877
+ const totalCount = conversationStore.countConversations();
878
+ const conversationIds = conversations.map((c) => c.id);
879
+ const bindings =
880
+ externalConversationStore.getBindingsForConversations(
881
+ conversationIds,
882
+ );
883
+ const attentionStates =
884
+ getAttentionStateByConversationIds(conversationIds);
885
+ return Response.json({
886
+ sessions: conversations.map((c) => {
887
+ const binding = bindings.get(c.id);
888
+ const originChannel = parseChannelId(c.originChannel);
889
+ const attn = attentionStates.get(c.id);
890
+ const assistantAttention = attn
952
891
  ? {
953
- channelBinding: {
954
- sourceChannel: binding.sourceChannel,
955
- externalChatId: binding.externalChatId,
956
- externalUserId: binding.externalUserId,
957
- displayName: binding.displayName,
958
- username: binding.username,
959
- },
892
+ hasUnseenLatestAssistantMessage:
893
+ attn.latestAssistantMessageAt != null &&
894
+ (attn.lastSeenAssistantMessageAt == null ||
895
+ attn.lastSeenAssistantMessageAt <
896
+ attn.latestAssistantMessageAt),
897
+ ...(attn.latestAssistantMessageAt != null
898
+ ? {
899
+ latestAssistantMessageAt:
900
+ attn.latestAssistantMessageAt,
901
+ }
902
+ : {}),
903
+ ...(attn.lastSeenAssistantMessageAt != null
904
+ ? {
905
+ lastSeenAssistantMessageAt:
906
+ attn.lastSeenAssistantMessageAt,
907
+ }
908
+ : {}),
909
+ ...(attn.lastSeenConfidence != null
910
+ ? { lastSeenConfidence: attn.lastSeenConfidence }
911
+ : {}),
912
+ ...(attn.lastSeenSignalType != null
913
+ ? { lastSeenSignalType: attn.lastSeenSignalType }
914
+ : {}),
960
915
  }
961
- : {}),
962
- ...(originChannel
963
- ? { conversationOriginChannel: originChannel }
964
- : {}),
965
- ...(assistantAttention ? { assistantAttention } : {}),
966
- };
967
- }),
968
- hasMore: offset + conversations.length < totalCount,
969
- });
970
- }
971
-
972
- if (endpoint === "conversations/attention" && req.method === "GET")
973
- return handleListConversationAttention(url);
974
-
975
- if (endpoint === "conversations/seen" && req.method === "POST") {
976
- const body = (await req.json()) as Record<string, unknown>;
977
- const conversationId = body.conversationId as string | undefined;
978
- if (!conversationId)
979
- return httpError("BAD_REQUEST", "Missing conversationId", 400);
980
- try {
981
- recordConversationSeenSignal({
982
- conversationId,
983
- assistantId: DAEMON_INTERNAL_ASSISTANT_ID,
984
- sourceChannel: (body.sourceChannel as string) ?? "vellum",
985
- signalType: ((body.signalType as string) ??
986
- "macos_conversation_opened") as SignalType,
987
- confidence: ((body.confidence as string) ??
988
- "explicit") as Confidence,
989
- source: (body.source as string) ?? "http-api",
990
- evidenceText: body.evidenceText as string | undefined,
991
- metadata: body.metadata as Record<string, unknown> | undefined,
992
- observedAt: body.observedAt as number | undefined,
916
+ : undefined;
917
+ return {
918
+ id: c.id,
919
+ title: c.title ?? "Untitled",
920
+ createdAt: c.createdAt,
921
+ updatedAt: c.updatedAt,
922
+ threadType: c.threadType === "private" ? "private" : "standard",
923
+ source: c.source ?? "user",
924
+ ...(binding
925
+ ? {
926
+ channelBinding: {
927
+ sourceChannel: binding.sourceChannel,
928
+ externalChatId: binding.externalChatId,
929
+ externalUserId: binding.externalUserId,
930
+ displayName: binding.displayName,
931
+ username: binding.username,
932
+ },
933
+ }
934
+ : {}),
935
+ ...(originChannel
936
+ ? { conversationOriginChannel: originChannel }
937
+ : {}),
938
+ ...(assistantAttention ? { assistantAttention } : {}),
939
+ };
940
+ }),
941
+ hasMore: offset + conversations.length < totalCount,
993
942
  });
994
- return Response.json({ ok: true });
995
- } catch (err) {
996
- log.error(
997
- { err, conversationId },
998
- "POST /v1/conversations/seen: failed",
999
- );
1000
- return httpError(
1001
- "INTERNAL_ERROR",
1002
- "Failed to record seen signal",
1003
- 500,
1004
- );
1005
- }
1006
- }
943
+ },
944
+ },
945
+ {
946
+ endpoint: "conversations/attention",
947
+ method: "GET",
948
+ handler: ({ url }) => handleListConversationAttention(url),
949
+ },
950
+ {
951
+ endpoint: "conversations/seen",
952
+ method: "POST",
953
+ handler: async ({ req }) => {
954
+ const body = (await req.json()) as Record<string, unknown>;
955
+ const conversationId = body.conversationId as string | undefined;
956
+ if (!conversationId)
957
+ return httpError("BAD_REQUEST", "Missing conversationId", 400);
958
+ try {
959
+ recordConversationSeenSignal({
960
+ conversationId,
961
+ assistantId: DAEMON_INTERNAL_ASSISTANT_ID,
962
+ sourceChannel: (body.sourceChannel as string) ?? "vellum",
963
+ signalType: ((body.signalType as string) ??
964
+ "macos_conversation_opened") as SignalType,
965
+ confidence: ((body.confidence as string) ??
966
+ "explicit") as Confidence,
967
+ source: (body.source as string) ?? "http-api",
968
+ evidenceText: body.evidenceText as string | undefined,
969
+ metadata: body.metadata as Record<string, unknown> | undefined,
970
+ observedAt: body.observedAt as number | undefined,
971
+ });
972
+ return Response.json({ ok: true });
973
+ } catch (err) {
974
+ log.error(
975
+ { err, conversationId },
976
+ "POST /v1/conversations/seen: failed",
977
+ );
978
+ return httpError(
979
+ "INTERNAL_ERROR",
980
+ "Failed to record seen signal",
981
+ 500,
982
+ );
983
+ }
984
+ },
985
+ },
1007
986
 
1008
- if (endpoint === "messages" && req.method === "GET")
1009
- return handleListMessages(url, this.interfacesDir);
1010
- if (endpoint === "search" && req.method === "GET")
1011
- return handleSearchConversations(url);
1012
-
1013
- if (endpoint === 'messages' && req.method === 'POST') {
1014
- return await handleSendMessage(req, {
1015
- processMessage: this.processMessage,
1016
- persistAndProcessMessage: this.persistAndProcessMessage,
1017
- sendMessageDeps: this.sendMessageDeps,
1018
- approvalConversationGenerator: this.approvalConversationGenerator,
1019
- }, authContext);
1020
- }
987
+ // ------------------------------------------------------------------
988
+ // Messages / search
989
+ // ------------------------------------------------------------------
990
+ {
991
+ endpoint: "messages",
992
+ method: "GET",
993
+ handler: ({ url }) => handleListMessages(url, this.interfacesDir),
994
+ },
995
+ {
996
+ endpoint: "messages",
997
+ method: "POST",
998
+ handler: async ({ req, authContext }) =>
999
+ handleSendMessage(
1000
+ req,
1001
+ {
1002
+ processMessage: this.processMessage,
1003
+ persistAndProcessMessage: this.persistAndProcessMessage,
1004
+ sendMessageDeps: this.sendMessageDeps,
1005
+ approvalConversationGenerator: this.approvalConversationGenerator,
1006
+ },
1007
+ authContext,
1008
+ ),
1009
+ },
1010
+ {
1011
+ endpoint: "search",
1012
+ method: "GET",
1013
+ handler: ({ url }) => handleSearchConversations(url),
1014
+ },
1015
+ {
1016
+ endpoint: "search/global",
1017
+ method: "GET",
1018
+ handler: async ({ url }) => handleGlobalSearch(url),
1019
+ },
1021
1020
 
1022
- // Standalone approval endpoints — keyed by requestId, orthogonal to message sending
1023
- if (endpoint === 'confirm' && req.method === 'POST') return await handleConfirm(req, authContext);
1024
- if (endpoint === 'secret' && req.method === 'POST') return await handleSecret(req, authContext);
1025
- if (endpoint === 'trust-rules' && req.method === 'POST') return await handleTrustRule(req, authContext);
1026
- if (endpoint === 'pending-interactions' && req.method === 'GET') return handleListPendingInteractions(url, authContext);
1027
-
1028
- // Trust rule CRUD standalone management (not approval-flow)
1029
- if (endpoint === "trust-rules/manage" && req.method === "GET")
1030
- return handleListTrustRules();
1031
- if (endpoint === "trust-rules/manage" && req.method === "POST")
1032
- return await handleAddTrustRuleManage(req);
1033
- const trustRuleManageMatch = endpoint.match(
1034
- /^trust-rules\/manage\/([^/]+)$/,
1035
- );
1036
- if (trustRuleManageMatch && req.method === "DELETE")
1037
- return handleRemoveTrustRuleManage(trustRuleManageMatch[1]);
1038
- if (trustRuleManageMatch && req.method === "PATCH")
1039
- return await handleUpdateTrustRuleManage(req, trustRuleManageMatch[1]);
1040
-
1041
- // Surface action dispatch
1042
- if (endpoint === "surface-actions" && req.method === "POST") {
1043
- if (!this.findSession) {
1044
- return httpError(
1045
- "NOT_IMPLEMENTED",
1046
- "Surface actions not available",
1047
- 501,
1048
- );
1049
- }
1050
- return await handleSurfaceAction(req, this.findSession);
1051
- }
1021
+ // ------------------------------------------------------------------
1022
+ // Approvals
1023
+ // ------------------------------------------------------------------
1024
+ {
1025
+ endpoint: "confirm",
1026
+ method: "POST",
1027
+ handler: async ({ req, authContext }) =>
1028
+ handleConfirm(req, authContext),
1029
+ },
1030
+ {
1031
+ endpoint: "secret",
1032
+ method: "POST",
1033
+ handler: async ({ req, authContext }) => handleSecret(req, authContext),
1034
+ },
1035
+ {
1036
+ endpoint: "trust-rules",
1037
+ method: "POST",
1038
+ handler: async ({ req, authContext }) =>
1039
+ handleTrustRule(req, authContext),
1040
+ },
1041
+ {
1042
+ endpoint: "pending-interactions",
1043
+ method: "GET",
1044
+ handler: ({ url, authContext }) =>
1045
+ handleListPendingInteractions(url, authContext),
1046
+ },
1047
+
1048
+ // ------------------------------------------------------------------
1049
+ // Trust rule CRUD management
1050
+ // ------------------------------------------------------------------
1051
+ {
1052
+ endpoint: "trust-rules/manage",
1053
+ method: "GET",
1054
+ handler: () => handleListTrustRules(),
1055
+ },
1056
+ {
1057
+ endpoint: "trust-rules/manage",
1058
+ method: "POST",
1059
+ handler: async ({ req }) => handleAddTrustRuleManage(req),
1060
+ },
1061
+ {
1062
+ endpoint: "trust-rules/manage/:id",
1063
+ method: "DELETE",
1064
+ handler: ({ params }) => handleRemoveTrustRuleManage(params.id),
1065
+ },
1066
+ {
1067
+ endpoint: "trust-rules/manage/:id",
1068
+ method: "PATCH",
1069
+ handler: async ({ req, params }) =>
1070
+ handleUpdateTrustRuleManage(req, params.id),
1071
+ },
1052
1072
 
1053
- // Guardian action endpoints — deterministic button-based decisions
1054
- if (endpoint === 'guardian-actions/pending' && req.method === 'GET') return handleGuardianActionsPending(url, authContext);
1055
- if (endpoint === 'guardian-actions/decision' && req.method === 'POST') return await handleGuardianActionDecision(req, authContext);
1073
+ // ------------------------------------------------------------------
1074
+ // Surface actions
1075
+ // ------------------------------------------------------------------
1076
+ {
1077
+ endpoint: "surface-actions",
1078
+ method: "POST",
1079
+ handler: async ({ req }) => {
1080
+ if (!this.findSession) {
1081
+ return httpError(
1082
+ "NOT_IMPLEMENTED",
1083
+ "Surface actions not available",
1084
+ 501,
1085
+ );
1086
+ }
1087
+ return handleSurfaceAction(req, this.findSession);
1088
+ },
1089
+ },
1056
1090
 
1091
+ // ------------------------------------------------------------------
1092
+ // Guardian actions
1093
+ // ------------------------------------------------------------------
1094
+ {
1095
+ endpoint: "guardian-actions/pending",
1096
+ method: "GET",
1097
+ handler: ({ url, authContext }) =>
1098
+ handleGuardianActionsPending(url, authContext),
1099
+ },
1100
+ {
1101
+ endpoint: "guardian-actions/decision",
1102
+ method: "POST",
1103
+ handler: async ({ req, authContext }) =>
1104
+ handleGuardianActionDecision(req, authContext),
1105
+ },
1106
+
1107
+ // ------------------------------------------------------------------
1057
1108
  // Contacts
1058
- if (endpoint === "contacts" && req.method === "GET")
1059
- return handleListContacts(url);
1060
- if (endpoint === "contacts/merge" && req.method === "POST")
1061
- return await handleMergeContacts(req);
1062
- const contactMatch = endpoint.match(/^contacts\/([^/]+)$/);
1063
- if (contactMatch && req.method === "GET")
1064
- return handleGetContact(contactMatch[1]);
1065
-
1066
- // Ingress members
1067
- if (endpoint === "ingress/members" && req.method === "GET")
1068
- return handleListMembers(url);
1069
- if (endpoint === "ingress/members" && req.method === "POST")
1070
- return await handleUpsertMember(req);
1071
- const memberBlockMatch = endpoint.match(
1072
- /^ingress\/members\/([^/]+)\/block$/,
1073
- );
1074
- if (memberBlockMatch && req.method === "POST")
1075
- return await handleBlockMember(req, memberBlockMatch[1]);
1076
- const memberMatch = endpoint.match(/^ingress\/members\/([^/]+)$/);
1077
- if (memberMatch && req.method === "DELETE")
1078
- return await handleRevokeMember(req, memberMatch[1]);
1109
+ // ------------------------------------------------------------------
1110
+ {
1111
+ endpoint: "contacts",
1112
+ method: "GET",
1113
+ handler: ({ url, authContext }) =>
1114
+ handleListContacts(url, authContext.assistantId),
1115
+ },
1116
+ {
1117
+ endpoint: "contacts",
1118
+ method: "POST",
1119
+ handler: async ({ req, authContext }) =>
1120
+ handleUpsertContact(req, authContext.assistantId),
1121
+ },
1122
+ {
1123
+ endpoint: "contacts/merge",
1124
+ method: "POST",
1125
+ handler: async ({ req, authContext }) =>
1126
+ handleMergeContacts(req, authContext.assistantId),
1127
+ },
1128
+ {
1129
+ endpoint: "contacts/channels/:id",
1130
+ method: "PATCH",
1131
+ policyKey: "contacts/channels",
1132
+ handler: async ({ req, params, authContext }) =>
1133
+ handleUpdateContactChannel(req, params.id, authContext.assistantId),
1134
+ },
1135
+ {
1136
+ endpoint: "contacts/:id",
1137
+ method: "GET",
1138
+ policyKey: "contacts",
1139
+ handler: ({ params, authContext }) =>
1140
+ handleGetContact(params.id, authContext.assistantId),
1141
+ },
1079
1142
 
1080
- // Ingress invites
1081
- if (endpoint === "ingress/invites" && req.method === "GET")
1082
- return handleListInvites(url);
1083
- if (endpoint === "ingress/invites" && req.method === "POST")
1084
- return await handleCreateInvite(req);
1085
- if (endpoint === "ingress/invites/redeem" && req.method === "POST")
1086
- return await handleRedeemInvite(req);
1087
- const inviteMatch = endpoint.match(/^ingress\/invites\/([^/]+)$/);
1088
- if (inviteMatch && req.method === "DELETE")
1089
- return handleRevokeInvite(inviteMatch[1]);
1090
-
1091
- // Integrations Telegram config
1092
- if (endpoint === "integrations/telegram/config" && req.method === "GET")
1093
- return handleGetTelegramConfig();
1094
- if (endpoint === "integrations/telegram/config" && req.method === "POST")
1095
- return await handleSetTelegramConfig(req);
1096
- if (
1097
- endpoint === "integrations/telegram/config" &&
1098
- req.method === "DELETE"
1099
- )
1100
- return await handleClearTelegramConfig();
1101
- if (
1102
- endpoint === "integrations/telegram/commands" &&
1103
- req.method === "POST"
1104
- )
1105
- return await handleSetTelegramCommands(req);
1106
- if (endpoint === "integrations/telegram/setup" && req.method === "POST")
1107
- return await handleSetupTelegram(req);
1108
-
1109
- // Integrations — Slack channel config
1110
- if (
1111
- endpoint === "integrations/slack/channel/config" &&
1112
- req.method === "GET"
1113
- )
1114
- return handleGetSlackChannelConfig();
1115
- if (
1116
- endpoint === "integrations/slack/channel/config" &&
1117
- req.method === "POST"
1118
- )
1119
- return await handleSetSlackChannelConfig(req);
1120
- if (
1121
- endpoint === "integrations/slack/channel/config" &&
1122
- req.method === "DELETE"
1123
- )
1124
- return handleClearSlackChannelConfig();
1125
-
1126
- // Integrations — Guardian verification
1127
- if (
1128
- endpoint === "integrations/guardian/challenge" &&
1129
- req.method === "POST"
1130
- )
1131
- return await handleCreateGuardianChallenge(req);
1132
- if (endpoint === "integrations/guardian/status" && req.method === "GET")
1133
- return handleGetGuardianStatus(url);
1134
- if (
1135
- endpoint === "integrations/guardian/outbound/start" &&
1136
- req.method === "POST"
1137
- )
1138
- return await handleStartOutbound(req);
1139
- if (
1140
- endpoint === "integrations/guardian/outbound/resend" &&
1141
- req.method === "POST"
1142
- )
1143
- return await handleResendOutbound(req);
1144
- if (
1145
- endpoint === "integrations/guardian/outbound/cancel" &&
1146
- req.method === "POST"
1147
- )
1148
- return await handleCancelOutbound(req);
1149
-
1150
- // Guardian vellum channel bootstrap and refresh are handled before
1151
- // JWT auth in routeRequest() — they are not dispatched here.
1152
-
1153
- // Integrations — Twilio config
1154
- if (endpoint === "integrations/twilio/config" && req.method === "GET")
1155
- return handleGetTwilioConfig();
1156
- if (
1157
- endpoint === "integrations/twilio/credentials" &&
1158
- req.method === "POST"
1159
- )
1160
- return await handleSetTwilioCredentials(req);
1161
- if (
1162
- endpoint === "integrations/twilio/credentials" &&
1163
- req.method === "DELETE"
1164
- )
1165
- return handleClearTwilioCredentials();
1166
- if (endpoint === "integrations/twilio/numbers" && req.method === "GET")
1167
- return await handleListTwilioNumbers();
1168
- if (
1169
- endpoint === "integrations/twilio/numbers/provision" &&
1170
- req.method === "POST"
1171
- )
1172
- return await handleProvisionTwilioNumber(req);
1173
- if (
1174
- endpoint === "integrations/twilio/numbers/assign" &&
1175
- req.method === "POST"
1176
- )
1177
- return await handleAssignTwilioNumber(req);
1178
- if (
1179
- endpoint === "integrations/twilio/numbers/release" &&
1180
- req.method === "POST"
1181
- )
1182
- return await handleReleaseTwilioNumber(req);
1183
- if (
1184
- endpoint === "integrations/twilio/sms/compliance" &&
1185
- req.method === "GET"
1186
- )
1187
- return await handleGetSmsCompliance();
1188
- if (
1189
- endpoint === "integrations/twilio/sms/compliance/tollfree" &&
1190
- req.method === "POST"
1191
- )
1192
- return await handleSubmitTollfreeVerification(req);
1193
- if (endpoint === "integrations/twilio/sms/test" && req.method === "POST")
1194
- return await handleSmsSendTest(req);
1195
- if (
1196
- endpoint === "integrations/twilio/sms/doctor" &&
1197
- req.method === "POST"
1198
- )
1199
- return await handleSmsDoctor();
1200
-
1201
- // Twilio toll-free verification PATCH/DELETE with :verificationSid
1202
- const tollfreeVerificationMatch = endpoint.match(
1203
- /^integrations\/twilio\/sms\/compliance\/tollfree\/([^/]+)$/,
1204
- );
1205
- if (tollfreeVerificationMatch) {
1206
- const verificationSid = tollfreeVerificationMatch[1];
1207
- if (req.method === "PATCH")
1208
- return await handleUpdateTollfreeVerification(req, verificationSid);
1209
- if (req.method === "DELETE")
1210
- return await handleDeleteTollfreeVerification(verificationSid);
1211
- }
1143
+ // ------------------------------------------------------------------
1144
+ // Ingress contacts
1145
+ // ------------------------------------------------------------------
1146
+ {
1147
+ endpoint: "ingress/members",
1148
+ method: "GET",
1149
+ handler: ({ url }) => handleListMembers(url),
1150
+ },
1151
+ {
1152
+ endpoint: "ingress/members",
1153
+ method: "POST",
1154
+ handler: async ({ req }) => handleUpsertMember(req),
1155
+ },
1156
+ {
1157
+ endpoint: "ingress/members/:id/block",
1158
+ method: "POST",
1159
+ policyKey: "ingress/members/block",
1160
+ handler: async ({ req, params }) => handleBlockMember(req, params.id),
1161
+ },
1162
+ {
1163
+ endpoint: "ingress/members/:id",
1164
+ method: "DELETE",
1165
+ policyKey: "ingress/members",
1166
+ handler: async ({ req, params }) => handleRevokeMember(req, params.id),
1167
+ },
1212
1168
 
1213
- // Channel readiness
1214
- if (endpoint === "channels/readiness" && req.method === "GET")
1215
- return await handleGetChannelReadiness(url);
1216
- if (endpoint === "channels/readiness/refresh" && req.method === "POST")
1217
- return await handleRefreshChannelReadiness(req);
1218
-
1219
- if (endpoint === "attachments" && req.method === "POST")
1220
- return await handleUploadAttachment(req);
1221
- if (endpoint === "attachments" && req.method === "DELETE")
1222
- return await handleDeleteAttachment(req);
1223
-
1224
- const attachmentContentMatch = endpoint.match(
1225
- /^attachments\/([^/]+)\/content$/,
1226
- );
1227
- if (attachmentContentMatch && req.method === "GET")
1228
- return handleGetAttachmentContent(attachmentContentMatch[1], req);
1169
+ // ------------------------------------------------------------------
1170
+ // Ingress invites
1171
+ // ------------------------------------------------------------------
1172
+ {
1173
+ endpoint: "ingress/invites",
1174
+ method: "GET",
1175
+ handler: ({ url }) => handleListInvites(url),
1176
+ },
1177
+ {
1178
+ endpoint: "ingress/invites",
1179
+ method: "POST",
1180
+ handler: async ({ req }) => handleCreateInvite(req),
1181
+ },
1182
+ {
1183
+ endpoint: "ingress/invites/redeem",
1184
+ method: "POST",
1185
+ handler: async ({ req }) => handleRedeemInvite(req),
1186
+ },
1187
+ {
1188
+ endpoint: "ingress/invites/:id",
1189
+ method: "DELETE",
1190
+ policyKey: "ingress/invites",
1191
+ handler: ({ params }) => handleRevokeInvite(params.id),
1192
+ },
1229
1193
 
1230
- const attachmentMatch = endpoint.match(/^attachments\/([^/]+)$/);
1231
- if (attachmentMatch && req.method === "GET")
1232
- return handleGetAttachment(attachmentMatch[1]);
1194
+ // ------------------------------------------------------------------
1195
+ // Integrations Telegram
1196
+ // ------------------------------------------------------------------
1197
+ {
1198
+ endpoint: "integrations/telegram/config",
1199
+ method: "GET",
1200
+ handler: () => handleGetTelegramConfig(),
1201
+ },
1202
+ {
1203
+ endpoint: "integrations/telegram/config",
1204
+ method: "POST",
1205
+ handler: async ({ req }) => handleSetTelegramConfig(req),
1206
+ },
1207
+ {
1208
+ endpoint: "integrations/telegram/config",
1209
+ method: "DELETE",
1210
+ handler: async () => handleClearTelegramConfig(),
1211
+ },
1212
+ {
1213
+ endpoint: "integrations/telegram/commands",
1214
+ method: "POST",
1215
+ handler: async ({ req }) => handleSetTelegramCommands(req),
1216
+ },
1217
+ {
1218
+ endpoint: "integrations/telegram/setup",
1219
+ method: "POST",
1220
+ handler: async ({ req }) => handleSetupTelegram(req),
1221
+ },
1233
1222
 
1234
- if (endpoint === "suggestion" && req.method === "GET") {
1235
- return await handleGetSuggestion(url, {
1236
- suggestionCache: this.suggestionCache,
1237
- suggestionInFlight: this.suggestionInFlight,
1238
- });
1239
- }
1223
+ // ------------------------------------------------------------------
1224
+ // Integrations Slack
1225
+ // ------------------------------------------------------------------
1226
+ {
1227
+ endpoint: "integrations/slack/channel/config",
1228
+ method: "GET",
1229
+ handler: () => handleGetSlackChannelConfig(),
1230
+ },
1231
+ {
1232
+ endpoint: "integrations/slack/channel/config",
1233
+ method: "POST",
1234
+ handler: async ({ req }) => handleSetSlackChannelConfig(req),
1235
+ },
1236
+ {
1237
+ endpoint: "integrations/slack/channel/config",
1238
+ method: "DELETE",
1239
+ handler: () => handleClearSlackChannelConfig(),
1240
+ },
1240
1241
 
1241
- const interfacesMatch = endpoint.match(/^interfaces\/(.+)$/);
1242
- if (interfacesMatch && req.method === "GET")
1243
- return this.handleGetInterface(interfacesMatch[1]);
1242
+ // ------------------------------------------------------------------
1243
+ // Integrations Guardian
1244
+ // ------------------------------------------------------------------
1245
+ {
1246
+ endpoint: "integrations/guardian/challenge",
1247
+ method: "POST",
1248
+ handler: async ({ req }) => handleCreateGuardianChallenge(req),
1249
+ },
1250
+ {
1251
+ endpoint: "integrations/guardian/status",
1252
+ method: "GET",
1253
+ handler: ({ url }) => handleGetGuardianStatus(url),
1254
+ },
1255
+ {
1256
+ endpoint: "integrations/guardian/revoke",
1257
+ method: "POST",
1258
+ handler: async ({ req }) => handleRevokeGuardian(req),
1259
+ },
1260
+ {
1261
+ endpoint: "integrations/guardian/outbound/start",
1262
+ method: "POST",
1263
+ handler: async ({ req }) => handleStartOutbound(req),
1264
+ },
1265
+ {
1266
+ endpoint: "integrations/guardian/outbound/resend",
1267
+ method: "POST",
1268
+ handler: async ({ req }) => handleResendOutbound(req),
1269
+ },
1270
+ {
1271
+ endpoint: "integrations/guardian/outbound/cancel",
1272
+ method: "POST",
1273
+ handler: async ({ req }) => handleCancelOutbound(req),
1274
+ },
1244
1275
 
1245
- if (endpoint === "channels/conversation" && req.method === "DELETE")
1246
- return await handleDeleteConversation(req, assistantId);
1276
+ // ------------------------------------------------------------------
1277
+ // Integrations Twilio
1278
+ // ------------------------------------------------------------------
1279
+ {
1280
+ endpoint: "integrations/twilio/config",
1281
+ method: "GET",
1282
+ handler: () => handleGetTwilioConfig(),
1283
+ },
1284
+ {
1285
+ endpoint: "integrations/twilio/credentials",
1286
+ method: "POST",
1287
+ handler: async ({ req }) => handleSetTwilioCredentials(req),
1288
+ },
1289
+ {
1290
+ endpoint: "integrations/twilio/credentials",
1291
+ method: "DELETE",
1292
+ handler: () => handleClearTwilioCredentials(),
1293
+ },
1294
+ {
1295
+ endpoint: "integrations/twilio/numbers",
1296
+ method: "GET",
1297
+ handler: async () => handleListTwilioNumbers(),
1298
+ },
1299
+ {
1300
+ endpoint: "integrations/twilio/numbers/provision",
1301
+ method: "POST",
1302
+ handler: async ({ req }) => handleProvisionTwilioNumber(req),
1303
+ },
1304
+ {
1305
+ endpoint: "integrations/twilio/numbers/assign",
1306
+ method: "POST",
1307
+ handler: async ({ req }) => handleAssignTwilioNumber(req),
1308
+ },
1309
+ {
1310
+ endpoint: "integrations/twilio/numbers/release",
1311
+ method: "POST",
1312
+ handler: async ({ req }) => handleReleaseTwilioNumber(req),
1313
+ },
1314
+ {
1315
+ endpoint: "integrations/twilio/sms/compliance",
1316
+ method: "GET",
1317
+ handler: async () => handleGetSmsCompliance(),
1318
+ },
1319
+ {
1320
+ endpoint: "integrations/twilio/sms/compliance/tollfree",
1321
+ method: "POST",
1322
+ handler: async ({ req }) => handleSubmitTollfreeVerification(req),
1323
+ },
1324
+ {
1325
+ endpoint: "integrations/twilio/sms/compliance/tollfree/:sid",
1326
+ method: "PATCH",
1327
+ policyKey: "integrations/twilio/sms/compliance/tollfree",
1328
+ handler: async ({ req, params }) =>
1329
+ handleUpdateTollfreeVerification(req, params.sid),
1330
+ },
1331
+ {
1332
+ endpoint: "integrations/twilio/sms/compliance/tollfree/:sid",
1333
+ method: "DELETE",
1334
+ policyKey: "integrations/twilio/sms/compliance/tollfree",
1335
+ handler: async ({ params }) =>
1336
+ handleDeleteTollfreeVerification(params.sid),
1337
+ },
1338
+ {
1339
+ endpoint: "integrations/twilio/sms/test",
1340
+ method: "POST",
1341
+ handler: async ({ req }) => handleSmsSendTest(req),
1342
+ },
1343
+ {
1344
+ endpoint: "integrations/twilio/sms/doctor",
1345
+ method: "POST",
1346
+ handler: async () => handleSmsDoctor(),
1347
+ },
1247
1348
 
1248
- if (endpoint === 'channels/inbound' && req.method === 'POST') {
1249
- // Route policy enforces svc_gateway principal type.
1250
- return await handleChannelInbound(req, this.processMessage, assistantId, this.approvalCopyGenerator, this.approvalConversationGenerator, this.guardianActionCopyGenerator, this.guardianFollowUpConversationGenerator);
1251
- }
1349
+ // ------------------------------------------------------------------
1350
+ // Channel readiness
1351
+ // ------------------------------------------------------------------
1352
+ {
1353
+ endpoint: "channels/readiness",
1354
+ method: "GET",
1355
+ handler: async ({ url }) => handleGetChannelReadiness(url),
1356
+ },
1357
+ {
1358
+ endpoint: "channels/readiness/refresh",
1359
+ method: "POST",
1360
+ handler: async ({ req }) => handleRefreshChannelReadiness(req),
1361
+ },
1252
1362
 
1253
- if (endpoint === "channels/delivery-ack" && req.method === "POST")
1254
- return await handleChannelDeliveryAck(req);
1255
- if (endpoint === "channels/dead-letters" && req.method === "GET")
1256
- return handleListDeadLetters();
1257
- if (endpoint === "channels/replay" && req.method === "POST")
1258
- return await handleReplayDeadLetters(req);
1363
+ // ------------------------------------------------------------------
1364
+ // Attachments — specific sub-resource routes before generic ones
1365
+ // ------------------------------------------------------------------
1366
+ {
1367
+ endpoint: "attachments",
1368
+ method: "POST",
1369
+ handler: async ({ req }) => handleUploadAttachment(req),
1370
+ },
1371
+ {
1372
+ endpoint: "attachments",
1373
+ method: "DELETE",
1374
+ handler: async ({ req }) => handleDeleteAttachment(req),
1375
+ },
1376
+ {
1377
+ endpoint: "attachments/:id/content",
1378
+ method: "GET",
1379
+ policyKey: "attachments/content",
1380
+ handler: ({ req, params }) =>
1381
+ handleGetAttachmentContent(params.id, req),
1382
+ },
1383
+ {
1384
+ endpoint: "attachments/:id",
1385
+ method: "GET",
1386
+ policyKey: "attachments",
1387
+ handler: ({ params }) => handleGetAttachment(params.id),
1388
+ },
1259
1389
 
1260
- if (endpoint === "calls/start" && req.method === "POST")
1261
- return await handleStartCall(req, assistantId);
1390
+ // ------------------------------------------------------------------
1391
+ // Suggestion
1392
+ // ------------------------------------------------------------------
1393
+ {
1394
+ endpoint: "suggestion",
1395
+ method: "GET",
1396
+ handler: async ({ url }) =>
1397
+ handleGetSuggestion(url, {
1398
+ suggestionCache: this.suggestionCache,
1399
+ suggestionInFlight: this.suggestionInFlight,
1400
+ }),
1401
+ },
1262
1402
 
1263
- const callsMatch = endpoint.match(
1264
- /^calls\/([^/]+?)(\/cancel|\/answer|\/instruction)?$/,
1265
- );
1266
- if (callsMatch) {
1267
- const callSessionId = callsMatch[1];
1268
- if (
1269
- callSessionId !== "twilio" &&
1270
- callSessionId !== "relay" &&
1271
- callSessionId !== "start"
1272
- ) {
1273
- if (callsMatch[2] === "/cancel" && req.method === "POST")
1274
- return await handleCancelCall(req, callSessionId);
1275
- if (callsMatch[2] === "/answer" && req.method === "POST")
1276
- return await handleAnswerCall(req, callSessionId);
1277
- if (callsMatch[2] === "/instruction" && req.method === "POST")
1278
- return await handleInstructionCall(req, callSessionId);
1279
- if (!callsMatch[2] && req.method === "GET")
1280
- return handleGetCallStatus(callSessionId);
1281
- }
1282
- }
1403
+ // ------------------------------------------------------------------
1404
+ // Interfaces
1405
+ // ------------------------------------------------------------------
1406
+ {
1407
+ endpoint: "interfaces/:path*",
1408
+ method: "GET",
1409
+ policyKey: "interfaces",
1410
+ handler: ({ params }) => this.handleGetInterface(params.path),
1411
+ },
1283
1412
 
1284
- // Internal Twilio forwarding endpoints (gateway -> runtime).
1285
- // Route policy enforces svc_gateway principal type.
1286
- if (endpoint === 'internal/twilio/voice-webhook' && req.method === 'POST') {
1287
- const json = await req.json() as { params: Record<string, string>; originalUrl?: string };
1288
- const formBody = new URLSearchParams(json.params).toString();
1289
- const reconstructedUrl = json.originalUrl ?? req.url;
1290
- const fakeReq = new Request(reconstructedUrl, {
1291
- method: "POST",
1292
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
1293
- body: formBody,
1294
- });
1295
- return await handleVoiceWebhook(fakeReq);
1296
- }
1413
+ // ------------------------------------------------------------------
1414
+ // Channel operations
1415
+ // ------------------------------------------------------------------
1416
+ {
1417
+ endpoint: "channels/conversation",
1418
+ method: "DELETE",
1419
+ handler: async ({ req }) => handleDeleteConversation(req, assistantId),
1420
+ },
1421
+ {
1422
+ endpoint: "channels/inbound",
1423
+ method: "POST",
1424
+ handler: async ({ req }) =>
1425
+ handleChannelInbound(
1426
+ req,
1427
+ this.processMessage,
1428
+ assistantId,
1429
+ this.approvalCopyGenerator,
1430
+ this.approvalConversationGenerator,
1431
+ this.guardianActionCopyGenerator,
1432
+ this.guardianFollowUpConversationGenerator,
1433
+ ),
1434
+ },
1435
+ {
1436
+ endpoint: "channels/delivery-ack",
1437
+ method: "POST",
1438
+ handler: async ({ req }) => handleChannelDeliveryAck(req),
1439
+ },
1440
+ {
1441
+ endpoint: "channels/dead-letters",
1442
+ method: "GET",
1443
+ handler: () => handleListDeadLetters(),
1444
+ },
1445
+ {
1446
+ endpoint: "channels/replay",
1447
+ method: "POST",
1448
+ handler: async ({ req }) => handleReplayDeadLetters(req),
1449
+ },
1297
1450
 
1298
- if (endpoint === 'internal/twilio/status' && req.method === 'POST') {
1299
- const json = await req.json() as { params: Record<string, string> };
1300
- const formBody = new URLSearchParams(json.params).toString();
1301
- const fakeReq = new Request(req.url, {
1302
- method: "POST",
1303
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
1304
- body: formBody,
1305
- });
1306
- return await handleStatusCallback(fakeReq);
1307
- }
1451
+ // ------------------------------------------------------------------
1452
+ // Calls specific sub-actions before the generic calls/:id route
1453
+ // ------------------------------------------------------------------
1454
+ {
1455
+ endpoint: "calls/start",
1456
+ method: "POST",
1457
+ handler: async ({ req }) => handleStartCall(req, assistantId),
1458
+ },
1459
+ {
1460
+ endpoint: "calls/:id/cancel",
1461
+ method: "POST",
1462
+ policyKey: "calls/cancel",
1463
+ handler: async ({ req, params }) => handleCancelCall(req, params.id),
1464
+ },
1465
+ {
1466
+ endpoint: "calls/:id/answer",
1467
+ method: "POST",
1468
+ policyKey: "calls/answer",
1469
+ handler: async ({ req, params }) => handleAnswerCall(req, params.id),
1470
+ },
1471
+ {
1472
+ endpoint: "calls/:id/instruction",
1473
+ method: "POST",
1474
+ policyKey: "calls/instruction",
1475
+ handler: async ({ req, params }) =>
1476
+ handleInstructionCall(req, params.id),
1477
+ },
1478
+ {
1479
+ endpoint: "calls/:id",
1480
+ method: "GET",
1481
+ policyKey: "calls",
1482
+ handler: ({ params }) => handleGetCallStatus(params.id),
1483
+ },
1308
1484
 
1309
- if (endpoint === 'internal/twilio/connect-action' && req.method === 'POST') {
1310
- const json = await req.json() as { params: Record<string, string> };
1311
- const formBody = new URLSearchParams(json.params).toString();
1312
- const fakeReq = new Request(req.url, {
1313
- method: "POST",
1314
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
1315
- body: formBody,
1316
- });
1317
- return await handleConnectAction(fakeReq);
1318
- }
1485
+ // ------------------------------------------------------------------
1486
+ // Internal Twilio forwarding (gateway -> runtime)
1487
+ // ------------------------------------------------------------------
1488
+ {
1489
+ endpoint: "internal/twilio/voice-webhook",
1490
+ method: "POST",
1491
+ handler: async ({ req }) => {
1492
+ const json = (await req.json()) as {
1493
+ params: Record<string, string>;
1494
+ originalUrl?: string;
1495
+ };
1496
+ const formBody = new URLSearchParams(json.params).toString();
1497
+ const reconstructedUrl = json.originalUrl ?? req.url;
1498
+ const fakeReq = new Request(reconstructedUrl, {
1499
+ method: "POST",
1500
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
1501
+ body: formBody,
1502
+ });
1503
+ return handleVoiceWebhook(fakeReq);
1504
+ },
1505
+ },
1506
+ {
1507
+ endpoint: "internal/twilio/status",
1508
+ method: "POST",
1509
+ handler: async ({ req }) => {
1510
+ const json = (await req.json()) as {
1511
+ params: Record<string, string>;
1512
+ };
1513
+ const formBody = new URLSearchParams(json.params).toString();
1514
+ const fakeReq = new Request(req.url, {
1515
+ method: "POST",
1516
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
1517
+ body: formBody,
1518
+ });
1519
+ return handleStatusCallback(fakeReq);
1520
+ },
1521
+ },
1522
+ {
1523
+ endpoint: "internal/twilio/connect-action",
1524
+ method: "POST",
1525
+ handler: async ({ req }) => {
1526
+ const json = (await req.json()) as {
1527
+ params: Record<string, string>;
1528
+ };
1529
+ const formBody = new URLSearchParams(json.params).toString();
1530
+ const fakeReq = new Request(req.url, {
1531
+ method: "POST",
1532
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
1533
+ body: formBody,
1534
+ });
1535
+ return handleConnectAction(fakeReq);
1536
+ },
1537
+ },
1319
1538
 
1320
- if (endpoint === 'identity' && req.method === 'GET') return handleGetIdentity();
1321
- if (endpoint === 'brain-graph' && req.method === 'GET') return handleGetBrainGraph();
1322
- if (endpoint === 'brain-graph-ui' && req.method === 'GET') return handleServeBrainGraphUI(mintUiPageToken());
1323
- if (endpoint === 'home-base-ui' && req.method === 'GET') return handleServeHomeBaseUI(mintUiPageToken());
1324
- if (endpoint === 'events' && req.method === 'GET') return handleSubscribeAssistantEvents(req, url, { authContext });
1325
-
1326
- // Internal OAuth callback endpoint (gateway -> runtime)
1327
- if (endpoint === 'internal/oauth/callback' && req.method === 'POST') {
1328
- const json = await req.json() as { state: string; code?: string; error?: string };
1329
- if (!json.state) return httpError('BAD_REQUEST', 'Missing state parameter', 400);
1330
- if (json.error) {
1331
- const consumed = consumeCallbackError(json.state, json.error);
1332
- return consumed
1333
- ? Response.json({ ok: true })
1334
- : httpError("NOT_FOUND", "Unknown state", 404);
1335
- }
1336
- if (json.code) {
1337
- const consumed = consumeCallback(json.state, json.code);
1338
- return consumed
1339
- ? Response.json({ ok: true })
1340
- : httpError("NOT_FOUND", "Unknown state", 404);
1341
- }
1342
- return httpError("BAD_REQUEST", "Missing code or error parameter", 400);
1343
- }
1539
+ // ------------------------------------------------------------------
1540
+ // Identity / brain graph / UIs / events
1541
+ // ------------------------------------------------------------------
1542
+ {
1543
+ endpoint: "identity",
1544
+ method: "GET",
1545
+ handler: () => handleGetIdentity(),
1546
+ },
1547
+ {
1548
+ endpoint: "brain-graph",
1549
+ method: "GET",
1550
+ handler: () => handleGetBrainGraph(),
1551
+ },
1552
+ {
1553
+ endpoint: "brain-graph-ui",
1554
+ method: "GET",
1555
+ handler: () => handleServeBrainGraphUI(mintUiPageToken()),
1556
+ },
1557
+ {
1558
+ endpoint: "home-base-ui",
1559
+ method: "GET",
1560
+ handler: () => handleServeHomeBaseUI(mintUiPageToken()),
1561
+ },
1562
+ {
1563
+ endpoint: "events",
1564
+ method: "GET",
1565
+ handler: ({ req, url, authContext }) =>
1566
+ handleSubscribeAssistantEvents(req, url, { authContext }),
1567
+ },
1344
1568
 
1345
- return httpError("NOT_FOUND", "Not found", 404);
1346
- });
1347
- }
1569
+ // ------------------------------------------------------------------
1570
+ // Migrations
1571
+ // ------------------------------------------------------------------
1572
+ {
1573
+ endpoint: "migrations/validate",
1574
+ method: "POST",
1575
+ handler: async ({ req }) => handleMigrationValidate(req),
1576
+ },
1577
+ {
1578
+ endpoint: "migrations/export",
1579
+ method: "POST",
1580
+ handler: async ({ req }) => handleMigrationExport(req),
1581
+ },
1582
+ {
1583
+ endpoint: "migrations/import-preflight",
1584
+ method: "POST",
1585
+ handler: async ({ req }) => handleMigrationImportPreflight(req),
1586
+ },
1587
+ {
1588
+ endpoint: "migrations/import",
1589
+ method: "POST",
1590
+ handler: async ({ req }) => handleMigrationImport(req),
1591
+ },
1348
1592
 
1349
- private handleGetInterface(interfacePath: string): Response {
1350
- if (!this.interfacesDir) {
1351
- return httpError("NOT_FOUND", "Interface not found", 404);
1352
- }
1353
- const fullPath = resolve(this.interfacesDir, interfacePath);
1354
- if (
1355
- (fullPath !== this.interfacesDir &&
1356
- !fullPath.startsWith(this.interfacesDir + "/")) ||
1357
- !existsSync(fullPath)
1358
- ) {
1359
- return httpError("NOT_FOUND", "Interface not found", 404);
1360
- }
1361
- const source = readFileSync(fullPath, "utf-8");
1362
- return new Response(source, {
1363
- headers: { "Content-Type": "text/plain; charset=utf-8" },
1364
- });
1593
+ // ------------------------------------------------------------------
1594
+ // Internal OAuth callback (gateway -> runtime)
1595
+ // ------------------------------------------------------------------
1596
+ {
1597
+ endpoint: "internal/oauth/callback",
1598
+ method: "POST",
1599
+ handler: async ({ req }) => {
1600
+ const json = (await req.json()) as {
1601
+ state: string;
1602
+ code?: string;
1603
+ error?: string;
1604
+ };
1605
+ if (!json.state)
1606
+ return httpError("BAD_REQUEST", "Missing state parameter", 400);
1607
+ if (json.error) {
1608
+ const consumed = consumeCallbackError(json.state, json.error);
1609
+ return consumed
1610
+ ? Response.json({ ok: true })
1611
+ : httpError("NOT_FOUND", "Unknown state", 404);
1612
+ }
1613
+ if (json.code) {
1614
+ const consumed = consumeCallback(json.state, json.code);
1615
+ return consumed
1616
+ ? Response.json({ ok: true })
1617
+ : httpError("NOT_FOUND", "Unknown state", 404);
1618
+ }
1619
+ return httpError(
1620
+ "BAD_REQUEST",
1621
+ "Missing code or error parameter",
1622
+ 400,
1623
+ );
1624
+ },
1625
+ },
1626
+ ];
1365
1627
  }
1366
1628
  }