@vellumai/assistant 0.6.3 → 0.6.4
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 +273 -10
- package/Dockerfile +2 -3
- package/bun.lock +5 -13
- package/docs/backup-troubleshooting.md +52 -0
- package/docs/browser-use-architecture-phase2.md +174 -0
- package/docs/stt-provider-onboarding.md +120 -0
- package/knip.json +12 -2
- package/node_modules/@vellumai/ces-contracts/bun.lock +8 -6
- package/node_modules/@vellumai/ces-contracts/package.json +3 -3
- package/openapi.yaml +982 -72
- package/package.json +4 -6
- package/scripts/generate-openapi.ts +0 -1
- package/scripts/test.sh +73 -18
- package/src/__tests__/agent-image-optimize.test.ts +28 -0
- package/src/__tests__/agent-loop.test.ts +123 -0
- package/src/__tests__/anthropic-provider.test.ts +263 -10
- package/src/__tests__/auto-analysis-end-to-end.test.ts +550 -0
- package/src/__tests__/auto-analysis-prompt.test.ts +50 -0
- package/src/__tests__/browser-fill-credential.test.ts +11 -0
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +2 -2
- package/src/__tests__/browser-skill-endstate.test.ts +31 -7
- package/src/__tests__/btw-routes.test.ts +7 -0
- package/src/__tests__/call-controller.test.ts +581 -20
- package/src/__tests__/catalog-files.test.ts +138 -0
- package/src/__tests__/channel-invite-transport.test.ts +2 -2
- package/src/__tests__/channel-readiness-routes.test.ts +16 -20
- package/src/__tests__/channel-readiness-service.test.ts +12 -7
- package/src/__tests__/checker.test.ts +157 -10
- package/src/__tests__/clawhub-files.test.ts +347 -0
- package/src/__tests__/commit-message-enrichment-service.test.ts +36 -19
- package/src/__tests__/config-analysis.test.ts +100 -0
- package/src/__tests__/config-schema.test.ts +1013 -66
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +339 -0
- package/src/__tests__/config-watcher.test.ts +43 -8
- package/src/__tests__/contact-store-user-file.test.ts +512 -0
- package/src/__tests__/contacts-write.test.ts +197 -0
- package/src/__tests__/context-window-manager.test.ts +88 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop.test.ts +98 -2
- package/src/__tests__/conversation-confirmation-signals.test.ts +135 -0
- package/src/__tests__/conversation-error.test.ts +70 -0
- package/src/__tests__/conversation-history-web-search.test.ts +11 -4
- package/src/__tests__/conversation-init.benchmark.test.ts +6 -1
- package/src/__tests__/conversation-launcher-skill-regression.test.ts +51 -0
- package/src/__tests__/conversation-list-source.test.ts +145 -0
- package/src/__tests__/conversation-pre-run-repair.test.ts +2 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -0
- package/src/__tests__/conversation-queue.test.ts +901 -60
- package/src/__tests__/conversation-routes-disk-view.test.ts +270 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +55 -0
- package/src/__tests__/conversation-skill-tools.test.ts +7 -4
- package/src/__tests__/conversation-slash-commands.test.ts +33 -0
- package/src/__tests__/conversation-slash-queue.test.ts +89 -18
- package/src/__tests__/conversation-slash-unknown.test.ts +2 -0
- package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +226 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +2 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +2 -0
- package/src/__tests__/credential-health-service.test.ts +352 -0
- package/src/__tests__/credential-security-invariants.test.ts +5 -3
- package/src/__tests__/credential-vault-unit.test.ts +379 -3
- package/src/__tests__/credentials-cli.test.ts +40 -16
- package/src/__tests__/cross-provider-web-search.test.ts +146 -35
- package/src/__tests__/deterministic-verification-control-plane.test.ts +10 -1
- package/src/__tests__/device-id.test.ts +112 -0
- package/src/__tests__/docker-signing-key-bootstrap.test.ts +167 -4
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +1 -3
- package/src/__tests__/email-html-renderer.test.ts +71 -0
- package/src/__tests__/email-invite-adapter.test.ts +36 -32
- package/src/__tests__/emit-event-signal.test.ts +71 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +75 -8
- package/src/__tests__/fixtures/mock-chrome-extension.ts +11 -0
- package/src/__tests__/gateway-only-enforcement.test.ts +206 -1
- package/src/__tests__/gateway-only-guard.test.ts +0 -1
- package/src/__tests__/gemini-provider.test.ts +64 -0
- package/src/__tests__/get-skill-detail-audit.test.ts +325 -0
- package/src/__tests__/gmail-archive-fallback.test.ts +193 -0
- package/src/__tests__/gmail-archive-gate.test.ts +246 -0
- package/src/__tests__/gmail-preferences.test.ts +117 -0
- package/src/__tests__/headless-browser-interactions.test.ts +43 -0
- package/src/__tests__/headless-browser-mode.test.ts +614 -0
- package/src/__tests__/headless-browser-navigate.test.ts +142 -5
- package/src/__tests__/headless-browser-read-tools.test.ts +11 -0
- package/src/__tests__/headless-browser-snapshot.test.ts +10 -0
- package/src/__tests__/heartbeat-service.test.ts +70 -17
- package/src/__tests__/home-state-routes.test.ts +162 -0
- package/src/__tests__/host-bash-proxy.test.ts +0 -5
- package/src/__tests__/host-browser-e2e-cloud.test.ts +138 -4
- package/src/__tests__/host-browser-e2e-self-hosted.test.ts +4 -4
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +103 -0
- package/src/__tests__/host-cu-proxy.test.ts +0 -5
- package/src/__tests__/identity-intro-cache.test.ts +40 -10
- package/src/__tests__/init-feature-flag-overrides.test.ts +38 -112
- package/src/__tests__/jobs-store-upsert-debounced.test.ts +141 -0
- package/src/__tests__/llm-context-normalization.test.ts +488 -0
- package/src/__tests__/llm-context-route-provider.test.ts +86 -5
- package/src/__tests__/llm-usage-store.test.ts +363 -0
- package/src/__tests__/media-stream-output.test.ts +555 -0
- package/src/__tests__/media-stream-parser.test.ts +374 -0
- package/src/__tests__/media-stream-server-integration.test.ts +1234 -0
- package/src/__tests__/media-stream-stt-session.test.ts +588 -0
- package/src/__tests__/media-turn-detector.test.ts +440 -0
- package/src/__tests__/message-queue.test.ts +125 -0
- package/src/__tests__/migration-export-http.test.ts +6 -6
- package/src/__tests__/migration-import-commit-http.test.ts +8 -6
- package/src/__tests__/migration-import-preflight-http.test.ts +6 -5
- package/src/__tests__/migration-validate-http.test.ts +3 -3
- package/src/__tests__/mock-gateway-ipc.ts +151 -0
- package/src/__tests__/model-intents.test.ts +2 -2
- package/src/__tests__/oauth-apps-routes.test.ts +1 -0
- package/src/__tests__/oauth-cli.test.ts +2 -0
- package/src/__tests__/oauth-connect-orchestrator.test.ts +2 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +1 -0
- package/src/__tests__/oauth-providers-routes.test.ts +2 -0
- package/src/__tests__/oauth-store.test.ts +85 -0
- package/src/__tests__/oauth2-gateway-transport.test.ts +249 -6
- package/src/__tests__/onboarding-template-contract.test.ts +6 -13
- package/src/__tests__/openai-provider.test.ts +176 -0
- package/src/__tests__/openai-responses-cutover-guard.test.ts +184 -0
- package/src/__tests__/openai-responses-provider.test.ts +1105 -0
- package/src/__tests__/openrouter-token-estimation.test.ts +100 -0
- package/src/__tests__/outlook-unsubscribe.test.ts +31 -2
- package/src/__tests__/persona-resolver.test.ts +251 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +4 -0
- package/src/__tests__/platform.test.ts +92 -1
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +47 -0
- package/src/__tests__/prechat-onboarding-contract.test.ts +267 -0
- package/src/__tests__/pricing.test.ts +174 -0
- package/src/__tests__/qdrant-manager.test.ts +29 -8
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +194 -0
- package/src/__tests__/relationship-state-contract.test.ts +175 -0
- package/src/__tests__/relay-server.test.ts +423 -5
- package/src/__tests__/search-skills-unified.test.ts +118 -0
- package/src/__tests__/secret-scanner-executor.test.ts +4 -0
- package/src/__tests__/secure-keys.test.ts +107 -0
- package/src/__tests__/send-endpoint-busy.test.ts +5 -1
- package/src/__tests__/sequence-store.test.ts +1 -1
- package/src/__tests__/server-history-render.test.ts +49 -0
- package/src/__tests__/settings-routes.test.ts +201 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
- package/src/__tests__/skills-file-content-endpoint.test.ts +276 -145
- package/src/__tests__/skills-files-catalog-fallback.test.ts +381 -93
- package/src/__tests__/skills.test.ts +5 -2
- package/src/__tests__/skillssh-files.test.ts +446 -0
- package/src/__tests__/slack-block-formatting.test.ts +110 -0
- package/src/__tests__/slack-channel-config.test.ts +564 -1
- package/src/__tests__/stt-catalog-parity.test.ts +282 -0
- package/src/__tests__/stt-stream-session.test.ts +535 -0
- package/src/__tests__/system-prompt.test.ts +112 -26
- package/src/__tests__/telephony-stt-routing.test.ts +329 -0
- package/src/__tests__/terminal-tools.test.ts +18 -7
- package/src/__tests__/test-preload.ts +18 -0
- package/src/__tests__/test-support/browser-skill-harness.ts +4 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +9 -5
- package/src/__tests__/tool-executor-shell-integration.test.ts +4 -0
- package/src/__tests__/tool-executor.test.ts +33 -24
- package/src/__tests__/tool-result-truncation.test.ts +36 -0
- package/src/__tests__/trust-store.test.ts +7 -1
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -1
- package/src/__tests__/tts-catalog-parity.test.ts +345 -0
- package/src/__tests__/twilio-routes-twiml.test.ts +512 -114
- package/src/__tests__/twilio-routes.test.ts +376 -0
- package/src/__tests__/unicode.test.ts +293 -0
- package/src/__tests__/update-bulletin-format.test.ts +59 -0
- package/src/__tests__/update-bulletin.test.ts +206 -5
- package/src/__tests__/usage-routes.test.ts +25 -4
- package/src/__tests__/user-reference.test.ts +46 -61
- package/src/__tests__/verification-control-plane-policy.test.ts +4 -0
- package/src/__tests__/voice-config-update.test.ts +403 -0
- package/src/__tests__/voice-quality.test.ts +434 -19
- package/src/__tests__/workspace-heartbeat-service.test.ts +7 -0
- package/src/__tests__/workspace-migration-033-stt-service-explicit-config.test.ts +547 -0
- package/src/__tests__/workspace-migration-034-remove-calls-voice-transcription-provider.test.ts +596 -0
- package/src/__tests__/workspace-migration-drop-user-md.test.ts +368 -0
- package/src/__tests__/workspace-migration-meets.test.ts +244 -0
- package/src/__tests__/workspace-migration-seed-device-id.test.ts +14 -20
- package/src/__tests__/workspace-policy.test.ts +2 -0
- package/src/agent/image-optimize.ts +24 -12
- package/src/agent/loop.ts +43 -3
- package/src/backup/__tests__/backup-key.test.ts +152 -0
- package/src/backup/__tests__/backup-worker.test.ts +767 -0
- package/src/backup/__tests__/list-snapshots.test.ts +87 -0
- package/src/backup/__tests__/local-writer.test.ts +218 -0
- package/src/backup/__tests__/offsite-writer.test.ts +641 -0
- package/src/backup/__tests__/paths.test.ts +300 -0
- package/src/backup/__tests__/restore.test.ts +498 -0
- package/src/backup/__tests__/snapshot-lock.test.ts +352 -0
- package/src/backup/__tests__/stream-crypt.test.ts +228 -0
- package/src/backup/backup-key.ts +137 -0
- package/src/backup/backup-worker.ts +459 -0
- package/src/backup/list-snapshots.ts +147 -0
- package/src/backup/local-writer.ts +133 -0
- package/src/backup/offsite-writer.ts +222 -0
- package/src/backup/paths.ts +226 -0
- package/src/backup/restore.ts +322 -0
- package/src/backup/snapshot-lock.ts +431 -0
- package/src/backup/stream-crypt.ts +263 -0
- package/src/bundler/package-resolver.ts +4 -0
- package/src/calls/audio-store.ts +11 -5
- package/src/calls/call-controller.ts +226 -71
- package/src/calls/call-domain.ts +9 -0
- package/src/calls/call-speech-output.ts +190 -0
- package/src/calls/call-transport.ts +77 -0
- package/src/calls/media-stream-audio-transcode.ts +173 -0
- package/src/calls/media-stream-output.ts +660 -0
- package/src/calls/media-stream-parser.ts +300 -0
- package/src/calls/media-stream-protocol.ts +166 -0
- package/src/calls/media-stream-server.ts +592 -0
- package/src/calls/media-stream-stt-session.ts +460 -0
- package/src/calls/media-turn-detector.ts +230 -0
- package/src/calls/relay-server.ts +90 -75
- package/src/calls/resolve-call-tts-provider.ts +136 -0
- package/src/calls/telephony-stt-routing.ts +145 -0
- package/src/calls/tts-call-strategy.ts +161 -0
- package/src/calls/tts-text-sanitizer.ts +32 -16
- package/src/calls/twilio-routes.ts +281 -17
- package/src/calls/voice-quality.ts +78 -35
- package/src/calls/voice-session-bridge.ts +8 -1
- package/src/channels/types.ts +16 -0
- package/src/cli/__tests__/run-assistant-command.ts +11 -1
- package/src/cli/commands/__tests__/backup.test.ts +1165 -0
- package/src/cli/commands/__tests__/domain-register.test.ts +234 -0
- package/src/cli/commands/__tests__/domain-status.test.ts +132 -0
- package/src/cli/commands/__tests__/email-attachment.test.ts +422 -0
- package/src/cli/commands/__tests__/email-download.test.ts +16 -1
- package/src/cli/commands/__tests__/email-list.test.ts +22 -4
- package/src/cli/commands/__tests__/email-register.test.ts +4 -4
- package/src/cli/commands/__tests__/email-send.test.ts +37 -4
- package/src/cli/commands/__tests__/email-status.test.ts +5 -1
- package/src/cli/commands/__tests__/email-unregister.test.ts +34 -5
- package/src/cli/commands/backup.ts +993 -0
- package/src/cli/commands/conversations.ts +77 -0
- package/src/cli/commands/credentials.ts +0 -1
- package/src/cli/commands/domain.ts +210 -0
- package/src/cli/commands/email.ts +255 -3
- package/src/cli/commands/oauth/__tests__/connect.test.ts +12 -0
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +1 -0
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -0
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -0
- package/src/cli/commands/oauth/mode.ts +12 -3
- package/src/cli/commands/oauth/providers.ts +15 -0
- package/src/cli/commands/oauth/shared.ts +2 -1
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +4 -9
- package/src/cli/commands/platform/__tests__/connect.test.ts +6 -0
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +6 -0
- package/src/cli/program.ts +30 -4
- package/src/config/__tests__/backup-schema.test.ts +134 -0
- package/src/config/assistant-feature-flags.ts +61 -62
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +37 -1
- package/src/config/bundled-skills/browser/SKILL.md +30 -5
- package/src/config/bundled-skills/browser/TOOLS.json +123 -0
- package/src/config/bundled-skills/browser/tools/browser-attach.ts +12 -0
- package/src/config/bundled-skills/browser/tools/browser-detach.ts +12 -0
- package/src/config/bundled-skills/browser/tools/browser-status.ts +12 -0
- package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +17 -0
- package/src/config/bundled-skills/contacts/SKILL.md +2 -2
- package/src/config/bundled-skills/gmail/SKILL.md +53 -7
- package/src/config/bundled-skills/gmail/TOOLS.json +33 -3
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +116 -9
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +138 -11
- package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +59 -0
- package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +82 -0
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +113 -17
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +2 -2
- package/src/config/bundled-skills/media-processing/SKILL.md +3 -9
- package/src/config/bundled-skills/media-processing/TOOLS.json +1 -6
- package/src/config/bundled-skills/media-processing/__tests__/audio-transcribe.test.ts +125 -0
- package/src/config/bundled-skills/media-processing/__tests__/extract-keyframes.test.ts +181 -0
- package/src/config/bundled-skills/media-processing/__tests__/preprocess-audio.test.ts +141 -0
- package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +32 -87
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +8 -4
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +0 -10
- package/src/config/bundled-skills/messaging/SKILL.md +3 -3
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +2 -2
- package/src/config/bundled-skills/outlook/SKILL.md +2 -2
- package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +2 -2
- package/src/config/bundled-skills/phone-calls/SKILL.md +2 -2
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +27 -18
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +3 -3
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +26 -22
- package/src/config/bundled-skills/slack/SKILL.md +1 -0
- package/src/config/bundled-skills/transcribe/SKILL.md +9 -14
- package/src/config/bundled-skills/transcribe/TOOLS.json +2 -7
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +256 -0
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +38 -188
- package/src/config/bundled-tool-registry.ts +8 -0
- package/src/config/env-registry.ts +24 -0
- package/src/config/env.ts +34 -10
- package/src/config/feature-flag-registry.json +46 -14
- package/src/config/loader.ts +26 -12
- package/src/config/schema.ts +35 -10
- package/src/config/schemas/__tests__/stt.test.ts +43 -0
- package/src/config/schemas/analysis.ts +51 -0
- package/src/config/schemas/backup.ts +72 -0
- package/src/config/schemas/calls.ts +1 -26
- package/src/config/schemas/elevenlabs.ts +0 -59
- package/src/config/schemas/filing.ts +47 -7
- package/src/config/schemas/heartbeat.ts +27 -5
- package/src/config/schemas/host-browser.ts +47 -1
- package/src/config/schemas/inference.ts +1 -1
- package/src/config/schemas/memory-lifecycle.ts +14 -2
- package/src/config/schemas/services.ts +44 -0
- package/src/config/schemas/stt.ts +59 -0
- package/src/config/schemas/tts.ts +230 -0
- package/src/config/schemas/updates.ts +14 -0
- package/src/config/skills.ts +4 -0
- package/src/config/types.ts +4 -0
- package/src/contacts/contact-store.ts +56 -11
- package/src/contacts/contacts-write.ts +38 -1
- package/src/context/post-turn-tool-result-truncation.ts +3 -2
- package/src/context/tool-result-truncation.ts +2 -1
- package/src/context/window-manager.ts +45 -12
- package/src/credential-execution/executable-discovery.ts +12 -2
- package/src/credential-execution/process-manager.ts +33 -2
- package/src/credential-health/credential-health-service.ts +366 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +324 -0
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +497 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +17 -8
- package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +127 -0
- package/src/daemon/config-watcher.ts +99 -5
- package/src/daemon/conversation-agent-loop-handlers.ts +6 -0
- package/src/daemon/conversation-agent-loop.ts +101 -24
- package/src/daemon/conversation-error.ts +11 -0
- package/src/daemon/conversation-history.ts +40 -6
- package/src/daemon/conversation-launch.ts +220 -0
- package/src/daemon/conversation-lifecycle.ts +59 -9
- package/src/daemon/conversation-messaging.ts +37 -3
- package/src/daemon/conversation-notifiers.ts +5 -0
- package/src/daemon/conversation-process.ts +581 -19
- package/src/daemon/conversation-queue-manager.ts +24 -0
- package/src/daemon/conversation-runtime-assembly.ts +11 -1
- package/src/daemon/conversation-slash.ts +36 -0
- package/src/daemon/conversation-surfaces.ts +94 -4
- package/src/daemon/conversation-tool-setup.ts +25 -0
- package/src/daemon/conversation-usage.ts +7 -4
- package/src/daemon/conversation.ts +86 -28
- package/src/daemon/handlers/config-slack-channel.ts +269 -94
- package/src/daemon/handlers/conversations.ts +4 -1
- package/src/daemon/handlers/shared.ts +22 -0
- package/src/daemon/handlers/skills.ts +321 -77
- package/src/daemon/host-browser-proxy.ts +2 -1
- package/src/daemon/lifecycle.ts +122 -25
- package/src/daemon/message-protocol.ts +6 -0
- package/src/daemon/message-types/conversations.ts +34 -1
- package/src/daemon/message-types/home.ts +40 -0
- package/src/daemon/message-types/meet.ts +143 -0
- package/src/daemon/message-types/messages.ts +14 -0
- package/src/daemon/message-types/schedules.ts +34 -2
- package/src/daemon/message-types/skills.ts +16 -0
- package/src/daemon/message-types/surfaces.ts +2 -0
- package/src/daemon/server.ts +347 -2
- package/src/daemon/shutdown-handlers.ts +32 -4
- package/src/daemon/shutdown-registry.ts +40 -0
- package/src/daemon/tool-side-effects.ts +9 -0
- package/src/email/html-renderer.ts +76 -0
- package/src/heartbeat/heartbeat-service.ts +93 -7
- package/src/home/__tests__/assistant-feed-authoring.test.ts +156 -0
- package/src/home/__tests__/emit-feed-event.test.ts +169 -0
- package/src/home/__tests__/feed-scheduler.test.ts +194 -0
- package/src/home/__tests__/feed-types.test.ts +275 -0
- package/src/home/__tests__/feed-writer.test.ts +688 -0
- package/src/home/__tests__/phase5-exit-criteria.test.ts +212 -0
- package/src/home/__tests__/platform-gmail-digest.test.ts +222 -0
- package/src/home/__tests__/progress-formula.test.ts +213 -0
- package/src/home/__tests__/relationship-state-writer.test.ts +740 -0
- package/src/home/__tests__/rollup-producer.test.ts +398 -0
- package/src/home/assistant-feed-authoring.ts +124 -0
- package/src/home/emit-feed-event.ts +158 -0
- package/src/home/feed-scheduler.ts +247 -0
- package/src/home/feed-types.ts +181 -0
- package/src/home/feed-writer.ts +469 -0
- package/src/home/platform-gmail-digest.ts +163 -0
- package/src/home/progress-formula.ts +86 -0
- package/src/home/relationship-state-writer.ts +824 -0
- package/src/home/relationship-state.ts +143 -0
- package/src/home/rollup-producer.ts +384 -0
- package/src/hooks/runner.ts +7 -0
- package/src/inbound/platform-callback-registration.ts +12 -3
- package/src/inbound/public-ingress-urls.ts +12 -0
- package/src/instrument.ts +1 -1
- package/src/ipc/__tests__/cli-ipc.test.ts +200 -0
- package/src/ipc/cli-client.ts +151 -0
- package/src/ipc/cli-server.ts +234 -0
- package/src/ipc/gateway-client.ts +180 -0
- package/src/ipc/routes/index.ts +5 -0
- package/src/ipc/routes/wake-conversation.ts +19 -0
- package/src/memory/__tests__/auto-analysis-enqueue.test.ts +356 -0
- package/src/memory/__tests__/auto-analysis-guard.test.ts +57 -0
- package/src/memory/__tests__/conversation-analyze-job.test.ts +232 -0
- package/src/memory/__tests__/find-analysis-conversation.test.ts +196 -0
- package/src/memory/app-store.ts +1 -1
- package/src/memory/attachments-store.ts +70 -0
- package/src/memory/auto-analysis-enqueue.ts +127 -0
- package/src/memory/auto-analysis-guard.ts +27 -0
- package/src/memory/cleanup-schedule-state.ts +37 -0
- package/src/memory/conversation-analyze-job.ts +73 -0
- package/src/memory/conversation-crud.ts +99 -0
- package/src/memory/conversation-disk-view.ts +7 -0
- package/src/memory/conversation-group-migration.ts +34 -2
- package/src/memory/conversation-queries.ts +6 -5
- package/src/memory/db-init.ts +6 -0
- package/src/memory/db-maintenance.ts +108 -0
- package/src/memory/db.ts +1 -0
- package/src/memory/graph/conversation-graph-memory.ts +15 -0
- package/src/memory/graph/extraction.test.ts +23 -0
- package/src/memory/graph/extraction.ts +8 -0
- package/src/memory/graph/retriever.ts +27 -18
- package/src/memory/graph/scoring.test.ts +186 -0
- package/src/memory/graph/scoring.ts +31 -1
- package/src/memory/graph/tools.ts +1 -1
- package/src/memory/group-crud.ts +6 -1
- package/src/memory/indexer.ts +95 -16
- package/src/memory/job-handlers/cleanup.ts +11 -8
- package/src/memory/job-handlers/conversation-starters.ts +16 -10
- package/src/memory/jobs-store.ts +64 -4
- package/src/memory/jobs-worker.ts +22 -9
- package/src/memory/llm-usage-store.ts +92 -56
- package/src/memory/migrations/219-oauth-providers-token-exchange-body-format.ts +15 -0
- package/src/memory/migrations/220-normalize-user-file-by-principal.ts +190 -0
- package/src/memory/migrations/221-conversations-archived-at.ts +16 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/qdrant-manager.ts +43 -16
- package/src/memory/schema/conversations.ts +2 -0
- package/src/memory/schema/oauth.ts +3 -0
- package/src/memory/usage-buckets.ts +396 -0
- package/src/messaging/providers/gmail/client.ts +57 -6
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +282 -0
- package/src/messaging/providers/slack/adapter.ts +143 -38
- package/src/messaging/providers/slack/client.ts +16 -0
- package/src/messaging/providers/slack/types.ts +4 -0
- package/src/notifications/decision-engine.ts +3 -3
- package/src/notifications/signal.ts +5 -0
- package/src/oauth/__tests__/identity-verifier.test.ts +1 -0
- package/src/oauth/byo-connection.test.ts +18 -1
- package/src/oauth/byo-connection.ts +3 -1
- package/src/oauth/connect-orchestrator.ts +2 -0
- package/src/oauth/connection-resolver.ts +6 -2
- package/src/oauth/connection.ts +2 -0
- package/src/oauth/oauth-store.ts +9 -0
- package/src/oauth/platform-connection.test.ts +98 -0
- package/src/oauth/platform-connection.ts +52 -31
- package/src/oauth/seed-providers.ts +7 -0
- package/src/permissions/checker.ts +16 -6
- package/src/permissions/defaults.ts +49 -1
- package/src/permissions/trust-store.ts +3 -3
- package/src/permissions/workspace-policy.ts +3 -0
- package/src/platform/client.test.ts +10 -0
- package/src/platform/sync-identity.ts +129 -0
- package/src/prompts/persona-resolver.ts +126 -2
- package/src/prompts/system-prompt.ts +59 -18
- package/src/prompts/templates/BOOTSTRAP.md +5 -5
- package/src/prompts/templates/SOUL.md +3 -1
- package/src/prompts/templates/UPDATES.md +12 -0
- package/src/prompts/templates/channels/slack.md +20 -0
- package/src/prompts/update-bulletin-format.ts +26 -9
- package/src/prompts/update-bulletin.ts +34 -23
- package/src/prompts/user-reference.ts +20 -17
- package/src/providers/__tests__/provider-secret-catalog.test.ts +42 -0
- package/src/providers/anthropic/client.ts +157 -61
- package/src/providers/fireworks/client.ts +2 -2
- package/src/providers/gemini/client.ts +9 -1
- package/src/providers/model-catalog.ts +6 -0
- package/src/providers/model-intents.ts +4 -4
- package/src/providers/ollama/client.ts +2 -2
- package/src/providers/openai/chat-completions-provider.ts +474 -0
- package/src/providers/openai/client.ts +25 -440
- package/src/providers/openai/responses-provider.ts +502 -0
- package/src/providers/openrouter/client.ts +101 -4
- package/src/providers/provider-secret-catalog.ts +139 -0
- package/src/providers/registry.ts +2 -2
- package/src/providers/retry.ts +14 -3
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +251 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +828 -0
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +980 -0
- package/src/providers/speech-to-text/deepgram-realtime.ts +767 -0
- package/src/providers/speech-to-text/deepgram.test.ts +332 -0
- package/src/providers/speech-to-text/deepgram.ts +115 -0
- package/src/providers/speech-to-text/google-gemini-live-stream.test.ts +743 -0
- package/src/providers/speech-to-text/google-gemini-live-stream.ts +625 -0
- package/src/providers/speech-to-text/google-gemini.test.ts +226 -0
- package/src/providers/speech-to-text/google-gemini.ts +101 -0
- package/src/providers/speech-to-text/openai-whisper-stream.test.ts +564 -0
- package/src/providers/speech-to-text/openai-whisper-stream.ts +381 -0
- package/src/providers/speech-to-text/openai-whisper.test.ts +1 -37
- package/src/providers/speech-to-text/openai-whisper.ts +63 -33
- package/src/providers/speech-to-text/provider-catalog.ts +306 -0
- package/src/providers/speech-to-text/resolve.ts +386 -6
- package/src/providers/types.ts +9 -0
- package/src/runtime/AGENTS.md +43 -1
- package/src/runtime/__tests__/agent-wake.test.ts +831 -0
- package/src/runtime/__tests__/runtime-mode.test.ts +62 -0
- package/src/runtime/__tests__/slack-block-formatting.test.ts +481 -0
- package/src/runtime/agent-wake.ts +512 -0
- package/src/runtime/auth/__tests__/route-policy.test.ts +40 -0
- package/src/runtime/auth/route-policy.ts +30 -5
- package/src/runtime/auth/token-service.ts +56 -1
- package/src/runtime/btw-sidechain.ts +2 -0
- package/src/runtime/capability-tokens.ts +10 -10
- package/src/runtime/channel-invite-transport.ts +1 -1
- package/src/runtime/channel-invite-transports/email.ts +14 -6
- package/src/runtime/channel-readiness-service.ts +12 -22
- package/src/runtime/chrome-extension-registry.ts +38 -2
- package/src/runtime/http-server.ts +395 -10
- package/src/runtime/http-types.ts +6 -2
- package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +36 -0
- package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +360 -0
- package/src/runtime/migrations/migration-transport.ts +1 -0
- package/src/runtime/migrations/migration-wizard.ts +1 -0
- package/src/runtime/migrations/vbundle-import-analyzer.ts +77 -1
- package/src/runtime/migrations/vbundle-importer.ts +34 -0
- package/src/runtime/pending-interactions.ts +0 -11
- package/src/runtime/routes/__tests__/backup-routes.test.ts +967 -0
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +507 -0
- package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +208 -0
- package/src/runtime/routes/__tests__/stt-routes.test.ts +406 -0
- package/src/runtime/routes/__tests__/tts-routes.test.ts +474 -0
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +148 -17
- package/src/runtime/routes/app-management-routes.ts +12 -18
- package/src/runtime/routes/attachment-routes.test.ts +9 -3
- package/src/runtime/routes/attachment-routes.ts +216 -17
- package/src/runtime/routes/backup-routes.ts +519 -0
- package/src/runtime/routes/browser-extension-pair-routes.ts +82 -23
- package/src/runtime/routes/btw-routes.ts +8 -6
- package/src/runtime/routes/contact-routes.test.ts +298 -0
- package/src/runtime/routes/contact-routes.ts +132 -5
- package/src/runtime/routes/conversation-analysis-routes.ts +22 -142
- package/src/runtime/routes/conversation-management-routes.ts +115 -0
- package/src/runtime/routes/conversation-routes.ts +367 -146
- package/src/runtime/routes/filing-routes.ts +93 -0
- package/src/runtime/routes/home-feed-routes.ts +334 -0
- package/src/runtime/routes/home-state-routes.ts +138 -0
- package/src/runtime/routes/host-browser-routes.ts +3 -14
- package/src/runtime/routes/identity-intro-cache.ts +7 -3
- package/src/runtime/routes/identity-routes.ts +3 -17
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +46 -39
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +15 -15
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +137 -0
- package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +179 -0
- package/src/runtime/routes/integrations/slack/channel.ts +11 -3
- package/src/runtime/routes/integrations/slack/share.ts +45 -7
- package/src/runtime/routes/llm-context-normalization.ts +303 -0
- package/src/runtime/routes/memory-item-routes.test.ts +3 -2
- package/src/runtime/routes/migration-routes.ts +40 -5
- package/src/runtime/routes/settings-routes.ts +22 -5
- package/src/runtime/routes/skills-routes.ts +76 -7
- package/src/runtime/routes/stt-routes.ts +233 -0
- package/src/runtime/routes/surface-action-routes.ts +41 -2
- package/src/runtime/routes/tts-routes.ts +108 -24
- package/src/runtime/routes/usage-routes.ts +30 -2
- package/src/runtime/routes/user-route-dispatcher.ts +50 -5
- package/src/runtime/routes/user-routes.ts +13 -1
- package/src/runtime/routes/work-items-routes.ts +8 -1
- package/src/runtime/runtime-mode.ts +33 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +444 -0
- package/src/runtime/services/__tests__/analyze-deps-singleton.test.ts +67 -0
- package/src/runtime/services/__tests__/auto-analysis-prompt.test.ts +53 -0
- package/src/runtime/services/__tests__/manual-analysis-prompt.test.ts +41 -0
- package/src/runtime/services/analyze-conversation.ts +344 -0
- package/src/runtime/services/analyze-deps-singleton.ts +32 -0
- package/src/runtime/services/auto-analysis-prompt.ts +55 -0
- package/src/runtime/skill-route-registry.ts +49 -0
- package/src/runtime/slack-block-formatting.ts +437 -10
- package/src/schedule/scheduler.ts +50 -0
- package/src/security/oauth2.ts +26 -4
- package/src/security/secure-keys.ts +25 -2
- package/src/security/token-manager.ts +8 -0
- package/src/sequence/engine.ts +23 -0
- package/src/sequence/types.ts +1 -1
- package/src/skills/catalog-files.ts +64 -2
- package/src/skills/category-inference.ts +122 -0
- package/src/skills/clawhub-files.ts +213 -0
- package/src/skills/clawhub.ts +84 -23
- package/src/skills/skill-file-provider.ts +40 -0
- package/src/skills/skillssh-files.ts +395 -0
- package/src/skills/skillssh-registry.ts +4 -4
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +392 -0
- package/src/stt/__tests__/types.test.ts +89 -0
- package/src/stt/daemon-batch-transcriber.ts +195 -0
- package/src/stt/stt-stream-session.ts +499 -0
- package/src/stt/types.ts +330 -0
- package/src/stt/wav-encoder.test.ts +373 -0
- package/src/stt/wav-encoder.ts +175 -0
- package/src/subagent/manager.ts +38 -14
- package/src/tools/browser/__tests__/browser-mode.test.ts +119 -0
- package/src/tools/browser/__tests__/browser-status.test.ts +123 -0
- package/src/tools/browser/browser-execution.ts +1163 -23
- package/src/tools/browser/browser-manager.ts +45 -0
- package/src/tools/browser/browser-mode-constants.ts +12 -0
- package/src/tools/browser/browser-mode.ts +92 -0
- package/src/tools/browser/browser-status-constants.ts +33 -0
- package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +393 -0
- package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +29 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +1648 -32
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +264 -0
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +183 -17
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +254 -21
- package/src/tools/browser/cdp-client/errors.ts +15 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +39 -16
- package/src/tools/browser/cdp-client/factory.ts +797 -87
- package/src/tools/browser/cdp-client/index.ts +16 -2
- package/src/tools/browser/cdp-client/types.ts +68 -0
- package/src/tools/credentials/vault.ts +35 -6
- package/src/tools/network/web-fetch.ts +5 -2
- package/src/tools/network/web-search.ts +5 -2
- package/src/tools/shared/shell-output.ts +3 -1
- package/src/tools/side-effects.ts +2 -0
- package/src/tools/skills/sandbox-runner.ts +3 -2
- package/src/tools/terminal/safe-env.ts +10 -2
- package/src/tools/terminal/shell.ts +15 -4
- package/src/tools/tool-manifest.ts +21 -0
- package/src/tools/types.ts +17 -0
- package/src/tools/ui-surface/definitions.ts +6 -1
- package/src/tts/__tests__/provider-adapters.test.ts +834 -0
- package/src/tts/__tests__/provider-catalog-consistency.test.ts +196 -0
- package/src/tts/__tests__/provider-catalog.test.ts +183 -0
- package/src/tts/__tests__/provider-registry.test.ts +90 -0
- package/src/tts/provider-catalog.ts +201 -0
- package/src/tts/provider-registry.ts +73 -0
- package/src/tts/providers/deepgram-provider.ts +219 -0
- package/src/tts/providers/elevenlabs-provider.ts +211 -0
- package/src/tts/providers/fish-audio-provider.ts +183 -0
- package/src/tts/providers/index.ts +42 -0
- package/src/tts/providers/register-builtins.ts +130 -0
- package/src/tts/synthesize-text.ts +110 -0
- package/src/tts/tts-config-resolver.ts +78 -0
- package/src/tts/types.ts +153 -0
- package/src/types/onboarding-context.ts +7 -0
- package/src/util/abort-reasons.ts +58 -0
- package/src/util/device-id.ts +32 -16
- package/src/util/errors.ts +9 -1
- package/src/util/platform.ts +54 -10
- package/src/util/pricing.ts +66 -3
- package/src/util/spawn.ts +1 -1
- package/src/util/truncate.ts +4 -2
- package/src/util/unicode.ts +201 -0
- package/src/version.ts +19 -24
- package/src/watcher/engine.ts +23 -0
- package/src/watcher/watcher-store.ts +31 -0
- package/src/workspace/migrations/003-seed-device-id.ts +9 -3
- package/src/workspace/migrations/017-seed-persona-dirs.ts +68 -4
- package/src/workspace/migrations/029-seed-pkb.ts +1 -1
- package/src/workspace/migrations/031-drop-user-md.ts +317 -0
- package/src/workspace/migrations/031-llm-log-retention-zero-to-null.ts +73 -0
- package/src/workspace/migrations/032-tts-provider-unification.ts +227 -0
- package/src/workspace/migrations/033-stt-service-explicit-config.ts +122 -0
- package/src/workspace/migrations/034-remove-calls-voice-transcription-provider.ts +215 -0
- package/src/workspace/migrations/035-seed-slack-channel-persona.ts +50 -0
- package/src/workspace/migrations/036-update-pkb-index-bar.ts +37 -0
- package/src/workspace/migrations/037-create-meets-dir.ts +61 -0
- package/src/workspace/migrations/registry.ts +16 -0
- package/src/workspace/top-level-renderer.ts +13 -1
- package/src/workspace/turn-commit.ts +31 -0
- package/src/__tests__/email-cli.test.ts +0 -297
- package/src/__tests__/email-service-config-fallback.test.ts +0 -102
- package/src/cli/commands/browser-relay.ts +0 -466
- package/src/email/guardrails.ts +0 -221
- package/src/email/provider.ts +0 -117
- package/src/email/providers/agentmail.ts +0 -361
- package/src/email/providers/index.ts +0 -65
- package/src/email/service.ts +0 -384
- package/src/email/types.ts +0 -126
- package/src/prompts/templates/USER.md +0 -13
- package/src/providers/speech-to-text/types.ts +0 -17
- package/src/runtime/routes/browser-cdp-routes.ts +0 -229
|
@@ -4,6 +4,7 @@ import { isAbsolute, join, relative, resolve } from "node:path";
|
|
|
4
4
|
import { getLogger } from "../../util/logger.js";
|
|
5
5
|
import { getDataDir } from "../../util/platform.js";
|
|
6
6
|
import { authSessionCache } from "./auth-cache.js";
|
|
7
|
+
import type { CdpClientKind } from "./cdp-client/types.js";
|
|
7
8
|
import type { ExtractedCredential } from "./network-recording-types.js";
|
|
8
9
|
import { importPlaywright } from "./runtime-check.js";
|
|
9
10
|
|
|
@@ -210,6 +211,16 @@ class BrowserManager {
|
|
|
210
211
|
* resulting backendNodeId.
|
|
211
212
|
*/
|
|
212
213
|
private snapshotBackendNodeMaps = new Map<string, Map<string, number>>();
|
|
214
|
+
/**
|
|
215
|
+
* The CDP backend kind that a conversation resolved to on an earlier
|
|
216
|
+
* tool call. When a subsequent browser_* call arrives with
|
|
217
|
+
* `browser_mode: "auto"`, the factory is pinned to this kind so
|
|
218
|
+
* navigate and screenshot cannot land on different Chromes within
|
|
219
|
+
* the same conversation. Explicit non-auto modes overwrite the entry.
|
|
220
|
+
* Cleared when the conversation's page is closed or all pages are
|
|
221
|
+
* closed.
|
|
222
|
+
*/
|
|
223
|
+
private preferredBackendKinds = new Map<string, CdpClientKind>();
|
|
213
224
|
private browserCdpSession: CDPSession | null = null;
|
|
214
225
|
private browserWindowId: number | null = null;
|
|
215
226
|
private interactiveModeSessions = new Set<string>();
|
|
@@ -444,6 +455,7 @@ class BrowserManager {
|
|
|
444
455
|
this.pages.delete(conversationId);
|
|
445
456
|
this.rawPages.delete(conversationId);
|
|
446
457
|
this.snapshotBackendNodeMaps.delete(conversationId);
|
|
458
|
+
this.preferredBackendKinds.delete(conversationId);
|
|
447
459
|
this.downloads.delete(conversationId);
|
|
448
460
|
// Reject any pending download waiters
|
|
449
461
|
const pending = this.pendingDownloads.get(conversationId);
|
|
@@ -477,6 +489,7 @@ class BrowserManager {
|
|
|
477
489
|
this.pages.clear();
|
|
478
490
|
this.rawPages.clear();
|
|
479
491
|
this.snapshotBackendNodeMaps.clear();
|
|
492
|
+
this.preferredBackendKinds.clear();
|
|
480
493
|
this.downloads.clear();
|
|
481
494
|
for (const pending of this.pendingDownloads.values()) {
|
|
482
495
|
for (const waiter of pending) waiter.reject(new Error("Browser closed"));
|
|
@@ -532,6 +545,38 @@ class BrowserManager {
|
|
|
532
545
|
}
|
|
533
546
|
}
|
|
534
547
|
|
|
548
|
+
/**
|
|
549
|
+
* Look up the backend kind this conversation has been using. Returns
|
|
550
|
+
* `null` before the first successful CDP send or after an explicit
|
|
551
|
+
* teardown. Callers should pass the result to the factory as a
|
|
552
|
+
* pinned mode so `auto`-mode calls stay consistent across tool
|
|
553
|
+
* invocations.
|
|
554
|
+
*/
|
|
555
|
+
getPreferredBackendKind(conversationId: string): CdpClientKind | null {
|
|
556
|
+
return this.preferredBackendKinds.get(conversationId) ?? null;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/**
|
|
560
|
+
* Record the backend kind that a tool call resolved to. Overwrites
|
|
561
|
+
* any prior value so an explicit `browser_mode` override on one call
|
|
562
|
+
* becomes the default for subsequent `auto`-mode calls.
|
|
563
|
+
*/
|
|
564
|
+
setPreferredBackendKind(
|
|
565
|
+
conversationId: string,
|
|
566
|
+
kind: CdpClientKind,
|
|
567
|
+
): void {
|
|
568
|
+
this.preferredBackendKinds.set(conversationId, kind);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
/**
|
|
572
|
+
* Drop the remembered backend kind for a conversation. Called on
|
|
573
|
+
* explicit teardown (browser_close, closeAllPages) so the next call
|
|
574
|
+
* re-runs the auto priority list.
|
|
575
|
+
*/
|
|
576
|
+
clearPreferredBackendKind(conversationId: string): void {
|
|
577
|
+
this.preferredBackendKinds.delete(conversationId);
|
|
578
|
+
}
|
|
579
|
+
|
|
535
580
|
/**
|
|
536
581
|
* Store the backendNodeId lookup produced by the AX-tree-based
|
|
537
582
|
* `executeBrowserSnapshot`. Callers overwrite any prior map for the
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { BrowserMode } from "./cdp-client/types.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Canonical browser-mode identifiers shared across parsing and status
|
|
5
|
+
* reporting paths.
|
|
6
|
+
*/
|
|
7
|
+
export const BROWSER_MODE = {
|
|
8
|
+
AUTO: "auto",
|
|
9
|
+
EXTENSION: "extension",
|
|
10
|
+
CDP_INSPECT: "cdp-inspect",
|
|
11
|
+
LOCAL: "local",
|
|
12
|
+
} as const satisfies Record<string, BrowserMode>;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalization helper for the `browser_mode` tool input parameter.
|
|
3
|
+
*
|
|
4
|
+
* Canonical values map directly to {@link CdpClientKind}:
|
|
5
|
+
* - `auto` -- let the factory pick the best backend (default)
|
|
6
|
+
* - `extension` -- force the Chrome extension transport
|
|
7
|
+
* - `cdp-inspect` -- force the CDP inspect/debugger transport
|
|
8
|
+
* - `local` -- force the Playwright-managed local browser
|
|
9
|
+
*
|
|
10
|
+
* Aliases are accepted and normalized to their canonical form:
|
|
11
|
+
* - `cdp-debugger` -> `cdp-inspect`
|
|
12
|
+
* - `playwright` -> `local`
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { BROWSER_MODE } from "./browser-mode-constants.js";
|
|
16
|
+
import type { BrowserMode } from "./cdp-client/types.js";
|
|
17
|
+
|
|
18
|
+
/** Canonical browser mode values. Re-exported from cdp-client/types. */
|
|
19
|
+
export type { BrowserMode } from "./cdp-client/types.js";
|
|
20
|
+
|
|
21
|
+
/** All accepted values (canonical + aliases). */
|
|
22
|
+
const ALIAS_MAP: Record<string, BrowserMode> = {
|
|
23
|
+
[BROWSER_MODE.AUTO]: BROWSER_MODE.AUTO,
|
|
24
|
+
[BROWSER_MODE.EXTENSION]: BROWSER_MODE.EXTENSION,
|
|
25
|
+
[BROWSER_MODE.CDP_INSPECT]: BROWSER_MODE.CDP_INSPECT,
|
|
26
|
+
"cdp-debugger": BROWSER_MODE.CDP_INSPECT,
|
|
27
|
+
[BROWSER_MODE.LOCAL]: BROWSER_MODE.LOCAL,
|
|
28
|
+
playwright: BROWSER_MODE.LOCAL,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/** Ordered list of accepted values for error messages. */
|
|
32
|
+
const ACCEPTED_VALUES = Object.keys(ALIAS_MAP);
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Human-readable alias mapping for error messages.
|
|
36
|
+
* Only includes entries where the alias differs from the canonical value.
|
|
37
|
+
*/
|
|
38
|
+
const ALIAS_DISPLAY: Record<string, string> = {
|
|
39
|
+
"cdp-debugger": "cdp-inspect",
|
|
40
|
+
playwright: "local",
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export interface NormalizeBrowserModeResult {
|
|
44
|
+
/** The normalized canonical mode. */
|
|
45
|
+
mode: BrowserMode;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface NormalizeBrowserModeError {
|
|
49
|
+
/** Deterministic error message describing the invalid value. */
|
|
50
|
+
error: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Normalize a raw `browser_mode` input value to a canonical {@link BrowserMode}.
|
|
55
|
+
*
|
|
56
|
+
* - `undefined` / `null` / empty string -> `{ mode: "auto" }`
|
|
57
|
+
* - Valid canonical value or alias -> `{ mode: <canonical> }`
|
|
58
|
+
* - Invalid value -> `{ error: "..." }` with accepted list and alias mapping
|
|
59
|
+
*/
|
|
60
|
+
export function normalizeBrowserMode(
|
|
61
|
+
raw: unknown,
|
|
62
|
+
): NormalizeBrowserModeResult | NormalizeBrowserModeError {
|
|
63
|
+
if (raw === undefined || raw === null || raw === "") {
|
|
64
|
+
return { mode: BROWSER_MODE.AUTO };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (typeof raw !== "string") {
|
|
68
|
+
return buildError(String(raw));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const lower = raw.toLowerCase().trim();
|
|
72
|
+
const canonical = ALIAS_MAP[lower];
|
|
73
|
+
|
|
74
|
+
if (canonical !== undefined) {
|
|
75
|
+
return { mode: canonical };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return buildError(raw);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function buildError(value: string): NormalizeBrowserModeError {
|
|
82
|
+
const aliasHints = Object.entries(ALIAS_DISPLAY)
|
|
83
|
+
.map(([alias, canonical]) => `${alias}->${canonical}`)
|
|
84
|
+
.join(", ");
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
error:
|
|
88
|
+
`Invalid browser_mode "${value}". ` +
|
|
89
|
+
`Accepted values: ${ACCEPTED_VALUES.join(", ")}. ` +
|
|
90
|
+
`Aliases: ${aliasHints}.`,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { BROWSER_MODE } from "./browser-mode-constants.js";
|
|
2
|
+
import { DEVTOOLS_DISCOVERY_CODE } from "./cdp-client/cdp-inspect/discovery.js";
|
|
3
|
+
|
|
4
|
+
export const BROWSER_STATUS_MODE = {
|
|
5
|
+
EXTENSION: BROWSER_MODE.EXTENSION,
|
|
6
|
+
CDP_INSPECT: BROWSER_MODE.CDP_INSPECT,
|
|
7
|
+
LOCAL: BROWSER_MODE.LOCAL,
|
|
8
|
+
} as const;
|
|
9
|
+
|
|
10
|
+
export type BrowserStatusMode =
|
|
11
|
+
(typeof BROWSER_STATUS_MODE)[keyof typeof BROWSER_STATUS_MODE];
|
|
12
|
+
|
|
13
|
+
export const BROWSER_STATUS_MODES: readonly BrowserStatusMode[] = [
|
|
14
|
+
BROWSER_STATUS_MODE.EXTENSION,
|
|
15
|
+
BROWSER_STATUS_MODE.CDP_INSPECT,
|
|
16
|
+
BROWSER_STATUS_MODE.LOCAL,
|
|
17
|
+
] as const;
|
|
18
|
+
|
|
19
|
+
export const BROWSER_STATUS_INPUT_FIELD = {
|
|
20
|
+
CHECK_LOCAL_LAUNCH: "check_local_launch",
|
|
21
|
+
} as const;
|
|
22
|
+
|
|
23
|
+
export const EXTENSION_STATUS_ERROR_MARKER = {
|
|
24
|
+
UNAUTHORIZED_ORIGIN: "unauthorized_origin",
|
|
25
|
+
NATIVE_MESSAGING_HOST: "native messaging host",
|
|
26
|
+
HTTP_401: "401",
|
|
27
|
+
} as const;
|
|
28
|
+
|
|
29
|
+
export const CDP_INSPECT_STATUS_DISCOVERY_CODE = {
|
|
30
|
+
NO_TARGETS: DEVTOOLS_DISCOVERY_CODE.NO_TARGETS,
|
|
31
|
+
INVALID_RESPONSE: DEVTOOLS_DISCOVERY_CODE.INVALID_RESPONSE,
|
|
32
|
+
WS_FALLBACK_FAILED: DEVTOOLS_DISCOVERY_CODE.WS_FALLBACK_FAILED,
|
|
33
|
+
} as const;
|
|
@@ -16,6 +16,7 @@ const { CdpInspectClient, createCdpInspectClient } =
|
|
|
16
16
|
await import("../cdp-inspect-client.js");
|
|
17
17
|
const { CdpError } = await import("../errors.js");
|
|
18
18
|
const { CdpWsTransportError } = await import("../cdp-inspect/ws-transport.js");
|
|
19
|
+
const { DevToolsDiscoveryError } = await import("../cdp-inspect/discovery.js");
|
|
19
20
|
|
|
20
21
|
type CdpInspectClientInstance = InstanceType<typeof CdpInspectClient>;
|
|
21
22
|
|
|
@@ -868,3 +869,395 @@ describe("CdpInspectClient", () => {
|
|
|
868
869
|
expect(harness.attachCallCount()).toBe(1);
|
|
869
870
|
});
|
|
870
871
|
});
|
|
872
|
+
|
|
873
|
+
// ---------------------------------------------------------------------------
|
|
874
|
+
// WS-only fallback — HTTP discovery absent, WS fallback succeeds.
|
|
875
|
+
// ---------------------------------------------------------------------------
|
|
876
|
+
|
|
877
|
+
describe("CdpInspectClient — WS-only fallback", () => {
|
|
878
|
+
test("falls back to WS when HTTP discovery returns invalid_response", async () => {
|
|
879
|
+
const sends: Array<{
|
|
880
|
+
method: string;
|
|
881
|
+
params?: Record<string, unknown>;
|
|
882
|
+
sessionId?: string;
|
|
883
|
+
}> = [];
|
|
884
|
+
let connectCount = 0;
|
|
885
|
+
let discoverViaWsCalls = 0;
|
|
886
|
+
|
|
887
|
+
const client = createCdpInspectClient("conv-ws-fallback", {
|
|
888
|
+
host: "127.0.0.1",
|
|
889
|
+
port: 9222,
|
|
890
|
+
discoveryTimeoutMs: 100,
|
|
891
|
+
wsConnectTimeoutMs: 100,
|
|
892
|
+
helpers: {
|
|
893
|
+
probeDevToolsJsonVersion: async () => {
|
|
894
|
+
throw new DevToolsDiscoveryError(
|
|
895
|
+
"invalid_response",
|
|
896
|
+
"DevTools /json/version returned HTTP 404.",
|
|
897
|
+
);
|
|
898
|
+
},
|
|
899
|
+
listDevToolsTargets: async () => {
|
|
900
|
+
throw new Error("listDevToolsTargets should not be called");
|
|
901
|
+
},
|
|
902
|
+
connectCdpWsTransport: async () => {
|
|
903
|
+
connectCount += 1;
|
|
904
|
+
return createFakeTransport({
|
|
905
|
+
onSend: async (method) => {
|
|
906
|
+
if (method === "Target.attachToTarget") {
|
|
907
|
+
return { sessionId: "ws-session" };
|
|
908
|
+
}
|
|
909
|
+
return { ok: true };
|
|
910
|
+
},
|
|
911
|
+
trackSends: sends,
|
|
912
|
+
});
|
|
913
|
+
},
|
|
914
|
+
discoverTargetsViaWs: async () => {
|
|
915
|
+
discoverViaWsCalls += 1;
|
|
916
|
+
return [
|
|
917
|
+
{
|
|
918
|
+
id: "ws-target-1",
|
|
919
|
+
type: "page",
|
|
920
|
+
title: "WS Page",
|
|
921
|
+
url: "https://example.com/",
|
|
922
|
+
webSocketDebuggerUrl:
|
|
923
|
+
"ws://127.0.0.1:9222/devtools/page/ws-target-1",
|
|
924
|
+
},
|
|
925
|
+
];
|
|
926
|
+
},
|
|
927
|
+
buildBrowserWsUrl: (host: string, port: number) =>
|
|
928
|
+
`ws://${host}:${port}/devtools/browser`,
|
|
929
|
+
},
|
|
930
|
+
});
|
|
931
|
+
|
|
932
|
+
const result = await client.send<{ ok: boolean }>("Browser.getVersion");
|
|
933
|
+
expect(result).toEqual({ ok: true });
|
|
934
|
+
expect(connectCount).toBe(1);
|
|
935
|
+
expect(discoverViaWsCalls).toBe(1);
|
|
936
|
+
// attach + forwarded call
|
|
937
|
+
expect(sends).toEqual([
|
|
938
|
+
{
|
|
939
|
+
method: "Target.attachToTarget",
|
|
940
|
+
params: { targetId: "ws-target-1", flatten: true },
|
|
941
|
+
sessionId: undefined,
|
|
942
|
+
},
|
|
943
|
+
{
|
|
944
|
+
method: "Browser.getVersion",
|
|
945
|
+
params: undefined,
|
|
946
|
+
sessionId: "ws-session",
|
|
947
|
+
},
|
|
948
|
+
]);
|
|
949
|
+
});
|
|
950
|
+
|
|
951
|
+
test("falls back to WS when HTTP discovery is unreachable", async () => {
|
|
952
|
+
let discoverViaWsCalls = 0;
|
|
953
|
+
|
|
954
|
+
const client = createCdpInspectClient("conv-ws-unreachable", {
|
|
955
|
+
host: "127.0.0.1",
|
|
956
|
+
port: 9222,
|
|
957
|
+
discoveryTimeoutMs: 100,
|
|
958
|
+
helpers: {
|
|
959
|
+
probeDevToolsJsonVersion: async () => {
|
|
960
|
+
throw new DevToolsDiscoveryError(
|
|
961
|
+
"unreachable",
|
|
962
|
+
"Failed to reach DevTools endpoint: ECONNREFUSED",
|
|
963
|
+
);
|
|
964
|
+
},
|
|
965
|
+
listDevToolsTargets: async () => {
|
|
966
|
+
throw new Error("should not be called");
|
|
967
|
+
},
|
|
968
|
+
connectCdpWsTransport: async () =>
|
|
969
|
+
createFakeTransport({
|
|
970
|
+
onSend: async (method) => {
|
|
971
|
+
if (method === "Target.attachToTarget") {
|
|
972
|
+
return { sessionId: "ws-session" };
|
|
973
|
+
}
|
|
974
|
+
return { ok: true };
|
|
975
|
+
},
|
|
976
|
+
}),
|
|
977
|
+
discoverTargetsViaWs: async () => {
|
|
978
|
+
discoverViaWsCalls += 1;
|
|
979
|
+
return [
|
|
980
|
+
{
|
|
981
|
+
id: "ws-target-1",
|
|
982
|
+
type: "page",
|
|
983
|
+
title: "Page",
|
|
984
|
+
url: "https://example.com/",
|
|
985
|
+
webSocketDebuggerUrl:
|
|
986
|
+
"ws://127.0.0.1:9222/devtools/page/ws-target-1",
|
|
987
|
+
},
|
|
988
|
+
];
|
|
989
|
+
},
|
|
990
|
+
buildBrowserWsUrl: (host: string, port: number) =>
|
|
991
|
+
`ws://${host}:${port}/devtools/browser`,
|
|
992
|
+
},
|
|
993
|
+
});
|
|
994
|
+
|
|
995
|
+
const result = await client.send<{ ok: boolean }>("Runtime.enable");
|
|
996
|
+
expect(result).toEqual({ ok: true });
|
|
997
|
+
expect(discoverViaWsCalls).toBe(1);
|
|
998
|
+
});
|
|
999
|
+
|
|
1000
|
+
test("does NOT fall back to WS on non_loopback error (safety constraint)", async () => {
|
|
1001
|
+
let connectCalled = false;
|
|
1002
|
+
|
|
1003
|
+
const client = createCdpInspectClient("conv-no-fallback-loopback", {
|
|
1004
|
+
host: "127.0.0.1",
|
|
1005
|
+
port: 9222,
|
|
1006
|
+
discoveryTimeoutMs: 100,
|
|
1007
|
+
helpers: {
|
|
1008
|
+
probeDevToolsJsonVersion: async () => {
|
|
1009
|
+
throw new DevToolsDiscoveryError(
|
|
1010
|
+
"non_loopback",
|
|
1011
|
+
"Refusing to probe non-loopback host",
|
|
1012
|
+
);
|
|
1013
|
+
},
|
|
1014
|
+
listDevToolsTargets: async () => {
|
|
1015
|
+
throw new Error("should not be called");
|
|
1016
|
+
},
|
|
1017
|
+
connectCdpWsTransport: async () => {
|
|
1018
|
+
connectCalled = true;
|
|
1019
|
+
return createFakeTransport({});
|
|
1020
|
+
},
|
|
1021
|
+
discoverTargetsViaWs: async () => {
|
|
1022
|
+
throw new Error("should not be called");
|
|
1023
|
+
},
|
|
1024
|
+
buildBrowserWsUrl: () => "ws://127.0.0.1:9222/devtools/browser",
|
|
1025
|
+
},
|
|
1026
|
+
});
|
|
1027
|
+
|
|
1028
|
+
let caught: unknown;
|
|
1029
|
+
try {
|
|
1030
|
+
await client.send("Browser.getVersion");
|
|
1031
|
+
} catch (err) {
|
|
1032
|
+
caught = err;
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
expect(caught).toBeInstanceOf(CdpError);
|
|
1036
|
+
const cdpErr = caught as InstanceType<typeof CdpError>;
|
|
1037
|
+
expect(cdpErr.code).toBe("transport_error");
|
|
1038
|
+
expect(cdpErr.message).toContain("non-loopback");
|
|
1039
|
+
expect(connectCalled).toBe(false);
|
|
1040
|
+
});
|
|
1041
|
+
|
|
1042
|
+
test("does NOT fall back to WS on non_chrome error", async () => {
|
|
1043
|
+
let connectCalled = false;
|
|
1044
|
+
|
|
1045
|
+
const client = createCdpInspectClient("conv-no-fallback-chrome", {
|
|
1046
|
+
host: "127.0.0.1",
|
|
1047
|
+
port: 9222,
|
|
1048
|
+
discoveryTimeoutMs: 100,
|
|
1049
|
+
helpers: {
|
|
1050
|
+
probeDevToolsJsonVersion: async () => {
|
|
1051
|
+
throw new DevToolsDiscoveryError(
|
|
1052
|
+
"non_chrome",
|
|
1053
|
+
"Not Chrome: Firefox/115.0",
|
|
1054
|
+
);
|
|
1055
|
+
},
|
|
1056
|
+
listDevToolsTargets: async () => {
|
|
1057
|
+
throw new Error("should not be called");
|
|
1058
|
+
},
|
|
1059
|
+
connectCdpWsTransport: async () => {
|
|
1060
|
+
connectCalled = true;
|
|
1061
|
+
return createFakeTransport({});
|
|
1062
|
+
},
|
|
1063
|
+
discoverTargetsViaWs: async () => {
|
|
1064
|
+
throw new Error("should not be called");
|
|
1065
|
+
},
|
|
1066
|
+
buildBrowserWsUrl: () => "ws://127.0.0.1:9222/devtools/browser",
|
|
1067
|
+
},
|
|
1068
|
+
});
|
|
1069
|
+
|
|
1070
|
+
let caught: unknown;
|
|
1071
|
+
try {
|
|
1072
|
+
await client.send("Browser.getVersion");
|
|
1073
|
+
} catch (err) {
|
|
1074
|
+
caught = err;
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
expect(caught).toBeInstanceOf(CdpError);
|
|
1078
|
+
const cdpErr = caught as InstanceType<typeof CdpError>;
|
|
1079
|
+
expect(cdpErr.code).toBe("transport_error");
|
|
1080
|
+
expect(connectCalled).toBe(false);
|
|
1081
|
+
});
|
|
1082
|
+
|
|
1083
|
+
test("does NOT fall back to WS on timeout error", async () => {
|
|
1084
|
+
let connectCalled = false;
|
|
1085
|
+
|
|
1086
|
+
const client = createCdpInspectClient("conv-no-fallback-timeout", {
|
|
1087
|
+
host: "127.0.0.1",
|
|
1088
|
+
port: 9222,
|
|
1089
|
+
discoveryTimeoutMs: 100,
|
|
1090
|
+
helpers: {
|
|
1091
|
+
probeDevToolsJsonVersion: async () => {
|
|
1092
|
+
throw new DevToolsDiscoveryError(
|
|
1093
|
+
"timeout",
|
|
1094
|
+
"Timed out waiting for DevTools HTTP response.",
|
|
1095
|
+
);
|
|
1096
|
+
},
|
|
1097
|
+
listDevToolsTargets: async () => {
|
|
1098
|
+
throw new Error("should not be called");
|
|
1099
|
+
},
|
|
1100
|
+
connectCdpWsTransport: async () => {
|
|
1101
|
+
connectCalled = true;
|
|
1102
|
+
return createFakeTransport({});
|
|
1103
|
+
},
|
|
1104
|
+
discoverTargetsViaWs: async () => {
|
|
1105
|
+
throw new Error("should not be called");
|
|
1106
|
+
},
|
|
1107
|
+
buildBrowserWsUrl: () => "ws://127.0.0.1:9222/devtools/browser",
|
|
1108
|
+
},
|
|
1109
|
+
});
|
|
1110
|
+
|
|
1111
|
+
let caught: unknown;
|
|
1112
|
+
try {
|
|
1113
|
+
await client.send("Browser.getVersion");
|
|
1114
|
+
} catch (err) {
|
|
1115
|
+
caught = err;
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
expect(caught).toBeInstanceOf(CdpError);
|
|
1119
|
+
const cdpErr = caught as InstanceType<typeof CdpError>;
|
|
1120
|
+
expect(cdpErr.code).toBe("transport_error");
|
|
1121
|
+
expect(connectCalled).toBe(false);
|
|
1122
|
+
});
|
|
1123
|
+
|
|
1124
|
+
test("full fallback failure: HTTP invalid_response + WS connect fails", async () => {
|
|
1125
|
+
const client = createCdpInspectClient("conv-full-fail", {
|
|
1126
|
+
host: "127.0.0.1",
|
|
1127
|
+
port: 9222,
|
|
1128
|
+
discoveryTimeoutMs: 100,
|
|
1129
|
+
helpers: {
|
|
1130
|
+
probeDevToolsJsonVersion: async () => {
|
|
1131
|
+
throw new DevToolsDiscoveryError(
|
|
1132
|
+
"invalid_response",
|
|
1133
|
+
"DevTools /json/version returned HTTP 404.",
|
|
1134
|
+
);
|
|
1135
|
+
},
|
|
1136
|
+
listDevToolsTargets: async () => {
|
|
1137
|
+
throw new Error("should not be called");
|
|
1138
|
+
},
|
|
1139
|
+
connectCdpWsTransport: async () => {
|
|
1140
|
+
throw new CdpWsTransportError(
|
|
1141
|
+
"transport_error",
|
|
1142
|
+
"websocket closed before open",
|
|
1143
|
+
);
|
|
1144
|
+
},
|
|
1145
|
+
discoverTargetsViaWs: async () => {
|
|
1146
|
+
throw new Error("should not be called");
|
|
1147
|
+
},
|
|
1148
|
+
buildBrowserWsUrl: (host: string, port: number) =>
|
|
1149
|
+
`ws://${host}:${port}/devtools/browser`,
|
|
1150
|
+
},
|
|
1151
|
+
});
|
|
1152
|
+
|
|
1153
|
+
let caught: unknown;
|
|
1154
|
+
try {
|
|
1155
|
+
await client.send("Browser.getVersion");
|
|
1156
|
+
} catch (err) {
|
|
1157
|
+
caught = err;
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
expect(caught).toBeInstanceOf(CdpError);
|
|
1161
|
+
const cdpErr = caught as InstanceType<typeof CdpError>;
|
|
1162
|
+
expect(cdpErr.code).toBe("transport_error");
|
|
1163
|
+
// Error message should explain both HTTP and WS failures
|
|
1164
|
+
expect(cdpErr.message).toContain("HTTP discovery failed");
|
|
1165
|
+
expect(cdpErr.message).toContain("WS-only fallback also failed");
|
|
1166
|
+
expect(cdpErr.message).toContain("127.0.0.1:9222");
|
|
1167
|
+
});
|
|
1168
|
+
|
|
1169
|
+
test("WS fallback: no page targets yields stable error", async () => {
|
|
1170
|
+
const client = createCdpInspectClient("conv-ws-no-targets", {
|
|
1171
|
+
host: "127.0.0.1",
|
|
1172
|
+
port: 9222,
|
|
1173
|
+
discoveryTimeoutMs: 100,
|
|
1174
|
+
helpers: {
|
|
1175
|
+
probeDevToolsJsonVersion: async () => {
|
|
1176
|
+
throw new DevToolsDiscoveryError("unreachable", "ECONNREFUSED");
|
|
1177
|
+
},
|
|
1178
|
+
listDevToolsTargets: async () => {
|
|
1179
|
+
throw new Error("should not be called");
|
|
1180
|
+
},
|
|
1181
|
+
connectCdpWsTransport: async () =>
|
|
1182
|
+
createFakeTransport({
|
|
1183
|
+
onSend: async () => ({ ok: true }),
|
|
1184
|
+
}),
|
|
1185
|
+
discoverTargetsViaWs: async () => {
|
|
1186
|
+
throw new DevToolsDiscoveryError(
|
|
1187
|
+
"no_targets",
|
|
1188
|
+
"No usable page targets returned by CDP Target.getTargets.",
|
|
1189
|
+
);
|
|
1190
|
+
},
|
|
1191
|
+
buildBrowserWsUrl: (host: string, port: number) =>
|
|
1192
|
+
`ws://${host}:${port}/devtools/browser`,
|
|
1193
|
+
},
|
|
1194
|
+
});
|
|
1195
|
+
|
|
1196
|
+
let caught: unknown;
|
|
1197
|
+
try {
|
|
1198
|
+
await client.send("Browser.getVersion");
|
|
1199
|
+
} catch (err) {
|
|
1200
|
+
caught = err;
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
expect(caught).toBeInstanceOf(CdpError);
|
|
1204
|
+
const cdpErr = caught as InstanceType<typeof CdpError>;
|
|
1205
|
+
expect(cdpErr.code).toBe("transport_error");
|
|
1206
|
+
expect(cdpErr.message).toContain("No usable page targets");
|
|
1207
|
+
});
|
|
1208
|
+
|
|
1209
|
+
test("WS fallback caches session for subsequent calls", async () => {
|
|
1210
|
+
let connectCount = 0;
|
|
1211
|
+
let discoverViaWsCalls = 0;
|
|
1212
|
+
|
|
1213
|
+
const client = createCdpInspectClient("conv-ws-cache", {
|
|
1214
|
+
host: "127.0.0.1",
|
|
1215
|
+
port: 9222,
|
|
1216
|
+
discoveryTimeoutMs: 100,
|
|
1217
|
+
helpers: {
|
|
1218
|
+
probeDevToolsJsonVersion: async () => {
|
|
1219
|
+
throw new DevToolsDiscoveryError(
|
|
1220
|
+
"invalid_response",
|
|
1221
|
+
"no HTTP discovery",
|
|
1222
|
+
);
|
|
1223
|
+
},
|
|
1224
|
+
listDevToolsTargets: async () => {
|
|
1225
|
+
throw new Error("should not be called");
|
|
1226
|
+
},
|
|
1227
|
+
connectCdpWsTransport: async () => {
|
|
1228
|
+
connectCount += 1;
|
|
1229
|
+
return createFakeTransport({
|
|
1230
|
+
onSend: async (method) => {
|
|
1231
|
+
if (method === "Target.attachToTarget") {
|
|
1232
|
+
return { sessionId: "ws-session-cached" };
|
|
1233
|
+
}
|
|
1234
|
+
return { ok: true };
|
|
1235
|
+
},
|
|
1236
|
+
});
|
|
1237
|
+
},
|
|
1238
|
+
discoverTargetsViaWs: async () => {
|
|
1239
|
+
discoverViaWsCalls += 1;
|
|
1240
|
+
return [
|
|
1241
|
+
{
|
|
1242
|
+
id: "t1",
|
|
1243
|
+
type: "page",
|
|
1244
|
+
title: "Page",
|
|
1245
|
+
url: "https://example.com/",
|
|
1246
|
+
webSocketDebuggerUrl: "ws://127.0.0.1:9222/devtools/page/t1",
|
|
1247
|
+
},
|
|
1248
|
+
];
|
|
1249
|
+
},
|
|
1250
|
+
buildBrowserWsUrl: (host: string, port: number) =>
|
|
1251
|
+
`ws://${host}:${port}/devtools/browser`,
|
|
1252
|
+
},
|
|
1253
|
+
});
|
|
1254
|
+
|
|
1255
|
+
await client.send("Runtime.enable");
|
|
1256
|
+
await client.send("Page.enable");
|
|
1257
|
+
await client.send("DOM.enable");
|
|
1258
|
+
|
|
1259
|
+
// Only one WS fallback discovery + one connect + one attach
|
|
1260
|
+
expect(connectCount).toBe(1);
|
|
1261
|
+
expect(discoverViaWsCalls).toBe(1);
|
|
1262
|
+
});
|
|
1263
|
+
});
|
|
@@ -185,6 +185,35 @@ describe("ExtensionCdpClient", () => {
|
|
|
185
185
|
expect(err.underlying).toBeInstanceOf(Error);
|
|
186
186
|
});
|
|
187
187
|
|
|
188
|
+
test("result.isError with non-JSON content throws CdpError('cdp_error')", async () => {
|
|
189
|
+
const { proxy } = fakeProxy(async () => ({
|
|
190
|
+
content:
|
|
191
|
+
"Host browser proxy timed out waiting for extension response (check callback failures).",
|
|
192
|
+
isError: true,
|
|
193
|
+
}));
|
|
194
|
+
|
|
195
|
+
const client = createExtensionCdpClient(proxy, "conv-6b");
|
|
196
|
+
|
|
197
|
+
let caught: unknown;
|
|
198
|
+
try {
|
|
199
|
+
await client.send("Runtime.evaluate", { expression: "document.title" });
|
|
200
|
+
} catch (err) {
|
|
201
|
+
caught = err;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
expect(caught).toBeInstanceOf(CdpError);
|
|
205
|
+
const err = caught as CdpError;
|
|
206
|
+
expect(err.code).toBe("cdp_error");
|
|
207
|
+
expect(err.message).toContain(
|
|
208
|
+
"Host browser proxy timed out waiting for extension response",
|
|
209
|
+
);
|
|
210
|
+
expect(err.cdpMethod).toBe("Runtime.evaluate");
|
|
211
|
+
expect(err.cdpParams).toEqual({ expression: "document.title" });
|
|
212
|
+
expect(err.underlying).toBe(
|
|
213
|
+
"Host browser proxy timed out waiting for extension response (check callback failures).",
|
|
214
|
+
);
|
|
215
|
+
});
|
|
216
|
+
|
|
188
217
|
test("result.content === 'Aborted' throws CdpError('aborted')", async () => {
|
|
189
218
|
const { proxy, request } = fakeProxy(async () => ({
|
|
190
219
|
content: "Aborted",
|