@vellumai/assistant 0.11.6 → 0.11.7-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/ARCHITECTURE.md +31 -19
- package/Dockerfile +1 -0
- package/docs/architecture/security.md +3 -3
- package/docs/flux-turn-detection-spike.md +8 -7
- package/docs/runbook-trusted-contacts.md +14 -0
- package/docs/stt-provider-onboarding.md +8 -4
- package/knip.json +1 -0
- package/node_modules/@vellumai/avatar-manifest/package.json +18 -0
- package/node_modules/@vellumai/avatar-manifest/src/__tests__/manifest.test.ts +173 -0
- package/node_modules/@vellumai/avatar-manifest/src/__tests__/read.test.ts +114 -0
- package/node_modules/@vellumai/avatar-manifest/src/index.ts +29 -0
- package/node_modules/@vellumai/avatar-manifest/src/layout.ts +18 -0
- package/node_modules/@vellumai/avatar-manifest/src/manifest.ts +156 -0
- package/node_modules/@vellumai/avatar-manifest/src/read.ts +109 -0
- package/node_modules/@vellumai/avatar-manifest/tsconfig.json +20 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +37 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/remote-web-pairing.test.ts +389 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/ingress.ts +22 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +508 -18
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/rpc.ts +174 -0
- package/node_modules/@vellumai/ces-client/src/http-credentials.ts +161 -0
- package/node_modules/@vellumai/ces-client/src/index.ts +1 -0
- package/node_modules/@vellumai/environments/package.json +2 -1
- package/node_modules/@vellumai/environments/src/shell.test.ts +56 -0
- package/node_modules/@vellumai/environments/src/shell.ts +65 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +37 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/remote-web-pairing.test.ts +389 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/ingress.ts +22 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +508 -18
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/rpc.ts +174 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/contact-read-contracts.test.ts +32 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/gateway-client.test.ts +1 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/inbound-event-kind.test.ts +82 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/plugin-admission-denied-contract.test.ts +56 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +18 -0
- package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +5 -11
- package/node_modules/@vellumai/gateway-client/src/channel-permission-contract.ts +3 -1
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +9 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +4 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-event-kind.ts +75 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +17 -0
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +8 -0
- package/node_modules/@vellumai/gateway-client/src/plugin-admission-denied-contract.ts +47 -0
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +11 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +37 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/remote-web-pairing.test.ts +389 -0
- package/node_modules/@vellumai/service-contracts/src/ingress.ts +22 -0
- package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +508 -18
- package/node_modules/@vellumai/service-contracts/src/rpc.ts +174 -0
- package/openapi.yaml +419 -55
- package/package.json +4 -1
- package/scripts/sync-llm-catalog.ts +6 -0
- package/src/__tests__/approval-card-edit-inbound-handoff.test.ts +199 -0
- package/src/__tests__/approval-card-edit.test.ts +153 -0
- package/src/__tests__/attachments-store-heic-normalize.test.ts +1 -1
- package/src/__tests__/available-skills.test.ts +54 -0
- package/src/__tests__/avatar-identity-sync.test.ts +5 -1
- package/src/__tests__/catalog-install-normalize.test.ts +9 -1
- package/src/__tests__/channel-policy.test.ts +1 -3
- package/src/__tests__/channel-readiness-discord.test.ts +9 -70
- package/src/__tests__/compactor-call-site-logging.test.ts +61 -0
- package/src/__tests__/config-loader-backfill.test.ts +69 -0
- package/src/__tests__/config-schema.test.ts +2 -3
- package/src/__tests__/conversation-agent-loop.test.ts +238 -0
- package/src/__tests__/conversation-attachments.test.ts +0 -1
- package/src/__tests__/conversation-error.test.ts +44 -0
- package/src/__tests__/conversation-evictor.test.ts +19 -0
- package/src/__tests__/conversation-fork-referential.test.ts +73 -63
- package/src/__tests__/conversation-fork-retrospective.test.ts +99 -74
- package/src/__tests__/conversation-runtime-assembly.test.ts +23 -0
- package/src/__tests__/conversation-slash.test.ts +9 -0
- package/src/__tests__/conversation-title-service.test.ts +97 -0
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +16 -0
- package/src/__tests__/credential-broker-server-use.test.ts +0 -218
- package/src/__tests__/credential-broker.test.ts +43 -420
- package/src/__tests__/credential-record-write-through.test.ts +78 -0
- package/src/__tests__/credential-routes.test.ts +17 -1
- package/src/__tests__/credential-security-invariants.test.ts +8 -9
- package/src/__tests__/default-profile-catalog-fallback.test.ts +289 -0
- package/src/__tests__/delete-propagation.test.ts +92 -2
- package/src/__tests__/discord-callback-round-trip.test.ts +93 -0
- package/src/__tests__/discord-channel-config.test.ts +237 -0
- package/src/__tests__/edit-propagation.test.ts +42 -2
- package/src/__tests__/evict-conversations-for-reload.test.ts +51 -1
- package/src/__tests__/fallback-breaker.test.ts +1335 -0
- package/src/__tests__/gateway-threshold-reader-mock.ts +6 -0
- package/src/__tests__/guardian-card-withdrawal.test.ts +30 -0
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -2
- package/src/__tests__/image-conversion.test.ts +38 -4
- package/src/__tests__/install-skill-routing.test.ts +25 -0
- package/src/__tests__/llm-catalog-parity.test.ts +4 -0
- package/src/__tests__/llm-resolver.test.ts +74 -0
- package/src/__tests__/llm-schema-fallback-profile.test.ts +359 -0
- package/src/__tests__/managed-fallback-dispatch.test.ts +430 -0
- package/src/__tests__/managed-profile-guard.test.ts +28 -0
- package/src/__tests__/managed-speech-defaults.test.ts +196 -1
- package/src/__tests__/mcp-cli.test.ts +23 -1
- package/src/__tests__/mcp-tool-annotations-risk.test.ts +43 -34
- package/src/__tests__/media-stream-stt-session.test.ts +2 -0
- package/src/__tests__/notification-decision-fallback.test.ts +106 -0
- package/src/__tests__/notification-discord-adapter.test.ts +162 -0
- package/src/__tests__/oauth-connect-orchestrator.test.ts +95 -0
- package/src/__tests__/persist-unsendable-image-downscale.test.ts +6 -8
- package/src/__tests__/persist-unsendable-image.test.ts +3 -3
- package/src/__tests__/platform.test.ts +19 -1
- package/src/__tests__/plugin-import-boundary-guard.test.ts +5 -1
- package/src/__tests__/provider-catalog-visibility.test.ts +17 -0
- package/src/__tests__/provider-platform-proxy-integration.test.ts +8 -1
- package/src/__tests__/provider-usage-tracking.test.ts +56 -0
- package/src/__tests__/require-fresh-approval.test.ts +5 -2
- package/src/__tests__/retry-fallback-escalation.test.ts +1093 -0
- package/src/__tests__/schedule-retry.test.ts +183 -4
- package/src/__tests__/scheduler-reuse-conversation.test.ts +6 -6
- package/src/__tests__/secret-routes-platform-proxy.test.ts +55 -0
- package/src/__tests__/skill-load-tool.test.ts +34 -0
- package/src/__tests__/skill-tool-factory.test.ts +6 -1
- package/src/__tests__/skill-tool-manifest.test.ts +20 -0
- package/src/__tests__/skills.test.ts +25 -0
- package/src/__tests__/subagent-manager-notify.test.ts +38 -0
- package/src/__tests__/terminal-tools.test.ts +2 -0
- package/src/__tests__/tool-approval-handler.test.ts +146 -2
- package/src/__tests__/tool-approval-seed-content-blocks.test.ts +108 -2
- package/src/__tests__/tool-audit.test.ts +111 -40
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +228 -18
- package/src/__tests__/ui-shape-teaching.test.ts +1 -1
- package/src/__tests__/verification-control-plane-policy.test.ts +6 -2
- package/src/__tests__/voice-config-update.test.ts +43 -0
- package/src/__tests__/workspace-migration-147-rename-colliding-backup-profile-names.test.ts +480 -0
- package/src/__tests__/workspace-migration-148-strip-unsupported-fallback-profiles.test.ts +167 -0
- package/src/__tests__/workspace-migration-149-repoint-backup-profile-selections.test.ts +144 -0
- package/src/agent/loop.ts +31 -2
- package/src/approvals/guardian-card-withdrawal.ts +22 -0
- package/src/avatar/__tests__/ensure-raster.test.ts +291 -0
- package/src/avatar/avatar-manifest.ts +48 -100
- package/src/avatar/avatar-store.ts +7 -7
- package/src/avatar/ensure-raster.ts +146 -0
- package/src/avatar/resvg-lazy.test.ts +0 -1
- package/src/avatar/traits-png-sync.ts +9 -10
- package/src/background-wake/wake-intent-hooks.test.ts +0 -1
- package/src/backup/__tests__/paths.test.ts +6 -2
- package/src/backup/paths.ts +6 -4
- package/src/bundler/app-compiler.ts +2 -2
- package/src/bundler/compiler-tools.test.ts +36 -0
- package/src/bundler/compiler-tools.ts +54 -18
- package/src/calls/__tests__/telephony-synthesis-language.test.ts +81 -0
- package/src/calls/__tests__/voice-session-bridge.test.ts +57 -0
- package/src/calls/media-stream-stt-session.ts +2 -1
- package/src/calls/telephony-synthesis-language.ts +13 -5
- package/src/calls/voice-session-bridge.ts +19 -4
- package/src/channels/config.ts +23 -12
- package/src/cli/AGENTS.md +3 -1
- package/src/cli/commands/backup.help.ts +10 -13
- package/src/cli/commands/contacts.help.ts +16 -4
- package/src/cli/commands/contacts.ts +5 -1
- package/src/cli/commands/credentials.help.ts +1 -1
- package/src/cli/commands/inference-providers.ts +18 -53
- package/src/cli/commands/mcp.help.ts +6 -5
- package/src/cli/commands/mcp.ts +1 -1
- package/src/cli/commands/memory/memory-retrospective.ts +1 -0
- package/src/cli/commands/stt.help.ts +2 -2
- package/src/config/__tests__/backup-schema.test.ts +1 -1
- package/src/config/__tests__/default-profile-catalog.test.ts +83 -2
- package/src/config/__tests__/loader-sparse-array-cleanup.test.ts +1 -1
- package/src/config/__tests__/memory-retrospective-schema.test.ts +12 -15
- package/src/config/bundled-skills/computer-use/SKILL.md +6 -6
- package/src/config/bundled-skills/computer-use/TOOLS.json +9 -6
- package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +3 -1
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +1 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +16 -15
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +2 -1
- package/src/config/bundled-skills/settings/TOOLS.json +11 -5
- package/src/config/bundled-skills/settings/tools/open-system-settings.test.ts +85 -0
- package/src/config/bundled-skills/settings/tools/open-system-settings.ts +33 -8
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +54 -3
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +1 -1
- package/src/config/default-profile-catalog.ts +195 -10
- package/src/config/default-profile-names.ts +41 -0
- package/src/config/feature-flag-registry.json +34 -2
- package/src/config/inference-profile-validation.ts +11 -2
- package/src/config/llm-resolver.ts +25 -0
- package/src/config/loader.ts +3 -0
- package/src/config/managed-speech-defaults.ts +160 -10
- package/src/config/schema.ts +2 -0
- package/src/config/schemas/__tests__/live-voice.test.ts +7 -6
- package/src/config/schemas/__tests__/stt.test.ts +94 -0
- package/src/config/schemas/backup.ts +1 -1
- package/src/config/schemas/channels.ts +32 -0
- package/src/config/schemas/live-voice.ts +13 -4
- package/src/config/schemas/llm.ts +263 -15
- package/src/config/schemas/mcp.ts +10 -2
- package/src/config/schemas/memory-retrospective.ts +1 -19
- package/src/config/schemas/services.ts +24 -0
- package/src/config/schemas/stt.ts +128 -5
- package/src/config/seed-inference-profiles.ts +32 -3
- package/src/config/skill-state.ts +5 -0
- package/src/config/skills.ts +21 -0
- package/src/contacts/notify-contacts-changed.ts +5 -2
- package/src/context/compactor.ts +74 -1
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +138 -1
- package/src/daemon/config-watcher.ts +2 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +27 -0
- package/src/daemon/conversation-agent-loop.ts +86 -10
- package/src/daemon/conversation-error.ts +25 -0
- package/src/daemon/conversation-evictor.ts +2 -4
- package/src/daemon/conversation-runtime-assembly.ts +19 -7
- package/src/daemon/conversation-skill-tools.ts +5 -1
- package/src/daemon/conversation-slash.ts +2 -2
- package/src/daemon/conversation-store.ts +8 -1
- package/src/daemon/conversation-tool-setup.ts +37 -0
- package/src/daemon/conversation.ts +0 -4
- package/src/daemon/handlers/channel-config-result.ts +30 -0
- package/src/daemon/handlers/config-discord-channel.ts +301 -0
- package/src/daemon/handlers/config-ingress.ts +9 -0
- package/src/daemon/handlers/config-slack-channel.ts +13 -15
- package/src/daemon/handlers/config-telegram.ts +2 -5
- package/src/daemon/handlers/conversations.ts +0 -2
- package/src/daemon/handlers/skills.ts +25 -7
- package/src/daemon/lifecycle.ts +3 -1
- package/src/daemon/message-types/messages.ts +0 -2
- package/src/daemon/tool-setup-types.ts +5 -3
- package/src/daemon/trust-context-types.test.ts +33 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +0 -1
- package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +58 -4
- package/src/live-voice/__tests__/live-voice-managed-speech-fallback.test.ts +8 -3
- package/src/live-voice/__tests__/live-voice-session-manager.test.ts +73 -11
- package/src/live-voice/__tests__/live-voice-session-preflight.test.ts +148 -2
- package/src/live-voice/__tests__/live-voice-session-telemetry.test.ts +64 -0
- package/src/live-voice/__tests__/live-voice-stt.test.ts +3 -0
- package/src/live-voice/__tests__/live-voice-text-turn.test.ts +391 -0
- package/src/live-voice/__tests__/protocol.test.ts +224 -0
- package/src/live-voice/live-voice-credential-preflight.ts +5 -1
- package/src/live-voice/live-voice-session-manager.ts +39 -2
- package/src/live-voice/live-voice-session.ts +224 -9
- package/src/live-voice/protocol.ts +187 -1
- package/src/messaging/providers/discord/api.ts +2 -1
- package/src/messaging/providers/discord/withdraw.ts +62 -0
- package/src/messaging/read-provider-metadata.ts +32 -0
- package/src/monitoring/__tests__/file-descriptors.test.ts +32 -0
- package/src/monitoring/__tests__/process-memory.test.ts +34 -1
- package/src/monitoring/db-integrity-sample.ts +1 -0
- package/src/monitoring/file-descriptors.ts +39 -6
- package/src/monitoring/process-memory.ts +37 -5
- package/src/monitoring/resource-sampler.ts +25 -8
- package/src/notifications/__tests__/activity-failed-dedupe.test.ts +161 -0
- package/src/notifications/__tests__/background-failure-signal.test.ts +107 -0
- package/src/notifications/__tests__/connected-channels.test.ts +12 -0
- package/src/notifications/__tests__/copy-composer.test.ts +83 -0
- package/src/notifications/__tests__/destination-resolver.test.ts +38 -0
- package/src/notifications/activity-failed-dedupe.ts +95 -0
- package/src/notifications/adapters/discord.ts +132 -0
- package/src/notifications/adapters/shared.ts +16 -0
- package/src/notifications/adapters/slack.ts +6 -1
- package/src/notifications/adapters/telegram.ts +5 -8
- package/src/notifications/approval-card-data.ts +94 -1
- package/src/notifications/background-failure-signal.ts +116 -0
- package/src/notifications/broadcaster.ts +3 -9
- package/src/notifications/copy-composer.ts +41 -8
- package/src/notifications/decision-engine.ts +55 -0
- package/src/notifications/destination-resolver.ts +45 -5
- package/src/notifications/emit-signal.ts +19 -5
- package/src/notifications/guardian-question-mode.ts +57 -0
- package/src/notifications/types.ts +2 -8
- package/src/oauth/__tests__/seed-providers-managed.test.ts +18 -0
- package/src/oauth/connect-orchestrator.ts +16 -0
- package/src/oauth/seed-providers.ts +262 -0
- package/src/permissions/checker.test.ts +21 -0
- package/src/permissions/checker.ts +6 -0
- package/src/permissions/gateway-threshold-reader.test.ts +184 -0
- package/src/permissions/gateway-threshold-reader.ts +144 -10
- package/src/permissions/prompter.ts +0 -6
- package/src/permissions/types.ts +5 -4
- package/src/persistence/__tests__/bulk-write-gate.test.ts +0 -38
- package/src/persistence/bulk-write-gate.ts +9 -10
- package/src/persistence/conversation-crud.ts +88 -134
- package/src/persistence/conversation-title-service.ts +43 -29
- package/src/persistence/embeddings/embedding-local.ts +14 -85
- package/src/persistence/embeddings/embedding-runtime-manager.ts +1 -0
- package/src/persistence/lifecycle-events-store.test.ts +50 -0
- package/src/persistence/lifecycle-events-store.ts +75 -5
- package/src/platform/platform-patch-queue.test.ts +368 -0
- package/src/platform/platform-patch-queue.ts +190 -0
- package/src/platform/sync-avatar.test.ts +527 -0
- package/src/platform/sync-avatar.ts +209 -0
- package/src/platform/sync-identity.test.ts +75 -0
- package/src/platform/sync-identity.ts +17 -110
- package/src/plugin-api/model-profiles.test.ts +2 -2
- package/src/plugin-api/model-profiles.ts +7 -7
- package/src/plugin-api/transcription-session.ts +1 -1
- package/src/plugins/defaults/compaction/window-manager.ts +4 -0
- package/src/plugins/defaults/image-recovery/recover.ts +2 -2
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +133 -34
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +21 -31
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +13 -9
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-wake-chain.test.ts +31 -4
- package/src/plugins/defaults/memory/memory-retrospective-constants.ts +0 -11
- package/src/plugins/defaults/memory/memory-retrospective-fork-boundary.ts +27 -13
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +183 -113
- package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +13 -13
- package/src/plugins/defaults/memory/src/memory-v2-routes.ts +2 -2
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +1 -1
- package/src/plugins/defaults/memory/substrate/consolidation-job.ts +4 -2
- package/src/plugins/defaults/memory/substrate/sweep-job.ts +9 -42
- package/src/plugins/defaults/memory/v2/rerank-local.ts +1 -0
- package/src/plugins/defaults/memory/worker.ts +7 -0
- package/src/providers/__tests__/provider-secret-catalog.test.ts +1 -0
- package/src/providers/__tests__/retry-callsite.test.ts +55 -0
- package/src/providers/__tests__/vellum-connection-routing.test.ts +21 -3
- package/src/providers/connection-resolution.ts +2 -17
- package/src/providers/fallback-breaker.ts +389 -0
- package/src/providers/inference/__tests__/adapter-factory-opencode.test.ts +92 -0
- package/src/providers/inference/__tests__/base-url-route-validation.test.ts +16 -0
- package/src/providers/inference/__tests__/base-url-security.test.ts +12 -0
- package/src/providers/inference/adapter-factory.ts +246 -3
- package/src/providers/inference/auth.ts +15 -14
- package/src/providers/inference/chatgpt-subscription-auth.ts +70 -0
- package/src/providers/inference/chatgpt-subscription-credentials.ts +84 -0
- package/src/providers/inference/resolve-auth.ts +1 -1
- package/src/providers/media-resolve.ts +2 -3
- package/src/providers/model-catalog.ts +100 -0
- package/src/providers/openai/__tests__/api-error-normalization.test.ts +22 -0
- package/src/providers/openai/__tests__/chat-template-flatten.test.ts +198 -0
- package/src/providers/openai/api-error-normalization.ts +13 -0
- package/src/providers/openai/chat-completions-provider.ts +84 -0
- package/src/providers/opencode/client.test.ts +150 -0
- package/src/providers/opencode/client.ts +61 -0
- package/src/providers/platform-proxy/constants.ts +5 -0
- package/src/providers/provider-resolvability.ts +20 -0
- package/src/providers/provider-secret-catalog.ts +3 -2
- package/src/providers/retry.ts +956 -68
- package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +42 -0
- package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +136 -0
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +120 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +316 -12
- package/src/providers/speech-to-text/deepgram-flux-frames.ts +83 -3
- package/src/providers/speech-to-text/deepgram-flux-realtime.ts +132 -4
- package/src/providers/speech-to-text/provider-catalog.ts +191 -3
- package/src/providers/speech-to-text/resolve.ts +132 -24
- package/src/providers/speech-to-text/vellum-managed-flux-realtime.ts +296 -0
- package/src/providers/types.ts +39 -0
- package/src/providers/usage-tracking.ts +12 -1
- package/src/providers/vellum/client.ts +29 -0
- package/src/providers/vellum-model-routing.test.ts +2 -0
- package/src/providers/vellum-model-routing.ts +3 -3
- package/src/runtime/AGENTS.md +1 -2
- package/src/runtime/__tests__/agent-wake.test.ts +105 -3
- package/src/runtime/__tests__/background-job-runner.test.ts +89 -3
- package/src/runtime/agent-wake.ts +44 -5
- package/src/runtime/background-job-runner.ts +68 -50
- package/src/runtime/channel-readiness-service.ts +0 -39
- package/src/runtime/http-server.ts +12 -4
- package/src/runtime/routes/__tests__/avatar-state-routes.test.ts +18 -18
- package/src/runtime/routes/__tests__/backup-routes.test.ts +9 -5
- package/src/runtime/routes/__tests__/chatgpt-subscription-auth-routes.test.ts +372 -0
- package/src/runtime/routes/__tests__/contact-routes.test.ts +7 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +96 -0
- package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +37 -0
- package/src/runtime/routes/__tests__/ingress-status-routes.test.ts +2 -1
- package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +87 -0
- package/src/runtime/routes/acp-claude-auth-routes.ts +25 -54
- package/src/runtime/routes/approval-routes.ts +0 -12
- package/src/runtime/routes/avatar-routes.ts +17 -30
- package/src/runtime/routes/backup-routes.ts +2 -2
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +296 -113
- package/src/runtime/routes/contact-prompt-routes.ts +65 -6
- package/src/runtime/routes/contact-routes.ts +20 -15
- package/src/runtime/routes/conversation-query-routes.ts +98 -10
- package/src/runtime/routes/conversation-routes.ts +2 -2
- package/src/runtime/routes/credential-routes.ts +2 -1
- package/src/runtime/routes/guardian-approval-interception.ts +12 -9
- package/src/runtime/routes/inbound-message-handler.ts +47 -48
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +18 -13
- package/src/runtime/routes/inbound-stages/admission-policy.ts +2 -2
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +20 -2
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +9 -8
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +1 -1
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +2 -2
- package/src/runtime/routes/inference-profiles-routes.ts +12 -7
- package/src/runtime/routes/inference-provider-connection-routes.ts +2 -2
- package/src/runtime/routes/inference-send-routes.ts +2 -2
- package/src/runtime/routes/ingress-status-routes.ts +2 -2
- package/src/runtime/routes/integrations/discord.ts +119 -0
- package/src/runtime/routes/llm-call-sites-routes.ts +2 -2
- package/src/runtime/routes/mcp-auth-routes.ts +12 -6
- package/src/runtime/routes/migration-routes.ts +3 -1
- package/src/runtime/routes/oauth-pending-flows.ts +136 -0
- package/src/runtime/routes/secret-routes.ts +7 -0
- package/src/runtime/routes/stt-routes.ts +38 -6
- package/src/runtime/routes/wake-conversation-routes.ts +8 -1
- package/src/runtime/routes/watch-routes.ts +9 -5
- package/src/runtime/sync/resource-sync-events.ts +2 -0
- package/src/runtime/trust-verdict-consumer.ts +3 -3
- package/src/schedule/__tests__/worker-feature-flags.test.ts +58 -0
- package/src/schedule/retry-policy.ts +8 -8
- package/src/schedule/run-script.ts +14 -23
- package/src/schedule/schedule-recovery.ts +0 -1
- package/src/schedule/scheduler.ts +89 -51
- package/src/schedule/worker.ts +57 -0
- package/src/security/__tests__/openai-device-auth.test.ts +355 -0
- package/src/security/ces-rpc-record-backend.ts +123 -0
- package/src/security/oauth2.ts +7 -0
- package/src/security/openai-device-auth.ts +364 -0
- package/src/security/secure-keys.ts +15 -0
- package/src/skills/available-skills.ts +10 -1
- package/src/skills/catalog-install.ts +19 -1
- package/src/skills/inline-command-runner.ts +6 -2
- package/src/skills/platform-compatibility.test.ts +49 -0
- package/src/skills/platform-compatibility.ts +65 -0
- package/src/skills/tool-manifest.ts +20 -0
- package/src/stt/__tests__/roles.test.ts +152 -0
- package/src/stt/daemon-batch-transcriber.ts +4 -1
- package/src/stt/roles.ts +180 -0
- package/src/stt/stt-stream-session.ts +3 -2
- package/src/stt/types.ts +33 -3
- package/src/subagent/manager.ts +12 -0
- package/src/telemetry/__tests__/live-voice-funnel.test.ts +34 -0
- package/src/telemetry/live-voice-funnel.ts +12 -2
- package/src/telemetry/telemetry-wire.generated.ts +6 -0
- package/src/telemetry/tool-audit.ts +83 -30
- package/src/telemetry/tool-executed-events-store.test.ts +0 -1
- package/src/telemetry/turn-outcome.ts +75 -4
- package/src/tools/client-os.ts +115 -0
- package/src/tools/computer-use/definitions.ts +11 -7
- package/src/tools/computer-use/skill-proxy-bridge.ts +2 -2
- package/src/tools/credentials/broker-types.ts +0 -71
- package/src/tools/credentials/broker.ts +6 -201
- package/src/tools/credentials/metadata-store.ts +65 -16
- package/src/tools/credentials/store.ts +2 -0
- package/src/tools/executor.ts +2 -8
- package/src/tools/host-shell.test.ts +75 -0
- package/src/tools/host-shell.ts +24 -0
- package/src/tools/host-terminal/host-shell.ts +15 -44
- package/src/tools/mcp/mcp-tool-factory.ts +44 -9
- package/src/tools/permission-checker.ts +73 -21
- package/src/tools/policy-context.ts +1 -0
- package/src/tools/shared/filesystem/image-read.ts +1 -1
- package/src/tools/skills/find-similar-skills.ts +10 -2
- package/src/tools/skills/load.ts +41 -6
- package/src/tools/skills/sandbox-runner.ts +8 -16
- package/src/tools/skills/skill-tool-factory.ts +1 -0
- package/src/tools/terminal/__tests__/safe-env.test.ts +64 -1
- package/src/tools/terminal/safe-env.ts +39 -9
- package/src/tools/terminal/shell.ts +12 -31
- package/src/tools/tool-approval-handler.ts +64 -10
- package/src/tools/tool-types.ts +10 -0
- package/src/tools/types.ts +19 -3
- package/src/tools/ui-surface/surface-shape-docs.ts +4 -3
- package/src/tools/workflows/manage-workflows.ts +2 -2
- package/src/tools/workflows/run-workflow.test.ts +2 -1
- package/src/util/__tests__/file-use.test.ts +61 -0
- package/src/util/__tests__/process-table.test.ts +66 -0
- package/src/util/__tests__/process-tree.test.ts +46 -0
- package/src/util/errors.ts +1 -0
- package/src/util/file-use.ts +91 -0
- package/src/util/host-process.test.ts +17 -0
- package/src/util/host-process.ts +75 -0
- package/src/util/image-conversion.ts +39 -7
- package/src/util/platform.ts +32 -13
- package/src/util/process-table.ts +249 -0
- package/src/util/process-tree.ts +85 -129
- package/src/util/provider-error-patterns.ts +20 -0
- package/src/util/spawn.ts +9 -2
- package/src/watch/__tests__/watch-retro.test.ts +48 -1
- package/src/watch/watch-retro.ts +46 -4
- package/src/workspace/git-service.ts +4 -14
- package/src/workspace/migrations/147-rename-colliding-backup-profile-names.ts +360 -0
- package/src/workspace/migrations/148-strip-unsupported-fallback-profiles.ts +117 -0
- package/src/workspace/migrations/149-repoint-backup-profile-selections.ts +204 -0
- package/src/workspace/migrations/150-stt-flux-provider-to-model-family.ts +139 -0
- package/src/workspace/migrations/__tests__/150-stt-flux-provider-to-model-family.test.ts +160 -0
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/__tests__/permission-types.test.ts +0 -17
- package/src/channels/gateway-discord-admission.ts +0 -32
- package/src/persistence/fork-message-copy.ts +0 -239
- package/src/plugins/defaults/memory/__tests__/fork-message-copy.test.ts +0 -221
- package/src/security/__tests__/oauth2-device-code.test.ts +0 -431
- package/src/security/oauth2-device-code.ts +0 -312
|
@@ -10,8 +10,7 @@
|
|
|
10
10
|
import { ApprovalUIMetadataSchema } from "@vellumai/gateway-client";
|
|
11
11
|
import { z } from "zod";
|
|
12
12
|
|
|
13
|
-
import type {
|
|
14
|
-
import type { ChannelId } from "../channels/types.js";
|
|
13
|
+
import type { DeliverableChannelId } from "../channels/config.js";
|
|
15
14
|
import { AccessRequestPayloadSchema } from "./access-request-copy.js";
|
|
16
15
|
import { ToolApprovalSourceViewSchema } from "./guardian-question-mode.js";
|
|
17
16
|
import { UrgencySchema } from "./urgency.js";
|
|
@@ -20,12 +19,7 @@ import { UrgencySchema } from "./urgency.js";
|
|
|
20
19
|
* Derived from the channel policy registry: only channels whose
|
|
21
20
|
* deliveryEnabled flag is true are valid notification channels.
|
|
22
21
|
*/
|
|
23
|
-
export type NotificationChannel =
|
|
24
|
-
[K in keyof ChannelPolicies]: ChannelPolicies[K]["notification"]["deliveryEnabled"] extends true
|
|
25
|
-
? K
|
|
26
|
-
: never;
|
|
27
|
-
}[keyof ChannelPolicies] &
|
|
28
|
-
ChannelId;
|
|
22
|
+
export type NotificationChannel = DeliverableChannelId;
|
|
29
23
|
|
|
30
24
|
export const NotificationDeliveryStatusSchema = z.enum([
|
|
31
25
|
"pending",
|
|
@@ -11,6 +11,24 @@ describe("PROVIDER_SEED_DATA managed mode wiring", () => {
|
|
|
11
11
|
expect("github-oauth" in ServicesSchema.shape).toBe(true);
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
+
test("monday only exposes scopes supported by its OAuth API", () => {
|
|
15
|
+
const monday = PROVIDER_SEED_DATA.monday;
|
|
16
|
+
expect(monday).toBeDefined();
|
|
17
|
+
expect(monday.defaultScopes).not.toContain("items:read");
|
|
18
|
+
expect(monday.defaultScopes).not.toContain("items:write");
|
|
19
|
+
|
|
20
|
+
const availableScopes = monday.availableScopes;
|
|
21
|
+
expect(Array.isArray(availableScopes)).toBe(true);
|
|
22
|
+
if (Array.isArray(availableScopes)) {
|
|
23
|
+
expect(availableScopes.map(({ scope }) => scope)).not.toContain(
|
|
24
|
+
"items:read",
|
|
25
|
+
);
|
|
26
|
+
expect(availableScopes.map(({ scope }) => scope)).not.toContain(
|
|
27
|
+
"items:write",
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
14
32
|
test("google base URL is host-only so relative paths select the product", () => {
|
|
15
33
|
// A host-only base URL (no product path) lets a relative request path pick
|
|
16
34
|
// the Google product — Gmail (/gmail/v1/...), Calendar (/calendar/v3/...),
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
* - Running identity verifiers
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
+
import { loadConfig } from "../config/loader.js";
|
|
22
23
|
import { emitPostConnectNudge } from "../home/post-connect-feed.js";
|
|
23
24
|
import { invalidateAssistantSuggestedPromptsCache } from "../home/suggested-prompts-cache.js";
|
|
24
25
|
import type { TokenEndpointAuthMethod } from "../security/oauth2.js";
|
|
@@ -27,6 +28,7 @@ import { getLogger } from "../util/logger.js";
|
|
|
27
28
|
import type { OAuthConnectResult } from "./connect-types.js";
|
|
28
29
|
import { verifyIdentity } from "./identity-verifier.js";
|
|
29
30
|
import { getProvider } from "./oauth-store.js";
|
|
31
|
+
import { isProviderVisible } from "./provider-visibility.js";
|
|
30
32
|
import { storeOAuth2Tokens } from "./token-persistence.js";
|
|
31
33
|
|
|
32
34
|
const log = getLogger("oauth-connect-orchestrator");
|
|
@@ -130,6 +132,20 @@ export async function orchestrateOAuthConnect(
|
|
|
130
132
|
};
|
|
131
133
|
}
|
|
132
134
|
|
|
135
|
+
// A provider gated behind a disabled feature flag is not connectable. This
|
|
136
|
+
// is the choke point every connect path funnels through (runtime routes,
|
|
137
|
+
// gateway, CLI, credential vault tool), so enforcing here covers all of
|
|
138
|
+
// them rather than relying on each entry point to check. The error matches
|
|
139
|
+
// the not-found case above so a gated provider is indistinguishable from an
|
|
140
|
+
// absent one, mirroring the provider routes.
|
|
141
|
+
if (!isProviderVisible(providerRow, loadConfig())) {
|
|
142
|
+
return {
|
|
143
|
+
success: false,
|
|
144
|
+
error: `No OAuth provider registered for "${options.service}". Ensure the provider is seeded in the database.`,
|
|
145
|
+
safeError: true,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
133
149
|
// Deserialize JSON fields from the DB row
|
|
134
150
|
const dbAuthorizeParams = safeJsonParse<Record<string, string> | undefined>(
|
|
135
151
|
providerRow.authorizeParams,
|
|
@@ -684,6 +684,268 @@ export const PROVIDER_SEED_DATA: Record<
|
|
|
684
684
|
identityResponsePaths: ["email", "preferred_username"],
|
|
685
685
|
},
|
|
686
686
|
|
|
687
|
+
monday: {
|
|
688
|
+
provider: "monday",
|
|
689
|
+
authorizeUrl: "https://auth.monday.com/oauth2/authorize",
|
|
690
|
+
tokenExchangeUrl: "https://auth.monday.com/oauth2/token",
|
|
691
|
+
pingUrl: "https://api.monday.com/v2",
|
|
692
|
+
pingMethod: "POST",
|
|
693
|
+
pingHeaders: { "Content-Type": "application/json" },
|
|
694
|
+
pingBody: { query: "{ me { id name email } }" },
|
|
695
|
+
baseUrl: "https://api.monday.com",
|
|
696
|
+
displayLabel: "monday.com",
|
|
697
|
+
description: "Boards, items, docs, and updates",
|
|
698
|
+
dashboardUrl: "https://auth.monday.com/apps",
|
|
699
|
+
clientIdPlaceholder: null,
|
|
700
|
+
// Simple Icons does not host a monday.com mark (both `monday` and
|
|
701
|
+
// `mondaydotcom` 404 on the CDN), so use the documented thesvg fallback.
|
|
702
|
+
logoUrl:
|
|
703
|
+
"https://cdn.jsdelivr.net/gh/glincker/thesvg@main/public/icons/monday/default.svg",
|
|
704
|
+
// monday tokens do not expire under the legacy OAuth flow and no refresh
|
|
705
|
+
// token is issued, so there is no refreshUrl. The newer OAuth 2.1 flow
|
|
706
|
+
// adds expiry/refresh/revocation but is opt-in per app version in the
|
|
707
|
+
// Developer Center and posts JSON (not form-encoded) credentials, so it
|
|
708
|
+
// is deliberately not used here.
|
|
709
|
+
defaultScopes: [
|
|
710
|
+
"me:read",
|
|
711
|
+
"account:read",
|
|
712
|
+
"users:read",
|
|
713
|
+
"teams:read",
|
|
714
|
+
"workspaces:read",
|
|
715
|
+
"boards:read",
|
|
716
|
+
"boards:write",
|
|
717
|
+
"docs:read",
|
|
718
|
+
"updates:read",
|
|
719
|
+
"updates:write",
|
|
720
|
+
"assets:read",
|
|
721
|
+
"tags:read",
|
|
722
|
+
"notifications:write",
|
|
723
|
+
],
|
|
724
|
+
availableScopes: [
|
|
725
|
+
{ scope: "me:read", description: "Read the user's profile information" },
|
|
726
|
+
{
|
|
727
|
+
scope: "account:read",
|
|
728
|
+
description: "Read general information about the account",
|
|
729
|
+
},
|
|
730
|
+
{
|
|
731
|
+
scope: "users:read",
|
|
732
|
+
description: "Read profile information of the account's users",
|
|
733
|
+
},
|
|
734
|
+
{
|
|
735
|
+
scope: "users:write",
|
|
736
|
+
description: "Modify profile information of the account's users",
|
|
737
|
+
},
|
|
738
|
+
{
|
|
739
|
+
scope: "teams:read",
|
|
740
|
+
description: "Read information about the account's teams",
|
|
741
|
+
},
|
|
742
|
+
{ scope: "teams:write", description: "Modify the account's teams" },
|
|
743
|
+
{
|
|
744
|
+
scope: "workspaces:read",
|
|
745
|
+
description: "Read a user's workspaces data",
|
|
746
|
+
},
|
|
747
|
+
{
|
|
748
|
+
scope: "workspaces:write",
|
|
749
|
+
description: "Modify a user's workspaces data",
|
|
750
|
+
},
|
|
751
|
+
{ scope: "boards:read", description: "Read a user's board data" },
|
|
752
|
+
{ scope: "boards:write", description: "Modify a user's board data" },
|
|
753
|
+
{ scope: "docs:read", description: "Read a user's docs" },
|
|
754
|
+
{ scope: "docs:write", description: "Modify a user's docs" },
|
|
755
|
+
{
|
|
756
|
+
scope: "updates:read",
|
|
757
|
+
description: "Read updates and replies the user can see",
|
|
758
|
+
},
|
|
759
|
+
{
|
|
760
|
+
scope: "updates:write",
|
|
761
|
+
description: "Post or edit updates on behalf of the user",
|
|
762
|
+
},
|
|
763
|
+
{
|
|
764
|
+
scope: "assets:read",
|
|
765
|
+
description: "Read data from assets the user has access to",
|
|
766
|
+
},
|
|
767
|
+
{ scope: "tags:read", description: "Read the account's tags" },
|
|
768
|
+
{
|
|
769
|
+
scope: "notifications:write",
|
|
770
|
+
description: "Send notifications on behalf of the user",
|
|
771
|
+
},
|
|
772
|
+
{
|
|
773
|
+
scope: "webhooks:read",
|
|
774
|
+
description: "Read existing webhooks configuration",
|
|
775
|
+
},
|
|
776
|
+
{
|
|
777
|
+
scope: "webhooks:write",
|
|
778
|
+
description: "Create and modify webhooks",
|
|
779
|
+
},
|
|
780
|
+
{
|
|
781
|
+
scope: "departments:read",
|
|
782
|
+
description: "Read the account's department data",
|
|
783
|
+
},
|
|
784
|
+
{
|
|
785
|
+
scope: "departments:write",
|
|
786
|
+
description: "Modify the account's departments",
|
|
787
|
+
},
|
|
788
|
+
],
|
|
789
|
+
tokenEndpointAuthMethod: "client_secret_post",
|
|
790
|
+
// 17337/17338 are taken by eventbrite/calendly (all three providers
|
|
791
|
+
// landed in parallel and independently picked the next free port at the
|
|
792
|
+
// time); 17339 is the real next-free slot once all three are seeded
|
|
793
|
+
// together.
|
|
794
|
+
loopbackPort: 17339,
|
|
795
|
+
managedServiceConfigKey: "monday-oauth",
|
|
796
|
+
injectionTemplates: [
|
|
797
|
+
{
|
|
798
|
+
hostPattern: "api.monday.com",
|
|
799
|
+
injectionType: "header",
|
|
800
|
+
headerName: "Authorization",
|
|
801
|
+
valuePrefix: "Bearer ",
|
|
802
|
+
},
|
|
803
|
+
],
|
|
804
|
+
appType: "App",
|
|
805
|
+
identityUrl: "https://api.monday.com/v2",
|
|
806
|
+
identityMethod: "POST",
|
|
807
|
+
identityHeaders: { "Content-Type": "application/json" },
|
|
808
|
+
identityBody: { query: "{ me { id name email } }" },
|
|
809
|
+
identityResponsePaths: ["data.me.name", "data.me.email"],
|
|
810
|
+
featureFlag: "monday-oauth",
|
|
811
|
+
},
|
|
812
|
+
|
|
813
|
+
eventbrite: {
|
|
814
|
+
provider: "eventbrite",
|
|
815
|
+
authorizeUrl: "https://www.eventbrite.com/oauth/authorize",
|
|
816
|
+
tokenExchangeUrl: "https://www.eventbrite.com/oauth/token",
|
|
817
|
+
refreshUrl: "https://www.eventbrite.com/oauth/token",
|
|
818
|
+
pingUrl: "https://www.eventbriteapi.com/v3/users/me/",
|
|
819
|
+
baseUrl: "https://www.eventbriteapi.com",
|
|
820
|
+
displayLabel: "Eventbrite",
|
|
821
|
+
description: "Events, attendees, and ticket orders",
|
|
822
|
+
dashboardUrl: "https://www.eventbrite.com/platform/api-keys/",
|
|
823
|
+
clientIdPlaceholder: null,
|
|
824
|
+
// Simple Icons does not host an Eventbrite mark (cdn.simpleicons.org
|
|
825
|
+
// 404s), so use the documented thesvg fallback.
|
|
826
|
+
logoUrl:
|
|
827
|
+
"https://cdn.jsdelivr.net/gh/glincker/thesvg@main/public/icons/eventbrite/default.svg",
|
|
828
|
+
// Eventbrite has no granular OAuth scope system: an access token carries
|
|
829
|
+
// the full permissions of the user who authorized it, and the authorize
|
|
830
|
+
// endpoint ignores a `scope` parameter. Seed an empty set rather than
|
|
831
|
+
// inventing scope strings the provider would silently drop (same shape
|
|
832
|
+
// as Notion).
|
|
833
|
+
defaultScopes: [],
|
|
834
|
+
tokenEndpointAuthMethod: "client_secret_post",
|
|
835
|
+
loopbackPort: 17337,
|
|
836
|
+
managedServiceConfigKey: "eventbrite-oauth",
|
|
837
|
+
injectionTemplates: [
|
|
838
|
+
{
|
|
839
|
+
hostPattern: "www.eventbriteapi.com",
|
|
840
|
+
injectionType: "header",
|
|
841
|
+
headerName: "Authorization",
|
|
842
|
+
valuePrefix: "Bearer ",
|
|
843
|
+
},
|
|
844
|
+
],
|
|
845
|
+
appType: "App",
|
|
846
|
+
identityUrl: "https://www.eventbriteapi.com/v3/users/me/",
|
|
847
|
+
identityResponsePaths: ["name", "first_name"],
|
|
848
|
+
},
|
|
849
|
+
|
|
850
|
+
calendly: {
|
|
851
|
+
provider: "calendly",
|
|
852
|
+
authorizeUrl: "https://auth.calendly.com/oauth/authorize",
|
|
853
|
+
tokenExchangeUrl: "https://auth.calendly.com/oauth/token",
|
|
854
|
+
pingUrl: "https://api.calendly.com/users/me",
|
|
855
|
+
baseUrl: "https://api.calendly.com",
|
|
856
|
+
displayLabel: "Calendly",
|
|
857
|
+
description: "Scheduling links and meetings",
|
|
858
|
+
dashboardUrl: "https://calendly.com/integrations/api_webhooks",
|
|
859
|
+
clientIdPlaceholder: null,
|
|
860
|
+
logoUrl: "https://cdn.simpleicons.org/calendly",
|
|
861
|
+
// A :write scope implicitly grants the matching :read in the same domain,
|
|
862
|
+
// so the baseline stays at the six that map to reading schedule data and
|
|
863
|
+
// creating bookings/links. Organization-wide visibility is opt-in.
|
|
864
|
+
defaultScopes: [
|
|
865
|
+
"users:read",
|
|
866
|
+
"event_types:read",
|
|
867
|
+
"scheduled_events:read",
|
|
868
|
+
"availability:read",
|
|
869
|
+
"scheduled_events:write",
|
|
870
|
+
"scheduling_links:write",
|
|
871
|
+
],
|
|
872
|
+
availableScopes: [
|
|
873
|
+
{ scope: "users:read", description: "Read the connected user's profile" },
|
|
874
|
+
{
|
|
875
|
+
scope: "event_types:read",
|
|
876
|
+
description: "Read event types and their available times",
|
|
877
|
+
},
|
|
878
|
+
{
|
|
879
|
+
scope: "event_types:write",
|
|
880
|
+
description: "Create and update event types",
|
|
881
|
+
},
|
|
882
|
+
{
|
|
883
|
+
scope: "scheduled_events:read",
|
|
884
|
+
description: "Read scheduled events and invitees",
|
|
885
|
+
},
|
|
886
|
+
{
|
|
887
|
+
scope: "scheduled_events:write",
|
|
888
|
+
description: "Create invitees, cancel events, mark no-shows",
|
|
889
|
+
},
|
|
890
|
+
{
|
|
891
|
+
scope: "availability:read",
|
|
892
|
+
description: "Read busy times and availability schedules",
|
|
893
|
+
},
|
|
894
|
+
{
|
|
895
|
+
scope: "availability:write",
|
|
896
|
+
description: "Update event type availability",
|
|
897
|
+
},
|
|
898
|
+
{
|
|
899
|
+
scope: "scheduling_links:write",
|
|
900
|
+
description: "Create single-use scheduling links",
|
|
901
|
+
},
|
|
902
|
+
{
|
|
903
|
+
scope: "shares:write",
|
|
904
|
+
description: "Create customized single-use scheduling links",
|
|
905
|
+
},
|
|
906
|
+
{
|
|
907
|
+
scope: "organizations:read",
|
|
908
|
+
description: "Read organization data and memberships",
|
|
909
|
+
},
|
|
910
|
+
{
|
|
911
|
+
scope: "groups:read",
|
|
912
|
+
description: "Read group details and relationships",
|
|
913
|
+
},
|
|
914
|
+
{
|
|
915
|
+
scope: "webhooks:read",
|
|
916
|
+
description: "Read webhook subscriptions",
|
|
917
|
+
},
|
|
918
|
+
{
|
|
919
|
+
scope: "webhooks:write",
|
|
920
|
+
description: "Create and delete webhook subscriptions",
|
|
921
|
+
},
|
|
922
|
+
{ scope: "contacts:read", description: "Read contact details" },
|
|
923
|
+
{
|
|
924
|
+
scope: "contacts:write",
|
|
925
|
+
description: "Create, update, and delete contacts",
|
|
926
|
+
},
|
|
927
|
+
],
|
|
928
|
+
tokenEndpointAuthMethod: "client_secret_basic",
|
|
929
|
+
// 17337 is taken by eventbrite (both providers landed in parallel and
|
|
930
|
+
// independently picked the next free port at the time); 17338 is the
|
|
931
|
+
// real next-free slot once both are seeded together.
|
|
932
|
+
loopbackPort: 17338,
|
|
933
|
+
managedServiceConfigKey: "calendly-oauth",
|
|
934
|
+
injectionTemplates: [
|
|
935
|
+
{
|
|
936
|
+
hostPattern: "api.calendly.com",
|
|
937
|
+
injectionType: "header",
|
|
938
|
+
headerName: "Authorization",
|
|
939
|
+
valuePrefix: "Bearer ",
|
|
940
|
+
},
|
|
941
|
+
],
|
|
942
|
+
revokeUrl: "https://auth.calendly.com/oauth/revoke",
|
|
943
|
+
revokeBodyTemplate: { token: "{access_token}" },
|
|
944
|
+
appType: "App",
|
|
945
|
+
identityUrl: "https://api.calendly.com/users/me",
|
|
946
|
+
identityResponsePaths: ["resource.email", "resource.name"],
|
|
947
|
+
},
|
|
948
|
+
|
|
687
949
|
figma: {
|
|
688
950
|
provider: "figma",
|
|
689
951
|
authorizeUrl: "https://www.figma.com/oauth",
|
|
@@ -547,6 +547,27 @@ describe("Permission Checker (gateway IPC)", () => {
|
|
|
547
547
|
expect(result.level).toBe(RiskLevel.Medium);
|
|
548
548
|
});
|
|
549
549
|
|
|
550
|
+
test("builds PowerShell params for Windows host_bash", async () => {
|
|
551
|
+
mockIpcClassifyRiskResult = {
|
|
552
|
+
risk: "high",
|
|
553
|
+
reason: "PowerShell mutation",
|
|
554
|
+
matchType: "registry",
|
|
555
|
+
scopeOptions: [],
|
|
556
|
+
};
|
|
557
|
+
|
|
558
|
+
await classifyRisk(
|
|
559
|
+
"host_bash",
|
|
560
|
+
{ command: "Remove-Item C:\\Temp\\data" },
|
|
561
|
+
"C:\\Users\\Example",
|
|
562
|
+
undefined,
|
|
563
|
+
undefined,
|
|
564
|
+
undefined,
|
|
565
|
+
"powershell",
|
|
566
|
+
);
|
|
567
|
+
|
|
568
|
+
expect(lastClassifyRiskParams?.shell).toBe("powershell");
|
|
569
|
+
});
|
|
570
|
+
|
|
550
571
|
test("builds params for file tools", async () => {
|
|
551
572
|
mockIpcClassifyRiskResult = {
|
|
552
573
|
risk: "low",
|
|
@@ -420,6 +420,7 @@ function buildClassifyRiskParams(
|
|
|
420
420
|
input: Record<string, unknown>,
|
|
421
421
|
workingDir?: string,
|
|
422
422
|
manifestOverride?: ManifestOverride,
|
|
423
|
+
shell?: ClassifyRiskIpcParams["shell"],
|
|
423
424
|
): ClassifyRiskIpcParams {
|
|
424
425
|
// ── Bash/host_bash ──
|
|
425
426
|
if (toolName === "bash" || toolName === "host_bash") {
|
|
@@ -437,6 +438,7 @@ function buildClassifyRiskParams(
|
|
|
437
438
|
return {
|
|
438
439
|
tool: toolName,
|
|
439
440
|
command: getStringField(input, "command"),
|
|
441
|
+
shell,
|
|
440
442
|
workingDir,
|
|
441
443
|
workspaceRoot: getWorkspaceDir(),
|
|
442
444
|
isContainerized: getIsContainerized(),
|
|
@@ -577,6 +579,7 @@ export async function classifyRisk(
|
|
|
577
579
|
_preParsed?: unknown,
|
|
578
580
|
manifestOverride?: ManifestOverride,
|
|
579
581
|
signal?: AbortSignal,
|
|
582
|
+
shell?: ClassifyRiskIpcParams["shell"],
|
|
580
583
|
): Promise<RiskClassificationWithMeta> {
|
|
581
584
|
signal?.throwIfAborted();
|
|
582
585
|
|
|
@@ -585,6 +588,7 @@ export async function classifyRisk(
|
|
|
585
588
|
input,
|
|
586
589
|
workingDir,
|
|
587
590
|
manifestOverride,
|
|
591
|
+
shell,
|
|
588
592
|
);
|
|
589
593
|
const gatewayResult = await ipcClassifyRisk(ipcParams, signal);
|
|
590
594
|
// A mid-retry cancellation should surface as an AbortError, not the
|
|
@@ -709,6 +713,7 @@ export async function check(
|
|
|
709
713
|
policyContext?.conversationId,
|
|
710
714
|
policyContext?.executionContext,
|
|
711
715
|
cellQuery,
|
|
716
|
+
policyContext?.requesterContactId,
|
|
712
717
|
);
|
|
713
718
|
const approvalContext: ApprovalContext = {
|
|
714
719
|
riskLevel: risk,
|
|
@@ -740,6 +745,7 @@ export async function check(
|
|
|
740
745
|
policyContext?.conversationId,
|
|
741
746
|
policyContext?.executionContext,
|
|
742
747
|
cellQuery,
|
|
748
|
+
policyContext?.requesterContactId,
|
|
743
749
|
);
|
|
744
750
|
if (freshThreshold !== null && freshThreshold !== threshold) {
|
|
745
751
|
approvalDecision = defaultApprovalPolicy.evaluate({
|
|
@@ -37,6 +37,9 @@ import {
|
|
|
37
37
|
_clearGlobalCacheForTesting,
|
|
38
38
|
_resetFailureCoalesceForTesting,
|
|
39
39
|
getAutoApproveThreshold,
|
|
40
|
+
getContactAutoApproveThreshold,
|
|
41
|
+
invalidateAllContactThresholdCaches,
|
|
42
|
+
invalidateContactThresholdCache,
|
|
40
43
|
refreshAutoApproveThreshold,
|
|
41
44
|
} from "./gateway-threshold-reader.js";
|
|
42
45
|
|
|
@@ -633,3 +636,184 @@ describe("contact cell layer failure semantics", () => {
|
|
|
633
636
|
).toBe("low");
|
|
634
637
|
});
|
|
635
638
|
});
|
|
639
|
+
|
|
640
|
+
describe("contact-level ceiling", () => {
|
|
641
|
+
beforeEach(() => {
|
|
642
|
+
_clearGlobalCacheForTesting();
|
|
643
|
+
_resetFailureCoalesceForTesting();
|
|
644
|
+
ipcHandlers.clear();
|
|
645
|
+
ipcCallLog.length = 0;
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
test("the conversation override beats the contact ceiling", async () => {
|
|
649
|
+
ipcHandlers.set("get_conversation_threshold", () => ({
|
|
650
|
+
threshold: "none",
|
|
651
|
+
}));
|
|
652
|
+
ipcHandlers.set("get_contact_threshold", () => ({ threshold: "high" }));
|
|
653
|
+
ipcHandlers.set("resolve_channel_permission_threshold", () => ({
|
|
654
|
+
resolved: { threshold: "low", scope: "channel" },
|
|
655
|
+
}));
|
|
656
|
+
setGlobals("low");
|
|
657
|
+
|
|
658
|
+
expect(
|
|
659
|
+
await getAutoApproveThreshold(
|
|
660
|
+
"conv-ct1",
|
|
661
|
+
"conversation",
|
|
662
|
+
CELL_QUERY,
|
|
663
|
+
"contact-1",
|
|
664
|
+
),
|
|
665
|
+
).toBe("none");
|
|
666
|
+
expect(countCalls("get_contact_threshold")).toBe(0);
|
|
667
|
+
expect(countCalls("resolve_channel_permission_threshold")).toBe(0);
|
|
668
|
+
});
|
|
669
|
+
|
|
670
|
+
test("the contact ceiling beats the cell", async () => {
|
|
671
|
+
ipcHandlers.set("get_conversation_threshold", () => null);
|
|
672
|
+
ipcHandlers.set("get_contact_threshold", () => ({ threshold: "high" }));
|
|
673
|
+
ipcHandlers.set("resolve_channel_permission_threshold", () => ({
|
|
674
|
+
resolved: { threshold: "none", scope: "channel" },
|
|
675
|
+
}));
|
|
676
|
+
setGlobals("low");
|
|
677
|
+
|
|
678
|
+
expect(
|
|
679
|
+
await getAutoApproveThreshold(
|
|
680
|
+
"conv-ct2",
|
|
681
|
+
"conversation",
|
|
682
|
+
CELL_QUERY,
|
|
683
|
+
"contact-1",
|
|
684
|
+
),
|
|
685
|
+
).toBe("high");
|
|
686
|
+
expect(countCalls("resolve_channel_permission_threshold")).toBe(0);
|
|
687
|
+
});
|
|
688
|
+
|
|
689
|
+
test("the contact ceiling is not collapsed", async () => {
|
|
690
|
+
ipcHandlers.set("get_conversation_threshold", () => null);
|
|
691
|
+
ipcHandlers.set("get_contact_threshold", () => ({ threshold: "medium" }));
|
|
692
|
+
ipcHandlers.set("resolve_channel_permission_threshold", () => ({
|
|
693
|
+
resolved: { threshold: "none", scope: "channel" },
|
|
694
|
+
}));
|
|
695
|
+
setGlobals("low");
|
|
696
|
+
|
|
697
|
+
expect(
|
|
698
|
+
await getAutoApproveThreshold(
|
|
699
|
+
"conv-ct3",
|
|
700
|
+
"conversation",
|
|
701
|
+
CELL_QUERY,
|
|
702
|
+
"contact-1",
|
|
703
|
+
),
|
|
704
|
+
).toBe("medium");
|
|
705
|
+
});
|
|
706
|
+
|
|
707
|
+
test("a null contact ceiling inherits the cell cascade", async () => {
|
|
708
|
+
ipcHandlers.set("get_conversation_threshold", () => null);
|
|
709
|
+
ipcHandlers.set("get_contact_threshold", () => null);
|
|
710
|
+
ipcHandlers.set("resolve_channel_permission_threshold", () => ({
|
|
711
|
+
resolved: { threshold: "none", scope: "channel" },
|
|
712
|
+
}));
|
|
713
|
+
setGlobals("high");
|
|
714
|
+
|
|
715
|
+
expect(
|
|
716
|
+
await getAutoApproveThreshold(
|
|
717
|
+
"conv-ct4",
|
|
718
|
+
"conversation",
|
|
719
|
+
CELL_QUERY,
|
|
720
|
+
"contact-1",
|
|
721
|
+
),
|
|
722
|
+
).toBe("none");
|
|
723
|
+
});
|
|
724
|
+
|
|
725
|
+
test("a contact-threshold transport failure falls through to the cell", async () => {
|
|
726
|
+
ipcHandlers.set("get_conversation_threshold", () => null);
|
|
727
|
+
ipcHandlers.set("resolve_channel_permission_threshold", () => ({
|
|
728
|
+
resolved: { threshold: "none", scope: "channel" },
|
|
729
|
+
}));
|
|
730
|
+
setGlobals("high");
|
|
731
|
+
|
|
732
|
+
expect(
|
|
733
|
+
await getAutoApproveThreshold(
|
|
734
|
+
"conv-ct-fail",
|
|
735
|
+
"conversation",
|
|
736
|
+
CELL_QUERY,
|
|
737
|
+
"contact-1",
|
|
738
|
+
),
|
|
739
|
+
).toBe("none");
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
test("refresh honors the contact ceiling after a conversation miss", async () => {
|
|
743
|
+
ipcHandlers.set("get_conversation_threshold", () => null);
|
|
744
|
+
ipcHandlers.set("get_contact_threshold", () => ({ threshold: "high" }));
|
|
745
|
+
ipcHandlers.set("resolve_channel_permission_threshold", () => ({
|
|
746
|
+
resolved: { threshold: "none", scope: "channel" },
|
|
747
|
+
}));
|
|
748
|
+
setGlobals("low");
|
|
749
|
+
|
|
750
|
+
expect(
|
|
751
|
+
await refreshAutoApproveThreshold(
|
|
752
|
+
"conv-ct5",
|
|
753
|
+
"conversation",
|
|
754
|
+
CELL_QUERY,
|
|
755
|
+
"contact-1",
|
|
756
|
+
),
|
|
757
|
+
).toBe("high");
|
|
758
|
+
expect(countCalls("resolve_channel_permission_threshold")).toBe(0);
|
|
759
|
+
});
|
|
760
|
+
|
|
761
|
+
test("refresh keeps the prompt when the contact lookup fails", async () => {
|
|
762
|
+
ipcHandlers.set("get_conversation_threshold", () => null);
|
|
763
|
+
ipcHandlers.set("resolve_channel_permission_threshold", () => ({
|
|
764
|
+
resolved: { threshold: "low", scope: "channel" },
|
|
765
|
+
}));
|
|
766
|
+
setGlobals("high");
|
|
767
|
+
|
|
768
|
+
expect(
|
|
769
|
+
await refreshAutoApproveThreshold(
|
|
770
|
+
"conv-ct6",
|
|
771
|
+
"conversation",
|
|
772
|
+
CELL_QUERY,
|
|
773
|
+
"contact-1",
|
|
774
|
+
),
|
|
775
|
+
).toBeNull();
|
|
776
|
+
expect(countCalls("resolve_channel_permission_threshold")).toBe(0);
|
|
777
|
+
});
|
|
778
|
+
|
|
779
|
+
test("getContactAutoApproveThreshold returns a live ceiling and caches it", async () => {
|
|
780
|
+
ipcHandlers.set("get_contact_threshold", () => ({ threshold: "high" }));
|
|
781
|
+
|
|
782
|
+
expect(await getContactAutoApproveThreshold("contact-1")).toBe("high");
|
|
783
|
+
expect(await getContactAutoApproveThreshold("contact-1")).toBe("high");
|
|
784
|
+
expect(countCalls("get_contact_threshold")).toBe(1);
|
|
785
|
+
});
|
|
786
|
+
|
|
787
|
+
test("invalidateContactThresholdCache drops a cached ceiling", async () => {
|
|
788
|
+
ipcHandlers.set("get_contact_threshold", () => ({ threshold: "high" }));
|
|
789
|
+
expect(await getContactAutoApproveThreshold("contact-1")).toBe("high");
|
|
790
|
+
|
|
791
|
+
invalidateContactThresholdCache("contact-1");
|
|
792
|
+
ipcHandlers.set("get_contact_threshold", () => ({ threshold: "low" }));
|
|
793
|
+
|
|
794
|
+
expect(await getContactAutoApproveThreshold("contact-1")).toBe("low");
|
|
795
|
+
expect(countCalls("get_contact_threshold")).toBe(2);
|
|
796
|
+
});
|
|
797
|
+
|
|
798
|
+
test("invalidateAllContactThresholdCaches drops every cached ceiling", async () => {
|
|
799
|
+
ipcHandlers.set("get_contact_threshold", () => ({ threshold: "high" }));
|
|
800
|
+
expect(await getContactAutoApproveThreshold("contact-1")).toBe("high");
|
|
801
|
+
|
|
802
|
+
invalidateAllContactThresholdCaches();
|
|
803
|
+
ipcHandlers.set("get_contact_threshold", () => ({ threshold: "none" }));
|
|
804
|
+
|
|
805
|
+
expect(await getContactAutoApproveThreshold("contact-1")).toBe("none");
|
|
806
|
+
expect(countCalls("get_contact_threshold")).toBe(2);
|
|
807
|
+
});
|
|
808
|
+
|
|
809
|
+
test("getContactAutoApproveThreshold returns null for an unset contact", async () => {
|
|
810
|
+
ipcHandlers.set("get_contact_threshold", () => null);
|
|
811
|
+
|
|
812
|
+
expect(await getContactAutoApproveThreshold("contact-1")).toBeNull();
|
|
813
|
+
});
|
|
814
|
+
|
|
815
|
+
test("getContactAutoApproveThreshold returns null when contactId is missing", async () => {
|
|
816
|
+
expect(await getContactAutoApproveThreshold(undefined)).toBeNull();
|
|
817
|
+
expect(countCalls("get_contact_threshold")).toBe(0);
|
|
818
|
+
});
|
|
819
|
+
});
|