@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
|
@@ -1,84 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `assistant browser chrome relay <action>` CLI shim.
|
|
3
|
+
*
|
|
4
|
+
* Translates the legacy relay actions (find_tab, new_tab, navigate,
|
|
5
|
+
* evaluate, get_cookies, set_cookie, screenshot) into Chrome DevTools
|
|
6
|
+
* Protocol commands and forwards them to the daemon's
|
|
7
|
+
* `/v1/browser-cdp` HTTP endpoint, which routes the command through
|
|
8
|
+
* the connected chrome-extension WebSocket.
|
|
9
|
+
*
|
|
10
|
+
* Why this exists: PR #24329 deleted the in-process extension relay
|
|
11
|
+
* server and the original CLI surface. Two in-tree skills (amazon and
|
|
12
|
+
* influencer) still spawn `assistant browser chrome relay <action>` as
|
|
13
|
+
* a subprocess and parse the JSON output. Until those skills migrate
|
|
14
|
+
* onto the new CDP-based skill API, this shim keeps them working by
|
|
15
|
+
* preserving the legacy stdout contract:
|
|
16
|
+
*
|
|
17
|
+
* { "ok": true, "tabId"?: <id>, "result"?: <unknown> }
|
|
18
|
+
* { "ok": false, "error": <string> }
|
|
19
|
+
*
|
|
20
|
+
* The CLI mints a short-lived daemon delivery JWT (same audience and
|
|
21
|
+
* scope profile as the daemon's internal callbacks) and POSTs directly
|
|
22
|
+
* to the runtime's loopback HTTP port — no gateway involvement
|
|
23
|
+
* required.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
27
|
+
|
|
1
28
|
import type { Command } from "commander";
|
|
2
29
|
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
30
|
+
import { getRuntimeHttpPort } from "../../config/env.js";
|
|
31
|
+
import { CURRENT_POLICY_EPOCH } from "../../runtime/auth/policy.js";
|
|
32
|
+
import { mintToken } from "../../runtime/auth/token-service.js";
|
|
5
33
|
import {
|
|
6
34
|
initAuthSigningKey,
|
|
7
35
|
isSigningKeyInitialized,
|
|
8
36
|
loadOrCreateSigningKey,
|
|
9
37
|
} from "../../runtime/auth/token-service.js";
|
|
10
|
-
import {
|
|
11
|
-
gatewayGet,
|
|
12
|
-
gatewayPost,
|
|
13
|
-
} from "../../runtime/gateway-internal-client.js";
|
|
14
|
-
import {
|
|
15
|
-
ensureChromeWithCdp,
|
|
16
|
-
minimizeChromeWindow,
|
|
17
|
-
restoreChromeWindow,
|
|
18
|
-
} from "../../tools/browser/chrome-cdp.js";
|
|
38
|
+
import { getRuntimePortFilePath } from "../../util/platform.js";
|
|
19
39
|
|
|
20
40
|
// ---------------------------------------------------------------------------
|
|
21
|
-
//
|
|
41
|
+
// Daemon HTTP client
|
|
22
42
|
// ---------------------------------------------------------------------------
|
|
23
43
|
|
|
24
|
-
|
|
44
|
+
interface BrowserCdpResponse {
|
|
45
|
+
result?: unknown;
|
|
46
|
+
error?: { code: string; message: string };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Resolve the daemon's runtime HTTP port. Prefers the runtime-port
|
|
51
|
+
* file written by the daemon at startup so non-default ports
|
|
52
|
+
* (RUNTIME_HTTP_PORT) are picked up automatically without an env var
|
|
53
|
+
* roundtrip. Falls back to the env-var-derived default.
|
|
54
|
+
*/
|
|
55
|
+
function resolveRuntimePort(): number {
|
|
25
56
|
try {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
id?: string;
|
|
33
|
-
success: boolean;
|
|
34
|
-
result?: unknown;
|
|
35
|
-
error?: string;
|
|
36
|
-
tabId?: number;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
if (extensionRelayServer.getStatus().connected) {
|
|
40
|
-
data = await extensionRelayServer.sendCommand(
|
|
41
|
-
command as Omit<ExtensionCommand, "id">,
|
|
42
|
-
);
|
|
43
|
-
} else {
|
|
44
|
-
// In-process relay not connected — fall back to gateway HTTP
|
|
45
|
-
if (!isSigningKeyInitialized()) {
|
|
46
|
-
initAuthSigningKey(loadOrCreateSigningKey());
|
|
57
|
+
const portFile = getRuntimePortFilePath();
|
|
58
|
+
if (existsSync(portFile)) {
|
|
59
|
+
const raw = readFileSync(portFile, "utf-8").trim();
|
|
60
|
+
const parsed = Number(raw);
|
|
61
|
+
if (Number.isFinite(parsed) && parsed > 0 && parsed < 65536) {
|
|
62
|
+
return parsed;
|
|
47
63
|
}
|
|
48
|
-
({ data } = await gatewayPost<typeof data>(
|
|
49
|
-
"/v1/browser-relay/command",
|
|
50
|
-
command,
|
|
51
|
-
));
|
|
52
64
|
}
|
|
65
|
+
} catch {
|
|
66
|
+
// Fall through to env-var default
|
|
67
|
+
}
|
|
68
|
+
return getRuntimeHttpPort();
|
|
69
|
+
}
|
|
53
70
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
process.stdout.write(
|
|
64
|
-
JSON.stringify({
|
|
65
|
-
ok: false,
|
|
66
|
-
error: data.error ?? "Unknown relay error",
|
|
67
|
-
}) + "\n",
|
|
68
|
-
);
|
|
69
|
-
process.exitCode = 1;
|
|
70
|
-
}
|
|
71
|
-
} catch (err) {
|
|
72
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
73
|
-
process.stdout.write(JSON.stringify({ ok: false, error: message }) + "\n");
|
|
74
|
-
process.exitCode = 1;
|
|
71
|
+
/**
|
|
72
|
+
* Mint a short-lived JWT acceptable to the runtime auth middleware.
|
|
73
|
+
* Mirrors `mintDaemonDeliveryToken` (sub=svc:daemon:self,
|
|
74
|
+
* scope_profile=gateway_service_v1, aud=vellum-daemon) but is minted
|
|
75
|
+
* out-of-process by the CLI using the on-disk signing key.
|
|
76
|
+
*/
|
|
77
|
+
function mintCliToken(): string {
|
|
78
|
+
if (!isSigningKeyInitialized()) {
|
|
79
|
+
initAuthSigningKey(loadOrCreateSigningKey());
|
|
75
80
|
}
|
|
81
|
+
return mintToken({
|
|
82
|
+
aud: "vellum-daemon",
|
|
83
|
+
sub: "svc:daemon:self",
|
|
84
|
+
scope_profile: "gateway_service_v1",
|
|
85
|
+
policy_epoch: CURRENT_POLICY_EPOCH,
|
|
86
|
+
ttlSeconds: 60,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Send a single CDP command to the daemon's /v1/browser-cdp route and
|
|
92
|
+
* return the parsed response. Throws on transport-level errors; the
|
|
93
|
+
* caller wraps the throw into a `{ ok: false, error }` envelope.
|
|
94
|
+
*/
|
|
95
|
+
async function postBrowserCdp(payload: {
|
|
96
|
+
cdpMethod: string;
|
|
97
|
+
cdpParams?: Record<string, unknown>;
|
|
98
|
+
cdpSessionId?: string;
|
|
99
|
+
timeoutMs?: number;
|
|
100
|
+
}): Promise<BrowserCdpResponse> {
|
|
101
|
+
const port = resolveRuntimePort();
|
|
102
|
+
const token = mintCliToken();
|
|
103
|
+
const url = `http://127.0.0.1:${port}/v1/browser-cdp`;
|
|
104
|
+
|
|
105
|
+
const resp = await fetch(url, {
|
|
106
|
+
method: "POST",
|
|
107
|
+
headers: {
|
|
108
|
+
"Content-Type": "application/json",
|
|
109
|
+
Authorization: `Bearer ${token}`,
|
|
110
|
+
},
|
|
111
|
+
body: JSON.stringify(payload),
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
const bodyText = await resp.text();
|
|
115
|
+
let parsed: BrowserCdpResponse;
|
|
116
|
+
try {
|
|
117
|
+
parsed = JSON.parse(bodyText) as BrowserCdpResponse;
|
|
118
|
+
} catch {
|
|
119
|
+
throw new Error(
|
|
120
|
+
`Daemon returned non-JSON response (HTTP ${resp.status}): ${bodyText.slice(0, 200)}`,
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (!resp.ok) {
|
|
125
|
+
const message = parsed.error?.message ?? `HTTP ${resp.status}`;
|
|
126
|
+
throw new Error(message);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return parsed;
|
|
76
130
|
}
|
|
77
131
|
|
|
78
132
|
// ---------------------------------------------------------------------------
|
|
79
|
-
//
|
|
133
|
+
// Stdout helpers
|
|
80
134
|
// ---------------------------------------------------------------------------
|
|
81
135
|
|
|
136
|
+
interface RelayResultOk {
|
|
137
|
+
ok: true;
|
|
138
|
+
tabId?: number | string;
|
|
139
|
+
result?: unknown;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
interface RelayResultErr {
|
|
143
|
+
ok: false;
|
|
144
|
+
error: string;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function emitOk(payload: Omit<RelayResultOk, "ok">): void {
|
|
148
|
+
const out: RelayResultOk = { ok: true, ...payload };
|
|
149
|
+
process.stdout.write(JSON.stringify(out) + "\n");
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function emitError(message: string): void {
|
|
153
|
+
const out: RelayResultErr = { ok: false, error: message };
|
|
154
|
+
process.stdout.write(JSON.stringify(out) + "\n");
|
|
155
|
+
process.exitCode = 1;
|
|
156
|
+
}
|
|
157
|
+
|
|
82
158
|
async function readStdin(): Promise<string> {
|
|
83
159
|
const chunks: Buffer[] = [];
|
|
84
160
|
for await (const chunk of process.stdin) {
|
|
@@ -87,6 +163,176 @@ async function readStdin(): Promise<string> {
|
|
|
87
163
|
return Buffer.concat(chunks).toString("utf-8");
|
|
88
164
|
}
|
|
89
165
|
|
|
166
|
+
// ---------------------------------------------------------------------------
|
|
167
|
+
// URL glob matching for find-tab
|
|
168
|
+
// ---------------------------------------------------------------------------
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Convert a Chrome match-pattern style glob (e.g. `*://*.amazon.com/*`)
|
|
172
|
+
* into a regular expression. Matches the chrome.tabs.query semantics
|
|
173
|
+
* the legacy relay CLI exposed:
|
|
174
|
+
*
|
|
175
|
+
* - `*` is a wildcard that matches any sequence (including `/` in
|
|
176
|
+
* the path component, mirroring the legacy minimatch behaviour).
|
|
177
|
+
* - All other regex metacharacters are escaped.
|
|
178
|
+
*/
|
|
179
|
+
function globToRegex(glob: string): RegExp {
|
|
180
|
+
const escaped = glob.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
181
|
+
const pattern = "^" + escaped.replace(/\*/g, ".*") + "$";
|
|
182
|
+
return new RegExp(pattern);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// ---------------------------------------------------------------------------
|
|
186
|
+
// Action handlers — translate legacy actions into CDP commands
|
|
187
|
+
// ---------------------------------------------------------------------------
|
|
188
|
+
|
|
189
|
+
interface CdpTarget {
|
|
190
|
+
targetId: string;
|
|
191
|
+
type: string;
|
|
192
|
+
url: string;
|
|
193
|
+
title?: string;
|
|
194
|
+
attached?: boolean;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
interface CdpTargetsResult {
|
|
198
|
+
targetInfos: CdpTarget[];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async function actionFindTab(urlPattern: string): Promise<void> {
|
|
202
|
+
try {
|
|
203
|
+
const resp = await postBrowserCdp({ cdpMethod: "Target.getTargets" });
|
|
204
|
+
const targets =
|
|
205
|
+
(resp.result as CdpTargetsResult | undefined)?.targetInfos ?? [];
|
|
206
|
+
const re = globToRegex(urlPattern);
|
|
207
|
+
const match = targets.find((t) => t.type === "page" && re.test(t.url));
|
|
208
|
+
if (!match) {
|
|
209
|
+
emitError(`No tab matched URL pattern: ${urlPattern}`);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
emitOk({ tabId: match.targetId });
|
|
213
|
+
} catch (err) {
|
|
214
|
+
emitError(err instanceof Error ? err.message : String(err));
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
async function actionNewTab(url: string): Promise<void> {
|
|
219
|
+
try {
|
|
220
|
+
const resp = await postBrowserCdp({
|
|
221
|
+
cdpMethod: "Target.createTarget",
|
|
222
|
+
cdpParams: { url },
|
|
223
|
+
});
|
|
224
|
+
const targetId = (resp.result as { targetId?: string } | undefined)
|
|
225
|
+
?.targetId;
|
|
226
|
+
if (!targetId) {
|
|
227
|
+
emitError("Target.createTarget did not return a targetId");
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
emitOk({ tabId: targetId });
|
|
231
|
+
} catch (err) {
|
|
232
|
+
emitError(err instanceof Error ? err.message : String(err));
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async function actionNavigate(tabId: string, url: string): Promise<void> {
|
|
237
|
+
try {
|
|
238
|
+
await postBrowserCdp({
|
|
239
|
+
cdpMethod: "Page.navigate",
|
|
240
|
+
cdpParams: { url },
|
|
241
|
+
cdpSessionId: tabId,
|
|
242
|
+
});
|
|
243
|
+
emitOk({});
|
|
244
|
+
} catch (err) {
|
|
245
|
+
emitError(err instanceof Error ? err.message : String(err));
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
async function actionEvaluate(tabId: string, code: string): Promise<void> {
|
|
250
|
+
try {
|
|
251
|
+
const resp = await postBrowserCdp({
|
|
252
|
+
cdpMethod: "Runtime.evaluate",
|
|
253
|
+
cdpParams: {
|
|
254
|
+
expression: code,
|
|
255
|
+
returnByValue: true,
|
|
256
|
+
awaitPromise: true,
|
|
257
|
+
},
|
|
258
|
+
cdpSessionId: tabId,
|
|
259
|
+
});
|
|
260
|
+
// CDP Runtime.evaluate returns { result: { type, value }, exceptionDetails? }.
|
|
261
|
+
// Surface exceptions as relay errors so callers don't silently get undefined.
|
|
262
|
+
const result = resp.result as
|
|
263
|
+
| {
|
|
264
|
+
result?: { value?: unknown };
|
|
265
|
+
exceptionDetails?: {
|
|
266
|
+
text?: string;
|
|
267
|
+
exception?: { description?: string };
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
| undefined;
|
|
271
|
+
if (result?.exceptionDetails) {
|
|
272
|
+
const desc =
|
|
273
|
+
result.exceptionDetails.exception?.description ??
|
|
274
|
+
result.exceptionDetails.text ??
|
|
275
|
+
"Runtime exception during evaluate";
|
|
276
|
+
emitError(desc);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
emitOk({ result: result?.result?.value });
|
|
280
|
+
} catch (err) {
|
|
281
|
+
emitError(err instanceof Error ? err.message : String(err));
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
async function actionGetCookies(domain: string): Promise<void> {
|
|
286
|
+
try {
|
|
287
|
+
const resp = await postBrowserCdp({ cdpMethod: "Network.getCookies" });
|
|
288
|
+
const cookies =
|
|
289
|
+
(resp.result as { cookies?: Array<Record<string, unknown>> } | undefined)
|
|
290
|
+
?.cookies ?? [];
|
|
291
|
+
// Filter by domain (Chrome stores cookies with leading-dot or bare-host
|
|
292
|
+
// domains depending on the Set-Cookie source). Match either form so the
|
|
293
|
+
// legacy "amazon.com" / ".amazon.com" callers both succeed.
|
|
294
|
+
const trimmed = domain.startsWith(".") ? domain.slice(1) : domain;
|
|
295
|
+
const filtered = cookies.filter((c) => {
|
|
296
|
+
const d = String(c.domain ?? "");
|
|
297
|
+
const dTrim = d.startsWith(".") ? d.slice(1) : d;
|
|
298
|
+
return dTrim === trimmed || dTrim.endsWith("." + trimmed);
|
|
299
|
+
});
|
|
300
|
+
emitOk({ result: filtered });
|
|
301
|
+
} catch (err) {
|
|
302
|
+
emitError(err instanceof Error ? err.message : String(err));
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
async function actionSetCookie(cookie: Record<string, unknown>): Promise<void> {
|
|
307
|
+
try {
|
|
308
|
+
await postBrowserCdp({
|
|
309
|
+
cdpMethod: "Network.setCookie",
|
|
310
|
+
cdpParams: cookie,
|
|
311
|
+
});
|
|
312
|
+
emitOk({});
|
|
313
|
+
} catch (err) {
|
|
314
|
+
emitError(err instanceof Error ? err.message : String(err));
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
async function actionScreenshot(tabId?: string): Promise<void> {
|
|
319
|
+
try {
|
|
320
|
+
const resp = await postBrowserCdp({
|
|
321
|
+
cdpMethod: "Page.captureScreenshot",
|
|
322
|
+
cdpParams: { format: "png" },
|
|
323
|
+
...(tabId !== undefined ? { cdpSessionId: tabId } : {}),
|
|
324
|
+
});
|
|
325
|
+
const data = (resp.result as { data?: string } | undefined)?.data;
|
|
326
|
+
if (data === undefined) {
|
|
327
|
+
emitError("Page.captureScreenshot returned no data");
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
emitOk({ result: data });
|
|
331
|
+
} catch (err) {
|
|
332
|
+
emitError(err instanceof Error ? err.message : String(err));
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
90
336
|
// ---------------------------------------------------------------------------
|
|
91
337
|
// Command registration
|
|
92
338
|
// ---------------------------------------------------------------------------
|
|
@@ -95,65 +341,35 @@ export function registerBrowserRelayCommand(program: Command): void {
|
|
|
95
341
|
const browser = program
|
|
96
342
|
.command("browser")
|
|
97
343
|
.description(
|
|
98
|
-
"Browser automation
|
|
344
|
+
"Browser automation surface (`chrome relay <action>` CDP shim)",
|
|
99
345
|
);
|
|
100
346
|
|
|
101
347
|
browser.addHelpText(
|
|
102
348
|
"after",
|
|
103
349
|
`
|
|
104
|
-
|
|
105
|
-
|
|
350
|
+
Provides a thin CDP-over-HTTP shim used by in-tree skills that have not
|
|
351
|
+
yet migrated onto the new CDP-based skill API. Each command translates
|
|
352
|
+
the legacy action into a Chrome DevTools Protocol call and forwards it
|
|
353
|
+
to the daemon's /v1/browser-cdp route, which routes through the
|
|
354
|
+
connected chrome-extension WebSocket.
|
|
106
355
|
|
|
107
356
|
Examples:
|
|
108
|
-
$ assistant browser chrome relay find-tab --url "*://*.
|
|
109
|
-
$ assistant browser chrome relay
|
|
110
|
-
$ assistant browser chrome relay
|
|
111
|
-
$ assistant browser chrome relay
|
|
357
|
+
$ assistant browser chrome relay find-tab --url "*://*.amazon.com/*"
|
|
358
|
+
$ assistant browser chrome relay new-tab --url "https://example.com"
|
|
359
|
+
$ assistant browser chrome relay evaluate --tab-id <id> --code "document.title"
|
|
360
|
+
$ assistant browser chrome relay screenshot --tab-id <id>`,
|
|
112
361
|
);
|
|
113
362
|
|
|
114
363
|
const chrome = browser
|
|
115
364
|
.command("chrome")
|
|
116
|
-
.description("Chrome browser automation via the extension
|
|
117
|
-
|
|
118
|
-
chrome.addHelpText(
|
|
119
|
-
"after",
|
|
120
|
-
`
|
|
121
|
-
Manages a dedicated Chrome instance with Chrome DevTools Protocol (CDP)
|
|
122
|
-
enabled, separate from the user's regular Chrome profile. The CDP instance
|
|
123
|
-
uses a dedicated user data directory at ~/Library/Application Support/Google/Chrome-CDP
|
|
124
|
-
and defaults to port 9222. Commands are routed through a Chrome extension
|
|
125
|
-
relay that bridges the assistant to open Chrome tabs.
|
|
126
|
-
|
|
127
|
-
Examples:
|
|
128
|
-
$ assistant browser chrome launch
|
|
129
|
-
$ assistant browser chrome launch --start-url "https://example.com" --port 9333
|
|
130
|
-
$ assistant browser chrome minimize
|
|
131
|
-
$ assistant browser chrome restore
|
|
132
|
-
$ assistant browser chrome relay status
|
|
133
|
-
$ assistant browser chrome relay find-tab --url "*://*.github.com/*"`,
|
|
134
|
-
);
|
|
365
|
+
.description("Chrome browser automation via the chrome-extension proxy");
|
|
135
366
|
|
|
136
367
|
const relay = chrome
|
|
137
368
|
.command("relay")
|
|
138
369
|
.description(
|
|
139
|
-
"Send
|
|
370
|
+
"Send a single CDP command to a Chrome tab via the chrome extension",
|
|
140
371
|
);
|
|
141
372
|
|
|
142
|
-
relay.addHelpText(
|
|
143
|
-
"after",
|
|
144
|
-
`
|
|
145
|
-
Routes commands to Chrome tabs through the browser extension relay. The relay
|
|
146
|
-
connects the assistant to a Chrome extension that can inspect and control
|
|
147
|
-
browser tabs. Commands support URL glob patterns for tab discovery and
|
|
148
|
-
JavaScript evaluation with stdin piping for long scripts.
|
|
149
|
-
|
|
150
|
-
Examples:
|
|
151
|
-
$ assistant browser chrome relay find-tab --url "*://*.amazon.com/*"
|
|
152
|
-
$ assistant browser chrome relay new-tab --url "https://example.com"
|
|
153
|
-
$ assistant browser chrome relay evaluate --tab-id 42 --code "document.title"
|
|
154
|
-
$ echo "document.querySelectorAll('a').length" | assistant browser chrome relay evaluate --tab-id 42`,
|
|
155
|
-
);
|
|
156
|
-
|
|
157
373
|
// -- find-tab --
|
|
158
374
|
|
|
159
375
|
relay
|
|
@@ -163,21 +379,8 @@ Examples:
|
|
|
163
379
|
"--url <pattern>",
|
|
164
380
|
"URL glob pattern to match (e.g. *://*.instagram.com/*)",
|
|
165
381
|
)
|
|
166
|
-
.addHelpText(
|
|
167
|
-
"after",
|
|
168
|
-
`
|
|
169
|
-
Arguments:
|
|
170
|
-
--url <pattern> Glob pattern matched against open tab URLs. Supports
|
|
171
|
-
wildcards: *://*.instagram.com/* matches any Instagram page.
|
|
172
|
-
|
|
173
|
-
Returns the tab ID of the first matching tab, or an error if no match is found.
|
|
174
|
-
|
|
175
|
-
Examples:
|
|
176
|
-
$ assistant browser chrome relay find-tab --url "*://*.amazon.com/*"
|
|
177
|
-
$ assistant browser chrome relay find-tab --url "*://mail.google.com/*"`,
|
|
178
|
-
)
|
|
179
382
|
.action(async (opts: { url: string }) => {
|
|
180
|
-
await
|
|
383
|
+
await actionFindTab(opts.url);
|
|
181
384
|
});
|
|
182
385
|
|
|
183
386
|
// -- new-tab --
|
|
@@ -186,20 +389,8 @@ Examples:
|
|
|
186
389
|
.command("new-tab")
|
|
187
390
|
.description("Open a new tab with the given URL")
|
|
188
391
|
.requiredOption("--url <url>", "URL to open in a new tab")
|
|
189
|
-
.addHelpText(
|
|
190
|
-
"after",
|
|
191
|
-
`
|
|
192
|
-
Arguments:
|
|
193
|
-
--url <url> The full URL to open in a new Chrome tab.
|
|
194
|
-
|
|
195
|
-
Returns the tab ID of the newly created tab.
|
|
196
|
-
|
|
197
|
-
Examples:
|
|
198
|
-
$ assistant browser chrome relay new-tab --url "https://example.com"
|
|
199
|
-
$ assistant browser chrome relay new-tab --url "https://www.instagram.com/explore/"`,
|
|
200
|
-
)
|
|
201
392
|
.action(async (opts: { url: string }) => {
|
|
202
|
-
await
|
|
393
|
+
await actionNewTab(opts.url);
|
|
203
394
|
});
|
|
204
395
|
|
|
205
396
|
// -- navigate --
|
|
@@ -207,24 +398,10 @@ Examples:
|
|
|
207
398
|
relay
|
|
208
399
|
.command("navigate")
|
|
209
400
|
.description("Navigate an existing tab to a new URL")
|
|
210
|
-
.requiredOption("--tab-id <id>", "Target tab ID"
|
|
401
|
+
.requiredOption("--tab-id <id>", "Target tab ID")
|
|
211
402
|
.requiredOption("--url <url>", "URL to navigate to")
|
|
212
|
-
.
|
|
213
|
-
|
|
214
|
-
`
|
|
215
|
-
Arguments:
|
|
216
|
-
--tab-id <id> Numeric Chrome tab ID (from find-tab or new-tab output).
|
|
217
|
-
--url <url> The URL to navigate the tab to.
|
|
218
|
-
|
|
219
|
-
Examples:
|
|
220
|
-
$ assistant browser chrome relay navigate --tab-id 123 --url "https://example.com/page2"`,
|
|
221
|
-
)
|
|
222
|
-
.action(async (opts: { tabId: number; url: string }) => {
|
|
223
|
-
await relayCommand({
|
|
224
|
-
action: "navigate",
|
|
225
|
-
tabId: opts.tabId,
|
|
226
|
-
url: opts.url,
|
|
227
|
-
});
|
|
403
|
+
.action(async (opts: { tabId: string; url: string }) => {
|
|
404
|
+
await actionNavigate(opts.tabId, opts.url);
|
|
228
405
|
});
|
|
229
406
|
|
|
230
407
|
// -- evaluate --
|
|
@@ -232,45 +409,22 @@ Examples:
|
|
|
232
409
|
relay
|
|
233
410
|
.command("evaluate")
|
|
234
411
|
.description("Execute JavaScript in a Chrome tab")
|
|
235
|
-
.requiredOption("--tab-id <id>", "Target tab ID"
|
|
236
|
-
.option(
|
|
237
|
-
|
|
238
|
-
"
|
|
239
|
-
`
|
|
240
|
-
Arguments:
|
|
241
|
-
--tab-id <id> Numeric Chrome tab ID (from find-tab or new-tab output).
|
|
242
|
-
--code <script> JavaScript code to evaluate. If omitted, reads from stdin.
|
|
243
|
-
|
|
244
|
-
If --code is omitted, reads JavaScript from stdin. This is useful for long
|
|
245
|
-
scripts that would be unwieldy as a single CLI argument.
|
|
246
|
-
|
|
247
|
-
Examples:
|
|
248
|
-
$ assistant browser chrome relay evaluate --tab-id 123 --code "document.title"
|
|
249
|
-
$ echo "document.querySelectorAll('a').length" | assistant browser chrome relay evaluate --tab-id 123
|
|
250
|
-
$ cat scrape.js | assistant browser chrome relay evaluate --tab-id 123`,
|
|
412
|
+
.requiredOption("--tab-id <id>", "Target tab ID")
|
|
413
|
+
.option(
|
|
414
|
+
"--code <script>",
|
|
415
|
+
"JavaScript code to evaluate (or read from stdin)",
|
|
251
416
|
)
|
|
252
|
-
.action(async (opts: { tabId:
|
|
417
|
+
.action(async (opts: { tabId: string; code?: string }) => {
|
|
253
418
|
let code: string;
|
|
254
419
|
if (opts.code) {
|
|
255
420
|
code = opts.code;
|
|
256
421
|
} else if (process.stdin.isTTY) {
|
|
257
|
-
|
|
258
|
-
JSON.stringify({
|
|
259
|
-
ok: false,
|
|
260
|
-
error: "No code provided. Use --code or pipe JavaScript via stdin.",
|
|
261
|
-
}) + "\n",
|
|
262
|
-
);
|
|
263
|
-
process.exitCode = 1;
|
|
422
|
+
emitError("No code provided. Use --code or pipe JavaScript via stdin.");
|
|
264
423
|
return;
|
|
265
424
|
} else {
|
|
266
425
|
code = await readStdin();
|
|
267
426
|
}
|
|
268
|
-
|
|
269
|
-
await relayCommand({
|
|
270
|
-
action: "evaluate",
|
|
271
|
-
tabId: opts.tabId,
|
|
272
|
-
code,
|
|
273
|
-
});
|
|
427
|
+
await actionEvaluate(opts.tabId, code);
|
|
274
428
|
});
|
|
275
429
|
|
|
276
430
|
// -- get-cookies --
|
|
@@ -279,20 +433,8 @@ Examples:
|
|
|
279
433
|
.command("get-cookies")
|
|
280
434
|
.description("Fetch cookies for a domain")
|
|
281
435
|
.requiredOption("--domain <domain>", "Cookie domain to fetch")
|
|
282
|
-
.addHelpText(
|
|
283
|
-
"after",
|
|
284
|
-
`
|
|
285
|
-
Arguments:
|
|
286
|
-
--domain <domain> The cookie domain to query (e.g. ".instagram.com").
|
|
287
|
-
|
|
288
|
-
Returns all cookies matching the specified domain.
|
|
289
|
-
|
|
290
|
-
Examples:
|
|
291
|
-
$ assistant browser chrome relay get-cookies --domain ".instagram.com"
|
|
292
|
-
$ assistant browser chrome relay get-cookies --domain ".amazon.com"`,
|
|
293
|
-
)
|
|
294
436
|
.action(async (opts: { domain: string }) => {
|
|
295
|
-
await
|
|
437
|
+
await actionGetCookies(opts.domain);
|
|
296
438
|
});
|
|
297
439
|
|
|
298
440
|
// -- set-cookie --
|
|
@@ -301,236 +443,24 @@ Examples:
|
|
|
301
443
|
.command("set-cookie")
|
|
302
444
|
.description("Set a cookie in the browser")
|
|
303
445
|
.requiredOption("--cookie <json>", "Cookie specification as JSON")
|
|
304
|
-
.addHelpText(
|
|
305
|
-
"after",
|
|
306
|
-
`
|
|
307
|
-
Arguments:
|
|
308
|
-
--cookie <json> JSON object specifying the cookie to set. Must include
|
|
309
|
-
at minimum "name", "value", and "domain" fields.
|
|
310
|
-
|
|
311
|
-
Examples:
|
|
312
|
-
$ assistant browser chrome relay set-cookie --cookie '{"name":"session","value":"abc123","domain":".example.com"}'`,
|
|
313
|
-
)
|
|
314
446
|
.action(async (opts: { cookie: string }) => {
|
|
315
|
-
let parsed: unknown
|
|
447
|
+
let parsed: Record<string, unknown>;
|
|
316
448
|
try {
|
|
317
|
-
parsed = JSON.parse(opts.cookie)
|
|
449
|
+
parsed = JSON.parse(opts.cookie) as Record<string, unknown>;
|
|
318
450
|
} catch {
|
|
319
|
-
|
|
320
|
-
JSON.stringify({
|
|
321
|
-
ok: false,
|
|
322
|
-
error: "Invalid JSON in --cookie argument",
|
|
323
|
-
}) + "\n",
|
|
324
|
-
);
|
|
325
|
-
process.exitCode = 1;
|
|
451
|
+
emitError("Invalid JSON in --cookie argument");
|
|
326
452
|
return;
|
|
327
453
|
}
|
|
328
|
-
await
|
|
454
|
+
await actionSetCookie(parsed);
|
|
329
455
|
});
|
|
330
456
|
|
|
331
457
|
// -- screenshot --
|
|
332
458
|
|
|
333
459
|
relay
|
|
334
460
|
.command("screenshot")
|
|
335
|
-
.description("Capture a screenshot of a Chrome tab")
|
|
336
|
-
.option("--tab-id <id>", "Target tab ID
|
|
337
|
-
.
|
|
338
|
-
|
|
339
|
-
`
|
|
340
|
-
Arguments:
|
|
341
|
-
--tab-id <id> Optional numeric Chrome tab ID. If omitted, captures
|
|
342
|
-
the currently active tab.
|
|
343
|
-
|
|
344
|
-
Returns a base64-encoded screenshot image.
|
|
345
|
-
|
|
346
|
-
Examples:
|
|
347
|
-
$ assistant browser chrome relay screenshot --tab-id 123
|
|
348
|
-
$ assistant browser chrome relay screenshot`,
|
|
349
|
-
)
|
|
350
|
-
.action(async (opts: { tabId?: number }) => {
|
|
351
|
-
await relayCommand({
|
|
352
|
-
action: "screenshot",
|
|
353
|
-
...(opts.tabId !== undefined ? { tabId: opts.tabId } : {}),
|
|
354
|
-
});
|
|
355
|
-
});
|
|
356
|
-
|
|
357
|
-
// -- status --
|
|
358
|
-
|
|
359
|
-
relay
|
|
360
|
-
.command("status")
|
|
361
|
-
.description("Check browser extension relay connection status")
|
|
362
|
-
.addHelpText(
|
|
363
|
-
"after",
|
|
364
|
-
`
|
|
365
|
-
Reports whether the browser extension relay is connected, including the
|
|
366
|
-
connection ID, last heartbeat time, and number of pending commands.
|
|
367
|
-
|
|
368
|
-
Examples:
|
|
369
|
-
$ assistant browser chrome relay status`,
|
|
370
|
-
)
|
|
371
|
-
.action(async () => {
|
|
372
|
-
try {
|
|
373
|
-
// Dual-path: use in-process status when connected (daemon context),
|
|
374
|
-
// otherwise query gateway HTTP (out-of-process CLI context).
|
|
375
|
-
// getStatus() is a synchronous getter that never throws — we check
|
|
376
|
-
// .connected to decide whether the local status is meaningful.
|
|
377
|
-
let data: {
|
|
378
|
-
connected: boolean;
|
|
379
|
-
connectionId?: string | null;
|
|
380
|
-
lastHeartbeatAt?: number | null;
|
|
381
|
-
pendingCommandCount: number;
|
|
382
|
-
};
|
|
383
|
-
|
|
384
|
-
const localStatus = extensionRelayServer.getStatus();
|
|
385
|
-
if (localStatus.connected) {
|
|
386
|
-
data = localStatus;
|
|
387
|
-
} else {
|
|
388
|
-
// In-process relay not connected — fall back to gateway HTTP
|
|
389
|
-
if (!isSigningKeyInitialized()) {
|
|
390
|
-
initAuthSigningKey(loadOrCreateSigningKey());
|
|
391
|
-
}
|
|
392
|
-
data = await gatewayGet<typeof data>("/v1/browser-relay/status");
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
process.stdout.write(
|
|
396
|
-
JSON.stringify({
|
|
397
|
-
ok: true,
|
|
398
|
-
connected: data.connected,
|
|
399
|
-
connectionId: data.connectionId ?? null,
|
|
400
|
-
lastHeartbeatAt: data.lastHeartbeatAt
|
|
401
|
-
? new Date(data.lastHeartbeatAt).toISOString()
|
|
402
|
-
: null,
|
|
403
|
-
pendingCommandCount: data.pendingCommandCount,
|
|
404
|
-
}) + "\n",
|
|
405
|
-
);
|
|
406
|
-
} catch (err) {
|
|
407
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
408
|
-
process.stdout.write(
|
|
409
|
-
JSON.stringify({ ok: false, error: message }) + "\n",
|
|
410
|
-
);
|
|
411
|
-
process.exitCode = 1;
|
|
412
|
-
}
|
|
413
|
-
});
|
|
414
|
-
|
|
415
|
-
// ---------------------------------------------------------------------------
|
|
416
|
-
// chrome launch
|
|
417
|
-
// ---------------------------------------------------------------------------
|
|
418
|
-
|
|
419
|
-
chrome
|
|
420
|
-
.command("launch")
|
|
421
|
-
.description(
|
|
422
|
-
"Launch or connect to a Chrome instance with CDP (Chrome DevTools Protocol)",
|
|
423
|
-
)
|
|
424
|
-
.option("--start-url <url>", "Initial URL to open when launching Chrome")
|
|
425
|
-
.option("--port <port>", "CDP port (default: 9222)", parseInt)
|
|
426
|
-
.addHelpText(
|
|
427
|
-
"after",
|
|
428
|
-
`
|
|
429
|
-
Launches a Chrome instance with Chrome DevTools Protocol (CDP) enabled, or
|
|
430
|
-
returns the existing session if Chrome is already running with open tabs.
|
|
431
|
-
Idempotent — returns immediately if Chrome is already running with tabs.
|
|
432
|
-
Kills stale CDP instances (CDP endpoint up but no tabs) and relaunches.
|
|
433
|
-
Polls up to 15 seconds for the CDP endpoint to become ready.
|
|
434
|
-
|
|
435
|
-
Arguments:
|
|
436
|
-
--start-url <url> Initial URL to open in the new Chrome window. If
|
|
437
|
-
omitted, Chrome opens to its default start page.
|
|
438
|
-
--port <port> CDP port to use. Defaults to 9222.
|
|
439
|
-
|
|
440
|
-
Examples:
|
|
441
|
-
$ assistant browser chrome launch
|
|
442
|
-
$ assistant browser chrome launch --start-url "https://x.com/login" --port 9333`,
|
|
443
|
-
)
|
|
444
|
-
.action(async (opts: { startUrl?: string; port?: number }) => {
|
|
445
|
-
try {
|
|
446
|
-
const session = await ensureChromeWithCdp({
|
|
447
|
-
startUrl: opts.startUrl,
|
|
448
|
-
port: opts.port,
|
|
449
|
-
});
|
|
450
|
-
process.stdout.write(
|
|
451
|
-
JSON.stringify({
|
|
452
|
-
ok: true,
|
|
453
|
-
baseUrl: session.baseUrl,
|
|
454
|
-
launchedByUs: session.launchedByUs,
|
|
455
|
-
userDataDir: session.userDataDir,
|
|
456
|
-
}) + "\n",
|
|
457
|
-
);
|
|
458
|
-
} catch (err) {
|
|
459
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
460
|
-
process.stdout.write(
|
|
461
|
-
JSON.stringify({ ok: false, error: message }) + "\n",
|
|
462
|
-
);
|
|
463
|
-
process.exitCode = 1;
|
|
464
|
-
}
|
|
465
|
-
});
|
|
466
|
-
|
|
467
|
-
// ---------------------------------------------------------------------------
|
|
468
|
-
// chrome minimize
|
|
469
|
-
// ---------------------------------------------------------------------------
|
|
470
|
-
|
|
471
|
-
chrome
|
|
472
|
-
.command("minimize")
|
|
473
|
-
.description("Minimize the Chrome CDP window")
|
|
474
|
-
.option("--port <port>", "CDP port (default: 9222)", parseInt)
|
|
475
|
-
.addHelpText(
|
|
476
|
-
"after",
|
|
477
|
-
`
|
|
478
|
-
Minimizes the Chrome window associated with the CDP session. Uses the
|
|
479
|
-
Browser.setWindowBounds CDP method to set the window state to minimized.
|
|
480
|
-
|
|
481
|
-
Arguments:
|
|
482
|
-
--port <port> CDP port to connect to. Defaults to 9222.
|
|
483
|
-
|
|
484
|
-
Examples:
|
|
485
|
-
$ assistant browser chrome minimize
|
|
486
|
-
$ assistant browser chrome minimize --port 9333`,
|
|
487
|
-
)
|
|
488
|
-
.action(async (opts: { port?: number }) => {
|
|
489
|
-
try {
|
|
490
|
-
const cdpBase = opts.port ? `http://localhost:${opts.port}` : undefined;
|
|
491
|
-
await minimizeChromeWindow(cdpBase);
|
|
492
|
-
process.stdout.write(JSON.stringify({ ok: true }) + "\n");
|
|
493
|
-
} catch (err) {
|
|
494
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
495
|
-
process.stdout.write(
|
|
496
|
-
JSON.stringify({ ok: false, error: message }) + "\n",
|
|
497
|
-
);
|
|
498
|
-
process.exitCode = 1;
|
|
499
|
-
}
|
|
500
|
-
});
|
|
501
|
-
|
|
502
|
-
// ---------------------------------------------------------------------------
|
|
503
|
-
// chrome restore
|
|
504
|
-
// ---------------------------------------------------------------------------
|
|
505
|
-
|
|
506
|
-
chrome
|
|
507
|
-
.command("restore")
|
|
508
|
-
.description("Restore the Chrome CDP window from minimized state")
|
|
509
|
-
.option("--port <port>", "CDP port (default: 9222)", parseInt)
|
|
510
|
-
.addHelpText(
|
|
511
|
-
"after",
|
|
512
|
-
`
|
|
513
|
-
Restores (un-minimizes) the Chrome window associated with the CDP session.
|
|
514
|
-
Uses the Browser.setWindowBounds CDP method to set the window state to normal.
|
|
515
|
-
|
|
516
|
-
Arguments:
|
|
517
|
-
--port <port> CDP port to connect to. Defaults to 9222.
|
|
518
|
-
|
|
519
|
-
Examples:
|
|
520
|
-
$ assistant browser chrome restore
|
|
521
|
-
$ assistant browser chrome restore --port 9333`,
|
|
522
|
-
)
|
|
523
|
-
.action(async (opts: { port?: number }) => {
|
|
524
|
-
try {
|
|
525
|
-
const cdpBase = opts.port ? `http://localhost:${opts.port}` : undefined;
|
|
526
|
-
await restoreChromeWindow(cdpBase);
|
|
527
|
-
process.stdout.write(JSON.stringify({ ok: true }) + "\n");
|
|
528
|
-
} catch (err) {
|
|
529
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
530
|
-
process.stdout.write(
|
|
531
|
-
JSON.stringify({ ok: false, error: message }) + "\n",
|
|
532
|
-
);
|
|
533
|
-
process.exitCode = 1;
|
|
534
|
-
}
|
|
461
|
+
.description("Capture a base64-encoded PNG screenshot of a Chrome tab")
|
|
462
|
+
.option("--tab-id <id>", "Target tab ID (defaults to active tab)")
|
|
463
|
+
.action(async (opts: { tabId?: string }) => {
|
|
464
|
+
await actionScreenshot(opts.tabId);
|
|
535
465
|
});
|
|
536
466
|
}
|