@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
|
@@ -9,8 +9,11 @@
|
|
|
9
9
|
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
10
10
|
|
|
11
11
|
import {
|
|
12
|
+
buildBrowserWsUrl,
|
|
12
13
|
DevToolsDiscoveryError,
|
|
13
14
|
type DevToolsTarget,
|
|
15
|
+
discoverTargetsViaWs,
|
|
16
|
+
isHttpDiscoveryFallbackEligible,
|
|
14
17
|
listDevToolsTargets,
|
|
15
18
|
pickDefaultTarget,
|
|
16
19
|
probeDevToolsJsonVersion,
|
|
@@ -741,3 +744,264 @@ describe("pickDefaultTarget", () => {
|
|
|
741
744
|
expect(pickDefaultTarget(targets).id).toBe("only");
|
|
742
745
|
});
|
|
743
746
|
});
|
|
747
|
+
|
|
748
|
+
// ---------------------------------------------------------------------------
|
|
749
|
+
// buildBrowserWsUrl — loopback enforcement and URL construction.
|
|
750
|
+
// ---------------------------------------------------------------------------
|
|
751
|
+
|
|
752
|
+
describe("buildBrowserWsUrl", () => {
|
|
753
|
+
test("builds ws URL for localhost", () => {
|
|
754
|
+
expect(buildBrowserWsUrl("localhost", 9222)).toBe(
|
|
755
|
+
"ws://localhost:9222/devtools/browser",
|
|
756
|
+
);
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
test("builds ws URL for 127.0.0.1", () => {
|
|
760
|
+
expect(buildBrowserWsUrl("127.0.0.1", 9333)).toBe(
|
|
761
|
+
"ws://127.0.0.1:9333/devtools/browser",
|
|
762
|
+
);
|
|
763
|
+
});
|
|
764
|
+
|
|
765
|
+
test("wraps bare ::1 in brackets", () => {
|
|
766
|
+
expect(buildBrowserWsUrl("::1", 9222)).toBe(
|
|
767
|
+
"ws://[::1]:9222/devtools/browser",
|
|
768
|
+
);
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
test("accepts [::1] (already bracketed)", () => {
|
|
772
|
+
expect(buildBrowserWsUrl("[::1]", 9222)).toBe(
|
|
773
|
+
"ws://[::1]:9222/devtools/browser",
|
|
774
|
+
);
|
|
775
|
+
});
|
|
776
|
+
|
|
777
|
+
test("is case-insensitive for LOCALHOST", () => {
|
|
778
|
+
expect(buildBrowserWsUrl("LOCALHOST", 9222)).toBe(
|
|
779
|
+
"ws://localhost:9222/devtools/browser",
|
|
780
|
+
);
|
|
781
|
+
});
|
|
782
|
+
|
|
783
|
+
test("rejects non-loopback hosts with non_loopback", () => {
|
|
784
|
+
expect(() => buildBrowserWsUrl("192.168.1.1", 9222)).toThrow(
|
|
785
|
+
DevToolsDiscoveryError,
|
|
786
|
+
);
|
|
787
|
+
try {
|
|
788
|
+
buildBrowserWsUrl("evil.com", 9222);
|
|
789
|
+
} catch (e) {
|
|
790
|
+
expect((e as DevToolsDiscoveryError).code).toBe("non_loopback");
|
|
791
|
+
}
|
|
792
|
+
});
|
|
793
|
+
});
|
|
794
|
+
|
|
795
|
+
// ---------------------------------------------------------------------------
|
|
796
|
+
// isHttpDiscoveryFallbackEligible — determines which errors trigger fallback.
|
|
797
|
+
// ---------------------------------------------------------------------------
|
|
798
|
+
|
|
799
|
+
describe("isHttpDiscoveryFallbackEligible", () => {
|
|
800
|
+
test("returns true for invalid_response", () => {
|
|
801
|
+
const err = new DevToolsDiscoveryError("invalid_response", "bad");
|
|
802
|
+
expect(isHttpDiscoveryFallbackEligible(err)).toBe(true);
|
|
803
|
+
});
|
|
804
|
+
|
|
805
|
+
test("returns true for unreachable", () => {
|
|
806
|
+
const err = new DevToolsDiscoveryError("unreachable", "gone");
|
|
807
|
+
expect(isHttpDiscoveryFallbackEligible(err)).toBe(true);
|
|
808
|
+
});
|
|
809
|
+
|
|
810
|
+
test("returns false for non_loopback", () => {
|
|
811
|
+
const err = new DevToolsDiscoveryError("non_loopback", "nope");
|
|
812
|
+
expect(isHttpDiscoveryFallbackEligible(err)).toBe(false);
|
|
813
|
+
});
|
|
814
|
+
|
|
815
|
+
test("returns false for non_chrome", () => {
|
|
816
|
+
const err = new DevToolsDiscoveryError("non_chrome", "Firefox");
|
|
817
|
+
expect(isHttpDiscoveryFallbackEligible(err)).toBe(false);
|
|
818
|
+
});
|
|
819
|
+
|
|
820
|
+
test("returns false for timeout", () => {
|
|
821
|
+
const err = new DevToolsDiscoveryError("timeout", "too slow");
|
|
822
|
+
expect(isHttpDiscoveryFallbackEligible(err)).toBe(false);
|
|
823
|
+
});
|
|
824
|
+
|
|
825
|
+
test("returns false for no_targets", () => {
|
|
826
|
+
const err = new DevToolsDiscoveryError("no_targets", "empty");
|
|
827
|
+
expect(isHttpDiscoveryFallbackEligible(err)).toBe(false);
|
|
828
|
+
});
|
|
829
|
+
|
|
830
|
+
test("returns false for non-DevToolsDiscoveryError", () => {
|
|
831
|
+
expect(isHttpDiscoveryFallbackEligible(new Error("random"))).toBe(false);
|
|
832
|
+
expect(isHttpDiscoveryFallbackEligible("string")).toBe(false);
|
|
833
|
+
expect(isHttpDiscoveryFallbackEligible(null)).toBe(false);
|
|
834
|
+
});
|
|
835
|
+
});
|
|
836
|
+
|
|
837
|
+
// ---------------------------------------------------------------------------
|
|
838
|
+
// discoverTargetsViaWs — target enumeration via CDP Target.getTargets.
|
|
839
|
+
// ---------------------------------------------------------------------------
|
|
840
|
+
|
|
841
|
+
describe("discoverTargetsViaWs", () => {
|
|
842
|
+
/**
|
|
843
|
+
* Minimal fake transport that resolves Target.getTargets with the
|
|
844
|
+
* provided target infos.
|
|
845
|
+
*/
|
|
846
|
+
function fakeTransport(targetInfos: unknown[]) {
|
|
847
|
+
return {
|
|
848
|
+
send: async () => ({ targetInfos }),
|
|
849
|
+
addEventListener: () => () => {},
|
|
850
|
+
dispose: () => {},
|
|
851
|
+
} as unknown as import("../../cdp-inspect/ws-transport.js").CdpWsTransport;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
test("filters page targets and constructs ws URLs", async () => {
|
|
855
|
+
const transport = fakeTransport([
|
|
856
|
+
{
|
|
857
|
+
targetId: "A",
|
|
858
|
+
type: "page",
|
|
859
|
+
title: "Example",
|
|
860
|
+
url: "https://example.com/",
|
|
861
|
+
},
|
|
862
|
+
{
|
|
863
|
+
targetId: "B",
|
|
864
|
+
type: "service_worker",
|
|
865
|
+
title: "sw",
|
|
866
|
+
url: "https://example.com/sw.js",
|
|
867
|
+
},
|
|
868
|
+
{
|
|
869
|
+
targetId: "C",
|
|
870
|
+
type: "page",
|
|
871
|
+
title: "Another",
|
|
872
|
+
url: "https://another.com/",
|
|
873
|
+
},
|
|
874
|
+
]);
|
|
875
|
+
|
|
876
|
+
const targets = await discoverTargetsViaWs({
|
|
877
|
+
transport,
|
|
878
|
+
host: "127.0.0.1",
|
|
879
|
+
port: 9222,
|
|
880
|
+
});
|
|
881
|
+
|
|
882
|
+
expect(targets).toHaveLength(2);
|
|
883
|
+
expect(targets[0]!.id).toBe("A");
|
|
884
|
+
expect(targets[0]!.webSocketDebuggerUrl).toBe(
|
|
885
|
+
"ws://127.0.0.1:9222/devtools/page/A",
|
|
886
|
+
);
|
|
887
|
+
expect(targets[1]!.id).toBe("C");
|
|
888
|
+
expect(targets[1]!.webSocketDebuggerUrl).toBe(
|
|
889
|
+
"ws://127.0.0.1:9222/devtools/page/C",
|
|
890
|
+
);
|
|
891
|
+
});
|
|
892
|
+
|
|
893
|
+
test("throws no_targets when no page targets exist", async () => {
|
|
894
|
+
const transport = fakeTransport([
|
|
895
|
+
{
|
|
896
|
+
targetId: "B",
|
|
897
|
+
type: "service_worker",
|
|
898
|
+
title: "sw",
|
|
899
|
+
url: "https://example.com/sw.js",
|
|
900
|
+
},
|
|
901
|
+
]);
|
|
902
|
+
|
|
903
|
+
const error = await discoverTargetsViaWs({
|
|
904
|
+
transport,
|
|
905
|
+
host: "127.0.0.1",
|
|
906
|
+
port: 9222,
|
|
907
|
+
}).catch((e: unknown) => e);
|
|
908
|
+
|
|
909
|
+
expect(error).toBeInstanceOf(DevToolsDiscoveryError);
|
|
910
|
+
expect((error as DevToolsDiscoveryError).code).toBe("no_targets");
|
|
911
|
+
});
|
|
912
|
+
|
|
913
|
+
test("throws no_targets when targetInfos is empty", async () => {
|
|
914
|
+
const transport = fakeTransport([]);
|
|
915
|
+
|
|
916
|
+
const error = await discoverTargetsViaWs({
|
|
917
|
+
transport,
|
|
918
|
+
host: "127.0.0.1",
|
|
919
|
+
port: 9222,
|
|
920
|
+
}).catch((e: unknown) => e);
|
|
921
|
+
|
|
922
|
+
expect(error).toBeInstanceOf(DevToolsDiscoveryError);
|
|
923
|
+
expect((error as DevToolsDiscoveryError).code).toBe("no_targets");
|
|
924
|
+
});
|
|
925
|
+
|
|
926
|
+
test("throws ws_fallback_failed when targetInfos is missing", async () => {
|
|
927
|
+
const transport = {
|
|
928
|
+
send: async () => ({}),
|
|
929
|
+
addEventListener: () => () => {},
|
|
930
|
+
dispose: () => {},
|
|
931
|
+
} as unknown as import("../../cdp-inspect/ws-transport.js").CdpWsTransport;
|
|
932
|
+
|
|
933
|
+
const error = await discoverTargetsViaWs({
|
|
934
|
+
transport,
|
|
935
|
+
host: "127.0.0.1",
|
|
936
|
+
port: 9222,
|
|
937
|
+
}).catch((e: unknown) => e);
|
|
938
|
+
|
|
939
|
+
expect(error).toBeInstanceOf(DevToolsDiscoveryError);
|
|
940
|
+
expect((error as DevToolsDiscoveryError).code).toBe("ws_fallback_failed");
|
|
941
|
+
});
|
|
942
|
+
|
|
943
|
+
test("rejects non-loopback host before calling transport", async () => {
|
|
944
|
+
let transportCalled = false;
|
|
945
|
+
const transport = {
|
|
946
|
+
send: async () => {
|
|
947
|
+
transportCalled = true;
|
|
948
|
+
return { targetInfos: [] };
|
|
949
|
+
},
|
|
950
|
+
addEventListener: () => () => {},
|
|
951
|
+
dispose: () => {},
|
|
952
|
+
} as unknown as import("../../cdp-inspect/ws-transport.js").CdpWsTransport;
|
|
953
|
+
|
|
954
|
+
const error = await discoverTargetsViaWs({
|
|
955
|
+
transport,
|
|
956
|
+
host: "evil.com",
|
|
957
|
+
port: 9222,
|
|
958
|
+
}).catch((e: unknown) => e);
|
|
959
|
+
|
|
960
|
+
expect(error).toBeInstanceOf(DevToolsDiscoveryError);
|
|
961
|
+
expect((error as DevToolsDiscoveryError).code).toBe("non_loopback");
|
|
962
|
+
expect(transportCalled).toBe(false);
|
|
963
|
+
});
|
|
964
|
+
|
|
965
|
+
test("skips entries with empty or missing targetId", async () => {
|
|
966
|
+
const transport = fakeTransport([
|
|
967
|
+
{ targetId: "", type: "page", title: "Empty ID", url: "https://a.com/" },
|
|
968
|
+
{ type: "page", title: "Missing ID", url: "https://b.com/" },
|
|
969
|
+
{
|
|
970
|
+
targetId: "valid",
|
|
971
|
+
type: "page",
|
|
972
|
+
title: "Valid",
|
|
973
|
+
url: "https://c.com/",
|
|
974
|
+
},
|
|
975
|
+
]);
|
|
976
|
+
|
|
977
|
+
const targets = await discoverTargetsViaWs({
|
|
978
|
+
transport,
|
|
979
|
+
host: "127.0.0.1",
|
|
980
|
+
port: 9222,
|
|
981
|
+
});
|
|
982
|
+
|
|
983
|
+
expect(targets).toHaveLength(1);
|
|
984
|
+
expect(targets[0]!.id).toBe("valid");
|
|
985
|
+
});
|
|
986
|
+
|
|
987
|
+
test("constructs IPv6 ws URLs with brackets", async () => {
|
|
988
|
+
const transport = fakeTransport([
|
|
989
|
+
{
|
|
990
|
+
targetId: "A",
|
|
991
|
+
type: "page",
|
|
992
|
+
title: "Page",
|
|
993
|
+
url: "https://example.com/",
|
|
994
|
+
},
|
|
995
|
+
]);
|
|
996
|
+
|
|
997
|
+
const targets = await discoverTargetsViaWs({
|
|
998
|
+
transport,
|
|
999
|
+
host: "::1",
|
|
1000
|
+
port: 9222,
|
|
1001
|
+
});
|
|
1002
|
+
|
|
1003
|
+
expect(targets[0]!.webSocketDebuggerUrl).toBe(
|
|
1004
|
+
"ws://[::1]:9222/devtools/page/A",
|
|
1005
|
+
);
|
|
1006
|
+
});
|
|
1007
|
+
});
|
|
@@ -1,21 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* DevTools
|
|
2
|
+
* DevTools discovery helpers for the `cdp-inspect` backend.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* websocket transport, a session manager, or any CDP command state.
|
|
6
|
-
* They exist so the higher-level `cdp-inspect` client can:
|
|
4
|
+
* Two discovery strategies are provided:
|
|
7
5
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
6
|
+
* **HTTP discovery** (primary path):
|
|
7
|
+
* 1. Probe `/json/version` to verify that a loopback port is actually
|
|
8
|
+
* a Chrome/Chromium DevTools endpoint.
|
|
9
|
+
* 2. Enumerate available page targets via `/json/list`.
|
|
10
|
+
* 3. Pick a sensible default target when the caller doesn't specify
|
|
11
|
+
* one explicitly.
|
|
14
12
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
13
|
+
* **WS-only discovery** (fallback path):
|
|
14
|
+
* When the HTTP endpoints (`/json/version`, `/json/list`) are
|
|
15
|
+
* unavailable (e.g. extension/proxy environments that expose only
|
|
16
|
+
* the WebSocket debugger), the client can fall back to a direct
|
|
17
|
+
* WebSocket connection to the well-known browser endpoint
|
|
18
|
+
* (`ws://<host>:<port>/devtools/browser`) and use CDP
|
|
19
|
+
* `Target.getTargets` to enumerate targets instead.
|
|
20
|
+
*
|
|
21
|
+
* Safety boundary: **only loopback hosts are allowed** for both
|
|
22
|
+
* strategies. A non-loopback host is rejected *before* any network
|
|
23
|
+
* I/O so that this module can never be coerced into making
|
|
24
|
+
* cross-origin requests on behalf of an attacker-controlled config
|
|
25
|
+
* value.
|
|
19
26
|
*/
|
|
20
27
|
|
|
21
28
|
/**
|
|
@@ -31,7 +38,22 @@ export type DevToolsDiscoveryErrorCode =
|
|
|
31
38
|
| "non_chrome"
|
|
32
39
|
| "invalid_response"
|
|
33
40
|
| "no_targets"
|
|
34
|
-
| "timeout"
|
|
41
|
+
| "timeout"
|
|
42
|
+
| "ws_fallback_failed";
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Canonical discovery-code constants for callers that need stable,
|
|
46
|
+
* typo-safe comparisons without repeating raw string literals.
|
|
47
|
+
*/
|
|
48
|
+
export const DEVTOOLS_DISCOVERY_CODE = {
|
|
49
|
+
UNREACHABLE: "unreachable",
|
|
50
|
+
NON_LOOPBACK: "non_loopback",
|
|
51
|
+
NON_CHROME: "non_chrome",
|
|
52
|
+
INVALID_RESPONSE: "invalid_response",
|
|
53
|
+
NO_TARGETS: "no_targets",
|
|
54
|
+
TIMEOUT: "timeout",
|
|
55
|
+
WS_FALLBACK_FAILED: "ws_fallback_failed",
|
|
56
|
+
} as const satisfies Record<string, DevToolsDiscoveryErrorCode>;
|
|
35
57
|
|
|
36
58
|
/**
|
|
37
59
|
* Single error type thrown by all discovery helpers. Mirrors the
|
|
@@ -126,14 +148,26 @@ function assertWsUrlLoopback(wsUrl: string): void {
|
|
|
126
148
|
}
|
|
127
149
|
}
|
|
128
150
|
|
|
151
|
+
/**
|
|
152
|
+
* Normalize a loopback host string for use in a URL. IPv6 bare form
|
|
153
|
+
* (`::1`) is wrapped in square brackets (`[::1]`) as required by
|
|
154
|
+
* RFC 3986; all other hosts are lowercased and returned as-is.
|
|
155
|
+
*
|
|
156
|
+
* This is the single source of truth for IPv6 bracket normalization
|
|
157
|
+
* across both HTTP and WS URL construction in this module.
|
|
158
|
+
*/
|
|
159
|
+
function normalizeHostForWsUrl(host: string): string {
|
|
160
|
+
const normalized = host.toLowerCase();
|
|
161
|
+
return normalized === "::1" ? "[::1]" : normalized;
|
|
162
|
+
}
|
|
163
|
+
|
|
129
164
|
/**
|
|
130
165
|
* Build a fetch-ready loopback URL. `host` is assumed to have already
|
|
131
166
|
* been validated by {@link assertLoopback}. IPv6 bare form (`::1`) is
|
|
132
167
|
* wrapped in square brackets for URL correctness.
|
|
133
168
|
*/
|
|
134
169
|
function buildUrl(host: string, port: number, pathname: string): string {
|
|
135
|
-
const
|
|
136
|
-
const hostSegment = normalized === "::1" ? "[::1]" : normalized;
|
|
170
|
+
const hostSegment = normalizeHostForWsUrl(host);
|
|
137
171
|
return `http://${hostSegment}:${port}${pathname}`;
|
|
138
172
|
}
|
|
139
173
|
|
|
@@ -576,3 +610,135 @@ function isUtilityTarget(target: DevToolsTarget): boolean {
|
|
|
576
610
|
if (url === "about:blank") return true;
|
|
577
611
|
return false;
|
|
578
612
|
}
|
|
613
|
+
|
|
614
|
+
// ---------------------------------------------------------------------------
|
|
615
|
+
// WS-only discovery fallback
|
|
616
|
+
// ---------------------------------------------------------------------------
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* Build a well-known browser-level WebSocket debugger URL from a
|
|
620
|
+
* loopback host and port. The resulting URL follows the standard
|
|
621
|
+
* Chrome DevTools pattern: `ws://<host>:<port>/devtools/browser`.
|
|
622
|
+
*
|
|
623
|
+
* Enforces the same loopback check as {@link probeDevToolsJsonVersion}
|
|
624
|
+
* so this function can never produce a URL that points outside the
|
|
625
|
+
* local machine. IPv6 bare form (`::1`) is wrapped in square brackets.
|
|
626
|
+
*
|
|
627
|
+
* Exported for use by the `cdp-inspect` client's WS fallback path and
|
|
628
|
+
* for unit testing.
|
|
629
|
+
*/
|
|
630
|
+
export function buildBrowserWsUrl(host: string, port: number): string {
|
|
631
|
+
assertLoopback(host);
|
|
632
|
+
const hostSegment = normalizeHostForWsUrl(host);
|
|
633
|
+
return `ws://${hostSegment}:${port}/devtools/browser`;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* Determine whether an HTTP discovery error is eligible for the
|
|
638
|
+
* WS-only fallback. Only `invalid_response` and `unreachable` qualify
|
|
639
|
+
* — these indicate the HTTP endpoints are absent or the server doesn't
|
|
640
|
+
* speak the JSON discovery protocol. Errors like `non_loopback`,
|
|
641
|
+
* `non_chrome`, and `timeout` should *not* trigger the fallback because
|
|
642
|
+
* they indicate a fundamental safety or configuration problem.
|
|
643
|
+
*/
|
|
644
|
+
export function isHttpDiscoveryFallbackEligible(
|
|
645
|
+
err: unknown,
|
|
646
|
+
): err is DevToolsDiscoveryError {
|
|
647
|
+
if (!(err instanceof DevToolsDiscoveryError)) return false;
|
|
648
|
+
return err.code === "invalid_response" || err.code === "unreachable";
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* Target info returned by CDP `Target.getTargets`. A subset of the
|
|
653
|
+
* full `TargetInfo` — we only need enough to build a
|
|
654
|
+
* {@link DevToolsTarget} for the attach step.
|
|
655
|
+
*/
|
|
656
|
+
interface CdpTargetInfo {
|
|
657
|
+
targetId: string;
|
|
658
|
+
type: string;
|
|
659
|
+
title: string;
|
|
660
|
+
url: string;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/**
|
|
664
|
+
* Enumerate page targets via a direct WebSocket connection to the
|
|
665
|
+
* browser-level DevTools endpoint. Uses CDP `Target.getTargets` instead
|
|
666
|
+
* of the HTTP `/json/list` endpoint.
|
|
667
|
+
*
|
|
668
|
+
* This function is the core of the WS-only fallback: when the HTTP
|
|
669
|
+
* discovery endpoints are absent, the caller connects to the well-known
|
|
670
|
+
* `ws://<host>:<port>/devtools/browser` URL and uses this function to
|
|
671
|
+
* discover page targets.
|
|
672
|
+
*
|
|
673
|
+
* The transport is provided by the caller (the cdp-inspect client's
|
|
674
|
+
* attach method) so this function doesn't own the socket lifecycle.
|
|
675
|
+
*
|
|
676
|
+
* Returns a filtered list of page targets. Throws `no_targets` when no
|
|
677
|
+
* page targets are found.
|
|
678
|
+
*
|
|
679
|
+
* @param transport - An already-connected {@link CdpWsTransport}.
|
|
680
|
+
* @param host - The loopback host, used to construct per-target ws URLs.
|
|
681
|
+
* @param port - The port, used to construct per-target ws URLs.
|
|
682
|
+
* @param signal - Optional abort signal for the CDP call.
|
|
683
|
+
*/
|
|
684
|
+
export async function discoverTargetsViaWs(opts: {
|
|
685
|
+
transport: import("./ws-transport.js").CdpWsTransport;
|
|
686
|
+
host: string;
|
|
687
|
+
port: number;
|
|
688
|
+
signal?: AbortSignal;
|
|
689
|
+
}): Promise<DevToolsTarget[]> {
|
|
690
|
+
assertLoopback(opts.host);
|
|
691
|
+
|
|
692
|
+
const result = await opts.transport.send<{
|
|
693
|
+
targetInfos?: CdpTargetInfo[];
|
|
694
|
+
}>("Target.getTargets", undefined, { signal: opts.signal });
|
|
695
|
+
|
|
696
|
+
const targetInfos = result?.targetInfos;
|
|
697
|
+
if (!Array.isArray(targetInfos)) {
|
|
698
|
+
throw new DevToolsDiscoveryError(
|
|
699
|
+
"ws_fallback_failed",
|
|
700
|
+
"Target.getTargets did not return a targetInfos array.",
|
|
701
|
+
);
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
const hostSegment = normalizeHostForWsUrl(opts.host);
|
|
705
|
+
|
|
706
|
+
const targets: DevToolsTarget[] = [];
|
|
707
|
+
for (const info of targetInfos) {
|
|
708
|
+
if (
|
|
709
|
+
typeof info !== "object" ||
|
|
710
|
+
info === null ||
|
|
711
|
+
typeof info.type !== "string"
|
|
712
|
+
) {
|
|
713
|
+
continue;
|
|
714
|
+
}
|
|
715
|
+
if (info.type !== "page") continue;
|
|
716
|
+
|
|
717
|
+
const id =
|
|
718
|
+
typeof info.targetId === "string" && info.targetId.length > 0
|
|
719
|
+
? info.targetId
|
|
720
|
+
: "";
|
|
721
|
+
if (!id) continue;
|
|
722
|
+
|
|
723
|
+
const title = typeof info.title === "string" ? info.title : "";
|
|
724
|
+
const url = typeof info.url === "string" ? info.url : "";
|
|
725
|
+
// In WS-only mode, Chrome does not provide per-target ws URLs via
|
|
726
|
+
// the HTTP API. Construct the standard DevTools per-page URL so
|
|
727
|
+
// downstream code has a consistent shape. Note: the cdp-inspect
|
|
728
|
+
// client does not actually use this URL to connect — it uses
|
|
729
|
+
// Target.attachToTarget on the browser-level transport instead.
|
|
730
|
+
const webSocketDebuggerUrl = `ws://${hostSegment}:${opts.port}/devtools/page/${id}`;
|
|
731
|
+
|
|
732
|
+
targets.push({ id, type: "page", title, url, webSocketDebuggerUrl });
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
if (targets.length === 0) {
|
|
736
|
+
throw new DevToolsDiscoveryError(
|
|
737
|
+
"no_targets",
|
|
738
|
+
"No usable page targets returned by CDP Target.getTargets. " +
|
|
739
|
+
"Ensure at least one browser tab is open.",
|
|
740
|
+
);
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
return targets;
|
|
744
|
+
}
|