@vellumai/assistant 0.5.6 → 0.5.8

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 (442) hide show
  1. package/.env.example +16 -2
  2. package/ARCHITECTURE.md +6 -75
  3. package/Dockerfile +3 -2
  4. package/README.md +0 -2
  5. package/bun.lock +0 -414
  6. package/docker-entrypoint.sh +9 -0
  7. package/docs/architecture/keychain-broker.md +45 -240
  8. package/docs/architecture/memory.md +13 -11
  9. package/docs/architecture/security.md +0 -17
  10. package/docs/credential-execution-service.md +2 -2
  11. package/node_modules/@vellumai/ces-contracts/package.json +1 -0
  12. package/node_modules/@vellumai/ces-contracts/src/error.ts +1 -1
  13. package/node_modules/@vellumai/ces-contracts/src/grants.ts +1 -1
  14. package/node_modules/@vellumai/ces-contracts/src/handles.ts +1 -1
  15. package/node_modules/@vellumai/ces-contracts/src/index.ts +1 -1
  16. package/node_modules/@vellumai/ces-contracts/src/rpc.ts +120 -1
  17. package/node_modules/@vellumai/credential-storage/package.json +1 -0
  18. package/node_modules/@vellumai/egress-proxy/package.json +1 -0
  19. package/package.json +2 -3
  20. package/src/__tests__/actor-token-service.test.ts +0 -114
  21. package/src/__tests__/approval-cascade.test.ts +0 -1
  22. package/src/__tests__/assistant-feature-flags-integration.test.ts +30 -29
  23. package/src/__tests__/browser-fill-credential.test.ts +1 -1
  24. package/src/__tests__/browser-skill-endstate.test.ts +6 -5
  25. package/src/__tests__/btw-routes.test.ts +0 -39
  26. package/src/__tests__/call-controller.test.ts +0 -1
  27. package/src/__tests__/call-domain.test.ts +0 -128
  28. package/src/__tests__/ces-rpc-credential-backend.test.ts +199 -0
  29. package/src/__tests__/ces-startup-timeout.test.ts +40 -0
  30. package/src/__tests__/channel-approval-routes.test.ts +0 -5
  31. package/src/__tests__/channel-readiness-service.test.ts +1 -60
  32. package/src/__tests__/checker.test.ts +4 -2
  33. package/src/__tests__/cli-command-risk-guard.test.ts +112 -0
  34. package/src/__tests__/config-schema-cmd.test.ts +0 -2
  35. package/src/__tests__/config-schema.test.ts +3 -1
  36. package/src/__tests__/conversation-abort-tool-results.test.ts +0 -1
  37. package/src/__tests__/conversation-agent-loop-overflow.test.ts +0 -2
  38. package/src/__tests__/conversation-agent-loop.test.ts +2 -4
  39. package/src/__tests__/conversation-attention-telegram.test.ts +0 -5
  40. package/src/__tests__/conversation-confirmation-signals.test.ts +0 -1
  41. package/src/__tests__/conversation-error.test.ts +15 -1
  42. package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
  43. package/src/__tests__/conversation-messaging-secret-redirect.test.ts +1 -1
  44. package/src/__tests__/conversation-pre-run-repair.test.ts +0 -1
  45. package/src/__tests__/conversation-provider-retry-repair.test.ts +0 -1
  46. package/src/__tests__/conversation-queue.test.ts +0 -1
  47. package/src/__tests__/conversation-skill-tools.test.ts +0 -54
  48. package/src/__tests__/conversation-slash-queue.test.ts +0 -1
  49. package/src/__tests__/conversation-slash-unknown.test.ts +0 -1
  50. package/src/__tests__/conversation-title-service.test.ts +87 -0
  51. package/src/__tests__/conversation-workspace-injection.test.ts +0 -1
  52. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -1
  53. package/src/__tests__/credential-execution-client.test.ts +5 -2
  54. package/src/__tests__/credential-execution-feature-gates.test.ts +59 -30
  55. package/src/__tests__/credential-execution-managed-contract.test.ts +35 -20
  56. package/src/__tests__/credential-security-e2e.test.ts +1 -67
  57. package/src/__tests__/credential-security-invariants.test.ts +6 -50
  58. package/src/__tests__/credentials-cli.test.ts +82 -3
  59. package/src/__tests__/daemon-credential-client.test.ts +123 -0
  60. package/src/__tests__/db-migration-rollback.test.ts +2015 -1
  61. package/src/__tests__/deterministic-verification-control-plane.test.ts +1 -0
  62. package/src/__tests__/docker-signing-key-bootstrap.test.ts +34 -143
  63. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +6 -4
  64. package/src/__tests__/gateway-client-managed-outbound.test.ts +79 -1
  65. package/src/__tests__/guardian-routing-state.test.ts +0 -5
  66. package/src/__tests__/host-shell-tool.test.ts +6 -7
  67. package/src/__tests__/http-user-message-parity.test.ts +3 -103
  68. package/src/__tests__/inbound-invite-redemption.test.ts +0 -4
  69. package/src/__tests__/inline-skill-load-permissions.test.ts +6 -8
  70. package/src/__tests__/intent-routing.test.ts +0 -13
  71. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +178 -0
  72. package/src/__tests__/journal-context.test.ts +335 -0
  73. package/src/__tests__/keychain-broker-client.test.ts +161 -22
  74. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +0 -3
  75. package/src/__tests__/memory-jobs-worker-backoff.test.ts +150 -0
  76. package/src/__tests__/memory-lifecycle-e2e.test.ts +70 -25
  77. package/src/__tests__/memory-recall-quality.test.ts +48 -17
  78. package/src/__tests__/memory-regressions.test.ts +408 -363
  79. package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -3
  80. package/src/__tests__/migration-export-http.test.ts +2 -2
  81. package/src/__tests__/migration-import-commit-http.test.ts +2 -2
  82. package/src/__tests__/migration-import-preflight-http.test.ts +2 -2
  83. package/src/__tests__/migration-validate-http.test.ts +2 -2
  84. package/src/__tests__/non-member-access-request.test.ts +2 -7
  85. package/src/__tests__/notification-decision-fallback.test.ts +4 -0
  86. package/src/__tests__/notification-decision-identity.test.ts +4 -0
  87. package/src/__tests__/notification-decision-strategy.test.ts +71 -0
  88. package/src/__tests__/oauth-cli.test.ts +5 -1
  89. package/src/__tests__/permission-types.test.ts +1 -0
  90. package/src/__tests__/provider-commit-message-generator.test.ts +0 -37
  91. package/src/__tests__/provider-error-scenarios.test.ts +0 -267
  92. package/src/__tests__/provider-managed-proxy-integration.test.ts +5 -6
  93. package/src/__tests__/provider-streaming.benchmark.test.ts +2 -81
  94. package/src/__tests__/qdrant-manager.test.ts +28 -2
  95. package/src/__tests__/registry.test.ts +0 -6
  96. package/src/__tests__/relay-server.test.ts +1 -2
  97. package/src/__tests__/runtime-attachment-metadata.test.ts +0 -4
  98. package/src/__tests__/script-proxy-injection-runtime.test.ts +1 -1
  99. package/src/__tests__/secret-onetime-send.test.ts +1 -1
  100. package/src/__tests__/secret-routes-managed-proxy.test.ts +0 -4
  101. package/src/__tests__/secure-keys.test.ts +95 -272
  102. package/src/__tests__/shell-identity.test.ts +96 -6
  103. package/src/__tests__/skill-feature-flags-integration.test.ts +22 -14
  104. package/src/__tests__/skill-feature-flags.test.ts +46 -45
  105. package/src/__tests__/skill-load-feature-flag.test.ts +7 -10
  106. package/src/__tests__/skill-load-inline-command.test.ts +8 -12
  107. package/src/__tests__/skill-load-inline-includes.test.ts +6 -10
  108. package/src/__tests__/skill-load-tool.test.ts +0 -2
  109. package/src/__tests__/skill-memory.test.ts +17 -3
  110. package/src/__tests__/skill-projection-feature-flag.test.ts +33 -29
  111. package/src/__tests__/skills.test.ts +0 -2
  112. package/src/__tests__/slack-inbound-verification.test.ts +0 -4
  113. package/src/__tests__/stale-approval-dedup.test.ts +171 -0
  114. package/src/__tests__/stt-hints.test.ts +437 -0
  115. package/src/__tests__/suggestion-routes.test.ts +1 -32
  116. package/src/__tests__/system-prompt.test.ts +0 -1
  117. package/src/__tests__/task-memory-cleanup.test.ts +14 -0
  118. package/src/__tests__/tool-executor-shell-integration.test.ts +5 -3
  119. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +0 -5
  120. package/src/__tests__/trusted-contact-multichannel.test.ts +0 -4
  121. package/src/__tests__/twilio-routes-twiml.test.ts +139 -1
  122. package/src/__tests__/update-bulletin.test.ts +0 -2
  123. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +6 -9
  124. package/src/__tests__/voice-quality.test.ts +58 -0
  125. package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -7
  126. package/src/__tests__/workspace-migration-015-migrate-credentials-to-keychain.test.ts +252 -0
  127. package/src/__tests__/workspace-migration-016-migrate-credentials-from-keychain.test.ts +220 -0
  128. package/src/__tests__/workspace-migration-down-functions.test.ts +1009 -0
  129. package/src/__tests__/workspace-migrations-runner.test.ts +114 -0
  130. package/src/acp/agent-process.ts +9 -1
  131. package/src/agent/loop.ts +1 -1
  132. package/src/approvals/guardian-request-resolvers.ts +164 -38
  133. package/src/calls/__tests__/tts-text-sanitizer.test.ts +254 -0
  134. package/src/calls/audio-store.test.ts +97 -0
  135. package/src/calls/audio-store.ts +205 -0
  136. package/src/calls/call-controller.ts +90 -8
  137. package/src/calls/call-domain.ts +3 -0
  138. package/src/calls/call-store.ts +10 -3
  139. package/src/calls/fish-audio-client.ts +129 -0
  140. package/src/calls/relay-server.ts +27 -0
  141. package/src/calls/stt-hints.ts +189 -0
  142. package/src/calls/tts-text-sanitizer.ts +61 -0
  143. package/src/calls/twilio-routes.ts +34 -5
  144. package/src/calls/types.ts +1 -0
  145. package/src/calls/voice-ingress-preflight.ts +0 -42
  146. package/src/calls/voice-quality.ts +38 -5
  147. package/src/calls/voice-session-bridge.ts +7 -12
  148. package/src/cli/commands/avatar.ts +2 -2
  149. package/src/cli/commands/config.ts +1 -4
  150. package/src/cli/commands/credentials.ts +128 -82
  151. package/src/cli/commands/doctor.ts +2 -2
  152. package/src/cli/commands/keys.ts +7 -7
  153. package/src/cli/commands/memory.ts +1 -1
  154. package/src/cli/commands/oauth/connections.ts +11 -29
  155. package/src/cli/commands/oauth/index.ts +7 -0
  156. package/src/cli/commands/oauth/platform.ts +525 -0
  157. package/src/cli/commands/platform.ts +3 -3
  158. package/src/cli/lib/daemon-credential-client.ts +284 -0
  159. package/src/cli.ts +1 -1
  160. package/src/config/assistant-feature-flags.ts +186 -5
  161. package/src/config/bundled-skills/AGENTS.md +34 -0
  162. package/src/config/bundled-skills/acp/SKILL.md +10 -0
  163. package/src/config/bundled-skills/app-builder/SKILL.md +0 -4
  164. package/src/config/bundled-skills/messaging/SKILL.md +5 -5
  165. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +2 -2
  166. package/src/config/bundled-skills/phone-calls/TOOLS.json +4 -0
  167. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +1 -0
  168. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +1 -0
  169. package/src/config/bundled-skills/settings/SKILL.md +15 -2
  170. package/src/config/bundled-skills/settings/TOOLS.json +47 -2
  171. package/src/config/bundled-skills/settings/tools/avatar-remove.ts +59 -0
  172. package/src/config/bundled-skills/settings/tools/avatar-update.ts +80 -0
  173. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +42 -0
  174. package/src/config/bundled-skills/slack/SKILL.md +1 -1
  175. package/src/config/bundled-tool-registry.ts +5 -11
  176. package/src/config/defaults.ts +0 -2
  177. package/src/config/env-registry.ts +5 -5
  178. package/src/config/env.ts +21 -14
  179. package/src/config/feature-flag-registry.json +49 -9
  180. package/src/config/loader.ts +106 -42
  181. package/src/config/schema.ts +9 -29
  182. package/src/config/schemas/calls.ts +30 -0
  183. package/src/config/schemas/fish-audio.ts +39 -0
  184. package/src/config/schemas/inference.ts +2 -2
  185. package/src/config/schemas/journal.ts +16 -0
  186. package/src/config/schemas/memory-processing.ts +2 -2
  187. package/src/config/schemas/security.ts +0 -4
  188. package/src/config/types.ts +1 -1
  189. package/src/contacts/contact-store.ts +39 -0
  190. package/src/contacts/types.ts +2 -0
  191. package/src/credential-execution/approval-bridge.ts +1 -0
  192. package/src/credential-execution/executable-discovery.ts +28 -4
  193. package/src/credential-execution/feature-gates.ts +16 -0
  194. package/src/credential-execution/process-manager.ts +38 -0
  195. package/src/credential-execution/startup-timeout.ts +36 -0
  196. package/src/daemon/approval-generators.ts +3 -9
  197. package/src/daemon/assistant-attachments.ts +9 -0
  198. package/src/daemon/config-watcher.ts +5 -0
  199. package/src/daemon/conversation-error.ts +13 -1
  200. package/src/daemon/conversation-memory.ts +1 -2
  201. package/src/daemon/conversation-process.ts +18 -1
  202. package/src/daemon/conversation-surfaces.ts +30 -1
  203. package/src/daemon/conversation-tool-setup.ts +0 -105
  204. package/src/daemon/conversation.ts +21 -1
  205. package/src/daemon/guardian-action-generators.ts +3 -9
  206. package/src/daemon/handlers/config-vercel.ts +92 -0
  207. package/src/daemon/handlers/skills.ts +2 -15
  208. package/src/daemon/install-symlink.ts +195 -0
  209. package/src/daemon/lifecycle.ts +234 -51
  210. package/src/daemon/message-types/conversations.ts +4 -4
  211. package/src/daemon/message-types/diagnostics.ts +3 -22
  212. package/src/daemon/message-types/messages.ts +0 -2
  213. package/src/daemon/message-types/upgrades.ts +8 -0
  214. package/src/daemon/server.ts +32 -95
  215. package/src/events/domain-events.ts +2 -1
  216. package/src/inbound/platform-callback-registration.ts +3 -3
  217. package/src/instrument.ts +8 -5
  218. package/src/memory/app-store.ts +31 -0
  219. package/src/memory/conversation-title-service.ts +50 -1
  220. package/src/memory/db-init.ts +16 -0
  221. package/src/memory/indexer.ts +19 -10
  222. package/src/memory/items-extractor.ts +328 -321
  223. package/src/memory/job-handlers/conversation-starters.ts +4 -1
  224. package/src/memory/job-handlers/summarization.ts +26 -16
  225. package/src/memory/jobs-store.ts +63 -6
  226. package/src/memory/jobs-worker.ts +31 -7
  227. package/src/memory/journal-memory.ts +214 -0
  228. package/src/memory/migrations/001-job-deferrals.ts +19 -0
  229. package/src/memory/migrations/004-entity-relation-dedup.ts +10 -0
  230. package/src/memory/migrations/005-fingerprint-scope-unique.ts +76 -0
  231. package/src/memory/migrations/006-scope-salted-fingerprints.ts +50 -0
  232. package/src/memory/migrations/007-assistant-id-to-self.ts +10 -0
  233. package/src/memory/migrations/008-remove-assistant-id-columns.ts +34 -0
  234. package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +26 -0
  235. package/src/memory/migrations/014-backfill-inbox-thread-state.ts +10 -0
  236. package/src/memory/migrations/015-drop-active-search-index.ts +17 -0
  237. package/src/memory/migrations/019-notification-tables-schema-migration.ts +12 -0
  238. package/src/memory/migrations/020-rename-macos-ios-channel-to-vellum.ts +121 -0
  239. package/src/memory/migrations/024-embedding-vector-blob.ts +74 -0
  240. package/src/memory/migrations/026a-embeddings-nullable-vector-json.ts +82 -0
  241. package/src/memory/migrations/036-normalize-phone-identities.ts +11 -0
  242. package/src/memory/migrations/116-messages-fts.ts +106 -1
  243. package/src/memory/migrations/126-backfill-guardian-principal-id.ts +52 -0
  244. package/src/memory/migrations/127-guardian-principal-id-not-null.ts +77 -0
  245. package/src/memory/migrations/134-contacts-notes-column.ts +13 -0
  246. package/src/memory/migrations/135-backfill-contact-interaction-stats.ts +20 -0
  247. package/src/memory/migrations/136-drop-assistant-id-columns.ts +52 -0
  248. package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +13 -0
  249. package/src/memory/migrations/141-rename-verification-table.ts +54 -0
  250. package/src/memory/migrations/142-rename-verification-session-id-column.ts +25 -0
  251. package/src/memory/migrations/143-rename-guardian-verification-values.ts +35 -0
  252. package/src/memory/migrations/144-rename-voice-to-phone.ts +136 -0
  253. package/src/memory/migrations/145-drop-accounts-table.ts +32 -0
  254. package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +14 -1
  255. package/src/memory/migrations/148-drop-reminders-table.ts +35 -1
  256. package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +69 -1
  257. package/src/memory/migrations/162-guardian-timestamps-epoch-ms.ts +290 -0
  258. package/src/memory/migrations/169-rename-gmail-provider-key-to-google.ts +51 -1
  259. package/src/memory/migrations/174-rename-thread-starters-table.ts +47 -1
  260. package/src/memory/migrations/176-drop-capability-card-state.ts +13 -0
  261. package/src/memory/migrations/180-backfill-inline-attachments-to-disk.ts +16 -0
  262. package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +28 -1
  263. package/src/memory/migrations/190-call-session-skip-disclosure.ts +15 -0
  264. package/src/memory/migrations/191-backfill-audio-attachment-mime-types.ts +64 -0
  265. package/src/memory/migrations/192-contacts-user-file-column.ts +15 -0
  266. package/src/memory/migrations/193-add-source-type-columns.ts +81 -0
  267. package/src/memory/migrations/index.ts +5 -0
  268. package/src/memory/migrations/registry.ts +98 -0
  269. package/src/memory/migrations/validate-migration-state.ts +137 -11
  270. package/src/memory/qdrant-circuit-breaker.ts +9 -0
  271. package/src/memory/qdrant-manager.ts +64 -7
  272. package/src/memory/retriever.test.ts +37 -25
  273. package/src/memory/retriever.ts +24 -49
  274. package/src/memory/schema/calls.ts +1 -0
  275. package/src/memory/schema/contacts.ts +1 -0
  276. package/src/memory/schema/memory-core.ts +2 -0
  277. package/src/memory/search/formatting.ts +7 -44
  278. package/src/memory/search/staleness.ts +4 -0
  279. package/src/memory/search/tier-classifier.ts +10 -2
  280. package/src/memory/search/types.ts +2 -5
  281. package/src/memory/task-memory-cleanup.ts +4 -3
  282. package/src/notifications/adapters/slack.ts +168 -6
  283. package/src/notifications/broadcaster.ts +1 -0
  284. package/src/notifications/copy-composer.ts +59 -2
  285. package/src/notifications/decision-engine.ts +4 -1
  286. package/src/notifications/signal.ts +2 -0
  287. package/src/notifications/types.ts +2 -0
  288. package/src/oauth/connection-resolver.ts +6 -4
  289. package/src/permissions/checker.ts +0 -38
  290. package/src/permissions/shell-identity.ts +76 -22
  291. package/src/permissions/types.ts +4 -2
  292. package/src/platform/client.ts +35 -7
  293. package/src/prompts/journal-context.ts +133 -0
  294. package/src/prompts/persona-resolver.ts +194 -0
  295. package/src/prompts/system-prompt.ts +44 -4
  296. package/src/prompts/templates/SOUL.md +10 -0
  297. package/src/prompts/templates/users/default.md +1 -0
  298. package/src/providers/provider-send-message.ts +3 -32
  299. package/src/providers/registry.ts +29 -179
  300. package/src/providers/types.ts +1 -1
  301. package/src/runtime/access-request-helper.ts +4 -0
  302. package/src/runtime/auth/__tests__/credential-service.test.ts +0 -1
  303. package/src/runtime/auth/__tests__/external-assistant-id.test.ts +13 -68
  304. package/src/runtime/auth/__tests__/guard-tests.test.ts +9 -50
  305. package/src/runtime/auth/external-assistant-id.ts +13 -59
  306. package/src/runtime/auth/route-policy.ts +17 -1
  307. package/src/runtime/auth/token-service.ts +43 -138
  308. package/src/runtime/channel-readiness-service.ts +1 -16
  309. package/src/runtime/gateway-client.ts +47 -4
  310. package/src/runtime/guardian-decision-types.ts +45 -4
  311. package/src/runtime/http-server.ts +31 -3
  312. package/src/runtime/middleware/error-handler.ts +1 -9
  313. package/src/runtime/routes/access-request-decision.ts +2 -2
  314. package/src/runtime/routes/app-management-routes.ts +2 -1
  315. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +219 -30
  316. package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +37 -14
  317. package/src/runtime/routes/audio-routes.ts +40 -0
  318. package/src/runtime/routes/btw-routes.ts +0 -17
  319. package/src/runtime/routes/channel-readiness-routes.ts +9 -4
  320. package/src/runtime/routes/conversation-query-routes.ts +63 -1
  321. package/src/runtime/routes/conversation-routes.ts +4 -44
  322. package/src/runtime/routes/debug-routes.ts +12 -9
  323. package/src/runtime/routes/diagnostics-routes.ts +1 -477
  324. package/src/runtime/routes/guardian-approval-interception.ts +168 -11
  325. package/src/runtime/routes/guardian-approval-prompt.ts +6 -1
  326. package/src/runtime/routes/guardian-approval-reply-helpers.ts +103 -21
  327. package/src/runtime/routes/identity-routes.ts +19 -30
  328. package/src/runtime/routes/inbound-message-handler.ts +31 -1
  329. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +64 -5
  330. package/src/runtime/routes/inbound-stages/background-dispatch.ts +52 -40
  331. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +4 -33
  332. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +1 -1
  333. package/src/runtime/routes/integrations/twilio.ts +52 -10
  334. package/src/runtime/routes/integrations/vercel.ts +89 -0
  335. package/src/runtime/routes/log-export-routes.ts +5 -0
  336. package/src/runtime/routes/memory-item-routes.test.ts +3 -3
  337. package/src/runtime/routes/memory-item-routes.ts +46 -14
  338. package/src/runtime/routes/migration-rollback-routes.ts +209 -0
  339. package/src/runtime/routes/migration-routes.ts +17 -1
  340. package/src/runtime/routes/notification-routes.ts +58 -0
  341. package/src/runtime/routes/schedule-routes.ts +65 -0
  342. package/src/runtime/routes/secret-routes.ts +141 -10
  343. package/src/runtime/routes/settings-routes.ts +41 -1
  344. package/src/runtime/routes/tts-routes.ts +96 -0
  345. package/src/runtime/routes/upgrade-broadcast-routes.ts +26 -2
  346. package/src/runtime/routes/workspace-commit-routes.ts +62 -0
  347. package/src/runtime/routes/workspace-routes.test.ts +22 -1
  348. package/src/runtime/routes/workspace-routes.ts +1 -1
  349. package/src/runtime/routes/workspace-utils.ts +86 -2
  350. package/src/security/ces-credential-client.ts +75 -29
  351. package/src/security/ces-rpc-credential-backend.ts +86 -0
  352. package/src/security/credential-backend.ts +22 -92
  353. package/src/security/keychain-broker-client.ts +10 -2
  354. package/src/security/secure-keys.ts +113 -115
  355. package/src/skills/catalog-install.ts +6 -32
  356. package/src/skills/skill-memory.ts +1 -0
  357. package/src/subagent/manager.ts +2 -5
  358. package/src/telemetry/usage-telemetry-reporter.ts +4 -2
  359. package/src/tools/acp/spawn.ts +78 -1
  360. package/src/tools/calls/call-start.ts +1 -0
  361. package/src/tools/credentials/vault.ts +5 -3
  362. package/src/tools/executor.ts +0 -4
  363. package/src/tools/memory/definitions.ts +3 -2
  364. package/src/tools/memory/handlers.ts +10 -7
  365. package/src/tools/network/script-proxy/session-manager.ts +19 -4
  366. package/src/tools/network/web-fetch.ts +3 -1
  367. package/src/tools/skills/execute.ts +1 -1
  368. package/src/tools/terminal/safe-env.ts +1 -0
  369. package/src/tools/types.ts +0 -8
  370. package/src/util/browser.ts +15 -0
  371. package/src/util/errors.ts +0 -12
  372. package/src/util/platform.ts +4 -51
  373. package/src/workspace/git-service.ts +5 -2
  374. package/src/workspace/migrations/001-avatar-rename.ts +15 -0
  375. package/src/workspace/migrations/003-seed-device-id.ts +17 -1
  376. package/src/workspace/migrations/004-extract-collect-usage-data.ts +33 -0
  377. package/src/workspace/migrations/005-add-send-diagnostics.ts +3 -0
  378. package/src/workspace/migrations/006-services-config.ts +49 -0
  379. package/src/workspace/migrations/007-web-search-provider-rename.ts +27 -0
  380. package/src/workspace/migrations/008-voice-timeout-and-max-steps.ts +3 -0
  381. package/src/workspace/migrations/009-backfill-conversation-disk-view.ts +4 -0
  382. package/src/workspace/migrations/010-app-dir-rename.ts +78 -0
  383. package/src/workspace/migrations/011-backfill-installation-id.ts +11 -0
  384. package/src/workspace/migrations/012-rename-conversation-disk-view-dirs.ts +44 -0
  385. package/src/workspace/migrations/013-repair-conversation-disk-view.ts +5 -0
  386. package/src/workspace/migrations/015-migrate-credentials-to-keychain.ts +153 -0
  387. package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +156 -0
  388. package/src/workspace/migrations/016-migrate-credentials-from-keychain.ts +150 -0
  389. package/src/workspace/migrations/017-seed-persona-dirs.ts +96 -0
  390. package/src/workspace/migrations/018-rekey-compound-credential-keys.ts +184 -0
  391. package/src/workspace/migrations/019-scope-journal-to-guardian.ts +103 -0
  392. package/src/workspace/migrations/migrate-to-workspace-volume.ts +27 -5
  393. package/src/workspace/migrations/registry.ts +12 -0
  394. package/src/workspace/migrations/runner.ts +106 -2
  395. package/src/workspace/migrations/types.ts +4 -0
  396. package/src/workspace/provider-commit-message-generator.ts +12 -21
  397. package/src/__tests__/claude-code-skill-regression.test.ts +0 -206
  398. package/src/__tests__/claude-code-tool-profiles.test.ts +0 -99
  399. package/src/__tests__/diagnostics-export.test.ts +0 -288
  400. package/src/__tests__/local-gateway-health.test.ts +0 -209
  401. package/src/__tests__/provider-fail-open-selection.test.ts +0 -271
  402. package/src/__tests__/provider-failover-actual-provider.test.ts +0 -66
  403. package/src/__tests__/secret-ingress-handler.test.ts +0 -120
  404. package/src/__tests__/swarm-conversation-integration.test.ts +0 -358
  405. package/src/__tests__/swarm-dag-pathological.test.ts +0 -547
  406. package/src/__tests__/swarm-orchestrator.test.ts +0 -463
  407. package/src/__tests__/swarm-plan-validator.test.ts +0 -384
  408. package/src/__tests__/swarm-recursion.test.ts +0 -197
  409. package/src/__tests__/swarm-router-planner.test.ts +0 -234
  410. package/src/__tests__/swarm-tool.test.ts +0 -185
  411. package/src/__tests__/swarm-worker-backend.test.ts +0 -144
  412. package/src/__tests__/swarm-worker-runner.test.ts +0 -288
  413. package/src/commands/__tests__/cc-command-registry.test.ts +0 -396
  414. package/src/commands/cc-command-registry.ts +0 -248
  415. package/src/config/bundled-skills/claude-code/SKILL.md +0 -53
  416. package/src/config/bundled-skills/claude-code/TOOLS.json +0 -47
  417. package/src/config/bundled-skills/claude-code/tools/claude-code.ts +0 -12
  418. package/src/config/bundled-skills/orchestration/SKILL.md +0 -33
  419. package/src/config/bundled-skills/orchestration/TOOLS.json +0 -35
  420. package/src/config/bundled-skills/orchestration/tools/swarm-delegate.ts +0 -12
  421. package/src/config/schemas/swarm.ts +0 -82
  422. package/src/logfire.ts +0 -135
  423. package/src/memory/search/lexical.ts +0 -48
  424. package/src/providers/failover.ts +0 -186
  425. package/src/runtime/local-gateway-health.ts +0 -275
  426. package/src/security/secret-ingress.ts +0 -68
  427. package/src/swarm/backend-claude-code.ts +0 -225
  428. package/src/swarm/checkpoint.ts +0 -137
  429. package/src/swarm/graph-utils.ts +0 -53
  430. package/src/swarm/index.ts +0 -55
  431. package/src/swarm/limits.ts +0 -66
  432. package/src/swarm/orchestrator.ts +0 -424
  433. package/src/swarm/plan-validator.ts +0 -117
  434. package/src/swarm/router-planner.ts +0 -162
  435. package/src/swarm/router-prompts.ts +0 -39
  436. package/src/swarm/synthesizer.ts +0 -81
  437. package/src/swarm/types.ts +0 -72
  438. package/src/swarm/worker-backend.ts +0 -131
  439. package/src/swarm/worker-prompts.ts +0 -80
  440. package/src/swarm/worker-runner.ts +0 -170
  441. package/src/tools/claude-code/claude-code.ts +0 -610
  442. package/src/tools/swarm/delegate.ts +0 -205
@@ -28,22 +28,6 @@ import type { ScopeProfile, TokenAudience, TokenClaims } from "./types.js";
28
28
 
29
29
  const log = getLogger("token-service");
30
30
 
31
- // ---------------------------------------------------------------------------
32
- // Bootstrap sentinel error
33
- // ---------------------------------------------------------------------------
34
-
35
- /**
36
- * Thrown when the gateway's signing-key bootstrap endpoint returns 403,
37
- * indicating that bootstrap has already completed (daemon restart case).
38
- * The caller should fall back to loading the key from disk.
39
- */
40
- export class BootstrapAlreadyCompleted extends Error {
41
- constructor() {
42
- super("Gateway signing key bootstrap already completed");
43
- this.name = "BootstrapAlreadyCompleted";
44
- }
45
- }
46
-
47
31
  // ---------------------------------------------------------------------------
48
32
  // Signing key management
49
33
  // ---------------------------------------------------------------------------
@@ -58,28 +42,44 @@ function getSigningKeyPath(): string {
58
42
  return join(getRootDir(), "protected", "actor-token-signing-key");
59
43
  }
60
44
 
45
+ /**
46
+ * Load a signing key from disk. Returns the key buffer if found and valid,
47
+ * or undefined if the file does not exist or is invalid.
48
+ *
49
+ * Used in the Docker 403-fallback path where generating a new key would
50
+ * create a mismatch with the gateway's already-bootstrapped key.
51
+ */
52
+ export function loadSigningKey(): Buffer | undefined {
53
+ const keyPath = getSigningKeyPath();
54
+ if (!existsSync(keyPath)) {
55
+ return undefined;
56
+ }
57
+ try {
58
+ const raw = readFileSync(keyPath);
59
+ if (raw.length === 32) {
60
+ log.info("Auth signing key loaded from disk");
61
+ return raw;
62
+ }
63
+ log.warn("Signing key file has unexpected length");
64
+ return undefined;
65
+ } catch (err) {
66
+ log.warn({ err }, "Failed to read signing key file");
67
+ return undefined;
68
+ }
69
+ }
70
+
61
71
  /**
62
72
  * Load a signing key from disk or generate and persist a new one.
63
73
  * Uses atomic-write + chmod 0o600 for safe persistence.
64
74
  */
65
75
  export function loadOrCreateSigningKey(): Buffer {
66
- const keyPath = getSigningKeyPath();
67
-
68
- // Try to load existing key
69
- if (existsSync(keyPath)) {
70
- try {
71
- const raw = readFileSync(keyPath);
72
- if (raw.length === 32) {
73
- log.info("Auth signing key loaded from disk");
74
- return raw;
75
- }
76
- log.warn("Signing key file has unexpected length, regenerating");
77
- } catch (err) {
78
- log.warn({ err }, "Failed to read signing key file, regenerating");
79
- }
76
+ const existing = loadSigningKey();
77
+ if (existing) {
78
+ return existing;
80
79
  }
81
80
 
82
81
  // Generate and persist a new key
82
+ const keyPath = getSigningKeyPath();
83
83
  const newKey = randomBytes(32);
84
84
  const dir = dirname(keyPath);
85
85
  if (!existsSync(dir)) {
@@ -94,120 +94,25 @@ export function loadOrCreateSigningKey(): Buffer {
94
94
  return newKey;
95
95
  }
96
96
 
97
- /**
98
- * Fetch the shared signing key from the gateway's bootstrap endpoint.
99
- *
100
- * Used in Docker mode where the gateway owns the signing key and the daemon
101
- * must fetch it at startup. Retries up to 30 times with 1s intervals to
102
- * tolerate gateway startup delays.
103
- *
104
- * @returns A 32-byte Buffer containing the signing key.
105
- * @throws {BootstrapAlreadyCompleted} If the gateway returns 403 (bootstrap
106
- * already completed — daemon restart case). Caller should fall back to
107
- * loading the key from disk.
108
- * @throws {Error} If the gateway is unreachable after all retry attempts.
109
- */
110
- export async function fetchSigningKeyFromGateway(): Promise<Buffer> {
111
- const gatewayUrl = process.env.GATEWAY_INTERNAL_URL;
112
- if (!gatewayUrl) {
113
- throw new Error("GATEWAY_INTERNAL_URL not set — cannot fetch signing key");
114
- }
115
-
116
- const maxAttempts = 30;
117
- const intervalMs = 1000;
118
-
119
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
120
- let resp: Response | undefined;
121
- try {
122
- resp = await fetch(`${gatewayUrl}/internal/signing-key-bootstrap`, {
123
- signal: AbortSignal.timeout(5000),
124
- });
125
- } catch (err) {
126
- log.warn(
127
- { err, attempt },
128
- "Signing key bootstrap: connection failed, retrying",
129
- );
130
- await Bun.sleep(intervalMs);
131
- continue;
132
- }
133
-
134
- if (resp.ok) {
135
- const body = (await resp.json()) as { key: string };
136
- const keyBuf = Buffer.from(body.key, "hex");
137
- if (keyBuf.length !== 32) {
138
- throw new Error(`Invalid signing key length: ${keyBuf.length}`);
139
- }
140
- log.info("Signing key fetched from gateway bootstrap endpoint");
141
- return keyBuf;
142
- }
143
-
144
- if (resp.status === 403) {
145
- // Bootstrap already completed — fall through to file-based load.
146
- // This happens on daemon restart when the gateway lockfile persists.
147
- log.info(
148
- "Gateway signing key bootstrap already completed — loading from disk",
149
- );
150
- throw new BootstrapAlreadyCompleted();
151
- }
152
-
153
- log.warn(
154
- { status: resp.status, attempt },
155
- "Signing key bootstrap: gateway not ready, retrying",
156
- );
157
-
158
- await Bun.sleep(intervalMs);
159
- }
160
-
161
- throw new Error("Signing key bootstrap: timed out waiting for gateway");
162
- }
163
-
164
- /**
165
- * Persist a signing key to disk using an atomic-write pattern.
166
- * Used after fetching the key from the gateway so daemon restarts can
167
- * load it from disk when the gateway returns 403.
168
- */
169
- function persistSigningKey(key: Buffer): void {
170
- const keyPath = getSigningKeyPath();
171
- const dir = dirname(keyPath);
172
- if (!existsSync(dir)) {
173
- mkdirSync(dir, { recursive: true });
174
- }
175
- const tmpPath = keyPath + ".tmp." + process.pid;
176
- writeFileSync(tmpPath, key, { mode: 0o600 });
177
- renameSync(tmpPath, keyPath);
178
- chmodSync(keyPath, 0o600);
179
- }
180
-
181
97
  /**
182
98
  * Resolve the signing key for the current environment.
183
99
  *
184
- * In Docker mode (IS_CONTAINERIZED=true + GATEWAY_INTERNAL_URL set), fetches
185
- * the key from the gateway's bootstrap endpoint and persists it locally for
186
- * restart resilience. On daemon restart (gateway returns 403), falls back to
187
- * loading the key from disk.
188
- *
189
- * In local mode, delegates to the existing file-based loadOrCreateSigningKey().
100
+ * Resolution order:
101
+ * 1. ACTOR_TOKEN_SIGNING_KEY env var (hex-encoded, set by CLI for Docker)
102
+ * 2. File-based load/create (~/.vellum/protected/actor-token-signing-key)
190
103
  */
191
- export async function resolveSigningKey(): Promise<Buffer> {
192
- const isContainerized = process.env.IS_CONTAINERIZED === "true";
193
- const gatewayUrl = process.env.GATEWAY_INTERNAL_URL;
194
-
195
- if (isContainerized && gatewayUrl) {
196
- try {
197
- const key = await fetchSigningKeyFromGateway();
198
- // Persist locally so daemon restarts (where gateway returns 403) load from disk.
199
- persistSigningKey(key);
200
- return key;
201
- } catch (err) {
202
- if (err instanceof BootstrapAlreadyCompleted) {
203
- // Gateway already bootstrapped (daemon restart) — load from disk.
204
- return loadOrCreateSigningKey();
205
- }
206
- throw err;
104
+ export function resolveSigningKey(): Buffer {
105
+ const envKey = process.env.ACTOR_TOKEN_SIGNING_KEY;
106
+ if (envKey) {
107
+ if (!/^[0-9a-f]{64}$/i.test(envKey)) {
108
+ throw new Error(
109
+ `Invalid ACTOR_TOKEN_SIGNING_KEY: expected 64 hex characters, got ${envKey.length} chars`,
110
+ );
207
111
  }
112
+ log.info("Signing key loaded from ACTOR_TOKEN_SIGNING_KEY env var");
113
+ return Buffer.from(envKey, "hex");
208
114
  }
209
115
 
210
- // Local mode: use file-based load/create (unchanged behavior).
211
116
  return loadOrCreateSigningKey();
212
117
  }
213
118
 
@@ -246,7 +151,7 @@ export function isSigningKeyInitialized(): boolean {
246
151
 
247
152
  /**
248
153
  * Returns a short hex fingerprint of the current signing key.
249
- * Used by daemon_status to let clients detect instance switches.
154
+ * Used by assistant_status to let clients detect instance switches.
250
155
  */
251
156
  export function getSigningKeyFingerprint(): string {
252
157
  return createHash("sha256")
@@ -15,7 +15,6 @@ import type {
15
15
  ReadinessCheckResult,
16
16
  SetupStatus,
17
17
  } from "./channel-readiness-types.js";
18
- import { probeLocalGatewayHealth } from "./local-gateway-health.js";
19
18
 
20
19
  /** Remote check results are cached for 5 minutes before being considered stale. */
21
20
  export const REMOTE_TTL_MS = 5 * 60 * 1000;
@@ -82,7 +81,7 @@ const voiceProbe: ChannelProbe = {
82
81
  const hasPhone = !!resolveTwilioPhoneNumber();
83
82
  const ingress = checkIngress();
84
83
 
85
- const checks: ReadinessCheckResult[] = [
84
+ return [
86
85
  check(
87
86
  "twilio_credentials",
88
87
  hasCreds,
@@ -97,20 +96,6 @@ const voiceProbe: ChannelProbe = {
97
96
  ),
98
97
  ingress,
99
98
  ];
100
-
101
- if (ingress.passed) {
102
- const gw = await probeLocalGatewayHealth();
103
- checks.push(
104
- check(
105
- "gateway_health",
106
- gw.healthy,
107
- `Local gateway is serving requests at ${gw.target}`,
108
- `Local gateway is not serving requests at ${gw.target}${gw.error ? `: ${gw.error}` : ""}`,
109
- ),
110
- );
111
- }
112
-
113
- return checks;
114
99
  },
115
100
  };
116
101
 
@@ -6,6 +6,24 @@ import type { RuntimeAttachmentMetadata } from "./http-types.js";
6
6
 
7
7
  const log = getLogger("gateway-client");
8
8
 
9
+ /**
10
+ * Error thrown when the gateway returns a non-OK response for channel delivery.
11
+ * Carries the optional `userMessage` field from the gateway so callers can
12
+ * surface actionable error text to end-users.
13
+ */
14
+ export class ChannelDeliveryError extends Error {
15
+ readonly statusCode: number;
16
+ /** A user-facing error message from the gateway, if available. */
17
+ readonly userMessage?: string;
18
+
19
+ constructor(statusCode: number, body: string, userMessage?: string) {
20
+ super(`Channel reply delivery failed (${statusCode}): ${body}`);
21
+ this.name = "ChannelDeliveryError";
22
+ this.statusCode = statusCode;
23
+ this.userMessage = userMessage;
24
+ }
25
+ }
26
+
9
27
  const DELIVERY_TIMEOUT_MS = 30_000;
10
28
  const MANAGED_OUTBOUND_SEND_PATH =
11
29
  "/v1/internal/managed-gateway/outbound-send/";
@@ -37,6 +55,8 @@ export interface ChannelReplyPayload {
37
55
  useBlocks?: boolean;
38
56
  /** When provided, add or remove an emoji reaction on a message. */
39
57
  reaction?: { action: "add" | "remove"; name: string; messageTs: string };
58
+ /** When provided, set or clear the Slack Assistants API thread status. */
59
+ assistantThreadStatus?: { channel: string; threadTs: string; status: string };
40
60
  }
41
61
 
42
62
  export interface ChannelDeliveryResult {
@@ -81,13 +101,36 @@ export async function deliverChannelReply(
81
101
 
82
102
  if (!response.ok) {
83
103
  const body = await response.text().catch(() => "<unreadable>");
104
+
105
+ // Try to extract userMessage from JSON error responses (e.g. from the
106
+ // Slack delivery endpoint) so callers can surface actionable errors.
107
+ let userMessage: string | undefined;
108
+ try {
109
+ const parsed = JSON.parse(body) as { userMessage?: string };
110
+ if (typeof parsed.userMessage === "string") {
111
+ userMessage = parsed.userMessage;
112
+ }
113
+ } catch {
114
+ // Body wasn't JSON — that's fine, userMessage stays undefined.
115
+ }
116
+
84
117
  log.error(
85
- { status: response.status, body, callbackUrl, chatId: payload.chatId },
118
+ {
119
+ status: response.status,
120
+ body,
121
+ callbackUrl,
122
+ chatId: payload.chatId,
123
+ ...(userMessage && { userMessage }),
124
+ },
86
125
  "Channel reply delivery failed",
87
126
  );
88
- throw new Error(
89
- `Channel reply delivery failed (${response.status}): ${body}`,
90
- );
127
+ if (userMessage) {
128
+ log.warn(
129
+ { chatId: payload.chatId, userMessage },
130
+ "Gateway returned actionable error for user",
131
+ );
132
+ }
133
+ throw new ChannelDeliveryError(response.status, body, userMessage);
91
134
  }
92
135
 
93
136
  const result: ChannelDeliveryResult = { ok: true };
@@ -38,6 +38,8 @@ export interface GuardianDecisionAction {
38
38
  action: string;
39
39
  /** Human-readable label for the action. */
40
40
  label: string;
41
+ /** Short explanation shown in rich-UI legends (Telegram, Slack). */
42
+ description?: string;
41
43
  }
42
44
 
43
45
  // ---------------------------------------------------------------------------
@@ -46,14 +48,27 @@ export interface GuardianDecisionAction {
46
48
 
47
49
  /** Canonical set of all guardian decision actions with their labels. */
48
50
  export const GUARDIAN_DECISION_ACTIONS = {
49
- approve_once: { action: "approve_once", label: "Approve once" },
50
- approve_10m: { action: "approve_10m", label: "Allow 10 min" },
51
+ approve_once: {
52
+ action: "approve_once",
53
+ label: "Approve once",
54
+ description: "This tool, this call only",
55
+ },
56
+ approve_10m: {
57
+ action: "approve_10m",
58
+ label: "Allow 10 min",
59
+ description: "All tools for 10 minutes",
60
+ },
51
61
  approve_conversation: {
52
62
  action: "approve_conversation",
53
63
  label: "Allow conversation",
64
+ description: "All tools for this conversation",
65
+ },
66
+ approve_always: {
67
+ action: "approve_always",
68
+ label: "Approve always",
69
+ description: "This tool, permanently",
54
70
  },
55
- approve_always: { action: "approve_always", label: "Approve always" },
56
- reject: { action: "reject", label: "Reject" },
71
+ reject: { action: "reject", label: "Reject", description: "Deny this call" },
57
72
  } as const satisfies Record<string, GuardianDecisionAction>;
58
73
 
59
74
  /**
@@ -89,6 +104,32 @@ export function buildDecisionActions(opts?: {
89
104
  ];
90
105
  }
91
106
 
107
+ /**
108
+ * Build a compact legend string explaining each action, for rich-UI channels
109
+ * (Telegram, Slack) where buttons are shown but their scope isn't obvious.
110
+ *
111
+ * Accepts either `GuardianDecisionAction[]` or action ID strings and looks up
112
+ * descriptions from the canonical constants.
113
+ */
114
+ export function buildActionLegend(
115
+ actionIds: readonly (string | { action?: string; id?: string })[],
116
+ ): string {
117
+ const lookup = GUARDIAN_DECISION_ACTIONS as Record<
118
+ string,
119
+ GuardianDecisionAction | undefined
120
+ >;
121
+ const lines = actionIds
122
+ .map((a) => {
123
+ const id = typeof a === "string" ? a : (a.action ?? a.id ?? "");
124
+ const canonical = lookup[id];
125
+ return canonical?.description
126
+ ? `• *${canonical.label}* — ${canonical.description}`
127
+ : null;
128
+ })
129
+ .filter(Boolean);
130
+ return lines.length > 0 ? lines.join("\n") : "";
131
+ }
132
+
92
133
  /**
93
134
  * Build the plain-text fallback instruction string that matches the given
94
135
  * set of decision actions. Ensures the text always includes parser-compatible
@@ -106,6 +106,7 @@ import { handleServePage } from "./routes/app-routes.js";
106
106
  import { appRouteDefinitions } from "./routes/app-routes.js";
107
107
  import { approvalRouteDefinitions } from "./routes/approval-routes.js";
108
108
  import { attachmentRouteDefinitions } from "./routes/attachment-routes.js";
109
+ import { handleGetAudio } from "./routes/audio-routes.js";
109
110
  import { avatarRouteDefinitions } from "./routes/avatar-routes.js";
110
111
  import { brainGraphRouteDefinitions } from "./routes/brain-graph-routes.js";
111
112
  import { btwRouteDefinitions } from "./routes/btw-routes.js";
@@ -144,16 +145,22 @@ import { handleGuardianRefresh } from "./routes/guardian-refresh-routes.js";
144
145
  import { hostBashRouteDefinitions } from "./routes/host-bash-routes.js";
145
146
  import { hostCuRouteDefinitions } from "./routes/host-cu-routes.js";
146
147
  import { hostFileRouteDefinitions } from "./routes/host-file-routes.js";
147
- import { handleHealth } from "./routes/identity-routes.js";
148
- import { identityRouteDefinitions } from "./routes/identity-routes.js";
148
+ import {
149
+ handleHealth,
150
+ handleReadyz,
151
+ identityRouteDefinitions,
152
+ } from "./routes/identity-routes.js";
149
153
  import { slackChannelRouteDefinitions } from "./routes/integrations/slack/channel.js";
150
154
  import { slackShareRouteDefinitions } from "./routes/integrations/slack/share.js";
151
155
  import { telegramRouteDefinitions } from "./routes/integrations/telegram.js";
152
156
  import { twilioRouteDefinitions } from "./routes/integrations/twilio.js";
157
+ import { vercelRouteDefinitions } from "./routes/integrations/vercel.js";
153
158
  import { inviteRouteDefinitions } from "./routes/invite-routes.js";
154
159
  import { logExportRouteDefinitions } from "./routes/log-export-routes.js";
155
160
  import { memoryItemRouteDefinitions } from "./routes/memory-item-routes.js";
161
+ import { migrationRollbackRouteDefinitions } from "./routes/migration-rollback-routes.js";
156
162
  import { migrationRouteDefinitions } from "./routes/migration-routes.js";
163
+ import { notificationRouteDefinitions } from "./routes/notification-routes.js";
157
164
  import { oauthAppsRouteDefinitions } from "./routes/oauth-apps.js";
158
165
  import type { PairingHandlerContext } from "./routes/pairing-routes.js";
159
166
  import {
@@ -172,10 +179,12 @@ import { surfaceContentRouteDefinitions } from "./routes/surface-content-routes.
172
179
  import { telemetryRouteDefinitions } from "./routes/telemetry-routes.js";
173
180
  import { traceEventRouteDefinitions } from "./routes/trace-event-routes.js";
174
181
  import { trustRulesRouteDefinitions } from "./routes/trust-rules-routes.js";
182
+ import { ttsRouteDefinitions } from "./routes/tts-routes.js";
175
183
  import { upgradeBroadcastRouteDefinitions } from "./routes/upgrade-broadcast-routes.js";
176
184
  import { usageRouteDefinitions } from "./routes/usage-routes.js";
177
185
  import { watchRouteDefinitions } from "./routes/watch-routes.js";
178
186
  import { workItemRouteDefinitions } from "./routes/work-items-routes.js";
187
+ import { workspaceCommitRouteDefinitions } from "./routes/workspace-commit-routes.js";
179
188
  import { workspaceRouteDefinitions } from "./routes/workspace-routes.js";
180
189
 
181
190
  // Re-export for consumers
@@ -464,7 +473,10 @@ export class RuntimeHttpServer {
464
473
  server.timeout(req, 1800);
465
474
  // Skip request logging for health-check probes to reduce log noise.
466
475
  const url = new URL(req.url);
467
- if (url.pathname === "/healthz" && req.method === "GET") {
476
+ if (
477
+ (url.pathname === "/healthz" || url.pathname === "/readyz") &&
478
+ req.method === "GET"
479
+ ) {
468
480
  return this.routeRequest(req, server);
469
481
  }
470
482
  return withRequestLogging(req, () => this.routeRequest(req, server));
@@ -481,6 +493,10 @@ export class RuntimeHttpServer {
481
493
  return handleHealth();
482
494
  }
483
495
 
496
+ if (path === "/readyz" && req.method === "GET") {
497
+ return handleReadyz();
498
+ }
499
+
484
500
  // WebSocket upgrade for the Chrome extension browser relay.
485
501
  if (
486
502
  path === "/v1/browser-relay" &&
@@ -503,6 +519,13 @@ export class RuntimeHttpServer {
503
519
  const twilioResponse = await this.handleTwilioWebhook(req, path);
504
520
  if (twilioResponse) return twilioResponse;
505
521
 
522
+ // Audio serving endpoint — before auth check because Twilio
523
+ // fetches these URLs directly. The audioId is an unguessable UUID.
524
+ const audioMatch = path.match(/^\/v1\/audio\/([^/]+)$/);
525
+ if (audioMatch && req.method === "GET") {
526
+ return handleGetAudio(audioMatch[1]);
527
+ }
528
+
506
529
  // Pairing endpoints (unauthenticated, secret-gated)
507
530
  if (path === "/v1/pairing/request" && req.method === "POST") {
508
531
  return await handlePairingRequest(req, this.pairingContext);
@@ -920,6 +943,8 @@ export class RuntimeHttpServer {
920
943
  }),
921
944
  ...identityRouteDefinitions(),
922
945
  ...upgradeBroadcastRouteDefinitions(),
946
+ ...workspaceCommitRouteDefinitions(),
947
+ ...migrationRollbackRouteDefinitions(),
923
948
  ...debugRouteDefinitions(),
924
949
  ...usageRouteDefinitions(),
925
950
  ...telemetryRouteDefinitions(),
@@ -931,6 +956,7 @@ export class RuntimeHttpServer {
931
956
  ...scheduleRouteDefinitions({
932
957
  sendMessageDeps: this.sendMessageDeps,
933
958
  }),
959
+ ...notificationRouteDefinitions(),
934
960
  ...diagnosticsRouteDefinitions(),
935
961
  ...logExportRouteDefinitions(),
936
962
  ...documentRouteDefinitions(),
@@ -961,6 +987,7 @@ export class RuntimeHttpServer {
961
987
  }
962
988
  : undefined,
963
989
  }),
990
+ ...ttsRouteDefinitions(),
964
991
 
965
992
  // Browser relay — not extracted into a domain module because
966
993
  // these two routes depend on the in-process extensionRelayServer
@@ -1165,6 +1192,7 @@ export class RuntimeHttpServer {
1165
1192
  ...slackChannelRouteDefinitions(),
1166
1193
  ...slackShareRouteDefinitions(),
1167
1194
  ...twilioRouteDefinitions(),
1195
+ ...vercelRouteDefinitions(),
1168
1196
  ...channelReadinessRouteDefinitions(),
1169
1197
  ...oauthAppsRouteDefinitions(),
1170
1198
  ...attachmentRouteDefinitions(),
@@ -4,7 +4,6 @@
4
4
 
5
5
  import {
6
6
  ConfigError,
7
- IngressBlockedError,
8
7
  ProviderNotConfiguredError,
9
8
  } from "../../util/errors.js";
10
9
  import { getLogger } from "../../util/logger.js";
@@ -14,7 +13,7 @@ const log = getLogger("runtime-http");
14
13
 
15
14
  /**
16
15
  * Wrap an async endpoint handler with standard error handling.
17
- * Catches IngressBlockedError (422), ConfigError (422), and generic errors (500).
16
+ * Catches ConfigError (422) and generic errors (500).
18
17
  */
19
18
  export async function withErrorHandling(
20
19
  endpoint: string,
@@ -23,13 +22,6 @@ export async function withErrorHandling(
23
22
  try {
24
23
  return await handler();
25
24
  } catch (err) {
26
- if (err instanceof IngressBlockedError) {
27
- log.warn(
28
- { endpoint, detectedTypes: err.detectedTypes },
29
- "Blocked HTTP request containing secrets",
30
- );
31
- return httpError("UNPROCESSABLE_ENTITY", err.message, 422);
32
- }
33
25
  if (err instanceof ProviderNotConfiguredError) {
34
26
  log.warn({ err, endpoint }, "No LLM provider configured");
35
27
  return httpError(
@@ -116,7 +116,7 @@ export async function deliverVerificationCodeToGuardian(params: {
116
116
  }): Promise<DeliveryResult> {
117
117
  const text =
118
118
  `You approved access for ${params.requesterIdentifier}. ` +
119
- `Give them this verification code: ${params.verificationCode}. ` +
119
+ `Give them this verification code: \`${params.verificationCode}\`. ` +
120
120
  `The code expires in 10 minutes.`;
121
121
 
122
122
  try {
@@ -189,7 +189,7 @@ export async function deliverVerificationCodeToRequester(params: {
189
189
  }): Promise<DeliveryResult> {
190
190
  const text =
191
191
  `Great news — your access request was approved! ` +
192
- `Your verification code is: ${params.verificationCode}. ` +
192
+ `Your verification code is: \`${params.verificationCode}\`. ` +
193
193
  `Reply with it here to complete verification. The code expires in 10 minutes.`;
194
194
 
195
195
  const target = resolveRequesterTarget(params);
@@ -36,6 +36,7 @@ import {
36
36
  getApp,
37
37
  getAppDirPath,
38
38
  getAppPreview,
39
+ inlineDistAssets,
39
40
  isMultifileApp,
40
41
  listApps,
41
42
  queryAppRecords,
@@ -684,7 +685,7 @@ export function appManagementRouteDefinitions(): RouteDefinition[] {
684
685
  }
685
686
  }
686
687
  if (existsSync(distIndex)) {
687
- html = readFileSync(distIndex, "utf-8");
688
+ html = inlineDistAssets(appDir, readFileSync(distIndex, "utf-8"));
688
689
  } else {
689
690
  html = `<p>App compilation failed. Edit a source file to trigger a rebuild.</p>`;
690
691
  }