@vellumai/assistant 0.8.0 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (991) hide show
  1. package/AGENTS.md +11 -0
  2. package/ARCHITECTURE.md +2 -7
  3. package/Dockerfile +80 -5
  4. package/README.md +2 -2
  5. package/bun.lock +11 -1
  6. package/docker-entrypoint.sh +21 -0
  7. package/docker-init-apt-root.sh +94 -0
  8. package/docker-kata-apt-env.sh +39 -0
  9. package/docs/plugins.md +88 -47
  10. package/docs/skills.md +9 -7
  11. package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +420 -0
  12. package/eslint-rules/cli-no-daemon-internals.js +283 -0
  13. package/eslint.config.mjs +12 -0
  14. package/examples/plugins/echo/README.md +27 -27
  15. package/examples/plugins/echo/package.json +3 -0
  16. package/examples/plugins/echo/register.ts +31 -31
  17. package/knip.json +2 -1
  18. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
  19. package/node_modules/@vellumai/slack-text/src/index.test.ts +114 -14
  20. package/node_modules/@vellumai/slack-text/src/index.ts +82 -18
  21. package/openapi.yaml +4462 -991
  22. package/package.json +5 -1
  23. package/scripts/generate-openapi.ts +135 -14
  24. package/scripts/sync-llm-catalog.ts +165 -0
  25. package/scripts/sync-web-search-catalog.ts +129 -0
  26. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +169 -0
  27. package/src/__tests__/agent-image-optimize.test.ts +11 -3
  28. package/src/__tests__/agent-loop-override-profile.test.ts +26 -1
  29. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +131 -0
  30. package/src/__tests__/anthropic-provider.test.ts +137 -2
  31. package/src/__tests__/app-builder-tool-scripts.test.ts +9 -3
  32. package/src/__tests__/app-control-flow.test.ts +7 -0
  33. package/src/__tests__/app-executors.test.ts +220 -4
  34. package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
  35. package/src/__tests__/auto-analysis-end-to-end.test.ts +35 -0
  36. package/src/__tests__/avatar-identity-sync.test.ts +87 -0
  37. package/src/__tests__/background-workers-disk-pressure.test.ts +11 -22
  38. package/src/__tests__/btw-routes.test.ts +1 -0
  39. package/src/__tests__/bundled-asset.test.ts +6 -6
  40. package/src/__tests__/call-site-routing-provider.test.ts +172 -45
  41. package/src/__tests__/cancel-resolves-conversation-key.test.ts +44 -3
  42. package/src/__tests__/channel-availability-routes.test.ts +206 -0
  43. package/src/__tests__/channel-delivery-store.test.ts +289 -1
  44. package/src/__tests__/channel-policy.test.ts +12 -0
  45. package/src/__tests__/checker.test.ts +89 -0
  46. package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -1
  47. package/src/__tests__/clawhub.test.ts +75 -16
  48. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +35 -7
  49. package/src/__tests__/compact-event-conversation-id-guard.test.ts +33 -5
  50. package/src/__tests__/compaction-strip-metadata-clear.test.ts +26 -1
  51. package/src/__tests__/compactor-tail-resolution.test.ts +41 -0
  52. package/src/__tests__/config-loader-backfill.test.ts +526 -102
  53. package/src/__tests__/config-loader-corrupt.test.ts +68 -0
  54. package/src/__tests__/config-loader-platform-defaults.test.ts +77 -23
  55. package/src/__tests__/config-schema-cmd.test.ts +63 -29
  56. package/src/__tests__/config-schema.test.ts +35 -3
  57. package/src/__tests__/config-set-platform-guard.test.ts +75 -152
  58. package/src/__tests__/config-set-route.test.ts +278 -0
  59. package/src/__tests__/config-sounds-sync.test.ts +97 -0
  60. package/src/__tests__/config-watcher-skill-reseed.test.ts +453 -0
  61. package/src/__tests__/config-watcher.test.ts +6 -0
  62. package/src/__tests__/contacts-tools.test.ts +51 -199
  63. package/src/__tests__/context-search-agent-protocol.test.ts +21 -2
  64. package/src/__tests__/context-search-agent-runner.test.ts +22 -138
  65. package/src/__tests__/context-search-conversations-source.test.ts +159 -18
  66. package/src/__tests__/context-search-fanout.test.ts +20 -157
  67. package/src/__tests__/context-search-memory-v2-source.test.ts +3 -4
  68. package/src/__tests__/context-search-types.test.ts +7 -2
  69. package/src/__tests__/context-search-workspace-source.test.ts +7 -0
  70. package/src/__tests__/context-token-estimator.test.ts +1 -0
  71. package/src/__tests__/conversation-abort-tool-results.test.ts +4 -1
  72. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
  73. package/src/__tests__/conversation-agent-loop-overflow.test.ts +93 -92
  74. package/src/__tests__/conversation-agent-loop.test.ts +2 -0
  75. package/src/__tests__/conversation-crud-inference-profile.test.ts +100 -0
  76. package/src/__tests__/conversation-error.test.ts +80 -3
  77. package/src/__tests__/conversation-fork-crud.test.ts +323 -1
  78. package/src/__tests__/conversation-inference-profile-route.test.ts +54 -18
  79. package/src/__tests__/conversation-init.benchmark.test.ts +1 -0
  80. package/src/__tests__/conversation-lifecycle.test.ts +297 -0
  81. package/src/__tests__/conversation-message-sync-tags.test.ts +97 -0
  82. package/src/__tests__/conversation-pairing.test.ts +54 -0
  83. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +100 -1
  84. package/src/__tests__/conversation-process-callsite.test.ts +25 -2
  85. package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -1
  86. package/src/__tests__/conversation-queue.test.ts +4 -1
  87. package/src/__tests__/conversation-runtime-assembly.test.ts +80 -13
  88. package/src/__tests__/conversation-slash-commands.test.ts +194 -2
  89. package/src/__tests__/conversation-slash-queue.test.ts +59 -1
  90. package/src/__tests__/conversation-slash-unknown.test.ts +4 -1
  91. package/src/__tests__/conversation-surfaces-app-control.test.ts +323 -3
  92. package/src/__tests__/conversation-surfaces-table-action.test.ts +360 -0
  93. package/src/__tests__/conversation-sync-tags.test.ts +235 -0
  94. package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
  95. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
  96. package/src/__tests__/credential-security-invariants.test.ts +8 -8
  97. package/src/__tests__/daemon-credential-client.test.ts +56 -1
  98. package/src/__tests__/db-activation-state-fk-cascade.test.ts +132 -0
  99. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +37 -0
  100. package/src/__tests__/db-memory-graph-event-date-repair.test.ts +43 -20
  101. package/src/__tests__/db-proxy-transaction.test.ts +206 -0
  102. package/src/__tests__/db-slack-external-content-normalization.test.ts +301 -0
  103. package/src/__tests__/delete-managed-skill-tool.test.ts +55 -13
  104. package/src/__tests__/disk-pressure-tools.test.ts +1 -0
  105. package/src/__tests__/dm-backfill.test.ts +121 -10
  106. package/src/__tests__/document-tool-security.test.ts +258 -0
  107. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
  108. package/src/__tests__/edit-propagation.test.ts +33 -0
  109. package/src/__tests__/empty-response-pipeline.test.ts +0 -4
  110. package/src/__tests__/external-plugin-loader.test.ts +482 -0
  111. package/src/__tests__/filing-service.test.ts +163 -3
  112. package/src/__tests__/fixtures/mock-chrome-extension.ts +5 -0
  113. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  114. package/src/__tests__/get-skill-detail-audit.test.ts +0 -4
  115. package/src/__tests__/graph-extraction-event-date.test.ts +34 -0
  116. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +42 -69
  117. package/src/__tests__/heartbeat-disk-pressure.test.ts +21 -8
  118. package/src/__tests__/heartbeat-service.test.ts +50 -233
  119. package/src/__tests__/helpers/tar-fixtures.ts +39 -0
  120. package/src/__tests__/helpers/wait-for.ts +21 -0
  121. package/src/__tests__/history-repair-pipeline.test.ts +0 -3
  122. package/src/__tests__/history-repair.test.ts +162 -0
  123. package/src/__tests__/host-app-control-proxy.test.ts +365 -1
  124. package/src/__tests__/host-app-control-routes.test.ts +247 -1
  125. package/src/__tests__/host-browser-proxy.test.ts +416 -20
  126. package/src/__tests__/host-browser-routes.test.ts +325 -33
  127. package/src/__tests__/host-proxy-preactivation.test.ts +211 -0
  128. package/src/__tests__/image-credentials.test.ts +1 -1
  129. package/src/__tests__/inbound-slack-persistence.test.ts +2 -0
  130. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +246 -0
  131. package/src/__tests__/inference-profile-reaper.test.ts +156 -0
  132. package/src/__tests__/inference-profile-session-handler.test.ts +410 -0
  133. package/src/__tests__/inference-profile-session-ipc.test.ts +248 -0
  134. package/src/__tests__/injector-chain.test.ts +10 -8
  135. package/src/__tests__/inline-skill-load-permissions.test.ts +6 -1
  136. package/src/__tests__/install-skill-routing.test.ts +157 -39
  137. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +107 -3
  138. package/src/__tests__/list-messages-page-latest.test.ts +55 -0
  139. package/src/__tests__/llm-call-pipeline.test.ts +0 -3
  140. package/src/__tests__/llm-callsite-catalog.test.ts +20 -1
  141. package/src/__tests__/llm-catalog-parity.test.ts +190 -2
  142. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +222 -0
  143. package/src/__tests__/llm-request-log-source-factory.test.ts +100 -0
  144. package/src/__tests__/llm-resolver.test.ts +46 -0
  145. package/src/__tests__/llm-usage-store.test.ts +114 -0
  146. package/src/__tests__/managed-profile-guard.test.ts +145 -14
  147. package/src/__tests__/managed-skill-lifecycle.test.ts +109 -18
  148. package/src/__tests__/managed-store.test.ts +84 -192
  149. package/src/__tests__/mcp-auth-routes.test.ts +1 -0
  150. package/src/__tests__/mcp-cli.test.ts +182 -220
  151. package/src/__tests__/mcp-health-check.test.ts +56 -27
  152. package/src/__tests__/media-generate-image.test.ts +1 -1
  153. package/src/__tests__/memory-jobs-worker-lanes.test.ts +18 -11
  154. package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -2
  155. package/src/__tests__/message-complete-display-id.test.ts +175 -0
  156. package/src/__tests__/messages-after-tiebreaker.test.ts +122 -0
  157. package/src/__tests__/notification-platform-adapter.test.ts +229 -0
  158. package/src/__tests__/oauth-cli.test.ts +38 -2009
  159. package/src/__tests__/oauth-commands-routes.test.ts +863 -0
  160. package/src/__tests__/oauth-connect-routes.test.ts +174 -11
  161. package/src/__tests__/oauth-provider-profiles.test.ts +9 -0
  162. package/src/__tests__/oauth-providers-routes.test.ts +14 -10
  163. package/src/__tests__/openai-provider.test.ts +24 -0
  164. package/src/__tests__/openai-responses-cutover-guard.test.ts +48 -19
  165. package/src/__tests__/openai-responses-provider.test.ts +17 -0
  166. package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -2
  167. package/src/__tests__/persistence-pipeline.test.ts +0 -2
  168. package/src/__tests__/{managed-proxy-context.test.ts → platform-proxy-context.test.ts} +1 -1
  169. package/src/__tests__/platform.test.ts +2 -0
  170. package/src/__tests__/plugin-api-shim.test.ts +125 -0
  171. package/src/__tests__/plugin-bootstrap.test.ts +41 -38
  172. package/src/__tests__/plugin-external-api.test.ts +68 -0
  173. package/src/__tests__/plugin-registry.test.ts +0 -77
  174. package/src/__tests__/plugin-route-contribution.test.ts +31 -4
  175. package/src/__tests__/plugin-skill-contribution.test.ts +0 -2
  176. package/src/__tests__/plugin-tool-contribution.test.ts +47 -18
  177. package/src/__tests__/plugin-types.test.ts +15 -23
  178. package/src/__tests__/process-message-background-slack.test.ts +53 -0
  179. package/src/__tests__/process-message-display-content.test.ts +421 -0
  180. package/src/__tests__/profile-entry-status.test.ts +43 -0
  181. package/src/__tests__/provider-catalog-visibility.test.ts +142 -0
  182. package/src/__tests__/provider-error-scenarios.test.ts +111 -0
  183. package/src/__tests__/{provider-managed-proxy-integration.test.ts → provider-platform-proxy-integration.test.ts} +20 -12
  184. package/src/__tests__/provider-registry-ollama.test.ts +12 -4
  185. package/src/__tests__/provider-send-message-override-profile.test.ts +10 -4
  186. package/src/__tests__/relay-server.test.ts +118 -0
  187. package/src/__tests__/retry-thinking-tool-choice.test.ts +15 -0
  188. package/src/__tests__/scaffold-managed-skill-tool.test.ts +65 -13
  189. package/src/__tests__/schedule-retry.test.ts +56 -4
  190. package/src/__tests__/schedule-routes.test.ts +151 -0
  191. package/src/__tests__/schedule-store.test.ts +94 -0
  192. package/src/__tests__/scheduler-disk-pressure.test.ts +0 -4
  193. package/src/__tests__/scheduler-recurrence.test.ts +87 -34
  194. package/src/__tests__/scheduler-reuse-conversation.test.ts +208 -5
  195. package/src/__tests__/scheduler-wake.test.ts +0 -63
  196. package/src/__tests__/schema-transforms.test.ts +20 -0
  197. package/src/__tests__/search-skills-unified.test.ts +0 -5
  198. package/src/__tests__/secret-allowlist.test.ts +1 -0
  199. package/src/__tests__/{secret-routes-managed-proxy.test.ts → secret-routes-platform-proxy.test.ts} +12 -4
  200. package/src/__tests__/server-history-render.test.ts +43 -0
  201. package/src/__tests__/shell-credential-ref.test.ts +95 -3
  202. package/src/__tests__/shell-tool-proxy-mode.test.ts +14 -0
  203. package/src/__tests__/skill-load-feature-flag.test.ts +1 -12
  204. package/src/__tests__/skill-load-tool.test.ts +29 -93
  205. package/src/__tests__/skill-memory.test.ts +23 -3
  206. package/src/__tests__/skills-file-content-endpoint.test.ts +9 -38
  207. package/src/__tests__/skills-files-catalog-fallback.test.ts +0 -3
  208. package/src/__tests__/skills-install-extract.test.ts +49 -38
  209. package/src/__tests__/skills-install-staging.test.ts +159 -0
  210. package/src/__tests__/skills-uninstall.test.ts +9 -41
  211. package/src/__tests__/skills.test.ts +51 -58
  212. package/src/__tests__/slack-channel-config.test.ts +9 -0
  213. package/src/__tests__/subagent-call-site-routing.test.ts +78 -16
  214. package/src/__tests__/subagent-tool-filtering.test.ts +50 -0
  215. package/src/__tests__/suggestion-routes.test.ts +3 -3
  216. package/src/__tests__/sync-message-contract.test.ts +63 -0
  217. package/src/__tests__/system-prompt.test.ts +737 -63
  218. package/src/__tests__/task-scheduler.test.ts +88 -23
  219. package/src/__tests__/terminal-tools.test.ts +28 -1
  220. package/src/__tests__/thread-backfill.test.ts +557 -27
  221. package/src/__tests__/title-generate-pipeline.test.ts +0 -13
  222. package/src/__tests__/token-estimate-pipeline.test.ts +0 -3
  223. package/src/__tests__/tool-error-pipeline.test.ts +0 -3
  224. package/src/__tests__/tool-execute-pipeline.test.ts +0 -5
  225. package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
  226. package/src/__tests__/tool-executor.test.ts +16 -4
  227. package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -12
  228. package/src/__tests__/turn-events-store.test.ts +256 -0
  229. package/src/__tests__/twilio-routes.test.ts +4 -0
  230. package/src/__tests__/update-bulletin-job.test.ts +96 -193
  231. package/src/__tests__/usage-cli.test.ts +11 -73
  232. package/src/__tests__/user-plugin-loader.test.ts +143 -5
  233. package/src/__tests__/vercel-config.test.ts +168 -0
  234. package/src/__tests__/voice-session-bridge.test.ts +198 -0
  235. package/src/__tests__/web-search-catalog-parity.test.ts +108 -0
  236. package/src/__tests__/web-search.test.ts +303 -2
  237. package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +1 -21
  238. package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +170 -0
  239. package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +53 -20
  240. package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +241 -0
  241. package/src/__tests__/workspace-migration-073-repair-recall-callsite-empty-profile.test.ts +153 -0
  242. package/src/__tests__/workspace-migration-076-drop-services-inference-mode.test.ts +211 -0
  243. package/src/__tests__/workspace-migration-077-seed-memory-router-callsite.test.ts +174 -0
  244. package/src/__tests__/workspace-migration-079-home-feed-notification-only.test.ts +323 -0
  245. package/src/__tests__/workspace-migration-080-restrict-vercel-api-token-metadata.test.ts +299 -0
  246. package/src/__tests__/workspace-migration-081-backfill-bash-allowed-tools.test.ts +410 -0
  247. package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +268 -0
  248. package/src/__tests__/workspace-migration-085-memory-v2-bm25-b-reembed-disabled-v2-pages.test.ts +220 -0
  249. package/src/__tests__/workspace-migration-086-revert-stale-gemini-mis-rewrites.test.ts +269 -0
  250. package/src/__tests__/workspace-migration-remove-legacy-skills-index.test.ts +309 -0
  251. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +3 -3
  252. package/src/__tests__/workspace-migrations-runner.test.ts +111 -3
  253. package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +115 -0
  254. package/src/acp/__tests__/helpers/which-stub.ts +4 -2
  255. package/src/acp/resolve-agent.test.ts +25 -0
  256. package/src/acp/resolve-agent.ts +13 -2
  257. package/src/acp/session-manager.ts +14 -0
  258. package/src/agent/image-optimize.ts +13 -5
  259. package/src/approvals/guardian-request-resolvers.ts +32 -87
  260. package/src/calls/relay-server.ts +35 -0
  261. package/src/calls/relay-setup-router.ts +36 -0
  262. package/src/calls/types.ts +1 -0
  263. package/src/calls/voice-session-bridge.ts +74 -36
  264. package/src/channels/config.ts +14 -1
  265. package/src/channels/types.ts +109 -0
  266. package/src/cli/AGENTS.md +164 -4
  267. package/src/cli/__tests__/notifications.test.ts +54 -0
  268. package/src/cli/__tests__/unknown-command.test.ts +24 -0
  269. package/src/cli/commands/__tests__/avatar.test.ts +540 -0
  270. package/src/cli/commands/__tests__/backup.test.ts +236 -776
  271. package/src/cli/commands/__tests__/cache.test.ts +1 -1
  272. package/src/cli/commands/__tests__/changelog.test.ts +578 -0
  273. package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +503 -0
  274. package/src/cli/commands/__tests__/conversations-import.test.ts +515 -0
  275. package/src/cli/commands/__tests__/domain-register.test.ts +140 -167
  276. package/src/cli/commands/__tests__/domain-status.test.ts +137 -76
  277. package/src/cli/commands/__tests__/email-attachment.test.ts +314 -337
  278. package/src/cli/commands/__tests__/email-core.test.ts +579 -0
  279. package/src/cli/commands/__tests__/image-generation.test.ts +87 -824
  280. package/src/cli/commands/__tests__/inference-send.test.ts +30 -266
  281. package/src/cli/commands/__tests__/inference-session.test.ts +423 -0
  282. package/src/cli/commands/__tests__/memory-v2.test.ts +81 -110
  283. package/src/cli/commands/__tests__/schedules.test.ts +491 -0
  284. package/src/cli/commands/__tests__/skills.test.ts +563 -0
  285. package/src/cli/commands/__tests__/status.test.ts +249 -0
  286. package/src/cli/commands/__tests__/stt.test.ts +320 -0
  287. package/src/cli/commands/__tests__/tts-synthesize.test.ts +4 -603
  288. package/src/cli/commands/__tests__/tts.test.ts +321 -0
  289. package/src/cli/commands/__tests__/webhooks.test.ts +86 -511
  290. package/src/cli/commands/attachment.ts +8 -3
  291. package/src/cli/commands/audit.ts +95 -64
  292. package/src/cli/commands/auth.ts +61 -58
  293. package/src/cli/commands/avatar.ts +276 -390
  294. package/src/cli/commands/backup.ts +409 -505
  295. package/src/cli/commands/bash.ts +9 -5
  296. package/src/cli/commands/browser.ts +28 -9
  297. package/src/cli/commands/cache.ts +9 -4
  298. package/src/cli/commands/changelog.ts +478 -0
  299. package/src/cli/commands/channel-verification-sessions.ts +238 -317
  300. package/src/cli/commands/clients.ts +8 -3
  301. package/src/cli/commands/completions.ts +9 -9
  302. package/src/cli/commands/config.ts +102 -72
  303. package/src/cli/commands/contacts.ts +575 -696
  304. package/src/cli/commands/conversations-defer.ts +17 -69
  305. package/src/cli/commands/conversations-import.ts +90 -253
  306. package/src/cli/commands/conversations.ts +429 -434
  307. package/src/cli/commands/credential-execution.ts +9 -6
  308. package/src/cli/commands/credentials.ts +456 -736
  309. package/src/cli/commands/default-action.ts +10 -53
  310. package/src/cli/commands/domain.ts +128 -206
  311. package/src/cli/commands/email.ts +606 -794
  312. package/src/cli/commands/gateway.ts +8 -1
  313. package/src/cli/commands/image-generation.ts +157 -205
  314. package/src/cli/commands/inference-providers.ts +352 -0
  315. package/src/cli/commands/inference-session.ts +415 -0
  316. package/src/cli/commands/inference.ts +87 -65
  317. package/src/cli/commands/keys.ts +8 -3
  318. package/src/cli/commands/mcp.ts +103 -287
  319. package/src/cli/commands/memory-v2.ts +162 -516
  320. package/src/cli/commands/notifications.ts +342 -304
  321. package/src/cli/commands/oauth/apps.ts +292 -261
  322. package/src/cli/commands/oauth/connect.ts +176 -297
  323. package/src/cli/commands/oauth/disconnect.ts +16 -215
  324. package/src/cli/commands/oauth/index.ts +49 -45
  325. package/src/cli/commands/oauth/mode.ts +43 -199
  326. package/src/cli/commands/oauth/ping.ts +17 -125
  327. package/src/cli/commands/oauth/providers.ts +732 -921
  328. package/src/cli/commands/oauth/request.ts +60 -350
  329. package/src/cli/commands/oauth/shared.ts +11 -121
  330. package/src/cli/commands/oauth/status.ts +31 -121
  331. package/src/cli/commands/oauth/token.ts +13 -55
  332. package/src/cli/commands/pending.ts +19 -10
  333. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +133 -183
  334. package/src/cli/commands/platform/__tests__/connect.test.ts +66 -181
  335. package/src/cli/commands/platform/__tests__/disconnect.test.ts +71 -227
  336. package/src/cli/commands/platform/__tests__/status.test.ts +169 -287
  337. package/src/cli/commands/platform/connect.ts +16 -80
  338. package/src/cli/commands/platform/disconnect.ts +14 -112
  339. package/src/cli/commands/platform/index.ts +177 -246
  340. package/src/cli/commands/plugins.ts +185 -0
  341. package/src/cli/commands/routes.ts +153 -336
  342. package/src/cli/commands/schedules.ts +391 -0
  343. package/src/cli/commands/sequence.ts +316 -360
  344. package/src/cli/commands/skills.ts +449 -671
  345. package/src/cli/commands/status.ts +58 -37
  346. package/src/cli/commands/stt.ts +94 -262
  347. package/src/cli/commands/task.ts +14 -40
  348. package/src/cli/commands/telemetry.ts +40 -0
  349. package/src/cli/commands/trust.ts +8 -3
  350. package/src/cli/commands/tts.ts +162 -167
  351. package/src/cli/commands/ui.ts +35 -42
  352. package/src/cli/commands/usage.ts +188 -126
  353. package/src/cli/commands/watchers.ts +8 -3
  354. package/src/cli/commands/webhooks.ts +99 -193
  355. package/src/cli/lib/__tests__/cli-colors.test.ts +48 -0
  356. package/src/cli/lib/__tests__/confirm-prompt.test.ts +159 -0
  357. package/src/cli/lib/__tests__/install-from-github.test.ts +355 -0
  358. package/src/cli/lib/__tests__/list-installed-plugins.test.ts +154 -0
  359. package/src/cli/lib/__tests__/register-command.test.ts +85 -0
  360. package/src/cli/lib/__tests__/uninstall-plugin.test.ts +124 -0
  361. package/src/cli/lib/__tests__/unknown-command.test.ts +106 -0
  362. package/src/cli/lib/cli-colors.ts +12 -0
  363. package/src/cli/lib/confirm-prompt.ts +79 -0
  364. package/src/cli/lib/daemon-credential-client.ts +4 -5
  365. package/src/cli/lib/install-from-github.ts +304 -0
  366. package/src/cli/lib/list-installed-plugins.ts +137 -0
  367. package/src/cli/lib/nested-value.ts +44 -0
  368. package/src/cli/lib/open-browser.ts +36 -0
  369. package/src/cli/lib/register-command.ts +19 -0
  370. package/src/cli/lib/time-ago.ts +34 -0
  371. package/src/cli/lib/uninstall-plugin.ts +82 -0
  372. package/src/cli/lib/unknown-command.ts +111 -0
  373. package/src/cli/program.ts +40 -6
  374. package/src/cli/utils/__tests__/conversation-id.test.ts +66 -0
  375. package/src/cli/utils/__tests__/parse-duration.test.ts +49 -0
  376. package/src/cli/utils/conversation-id.ts +30 -0
  377. package/src/cli/utils/parse-duration.ts +41 -0
  378. package/src/config/acp-defaults.test.ts +5 -1
  379. package/src/config/acp-defaults.ts +11 -4
  380. package/src/config/bundled-skills/acp/TOOLS.json +2 -2
  381. package/src/config/bundled-skills/app-builder/SKILL.md +23 -21
  382. package/src/config/bundled-skills/app-builder/TOOLS.json +7 -0
  383. package/src/config/bundled-skills/app-control/TOOLS.json +32 -0
  384. package/src/config/bundled-skills/computer-use/TOOLS.json +15 -52
  385. package/src/config/bundled-skills/contacts/SKILL.md +12 -45
  386. package/src/config/bundled-skills/contacts/TOOLS.json +0 -57
  387. package/src/config/bundled-skills/document/SKILL.md +23 -3
  388. package/src/config/bundled-skills/document/TOOLS.json +53 -0
  389. package/src/config/bundled-skills/document/tools/document-delete.ts +12 -0
  390. package/src/config/bundled-skills/document/tools/document-list.ts +12 -0
  391. package/src/config/bundled-skills/document/tools/document-read.ts +12 -0
  392. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +0 -12
  393. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -58
  394. package/src/config/bundled-skills/skill-management/SKILL.md +2 -2
  395. package/src/config/bundled-skills/skill-management/TOOLS.json +7 -7
  396. package/src/config/bundled-tool-registry.ts +6 -2
  397. package/src/config/feature-flag-registry.json +57 -1
  398. package/src/config/llm-resolver.ts +16 -1
  399. package/src/config/loader.ts +140 -52
  400. package/src/config/raw-config-utils.ts +2 -30
  401. package/src/config/schema.ts +8 -7
  402. package/src/config/schemas/__tests__/llm-request-logs.test.ts +36 -0
  403. package/src/config/schemas/__tests__/memory-v2.test.ts +49 -0
  404. package/src/config/schemas/call-site-catalog.ts +29 -7
  405. package/src/config/schemas/channels.ts +8 -0
  406. package/src/config/schemas/compaction.ts +28 -0
  407. package/src/config/schemas/heartbeat.ts +9 -0
  408. package/src/config/schemas/llm-request-logs.ts +81 -0
  409. package/src/config/schemas/llm.ts +55 -2
  410. package/src/config/schemas/memory-retrieval.ts +18 -0
  411. package/src/config/schemas/memory-retrospective.ts +48 -0
  412. package/src/config/schemas/memory-v2.ts +32 -1
  413. package/src/config/schemas/memory.ts +4 -0
  414. package/src/config/schemas/services.ts +15 -12
  415. package/src/config/schemas/tools.ts +14 -0
  416. package/src/config/seed-inference-profiles.ts +195 -134
  417. package/src/config/skills.ts +3 -96
  418. package/src/contacts/contact-store.ts +0 -61
  419. package/src/context/compactor.ts +1047 -0
  420. package/src/context/token-estimator.ts +2 -2
  421. package/src/context/window-manager.ts +197 -1334
  422. package/src/credential-execution/managed-catalog.ts +37 -0
  423. package/src/credential-health/credential-health-service.ts +280 -19
  424. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +113 -0
  425. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +138 -0
  426. package/src/daemon/__tests__/conversation-tool-setup.test.ts +183 -4
  427. package/src/daemon/__tests__/daemon-skill-host.test.ts +10 -4
  428. package/src/daemon/approval-generators.ts +26 -30
  429. package/src/daemon/config-watcher.ts +94 -29
  430. package/src/daemon/conversation-agent-loop-handlers.ts +24 -0
  431. package/src/daemon/conversation-agent-loop.ts +293 -103
  432. package/src/daemon/conversation-error.ts +188 -33
  433. package/src/daemon/conversation-lifecycle.ts +80 -26
  434. package/src/daemon/conversation-messaging.ts +25 -6
  435. package/src/daemon/conversation-process.ts +85 -31
  436. package/src/daemon/conversation-runtime-assembly.ts +30 -6
  437. package/src/daemon/conversation-slash.ts +184 -25
  438. package/src/daemon/conversation-store.ts +24 -10
  439. package/src/daemon/conversation-surfaces.ts +76 -12
  440. package/src/daemon/conversation-tool-setup.ts +63 -21
  441. package/src/daemon/conversation.ts +81 -10
  442. package/src/daemon/external-plugins-bootstrap.ts +231 -185
  443. package/src/daemon/first-greeting.ts +22 -2
  444. package/src/daemon/guardian-action-generators.ts +7 -22
  445. package/src/daemon/handlers/config-model.ts +13 -130
  446. package/src/daemon/handlers/config-slack-channel.ts +25 -10
  447. package/src/daemon/handlers/config-vercel.ts +3 -1
  448. package/src/daemon/handlers/shared.ts +14 -5
  449. package/src/daemon/handlers/skills.ts +166 -84
  450. package/src/daemon/history-repair.ts +61 -7
  451. package/src/daemon/host-app-control-proxy.ts +129 -29
  452. package/src/daemon/host-bash-proxy.ts +85 -158
  453. package/src/daemon/host-browser-proxy.ts +96 -35
  454. package/src/daemon/host-proxy-base.ts +13 -1
  455. package/src/daemon/host-proxy-preactivation.ts +25 -1
  456. package/src/daemon/identity-helpers.ts +19 -0
  457. package/src/daemon/lifecycle.ts +79 -70
  458. package/src/daemon/meet-host-supervisor.ts +20 -19
  459. package/src/daemon/memory-v2-startup.ts +58 -2
  460. package/src/daemon/message-protocol.ts +7 -0
  461. package/src/daemon/message-types/bookmarks.ts +18 -0
  462. package/src/daemon/message-types/conversations.ts +37 -9
  463. package/src/daemon/message-types/messages.ts +70 -1
  464. package/src/daemon/message-types/subagents.ts +1 -0
  465. package/src/daemon/message-types/sync.ts +61 -0
  466. package/src/daemon/pkb-reminder-builder.test.ts +54 -13
  467. package/src/daemon/pkb-reminder-builder.ts +21 -7
  468. package/src/daemon/plugin-source-watcher.ts +146 -0
  469. package/src/daemon/process-message.ts +77 -26
  470. package/src/daemon/server.ts +34 -20
  471. package/src/daemon/shutdown-handlers.ts +0 -2
  472. package/src/daemon/skill-memory-refresh.ts +29 -0
  473. package/src/daemon/tool-setup-types.ts +9 -0
  474. package/src/daemon/tool-side-effects.ts +6 -4
  475. package/src/daemon/wake-target-adapter.ts +11 -0
  476. package/src/documents/document-store.ts +221 -3
  477. package/src/embedded/plugin-api.ts +40 -0
  478. package/src/export/transcript-formatter.ts +61 -2
  479. package/src/filing/filing-service.ts +79 -53
  480. package/src/heartbeat/__tests__/heartbeat-service.test.ts +444 -0
  481. package/src/heartbeat/heartbeat-run-store.ts +3 -1
  482. package/src/heartbeat/heartbeat-service.ts +189 -127
  483. package/src/home/__tests__/feed-types.test.ts +99 -127
  484. package/src/home/__tests__/feed-writer.test.ts +77 -278
  485. package/src/home/__tests__/post-connect-feed.test.ts +9 -12
  486. package/src/home/feed-types.ts +41 -73
  487. package/src/home/feed-writer.ts +25 -156
  488. package/src/home/post-connect-feed.ts +2 -3
  489. package/src/index.ts +18 -1
  490. package/src/ipc/__tests__/cli-ipc.test.ts +2 -0
  491. package/src/ipc/__tests__/email-ipc.test.ts +506 -0
  492. package/src/ipc/__tests__/exit-helper.test.ts +104 -0
  493. package/src/ipc/__tests__/streaming-client.test.ts +237 -0
  494. package/src/ipc/__tests__/streaming-framing.test.ts +142 -0
  495. package/src/ipc/assistant-server.ts +55 -6
  496. package/src/ipc/cli-client.ts +370 -50
  497. package/src/ipc/routes/db-proxy-transaction.ts +151 -0
  498. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +60 -0
  499. package/src/ipc/skill-routes/events.ts +30 -3
  500. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +46 -0
  501. package/src/live-voice/__tests__/live-voice-stt.test.ts +57 -0
  502. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +1 -0
  503. package/src/live-voice/live-voice-session-manager.ts +11 -4
  504. package/src/live-voice/live-voice-session.ts +14 -6
  505. package/src/mcp/client.ts +20 -4
  506. package/src/media/image-credentials.ts +3 -3
  507. package/src/memory/__tests__/bookmark-crud.test.ts +264 -0
  508. package/src/memory/__tests__/bookmark-schema.test.ts +181 -0
  509. package/src/memory/__tests__/conversation-queries.test.ts +263 -0
  510. package/src/memory/__tests__/conversation-types.test.ts +36 -0
  511. package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +130 -0
  512. package/src/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +113 -0
  513. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +177 -0
  514. package/src/memory/__tests__/memory-retrospective-job.test.ts +328 -0
  515. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +318 -0
  516. package/src/memory/__tests__/memory-retrospective-trigger-check.test.ts +90 -0
  517. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +69 -0
  518. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -0
  519. package/src/memory/__tests__/message-content.test.ts +35 -0
  520. package/src/memory/bookmark-crud.ts +211 -0
  521. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +31 -9
  522. package/src/memory/context-search/agent-protocol.ts +5 -1
  523. package/src/memory/context-search/agent-runner.ts +60 -85
  524. package/src/memory/context-search/limits.ts +1 -4
  525. package/src/memory/context-search/search.ts +23 -113
  526. package/src/memory/context-search/sources/conversations.ts +80 -8
  527. package/src/memory/context-search/sources/memory-v2.ts +39 -14
  528. package/src/memory/context-search/sources/memory.ts +7 -0
  529. package/src/memory/context-search/sources/workspace.ts +17 -10
  530. package/src/memory/context-search/types.ts +1 -1
  531. package/src/memory/conversation-bootstrap.ts +11 -0
  532. package/src/memory/conversation-crud.ts +368 -22
  533. package/src/memory/conversation-queries.ts +116 -12
  534. package/src/memory/conversation-title-service.ts +1 -0
  535. package/src/memory/conversation-types.ts +16 -0
  536. package/src/memory/db-init.ts +20 -0
  537. package/src/memory/delivery-crud.ts +152 -5
  538. package/src/memory/embedding-backend.ts +6 -5
  539. package/src/memory/embedding-runtime-manager.ts +1 -2
  540. package/src/memory/external-conversation-store.ts +66 -5
  541. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +66 -9
  542. package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
  543. package/src/memory/graph/conversation-graph-memory.ts +92 -5
  544. package/src/memory/graph/extraction.ts +4 -0
  545. package/src/memory/graph/graph-memory-state-store.ts +16 -3
  546. package/src/memory/graph/tool-handlers.ts +17 -7
  547. package/src/memory/graph/tools.ts +45 -6
  548. package/src/memory/indexer.ts +51 -29
  549. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +86 -15
  550. package/src/memory/jobs/embed-concept-page.ts +65 -20
  551. package/src/memory/jobs-store.ts +51 -1
  552. package/src/memory/jobs-worker.ts +57 -3
  553. package/src/memory/llm-request-log-source-clickhouse.ts +324 -0
  554. package/src/memory/llm-request-log-source-local.ts +26 -0
  555. package/src/memory/llm-request-log-source.ts +64 -0
  556. package/src/memory/llm-request-log-store.ts +1 -1
  557. package/src/memory/llm-usage-store.ts +125 -5
  558. package/src/memory/memory-retrospective-constants.ts +13 -0
  559. package/src/memory/memory-retrospective-enqueue.ts +114 -0
  560. package/src/memory/memory-retrospective-job.ts +351 -0
  561. package/src/memory/memory-retrospective-startup-cleanup.ts +175 -0
  562. package/src/memory/memory-retrospective-state.ts +162 -0
  563. package/src/memory/memory-retrospective-trigger-check.ts +91 -0
  564. package/src/memory/memory-v2-activation-log-store.ts +49 -5
  565. package/src/memory/memory-v2-concept-frequency.ts +4 -0
  566. package/src/memory/message-content.ts +38 -1
  567. package/src/memory/migrations/109-external-conversation-bindings.ts +15 -4
  568. package/src/memory/migrations/227-add-conversation-inference-profile.ts +6 -1
  569. package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +20 -7
  570. package/src/memory/migrations/229-delete-private-conversations.test.ts +107 -1
  571. package/src/memory/migrations/229-delete-private-conversations.ts +19 -0
  572. package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +16 -2
  573. package/src/memory/migrations/240-conversation-inference-profile-session.ts +25 -0
  574. package/src/memory/migrations/241-activation-state-fk-cascade.ts +50 -0
  575. package/src/memory/migrations/242-message-bookmarks.ts +38 -0
  576. package/src/memory/migrations/243-provider-connections.ts +68 -0
  577. package/src/memory/migrations/244-provider-connection-status-label.ts +23 -0
  578. package/src/memory/migrations/245-memory-retrospective-state.ts +36 -0
  579. package/src/memory/migrations/246-backfill-provider-connection-label.ts +81 -0
  580. package/src/memory/migrations/247-external-conversation-binding-thread-id.ts +78 -0
  581. package/src/memory/migrations/248-create-onboarding-events.ts +21 -0
  582. package/src/memory/migrations/249-normalize-slack-external-content.ts +240 -0
  583. package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +84 -0
  584. package/src/memory/migrations/__tests__/245-memory-retrospective-state.test.ts +125 -0
  585. package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +192 -0
  586. package/src/memory/migrations/index.ts +13 -0
  587. package/src/memory/migrations/registry.ts +8 -0
  588. package/src/memory/onboarding-events-store.ts +106 -0
  589. package/src/memory/published-pages-store.ts +16 -0
  590. package/src/memory/schema/bookmarks.ts +36 -0
  591. package/src/memory/schema/calls.ts +1 -0
  592. package/src/memory/schema/conversations.ts +2 -0
  593. package/src/memory/schema/index.ts +2 -0
  594. package/src/memory/schema/inference.ts +27 -0
  595. package/src/memory/schema/infrastructure.ts +12 -0
  596. package/src/memory/schema/memory-core.ts +9 -0
  597. package/src/memory/search/semantic.ts +1 -4
  598. package/src/memory/turn-events-store.ts +127 -2
  599. package/src/memory/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +27 -0
  600. package/src/memory/v2/__tests__/activation-store.test.ts +5 -5
  601. package/src/memory/v2/__tests__/activation.test.ts +11 -12
  602. package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
  603. package/src/memory/v2/__tests__/consolidation-job.test.ts +123 -135
  604. package/src/memory/v2/__tests__/edge-index.test.ts +1 -1
  605. package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +111 -0
  606. package/src/memory/v2/__tests__/injection.test.ts +726 -18
  607. package/src/memory/v2/__tests__/migration.test.ts +94 -3
  608. package/src/memory/v2/__tests__/page-index.test.ts +360 -0
  609. package/src/memory/v2/__tests__/page-store.test.ts +14 -1
  610. package/src/memory/v2/__tests__/prompts-router.test.ts +309 -0
  611. package/src/memory/v2/__tests__/qdrant.test.ts +138 -3
  612. package/src/memory/v2/__tests__/reranker.test.ts +4 -4
  613. package/src/memory/v2/__tests__/router.test.ts +531 -0
  614. package/src/memory/v2/__tests__/sim.test.ts +45 -1
  615. package/src/memory/v2/__tests__/skill-store.test.ts +445 -11
  616. package/src/memory/v2/__tests__/static-context.test.ts +7 -22
  617. package/src/memory/v2/__tests__/sweep-job.test.ts +95 -0
  618. package/src/memory/v2/activation-store.ts +34 -5
  619. package/src/memory/v2/activation.ts +40 -27
  620. package/src/memory/v2/backfill-jobs.ts +17 -84
  621. package/src/memory/v2/consolidation-job.ts +85 -78
  622. package/src/memory/v2/frontmatter-sweep.ts +91 -0
  623. package/src/memory/v2/injection.ts +466 -109
  624. package/src/memory/v2/migration.ts +147 -20
  625. package/src/memory/v2/page-index.ts +221 -0
  626. package/src/memory/v2/page-store.ts +3 -0
  627. package/src/memory/v2/prompts/consolidation.ts +9 -7
  628. package/src/memory/v2/prompts/router.ts +195 -0
  629. package/src/memory/v2/prompts/sweep.ts +2 -2
  630. package/src/memory/v2/qdrant.ts +234 -93
  631. package/src/memory/v2/reranker.ts +14 -7
  632. package/src/memory/v2/router.ts +323 -0
  633. package/src/memory/v2/sim.ts +25 -12
  634. package/src/memory/v2/skill-store.ts +204 -30
  635. package/src/memory/v2/static-context.ts +16 -9
  636. package/src/memory/v2/sweep-job.ts +122 -96
  637. package/src/memory/v2/types.ts +10 -6
  638. package/src/memory/validation.ts +13 -0
  639. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +45 -5
  640. package/src/messaging/providers/slack/__tests__/download.test.ts +231 -0
  641. package/src/messaging/providers/slack/adapter.ts +43 -5
  642. package/src/messaging/providers/slack/client.ts +27 -0
  643. package/src/messaging/providers/slack/deep-link.ts +65 -0
  644. package/src/messaging/providers/slack/download.ts +104 -0
  645. package/src/messaging/providers/slack/message-metadata.test.ts +32 -0
  646. package/src/messaging/providers/slack/message-metadata.ts +27 -0
  647. package/src/messaging/providers/slack/render-transcript.test.ts +134 -0
  648. package/src/messaging/providers/slack/render-transcript.ts +69 -5
  649. package/src/messaging/providers/slack/types.ts +20 -1
  650. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +182 -0
  651. package/src/notifications/__tests__/home-feed-side-effect.test.ts +199 -0
  652. package/src/notifications/__tests__/signal-registry.test.ts +17 -0
  653. package/src/notifications/adapters/platform.ts +171 -0
  654. package/src/notifications/conversation-pairing.ts +4 -3
  655. package/src/notifications/copy-composer.ts +15 -0
  656. package/src/notifications/decision-engine.ts +2 -1
  657. package/src/notifications/destination-resolver.ts +21 -0
  658. package/src/notifications/emit-signal.ts +48 -2
  659. package/src/notifications/home-feed-side-effect.ts +165 -0
  660. package/src/notifications/signal.ts +8 -1
  661. package/src/oauth/connection-resolver.ts +8 -4
  662. package/src/oauth/platform-connection.ts +6 -2
  663. package/src/oauth/seed-providers.ts +10 -1
  664. package/src/permissions/checker.ts +14 -0
  665. package/src/permissions/ipc-risk-types.ts +3 -0
  666. package/src/permissions/question-prompter.test.ts +416 -0
  667. package/src/permissions/question-prompter.ts +294 -0
  668. package/src/platform/client.test.ts +1 -1
  669. package/src/platform/client.ts +1 -1
  670. package/src/plugin-api/constants.ts +26 -0
  671. package/src/plugin-api/index.ts +46 -0
  672. package/src/plugin-api/package.json +12 -0
  673. package/src/plugin-api/types.ts +144 -0
  674. package/src/plugins/defaults/circuit-breaker.ts +0 -5
  675. package/src/plugins/defaults/compaction.ts +0 -4
  676. package/src/plugins/defaults/empty-response.ts +0 -2
  677. package/src/plugins/defaults/history-repair.ts +0 -2
  678. package/src/plugins/defaults/injectors.ts +55 -6
  679. package/src/plugins/defaults/llm-call.ts +0 -2
  680. package/src/plugins/defaults/memory-retrieval.ts +0 -1
  681. package/src/plugins/defaults/overflow-reduce.ts +0 -1
  682. package/src/plugins/defaults/persistence.ts +0 -2
  683. package/src/plugins/defaults/title-generate.ts +0 -5
  684. package/src/plugins/defaults/token-estimate.ts +0 -2
  685. package/src/plugins/defaults/tool-error.ts +0 -7
  686. package/src/plugins/defaults/tool-execute.ts +0 -2
  687. package/src/plugins/defaults/tool-result-truncate.ts +0 -4
  688. package/src/plugins/ensure-plugin-api-shim.ts +96 -0
  689. package/src/plugins/external-api.ts +104 -0
  690. package/src/plugins/external-plugin-loader.ts +367 -0
  691. package/src/plugins/feature-gate.ts +22 -0
  692. package/src/plugins/pipeline.ts +37 -0
  693. package/src/plugins/registry.ts +48 -80
  694. package/src/plugins/types.ts +74 -53
  695. package/src/plugins/user-loader.ts +85 -43
  696. package/src/proactive-artifact/aux-message-injector.ts +11 -0
  697. package/src/proactive-artifact/job.test.ts +49 -9
  698. package/src/proactive-artifact/job.ts +4 -0
  699. package/src/proactive-artifact/trigger-state.test.ts +9 -0
  700. package/src/proactive-artifact/trigger-state.ts +4 -0
  701. package/src/prompts/__tests__/system-prompt.test.ts +117 -0
  702. package/src/prompts/__tests__/task-progress-hint-section.test.ts +99 -0
  703. package/src/prompts/normalize-onboarding.ts +27 -0
  704. package/src/prompts/sections.ts +302 -0
  705. package/src/prompts/system-prompt.ts +72 -154
  706. package/src/prompts/templates/BOOTSTRAP.md +17 -1
  707. package/src/prompts/templates/system-sections.ts +173 -0
  708. package/src/prompts/update-bulletin-job.ts +61 -73
  709. package/src/providers/__tests__/dispatch-connection-routing.test.ts +279 -0
  710. package/src/providers/__tests__/inference.test.ts +303 -0
  711. package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
  712. package/src/providers/__tests__/provider-secret-catalog.test.ts +6 -0
  713. package/src/providers/__tests__/retry-callsite.test.ts +14 -32
  714. package/src/providers/__tests__/satellite-connection-routing.test.ts +510 -0
  715. package/src/providers/__tests__/search-provider-catalog.test.ts +80 -0
  716. package/src/providers/anthropic/client.ts +123 -54
  717. package/src/providers/call-site-routing.ts +94 -16
  718. package/src/providers/connection-resolution.ts +170 -0
  719. package/src/providers/inference/__tests__/connections-status-label.test.ts +250 -0
  720. package/src/providers/inference/adapter-factory.ts +210 -0
  721. package/src/providers/inference/auth.ts +112 -0
  722. package/src/providers/inference/backfill.ts +196 -0
  723. package/src/providers/inference/connections.ts +401 -0
  724. package/src/providers/inference/resolve-auth.ts +73 -0
  725. package/src/providers/model-catalog.ts +386 -6
  726. package/src/providers/openai/chat-completions-provider.ts +10 -2
  727. package/src/providers/openai/responses-provider.ts +4 -2
  728. package/src/providers/openrouter/client.ts +7 -0
  729. package/src/providers/{managed-proxy → platform-proxy}/constants.ts +4 -1
  730. package/src/providers/{managed-proxy → platform-proxy}/context.ts +3 -3
  731. package/src/providers/provider-availability.ts +17 -2
  732. package/src/providers/provider-catalog-visibility.ts +36 -0
  733. package/src/providers/provider-env-vars.ts +17 -7
  734. package/src/providers/provider-secret-catalog.ts +49 -30
  735. package/src/providers/provider-send-message.ts +41 -20
  736. package/src/providers/registry.ts +151 -159
  737. package/src/providers/retry.ts +65 -11
  738. package/src/providers/search-provider-catalog.ts +121 -0
  739. package/src/runtime/AGENTS.md +18 -5
  740. package/src/runtime/__tests__/agent-wake.test.ts +152 -0
  741. package/src/runtime/__tests__/background-job-runner.test.ts +357 -0
  742. package/src/runtime/__tests__/pre-first-message-gate.test.ts +82 -0
  743. package/src/runtime/actor-trust-resolver.ts +32 -10
  744. package/src/runtime/agent-wake.ts +64 -7
  745. package/src/runtime/assistant-event-hub.ts +3 -85
  746. package/src/runtime/auth/route-policy.ts +311 -9
  747. package/src/runtime/auth/same-actor.ts +2 -0
  748. package/src/runtime/background-job-runner.ts +339 -0
  749. package/src/runtime/btw-sidechain.ts +3 -0
  750. package/src/runtime/http-router.ts +36 -1
  751. package/src/runtime/http-server.ts +31 -5
  752. package/src/runtime/http-types.ts +21 -0
  753. package/src/runtime/middleware/__tests__/request-logger.test.ts +162 -0
  754. package/src/runtime/middleware/request-logger.ts +62 -1
  755. package/src/runtime/migrations/origin-mode.ts +1 -1
  756. package/src/runtime/pending-interactions.ts +1 -0
  757. package/src/runtime/pre-first-message-gate.ts +83 -0
  758. package/src/runtime/routes/__tests__/backup-routes.test.ts +8 -1
  759. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +268 -0
  760. package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +142 -0
  761. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +319 -0
  762. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +280 -4
  763. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +15 -136
  764. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +736 -0
  765. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +4 -4
  766. package/src/runtime/routes/__tests__/question-routes.test.ts +395 -0
  767. package/src/runtime/routes/__tests__/stt-routes.test.ts +5 -1
  768. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +384 -0
  769. package/src/runtime/routes/__tests__/tts-routes.test.ts +70 -3
  770. package/src/runtime/routes/acp-routes-list.test.ts +143 -0
  771. package/src/runtime/routes/acp-routes.ts +12 -8
  772. package/src/runtime/routes/app-management-routes.ts +228 -3
  773. package/src/runtime/routes/approval-routes.ts +0 -18
  774. package/src/runtime/routes/audit-routes.ts +43 -0
  775. package/src/runtime/routes/auth-routes.ts +72 -0
  776. package/src/runtime/routes/avatar-routes.ts +273 -20
  777. package/src/runtime/routes/backup-routes.ts +406 -2
  778. package/src/runtime/routes/bookmark-routes.ts +156 -0
  779. package/src/runtime/routes/btw-routes.ts +5 -1
  780. package/src/runtime/routes/channel-availability-routes.ts +121 -0
  781. package/src/runtime/routes/channel-verification-routes.ts +2 -1
  782. package/src/runtime/routes/contact-routes.ts +0 -160
  783. package/src/runtime/routes/conversation-cli-routes.ts +233 -0
  784. package/src/runtime/routes/conversation-list-routes.ts +3 -20
  785. package/src/runtime/routes/conversation-management-routes.ts +47 -85
  786. package/src/runtime/routes/conversation-query-routes.ts +350 -97
  787. package/src/runtime/routes/conversation-routes.ts +121 -21
  788. package/src/runtime/routes/conversations-import-routes.ts +229 -0
  789. package/src/runtime/routes/credential-routes.ts +540 -0
  790. package/src/runtime/routes/debug-routes.ts +2 -2
  791. package/src/runtime/routes/document-pdf-renderer.ts +5 -1
  792. package/src/runtime/routes/documents-routes.ts +25 -86
  793. package/src/runtime/routes/domain-routes.ts +167 -0
  794. package/src/runtime/routes/email-routes.ts +603 -0
  795. package/src/runtime/routes/errors.ts +2 -2
  796. package/src/runtime/routes/events-routes.ts +192 -0
  797. package/src/runtime/routes/group-routes.ts +5 -0
  798. package/src/runtime/routes/home-feed-routes.ts +6 -78
  799. package/src/runtime/routes/host-app-control-routes.ts +44 -2
  800. package/src/runtime/routes/host-browser-routes.ts +103 -22
  801. package/src/runtime/routes/http-adapter.ts +2 -0
  802. package/src/runtime/routes/identity-routes.ts +5 -0
  803. package/src/runtime/routes/image-generation-routes.ts +99 -0
  804. package/src/runtime/routes/inbound-conversation.ts +28 -8
  805. package/src/runtime/routes/inbound-message-handler.ts +236 -41
  806. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +248 -1
  807. package/src/runtime/routes/inbound-stages/background-dispatch.ts +118 -7
  808. package/src/runtime/routes/inbound-stages/edit-intercept.ts +17 -4
  809. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +156 -0
  810. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +22 -4
  811. package/src/runtime/routes/index.ts +42 -0
  812. package/src/runtime/routes/inference-profile-session-handler.ts +285 -0
  813. package/src/runtime/routes/inference-profile-session-reaper.ts +84 -0
  814. package/src/runtime/routes/inference-profile-session-routes.ts +146 -0
  815. package/src/runtime/routes/inference-provider-connection-routes.ts +361 -0
  816. package/src/runtime/routes/inference-send-routes.ts +115 -0
  817. package/src/runtime/routes/integrations/slack/share.ts +4 -52
  818. package/src/runtime/routes/integrations/slack/token.ts +43 -0
  819. package/src/runtime/routes/integrations/twilio.ts +7 -13
  820. package/src/runtime/routes/mcp-auth-routes.ts +283 -9
  821. package/src/runtime/routes/memory-v2-routes.ts +13 -398
  822. package/src/runtime/routes/notification-routes.ts +3 -1
  823. package/src/runtime/routes/oauth-apps.ts +112 -7
  824. package/src/runtime/routes/oauth-commands-routes.ts +1097 -0
  825. package/src/runtime/routes/oauth-connect-routes.ts +67 -5
  826. package/src/runtime/routes/oauth-lifecycle-routes.ts +43 -0
  827. package/src/runtime/routes/oauth-providers.ts +298 -8
  828. package/src/runtime/routes/platform-routes.ts +336 -0
  829. package/src/runtime/routes/playground/inject-failures.ts +2 -1
  830. package/src/runtime/routes/playground/reset-circuit.ts +2 -1
  831. package/src/runtime/routes/playground/state.ts +2 -1
  832. package/src/runtime/routes/publish-routes.ts +221 -0
  833. package/src/runtime/routes/question-routes.ts +259 -0
  834. package/src/runtime/routes/rename-conversation-routes.ts +2 -33
  835. package/src/runtime/routes/schedule-routes.ts +79 -0
  836. package/src/runtime/routes/sequence-routes.ts +291 -0
  837. package/src/runtime/routes/settings-routes.ts +2 -10
  838. package/src/runtime/routes/skills-routes.ts +31 -1
  839. package/src/runtime/routes/stt-routes.ts +240 -3
  840. package/src/runtime/routes/subagents-routes.ts +57 -18
  841. package/src/runtime/routes/surface-action-routes.ts +43 -7
  842. package/src/runtime/routes/telemetry-routes.ts +27 -0
  843. package/src/runtime/routes/tts-routes.ts +93 -1
  844. package/src/runtime/routes/types.ts +32 -0
  845. package/src/runtime/routes/user-routes-cli.ts +243 -0
  846. package/src/runtime/routes/webhook-routes.ts +165 -0
  847. package/src/runtime/routes/workspace-routes.test.ts +43 -0
  848. package/src/runtime/routes/workspace-routes.ts +28 -0
  849. package/src/runtime/services/conversation-serializer.ts +39 -7
  850. package/src/runtime/sync/resource-sync-events.ts +117 -0
  851. package/src/runtime/sync/sync-publisher.test.ts +105 -0
  852. package/src/runtime/sync/sync-publisher.ts +21 -0
  853. package/src/schedule/schedule-store.ts +27 -2
  854. package/src/schedule/scheduler.ts +208 -123
  855. package/src/security/__tests__/provider-key-env-fallback.test.ts +12 -6
  856. package/src/security/__tests__/untrusted-content.test.ts +86 -0
  857. package/src/security/secret-patterns.ts +3 -0
  858. package/src/security/untrusted-content.ts +93 -8
  859. package/src/sequence/engine.ts +38 -40
  860. package/src/skills/catalog-files.ts +1 -1
  861. package/src/skills/catalog-install.ts +233 -116
  862. package/src/skills/clawhub.ts +70 -13
  863. package/src/skills/managed-store.ts +4 -119
  864. package/src/skills/skillssh-registry.ts +27 -48
  865. package/src/subagent/manager.ts +28 -15
  866. package/src/telemetry/types.ts +113 -1
  867. package/src/telemetry/usage-telemetry-reporter.test.ts +312 -5
  868. package/src/telemetry/usage-telemetry-reporter.ts +113 -7
  869. package/src/tools/apps/executors.ts +58 -7
  870. package/src/tools/ask-question/ask-question-tool.test.ts +509 -0
  871. package/src/tools/ask-question/ask-question-tool.ts +304 -0
  872. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +206 -0
  873. package/src/tools/browser/browser-execution.ts +29 -14
  874. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +174 -0
  875. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +16 -13
  876. package/src/tools/browser/cdp-client/extension-cdp-client.ts +24 -1
  877. package/src/tools/browser/cdp-client/factory.ts +66 -5
  878. package/src/tools/browser/runtime-check.ts +77 -0
  879. package/src/tools/computer-use/definitions.ts +3 -3
  880. package/src/tools/credentials/vault.ts +1 -1
  881. package/src/tools/document/document-tool.ts +124 -1
  882. package/src/tools/filesystem/edit.ts +1 -1
  883. package/src/tools/filesystem/list.ts +1 -1
  884. package/src/tools/filesystem/read.ts +1 -1
  885. package/src/tools/filesystem/write.ts +5 -2
  886. package/src/tools/host-filesystem/transfer.ts +1 -1
  887. package/src/tools/host-terminal/host-shell.ts +1 -1
  888. package/src/tools/memory/register.test.ts +3 -3
  889. package/src/tools/memory/register.ts +9 -1
  890. package/src/tools/network/__tests__/web-search.test.ts +156 -0
  891. package/src/tools/network/web-search.ts +280 -37
  892. package/src/tools/permission-checker.ts +14 -6
  893. package/src/tools/registry.ts +17 -7
  894. package/src/tools/schedule/create.ts +2 -2
  895. package/src/tools/schema-transforms.ts +7 -2
  896. package/src/tools/side-effects.ts +1 -0
  897. package/src/tools/skills/delete-managed.ts +4 -4
  898. package/src/tools/skills/execute.ts +1 -1
  899. package/src/tools/skills/scaffold-managed.ts +3 -2
  900. package/src/tools/subagent/notify-parent.ts +1 -1
  901. package/src/tools/subagent/spawn.ts +3 -3
  902. package/src/tools/system/request-permission.ts +2 -2
  903. package/src/tools/terminal/safe-env.ts +60 -1
  904. package/src/tools/terminal/shell.ts +44 -0
  905. package/src/tools/tool-manifest.ts +2 -0
  906. package/src/tools/types.ts +72 -21
  907. package/src/tools/ui-surface/definitions.ts +6 -5
  908. package/src/tts/__tests__/provider-adapters.test.ts +76 -2
  909. package/src/tts/providers/elevenlabs-provider.ts +75 -1
  910. package/src/types/onboarding-context.ts +2 -0
  911. package/src/usage/attribution.ts +3 -2
  912. package/src/util/errors.ts +17 -0
  913. package/src/util/platform.ts +10 -0
  914. package/src/util/pricing.ts +86 -160
  915. package/src/watcher/__tests__/engine.test.ts +323 -0
  916. package/src/watcher/constants.ts +7 -0
  917. package/src/watcher/engine.ts +94 -90
  918. package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +6 -9
  919. package/src/workspace/migrations/054-seed-recall-callsite.ts +10 -1
  920. package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +94 -5
  921. package/src/workspace/migrations/069-seed-onboarding-threads.ts +8 -2
  922. package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +117 -0
  923. package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +95 -0
  924. package/src/workspace/migrations/074-drop-deprecated-secret-detection-keys.ts +117 -0
  925. package/src/workspace/migrations/075-memory-v2-bm25-b-default-reembed.ts +61 -0
  926. package/src/workspace/migrations/076-drop-services-inference-mode.ts +62 -0
  927. package/src/workspace/migrations/077-seed-memory-router-callsite.ts +89 -0
  928. package/src/workspace/migrations/078-release-notes-tavily-web-search.ts +66 -0
  929. package/src/workspace/migrations/079-home-feed-notification-only.ts +197 -0
  930. package/src/workspace/migrations/080-restrict-vercel-api-token-metadata.ts +182 -0
  931. package/src/workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.ts +160 -0
  932. package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +154 -0
  933. package/src/workspace/migrations/083-system-prompt-prefix-to-file.ts +191 -0
  934. package/src/workspace/migrations/084-remove-legacy-skills-index.ts +276 -0
  935. package/src/workspace/migrations/085-memory-v2-bm25-b-reembed-disabled-v2-pages.ts +137 -0
  936. package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +198 -0
  937. package/src/workspace/migrations/registry.ts +30 -0
  938. package/src/workspace/migrations/runner.ts +46 -5
  939. package/src/workspace/migrations/types.ts +17 -3
  940. package/src/workspace/provider-commit-message-generator.ts +3 -2
  941. package/examples/plugins/echo/bun.lock +0 -25
  942. package/src/__tests__/context-search-pkb-source.test.ts +0 -498
  943. package/src/__tests__/context-window-manager.test.ts +0 -2093
  944. package/src/__tests__/credentials-cli.test.ts +0 -1225
  945. package/src/__tests__/memory-admin-recall.test.ts +0 -213
  946. package/src/approvals/__tests__/guardian-feed-event.test.ts +0 -303
  947. package/src/cli/commands/__tests__/email-download.test.ts +0 -260
  948. package/src/cli/commands/__tests__/email-list.test.ts +0 -216
  949. package/src/cli/commands/__tests__/email-register.test.ts +0 -186
  950. package/src/cli/commands/__tests__/email-send.test.ts +0 -416
  951. package/src/cli/commands/__tests__/email-status.test.ts +0 -185
  952. package/src/cli/commands/__tests__/email-unregister.test.ts +0 -168
  953. package/src/cli/commands/__tests__/routes.test.ts +0 -562
  954. package/src/cli/commands/__tests__/stt-transcribe.test.ts +0 -454
  955. package/src/cli/commands/autonomy.ts +0 -365
  956. package/src/cli/commands/memory.ts +0 -424
  957. package/src/cli/commands/oauth/__tests__/connect.test.ts +0 -947
  958. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +0 -686
  959. package/src/cli/commands/oauth/__tests__/mode.test.ts +0 -632
  960. package/src/cli/commands/oauth/__tests__/ping.test.ts +0 -631
  961. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +0 -573
  962. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +0 -330
  963. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +0 -521
  964. package/src/cli/commands/oauth/__tests__/status.test.ts +0 -551
  965. package/src/cli/commands/oauth/__tests__/token.test.ts +0 -420
  966. package/src/cli/lib/daemon-avatar-client.ts +0 -37
  967. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -87
  968. package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +0 -207
  969. package/src/context/__tests__/compact-prompt.test.ts +0 -63
  970. package/src/context/prompts/compact.md +0 -26
  971. package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -304
  972. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +0 -233
  973. package/src/home/__tests__/assistant-feed-authoring.test.ts +0 -156
  974. package/src/home/__tests__/emit-feed-event.test.ts +0 -169
  975. package/src/home/__tests__/feed-population-integration.test.ts +0 -312
  976. package/src/home/__tests__/feed-scheduler.test.ts +0 -222
  977. package/src/home/__tests__/phase5-exit-criteria.test.ts +0 -229
  978. package/src/home/__tests__/platform-gmail-digest.test.ts +0 -222
  979. package/src/home/__tests__/rollup-producer.test.ts +0 -507
  980. package/src/home/assistant-feed-authoring.ts +0 -135
  981. package/src/home/emit-feed-event.ts +0 -169
  982. package/src/home/feed-scheduler.ts +0 -281
  983. package/src/home/platform-gmail-digest.ts +0 -163
  984. package/src/home/rewrite-command-preview.ts +0 -66
  985. package/src/home/rewrite-feed-title.ts +0 -58
  986. package/src/home/rollup-producer.ts +0 -426
  987. package/src/memory/admin.ts +0 -326
  988. package/src/memory/context-search/sources/pkb.ts +0 -476
  989. package/src/memory/graph/compaction.ts +0 -299
  990. package/src/prompts/__tests__/build-cli-reference-section.test.ts +0 -37
  991. /package/src/cli/{commands → lib}/cache-fs.ts +0 -0
@@ -0,0 +1,1097 @@
1
+ /**
2
+ * Route handlers for OAuth CLI command operations: disconnect, mode, status,
3
+ * ping, token, and request.
4
+ *
5
+ * These routes back the thin IPC wrappers in assistant/src/cli/commands/oauth/.
6
+ */
7
+
8
+ import { readFileSync } from "node:fs";
9
+
10
+ import {
11
+ getConfig,
12
+ loadRawConfig,
13
+ saveRawConfig,
14
+ setNestedValue,
15
+ } from "../../config/loader.js";
16
+ import {
17
+ getServiceMode,
18
+ type Services,
19
+ ServicesSchema,
20
+ } from "../../config/schemas/services.js";
21
+ import type { OAuthConnectionRequest } from "../../oauth/connection.js";
22
+ import {
23
+ resolveOAuthConnection,
24
+ type ResolveOAuthConnectionOptions,
25
+ } from "../../oauth/connection-resolver.js";
26
+ import {
27
+ disconnectOAuthProvider,
28
+ getActiveConnection,
29
+ getAppByProviderAndClientId,
30
+ getConnection,
31
+ getProvider,
32
+ listActiveConnectionsByProvider,
33
+ listConnections,
34
+ type OAuthProviderRow,
35
+ } from "../../oauth/oauth-store.js";
36
+ import { VellumPlatformClient } from "../../platform/client.js";
37
+ import { withValidToken } from "../../security/token-manager.js";
38
+ import { matchHostPattern } from "../../tools/credentials/host-pattern-match.js";
39
+ import { getLogger } from "../../util/logger.js";
40
+ import { BadRequestError, InternalError, NotFoundError } from "./errors.js";
41
+ import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
42
+
43
+ const log = getLogger("oauth-commands-routes");
44
+
45
+ // ---------------------------------------------------------------------------
46
+ // Shared helpers
47
+ // ---------------------------------------------------------------------------
48
+
49
+ interface PlatformConnectionEntry {
50
+ id: string;
51
+ account_label?: string;
52
+ scopes_granted?: string[];
53
+ status?: string;
54
+ }
55
+
56
+ function getManagedServiceConfigKey(provider: string): string | null {
57
+ const providerRow = getProvider(provider);
58
+ const managedKey = providerRow?.managedServiceConfigKey;
59
+ if (!managedKey || !(managedKey in ServicesSchema.shape)) return null;
60
+ return managedKey;
61
+ }
62
+
63
+ function isManagedMode(provider: string): boolean {
64
+ const managedKey = getManagedServiceConfigKey(provider);
65
+ if (!managedKey) return false;
66
+ try {
67
+ const services: Services = getConfig().services;
68
+ return getServiceMode(services, managedKey as keyof Services) === "managed";
69
+ } catch {
70
+ return false;
71
+ }
72
+ }
73
+
74
+ async function requirePlatformClient(): Promise<VellumPlatformClient> {
75
+ const client = await VellumPlatformClient.create();
76
+ if (!client) {
77
+ throw new BadRequestError(
78
+ "Not connected to Vellum platform. Run `vellum platform connect` to connect first.",
79
+ );
80
+ }
81
+ if (!client.platformAssistantId) {
82
+ throw new BadRequestError(
83
+ "Connected to Vellum platform but no assistant ID is configured. Ensure the assistant is registered on the platform.",
84
+ );
85
+ }
86
+ return client;
87
+ }
88
+
89
+ async function fetchActiveConnections(
90
+ client: VellumPlatformClient,
91
+ provider: string,
92
+ ): Promise<PlatformConnectionEntry[]> {
93
+ const params = new URLSearchParams();
94
+ params.set("provider", provider);
95
+ params.set("status", "ACTIVE");
96
+
97
+ const path = `/v1/assistants/${encodeURIComponent(client.platformAssistantId)}/oauth/connections/?${params.toString()}`;
98
+ const response = await client.fetch(path);
99
+
100
+ if (!response.ok) {
101
+ const hint =
102
+ response.status === 401 || response.status === 403
103
+ ? `. Your platform session may have expired. Run \`vellum platform connect\` to reconnect.`
104
+ : "";
105
+ throw new InternalError(`Platform returned HTTP ${response.status}${hint}`);
106
+ }
107
+
108
+ const body = (await response.json()) as unknown;
109
+ return (
110
+ Array.isArray(body)
111
+ ? body
112
+ : ((body as Record<string, unknown>).results ?? [])
113
+ ) as PlatformConnectionEntry[];
114
+ }
115
+
116
+ /**
117
+ * Best-effort helper to count active platform connections for a provider.
118
+ * Returns 0 if the platform client cannot be created or the fetch fails.
119
+ */
120
+ async function countManagedConnections(provider: string): Promise<number> {
121
+ try {
122
+ const client = await VellumPlatformClient.create();
123
+ if (!client || !client.platformAssistantId) return 0;
124
+ const entries = await fetchActiveConnections(client, provider);
125
+ return entries.length;
126
+ } catch {
127
+ return 0;
128
+ }
129
+ }
130
+
131
+ function parseUrl(value: string | null | undefined): URL | undefined {
132
+ if (!value) return undefined;
133
+ try {
134
+ return new URL(value);
135
+ } catch {
136
+ return undefined;
137
+ }
138
+ }
139
+
140
+ function getAllowedRequestHostPatterns(
141
+ providerRow: OAuthProviderRow,
142
+ ): string[] {
143
+ const patterns: string[] = [];
144
+
145
+ if (providerRow.injectionTemplates) {
146
+ try {
147
+ const parsed = JSON.parse(providerRow.injectionTemplates) as unknown;
148
+ if (Array.isArray(parsed)) {
149
+ for (const entry of parsed) {
150
+ if (
151
+ entry &&
152
+ typeof entry === "object" &&
153
+ typeof (entry as { hostPattern?: unknown }).hostPattern === "string"
154
+ ) {
155
+ const hostPattern = (
156
+ entry as { hostPattern: string }
157
+ ).hostPattern.trim();
158
+ if (hostPattern) patterns.push(hostPattern);
159
+ }
160
+ }
161
+ }
162
+ } catch {
163
+ // Fall back to the provider's base URL host below.
164
+ }
165
+ }
166
+
167
+ if (patterns.length === 0) {
168
+ const baseUrl = parseUrl(providerRow.baseUrl);
169
+ if (baseUrl) patterns.push(baseUrl.hostname);
170
+ }
171
+
172
+ return [...new Set(patterns)];
173
+ }
174
+
175
+ function assertOAuthRequestUrlAllowed(
176
+ providerRow: OAuthProviderRow,
177
+ parsedUrl: URL,
178
+ ): void {
179
+ const providerBaseUrl = parseUrl(providerRow.baseUrl);
180
+ const allowedProtocol = providerBaseUrl?.protocol ?? "https:";
181
+ if (parsedUrl.protocol !== allowedProtocol) {
182
+ throw new BadRequestError(
183
+ `OAuth request URL for "${providerRow.provider}" must use ${allowedProtocol.replace(/:$/, "")}.`,
184
+ );
185
+ }
186
+
187
+ const allowedHostPatterns = getAllowedRequestHostPatterns(providerRow);
188
+ if (allowedHostPatterns.length === 0) {
189
+ throw new BadRequestError(
190
+ `OAuth provider "${providerRow.provider}" does not define an allowed request host.`,
191
+ );
192
+ }
193
+
194
+ const allowed = allowedHostPatterns.some(
195
+ (pattern) =>
196
+ matchHostPattern(parsedUrl.hostname, pattern, {
197
+ includeApexForWildcard: true,
198
+ }) !== "none",
199
+ );
200
+ if (!allowed) {
201
+ throw new BadRequestError(
202
+ `OAuth request URL host "${parsedUrl.hostname}" is not allowed for "${providerRow.provider}". Allowed hosts: ${allowedHostPatterns.join(", ")}.`,
203
+ );
204
+ }
205
+ }
206
+
207
+ // ---------------------------------------------------------------------------
208
+ // Disconnect handler
209
+ // ---------------------------------------------------------------------------
210
+
211
+ async function handleDisconnect({ body = {} }: RouteHandlerArgs) {
212
+ const b = body as {
213
+ provider: string;
214
+ account?: string;
215
+ connection_id?: string;
216
+ };
217
+
218
+ if (!b.provider) throw new BadRequestError("provider is required");
219
+
220
+ const providerRow = getProvider(b.provider);
221
+ if (!providerRow) {
222
+ throw new NotFoundError(
223
+ `Unknown provider "${b.provider}". Run 'assistant oauth providers list' to see available providers.`,
224
+ );
225
+ }
226
+
227
+ if (b.account && b.connection_id) {
228
+ throw new BadRequestError(
229
+ `Cannot specify both account and connection_id. Use one or the other.`,
230
+ );
231
+ }
232
+
233
+ const managed = isManagedMode(b.provider);
234
+
235
+ if (managed) {
236
+ const client = await requirePlatformClient();
237
+ const entries = await fetchActiveConnections(client, b.provider);
238
+
239
+ let connectionId: string | undefined;
240
+ let accountLabel: string | undefined;
241
+
242
+ if (b.account) {
243
+ const matching = entries.filter((c) => c.account_label === b.account);
244
+ if (matching.length === 0) {
245
+ throw new NotFoundError(
246
+ `No active connection found for "${b.provider}" with account "${b.account}".`,
247
+ );
248
+ }
249
+ connectionId = matching[0].id;
250
+ accountLabel = matching[0].account_label;
251
+ } else if (b.connection_id) {
252
+ const match = entries.find((c) => c.id === b.connection_id);
253
+ if (!match) {
254
+ throw new NotFoundError(
255
+ `Connection "${b.connection_id}" is not an active ${b.provider} connection.`,
256
+ );
257
+ }
258
+ connectionId = match.id;
259
+ accountLabel = match.account_label;
260
+ } else {
261
+ if (entries.length === 0) {
262
+ throw new NotFoundError(
263
+ `No active connections found for "${b.provider}".`,
264
+ );
265
+ }
266
+ if (entries.length > 1) {
267
+ throw new BadRequestError(
268
+ `Multiple active connections for "${b.provider}". Specify which one to disconnect with account or connection_id. ` +
269
+ `Run 'assistant oauth status ${b.provider}' to see connected accounts and IDs.`,
270
+ );
271
+ }
272
+ connectionId = entries[0].id;
273
+ accountLabel = entries[0].account_label;
274
+ }
275
+
276
+ const disconnectPath = `/v1/assistants/${encodeURIComponent(client.platformAssistantId)}/oauth/connections/${encodeURIComponent(connectionId!)}/disconnect/`;
277
+ const disconnectResponse = await client.fetch(disconnectPath, {
278
+ method: "POST",
279
+ headers: { "Content-Type": "application/json" },
280
+ });
281
+
282
+ if (!disconnectResponse.ok) {
283
+ const errorText = await disconnectResponse.text().catch(() => "");
284
+ throw new InternalError(
285
+ `Platform returned HTTP ${disconnectResponse.status}${errorText ? `: ${errorText}` : ""}`,
286
+ );
287
+ }
288
+
289
+ const result: Record<string, unknown> = {
290
+ ok: true,
291
+ provider: b.provider,
292
+ connectionId,
293
+ };
294
+ if (accountLabel) result.account = accountLabel;
295
+ return result;
296
+ }
297
+
298
+ // BYO path
299
+ let connectionId: string | undefined;
300
+ let accountLabel: string | undefined;
301
+
302
+ if (b.account) {
303
+ const conn = getActiveConnection(b.provider, { account: b.account });
304
+ if (!conn) {
305
+ throw new NotFoundError(
306
+ `No active connection found for "${b.provider}" with account "${b.account}".`,
307
+ );
308
+ }
309
+ connectionId = conn.id;
310
+ accountLabel = conn.accountInfo ?? undefined;
311
+ } else if (b.connection_id) {
312
+ const conn = getConnection(b.connection_id);
313
+ if (!conn || conn.provider !== b.provider) {
314
+ throw new NotFoundError(
315
+ `Connection "${b.connection_id}" is not an active ${b.provider} connection.`,
316
+ );
317
+ }
318
+ connectionId = conn.id;
319
+ accountLabel = conn.accountInfo ?? undefined;
320
+ } else {
321
+ const active = listActiveConnectionsByProvider(b.provider);
322
+ if (active.length === 0) {
323
+ throw new NotFoundError(
324
+ `No active connections found for "${b.provider}".`,
325
+ );
326
+ }
327
+ if (active.length > 1) {
328
+ throw new BadRequestError(
329
+ `Multiple active connections for "${b.provider}". Specify which one to disconnect with account or connection_id. ` +
330
+ `Run 'assistant oauth status ${b.provider}' to see connected accounts and IDs.`,
331
+ );
332
+ }
333
+ connectionId = active[0].id;
334
+ accountLabel = active[0].accountInfo ?? undefined;
335
+ }
336
+
337
+ const oauthResult = await disconnectOAuthProvider(
338
+ b.provider,
339
+ undefined,
340
+ connectionId,
341
+ );
342
+ if (oauthResult === "error") {
343
+ throw new InternalError(
344
+ `Failed to disconnect OAuth provider "${b.provider}" — please try again.`,
345
+ );
346
+ }
347
+
348
+ const result: Record<string, unknown> = {
349
+ ok: true,
350
+ provider: b.provider,
351
+ connectionId,
352
+ };
353
+ if (accountLabel) result.account = accountLabel;
354
+ return result;
355
+ }
356
+
357
+ // ---------------------------------------------------------------------------
358
+ // Mode handlers
359
+ // ---------------------------------------------------------------------------
360
+
361
+ function handleModeGet({ queryParams = {} }: RouteHandlerArgs) {
362
+ const provider = queryParams.provider;
363
+ if (!provider) throw new BadRequestError("provider query param is required");
364
+
365
+ const providerRow = getProvider(provider);
366
+ if (!providerRow) {
367
+ throw new NotFoundError(
368
+ `Unknown provider "${provider}". Run 'assistant oauth providers list' to see available providers.`,
369
+ );
370
+ }
371
+
372
+ const managedKey = getManagedServiceConfigKey(provider);
373
+ if (managedKey === null) {
374
+ return {
375
+ ok: true,
376
+ provider,
377
+ mode: "your-own",
378
+ managedModeSupported: false,
379
+ };
380
+ }
381
+
382
+ const services: Services = getConfig().services;
383
+ const currentMode = getServiceMode(services, managedKey as keyof Services);
384
+
385
+ return {
386
+ ok: true,
387
+ provider,
388
+ mode: currentMode,
389
+ managedModeSupported: true,
390
+ };
391
+ }
392
+
393
+ async function handleModeSet({ body = {} }: RouteHandlerArgs) {
394
+ const b = body as { provider: string; mode: string };
395
+ if (!b.provider) throw new BadRequestError("provider is required");
396
+ if (!b.mode) throw new BadRequestError("mode is required");
397
+
398
+ const providerRow = getProvider(b.provider);
399
+ if (!providerRow) {
400
+ throw new NotFoundError(
401
+ `Unknown provider "${b.provider}". Run 'assistant oauth providers list' to see available providers.`,
402
+ );
403
+ }
404
+
405
+ if (b.mode !== "managed" && b.mode !== "your-own") {
406
+ throw new BadRequestError(
407
+ `Invalid mode "${b.mode}". Valid values are "managed" or "your-own".`,
408
+ );
409
+ }
410
+
411
+ const managedKey = getManagedServiceConfigKey(b.provider);
412
+
413
+ if (managedKey === null) {
414
+ if (b.mode === "your-own") {
415
+ return {
416
+ ok: true,
417
+ provider: b.provider,
418
+ mode: "your-own",
419
+ changed: false,
420
+ managedModeSupported: false,
421
+ };
422
+ }
423
+ throw new BadRequestError(
424
+ `Managed mode is not available for ${b.provider}. Only providers with platform-managed OAuth support can be switched to managed mode.`,
425
+ );
426
+ }
427
+
428
+ // Require platform connection when switching to managed mode
429
+ if (b.mode === "managed") {
430
+ const client = await VellumPlatformClient.create();
431
+ if (!client) {
432
+ throw new BadRequestError(
433
+ "Not connected to Vellum platform. Run `vellum platform connect` to connect first.",
434
+ );
435
+ }
436
+ }
437
+
438
+ const services: Services = getConfig().services;
439
+ const currentMode = getServiceMode(services, managedKey as keyof Services);
440
+
441
+ if (currentMode === b.mode) {
442
+ return {
443
+ ok: true,
444
+ provider: b.provider,
445
+ mode: b.mode,
446
+ changed: false,
447
+ managedModeSupported: true,
448
+ };
449
+ }
450
+
451
+ const raw = loadRawConfig();
452
+ setNestedValue(raw, `services.${managedKey}.mode`, b.mode);
453
+ saveRawConfig(raw);
454
+
455
+ // Best-effort check for active connections on old and new modes
456
+ let oldModeConnections = 0;
457
+ let newModeConnections = 0;
458
+ if (currentMode === "managed") {
459
+ oldModeConnections = await countManagedConnections(b.provider);
460
+ newModeConnections = listActiveConnectionsByProvider(b.provider).length;
461
+ } else {
462
+ oldModeConnections = listActiveConnectionsByProvider(b.provider).length;
463
+ newModeConnections = await countManagedConnections(b.provider);
464
+ }
465
+
466
+ let hint: string | undefined;
467
+ if (oldModeConnections > 0 && newModeConnections === 0) {
468
+ hint = `No active connections in ${b.mode} mode. Run 'assistant oauth connect ${b.provider}' to connect.`;
469
+ }
470
+
471
+ const result: Record<string, unknown> = {
472
+ ok: true,
473
+ provider: b.provider,
474
+ mode: b.mode,
475
+ changed: true,
476
+ managedModeSupported: true,
477
+ };
478
+ if (hint) result.hint = hint;
479
+ return result;
480
+ }
481
+
482
+ // ---------------------------------------------------------------------------
483
+ // Status handler
484
+ // ---------------------------------------------------------------------------
485
+
486
+ async function handleStatus({ queryParams = {} }: RouteHandlerArgs) {
487
+ const provider = queryParams.provider;
488
+ if (!provider) throw new BadRequestError("provider query param is required");
489
+
490
+ const providerRow = getProvider(provider);
491
+ if (!providerRow) {
492
+ throw new NotFoundError(
493
+ `Unknown provider "${provider}". Run 'assistant oauth providers list' to see available providers.`,
494
+ );
495
+ }
496
+
497
+ const managed = isManagedMode(provider);
498
+
499
+ if (managed) {
500
+ const client = await requirePlatformClient();
501
+ const rawEntries = await fetchActiveConnections(client, provider);
502
+
503
+ const connections = rawEntries.map((c) => ({
504
+ id: c.id,
505
+ account: c.account_label ?? null,
506
+ grantedScopes: c.scopes_granted ?? [],
507
+ status: c.status ?? "ACTIVE",
508
+ }));
509
+
510
+ return {
511
+ ok: true,
512
+ provider,
513
+ mode: "managed",
514
+ connections,
515
+ };
516
+ }
517
+
518
+ // BYO path
519
+ const allConnections = listConnections(provider);
520
+ const activeRows = allConnections.filter((r) => r.status === "active");
521
+
522
+ const connections = activeRows.map((r) => {
523
+ let grantedScopes: string[] = [];
524
+ try {
525
+ grantedScopes = r.grantedScopes ? JSON.parse(r.grantedScopes) : [];
526
+ } catch {
527
+ // Malformed JSON — default to empty
528
+ }
529
+
530
+ return {
531
+ id: r.id,
532
+ account: r.accountInfo ?? null,
533
+ grantedScopes,
534
+ expiresAt: r.expiresAt ? new Date(r.expiresAt).toISOString() : null,
535
+ hasRefreshToken: r.hasRefreshToken === 1,
536
+ status: r.status,
537
+ };
538
+ });
539
+
540
+ return {
541
+ ok: true,
542
+ provider,
543
+ mode: "byo",
544
+ connections,
545
+ };
546
+ }
547
+
548
+ // ---------------------------------------------------------------------------
549
+ // Ping handler
550
+ // ---------------------------------------------------------------------------
551
+
552
+ async function handlePing({ body = {} }: RouteHandlerArgs) {
553
+ const b = body as {
554
+ provider: string;
555
+ account?: string;
556
+ client_id?: string;
557
+ };
558
+
559
+ if (!b.provider) throw new BadRequestError("provider is required");
560
+
561
+ const providerRow = getProvider(b.provider);
562
+ if (!providerRow) {
563
+ throw new NotFoundError(
564
+ `Unknown provider "${b.provider}". Run 'assistant oauth providers list' to see available providers.`,
565
+ );
566
+ }
567
+
568
+ if (!providerRow.pingUrl) {
569
+ throw new BadRequestError(
570
+ `No ping URL configured for "${b.provider}". Register one with 'assistant oauth providers register --ping-url <url>'.`,
571
+ );
572
+ }
573
+
574
+ const pingUrl = providerRow.pingUrl as string;
575
+ const parsed = new URL(pingUrl);
576
+ const baseUrl = `${parsed.protocol}//${parsed.host}`;
577
+ const path = parsed.pathname;
578
+
579
+ const query: Record<string, string> = {};
580
+ for (const [key, value] of parsed.searchParams) {
581
+ query[key] = value;
582
+ }
583
+
584
+ const resolveOptions: ResolveOAuthConnectionOptions = {};
585
+ if (b.account) resolveOptions.account = b.account;
586
+ if (b.client_id) resolveOptions.clientId = b.client_id;
587
+
588
+ const connection = await resolveOAuthConnection(b.provider, resolveOptions);
589
+
590
+ const method = (providerRow.pingMethod as string | null) ?? "GET";
591
+
592
+ const pingHeaders: Record<string, string> = providerRow.pingHeaders
593
+ ? JSON.parse(providerRow.pingHeaders as string)
594
+ : {};
595
+
596
+ const pingBody: unknown = providerRow.pingBody
597
+ ? JSON.parse(providerRow.pingBody as string)
598
+ : undefined;
599
+
600
+ const response = await connection.request({
601
+ method,
602
+ path,
603
+ baseUrl,
604
+ ...(Object.keys(query).length > 0 ? { query } : {}),
605
+ ...(Object.keys(pingHeaders).length > 0 ? { headers: pingHeaders } : {}),
606
+ ...(pingBody !== undefined ? { body: pingBody } : {}),
607
+ });
608
+
609
+ if (response.status >= 200 && response.status < 300) {
610
+ return { ok: true, provider: b.provider, status: response.status };
611
+ }
612
+
613
+ const payload: Record<string, unknown> = {
614
+ ok: false,
615
+ provider: b.provider,
616
+ status: response.status,
617
+ error: `Ping failed with HTTP ${response.status}`,
618
+ };
619
+
620
+ if (response.status === 401 || response.status === 403) {
621
+ payload.hint =
622
+ `Run 'assistant oauth status ${b.provider}' to check connection health. ` +
623
+ `To reconnect, run 'assistant oauth connect --help'.`;
624
+ }
625
+
626
+ return payload;
627
+ }
628
+
629
+ // ---------------------------------------------------------------------------
630
+ // Token handler
631
+ // ---------------------------------------------------------------------------
632
+
633
+ async function handleToken({ body = {} }: RouteHandlerArgs) {
634
+ const b = body as {
635
+ provider: string;
636
+ account?: string;
637
+ client_id?: string;
638
+ };
639
+
640
+ if (!b.provider) throw new BadRequestError("provider is required");
641
+
642
+ if (isManagedMode(b.provider)) {
643
+ throw new BadRequestError(
644
+ "Token retrieval is not supported for platform-managed providers. " +
645
+ "When a provider is in managed mode, Vellum handles OAuth tokens on your behalf — " +
646
+ "they are not exposed directly.\n\n" +
647
+ `To verify your connection is working, run 'assistant oauth ping ${b.provider}'.\n` +
648
+ `To make authenticated requests, use 'assistant oauth request --provider ${b.provider} <url>'.`,
649
+ );
650
+ }
651
+
652
+ let tokenOpts: string | { connectionId: string } | undefined;
653
+
654
+ if (b.account || b.client_id) {
655
+ const conn = getActiveConnection(b.provider, {
656
+ clientId: b.client_id,
657
+ account: b.account,
658
+ });
659
+ if (!conn) {
660
+ const hint = b.account
661
+ ? ` for account "${b.account}"`
662
+ : b.client_id
663
+ ? ` with client ID "${b.client_id}"`
664
+ : "";
665
+ throw new NotFoundError(
666
+ `No active connection found for "${b.provider}"${hint}. Connect first with 'assistant oauth connect ${b.provider}'.`,
667
+ );
668
+ }
669
+ tokenOpts = { connectionId: conn.id };
670
+ }
671
+
672
+ const token = await withValidToken(b.provider, async (t) => t, tokenOpts);
673
+
674
+ return { ok: true, token };
675
+ }
676
+
677
+ // ---------------------------------------------------------------------------
678
+ // Request handler
679
+ // ---------------------------------------------------------------------------
680
+
681
+ function tryJsonParse(raw: string): unknown {
682
+ try {
683
+ return JSON.parse(raw);
684
+ } catch {
685
+ return raw;
686
+ }
687
+ }
688
+
689
+ function readBodyData(data: string): unknown {
690
+ if (data === "@-") {
691
+ const raw = readFileSync("/dev/stdin", "utf-8");
692
+ return tryJsonParse(raw);
693
+ }
694
+
695
+ if (data.startsWith("@")) {
696
+ const filePath = data.slice(1);
697
+ const raw = readFileSync(filePath, "utf-8");
698
+ return tryJsonParse(raw);
699
+ }
700
+
701
+ return tryJsonParse(data);
702
+ }
703
+
704
+ async function handleRequest({ body = {} }: RouteHandlerArgs) {
705
+ const b = body as {
706
+ provider: string;
707
+ url: string;
708
+ method?: string;
709
+ headers?: Record<string, string>;
710
+ /** Pre-parsed body data (file/stdin reading happens CLI-side). */
711
+ parsed_data?: unknown;
712
+ /** Raw data string (for direct API callers, not the CLI). */
713
+ data?: string;
714
+ force_get?: boolean;
715
+ head?: boolean;
716
+ account?: string;
717
+ client_id?: string;
718
+ };
719
+
720
+ if (!b.provider) throw new BadRequestError("provider is required");
721
+ if (!b.url) throw new BadRequestError("url is required");
722
+
723
+ const providerRow = getProvider(b.provider);
724
+ if (!providerRow) {
725
+ throw new NotFoundError(
726
+ `Unknown provider "${b.provider}". Run 'assistant oauth providers list' to see available providers.`,
727
+ );
728
+ }
729
+
730
+ const managed = isManagedMode(b.provider);
731
+
732
+ if (b.client_id) {
733
+ if (managed) {
734
+ log.info("--client-id is ignored for platform-managed providers");
735
+ } else {
736
+ const app = getAppByProviderAndClientId(b.provider, b.client_id);
737
+ if (!app) {
738
+ throw new NotFoundError(
739
+ `No registered OAuth app found for "${b.provider}" with client ID "${b.client_id}".`,
740
+ );
741
+ }
742
+ }
743
+ }
744
+
745
+ // Parse URL
746
+ let baseUrl: string | undefined;
747
+ let requestPath: string;
748
+ const queryFromUrl: Record<string, string | string[]> = {};
749
+
750
+ if (b.url.startsWith("http://") || b.url.startsWith("https://")) {
751
+ const parsed = new URL(b.url);
752
+ assertOAuthRequestUrlAllowed(providerRow, parsed);
753
+ baseUrl = `${parsed.protocol}//${parsed.host}`;
754
+ requestPath = parsed.pathname;
755
+ for (const [key, value] of parsed.searchParams.entries()) {
756
+ const existing = queryFromUrl[key];
757
+ if (existing !== undefined) {
758
+ queryFromUrl[key] = Array.isArray(existing)
759
+ ? [...existing, value]
760
+ : [existing, value];
761
+ } else {
762
+ queryFromUrl[key] = value;
763
+ }
764
+ }
765
+ } else {
766
+ const qIdx = b.url.indexOf("?");
767
+ if (qIdx !== -1) {
768
+ requestPath = b.url.slice(0, qIdx);
769
+ const embeddedParams = new URLSearchParams(b.url.slice(qIdx + 1));
770
+ for (const [key, value] of embeddedParams.entries()) {
771
+ const existing = queryFromUrl[key];
772
+ if (existing !== undefined) {
773
+ queryFromUrl[key] = Array.isArray(existing)
774
+ ? [...existing, value]
775
+ : [existing, value];
776
+ } else {
777
+ queryFromUrl[key] = value;
778
+ }
779
+ }
780
+ } else {
781
+ requestPath = b.url;
782
+ }
783
+ }
784
+
785
+ // Resolve method
786
+ let method: string;
787
+ if (b.head) {
788
+ method = "HEAD";
789
+ } else if (b.method) {
790
+ method = b.method.toUpperCase();
791
+ } else if (b.force_get) {
792
+ method = "GET";
793
+ } else if (b.data !== undefined || b.parsed_data !== undefined) {
794
+ method = "POST";
795
+ } else {
796
+ method = "GET";
797
+ }
798
+
799
+ // Handle body / query params
800
+ let reqBody: unknown = undefined;
801
+ const query: Record<string, string | string[]> = { ...queryFromUrl };
802
+
803
+ // Use pre-parsed data from CLI, or fall back to raw data string for direct API callers
804
+ const resolvedData =
805
+ b.parsed_data !== undefined
806
+ ? b.parsed_data
807
+ : b.data !== undefined
808
+ ? readBodyData(b.data)
809
+ : undefined;
810
+
811
+ if (resolvedData !== undefined) {
812
+ const rawBody = resolvedData;
813
+
814
+ if (b.force_get) {
815
+ if (typeof rawBody === "string") {
816
+ const bodyParams = new URLSearchParams(rawBody);
817
+ for (const [key, value] of bodyParams.entries()) {
818
+ const existing = query[key];
819
+ if (existing !== undefined) {
820
+ query[key] = Array.isArray(existing)
821
+ ? [...existing, value]
822
+ : [existing, value];
823
+ } else {
824
+ query[key] = value;
825
+ }
826
+ }
827
+ } else if (
828
+ rawBody !== null &&
829
+ typeof rawBody === "object" &&
830
+ !Array.isArray(rawBody)
831
+ ) {
832
+ for (const [key, value] of Object.entries(
833
+ rawBody as Record<string, unknown>,
834
+ )) {
835
+ const existing = query[key];
836
+ const strValue = String(value);
837
+ if (existing !== undefined) {
838
+ query[key] = Array.isArray(existing)
839
+ ? [...existing, strValue]
840
+ : [existing, strValue];
841
+ } else {
842
+ query[key] = strValue;
843
+ }
844
+ }
845
+ }
846
+ } else {
847
+ reqBody = rawBody;
848
+ }
849
+ }
850
+
851
+ // Resolve connection and make request
852
+ const resolveOptions: ResolveOAuthConnectionOptions = {};
853
+ if (b.client_id && !managed) {
854
+ resolveOptions.clientId = b.client_id;
855
+ }
856
+ if (b.account) {
857
+ resolveOptions.account = b.account;
858
+ }
859
+
860
+ const connection = await resolveOAuthConnection(b.provider, resolveOptions);
861
+
862
+ const headers = b.headers ?? {};
863
+
864
+ const req: OAuthConnectionRequest = {
865
+ method,
866
+ path: requestPath,
867
+ ...(Object.keys(query).length > 0 ? { query } : {}),
868
+ ...(Object.keys(headers).length > 0 ? { headers } : {}),
869
+ ...(reqBody !== undefined ? { body: reqBody } : {}),
870
+ ...(baseUrl ? { baseUrl } : {}),
871
+ };
872
+
873
+ const response = await connection.request(req);
874
+
875
+ const result: Record<string, unknown> = {
876
+ ok: response.status >= 200 && response.status < 300,
877
+ status: response.status,
878
+ headers: response.headers,
879
+ body: response.body,
880
+ };
881
+
882
+ if (response.status === 401 || response.status === 403) {
883
+ result.hint = managed
884
+ ? `Request returned HTTP ${response.status}. The OAuth token may be expired or revoked.\n\n` +
885
+ `Run 'assistant oauth status ${b.provider}' to check connection health.\n` +
886
+ `To reconnect, run 'assistant oauth connect --help'.`
887
+ : `Request returned HTTP ${response.status}. The OAuth token may be expired or revoked.\n\n` +
888
+ `Run 'assistant oauth status ${b.provider}' to check connection status.\n` +
889
+ `To reconnect, run 'assistant oauth connect --help'.`;
890
+ }
891
+
892
+ return result;
893
+ }
894
+
895
+ // ---------------------------------------------------------------------------
896
+ // Connect handler (managed path for platform OAuth)
897
+ // ---------------------------------------------------------------------------
898
+
899
+ async function handleManagedConnect({ body = {} }: RouteHandlerArgs) {
900
+ const b = body as {
901
+ provider: string;
902
+ scopes?: string[];
903
+ redirect_after_connect?: string;
904
+ };
905
+
906
+ if (!b.provider) throw new BadRequestError("provider is required");
907
+
908
+ const client = await requirePlatformClient();
909
+
910
+ const startPath = `/v1/assistants/${encodeURIComponent(client.platformAssistantId)}/oauth/${encodeURIComponent(b.provider)}/start/`;
911
+
912
+ const reqBody: Record<string, unknown> = {};
913
+ if (b.scopes && b.scopes.length > 0) {
914
+ reqBody.requested_scopes = b.scopes;
915
+ }
916
+ reqBody.redirect_after_connect =
917
+ b.redirect_after_connect ?? "/account/oauth/desktop-complete";
918
+
919
+ const response = await client.fetch(startPath, {
920
+ method: "POST",
921
+ headers: { "Content-Type": "application/json" },
922
+ body: JSON.stringify(reqBody),
923
+ });
924
+
925
+ if (!response.ok) {
926
+ const errorText = await response.text().catch(() => "");
927
+ const baseMsg = `Platform returned HTTP ${response.status}${errorText ? `: ${errorText}` : ""}`;
928
+ if (response.status === 401 || response.status === 403) {
929
+ throw new InternalError(
930
+ `${baseMsg}. Your platform session may have expired. Run \`vellum platform connect\` to reconnect.`,
931
+ );
932
+ }
933
+ throw new InternalError(baseMsg);
934
+ }
935
+
936
+ const result = (await response.json()) as { connect_url?: string };
937
+
938
+ if (!result.connect_url) {
939
+ throw new InternalError(
940
+ "Platform did not return a connect URL — the OAuth flow could not be started",
941
+ );
942
+ }
943
+
944
+ return { ok: true, connect_url: result.connect_url };
945
+ }
946
+
947
+ async function handleManagedConnectPoll({
948
+ queryParams = {},
949
+ }: RouteHandlerArgs) {
950
+ const provider = queryParams.provider;
951
+ if (!provider) throw new BadRequestError("provider query param is required");
952
+
953
+ const client = await requirePlatformClient();
954
+ const entries = await fetchActiveConnections(client, provider);
955
+
956
+ return {
957
+ ok: true,
958
+ connections: entries.map((e) => ({
959
+ id: e.id,
960
+ account_label: e.account_label ?? null,
961
+ scopes_granted: e.scopes_granted ?? [],
962
+ })),
963
+ };
964
+ }
965
+
966
+ // ---------------------------------------------------------------------------
967
+ // Route definitions
968
+ // ---------------------------------------------------------------------------
969
+
970
+ export const ROUTES: RouteDefinition[] = [
971
+ {
972
+ operationId: "oauth_disconnect",
973
+ endpoint: "oauth/disconnect",
974
+ method: "POST",
975
+ policyKey: "oauth/disconnect",
976
+ summary: "Disconnect OAuth provider",
977
+ description:
978
+ "Disconnect an OAuth provider and remove associated credentials (BYO or managed).",
979
+ tags: ["oauth"],
980
+ requirePolicyEnforcement: true,
981
+ handler: handleDisconnect,
982
+ },
983
+ {
984
+ operationId: "oauth_mode_get",
985
+ endpoint: "oauth/mode",
986
+ method: "GET",
987
+ summary: "Get OAuth mode",
988
+ description:
989
+ "Get the current OAuth mode (managed or your-own) for a provider.",
990
+ tags: ["oauth"],
991
+ requirePolicyEnforcement: true,
992
+ queryParams: [
993
+ {
994
+ name: "provider",
995
+ type: "string",
996
+ required: true,
997
+ description: "Provider key",
998
+ },
999
+ ],
1000
+ handler: handleModeGet,
1001
+ },
1002
+ {
1003
+ operationId: "oauth_mode_set",
1004
+ endpoint: "oauth/mode",
1005
+ method: "POST",
1006
+ policyKey: "oauth/mode.set",
1007
+ summary: "Set OAuth mode",
1008
+ description: "Set the OAuth mode (managed or your-own) for a provider.",
1009
+ tags: ["oauth"],
1010
+ requirePolicyEnforcement: true,
1011
+ handler: handleModeSet,
1012
+ },
1013
+ {
1014
+ operationId: "oauth_status",
1015
+ endpoint: "oauth/status",
1016
+ method: "GET",
1017
+ summary: "Get OAuth status",
1018
+ description:
1019
+ "Show OAuth connection status for a specified provider (BYO or managed).",
1020
+ tags: ["oauth"],
1021
+ requirePolicyEnforcement: true,
1022
+ queryParams: [
1023
+ {
1024
+ name: "provider",
1025
+ type: "string",
1026
+ required: true,
1027
+ description: "Provider key",
1028
+ },
1029
+ ],
1030
+ handler: handleStatus,
1031
+ },
1032
+ {
1033
+ operationId: "oauth_ping",
1034
+ endpoint: "oauth/ping",
1035
+ method: "POST",
1036
+ summary: "Ping OAuth provider",
1037
+ description:
1038
+ "Verify an OAuth token is valid by hitting the provider's configured health-check endpoint.",
1039
+ tags: ["oauth"],
1040
+ requirePolicyEnforcement: true,
1041
+ handler: handlePing,
1042
+ },
1043
+ {
1044
+ operationId: "oauth_token",
1045
+ endpoint: "oauth/token",
1046
+ method: "POST",
1047
+ policyKey: "oauth/token",
1048
+ summary: "Get OAuth token",
1049
+ description: "Retrieve a valid OAuth access token for a BYO-mode provider.",
1050
+ tags: ["oauth"],
1051
+ requirePolicyEnforcement: true,
1052
+ handler: handleToken,
1053
+ },
1054
+ {
1055
+ operationId: "oauth_request",
1056
+ endpoint: "oauth/request",
1057
+ method: "POST",
1058
+ policyKey: "oauth/request",
1059
+ summary: "Make authenticated OAuth request",
1060
+ description:
1061
+ "Make an authenticated HTTP request through an OAuth connection (supports curl-like interface).",
1062
+ tags: ["oauth"],
1063
+ requirePolicyEnforcement: true,
1064
+ handler: handleRequest,
1065
+ },
1066
+ {
1067
+ operationId: "oauth_managed_connect_start",
1068
+ endpoint: "oauth/managed-connect/start",
1069
+ method: "POST",
1070
+ policyKey: "oauth/managed-connect.start",
1071
+ summary: "Start managed OAuth connect",
1072
+ description:
1073
+ "Start a managed (platform) OAuth connect flow and return the connect URL.",
1074
+ tags: ["oauth"],
1075
+ requirePolicyEnforcement: true,
1076
+ handler: handleManagedConnect,
1077
+ },
1078
+ {
1079
+ operationId: "oauth_managed_connect_poll",
1080
+ endpoint: "oauth/managed-connect/poll",
1081
+ method: "GET",
1082
+ summary: "Poll managed OAuth connections",
1083
+ description:
1084
+ "Fetch active platform connections for a provider (used to detect new connections after managed connect).",
1085
+ tags: ["oauth"],
1086
+ requirePolicyEnforcement: true,
1087
+ queryParams: [
1088
+ {
1089
+ name: "provider",
1090
+ type: "string",
1091
+ required: true,
1092
+ description: "Provider key",
1093
+ },
1094
+ ],
1095
+ handler: handleManagedConnectPoll,
1096
+ },
1097
+ ];