@vellumai/assistant 0.7.1 → 0.7.2
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 +32 -49
- package/Dockerfile +1 -0
- package/README.md +1 -2
- package/__tests__/permissions/gateway-threshold-reader.test.ts +9 -3
- package/bun.lock +26 -26
- package/docs/architecture/security.md +20 -0
- package/docs/plugins.md +7 -9
- package/knip.json +1 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +1 -0
- package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +39 -1
- package/node_modules/@vellumai/gateway-client/src/types.ts +11 -0
- package/node_modules/@vellumai/service-contracts/package.json +2 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/contracts.test.ts +4 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +107 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +5 -1
- package/node_modules/@vellumai/service-contracts/src/ingress.ts +24 -0
- package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +84 -0
- package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +9 -0
- package/node_modules/@vellumai/twilio-client/bun.lock +24 -0
- package/node_modules/@vellumai/twilio-client/package.json +18 -0
- package/node_modules/@vellumai/twilio-client/src/__tests__/twilio-client.test.ts +128 -0
- package/node_modules/@vellumai/twilio-client/src/index.ts +179 -0
- package/node_modules/@vellumai/twilio-client/tsconfig.json +20 -0
- package/openapi.yaml +565 -12
- package/package.json +6 -3
- package/src/__tests__/app-builder-tool-scripts.test.ts +3 -3
- package/src/__tests__/app-bundler.test.ts +170 -1
- package/src/__tests__/app-control-flow.test.ts +374 -0
- package/src/__tests__/app-control-no-global-cgevent.test.ts +98 -0
- package/src/__tests__/app-control-tool-schemas.test.ts +621 -0
- package/src/__tests__/app-executors.test.ts +30 -43
- package/src/__tests__/approval-routes-http.test.ts +23 -6
- package/src/__tests__/assistant-event-hub-machine-name.test.ts +146 -0
- package/src/__tests__/assistant-event-hub-targeted.test.ts +257 -0
- package/src/__tests__/assistant-event-hub.test.ts +109 -2
- package/src/__tests__/assistant-event.test.ts +10 -0
- package/src/__tests__/assistant-events-sse-hardening.test.ts +7 -2
- package/src/__tests__/assistant-feature-flags-integration.test.ts +11 -7
- package/src/__tests__/background-shell-host-bash.test.ts +14 -15
- package/src/__tests__/bootstrap-turn-cleanup.test.ts +44 -0
- package/src/__tests__/btw-routes.test.ts +13 -4
- package/src/__tests__/call-controller.test.ts +49 -1
- package/src/__tests__/call-domain.test.ts +0 -2
- package/src/__tests__/call-routes-http.test.ts +0 -2
- package/src/__tests__/channel-readiness-service.test.ts +59 -1
- package/src/__tests__/checker.test.ts +3 -4
- package/src/__tests__/config-loader-backfill.test.ts +90 -155
- package/src/__tests__/config-loader-platform-defaults.test.ts +196 -0
- package/src/__tests__/config-schema-cmd.test.ts +0 -1
- package/src/__tests__/config-set-platform-guard.test.ts +48 -4
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +2 -2
- package/src/__tests__/config-watcher.test.ts +2 -2
- package/src/__tests__/conversation-app-control-instantiation.test.ts +392 -0
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +237 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
- package/src/__tests__/conversation-lifecycle.test.ts +36 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +283 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +6 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +120 -72
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
- package/src/__tests__/conversation-slash-commands.test.ts +0 -4
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +202 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +317 -0
- package/src/__tests__/credential-execution-feature-gates.test.ts +5 -12
- package/src/__tests__/credential-execution-managed-contract.test.ts +3 -131
- package/src/__tests__/credentials-cli.test.ts +5 -12
- package/src/__tests__/cu-unified-flow.test.ts +185 -23
- package/src/__tests__/daemon-credential-client.test.ts +101 -19
- package/src/__tests__/db-schedule-syntax-migration.test.ts +2 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
- package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -2
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -2
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -1
- package/src/__tests__/heartbeat-service.test.ts +718 -1
- package/src/__tests__/helpers/call-route-handler.ts +7 -1
- package/src/__tests__/host-app-control-proxy.test.ts +602 -0
- package/src/__tests__/host-app-control-routes.test.ts +263 -0
- package/src/__tests__/host-bash-proxy.test.ts +246 -47
- package/src/__tests__/host-bash-routes.test.ts +294 -0
- package/src/__tests__/host-browser-proxy.test.ts +24 -22
- package/src/__tests__/host-browser-routes.test.ts +39 -13
- package/src/__tests__/host-cu-proxy.test.ts +41 -52
- package/src/__tests__/host-cu-routes-targeted.test.ts +300 -0
- package/src/__tests__/host-file-edit-tool.test.ts +47 -1
- package/src/__tests__/host-file-proxy-targeted.test.ts +339 -0
- package/src/__tests__/host-file-proxy.test.ts +37 -43
- package/src/__tests__/host-file-read-tool.test.ts +17 -0
- package/src/__tests__/host-file-routes-targeted.test.ts +262 -0
- package/src/__tests__/host-file-write-tool.test.ts +42 -1
- package/src/__tests__/host-proxy-base.test.ts +312 -0
- package/src/__tests__/host-shell-tool.test.ts +22 -4
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +583 -0
- package/src/__tests__/host-transfer-proxy.test.ts +121 -22
- package/src/__tests__/host-transfer-routes-targeted.test.ts +447 -0
- package/src/__tests__/http-user-message-parity.test.ts +1 -0
- package/src/__tests__/identity-intro-cache.test.ts +29 -0
- package/src/__tests__/identity-routes.test.ts +103 -1
- package/src/__tests__/init-feature-flag-overrides.test.ts +26 -3
- package/src/__tests__/inline-command-runner.test.ts +0 -1
- package/src/__tests__/inline-skill-load-permissions.test.ts +5 -11
- package/src/__tests__/integration-status.test.ts +85 -5
- package/src/__tests__/intent-routing.test.ts +0 -1
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +95 -5
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +17 -0
- package/src/__tests__/managed-skill-lifecycle.test.ts +0 -1
- package/src/__tests__/mcp-auth-routes.test.ts +197 -0
- package/src/__tests__/mcp-cli.test.ts +338 -2
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +188 -0
- package/src/__tests__/migration-import-commit-http.test.ts +108 -2
- package/src/__tests__/mock-gateway-ipc.ts +1 -0
- package/src/__tests__/oauth-cli.test.ts +0 -2
- package/src/__tests__/oauth2-gateway-transport.test.ts +0 -1
- package/src/__tests__/persistence-secret-redaction.test.ts +299 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +5 -9
- package/src/__tests__/prechat-onboarding-contract.test.ts +3 -1
- package/src/__tests__/process-message-background-slack.test.ts +2 -0
- package/src/__tests__/provider-commit-message-generator.test.ts +0 -1
- package/src/__tests__/public-ingress-urls.test.ts +97 -0
- package/src/__tests__/require-fresh-approval.test.ts +0 -1
- package/src/__tests__/retry-backoff.test.ts +87 -0
- package/src/__tests__/runtime-events-sse.test.ts +10 -6
- package/src/__tests__/sanitize-config-for-transfer.test.ts +24 -2
- package/src/__tests__/schedule-retry.test.ts +715 -0
- package/src/__tests__/script-proxy-mitm-handler.test.ts +1 -1
- package/src/__tests__/secret-ingress-http.test.ts +1 -0
- package/src/__tests__/send-endpoint-busy.test.ts +3 -0
- package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -1
- package/src/__tests__/skill-feature-flags.test.ts +43 -41
- package/src/__tests__/skill-load-feature-flag.test.ts +13 -14
- package/src/__tests__/skill-load-inline-command.test.ts +0 -51
- package/src/__tests__/skill-load-inline-includes.test.ts +0 -43
- package/src/__tests__/skill-projection.benchmark.test.ts +0 -1
- package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -1
- package/src/__tests__/slack-channel-config.test.ts +9 -14
- package/src/__tests__/system-prompt-ask-mode.test.ts +0 -1
- package/src/__tests__/system-prompt.test.ts +0 -1
- package/src/__tests__/telegram-config.test.ts +0 -1
- package/src/__tests__/test-preload.ts +8 -0
- package/src/__tests__/tool-approval-handler.test.ts +3 -4
- package/src/__tests__/tool-audit-listener.test.ts +48 -0
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -1
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
- package/src/__tests__/tool-executor.test.ts +0 -1
- package/src/__tests__/twilio-config.test.ts +3 -16
- package/src/__tests__/twilio-routes.test.ts +3 -5
- package/src/__tests__/twilio-validation.test.ts +93 -0
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +1 -4
- package/src/__tests__/verification-control-plane-policy.test.ts +2 -4
- package/src/__tests__/voice-ingress-preflight.test.ts +19 -0
- package/src/__tests__/workspace-migration-006-services-config.test.ts +3 -2
- package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +1 -5
- package/src/__tests__/workspace-migration-down-functions.test.ts +8 -8
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +10 -6
- package/src/backup/__tests__/paths.test.ts +0 -22
- package/src/backup/__tests__/restore.test.ts +51 -151
- package/src/backup/paths.ts +2 -18
- package/src/backup/restore.ts +107 -231
- package/src/bundler/app-bundler.ts +51 -3
- package/src/calls/relay-server.ts +4 -44
- package/src/calls/twilio-config.ts +2 -17
- package/src/calls/twilio-rest.ts +33 -105
- package/src/calls/twilio-routes.ts +11 -12
- package/src/channels/types.ts +8 -7
- package/src/cli/commands/__tests__/backup.test.ts +6 -277
- package/src/cli/commands/__tests__/gateway.test.ts +288 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +4 -0
- package/src/cli/commands/__tests__/webhooks.test.ts +0 -1
- package/src/cli/commands/backup.ts +6 -331
- package/src/cli/commands/clients.ts +36 -37
- package/src/cli/commands/contacts.ts +73 -0
- package/src/cli/commands/conversations.ts +2 -5
- package/src/cli/commands/credentials.ts +15 -7
- package/src/cli/commands/domain.ts +66 -15
- package/src/cli/commands/gateway.ts +183 -0
- package/src/cli/commands/keys.ts +9 -6
- package/src/cli/commands/mcp.ts +116 -156
- package/src/cli/commands/memory-v2.ts +296 -1
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -1
- package/src/cli/commands/platform/__tests__/connect.test.ts +0 -2
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +0 -2
- package/src/cli/commands/platform/__tests__/status.test.ts +13 -15
- package/src/cli/commands/platform/disconnect.ts +5 -4
- package/src/cli/commands/platform/index.ts +0 -18
- package/src/cli/lib/daemon-credential-client.ts +110 -28
- package/src/cli/program.ts +2 -0
- package/src/config/assistant-feature-flags.ts +67 -10
- package/src/config/bundled-skills/acp/SKILL.md +6 -0
- package/src/config/bundled-skills/acp/TOOLS.json +1 -22
- package/src/config/bundled-skills/app-builder/SKILL.md +14 -109
- package/src/config/bundled-skills/app-builder/TOOLS.json +1 -28
- package/src/config/bundled-skills/app-builder/tools/app-create.ts +1 -10
- package/src/config/bundled-skills/app-control/SKILL.md +75 -0
- package/src/config/bundled-skills/app-control/TOOLS.json +299 -0
- package/src/config/bundled-skills/app-control/tools/app-control-click.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-combo.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-drag.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-observe.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-press.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-sequence.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-start.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-stop.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-type.ts +12 -0
- package/src/config/bundled-skills/computer-use/SKILL.md +6 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +67 -43
- package/src/config/bundled-skills/contacts/TOOLS.json +0 -16
- package/src/config/bundled-skills/document/TOOLS.json +0 -8
- package/src/config/bundled-skills/followups/TOOLS.json +0 -12
- package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
- package/src/config/bundled-skills/image-studio/TOOLS.json +0 -4
- package/src/config/bundled-skills/media-processing/TOOLS.json +0 -24
- package/src/config/bundled-skills/messaging/TOOLS.json +0 -40
- package/src/config/bundled-skills/phone-calls/TOOLS.json +0 -12
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +19 -4
- package/src/config/bundled-skills/playbooks/TOOLS.json +0 -16
- package/src/config/bundled-skills/schedule/TOOLS.json +14 -14
- package/src/config/bundled-skills/sequences/TOOLS.json +0 -36
- package/src/config/bundled-skills/settings/SKILL.md +4 -0
- package/src/config/bundled-skills/settings/TOOLS.json +0 -12
- package/src/config/bundled-skills/skill-management/SKILL.md +6 -0
- package/src/config/bundled-skills/skill-management/TOOLS.json +0 -8
- package/src/config/bundled-skills/subagent/SKILL.md +6 -2
- package/src/config/bundled-skills/subagent/TOOLS.json +0 -20
- package/src/config/bundled-skills/transcribe/SKILL.md +4 -0
- package/src/config/bundled-skills/transcribe/TOOLS.json +0 -4
- package/src/config/bundled-tool-registry.ts +21 -0
- package/src/config/env-registry.ts +0 -2
- package/src/config/env.ts +19 -12
- package/src/config/feature-flag-registry.json +21 -133
- package/src/config/loader.ts +73 -99
- package/src/config/sanitize-for-transfer.ts +2 -0
- package/src/config/schemas/__tests__/memory-lifecycle.test.ts +80 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +7 -4
- package/src/config/schemas/calls.ts +0 -9
- package/src/config/schemas/heartbeat.ts +63 -0
- package/src/config/schemas/ingress.ts +10 -6
- package/src/config/schemas/llm.ts +5 -10
- package/src/config/schemas/memory-lifecycle.ts +77 -24
- package/src/config/schemas/memory-v2.ts +48 -4
- package/src/config/schemas/platform.ts +6 -0
- package/src/config/schemas/services.ts +1 -15
- package/src/config/schemas/skills.ts +0 -6
- package/src/config/seed-inference-profiles.ts +1 -1
- package/src/contacts/contact-store.ts +0 -30
- package/src/contacts/contacts-write.ts +0 -27
- package/src/context/window-manager.ts +1 -2
- package/src/credential-execution/feature-gates.ts +10 -10
- package/src/credential-execution/process-manager.ts +12 -41
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +126 -5
- package/src/daemon/bootstrap-turn-cleanup.ts +45 -0
- package/src/daemon/config-watcher.ts +4 -3
- package/src/daemon/conversation-agent-loop-handlers.ts +21 -3
- package/src/daemon/conversation-agent-loop.ts +32 -28
- package/src/daemon/conversation-lifecycle.ts +8 -1
- package/src/daemon/conversation-process.ts +16 -11
- package/src/daemon/conversation-runtime-assembly.ts +2 -2
- package/src/daemon/conversation-surfaces.ts +125 -4
- package/src/daemon/conversation-tool-setup.ts +16 -55
- package/src/daemon/conversation.ts +21 -2
- package/src/daemon/doordash-steps.ts +1 -1
- package/src/daemon/handlers/shared.ts +4 -1
- package/src/daemon/host-app-control-proxy.ts +293 -0
- package/src/daemon/host-bash-proxy.ts +84 -74
- package/src/daemon/host-browser-proxy.ts +67 -82
- package/src/daemon/host-cu-proxy.ts +81 -86
- package/src/daemon/host-file-proxy.ts +93 -69
- package/src/daemon/host-proxy-base.ts +294 -0
- package/src/daemon/host-proxy-preactivation.ts +82 -0
- package/src/daemon/host-transfer-proxy.ts +247 -129
- package/src/daemon/lifecycle.ts +115 -117
- package/src/daemon/message-protocol.ts +3 -8
- package/src/daemon/message-types/contacts.ts +23 -1
- package/src/daemon/message-types/conversations.ts +11 -8
- package/src/daemon/message-types/host-app-control.ts +150 -0
- package/src/daemon/message-types/host-bash.ts +4 -0
- package/src/daemon/message-types/host-cu.ts +2 -0
- package/src/daemon/message-types/host-file.ts +4 -0
- package/src/daemon/message-types/host-transfer.ts +3 -0
- package/src/daemon/message-types/schedules.ts +8 -3
- package/src/daemon/message-types/skills.ts +2 -2
- package/src/daemon/process-message.ts +18 -1
- package/src/daemon/shutdown-handlers.ts +0 -3
- package/src/daemon/tool-setup-types.ts +51 -0
- package/src/daemon/tool-side-effects.ts +1 -1
- package/src/events/tool-audit-listener.ts +2 -1
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +15 -7
- package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +216 -0
- package/src/heartbeat/heartbeat-run-store.ts +236 -0
- package/src/heartbeat/heartbeat-service.ts +280 -49
- package/src/home/__tests__/post-connect-feed.test.ts +99 -0
- package/src/home/__tests__/relationship-state-writer.test.ts +11 -9
- package/src/home/__tests__/suggested-prompts.test.ts +89 -0
- package/src/home/post-connect-feed.ts +68 -0
- package/src/home/relationship-state-writer.ts +17 -92
- package/src/home/suggested-prompts.ts +46 -10
- package/src/inbound/public-ingress-urls.ts +32 -34
- package/src/ipc/__tests__/route-error-envelope.test.ts +80 -0
- package/src/ipc/assistant-server.ts +14 -1
- package/src/ipc/cli-client.ts +32 -1
- package/src/live-voice/live-voice-metrics.ts +10 -10
- package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +304 -0
- package/src/mcp/mcp-auth-orchestrator.ts +213 -0
- package/src/mcp/mcp-auth-state.ts +133 -0
- package/src/mcp/mcp-oauth-provider.ts +19 -0
- package/src/memory/__tests__/jobs-store-job-classes.test.ts +24 -0
- package/src/memory/__tests__/qdrant-client-sentinel.test.ts +49 -0
- package/src/memory/__tests__/sparse-tokenize.test.ts +66 -0
- package/src/memory/anisotropy.test.ts +247 -0
- package/src/memory/anisotropy.ts +443 -0
- package/src/memory/auto-analysis-constants.ts +17 -0
- package/src/memory/auto-analysis-guard.ts +5 -15
- package/src/memory/canonical-guardian-store.ts +7 -7
- package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +122 -0
- package/src/memory/context-search/agent-protocol.ts +6 -6
- package/src/memory/context-search/agent-runner.ts +32 -7
- package/src/memory/context-search/sources/memory-v2.ts +17 -5
- package/src/memory/conversation-crud.ts +1 -1
- package/src/memory/conversation-key-store.ts +2 -15
- package/src/memory/db-init.ts +4 -0
- package/src/memory/embedding-backend.ts +9 -21
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +49 -4
- package/src/memory/graph/conversation-graph-memory.ts +1 -24
- package/src/memory/graph/graph-search.ts +8 -0
- package/src/memory/graph/retriever.ts +28 -0
- package/src/memory/graph/tools.ts +1 -1
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +8 -2
- package/src/memory/jobs/embed-concept-page.ts +28 -2
- package/src/memory/jobs/embed-pkb-file.test.ts +2 -2
- package/src/memory/jobs-store.ts +66 -22
- package/src/memory/jobs-worker.ts +112 -63
- package/src/memory/memory-v2-activation-log-store.ts +1 -1
- package/src/memory/migrations/237-heartbeat-runs.ts +45 -0
- package/src/memory/migrations/238-schedule-retry-policy.ts +20 -0
- package/src/memory/migrations/index.ts +5 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/pkb/pkb-search.ts +7 -0
- package/src/memory/qdrant-client.ts +50 -20
- package/src/memory/schema/infrastructure.ts +15 -0
- package/src/memory/search/semantic.ts +7 -0
- package/src/memory/sparse-tokenize.ts +49 -0
- package/src/memory/v2/__tests__/activation.test.ts +77 -95
- package/src/memory/v2/__tests__/injection.test.ts +43 -21
- package/src/memory/v2/__tests__/sim.test.ts +166 -6
- package/src/memory/v2/__tests__/sparse-bm25.test.ts +292 -0
- package/src/memory/v2/__tests__/static-context.test.ts +0 -1
- package/src/memory/v2/activation.ts +69 -88
- package/src/memory/v2/consolidation-job.ts +3 -5
- package/src/memory/v2/constants.ts +7 -0
- package/src/memory/v2/injection.ts +86 -53
- package/src/memory/v2/prompts/consolidation.ts +312 -91
- package/src/memory/v2/qdrant.ts +99 -1
- package/src/memory/v2/sim.ts +126 -16
- package/src/memory/v2/skill-qdrant.ts +12 -3
- package/src/memory/v2/skill-store.ts +16 -1
- package/src/memory/v2/sparse-bm25.ts +245 -0
- package/src/memory/v2/static-context.ts +6 -5
- package/src/messaging/providers/gmail/types.ts +0 -49
- package/src/messaging/providers/slack/adapter.ts +1 -31
- package/src/messaging/providers/slack/types.ts +0 -32
- package/src/notifications/README.md +10 -10
- package/src/notifications/broadcaster.ts +1 -1
- package/src/notifications/guardian-question-mode.ts +5 -5
- package/src/oauth/connect-orchestrator.ts +4 -0
- package/src/oauth/credential-token-resolver.ts +1 -3
- package/src/oauth/manual-token-connection.ts +0 -4
- package/src/outbound-proxy/index.ts +1 -37
- package/src/outbound-proxy/logging.ts +1 -1
- package/src/outbound-proxy/policy.ts +6 -5
- package/src/outbound-proxy/router.ts +2 -1
- package/src/permissions/approval-policy.test.ts +6 -275
- package/src/permissions/approval-policy.ts +0 -51
- package/src/permissions/checker.test.ts +0 -1
- package/src/permissions/checker.ts +3 -17
- package/src/permissions/gateway-threshold-reader.ts +2 -0
- package/src/permissions/prompter.ts +34 -1
- package/src/permissions/secret-prompter.ts +6 -2
- package/src/prompts/bootstrap-cleanup.ts +27 -0
- package/src/prompts/system-prompt.ts +3 -18
- package/src/prompts/templates/SOUL.md +13 -1
- package/src/providers/speech-to-text/provider-catalog.ts +7 -8
- package/src/runtime/assistant-event-hub.ts +118 -96
- package/src/runtime/assistant-event.ts +1 -0
- package/src/runtime/auth/__tests__/middleware.test.ts +11 -56
- package/src/runtime/auth/middleware.ts +0 -96
- package/src/runtime/auth/route-policy.ts +19 -0
- package/src/runtime/btw-sidechain.ts +2 -3
- package/src/runtime/channel-invite-transport.ts +2 -48
- package/src/runtime/channel-invite-transports/email.ts +1 -1
- package/src/runtime/channel-invite-transports/slack.ts +1 -1
- package/src/runtime/channel-invite-transports/telegram.ts +1 -1
- package/src/runtime/channel-invite-transports/voice.ts +1 -1
- package/src/runtime/channel-invite-transports/whatsapp.ts +1 -1
- package/src/runtime/channel-invite-types.ts +54 -0
- package/src/runtime/channel-readiness-service.ts +32 -13
- package/src/runtime/http-server.ts +3 -329
- package/src/runtime/http-types.ts +0 -5
- package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +413 -0
- package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +260 -0
- package/src/runtime/migrations/__tests__/vbundle-import-version-compat.test.ts +189 -0
- package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +153 -1
- package/src/runtime/migrations/__tests__/vbundle-symlink-importer.test.ts +451 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming.test.ts +515 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-tar.test.ts +437 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-walker.test.ts +319 -0
- package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +51 -1
- package/src/runtime/migrations/migration-transport.ts +7 -7
- package/src/runtime/migrations/vbundle-builder.ts +327 -60
- package/src/runtime/migrations/vbundle-import-analyzer.ts +4 -4
- package/src/runtime/migrations/vbundle-import-policy.ts +172 -0
- package/src/runtime/migrations/vbundle-importer.ts +245 -68
- package/src/runtime/migrations/vbundle-streaming-importer.ts +326 -35
- package/src/runtime/migrations/vbundle-streaming-validator.ts +157 -4
- package/src/runtime/migrations/vbundle-tar-stream.ts +15 -6
- package/src/runtime/migrations/vbundle-validator.ts +114 -0
- package/src/runtime/pending-interactions.ts +35 -9
- package/src/runtime/routes/__tests__/backup-routes.test.ts +22 -150
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -0
- package/src/runtime/routes/__tests__/gateway-log-routes.test.ts +242 -0
- package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +112 -0
- package/src/runtime/routes/approval-interception-types.ts +13 -0
- package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +1 -1
- package/src/runtime/routes/backup-routes.ts +15 -38
- package/src/runtime/routes/btw-routes.ts +14 -37
- package/src/runtime/routes/client-routes.ts +1 -0
- package/src/runtime/routes/contact-prompt-routes.ts +183 -0
- package/src/runtime/routes/conversation-query-routes.ts +36 -1
- package/src/runtime/routes/conversation-routes.ts +30 -13
- package/src/runtime/routes/document-pdf-renderer.ts +165 -0
- package/src/runtime/routes/documents-routes.ts +30 -0
- package/src/runtime/routes/errors.ts +19 -4
- package/src/runtime/routes/events-routes.ts +12 -6
- package/src/runtime/routes/gateway-log-routes.ts +79 -0
- package/src/runtime/routes/guardian-approval-interception.ts +2 -8
- package/src/runtime/routes/heartbeat-routes.ts +103 -38
- package/src/runtime/routes/host-app-control-routes.ts +134 -0
- package/src/runtime/routes/host-bash-routes.ts +36 -6
- package/src/runtime/routes/host-browser-routes.ts +108 -13
- package/src/runtime/routes/host-cu-routes.ts +44 -14
- package/src/runtime/routes/host-file-routes.ts +33 -10
- package/src/runtime/routes/host-transfer-routes.ts +64 -24
- package/src/runtime/routes/http-adapter.ts +1 -0
- package/src/runtime/routes/identity-intro-cache.ts +30 -0
- package/src/runtime/routes/identity-routes.ts +15 -43
- package/src/runtime/routes/inbound-message-handler.ts +1 -9
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -7
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +0 -8
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +0 -20
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +5 -13
- package/src/runtime/routes/index.ts +8 -0
- package/src/runtime/routes/mcp-auth-routes.ts +132 -0
- package/src/runtime/routes/memory-item-routes.ts +10 -12
- package/src/runtime/routes/memory-v2-routes.ts +441 -1
- package/src/runtime/routes/migration-routes.ts +96 -0
- package/src/runtime/routes/schedule-routes.ts +7 -0
- package/src/runtime/verification-templates.ts +4 -7
- package/src/schedule/integration-status.ts +66 -2
- package/src/schedule/recurrence-engine.ts +4 -1
- package/src/schedule/retry-backoff.ts +18 -0
- package/src/schedule/retry-policy.ts +82 -0
- package/src/schedule/schedule-recovery.ts +64 -0
- package/src/schedule/schedule-store.ts +106 -2
- package/src/schedule/scheduler-types.ts +25 -0
- package/src/schedule/scheduler.ts +63 -38
- package/src/security/oauth-callback-registry.ts +8 -0
- package/src/sequence/analytics.ts +5 -5
- package/src/sequence/engine.ts +1 -1
- package/src/skills/catalog-files.ts +2 -8
- package/src/skills/include-graph.ts +5 -5
- package/src/skills/remote-skill-policy.ts +5 -5
- package/src/skills/skill-file-provider.ts +1 -1
- package/src/skills/skill-file-types.ts +13 -0
- package/src/skills/skillssh-audit-types.ts +28 -0
- package/src/skills/skillssh-registry.ts +8 -21
- package/src/telemetry/types.ts +2 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +21 -0
- package/src/telemetry/usage-telemetry-reporter.ts +1 -0
- package/src/tools/app-control/skill-proxy-bridge.ts +28 -0
- package/src/tools/apps/executors.ts +56 -69
- package/src/tools/browser/__tests__/browser-status.test.ts +21 -18
- package/src/tools/browser/browser-execution.ts +2 -2
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +55 -4
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +12 -6
- package/src/tools/browser/cdp-client/factory.ts +23 -24
- package/src/tools/browser/cdp-client/index.ts +1 -14
- package/src/tools/computer-use/definitions.ts +42 -20
- package/src/tools/executor.ts +2 -0
- package/src/tools/host-filesystem/edit.ts +26 -0
- package/src/tools/host-filesystem/read.ts +26 -0
- package/src/tools/host-filesystem/transfer.ts +31 -1
- package/src/tools/host-filesystem/write.ts +26 -0
- package/src/tools/host-terminal/host-shell.ts +58 -0
- package/src/tools/schedule/create.ts +6 -0
- package/src/tools/schedule/list.ts +2 -0
- package/src/tools/schedule/update.ts +10 -0
- package/src/tools/shared/filesystem/file-ops-service.ts +2 -0
- package/src/tools/shared/filesystem/path-policy.ts +25 -1
- package/src/tools/skills/load.ts +0 -32
- package/src/tools/tool-approval-handler.ts +1 -5
- package/src/tools/types.ts +4 -0
- package/src/usage/pricing.ts +1 -1
- package/src/workspace/hatched-date.ts +86 -0
- package/src/workspace/migrations/003-seed-device-id.ts +1 -1
- package/src/workspace/migrations/006-services-config.ts +8 -5
- package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +3 -9
- package/src/workspace/migrations/021-move-signals-to-workspace.ts +4 -10
- package/src/workspace/migrations/022-move-hooks-to-workspace.ts +4 -10
- package/src/workspace/migrations/023-move-config-files-to-workspace.ts +4 -11
- package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +3 -10
- package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +3 -2
- package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +2 -1
- package/src/workspace/migrations/059-move-pid-to-workspace.ts +3 -8
- package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +3 -8
- package/src/workspace/migrations/AGENTS.md +1 -1
- package/src/workspace/migrations/migrate-to-workspace-volume.ts +4 -10
- package/src/workspace/migrations/utils.ts +21 -0
- package/src/__tests__/host-browser-e2e-cloud.test.ts +0 -443
- package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +0 -226
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +0 -427
- package/src/__tests__/twilio-rest.test.ts +0 -34
- package/src/backup/__tests__/backup-key.test.ts +0 -152
- package/src/backup/__tests__/backup-worker.test.ts +0 -782
- package/src/backup/__tests__/offsite-writer.test.ts +0 -641
- package/src/backup/__tests__/stream-crypt.test.ts +0 -228
- package/src/backup/backup-key.ts +0 -137
- package/src/backup/backup-worker.ts +0 -472
- package/src/backup/offsite-writer.ts +0 -222
- package/src/backup/stream-crypt.ts +0 -263
- package/src/daemon/message-types/pairing.ts +0 -58
- package/src/outbound-proxy/config.ts +0 -20
- package/src/outbound-proxy/health.ts +0 -18
- package/src/outbound-proxy/types.ts +0 -150
- package/src/runtime/capability-tokens.ts +0 -190
- package/src/signals/mcp-reload.ts +0 -18
|
@@ -42,7 +42,6 @@ export interface AppStoreWriter {
|
|
|
42
42
|
icon?: string;
|
|
43
43
|
schemaJson: string;
|
|
44
44
|
htmlDefinition: string;
|
|
45
|
-
pages?: Record<string, string>;
|
|
46
45
|
formatVersion?: number;
|
|
47
46
|
}): AppDefinition;
|
|
48
47
|
updateApp(
|
|
@@ -77,12 +76,16 @@ export interface AppCreateInput {
|
|
|
77
76
|
name: string;
|
|
78
77
|
description?: string;
|
|
79
78
|
schema_json?: string;
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Retired single-file shortcut. Kept in the type so legacy or stale callers
|
|
81
|
+
* get a clear tool error instead of silently creating a v2 app with stale
|
|
82
|
+
* scaffold content.
|
|
83
|
+
*/
|
|
84
|
+
html?: unknown;
|
|
85
|
+
/** Retired single-file multi-page shortcut. */
|
|
86
|
+
pages?: unknown;
|
|
82
87
|
auto_open?: boolean;
|
|
83
88
|
preview?: Record<string, unknown>;
|
|
84
|
-
/** When provided, controls multifile scaffold behavior. */
|
|
85
|
-
featureFlags?: { multifileEnabled: boolean };
|
|
86
89
|
}
|
|
87
90
|
|
|
88
91
|
export async function executeAppCreate(
|
|
@@ -93,22 +96,26 @@ export async function executeAppCreate(
|
|
|
93
96
|
const name = input.name;
|
|
94
97
|
const description = input.description;
|
|
95
98
|
const schemaJson = input.schema_json ?? "{}";
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
let htmlDefinition: string;
|
|
99
|
-
if (typeof input.html === "string") {
|
|
100
|
-
htmlDefinition = input.html;
|
|
101
|
-
} else if (input.html == null) {
|
|
102
|
-
htmlDefinition = "<!DOCTYPE html><html><head></head><body></body></html>";
|
|
103
|
-
} else {
|
|
99
|
+
|
|
100
|
+
if (Object.prototype.hasOwnProperty.call(input, "html")) {
|
|
104
101
|
return {
|
|
105
102
|
content: JSON.stringify({
|
|
106
|
-
error:
|
|
103
|
+
error:
|
|
104
|
+
"app_create no longer accepts html. Create the app scaffold, write src/index.html and src/main.tsx with file_write, then call app_refresh.",
|
|
105
|
+
}),
|
|
106
|
+
isError: true,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (Object.prototype.hasOwnProperty.call(input, "pages")) {
|
|
111
|
+
return {
|
|
112
|
+
content: JSON.stringify({
|
|
113
|
+
error:
|
|
114
|
+
"app_create no longer accepts pages. Build multi-file TSX apps under src/ and route inside the Preact app instead.",
|
|
107
115
|
}),
|
|
108
116
|
isError: true,
|
|
109
117
|
};
|
|
110
118
|
}
|
|
111
|
-
const pages = input.pages;
|
|
112
119
|
const autoOpen = input.auto_open !== false; // default true
|
|
113
120
|
const preview = input.preview;
|
|
114
121
|
|
|
@@ -121,49 +128,30 @@ export async function executeAppCreate(
|
|
|
121
128
|
isError: true,
|
|
122
129
|
};
|
|
123
130
|
}
|
|
124
|
-
if (pages) {
|
|
125
|
-
for (const [filename, content] of Object.entries(pages)) {
|
|
126
|
-
if (typeof content !== "string") {
|
|
127
|
-
return {
|
|
128
|
-
content: JSON.stringify({
|
|
129
|
-
error: `pages["${filename}"] must be a string, got ${typeof content}`,
|
|
130
|
-
}),
|
|
131
|
-
isError: true,
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
131
|
|
|
137
132
|
// Extract icon from preview if provided - only persist emoji-like values,
|
|
138
133
|
// not URLs which would render as raw strings in UI and bundle manifests.
|
|
139
134
|
const rawIcon = preview?.icon as string | undefined;
|
|
140
135
|
const icon = rawIcon && !rawIcon.startsWith("http") ? rawIcon : undefined;
|
|
141
136
|
|
|
142
|
-
const multifileEnabled = input.featureFlags?.multifileEnabled === true;
|
|
143
|
-
|
|
144
137
|
const app = store.createApp({
|
|
145
138
|
name,
|
|
146
139
|
description,
|
|
147
140
|
icon,
|
|
148
141
|
schemaJson,
|
|
149
|
-
htmlDefinition:
|
|
150
|
-
|
|
151
|
-
formatVersion: multifileEnabled ? 2 : undefined,
|
|
142
|
+
htmlDefinition: "",
|
|
143
|
+
formatVersion: 2,
|
|
152
144
|
});
|
|
153
145
|
|
|
154
146
|
// Scaffold multifile app with src/ files and compile to dist/
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
const indexHtml =
|
|
164
|
-
typeof input.html === "string"
|
|
165
|
-
? input.html
|
|
166
|
-
: `<!DOCTYPE html>
|
|
147
|
+
const htmlSafeName = name
|
|
148
|
+
.replace(/&/g, "&")
|
|
149
|
+
.replace(/</g, "<")
|
|
150
|
+
.replace(/>/g, ">")
|
|
151
|
+
.replace(/"/g, """);
|
|
152
|
+
const jsxSafeName = name.replace(/[<>{}&"']/g, "");
|
|
153
|
+
|
|
154
|
+
const indexHtml = `<!DOCTYPE html>
|
|
167
155
|
<html lang="en">
|
|
168
156
|
<head>
|
|
169
157
|
<meta charset="UTF-8">
|
|
@@ -175,7 +163,7 @@ export async function executeAppCreate(
|
|
|
175
163
|
</body>
|
|
176
164
|
</html>`;
|
|
177
165
|
|
|
178
|
-
|
|
166
|
+
const mainTsx = `import { render } from 'preact';
|
|
179
167
|
|
|
180
168
|
function App() {
|
|
181
169
|
return <div>{"Hello, ${jsxSafeName}!"}</div>;
|
|
@@ -184,31 +172,30 @@ function App() {
|
|
|
184
172
|
render(<App />, document.getElementById('app')!);
|
|
185
173
|
`;
|
|
186
174
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
175
|
+
// Only write scaffold files when they don't already exist on disk.
|
|
176
|
+
// The LLM may have written custom source files via file_write before
|
|
177
|
+
// calling app_create, and overwriting them would destroy the real app
|
|
178
|
+
// content, leaving only the scaffold placeholder.
|
|
179
|
+
if (!store.appFileExists(app.id, "src/index.html")) {
|
|
180
|
+
store.writeAppFile(app.id, "src/index.html", indexHtml);
|
|
181
|
+
}
|
|
182
|
+
if (!store.appFileExists(app.id, "src/main.tsx")) {
|
|
183
|
+
store.writeAppFile(app.id, "src/main.tsx", mainTsx);
|
|
184
|
+
}
|
|
197
185
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
}
|
|
186
|
+
// Compile src/ → dist/
|
|
187
|
+
const appDir = getAppDirPath(app.id);
|
|
188
|
+
const compileResult = await compileApp(appDir);
|
|
189
|
+
if (!compileResult.ok) {
|
|
190
|
+
return {
|
|
191
|
+
content: JSON.stringify({
|
|
192
|
+
...app,
|
|
193
|
+
compile_errors: compileResult.errors,
|
|
194
|
+
compile_warnings: compileResult.warnings,
|
|
195
|
+
compile_duration_ms: compileResult.durationMs,
|
|
196
|
+
}),
|
|
197
|
+
isError: false,
|
|
198
|
+
};
|
|
212
199
|
}
|
|
213
200
|
|
|
214
201
|
// Emit the inline preview card via the proxy without opening a workspace panel.
|
|
@@ -85,11 +85,13 @@ mock.module("../browser-manager.js", () => ({
|
|
|
85
85
|
/** Mutable proxy returned by HostBrowserProxy.instance. */
|
|
86
86
|
let mockSingletonProxy: {
|
|
87
87
|
isAvailable: () => boolean;
|
|
88
|
+
hasExtensionClient: () => boolean;
|
|
88
89
|
request: unknown;
|
|
89
90
|
} | null = null;
|
|
90
91
|
|
|
91
92
|
const unavailableFallback = {
|
|
92
93
|
isAvailable: () => false,
|
|
94
|
+
hasExtensionClient: () => false,
|
|
93
95
|
request: () => Promise.reject(new Error("no extension")),
|
|
94
96
|
};
|
|
95
97
|
|
|
@@ -159,7 +161,7 @@ describe("executeBrowserStatus", () => {
|
|
|
159
161
|
});
|
|
160
162
|
|
|
161
163
|
test("reports extension as connected when probe fails on restricted chrome:// page", async () => {
|
|
162
|
-
mockSingletonProxy = { isAvailable: () => true, request: () => {} };
|
|
164
|
+
mockSingletonProxy = { isAvailable: () => true, hasExtensionClient: () => true, request: () => {} };
|
|
163
165
|
probeOutcomes[BROWSER_STATUS_MODE.EXTENSION] = "fail";
|
|
164
166
|
probeErrors[BROWSER_STATUS_MODE.EXTENSION] = new CdpError(
|
|
165
167
|
"cdp_error",
|
|
@@ -181,7 +183,7 @@ describe("executeBrowserStatus", () => {
|
|
|
181
183
|
// ── macOS host-browser proxy mode tests ─────────────────────────────
|
|
182
184
|
|
|
183
185
|
test("reports extension as available when singleton proxy is connected", async () => {
|
|
184
|
-
mockSingletonProxy = { isAvailable: () => true, request: () => {} };
|
|
186
|
+
mockSingletonProxy = { isAvailable: () => true, hasExtensionClient: () => true, request: () => {} };
|
|
185
187
|
const result = await executeBrowserStatus(
|
|
186
188
|
{},
|
|
187
189
|
makeContext({
|
|
@@ -199,22 +201,23 @@ describe("executeBrowserStatus", () => {
|
|
|
199
201
|
expect(extension.details.transport).toBe("extension-ws");
|
|
200
202
|
});
|
|
201
203
|
|
|
202
|
-
test("reports extension
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
204
|
+
test("reports extension unavailable when no Chrome Extension is connected", async () => {
|
|
205
|
+
// mockSingletonProxy = null → falls back to unavailableFallback (hasExtensionClient = false)
|
|
206
|
+
const result = await executeBrowserStatus({}, makeContext());
|
|
207
|
+
expect(result.isError).toBe(false);
|
|
208
|
+
const payload = JSON.parse(result.content);
|
|
209
|
+
const extension = payload.modes.find(
|
|
210
|
+
(m: { mode: string }) => m.mode === BROWSER_STATUS_MODE.EXTENSION,
|
|
211
|
+
);
|
|
212
|
+
expect(extension).toBeDefined();
|
|
213
|
+
expect(extension.available).toBe(false);
|
|
214
|
+
expect(extension.summary).toContain("no Chrome Extension is connected");
|
|
215
|
+
expect(extension.verified).toBe("preflight");
|
|
216
|
+
expect(extension.details.transport).toBe("extension-ws");
|
|
217
|
+
});
|
|
215
218
|
|
|
216
219
|
test("probe failure diagnostics include remediation actions", async () => {
|
|
217
|
-
mockSingletonProxy = { isAvailable: () => true, request: () => {} };
|
|
220
|
+
mockSingletonProxy = { isAvailable: () => true, hasExtensionClient: () => true, request: () => {} };
|
|
218
221
|
probeOutcomes[BROWSER_STATUS_MODE.EXTENSION] = "fail";
|
|
219
222
|
probeErrors[BROWSER_STATUS_MODE.EXTENSION] = new CdpError(
|
|
220
223
|
"transport_error",
|
|
@@ -233,7 +236,7 @@ describe("executeBrowserStatus", () => {
|
|
|
233
236
|
});
|
|
234
237
|
|
|
235
238
|
test("recommendation order follows auto candidate precedence with available extension", async () => {
|
|
236
|
-
mockSingletonProxy = { isAvailable: () => true, request: () => {} };
|
|
239
|
+
mockSingletonProxy = { isAvailable: () => true, hasExtensionClient: () => true, request: () => {} };
|
|
237
240
|
const result = await executeBrowserStatus({}, makeContext());
|
|
238
241
|
expect(result.isError).toBe(false);
|
|
239
242
|
const payload = JSON.parse(result.content);
|
|
@@ -252,7 +255,7 @@ describe("executeBrowserStatus", () => {
|
|
|
252
255
|
});
|
|
253
256
|
|
|
254
257
|
test("restricted chrome:// page probe includes transport details", async () => {
|
|
255
|
-
mockSingletonProxy = { isAvailable: () => true, request: () => {} };
|
|
258
|
+
mockSingletonProxy = { isAvailable: () => true, hasExtensionClient: () => true, request: () => {} };
|
|
256
259
|
probeOutcomes[BROWSER_STATUS_MODE.EXTENSION] = "fail";
|
|
257
260
|
probeErrors[BROWSER_STATUS_MODE.EXTENSION] = new CdpError(
|
|
258
261
|
"cdp_error",
|
|
@@ -2251,14 +2251,14 @@ async function checkExtensionModeStatus(
|
|
|
2251
2251
|
): Promise<BrowserStatusModeResult> {
|
|
2252
2252
|
const proxy = HostBrowserProxy.instance;
|
|
2253
2253
|
|
|
2254
|
-
if (!proxy.
|
|
2254
|
+
if (!proxy.hasExtensionClient()) {
|
|
2255
2255
|
return {
|
|
2256
2256
|
mode: BROWSER_STATUS_MODE.EXTENSION,
|
|
2257
2257
|
available: false,
|
|
2258
2258
|
verified: "preflight",
|
|
2259
2259
|
autoCandidate,
|
|
2260
2260
|
summary:
|
|
2261
|
-
"Extension mode is unavailable:
|
|
2261
|
+
"Extension mode is unavailable: no Chrome Extension is connected.",
|
|
2262
2262
|
userActions: extensionSetupActions(),
|
|
2263
2263
|
tradeoffs: modeTradeoffs(BROWSER_STATUS_MODE.EXTENSION),
|
|
2264
2264
|
details: { transport: "extension-ws" },
|
|
@@ -119,6 +119,7 @@ let mockSingletonProxy: HostBrowserProxy | null = null;
|
|
|
119
119
|
/** Default proxy that reports unavailable — used when no test override is set. */
|
|
120
120
|
const unavailableFallback: HostBrowserProxy = {
|
|
121
121
|
isAvailable: () => false,
|
|
122
|
+
hasExtensionClient: () => false,
|
|
122
123
|
request: () => Promise.reject(new Error("no extension")),
|
|
123
124
|
resolve: () => {},
|
|
124
125
|
hasPendingRequest: () => false,
|
|
@@ -161,23 +162,38 @@ function makeContext(
|
|
|
161
162
|
}
|
|
162
163
|
|
|
163
164
|
/**
|
|
164
|
-
* Create a fake HostBrowserProxy
|
|
165
|
+
* Create a fake HostBrowserProxy with a Chrome Extension client connected.
|
|
166
|
+
* Both isAvailable() and hasExtensionClient() return true.
|
|
165
167
|
*/
|
|
166
168
|
function makeAvailableProxy(): HostBrowserProxy {
|
|
167
169
|
return {
|
|
168
170
|
request: mock(async () => ({})),
|
|
169
171
|
isAvailable: () => true,
|
|
172
|
+
hasExtensionClient: () => true,
|
|
173
|
+
} as unknown as HostBrowserProxy;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Create a fake HostBrowserProxy where only the macOS SSE bridge is connected
|
|
178
|
+
* (no Chrome Extension). isAvailable() is true but hasExtensionClient() is false.
|
|
179
|
+
*/
|
|
180
|
+
function makeMacosBridgeOnlyProxy(): HostBrowserProxy {
|
|
181
|
+
return {
|
|
182
|
+
request: mock(async () => ({})),
|
|
183
|
+
isAvailable: () => true,
|
|
184
|
+
hasExtensionClient: () => false,
|
|
170
185
|
} as unknown as HostBrowserProxy;
|
|
171
186
|
}
|
|
172
187
|
|
|
173
188
|
/**
|
|
174
189
|
* Create a fake HostBrowserProxy that reports as unavailable
|
|
175
|
-
* (proxy exists but client is
|
|
190
|
+
* (proxy exists but no client of any kind is connected).
|
|
176
191
|
*/
|
|
177
192
|
function makeUnavailableProxy(): HostBrowserProxy {
|
|
178
193
|
return {
|
|
179
194
|
request: mock(async () => ({})),
|
|
180
195
|
isAvailable: () => false,
|
|
196
|
+
hasExtensionClient: () => false,
|
|
181
197
|
} as unknown as HostBrowserProxy;
|
|
182
198
|
}
|
|
183
199
|
|
|
@@ -682,6 +698,22 @@ describe("buildCandidateList", () => {
|
|
|
682
698
|
expect(candidates[0].kind).toBe("local");
|
|
683
699
|
});
|
|
684
700
|
|
|
701
|
+
test("excludes extension candidate when only macOS SSE bridge is connected", () => {
|
|
702
|
+
// isAvailable() = true but hasExtensionClient() = false: only macOS bridge.
|
|
703
|
+
// The macOS bridge routes through localhost:9222 on the host, so it must
|
|
704
|
+
// NOT be included under the "extension" candidate kind.
|
|
705
|
+
const fakeProxy = makeMacosBridgeOnlyProxy();
|
|
706
|
+
mockSingletonProxy = fakeProxy;
|
|
707
|
+
const ctx = makeContext({
|
|
708
|
+
conversationId: "candidates-macos-bridge-only",
|
|
709
|
+
});
|
|
710
|
+
|
|
711
|
+
const candidates = buildCandidateList(ctx);
|
|
712
|
+
|
|
713
|
+
expect(candidates.every((c) => c.kind !== "extension")).toBe(true);
|
|
714
|
+
expect(candidates[candidates.length - 1].kind).toBe("local");
|
|
715
|
+
});
|
|
716
|
+
|
|
685
717
|
test("includes cdp-inspect candidate when enabled in config", () => {
|
|
686
718
|
cdpInspectEnabled = true;
|
|
687
719
|
const ctx = makeContext({ conversationId: "candidates-inspect" });
|
|
@@ -1435,7 +1467,7 @@ describe("pinned-mode selection", () => {
|
|
|
1435
1467
|
const cdpErr = err as CdpError;
|
|
1436
1468
|
expect(cdpErr.code).toBe("transport_error");
|
|
1437
1469
|
expect(cdpErr.message).toContain('Pinned mode "extension" unavailable');
|
|
1438
|
-
expect(cdpErr.message).toContain("no
|
|
1470
|
+
expect(cdpErr.message).toContain("no Chrome Extension connected");
|
|
1439
1471
|
expect(cdpErr.attemptDiagnostics).toBeDefined();
|
|
1440
1472
|
expect(cdpErr.attemptDiagnostics).toHaveLength(1);
|
|
1441
1473
|
expect(cdpErr.attemptDiagnostics![0].candidateKind).toBe("extension");
|
|
@@ -1457,7 +1489,7 @@ describe("pinned-mode selection", () => {
|
|
|
1457
1489
|
} catch (err) {
|
|
1458
1490
|
const cdpErr = err as CdpError;
|
|
1459
1491
|
expect(cdpErr.code).toBe("transport_error");
|
|
1460
|
-
expect(cdpErr.message).toContain("no
|
|
1492
|
+
expect(cdpErr.message).toContain("no Chrome Extension connected");
|
|
1461
1493
|
expect(cdpErr.attemptDiagnostics![0].stage).toBe("candidate_selection");
|
|
1462
1494
|
}
|
|
1463
1495
|
});
|
|
@@ -1667,6 +1699,25 @@ describe("buildPinnedCandidateList", () => {
|
|
|
1667
1699
|
});
|
|
1668
1700
|
}
|
|
1669
1701
|
});
|
|
1702
|
+
|
|
1703
|
+
test("extension mode throws when only macOS SSE bridge is connected", () => {
|
|
1704
|
+
// This is the bug case: isAvailable() = true but hasExtensionClient() = false.
|
|
1705
|
+
// Before the fix, this would build an extension candidate that silently
|
|
1706
|
+
// dispatched to the macOS bridge and failed with a misleading localhost:9222 error.
|
|
1707
|
+
const fakeProxy = makeMacosBridgeOnlyProxy();
|
|
1708
|
+
mockSingletonProxy = fakeProxy;
|
|
1709
|
+
const ctx = makeContext({ conversationId: "bpl-ext-macos-bridge-only" });
|
|
1710
|
+
|
|
1711
|
+
try {
|
|
1712
|
+
buildPinnedCandidateList(ctx, "extension");
|
|
1713
|
+
expect(true).toBe(false); // should not reach
|
|
1714
|
+
} catch (err) {
|
|
1715
|
+
expect(err).toBeInstanceOf(CdpError);
|
|
1716
|
+
const cdpErr = err as CdpError;
|
|
1717
|
+
expect(cdpErr.code).toBe("transport_error");
|
|
1718
|
+
expect(cdpErr.message).toContain("no Chrome Extension connected");
|
|
1719
|
+
}
|
|
1720
|
+
});
|
|
1670
1721
|
});
|
|
1671
1722
|
|
|
1672
1723
|
// ── Attempt diagnostics & fallback log tests ─────────────────────────────
|
|
@@ -511,14 +511,19 @@ describe("connectCdpWsTransport", () => {
|
|
|
511
511
|
});
|
|
512
512
|
|
|
513
513
|
test("addEventListener returns an unsubscribe function", async () => {
|
|
514
|
+
// Use a sentinel request to gate event emission on the server: the
|
|
515
|
+
// listener is registered before send() runs, so by the time the server
|
|
516
|
+
// receives the sentinel and starts emitting events the client listener
|
|
517
|
+
// is guaranteed to be attached. A bare setTimeout-after-open race is
|
|
518
|
+
// tight enough to flake on busy CI runners.
|
|
514
519
|
const server = startFakeWsServer({
|
|
515
|
-
|
|
520
|
+
onMessage(ws, frame) {
|
|
521
|
+
if (frame.method !== "Test.startEvents") return;
|
|
522
|
+
ws.send(JSON.stringify({ id: frame.id, result: {} }));
|
|
523
|
+
ws.send(JSON.stringify({ method: "Ev.first", params: {} }));
|
|
516
524
|
setTimeout(() => {
|
|
517
|
-
ws.send(JSON.stringify({ method: "Ev.
|
|
518
|
-
|
|
519
|
-
ws.send(JSON.stringify({ method: "Ev.second", params: {} }));
|
|
520
|
-
}, 10);
|
|
521
|
-
}, 5);
|
|
525
|
+
ws.send(JSON.stringify({ method: "Ev.second", params: {} }));
|
|
526
|
+
}, 10);
|
|
522
527
|
},
|
|
523
528
|
});
|
|
524
529
|
try {
|
|
@@ -528,6 +533,7 @@ describe("connectCdpWsTransport", () => {
|
|
|
528
533
|
received.push(ev.method);
|
|
529
534
|
if (ev.method === "Ev.first") unsub();
|
|
530
535
|
});
|
|
536
|
+
await transport.send("Test.startEvents");
|
|
531
537
|
await new Promise((r) => setTimeout(r, 60));
|
|
532
538
|
expect(received).toEqual(["Ev.first"]);
|
|
533
539
|
});
|
|
@@ -187,25 +187,25 @@ export function buildPinnedCandidateList(
|
|
|
187
187
|
|
|
188
188
|
switch (mode) {
|
|
189
189
|
case "extension": {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
190
|
+
const hostBrowserProxy = HostBrowserProxy.instance;
|
|
191
|
+
if (!hostBrowserProxy.hasExtensionClient()) {
|
|
192
|
+
throw new CdpError(
|
|
193
|
+
"transport_error",
|
|
194
|
+
`Pinned mode "extension" unavailable: no Chrome Extension connected`,
|
|
195
|
+
{
|
|
196
|
+
attemptDiagnostics: [
|
|
197
|
+
{
|
|
198
|
+
candidateKind: "extension",
|
|
199
|
+
inclusionReason: `pinned mode: extension`,
|
|
200
|
+
stage: "candidate_selection",
|
|
201
|
+
errorCode: "transport_error",
|
|
202
|
+
errorMessage: "no Chrome Extension connected",
|
|
203
|
+
},
|
|
204
|
+
],
|
|
205
|
+
},
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
return [
|
|
209
209
|
{
|
|
210
210
|
kind: "extension",
|
|
211
211
|
reason: "pinned mode: extension",
|
|
@@ -291,12 +291,11 @@ export function buildCandidateList(context: ToolContext): BackendCandidate[] {
|
|
|
291
291
|
const candidates: BackendCandidate[] = [];
|
|
292
292
|
const hostBrowserProxy = HostBrowserProxy.instance;
|
|
293
293
|
|
|
294
|
-
// 1. Extension -- preferred when
|
|
295
|
-
|
|
296
|
-
if (hostBrowserProxy.isAvailable()) {
|
|
294
|
+
// 1. Extension -- preferred when a Chrome Extension client is connected.
|
|
295
|
+
if (hostBrowserProxy.hasExtensionClient()) {
|
|
297
296
|
candidates.push({
|
|
298
297
|
kind: "extension",
|
|
299
|
-
reason: "
|
|
298
|
+
reason: "Chrome Extension connected via registry singleton",
|
|
300
299
|
create() {
|
|
301
300
|
const client = createExtensionCdpClient(
|
|
302
301
|
hostBrowserProxy,
|
|
@@ -314,7 +313,7 @@ export function buildCandidateList(context: ToolContext): BackendCandidate[] {
|
|
|
314
313
|
} else {
|
|
315
314
|
log.debug(
|
|
316
315
|
{ conversationId },
|
|
317
|
-
"CDP factory: no
|
|
316
|
+
"CDP factory: no Chrome Extension connected, skipping extension candidate",
|
|
318
317
|
);
|
|
319
318
|
}
|
|
320
319
|
|
|
@@ -1,15 +1,2 @@
|
|
|
1
|
-
export {
|
|
2
|
-
type CdpInspectClientOptions,
|
|
3
|
-
type CdpInspectHelpers,
|
|
4
|
-
} from "./cdp-inspect-client.js";
|
|
5
1
|
export { CdpError, type CdpErrorCode } from "./errors.js";
|
|
6
|
-
export {
|
|
7
|
-
export type {
|
|
8
|
-
AttemptDiagnostic,
|
|
9
|
-
AttemptStage,
|
|
10
|
-
BackendCandidate,
|
|
11
|
-
BrowserMode,
|
|
12
|
-
CdpClient,
|
|
13
|
-
CdpClientKind,
|
|
14
|
-
ScopedCdpClient,
|
|
15
|
-
} from "./types.js";
|
|
2
|
+
export type { CdpClient, CdpClientKind, ScopedCdpClient } from "./types.js";
|