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