@vellumai/assistant 0.6.2 → 0.6.3
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/bun.lock +40 -40
- package/bunfig.toml +3 -0
- package/docs/architecture/memory.md +1 -1
- package/node_modules/@vellumai/ces-contracts/src/rpc.ts +42 -0
- package/openapi.yaml +184 -69
- package/package.json +41 -41
- package/scripts/generate-openapi.ts +1 -2
- package/src/__tests__/acp-session.test.ts +43 -0
- package/src/__tests__/app-builder-tool-scripts.test.ts +1 -0
- package/src/__tests__/app-executors.test.ts +1 -0
- package/src/__tests__/app-source-watcher.test.ts +37 -11
- package/src/__tests__/approval-routes-http.test.ts +178 -1
- package/src/__tests__/browser-fill-credential.test.ts +229 -94
- package/src/__tests__/browser-manager.test.ts +40 -27
- package/src/__tests__/catalog-files.test.ts +862 -0
- package/src/__tests__/channel-approvals.test.ts +53 -0
- package/src/__tests__/config-managed-gemini-defaults.test.ts +326 -0
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +125 -48
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +23 -0
- package/src/__tests__/context-overflow-approval.test.ts +16 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop.test.ts +1 -1
- package/src/__tests__/conversation-analysis-routes.test.ts +2 -2
- package/src/__tests__/conversation-attachments.test.ts +80 -4
- package/src/__tests__/conversation-confirmation-signals.test.ts +155 -0
- package/src/__tests__/conversation-fork-crud.test.ts +17 -0
- package/src/__tests__/conversation-history-web-search.test.ts +1 -0
- package/src/__tests__/conversation-host-access-routes.test.ts +229 -0
- package/src/__tests__/conversation-inject-context.test.ts +103 -0
- package/src/__tests__/conversation-queue.test.ts +45 -2
- package/src/__tests__/conversation-routes-disk-view.test.ts +5 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +16 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +269 -46
- package/src/__tests__/conversation-starter-routes.test.ts +126 -0
- package/src/__tests__/conversation-starters-cadence.test.ts +161 -0
- package/src/__tests__/conversation-store.test.ts +195 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +193 -0
- package/src/__tests__/credential-execution-approval-bridge.test.ts +32 -1
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/credential-vault-unit.test.ts +4 -4
- package/src/__tests__/credential-vault.test.ts +152 -13
- package/src/__tests__/credentials-cli.test.ts +2 -2
- package/src/__tests__/date-context.test.ts +4 -4
- package/src/__tests__/embedding-managed-proxy-selection.test.ts +256 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +155 -0
- package/src/__tests__/fixtures/mock-chrome-extension.ts +375 -0
- package/src/__tests__/gateway-only-guard.test.ts +3 -0
- package/src/__tests__/gemini-provider.test.ts +2 -2
- package/src/__tests__/guardian-routing-invariants.test.ts +70 -2
- package/src/__tests__/headless-browser-interactions.test.ts +707 -371
- package/src/__tests__/headless-browser-navigate.test.ts +389 -47
- package/src/__tests__/headless-browser-read-tools.test.ts +266 -103
- package/src/__tests__/headless-browser-snapshot.test.ts +240 -77
- package/src/__tests__/host-bash-proxy.test.ts +150 -1
- package/src/__tests__/host-browser-e2e-cloud.test.ts +462 -0
- package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +286 -0
- package/src/__tests__/host-browser-e2e-self-hosted.test.ts +374 -0
- package/src/__tests__/host-browser-event-routes.test.ts +350 -0
- package/src/__tests__/host-browser-proxy.test.ts +444 -0
- package/src/__tests__/host-browser-routes.test.ts +198 -0
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +320 -0
- package/src/__tests__/host-cu-proxy.test.ts +171 -1
- package/src/__tests__/host-file-proxy.test.ts +185 -1
- package/src/__tests__/host-file-read-tool.test.ts +52 -0
- package/src/__tests__/host-proxy-interface.test.ts +165 -0
- package/src/__tests__/host-shell-tool.test.ts +1 -11
- package/src/__tests__/http-user-message-parity.test.ts +1 -0
- package/src/__tests__/integration-status.test.ts +6 -7
- package/src/__tests__/list-messages-tool-merge.test.ts +37 -12
- package/src/__tests__/mcp-client-auth.test.ts +40 -4
- package/src/__tests__/mcp-health-check.test.ts +10 -3
- package/src/__tests__/migration-cross-version-compatibility.test.ts +3 -1
- package/src/__tests__/migration-export-http.test.ts +61 -2
- package/src/__tests__/migration-export-streaming.test.ts +66 -0
- package/src/__tests__/migration-import-commit-http.test.ts +101 -1
- package/src/__tests__/native-host-marker-sync-guard.test.ts +157 -0
- package/src/__tests__/oauth-apps-routes.test.ts +17 -12
- package/src/__tests__/oauth-cli.test.ts +707 -60
- package/src/__tests__/oauth-connect-orchestrator.test.ts +116 -24
- package/src/__tests__/oauth-provider-seed-logos.test.ts +23 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +146 -10
- package/src/__tests__/oauth-provider-visibility.test.ts +19 -21
- package/src/__tests__/oauth-providers-routes.test.ts +50 -14
- package/src/__tests__/oauth-store.test.ts +1386 -182
- package/src/__tests__/oauth2-gateway-transport.test.ts +211 -20
- package/src/__tests__/onboarding-template-contract.test.ts +75 -57
- package/src/__tests__/openai-provider.test.ts +2 -2
- package/src/__tests__/outlook-categories.test.ts +1 -1
- package/src/__tests__/outlook-client-automation.test.ts +1 -1
- package/src/__tests__/outlook-compose-tools.test.ts +1 -1
- package/src/__tests__/outlook-email-watcher.test.ts +1 -1
- package/src/__tests__/outlook-follow-up.test.ts +1 -1
- package/src/__tests__/outlook-messaging-provider.test.ts +2 -2
- package/src/__tests__/outlook-trash.test.ts +1 -1
- package/src/__tests__/outlook-unsubscribe.test.ts +1 -1
- package/src/__tests__/permission-checker-host-gate.test.ts +74 -14
- package/src/__tests__/permission-mode.test.ts +28 -56
- package/src/__tests__/platform-callback-registration.test.ts +19 -0
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +296 -0
- package/src/__tests__/proxy-approval-callback.test.ts +18 -0
- package/src/__tests__/require-fresh-approval.test.ts +40 -1
- package/src/__tests__/sanitize-config-for-transfer.test.ts +132 -0
- package/src/__tests__/schedule-routes.test.ts +162 -0
- package/src/__tests__/secret-detection-handler.test.ts +84 -0
- package/src/__tests__/secret-ingress-http.test.ts +1 -0
- package/src/__tests__/send-endpoint-busy.test.ts +3 -0
- package/src/__tests__/set-permission-mode.test.ts +13 -250
- package/src/__tests__/skills-file-content-endpoint.test.ts +670 -0
- package/src/__tests__/skills-files-catalog-fallback.test.ts +450 -0
- package/src/__tests__/slack-channel-config.test.ts +12 -15
- package/src/__tests__/subagent-detail.test.ts +44 -2
- package/src/__tests__/subagent-disposal.test.ts +1 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +291 -0
- package/src/__tests__/subagent-fork-spawn.test.ts +384 -0
- package/src/__tests__/subagent-manager-notify.test.ts +1 -0
- package/src/__tests__/subagent-notify-parent.test.ts +1 -0
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +411 -0
- package/src/__tests__/subagent-tools.test.ts +1 -0
- package/src/__tests__/subagent-types.test.ts +1 -0
- package/src/__tests__/system-prompt-ask-mode.test.ts +27 -71
- package/src/__tests__/system-prompt.test.ts +72 -1
- package/src/__tests__/task-scheduler.test.ts +32 -6
- package/src/__tests__/telegram-config.test.ts +10 -13
- package/src/__tests__/terminal-tools.test.ts +9 -0
- package/src/__tests__/tool-approval-handler.test.ts +73 -0
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +22 -0
- package/src/__tests__/top-level-renderer.test.ts +73 -1
- package/src/__tests__/transport-hints-queue.test.ts +14 -29
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +109 -0
- package/src/__tests__/v2-consent-policy.test.ts +103 -0
- package/src/acp/client-handler.ts +30 -4
- package/src/agent/loop.ts +12 -6
- package/src/approvals/guardian-request-resolvers.ts +21 -15
- package/src/browser-session/__tests__/manager.test.ts +297 -0
- package/src/browser-session/backends/cdp-inspect.ts +30 -0
- package/src/browser-session/backends/extension.ts +26 -0
- package/src/browser-session/backends/local.ts +24 -0
- package/src/browser-session/events.ts +164 -0
- package/src/browser-session/index.ts +27 -0
- package/src/browser-session/manager.ts +159 -0
- package/src/browser-session/types.ts +28 -0
- package/src/channels/__tests__/types.test.ts +134 -0
- package/src/channels/types.ts +53 -3
- package/src/cli/commands/browser-relay.ts +339 -409
- package/src/cli/commands/credentials.ts +3 -3
- package/src/cli/commands/email.ts +18 -13
- package/src/cli/commands/mcp.ts +16 -4
- package/src/cli/commands/oauth/__tests__/connect.test.ts +44 -44
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +21 -21
- package/src/cli/commands/oauth/__tests__/mode.test.ts +17 -17
- package/src/cli/commands/oauth/__tests__/ping.test.ts +16 -16
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +31 -33
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +329 -0
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +116 -12
- package/src/cli/commands/oauth/__tests__/status.test.ts +10 -10
- package/src/cli/commands/oauth/__tests__/token.test.ts +7 -7
- package/src/cli/commands/oauth/apps.ts +7 -4
- package/src/cli/commands/oauth/connect.ts +6 -3
- package/src/cli/commands/oauth/disconnect.ts +1 -1
- package/src/cli/commands/oauth/providers.ts +200 -36
- package/src/cli/commands/oauth/shared.ts +5 -5
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +259 -0
- package/src/cli/commands/platform/index.ts +107 -10
- package/src/cli/commands/usage.ts +10 -9
- package/src/cli/lib/daemon-credential-client.ts +4 -0
- package/src/cli/program.ts +1 -1
- package/src/config/bundled-skills/app-builder/SKILL.md +26 -249
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +105 -0
- package/src/config/bundled-skills/app-builder/references/INTERACTION_HOOKS.md +56 -0
- package/src/config/bundled-skills/app-builder/references/WIDGETS.md +125 -0
- package/src/config/bundled-skills/contacts/SKILL.md +3 -0
- package/src/config/bundled-skills/document/SKILL.md +4 -0
- package/src/config/bundled-skills/gmail/SKILL.md +1 -1
- package/src/config/bundled-skills/outlook/SKILL.md +7 -0
- package/src/config/bundled-skills/subagent/SKILL.md +21 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +8 -4
- package/src/config/bundled-skills/tasks/SKILL.md +5 -0
- package/src/config/env-registry.ts +14 -0
- package/src/config/env.ts +21 -0
- package/src/config/feature-flag-registry.json +44 -5
- package/src/config/loader.ts +56 -1
- package/src/config/sanitize-for-transfer.ts +47 -0
- package/src/config/schema.ts +46 -5
- package/src/config/schemas/host-browser.ts +66 -0
- package/src/config/schemas/memory-lifecycle.ts +1 -1
- package/src/config/schemas/memory-retrieval.ts +103 -0
- package/src/config/schemas/security.ts +0 -6
- package/src/config/schemas/services.ts +8 -0
- package/src/config/types.ts +0 -1
- package/src/context/post-turn-tool-result-truncation.ts +176 -0
- package/src/context/window-manager.ts +19 -1
- package/src/credential-execution/approval-bridge.ts +49 -15
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +186 -0
- package/src/daemon/app-source-watcher.ts +35 -0
- package/src/daemon/context-overflow-approval.ts +5 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +17 -2
- package/src/daemon/conversation-agent-loop.ts +58 -24
- package/src/daemon/conversation-attachments.ts +40 -0
- package/src/daemon/conversation-process.ts +48 -1
- package/src/daemon/conversation-runtime-assembly.ts +118 -36
- package/src/daemon/conversation-surfaces.ts +37 -36
- package/src/daemon/conversation-tool-setup.ts +74 -8
- package/src/daemon/conversation-workspace.ts +12 -0
- package/src/daemon/conversation.ts +226 -8
- package/src/daemon/date-context.ts +10 -10
- package/src/daemon/first-greeting.ts +3 -2
- package/src/daemon/handlers/conversations.ts +9 -140
- package/src/daemon/handlers/shared.ts +58 -0
- package/src/daemon/handlers/skills.ts +232 -37
- package/src/daemon/host-bash-proxy.ts +48 -13
- package/src/daemon/host-browser-proxy.ts +191 -0
- package/src/daemon/host-cu-proxy.ts +36 -11
- package/src/daemon/host-file-proxy.ts +57 -9
- package/src/daemon/lifecycle.ts +65 -11
- package/src/daemon/message-protocol.ts +7 -0
- package/src/daemon/message-types/conversations.ts +55 -13
- package/src/daemon/message-types/host-browser.ts +100 -0
- package/src/daemon/message-types/messages.ts +5 -5
- package/src/daemon/message-types/skills.ts +10 -0
- package/src/daemon/message-types/subagents.ts +2 -0
- package/src/daemon/server.ts +92 -12
- package/src/daemon/tool-side-effects.ts +6 -0
- package/src/daemon/transport-hints.ts +5 -24
- package/src/inbound/platform-callback-registration.ts +18 -17
- package/src/mcp/client.ts +59 -24
- package/src/memory/app-store.ts +31 -1
- package/src/memory/conversation-crud.ts +23 -0
- package/src/memory/conversation-starters-cadence.ts +76 -0
- package/src/memory/conversation-title-service.ts +5 -2
- package/src/memory/db-init.ts +12 -0
- package/src/memory/embedding-backend.test.ts +75 -0
- package/src/memory/embedding-backend.ts +131 -5
- package/src/memory/embedding-gemini.test.ts +54 -0
- package/src/memory/embedding-gemini.ts +20 -9
- package/src/memory/embedding-local.ts +176 -17
- package/src/memory/graph/consolidation.ts +10 -23
- package/src/memory/graph/extraction-job.ts +15 -0
- package/src/memory/graph/retriever.ts +40 -22
- package/src/memory/graph/store.test.ts +7 -3
- package/src/memory/graph/store.ts +47 -12
- package/src/memory/llm-usage-store.ts +45 -4
- package/src/memory/migrations/213-oauth-providers-scope-separator.ts +13 -0
- package/src/memory/migrations/214-oauth-providers-refresh-url.ts +11 -0
- package/src/memory/migrations/215-oauth-providers-revoke.ts +14 -0
- package/src/memory/migrations/216-oauth-providers-token-auth-method.ts +30 -0
- package/src/memory/migrations/217-conversation-host-access.ts +40 -0
- package/src/memory/migrations/218-oauth-providers-logo-url.ts +11 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/schema/conversations.ts +1 -0
- package/src/memory/schema/oauth.ts +18 -13
- package/src/oauth/AGENTS.md +76 -0
- package/src/oauth/__tests__/identity-verifier.test.ts +24 -19
- package/src/oauth/__tests__/seed-providers-managed.test.ts +32 -0
- package/src/oauth/byo-connection.test.ts +8 -8
- package/src/oauth/byo-connection.ts +7 -7
- package/src/oauth/connect-orchestrator.ts +23 -21
- package/src/oauth/connect-types.ts +3 -3
- package/src/oauth/connection-resolver.test.ts +17 -4
- package/src/oauth/connection-resolver.ts +16 -16
- package/src/oauth/connection.ts +1 -1
- package/src/oauth/manual-token-connection.ts +13 -13
- package/src/oauth/oauth-store.ts +214 -100
- package/src/oauth/platform-connection.test.ts +3 -3
- package/src/oauth/platform-connection.ts +4 -4
- package/src/oauth/provider-serializer.ts +31 -5
- package/src/oauth/revoke.ts +76 -0
- package/src/oauth/seed-providers.ts +126 -87
- package/src/oauth/token-persistence.ts +1 -1
- package/src/permissions/permission-mode.ts +4 -11
- package/src/permissions/prompter.ts +13 -1
- package/src/permissions/v2-consent-policy.ts +87 -0
- package/src/prompts/system-prompt.ts +18 -21
- package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +3 -65
- package/src/prompts/templates/BOOTSTRAP.md +59 -105
- package/src/providers/anthropic/client.ts +1 -0
- package/src/providers/types.ts +1 -1
- package/src/runtime/AGENTS.md +23 -0
- package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +715 -0
- package/src/runtime/__tests__/capability-tokens.test.ts +258 -0
- package/src/runtime/__tests__/chrome-extension-registry.test.ts +518 -0
- package/src/runtime/assistant-event-hub.ts +2 -2
- package/src/runtime/auth/__tests__/guard-tests.test.ts +1 -0
- package/src/runtime/auth/__tests__/middleware.test.ts +116 -1
- package/src/runtime/auth/__tests__/route-policy.test.ts +8 -0
- package/src/runtime/auth/middleware.ts +98 -0
- package/src/runtime/auth/route-policy.ts +6 -7
- package/src/runtime/capability-tokens.ts +414 -0
- package/src/runtime/channel-approvals.ts +18 -5
- package/src/runtime/chrome-extension-registry.ts +332 -0
- package/src/runtime/confirmation-request-guardian-bridge.ts +6 -0
- package/src/runtime/guardian-decision-types.ts +7 -0
- package/src/runtime/http-server.ts +425 -70
- package/src/runtime/migrations/__tests__/rebind-secrets-credentials.test.ts +172 -0
- package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +276 -0
- package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +162 -0
- package/src/runtime/migrations/migration-transport.ts +6 -0
- package/src/runtime/migrations/migration-wizard.ts +22 -2
- package/src/runtime/migrations/rebind-secrets-screen.ts +76 -15
- package/src/runtime/migrations/vbundle-builder.ts +145 -38
- package/src/runtime/migrations/vbundle-import-analyzer.ts +19 -0
- package/src/runtime/migrations/vbundle-importer.ts +55 -5
- package/src/runtime/pending-interactions.ts +29 -13
- package/src/runtime/routes/approval-routes.ts +90 -16
- package/src/runtime/routes/browser-cdp-routes.ts +229 -0
- package/src/runtime/routes/browser-extension-pair-routes.ts +497 -0
- package/src/runtime/routes/conversation-analysis-routes.ts +2 -1
- package/src/runtime/routes/conversation-management-routes.ts +108 -0
- package/src/runtime/routes/conversation-routes.ts +301 -27
- package/src/runtime/routes/conversation-starter-routes.ts +78 -16
- package/src/runtime/routes/guardian-action-routes.ts +24 -13
- package/src/runtime/routes/host-browser-routes.ts +279 -0
- package/src/runtime/routes/host-file-routes.ts +9 -1
- package/src/runtime/routes/identity-routes.ts +259 -16
- package/src/runtime/routes/log-export-routes.ts +42 -22
- package/src/runtime/routes/memory-item-routes.ts +1 -7
- package/src/runtime/routes/migration-routes.ts +87 -2
- package/src/runtime/routes/oauth-apps.ts +15 -17
- package/src/runtime/routes/oauth-providers.ts +4 -0
- package/src/runtime/routes/schedule-routes.ts +24 -11
- package/src/runtime/routes/settings-routes.ts +9 -97
- package/src/runtime/routes/skills-routes.ts +52 -2
- package/src/runtime/routes/subagents-routes.ts +14 -10
- package/src/runtime/routes/usage-routes.ts +8 -7
- package/src/runtime/routes/workspace-routes.test.ts +22 -0
- package/src/runtime/routes/workspace-routes.ts +8 -1
- package/src/runtime/routes/workspace-utils.ts +2 -0
- package/src/schedule/scheduler.ts +7 -5
- package/src/security/ces-credential-client.ts +20 -0
- package/src/security/ces-rpc-credential-backend.ts +17 -0
- package/src/security/credential-backend.ts +5 -0
- package/src/security/oauth2.ts +42 -25
- package/src/security/secure-keys.ts +118 -25
- package/src/security/token-manager.ts +23 -10
- package/src/skills/catalog-files.ts +492 -0
- package/src/subagent/manager.ts +131 -26
- package/src/subagent/types.ts +19 -0
- package/src/tools/apps/executors.ts +11 -2
- package/src/tools/browser/__tests__/auth-detector.test.ts +202 -108
- package/src/tools/browser/auth-detector.ts +43 -12
- package/src/tools/browser/browser-execution.ts +645 -340
- package/src/tools/browser/browser-manager.ts +36 -12
- package/src/tools/browser/cdp-client/__tests__/accessibility-snapshot.test.ts +318 -0
- package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +1175 -0
- package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +870 -0
- package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +330 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +377 -0
- package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-nested-frames.json +64 -0
- package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-simple.json +69 -0
- package/src/tools/browser/cdp-client/__tests__/local-cdp-client.test.ts +310 -0
- package/src/tools/browser/cdp-client/__tests__/types.test.ts +96 -0
- package/src/tools/browser/cdp-client/accessibility-snapshot.ts +387 -0
- package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +695 -0
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +743 -0
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +580 -0
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +578 -0
- package/src/tools/browser/cdp-client/cdp-inspect/ws-transport.ts +579 -0
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +635 -0
- package/src/tools/browser/cdp-client/errors.ts +34 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +125 -0
- package/src/tools/browser/cdp-client/factory.ts +204 -0
- package/src/tools/browser/cdp-client/index.ts +14 -0
- package/src/tools/browser/cdp-client/local-cdp-client.ts +187 -0
- package/src/tools/browser/cdp-client/types.ts +52 -0
- package/src/tools/filesystem/edit.ts +1 -1
- package/src/tools/filesystem/list.ts +1 -1
- package/src/tools/filesystem/read.ts +1 -1
- package/src/tools/filesystem/write.ts +2 -1
- package/src/tools/host-filesystem/edit.ts +1 -1
- package/src/tools/host-filesystem/read.ts +12 -15
- package/src/tools/host-filesystem/write.ts +1 -1
- package/src/tools/host-terminal/host-shell.ts +21 -16
- package/src/tools/permission-checker.ts +77 -82
- package/src/tools/registry.ts +0 -2
- package/src/tools/secret-detection-handler.ts +34 -0
- package/src/tools/shared/filesystem/image-read.ts +61 -40
- package/src/tools/subagent/spawn.ts +47 -3
- package/src/tools/subagent/status.ts +2 -0
- package/src/tools/system/register.ts +2 -16
- package/src/tools/terminal/safe-env.ts +7 -0
- package/src/tools/terminal/shell.ts +21 -16
- package/src/tools/tool-approval-handler.ts +48 -2
- package/src/tools/types.ts +2 -0
- package/src/util/platform.ts +14 -19
- package/src/workspace/top-level-renderer.ts +19 -1
- package/src/__tests__/chrome-cdp.test.ts +0 -419
- package/src/__tests__/permission-mode-sse.test.ts +0 -418
- package/src/__tests__/permission-mode-store.test.ts +0 -277
- package/src/browser-extension-relay/protocol.ts +0 -63
- package/src/browser-extension-relay/server.ts +0 -203
- package/src/config/schemas/sandbox.ts +0 -14
- package/src/permissions/permission-mode-store.ts +0 -180
- package/src/tools/browser/chrome-cdp.ts +0 -239
- package/src/tools/system/set-permission-mode.ts +0 -103
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
draftSkill,
|
|
20
20
|
enableSkill,
|
|
21
21
|
getSkill,
|
|
22
|
+
getSkillFileContent,
|
|
22
23
|
getSkillFiles,
|
|
23
24
|
inspectSkill,
|
|
24
25
|
installSkill,
|
|
@@ -151,6 +152,55 @@ export function skillRouteDefinitions(deps: SkillRouteDeps): RouteDefinition[] {
|
|
|
151
152
|
},
|
|
152
153
|
},
|
|
153
154
|
|
|
155
|
+
// The router uses strict anchored-regex matching, so this route is never
|
|
156
|
+
// ambiguous with skills/:id/files.
|
|
157
|
+
{
|
|
158
|
+
endpoint: "skills/:id/files/content",
|
|
159
|
+
method: "GET",
|
|
160
|
+
policyKey: "skills",
|
|
161
|
+
summary: "Get skill file content",
|
|
162
|
+
description:
|
|
163
|
+
"Return the content of a single file belonging to an installed or catalog skill.",
|
|
164
|
+
tags: ["skills"],
|
|
165
|
+
queryParams: [
|
|
166
|
+
{
|
|
167
|
+
name: "path",
|
|
168
|
+
schema: { type: "string" },
|
|
169
|
+
required: true,
|
|
170
|
+
description: "Relative path of the file within the skill directory",
|
|
171
|
+
},
|
|
172
|
+
],
|
|
173
|
+
responseBody: z.object({
|
|
174
|
+
path: z.string(),
|
|
175
|
+
name: z.string(),
|
|
176
|
+
size: z.number().int(),
|
|
177
|
+
mimeType: z.string(),
|
|
178
|
+
isBinary: z.boolean(),
|
|
179
|
+
content: z.string().nullable(),
|
|
180
|
+
}),
|
|
181
|
+
handler: async ({ params, url }) => {
|
|
182
|
+
const path = url.searchParams.get("path");
|
|
183
|
+
if (!path) {
|
|
184
|
+
return httpError(
|
|
185
|
+
"BAD_REQUEST",
|
|
186
|
+
"path query parameter is required",
|
|
187
|
+
400,
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
const result = await getSkillFileContent(params.id, path, ctx());
|
|
191
|
+
if ("error" in result) {
|
|
192
|
+
if (result.status === 400) {
|
|
193
|
+
return httpError("BAD_REQUEST", result.error, 400);
|
|
194
|
+
}
|
|
195
|
+
if (result.status === 404) {
|
|
196
|
+
return httpError("NOT_FOUND", result.error, 404);
|
|
197
|
+
}
|
|
198
|
+
return httpError("INTERNAL_ERROR", result.error, 500);
|
|
199
|
+
}
|
|
200
|
+
return Response.json(result);
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
|
|
154
204
|
{
|
|
155
205
|
endpoint: "skills/:id/files",
|
|
156
206
|
method: "GET",
|
|
@@ -158,8 +208,8 @@ export function skillRouteDefinitions(deps: SkillRouteDeps): RouteDefinition[] {
|
|
|
158
208
|
summary: "Get skill files",
|
|
159
209
|
description: "Return skill metadata and directory contents.",
|
|
160
210
|
tags: ["skills"],
|
|
161
|
-
handler: ({ params }) => {
|
|
162
|
-
const result = getSkillFiles(params.id, ctx());
|
|
211
|
+
handler: async ({ params }) => {
|
|
212
|
+
const result = await getSkillFiles(params.id, ctx());
|
|
163
213
|
if ("error" in result) {
|
|
164
214
|
if (result.status === 404) {
|
|
165
215
|
return httpError("NOT_FOUND", result.error, 404);
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
|
|
10
|
-
import { getMessages } from "../../memory/conversation-crud.js";
|
|
10
|
+
import { getMessages, type MessageRow } from "../../memory/conversation-crud.js";
|
|
11
11
|
import { getSubagentManager } from "../../subagent/index.js";
|
|
12
12
|
import { getLogger } from "../../util/logger.js";
|
|
13
13
|
import { httpError } from "../http-errors.js";
|
|
@@ -31,16 +31,25 @@ export interface SubagentDetailResult {
|
|
|
31
31
|
content: string;
|
|
32
32
|
toolName?: string;
|
|
33
33
|
isError?: boolean;
|
|
34
|
+
messageId?: string;
|
|
34
35
|
}>;
|
|
35
36
|
}
|
|
36
37
|
|
|
38
|
+
const FORK_DIRECTIVE_RE =
|
|
39
|
+
/^⎯⎯⎯ FORK TASK ⎯⎯⎯\n[\s\S]*?Complete this task directly and return only your findings:\n\n([\s\S]*?)\n⎯⎯⎯+$/;
|
|
40
|
+
|
|
41
|
+
function stripForkDirectiveFraming(text: string): string {
|
|
42
|
+
const match = FORK_DIRECTIVE_RE.exec(text);
|
|
43
|
+
return match ? match[1] : text;
|
|
44
|
+
}
|
|
45
|
+
|
|
37
46
|
/**
|
|
38
47
|
* Parse raw message rows into subagent detail events. Extracted as a pure
|
|
39
48
|
* function so it can be unit-tested without a database.
|
|
40
49
|
*/
|
|
41
50
|
export function parseSubagentMessages(
|
|
42
51
|
subagentId: string,
|
|
43
|
-
messages:
|
|
52
|
+
messages: MessageRow[],
|
|
44
53
|
): SubagentDetailResult {
|
|
45
54
|
// Extract objective from the first user message
|
|
46
55
|
let objective: string | undefined;
|
|
@@ -53,7 +62,7 @@ export function parseSubagentMessages(
|
|
|
53
62
|
(b: Record<string, unknown>) => isRecord(b) && b.type === "text",
|
|
54
63
|
);
|
|
55
64
|
if (textBlock && typeof textBlock.text === "string") {
|
|
56
|
-
objective = textBlock.text;
|
|
65
|
+
objective = stripForkDirectiveFraming(textBlock.text);
|
|
57
66
|
}
|
|
58
67
|
}
|
|
59
68
|
} catch {
|
|
@@ -62,12 +71,7 @@ export function parseSubagentMessages(
|
|
|
62
71
|
}
|
|
63
72
|
|
|
64
73
|
// Extract events from both assistant and user messages.
|
|
65
|
-
const events:
|
|
66
|
-
type: string;
|
|
67
|
-
content: string;
|
|
68
|
-
toolName?: string;
|
|
69
|
-
isError?: boolean;
|
|
70
|
-
}> = [];
|
|
74
|
+
const events: SubagentDetailResult["events"] = [];
|
|
71
75
|
const pendingTools = new Map<string, string>();
|
|
72
76
|
for (const m of messages) {
|
|
73
77
|
if (m.role !== "assistant" && m.role !== "user") continue;
|
|
@@ -86,7 +90,7 @@ export function parseSubagentMessages(
|
|
|
86
90
|
block.type === "text" &&
|
|
87
91
|
typeof block.text === "string"
|
|
88
92
|
) {
|
|
89
|
-
events.push({ type: "text", content: block.text });
|
|
93
|
+
events.push({ type: "text", content: block.text, messageId: m.id });
|
|
90
94
|
} else if (block.type === "tool_use") {
|
|
91
95
|
const name = typeof block.name === "string" ? block.name : "unknown";
|
|
92
96
|
const input = isRecord(block.input)
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* GET /v1/usage/totals?from=&to= — aggregate totals for a time range
|
|
5
5
|
* GET /v1/usage/daily?from=&to= — per-day buckets for a time range
|
|
6
|
-
* GET /v1/usage/breakdown?from=&to=&groupBy= — grouped breakdown (actor, provider, model)
|
|
6
|
+
* GET /v1/usage/breakdown?from=&to=&groupBy= — grouped breakdown (actor, provider, model, or conversation)
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { z } from "zod";
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
import { httpError } from "../http-errors.js";
|
|
18
18
|
import type { RouteDefinition } from "../http-router.js";
|
|
19
19
|
|
|
20
|
-
const VALID_GROUP_BY = new Set(["actor", "provider", "model"]);
|
|
20
|
+
const VALID_GROUP_BY = new Set(["actor", "provider", "model", "conversation"]);
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Parse and validate the `from` and `to` epoch-millis query parameters.
|
|
@@ -137,7 +137,7 @@ export function usageRouteDefinitions(): RouteDefinition[] {
|
|
|
137
137
|
method: "GET",
|
|
138
138
|
summary: "Get usage breakdown",
|
|
139
139
|
description:
|
|
140
|
-
"Return grouped usage breakdown (by actor, provider, or
|
|
140
|
+
"Return grouped usage breakdown (by actor, provider, model, or conversation).",
|
|
141
141
|
tags: ["usage"],
|
|
142
142
|
queryParams: [
|
|
143
143
|
{
|
|
@@ -153,7 +153,8 @@ export function usageRouteDefinitions(): RouteDefinition[] {
|
|
|
153
153
|
{
|
|
154
154
|
name: "groupBy",
|
|
155
155
|
schema: { type: "string" },
|
|
156
|
-
description:
|
|
156
|
+
description:
|
|
157
|
+
"Group by: actor, provider, model, or conversation (required)",
|
|
157
158
|
},
|
|
158
159
|
],
|
|
159
160
|
responseBody: z.object({
|
|
@@ -167,21 +168,21 @@ export function usageRouteDefinitions(): RouteDefinition[] {
|
|
|
167
168
|
if (!groupBy) {
|
|
168
169
|
return httpError(
|
|
169
170
|
"BAD_REQUEST",
|
|
170
|
-
'Missing required query parameter: "groupBy" (one of: actor, provider, model)',
|
|
171
|
+
'Missing required query parameter: "groupBy" (one of: actor, provider, model, conversation)',
|
|
171
172
|
400,
|
|
172
173
|
);
|
|
173
174
|
}
|
|
174
175
|
if (!VALID_GROUP_BY.has(groupBy)) {
|
|
175
176
|
return httpError(
|
|
176
177
|
"BAD_REQUEST",
|
|
177
|
-
`Invalid "groupBy" value: "${groupBy}". Must be one of: actor, provider, model`,
|
|
178
|
+
`Invalid "groupBy" value: "${groupBy}". Must be one of: actor, provider, model, conversation`,
|
|
178
179
|
400,
|
|
179
180
|
);
|
|
180
181
|
}
|
|
181
182
|
|
|
182
183
|
const breakdown = getUsageGroupBreakdown(
|
|
183
184
|
range,
|
|
184
|
-
groupBy as "actor" | "provider" | "model",
|
|
185
|
+
groupBy as "actor" | "provider" | "model" | "conversation",
|
|
185
186
|
);
|
|
186
187
|
return Response.json({ breakdown });
|
|
187
188
|
},
|
|
@@ -190,6 +190,28 @@ describe("isTextMimeType", () => {
|
|
|
190
190
|
// A binary plist has a specific MIME type — extension should not override it
|
|
191
191
|
expect(isTextMimeType("application/x-plist", "Info.plist")).toBe(false);
|
|
192
192
|
});
|
|
193
|
+
|
|
194
|
+
test("application/octet-stream with .jsonl filename is text", () => {
|
|
195
|
+
expect(isTextMimeType("application/octet-stream", "messages.jsonl")).toBe(
|
|
196
|
+
true,
|
|
197
|
+
);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
test("application/octet-stream with .ndjson filename is text", () => {
|
|
201
|
+
expect(isTextMimeType("application/octet-stream", "events.ndjson")).toBe(
|
|
202
|
+
true,
|
|
203
|
+
);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
test("application/octet-stream with .JSONL uppercase is text", () => {
|
|
207
|
+
expect(isTextMimeType("application/octet-stream", "DATA.JSONL")).toBe(true);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
test("application/octet-stream with .NDJSON uppercase is text", () => {
|
|
211
|
+
expect(isTextMimeType("application/octet-stream", "DATA.NDJSON")).toBe(
|
|
212
|
+
true,
|
|
213
|
+
);
|
|
214
|
+
});
|
|
193
215
|
});
|
|
194
216
|
|
|
195
217
|
// ===========================================================================
|
|
@@ -120,7 +120,14 @@ function handleWorkspaceFile(ctx: RouteContext): Response {
|
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
const mimeType = Bun.file(resolved).type;
|
|
123
|
-
|
|
123
|
+
// Empty files with unknown MIME type default to text — there is no binary
|
|
124
|
+
// content to protect, and files created via the UI "New File" action are
|
|
125
|
+
// always 0 bytes. Without this override, extensionless files (e.g. "Test")
|
|
126
|
+
// would be classified as binary and rendered in a non-editable fallback view.
|
|
127
|
+
const isText =
|
|
128
|
+
stat.size === 0 && mimeType === "application/octet-stream"
|
|
129
|
+
? true
|
|
130
|
+
: isTextMimeType(mimeType, basename(resolved));
|
|
124
131
|
const isBinary = !isText;
|
|
125
132
|
|
|
126
133
|
let content: string | undefined = undefined;
|
|
@@ -23,6 +23,7 @@ const log = getLogger("scheduler");
|
|
|
23
23
|
|
|
24
24
|
export interface ScheduleMessageOptions {
|
|
25
25
|
trustClass?: "guardian" | "trusted_contact" | "unknown";
|
|
26
|
+
taskRunId?: string;
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
export type ScheduleMessageProcessor = (
|
|
@@ -196,11 +197,12 @@ async function runScheduleOnce(
|
|
|
196
197
|
source: "schedule",
|
|
197
198
|
scheduleJobId: job.id,
|
|
198
199
|
},
|
|
199
|
-
|
|
200
|
-
conversationId
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
200
|
+
async (conversationId, message, taskRunId) => {
|
|
201
|
+
await processMessage(conversationId, message, {
|
|
202
|
+
trustClass: "guardian",
|
|
203
|
+
taskRunId,
|
|
204
|
+
});
|
|
205
|
+
},
|
|
204
206
|
);
|
|
205
207
|
|
|
206
208
|
onScheduleConversationCreated?.({
|
|
@@ -190,6 +190,26 @@ export class CesCredentialBackend implements CredentialBackend {
|
|
|
190
190
|
}
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
+
async bulkSet(
|
|
194
|
+
credentials: Array<{ account: string; value: string }>,
|
|
195
|
+
): Promise<Array<{ account: string; ok: boolean }>> {
|
|
196
|
+
try {
|
|
197
|
+
const res = await cesRequest("POST", "/v1/credentials/bulk", {
|
|
198
|
+
credentials,
|
|
199
|
+
});
|
|
200
|
+
if (!res?.ok) {
|
|
201
|
+
return credentials.map((c) => ({ account: c.account, ok: false }));
|
|
202
|
+
}
|
|
203
|
+
const data = (await res.json()) as {
|
|
204
|
+
results: Array<{ account: string; ok: boolean }>;
|
|
205
|
+
};
|
|
206
|
+
return data.results;
|
|
207
|
+
} catch (err) {
|
|
208
|
+
log.warn({ err }, "CES credential bulk set threw unexpectedly");
|
|
209
|
+
return credentials.map((c) => ({ account: c.account, ok: false }));
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
193
213
|
async list(): Promise<CredentialListResult> {
|
|
194
214
|
try {
|
|
195
215
|
const res = await cesRequest("GET", "/v1/credentials");
|
|
@@ -86,4 +86,21 @@ export class CesRpcCredentialBackend implements CredentialBackend {
|
|
|
86
86
|
return { accounts: [], unreachable: true };
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
|
+
|
|
90
|
+
async bulkSet(
|
|
91
|
+
credentials: Array<{ account: string; value: string }>,
|
|
92
|
+
): Promise<Array<{ account: string; ok: boolean }>> {
|
|
93
|
+
if (!this.isAvailable()) {
|
|
94
|
+
return credentials.map((c) => ({ account: c.account, ok: false }));
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
const result = await this.client.call(CesRpcMethod.BulkSetCredentials, {
|
|
98
|
+
credentials,
|
|
99
|
+
});
|
|
100
|
+
return result.results;
|
|
101
|
+
} catch (err) {
|
|
102
|
+
log.warn({ err }, "CES RPC bulk credential set failed");
|
|
103
|
+
return credentials.map((c) => ({ account: c.account, ok: false }));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
89
106
|
}
|
|
@@ -47,6 +47,11 @@ export interface CredentialBackend {
|
|
|
47
47
|
|
|
48
48
|
/** List all account names. */
|
|
49
49
|
list(): Promise<CredentialListResult>;
|
|
50
|
+
|
|
51
|
+
/** Bulk-set multiple credentials. Optional — backends without native bulk support omit this. */
|
|
52
|
+
bulkSet?(
|
|
53
|
+
credentials: Array<{ account: string; value: string }>,
|
|
54
|
+
): Promise<Array<{ account: string; ok: boolean }>>;
|
|
50
55
|
}
|
|
51
56
|
|
|
52
57
|
// ---------------------------------------------------------------------------
|
package/src/security/oauth2.ts
CHANGED
|
@@ -33,13 +33,13 @@ export type TokenEndpointAuthMethod =
|
|
|
33
33
|
| "client_secret_post";
|
|
34
34
|
|
|
35
35
|
export interface OAuth2Config {
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
authorizeUrl: string;
|
|
37
|
+
tokenExchangeUrl: string;
|
|
38
38
|
scopes: string[];
|
|
39
39
|
clientId: string;
|
|
40
40
|
/** Client secret for providers that require it (e.g. Slack). PKCE is always used regardless. */
|
|
41
41
|
clientSecret?: string;
|
|
42
|
-
|
|
42
|
+
authorizeParams?: Record<string, string>;
|
|
43
43
|
/** URL to fetch user identity info after OAuth. If omitted, account info is not fetched. */
|
|
44
44
|
userinfoUrl?: string;
|
|
45
45
|
/**
|
|
@@ -49,6 +49,13 @@ export interface OAuth2Config {
|
|
|
49
49
|
* Defaults to `client_secret_post`.
|
|
50
50
|
*/
|
|
51
51
|
tokenEndpointAuthMethod?: TokenEndpointAuthMethod;
|
|
52
|
+
/**
|
|
53
|
+
* Separator used to join scopes in the authorize URL and split the
|
|
54
|
+
* granted-scope string returned by the token endpoint. Defaults to
|
|
55
|
+
* `" "` (space) per the OAuth 2.0 spec, but providers like Linear
|
|
56
|
+
* use `","` (comma).
|
|
57
|
+
*/
|
|
58
|
+
scopeSeparator: string;
|
|
52
59
|
}
|
|
53
60
|
|
|
54
61
|
export interface OAuth2TokenResult {
|
|
@@ -130,7 +137,7 @@ async function exchangeCodeForTokens(
|
|
|
130
137
|
}
|
|
131
138
|
}
|
|
132
139
|
|
|
133
|
-
const tokenResp = await fetch(config.
|
|
140
|
+
const tokenResp = await fetch(config.tokenExchangeUrl, {
|
|
134
141
|
method: "POST",
|
|
135
142
|
headers,
|
|
136
143
|
body: new URLSearchParams(tokenBody),
|
|
@@ -187,9 +194,19 @@ async function exchangeCodeForTokens(
|
|
|
187
194
|
(tokenData.token_type as string | undefined),
|
|
188
195
|
};
|
|
189
196
|
|
|
197
|
+
// Defensive split: providers (e.g. GitHub, Slack) may return comma-separated
|
|
198
|
+
// scopes in token responses regardless of the scope_separator used to join
|
|
199
|
+
// outbound authorize URLs, so we tolerate both spaces and commas here. When
|
|
200
|
+
// a provider explicitly configures a non-default separator (e.g. Linear uses
|
|
201
|
+
// ","), we honor that to keep symmetric round-tripping of configured scopes.
|
|
202
|
+
const splitPattern =
|
|
203
|
+
config.scopeSeparator === " " ? /[ ,]/ : config.scopeSeparator;
|
|
190
204
|
const grantedScopes =
|
|
191
205
|
typeof tokens.scope === "string"
|
|
192
|
-
? tokens.scope
|
|
206
|
+
? tokens.scope
|
|
207
|
+
.split(splitPattern)
|
|
208
|
+
.map((s) => s.trim())
|
|
209
|
+
.filter(Boolean)
|
|
193
210
|
: [...config.scopes];
|
|
194
211
|
|
|
195
212
|
return { tokens, grantedScopes, rawTokenResponse: tokenData };
|
|
@@ -228,18 +245,18 @@ async function runGatewayFlow(
|
|
|
228
245
|
});
|
|
229
246
|
|
|
230
247
|
const authParams = new URLSearchParams({
|
|
231
|
-
...config.
|
|
248
|
+
...config.authorizeParams,
|
|
232
249
|
client_id: config.clientId,
|
|
233
250
|
redirect_uri: redirectUri,
|
|
234
251
|
response_type: "code",
|
|
235
|
-
scope: config.scopes.join(
|
|
252
|
+
scope: config.scopes.join(config.scopeSeparator),
|
|
236
253
|
state,
|
|
237
254
|
code_challenge: codeChallenge,
|
|
238
255
|
code_challenge_method: "S256",
|
|
239
256
|
});
|
|
240
257
|
|
|
241
|
-
const
|
|
242
|
-
callbacks.openUrl(
|
|
258
|
+
const authorizeUrl = `${config.authorizeUrl}?${authParams}`;
|
|
259
|
+
callbacks.openUrl(authorizeUrl);
|
|
243
260
|
|
|
244
261
|
const code = await codePromise;
|
|
245
262
|
|
|
@@ -401,22 +418,22 @@ function startLoopbackServerAndWaitForCode(
|
|
|
401
418
|
);
|
|
402
419
|
|
|
403
420
|
const authParams = new URLSearchParams({
|
|
404
|
-
...config.
|
|
421
|
+
...config.authorizeParams,
|
|
405
422
|
client_id: config.clientId,
|
|
406
423
|
redirect_uri: boundRedirectUri,
|
|
407
424
|
response_type: "code",
|
|
408
|
-
scope: config.scopes.join(
|
|
425
|
+
scope: config.scopes.join(config.scopeSeparator),
|
|
409
426
|
state,
|
|
410
427
|
code_challenge: codeChallenge,
|
|
411
428
|
code_challenge_method: "S256",
|
|
412
429
|
});
|
|
413
430
|
|
|
414
|
-
const
|
|
431
|
+
const authorizeUrl = `${config.authorizeUrl}?${authParams}`;
|
|
415
432
|
log.info(
|
|
416
|
-
{
|
|
433
|
+
{ authorizeUrlLength: authorizeUrl.length, state },
|
|
417
434
|
"oauth2 loopback: built auth URL, calling openUrl callback",
|
|
418
435
|
);
|
|
419
|
-
callbacks.openUrl(
|
|
436
|
+
callbacks.openUrl(authorizeUrl);
|
|
420
437
|
log.info("oauth2 loopback: openUrl callback returned");
|
|
421
438
|
});
|
|
422
439
|
|
|
@@ -439,7 +456,7 @@ function startLoopbackServerAndWaitForCode(
|
|
|
439
456
|
// ---------------------------------------------------------------------------
|
|
440
457
|
|
|
441
458
|
export interface OAuth2PreparedFlow {
|
|
442
|
-
|
|
459
|
+
authorizeUrl: string;
|
|
443
460
|
state: string;
|
|
444
461
|
/** Resolves when the user completes authorization and tokens are exchanged. */
|
|
445
462
|
completion: Promise<OAuth2FlowResult>;
|
|
@@ -493,17 +510,17 @@ export async function prepareOAuth2Flow(
|
|
|
493
510
|
});
|
|
494
511
|
|
|
495
512
|
const authParams = new URLSearchParams({
|
|
496
|
-
...config.
|
|
513
|
+
...config.authorizeParams,
|
|
497
514
|
client_id: config.clientId,
|
|
498
515
|
redirect_uri: redirectUri,
|
|
499
516
|
response_type: "code",
|
|
500
|
-
scope: config.scopes.join(
|
|
517
|
+
scope: config.scopes.join(config.scopeSeparator),
|
|
501
518
|
state,
|
|
502
519
|
code_challenge: codeChallenge,
|
|
503
520
|
code_challenge_method: "S256",
|
|
504
521
|
});
|
|
505
522
|
|
|
506
|
-
const
|
|
523
|
+
const authorizeUrl = `${config.authorizeUrl}?${authParams}`;
|
|
507
524
|
|
|
508
525
|
const completion = codePromise.then(async (code) => {
|
|
509
526
|
return await exchangeCodeForTokens(config, code, redirectUri, codeVerifier);
|
|
@@ -511,7 +528,7 @@ export async function prepareOAuth2Flow(
|
|
|
511
528
|
|
|
512
529
|
log.debug({ transport: "gateway", state }, "Prepared deferred OAuth2 flow");
|
|
513
530
|
|
|
514
|
-
return {
|
|
531
|
+
return { authorizeUrl, state, completion };
|
|
515
532
|
}
|
|
516
533
|
|
|
517
534
|
/**
|
|
@@ -533,17 +550,17 @@ async function prepareLoopbackFlow(
|
|
|
533
550
|
);
|
|
534
551
|
|
|
535
552
|
const authParams = new URLSearchParams({
|
|
536
|
-
...config.
|
|
553
|
+
...config.authorizeParams,
|
|
537
554
|
client_id: config.clientId,
|
|
538
555
|
redirect_uri: redirectUri,
|
|
539
556
|
response_type: "code",
|
|
540
|
-
scope: config.scopes.join(
|
|
557
|
+
scope: config.scopes.join(config.scopeSeparator),
|
|
541
558
|
state,
|
|
542
559
|
code_challenge: codeChallenge,
|
|
543
560
|
code_challenge_method: "S256",
|
|
544
561
|
});
|
|
545
562
|
|
|
546
|
-
const
|
|
563
|
+
const authorizeUrl = `${config.authorizeUrl}?${authParams}`;
|
|
547
564
|
|
|
548
565
|
const completion = codePromise.then(async (code) => {
|
|
549
566
|
return await exchangeCodeForTokens(config, code, redirectUri, codeVerifier);
|
|
@@ -554,7 +571,7 @@ async function prepareLoopbackFlow(
|
|
|
554
571
|
"Prepared deferred OAuth2 flow (loopback)",
|
|
555
572
|
);
|
|
556
573
|
|
|
557
|
-
return {
|
|
574
|
+
return { authorizeUrl, state, completion };
|
|
558
575
|
}
|
|
559
576
|
|
|
560
577
|
/**
|
|
@@ -763,7 +780,7 @@ export async function startOAuth2Flow(
|
|
|
763
780
|
* Supports both PKCE (no secret) and client_secret flows.
|
|
764
781
|
*/
|
|
765
782
|
export async function refreshOAuth2Token(
|
|
766
|
-
|
|
783
|
+
tokenExchangeUrl: string,
|
|
767
784
|
clientId: string,
|
|
768
785
|
refreshToken: string,
|
|
769
786
|
clientSecret?: string,
|
|
@@ -792,7 +809,7 @@ export async function refreshOAuth2Token(
|
|
|
792
809
|
}
|
|
793
810
|
}
|
|
794
811
|
|
|
795
|
-
const resp = await fetch(
|
|
812
|
+
const resp = await fetch(tokenExchangeUrl, {
|
|
796
813
|
method: "POST",
|
|
797
814
|
headers,
|
|
798
815
|
body: new URLSearchParams(body),
|