@vellumai/assistant 0.6.2 → 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 +41 -49
- package/bunfig.toml +3 -0
- package/docs/architecture/memory.md +1 -1
- 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/node_modules/@vellumai/ces-contracts/src/rpc.ts +42 -0
- package/openapi.yaml +1111 -86
- package/package.json +40 -42
- package/scripts/generate-openapi.ts +0 -2
- package/scripts/test.sh +73 -18
- package/src/__tests__/acp-session.test.ts +43 -0
- 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__/app-builder-tool-scripts.test.ts +1 -0
- package/src/__tests__/app-executors.test.ts +1 -0
- package/src/__tests__/app-source-watcher.test.ts +37 -11
- package/src/__tests__/approval-routes-http.test.ts +178 -1
- 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 +240 -94
- package/src/__tests__/browser-manager.test.ts +40 -27
- 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 +1000 -0
- package/src/__tests__/channel-approvals.test.ts +53 -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-managed-gemini-defaults.test.ts +326 -0
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +1248 -224
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +339 -0
- package/src/__tests__/config-watcher.test.ts +43 -8
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +23 -0
- package/src/__tests__/contact-store-user-file.test.ts +512 -0
- package/src/__tests__/contacts-write.test.ts +197 -0
- package/src/__tests__/context-overflow-approval.test.ts +16 -1
- 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 +2 -1
- package/src/__tests__/conversation-agent-loop.test.ts +99 -3
- package/src/__tests__/conversation-analysis-routes.test.ts +2 -2
- package/src/__tests__/conversation-attachments.test.ts +80 -4
- package/src/__tests__/conversation-confirmation-signals.test.ts +290 -0
- package/src/__tests__/conversation-error.test.ts +70 -0
- package/src/__tests__/conversation-fork-crud.test.ts +17 -0
- package/src/__tests__/conversation-history-web-search.test.ts +12 -4
- package/src/__tests__/conversation-host-access-routes.test.ts +229 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +6 -1
- package/src/__tests__/conversation-inject-context.test.ts +103 -0
- 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 +946 -62
- package/src/__tests__/conversation-routes-disk-view.test.ts +275 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +16 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +324 -46
- 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-starter-routes.test.ts +126 -0
- package/src/__tests__/conversation-starters-cadence.test.ts +161 -0
- package/src/__tests__/conversation-store.test.ts +195 -0
- package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +226 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +193 -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-execution-approval-bridge.test.ts +32 -1
- package/src/__tests__/credential-health-service.test.ts +352 -0
- package/src/__tests__/credential-security-invariants.test.ts +6 -3
- package/src/__tests__/credential-vault-unit.test.ts +383 -7
- package/src/__tests__/credential-vault.test.ts +152 -13
- package/src/__tests__/credentials-cli.test.ts +42 -18
- package/src/__tests__/cross-provider-web-search.test.ts +146 -35
- package/src/__tests__/date-context.test.ts +4 -4
- 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__/embedding-managed-proxy-selection.test.ts +256 -0
- package/src/__tests__/emit-event-signal.test.ts +71 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +222 -0
- package/src/__tests__/fixtures/mock-chrome-extension.ts +386 -0
- package/src/__tests__/gateway-only-enforcement.test.ts +206 -1
- package/src/__tests__/gateway-only-guard.test.ts +2 -0
- package/src/__tests__/gemini-provider.test.ts +66 -2
- 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__/guardian-routing-invariants.test.ts +70 -2
- package/src/__tests__/headless-browser-interactions.test.ts +738 -359
- package/src/__tests__/headless-browser-mode.test.ts +614 -0
- package/src/__tests__/headless-browser-navigate.test.ts +528 -49
- package/src/__tests__/headless-browser-read-tools.test.ts +274 -100
- package/src/__tests__/headless-browser-snapshot.test.ts +250 -77
- 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 +145 -1
- package/src/__tests__/host-browser-e2e-cloud.test.ts +596 -0
- package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +286 -0
- package/src/__tests__/host-browser-e2e-self-hosted.test.ts +374 -0
- package/src/__tests__/host-browser-event-routes.test.ts +350 -0
- package/src/__tests__/host-browser-proxy.test.ts +444 -0
- package/src/__tests__/host-browser-routes.test.ts +198 -0
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +423 -0
- package/src/__tests__/host-cu-proxy.test.ts +166 -1
- package/src/__tests__/host-file-proxy.test.ts +185 -1
- package/src/__tests__/host-file-read-tool.test.ts +52 -0
- package/src/__tests__/host-proxy-interface.test.ts +165 -0
- package/src/__tests__/host-shell-tool.test.ts +1 -11
- package/src/__tests__/http-user-message-parity.test.ts +1 -0
- package/src/__tests__/identity-intro-cache.test.ts +40 -10
- package/src/__tests__/init-feature-flag-overrides.test.ts +38 -112
- package/src/__tests__/integration-status.test.ts +6 -7
- package/src/__tests__/jobs-store-upsert-debounced.test.ts +141 -0
- package/src/__tests__/list-messages-tool-merge.test.ts +37 -12
- 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__/mcp-client-auth.test.ts +40 -4
- package/src/__tests__/mcp-health-check.test.ts +10 -3
- 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-cross-version-compatibility.test.ts +3 -1
- package/src/__tests__/migration-export-http.test.ts +67 -8
- package/src/__tests__/migration-export-streaming.test.ts +66 -0
- package/src/__tests__/migration-import-commit-http.test.ts +109 -7
- 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__/native-host-marker-sync-guard.test.ts +157 -0
- package/src/__tests__/oauth-apps-routes.test.ts +18 -12
- package/src/__tests__/oauth-cli.test.ts +709 -60
- package/src/__tests__/oauth-connect-orchestrator.test.ts +118 -24
- package/src/__tests__/oauth-provider-seed-logos.test.ts +23 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +147 -10
- package/src/__tests__/oauth-provider-visibility.test.ts +19 -21
- package/src/__tests__/oauth-providers-routes.test.ts +52 -14
- package/src/__tests__/oauth-store.test.ts +1465 -176
- package/src/__tests__/oauth2-gateway-transport.test.ts +460 -26
- package/src/__tests__/onboarding-template-contract.test.ts +81 -70
- package/src/__tests__/openai-provider.test.ts +178 -2
- 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-categories.test.ts +1 -1
- package/src/__tests__/outlook-client-automation.test.ts +1 -1
- package/src/__tests__/outlook-compose-tools.test.ts +1 -1
- package/src/__tests__/outlook-email-watcher.test.ts +1 -1
- package/src/__tests__/outlook-follow-up.test.ts +1 -1
- package/src/__tests__/outlook-messaging-provider.test.ts +2 -2
- package/src/__tests__/outlook-trash.test.ts +1 -1
- package/src/__tests__/outlook-unsubscribe.test.ts +32 -3
- package/src/__tests__/permission-checker-host-gate.test.ts +74 -14
- package/src/__tests__/permission-mode.test.ts +28 -56
- package/src/__tests__/persona-resolver.test.ts +251 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +4 -0
- package/src/__tests__/platform-callback-registration.test.ts +19 -0
- package/src/__tests__/platform.test.ts +92 -1
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +343 -0
- package/src/__tests__/prechat-onboarding-contract.test.ts +267 -0
- package/src/__tests__/pricing.test.ts +174 -0
- package/src/__tests__/proxy-approval-callback.test.ts +18 -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__/require-fresh-approval.test.ts +40 -1
- package/src/__tests__/sanitize-config-for-transfer.test.ts +132 -0
- package/src/__tests__/schedule-routes.test.ts +162 -0
- package/src/__tests__/search-skills-unified.test.ts +118 -0
- package/src/__tests__/secret-detection-handler.test.ts +84 -0
- package/src/__tests__/secret-ingress-http.test.ts +1 -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 +8 -1
- package/src/__tests__/sequence-store.test.ts +1 -1
- package/src/__tests__/server-history-render.test.ts +49 -0
- package/src/__tests__/set-permission-mode.test.ts +13 -250
- 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 +801 -0
- package/src/__tests__/skills-files-catalog-fallback.test.ts +738 -0
- 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 +576 -16
- package/src/__tests__/stt-catalog-parity.test.ts +282 -0
- package/src/__tests__/stt-stream-session.test.ts +535 -0
- package/src/__tests__/subagent-detail.test.ts +44 -2
- package/src/__tests__/subagent-disposal.test.ts +1 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +291 -0
- package/src/__tests__/subagent-fork-spawn.test.ts +384 -0
- package/src/__tests__/subagent-manager-notify.test.ts +1 -0
- package/src/__tests__/subagent-notify-parent.test.ts +1 -0
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +411 -0
- package/src/__tests__/subagent-tools.test.ts +1 -0
- package/src/__tests__/subagent-types.test.ts +1 -0
- package/src/__tests__/system-prompt-ask-mode.test.ts +27 -71
- package/src/__tests__/system-prompt.test.ts +184 -27
- package/src/__tests__/task-scheduler.test.ts +32 -6
- package/src/__tests__/telegram-config.test.ts +10 -13
- package/src/__tests__/telephony-stt-routing.test.ts +329 -0
- package/src/__tests__/terminal-tools.test.ts +25 -5
- package/src/__tests__/test-preload.ts +18 -0
- package/src/__tests__/test-support/browser-skill-harness.ts +4 -1
- package/src/__tests__/tool-approval-handler.test.ts +73 -0
- 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__/tool-side-effects-slack-dm.test.ts +22 -0
- package/src/__tests__/top-level-renderer.test.ts +73 -1
- package/src/__tests__/transport-hints-queue.test.ts +14 -29
- package/src/__tests__/trust-store.test.ts +7 -1
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +109 -0
- 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__/v2-consent-policy.test.ts +103 -0
- 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/acp/client-handler.ts +30 -4
- package/src/agent/image-optimize.ts +24 -12
- package/src/agent/loop.ts +55 -9
- package/src/approvals/guardian-request-resolvers.ts +21 -15
- 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/browser-session/__tests__/manager.test.ts +297 -0
- package/src/browser-session/backends/cdp-inspect.ts +30 -0
- package/src/browser-session/backends/extension.ts +26 -0
- package/src/browser-session/backends/local.ts +24 -0
- package/src/browser-session/events.ts +164 -0
- package/src/browser-session/index.ts +27 -0
- package/src/browser-session/manager.ts +159 -0
- package/src/browser-session/types.ts +28 -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/__tests__/types.test.ts +134 -0
- package/src/channels/types.ts +69 -3
- 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 +3 -4
- package/src/cli/commands/domain.ts +210 -0
- package/src/cli/commands/email.ts +273 -16
- package/src/cli/commands/mcp.ts +16 -4
- package/src/cli/commands/oauth/__tests__/connect.test.ts +56 -44
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +21 -21
- package/src/cli/commands/oauth/__tests__/mode.test.ts +17 -17
- package/src/cli/commands/oauth/__tests__/ping.test.ts +16 -16
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +32 -33
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +330 -0
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +117 -12
- package/src/cli/commands/oauth/__tests__/status.test.ts +10 -10
- package/src/cli/commands/oauth/__tests__/token.test.ts +7 -7
- package/src/cli/commands/oauth/apps.ts +7 -4
- package/src/cli/commands/oauth/connect.ts +6 -3
- package/src/cli/commands/oauth/disconnect.ts +1 -1
- package/src/cli/commands/oauth/mode.ts +12 -3
- package/src/cli/commands/oauth/providers.ts +215 -36
- package/src/cli/commands/oauth/shared.ts +7 -6
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +254 -0
- 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/commands/platform/index.ts +107 -10
- package/src/cli/commands/usage.ts +10 -9
- package/src/cli/lib/daemon-credential-client.ts +4 -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/SKILL.md +26 -249
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +141 -0
- package/src/config/bundled-skills/app-builder/references/INTERACTION_HOOKS.md +56 -0
- package/src/config/bundled-skills/app-builder/references/WIDGETS.md +125 -0
- 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 +5 -2
- package/src/config/bundled-skills/document/SKILL.md +4 -0
- package/src/config/bundled-skills/gmail/SKILL.md +54 -8
- 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 +9 -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/subagent/SKILL.md +21 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +8 -4
- package/src/config/bundled-skills/tasks/SKILL.md +5 -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 +38 -0
- package/src/config/env.ts +49 -4
- package/src/config/feature-flag-registry.json +85 -14
- package/src/config/loader.ts +82 -13
- package/src/config/sanitize-for-transfer.ts +47 -0
- package/src/config/schema.ts +81 -15
- 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 +112 -0
- package/src/config/schemas/inference.ts +1 -1
- package/src/config/schemas/memory-lifecycle.ts +14 -2
- package/src/config/schemas/memory-retrieval.ts +103 -0
- package/src/config/schemas/security.ts +0 -6
- package/src/config/schemas/services.ts +52 -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 -1
- 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 +177 -0
- package/src/context/tool-result-truncation.ts +2 -1
- package/src/context/window-manager.ts +61 -10
- package/src/credential-execution/approval-bridge.ts +49 -15
- 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 +195 -0
- package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +127 -0
- package/src/daemon/app-source-watcher.ts +35 -0
- package/src/daemon/config-watcher.ts +99 -5
- package/src/daemon/context-overflow-approval.ts +5 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +23 -2
- package/src/daemon/conversation-agent-loop.ts +153 -42
- package/src/daemon/conversation-attachments.ts +40 -0
- 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 +622 -13
- package/src/daemon/conversation-queue-manager.ts +24 -0
- package/src/daemon/conversation-runtime-assembly.ts +128 -36
- package/src/daemon/conversation-slash.ts +36 -0
- package/src/daemon/conversation-surfaces.ts +131 -40
- package/src/daemon/conversation-tool-setup.ts +99 -8
- package/src/daemon/conversation-usage.ts +7 -4
- package/src/daemon/conversation-workspace.ts +12 -0
- package/src/daemon/conversation.ts +292 -16
- package/src/daemon/date-context.ts +10 -10
- package/src/daemon/first-greeting.ts +3 -2
- package/src/daemon/handlers/config-slack-channel.ts +269 -94
- package/src/daemon/handlers/conversations.ts +13 -141
- package/src/daemon/handlers/shared.ts +80 -0
- package/src/daemon/handlers/skills.ts +483 -44
- package/src/daemon/host-bash-proxy.ts +48 -13
- package/src/daemon/host-browser-proxy.ts +192 -0
- package/src/daemon/host-cu-proxy.ts +36 -11
- package/src/daemon/host-file-proxy.ts +57 -9
- package/src/daemon/lifecycle.ts +179 -28
- package/src/daemon/message-protocol.ts +13 -0
- package/src/daemon/message-types/conversations.ts +89 -14
- package/src/daemon/message-types/home.ts +40 -0
- package/src/daemon/message-types/host-browser.ts +100 -0
- package/src/daemon/message-types/meet.ts +143 -0
- package/src/daemon/message-types/messages.ts +19 -5
- package/src/daemon/message-types/schedules.ts +34 -2
- package/src/daemon/message-types/skills.ts +26 -0
- package/src/daemon/message-types/subagents.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +2 -0
- package/src/daemon/server.ts +439 -14
- package/src/daemon/shutdown-handlers.ts +32 -4
- package/src/daemon/shutdown-registry.ts +40 -0
- package/src/daemon/tool-side-effects.ts +15 -0
- package/src/daemon/transport-hints.ts +5 -24
- 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 +30 -20
- 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/mcp/client.ts +59 -24
- 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 +31 -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 +122 -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/conversation-starters-cadence.ts +76 -0
- package/src/memory/conversation-title-service.ts +5 -2
- package/src/memory/db-init.ts +18 -0
- package/src/memory/db-maintenance.ts +108 -0
- package/src/memory/db.ts +1 -0
- package/src/memory/embedding-backend.test.ts +75 -0
- package/src/memory/embedding-backend.ts +131 -5
- package/src/memory/embedding-gemini.test.ts +54 -0
- package/src/memory/embedding-gemini.ts +20 -9
- package/src/memory/embedding-local.ts +176 -17
- package/src/memory/graph/consolidation.ts +10 -23
- package/src/memory/graph/conversation-graph-memory.ts +15 -0
- package/src/memory/graph/extraction-job.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 +67 -40
- package/src/memory/graph/scoring.test.ts +186 -0
- package/src/memory/graph/scoring.ts +31 -1
- package/src/memory/graph/store.test.ts +7 -3
- package/src/memory/graph/store.ts +47 -12
- 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 +137 -60
- package/src/memory/migrations/213-oauth-providers-scope-separator.ts +13 -0
- package/src/memory/migrations/214-oauth-providers-refresh-url.ts +11 -0
- package/src/memory/migrations/215-oauth-providers-revoke.ts +14 -0
- package/src/memory/migrations/216-oauth-providers-token-auth-method.ts +30 -0
- package/src/memory/migrations/217-conversation-host-access.ts +40 -0
- package/src/memory/migrations/218-oauth-providers-logo-url.ts +11 -0
- 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 +12 -0
- package/src/memory/migrations/registry.ts +16 -0
- package/src/memory/qdrant-manager.ts +43 -16
- package/src/memory/schema/conversations.ts +3 -0
- package/src/memory/schema/oauth.ts +21 -13
- 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/AGENTS.md +76 -0
- package/src/oauth/__tests__/identity-verifier.test.ts +25 -19
- package/src/oauth/__tests__/seed-providers-managed.test.ts +32 -0
- package/src/oauth/byo-connection.test.ts +26 -9
- package/src/oauth/byo-connection.ts +10 -8
- package/src/oauth/connect-orchestrator.ts +25 -21
- package/src/oauth/connect-types.ts +3 -3
- package/src/oauth/connection-resolver.test.ts +17 -4
- package/src/oauth/connection-resolver.ts +22 -18
- package/src/oauth/connection.ts +3 -1
- package/src/oauth/manual-token-connection.ts +13 -13
- package/src/oauth/oauth-store.ts +223 -100
- package/src/oauth/platform-connection.test.ts +101 -3
- package/src/oauth/platform-connection.ts +56 -35
- package/src/oauth/provider-serializer.ts +31 -5
- package/src/oauth/revoke.ts +76 -0
- package/src/oauth/seed-providers.ts +133 -87
- package/src/oauth/token-persistence.ts +1 -1
- package/src/permissions/checker.ts +16 -6
- package/src/permissions/defaults.ts +49 -1
- package/src/permissions/permission-mode.ts +4 -11
- package/src/permissions/prompter.ts +13 -1
- package/src/permissions/trust-store.ts +3 -3
- package/src/permissions/v2-consent-policy.ts +87 -0
- 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 +76 -38
- package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +3 -65
- package/src/prompts/templates/BOOTSTRAP.md +59 -105
- 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 -60
- 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 +10 -1
- package/src/runtime/AGENTS.md +65 -0
- package/src/runtime/__tests__/agent-wake.test.ts +831 -0
- package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +715 -0
- package/src/runtime/__tests__/capability-tokens.test.ts +258 -0
- package/src/runtime/__tests__/chrome-extension-registry.test.ts +518 -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/assistant-event-hub.ts +2 -2
- package/src/runtime/auth/__tests__/guard-tests.test.ts +1 -0
- package/src/runtime/auth/__tests__/middleware.test.ts +116 -1
- package/src/runtime/auth/__tests__/route-policy.test.ts +48 -0
- package/src/runtime/auth/middleware.ts +98 -0
- package/src/runtime/auth/route-policy.ts +33 -9
- package/src/runtime/auth/token-service.ts +56 -1
- package/src/runtime/btw-sidechain.ts +2 -0
- package/src/runtime/capability-tokens.ts +414 -0
- package/src/runtime/channel-approvals.ts +18 -5
- 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 +368 -0
- package/src/runtime/confirmation-request-guardian-bridge.ts +6 -0
- package/src/runtime/guardian-decision-types.ts +7 -0
- package/src/runtime/http-server.ts +815 -75
- package/src/runtime/http-types.ts +6 -2
- package/src/runtime/migrations/__tests__/rebind-secrets-credentials.test.ts +172 -0
- package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +276 -0
- package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +198 -0
- package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +360 -0
- package/src/runtime/migrations/migration-transport.ts +7 -0
- package/src/runtime/migrations/migration-wizard.ts +23 -2
- package/src/runtime/migrations/rebind-secrets-screen.ts +76 -15
- package/src/runtime/migrations/vbundle-builder.ts +145 -38
- package/src/runtime/migrations/vbundle-import-analyzer.ts +96 -1
- package/src/runtime/migrations/vbundle-importer.ts +89 -5
- package/src/runtime/pending-interactions.ts +18 -13
- 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/approval-routes.ts +90 -16
- 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 +556 -0
- 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 -141
- package/src/runtime/routes/conversation-management-routes.ts +223 -0
- package/src/runtime/routes/conversation-routes.ts +598 -103
- package/src/runtime/routes/conversation-starter-routes.ts +78 -16
- package/src/runtime/routes/filing-routes.ts +93 -0
- package/src/runtime/routes/guardian-action-routes.ts +24 -13
- 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 +268 -0
- package/src/runtime/routes/host-file-routes.ts +9 -1
- package/src/runtime/routes/identity-intro-cache.ts +7 -3
- package/src/runtime/routes/identity-routes.ts +262 -33
- 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/log-export-routes.ts +42 -22
- package/src/runtime/routes/memory-item-routes.test.ts +3 -2
- package/src/runtime/routes/memory-item-routes.ts +1 -7
- package/src/runtime/routes/migration-routes.ts +122 -2
- package/src/runtime/routes/oauth-apps.ts +15 -17
- package/src/runtime/routes/oauth-providers.ts +4 -0
- package/src/runtime/routes/schedule-routes.ts +24 -11
- package/src/runtime/routes/settings-routes.ts +31 -102
- package/src/runtime/routes/skills-routes.ts +128 -9
- package/src/runtime/routes/stt-routes.ts +233 -0
- package/src/runtime/routes/subagents-routes.ts +14 -10
- 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 +38 -9
- 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/routes/workspace-routes.test.ts +22 -0
- package/src/runtime/routes/workspace-routes.ts +8 -1
- package/src/runtime/routes/workspace-utils.ts +2 -0
- 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 +57 -5
- package/src/security/ces-credential-client.ts +20 -0
- package/src/security/ces-rpc-credential-backend.ts +17 -0
- package/src/security/credential-backend.ts +5 -0
- package/src/security/oauth2.ts +68 -29
- package/src/security/secure-keys.ts +143 -27
- package/src/security/token-manager.ts +31 -10
- package/src/sequence/engine.ts +23 -0
- package/src/sequence/types.ts +1 -1
- package/src/skills/catalog-files.ts +554 -0
- 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 +169 -40
- package/src/subagent/types.ts +19 -0
- package/src/tools/apps/executors.ts +11 -2
- package/src/tools/browser/__tests__/auth-detector.test.ts +202 -108
- 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/auth-detector.ts +43 -12
- package/src/tools/browser/browser-execution.ts +1787 -342
- package/src/tools/browser/browser-manager.ts +81 -12
- 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__/accessibility-snapshot.test.ts +318 -0
- package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +1175 -0
- package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +1263 -0
- package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +359 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +1993 -0
- package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-nested-frames.json +64 -0
- package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-simple.json +69 -0
- package/src/tools/browser/cdp-client/__tests__/local-cdp-client.test.ts +310 -0
- package/src/tools/browser/cdp-client/__tests__/types.test.ts +96 -0
- package/src/tools/browser/cdp-client/accessibility-snapshot.ts +387 -0
- package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +695 -0
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +1007 -0
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +580 -0
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +744 -0
- package/src/tools/browser/cdp-client/cdp-inspect/ws-transport.ts +579 -0
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +868 -0
- package/src/tools/browser/cdp-client/errors.ts +49 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +148 -0
- package/src/tools/browser/cdp-client/factory.ts +914 -0
- package/src/tools/browser/cdp-client/index.ts +28 -0
- package/src/tools/browser/cdp-client/local-cdp-client.ts +187 -0
- package/src/tools/browser/cdp-client/types.ts +120 -0
- package/src/tools/credentials/vault.ts +35 -6
- package/src/tools/filesystem/edit.ts +1 -1
- package/src/tools/filesystem/list.ts +1 -1
- package/src/tools/filesystem/read.ts +1 -1
- package/src/tools/filesystem/write.ts +2 -1
- package/src/tools/host-filesystem/edit.ts +1 -1
- package/src/tools/host-filesystem/read.ts +12 -15
- package/src/tools/host-filesystem/write.ts +1 -1
- package/src/tools/host-terminal/host-shell.ts +21 -16
- package/src/tools/network/web-fetch.ts +5 -2
- package/src/tools/network/web-search.ts +5 -2
- package/src/tools/permission-checker.ts +77 -82
- package/src/tools/registry.ts +0 -2
- package/src/tools/secret-detection-handler.ts +34 -0
- package/src/tools/shared/filesystem/image-read.ts +61 -40
- 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/subagent/spawn.ts +47 -3
- package/src/tools/subagent/status.ts +2 -0
- package/src/tools/system/register.ts +2 -16
- package/src/tools/terminal/safe-env.ts +15 -0
- package/src/tools/terminal/shell.ts +36 -20
- package/src/tools/tool-approval-handler.ts +48 -2
- package/src/tools/tool-manifest.ts +21 -0
- package/src/tools/types.ts +19 -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 +63 -24
- 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 +31 -1
- package/src/workspace/turn-commit.ts +31 -0
- package/src/__tests__/chrome-cdp.test.ts +0 -419
- package/src/__tests__/email-cli.test.ts +0 -297
- package/src/__tests__/email-service-config-fallback.test.ts +0 -102
- package/src/__tests__/permission-mode-sse.test.ts +0 -418
- package/src/__tests__/permission-mode-store.test.ts +0 -277
- package/src/browser-extension-relay/protocol.ts +0 -63
- package/src/browser-extension-relay/server.ts +0 -203
- package/src/cli/commands/browser-relay.ts +0 -536
- package/src/config/schemas/sandbox.ts +0 -14
- 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/permissions/permission-mode-store.ts +0 -180
- package/src/prompts/templates/USER.md +0 -13
- package/src/providers/speech-to-text/types.ts +0 -17
- package/src/tools/browser/chrome-cdp.ts +0 -239
- package/src/tools/system/set-permission-mode.ts +0 -103
|
@@ -0,0 +1,744 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DevTools discovery helpers for the `cdp-inspect` backend.
|
|
3
|
+
*
|
|
4
|
+
* Two discovery strategies are provided:
|
|
5
|
+
*
|
|
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.
|
|
12
|
+
*
|
|
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.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Stable error codes surfaced by discovery helpers.
|
|
30
|
+
*
|
|
31
|
+
* Callers branch on these codes instead of string-matching messages so
|
|
32
|
+
* upstream UX (status bar, toasts, logs) can render a stable, localized
|
|
33
|
+
* explanation.
|
|
34
|
+
*/
|
|
35
|
+
export type DevToolsDiscoveryErrorCode =
|
|
36
|
+
| "unreachable"
|
|
37
|
+
| "non_loopback"
|
|
38
|
+
| "non_chrome"
|
|
39
|
+
| "invalid_response"
|
|
40
|
+
| "no_targets"
|
|
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>;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Single error type thrown by all discovery helpers. Mirrors the
|
|
60
|
+
* shape of {@link import("../errors.js").CdpError} so catch sites can
|
|
61
|
+
* rely on an explicit `code` field and an optional underlying cause.
|
|
62
|
+
*/
|
|
63
|
+
export class DevToolsDiscoveryError extends Error {
|
|
64
|
+
constructor(
|
|
65
|
+
public readonly code: DevToolsDiscoveryErrorCode,
|
|
66
|
+
message: string,
|
|
67
|
+
public readonly cause?: unknown,
|
|
68
|
+
) {
|
|
69
|
+
super(message);
|
|
70
|
+
this.name = "DevToolsDiscoveryError";
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Normalized `/json/version` payload. Chrome returns canonical field
|
|
76
|
+
* names like `Browser` and `Protocol-Version`, but some forks and
|
|
77
|
+
* tests prefer camelCase. The parser here accepts both and normalizes
|
|
78
|
+
* to the camelCase shape below.
|
|
79
|
+
*/
|
|
80
|
+
export interface DevToolsVersionInfo {
|
|
81
|
+
/** Normalized from `"Browser"` or `"browser"`. */
|
|
82
|
+
browser: string;
|
|
83
|
+
/** Normalized from `"Protocol-Version"` or `"protocolVersion"`. */
|
|
84
|
+
protocolVersion: string;
|
|
85
|
+
/** WebSocket URL for the browser-level debugger endpoint. */
|
|
86
|
+
webSocketDebuggerUrl: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* A DevTools page target as returned by `/json/list`, filtered down to
|
|
91
|
+
* the fields the cdp-inspect backend actually needs.
|
|
92
|
+
*/
|
|
93
|
+
export interface DevToolsTarget {
|
|
94
|
+
id: string;
|
|
95
|
+
type: string;
|
|
96
|
+
title: string;
|
|
97
|
+
url: string;
|
|
98
|
+
webSocketDebuggerUrl: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Loopback allowlist (exact match, case-insensitive). Any host not in
|
|
103
|
+
* this list is rejected *before* we touch the network.
|
|
104
|
+
*
|
|
105
|
+
* We intentionally do not resolve DNS here — if a config ever gains a
|
|
106
|
+
* hostname that happens to resolve to 127.0.0.1, we still refuse it,
|
|
107
|
+
* because DNS rebinding attacks can flip that answer between the
|
|
108
|
+
* pre-check and the actual fetch.
|
|
109
|
+
*/
|
|
110
|
+
const LOOPBACK_HOSTS = new Set(["localhost", "127.0.0.1", "::1", "[::1]"]);
|
|
111
|
+
|
|
112
|
+
function assertLoopback(host: string): void {
|
|
113
|
+
const normalized = host.toLowerCase();
|
|
114
|
+
if (!LOOPBACK_HOSTS.has(normalized)) {
|
|
115
|
+
throw new DevToolsDiscoveryError(
|
|
116
|
+
"non_loopback",
|
|
117
|
+
`Refusing to probe non-loopback DevTools host "${host}". Only loopback hosts (localhost, 127.0.0.1, ::1) are permitted.`,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Validate that a `webSocketDebuggerUrl` points to a loopback host.
|
|
124
|
+
*
|
|
125
|
+
* Chrome returns this URL in `/json/version` and `/json/list` responses.
|
|
126
|
+
* A rogue responder on the loopback port could return a ws:// URL
|
|
127
|
+
* pointing to an attacker-controlled host, tricking the client into
|
|
128
|
+
* opening a cross-origin WebSocket. This check ensures the hostname
|
|
129
|
+
* extracted from the URL is in the {@link LOOPBACK_HOSTS} allowlist.
|
|
130
|
+
*/
|
|
131
|
+
function assertWsUrlLoopback(wsUrl: string): void {
|
|
132
|
+
let url: URL;
|
|
133
|
+
try {
|
|
134
|
+
url = new URL(wsUrl);
|
|
135
|
+
} catch {
|
|
136
|
+
throw new DevToolsDiscoveryError(
|
|
137
|
+
"invalid_response",
|
|
138
|
+
`webSocketDebuggerUrl is not a valid URL: ${wsUrl}`,
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const hostname = url.hostname.toLowerCase();
|
|
143
|
+
if (!LOOPBACK_HOSTS.has(hostname)) {
|
|
144
|
+
throw new DevToolsDiscoveryError(
|
|
145
|
+
"non_loopback",
|
|
146
|
+
`webSocketDebuggerUrl host "${url.hostname}" is not loopback. A rogue responder may be redirecting the connection.`,
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
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
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Build a fetch-ready loopback URL. `host` is assumed to have already
|
|
166
|
+
* been validated by {@link assertLoopback}. IPv6 bare form (`::1`) is
|
|
167
|
+
* wrapped in square brackets for URL correctness.
|
|
168
|
+
*/
|
|
169
|
+
function buildUrl(host: string, port: number, pathname: string): string {
|
|
170
|
+
const hostSegment = normalizeHostForWsUrl(host);
|
|
171
|
+
return `http://${hostSegment}:${port}${pathname}`;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Timeout controller handle returned by {@link withTimeout}. `cleanup`
|
|
176
|
+
* must be called in a `finally` block to avoid leaking the timer and
|
|
177
|
+
* the abort listener. `timedOut` is flipped to `true` if the timer
|
|
178
|
+
* fires before `cleanup` runs.
|
|
179
|
+
*/
|
|
180
|
+
interface TimeoutHandle {
|
|
181
|
+
signal: AbortSignal;
|
|
182
|
+
cleanup: () => void;
|
|
183
|
+
readonly timedOut: boolean;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Merge the caller's signal (if any) with a freshly-minted timeout
|
|
188
|
+
* controller. The flag on the returned handle is the single source of
|
|
189
|
+
* truth for "timed out vs. aborted vs. network error" — we can't
|
|
190
|
+
* recover that distinction from the fetch rejection alone.
|
|
191
|
+
*/
|
|
192
|
+
function withTimeout(
|
|
193
|
+
timeoutMs: number,
|
|
194
|
+
callerSignal?: AbortSignal,
|
|
195
|
+
): TimeoutHandle {
|
|
196
|
+
const controller = new AbortController();
|
|
197
|
+
let timedOut = false;
|
|
198
|
+
const timer = setTimeout(() => {
|
|
199
|
+
timedOut = true;
|
|
200
|
+
controller.abort(new Error("timeout"));
|
|
201
|
+
}, timeoutMs);
|
|
202
|
+
|
|
203
|
+
let onCallerAbort: (() => void) | null = null;
|
|
204
|
+
if (callerSignal) {
|
|
205
|
+
if (callerSignal.aborted) {
|
|
206
|
+
controller.abort(callerSignal.reason);
|
|
207
|
+
} else {
|
|
208
|
+
onCallerAbort = () => controller.abort(callerSignal.reason);
|
|
209
|
+
callerSignal.addEventListener("abort", onCallerAbort, { once: true });
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
signal: controller.signal,
|
|
215
|
+
get timedOut() {
|
|
216
|
+
return timedOut;
|
|
217
|
+
},
|
|
218
|
+
cleanup: () => {
|
|
219
|
+
clearTimeout(timer);
|
|
220
|
+
if (onCallerAbort && callerSignal) {
|
|
221
|
+
callerSignal.removeEventListener("abort", onCallerAbort);
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Classify a `fetch()` rejection into a stable discovery code. We
|
|
229
|
+
* intentionally do not depend on Node's error code strings here — the
|
|
230
|
+
* fetch implementation varies between Bun, Node, and undici — so we
|
|
231
|
+
* look at the name, the message, and the caller-visible abort state
|
|
232
|
+
* instead.
|
|
233
|
+
*/
|
|
234
|
+
function classifyFetchError(
|
|
235
|
+
err: unknown,
|
|
236
|
+
timedOut: boolean,
|
|
237
|
+
callerAborted: boolean,
|
|
238
|
+
): DevToolsDiscoveryError {
|
|
239
|
+
if (callerAborted) {
|
|
240
|
+
return new DevToolsDiscoveryError(
|
|
241
|
+
"unreachable",
|
|
242
|
+
"Discovery fetch was aborted by the caller before completion.",
|
|
243
|
+
err,
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
if (timedOut) {
|
|
247
|
+
return new DevToolsDiscoveryError(
|
|
248
|
+
"timeout",
|
|
249
|
+
"Timed out waiting for DevTools HTTP response.",
|
|
250
|
+
err,
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
255
|
+
const name = err instanceof Error ? err.name : "";
|
|
256
|
+
if (name === "AbortError" || /aborted/i.test(message)) {
|
|
257
|
+
// Unspecified abort — most likely the timeout fired but the flag
|
|
258
|
+
// was not flipped yet. Treat as timeout to give the user the
|
|
259
|
+
// clearer message.
|
|
260
|
+
return new DevToolsDiscoveryError(
|
|
261
|
+
"timeout",
|
|
262
|
+
"Timed out waiting for DevTools HTTP response.",
|
|
263
|
+
err,
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return new DevToolsDiscoveryError(
|
|
268
|
+
"unreachable",
|
|
269
|
+
`Failed to reach DevTools endpoint: ${message}`,
|
|
270
|
+
err,
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Read the response body as text, propagating abort/timeout errors so
|
|
276
|
+
* the caller can distinguish them from a merely malformed payload.
|
|
277
|
+
*
|
|
278
|
+
* The fetch signal is the same AbortSignal passed to the original
|
|
279
|
+
* `fetch()` call, so if the timeout fires (or the caller aborts) while
|
|
280
|
+
* we're still reading the body, the underlying stream is cancelled and
|
|
281
|
+
* `response.text()` rejects. We rethrow those abort-shaped failures as
|
|
282
|
+
* a distinct sentinel (`TimeoutDuringBodyReadError`) so the caller can
|
|
283
|
+
* map them to `timeout` / `unreachable` instead of `invalid_response`.
|
|
284
|
+
*/
|
|
285
|
+
class TimeoutDuringBodyReadError extends Error {
|
|
286
|
+
constructor(
|
|
287
|
+
public readonly timedOut: boolean,
|
|
288
|
+
public readonly callerAborted: boolean,
|
|
289
|
+
public readonly underlying: unknown,
|
|
290
|
+
) {
|
|
291
|
+
super("Discovery body read aborted.");
|
|
292
|
+
this.name = "TimeoutDuringBodyReadError";
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function isAbortShaped(err: unknown): boolean {
|
|
297
|
+
if (!(err instanceof Error)) return false;
|
|
298
|
+
if (err.name === "AbortError") return true;
|
|
299
|
+
if (/abort/i.test(err.message)) return true;
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
async function readResponseText(
|
|
304
|
+
response: Response,
|
|
305
|
+
handle: TimeoutHandle,
|
|
306
|
+
callerSignal: AbortSignal | undefined,
|
|
307
|
+
): Promise<string> {
|
|
308
|
+
try {
|
|
309
|
+
return await response.text();
|
|
310
|
+
} catch (err) {
|
|
311
|
+
const callerAborted = callerSignal?.aborted === true;
|
|
312
|
+
if (handle.timedOut || callerAborted || isAbortShaped(err)) {
|
|
313
|
+
throw new TimeoutDuringBodyReadError(handle.timedOut, callerAborted, err);
|
|
314
|
+
}
|
|
315
|
+
throw err;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Best-effort JSON parser. Returns a parsed object or throws a
|
|
321
|
+
* discovery error with `invalid_response` so the caller doesn't need
|
|
322
|
+
* to wrap this itself. Assumes the body text has already been read
|
|
323
|
+
* (see {@link readResponseText}).
|
|
324
|
+
*/
|
|
325
|
+
function parseJsonText(text: string, endpoint: string): unknown {
|
|
326
|
+
try {
|
|
327
|
+
return JSON.parse(text);
|
|
328
|
+
} catch (err) {
|
|
329
|
+
throw new DevToolsDiscoveryError(
|
|
330
|
+
"invalid_response",
|
|
331
|
+
`Expected JSON from ${endpoint} but got: ${text.slice(0, 200)}`,
|
|
332
|
+
err,
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Pull a string field out of an arbitrary JSON object, supporting
|
|
339
|
+
* either of two casings (e.g. `"Browser"` and `"browser"`). Returns
|
|
340
|
+
* `undefined` if neither key exists or the value is not a string.
|
|
341
|
+
*/
|
|
342
|
+
function readStringField(
|
|
343
|
+
obj: Record<string, unknown>,
|
|
344
|
+
...keys: string[]
|
|
345
|
+
): string | undefined {
|
|
346
|
+
for (const key of keys) {
|
|
347
|
+
const value = obj[key];
|
|
348
|
+
if (typeof value === "string" && value.length > 0) {
|
|
349
|
+
return value;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return undefined;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Probe `/json/version` on a loopback DevTools endpoint and return a
|
|
357
|
+
* normalized {@link DevToolsVersionInfo}.
|
|
358
|
+
*
|
|
359
|
+
* Failure modes:
|
|
360
|
+
*
|
|
361
|
+
* - `non_loopback`: host is not one of {localhost, 127.0.0.1, ::1, [::1]}.
|
|
362
|
+
* Raised *before* any network I/O.
|
|
363
|
+
* - `unreachable`: network error, connection refused, DNS failure, etc.
|
|
364
|
+
* - `timeout`: no response within `timeoutMs`.
|
|
365
|
+
* - `invalid_response`: HTTP status != 200, non-JSON body, or missing
|
|
366
|
+
* required fields.
|
|
367
|
+
* - `non_chrome`: the responder does not identify itself as Chrome or
|
|
368
|
+
* Chromium. Guards against e.g. a dev server happening to listen on
|
|
369
|
+
* port 9222.
|
|
370
|
+
*/
|
|
371
|
+
export async function probeDevToolsJsonVersion(opts: {
|
|
372
|
+
host: string;
|
|
373
|
+
port: number;
|
|
374
|
+
timeoutMs: number;
|
|
375
|
+
signal?: AbortSignal;
|
|
376
|
+
}): Promise<DevToolsVersionInfo> {
|
|
377
|
+
assertLoopback(opts.host);
|
|
378
|
+
|
|
379
|
+
const url = buildUrl(opts.host, opts.port, "/json/version");
|
|
380
|
+
const handle = withTimeout(opts.timeoutMs, opts.signal);
|
|
381
|
+
|
|
382
|
+
// Keep `handle` active until AFTER the body has been read, so the
|
|
383
|
+
// timeout (and caller abort) still enforce against a server that
|
|
384
|
+
// stalls mid-body. If we cleared the timer right after `fetch()`
|
|
385
|
+
// resolved, a chunked response that stalls on the second chunk would
|
|
386
|
+
// block `response.text()` indefinitely.
|
|
387
|
+
let text: string;
|
|
388
|
+
try {
|
|
389
|
+
let response: Response;
|
|
390
|
+
try {
|
|
391
|
+
response = await fetch(url, { signal: handle.signal });
|
|
392
|
+
} catch (err) {
|
|
393
|
+
throw classifyFetchError(
|
|
394
|
+
err,
|
|
395
|
+
handle.timedOut,
|
|
396
|
+
opts.signal?.aborted === true,
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
if (!response.ok) {
|
|
401
|
+
throw new DevToolsDiscoveryError(
|
|
402
|
+
"invalid_response",
|
|
403
|
+
`DevTools /json/version returned HTTP ${response.status}.`,
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
try {
|
|
408
|
+
text = await readResponseText(response, handle, opts.signal);
|
|
409
|
+
} catch (err) {
|
|
410
|
+
if (err instanceof TimeoutDuringBodyReadError) {
|
|
411
|
+
throw classifyFetchError(
|
|
412
|
+
err.underlying,
|
|
413
|
+
err.timedOut,
|
|
414
|
+
err.callerAborted,
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
throw new DevToolsDiscoveryError(
|
|
418
|
+
"invalid_response",
|
|
419
|
+
"Failed to read /json/version response body.",
|
|
420
|
+
err,
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
} finally {
|
|
424
|
+
handle.cleanup();
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
const parsed = parseJsonText(text, "/json/version");
|
|
428
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
429
|
+
throw new DevToolsDiscoveryError(
|
|
430
|
+
"invalid_response",
|
|
431
|
+
"DevTools /json/version payload is not a JSON object.",
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const record = parsed as Record<string, unknown>;
|
|
436
|
+
const browser = readStringField(record, "Browser", "browser");
|
|
437
|
+
const protocolVersion = readStringField(
|
|
438
|
+
record,
|
|
439
|
+
"Protocol-Version",
|
|
440
|
+
"protocolVersion",
|
|
441
|
+
);
|
|
442
|
+
const webSocketDebuggerUrl = readStringField(
|
|
443
|
+
record,
|
|
444
|
+
"webSocketDebuggerUrl",
|
|
445
|
+
"WebSocketDebuggerUrl",
|
|
446
|
+
);
|
|
447
|
+
|
|
448
|
+
if (!browser || !protocolVersion || !webSocketDebuggerUrl) {
|
|
449
|
+
throw new DevToolsDiscoveryError(
|
|
450
|
+
"invalid_response",
|
|
451
|
+
"DevTools /json/version payload is missing required fields (browser, protocolVersion, webSocketDebuggerUrl).",
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (!/chrom(e|ium)/i.test(browser)) {
|
|
456
|
+
throw new DevToolsDiscoveryError(
|
|
457
|
+
"non_chrome",
|
|
458
|
+
`DevTools endpoint is not Chrome or Chromium: ${browser}`,
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
assertWsUrlLoopback(webSocketDebuggerUrl);
|
|
463
|
+
|
|
464
|
+
return { browser, protocolVersion, webSocketDebuggerUrl };
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Enumerate `/json/list` and return only usable page targets — i.e.
|
|
469
|
+
* `type === "page"` with a non-empty `webSocketDebuggerUrl`. Throws
|
|
470
|
+
* `no_targets` when the filtered list is empty so the caller doesn't
|
|
471
|
+
* have to decide how to phrase that.
|
|
472
|
+
*
|
|
473
|
+
* Sibling failure modes match {@link probeDevToolsJsonVersion}:
|
|
474
|
+
* `non_loopback`, `unreachable`, `timeout`, `invalid_response`.
|
|
475
|
+
*/
|
|
476
|
+
export async function listDevToolsTargets(opts: {
|
|
477
|
+
host: string;
|
|
478
|
+
port: number;
|
|
479
|
+
timeoutMs: number;
|
|
480
|
+
signal?: AbortSignal;
|
|
481
|
+
}): Promise<DevToolsTarget[]> {
|
|
482
|
+
assertLoopback(opts.host);
|
|
483
|
+
|
|
484
|
+
const url = buildUrl(opts.host, opts.port, "/json/list");
|
|
485
|
+
const handle = withTimeout(opts.timeoutMs, opts.signal);
|
|
486
|
+
|
|
487
|
+
// Keep `handle` active until AFTER the body has been read, so the
|
|
488
|
+
// timeout (and caller abort) still enforce against a server that
|
|
489
|
+
// stalls mid-body. See the matching comment in
|
|
490
|
+
// probeDevToolsJsonVersion for the exact failure mode this guards
|
|
491
|
+
// against.
|
|
492
|
+
let text: string;
|
|
493
|
+
try {
|
|
494
|
+
let response: Response;
|
|
495
|
+
try {
|
|
496
|
+
response = await fetch(url, { signal: handle.signal });
|
|
497
|
+
} catch (err) {
|
|
498
|
+
throw classifyFetchError(
|
|
499
|
+
err,
|
|
500
|
+
handle.timedOut,
|
|
501
|
+
opts.signal?.aborted === true,
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
if (!response.ok) {
|
|
506
|
+
throw new DevToolsDiscoveryError(
|
|
507
|
+
"invalid_response",
|
|
508
|
+
`DevTools /json/list returned HTTP ${response.status}.`,
|
|
509
|
+
);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
try {
|
|
513
|
+
text = await readResponseText(response, handle, opts.signal);
|
|
514
|
+
} catch (err) {
|
|
515
|
+
if (err instanceof TimeoutDuringBodyReadError) {
|
|
516
|
+
throw classifyFetchError(
|
|
517
|
+
err.underlying,
|
|
518
|
+
err.timedOut,
|
|
519
|
+
err.callerAborted,
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
throw new DevToolsDiscoveryError(
|
|
523
|
+
"invalid_response",
|
|
524
|
+
"Failed to read /json/list response body.",
|
|
525
|
+
err,
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
} finally {
|
|
529
|
+
handle.cleanup();
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
const parsed = parseJsonText(text, "/json/list");
|
|
533
|
+
if (!Array.isArray(parsed)) {
|
|
534
|
+
throw new DevToolsDiscoveryError(
|
|
535
|
+
"invalid_response",
|
|
536
|
+
"DevTools /json/list payload is not a JSON array.",
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
const targets: DevToolsTarget[] = [];
|
|
541
|
+
for (const entry of parsed) {
|
|
542
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
543
|
+
continue;
|
|
544
|
+
}
|
|
545
|
+
const record = entry as Record<string, unknown>;
|
|
546
|
+
const type = readStringField(record, "type");
|
|
547
|
+
if (type !== "page") continue;
|
|
548
|
+
|
|
549
|
+
const webSocketDebuggerUrl = readStringField(
|
|
550
|
+
record,
|
|
551
|
+
"webSocketDebuggerUrl",
|
|
552
|
+
);
|
|
553
|
+
if (!webSocketDebuggerUrl) continue;
|
|
554
|
+
|
|
555
|
+
try {
|
|
556
|
+
assertWsUrlLoopback(webSocketDebuggerUrl);
|
|
557
|
+
} catch {
|
|
558
|
+
continue;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
const id = readStringField(record, "id") ?? "";
|
|
562
|
+
const title = readStringField(record, "title") ?? "";
|
|
563
|
+
const targetUrl = readStringField(record, "url") ?? "";
|
|
564
|
+
|
|
565
|
+
targets.push({
|
|
566
|
+
id,
|
|
567
|
+
type,
|
|
568
|
+
title,
|
|
569
|
+
url: targetUrl,
|
|
570
|
+
webSocketDebuggerUrl,
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
if (targets.length === 0) {
|
|
575
|
+
throw new DevToolsDiscoveryError(
|
|
576
|
+
"no_targets",
|
|
577
|
+
"No usable page targets returned by DevTools /json/list.",
|
|
578
|
+
);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
return targets;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* Pick a sensible default target from a filtered list. Prefers targets
|
|
586
|
+
* whose URL is not `chrome://`, `devtools://`, or `about:blank`, then
|
|
587
|
+
* falls back to the first entry. Callers that need more specific
|
|
588
|
+
* control should iterate the list themselves.
|
|
589
|
+
*
|
|
590
|
+
* Throws `no_targets` on an empty input list — this mirrors the shape
|
|
591
|
+
* of {@link listDevToolsTargets}, so callers that chain the two can
|
|
592
|
+
* rely on a single error code path.
|
|
593
|
+
*/
|
|
594
|
+
export function pickDefaultTarget(targets: DevToolsTarget[]): DevToolsTarget {
|
|
595
|
+
if (targets.length === 0) {
|
|
596
|
+
throw new DevToolsDiscoveryError(
|
|
597
|
+
"no_targets",
|
|
598
|
+
"pickDefaultTarget called with an empty target list.",
|
|
599
|
+
);
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
const preferred = targets.find((target) => !isUtilityTarget(target));
|
|
603
|
+
return preferred ?? targets[0]!;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
function isUtilityTarget(target: DevToolsTarget): boolean {
|
|
607
|
+
const url = target.url.toLowerCase();
|
|
608
|
+
if (url.startsWith("chrome://")) return true;
|
|
609
|
+
if (url.startsWith("devtools://")) return true;
|
|
610
|
+
if (url === "about:blank") return true;
|
|
611
|
+
return false;
|
|
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
|
+
}
|