@vellumai/assistant 0.12.1-dev.202609141913.5e16607 → 0.12.1-staging.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +0 -4
- package/ARCHITECTURE.md +12 -11
- package/docs/architecture/turn-actor.md +8 -15
- package/docs/guardian-request-flow.md +0 -16
- package/openapi.yaml +49 -291
- package/package.json +1 -1
- package/src/__tests__/always-loaded-tools-guard.test.ts +10 -18
- package/src/__tests__/app-compiler.test.ts +0 -6
- package/src/__tests__/app-control-tool-schemas.test.ts +2 -5
- package/src/__tests__/app-dir-path-guard.test.ts +3 -1
- package/src/__tests__/app-source-watcher.test.ts +218 -0
- package/src/{calls/__tests__ → __tests__}/call-controller.test.ts +82 -503
- package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +2 -5
- package/src/__tests__/computer-use-tools.test.ts +5 -17
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +29 -28
- package/src/__tests__/config-watcher-skill-reseed.test.ts +359 -0
- package/src/__tests__/config-watcher.test.ts +8 -23
- package/src/__tests__/connection-model-compat.test.ts +2 -2
- package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-pairing.test.ts +0 -26
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +10 -4
- package/src/__tests__/conversation-queue.test.ts +207 -48
- package/src/__tests__/conversation-retry-discard.test.ts +1 -54
- package/src/__tests__/conversation-skill-tools.test.ts +0 -27
- package/src/__tests__/conversation-surfaces-app-control.test.ts +3 -8
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +0 -67
- package/src/__tests__/conversation-title-service.test.ts +10 -14
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +5 -3
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -51
- package/src/__tests__/credential-record-retire.test.ts +1 -171
- package/src/__tests__/credential-routes.test.ts +3 -212
- package/src/__tests__/credential-security-invariants.test.ts +2 -4
- package/src/__tests__/cu-unified-flow.test.ts +2 -8
- package/src/__tests__/document-sync-tags.test.ts +0 -25
- package/src/__tests__/drain-kick-guard.test.ts +2 -0
- package/src/__tests__/drain-requeue-on-contention.test.ts +6 -0
- package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
- package/src/__tests__/host-bash-proxy.test.ts +45 -26
- package/src/__tests__/host-browser-proxy.test.ts +17 -6
- package/src/__tests__/host-file-proxy-targeted.test.ts +0 -23
- package/src/__tests__/host-file-proxy.test.ts +23 -11
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +9 -30
- package/src/__tests__/llm-catalog-parity.test.ts +0 -25
- package/src/__tests__/mcp-auth-routes.test.ts +9 -6
- package/src/__tests__/mcp-config-secret-boundary.test.ts +136 -78
- package/src/__tests__/mcp-health-check.test.ts +11 -8
- package/src/__tests__/mcp-list-plugin-servers.test.ts +10 -8
- package/src/{calls/__tests__ → __tests__}/media-stream-audio-transcode.test.ts +1 -1
- package/src/{calls/__tests__ → __tests__}/media-stream-output.test.ts +8 -37
- package/src/{calls/__tests__ → __tests__}/media-stream-parser.test.ts +1 -1
- package/src/{calls/__tests__ → __tests__}/media-stream-server-integration.test.ts +57 -150
- package/src/{calls/__tests__ → __tests__}/media-stream-stt-session.test.ts +5 -5
- package/src/{calls/__tests__ → __tests__}/media-turn-detector.test.ts +1 -1
- package/src/__tests__/messages-after-tiebreaker.test.ts +0 -91
- package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
- package/src/__tests__/messaging-send-tool.test.ts +548 -355
- package/src/__tests__/model-intents.test.ts +0 -3
- package/src/__tests__/notification-vellum-adapter.test.ts +2 -85
- package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
- package/src/__tests__/platform-callback-registration.test.ts +16 -8
- package/src/__tests__/platform-client-verify-credential.test.ts +0 -2
- package/src/__tests__/plugin-import-boundary-guard.test.ts +0 -13
- package/src/__tests__/script-proxy-certs.test.ts +0 -35
- package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
- package/src/__tests__/skill-feature-flags.test.ts +2 -2
- package/src/__tests__/speaker-identification.test.ts +56 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +3 -19
- package/src/__tests__/subagent-tools.test.ts +2 -3
- package/src/__tests__/telephony-tts-guard.test.ts +3 -38
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +0 -4
- package/src/{calls/__tests__/voice-session-bridge-turn-flow.test.ts → __tests__/voice-session-bridge.test.ts} +12 -20
- package/src/__tests__/watch-retro-tool-availability.test.ts +17 -8
- package/src/__tests__/workspace-git-service.test.ts +0 -26
- package/src/acp/__tests__/agent-process.test.ts +4 -258
- package/src/acp/__tests__/auth-required.test.ts +0 -96
- package/src/acp/__tests__/client-handler.test.ts +2 -90
- package/src/acp/__tests__/session-manager-persistence.test.ts +1 -5
- package/src/acp/__tests__/session-manager-resume.test.ts +6 -270
- package/src/acp/__tests__/session-manager-usage.test.ts +2 -4
- package/src/acp/__tests__/session-manager.test.ts +4 -895
- package/src/acp/agent-process.test.ts +1 -4
- package/src/acp/agent-process.ts +9 -94
- package/src/acp/auth-required.ts +1 -50
- package/src/acp/auto-install.test.ts +7 -9
- package/src/acp/client-handler.ts +3 -16
- package/src/acp/resolve-agent.test.ts +6 -220
- package/src/acp/resolve-agent.ts +23 -88
- package/src/acp/session-manager.test.ts +3 -196
- package/src/acp/session-manager.ts +18 -441
- package/src/acp/types.ts +5 -50
- package/src/api/events/app-files-changed.ts +3 -4
- package/src/api/events/notification-intent.ts +0 -2
- package/src/api/index.ts +0 -6
- package/src/apps/app-store.ts +1 -1
- package/src/bundler/app-compiler.ts +0 -15
- package/src/calls/__tests__/voice-control-protocol.test.ts +25 -58
- package/src/calls/__tests__/voice-session-bridge.test.ts +1 -37
- package/src/calls/__tests__/voice-triage-escalate.test.ts +0 -105
- package/src/calls/call-constants.ts +4 -24
- package/src/calls/call-controller.ts +199 -499
- package/src/calls/call-transport.ts +0 -16
- package/src/calls/media-stream-output.ts +0 -32
- package/src/calls/media-stream-server.ts +30 -82
- package/src/calls/media-stream-stt-session.ts +0 -15
- package/src/calls/resolve-call-tts-provider.ts +2 -33
- package/src/calls/speaker-identification.ts +233 -0
- package/src/calls/tts-call-strategy.ts +5 -9
- package/src/calls/types.ts +0 -2
- package/src/calls/voice-control-protocol.ts +21 -53
- package/src/calls/voice-session-bridge.ts +46 -59
- package/src/calls/voice-triage-escalate.ts +56 -175
- package/src/cli/commands/apps.help.ts +13 -67
- package/src/cli/commands/apps.ts +0 -183
- package/src/cli/commands/bash.help.ts +13 -8
- package/src/cli/commands/bash.ts +25 -7
- package/src/cli/commands/channels/index.help.ts +2 -70
- package/src/cli/commands/channels/index.ts +3 -16
- package/src/cli/commands/credentials.help.ts +2 -6
- package/src/cli/commands/credentials.ts +2 -2
- package/src/cli/commands/mcp.help.ts +8 -8
- package/src/cli/commands/mcp.ts +1 -1
- package/src/cli/commands/roadmap.help.ts +1 -5
- package/src/cli/commands/roadmap.ts +1 -1
- package/src/cli/lib/bundled-marketplace.json +90 -103
- package/src/config/__tests__/default-profile-catalog.test.ts +0 -22
- package/src/config/__tests__/memory-retrospective-schema.test.ts +1 -15
- package/src/config/__tests__/platform-rehydration.test.ts +9 -99
- package/src/config/acp-defaults.test.ts +3 -13
- package/src/config/acp-defaults.ts +6 -23
- package/src/config/acp-schema.ts +2 -30
- package/src/config/bundled-skills/acp/SKILL.md +14 -22
- package/src/config/bundled-skills/acp/TOOLS.json +1 -5
- package/src/config/bundled-skills/app-builder/SKILL.md +9 -12
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
- package/src/config/bundled-skills/messaging/SKILL.md +3 -3
- package/src/config/bundled-skills/messaging/TOOLS.json +3 -3
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +139 -67
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
- package/src/config/bundled-skills/schedule/SKILL.md +4 -3
- package/src/config/bundled-skills/screen-annotation/SKILL.md +1 -8
- package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +1 -4
- package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
- package/src/config/default-profile-catalog.ts +1 -1
- package/src/config/env.ts +2 -2
- package/src/config/feature-flag-registry.json +12 -24
- package/src/config/loader.ts +0 -1
- package/src/config/memory-v3-gate.test.ts +0 -31
- package/src/config/memory-v3-gate.ts +16 -20
- package/src/config/platform-rehydration.ts +27 -11
- package/src/config/schema.ts +2 -2
- package/src/config/schemas/__tests__/live-voice.test.ts +158 -8
- package/src/config/schemas/calls.ts +28 -1
- package/src/config/schemas/live-voice.ts +173 -1
- package/src/config/schemas/mcp.ts +1 -1
- package/src/config/schemas/memory-retrospective.ts +0 -10
- package/src/config/schemas/services.ts +0 -8
- package/src/config/schemas/skills.ts +14 -0
- package/src/credential-execution/process-manager.test.ts +19 -18
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +121 -66
- package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +1 -4
- package/src/daemon/app-source-watcher.ts +218 -0
- package/src/daemon/config-watcher.ts +194 -13
- package/src/daemon/conversation-process.ts +64 -35
- package/src/daemon/conversation-skill-tools.ts +31 -13
- package/src/daemon/conversation-store.ts +1 -1
- package/src/daemon/conversation-surfaces.ts +8 -10
- package/src/daemon/conversation-tool-setup.ts +43 -37
- package/src/daemon/conversation.ts +3 -0
- package/src/daemon/host-bash-proxy.ts +12 -8
- package/src/daemon/host-browser-proxy.ts +1 -15
- package/src/daemon/host-file-proxy.ts +10 -8
- package/src/daemon/host-transfer-proxy.ts +18 -14
- package/src/daemon/lifecycle.ts +5 -0
- package/src/daemon/mcp-reload-service.ts +5 -5
- package/src/daemon/message-types/sync.ts +0 -1
- package/src/daemon/orphan-reaper.ts +1 -1
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/shutdown-handlers.ts +9 -1
- package/src/daemon/skill-memory-refresh.ts +0 -64
- package/src/daemon/tool-side-effects.ts +18 -7
- package/src/home/__tests__/feed-writer.test.ts +0 -22
- package/src/home/feed-writer.ts +2 -11
- package/src/hooks/types.ts +0 -33
- package/src/inbound/platform-callback-registration.ts +5 -4
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +3 -0
- package/src/live-voice/__tests__/live-voice-progress.test.ts +15 -15
- package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
- package/src/{calls → live-voice}/__tests__/progress-narration.test.ts +4 -4
- package/src/{calls → live-voice}/__tests__/progress-phrases.test.ts +1 -1
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +69 -13
- package/src/live-voice/live-voice-session.ts +693 -213
- package/src/{calls → live-voice}/progress-narration.ts +2 -2
- package/src/live-voice/protocol.ts +2 -0
- package/src/mcp/__tests__/effective-config.test.ts +2 -2
- package/src/mcp/effective-config.ts +3 -3
- package/src/mcp/mcp-header-store.ts +45 -29
- package/src/mcp/startup.ts +4 -8
- package/src/messaging/provider.ts +3 -10
- package/src/messaging/providers/callback-routing.ts +0 -18
- package/src/messaging/providers/channel-transport.ts +0 -56
- package/src/messaging/providers/discord/transport.ts +0 -17
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +17 -6
- package/src/messaging/providers/slack/adapter.ts +44 -7
- package/src/messaging/providers/slack/transport.ts +0 -16
- package/src/messaging/providers/telegram-bot/adapter.ts +48 -1
- package/src/messaging/providers/telegram-bot/client.ts +26 -0
- package/src/messaging/providers/telegram-bot/transport.ts +0 -20
- package/src/messaging/providers/whatsapp/adapter.ts +48 -1
- package/src/messaging/providers/whatsapp/client.ts +29 -0
- package/src/messaging/providers/whatsapp/transport.ts +0 -18
- package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +0 -8
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +0 -55
- package/src/notifications/__tests__/guardian-feed-projection.test.ts +2 -158
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +3 -153
- package/src/notifications/__tests__/schedule-result-producer.test.ts +3 -99
- package/src/notifications/adapters/macos.ts +0 -3
- package/src/notifications/assistant-reply-producer.ts +3 -8
- package/src/notifications/conversation-pairing.ts +16 -36
- package/src/notifications/delivered-post-record.ts +1 -11
- package/src/notifications/guardian-feed-projection.ts +5 -125
- package/src/notifications/home-feed-side-effect.ts +7 -55
- package/src/notifications/schedule-result-producer.ts +22 -66
- package/src/oauth/__tests__/seed-providers-managed.test.ts +0 -54
- package/src/oauth/byo-connection.test.ts +0 -45
- package/src/oauth/byo-connection.ts +6 -36
- package/src/oauth/connection-resolver.test.ts +0 -73
- package/src/oauth/connection-resolver.ts +2 -95
- package/src/oauth/seed-providers.ts +0 -165
- package/src/outbound-proxy/certs.ts +5 -3
- package/src/permissions/checker.test.ts +6 -11
- package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
- package/src/persistence/conversation-crud.ts +63 -71
- package/src/persistence/conversation-lineage.ts +4 -12
- package/src/persistence/conversation-title-service.ts +26 -9
- package/src/persistence/llm-request-log-sink-clickhouse.ts +3 -3
- package/src/persistence/llm-request-log-source-clickhouse.ts +3 -3
- package/src/persistence/message-reads.ts +0 -30
- package/src/persistence/migrations/157-invite-contact-id.ts +6 -18
- package/src/persistence/schema/memory-core.ts +0 -5
- package/src/platform/client.test.ts +2 -4
- package/src/platform/client.ts +10 -2
- package/src/plugin-api/constants.ts +0 -2
- package/src/plugin-api/index.ts +0 -1
- package/src/plugin-api/types.ts +0 -2
- package/src/plugins/defaults/index.ts +0 -2
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +0 -46
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +5 -9
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +10 -20
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +0 -219
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +0 -31
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +0 -63
- package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +0 -4
- package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -4
- package/src/plugins/defaults/memory/hooks/init.ts +0 -10
- package/src/plugins/defaults/memory/hooks/shutdown.ts +0 -2
- package/src/plugins/defaults/memory/jobs-worker.ts +0 -13
- package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +60 -34
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +5 -3
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +3 -12
- package/src/plugins/defaults/memory/memory-retrospective-state.ts +71 -312
- package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +1 -2
- package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +3 -5
- package/src/plugins/defaults/memory/startup.ts +1 -6
- package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +9 -7
- package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +0 -89
- package/src/plugins/defaults/memory/worker.ts +0 -6
- package/src/plugins/mcp-servers.ts +75 -15
- package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
- package/src/providers/gemini/client.ts +23 -9
- package/src/providers/inference/auth.ts +3 -2
- package/src/providers/inference/connection-availability.ts +8 -27
- package/src/providers/inference/resolve-auth.ts +4 -22
- package/src/providers/model-catalog.ts +0 -34
- package/src/providers/model-intents.ts +5 -10
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +18 -146
- package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +1 -83
- package/src/providers/openai/chat-completions-provider.ts +78 -192
- package/src/providers/openai/codex-models.ts +4 -0
- package/src/runtime/AGENTS.md +0 -2
- package/src/runtime/auth/same-actor.ts +3 -38
- package/src/runtime/http-server.ts +151 -160
- package/src/runtime/routes/__tests__/acp-routes.test.ts +4 -159
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +1 -108
- package/src/runtime/routes/__tests__/default-provider-routes.test.ts +2 -2
- package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +12 -16
- package/src/runtime/routes/acp-routes.test.ts +0 -15
- package/src/runtime/routes/acp-routes.ts +9 -72
- package/src/runtime/routes/app-management-routes.ts +0 -73
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/conversation-list-routes.ts +3 -14
- package/src/runtime/routes/conversation-query-routes.ts +0 -40
- package/src/runtime/routes/credential-routes.ts +10 -19
- package/src/runtime/routes/debug-bash-routes.ts +173 -0
- package/src/runtime/routes/diagnostics-routes.ts +3 -55
- package/src/runtime/routes/index.ts +2 -4
- package/src/runtime/routes/log-export-routes.ts +0 -2
- package/src/runtime/routes/mcp-auth-routes.ts +47 -39
- package/src/runtime/routes/migration-routes.ts +20 -6
- package/src/runtime/routes/platform-routes.ts +15 -18
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -28
- package/src/runtime/services/conversation-serializer.ts +3 -16
- package/src/runtime/sync/resource-sync-events.ts +1 -2
- package/src/schedule/worker.ts +1 -1
- package/src/security/ces-rpc-record-backend.ts +0 -7
- package/src/subagent/consult-context.ts +25 -12
- package/src/tools/acp/list-agents.test.ts +1 -3
- package/src/tools/acp/spawn.test.ts +11 -146
- package/src/tools/acp/spawn.ts +3 -21
- package/src/tools/acp/status.ts +3 -40
- package/src/tools/app-control/skill-proxy-bridge.ts +1 -2
- package/src/tools/capability-offer.test.ts +2 -22
- package/src/tools/capability-offer.ts +1 -16
- package/src/tools/computer-use/definitions.ts +2 -4
- package/src/tools/computer-use/skill-proxy-bridge.ts +1 -2
- package/src/tools/credentials/metadata-store.ts +0 -100
- package/src/tools/host-filesystem/edit.test.ts +1 -2
- package/src/tools/host-filesystem/edit.ts +2 -2
- package/src/tools/host-filesystem/read.test.ts +1 -2
- package/src/tools/host-filesystem/read.ts +2 -2
- package/src/tools/host-filesystem/transfer.test.ts +1 -2
- package/src/tools/host-filesystem/transfer.ts +2 -2
- package/src/tools/host-filesystem/write.test.ts +1 -2
- package/src/tools/host-filesystem/write.ts +2 -2
- package/src/tools/host-terminal/host-shell.test.ts +0 -16
- package/src/tools/host-terminal/host-shell.ts +20 -4
- package/src/tools/policy-context.ts +7 -6
- package/src/tools/subagent/spawn.ts +8 -5
- package/src/tools/watch/watch-retro-report.ts +8 -0
- package/src/util/__tests__/language-subtag.test.ts +1 -23
- package/src/util/fs-watcher-error.ts +36 -0
- package/src/util/language-subtag.ts +0 -16
- package/src/util/platform.ts +0 -8
- package/src/workspace/git-service.ts +54 -5
- package/src/workspace/migrations/registry.ts +0 -6
- package/scripts/smoke-desktop-window-theme.ts +0 -186
- package/src/__tests__/git-porcelain.test.ts +0 -47
- package/src/__tests__/helpers/set-workspace-mcp.ts +0 -11
- package/src/__tests__/message-deleted-hook-dispatch.test.ts +0 -119
- package/src/__tests__/resolve-app.test.ts +0 -135
- package/src/__tests__/service-account-token.test.ts +0 -247
- package/src/__tests__/source-fingerprint.test.ts +0 -184
- package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +0 -336
- package/src/acp/__tests__/helpers/acp-model-option.ts +0 -51
- package/src/acp/model-config.test.ts +0 -166
- package/src/acp/model-config.ts +0 -138
- package/src/api/events/acp-session-model-update.test.ts +0 -88
- package/src/api/events/acp-session-model-update.ts +0 -46
- package/src/apps/resolve-app.ts +0 -81
- package/src/apps/source-fingerprint.ts +0 -266
- package/src/calls/__tests__/barge-in-guard.test.ts +0 -81
- package/src/calls/__tests__/voice-leg-coordinator.test.ts +0 -229
- package/src/calls/__tests__/voice-progress-cadence.test.ts +0 -274
- package/src/calls/barge-in-guard.ts +0 -118
- package/src/calls/voice-leg-coordinator.ts +0 -189
- package/src/calls/voice-progress-cadence.ts +0 -423
- package/src/cli/commands/__tests__/apps.test.ts +0 -245
- package/src/cli/commands/__tests__/bash.test.ts +0 -53
- package/src/cli/commands/__tests__/roadmap.help.test.ts +0 -19
- package/src/cli/commands/channels/__tests__/send.test.ts +0 -218
- package/src/cli/commands/channels/send.ts +0 -128
- package/src/config/__tests__/platform-identity.test.ts +0 -255
- package/src/config/acp-agent-write.ts +0 -43
- package/src/config/acp-schema.test.ts +0 -81
- package/src/config/platform-identity.ts +0 -201
- package/src/config/schemas/__tests__/voice.test.ts +0 -148
- package/src/config/schemas/voice.ts +0 -150
- package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +0 -133
- package/src/daemon/app-change-notify.ts +0 -45
- package/src/desktop/__tests__/fake-desktop.ts +0 -119
- package/src/desktop/desktop-chrome-policy.test.ts +0 -71
- package/src/desktop/desktop-chrome-policy.ts +0 -42
- package/src/desktop/desktop-dependencies.test.ts +0 -102
- package/src/desktop/desktop-dependencies.ts +0 -306
- package/src/desktop/desktop-feature.test.ts +0 -18
- package/src/desktop/desktop-feature.ts +0 -19
- package/src/desktop/desktop-panel-config.test.ts +0 -135
- package/src/desktop/desktop-panel-config.ts +0 -149
- package/src/desktop/desktop-session-manager.test.ts +0 -627
- package/src/desktop/desktop-session-manager.ts +0 -814
- package/src/desktop/desktop-stream-bridge.test.ts +0 -395
- package/src/desktop/desktop-stream-bridge.ts +0 -214
- package/src/desktop/desktop-wallpaper.test.ts +0 -191
- package/src/desktop/desktop-wallpaper.ts +0 -113
- package/src/desktop/desktop-window-theme.ts +0 -170
- package/src/i18n/AGENTS.md +0 -22
- package/src/i18n/__tests__/i18n.test.ts +0 -108
- package/src/i18n/index.ts +0 -16
- package/src/i18n/locales.ts +0 -93
- package/src/i18n/messages.ts +0 -61
- package/src/i18n/title.ts +0 -25
- package/src/mcp/__tests__/workspace-mcp-config.test.ts +0 -135
- package/src/mcp/spec-schema.ts +0 -111
- package/src/mcp/workspace-mcp-config.ts +0 -188
- package/src/messaging/providers/__tests__/proactive-address.test.ts +0 -95
- package/src/persistence/conversation-title-placeholders.ts +0 -23
- package/src/persistence/message-cursor.ts +0 -78
- package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +0 -149
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +0 -118
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +0 -83
- package/src/plugins/defaults/memory/hooks/message-deleted.ts +0 -21
- package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +0 -126
- package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +0 -79
- package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +0 -28
- package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +0 -9
- package/src/providers/gemini-thought-signature.test.ts +0 -63
- package/src/providers/gemini-thought-signature.ts +0 -44
- package/src/providers/inference/service-account-token.ts +0 -248
- package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +0 -613
- package/src/providers/openai/__tests__/google-thought-signature.test.ts +0 -235
- package/src/providers/openai/google-thought-signature.ts +0 -320
- package/src/runtime/__tests__/channel-send.test.ts +0 -443
- package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +0 -89
- package/src/runtime/__tests__/live-voice-upgrade.test.ts +0 -58
- package/src/runtime/__tests__/runtime-ws-test-utils.ts +0 -72
- package/src/runtime/__tests__/watch-stream-upgrade.test.ts +0 -59
- package/src/runtime/channel-send.ts +0 -316
- package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +0 -205
- package/src/runtime/routes/__tests__/channel-send-routes.test.ts +0 -127
- package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +0 -107
- package/src/runtime/routes/channel-send-routes.ts +0 -85
- package/src/runtime/routes/desktop-setup-routes.test.ts +0 -74
- package/src/runtime/routes/desktop-setup-routes.ts +0 -35
- package/src/security/__tests__/ces-http-record-backend.test.ts +0 -137
- package/src/security/ces-http-record-backend.ts +0 -120
- package/src/skills/__tests__/workspace-skill-md-signature.test.ts +0 -60
- package/src/skills/workspace-skill-md-signature.ts +0 -50
- package/src/tools/acp/status.test.ts +0 -94
- package/src/tools/terminal/__tests__/sanitized-bash.test.ts +0 -57
- package/src/tools/terminal/sanitized-bash.ts +0 -105
- package/src/util/ca-bundle.ts +0 -13
- package/src/workspace/git-porcelain.ts +0 -66
- package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +0 -258
- package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +0 -78
- package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +0 -214
- package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +0 -102
- package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +0 -199
- /package/src/{calls → live-voice}/progress-phrases.ts +0 -0
|
@@ -32,7 +32,6 @@ import { getAttentionStateByConversationIds } from "../persistence/conversation-
|
|
|
32
32
|
import {
|
|
33
33
|
getAssistantMessageIdsInTurn,
|
|
34
34
|
getMessageById,
|
|
35
|
-
getMessagesAfter,
|
|
36
35
|
type MessageRow,
|
|
37
36
|
} from "../persistence/conversation-crud.js";
|
|
38
37
|
import { stringifyMessageContent } from "../persistence/message-content.js";
|
|
@@ -40,6 +39,7 @@ import {
|
|
|
40
39
|
isPrivateAssistantText,
|
|
41
40
|
projectPersistedAssistantContent,
|
|
42
41
|
} from "../persistence/user-facing-content.js";
|
|
42
|
+
import type { ContentBlock } from "../providers/types.js";
|
|
43
43
|
import { emitNotificationSignal } from "./emit-signal.js";
|
|
44
44
|
import { hasNotifiedSourceContextSince } from "./events-store.js";
|
|
45
45
|
import {
|
|
@@ -79,72 +79,28 @@ export interface ScheduleResultNotificationParams {
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
/**
|
|
82
|
-
* Whether the run delivered
|
|
83
|
-
*
|
|
82
|
+
* Whether a tool call in the run's turn delivered the result somewhere the
|
|
83
|
+
* user will see it, outside the notification pipeline.
|
|
84
84
|
*
|
|
85
|
-
* The
|
|
86
|
-
*
|
|
87
|
-
*
|
|
85
|
+
* The schedule skill prescribes two such routes for rich content — the
|
|
86
|
+
* messaging tool for email, and the Slack Web API's `chat.postMessage` through
|
|
87
|
+
* bash — and neither writes a `notification_events` row, so the pipeline probe
|
|
88
|
+
* cannot see them. Without this check a well-authored Slack digest would post
|
|
88
89
|
* its summary and then get a second notification whose body is "Posted the
|
|
89
|
-
* digest to #general."
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
* this is a known-routes list rather than a general "did the run do anything?"
|
|
93
|
-
* heuristic. And the call has to have succeeded: a `tool_use` block records
|
|
94
|
-
* only that the model called the tool, so a send the channel refused leaves
|
|
95
|
-
* the same block as one that landed, and suppressing on it costs the user both
|
|
96
|
-
* the digest and the run's explanation of the failure. The executor's verdict
|
|
97
|
-
* is on the `tool_result` the call produced, so success is read from there,
|
|
98
|
-
* and a call with no result counts as undelivered. Either condition unmet gets
|
|
99
|
-
* the fallback, which is the safe failure.
|
|
100
|
-
*
|
|
101
|
-
* The result read starts at the run's first row, so it covers the results
|
|
102
|
-
* interleaved through the turn. Rows from a later turn in a reused
|
|
103
|
-
* conversation can come back too and are harmless, because only this run's
|
|
104
|
-
* own call ids are matched.
|
|
105
|
-
*
|
|
106
|
-
* A Slack Web API post through bash is deliberately not a route, because its
|
|
107
|
-
* success proves nothing about the post. Slack refuses a call with HTTP 200
|
|
108
|
-
* and `ok: false` in the body, and the authenticated-request command fails
|
|
109
|
-
* only on a non-2xx status, so a post Slack refused still leaves a successful
|
|
110
|
-
* tool result. A run that posts that way gets the fallback too: at worst a
|
|
111
|
-
* duplicate, never a silence.
|
|
90
|
+
* digest to #general." This is a recognized-routes list, not a general "did
|
|
91
|
+
* the run do anything?" heuristic: a route that is not here gets the fallback,
|
|
92
|
+
* which is the safe failure.
|
|
112
93
|
*/
|
|
113
|
-
function
|
|
114
|
-
|
|
115
|
-
runRows: readonly MessageRow[],
|
|
116
|
-
): boolean {
|
|
117
|
-
const callIds = new Set<string>();
|
|
118
|
-
for (const row of runRows) {
|
|
119
|
-
for (const block of row.content) {
|
|
120
|
-
if (block.type === "tool_use" && block.name === "messaging_send") {
|
|
121
|
-
callIds.add(block.id);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
if (callIds.size === 0) {
|
|
94
|
+
function isDirectDelivery(block: ContentBlock): boolean {
|
|
95
|
+
if (block.type !== "tool_use") {
|
|
126
96
|
return false;
|
|
127
97
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
continue;
|
|
135
|
-
}
|
|
136
|
-
for (const block of row.content) {
|
|
137
|
-
// guard:allow-tool-result-only: the local executor's verdict on a
|
|
138
|
-
// delivery it ran. A server-side `web_search_tool_result` carries no
|
|
139
|
-
// `is_error` and never delivers anything.
|
|
140
|
-
if (
|
|
141
|
-
block.type === "tool_result" &&
|
|
142
|
-
block.is_error !== true &&
|
|
143
|
-
callIds.has(block.tool_use_id)
|
|
144
|
-
) {
|
|
145
|
-
return true;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
98
|
+
if (block.name === "messaging_send") {
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
if (block.name === "bash") {
|
|
102
|
+
const command = (block.input as { command?: unknown } | undefined)?.command;
|
|
103
|
+
return typeof command === "string" && command.includes("chat.postMessage");
|
|
148
104
|
}
|
|
149
105
|
return false;
|
|
150
106
|
}
|
|
@@ -281,11 +237,11 @@ export async function emitScheduleResultNotification(
|
|
|
281
237
|
return;
|
|
282
238
|
}
|
|
283
239
|
|
|
284
|
-
// The run delivered around the pipeline through the messaging
|
|
285
|
-
// the
|
|
286
|
-
// "posted it" on top would be the duplicate.
|
|
240
|
+
// The run delivered around the pipeline — an email through the messaging
|
|
241
|
+
// tool, a Slack post through the Web API. The user has the result; a
|
|
242
|
+
// notification reading "posted it" on top would be the duplicate.
|
|
287
243
|
const runRows = collectRunRows(latestRow, conversationId, runStartedAt);
|
|
288
|
-
if (
|
|
244
|
+
if (runRows.some((row) => row.content.some(isDirectDelivery))) {
|
|
289
245
|
return;
|
|
290
246
|
}
|
|
291
247
|
|
|
@@ -127,60 +127,6 @@ describe("PROVIDER_SEED_DATA managed mode wiring", () => {
|
|
|
127
127
|
expect(figma.featureFlag).toBe("figma-oauth");
|
|
128
128
|
});
|
|
129
129
|
|
|
130
|
-
test("shopify keeps its per-tenant URL templates", () => {
|
|
131
|
-
// Shopify has no global OAuth host: every endpoint lives on the
|
|
132
|
-
// merchant's own domain. Hardcoding any host here would send every
|
|
133
|
-
// merchant's authorization to the wrong store, so the {tenant_host}
|
|
134
|
-
// placeholder the platform substitutes must survive.
|
|
135
|
-
const shopify = PROVIDER_SEED_DATA.shopify;
|
|
136
|
-
expect(shopify).toBeDefined();
|
|
137
|
-
for (const url of [
|
|
138
|
-
shopify.authorizeUrl,
|
|
139
|
-
shopify.tokenExchangeUrl,
|
|
140
|
-
shopify.refreshUrl,
|
|
141
|
-
shopify.baseUrl,
|
|
142
|
-
shopify.identityUrl,
|
|
143
|
-
]) {
|
|
144
|
-
expect(url).toContain("{tenant_host}");
|
|
145
|
-
}
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
test("shopify requests comma-separated scopes", () => {
|
|
149
|
-
// Shopify parses `scope` as a comma-separated list; the OAuth2 default
|
|
150
|
-
// space separator is read as one malformed scope and the whole
|
|
151
|
-
// authorization request is rejected.
|
|
152
|
-
expect(PROVIDER_SEED_DATA.shopify.scopeSeparator).toBe(",");
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
test("shopify does not request approval-gated scopes", () => {
|
|
156
|
-
// Shopify rejects the entire authorization request when the app cannot
|
|
157
|
-
// grant a requested scope -- the same failure that broke monday and
|
|
158
|
-
// Figma. These scopes all require Shopify's prior approval.
|
|
159
|
-
const gated = [
|
|
160
|
-
"read_all_orders",
|
|
161
|
-
"read_customer_payment_methods",
|
|
162
|
-
"read_own_subscription_contracts",
|
|
163
|
-
"write_own_subscription_contracts",
|
|
164
|
-
"read_shopify_payments_dispute_evidences",
|
|
165
|
-
"write_shopify_payments_dispute_evidences",
|
|
166
|
-
];
|
|
167
|
-
for (const scope of gated) {
|
|
168
|
-
expect(PROVIDER_SEED_DATA.shopify.defaultScopes).not.toContain(scope);
|
|
169
|
-
}
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
test("shopify injects the Admin API's own auth header", () => {
|
|
173
|
-
// The Admin API reads X-Shopify-Access-Token and ignores an
|
|
174
|
-
// Authorization: Bearer header entirely, so a Bearer template here would
|
|
175
|
-
// make every proxied request unauthenticated.
|
|
176
|
-
const templates = PROVIDER_SEED_DATA.shopify.injectionTemplates;
|
|
177
|
-
expect(templates).toBeDefined();
|
|
178
|
-
const [template] = templates ?? [];
|
|
179
|
-
expect(template?.headerName).toBe("X-Shopify-Access-Token");
|
|
180
|
-
expect(template?.valuePrefix).toBe("");
|
|
181
|
-
expect(template?.hostPattern).toBe("*.myshopify.com");
|
|
182
|
-
});
|
|
183
|
-
|
|
184
130
|
test("every managedServiceConfigKey resolves to a ServicesSchema key", () => {
|
|
185
131
|
// Cross-repo invariant: a provider with managedServiceConfigKey but no
|
|
186
132
|
// matching ServicesSchema entry silently falls back to BYO mode in
|
|
@@ -708,51 +708,6 @@ describe("BYOOAuthConnection", () => {
|
|
|
708
708
|
expect(headers.get("Authorization")).toBe("Bearer test-access-token");
|
|
709
709
|
});
|
|
710
710
|
|
|
711
|
-
test("sends the token in the provider's own header when one is configured", async () => {
|
|
712
|
-
// Shopify's Admin API reads X-Shopify-Access-Token and ignores
|
|
713
|
-
// Authorization, so a Bearer header reaches the shop unauthenticated.
|
|
714
|
-
await setupCredential("google");
|
|
715
|
-
const conn = new BYOOAuthConnection({
|
|
716
|
-
id: "conn-google",
|
|
717
|
-
provider: "google",
|
|
718
|
-
baseUrl: "https://example-store.myshopify.com",
|
|
719
|
-
accountInfo: null,
|
|
720
|
-
tokenHeader: { name: "X-Shopify-Access-Token", valuePrefix: "" },
|
|
721
|
-
});
|
|
722
|
-
|
|
723
|
-
await conn.request({
|
|
724
|
-
method: "GET",
|
|
725
|
-
path: "/admin/api/2026-07/shop.json",
|
|
726
|
-
// A caller-supplied Authorization must not ride along.
|
|
727
|
-
headers: { Authorization: "Bearer caller-supplied" },
|
|
728
|
-
});
|
|
729
|
-
|
|
730
|
-
const [url, init] = mockFetch.mock.calls[0];
|
|
731
|
-
expect(url).toBe(
|
|
732
|
-
"https://example-store.myshopify.com/admin/api/2026-07/shop.json",
|
|
733
|
-
);
|
|
734
|
-
const headers = (init as RequestInit).headers as Headers;
|
|
735
|
-
expect(headers.get("X-Shopify-Access-Token")).toBe("test-access-token");
|
|
736
|
-
expect(headers.has("Authorization")).toBe(false);
|
|
737
|
-
});
|
|
738
|
-
|
|
739
|
-
test("keeps the value prefix from the token header template", async () => {
|
|
740
|
-
await setupCredential("google");
|
|
741
|
-
const conn = new BYOOAuthConnection({
|
|
742
|
-
id: "conn-google",
|
|
743
|
-
provider: "google",
|
|
744
|
-
baseUrl: "https://discord.com/api",
|
|
745
|
-
accountInfo: null,
|
|
746
|
-
tokenHeader: { name: "Authorization", valuePrefix: "Bot " },
|
|
747
|
-
});
|
|
748
|
-
|
|
749
|
-
await conn.request({ method: "GET", path: "/users/@me" });
|
|
750
|
-
|
|
751
|
-
const [, init] = mockFetch.mock.calls[0];
|
|
752
|
-
const headers = (init as RequestInit).headers as Headers;
|
|
753
|
-
expect(headers.get("Authorization")).toBe("Bot test-access-token");
|
|
754
|
-
});
|
|
755
|
-
|
|
756
711
|
test("uses Telegram Bot API token URL format without Bearer auth", async () => {
|
|
757
712
|
await setupTelegramCredential();
|
|
758
713
|
const conn = createConnection("telegram");
|
|
@@ -21,29 +21,11 @@ const log = getLogger("byo-oauth-connection");
|
|
|
21
21
|
/** Default per-request timeout to prevent hung requests from blocking indefinitely. */
|
|
22
22
|
const REQUEST_TIMEOUT_MS = 30_000;
|
|
23
23
|
|
|
24
|
-
/**
|
|
25
|
-
* How the access token is attached to an outbound request. Almost every
|
|
26
|
-
* provider reads `Authorization: Bearer <token>`; a few use their own header
|
|
27
|
-
* (Shopify's Admin API reads `X-Shopify-Access-Token` and ignores
|
|
28
|
-
* Authorization entirely). Derived from the provider's header-type injection
|
|
29
|
-
* template so the seed is the single source of truth.
|
|
30
|
-
*/
|
|
31
|
-
export interface BYOTokenHeader {
|
|
32
|
-
name: string;
|
|
33
|
-
/** Text placed before the token, e.g. `"Bearer "`, `"Bot "`, or `""`. */
|
|
34
|
-
valuePrefix: string;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
24
|
export interface BYOOAuthConnectionOptions {
|
|
38
25
|
id: string;
|
|
39
26
|
provider: string;
|
|
40
27
|
baseUrl: string;
|
|
41
28
|
accountInfo: string | null;
|
|
42
|
-
/**
|
|
43
|
-
* Token header override. When omitted the connection falls back to
|
|
44
|
-
* `Authorization: Bearer` (or `Bot` for discord_channel).
|
|
45
|
-
*/
|
|
46
|
-
tokenHeader?: BYOTokenHeader | null;
|
|
47
29
|
}
|
|
48
30
|
|
|
49
31
|
export class BYOOAuthConnection implements OAuthConnection {
|
|
@@ -52,14 +34,12 @@ export class BYOOAuthConnection implements OAuthConnection {
|
|
|
52
34
|
readonly accountInfo: string | null;
|
|
53
35
|
|
|
54
36
|
private readonly baseUrl: string;
|
|
55
|
-
private readonly tokenHeader: BYOTokenHeader | null;
|
|
56
37
|
|
|
57
38
|
constructor(opts: BYOOAuthConnectionOptions) {
|
|
58
39
|
this.id = opts.id;
|
|
59
40
|
this.provider = opts.provider;
|
|
60
41
|
this.baseUrl = opts.baseUrl;
|
|
61
42
|
this.accountInfo = opts.accountInfo;
|
|
62
|
-
this.tokenHeader = opts.tokenHeader ?? null;
|
|
63
43
|
}
|
|
64
44
|
|
|
65
45
|
async request(req: OAuthConnectionRequest): Promise<OAuthConnectionResponse> {
|
|
@@ -71,12 +51,8 @@ export class BYOOAuthConnection implements OAuthConnection {
|
|
|
71
51
|
// Discord bot tokens authenticate with the `Bot ` scheme, not
|
|
72
52
|
// `Bearer`. Sending Bearer here reaches Discord as an unusable
|
|
73
53
|
// credential and comes back 401, which reads as a revoked token.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const tokenHeader: BYOTokenHeader = this.tokenHeader ?? {
|
|
77
|
-
name: "Authorization",
|
|
78
|
-
valuePrefix: this.provider === "discord_channel" ? "Bot " : "Bearer ",
|
|
79
|
-
};
|
|
54
|
+
const authScheme =
|
|
55
|
+
this.provider === "discord_channel" ? "Bot" : "Bearer";
|
|
80
56
|
const requestPath = isTelegram
|
|
81
57
|
? buildTelegramBotApiPath(req.path, token)
|
|
82
58
|
: req.path;
|
|
@@ -117,22 +93,16 @@ export class BYOOAuthConnection implements OAuthConnection {
|
|
|
117
93
|
}
|
|
118
94
|
}
|
|
119
95
|
if (!isTelegram) {
|
|
120
|
-
|
|
121
|
-
// provider that reads its own header must not also receive a
|
|
122
|
-
// stray Authorization the caller happened to send.
|
|
123
|
-
if (tokenHeader.name.toLowerCase() !== "authorization") {
|
|
124
|
-
headers.delete("Authorization");
|
|
125
|
-
}
|
|
126
|
-
headers.set(tokenHeader.name, `${tokenHeader.valuePrefix}${token}`);
|
|
96
|
+
headers.set("Authorization", `${authScheme} ${token}`);
|
|
127
97
|
}
|
|
128
98
|
|
|
129
99
|
const resp = await fetch(fullUrl, {
|
|
130
100
|
method: req.method,
|
|
131
101
|
headers,
|
|
132
102
|
body: hasBody
|
|
133
|
-
? binaryBody !== undefined
|
|
134
|
-
|
|
135
|
-
|
|
103
|
+
? (binaryBody !== undefined
|
|
104
|
+
? Buffer.from(binaryBody)
|
|
105
|
+
: (rawBody ?? JSON.stringify(req.body)))
|
|
136
106
|
: undefined,
|
|
137
107
|
// Following a redirect would replay a POST as a GET against a URL
|
|
138
108
|
// the caller never asked for, and hide the 3xx from them.
|
|
@@ -75,7 +75,6 @@ import {
|
|
|
75
75
|
resolveEffectiveBaseUrl,
|
|
76
76
|
resolveOAuthConnection,
|
|
77
77
|
resolveOAuthConnectionWithMeta,
|
|
78
|
-
resolveTokenHeader,
|
|
79
78
|
} from "./connection-resolver.js";
|
|
80
79
|
import { PlatformOAuthConnection } from "./platform-connection.js";
|
|
81
80
|
|
|
@@ -754,75 +753,3 @@ describe("resolveEffectiveBaseUrl", () => {
|
|
|
754
753
|
).toBe("https://gmail.googleapis.com/gmail/v1/users/me");
|
|
755
754
|
});
|
|
756
755
|
});
|
|
757
|
-
|
|
758
|
-
describe("resolveTokenHeader", () => {
|
|
759
|
-
const shopify = JSON.stringify([
|
|
760
|
-
{
|
|
761
|
-
hostPattern: "*.myshopify.com",
|
|
762
|
-
injectionType: "header",
|
|
763
|
-
headerName: "X-Shopify-Access-Token",
|
|
764
|
-
valuePrefix: "",
|
|
765
|
-
},
|
|
766
|
-
]);
|
|
767
|
-
|
|
768
|
-
test("returns null when the provider declares no templates", () => {
|
|
769
|
-
expect(resolveTokenHeader(undefined, "https://api.example.com")).toBeNull();
|
|
770
|
-
expect(resolveTokenHeader(null, "https://api.example.com")).toBeNull();
|
|
771
|
-
expect(resolveTokenHeader("[]", "https://api.example.com")).toBeNull();
|
|
772
|
-
});
|
|
773
|
-
|
|
774
|
-
test("returns null for malformed JSON", () => {
|
|
775
|
-
expect(
|
|
776
|
-
resolveTokenHeader("{not json", "https://api.example.com"),
|
|
777
|
-
).toBeNull();
|
|
778
|
-
});
|
|
779
|
-
|
|
780
|
-
test("ignores non-header injection templates", () => {
|
|
781
|
-
const query = JSON.stringify([
|
|
782
|
-
{
|
|
783
|
-
hostPattern: "api.example.com",
|
|
784
|
-
injectionType: "query",
|
|
785
|
-
headerName: "",
|
|
786
|
-
},
|
|
787
|
-
]);
|
|
788
|
-
expect(resolveTokenHeader(query, "https://api.example.com")).toBeNull();
|
|
789
|
-
});
|
|
790
|
-
|
|
791
|
-
test("picks the template whose wildcard host pattern matches the base URL", () => {
|
|
792
|
-
const templates = JSON.stringify([
|
|
793
|
-
{
|
|
794
|
-
hostPattern: "api.other.com",
|
|
795
|
-
injectionType: "header",
|
|
796
|
-
headerName: "Authorization",
|
|
797
|
-
valuePrefix: "Bearer ",
|
|
798
|
-
},
|
|
799
|
-
...JSON.parse(shopify),
|
|
800
|
-
]);
|
|
801
|
-
expect(
|
|
802
|
-
resolveTokenHeader(templates, "https://example-store.myshopify.com"),
|
|
803
|
-
).toEqual({ name: "X-Shopify-Access-Token", valuePrefix: "" });
|
|
804
|
-
});
|
|
805
|
-
|
|
806
|
-
test("falls back to the first header template when the host cannot be matched", () => {
|
|
807
|
-
// A still-templated base URL is not a parseable URL.
|
|
808
|
-
expect(resolveTokenHeader(shopify, "https://{tenant_host}")).toEqual({
|
|
809
|
-
name: "X-Shopify-Access-Token",
|
|
810
|
-
valuePrefix: "",
|
|
811
|
-
});
|
|
812
|
-
});
|
|
813
|
-
|
|
814
|
-
test("preserves the Bot prefix for discord_channel", () => {
|
|
815
|
-
const discord = JSON.stringify([
|
|
816
|
-
{
|
|
817
|
-
hostPattern: "discord.com",
|
|
818
|
-
injectionType: "header",
|
|
819
|
-
headerName: "Authorization",
|
|
820
|
-
valuePrefix: "Bot ",
|
|
821
|
-
},
|
|
822
|
-
]);
|
|
823
|
-
expect(resolveTokenHeader(discord, "https://discord.com/api")).toEqual({
|
|
824
|
-
name: "Authorization",
|
|
825
|
-
valuePrefix: "Bot ",
|
|
826
|
-
});
|
|
827
|
-
});
|
|
828
|
-
});
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
} from "../config/schemas/services.js";
|
|
7
7
|
import { VellumPlatformClient } from "../platform/client.js";
|
|
8
8
|
import { getLogger } from "../util/logger.js";
|
|
9
|
-
import { BYOOAuthConnection
|
|
9
|
+
import { BYOOAuthConnection } from "./byo-connection.js";
|
|
10
10
|
import type { OAuthConnection } from "./connection.js";
|
|
11
11
|
import { getConnectionAccessTokenResult } from "./credential-token-resolver.js";
|
|
12
12
|
import { syncManualTokenConnection } from "./manual-token-connection.js";
|
|
@@ -215,108 +215,15 @@ export async function resolveOAuthConnectionWithMeta(
|
|
|
215
215
|
);
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
-
const effectiveBaseUrl = resolveEffectiveBaseUrl(
|
|
219
|
-
conn.provider,
|
|
220
|
-
baseUrl,
|
|
221
|
-
conn.metadata,
|
|
222
|
-
);
|
|
223
218
|
const connection = new BYOOAuthConnection({
|
|
224
219
|
id: conn.id,
|
|
225
220
|
provider: conn.provider,
|
|
226
|
-
baseUrl:
|
|
221
|
+
baseUrl: resolveEffectiveBaseUrl(conn.provider, baseUrl, conn.metadata),
|
|
227
222
|
accountInfo: conn.accountInfo,
|
|
228
|
-
tokenHeader: resolveTokenHeader(
|
|
229
|
-
providerRow?.injectionTemplates,
|
|
230
|
-
effectiveBaseUrl,
|
|
231
|
-
),
|
|
232
223
|
});
|
|
233
224
|
return { connection, ambiguous, allAccounts };
|
|
234
225
|
}
|
|
235
226
|
|
|
236
|
-
/**
|
|
237
|
-
* Pick the header a provider expects its access token in from the seed's
|
|
238
|
-
* header-type injection templates.
|
|
239
|
-
*
|
|
240
|
-
* Prefers the template whose `hostPattern` matches the base URL's host
|
|
241
|
-
* (`*.myshopify.com` style globs included), then falls back to the first
|
|
242
|
-
* header template. Returns `null` when the provider declares none, which
|
|
243
|
-
* leaves `BYOOAuthConnection` on its `Authorization: Bearer` default.
|
|
244
|
-
*
|
|
245
|
-
* Shopify is why this exists: its Admin API reads `X-Shopify-Access-Token`
|
|
246
|
-
* and ignores `Authorization`, so a Bearer header reaches the shop as an
|
|
247
|
-
* unauthenticated request and comes back 401.
|
|
248
|
-
*/
|
|
249
|
-
export function resolveTokenHeader(
|
|
250
|
-
rawTemplates: string | null | undefined,
|
|
251
|
-
baseUrl: string,
|
|
252
|
-
): BYOTokenHeader | null {
|
|
253
|
-
if (!rawTemplates) {
|
|
254
|
-
return null;
|
|
255
|
-
}
|
|
256
|
-
let parsed: unknown;
|
|
257
|
-
try {
|
|
258
|
-
parsed = JSON.parse(rawTemplates);
|
|
259
|
-
} catch {
|
|
260
|
-
return null;
|
|
261
|
-
}
|
|
262
|
-
if (!Array.isArray(parsed)) {
|
|
263
|
-
return null;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
const headerTemplates = parsed.filter(
|
|
267
|
-
(
|
|
268
|
-
t,
|
|
269
|
-
): t is {
|
|
270
|
-
hostPattern?: unknown;
|
|
271
|
-
headerName: string;
|
|
272
|
-
valuePrefix?: unknown;
|
|
273
|
-
} =>
|
|
274
|
-
typeof t === "object" &&
|
|
275
|
-
t !== null &&
|
|
276
|
-
(t as { injectionType?: unknown }).injectionType === "header" &&
|
|
277
|
-
typeof (t as { headerName?: unknown }).headerName === "string" &&
|
|
278
|
-
(t as { headerName: string }).headerName.trim() !== "",
|
|
279
|
-
);
|
|
280
|
-
if (headerTemplates.length === 0) {
|
|
281
|
-
return null;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
let host = "";
|
|
285
|
-
try {
|
|
286
|
-
host = new URL(baseUrl).hostname.toLowerCase();
|
|
287
|
-
} catch {
|
|
288
|
-
// Templated or malformed base URLs (e.g. a still-unfilled
|
|
289
|
-
// `https://{tenant_host}`) cannot be matched by host; fall through to
|
|
290
|
-
// the first header template.
|
|
291
|
-
}
|
|
292
|
-
const matching =
|
|
293
|
-
host === ""
|
|
294
|
-
? undefined
|
|
295
|
-
: headerTemplates.find(
|
|
296
|
-
(t) =>
|
|
297
|
-
typeof t.hostPattern === "string" &&
|
|
298
|
-
hostMatchesPattern(host, t.hostPattern),
|
|
299
|
-
);
|
|
300
|
-
const chosen = matching ?? headerTemplates[0];
|
|
301
|
-
return {
|
|
302
|
-
name: chosen.headerName.trim(),
|
|
303
|
-
valuePrefix:
|
|
304
|
-
typeof chosen.valuePrefix === "string" ? chosen.valuePrefix : "",
|
|
305
|
-
};
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
function hostMatchesPattern(host: string, pattern: string): boolean {
|
|
309
|
-
const p = pattern.trim().toLowerCase();
|
|
310
|
-
if (p === "") {
|
|
311
|
-
return false;
|
|
312
|
-
}
|
|
313
|
-
if (p.startsWith("*.")) {
|
|
314
|
-
const suffix = p.slice(1); // ".myshopify.com"
|
|
315
|
-
return host.endsWith(suffix) && host.length > suffix.length;
|
|
316
|
-
}
|
|
317
|
-
return host === p;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
227
|
/**
|
|
321
228
|
* Resolve the effective API base URL for a connection, preferring per-tenant
|
|
322
229
|
* values stored on the connection's `metadata` over the provider's static
|