@vellumai/assistant 0.7.1 → 0.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +48 -50
- package/Dockerfile +1 -0
- package/README.md +1 -2
- package/__tests__/permissions/gateway-threshold-reader.test.ts +9 -3
- package/bun.lock +26 -26
- package/docs/architecture/memory.md +5 -2
- package/docs/architecture/security.md +20 -0
- package/docs/plugins.md +7 -9
- package/knip.json +1 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +1 -0
- package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +52 -5
- package/node_modules/@vellumai/gateway-client/src/types.ts +11 -0
- package/node_modules/@vellumai/service-contracts/package.json +2 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/contracts.test.ts +4 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +107 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +5 -1
- package/node_modules/@vellumai/service-contracts/src/ingress.ts +24 -0
- package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +84 -0
- package/node_modules/@vellumai/slack-text/src/index.test.ts +18 -35
- package/node_modules/@vellumai/slack-text/src/index.ts +2 -48
- package/node_modules/@vellumai/twilio-client/bun.lock +24 -0
- package/node_modules/@vellumai/twilio-client/package.json +18 -0
- package/node_modules/@vellumai/twilio-client/src/__tests__/twilio-client.test.ts +128 -0
- package/node_modules/@vellumai/twilio-client/src/index.ts +179 -0
- package/node_modules/@vellumai/twilio-client/tsconfig.json +20 -0
- package/openapi.yaml +1020 -40
- package/package.json +6 -3
- package/src/__tests__/app-builder-tool-scripts.test.ts +3 -3
- package/src/__tests__/app-bundler.test.ts +170 -1
- package/src/__tests__/app-control-flow.test.ts +384 -0
- package/src/__tests__/app-control-no-global-cgevent.test.ts +98 -0
- package/src/__tests__/app-control-tool-schemas.test.ts +621 -0
- package/src/__tests__/app-executors.test.ts +30 -43
- package/src/__tests__/approval-routes-http.test.ts +23 -6
- package/src/__tests__/assistant-event-hub-machine-name.test.ts +146 -0
- package/src/__tests__/assistant-event-hub-targeted.test.ts +257 -0
- package/src/__tests__/assistant-event-hub.test.ts +157 -2
- package/src/__tests__/assistant-feature-flags-integration.test.ts +29 -7
- package/src/__tests__/auto-analysis-end-to-end.test.ts +62 -1
- package/src/__tests__/background-shell-host-bash.test.ts +14 -15
- package/src/__tests__/background-workers-disk-pressure.test.ts +268 -0
- package/src/__tests__/bootstrap-turn-cleanup.test.ts +44 -0
- package/src/__tests__/btw-routes.test.ts +13 -4
- package/src/__tests__/call-controller.test.ts +49 -1
- package/src/__tests__/call-conversation-messages.test.ts +8 -2
- package/src/__tests__/call-domain.test.ts +0 -2
- package/src/__tests__/call-routes-http.test.ts +0 -2
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +537 -0
- package/src/__tests__/channel-readiness-service.test.ts +62 -2
- package/src/__tests__/checker.test.ts +3 -4
- package/src/__tests__/config-loader-backfill.test.ts +461 -147
- package/src/__tests__/config-loader-platform-defaults.test.ts +196 -0
- package/src/__tests__/config-schema-cmd.test.ts +0 -1
- package/src/__tests__/config-schema.test.ts +1 -0
- package/src/__tests__/config-set-platform-guard.test.ts +48 -4
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +20 -11
- package/src/__tests__/config-watcher.test.ts +142 -71
- package/src/__tests__/context-search-agent-runner.test.ts +61 -3
- package/src/__tests__/context-search-conversations-source.test.ts +0 -24
- package/src/__tests__/context-search-fanout.test.ts +0 -1
- package/src/__tests__/context-search-memory-source.test.ts +3 -7
- package/src/__tests__/context-search-memory-v2-source.test.ts +0 -2
- package/src/__tests__/context-search-pkb-source.test.ts +0 -1
- package/src/__tests__/context-search-workspace-source.test.ts +0 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +223 -0
- package/src/__tests__/conversation-agent-loop.test.ts +454 -5
- package/src/__tests__/conversation-app-control-instantiation.test.ts +392 -0
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +237 -0
- package/src/__tests__/conversation-error.test.ts +150 -3
- package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
- package/src/__tests__/conversation-lifecycle.test.ts +36 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +283 -0
- package/src/__tests__/conversation-process-callsite.test.ts +43 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +6 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +120 -72
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +65 -0
- package/src/__tests__/conversation-slash-commands.test.ts +0 -4
- package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
- package/src/__tests__/conversation-speed-override.test.ts +0 -3
- package/src/__tests__/conversation-store.test.ts +0 -18
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +202 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +328 -0
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +404 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +2 -5
- package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
- package/src/__tests__/credential-execution-feature-gates.test.ts +5 -12
- package/src/__tests__/credential-execution-managed-contract.test.ts +3 -131
- package/src/__tests__/credentials-cli.test.ts +12 -12
- package/src/__tests__/cu-unified-flow.test.ts +351 -23
- package/src/__tests__/daemon-credential-client.test.ts +101 -19
- package/src/__tests__/date-context.test.ts +164 -2
- package/src/__tests__/db-schedule-syntax-migration.test.ts +2 -0
- package/src/__tests__/disk-pressure-guard.test.ts +262 -0
- package/src/__tests__/disk-pressure-lifecycle.test.ts +168 -0
- package/src/__tests__/disk-pressure-policy.test.ts +241 -0
- package/src/__tests__/disk-pressure-routes.test.ts +379 -0
- package/src/__tests__/disk-pressure-tools.test.ts +277 -0
- package/src/__tests__/disk-usage.test.ts +150 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- package/src/__tests__/events-client-registration.test.ts +52 -0
- package/src/__tests__/events-dev-bypass-actor.test.ts +162 -0
- package/src/__tests__/file-write-tool.test.ts +4 -10
- package/src/__tests__/filing-service.test.ts +3 -4
- package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
- package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -2
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -2
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +183 -0
- package/src/__tests__/heartbeat-service.test.ts +968 -2
- package/src/__tests__/helpers/call-route-handler.ts +7 -1
- package/src/__tests__/host-app-control-proxy.test.ts +772 -0
- package/src/__tests__/host-app-control-routes.test.ts +263 -0
- package/src/__tests__/host-bash-proxy.test.ts +439 -47
- package/src/__tests__/host-bash-routes.test.ts +459 -0
- package/src/__tests__/host-browser-proxy.test.ts +24 -22
- package/src/__tests__/host-browser-routes.test.ts +39 -13
- package/src/__tests__/host-cu-proxy.test.ts +248 -52
- package/src/__tests__/host-cu-routes-targeted.test.ts +429 -0
- package/src/__tests__/host-file-edit-tool.test.ts +47 -1
- package/src/__tests__/host-file-proxy-targeted.test.ts +378 -0
- package/src/__tests__/host-file-proxy.test.ts +301 -45
- package/src/__tests__/host-file-read-tool.test.ts +17 -0
- package/src/__tests__/host-file-routes-targeted.test.ts +420 -0
- package/src/__tests__/host-file-write-tool.test.ts +42 -1
- package/src/__tests__/host-proxy-base.test.ts +312 -0
- package/src/__tests__/host-shell-tool.test.ts +22 -4
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +932 -0
- package/src/__tests__/host-transfer-proxy.test.ts +121 -22
- package/src/__tests__/host-transfer-routes-targeted.test.ts +662 -0
- package/src/__tests__/http-user-message-parity.test.ts +108 -1
- package/src/__tests__/identity-intro-cache.test.ts +29 -0
- package/src/__tests__/identity-routes.test.ts +103 -1
- package/src/__tests__/init-feature-flag-overrides.test.ts +26 -3
- package/src/__tests__/injector-chain.test.ts +18 -6
- package/src/__tests__/injector-disk-pressure.test.ts +224 -0
- package/src/__tests__/inline-command-runner.test.ts +0 -1
- package/src/__tests__/inline-skill-load-permissions.test.ts +5 -11
- package/src/__tests__/integration-status.test.ts +85 -5
- package/src/__tests__/intent-routing.test.ts +0 -1
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +95 -5
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +17 -0
- package/src/__tests__/managed-profile-guard.test.ts +18 -0
- package/src/__tests__/managed-skill-lifecycle.test.ts +0 -1
- package/src/__tests__/mcp-abort-signal.test.ts +130 -0
- package/src/__tests__/mcp-auth-routes.test.ts +197 -0
- package/src/__tests__/mcp-cli.test.ts +338 -2
- package/src/__tests__/memory-admin-recall.test.ts +3 -11
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +188 -0
- package/src/__tests__/memory-retrieval-pipeline.test.ts +22 -1
- package/src/__tests__/migration-import-commit-http.test.ts +108 -2
- package/src/__tests__/mock-gateway-ipc.ts +1 -0
- package/src/__tests__/normalize-onboarding.test.ts +180 -0
- package/src/__tests__/oauth-cli.test.ts +0 -2
- package/src/__tests__/oauth-connect-routes.test.ts +316 -0
- package/src/__tests__/oauth-provider-seed-logos.test.ts +24 -2
- package/src/__tests__/oauth2-gateway-transport.test.ts +0 -1
- package/src/__tests__/onboarding-persona-write.test.ts +308 -0
- package/src/__tests__/openai-provider.test.ts +45 -8
- package/src/__tests__/persist-onboarding-artifacts.test.ts +44 -64
- package/src/__tests__/persistence-secret-redaction.test.ts +299 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +5 -9
- package/src/__tests__/platform-callback-registration.test.ts +21 -4
- package/src/__tests__/platform.test.ts +2 -1
- package/src/__tests__/playbook-execution.test.ts +0 -43
- package/src/__tests__/plugin-tool-contribution.test.ts +47 -0
- package/src/__tests__/prechat-onboarding-contract.test.ts +214 -25
- package/src/__tests__/process-message-background-slack.test.ts +2 -0
- package/src/__tests__/provider-commit-message-generator.test.ts +0 -1
- package/src/__tests__/provider-tool-name.test.ts +23 -0
- package/src/__tests__/public-ingress-urls.test.ts +97 -0
- package/src/__tests__/relay-server.test.ts +15 -4
- package/src/__tests__/require-fresh-approval.test.ts +0 -1
- package/src/__tests__/retry-backoff.test.ts +87 -0
- package/src/__tests__/runtime-events-sse.test.ts +2 -2
- package/src/__tests__/sanitize-config-for-transfer.test.ts +24 -2
- package/src/__tests__/schedule-retry.test.ts +715 -0
- package/src/__tests__/scheduler-disk-pressure.test.ts +148 -0
- package/src/__tests__/script-proxy-mitm-handler.test.ts +1 -1
- package/src/__tests__/secret-ingress-http.test.ts +1 -1
- package/src/__tests__/send-endpoint-busy.test.ts +3 -0
- package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -1
- package/src/__tests__/skill-feature-flags.test.ts +43 -41
- package/src/__tests__/skill-load-feature-flag.test.ts +13 -14
- package/src/__tests__/skill-load-inline-command.test.ts +0 -51
- package/src/__tests__/skill-load-inline-includes.test.ts +0 -43
- package/src/__tests__/skill-projection.benchmark.test.ts +0 -1
- package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -1
- package/src/__tests__/slack-channel-config.test.ts +9 -14
- package/src/__tests__/suggestion-routes.test.ts +46 -0
- package/src/__tests__/system-prompt-ask-mode.test.ts +0 -1
- package/src/__tests__/system-prompt.test.ts +0 -1
- package/src/__tests__/telegram-config.test.ts +0 -1
- package/src/__tests__/test-preload.ts +8 -0
- package/src/__tests__/tool-approval-handler.test.ts +3 -4
- package/src/__tests__/tool-audit-listener.test.ts +48 -0
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -1
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
- package/src/__tests__/tool-executor.test.ts +0 -1
- package/src/__tests__/twilio-config.test.ts +3 -16
- package/src/__tests__/twilio-routes.test.ts +3 -5
- package/src/__tests__/twilio-validation.test.ts +93 -0
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +1 -4
- package/src/__tests__/verification-control-plane-policy.test.ts +2 -4
- package/src/__tests__/voice-ingress-preflight.test.ts +19 -0
- package/src/__tests__/workspace-migration-006-services-config.test.ts +3 -2
- package/src/__tests__/workspace-migration-065-bump-stale-heartbeat-interval.test.ts +122 -0
- package/src/__tests__/workspace-migration-066-seed-heartbeat-callsite-cost-default.test.ts +285 -0
- package/src/__tests__/workspace-migration-068-release-notes-local-timezone.test.ts +90 -0
- package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +1 -5
- package/src/__tests__/workspace-migration-down-functions.test.ts +8 -8
- package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +90 -0
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +10 -6
- package/src/approvals/guardian-decision-primitive.ts +13 -0
- package/src/approvals/guardian-request-resolvers.ts +16 -17
- package/src/backup/__tests__/paths.test.ts +0 -22
- package/src/backup/__tests__/restore.test.ts +51 -151
- package/src/backup/paths.ts +2 -18
- package/src/backup/restore.ts +107 -231
- package/src/backup/snapshot-lock.ts +2 -27
- package/src/bundler/app-bundler.ts +51 -3
- package/src/bundler/compiler-tools.ts +3 -2
- package/src/calls/call-conversation-messages.ts +46 -10
- package/src/calls/relay-server.ts +4 -44
- package/src/calls/twilio-config.ts +2 -17
- package/src/calls/twilio-rest.ts +33 -105
- package/src/calls/twilio-routes.ts +11 -12
- package/src/channels/types.ts +8 -7
- package/src/cli/commands/__tests__/backup.test.ts +6 -277
- package/src/cli/commands/__tests__/gateway.test.ts +288 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +4 -0
- package/src/cli/commands/__tests__/webhooks.test.ts +0 -5
- package/src/cli/commands/backup.ts +6 -331
- package/src/cli/commands/bash.ts +35 -108
- package/src/cli/commands/clients.ts +36 -37
- package/src/cli/commands/contacts.ts +137 -25
- package/src/cli/commands/conversations.ts +2 -5
- package/src/cli/commands/credentials.ts +71 -7
- package/src/cli/commands/domain.ts +66 -15
- package/src/cli/commands/gateway.ts +183 -0
- package/src/cli/commands/keys.ts +9 -6
- package/src/cli/commands/mcp.ts +116 -156
- package/src/cli/commands/memory-v2.ts +303 -7
- package/src/cli/commands/oauth/__tests__/connect.test.ts +437 -1
- package/src/cli/commands/oauth/connect.ts +127 -1
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -4
- package/src/cli/commands/platform/__tests__/connect.test.ts +7 -3
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -3
- package/src/cli/commands/platform/__tests__/status.test.ts +116 -21
- package/src/cli/commands/platform/disconnect.ts +5 -4
- package/src/cli/commands/platform/index.ts +16 -25
- package/src/cli/commands/status.ts +57 -0
- package/src/cli/lib/daemon-credential-client.ts +110 -28
- package/src/cli/program.ts +6 -2
- package/src/config/assistant-feature-flags.ts +79 -12
- package/src/config/bundled-skills/acp/SKILL.md +6 -0
- package/src/config/bundled-skills/acp/TOOLS.json +1 -22
- package/src/config/bundled-skills/app-builder/SKILL.md +14 -109
- package/src/config/bundled-skills/app-builder/TOOLS.json +1 -28
- package/src/config/bundled-skills/app-builder/tools/app-create.ts +1 -10
- package/src/config/bundled-skills/app-control/SKILL.md +75 -0
- package/src/config/bundled-skills/app-control/TOOLS.json +299 -0
- package/src/config/bundled-skills/app-control/tools/app-control-click.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-combo.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-drag.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-observe.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-press.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-sequence.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-start.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-stop.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-type.ts +12 -0
- package/src/config/bundled-skills/computer-use/SKILL.md +6 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +67 -43
- package/src/config/bundled-skills/contacts/TOOLS.json +0 -16
- package/src/config/bundled-skills/document/TOOLS.json +0 -8
- package/src/config/bundled-skills/followups/TOOLS.json +0 -12
- package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
- package/src/config/bundled-skills/image-studio/TOOLS.json +0 -4
- package/src/config/bundled-skills/media-processing/TOOLS.json +0 -24
- package/src/config/bundled-skills/messaging/TOOLS.json +0 -40
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -3
- package/src/config/bundled-skills/phone-calls/TOOLS.json +0 -12
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +25 -4
- package/src/config/bundled-skills/playbooks/TOOLS.json +0 -16
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -2
- package/src/config/bundled-skills/schedule/TOOLS.json +14 -14
- package/src/config/bundled-skills/sequences/TOOLS.json +0 -36
- package/src/config/bundled-skills/settings/SKILL.md +4 -0
- package/src/config/bundled-skills/settings/TOOLS.json +0 -12
- package/src/config/bundled-skills/skill-management/SKILL.md +6 -0
- package/src/config/bundled-skills/skill-management/TOOLS.json +0 -8
- package/src/config/bundled-skills/subagent/SKILL.md +6 -2
- package/src/config/bundled-skills/subagent/TOOLS.json +0 -20
- package/src/config/bundled-skills/transcribe/SKILL.md +4 -0
- package/src/config/bundled-skills/transcribe/TOOLS.json +0 -4
- package/src/config/bundled-tool-registry.ts +21 -0
- package/src/config/env-registry.ts +0 -2
- package/src/config/env.ts +19 -20
- package/src/config/feature-flag-registry.json +47 -135
- package/src/config/loader.ts +197 -104
- package/src/config/sanitize-for-transfer.ts +2 -0
- package/src/config/schemas/__tests__/memory-lifecycle.test.ts +80 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +17 -9
- package/src/config/schemas/call-site-catalog.ts +14 -0
- package/src/config/schemas/calls.ts +0 -9
- package/src/config/schemas/channels.ts +0 -5
- package/src/config/schemas/heartbeat.ts +64 -1
- package/src/config/schemas/ingress.ts +10 -6
- package/src/config/schemas/llm.ts +7 -10
- package/src/config/schemas/memory-lifecycle.ts +90 -24
- package/src/config/schemas/memory-v2.ts +121 -13
- package/src/config/schemas/platform.ts +49 -3
- package/src/config/schemas/services.ts +29 -15
- package/src/config/schemas/skills.ts +0 -6
- package/src/config/seed-inference-profiles.ts +230 -33
- package/src/contacts/contact-store.ts +0 -55
- package/src/contacts/contacts-write.ts +0 -27
- package/src/context/window-manager.ts +1 -2
- package/src/credential-execution/feature-gates.ts +10 -10
- package/src/credential-execution/process-manager.ts +12 -41
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +187 -5
- package/src/daemon/assistant-attachments.ts +4 -4
- package/src/daemon/bootstrap-turn-cleanup.ts +45 -0
- package/src/daemon/config-watcher.ts +89 -60
- package/src/daemon/conversation-agent-loop-handlers.ts +27 -3
- package/src/daemon/conversation-agent-loop.ts +202 -61
- package/src/daemon/conversation-error.ts +87 -15
- package/src/daemon/conversation-lifecycle.ts +9 -4
- package/src/daemon/conversation-process.ts +24 -11
- package/src/daemon/conversation-runtime-assembly.ts +28 -2
- package/src/daemon/conversation-store.ts +2 -2
- package/src/daemon/conversation-surfaces.ts +305 -4
- package/src/daemon/conversation-tool-setup.ts +66 -62
- package/src/daemon/conversation.ts +38 -24
- package/src/daemon/date-context.ts +71 -22
- package/src/daemon/disk-pressure-background-gate.ts +73 -0
- package/src/daemon/disk-pressure-guard.ts +343 -0
- package/src/daemon/disk-pressure-policy.ts +163 -0
- package/src/daemon/doordash-steps.ts +1 -1
- package/src/daemon/handlers/shared.ts +4 -2
- package/src/daemon/handlers/skills.ts +3 -4
- package/src/daemon/host-app-control-proxy.ts +389 -0
- package/src/daemon/host-bash-proxy.ts +117 -82
- package/src/daemon/host-browser-proxy.ts +67 -82
- package/src/daemon/host-cu-proxy.ts +127 -86
- package/src/daemon/host-file-proxy.ts +129 -69
- package/src/daemon/host-proxy-base.ts +294 -0
- package/src/daemon/host-proxy-preactivation.ts +82 -0
- package/src/daemon/host-transfer-proxy.ts +338 -129
- package/src/daemon/lifecycle.ts +194 -145
- package/src/daemon/meet-host-supervisor.ts +4 -4
- package/src/daemon/meet-manifest-loader.ts +0 -1
- package/src/daemon/memory-v2-startup.ts +14 -4
- package/src/daemon/message-protocol.ts +6 -8
- package/src/daemon/message-types/contacts.ts +23 -1
- package/src/daemon/message-types/conversations.ts +15 -8
- package/src/daemon/message-types/disk-pressure.ts +9 -0
- package/src/daemon/message-types/host-app-control.ts +150 -0
- package/src/daemon/message-types/host-bash.ts +4 -0
- package/src/daemon/message-types/host-cu.ts +2 -0
- package/src/daemon/message-types/host-file.ts +4 -0
- package/src/daemon/message-types/host-transfer.ts +3 -0
- package/src/daemon/message-types/messages.ts +3 -0
- package/src/daemon/message-types/schedules.ts +8 -3
- package/src/daemon/message-types/skills.ts +2 -2
- package/src/daemon/process-message.ts +18 -1
- package/src/daemon/profiler-run-store.ts +5 -5
- package/src/daemon/shutdown-handlers.ts +0 -3
- package/src/daemon/tool-setup-types.ts +51 -0
- package/src/daemon/tool-side-effects.ts +1 -1
- package/src/documents/document-store.ts +85 -0
- package/src/events/tool-audit-listener.ts +2 -1
- package/src/filing/filing-service.ts +30 -5
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +24 -23
- package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +252 -0
- package/src/heartbeat/heartbeat-run-store.ts +249 -0
- package/src/heartbeat/heartbeat-service.ts +459 -54
- package/src/home/__tests__/post-connect-feed.test.ts +99 -0
- package/src/home/__tests__/relationship-state-writer.test.ts +11 -9
- package/src/home/__tests__/suggested-prompts.test.ts +89 -0
- package/src/home/feed-scheduler.ts +18 -0
- package/src/home/post-connect-feed.ts +68 -0
- package/src/home/relationship-state-writer.ts +17 -92
- package/src/home/suggested-prompts.ts +46 -10
- package/src/inbound/platform-callback-registration.ts +8 -15
- package/src/inbound/public-ingress-urls.ts +32 -34
- package/src/ipc/__tests__/clients-list-ipc.test.ts +169 -0
- package/src/ipc/__tests__/route-error-envelope.test.ts +80 -0
- package/src/ipc/assistant-server.ts +70 -3
- package/src/ipc/cli-client.ts +32 -1
- package/src/ipc/gateway-client.ts +37 -3
- package/src/live-voice/live-voice-archive.ts +4 -4
- package/src/live-voice/live-voice-metrics.ts +10 -10
- package/src/live-voice/protocol.ts +5 -7
- package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +304 -0
- package/src/mcp/mcp-auth-orchestrator.ts +213 -0
- package/src/mcp/mcp-auth-state.ts +133 -0
- package/src/mcp/mcp-oauth-provider.ts +19 -0
- package/src/media/image-service.ts +1 -7
- package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +21 -13
- package/src/memory/__tests__/jobs-store-job-classes.test.ts +24 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +52 -22
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +0 -6
- package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +272 -0
- package/src/memory/__tests__/qdrant-client-sentinel.test.ts +49 -0
- package/src/memory/__tests__/sparse-tokenize.test.ts +66 -0
- package/src/memory/admin.ts +5 -9
- package/src/memory/anisotropy.test.ts +247 -0
- package/src/memory/anisotropy.ts +443 -0
- package/src/memory/auto-analysis-constants.ts +17 -0
- package/src/memory/auto-analysis-guard.ts +5 -15
- package/src/memory/canonical-guardian-store.ts +7 -7
- package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +122 -0
- package/src/memory/context-search/agent-protocol.ts +6 -6
- package/src/memory/context-search/agent-runner.ts +51 -9
- package/src/memory/context-search/sources/conversations.ts +2 -11
- package/src/memory/context-search/sources/memory-v2.ts +22 -9
- package/src/memory/context-search/sources/memory.ts +0 -1
- package/src/memory/context-search/types.ts +0 -1
- package/src/memory/conversation-crud.ts +5 -13
- package/src/memory/conversation-key-store.ts +2 -15
- package/src/memory/db-init.ts +6 -0
- package/src/memory/embedding-backend.ts +9 -21
- package/src/memory/embedding-runtime-manager.ts +119 -5
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +81 -25
- package/src/memory/graph/conversation-graph-memory.ts +43 -78
- package/src/memory/graph/extraction.ts +1 -3
- package/src/memory/graph/graph-search.test.ts +10 -67
- package/src/memory/graph/graph-search.ts +9 -20
- package/src/memory/graph/retriever.test.ts +6 -0
- package/src/memory/graph/retriever.ts +34 -10
- package/src/memory/graph/tools.ts +1 -1
- package/src/memory/indexer.ts +54 -45
- package/src/memory/job-handlers/backfill.ts +2 -11
- package/src/memory/job-handlers/cleanup.ts +43 -0
- package/src/memory/job-handlers/embedding.ts +6 -8
- package/src/memory/job-handlers/summarization.ts +2 -7
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +8 -2
- package/src/memory/jobs/embed-concept-page.ts +28 -2
- package/src/memory/jobs/embed-pkb-file.test.ts +2 -2
- package/src/memory/jobs-store.ts +114 -22
- package/src/memory/jobs-worker.ts +193 -106
- package/src/memory/memory-v2-activation-log-store.ts +33 -15
- package/src/memory/memory-v2-concept-frequency.ts +169 -0
- package/src/memory/migrations/237-heartbeat-runs.ts +45 -0
- package/src/memory/migrations/238-schedule-retry-policy.ts +20 -0
- package/src/memory/migrations/239-trace-events-created-at-index.ts +18 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/pkb/pkb-search.test.ts +6 -0
- package/src/memory/pkb/pkb-search.ts +7 -0
- package/src/memory/qdrant-client.ts +49 -32
- package/src/memory/rerank-local.ts +374 -0
- package/src/memory/schema/infrastructure.ts +15 -0
- package/src/memory/search/semantic.ts +13 -67
- package/src/memory/sparse-tokenize.ts +49 -0
- package/src/memory/trace-event-store.ts +1 -17
- package/src/memory/v2/__tests__/activation.test.ts +387 -344
- package/src/memory/v2/__tests__/consolidation-job.test.ts +40 -8
- package/src/memory/v2/__tests__/injection.test.ts +181 -169
- package/src/memory/v2/__tests__/prompts-consolidation.test.ts +61 -2
- package/src/memory/v2/__tests__/qdrant.test.ts +16 -0
- package/src/memory/v2/__tests__/reranker.test.ts +338 -0
- package/src/memory/v2/__tests__/sim.test.ts +154 -188
- package/src/memory/v2/__tests__/skill-store.test.ts +71 -65
- package/src/memory/v2/__tests__/sparse-bm25.test.ts +292 -0
- package/src/memory/v2/__tests__/static-context.test.ts +76 -2
- package/src/memory/v2/activation.ts +213 -239
- package/src/memory/v2/consolidation-job.ts +65 -17
- package/src/memory/v2/constants.ts +7 -0
- package/src/memory/v2/injection.ts +123 -103
- package/src/memory/v2/prompts/consolidation.ts +348 -92
- package/src/memory/v2/qdrant.ts +198 -1
- package/src/memory/v2/reranker.ts +177 -0
- package/src/memory/v2/sim.ts +113 -77
- package/src/memory/v2/skill-content.ts +4 -3
- package/src/memory/v2/skill-store.ts +91 -53
- package/src/memory/v2/sparse-bm25.ts +245 -0
- package/src/memory/v2/static-context.ts +28 -5
- package/src/memory/v2/types.ts +10 -10
- package/src/messaging/providers/gmail/types.ts +0 -49
- package/src/messaging/providers/slack/adapter.ts +1 -31
- package/src/messaging/providers/slack/types.ts +0 -32
- package/src/notifications/README.md +10 -10
- package/src/notifications/broadcaster.ts +1 -1
- package/src/notifications/copy-composer.ts +13 -0
- package/src/notifications/guardian-question-mode.ts +5 -5
- package/src/notifications/signal.ts +4 -0
- package/src/oauth/AGENTS.md +3 -1
- package/src/oauth/__tests__/oauth-connect-state.test.ts +137 -0
- package/src/oauth/connect-orchestrator.ts +6 -0
- package/src/oauth/connection-resolver.test.ts +66 -1
- package/src/oauth/connection-resolver.ts +55 -1
- package/src/oauth/credential-token-resolver.ts +1 -3
- package/src/oauth/manual-token-connection.ts +0 -4
- package/src/oauth/oauth-connect-state.ts +77 -0
- package/src/oauth/seed-providers.ts +58 -1
- package/src/outbound-proxy/index.ts +1 -37
- package/src/outbound-proxy/logging.ts +1 -1
- package/src/outbound-proxy/policy.ts +6 -5
- package/src/outbound-proxy/router.ts +2 -1
- package/src/permissions/approval-policy.test.ts +6 -275
- package/src/permissions/approval-policy.ts +0 -51
- package/src/permissions/checker.test.ts +0 -1
- package/src/permissions/checker.ts +3 -17
- package/src/permissions/gateway-threshold-reader.ts +2 -0
- package/src/permissions/prompter.ts +34 -1
- package/src/permissions/secret-prompter.ts +6 -2
- package/src/plugins/defaults/injectors.ts +35 -2
- package/src/plugins/defaults/memory-retrieval.ts +5 -6
- package/src/plugins/types.ts +7 -0
- package/src/proactive-artifact/aux-message-injector.ts +74 -0
- package/src/proactive-artifact/decision.test.ts +226 -0
- package/src/proactive-artifact/decision.ts +165 -0
- package/src/proactive-artifact/index.ts +7 -0
- package/src/proactive-artifact/job.test.ts +867 -0
- package/src/proactive-artifact/job.ts +352 -0
- package/src/proactive-artifact/message-copy.ts +41 -0
- package/src/proactive-artifact/trigger-state.test.ts +277 -0
- package/src/proactive-artifact/trigger-state.ts +119 -0
- package/src/prompts/bootstrap-cleanup.ts +27 -0
- package/src/prompts/normalize-onboarding.ts +80 -0
- package/src/prompts/persona-resolver.ts +101 -9
- package/src/prompts/system-prompt.ts +23 -24
- package/src/prompts/templates/BOOTSTRAP.md +13 -5
- package/src/prompts/templates/SOUL.md +13 -1
- package/src/providers/__tests__/retry-callsite.test.ts +222 -1
- package/src/providers/model-intents.ts +7 -0
- package/src/providers/openrouter/client.ts +8 -0
- package/src/providers/retry.ts +50 -0
- package/src/providers/speech-to-text/provider-catalog.ts +7 -8
- package/src/providers/types.ts +1 -0
- package/src/runtime/__tests__/agent-wake.test.ts +456 -3
- package/src/runtime/agent-wake.ts +238 -100
- package/src/runtime/assistant-event-hub.ts +151 -99
- package/src/runtime/auth/__tests__/middleware.test.ts +11 -56
- package/src/runtime/auth/__tests__/route-policy.test.ts +64 -0
- package/src/runtime/auth/middleware.ts +0 -96
- package/src/runtime/auth/route-policy.ts +32 -0
- package/src/runtime/auth/same-actor.ts +216 -0
- package/src/runtime/btw-sidechain.ts +2 -3
- package/src/runtime/channel-invite-transport.ts +2 -48
- package/src/runtime/channel-invite-transports/email.ts +1 -1
- package/src/runtime/channel-invite-transports/slack.ts +1 -1
- package/src/runtime/channel-invite-transports/telegram.ts +1 -1
- package/src/runtime/channel-invite-transports/voice.ts +1 -1
- package/src/runtime/channel-invite-transports/whatsapp.ts +1 -1
- package/src/runtime/channel-invite-types.ts +54 -0
- package/src/runtime/channel-readiness-service.ts +32 -13
- package/src/runtime/channel-retry-sweep.ts +65 -1
- package/src/runtime/guardian-reply-router.ts +10 -0
- package/src/runtime/http-server.ts +3 -329
- package/src/runtime/http-types.ts +0 -5
- package/src/runtime/local-actor-identity.ts +52 -11
- package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +413 -0
- package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +260 -0
- package/src/runtime/migrations/__tests__/vbundle-import-version-compat.test.ts +189 -0
- package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +153 -1
- package/src/runtime/migrations/__tests__/vbundle-symlink-importer.test.ts +451 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming.test.ts +515 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-tar.test.ts +437 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-walker.test.ts +319 -0
- package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +51 -1
- package/src/runtime/migrations/migration-transport.ts +7 -7
- package/src/runtime/migrations/vbundle-builder.ts +327 -60
- package/src/runtime/migrations/vbundle-import-analyzer.ts +4 -4
- package/src/runtime/migrations/vbundle-import-policy.ts +172 -0
- package/src/runtime/migrations/vbundle-importer.ts +245 -68
- package/src/runtime/migrations/vbundle-streaming-importer.ts +326 -35
- package/src/runtime/migrations/vbundle-streaming-validator.ts +157 -4
- package/src/runtime/migrations/vbundle-tar-stream.ts +15 -6
- package/src/runtime/migrations/vbundle-validator.ts +114 -0
- package/src/runtime/pending-interactions.ts +43 -9
- package/src/runtime/routes/__tests__/backup-routes.test.ts +22 -150
- package/src/runtime/routes/__tests__/client-routes.test.ts +155 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -5
- package/src/runtime/routes/__tests__/gateway-log-routes.test.ts +242 -0
- package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +112 -0
- package/src/runtime/routes/approval-interception-types.ts +13 -0
- package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +1 -1
- package/src/runtime/routes/backup-routes.ts +15 -38
- package/src/runtime/routes/btw-routes.ts +14 -37
- package/src/runtime/routes/client-routes.ts +21 -2
- package/src/runtime/routes/contact-prompt-routes.ts +183 -0
- package/src/runtime/routes/contact-routes.ts +0 -25
- package/src/runtime/routes/conversation-query-routes.ts +36 -1
- package/src/runtime/routes/conversation-routes.ts +65 -39
- package/src/runtime/routes/debug-bash-routes.ts +163 -0
- package/src/runtime/routes/disk-pressure-routes.ts +121 -0
- package/src/runtime/routes/document-pdf-renderer.ts +169 -0
- package/src/runtime/routes/documents-routes.ts +32 -75
- package/src/runtime/routes/errors.ts +19 -4
- package/src/runtime/routes/events-routes.ts +38 -0
- package/src/runtime/routes/gateway-log-routes.ts +79 -0
- package/src/runtime/routes/guardian-approval-interception.ts +2 -8
- package/src/runtime/routes/heartbeat-routes.ts +103 -38
- package/src/runtime/routes/host-app-control-routes.ts +134 -0
- package/src/runtime/routes/host-bash-routes.ts +56 -6
- package/src/runtime/routes/host-browser-routes.ts +108 -13
- package/src/runtime/routes/host-cu-routes.ts +66 -9
- package/src/runtime/routes/host-file-routes.ts +54 -5
- package/src/runtime/routes/host-transfer-routes.ts +122 -19
- package/src/runtime/routes/http-adapter.ts +1 -0
- package/src/runtime/routes/identity-intro-cache.ts +30 -0
- package/src/runtime/routes/identity-routes.ts +21 -180
- package/src/runtime/routes/inbound-message-handler.ts +78 -21
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -7
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +0 -8
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +3 -0
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +0 -20
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +5 -13
- package/src/runtime/routes/index.ts +14 -0
- package/src/runtime/routes/mcp-auth-routes.ts +132 -0
- package/src/runtime/routes/memory-item-routes.test.ts +41 -15
- package/src/runtime/routes/memory-item-routes.ts +10 -12
- package/src/runtime/routes/memory-v2-routes.ts +474 -1
- package/src/runtime/routes/migration-routes.ts +96 -0
- package/src/runtime/routes/oauth-connect-routes.ts +153 -0
- package/src/runtime/routes/schedule-routes.ts +7 -0
- package/src/runtime/verification-outbound-actions.ts +4 -4
- package/src/runtime/verification-templates.ts +4 -7
- package/src/schedule/integration-status.ts +66 -2
- package/src/schedule/recurrence-engine.ts +4 -1
- package/src/schedule/retry-backoff.ts +18 -0
- package/src/schedule/retry-policy.ts +82 -0
- package/src/schedule/run-script.ts +37 -5
- package/src/schedule/schedule-recovery.ts +64 -0
- package/src/schedule/schedule-store.ts +106 -2
- package/src/schedule/scheduler-types.ts +25 -0
- package/src/schedule/scheduler.ts +83 -39
- package/src/security/encrypted-store.ts +2 -0
- package/src/security/oauth-callback-registry.ts +8 -0
- package/src/security/secure-keys.ts +55 -0
- package/src/sequence/analytics.ts +5 -5
- package/src/sequence/engine.ts +1 -1
- package/src/skills/catalog-files.ts +2 -8
- package/src/skills/include-graph.ts +5 -5
- package/src/skills/remote-skill-policy.ts +10 -16
- package/src/skills/skill-file-provider.ts +1 -1
- package/src/skills/skill-file-types.ts +13 -0
- package/src/skills/skillssh-audit-types.ts +28 -0
- package/src/skills/skillssh-registry.ts +8 -21
- package/src/subagent/index.ts +1 -7
- package/src/subagent/manager.ts +1 -15
- package/src/tasks/task-runner.ts +0 -1
- package/src/tasks/task-store.ts +0 -3
- package/src/telemetry/types.ts +2 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +21 -0
- package/src/telemetry/usage-telemetry-reporter.ts +1 -0
- package/src/tools/app-control/skill-proxy-bridge.ts +28 -0
- package/src/tools/apps/executors.ts +56 -69
- package/src/tools/background-tool-registry.ts +17 -3
- package/src/tools/browser/__tests__/browser-status.test.ts +21 -18
- package/src/tools/browser/browser-execution.ts +2 -2
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +55 -4
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +12 -6
- package/src/tools/browser/cdp-client/factory.ts +23 -24
- package/src/tools/browser/cdp-client/index.ts +1 -14
- package/src/tools/computer-use/definitions.ts +42 -20
- package/src/tools/executor.ts +2 -0
- package/src/tools/host-filesystem/edit.test.ts +151 -0
- package/src/tools/host-filesystem/edit.ts +68 -0
- package/src/tools/host-filesystem/read.test.ts +129 -0
- package/src/tools/host-filesystem/read.ts +68 -0
- package/src/tools/host-filesystem/transfer.test.ts +127 -2
- package/src/tools/host-filesystem/transfer.ts +78 -3
- package/src/tools/host-filesystem/write.test.ts +134 -0
- package/src/tools/host-filesystem/write.ts +68 -0
- package/src/tools/host-terminal/host-shell.ts +66 -1
- package/src/tools/mcp/mcp-tool-factory.ts +2 -1
- package/src/tools/memory/register.test.ts +12 -9
- package/src/tools/memory/register.ts +1 -2
- package/src/tools/provider-tool-name.ts +28 -0
- package/src/tools/registry.ts +30 -9
- package/src/tools/schedule/create.ts +6 -0
- package/src/tools/schedule/list.ts +2 -0
- package/src/tools/schedule/update.ts +10 -0
- package/src/tools/shared/filesystem/file-ops-service.ts +2 -0
- package/src/tools/shared/filesystem/path-policy.ts +25 -1
- package/src/tools/skills/load.ts +0 -32
- package/src/tools/terminal/shell.ts +9 -1
- package/src/tools/tool-approval-handler.ts +32 -11
- package/src/tools/types.ts +28 -2
- package/src/tts/provider-catalog.ts +3 -5
- package/src/usage/pricing.ts +1 -1
- package/src/util/disk-usage.ts +138 -0
- package/src/util/platform.ts +21 -11
- package/src/util/process-liveness.ts +26 -0
- package/src/workspace/hatched-date.ts +86 -0
- package/src/workspace/heartbeat-service.ts +19 -0
- package/src/workspace/migrations/003-seed-device-id.ts +1 -1
- package/src/workspace/migrations/006-services-config.ts +8 -5
- package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +3 -9
- package/src/workspace/migrations/021-move-signals-to-workspace.ts +4 -10
- package/src/workspace/migrations/022-move-hooks-to-workspace.ts +4 -10
- package/src/workspace/migrations/023-move-config-files-to-workspace.ts +4 -11
- package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +3 -10
- package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +3 -2
- package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +2 -1
- package/src/workspace/migrations/059-move-pid-to-workspace.ts +3 -8
- package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +3 -8
- package/src/workspace/migrations/065-bump-stale-heartbeat-interval.ts +60 -0
- package/src/workspace/migrations/066-seed-heartbeat-callsite-cost-default.ts +146 -0
- package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +72 -0
- package/src/workspace/migrations/068-release-notes-local-timezone.ts +65 -0
- package/src/workspace/migrations/AGENTS.md +1 -1
- package/src/workspace/migrations/migrate-to-workspace-volume.ts +4 -10
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/workspace/migrations/utils.ts +21 -0
- package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +0 -167
- package/src/__tests__/host-browser-e2e-cloud.test.ts +0 -443
- package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +0 -226
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +0 -427
- package/src/__tests__/twilio-rest.test.ts +0 -34
- package/src/backup/__tests__/backup-key.test.ts +0 -152
- package/src/backup/__tests__/backup-worker.test.ts +0 -782
- package/src/backup/__tests__/offsite-writer.test.ts +0 -641
- package/src/backup/__tests__/stream-crypt.test.ts +0 -228
- package/src/backup/backup-key.ts +0 -137
- package/src/backup/backup-worker.ts +0 -472
- package/src/backup/offsite-writer.ts +0 -222
- package/src/backup/stream-crypt.ts +0 -263
- package/src/daemon/message-types/pairing.ts +0 -58
- package/src/memory/v2/__tests__/skill-qdrant.test.ts +0 -657
- package/src/memory/v2/skill-qdrant.ts +0 -395
- package/src/outbound-proxy/config.ts +0 -20
- package/src/outbound-proxy/health.ts +0 -18
- package/src/outbound-proxy/types.ts +0 -150
- package/src/runtime/capability-tokens.ts +0 -190
- package/src/signals/bash.ts +0 -198
- package/src/signals/mcp-reload.ts +0 -18
|
@@ -14,9 +14,9 @@ export type LiveVoiceMetricsEvent =
|
|
|
14
14
|
| "turn_cancelled"
|
|
15
15
|
| "session_ended";
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
type LiveVoiceTurnStatus = "active" | "completed" | "cancelled";
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
interface LiveVoiceMetricsCollectorOptions {
|
|
20
20
|
sessionId: string;
|
|
21
21
|
conversationId?: string;
|
|
22
22
|
clock?: LiveVoiceMetricsClock;
|
|
@@ -24,7 +24,7 @@ export interface LiveVoiceMetricsCollectorOptions {
|
|
|
24
24
|
recentTurnLimit?: number;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
interface LiveVoiceSessionMetrics {
|
|
28
28
|
sessionId: string;
|
|
29
29
|
conversationId?: string;
|
|
30
30
|
startedAtMs: number;
|
|
@@ -32,7 +32,7 @@ export interface LiveVoiceSessionMetrics {
|
|
|
32
32
|
startToReadyMs: number | null;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
interface LiveVoiceTurnTimestamps {
|
|
36
36
|
startedAtMs: number;
|
|
37
37
|
firstAudioAtMs: number | null;
|
|
38
38
|
firstPartialAtMs: number | null;
|
|
@@ -44,7 +44,7 @@ export interface LiveVoiceTurnTimestamps {
|
|
|
44
44
|
cancelledAtMs: number | null;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
interface LiveVoiceTurnDurations {
|
|
48
48
|
firstAudioToFirstPartialMs: number | null;
|
|
49
49
|
pttReleaseToFinalTranscriptMs: number | null;
|
|
50
50
|
finalTranscriptToFirstAssistantDeltaMs: number | null;
|
|
@@ -52,7 +52,7 @@ export interface LiveVoiceTurnDurations {
|
|
|
52
52
|
totalTurnDurationMs: number | null;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
interface LiveVoiceTurnMetrics {
|
|
56
56
|
turnId: string;
|
|
57
57
|
status: LiveVoiceTurnStatus;
|
|
58
58
|
cancellationReason: string | null;
|
|
@@ -60,13 +60,13 @@ export interface LiveVoiceTurnMetrics {
|
|
|
60
60
|
durations: LiveVoiceTurnDurations;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
interface LiveVoiceDurationSummary {
|
|
64
64
|
count: number;
|
|
65
65
|
p50Ms: number | null;
|
|
66
66
|
p95Ms: number | null;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
interface LiveVoiceMetricsSummary {
|
|
70
70
|
retainedTurnCount: number;
|
|
71
71
|
completedTurnCount: number;
|
|
72
72
|
cancelledTurnCount: number;
|
|
@@ -79,14 +79,14 @@ export interface LiveVoiceMetricsSummary {
|
|
|
79
79
|
};
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
interface LiveVoiceMetricsSnapshot {
|
|
83
83
|
session: LiveVoiceSessionMetrics;
|
|
84
84
|
activeTurn: LiveVoiceTurnMetrics | null;
|
|
85
85
|
recentTurns: LiveVoiceTurnMetrics[];
|
|
86
86
|
summary: LiveVoiceMetricsSummary;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
interface LiveVoiceMetricsAggregateFields {
|
|
90
90
|
sttMs: number | null;
|
|
91
91
|
llmFirstDeltaMs: number | null;
|
|
92
92
|
ttsFirstAudioMs: number | null;
|
|
@@ -6,8 +6,7 @@ const LIVE_VOICE_CLIENT_FRAME_TYPES = [
|
|
|
6
6
|
"end",
|
|
7
7
|
] as const;
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
(typeof LIVE_VOICE_CLIENT_FRAME_TYPES)[number];
|
|
9
|
+
type LiveVoiceClientFrameType = (typeof LIVE_VOICE_CLIENT_FRAME_TYPES)[number];
|
|
11
10
|
|
|
12
11
|
const _LIVE_VOICE_SERVER_FRAME_TYPES = [
|
|
13
12
|
"ready",
|
|
@@ -23,8 +22,7 @@ const _LIVE_VOICE_SERVER_FRAME_TYPES = [
|
|
|
23
22
|
"error",
|
|
24
23
|
] as const;
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
(typeof _LIVE_VOICE_SERVER_FRAME_TYPES)[number];
|
|
25
|
+
type LiveVoiceServerFrameType = (typeof _LIVE_VOICE_SERVER_FRAME_TYPES)[number];
|
|
28
26
|
|
|
29
27
|
export const LiveVoiceProtocolErrorCode = {
|
|
30
28
|
InvalidJson: "invalid_json",
|
|
@@ -45,7 +43,7 @@ export interface LiveVoiceProtocolError {
|
|
|
45
43
|
readonly frameType?: string;
|
|
46
44
|
}
|
|
47
45
|
|
|
48
|
-
|
|
46
|
+
type LiveVoiceParseResult<T> =
|
|
49
47
|
| { ok: true; frame: T }
|
|
50
48
|
| { ok: false; error: LiveVoiceProtocolError };
|
|
51
49
|
|
|
@@ -85,12 +83,12 @@ export type LiveVoiceClientFrame =
|
|
|
85
83
|
| LiveVoiceClientInterruptFrame
|
|
86
84
|
| LiveVoiceClientEndFrame;
|
|
87
85
|
|
|
88
|
-
|
|
86
|
+
interface LiveVoiceBinaryAudioFrame {
|
|
89
87
|
readonly type: "binary_audio";
|
|
90
88
|
readonly data: Uint8Array;
|
|
91
89
|
}
|
|
92
90
|
|
|
93
|
-
|
|
91
|
+
interface LiveVoiceServerFrameBase {
|
|
94
92
|
readonly type: LiveVoiceServerFrameType;
|
|
95
93
|
readonly seq: number;
|
|
96
94
|
}
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
// ── Module mocks (must precede imports) ───────────────────────────────────────
|
|
4
|
+
|
|
5
|
+
// Track captured callbacks and deferred code promises for each McpOAuthProvider
|
|
6
|
+
// instance so tests can drive the flow.
|
|
7
|
+
let capturedOnAuthorizationUrl: ((url: string) => void) | undefined;
|
|
8
|
+
let deferredCodeResolve: ((code: string) => void) | undefined;
|
|
9
|
+
let deferredCodeReject: ((err: Error) => void) | undefined;
|
|
10
|
+
|
|
11
|
+
const mockInvalidateCredentials = mock(async () => {});
|
|
12
|
+
const mockStartCallbackServer = mock(async () => {
|
|
13
|
+
const codePromise = new Promise<string>((resolve, reject) => {
|
|
14
|
+
deferredCodeResolve = resolve;
|
|
15
|
+
deferredCodeReject = reject;
|
|
16
|
+
});
|
|
17
|
+
return { codePromise };
|
|
18
|
+
});
|
|
19
|
+
const mockStopCallbackServer = mock(() => {});
|
|
20
|
+
|
|
21
|
+
mock.module("../mcp-oauth-provider.js", () => ({
|
|
22
|
+
McpOAuthProvider: class {
|
|
23
|
+
constructor(
|
|
24
|
+
_serverId: string,
|
|
25
|
+
_serverUrl: string,
|
|
26
|
+
_interactive: boolean,
|
|
27
|
+
_callbackTransport: string,
|
|
28
|
+
options: { onAuthorizationUrl?: (url: string) => void } = {},
|
|
29
|
+
) {
|
|
30
|
+
capturedOnAuthorizationUrl = options.onAuthorizationUrl;
|
|
31
|
+
}
|
|
32
|
+
invalidateCredentials = mockInvalidateCredentials;
|
|
33
|
+
startCallbackServer = mockStartCallbackServer;
|
|
34
|
+
stopCallbackServer = mockStopCallbackServer;
|
|
35
|
+
},
|
|
36
|
+
}));
|
|
37
|
+
|
|
38
|
+
const mockSetMcpAuthPending = mock(
|
|
39
|
+
(_serverId: string, _authUrl: string, _attemptId: string) => {},
|
|
40
|
+
);
|
|
41
|
+
// Default behavior: pretend the attempt still owns the slot (return true),
|
|
42
|
+
// so completion writes are applied unless a test overrides this.
|
|
43
|
+
const mockSetMcpAuthComplete = mock(
|
|
44
|
+
(_serverId: string, _attemptId: string): boolean => true,
|
|
45
|
+
);
|
|
46
|
+
const mockSetMcpAuthError = mock(
|
|
47
|
+
(_serverId: string, _error: string, _attemptId: string): boolean => true,
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
mock.module("../mcp-auth-state.js", () => ({
|
|
51
|
+
setMcpAuthPending: (...args: unknown[]) =>
|
|
52
|
+
mockSetMcpAuthPending(...(args as [string, string, string])),
|
|
53
|
+
setMcpAuthComplete: (...args: unknown[]) =>
|
|
54
|
+
mockSetMcpAuthComplete(...(args as [string, string])),
|
|
55
|
+
setMcpAuthError: (...args: unknown[]) =>
|
|
56
|
+
mockSetMcpAuthError(...(args as [string, string, string])),
|
|
57
|
+
}));
|
|
58
|
+
|
|
59
|
+
const mockReloadMcpServers = mock(async () => ({
|
|
60
|
+
ok: true,
|
|
61
|
+
reloaded: 0,
|
|
62
|
+
servers: [],
|
|
63
|
+
}));
|
|
64
|
+
|
|
65
|
+
mock.module("../../daemon/mcp-reload-service.js", () => ({
|
|
66
|
+
reloadMcpServers: () => mockReloadMcpServers(),
|
|
67
|
+
}));
|
|
68
|
+
|
|
69
|
+
mock.module("../../config/env-registry.js", () => ({
|
|
70
|
+
getIsContainerized: () => false,
|
|
71
|
+
}));
|
|
72
|
+
|
|
73
|
+
mock.module("../../util/logger.js", () => ({
|
|
74
|
+
getLogger: () =>
|
|
75
|
+
new Proxy({} as Record<string, unknown>, {
|
|
76
|
+
get: () => () => {},
|
|
77
|
+
}),
|
|
78
|
+
}));
|
|
79
|
+
|
|
80
|
+
// Create a fake UnauthorizedError class that the orchestrator's instanceof check
|
|
81
|
+
// will recognize (since we're also mocking the auth module).
|
|
82
|
+
class FakeUnauthorizedError extends Error {
|
|
83
|
+
constructor(message: string) {
|
|
84
|
+
super(message);
|
|
85
|
+
this.name = "UnauthorizedError";
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
mock.module("@modelcontextprotocol/sdk/client/auth.js", () => ({
|
|
90
|
+
UnauthorizedError: FakeUnauthorizedError,
|
|
91
|
+
}));
|
|
92
|
+
|
|
93
|
+
const mockFinishAuth = mock(async (_code: string) => {});
|
|
94
|
+
let mockConnectCallCount = 0;
|
|
95
|
+
|
|
96
|
+
mock.module("@modelcontextprotocol/sdk/client/index.js", () => ({
|
|
97
|
+
Client: class {
|
|
98
|
+
async connect() {
|
|
99
|
+
mockConnectCallCount++;
|
|
100
|
+
// Every connect fires onAuthorizationUrl and throws UnauthorizedError —
|
|
101
|
+
// the orchestrator never calls connect() a second time after finishAuth.
|
|
102
|
+
if (capturedOnAuthorizationUrl) {
|
|
103
|
+
capturedOnAuthorizationUrl("https://auth.example.com/oauth");
|
|
104
|
+
}
|
|
105
|
+
throw new FakeUnauthorizedError("unauthorized");
|
|
106
|
+
}
|
|
107
|
+
async close() {}
|
|
108
|
+
},
|
|
109
|
+
}));
|
|
110
|
+
|
|
111
|
+
mock.module("@modelcontextprotocol/sdk/client/sse.js", () => ({
|
|
112
|
+
SSEClientTransport: class {
|
|
113
|
+
constructor(_url: URL, _opts: unknown) {}
|
|
114
|
+
finishAuth = mockFinishAuth;
|
|
115
|
+
},
|
|
116
|
+
}));
|
|
117
|
+
|
|
118
|
+
mock.module("@modelcontextprotocol/sdk/client/streamableHttp.js", () => ({
|
|
119
|
+
StreamableHTTPClientTransport: class {
|
|
120
|
+
constructor(_url: URL, _opts: unknown) {}
|
|
121
|
+
finishAuth = mockFinishAuth;
|
|
122
|
+
},
|
|
123
|
+
}));
|
|
124
|
+
|
|
125
|
+
// ── Import SUT after mocks ─────────────────────────────────────────────────────
|
|
126
|
+
|
|
127
|
+
const { orchestrateMcpOAuthConnect } =
|
|
128
|
+
await import("../mcp-auth-orchestrator.js");
|
|
129
|
+
|
|
130
|
+
// ── Helpers ────────────────────────────────────────────────────────────────────
|
|
131
|
+
|
|
132
|
+
function resetMocks() {
|
|
133
|
+
capturedOnAuthorizationUrl = undefined;
|
|
134
|
+
deferredCodeResolve = undefined;
|
|
135
|
+
deferredCodeReject = undefined;
|
|
136
|
+
mockInvalidateCredentials.mockClear();
|
|
137
|
+
mockStartCallbackServer.mockClear();
|
|
138
|
+
mockStopCallbackServer.mockClear();
|
|
139
|
+
mockSetMcpAuthPending.mockClear();
|
|
140
|
+
mockSetMcpAuthComplete.mockClear();
|
|
141
|
+
mockSetMcpAuthError.mockClear();
|
|
142
|
+
mockReloadMcpServers.mockClear();
|
|
143
|
+
mockFinishAuth.mockClear();
|
|
144
|
+
// Reset complete/error mocks to default "applied=true" behavior; tests
|
|
145
|
+
// that exercise the superseded branch override these in-test.
|
|
146
|
+
mockSetMcpAuthComplete.mockImplementation(() => true);
|
|
147
|
+
mockSetMcpAuthError.mockImplementation(() => true);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// ── Tests ──────────────────────────────────────────────────────────────────────
|
|
151
|
+
|
|
152
|
+
describe("orchestrateMcpOAuthConnect", () => {
|
|
153
|
+
beforeEach(() => {
|
|
154
|
+
resetMocks();
|
|
155
|
+
mockConnectCallCount = 0;
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
afterEach(() => {
|
|
159
|
+
resetMocks();
|
|
160
|
+
mockConnectCallCount = 0;
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
test("happy path — returns auth_url and sets state to pending", async () => {
|
|
164
|
+
const result = await orchestrateMcpOAuthConnect({
|
|
165
|
+
serverId: "test-server",
|
|
166
|
+
transport: { url: "https://example.com", type: "sse" },
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
expect(result.auth_url).toBe("https://auth.example.com/oauth");
|
|
170
|
+
expect(mockSetMcpAuthPending.mock.calls[0]).toEqual([
|
|
171
|
+
"test-server",
|
|
172
|
+
"https://auth.example.com/oauth",
|
|
173
|
+
expect.any(String) as unknown as string, // attemptId UUID
|
|
174
|
+
]);
|
|
175
|
+
// Sanity-check the attemptId looks UUID-shaped
|
|
176
|
+
expect(mockSetMcpAuthPending.mock.calls[0][2]).toMatch(
|
|
177
|
+
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/,
|
|
178
|
+
);
|
|
179
|
+
expect(result).toBeDefined();
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
test("tail completion — codePromise resolves → state goes to complete", async () => {
|
|
183
|
+
await orchestrateMcpOAuthConnect({
|
|
184
|
+
serverId: "test-server",
|
|
185
|
+
transport: { url: "https://example.com", type: "sse" },
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// Resolve the code to trigger the background tail
|
|
189
|
+
deferredCodeResolve!("auth-code-123");
|
|
190
|
+
|
|
191
|
+
// Wait for fire-and-forget tail to settle
|
|
192
|
+
await new Promise<void>((resolve) => setTimeout(resolve, 20));
|
|
193
|
+
|
|
194
|
+
expect(mockFinishAuth).toHaveBeenCalledWith("auth-code-123");
|
|
195
|
+
// The orchestrator calls connect() exactly once (the initial attempt that triggers
|
|
196
|
+
// UnauthorizedError). It does NOT reconnect after finishAuth to avoid the
|
|
197
|
+
// "already started" error thrown by SSE/StreamableHTTP transports.
|
|
198
|
+
expect(mockConnectCallCount).toBe(1);
|
|
199
|
+
expect(mockSetMcpAuthComplete).toHaveBeenCalledWith(
|
|
200
|
+
"test-server",
|
|
201
|
+
expect.any(String) as unknown as string,
|
|
202
|
+
);
|
|
203
|
+
// Daemon-side reload should be triggered after a successful completion.
|
|
204
|
+
expect(mockReloadMcpServers).toHaveBeenCalled();
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
test("transport.finishAuth rejects → state goes to error", async () => {
|
|
208
|
+
mockFinishAuth.mockImplementationOnce(async () => {
|
|
209
|
+
throw new Error("exchange failed");
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
await orchestrateMcpOAuthConnect({
|
|
213
|
+
serverId: "test-server",
|
|
214
|
+
transport: { url: "https://example.com", type: "sse" },
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
deferredCodeResolve!("auth-code-456");
|
|
218
|
+
|
|
219
|
+
await new Promise<void>((resolve) => setTimeout(resolve, 20));
|
|
220
|
+
|
|
221
|
+
expect(mockSetMcpAuthError).toHaveBeenCalledWith(
|
|
222
|
+
"test-server",
|
|
223
|
+
"exchange failed",
|
|
224
|
+
expect.any(String) as unknown as string,
|
|
225
|
+
);
|
|
226
|
+
expect(mockSetMcpAuthComplete).not.toHaveBeenCalled();
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
test("codePromise rejects (timeout/user deny) → state goes to error", async () => {
|
|
230
|
+
await orchestrateMcpOAuthConnect({
|
|
231
|
+
serverId: "test-server",
|
|
232
|
+
transport: { url: "https://example.com", type: "sse" },
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
deferredCodeReject!(new Error("MCP OAuth callback timed out"));
|
|
236
|
+
|
|
237
|
+
await new Promise<void>((resolve) => setTimeout(resolve, 20));
|
|
238
|
+
|
|
239
|
+
expect(mockSetMcpAuthError).toHaveBeenCalledWith(
|
|
240
|
+
"test-server",
|
|
241
|
+
"MCP OAuth callback timed out",
|
|
242
|
+
expect.any(String) as unknown as string,
|
|
243
|
+
);
|
|
244
|
+
expect(mockSetMcpAuthComplete).not.toHaveBeenCalled();
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
test("re-start for same serverId while previous is pending → new state overwrites with a fresh attemptId", async () => {
|
|
248
|
+
await orchestrateMcpOAuthConnect({
|
|
249
|
+
serverId: "srv",
|
|
250
|
+
transport: { url: "https://example.com", type: "sse" },
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
await orchestrateMcpOAuthConnect({
|
|
254
|
+
serverId: "srv",
|
|
255
|
+
transport: { url: "https://example.com", type: "sse" },
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
expect(mockSetMcpAuthPending.mock.calls).toHaveLength(2);
|
|
259
|
+
expect(mockSetMcpAuthPending.mock.calls[0][0]).toBe("srv");
|
|
260
|
+
expect(mockSetMcpAuthPending.mock.calls[1][0]).toBe("srv");
|
|
261
|
+
// Each attempt gets a distinct UUID so superseded tails can be detected.
|
|
262
|
+
const firstAttemptId = mockSetMcpAuthPending.mock.calls[0][2];
|
|
263
|
+
const secondAttemptId = mockSetMcpAuthPending.mock.calls[1][2];
|
|
264
|
+
expect(firstAttemptId).not.toBe(secondAttemptId);
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
test("supersede — when setMcpAuthComplete returns false, daemon-side reload is NOT triggered", async () => {
|
|
268
|
+
// Simulate a newer attempt having taken the slot: completion writes
|
|
269
|
+
// for the older attempt should be skipped, and reload should not fire.
|
|
270
|
+
mockSetMcpAuthComplete.mockImplementation(() => false);
|
|
271
|
+
|
|
272
|
+
await orchestrateMcpOAuthConnect({
|
|
273
|
+
serverId: "test-server",
|
|
274
|
+
transport: { url: "https://example.com", type: "sse" },
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
deferredCodeResolve!("auth-code-superseded");
|
|
278
|
+
await new Promise<void>((resolve) => setTimeout(resolve, 20));
|
|
279
|
+
|
|
280
|
+
// The set was attempted but returned false, so no reload should happen
|
|
281
|
+
expect(mockSetMcpAuthComplete).toHaveBeenCalled();
|
|
282
|
+
expect(mockReloadMcpServers).not.toHaveBeenCalled();
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
test("reload failure after completion is logged but does not corrupt success state", async () => {
|
|
286
|
+
mockReloadMcpServers.mockImplementation(async () => {
|
|
287
|
+
throw new Error("reload boom");
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
await orchestrateMcpOAuthConnect({
|
|
291
|
+
serverId: "test-server",
|
|
292
|
+
transport: { url: "https://example.com", type: "sse" },
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
deferredCodeResolve!("auth-code-789");
|
|
296
|
+
await new Promise<void>((resolve) => setTimeout(resolve, 20));
|
|
297
|
+
|
|
298
|
+
// Completion was applied even though reload threw — the polling CLI
|
|
299
|
+
// still observes status=complete.
|
|
300
|
+
expect(mockSetMcpAuthComplete).toHaveBeenCalled();
|
|
301
|
+
expect(mockSetMcpAuthError).not.toHaveBeenCalled();
|
|
302
|
+
expect(mockReloadMcpServers).toHaveBeenCalled();
|
|
303
|
+
});
|
|
304
|
+
});
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Daemon-side orchestrator for MCP OAuth flows.
|
|
3
|
+
*
|
|
4
|
+
* Runs the entire OAuth exchange (callback registration, auth URL capture,
|
|
5
|
+
* code exchange, token persistence) inside the daemon heap so that
|
|
6
|
+
* registerPendingCallback and consumeCallback always execute in the same
|
|
7
|
+
* process. The CLI receives only the authorization URL via IPC and polls
|
|
8
|
+
* for completion.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { UnauthorizedError } from "@modelcontextprotocol/sdk/client/auth.js";
|
|
12
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
13
|
+
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
14
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
15
|
+
|
|
16
|
+
import { getIsContainerized } from "../config/env-registry.js";
|
|
17
|
+
import { reloadMcpServers } from "../daemon/mcp-reload-service.js";
|
|
18
|
+
import { getLogger } from "../util/logger.js";
|
|
19
|
+
import {
|
|
20
|
+
setMcpAuthComplete,
|
|
21
|
+
setMcpAuthError,
|
|
22
|
+
setMcpAuthPending,
|
|
23
|
+
} from "./mcp-auth-state.js";
|
|
24
|
+
import {
|
|
25
|
+
type McpOAuthCallbackTransport,
|
|
26
|
+
McpOAuthProvider,
|
|
27
|
+
} from "./mcp-oauth-provider.js";
|
|
28
|
+
|
|
29
|
+
const log = getLogger("mcp-auth-orchestrator");
|
|
30
|
+
|
|
31
|
+
export interface McpAuthTransportConfig {
|
|
32
|
+
url: string;
|
|
33
|
+
type: "sse" | "streamable-http";
|
|
34
|
+
headers?: Record<string, string>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface OrchestrateMcpOAuthConnectResult {
|
|
38
|
+
auth_url: string;
|
|
39
|
+
already_authenticated?: true;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Start a daemon-owned MCP OAuth flow.
|
|
44
|
+
*
|
|
45
|
+
* Returns immediately with the authorization URL for the CLI to open in
|
|
46
|
+
* the browser. The token exchange runs in the background in the daemon heap
|
|
47
|
+
* and updates the in-memory auth state map on completion.
|
|
48
|
+
*/
|
|
49
|
+
export async function orchestrateMcpOAuthConnect(args: {
|
|
50
|
+
serverId: string;
|
|
51
|
+
transport: McpAuthTransportConfig;
|
|
52
|
+
}): Promise<OrchestrateMcpOAuthConnectResult> {
|
|
53
|
+
const { serverId, transport } = args;
|
|
54
|
+
|
|
55
|
+
// Containerized deployments (platform-managed AND self-hosted Docker) must
|
|
56
|
+
// use the gateway transport: the browser is outside the daemon container,
|
|
57
|
+
// so a loopback callback inside the container is unreachable. Bare-metal
|
|
58
|
+
// daemons can use loopback as before.
|
|
59
|
+
const callbackTransport: McpOAuthCallbackTransport = getIsContainerized()
|
|
60
|
+
? "gateway"
|
|
61
|
+
: "loopback";
|
|
62
|
+
|
|
63
|
+
let capturedAuthUrl: string | undefined;
|
|
64
|
+
const provider = new McpOAuthProvider(
|
|
65
|
+
serverId,
|
|
66
|
+
transport.url,
|
|
67
|
+
/* interactive */ false,
|
|
68
|
+
callbackTransport,
|
|
69
|
+
{
|
|
70
|
+
onAuthorizationUrl: (url) => {
|
|
71
|
+
capturedAuthUrl = url;
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
// Clear stale credentials so the flow starts fresh
|
|
77
|
+
await provider.invalidateCredentials("client");
|
|
78
|
+
await provider.invalidateCredentials("discovery");
|
|
79
|
+
|
|
80
|
+
// Register the pending callback in the daemon heap
|
|
81
|
+
const { codePromise } = await provider.startCallbackServer();
|
|
82
|
+
|
|
83
|
+
// Build the MCP transport and client
|
|
84
|
+
const serverUrl = new URL(transport.url);
|
|
85
|
+
const TransportClass =
|
|
86
|
+
transport.type === "sse"
|
|
87
|
+
? SSEClientTransport
|
|
88
|
+
: StreamableHTTPClientTransport;
|
|
89
|
+
const mcpTransport = new TransportClass(serverUrl, {
|
|
90
|
+
authProvider: provider,
|
|
91
|
+
requestInit: transport.headers ? { headers: transport.headers } : undefined,
|
|
92
|
+
});
|
|
93
|
+
const client = new Client({ name: "vellum-assistant", version: "1.0.0" });
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
await client.connect(mcpTransport);
|
|
97
|
+
// No error — server is already authenticated
|
|
98
|
+
provider.stopCallbackServer();
|
|
99
|
+
try {
|
|
100
|
+
await client.close();
|
|
101
|
+
} catch {
|
|
102
|
+
/* ignore */
|
|
103
|
+
}
|
|
104
|
+
return { auth_url: "", already_authenticated: true };
|
|
105
|
+
} catch (err) {
|
|
106
|
+
if (err instanceof UnauthorizedError) {
|
|
107
|
+
// Expected — onAuthorizationUrl has fired, capturedAuthUrl is set
|
|
108
|
+
} else {
|
|
109
|
+
provider.stopCallbackServer();
|
|
110
|
+
try {
|
|
111
|
+
await client.close();
|
|
112
|
+
} catch {
|
|
113
|
+
/* ignore */
|
|
114
|
+
}
|
|
115
|
+
throw err;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (!capturedAuthUrl) {
|
|
120
|
+
provider.stopCallbackServer();
|
|
121
|
+
try {
|
|
122
|
+
await client.close();
|
|
123
|
+
} catch {
|
|
124
|
+
/* ignore */
|
|
125
|
+
}
|
|
126
|
+
throw new Error("No authorization URL captured from OAuth provider");
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Per-attempt token. Gates fire-and-forget state writes so that a
|
|
130
|
+
// re-run of `assistant mcp auth <serverId>` before the previous attempt
|
|
131
|
+
// finishes cannot have its slot overwritten by stale completion writes
|
|
132
|
+
// from the older attempt.
|
|
133
|
+
const attemptId = crypto.randomUUID();
|
|
134
|
+
setMcpAuthPending(serverId, capturedAuthUrl, attemptId);
|
|
135
|
+
|
|
136
|
+
// Fire-and-forget background tail — completes the token exchange once
|
|
137
|
+
// the user approves in the browser.
|
|
138
|
+
// Note: we do NOT call client.connect() again here — both SSEClientTransport
|
|
139
|
+
// and StreamableHTTPClientTransport throw "already started" on a second
|
|
140
|
+
// connect() call. The tokens are persisted by saveTokens inside finishAuth,
|
|
141
|
+
// so the daemon can reconnect on the next MCP reload without re-connecting here.
|
|
142
|
+
void (async () => {
|
|
143
|
+
try {
|
|
144
|
+
// Apply an explicit timeout: the loopback callback path has a built-in
|
|
145
|
+
// 2-minute timer, but the gateway transport's deferred promise relies on
|
|
146
|
+
// the caller for time-boxing. Without this race, gateway-mode tails leak
|
|
147
|
+
// forever if the user never completes the OAuth handshake.
|
|
148
|
+
const code = await Promise.race([
|
|
149
|
+
codePromise,
|
|
150
|
+
new Promise<never>((_, reject) => {
|
|
151
|
+
const t = setTimeout(
|
|
152
|
+
() => reject(new Error("OAuth callback timed out")),
|
|
153
|
+
CALLBACK_TIMEOUT_MS,
|
|
154
|
+
);
|
|
155
|
+
// Don't keep the event loop alive solely for this timer
|
|
156
|
+
if (typeof t.unref === "function") t.unref();
|
|
157
|
+
}),
|
|
158
|
+
]);
|
|
159
|
+
await mcpTransport.finishAuth(code);
|
|
160
|
+
const applied = setMcpAuthComplete(serverId, attemptId);
|
|
161
|
+
if (!applied) {
|
|
162
|
+
log.info(
|
|
163
|
+
{ serverId, attemptId },
|
|
164
|
+
"MCP OAuth completion superseded by newer attempt — skipping state write",
|
|
165
|
+
);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
log.info({ serverId }, "MCP OAuth flow completed");
|
|
169
|
+
// Trigger MCP reload from inside the daemon so the CLI doesn't need
|
|
170
|
+
// to fall back on the deprecated file-based signal mechanism.
|
|
171
|
+
// Best-effort: reload failures are logged but don't poison the
|
|
172
|
+
// success status the polling CLI is about to observe.
|
|
173
|
+
try {
|
|
174
|
+
await reloadMcpServers();
|
|
175
|
+
} catch (reloadErr) {
|
|
176
|
+
log.warn(
|
|
177
|
+
{
|
|
178
|
+
serverId,
|
|
179
|
+
err:
|
|
180
|
+
reloadErr instanceof Error
|
|
181
|
+
? reloadErr.message
|
|
182
|
+
: String(reloadErr),
|
|
183
|
+
},
|
|
184
|
+
"MCP reload after auth completion failed",
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
} catch (err) {
|
|
188
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
189
|
+
const applied = setMcpAuthError(serverId, message, attemptId);
|
|
190
|
+
if (!applied) {
|
|
191
|
+
log.info(
|
|
192
|
+
{ serverId, attemptId, error: message },
|
|
193
|
+
"MCP OAuth error superseded by newer attempt — skipping state write",
|
|
194
|
+
);
|
|
195
|
+
} else {
|
|
196
|
+
log.warn({ serverId, error: message }, "MCP OAuth flow failed");
|
|
197
|
+
}
|
|
198
|
+
} finally {
|
|
199
|
+
provider.stopCallbackServer();
|
|
200
|
+
try {
|
|
201
|
+
await client.close();
|
|
202
|
+
} catch {
|
|
203
|
+
/* ignore */
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
})();
|
|
207
|
+
|
|
208
|
+
return { auth_url: capturedAuthUrl };
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Matches the loopback callback timeout; keep both in lockstep so loopback
|
|
212
|
+
// and gateway transports time-box OAuth identically.
|
|
213
|
+
const CALLBACK_TIMEOUT_MS = 2 * 60 * 1000;
|