@vellumai/assistant 0.6.1 → 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/docker-entrypoint.sh +12 -2
- package/docs/architecture/memory.md +1 -1
- package/node_modules/@vellumai/ces-contracts/src/handles.ts +7 -9
- 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__/assistant-event-hub.test.ts +30 -0
- 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__/checker.test.ts +104 -170
- package/src/__tests__/cli-command-risk-guard.test.ts +1 -1
- 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 +21 -6
- 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 +169 -0
- package/src/__tests__/conversation-attachments.test.ts +80 -4
- package/src/__tests__/conversation-confirmation-signals.test.ts +155 -0
- package/src/__tests__/conversation-directories-parse.test.ts +105 -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 -3
- 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__/init-feature-flag-overrides.test.ts +167 -0
- package/src/__tests__/inline-command-runner.test.ts +7 -5
- package/src/__tests__/integration-status.test.ts +6 -7
- package/src/__tests__/list-messages-tool-merge.test.ts +37 -12
- package/src/__tests__/log-export-workspace.test.ts +190 -0
- package/src/__tests__/managed-credential-catalog-cli.test.ts +12 -14
- 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__/navigate-settings-tab.test.ts +14 -1
- package/src/__tests__/notification-broadcaster.test.ts +65 -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 +74 -55
- 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__/pkb-autoinject.test.ts +96 -0
- 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 -3
- package/src/__tests__/sandbox-diagnostics.test.ts +1 -32
- 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-sandbox.test.ts +1 -1
- package/src/__tests__/terminal-tools.test.ts +11 -5
- package/src/__tests__/test-preload.ts +14 -0
- package/src/__tests__/tool-approval-handler.test.ts +73 -0
- package/src/__tests__/tool-domain-event-publisher.test.ts +0 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -8
- package/src/__tests__/tool-executor.test.ts +0 -1
- 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 +62 -0
- package/src/__tests__/trust-store.test.ts +4 -4
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +109 -0
- package/src/__tests__/v2-consent-policy.test.ts +103 -0
- package/src/__tests__/workspace-migration-030-seed-pkb-autoinject.test.ts +168 -0
- package/src/__tests__/workspace-policy.test.ts +2 -7
- package/src/acp/client-handler.ts +30 -4
- package/src/agent/loop.ts +12 -35
- 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 +55 -0
- package/src/cli/__tests__/run-assistant-command.ts +34 -7
- package/src/cli/__tests__/unknown-command.test.ts +33 -0
- package/src/cli/commands/browser-relay.ts +339 -409
- package/src/cli/commands/credentials.ts +3 -3
- package/src/cli/commands/default-action.ts +68 -1
- 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 +68 -41
- 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 +16 -2
- 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/__tests__/connect.test.ts +1 -1
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +1 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +1 -1
- 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 +10 -3
- package/src/config/assistant-feature-flags.ts +59 -55
- package/src/config/bundled-skills/app-builder/SKILL.md +33 -173
- 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 +12 -7
- package/src/config/bundled-skills/gmail/TOOLS.json +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +2 -1
- package/src/config/bundled-skills/outlook/SKILL.md +7 -0
- package/src/config/bundled-skills/settings/TOOLS.json +1 -1
- package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +8 -3
- 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 +46 -7
- 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 +16 -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 -16
- package/src/credential-execution/managed-catalog.ts +3 -7
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +186 -0
- package/src/daemon/app-source-watcher.ts +35 -0
- package/src/daemon/config-watcher.ts +6 -2
- package/src/daemon/context-overflow-approval.ts +5 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +17 -2
- package/src/daemon/conversation-agent-loop.ts +74 -19
- package/src/daemon/conversation-attachments.ts +40 -1
- package/src/daemon/conversation-messaging.ts +3 -0
- package/src/daemon/conversation-process.ts +66 -3
- package/src/daemon/conversation-queue-manager.ts +8 -0
- package/src/daemon/conversation-runtime-assembly.ts +159 -20
- package/src/daemon/conversation-surfaces.ts +78 -12
- package/src/daemon/conversation-tool-setup.ts +74 -11
- package/src/daemon/conversation-workspace.ts +12 -0
- package/src/daemon/conversation.ts +227 -11
- package/src/daemon/date-context.ts +10 -10
- package/src/daemon/first-greeting.ts +3 -2
- package/src/daemon/handlers/conversations.ts +9 -139
- package/src/daemon/handlers/shared.ts +65 -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 +86 -12
- package/src/daemon/message-protocol.ts +7 -0
- package/src/daemon/message-types/conversations.ts +59 -13
- package/src/daemon/message-types/host-browser.ts +100 -0
- package/src/daemon/message-types/messages.ts +5 -6
- package/src/daemon/message-types/notifications.ts +12 -0
- package/src/daemon/message-types/settings.ts +12 -0
- package/src/daemon/message-types/skills.ts +10 -0
- package/src/daemon/message-types/subagents.ts +2 -0
- package/src/daemon/server.ts +112 -35
- package/src/daemon/tool-side-effects.ts +6 -0
- package/src/daemon/transport-hints.ts +14 -0
- package/src/inbound/platform-callback-registration.ts +18 -17
- package/src/index.ts +1 -1
- package/src/mcp/client.ts +59 -24
- package/src/memory/app-store.ts +31 -1
- package/src/memory/conversation-crud.ts +38 -10
- package/src/memory/conversation-directories.ts +39 -0
- package/src/memory/conversation-group-migration.ts +65 -5
- package/src/memory/conversation-starters-cadence.ts +76 -0
- package/src/memory/conversation-title-service.ts +5 -2
- package/src/memory/db-init.ts +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 +177 -18
- package/src/memory/graph/capability-seed.ts +3 -5
- 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/group-crud.ts +25 -9
- 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/messaging/provider.ts +1 -1
- package/src/notifications/broadcaster.ts +6 -0
- package/src/notifications/conversation-pairing.ts +12 -4
- package/src/notifications/emit-signal.ts +14 -0
- package/src/notifications/signal.ts +11 -0
- 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 +5 -5
- 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 +127 -87
- package/src/oauth/token-persistence.ts +1 -1
- package/src/permissions/checker.ts +3 -3
- package/src/permissions/defaults.ts +7 -8
- package/src/permissions/permission-mode.ts +4 -11
- package/src/permissions/prompter.ts +13 -3
- package/src/permissions/v2-consent-policy.ts +87 -0
- package/src/platform/client.ts +1 -1
- package/src/prompts/system-prompt.ts +18 -21
- package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +3 -65
- package/src/prompts/templates/BOOTSTRAP.md +59 -96
- package/src/prompts/templates/SOUL.md +11 -11
- 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 +24 -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/auth/token-service.ts +8 -0
- 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 +18 -5
- package/src/runtime/routes/conversation-management-routes.ts +108 -0
- package/src/runtime/routes/conversation-routes.ts +308 -28
- package/src/runtime/routes/conversation-starter-routes.ts +78 -16
- package/src/runtime/routes/group-routes.ts +22 -8
- 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/AGENTS.md +104 -0
- package/src/runtime/routes/log-export/__tests__/workspace-allowlist-error-contract.test.ts +103 -0
- package/src/runtime/routes/log-export/__tests__/workspace-allowlist.test.ts +716 -0
- package/src/runtime/routes/log-export/workspace-allowlist.ts +458 -0
- package/src/runtime/routes/log-export-routes.ts +60 -25
- 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/skills/inline-command-runner.ts +12 -14
- 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 -100
- package/src/tools/registry.ts +0 -2
- package/src/tools/secret-detection-handler.ts +34 -1
- package/src/tools/shared/filesystem/image-read.ts +61 -40
- package/src/tools/skills/sandbox-runner.ts +3 -6
- 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/sandbox-diagnostics.ts +4 -4
- package/src/tools/terminal/sandbox.ts +4 -1
- package/src/tools/terminal/shell.ts +24 -21
- package/src/tools/tool-approval-handler.ts +48 -2
- package/src/tools/types.ts +2 -3
- package/src/util/platform.ts +14 -19
- package/src/watcher/provider-types.ts +1 -1
- package/src/workspace/migrations/029-seed-pkb.ts +1 -0
- package/src/workspace/migrations/030-seed-pkb-autoinject.ts +73 -0
- package/src/workspace/migrations/registry.ts +2 -0
- 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,159 @@
|
|
|
1
|
+
import { v4 as uuid } from "uuid";
|
|
2
|
+
|
|
3
|
+
import { consumeInvalidatedTargetId } from "./events.js";
|
|
4
|
+
import type {
|
|
5
|
+
BrowserBackend,
|
|
6
|
+
BrowserSession,
|
|
7
|
+
CdpCommand,
|
|
8
|
+
CdpResult,
|
|
9
|
+
} from "./types.js";
|
|
10
|
+
|
|
11
|
+
export interface BrowserSessionManagerOptions {
|
|
12
|
+
/** Ordered list of backends to try; first available wins. */
|
|
13
|
+
backends: BrowserBackend[];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class BrowserSessionManager {
|
|
17
|
+
private backends: BrowserBackend[];
|
|
18
|
+
private sessions = new Map<string, BrowserSession>();
|
|
19
|
+
|
|
20
|
+
constructor(opts: BrowserSessionManagerOptions) {
|
|
21
|
+
this.backends = opts.backends;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Pick an available backend or throw. */
|
|
25
|
+
selectBackend(): BrowserBackend {
|
|
26
|
+
const b = this.backends.find((x) => x.isAvailable());
|
|
27
|
+
if (!b) throw new Error("No available browser backend");
|
|
28
|
+
return b;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
createSession(): BrowserSession {
|
|
32
|
+
const backend = this.selectBackend();
|
|
33
|
+
const session: BrowserSession = { id: uuid(), backendKind: backend.kind };
|
|
34
|
+
this.sessions.set(session.id, session);
|
|
35
|
+
return session;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
getSession(id: string): BrowserSession | undefined {
|
|
39
|
+
return this.sessions.get(id);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Dispatch a CDP command.
|
|
44
|
+
*
|
|
45
|
+
* - If `sessionId` is provided, the session must exist in the manager; otherwise this throws.
|
|
46
|
+
* The command is routed through the backend whose `kind` matches the session's `backendKind`,
|
|
47
|
+
* ensuring per-session backend isolation and making `disposeSession()` an actual enforcement
|
|
48
|
+
* boundary against stale ids. If the session has an opaque `targetId` and the command does
|
|
49
|
+
* not already carry its own CDP `sessionId`, the manager injects the session's `targetId`
|
|
50
|
+
* as the CDP `sessionId` so backends can multiplex commands across multiple tabs/targets.
|
|
51
|
+
* - If `sessionId` is `undefined`, the first available backend is selected for one-off
|
|
52
|
+
* commands without a session handle (e.g. transport health probes).
|
|
53
|
+
*/
|
|
54
|
+
async send(
|
|
55
|
+
sessionId: string | undefined,
|
|
56
|
+
command: CdpCommand,
|
|
57
|
+
signal?: AbortSignal,
|
|
58
|
+
): Promise<CdpResult> {
|
|
59
|
+
let backend: BrowserBackend;
|
|
60
|
+
let outgoing = command;
|
|
61
|
+
if (sessionId !== undefined) {
|
|
62
|
+
const session = this.sessions.get(sessionId);
|
|
63
|
+
if (!session) {
|
|
64
|
+
throw new Error(`Unknown browser session: ${sessionId}`);
|
|
65
|
+
}
|
|
66
|
+
// If the chrome extension has reported this session's target
|
|
67
|
+
// as detached since the last dispatch, evict the session and
|
|
68
|
+
// throw so the caller can create a fresh one. Reading (and
|
|
69
|
+
// consuming) the invalidation flag here keeps the "next
|
|
70
|
+
// command forces reattach" semantics in lockstep with the
|
|
71
|
+
// host_browser_session_invalidated envelope handler — without
|
|
72
|
+
// this check the manager would happily forward a CDP command
|
|
73
|
+
// against a torn-down target and hit a permanent failure.
|
|
74
|
+
if (
|
|
75
|
+
session.targetId !== undefined &&
|
|
76
|
+
consumeInvalidatedTargetId(session.targetId)
|
|
77
|
+
) {
|
|
78
|
+
this.sessions.delete(sessionId);
|
|
79
|
+
throw new Error(
|
|
80
|
+
`Browser session ${sessionId} was invalidated (target ${session.targetId} detached)`,
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
const matched = this.backends.find((b) => b.kind === session.backendKind);
|
|
84
|
+
if (!matched) {
|
|
85
|
+
throw new Error(
|
|
86
|
+
`No backend available for session kind: ${session.backendKind}`,
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
backend = matched;
|
|
90
|
+
// If the session has an opaque targetId and the command does not
|
|
91
|
+
// carry its own CDP sessionId, inject the session's targetId as
|
|
92
|
+
// the CDP sessionId. Backends that support multi-target routing
|
|
93
|
+
// will forward it; backends that ignore it will treat the call
|
|
94
|
+
// as "most-recent-tab" as before.
|
|
95
|
+
if (session.targetId !== undefined && command.sessionId === undefined) {
|
|
96
|
+
outgoing = { ...command, sessionId: session.targetId };
|
|
97
|
+
}
|
|
98
|
+
} else {
|
|
99
|
+
backend = this.selectBackend();
|
|
100
|
+
}
|
|
101
|
+
return backend.send(outgoing, signal);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
disposeSession(id: string): void {
|
|
105
|
+
this.sessions.delete(id);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Evict a session that the backend has informed us is no longer
|
|
110
|
+
* valid — e.g. the chrome extension dispatched a
|
|
111
|
+
* `host_browser_session_invalidated` envelope after Chrome detached
|
|
112
|
+
* the debugger from the underlying tab/target.
|
|
113
|
+
*
|
|
114
|
+
* Functionally equivalent to {@link disposeSession} today (both
|
|
115
|
+
* remove the session from the manager's map so a subsequent
|
|
116
|
+
* `send()` throws "Unknown browser session") but preserved as a
|
|
117
|
+
* distinct method so call sites can stay explicit about intent.
|
|
118
|
+
* Callers that receive a detach/invalidated signal should use this
|
|
119
|
+
* method; callers that are cleaning up at end-of-lifecycle should
|
|
120
|
+
* use {@link disposeSession}.
|
|
121
|
+
*
|
|
122
|
+
* Returns `true` when a session was actually removed, `false` when
|
|
123
|
+
* no session with that id was tracked. Returning a boolean lets
|
|
124
|
+
* transport-level dispatchers (see
|
|
125
|
+
* `resolveHostBrowserSessionInvalidated`) log at the right level
|
|
126
|
+
* based on whether the invalidation had any effect.
|
|
127
|
+
*/
|
|
128
|
+
invalidateSession(id: string): boolean {
|
|
129
|
+
return this.sessions.delete(id);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Evict every session whose opaque `targetId` matches the supplied
|
|
134
|
+
* id. Used by the WS dispatcher when a `host_browser_session_invalidated`
|
|
135
|
+
* envelope arrives without a manager-level session id: the
|
|
136
|
+
* extension-side dispatcher only knows its own `tabId` / `targetId`
|
|
137
|
+
* and does not carry our uuid session handle.
|
|
138
|
+
*
|
|
139
|
+
* Returns the number of sessions removed. A zero return does not
|
|
140
|
+
* necessarily indicate an error — the target may not have a
|
|
141
|
+
* runtime-side session attached to it yet, or the session may
|
|
142
|
+
* already have been disposed by its owning tool.
|
|
143
|
+
*/
|
|
144
|
+
invalidateByTargetId(targetId: string): number {
|
|
145
|
+
let removed = 0;
|
|
146
|
+
for (const [id, session] of this.sessions) {
|
|
147
|
+
if (session.targetId === targetId) {
|
|
148
|
+
this.sessions.delete(id);
|
|
149
|
+
removed += 1;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return removed;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
disposeAll(): void {
|
|
156
|
+
for (const b of this.backends) b.dispose();
|
|
157
|
+
this.sessions.clear();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export type BrowserBackendKind = "extension" | "local" | "cdp-inspect";
|
|
2
|
+
|
|
3
|
+
export interface CdpCommand {
|
|
4
|
+
method: string;
|
|
5
|
+
params?: Record<string, unknown>;
|
|
6
|
+
sessionId?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface CdpResult {
|
|
10
|
+
/** Raw CDP result object; opaque to the manager. */
|
|
11
|
+
result?: unknown;
|
|
12
|
+
/** CDP error envelope if the command failed. */
|
|
13
|
+
error?: { code: number; message: string; data?: unknown };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface BrowserSession {
|
|
17
|
+
id: string;
|
|
18
|
+
backendKind: BrowserBackendKind;
|
|
19
|
+
/** Opaque target/sessionId from the backend. Omitted for "most-recent-tab" commands. */
|
|
20
|
+
targetId?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface BrowserBackend {
|
|
24
|
+
kind: BrowserBackendKind;
|
|
25
|
+
isAvailable(): boolean;
|
|
26
|
+
send(command: CdpCommand, signal?: AbortSignal): Promise<CdpResult>;
|
|
27
|
+
dispose(): void;
|
|
28
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
INTERACTIVE_INTERFACES,
|
|
5
|
+
INTERFACE_IDS,
|
|
6
|
+
isInterfaceId,
|
|
7
|
+
supportsHostProxy,
|
|
8
|
+
} from "../types.js";
|
|
9
|
+
|
|
10
|
+
describe("INTERFACE_IDS", () => {
|
|
11
|
+
test("includes chrome-extension", () => {
|
|
12
|
+
expect(
|
|
13
|
+
(INTERFACE_IDS as readonly string[]).includes("chrome-extension"),
|
|
14
|
+
).toBe(true);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test("still includes macos and other existing interfaces", () => {
|
|
18
|
+
for (const id of [
|
|
19
|
+
"macos",
|
|
20
|
+
"ios",
|
|
21
|
+
"cli",
|
|
22
|
+
"telegram",
|
|
23
|
+
"phone",
|
|
24
|
+
"vellum",
|
|
25
|
+
"whatsapp",
|
|
26
|
+
"slack",
|
|
27
|
+
"email",
|
|
28
|
+
]) {
|
|
29
|
+
expect((INTERFACE_IDS as readonly string[]).includes(id)).toBe(true);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe("INTERACTIVE_INTERFACES", () => {
|
|
35
|
+
test("does NOT include chrome-extension", () => {
|
|
36
|
+
// Chrome extensions don't render SSE-backed prompter UI, so they must
|
|
37
|
+
// stay out of the interactive set even though they have an InterfaceId.
|
|
38
|
+
expect(INTERACTIVE_INTERFACES.has("chrome-extension" as never)).toBe(false);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test("still includes macos", () => {
|
|
42
|
+
expect(INTERACTIVE_INTERFACES.has("macos")).toBe(true);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe("isInterfaceId", () => {
|
|
47
|
+
test("returns true for chrome-extension", () => {
|
|
48
|
+
expect(isInterfaceId("chrome-extension")).toBe(true);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("returns true for macos", () => {
|
|
52
|
+
expect(isInterfaceId("macos")).toBe(true);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("returns false for unknown interface", () => {
|
|
56
|
+
expect(isInterfaceId("safari-extension")).toBe(false);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
describe("supportsHostProxy", () => {
|
|
61
|
+
// ── macOS: supports host_bash / host_file / host_cu, but NOT host_browser. ──
|
|
62
|
+
test("macos returns true (no capability)", () => {
|
|
63
|
+
expect(supportsHostProxy("macos")).toBe(true);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test("macos returns true for host_bash", () => {
|
|
67
|
+
expect(supportsHostProxy("macos", "host_bash")).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test("macos returns true for host_file", () => {
|
|
71
|
+
expect(supportsHostProxy("macos", "host_file")).toBe(true);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("macos returns true for host_cu", () => {
|
|
75
|
+
expect(supportsHostProxy("macos", "host_cu")).toBe(true);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test("macos returns false for host_browser", () => {
|
|
79
|
+
expect(supportsHostProxy("macos", "host_browser")).toBe(false);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// ── chrome-extension: only host_browser. ──
|
|
83
|
+
test("chrome-extension returns false (no capability)", () => {
|
|
84
|
+
// Chrome extension does not support "any host proxy at all" — it only
|
|
85
|
+
// supports host_browser, so the no-arg form must return false to keep
|
|
86
|
+
// existing call sites that guard desktop-only behavior unchanged.
|
|
87
|
+
expect(supportsHostProxy("chrome-extension")).toBe(false);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("chrome-extension returns true for host_browser", () => {
|
|
91
|
+
expect(supportsHostProxy("chrome-extension", "host_browser")).toBe(true);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("chrome-extension returns false for host_bash", () => {
|
|
95
|
+
expect(supportsHostProxy("chrome-extension", "host_bash")).toBe(false);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test("chrome-extension returns false for host_file", () => {
|
|
99
|
+
expect(supportsHostProxy("chrome-extension", "host_file")).toBe(false);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test("chrome-extension returns false for host_cu", () => {
|
|
103
|
+
expect(supportsHostProxy("chrome-extension", "host_cu")).toBe(false);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// ── Non-supporting interfaces: false in all forms. ──
|
|
107
|
+
test("cli returns false (no capability)", () => {
|
|
108
|
+
expect(supportsHostProxy("cli")).toBe(false);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test("cli returns false for host_bash", () => {
|
|
112
|
+
expect(supportsHostProxy("cli", "host_bash")).toBe(false);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test("cli returns false for host_browser", () => {
|
|
116
|
+
expect(supportsHostProxy("cli", "host_browser")).toBe(false);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test("telegram returns false (no capability)", () => {
|
|
120
|
+
expect(supportsHostProxy("telegram")).toBe(false);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test("telegram returns false for host_browser", () => {
|
|
124
|
+
expect(supportsHostProxy("telegram", "host_browser")).toBe(false);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test("vellum returns false (no capability)", () => {
|
|
128
|
+
expect(supportsHostProxy("vellum")).toBe(false);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test("email returns false for host_browser", () => {
|
|
132
|
+
expect(supportsHostProxy("email", "host_browser")).toBe(false);
|
|
133
|
+
});
|
|
134
|
+
});
|
package/src/channels/types.ts
CHANGED
|
@@ -48,6 +48,7 @@ export const INTERFACE_IDS = [
|
|
|
48
48
|
"whatsapp",
|
|
49
49
|
"slack",
|
|
50
50
|
"email",
|
|
51
|
+
"chrome-extension",
|
|
51
52
|
] as const;
|
|
52
53
|
|
|
53
54
|
export type InterfaceId = (typeof INTERFACE_IDS)[number];
|
|
@@ -90,6 +91,60 @@ export function isInteractiveInterface(id: InterfaceId): boolean {
|
|
|
90
91
|
return INTERACTIVE_INTERFACES.has(id);
|
|
91
92
|
}
|
|
92
93
|
|
|
94
|
+
/**
|
|
95
|
+
* Host proxy capabilities that an interface can support. The macOS client
|
|
96
|
+
* supports all four; the chrome-extension interface only supports
|
|
97
|
+
* host_browser (via the Chrome DevTools Protocol proxy).
|
|
98
|
+
*/
|
|
99
|
+
export type HostProxyCapability =
|
|
100
|
+
| "host_bash"
|
|
101
|
+
| "host_file"
|
|
102
|
+
| "host_cu"
|
|
103
|
+
| "host_browser";
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Interfaces that support the full desktop host-proxy set (all four
|
|
107
|
+
* `HostProxyCapability` values). This is the capability-level identity used
|
|
108
|
+
* by the discriminated transport metadata union and by the
|
|
109
|
+
* `supportsHostProxy(id)` type predicate.
|
|
110
|
+
*
|
|
111
|
+
* Extend this literal type AND the `supportsHostProxy` implementation
|
|
112
|
+
* below in lock-step when adding a new host-capable client (e.g. a native
|
|
113
|
+
* Linux or Windows desktop).
|
|
114
|
+
*/
|
|
115
|
+
export type HostProxyInterfaceId = "macos";
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Whether the interface supports a host proxy capability.
|
|
119
|
+
*
|
|
120
|
+
* The no-arg form `supportsHostProxy(id)` asks "is this interface a desktop
|
|
121
|
+
* host-proxy client?" — it returns `true` only for macOS and is the type
|
|
122
|
+
* predicate that narrows `InterfaceId` to `HostProxyInterfaceId`. It returns
|
|
123
|
+
* `false` for chrome-extension because chrome-extension only supports
|
|
124
|
+
* `host_browser`, and the no-arg form is the gate that legacy desktop-only
|
|
125
|
+
* call sites use (e.g. preactivating computer-use, restoring host proxies
|
|
126
|
+
* in the drain queue). Callers that want to check a single capability —
|
|
127
|
+
* for example, to decide whether to keep `hostBrowserProxy` available for
|
|
128
|
+
* chrome-extension — should pass the capability explicitly:
|
|
129
|
+
* `supportsHostProxy(id, "host_browser")`.
|
|
130
|
+
*/
|
|
131
|
+
export function supportsHostProxy(id: InterfaceId): id is HostProxyInterfaceId;
|
|
132
|
+
export function supportsHostProxy(
|
|
133
|
+
id: InterfaceId,
|
|
134
|
+
capability: HostProxyCapability,
|
|
135
|
+
): boolean;
|
|
136
|
+
export function supportsHostProxy(
|
|
137
|
+
id: InterfaceId,
|
|
138
|
+
capability?: HostProxyCapability,
|
|
139
|
+
): boolean {
|
|
140
|
+
// host_browser is excluded for macos because the proxy path requires a
|
|
141
|
+
// Chrome extension that isn't guaranteed to be attached; browser tools
|
|
142
|
+
// fall back to the local Playwright Chromium instead.
|
|
143
|
+
if (id === "macos") return capability !== "host_browser";
|
|
144
|
+
if (id === "chrome-extension" && capability === "host_browser") return true;
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
|
|
93
148
|
export interface TurnInterfaceContext {
|
|
94
149
|
userMessageInterface: InterfaceId;
|
|
95
150
|
assistantMessageInterface: InterfaceId;
|
|
@@ -1,17 +1,32 @@
|
|
|
1
|
+
export interface AssistantCommandResult {
|
|
2
|
+
stdout: string;
|
|
3
|
+
stderr: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
1
6
|
/**
|
|
2
7
|
* CLI test utility — run an assistant CLI command via the real program,
|
|
3
|
-
* capturing stdout.
|
|
8
|
+
* capturing stdout and stderr.
|
|
9
|
+
*
|
|
10
|
+
* Returns both stdout and stderr. For backward compatibility, the function
|
|
11
|
+
* is also callable with just a string return (use `runAssistantCommand`).
|
|
4
12
|
*/
|
|
5
|
-
export async function
|
|
13
|
+
export async function runAssistantCommandFull(
|
|
14
|
+
...args: string[]
|
|
15
|
+
): Promise<AssistantCommandResult> {
|
|
6
16
|
const { buildCliProgram } = await import("../program.js");
|
|
7
|
-
const program = buildCliProgram();
|
|
17
|
+
const program = await buildCliProgram();
|
|
8
18
|
program.exitOverride();
|
|
9
|
-
program.configureOutput({ writeErr: () => {}, writeOut: () => {} });
|
|
10
19
|
|
|
11
|
-
const
|
|
20
|
+
const stderrChunks: string[] = [];
|
|
21
|
+
program.configureOutput({
|
|
22
|
+
writeErr: (str: string) => stderrChunks.push(str),
|
|
23
|
+
writeOut: () => {},
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const stdoutChunks: string[] = [];
|
|
12
27
|
const originalWrite = process.stdout.write;
|
|
13
28
|
process.stdout.write = ((chunk: string | Uint8Array) => {
|
|
14
|
-
|
|
29
|
+
stdoutChunks.push(
|
|
15
30
|
typeof chunk === "string" ? chunk : new TextDecoder().decode(chunk),
|
|
16
31
|
);
|
|
17
32
|
return true;
|
|
@@ -25,5 +40,17 @@ export async function runAssistantCommand(...args: string[]): Promise<string> {
|
|
|
25
40
|
process.stdout.write = originalWrite;
|
|
26
41
|
}
|
|
27
42
|
|
|
28
|
-
return
|
|
43
|
+
return {
|
|
44
|
+
stdout: stdoutChunks.join(""),
|
|
45
|
+
stderr: stderrChunks.join(""),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* CLI test utility — run an assistant CLI command via the real program,
|
|
51
|
+
* capturing stdout (backward-compatible wrapper).
|
|
52
|
+
*/
|
|
53
|
+
export async function runAssistantCommand(...args: string[]): Promise<string> {
|
|
54
|
+
const result = await runAssistantCommandFull(...args);
|
|
55
|
+
return result.stdout;
|
|
29
56
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import { runAssistantCommandFull } from "./run-assistant-command.js";
|
|
4
|
+
|
|
5
|
+
describe("unknown command handling", () => {
|
|
6
|
+
it("reports an error for an unknown subcommand", async () => {
|
|
7
|
+
const { stderr } = await runAssistantCommandFull("invalid");
|
|
8
|
+
|
|
9
|
+
expect(stderr).toContain("unknown command 'invalid'");
|
|
10
|
+
expect(stderr).toContain("Run 'assistant --help'");
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("reports an error for an unknown subcommand with extra arguments", async () => {
|
|
14
|
+
const { stderr } = await runAssistantCommandFull("invalid", "something");
|
|
15
|
+
|
|
16
|
+
expect(stderr).toContain("unknown command 'invalid'");
|
|
17
|
+
expect(stderr).toContain("Run 'assistant --help'");
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("suggests a similar command when the input is close", async () => {
|
|
21
|
+
const { stderr } = await runAssistantCommandFull("confg");
|
|
22
|
+
|
|
23
|
+
expect(stderr).toContain("unknown command 'confg'");
|
|
24
|
+
expect(stderr).toContain("Did you mean 'config'");
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("does not suggest a command when the input is too far off", async () => {
|
|
28
|
+
const { stderr } = await runAssistantCommandFull("xyzzy");
|
|
29
|
+
|
|
30
|
+
expect(stderr).toContain("unknown command 'xyzzy'");
|
|
31
|
+
expect(stderr).not.toContain("Did you mean");
|
|
32
|
+
});
|
|
33
|
+
});
|