@vellumai/assistant 0.6.5 → 0.6.6
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/AGENTS.md +9 -1
- package/ARCHITECTURE.md +15 -17
- package/Dockerfile +6 -4
- package/__tests__/permissions/gateway-threshold-reader.test.ts +283 -0
- package/docs/architecture/integrations.md +32 -39
- package/docs/architecture/memory.md +25 -30
- package/docs/architecture/security.md +7 -6
- package/docs/browser-use-architecture-phase2.md +63 -20
- package/docs/plugins.md +761 -0
- package/examples/plugins/echo/README.md +132 -0
- package/examples/plugins/echo/package.json +17 -0
- package/examples/plugins/echo/register.ts +187 -0
- package/node_modules/@vellumai/egress-proxy/src/types.ts +19 -0
- package/openapi.yaml +212 -68
- package/package.json +1 -1
- package/src/__tests__/app-compiler.test.ts +57 -0
- package/src/__tests__/approval-cascade.test.ts +7 -2
- package/src/__tests__/auto-analysis-end-to-end.test.ts +1 -0
- package/src/__tests__/avatar-generator.test.ts +4 -2
- package/src/__tests__/bundled-asset.test.ts +6 -6
- package/src/__tests__/catalog-cache.test.ts +69 -0
- package/src/__tests__/checker.test.ts +459 -171
- package/src/__tests__/circuit-breaker-pipeline.test.ts +406 -0
- package/src/__tests__/compaction-events.test.ts +501 -0
- package/src/__tests__/compaction-pipeline.test.ts +210 -0
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +181 -0
- package/src/__tests__/compaction-timeout-recovery.test.ts +262 -0
- package/src/__tests__/config-model-image-provider.test.ts +110 -0
- package/src/__tests__/config-schema.test.ts +22 -9
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +0 -4
- package/src/__tests__/contacts-tools.test.ts +26 -0
- package/src/__tests__/context-overflow-policy.test.ts +7 -7
- package/src/__tests__/context-window-manager.test.ts +355 -4
- package/src/__tests__/conversation-abort-tool-results.test.ts +4 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +26 -30
- package/src/__tests__/conversation-agent-loop.test.ts +30 -141
- package/src/__tests__/conversation-confirmation-signals.test.ts +6 -1
- package/src/__tests__/conversation-history-web-search.test.ts +1 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +2 -16
- package/src/__tests__/conversation-pairing.test.ts +174 -10
- package/src/__tests__/conversation-pre-run-repair.test.ts +4 -1
- package/src/__tests__/conversation-process-callsite.test.ts +3 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +16 -7
- package/src/__tests__/conversation-queue.test.ts +29 -14
- package/src/__tests__/conversation-routes-disk-view.test.ts +7 -6
- package/src/__tests__/conversation-runtime-assembly.test.ts +155 -110
- package/src/__tests__/conversation-runtime-workspace.test.ts +23 -38
- package/src/__tests__/conversation-seed-composer.test.ts +2 -2
- package/src/__tests__/conversation-slash-queue.test.ts +7 -2
- package/src/__tests__/conversation-slash-unknown.test.ts +25 -2
- package/src/__tests__/conversation-speed-override.test.ts +6 -1
- package/src/__tests__/conversation-title-service.test.ts +116 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +41 -2
- package/src/__tests__/conversation-usage.test.ts +1 -1
- package/src/__tests__/conversation-workspace-cache-state.test.ts +4 -1
- package/src/__tests__/conversation-workspace-injection.test.ts +3 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +4 -1
- package/src/__tests__/credential-health-service.test.ts +78 -9
- package/src/__tests__/credential-security-invariants.test.ts +2 -2
- package/src/__tests__/db-schedule-syntax-migration.test.ts +1 -0
- package/src/__tests__/empty-response-pipeline.test.ts +305 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +3 -3
- package/src/__tests__/first-greeting.test.ts +247 -5
- package/src/__tests__/headless-browser-mode.test.ts +57 -0
- package/src/__tests__/history-repair-pipeline.test.ts +399 -0
- package/src/__tests__/host-browser-e2e-cloud.test.ts +307 -0
- package/src/__tests__/host-browser-e2e-self-hosted.test.ts +3 -3
- package/src/__tests__/host-proxy-interface.test.ts +36 -2
- package/src/__tests__/image-credentials.test.ts +137 -0
- package/src/__tests__/image-service-dispatcher.test.ts +186 -0
- package/src/__tests__/injector-chain.test.ts +526 -0
- package/src/__tests__/intent-routing.test.ts +0 -26
- package/src/__tests__/llm-call-pipeline.test.ts +285 -0
- package/src/__tests__/llm-schema.test.ts +1 -1
- package/src/__tests__/media-generate-image.test.ts +119 -13
- package/src/__tests__/memory-retrieval-pipeline.test.ts +401 -0
- package/src/__tests__/memory-upsert-concurrency.test.ts +1 -0
- package/src/__tests__/migration-import-from-url.test.ts +5 -68
- package/src/__tests__/model-intents.test.ts +4 -2
- package/src/__tests__/notification-broadcaster.test.ts +3 -3
- package/src/__tests__/notification-decision-strategy.test.ts +0 -11
- package/src/__tests__/notification-schedule-notify-dedup.test.ts +108 -0
- package/src/__tests__/oauth-apps-routes.test.ts +1 -1
- package/src/__tests__/oauth-cli.test.ts +14 -12
- package/src/__tests__/oauth-connect-orchestrator.test.ts +4 -13
- package/src/__tests__/oauth-provider-serializer.test.ts +6 -4
- package/src/__tests__/oauth-provider-visibility.test.ts +3 -5
- package/src/__tests__/oauth-providers-routes.test.ts +3 -2
- package/src/__tests__/oauth-store.test.ts +41 -76
- package/src/__tests__/onboarding-template-contract.test.ts +16 -64
- package/src/__tests__/openai-image-service.test.ts +368 -0
- package/src/__tests__/overflow-reduce-pipeline.test.ts +676 -0
- package/src/__tests__/permission-checker-host-gate.test.ts +0 -24
- package/src/__tests__/persist-onboarding-artifacts.test.ts +266 -0
- package/src/__tests__/persistence-pipeline.test.ts +377 -0
- package/src/__tests__/pipeline-runner.test.ts +565 -0
- package/src/__tests__/platform.test.ts +5 -2
- package/src/__tests__/plugin-bootstrap.test.ts +483 -0
- package/src/__tests__/plugin-registry.test.ts +273 -0
- package/src/__tests__/plugin-route-contribution.test.ts +288 -0
- package/src/__tests__/plugin-skill-contribution.test.ts +367 -0
- package/src/__tests__/plugin-tool-contribution.test.ts +286 -0
- package/src/__tests__/plugin-types.test.ts +320 -0
- package/src/__tests__/pricing.test.ts +44 -12
- package/src/__tests__/proxy-approval-callback.test.ts +69 -8
- package/src/__tests__/reaction-persistence.test.ts +1 -0
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
- package/src/__tests__/registry.test.ts +0 -2
- package/src/__tests__/schedule-routes.test.ts +131 -1
- package/src/__tests__/scheduler-recurrence.test.ts +14 -70
- package/src/__tests__/scheduler-reuse-conversation.test.ts +10 -50
- package/src/__tests__/secret-detection-handler.test.ts +0 -10
- package/src/__tests__/shell-identity.test.ts +0 -134
- package/src/__tests__/suggestion-routes.test.ts +103 -4
- package/src/__tests__/task-memory-cleanup.test.ts +1 -0
- package/src/__tests__/task-scheduler.test.ts +3 -15
- package/src/__tests__/test-preload.ts +11 -0
- package/src/__tests__/title-generate-pipeline.test.ts +224 -0
- package/src/__tests__/token-estimate-pipeline.test.ts +431 -0
- package/src/__tests__/tool-error-pipeline.test.ts +244 -0
- package/src/__tests__/tool-execute-pipeline.test.ts +431 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -6
- package/src/__tests__/tool-executor-shell-integration.test.ts +7 -10
- package/src/__tests__/tool-executor.test.ts +141 -0
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +356 -0
- package/src/__tests__/tool-result-truncation.test.ts +0 -110
- package/src/__tests__/user-plugin-loader.test.ts +191 -0
- package/src/__tests__/workspace-migration-046-seed-conversation-starters-callsite.test.ts +185 -0
- package/src/__tests__/workspace-migration-049-release-notes-default-sonnet.test.ts +100 -0
- package/src/__tests__/workspace-migration-050-seed-main-agent-opus-callsite.test.ts +171 -0
- package/src/__tests__/workspace-migration-051-seed-conversation-summarization-callsite.test.ts +252 -0
- package/src/__tests__/workspace-migration-remove-hooks.test.ts +99 -0
- package/src/__tests__/workspace-policy.test.ts +21 -3
- package/src/agent/loop.ts +340 -102
- package/src/approvals/__tests__/guardian-feed-event.test.ts +304 -0
- package/src/approvals/guardian-request-resolvers.ts +80 -0
- package/src/backup/__tests__/backup-worker.test.ts +2 -13
- package/src/backup/backup-worker.ts +3 -15
- package/src/bundler/app-compiler.ts +84 -1
- package/src/calls/call-state.ts +2 -2
- package/src/channels/__tests__/types.test.ts +3 -3
- package/src/channels/types.ts +6 -4
- package/src/cli/__tests__/notifications.test.ts +87 -211
- package/src/cli/commands/__tests__/backup.test.ts +1 -1
- package/src/cli/commands/__tests__/image-generation.test.ts +255 -35
- package/src/cli/commands/__tests__/inference-send.test.ts +12 -0
- package/src/cli/commands/__tests__/tts-synthesize.test.ts +12 -0
- package/src/cli/commands/backup.ts +2 -2
- package/src/cli/commands/clients.ts +138 -0
- package/src/cli/commands/completions.ts +2 -9
- package/src/cli/commands/conversations.ts +55 -7
- package/src/cli/commands/image-generation.ts +33 -34
- package/src/cli/commands/notifications.ts +68 -103
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -1
- package/src/cli/commands/oauth/connect.ts +2 -2
- package/src/cli/commands/oauth/providers.ts +176 -8
- package/src/cli/commands/oauth/status.ts +46 -36
- package/src/cli/commands/skills.ts +3 -4
- package/src/cli/program.ts +25 -29
- package/src/config/__tests__/backup-schema.test.ts +7 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
- package/src/config/bundled-skills/app-builder/references/WIDGETS.md +10 -10
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +66 -87
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +28 -51
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +22 -40
- package/src/config/bundled-skills/image-studio/SKILL.md +2 -1
- package/src/config/bundled-skills/image-studio/TOOLS.json +2 -1
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +23 -39
- package/src/config/bundled-skills/messaging/SKILL.md +3 -3
- package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +207 -0
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +12 -0
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +58 -0
- package/src/config/bundled-skills/schedule/SKILL.md +8 -3
- package/src/config/bundled-skills/schedule/TOOLS.json +15 -7
- package/src/config/bundled-skills/schedule/references/SCRIPT_MODE_PATTERNS.md +59 -0
- package/src/config/bundled-tool-registry.ts +0 -15
- package/src/config/feature-flag-registry.json +17 -1
- package/src/config/schema.ts +19 -0
- package/src/config/schemas/backup.ts +1 -1
- package/src/config/schemas/conversations.ts +16 -0
- package/src/config/schemas/llm.ts +2 -3
- package/src/config/schemas/security.ts +6 -6
- package/src/config/schemas/tts.ts +11 -0
- package/src/config/skill-state.ts +6 -2
- package/src/config/skills.ts +94 -5
- package/src/context/__tests__/compact-prompt.test.ts +27 -9
- package/src/context/prompts/compact.md +26 -12
- package/src/context/tool-result-truncation.ts +3 -63
- package/src/context/window-manager.ts +190 -16
- package/src/credential-health/credential-health-service.ts +19 -6
- package/src/daemon/__tests__/conversation-feed-event.test.ts +317 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +4 -12
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +14 -15
- package/src/daemon/config-watcher.ts +0 -2
- package/src/daemon/context-overflow-policy.ts +4 -13
- package/src/daemon/conversation-agent-loop-handlers.ts +83 -22
- package/src/daemon/conversation-agent-loop.ts +984 -683
- package/src/daemon/conversation-history.ts +10 -19
- package/src/daemon/conversation-lifecycle.ts +37 -19
- package/src/daemon/conversation-notifiers.ts +2 -110
- package/src/daemon/conversation-process.ts +14 -7
- package/src/daemon/conversation-runtime-assembly.ts +532 -411
- package/src/daemon/conversation-tool-setup.ts +41 -4
- package/src/daemon/conversation.ts +80 -35
- package/src/daemon/external-plugins-bootstrap.ts +478 -0
- package/src/daemon/first-greeting.ts +191 -14
- package/src/daemon/handlers/config-model.ts +11 -0
- package/src/daemon/handlers/skills.ts +5 -1
- package/src/daemon/lifecycle.ts +33 -68
- package/src/daemon/message-types/computer-use.ts +2 -34
- package/src/daemon/message-types/conversations.ts +49 -0
- package/src/daemon/message-types/messages.ts +12 -0
- package/src/daemon/server.ts +5 -3
- package/src/daemon/shutdown-handlers.ts +2 -12
- package/src/daemon/tool-side-effects.ts +14 -56
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +160 -0
- package/src/heartbeat/heartbeat-service.ts +24 -1
- package/src/home/__tests__/feed-population-integration.test.ts +312 -0
- package/src/home/emit-feed-event.ts +7 -0
- package/src/home/feed-types.ts +41 -2
- package/src/home/rewrite-command-preview.ts +66 -0
- package/src/ipc/__tests__/socket-path.test.ts +11 -50
- package/src/ipc/cli-client.ts +1 -1
- package/src/ipc/cli-server.ts +3 -3
- package/src/ipc/gateway-client.ts +4 -1
- package/src/ipc/routes/browser-context.ts +2 -0
- package/src/ipc/routes/browser.ts +1 -0
- package/src/ipc/routes/get-contact.ts +16 -0
- package/src/ipc/routes/index.ts +14 -0
- package/src/ipc/routes/list-clients.ts +31 -0
- package/src/ipc/routes/merge-contacts.ts +17 -0
- package/src/ipc/routes/notification.ts +133 -0
- package/src/ipc/routes/rename-conversation.ts +59 -0
- package/src/ipc/routes/search-contacts.ts +19 -0
- package/src/ipc/routes/upsert-contact.ts +25 -0
- package/src/ipc/socket-path.ts +14 -38
- package/src/media/app-icon-generator.ts +23 -46
- package/src/media/avatar-router.ts +26 -41
- package/src/media/gemini-image-service.ts +8 -41
- package/src/media/image-credentials.ts +73 -0
- package/src/media/image-service.ts +85 -0
- package/src/media/openai-image-service.ts +131 -0
- package/src/media/types.ts +46 -0
- package/src/memory/conversation-crud.ts +48 -18
- package/src/memory/conversation-queries.ts +57 -4
- package/src/memory/conversation-title-service.ts +25 -0
- package/src/memory/db-init.ts +8 -0
- package/src/memory/embedding-gemini.test.ts +41 -2
- package/src/memory/embedding-gemini.ts +6 -1
- package/src/memory/graph/bootstrap.test.ts +282 -0
- package/src/memory/graph/bootstrap.ts +8 -5
- package/src/memory/graph/extraction.ts +10 -2
- package/src/memory/graph/graph-search.test.ts +1 -0
- package/src/memory/graph/inspect.ts +2 -2
- package/src/memory/graph/retriever.ts +10 -3
- package/src/memory/migrations/041-approval-prompt-ts-tracker.ts +26 -0
- package/src/memory/migrations/149-oauth-tables.ts +1 -0
- package/src/memory/migrations/223-schedule-script-column.ts +11 -0
- package/src/memory/migrations/224-oauth-providers-managed-service-is-paid.ts +24 -0
- package/src/memory/migrations/225-oauth-providers-available-scopes.ts +13 -0
- package/src/memory/migrations/index.ts +4 -0
- package/src/memory/pkb/pkb-index.test.ts +1 -0
- package/src/memory/pkb/pkb-reconcile.test.ts +1 -0
- package/src/memory/pkb/pkb-search.test.ts +65 -4
- package/src/memory/pkb/pkb-search.ts +40 -18
- package/src/memory/qdrant-client.test.ts +60 -0
- package/src/memory/qdrant-client.ts +25 -0
- package/src/memory/schema/infrastructure.ts +1 -0
- package/src/memory/schema/oauth.ts +4 -1
- package/src/messaging/providers/slack/render-transcript.test.ts +77 -29
- package/src/messaging/providers/slack/render-transcript.ts +58 -0
- package/src/notifications/conversation-pairing.ts +78 -19
- package/src/notifications/copy-composer.ts +0 -5
- package/src/notifications/emit-signal.ts +1 -1
- package/src/notifications/signal.ts +1 -2
- package/src/oauth/AGENTS.md +1 -1
- package/src/oauth/__tests__/identity-verifier.test.ts +2 -1
- package/src/oauth/connect-orchestrator.ts +8 -34
- package/src/oauth/connect-types.ts +6 -10
- package/src/oauth/manual-token-connection.ts +23 -0
- package/src/oauth/oauth-store.ts +30 -14
- package/src/oauth/provider-serializer.ts +6 -1
- package/src/oauth/seed-providers.ts +56 -108
- package/src/outbound-proxy/http-forwarder.ts +9 -0
- package/src/permissions/approval-policy.test.ts +293 -18
- package/src/permissions/approval-policy.ts +110 -58
- package/src/permissions/arg-parser.test.ts +161 -0
- package/src/permissions/arg-parser.ts +141 -0
- package/src/permissions/bash-risk-classifier.test.ts +414 -2
- package/src/permissions/bash-risk-classifier.ts +303 -60
- package/src/permissions/checker.ts +157 -29
- package/src/permissions/command-registry.test.ts +239 -0
- package/src/permissions/command-registry.ts +234 -54
- package/src/permissions/defaults.ts +5 -4
- package/src/permissions/gateway-threshold-reader.ts +196 -0
- package/src/permissions/prompter.ts +4 -0
- package/src/permissions/risk-types.ts +61 -4
- package/src/permissions/schedule-risk-classifier.test.ts +129 -0
- package/src/permissions/schedule-risk-classifier.ts +85 -0
- package/src/permissions/shell-identity.ts +2 -42
- package/src/permissions/types.ts +2 -0
- package/src/permissions/workspace-policy.ts +8 -3
- package/src/plugins/defaults/circuit-breaker.ts +146 -0
- package/src/plugins/defaults/compaction.ts +145 -0
- package/src/plugins/defaults/empty-response.ts +126 -0
- package/src/plugins/defaults/history-repair.ts +85 -0
- package/src/plugins/defaults/index.ts +116 -0
- package/src/plugins/defaults/injectors.ts +491 -0
- package/src/plugins/defaults/llm-call.ts +82 -0
- package/src/plugins/defaults/memory-retrieval.ts +226 -0
- package/src/plugins/defaults/overflow-reduce.ts +181 -0
- package/src/plugins/defaults/persistence.ts +129 -0
- package/src/plugins/defaults/title-generate.ts +95 -0
- package/src/plugins/defaults/token-estimate.ts +104 -0
- package/src/plugins/defaults/tool-error.ts +126 -0
- package/src/plugins/defaults/tool-execute.ts +89 -0
- package/src/plugins/defaults/tool-result-truncate.ts +88 -0
- package/src/plugins/pipeline.ts +316 -0
- package/src/plugins/plugin-skill-contributions.ts +292 -0
- package/src/plugins/registry.ts +241 -0
- package/src/plugins/types.ts +1134 -0
- package/src/plugins/user-loader.ts +177 -0
- package/src/prompts/templates/BOOTSTRAP.md +27 -77
- package/src/providers/model-catalog.ts +52 -29
- package/src/providers/model-intents.ts +1 -1
- package/src/providers/openrouter/client.ts +5 -1
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +61 -0
- package/src/providers/speech-to-text/deepgram-realtime.ts +57 -0
- package/src/providers/speech-to-text/xai-realtime.test.ts +72 -4
- package/src/providers/speech-to-text/xai-realtime.ts +39 -14
- package/src/runtime/AGENTS.md +25 -16
- package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +3 -3
- package/src/runtime/__tests__/client-registry.test.ts +293 -0
- package/src/runtime/client-registry.ts +261 -0
- package/src/runtime/http-server.ts +77 -8
- package/src/runtime/http-types.ts +0 -2
- package/src/runtime/migrations/vbundle-builder.ts +1 -22
- package/src/runtime/routes/approval-prompt-ts-tracker.ts +51 -31
- package/src/runtime/routes/approval-routes.ts +17 -0
- package/src/runtime/routes/browser-extension-pair-routes.ts +27 -8
- package/src/runtime/routes/conversation-routes.ts +223 -116
- package/src/runtime/routes/inbound-message-handler.ts +88 -13
- package/src/runtime/routes/memory-item-routes.test.ts +1 -0
- package/src/runtime/routes/migration-routes.ts +0 -3
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +284 -0
- package/src/runtime/routes/playground/__tests__/guard.test.ts +80 -0
- package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +294 -0
- package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +271 -0
- package/src/runtime/routes/playground/__tests__/seed-conversation.test.ts +202 -0
- package/src/runtime/routes/playground/__tests__/seeded-conversations.test.ts +309 -0
- package/src/runtime/routes/playground/__tests__/state.test.ts +224 -0
- package/src/runtime/routes/playground/conversation-not-found.ts +29 -0
- package/src/runtime/routes/playground/deps.ts +56 -0
- package/src/runtime/routes/playground/force-compact.ts +73 -0
- package/src/runtime/routes/playground/guard.ts +37 -0
- package/src/runtime/routes/playground/index.ts +28 -0
- package/src/runtime/routes/playground/inject-failures.ts +159 -0
- package/src/runtime/routes/playground/reset-circuit.ts +115 -0
- package/src/runtime/routes/playground/seed-conversation.ts +139 -0
- package/src/runtime/routes/playground/seeded-conversations.ts +78 -0
- package/src/runtime/routes/playground/state.ts +78 -0
- package/src/runtime/routes/schedule-routes.ts +89 -8
- package/src/runtime/skill-route-registry.ts +75 -15
- package/src/schedule/run-script.ts +68 -0
- package/src/schedule/schedule-store.ts +7 -1
- package/src/schedule/scheduler.ts +48 -8
- package/src/skills/catalog-cache.ts +12 -5
- package/src/tools/browser/__tests__/browser-status.test.ts +189 -0
- package/src/tools/browser/browser-execution.ts +88 -19
- package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +230 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +146 -3
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +54 -3
- package/src/tools/browser/cdp-client/factory.ts +15 -4
- package/src/tools/executor.ts +126 -74
- package/src/tools/network/script-proxy/session-manager.ts +37 -1
- package/src/tools/permission-checker.ts +98 -49
- package/src/tools/policy-context.ts +4 -0
- package/src/tools/registry.ts +140 -3
- package/src/tools/schedule/create.ts +23 -8
- package/src/tools/schedule/update.ts +3 -1
- package/src/tools/secret-detection-handler.ts +0 -51
- package/src/tools/system/avatar-generator.ts +6 -2
- package/src/tools/types.ts +28 -2
- package/src/util/platform.ts +7 -2
- package/src/util/pricing.ts +26 -3
- package/src/workspace/migrations/006-services-config.ts +2 -4
- package/src/workspace/migrations/022-move-hooks-to-workspace.ts +2 -3
- package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +3 -4
- package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +108 -0
- package/src/workspace/migrations/047-remove-watch-callsites.ts +54 -0
- package/src/workspace/migrations/048-remove-workspace-hooks.ts +81 -0
- package/src/workspace/migrations/049-release-notes-default-sonnet.ts +80 -0
- package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +86 -0
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +128 -0
- package/src/workspace/migrations/registry.ts +12 -0
- package/tsconfig.json +1 -1
- package/hook-templates/debug-prompt-logger/hook.json +0 -7
- package/hook-templates/debug-prompt-logger/run.sh +0 -66
- package/src/__tests__/compaction-circuit-breaker.test.ts +0 -336
- package/src/__tests__/context-overflow-approval.test.ts +0 -156
- package/src/__tests__/hooks-blocking.test.ts +0 -178
- package/src/__tests__/hooks-cli.test.ts +0 -182
- package/src/__tests__/hooks-config.test.ts +0 -108
- package/src/__tests__/hooks-discovery.test.ts +0 -211
- package/src/__tests__/hooks-integration.test.ts +0 -196
- package/src/__tests__/hooks-manager.test.ts +0 -226
- package/src/__tests__/hooks-runner.test.ts +0 -175
- package/src/__tests__/hooks-settings.test.ts +0 -160
- package/src/__tests__/hooks-templates.test.ts +0 -169
- package/src/__tests__/hooks-ts-runner.test.ts +0 -170
- package/src/__tests__/hooks-watch.test.ts +0 -112
- package/src/__tests__/notification-schedule-dedup.test.ts +0 -213
- package/src/__tests__/oauth-scope-policy.test.ts +0 -180
- package/src/__tests__/send-notification-tool.test.ts +0 -83
- package/src/cli/commands/shotgun.ts +0 -266
- package/src/config/bundled-skills/conversations/SKILL.md +0 -20
- package/src/config/bundled-skills/conversations/TOOLS.json +0 -23
- package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +0 -88
- package/src/config/bundled-skills/heartbeat/SKILL.md +0 -43
- package/src/config/bundled-skills/notifications/SKILL.md +0 -40
- package/src/config/bundled-skills/notifications/TOOLS.json +0 -80
- package/src/config/bundled-skills/notifications/tools/send-notification.ts +0 -152
- package/src/config/bundled-skills/notifications/tools/shared.ts +0 -13
- package/src/config/bundled-skills/screen-watch/SKILL.md +0 -27
- package/src/config/bundled-skills/screen-watch/TOOLS.json +0 -35
- package/src/config/bundled-skills/screen-watch/tools/start-screen-watch.ts +0 -12
- package/src/config/bundled-skills/skills-catalog/SKILL.md +0 -84
- package/src/daemon/context-overflow-approval.ts +0 -52
- package/src/daemon/watch-handler.ts +0 -399
- package/src/hooks/cli.ts +0 -253
- package/src/hooks/config.ts +0 -100
- package/src/hooks/discovery.ts +0 -135
- package/src/hooks/manager.ts +0 -179
- package/src/hooks/runner.ts +0 -117
- package/src/hooks/templates.ts +0 -77
- package/src/hooks/types.ts +0 -75
- package/src/oauth/scope-policy.ts +0 -89
- package/src/runtime/gateway-internal-client.ts +0 -94
- package/src/runtime/routes/watch-routes.ts +0 -156
- package/src/signals/shotgun.ts +0 -203
- package/src/tools/watch/screen-watch.ts +0 -144
- package/src/tools/watch/watch-state.ts +0 -142
|
@@ -163,4 +163,193 @@ describe("executeBrowserStatus", () => {
|
|
|
163
163
|
expect(extension.verified).toBe("active_probe");
|
|
164
164
|
expect(extension.details.restrictedActiveTab).toBe(true);
|
|
165
165
|
});
|
|
166
|
+
|
|
167
|
+
// ── macOS host-browser proxy mode tests ─────────────────────────────
|
|
168
|
+
|
|
169
|
+
test("macOS: reports host browser proxy as available when proxy is bound and connected", async () => {
|
|
170
|
+
const result = await executeBrowserStatus(
|
|
171
|
+
{},
|
|
172
|
+
makeContext({
|
|
173
|
+
transportInterface: "macos",
|
|
174
|
+
hostBrowserProxy: {
|
|
175
|
+
isAvailable: () => true,
|
|
176
|
+
} as ToolContext["hostBrowserProxy"],
|
|
177
|
+
}),
|
|
178
|
+
);
|
|
179
|
+
expect(result.isError).toBe(false);
|
|
180
|
+
const payload = JSON.parse(result.content);
|
|
181
|
+
const extension = payload.modes.find(
|
|
182
|
+
(m: { mode: string }) => m.mode === BROWSER_STATUS_MODE.EXTENSION,
|
|
183
|
+
);
|
|
184
|
+
expect(extension).toBeDefined();
|
|
185
|
+
expect(extension.available).toBe(true);
|
|
186
|
+
expect(extension.verified).toBe("active_probe");
|
|
187
|
+
expect(extension.summary).toContain("macOS host browser proxy");
|
|
188
|
+
expect(extension.details.transport).toBe("macos-sse");
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
test("macOS: reports transport as extension-ws when hostBrowserRegistryRouted is true", async () => {
|
|
192
|
+
const result = await executeBrowserStatus(
|
|
193
|
+
{},
|
|
194
|
+
makeContext({
|
|
195
|
+
transportInterface: "macos",
|
|
196
|
+
hostBrowserRegistryRouted: true,
|
|
197
|
+
hostBrowserProxy: {
|
|
198
|
+
isAvailable: () => true,
|
|
199
|
+
} as ToolContext["hostBrowserProxy"],
|
|
200
|
+
}),
|
|
201
|
+
);
|
|
202
|
+
expect(result.isError).toBe(false);
|
|
203
|
+
const payload = JSON.parse(result.content);
|
|
204
|
+
const extension = payload.modes.find(
|
|
205
|
+
(m: { mode: string }) => m.mode === BROWSER_STATUS_MODE.EXTENSION,
|
|
206
|
+
);
|
|
207
|
+
expect(extension).toBeDefined();
|
|
208
|
+
expect(extension.available).toBe(true);
|
|
209
|
+
expect(extension.details.transport).toBe("extension-ws");
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
test("macOS: reports proxy unbound with macOS-specific actions when no proxy is present", async () => {
|
|
213
|
+
const result = await executeBrowserStatus(
|
|
214
|
+
{},
|
|
215
|
+
makeContext({
|
|
216
|
+
transportInterface: "macos",
|
|
217
|
+
}),
|
|
218
|
+
);
|
|
219
|
+
expect(result.isError).toBe(false);
|
|
220
|
+
const payload = JSON.parse(result.content);
|
|
221
|
+
const extension = payload.modes.find(
|
|
222
|
+
(m: { mode: string }) => m.mode === BROWSER_STATUS_MODE.EXTENSION,
|
|
223
|
+
);
|
|
224
|
+
expect(extension).toBeDefined();
|
|
225
|
+
expect(extension.available).toBe(false);
|
|
226
|
+
expect(extension.summary).toContain("macOS host browser proxy");
|
|
227
|
+
expect(extension.summary).toContain("desktop client");
|
|
228
|
+
expect(extension.details.transport).toBe("macos-sse");
|
|
229
|
+
// macOS-specific user actions should mention the desktop app, not the extension
|
|
230
|
+
expect(
|
|
231
|
+
extension.userActions.some((a: string) => a.includes("desktop app")),
|
|
232
|
+
).toBe(true);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
test("macOS: reports proxy disconnected with reconnect actions when proxy is bound but not available", async () => {
|
|
236
|
+
const result = await executeBrowserStatus(
|
|
237
|
+
{},
|
|
238
|
+
makeContext({
|
|
239
|
+
transportInterface: "macos",
|
|
240
|
+
hostBrowserProxy: {
|
|
241
|
+
isAvailable: () => false,
|
|
242
|
+
} as ToolContext["hostBrowserProxy"],
|
|
243
|
+
}),
|
|
244
|
+
);
|
|
245
|
+
expect(result.isError).toBe(false);
|
|
246
|
+
const payload = JSON.parse(result.content);
|
|
247
|
+
const extension = payload.modes.find(
|
|
248
|
+
(m: { mode: string }) => m.mode === BROWSER_STATUS_MODE.EXTENSION,
|
|
249
|
+
);
|
|
250
|
+
expect(extension).toBeDefined();
|
|
251
|
+
expect(extension.available).toBe(false);
|
|
252
|
+
expect(extension.summary).toContain("macOS host browser proxy");
|
|
253
|
+
expect(extension.summary).toContain("SSE transport");
|
|
254
|
+
expect(extension.details.transport).toBe("macos-sse");
|
|
255
|
+
// Should suggest reconnection, not extension install
|
|
256
|
+
expect(
|
|
257
|
+
extension.userActions.some((a: string) => a.includes("desktop app")),
|
|
258
|
+
).toBe(true);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
test("macOS: probe failure diagnostics include transport-specific remediation", async () => {
|
|
262
|
+
probeOutcomes[BROWSER_STATUS_MODE.EXTENSION] = "fail";
|
|
263
|
+
probeErrors[BROWSER_STATUS_MODE.EXTENSION] = new CdpError(
|
|
264
|
+
"transport_error",
|
|
265
|
+
"transport disconnected before response",
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
const result = await executeBrowserStatus(
|
|
269
|
+
{},
|
|
270
|
+
makeContext({
|
|
271
|
+
transportInterface: "macos",
|
|
272
|
+
hostBrowserProxy: {
|
|
273
|
+
isAvailable: () => true,
|
|
274
|
+
} as ToolContext["hostBrowserProxy"],
|
|
275
|
+
}),
|
|
276
|
+
);
|
|
277
|
+
expect(result.isError).toBe(false);
|
|
278
|
+
const payload = JSON.parse(result.content);
|
|
279
|
+
const extension = payload.modes.find(
|
|
280
|
+
(m: { mode: string }) => m.mode === BROWSER_STATUS_MODE.EXTENSION,
|
|
281
|
+
);
|
|
282
|
+
expect(extension).toBeDefined();
|
|
283
|
+
expect(extension.available).toBe(false);
|
|
284
|
+
expect(extension.summary).toContain("macOS host browser proxy");
|
|
285
|
+
// Should have remediation actions mentioning SSE bridge
|
|
286
|
+
expect(
|
|
287
|
+
extension.userActions.some((a: string) => a.includes("SSE bridge")),
|
|
288
|
+
).toBe(true);
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
test("recommendation order follows auto candidate precedence for macOS with available extension proxy", async () => {
|
|
292
|
+
const result = await executeBrowserStatus(
|
|
293
|
+
{},
|
|
294
|
+
makeContext({
|
|
295
|
+
transportInterface: "macos",
|
|
296
|
+
hostBrowserProxy: {
|
|
297
|
+
isAvailable: () => true,
|
|
298
|
+
} as ToolContext["hostBrowserProxy"],
|
|
299
|
+
}),
|
|
300
|
+
);
|
|
301
|
+
expect(result.isError).toBe(false);
|
|
302
|
+
const payload = JSON.parse(result.content);
|
|
303
|
+
// Extension is the top auto candidate and is available, so it should be recommended
|
|
304
|
+
expect(payload.recommendedMode).toBe(BROWSER_STATUS_MODE.EXTENSION);
|
|
305
|
+
expect(payload.autoCandidateOrder[0]).toBe(BROWSER_STATUS_MODE.EXTENSION);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
test("recommendation falls to cdp-inspect when macOS proxy is unavailable", async () => {
|
|
309
|
+
// Extension probe fails
|
|
310
|
+
probeOutcomes[BROWSER_STATUS_MODE.EXTENSION] = "fail";
|
|
311
|
+
probeErrors[BROWSER_STATUS_MODE.EXTENSION] = new CdpError(
|
|
312
|
+
"transport_error",
|
|
313
|
+
"proxy not connected",
|
|
314
|
+
);
|
|
315
|
+
|
|
316
|
+
const result = await executeBrowserStatus(
|
|
317
|
+
{},
|
|
318
|
+
makeContext({
|
|
319
|
+
transportInterface: "macos",
|
|
320
|
+
// No proxy bound, so extension unavailable
|
|
321
|
+
}),
|
|
322
|
+
);
|
|
323
|
+
expect(result.isError).toBe(false);
|
|
324
|
+
const payload = JSON.parse(result.content);
|
|
325
|
+
// Extension is unavailable (no proxy), so recommendation should fall to next available
|
|
326
|
+
expect(payload.recommendedMode).toBe(BROWSER_STATUS_MODE.CDP_INSPECT);
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
test("macOS: restricted chrome:// page probe includes macOS transport details", async () => {
|
|
330
|
+
probeOutcomes[BROWSER_STATUS_MODE.EXTENSION] = "fail";
|
|
331
|
+
probeErrors[BROWSER_STATUS_MODE.EXTENSION] = new CdpError(
|
|
332
|
+
"cdp_error",
|
|
333
|
+
"Cannot access a chrome:// URL",
|
|
334
|
+
);
|
|
335
|
+
|
|
336
|
+
const result = await executeBrowserStatus(
|
|
337
|
+
{},
|
|
338
|
+
makeContext({
|
|
339
|
+
transportInterface: "macos",
|
|
340
|
+
hostBrowserProxy: {
|
|
341
|
+
isAvailable: () => true,
|
|
342
|
+
} as ToolContext["hostBrowserProxy"],
|
|
343
|
+
}),
|
|
344
|
+
);
|
|
345
|
+
expect(result.isError).toBe(false);
|
|
346
|
+
const payload = JSON.parse(result.content);
|
|
347
|
+
const extension = payload.modes.find(
|
|
348
|
+
(m: { mode: string }) => m.mode === BROWSER_STATUS_MODE.EXTENSION,
|
|
349
|
+
);
|
|
350
|
+
expect(extension).toBeDefined();
|
|
351
|
+
expect(extension.available).toBe(true);
|
|
352
|
+
expect(extension.summary).toContain("macOS host browser proxy");
|
|
353
|
+
expect(extension.details.transport).toBe("macos-sse");
|
|
354
|
+
});
|
|
166
355
|
});
|
|
@@ -88,9 +88,9 @@ type StatusCheckMode = BrowserStatusMode;
|
|
|
88
88
|
const MODE_TRADEOFFS: Record<StatusCheckMode, string[]> = {
|
|
89
89
|
[BROWSER_STATUS_MODE.EXTENSION]: [
|
|
90
90
|
"This is the preferred approach for all things browser-use.",
|
|
91
|
-
"
|
|
91
|
+
"On macOS, the host browser proxy is provisioned automatically via the desktop client's SSE bridge — no extension install required.",
|
|
92
|
+
"When the Chrome extension is also installed, it takes priority for direct WebSocket routing to the user's Chrome session.",
|
|
92
93
|
"More secure than relying on Chrome's native remote debugging functionality.",
|
|
93
|
-
"Requires the Vellum extension to be paired and actively connected.",
|
|
94
94
|
],
|
|
95
95
|
[BROWSER_STATUS_MODE.CDP_INSPECT]: [
|
|
96
96
|
"This is the second-best approach for all things browser-use, after the native Vellum Assistant Chrome Extension.",
|
|
@@ -190,9 +190,10 @@ export function parseBrowserMode(
|
|
|
190
190
|
const REMEDIATION_HINTS: Record<string, string[]> = {
|
|
191
191
|
// Extension backend
|
|
192
192
|
"extension:transport_error": [
|
|
193
|
-
"Ensure the Vellum browser extension is installed and enabled.",
|
|
194
|
-
"
|
|
195
|
-
"
|
|
193
|
+
"Ensure the Vellum browser extension is installed and enabled, or that the macOS desktop client is running for host browser proxy mode.",
|
|
194
|
+
"For extension mode: check that the extension WebSocket connection is active (extension popup → status).",
|
|
195
|
+
"For macOS host browser proxy: verify the desktop client is running and has an active SSE connection to the assistant.",
|
|
196
|
+
"Try reconnecting the extension or restarting the desktop client.",
|
|
196
197
|
],
|
|
197
198
|
// cdp-inspect backend — discovery-level failures
|
|
198
199
|
"cdp-inspect:unreachable": [
|
|
@@ -2098,6 +2099,43 @@ function extensionSetupActions(): string[] {
|
|
|
2098
2099
|
];
|
|
2099
2100
|
}
|
|
2100
2101
|
|
|
2102
|
+
function macOSHostBrowserSetupActions(): string[] {
|
|
2103
|
+
return [
|
|
2104
|
+
"Ensure the Vellum desktop app is running and connected to the assistant.",
|
|
2105
|
+
"Open Google Chrome on the desktop machine so the host browser proxy can attach.",
|
|
2106
|
+
"If the desktop client is not running, launch it and wait for the SSE connection to establish.",
|
|
2107
|
+
];
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
function macOSHostBrowserReconnectActions(): string[] {
|
|
2111
|
+
return [
|
|
2112
|
+
"Verify the Vellum desktop app is still running and has an active network connection.",
|
|
2113
|
+
"If the desktop client was recently restarted, send a new message to re-establish the SSE bridge.",
|
|
2114
|
+
"Ensure Chrome is open on the desktop machine for the host browser proxy to target.",
|
|
2115
|
+
];
|
|
2116
|
+
}
|
|
2117
|
+
|
|
2118
|
+
function macOSHostBrowserProbeFailureActions(error: CdpError): string[] {
|
|
2119
|
+
const actions: string[] = [
|
|
2120
|
+
"Ensure Google Chrome is running on the desktop machine.",
|
|
2121
|
+
];
|
|
2122
|
+
const message = error.message.toLowerCase();
|
|
2123
|
+
if (message.includes("timeout") || message.includes("timed out")) {
|
|
2124
|
+
actions.push(
|
|
2125
|
+
"The desktop client may be unresponsive — try restarting the Vellum desktop app.",
|
|
2126
|
+
);
|
|
2127
|
+
}
|
|
2128
|
+
if (message.includes("transport") || message.includes("disconnected")) {
|
|
2129
|
+
actions.push(
|
|
2130
|
+
"The SSE bridge between the assistant and the desktop client appears broken. Send a new message to re-establish the connection.",
|
|
2131
|
+
);
|
|
2132
|
+
}
|
|
2133
|
+
actions.push(
|
|
2134
|
+
"Switch Chrome to a regular http(s) tab (not chrome://...) and retry.",
|
|
2135
|
+
);
|
|
2136
|
+
return dedupeStrings(actions);
|
|
2137
|
+
}
|
|
2138
|
+
|
|
2101
2139
|
function cdpInspectSetupActions(): string[] {
|
|
2102
2140
|
return [
|
|
2103
2141
|
"Update Chrome to the latest version by going to chrome://settings/help",
|
|
@@ -2247,6 +2285,7 @@ async function checkExtensionModeStatus(
|
|
|
2247
2285
|
): Promise<BrowserStatusModeResult> {
|
|
2248
2286
|
const proxyBound = Boolean(context.hostBrowserProxy);
|
|
2249
2287
|
const proxyConnected = context.hostBrowserProxy?.isAvailable() ?? false;
|
|
2288
|
+
const isMacOS = context.transportInterface === "macos";
|
|
2250
2289
|
|
|
2251
2290
|
if (!proxyBound) {
|
|
2252
2291
|
return {
|
|
@@ -2254,13 +2293,20 @@ async function checkExtensionModeStatus(
|
|
|
2254
2293
|
available: false,
|
|
2255
2294
|
verified: "preflight",
|
|
2256
2295
|
autoCandidate,
|
|
2257
|
-
summary:
|
|
2258
|
-
"Extension mode is unavailable:
|
|
2259
|
-
|
|
2296
|
+
summary: isMacOS
|
|
2297
|
+
? "Extension mode is unavailable: the macOS host browser proxy is not bound to this conversation. Ensure the desktop client is connected."
|
|
2298
|
+
: "Extension mode is unavailable: no host browser proxy is bound to this conversation.",
|
|
2299
|
+
userActions: isMacOS
|
|
2300
|
+
? macOSHostBrowserSetupActions()
|
|
2301
|
+
: extensionSetupActions(),
|
|
2260
2302
|
tradeoffs: modeTradeoffs(BROWSER_STATUS_MODE.EXTENSION),
|
|
2261
2303
|
details: {
|
|
2262
2304
|
proxyBound,
|
|
2263
2305
|
proxyConnected,
|
|
2306
|
+
transport:
|
|
2307
|
+
isMacOS && !context.hostBrowserRegistryRouted
|
|
2308
|
+
? "macos-sse"
|
|
2309
|
+
: "extension-ws",
|
|
2264
2310
|
},
|
|
2265
2311
|
};
|
|
2266
2312
|
}
|
|
@@ -2271,13 +2317,20 @@ async function checkExtensionModeStatus(
|
|
|
2271
2317
|
available: false,
|
|
2272
2318
|
verified: "preflight",
|
|
2273
2319
|
autoCandidate,
|
|
2274
|
-
summary:
|
|
2275
|
-
"Extension mode is unavailable: the
|
|
2276
|
-
|
|
2320
|
+
summary: isMacOS
|
|
2321
|
+
? "Extension mode is unavailable: the macOS host browser proxy is bound but the SSE transport is currently disconnected. Verify the desktop client is running and connected."
|
|
2322
|
+
: "Extension mode is unavailable: the extension transport is currently disconnected.",
|
|
2323
|
+
userActions: isMacOS
|
|
2324
|
+
? macOSHostBrowserReconnectActions()
|
|
2325
|
+
: extensionSetupActions(),
|
|
2277
2326
|
tradeoffs: modeTradeoffs(BROWSER_STATUS_MODE.EXTENSION),
|
|
2278
2327
|
details: {
|
|
2279
2328
|
proxyBound,
|
|
2280
2329
|
proxyConnected,
|
|
2330
|
+
transport:
|
|
2331
|
+
isMacOS && !context.hostBrowserRegistryRouted
|
|
2332
|
+
? "macos-sse"
|
|
2333
|
+
: "extension-ws",
|
|
2281
2334
|
},
|
|
2282
2335
|
};
|
|
2283
2336
|
}
|
|
@@ -2292,13 +2345,19 @@ async function checkExtensionModeStatus(
|
|
|
2292
2345
|
available: true,
|
|
2293
2346
|
verified: "active_probe",
|
|
2294
2347
|
autoCandidate,
|
|
2295
|
-
summary:
|
|
2348
|
+
summary: isMacOS
|
|
2349
|
+
? "Extension mode is ready via macOS host browser proxy and responded to an active CDP probe."
|
|
2350
|
+
: "Extension mode is ready and responded to an active CDP probe.",
|
|
2296
2351
|
userActions: [],
|
|
2297
2352
|
tradeoffs: modeTradeoffs(BROWSER_STATUS_MODE.EXTENSION),
|
|
2298
2353
|
details: {
|
|
2299
2354
|
proxyBound,
|
|
2300
2355
|
proxyConnected,
|
|
2301
2356
|
backendKind: probe.backendKind,
|
|
2357
|
+
transport:
|
|
2358
|
+
isMacOS && !context.hostBrowserRegistryRouted
|
|
2359
|
+
? "macos-sse"
|
|
2360
|
+
: "extension-ws",
|
|
2302
2361
|
},
|
|
2303
2362
|
};
|
|
2304
2363
|
}
|
|
@@ -2309,8 +2368,9 @@ async function checkExtensionModeStatus(
|
|
|
2309
2368
|
available: true,
|
|
2310
2369
|
verified: "active_probe",
|
|
2311
2370
|
autoCandidate,
|
|
2312
|
-
summary:
|
|
2313
|
-
"Extension mode transport is connected, but the active Chrome tab is a restricted chrome:// page. Switch to a regular website tab if browser actions fail."
|
|
2371
|
+
summary: isMacOS
|
|
2372
|
+
? "Extension mode transport is connected via macOS host browser proxy, but the active Chrome tab is a restricted chrome:// page. Switch to a regular website tab if browser actions fail."
|
|
2373
|
+
: "Extension mode transport is connected, but the active Chrome tab is a restricted chrome:// page. Switch to a regular website tab if browser actions fail.",
|
|
2314
2374
|
userActions: [
|
|
2315
2375
|
"Switch Chrome to a regular http(s) tab (not chrome://...) and retry.",
|
|
2316
2376
|
],
|
|
@@ -2322,6 +2382,10 @@ async function checkExtensionModeStatus(
|
|
|
2322
2382
|
errorCode: probe.error.code,
|
|
2323
2383
|
diagnostic: probe.diagnostic,
|
|
2324
2384
|
attemptDiagnostics: probe.error.attemptDiagnostics ?? [],
|
|
2385
|
+
transport:
|
|
2386
|
+
isMacOS && !context.hostBrowserRegistryRouted
|
|
2387
|
+
? "macos-sse"
|
|
2388
|
+
: "extension-ws",
|
|
2325
2389
|
},
|
|
2326
2390
|
};
|
|
2327
2391
|
}
|
|
@@ -2331,11 +2395,12 @@ async function checkExtensionModeStatus(
|
|
|
2331
2395
|
available: false,
|
|
2332
2396
|
verified: "active_probe",
|
|
2333
2397
|
autoCandidate,
|
|
2334
|
-
summary:
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2398
|
+
summary: isMacOS
|
|
2399
|
+
? `Extension mode probe failed via macOS host browser proxy: ${probe.error.message}`
|
|
2400
|
+
: `Extension mode probe failed: ${probe.error.message}`,
|
|
2401
|
+
userActions: isMacOS
|
|
2402
|
+
? macOSHostBrowserProbeFailureActions(probe.error)
|
|
2403
|
+
: probeFailureActions(BROWSER_STATUS_MODE.EXTENSION, probe.error),
|
|
2339
2404
|
tradeoffs: modeTradeoffs(BROWSER_STATUS_MODE.EXTENSION),
|
|
2340
2405
|
details: {
|
|
2341
2406
|
proxyBound,
|
|
@@ -2343,6 +2408,10 @@ async function checkExtensionModeStatus(
|
|
|
2343
2408
|
errorCode: probe.error.code,
|
|
2344
2409
|
diagnostic: probe.diagnostic,
|
|
2345
2410
|
attemptDiagnostics: probe.error.attemptDiagnostics ?? [],
|
|
2411
|
+
transport:
|
|
2412
|
+
isMacOS && !context.hostBrowserRegistryRouted
|
|
2413
|
+
? "macos-sse"
|
|
2414
|
+
: "extension-ws",
|
|
2346
2415
|
},
|
|
2347
2416
|
};
|
|
2348
2417
|
}
|
|
@@ -356,4 +356,234 @@ describe("ExtensionCdpClient", () => {
|
|
|
356
356
|
expect(err.message).toBe("CDP call aborted");
|
|
357
357
|
expect(err.cdpMethod).toBe("Browser.getVersion");
|
|
358
358
|
});
|
|
359
|
+
|
|
360
|
+
// ── Structured transport error classification ────────────────────────
|
|
361
|
+
|
|
362
|
+
test("structured error with code 'transport_error' is classified as transport_error", async () => {
|
|
363
|
+
const errorBody = {
|
|
364
|
+
code: "transport_error",
|
|
365
|
+
message: "Extension WebSocket disconnected",
|
|
366
|
+
};
|
|
367
|
+
const { proxy } = fakeProxy(async () => ({
|
|
368
|
+
content: JSON.stringify(errorBody),
|
|
369
|
+
isError: true,
|
|
370
|
+
}));
|
|
371
|
+
|
|
372
|
+
const client = createExtensionCdpClient(proxy, "conv-transport-1");
|
|
373
|
+
|
|
374
|
+
let caught: unknown;
|
|
375
|
+
try {
|
|
376
|
+
await client.send("Page.navigate", { url: "https://example.com" });
|
|
377
|
+
} catch (err) {
|
|
378
|
+
caught = err;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
expect(caught).toBeInstanceOf(CdpError);
|
|
382
|
+
const err = caught as CdpError;
|
|
383
|
+
expect(err.code).toBe("transport_error");
|
|
384
|
+
expect(err.message).toBe("Extension WebSocket disconnected");
|
|
385
|
+
expect(err.cdpMethod).toBe("Page.navigate");
|
|
386
|
+
expect(err.cdpParams).toEqual({ url: "https://example.com" });
|
|
387
|
+
expect(err.underlying).toEqual(errorBody);
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
test("structured error with code 'unreachable' is classified as transport_error", async () => {
|
|
391
|
+
const errorBody = {
|
|
392
|
+
code: "unreachable",
|
|
393
|
+
message: "Host browser not reachable",
|
|
394
|
+
};
|
|
395
|
+
const { proxy } = fakeProxy(async () => ({
|
|
396
|
+
content: JSON.stringify(errorBody),
|
|
397
|
+
isError: true,
|
|
398
|
+
}));
|
|
399
|
+
|
|
400
|
+
const client = createExtensionCdpClient(proxy, "conv-transport-2");
|
|
401
|
+
|
|
402
|
+
let caught: unknown;
|
|
403
|
+
try {
|
|
404
|
+
await client.send("Runtime.evaluate", { expression: "1+1" });
|
|
405
|
+
} catch (err) {
|
|
406
|
+
caught = err;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
expect(caught).toBeInstanceOf(CdpError);
|
|
410
|
+
const err = caught as CdpError;
|
|
411
|
+
expect(err.code).toBe("transport_error");
|
|
412
|
+
expect(err.message).toBe("Host browser not reachable");
|
|
413
|
+
expect(err.underlying).toEqual(errorBody);
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
test("structured error with code 'timeout' is classified as transport_error", async () => {
|
|
417
|
+
const errorBody = {
|
|
418
|
+
code: "timeout",
|
|
419
|
+
message: "CDP call timed out",
|
|
420
|
+
};
|
|
421
|
+
const { proxy } = fakeProxy(async () => ({
|
|
422
|
+
content: JSON.stringify(errorBody),
|
|
423
|
+
isError: true,
|
|
424
|
+
}));
|
|
425
|
+
|
|
426
|
+
const client = createExtensionCdpClient(proxy, "conv-transport-3");
|
|
427
|
+
|
|
428
|
+
let caught: unknown;
|
|
429
|
+
try {
|
|
430
|
+
await client.send("Page.captureScreenshot");
|
|
431
|
+
} catch (err) {
|
|
432
|
+
caught = err;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
expect(caught).toBeInstanceOf(CdpError);
|
|
436
|
+
const err = caught as CdpError;
|
|
437
|
+
expect(err.code).toBe("transport_error");
|
|
438
|
+
expect(err.message).toBe("CDP call timed out");
|
|
439
|
+
expect(err.underlying).toEqual(errorBody);
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
test("structured error with code 'non_loopback' is classified as transport_error", async () => {
|
|
443
|
+
const errorBody = {
|
|
444
|
+
code: "non_loopback",
|
|
445
|
+
message: "Only loopback addresses are allowed",
|
|
446
|
+
};
|
|
447
|
+
const { proxy } = fakeProxy(async () => ({
|
|
448
|
+
content: JSON.stringify(errorBody),
|
|
449
|
+
isError: true,
|
|
450
|
+
}));
|
|
451
|
+
|
|
452
|
+
const client = createExtensionCdpClient(proxy, "conv-transport-4");
|
|
453
|
+
|
|
454
|
+
let caught: unknown;
|
|
455
|
+
try {
|
|
456
|
+
await client.send("Browser.getVersion");
|
|
457
|
+
} catch (err) {
|
|
458
|
+
caught = err;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
expect(caught).toBeInstanceOf(CdpError);
|
|
462
|
+
const err = caught as CdpError;
|
|
463
|
+
expect(err.code).toBe("transport_error");
|
|
464
|
+
expect(err.message).toBe("Only loopback addresses are allowed");
|
|
465
|
+
expect(err.underlying).toEqual(errorBody);
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
// ── Command-level CDP errors remain cdp_error ────────────────────────
|
|
469
|
+
|
|
470
|
+
test("structured error with numeric code (CDP JSON-RPC) remains cdp_error", async () => {
|
|
471
|
+
const errorBody = {
|
|
472
|
+
code: -32000,
|
|
473
|
+
message: "Cannot find context with specified id",
|
|
474
|
+
};
|
|
475
|
+
const { proxy } = fakeProxy(async () => ({
|
|
476
|
+
content: JSON.stringify(errorBody),
|
|
477
|
+
isError: true,
|
|
478
|
+
}));
|
|
479
|
+
|
|
480
|
+
const client = createExtensionCdpClient(proxy, "conv-cdp-1");
|
|
481
|
+
|
|
482
|
+
let caught: unknown;
|
|
483
|
+
try {
|
|
484
|
+
await client.send("Runtime.evaluate", { expression: "boom" });
|
|
485
|
+
} catch (err) {
|
|
486
|
+
caught = err;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
expect(caught).toBeInstanceOf(CdpError);
|
|
490
|
+
const err = caught as CdpError;
|
|
491
|
+
expect(err.code).toBe("cdp_error");
|
|
492
|
+
expect(err.message).toBe("Cannot find context with specified id");
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
test("structured error with unknown string code remains cdp_error", async () => {
|
|
496
|
+
const errorBody = {
|
|
497
|
+
code: "some_unknown_code",
|
|
498
|
+
message: "Unrecognized error",
|
|
499
|
+
};
|
|
500
|
+
const { proxy } = fakeProxy(async () => ({
|
|
501
|
+
content: JSON.stringify(errorBody),
|
|
502
|
+
isError: true,
|
|
503
|
+
}));
|
|
504
|
+
|
|
505
|
+
const client = createExtensionCdpClient(proxy, "conv-cdp-2");
|
|
506
|
+
|
|
507
|
+
let caught: unknown;
|
|
508
|
+
try {
|
|
509
|
+
await client.send("Page.navigate", { url: "https://example.com" });
|
|
510
|
+
} catch (err) {
|
|
511
|
+
caught = err;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
expect(caught).toBeInstanceOf(CdpError);
|
|
515
|
+
const err = caught as CdpError;
|
|
516
|
+
expect(err.code).toBe("cdp_error");
|
|
517
|
+
expect(err.message).toBe("Unrecognized error");
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
test("structured error without code field remains cdp_error", async () => {
|
|
521
|
+
const errorBody = {
|
|
522
|
+
message: "Something went wrong",
|
|
523
|
+
};
|
|
524
|
+
const { proxy } = fakeProxy(async () => ({
|
|
525
|
+
content: JSON.stringify(errorBody),
|
|
526
|
+
isError: true,
|
|
527
|
+
}));
|
|
528
|
+
|
|
529
|
+
const client = createExtensionCdpClient(proxy, "conv-cdp-3");
|
|
530
|
+
|
|
531
|
+
let caught: unknown;
|
|
532
|
+
try {
|
|
533
|
+
await client.send("DOM.getDocument");
|
|
534
|
+
} catch (err) {
|
|
535
|
+
caught = err;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
expect(caught).toBeInstanceOf(CdpError);
|
|
539
|
+
const err = caught as CdpError;
|
|
540
|
+
expect(err.code).toBe("cdp_error");
|
|
541
|
+
expect(err.message).toBe("Something went wrong");
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
test("structured error with code: null remains cdp_error", async () => {
|
|
545
|
+
const errorBody = {
|
|
546
|
+
code: null,
|
|
547
|
+
message: "Null code error",
|
|
548
|
+
};
|
|
549
|
+
const { proxy } = fakeProxy(async () => ({
|
|
550
|
+
content: JSON.stringify(errorBody),
|
|
551
|
+
isError: true,
|
|
552
|
+
}));
|
|
553
|
+
|
|
554
|
+
const client = createExtensionCdpClient(proxy, "conv-cdp-4");
|
|
555
|
+
|
|
556
|
+
let caught: unknown;
|
|
557
|
+
try {
|
|
558
|
+
await client.send("Browser.getVersion");
|
|
559
|
+
} catch (err) {
|
|
560
|
+
caught = err;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
expect(caught).toBeInstanceOf(CdpError);
|
|
564
|
+
const err = caught as CdpError;
|
|
565
|
+
expect(err.code).toBe("cdp_error");
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
test("plain-text isError content still throws cdp_error (no failover)", async () => {
|
|
569
|
+
const { proxy } = fakeProxy(async () => ({
|
|
570
|
+
content: "Connection lost unexpectedly",
|
|
571
|
+
isError: true,
|
|
572
|
+
}));
|
|
573
|
+
|
|
574
|
+
const client = createExtensionCdpClient(proxy, "conv-cdp-5");
|
|
575
|
+
|
|
576
|
+
let caught: unknown;
|
|
577
|
+
try {
|
|
578
|
+
await client.send("Page.navigate", { url: "https://example.com" });
|
|
579
|
+
} catch (err) {
|
|
580
|
+
caught = err;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
expect(caught).toBeInstanceOf(CdpError);
|
|
584
|
+
const err = caught as CdpError;
|
|
585
|
+
expect(err.code).toBe("cdp_error");
|
|
586
|
+
expect(err.message).toBe("Connection lost unexpectedly");
|
|
587
|
+
expect(err.underlying).toBe("Connection lost unexpectedly");
|
|
588
|
+
});
|
|
359
589
|
});
|