@vellumai/assistant 0.6.2 → 0.6.3
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/bun.lock +40 -40
- package/bunfig.toml +3 -0
- package/docs/architecture/memory.md +1 -1
- package/node_modules/@vellumai/ces-contracts/src/rpc.ts +42 -0
- package/openapi.yaml +184 -69
- package/package.json +41 -41
- package/scripts/generate-openapi.ts +1 -2
- package/src/__tests__/acp-session.test.ts +43 -0
- package/src/__tests__/app-builder-tool-scripts.test.ts +1 -0
- package/src/__tests__/app-executors.test.ts +1 -0
- package/src/__tests__/app-source-watcher.test.ts +37 -11
- package/src/__tests__/approval-routes-http.test.ts +178 -1
- package/src/__tests__/browser-fill-credential.test.ts +229 -94
- package/src/__tests__/browser-manager.test.ts +40 -27
- package/src/__tests__/catalog-files.test.ts +862 -0
- package/src/__tests__/channel-approvals.test.ts +53 -0
- package/src/__tests__/config-managed-gemini-defaults.test.ts +326 -0
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +125 -48
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +23 -0
- package/src/__tests__/context-overflow-approval.test.ts +16 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop.test.ts +1 -1
- package/src/__tests__/conversation-analysis-routes.test.ts +2 -2
- package/src/__tests__/conversation-attachments.test.ts +80 -4
- package/src/__tests__/conversation-confirmation-signals.test.ts +155 -0
- package/src/__tests__/conversation-fork-crud.test.ts +17 -0
- package/src/__tests__/conversation-history-web-search.test.ts +1 -0
- package/src/__tests__/conversation-host-access-routes.test.ts +229 -0
- package/src/__tests__/conversation-inject-context.test.ts +103 -0
- package/src/__tests__/conversation-queue.test.ts +45 -2
- package/src/__tests__/conversation-routes-disk-view.test.ts +5 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +16 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +269 -46
- package/src/__tests__/conversation-starter-routes.test.ts +126 -0
- package/src/__tests__/conversation-starters-cadence.test.ts +161 -0
- package/src/__tests__/conversation-store.test.ts +195 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +193 -0
- package/src/__tests__/credential-execution-approval-bridge.test.ts +32 -1
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/credential-vault-unit.test.ts +4 -4
- package/src/__tests__/credential-vault.test.ts +152 -13
- package/src/__tests__/credentials-cli.test.ts +2 -2
- package/src/__tests__/date-context.test.ts +4 -4
- package/src/__tests__/embedding-managed-proxy-selection.test.ts +256 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +155 -0
- package/src/__tests__/fixtures/mock-chrome-extension.ts +375 -0
- package/src/__tests__/gateway-only-guard.test.ts +3 -0
- package/src/__tests__/gemini-provider.test.ts +2 -2
- package/src/__tests__/guardian-routing-invariants.test.ts +70 -2
- package/src/__tests__/headless-browser-interactions.test.ts +707 -371
- package/src/__tests__/headless-browser-navigate.test.ts +389 -47
- package/src/__tests__/headless-browser-read-tools.test.ts +266 -103
- package/src/__tests__/headless-browser-snapshot.test.ts +240 -77
- package/src/__tests__/host-bash-proxy.test.ts +150 -1
- package/src/__tests__/host-browser-e2e-cloud.test.ts +462 -0
- package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +286 -0
- package/src/__tests__/host-browser-e2e-self-hosted.test.ts +374 -0
- package/src/__tests__/host-browser-event-routes.test.ts +350 -0
- package/src/__tests__/host-browser-proxy.test.ts +444 -0
- package/src/__tests__/host-browser-routes.test.ts +198 -0
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +320 -0
- package/src/__tests__/host-cu-proxy.test.ts +171 -1
- package/src/__tests__/host-file-proxy.test.ts +185 -1
- package/src/__tests__/host-file-read-tool.test.ts +52 -0
- package/src/__tests__/host-proxy-interface.test.ts +165 -0
- package/src/__tests__/host-shell-tool.test.ts +1 -11
- package/src/__tests__/http-user-message-parity.test.ts +1 -0
- package/src/__tests__/integration-status.test.ts +6 -7
- package/src/__tests__/list-messages-tool-merge.test.ts +37 -12
- package/src/__tests__/mcp-client-auth.test.ts +40 -4
- package/src/__tests__/mcp-health-check.test.ts +10 -3
- package/src/__tests__/migration-cross-version-compatibility.test.ts +3 -1
- package/src/__tests__/migration-export-http.test.ts +61 -2
- package/src/__tests__/migration-export-streaming.test.ts +66 -0
- package/src/__tests__/migration-import-commit-http.test.ts +101 -1
- package/src/__tests__/native-host-marker-sync-guard.test.ts +157 -0
- package/src/__tests__/oauth-apps-routes.test.ts +17 -12
- package/src/__tests__/oauth-cli.test.ts +707 -60
- package/src/__tests__/oauth-connect-orchestrator.test.ts +116 -24
- package/src/__tests__/oauth-provider-seed-logos.test.ts +23 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +146 -10
- package/src/__tests__/oauth-provider-visibility.test.ts +19 -21
- package/src/__tests__/oauth-providers-routes.test.ts +50 -14
- package/src/__tests__/oauth-store.test.ts +1386 -182
- package/src/__tests__/oauth2-gateway-transport.test.ts +211 -20
- package/src/__tests__/onboarding-template-contract.test.ts +75 -57
- package/src/__tests__/openai-provider.test.ts +2 -2
- package/src/__tests__/outlook-categories.test.ts +1 -1
- package/src/__tests__/outlook-client-automation.test.ts +1 -1
- package/src/__tests__/outlook-compose-tools.test.ts +1 -1
- package/src/__tests__/outlook-email-watcher.test.ts +1 -1
- package/src/__tests__/outlook-follow-up.test.ts +1 -1
- package/src/__tests__/outlook-messaging-provider.test.ts +2 -2
- package/src/__tests__/outlook-trash.test.ts +1 -1
- package/src/__tests__/outlook-unsubscribe.test.ts +1 -1
- package/src/__tests__/permission-checker-host-gate.test.ts +74 -14
- package/src/__tests__/permission-mode.test.ts +28 -56
- package/src/__tests__/platform-callback-registration.test.ts +19 -0
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +296 -0
- package/src/__tests__/proxy-approval-callback.test.ts +18 -0
- package/src/__tests__/require-fresh-approval.test.ts +40 -1
- package/src/__tests__/sanitize-config-for-transfer.test.ts +132 -0
- package/src/__tests__/schedule-routes.test.ts +162 -0
- package/src/__tests__/secret-detection-handler.test.ts +84 -0
- package/src/__tests__/secret-ingress-http.test.ts +1 -0
- package/src/__tests__/send-endpoint-busy.test.ts +3 -0
- package/src/__tests__/set-permission-mode.test.ts +13 -250
- package/src/__tests__/skills-file-content-endpoint.test.ts +670 -0
- package/src/__tests__/skills-files-catalog-fallback.test.ts +450 -0
- package/src/__tests__/slack-channel-config.test.ts +12 -15
- package/src/__tests__/subagent-detail.test.ts +44 -2
- package/src/__tests__/subagent-disposal.test.ts +1 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +291 -0
- package/src/__tests__/subagent-fork-spawn.test.ts +384 -0
- package/src/__tests__/subagent-manager-notify.test.ts +1 -0
- package/src/__tests__/subagent-notify-parent.test.ts +1 -0
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +411 -0
- package/src/__tests__/subagent-tools.test.ts +1 -0
- package/src/__tests__/subagent-types.test.ts +1 -0
- package/src/__tests__/system-prompt-ask-mode.test.ts +27 -71
- package/src/__tests__/system-prompt.test.ts +72 -1
- package/src/__tests__/task-scheduler.test.ts +32 -6
- package/src/__tests__/telegram-config.test.ts +10 -13
- package/src/__tests__/terminal-tools.test.ts +9 -0
- package/src/__tests__/tool-approval-handler.test.ts +73 -0
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +22 -0
- package/src/__tests__/top-level-renderer.test.ts +73 -1
- package/src/__tests__/transport-hints-queue.test.ts +14 -29
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +109 -0
- package/src/__tests__/v2-consent-policy.test.ts +103 -0
- package/src/acp/client-handler.ts +30 -4
- package/src/agent/loop.ts +12 -6
- package/src/approvals/guardian-request-resolvers.ts +21 -15
- package/src/browser-session/__tests__/manager.test.ts +297 -0
- package/src/browser-session/backends/cdp-inspect.ts +30 -0
- package/src/browser-session/backends/extension.ts +26 -0
- package/src/browser-session/backends/local.ts +24 -0
- package/src/browser-session/events.ts +164 -0
- package/src/browser-session/index.ts +27 -0
- package/src/browser-session/manager.ts +159 -0
- package/src/browser-session/types.ts +28 -0
- package/src/channels/__tests__/types.test.ts +134 -0
- package/src/channels/types.ts +53 -3
- package/src/cli/commands/browser-relay.ts +339 -409
- package/src/cli/commands/credentials.ts +3 -3
- package/src/cli/commands/email.ts +18 -13
- package/src/cli/commands/mcp.ts +16 -4
- package/src/cli/commands/oauth/__tests__/connect.test.ts +44 -44
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +21 -21
- package/src/cli/commands/oauth/__tests__/mode.test.ts +17 -17
- package/src/cli/commands/oauth/__tests__/ping.test.ts +16 -16
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +31 -33
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +329 -0
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +116 -12
- package/src/cli/commands/oauth/__tests__/status.test.ts +10 -10
- package/src/cli/commands/oauth/__tests__/token.test.ts +7 -7
- package/src/cli/commands/oauth/apps.ts +7 -4
- package/src/cli/commands/oauth/connect.ts +6 -3
- package/src/cli/commands/oauth/disconnect.ts +1 -1
- package/src/cli/commands/oauth/providers.ts +200 -36
- package/src/cli/commands/oauth/shared.ts +5 -5
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +259 -0
- package/src/cli/commands/platform/index.ts +107 -10
- package/src/cli/commands/usage.ts +10 -9
- package/src/cli/lib/daemon-credential-client.ts +4 -0
- package/src/cli/program.ts +1 -1
- package/src/config/bundled-skills/app-builder/SKILL.md +26 -249
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +105 -0
- package/src/config/bundled-skills/app-builder/references/INTERACTION_HOOKS.md +56 -0
- package/src/config/bundled-skills/app-builder/references/WIDGETS.md +125 -0
- package/src/config/bundled-skills/contacts/SKILL.md +3 -0
- package/src/config/bundled-skills/document/SKILL.md +4 -0
- package/src/config/bundled-skills/gmail/SKILL.md +1 -1
- package/src/config/bundled-skills/outlook/SKILL.md +7 -0
- package/src/config/bundled-skills/subagent/SKILL.md +21 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +8 -4
- package/src/config/bundled-skills/tasks/SKILL.md +5 -0
- package/src/config/env-registry.ts +14 -0
- package/src/config/env.ts +21 -0
- package/src/config/feature-flag-registry.json +44 -5
- package/src/config/loader.ts +56 -1
- package/src/config/sanitize-for-transfer.ts +47 -0
- package/src/config/schema.ts +46 -5
- package/src/config/schemas/host-browser.ts +66 -0
- package/src/config/schemas/memory-lifecycle.ts +1 -1
- package/src/config/schemas/memory-retrieval.ts +103 -0
- package/src/config/schemas/security.ts +0 -6
- package/src/config/schemas/services.ts +8 -0
- package/src/config/types.ts +0 -1
- package/src/context/post-turn-tool-result-truncation.ts +176 -0
- package/src/context/window-manager.ts +19 -1
- package/src/credential-execution/approval-bridge.ts +49 -15
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +186 -0
- package/src/daemon/app-source-watcher.ts +35 -0
- package/src/daemon/context-overflow-approval.ts +5 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +17 -2
- package/src/daemon/conversation-agent-loop.ts +58 -24
- package/src/daemon/conversation-attachments.ts +40 -0
- package/src/daemon/conversation-process.ts +48 -1
- package/src/daemon/conversation-runtime-assembly.ts +118 -36
- package/src/daemon/conversation-surfaces.ts +37 -36
- package/src/daemon/conversation-tool-setup.ts +74 -8
- package/src/daemon/conversation-workspace.ts +12 -0
- package/src/daemon/conversation.ts +226 -8
- package/src/daemon/date-context.ts +10 -10
- package/src/daemon/first-greeting.ts +3 -2
- package/src/daemon/handlers/conversations.ts +9 -140
- package/src/daemon/handlers/shared.ts +58 -0
- package/src/daemon/handlers/skills.ts +232 -37
- package/src/daemon/host-bash-proxy.ts +48 -13
- package/src/daemon/host-browser-proxy.ts +191 -0
- package/src/daemon/host-cu-proxy.ts +36 -11
- package/src/daemon/host-file-proxy.ts +57 -9
- package/src/daemon/lifecycle.ts +65 -11
- package/src/daemon/message-protocol.ts +7 -0
- package/src/daemon/message-types/conversations.ts +55 -13
- package/src/daemon/message-types/host-browser.ts +100 -0
- package/src/daemon/message-types/messages.ts +5 -5
- package/src/daemon/message-types/skills.ts +10 -0
- package/src/daemon/message-types/subagents.ts +2 -0
- package/src/daemon/server.ts +92 -12
- package/src/daemon/tool-side-effects.ts +6 -0
- package/src/daemon/transport-hints.ts +5 -24
- package/src/inbound/platform-callback-registration.ts +18 -17
- package/src/mcp/client.ts +59 -24
- package/src/memory/app-store.ts +31 -1
- package/src/memory/conversation-crud.ts +23 -0
- package/src/memory/conversation-starters-cadence.ts +76 -0
- package/src/memory/conversation-title-service.ts +5 -2
- package/src/memory/db-init.ts +12 -0
- package/src/memory/embedding-backend.test.ts +75 -0
- package/src/memory/embedding-backend.ts +131 -5
- package/src/memory/embedding-gemini.test.ts +54 -0
- package/src/memory/embedding-gemini.ts +20 -9
- package/src/memory/embedding-local.ts +176 -17
- package/src/memory/graph/consolidation.ts +10 -23
- package/src/memory/graph/extraction-job.ts +15 -0
- package/src/memory/graph/retriever.ts +40 -22
- package/src/memory/graph/store.test.ts +7 -3
- package/src/memory/graph/store.ts +47 -12
- package/src/memory/llm-usage-store.ts +45 -4
- package/src/memory/migrations/213-oauth-providers-scope-separator.ts +13 -0
- package/src/memory/migrations/214-oauth-providers-refresh-url.ts +11 -0
- package/src/memory/migrations/215-oauth-providers-revoke.ts +14 -0
- package/src/memory/migrations/216-oauth-providers-token-auth-method.ts +30 -0
- package/src/memory/migrations/217-conversation-host-access.ts +40 -0
- package/src/memory/migrations/218-oauth-providers-logo-url.ts +11 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/schema/conversations.ts +1 -0
- package/src/memory/schema/oauth.ts +18 -13
- package/src/oauth/AGENTS.md +76 -0
- package/src/oauth/__tests__/identity-verifier.test.ts +24 -19
- package/src/oauth/__tests__/seed-providers-managed.test.ts +32 -0
- package/src/oauth/byo-connection.test.ts +8 -8
- package/src/oauth/byo-connection.ts +7 -7
- package/src/oauth/connect-orchestrator.ts +23 -21
- package/src/oauth/connect-types.ts +3 -3
- package/src/oauth/connection-resolver.test.ts +17 -4
- package/src/oauth/connection-resolver.ts +16 -16
- package/src/oauth/connection.ts +1 -1
- package/src/oauth/manual-token-connection.ts +13 -13
- package/src/oauth/oauth-store.ts +214 -100
- package/src/oauth/platform-connection.test.ts +3 -3
- package/src/oauth/platform-connection.ts +4 -4
- package/src/oauth/provider-serializer.ts +31 -5
- package/src/oauth/revoke.ts +76 -0
- package/src/oauth/seed-providers.ts +126 -87
- package/src/oauth/token-persistence.ts +1 -1
- package/src/permissions/permission-mode.ts +4 -11
- package/src/permissions/prompter.ts +13 -1
- package/src/permissions/v2-consent-policy.ts +87 -0
- package/src/prompts/system-prompt.ts +18 -21
- package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +3 -65
- package/src/prompts/templates/BOOTSTRAP.md +59 -105
- package/src/providers/anthropic/client.ts +1 -0
- package/src/providers/types.ts +1 -1
- package/src/runtime/AGENTS.md +23 -0
- package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +715 -0
- package/src/runtime/__tests__/capability-tokens.test.ts +258 -0
- package/src/runtime/__tests__/chrome-extension-registry.test.ts +518 -0
- package/src/runtime/assistant-event-hub.ts +2 -2
- package/src/runtime/auth/__tests__/guard-tests.test.ts +1 -0
- package/src/runtime/auth/__tests__/middleware.test.ts +116 -1
- package/src/runtime/auth/__tests__/route-policy.test.ts +8 -0
- package/src/runtime/auth/middleware.ts +98 -0
- package/src/runtime/auth/route-policy.ts +6 -7
- package/src/runtime/capability-tokens.ts +414 -0
- package/src/runtime/channel-approvals.ts +18 -5
- package/src/runtime/chrome-extension-registry.ts +332 -0
- package/src/runtime/confirmation-request-guardian-bridge.ts +6 -0
- package/src/runtime/guardian-decision-types.ts +7 -0
- package/src/runtime/http-server.ts +425 -70
- package/src/runtime/migrations/__tests__/rebind-secrets-credentials.test.ts +172 -0
- package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +276 -0
- package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +162 -0
- package/src/runtime/migrations/migration-transport.ts +6 -0
- package/src/runtime/migrations/migration-wizard.ts +22 -2
- package/src/runtime/migrations/rebind-secrets-screen.ts +76 -15
- package/src/runtime/migrations/vbundle-builder.ts +145 -38
- package/src/runtime/migrations/vbundle-import-analyzer.ts +19 -0
- package/src/runtime/migrations/vbundle-importer.ts +55 -5
- package/src/runtime/pending-interactions.ts +29 -13
- package/src/runtime/routes/approval-routes.ts +90 -16
- package/src/runtime/routes/browser-cdp-routes.ts +229 -0
- package/src/runtime/routes/browser-extension-pair-routes.ts +497 -0
- package/src/runtime/routes/conversation-analysis-routes.ts +2 -1
- package/src/runtime/routes/conversation-management-routes.ts +108 -0
- package/src/runtime/routes/conversation-routes.ts +301 -27
- package/src/runtime/routes/conversation-starter-routes.ts +78 -16
- package/src/runtime/routes/guardian-action-routes.ts +24 -13
- package/src/runtime/routes/host-browser-routes.ts +279 -0
- package/src/runtime/routes/host-file-routes.ts +9 -1
- package/src/runtime/routes/identity-routes.ts +259 -16
- package/src/runtime/routes/log-export-routes.ts +42 -22
- package/src/runtime/routes/memory-item-routes.ts +1 -7
- package/src/runtime/routes/migration-routes.ts +87 -2
- package/src/runtime/routes/oauth-apps.ts +15 -17
- package/src/runtime/routes/oauth-providers.ts +4 -0
- package/src/runtime/routes/schedule-routes.ts +24 -11
- package/src/runtime/routes/settings-routes.ts +9 -97
- package/src/runtime/routes/skills-routes.ts +52 -2
- package/src/runtime/routes/subagents-routes.ts +14 -10
- package/src/runtime/routes/usage-routes.ts +8 -7
- package/src/runtime/routes/workspace-routes.test.ts +22 -0
- package/src/runtime/routes/workspace-routes.ts +8 -1
- package/src/runtime/routes/workspace-utils.ts +2 -0
- package/src/schedule/scheduler.ts +7 -5
- package/src/security/ces-credential-client.ts +20 -0
- package/src/security/ces-rpc-credential-backend.ts +17 -0
- package/src/security/credential-backend.ts +5 -0
- package/src/security/oauth2.ts +42 -25
- package/src/security/secure-keys.ts +118 -25
- package/src/security/token-manager.ts +23 -10
- package/src/skills/catalog-files.ts +492 -0
- package/src/subagent/manager.ts +131 -26
- package/src/subagent/types.ts +19 -0
- package/src/tools/apps/executors.ts +11 -2
- package/src/tools/browser/__tests__/auth-detector.test.ts +202 -108
- package/src/tools/browser/auth-detector.ts +43 -12
- package/src/tools/browser/browser-execution.ts +645 -340
- package/src/tools/browser/browser-manager.ts +36 -12
- package/src/tools/browser/cdp-client/__tests__/accessibility-snapshot.test.ts +318 -0
- package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +1175 -0
- package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +870 -0
- package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +330 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +377 -0
- package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-nested-frames.json +64 -0
- package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-simple.json +69 -0
- package/src/tools/browser/cdp-client/__tests__/local-cdp-client.test.ts +310 -0
- package/src/tools/browser/cdp-client/__tests__/types.test.ts +96 -0
- package/src/tools/browser/cdp-client/accessibility-snapshot.ts +387 -0
- package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +695 -0
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +743 -0
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +580 -0
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +578 -0
- package/src/tools/browser/cdp-client/cdp-inspect/ws-transport.ts +579 -0
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +635 -0
- package/src/tools/browser/cdp-client/errors.ts +34 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +125 -0
- package/src/tools/browser/cdp-client/factory.ts +204 -0
- package/src/tools/browser/cdp-client/index.ts +14 -0
- package/src/tools/browser/cdp-client/local-cdp-client.ts +187 -0
- package/src/tools/browser/cdp-client/types.ts +52 -0
- package/src/tools/filesystem/edit.ts +1 -1
- package/src/tools/filesystem/list.ts +1 -1
- package/src/tools/filesystem/read.ts +1 -1
- package/src/tools/filesystem/write.ts +2 -1
- package/src/tools/host-filesystem/edit.ts +1 -1
- package/src/tools/host-filesystem/read.ts +12 -15
- package/src/tools/host-filesystem/write.ts +1 -1
- package/src/tools/host-terminal/host-shell.ts +21 -16
- package/src/tools/permission-checker.ts +77 -82
- package/src/tools/registry.ts +0 -2
- package/src/tools/secret-detection-handler.ts +34 -0
- package/src/tools/shared/filesystem/image-read.ts +61 -40
- package/src/tools/subagent/spawn.ts +47 -3
- package/src/tools/subagent/status.ts +2 -0
- package/src/tools/system/register.ts +2 -16
- package/src/tools/terminal/safe-env.ts +7 -0
- package/src/tools/terminal/shell.ts +21 -16
- package/src/tools/tool-approval-handler.ts +48 -2
- package/src/tools/types.ts +2 -0
- package/src/util/platform.ts +14 -19
- package/src/workspace/top-level-renderer.ts +19 -1
- package/src/__tests__/chrome-cdp.test.ts +0 -419
- package/src/__tests__/permission-mode-sse.test.ts +0 -418
- package/src/__tests__/permission-mode-store.test.ts +0 -277
- package/src/browser-extension-relay/protocol.ts +0 -63
- package/src/browser-extension-relay/server.ts +0 -203
- package/src/config/schemas/sandbox.ts +0 -14
- package/src/permissions/permission-mode-store.ts +0 -180
- package/src/tools/browser/chrome-cdp.ts +0 -239
- package/src/tools/system/set-permission-mode.ts +0 -103
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the PR10 client-message envelopes:
|
|
3
|
+
* - `host_browser_event`
|
|
4
|
+
* - `host_browser_session_invalidated`
|
|
5
|
+
*
|
|
6
|
+
* The resolvers exported from `host-browser-routes.ts` are the single
|
|
7
|
+
* entry point for both the WS and any future HTTP transport. These
|
|
8
|
+
* tests drive them directly (bypassing the WS upgrade + frame parse
|
|
9
|
+
* machinery) so we can assert:
|
|
10
|
+
*
|
|
11
|
+
* 1. A well-formed `host_browser_event` frame fans out to the
|
|
12
|
+
* browser-session event bus — a listener subscribed via
|
|
13
|
+
* `onCdpEvent` observes the forwarded event with method + params
|
|
14
|
+
* + sessionId preserved.
|
|
15
|
+
*
|
|
16
|
+
* 2. A well-formed `host_browser_session_invalidated` frame marks
|
|
17
|
+
* the target as invalidated in the runtime-side registry. The
|
|
18
|
+
* next `BrowserSessionManager.send()` against a session with
|
|
19
|
+
* that targetId evicts the session and throws, forcing the
|
|
20
|
+
* owning tool to create a fresh one (which, on the extension
|
|
21
|
+
* side, triggers a reattach).
|
|
22
|
+
*
|
|
23
|
+
* 3. Malformed frames return a well-typed `BAD_REQUEST` resolution
|
|
24
|
+
* so the WS dispatcher in `http-server.ts` can log them without
|
|
25
|
+
* tearing down the socket.
|
|
26
|
+
*
|
|
27
|
+
* The invalidated-target set is consumed on first lookup (see
|
|
28
|
+
* `consumeInvalidatedTargetId`), so every test that touches it calls
|
|
29
|
+
* `__resetBrowserSessionEventsForTests()` in `beforeEach` to start
|
|
30
|
+
* from a clean slate.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
import { beforeEach, describe, expect, test } from "bun:test";
|
|
34
|
+
|
|
35
|
+
import {
|
|
36
|
+
__resetBrowserSessionEventsForTests,
|
|
37
|
+
type BrowserBackend,
|
|
38
|
+
BrowserSessionManager,
|
|
39
|
+
consumeInvalidatedTargetId,
|
|
40
|
+
createExtensionBackend,
|
|
41
|
+
type ForwardedCdpEvent,
|
|
42
|
+
isTargetInvalidated,
|
|
43
|
+
onCdpEvent,
|
|
44
|
+
} from "../browser-session/index.js";
|
|
45
|
+
import {
|
|
46
|
+
resolveHostBrowserEvent,
|
|
47
|
+
resolveHostBrowserSessionInvalidated,
|
|
48
|
+
} from "../runtime/routes/host-browser-routes.js";
|
|
49
|
+
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
// Shared fixtures
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
|
|
54
|
+
function makeBackend(): BrowserBackend {
|
|
55
|
+
return createExtensionBackend({
|
|
56
|
+
isAvailable: () => true,
|
|
57
|
+
sendCdp: async () => ({ result: { ok: true } }),
|
|
58
|
+
dispose: () => {},
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
describe("resolveHostBrowserEvent", () => {
|
|
63
|
+
beforeEach(() => {
|
|
64
|
+
__resetBrowserSessionEventsForTests();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test("publishes well-formed frames to subscribers", () => {
|
|
68
|
+
const observed: ForwardedCdpEvent[] = [];
|
|
69
|
+
const unsubscribe = onCdpEvent((event) => observed.push(event));
|
|
70
|
+
|
|
71
|
+
const resolution = resolveHostBrowserEvent({
|
|
72
|
+
method: "Page.frameNavigated",
|
|
73
|
+
params: { frame: { id: "frame-1", url: "https://example.com" } },
|
|
74
|
+
cdpSessionId: "target-abc",
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
expect(resolution.ok).toBe(true);
|
|
78
|
+
expect(observed).toHaveLength(1);
|
|
79
|
+
expect(observed[0].method).toBe("Page.frameNavigated");
|
|
80
|
+
expect(observed[0].params).toEqual({
|
|
81
|
+
frame: { id: "frame-1", url: "https://example.com" },
|
|
82
|
+
});
|
|
83
|
+
expect(observed[0].cdpSessionId).toBe("target-abc");
|
|
84
|
+
|
|
85
|
+
unsubscribe();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test("tolerates missing params — publishes with params undefined", () => {
|
|
89
|
+
const observed: ForwardedCdpEvent[] = [];
|
|
90
|
+
const unsubscribe = onCdpEvent((event) => observed.push(event));
|
|
91
|
+
|
|
92
|
+
const resolution = resolveHostBrowserEvent({
|
|
93
|
+
method: "Target.targetDestroyed",
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
expect(resolution.ok).toBe(true);
|
|
97
|
+
expect(observed).toHaveLength(1);
|
|
98
|
+
expect(observed[0].method).toBe("Target.targetDestroyed");
|
|
99
|
+
expect(observed[0].params).toBeUndefined();
|
|
100
|
+
expect(observed[0].cdpSessionId).toBeUndefined();
|
|
101
|
+
|
|
102
|
+
unsubscribe();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("treats empty-string cdpSessionId as absent", () => {
|
|
106
|
+
const observed: ForwardedCdpEvent[] = [];
|
|
107
|
+
const unsubscribe = onCdpEvent((event) => observed.push(event));
|
|
108
|
+
|
|
109
|
+
resolveHostBrowserEvent({
|
|
110
|
+
method: "Runtime.consoleAPICalled",
|
|
111
|
+
cdpSessionId: "",
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
expect(observed[0].cdpSessionId).toBeUndefined();
|
|
115
|
+
unsubscribe();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test("rejects frames missing a method", () => {
|
|
119
|
+
const observed: ForwardedCdpEvent[] = [];
|
|
120
|
+
const unsubscribe = onCdpEvent((event) => observed.push(event));
|
|
121
|
+
|
|
122
|
+
const resolution = resolveHostBrowserEvent({});
|
|
123
|
+
|
|
124
|
+
expect(resolution.ok).toBe(false);
|
|
125
|
+
expect(observed).toHaveLength(0);
|
|
126
|
+
|
|
127
|
+
unsubscribe();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("rejects frames with a non-string method", () => {
|
|
131
|
+
const resolution = resolveHostBrowserEvent({ method: 42 });
|
|
132
|
+
expect(resolution.ok).toBe(false);
|
|
133
|
+
if (!resolution.ok) {
|
|
134
|
+
expect(resolution.code).toBe("BAD_REQUEST");
|
|
135
|
+
expect(resolution.status).toBe(400);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test("multiple subscribers all receive the event", () => {
|
|
140
|
+
const a: ForwardedCdpEvent[] = [];
|
|
141
|
+
const b: ForwardedCdpEvent[] = [];
|
|
142
|
+
const unsubA = onCdpEvent((event) => a.push(event));
|
|
143
|
+
const unsubB = onCdpEvent((event) => b.push(event));
|
|
144
|
+
|
|
145
|
+
resolveHostBrowserEvent({
|
|
146
|
+
method: "Network.responseReceived",
|
|
147
|
+
params: { requestId: "r1" },
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
expect(a).toHaveLength(1);
|
|
151
|
+
expect(b).toHaveLength(1);
|
|
152
|
+
expect(a[0].method).toBe("Network.responseReceived");
|
|
153
|
+
expect(b[0].method).toBe("Network.responseReceived");
|
|
154
|
+
|
|
155
|
+
unsubA();
|
|
156
|
+
unsubB();
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
test("unsubscribe stops delivery", () => {
|
|
160
|
+
const observed: ForwardedCdpEvent[] = [];
|
|
161
|
+
const unsubscribe = onCdpEvent((event) => observed.push(event));
|
|
162
|
+
|
|
163
|
+
resolveHostBrowserEvent({ method: "Page.loadEventFired" });
|
|
164
|
+
expect(observed).toHaveLength(1);
|
|
165
|
+
|
|
166
|
+
unsubscribe();
|
|
167
|
+
resolveHostBrowserEvent({ method: "Page.loadEventFired" });
|
|
168
|
+
expect(observed).toHaveLength(1);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
test("a throwing listener does not block subsequent listeners", () => {
|
|
172
|
+
const observed: ForwardedCdpEvent[] = [];
|
|
173
|
+
const unsubA = onCdpEvent(() => {
|
|
174
|
+
throw new Error("listener exploded");
|
|
175
|
+
});
|
|
176
|
+
const unsubB = onCdpEvent((event) => observed.push(event));
|
|
177
|
+
|
|
178
|
+
// Must not throw
|
|
179
|
+
const resolution = resolveHostBrowserEvent({
|
|
180
|
+
method: "Page.frameNavigated",
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
expect(resolution.ok).toBe(true);
|
|
184
|
+
expect(observed).toHaveLength(1);
|
|
185
|
+
|
|
186
|
+
unsubA();
|
|
187
|
+
unsubB();
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
describe("resolveHostBrowserSessionInvalidated", () => {
|
|
192
|
+
beforeEach(() => {
|
|
193
|
+
__resetBrowserSessionEventsForTests();
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
test("marks the target as invalidated in the registry", () => {
|
|
197
|
+
const resolution = resolveHostBrowserSessionInvalidated({
|
|
198
|
+
targetId: "tab-42",
|
|
199
|
+
reason: "target_closed",
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
expect(resolution.ok).toBe(true);
|
|
203
|
+
expect(isTargetInvalidated("tab-42")).toBe(true);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
test("tolerates frames with no targetId (advisory only)", () => {
|
|
207
|
+
const resolution = resolveHostBrowserSessionInvalidated({
|
|
208
|
+
reason: "canceled_by_user",
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
expect(resolution.ok).toBe(true);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
test("rejects frames whose targetId is not a string", () => {
|
|
215
|
+
const resolution = resolveHostBrowserSessionInvalidated({
|
|
216
|
+
targetId: 42 as unknown as string,
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
expect(resolution.ok).toBe(false);
|
|
220
|
+
if (!resolution.ok) {
|
|
221
|
+
expect(resolution.code).toBe("BAD_REQUEST");
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
test("BrowserSessionManager evicts a session whose targetId was invalidated and next send forces reattach", async () => {
|
|
226
|
+
// Track every CDP command the backend sees so we can assert that
|
|
227
|
+
// the first send (post-invalidation) never reached the backend
|
|
228
|
+
// while the second send (after reattach) did.
|
|
229
|
+
const sent: Array<{ method: string }> = [];
|
|
230
|
+
const backend = createExtensionBackend({
|
|
231
|
+
isAvailable: () => true,
|
|
232
|
+
sendCdp: async (command) => {
|
|
233
|
+
sent.push({ method: command.method });
|
|
234
|
+
return { result: { ok: true } };
|
|
235
|
+
},
|
|
236
|
+
dispose: () => {},
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
const manager = new BrowserSessionManager({ backends: [backend] });
|
|
240
|
+
const session = manager.createSession();
|
|
241
|
+
// Tag the session with a targetId — this is how a real tool
|
|
242
|
+
// invocation would bind its runtime-side session to the
|
|
243
|
+
// extension's debuggee target.
|
|
244
|
+
session.targetId = "tab-42";
|
|
245
|
+
|
|
246
|
+
// Fire the invalidation envelope as if the extension just
|
|
247
|
+
// forwarded a detach over the relay WebSocket.
|
|
248
|
+
const resolution = resolveHostBrowserSessionInvalidated({
|
|
249
|
+
targetId: "tab-42",
|
|
250
|
+
reason: "target_closed",
|
|
251
|
+
});
|
|
252
|
+
expect(resolution.ok).toBe(true);
|
|
253
|
+
|
|
254
|
+
// The next send against the invalidated session MUST throw —
|
|
255
|
+
// the manager consumes the invalidation flag, evicts the
|
|
256
|
+
// session, and rejects the command so the caller can create a
|
|
257
|
+
// fresh session (which triggers a reattach on the extension
|
|
258
|
+
// side).
|
|
259
|
+
await expect(
|
|
260
|
+
manager.send(session.id, { method: "Page.navigate" }),
|
|
261
|
+
).rejects.toThrow(/invalidated/);
|
|
262
|
+
|
|
263
|
+
// Sanity: the backend never saw the doomed command.
|
|
264
|
+
expect(sent).toHaveLength(0);
|
|
265
|
+
|
|
266
|
+
// The evicted session is gone — sending again throws
|
|
267
|
+
// "Unknown browser session".
|
|
268
|
+
await expect(
|
|
269
|
+
manager.send(session.id, { method: "Page.navigate" }),
|
|
270
|
+
).rejects.toThrow(/Unknown browser session/);
|
|
271
|
+
|
|
272
|
+
// Creating a fresh session proves the reattach path works: the
|
|
273
|
+
// caller bounces through `createSession` and a subsequent send
|
|
274
|
+
// dispatches normally through the backend.
|
|
275
|
+
const fresh = manager.createSession();
|
|
276
|
+
const result = await manager.send(fresh.id, { method: "Page.navigate" });
|
|
277
|
+
expect(result.result).toEqual({ ok: true });
|
|
278
|
+
expect(sent).toEqual([{ method: "Page.navigate" }]);
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
test("invalidation is consumed on first lookup (set never grows unbounded)", async () => {
|
|
282
|
+
// Registering the invalidation once should affect only the next
|
|
283
|
+
// send against that target. A second send against a brand-new
|
|
284
|
+
// session with the same targetId must NOT be evicted — the entry
|
|
285
|
+
// was already consumed by the first eviction.
|
|
286
|
+
const sent: Array<{ method: string }> = [];
|
|
287
|
+
const backend = createExtensionBackend({
|
|
288
|
+
isAvailable: () => true,
|
|
289
|
+
sendCdp: async (command) => {
|
|
290
|
+
sent.push({ method: command.method });
|
|
291
|
+
return { result: { ok: true } };
|
|
292
|
+
},
|
|
293
|
+
dispose: () => {},
|
|
294
|
+
});
|
|
295
|
+
const manager = new BrowserSessionManager({ backends: [backend] });
|
|
296
|
+
|
|
297
|
+
resolveHostBrowserSessionInvalidated({ targetId: "tab-99" });
|
|
298
|
+
|
|
299
|
+
const first = manager.createSession();
|
|
300
|
+
first.targetId = "tab-99";
|
|
301
|
+
await expect(
|
|
302
|
+
manager.send(first.id, { method: "Page.navigate" }),
|
|
303
|
+
).rejects.toThrow(/invalidated/);
|
|
304
|
+
|
|
305
|
+
// Second session bound to the same targetId — should dispatch
|
|
306
|
+
// normally because the registry entry was consumed.
|
|
307
|
+
const second = manager.createSession();
|
|
308
|
+
second.targetId = "tab-99";
|
|
309
|
+
const result = await manager.send(second.id, {
|
|
310
|
+
method: "Page.navigate",
|
|
311
|
+
});
|
|
312
|
+
expect(result.result).toEqual({ ok: true });
|
|
313
|
+
expect(sent).toHaveLength(1);
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
test("consumeInvalidatedTargetId drains the entry", () => {
|
|
317
|
+
resolveHostBrowserSessionInvalidated({ targetId: "tab-1" });
|
|
318
|
+
expect(consumeInvalidatedTargetId("tab-1")).toBe(true);
|
|
319
|
+
// Second consume is a no-op — the entry was already drained.
|
|
320
|
+
expect(consumeInvalidatedTargetId("tab-1")).toBe(false);
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
test("invalidateSession on BrowserSessionManager evicts by id", () => {
|
|
324
|
+
const manager = new BrowserSessionManager({ backends: [makeBackend()] });
|
|
325
|
+
const session = manager.createSession();
|
|
326
|
+
expect(manager.getSession(session.id)).toBeDefined();
|
|
327
|
+
expect(manager.invalidateSession(session.id)).toBe(true);
|
|
328
|
+
expect(manager.getSession(session.id)).toBeUndefined();
|
|
329
|
+
// Second invalidate returns false — nothing to remove.
|
|
330
|
+
expect(manager.invalidateSession(session.id)).toBe(false);
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
test("invalidateByTargetId evicts every session matching the target", () => {
|
|
334
|
+
const manager = new BrowserSessionManager({ backends: [makeBackend()] });
|
|
335
|
+
const a = manager.createSession();
|
|
336
|
+
a.targetId = "tab-7";
|
|
337
|
+
const b = manager.createSession();
|
|
338
|
+
b.targetId = "tab-7";
|
|
339
|
+
const c = manager.createSession();
|
|
340
|
+
c.targetId = "tab-8";
|
|
341
|
+
|
|
342
|
+
expect(manager.invalidateByTargetId("tab-7")).toBe(2);
|
|
343
|
+
expect(manager.getSession(a.id)).toBeUndefined();
|
|
344
|
+
expect(manager.getSession(b.id)).toBeUndefined();
|
|
345
|
+
expect(manager.getSession(c.id)).toBeDefined();
|
|
346
|
+
|
|
347
|
+
// Second invalidate returns 0 — both matching sessions are gone.
|
|
348
|
+
expect(manager.invalidateByTargetId("tab-7")).toBe(0);
|
|
349
|
+
});
|
|
350
|
+
});
|