@farazirfan/costar-server-executor 1.0.0
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/.env.example +53 -0
- package/README.md +313 -0
- package/costar.mjs +19 -0
- package/dist/agent/agent-old.d.ts +61 -0
- package/dist/agent/agent-old.d.ts.map +1 -0
- package/dist/agent/agent-old.js +282 -0
- package/dist/agent/agent-old.js.map +1 -0
- package/dist/agent/agent.d.ts +110 -0
- package/dist/agent/agent.d.ts.map +1 -0
- package/dist/agent/agent.js +349 -0
- package/dist/agent/agent.js.map +1 -0
- package/dist/agent/context-loader.d.ts +41 -0
- package/dist/agent/context-loader.d.ts.map +1 -0
- package/dist/agent/context-loader.js +166 -0
- package/dist/agent/context-loader.js.map +1 -0
- package/dist/agent/index.d.ts +13 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +11 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/model-fallback.d.ts +48 -0
- package/dist/agent/model-fallback.d.ts.map +1 -0
- package/dist/agent/model-fallback.js +103 -0
- package/dist/agent/model-fallback.js.map +1 -0
- package/dist/agent/pi-embedded-runner/model.d.ts +31 -0
- package/dist/agent/pi-embedded-runner/model.d.ts.map +1 -0
- package/dist/agent/pi-embedded-runner/model.js +65 -0
- package/dist/agent/pi-embedded-runner/model.js.map +1 -0
- package/dist/agent/pi-embedded-runner/run.d.ts +10 -0
- package/dist/agent/pi-embedded-runner/run.d.ts.map +1 -0
- package/dist/agent/pi-embedded-runner/run.js +230 -0
- package/dist/agent/pi-embedded-runner/run.js.map +1 -0
- package/dist/agent/pi-embedded-runner/subscribe.d.ts +42 -0
- package/dist/agent/pi-embedded-runner/subscribe.d.ts.map +1 -0
- package/dist/agent/pi-embedded-runner/subscribe.js +237 -0
- package/dist/agent/pi-embedded-runner/subscribe.js.map +1 -0
- package/dist/agent/pi-embedded-runner/system-prompt.d.ts +52 -0
- package/dist/agent/pi-embedded-runner/system-prompt.d.ts.map +1 -0
- package/dist/agent/pi-embedded-runner/system-prompt.js +331 -0
- package/dist/agent/pi-embedded-runner/system-prompt.js.map +1 -0
- package/dist/agent/pi-embedded-runner/tools.d.ts +16 -0
- package/dist/agent/pi-embedded-runner/tools.d.ts.map +1 -0
- package/dist/agent/pi-embedded-runner/tools.js +52 -0
- package/dist/agent/pi-embedded-runner/tools.js.map +1 -0
- package/dist/agent/pi-embedded-runner/types.d.ts +176 -0
- package/dist/agent/pi-embedded-runner/types.d.ts.map +1 -0
- package/dist/agent/pi-embedded-runner/types.js +5 -0
- package/dist/agent/pi-embedded-runner/types.js.map +1 -0
- package/dist/agent/tool-executor.d.ts +44 -0
- package/dist/agent/tool-executor.d.ts.map +1 -0
- package/dist/agent/tool-executor.js +159 -0
- package/dist/agent/tool-executor.js.map +1 -0
- package/dist/api/chat.d.ts +22 -0
- package/dist/api/chat.d.ts.map +1 -0
- package/dist/api/chat.js +66 -0
- package/dist/api/chat.js.map +1 -0
- package/dist/browser/bridge-server.d.ts +18 -0
- package/dist/browser/bridge-server.d.ts.map +1 -0
- package/dist/browser/bridge-server.js +46 -0
- package/dist/browser/bridge-server.js.map +1 -0
- package/dist/browser/cdp.d.ts +124 -0
- package/dist/browser/cdp.d.ts.map +1 -0
- package/dist/browser/cdp.helpers.d.ts +10 -0
- package/dist/browser/cdp.helpers.d.ts.map +1 -0
- package/dist/browser/cdp.helpers.js +137 -0
- package/dist/browser/cdp.helpers.js.map +1 -0
- package/dist/browser/cdp.js +294 -0
- package/dist/browser/cdp.js.map +1 -0
- package/dist/browser/chrome.d.ts +21 -0
- package/dist/browser/chrome.d.ts.map +1 -0
- package/dist/browser/chrome.executables.d.ts +10 -0
- package/dist/browser/chrome.executables.d.ts.map +1 -0
- package/dist/browser/chrome.executables.js +510 -0
- package/dist/browser/chrome.executables.js.map +1 -0
- package/dist/browser/chrome.js +254 -0
- package/dist/browser/chrome.js.map +1 -0
- package/dist/browser/chrome.profile-decoration.d.ts +11 -0
- package/dist/browser/chrome.profile-decoration.d.ts.map +1 -0
- package/dist/browser/chrome.profile-decoration.js +145 -0
- package/dist/browser/chrome.profile-decoration.js.map +1 -0
- package/dist/browser/client-actions-core.d.ts +144 -0
- package/dist/browser/client-actions-core.d.ts.map +1 -0
- package/dist/browser/client-actions-core.js +101 -0
- package/dist/browser/client-actions-core.js.map +1 -0
- package/dist/browser/client-actions-observe.d.ts +69 -0
- package/dist/browser/client-actions-observe.d.ts.map +1 -0
- package/dist/browser/client-actions-observe.js +101 -0
- package/dist/browser/client-actions-observe.js.map +1 -0
- package/dist/browser/client-actions-state.d.ts +91 -0
- package/dist/browser/client-actions-state.d.ts.map +1 -0
- package/dist/browser/client-actions-state.js +170 -0
- package/dist/browser/client-actions-state.js.map +1 -0
- package/dist/browser/client-actions-types.d.ts +19 -0
- package/dist/browser/client-actions-types.d.ts.map +1 -0
- package/dist/browser/client-actions-types.js +2 -0
- package/dist/browser/client-actions-types.js.map +1 -0
- package/dist/browser/client-actions.d.ts +5 -0
- package/dist/browser/client-actions.d.ts.map +1 -0
- package/dist/browser/client-actions.js +5 -0
- package/dist/browser/client-actions.js.map +1 -0
- package/dist/browser/client-fetch.d.ts +4 -0
- package/dist/browser/client-fetch.d.ts.map +1 -0
- package/dist/browser/client-fetch.js +92 -0
- package/dist/browser/client-fetch.js.map +1 -0
- package/dist/browser/client.d.ts +148 -0
- package/dist/browser/client.d.ts.map +1 -0
- package/dist/browser/client.js +138 -0
- package/dist/browser/client.js.map +1 -0
- package/dist/browser/config.d.ts +40 -0
- package/dist/browser/config.d.ts.map +1 -0
- package/dist/browser/config.js +181 -0
- package/dist/browser/config.js.map +1 -0
- package/dist/browser/constants.d.ts +9 -0
- package/dist/browser/constants.d.ts.map +1 -0
- package/dist/browser/constants.js +9 -0
- package/dist/browser/constants.js.map +1 -0
- package/dist/browser/control-service.d.ts +6 -0
- package/dist/browser/control-service.d.ts.map +1 -0
- package/dist/browser/control-service.js +73 -0
- package/dist/browser/control-service.js.map +1 -0
- package/dist/browser/extension-relay.d.ts +15 -0
- package/dist/browser/extension-relay.d.ts.map +1 -0
- package/dist/browser/extension-relay.js +542 -0
- package/dist/browser/extension-relay.js.map +1 -0
- package/dist/browser/profiles-service.d.ts +26 -0
- package/dist/browser/profiles-service.d.ts.map +1 -0
- package/dist/browser/profiles-service.js +133 -0
- package/dist/browser/profiles-service.js.map +1 -0
- package/dist/browser/profiles.d.ts +31 -0
- package/dist/browser/profiles.d.ts.map +1 -0
- package/dist/browser/profiles.js +94 -0
- package/dist/browser/profiles.js.map +1 -0
- package/dist/browser/pw-ai-module.d.ts +7 -0
- package/dist/browser/pw-ai-module.d.ts.map +1 -0
- package/dist/browser/pw-ai-module.js +38 -0
- package/dist/browser/pw-ai-module.js.map +1 -0
- package/dist/browser/pw-ai.d.ts +3 -0
- package/dist/browser/pw-ai.d.ts.map +1 -0
- package/dist/browser/pw-ai.js +3 -0
- package/dist/browser/pw-ai.js.map +1 -0
- package/dist/browser/pw-role-snapshot.d.ts +36 -0
- package/dist/browser/pw-role-snapshot.d.ts.map +1 -0
- package/dist/browser/pw-role-snapshot.js +311 -0
- package/dist/browser/pw-role-snapshot.js.map +1 -0
- package/dist/browser/pw-session.d.ts +136 -0
- package/dist/browser/pw-session.d.ts.map +1 -0
- package/dist/browser/pw-session.js +432 -0
- package/dist/browser/pw-session.js.map +1 -0
- package/dist/browser/pw-tools-core.activity.d.ts +22 -0
- package/dist/browser/pw-tools-core.activity.d.ts.map +1 -0
- package/dist/browser/pw-tools-core.activity.js +45 -0
- package/dist/browser/pw-tools-core.activity.js.map +1 -0
- package/dist/browser/pw-tools-core.d.ts +9 -0
- package/dist/browser/pw-tools-core.d.ts.map +1 -0
- package/dist/browser/pw-tools-core.downloads.d.ts +35 -0
- package/dist/browser/pw-tools-core.downloads.d.ts.map +1 -0
- package/dist/browser/pw-tools-core.downloads.js +177 -0
- package/dist/browser/pw-tools-core.downloads.js.map +1 -0
- package/dist/browser/pw-tools-core.interactions.d.ts +113 -0
- package/dist/browser/pw-tools-core.interactions.d.ts.map +1 -0
- package/dist/browser/pw-tools-core.interactions.js +421 -0
- package/dist/browser/pw-tools-core.interactions.js.map +1 -0
- package/dist/browser/pw-tools-core.js +9 -0
- package/dist/browser/pw-tools-core.js.map +1 -0
- package/dist/browser/pw-tools-core.responses.d.ts +14 -0
- package/dist/browser/pw-tools-core.responses.d.ts.map +1 -0
- package/dist/browser/pw-tools-core.responses.js +84 -0
- package/dist/browser/pw-tools-core.responses.js.map +1 -0
- package/dist/browser/pw-tools-core.shared.d.ts +7 -0
- package/dist/browser/pw-tools-core.shared.d.ts.map +1 -0
- package/dist/browser/pw-tools-core.shared.js +49 -0
- package/dist/browser/pw-tools-core.shared.js.map +1 -0
- package/dist/browser/pw-tools-core.snapshot.d.ts +65 -0
- package/dist/browser/pw-tools-core.snapshot.d.ts.map +1 -0
- package/dist/browser/pw-tools-core.snapshot.js +143 -0
- package/dist/browser/pw-tools-core.snapshot.js.map +1 -0
- package/dist/browser/pw-tools-core.state.d.ts +47 -0
- package/dist/browser/pw-tools-core.state.d.ts.map +1 -0
- package/dist/browser/pw-tools-core.state.js +148 -0
- package/dist/browser/pw-tools-core.state.js.map +1 -0
- package/dist/browser/pw-tools-core.storage.d.ts +48 -0
- package/dist/browser/pw-tools-core.storage.d.ts.map +1 -0
- package/dist/browser/pw-tools-core.storage.js +73 -0
- package/dist/browser/pw-tools-core.storage.js.map +1 -0
- package/dist/browser/pw-tools-core.trace.d.ts +13 -0
- package/dist/browser/pw-tools-core.trace.d.ts.map +1 -0
- package/dist/browser/pw-tools-core.trace.js +26 -0
- package/dist/browser/pw-tools-core.trace.js.map +1 -0
- package/dist/browser/routes/agent.act.d.ts +4 -0
- package/dist/browser/routes/agent.act.d.ts.map +1 -0
- package/dist/browser/routes/agent.act.js +467 -0
- package/dist/browser/routes/agent.act.js.map +1 -0
- package/dist/browser/routes/agent.act.shared.d.ts +11 -0
- package/dist/browser/routes/agent.act.shared.d.ts.map +1 -0
- package/dist/browser/routes/agent.act.shared.js +39 -0
- package/dist/browser/routes/agent.act.shared.js.map +1 -0
- package/dist/browser/routes/agent.d.ts +4 -0
- package/dist/browser/routes/agent.d.ts.map +1 -0
- package/dist/browser/routes/agent.debug.d.ts +4 -0
- package/dist/browser/routes/agent.debug.d.ts.map +1 -0
- package/dist/browser/routes/agent.debug.js +134 -0
- package/dist/browser/routes/agent.debug.js.map +1 -0
- package/dist/browser/routes/agent.js +11 -0
- package/dist/browser/routes/agent.js.map +1 -0
- package/dist/browser/routes/agent.shared.d.ts +10 -0
- package/dist/browser/routes/agent.shared.d.ts.map +1 -0
- package/dist/browser/routes/agent.shared.js +46 -0
- package/dist/browser/routes/agent.shared.js.map +1 -0
- package/dist/browser/routes/agent.snapshot.d.ts +4 -0
- package/dist/browser/routes/agent.snapshot.d.ts.map +1 -0
- package/dist/browser/routes/agent.snapshot.js +270 -0
- package/dist/browser/routes/agent.snapshot.js.map +1 -0
- package/dist/browser/routes/agent.storage.d.ts +4 -0
- package/dist/browser/routes/agent.storage.d.ts.map +1 -0
- package/dist/browser/routes/agent.storage.js +387 -0
- package/dist/browser/routes/agent.storage.js.map +1 -0
- package/dist/browser/routes/basic.d.ts +4 -0
- package/dist/browser/routes/basic.d.ts.map +1 -0
- package/dist/browser/routes/basic.js +174 -0
- package/dist/browser/routes/basic.js.map +1 -0
- package/dist/browser/routes/dispatcher.d.ts +16 -0
- package/dist/browser/routes/dispatcher.d.ts.map +1 -0
- package/dist/browser/routes/dispatcher.js +87 -0
- package/dist/browser/routes/dispatcher.js.map +1 -0
- package/dist/browser/routes/index.d.ts +4 -0
- package/dist/browser/routes/index.d.ts.map +1 -0
- package/dist/browser/routes/index.js +9 -0
- package/dist/browser/routes/index.js.map +1 -0
- package/dist/browser/routes/tabs.d.ts +4 -0
- package/dist/browser/routes/tabs.d.ts.map +1 -0
- package/dist/browser/routes/tabs.js +121 -0
- package/dist/browser/routes/tabs.js.map +1 -0
- package/dist/browser/routes/types.d.ts +16 -0
- package/dist/browser/routes/types.d.ts.map +1 -0
- package/dist/browser/routes/types.js +2 -0
- package/dist/browser/routes/types.js.map +1 -0
- package/dist/browser/routes/utils.d.ts +16 -0
- package/dist/browser/routes/utils.d.ts.map +1 -0
- package/dist/browser/routes/utils.js +58 -0
- package/dist/browser/routes/utils.js.map +1 -0
- package/dist/browser/screenshot.d.ts +10 -0
- package/dist/browser/screenshot.d.ts.map +1 -0
- package/dist/browser/screenshot.js +40 -0
- package/dist/browser/screenshot.js.map +1 -0
- package/dist/browser/server-context.d.ts +4 -0
- package/dist/browser/server-context.d.ts.map +1 -0
- package/dist/browser/server-context.js +534 -0
- package/dist/browser/server-context.js.map +1 -0
- package/dist/browser/server-context.types.d.ts +79 -0
- package/dist/browser/server-context.types.d.ts.map +1 -0
- package/dist/browser/server-context.types.js +2 -0
- package/dist/browser/server-context.types.js.map +1 -0
- package/dist/browser/server.d.ts +4 -0
- package/dist/browser/server.d.ts.map +1 -0
- package/dist/browser/server.js +91 -0
- package/dist/browser/server.js.map +1 -0
- package/dist/browser/target-id.d.ts +12 -0
- package/dist/browser/target-id.d.ts.map +1 -0
- package/dist/browser/target-id.js +17 -0
- package/dist/browser/target-id.js.map +1 -0
- package/dist/browser/trash.d.ts +2 -0
- package/dist/browser/trash.d.ts.map +1 -0
- package/dist/browser/trash.js +22 -0
- package/dist/browser/trash.js.map +1 -0
- package/dist/chat-server.d.ts +2 -0
- package/dist/chat-server.d.ts.map +1 -0
- package/dist/chat-server.js +91 -0
- package/dist/chat-server.js.map +1 -0
- package/dist/cli/command-format.d.ts +2 -0
- package/dist/cli/command-format.d.ts.map +1 -0
- package/dist/cli/command-format.js +19 -0
- package/dist/cli/command-format.js.map +1 -0
- package/dist/cli/config-cmd.d.ts +6 -0
- package/dist/cli/config-cmd.d.ts.map +1 -0
- package/dist/cli/config-cmd.js +52 -0
- package/dist/cli/config-cmd.js.map +1 -0
- package/dist/cli/doctor.d.ts +6 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +198 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/env-loader.d.ts +23 -0
- package/dist/cli/env-loader.d.ts.map +1 -0
- package/dist/cli/env-loader.js +104 -0
- package/dist/cli/env-loader.js.map +1 -0
- package/dist/cli/paths.d.ts +22 -0
- package/dist/cli/paths.d.ts.map +1 -0
- package/dist/cli/paths.js +38 -0
- package/dist/cli/paths.js.map +1 -0
- package/dist/cli/service.d.ts +11 -0
- package/dist/cli/service.d.ts.map +1 -0
- package/dist/cli/service.js +481 -0
- package/dist/cli/service.js.map +1 -0
- package/dist/cli/setup.d.ts +16 -0
- package/dist/cli/setup.d.ts.map +1 -0
- package/dist/cli/setup.js +317 -0
- package/dist/cli/setup.js.map +1 -0
- package/dist/cli/skill-cmd.d.ts +12 -0
- package/dist/cli/skill-cmd.d.ts.map +1 -0
- package/dist/cli/skill-cmd.js +297 -0
- package/dist/cli/skill-cmd.js.map +1 -0
- package/dist/cli/status.d.ts +6 -0
- package/dist/cli/status.d.ts.map +1 -0
- package/dist/cli/status.js +81 -0
- package/dist/cli/status.js.map +1 -0
- package/dist/cli.d.ts +18 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +157 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/config.d.ts +16 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/config.js +64 -0
- package/dist/config/config.js.map +1 -0
- package/dist/config/paths.d.ts +58 -0
- package/dist/config/paths.d.ts.map +1 -0
- package/dist/config/paths.js +195 -0
- package/dist/config/paths.js.map +1 -0
- package/dist/config/port-defaults.d.ts +14 -0
- package/dist/config/port-defaults.d.ts.map +1 -0
- package/dist/config/port-defaults.js +31 -0
- package/dist/config/port-defaults.js.map +1 -0
- package/dist/config/types.d.ts +86 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +5 -0
- package/dist/config/types.js.map +1 -0
- package/dist/cron/index.d.ts +7 -0
- package/dist/cron/index.d.ts.map +1 -0
- package/dist/cron/index.js +6 -0
- package/dist/cron/index.js.map +1 -0
- package/dist/cron/job-executor.d.ts +14 -0
- package/dist/cron/job-executor.d.ts.map +1 -0
- package/dist/cron/job-executor.js +106 -0
- package/dist/cron/job-executor.js.map +1 -0
- package/dist/cron/scheduler.d.ts +64 -0
- package/dist/cron/scheduler.d.ts.map +1 -0
- package/dist/cron/scheduler.js +220 -0
- package/dist/cron/scheduler.js.map +1 -0
- package/dist/cron/types.d.ts +75 -0
- package/dist/cron/types.d.ts.map +1 -0
- package/dist/cron/types.js +6 -0
- package/dist/cron/types.js.map +1 -0
- package/dist/heartbeat/index.d.ts +6 -0
- package/dist/heartbeat/index.d.ts.map +1 -0
- package/dist/heartbeat/index.js +5 -0
- package/dist/heartbeat/index.js.map +1 -0
- package/dist/heartbeat/runner.d.ts +94 -0
- package/dist/heartbeat/runner.d.ts.map +1 -0
- package/dist/heartbeat/runner.js +528 -0
- package/dist/heartbeat/runner.js.map +1 -0
- package/dist/heartbeat/types.d.ts +30 -0
- package/dist/heartbeat/types.d.ts.map +1 -0
- package/dist/heartbeat/types.js +5 -0
- package/dist/heartbeat/types.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +183 -0
- package/dist/index.js.map +1 -0
- package/dist/infra/agent-events.d.ts +22 -0
- package/dist/infra/agent-events.d.ts.map +1 -0
- package/dist/infra/agent-events.js +58 -0
- package/dist/infra/agent-events.js.map +1 -0
- package/dist/infra/archive.d.ts +17 -0
- package/dist/infra/archive.d.ts.map +1 -0
- package/dist/infra/archive.js +98 -0
- package/dist/infra/archive.js.map +1 -0
- package/dist/infra/backoff.d.ts +9 -0
- package/dist/infra/backoff.d.ts.map +1 -0
- package/dist/infra/backoff.js +20 -0
- package/dist/infra/backoff.js.map +1 -0
- package/dist/infra/binaries.d.ts +4 -0
- package/dist/infra/binaries.d.ts.map +1 -0
- package/dist/infra/binaries.js +10 -0
- package/dist/infra/binaries.js.map +1 -0
- package/dist/infra/bonjour-ciao.d.ts +2 -0
- package/dist/infra/bonjour-ciao.d.ts.map +1 -0
- package/dist/infra/bonjour-ciao.js +11 -0
- package/dist/infra/bonjour-ciao.js.map +1 -0
- package/dist/infra/bonjour-discovery.d.ts +27 -0
- package/dist/infra/bonjour-discovery.d.ts.map +1 -0
- package/dist/infra/bonjour-discovery.js +450 -0
- package/dist/infra/bonjour-discovery.js.map +1 -0
- package/dist/infra/bonjour-errors.d.ts +2 -0
- package/dist/infra/bonjour-errors.d.ts.map +1 -0
- package/dist/infra/bonjour-errors.js +8 -0
- package/dist/infra/bonjour-errors.js.map +1 -0
- package/dist/infra/bonjour.d.ts +20 -0
- package/dist/infra/bonjour.d.ts.map +1 -0
- package/dist/infra/bonjour.js +211 -0
- package/dist/infra/bonjour.js.map +1 -0
- package/dist/infra/brew.d.ts +9 -0
- package/dist/infra/brew.d.ts.map +1 -0
- package/dist/infra/brew.js +56 -0
- package/dist/infra/brew.js.map +1 -0
- package/dist/infra/canvas-host-url.d.ts +12 -0
- package/dist/infra/canvas-host-url.d.ts.map +1 -0
- package/dist/infra/canvas-host-url.js +53 -0
- package/dist/infra/canvas-host-url.js.map +1 -0
- package/dist/infra/channel-activity.d.ts +19 -0
- package/dist/infra/channel-activity.d.ts.map +1 -0
- package/dist/infra/channel-activity.js +33 -0
- package/dist/infra/channel-activity.js.map +1 -0
- package/dist/infra/channel-summary.d.ts +8 -0
- package/dist/infra/channel-summary.d.ts.map +1 -0
- package/dist/infra/channel-summary.js +184 -0
- package/dist/infra/channel-summary.js.map +1 -0
- package/dist/infra/channels-status-issues.d.ts +3 -0
- package/dist/infra/channels-status-issues.d.ts.map +1 -0
- package/dist/infra/channels-status-issues.js +16 -0
- package/dist/infra/channels-status-issues.js.map +1 -0
- package/dist/infra/clipboard.d.ts +2 -0
- package/dist/infra/clipboard.d.ts.map +1 -0
- package/dist/infra/clipboard.js +25 -0
- package/dist/infra/clipboard.js.map +1 -0
- package/dist/infra/control-ui-assets.d.ts +12 -0
- package/dist/infra/control-ui-assets.d.ts.map +1 -0
- package/dist/infra/control-ui-assets.js +99 -0
- package/dist/infra/control-ui-assets.js.map +1 -0
- package/dist/infra/dedupe.d.ts +12 -0
- package/dist/infra/dedupe.d.ts.map +1 -0
- package/dist/infra/dedupe.js +48 -0
- package/dist/infra/dedupe.js.map +1 -0
- package/dist/infra/device-auth-store.d.ts +24 -0
- package/dist/infra/device-auth-store.d.ts.map +1 -0
- package/dist/infra/device-auth-store.js +98 -0
- package/dist/infra/device-auth-store.js.map +1 -0
- package/dist/infra/device-identity.d.ts +12 -0
- package/dist/infra/device-identity.d.ts.map +1 -0
- package/dist/infra/device-identity.js +150 -0
- package/dist/infra/device-identity.js.map +1 -0
- package/dist/infra/device-pairing.d.ts +97 -0
- package/dist/infra/device-pairing.d.ts.map +1 -0
- package/dist/infra/device-pairing.js +402 -0
- package/dist/infra/device-pairing.js.map +1 -0
- package/dist/infra/diagnostic-events.d.ts +122 -0
- package/dist/infra/diagnostic-events.d.ts.map +1 -0
- package/dist/infra/diagnostic-events.js +29 -0
- package/dist/infra/diagnostic-events.js.map +1 -0
- package/dist/infra/diagnostic-flags.d.ts +5 -0
- package/dist/infra/diagnostic-flags.d.ts.map +1 -0
- package/dist/infra/diagnostic-flags.js +67 -0
- package/dist/infra/diagnostic-flags.js.map +1 -0
- package/dist/infra/dotenv.d.ts +4 -0
- package/dist/infra/dotenv.d.ts.map +1 -0
- package/dist/infra/dotenv.js +16 -0
- package/dist/infra/dotenv.js.map +1 -0
- package/dist/infra/env-file.d.ts +10 -0
- package/dist/infra/env-file.d.ts.map +1 -0
- package/dist/infra/env-file.js +44 -0
- package/dist/infra/env-file.js.map +1 -0
- package/dist/infra/env.d.ts +12 -0
- package/dist/infra/env.d.ts.map +1 -0
- package/dist/infra/env.js +35 -0
- package/dist/infra/env.js.map +1 -0
- package/dist/infra/errors.d.ts +4 -0
- package/dist/infra/errors.d.ts.map +1 -0
- package/dist/infra/errors.js +36 -0
- package/dist/infra/errors.js.map +1 -0
- package/dist/infra/exec-approval-forwarder.d.ts +45 -0
- package/dist/infra/exec-approval-forwarder.d.ts.map +1 -0
- package/dist/infra/exec-approval-forwarder.js +213 -0
- package/dist/infra/exec-approval-forwarder.js.map +1 -0
- package/dist/infra/exec-approvals.d.ts +154 -0
- package/dist/infra/exec-approvals.d.ts.map +1 -0
- package/dist/infra/exec-approvals.js +1041 -0
- package/dist/infra/exec-approvals.js.map +1 -0
- package/dist/infra/exec-host.d.ts +38 -0
- package/dist/infra/exec-host.d.ts.map +1 -0
- package/dist/infra/exec-host.js +76 -0
- package/dist/infra/exec-host.js.map +1 -0
- package/dist/infra/exec-safety.d.ts +2 -0
- package/dist/infra/exec-safety.d.ts.map +1 -0
- package/dist/infra/exec-safety.js +32 -0
- package/dist/infra/exec-safety.js.map +1 -0
- package/dist/infra/fetch.d.ts +3 -0
- package/dist/infra/fetch.d.ts.map +1 -0
- package/dist/infra/fetch.js +59 -0
- package/dist/infra/fetch.js.map +1 -0
- package/dist/infra/format-duration.d.ts +11 -0
- package/dist/infra/format-duration.d.ts.map +1 -0
- package/dist/infra/format-duration.js +21 -0
- package/dist/infra/format-duration.js.map +1 -0
- package/dist/infra/fs-safe.d.ts +17 -0
- package/dist/infra/fs-safe.d.ts.map +1 -0
- package/dist/infra/fs-safe.js +77 -0
- package/dist/infra/fs-safe.js.map +1 -0
- package/dist/infra/gateway-lock.d.ts +19 -0
- package/dist/infra/gateway-lock.d.ts.map +1 -0
- package/dist/infra/gateway-lock.js +204 -0
- package/dist/infra/gateway-lock.js.map +1 -0
- package/dist/infra/git-commit.d.ts +5 -0
- package/dist/infra/git-commit.d.ts.map +1 -0
- package/dist/infra/git-commit.js +107 -0
- package/dist/infra/git-commit.js.map +1 -0
- package/dist/infra/heartbeat-events.d.ts +21 -0
- package/dist/infra/heartbeat-events.d.ts.map +1 -0
- package/dist/infra/heartbeat-events.js +35 -0
- package/dist/infra/heartbeat-events.js.map +1 -0
- package/dist/infra/heartbeat-runner.d.ts +45 -0
- package/dist/infra/heartbeat-runner.d.ts.map +1 -0
- package/dist/infra/heartbeat-runner.js +745 -0
- package/dist/infra/heartbeat-runner.js.map +1 -0
- package/dist/infra/heartbeat-visibility.d.ts +18 -0
- package/dist/infra/heartbeat-visibility.d.ts.map +1 -0
- package/dist/infra/heartbeat-visibility.js +46 -0
- package/dist/infra/heartbeat-visibility.js.map +1 -0
- package/dist/infra/heartbeat-wake.d.ts +21 -0
- package/dist/infra/heartbeat-wake.d.ts.map +1 -0
- package/dist/infra/heartbeat-wake.js +62 -0
- package/dist/infra/heartbeat-wake.js.map +1 -0
- package/dist/infra/is-main.d.ts +9 -0
- package/dist/infra/is-main.d.ts.map +1 -0
- package/dist/infra/is-main.js +34 -0
- package/dist/infra/is-main.js.map +1 -0
- package/dist/infra/json-file.d.ts +3 -0
- package/dist/infra/json-file.d.ts.map +1 -0
- package/dist/infra/json-file.js +22 -0
- package/dist/infra/json-file.js.map +1 -0
- package/dist/infra/machine-name.d.ts +2 -0
- package/dist/infra/machine-name.d.ts.map +1 -0
- package/dist/infra/machine-name.js +44 -0
- package/dist/infra/machine-name.js.map +1 -0
- package/dist/infra/node-pairing.d.ts +63 -0
- package/dist/infra/node-pairing.d.ts.map +1 -0
- package/dist/infra/node-pairing.js +229 -0
- package/dist/infra/node-pairing.js.map +1 -0
- package/dist/infra/node-shell.d.ts +2 -0
- package/dist/infra/node-shell.d.ts.map +1 -0
- package/dist/infra/node-shell.js +10 -0
- package/dist/infra/node-shell.js.map +1 -0
- package/dist/infra/openclaw-root.d.ts +6 -0
- package/dist/infra/openclaw-root.d.ts.map +1 -0
- package/dist/infra/openclaw-root.js +58 -0
- package/dist/infra/openclaw-root.js.map +1 -0
- package/dist/infra/os-summary.d.ts +8 -0
- package/dist/infra/os-summary.d.ts.map +1 -0
- package/dist/infra/os-summary.js +24 -0
- package/dist/infra/os-summary.js.map +1 -0
- package/dist/infra/path-env.d.ts +14 -0
- package/dist/infra/path-env.d.ts.map +1 -0
- package/dist/infra/path-env.js +95 -0
- package/dist/infra/path-env.js.map +1 -0
- package/dist/infra/ports-format.d.ts +6 -0
- package/dist/infra/ports-format.d.ts.map +1 -0
- package/dist/infra/ports-format.js +55 -0
- package/dist/infra/ports-format.js.map +1 -0
- package/dist/infra/ports-inspect.d.ts +3 -0
- package/dist/infra/ports-inspect.d.ts.map +1 -0
- package/dist/infra/ports-inspect.js +241 -0
- package/dist/infra/ports-inspect.js.map +1 -0
- package/dist/infra/ports-lsof.d.ts +3 -0
- package/dist/infra/ports-lsof.d.ts.map +1 -0
- package/dist/infra/ports-lsof.js +34 -0
- package/dist/infra/ports-lsof.js.map +1 -0
- package/dist/infra/ports-types.d.ts +18 -0
- package/dist/infra/ports-types.d.ts.map +1 -0
- package/dist/infra/ports-types.js +2 -0
- package/dist/infra/ports-types.js.map +1 -0
- package/dist/infra/ports.d.ts +15 -0
- package/dist/infra/ports.d.ts.map +1 -0
- package/dist/infra/ports.js +76 -0
- package/dist/infra/ports.js.map +1 -0
- package/dist/infra/provider-usage.auth.d.ts +12 -0
- package/dist/infra/provider-usage.auth.d.ts.map +1 -0
- package/dist/infra/provider-usage.auth.js +222 -0
- package/dist/infra/provider-usage.auth.js.map +1 -0
- package/dist/infra/provider-usage.d.ts +5 -0
- package/dist/infra/provider-usage.d.ts.map +1 -0
- package/dist/infra/provider-usage.fetch.antigravity.d.ts +3 -0
- package/dist/infra/provider-usage.fetch.antigravity.d.ts.map +1 -0
- package/dist/infra/provider-usage.fetch.antigravity.js +213 -0
- package/dist/infra/provider-usage.fetch.antigravity.js.map +1 -0
- package/dist/infra/provider-usage.fetch.claude.d.ts +3 -0
- package/dist/infra/provider-usage.fetch.claude.d.ts.map +1 -0
- package/dist/infra/provider-usage.fetch.claude.js +130 -0
- package/dist/infra/provider-usage.fetch.claude.js.map +1 -0
- package/dist/infra/provider-usage.fetch.codex.d.ts +3 -0
- package/dist/infra/provider-usage.fetch.codex.d.ts.map +1 -0
- package/dist/infra/provider-usage.fetch.codex.js +63 -0
- package/dist/infra/provider-usage.fetch.codex.js.map +1 -0
- package/dist/infra/provider-usage.fetch.copilot.d.ts +3 -0
- package/dist/infra/provider-usage.fetch.copilot.d.ts.map +1 -0
- package/dist/infra/provider-usage.fetch.copilot.js +43 -0
- package/dist/infra/provider-usage.fetch.copilot.js.map +1 -0
- package/dist/infra/provider-usage.fetch.d.ts +8 -0
- package/dist/infra/provider-usage.fetch.d.ts.map +1 -0
- package/dist/infra/provider-usage.fetch.gemini.d.ts +3 -0
- package/dist/infra/provider-usage.fetch.gemini.d.ts.map +1 -0
- package/dist/infra/provider-usage.fetch.gemini.js +58 -0
- package/dist/infra/provider-usage.fetch.gemini.js.map +1 -0
- package/dist/infra/provider-usage.fetch.js +8 -0
- package/dist/infra/provider-usage.fetch.js.map +1 -0
- package/dist/infra/provider-usage.fetch.minimax.d.ts +3 -0
- package/dist/infra/provider-usage.fetch.minimax.d.ts.map +1 -0
- package/dist/infra/provider-usage.fetch.minimax.js +333 -0
- package/dist/infra/provider-usage.fetch.minimax.js.map +1 -0
- package/dist/infra/provider-usage.fetch.shared.d.ts +2 -0
- package/dist/infra/provider-usage.fetch.shared.d.ts.map +1 -0
- package/dist/infra/provider-usage.fetch.shared.js +11 -0
- package/dist/infra/provider-usage.fetch.shared.js.map +1 -0
- package/dist/infra/provider-usage.fetch.zai.d.ts +3 -0
- package/dist/infra/provider-usage.fetch.zai.d.ts.map +1 -0
- package/dist/infra/provider-usage.fetch.zai.js +63 -0
- package/dist/infra/provider-usage.fetch.zai.js.map +1 -0
- package/dist/infra/provider-usage.format.d.ts +14 -0
- package/dist/infra/provider-usage.format.d.ts.map +1 -0
- package/dist/infra/provider-usage.format.js +97 -0
- package/dist/infra/provider-usage.format.js.map +1 -0
- package/dist/infra/provider-usage.js +4 -0
- package/dist/infra/provider-usage.js.map +1 -0
- package/dist/infra/provider-usage.load.d.ts +13 -0
- package/dist/infra/provider-usage.load.d.ts.map +1 -0
- package/dist/infra/provider-usage.load.js +66 -0
- package/dist/infra/provider-usage.load.js.map +1 -0
- package/dist/infra/provider-usage.shared.d.ts +9 -0
- package/dist/infra/provider-usage.shared.d.ts.map +1 -0
- package/dist/infra/provider-usage.shared.js +54 -0
- package/dist/infra/provider-usage.shared.js.map +1 -0
- package/dist/infra/provider-usage.types.d.ts +18 -0
- package/dist/infra/provider-usage.types.d.ts.map +1 -0
- package/dist/infra/provider-usage.types.js +2 -0
- package/dist/infra/provider-usage.types.js.map +1 -0
- package/dist/infra/restart-sentinel.d.ts +51 -0
- package/dist/infra/restart-sentinel.d.ts.map +1 -0
- package/dist/infra/restart-sentinel.js +66 -0
- package/dist/infra/restart-sentinel.js.map +1 -0
- package/dist/infra/restart.d.ts +29 -0
- package/dist/infra/restart.d.ts.map +1 -0
- package/dist/infra/restart.js +172 -0
- package/dist/infra/restart.js.map +1 -0
- package/dist/infra/retry-policy.d.ts +26 -0
- package/dist/infra/retry-policy.d.ts.map +1 -0
- package/dist/infra/retry-policy.js +72 -0
- package/dist/infra/retry-policy.js.map +1 -0
- package/dist/infra/retry.d.ts +22 -0
- package/dist/infra/retry.d.ts.map +1 -0
- package/dist/infra/retry.js +86 -0
- package/dist/infra/retry.js.map +1 -0
- package/dist/infra/runtime-guard.d.ts +21 -0
- package/dist/infra/runtime-guard.d.ts.map +1 -0
- package/dist/infra/runtime-guard.js +61 -0
- package/dist/infra/runtime-guard.js.map +1 -0
- package/dist/infra/session-cost-usage.d.ts +37 -0
- package/dist/infra/session-cost-usage.d.ts.map +1 -0
- package/dist/infra/session-cost-usage.js +191 -0
- package/dist/infra/session-cost-usage.js.map +1 -0
- package/dist/infra/shell-env.d.ts +34 -0
- package/dist/infra/shell-env.d.ts.map +1 -0
- package/dist/infra/shell-env.js +126 -0
- package/dist/infra/shell-env.js.map +1 -0
- package/dist/infra/skills-remote.d.ts +25 -0
- package/dist/infra/skills-remote.d.ts.map +1 -0
- package/dist/infra/skills-remote.js +283 -0
- package/dist/infra/skills-remote.js.map +1 -0
- package/dist/infra/ssh-config.d.ts +13 -0
- package/dist/infra/ssh-config.d.ts.map +1 -0
- package/dist/infra/ssh-config.js +85 -0
- package/dist/infra/ssh-config.js.map +1 -0
- package/dist/infra/ssh-tunnel.d.ts +22 -0
- package/dist/infra/ssh-tunnel.d.ts.map +1 -0
- package/dist/infra/ssh-tunnel.js +174 -0
- package/dist/infra/ssh-tunnel.js.map +1 -0
- package/dist/infra/state-migrations.d.ts +88 -0
- package/dist/infra/state-migrations.d.ts.map +1 -0
- package/dist/infra/state-migrations.fs.d.ts +15 -0
- package/dist/infra/state-migrations.fs.d.ts.map +1 -0
- package/dist/infra/state-migrations.fs.js +50 -0
- package/dist/infra/state-migrations.fs.js.map +1 -0
- package/dist/infra/state-migrations.js +658 -0
- package/dist/infra/state-migrations.js.map +1 -0
- package/dist/infra/system-events.d.ts +17 -0
- package/dist/infra/system-events.d.ts.map +1 -0
- package/dist/infra/system-events.js +76 -0
- package/dist/infra/system-events.js.map +1 -0
- package/dist/infra/system-presence.d.ts +46 -0
- package/dist/infra/system-presence.d.ts.map +1 -0
- package/dist/infra/system-presence.js +232 -0
- package/dist/infra/system-presence.js.map +1 -0
- package/dist/infra/tailnet.d.ts +8 -0
- package/dist/infra/tailnet.d.ts.map +1 -0
- package/dist/infra/tailnet.js +47 -0
- package/dist/infra/tailnet.js.map +1 -0
- package/dist/infra/tailscale.d.ts +35 -0
- package/dist/infra/tailscale.d.ts.map +1 -0
- package/dist/infra/tailscale.js +369 -0
- package/dist/infra/tailscale.js.map +1 -0
- package/dist/infra/transport-ready.d.ts +17 -0
- package/dist/infra/transport-ready.d.ts.map +1 -0
- package/dist/infra/transport-ready.js +39 -0
- package/dist/infra/transport-ready.js.map +1 -0
- package/dist/infra/unhandled-rejections.d.ts +16 -0
- package/dist/infra/unhandled-rejections.d.ts.map +1 -0
- package/dist/infra/unhandled-rejections.js +140 -0
- package/dist/infra/unhandled-rejections.js.map +1 -0
- package/dist/infra/update-channels.d.ts +27 -0
- package/dist/infra/update-channels.d.ts.map +1 -0
- package/dist/infra/update-channels.js +58 -0
- package/dist/infra/update-channels.js.map +1 -0
- package/dist/infra/update-check.d.ts +69 -0
- package/dist/infra/update-check.d.ts.map +1 -0
- package/dist/infra/update-check.js +294 -0
- package/dist/infra/update-check.js.map +1 -0
- package/dist/infra/update-global.d.ts +16 -0
- package/dist/infra/update-global.d.ts.map +1 -0
- package/dist/infra/update-global.js +96 -0
- package/dist/infra/update-global.js.map +1 -0
- package/dist/infra/update-runner.d.ts +59 -0
- package/dist/infra/update-runner.d.ts.map +1 -0
- package/dist/infra/update-runner.js +578 -0
- package/dist/infra/update-runner.js.map +1 -0
- package/dist/infra/update-startup.d.ts +17 -0
- package/dist/infra/update-startup.d.ts.map +1 -0
- package/dist/infra/update-startup.js +87 -0
- package/dist/infra/update-startup.js.map +1 -0
- package/dist/infra/voicewake.d.ts +8 -0
- package/dist/infra/voicewake.d.ts.map +1 -0
- package/dist/infra/voicewake.js +75 -0
- package/dist/infra/voicewake.js.map +1 -0
- package/dist/infra/warnings.d.ts +2 -0
- package/dist/infra/warnings.d.ts.map +1 -0
- package/dist/infra/warnings.js +26 -0
- package/dist/infra/warnings.js.map +1 -0
- package/dist/infra/widearea-dns.d.ts +28 -0
- package/dist/infra/widearea-dns.d.ts.map +1 -0
- package/dist/infra/widearea-dns.js +149 -0
- package/dist/infra/widearea-dns.js.map +1 -0
- package/dist/infra/ws.d.ts +3 -0
- package/dist/infra/ws.d.ts.map +1 -0
- package/dist/infra/ws.js +14 -0
- package/dist/infra/ws.js.map +1 -0
- package/dist/infra/wsl.d.ts +3 -0
- package/dist/infra/wsl.d.ts.map +1 -0
- package/dist/infra/wsl.js +26 -0
- package/dist/infra/wsl.js.map +1 -0
- package/dist/logging/config.d.ts +5 -0
- package/dist/logging/config.d.ts.map +1 -0
- package/dist/logging/config.js +20 -0
- package/dist/logging/config.js.map +1 -0
- package/dist/logging/console.d.ts +20 -0
- package/dist/logging/console.d.ts.map +1 -0
- package/dist/logging/console.js +238 -0
- package/dist/logging/console.js.map +1 -0
- package/dist/logging/diagnostic.d.ts +59 -0
- package/dist/logging/diagnostic.d.ts.map +1 -0
- package/dist/logging/diagnostic.js +237 -0
- package/dist/logging/diagnostic.js.map +1 -0
- package/dist/logging/levels.d.ts +5 -0
- package/dist/logging/levels.d.ts.map +1 -0
- package/dist/logging/levels.js +27 -0
- package/dist/logging/levels.js.map +1 -0
- package/dist/logging/logger.d.ts +43 -0
- package/dist/logging/logger.d.ts.map +1 -0
- package/dist/logging/logger.js +186 -0
- package/dist/logging/logger.js.map +1 -0
- package/dist/logging/parse-log-line.d.ts +10 -0
- package/dist/logging/parse-log-line.d.ts.map +1 -0
- package/dist/logging/parse-log-line.js +53 -0
- package/dist/logging/parse-log-line.js.map +1 -0
- package/dist/logging/redact.d.ts +10 -0
- package/dist/logging/redact.d.ts.map +1 -0
- package/dist/logging/redact.js +116 -0
- package/dist/logging/redact.js.map +1 -0
- package/dist/logging/state.d.ts +18 -0
- package/dist/logging/state.d.ts.map +1 -0
- package/dist/logging/state.js +13 -0
- package/dist/logging/state.js.map +1 -0
- package/dist/logging/subsystem.d.ts +17 -0
- package/dist/logging/subsystem.d.ts.map +1 -0
- package/dist/logging/subsystem.js +235 -0
- package/dist/logging/subsystem.js.map +1 -0
- package/dist/media/audio-tags.d.ts +11 -0
- package/dist/media/audio-tags.d.ts.map +1 -0
- package/dist/media/audio-tags.js +15 -0
- package/dist/media/audio-tags.js.map +1 -0
- package/dist/media/audio.d.ts +5 -0
- package/dist/media/audio.d.ts.map +1 -0
- package/dist/media/audio.js +16 -0
- package/dist/media/audio.js.map +1 -0
- package/dist/media/constants.d.ts +8 -0
- package/dist/media/constants.d.ts.map +1 -0
- package/dist/media/constants.js +34 -0
- package/dist/media/constants.js.map +1 -0
- package/dist/media/fetch.d.ts +20 -0
- package/dist/media/fetch.d.ts.map +1 -0
- package/dist/media/fetch.js +152 -0
- package/dist/media/fetch.js.map +1 -0
- package/dist/media/host.d.ts +12 -0
- package/dist/media/host.d.ts.map +1 -0
- package/dist/media/host.js +44 -0
- package/dist/media/host.js.map +1 -0
- package/dist/media/image-ops.d.ts +40 -0
- package/dist/media/image-ops.d.ts.map +1 -0
- package/dist/media/image-ops.js +386 -0
- package/dist/media/image-ops.js.map +1 -0
- package/dist/media/input-files.d.ts +77 -0
- package/dist/media/input-files.d.ts.map +1 -0
- package/dist/media/input-files.js +277 -0
- package/dist/media/input-files.js.map +1 -0
- package/dist/media/mime.d.ts +16 -0
- package/dist/media/mime.d.ts.map +1 -0
- package/dist/media/mime.js +151 -0
- package/dist/media/mime.js.map +1 -0
- package/dist/media/parse.d.ts +9 -0
- package/dist/media/parse.d.ts.map +1 -0
- package/dist/media/parse.js +176 -0
- package/dist/media/parse.js.map +1 -0
- package/dist/media/server.d.ts +6 -0
- package/dist/media/server.d.ts.map +1 -0
- package/dist/media/server.js +89 -0
- package/dist/media/server.js.map +1 -0
- package/dist/media/store.d.ts +19 -0
- package/dist/media/store.d.ts.map +1 -0
- package/dist/media/store.js +201 -0
- package/dist/media/store.js.map +1 -0
- package/dist/process/exec.d.ts +23 -0
- package/dist/process/exec.d.ts.map +1 -0
- package/dist/process/exec.js +99 -0
- package/dist/process/exec.js.map +1 -0
- package/dist/schema/typebox.d.ts +40 -0
- package/dist/schema/typebox.d.ts.map +1 -0
- package/dist/schema/typebox.js +796 -0
- package/dist/schema/typebox.js.map +1 -0
- package/dist/server.d.ts +52 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +322 -0
- package/dist/server.js.map +1 -0
- package/dist/services/supabase.d.ts +67 -0
- package/dist/services/supabase.d.ts.map +1 -0
- package/dist/services/supabase.js +106 -0
- package/dist/services/supabase.js.map +1 -0
- package/dist/skills/index.d.ts +24 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +26 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/skills/loader.d.ts +29 -0
- package/dist/skills/loader.d.ts.map +1 -0
- package/dist/skills/loader.js +176 -0
- package/dist/skills/loader.js.map +1 -0
- package/dist/skills/manager.d.ts +85 -0
- package/dist/skills/manager.d.ts.map +1 -0
- package/dist/skills/manager.js +179 -0
- package/dist/skills/manager.js.map +1 -0
- package/dist/skills/status.d.ts +26 -0
- package/dist/skills/status.d.ts.map +1 -0
- package/dist/skills/status.js +238 -0
- package/dist/skills/status.js.map +1 -0
- package/dist/skills/types.d.ts +182 -0
- package/dist/skills/types.d.ts.map +1 -0
- package/dist/skills/types.js +9 -0
- package/dist/skills/types.js.map +1 -0
- package/dist/supabase/client.d.ts +18 -0
- package/dist/supabase/client.d.ts.map +1 -0
- package/dist/supabase/client.js +43 -0
- package/dist/supabase/client.js.map +1 -0
- package/dist/supabase/context.d.ts +25 -0
- package/dist/supabase/context.d.ts.map +1 -0
- package/dist/supabase/context.js +109 -0
- package/dist/supabase/context.js.map +1 -0
- package/dist/supabase/cron-jobs.d.ts +79 -0
- package/dist/supabase/cron-jobs.d.ts.map +1 -0
- package/dist/supabase/cron-jobs.js +396 -0
- package/dist/supabase/cron-jobs.js.map +1 -0
- package/dist/supabase/heartbeat-items.d.ts +50 -0
- package/dist/supabase/heartbeat-items.d.ts.map +1 -0
- package/dist/supabase/heartbeat-items.js +179 -0
- package/dist/supabase/heartbeat-items.js.map +1 -0
- package/dist/supabase/index.d.ts +13 -0
- package/dist/supabase/index.d.ts.map +1 -0
- package/dist/supabase/index.js +12 -0
- package/dist/supabase/index.js.map +1 -0
- package/dist/supabase/memory.d.ts +49 -0
- package/dist/supabase/memory.d.ts.map +1 -0
- package/dist/supabase/memory.js +157 -0
- package/dist/supabase/memory.js.map +1 -0
- package/dist/supabase/notifications.d.ts +35 -0
- package/dist/supabase/notifications.d.ts.map +1 -0
- package/dist/supabase/notifications.js +46 -0
- package/dist/supabase/notifications.js.map +1 -0
- package/dist/supabase/requests.d.ts +69 -0
- package/dist/supabase/requests.d.ts.map +1 -0
- package/dist/supabase/requests.js +246 -0
- package/dist/supabase/requests.js.map +1 -0
- package/dist/supabase/types.d.ts +65 -0
- package/dist/supabase/types.d.ts.map +1 -0
- package/dist/supabase/types.js +5 -0
- package/dist/supabase/types.js.map +1 -0
- package/dist/supabase/workspace-storage.d.ts +54 -0
- package/dist/supabase/workspace-storage.d.ts.map +1 -0
- package/dist/supabase/workspace-storage.js +217 -0
- package/dist/supabase/workspace-storage.js.map +1 -0
- package/dist/tools/bash-tools.shared.d.ts +26 -0
- package/dist/tools/bash-tools.shared.d.ts.map +1 -0
- package/dist/tools/bash-tools.shared.js +135 -0
- package/dist/tools/bash-tools.shared.js.map +1 -0
- package/dist/tools/browser-new.d.ts +7 -0
- package/dist/tools/browser-new.d.ts.map +1 -0
- package/dist/tools/browser-new.js +329 -0
- package/dist/tools/browser-new.js.map +1 -0
- package/dist/tools/browser-openclaw.d.ts +6 -0
- package/dist/tools/browser-openclaw.d.ts.map +1 -0
- package/dist/tools/browser-openclaw.js +597 -0
- package/dist/tools/browser-openclaw.js.map +1 -0
- package/dist/tools/browser-tool.schema.d.ts +51 -0
- package/dist/tools/browser-tool.schema.d.ts.map +1 -0
- package/dist/tools/browser-tool.schema.js +106 -0
- package/dist/tools/browser-tool.schema.js.map +1 -0
- package/dist/tools/browser.d.ts +9 -0
- package/dist/tools/browser.d.ts.map +1 -0
- package/dist/tools/browser.js +1629 -0
- package/dist/tools/browser.js.map +1 -0
- package/dist/tools/built-in-tools.d.ts +27 -0
- package/dist/tools/built-in-tools.d.ts.map +1 -0
- package/dist/tools/built-in-tools.js +86 -0
- package/dist/tools/built-in-tools.js.map +1 -0
- package/dist/tools/calendar.d.ts +16 -0
- package/dist/tools/calendar.d.ts.map +1 -0
- package/dist/tools/calendar.js +244 -0
- package/dist/tools/calendar.js.map +1 -0
- package/dist/tools/cron.d.ts +22 -0
- package/dist/tools/cron.d.ts.map +1 -0
- package/dist/tools/cron.js +273 -0
- package/dist/tools/cron.js.map +1 -0
- package/dist/tools/email.d.ts +16 -0
- package/dist/tools/email.d.ts.map +1 -0
- package/dist/tools/email.js +435 -0
- package/dist/tools/email.js.map +1 -0
- package/dist/tools/exec.d.ts +40 -0
- package/dist/tools/exec.d.ts.map +1 -0
- package/dist/tools/exec.js +446 -0
- package/dist/tools/exec.js.map +1 -0
- package/dist/tools/fetch-api-data.d.ts +9 -0
- package/dist/tools/fetch-api-data.d.ts.map +1 -0
- package/dist/tools/fetch-api-data.js +120 -0
- package/dist/tools/fetch-api-data.js.map +1 -0
- package/dist/tools/file-ops.d.ts +14 -0
- package/dist/tools/file-ops.d.ts.map +1 -0
- package/dist/tools/file-ops.js +19 -0
- package/dist/tools/file-ops.js.map +1 -0
- package/dist/tools/generate-image.d.ts +8 -0
- package/dist/tools/generate-image.d.ts.map +1 -0
- package/dist/tools/generate-image.js +99 -0
- package/dist/tools/generate-image.js.map +1 -0
- package/dist/tools/generate-video.d.ts +9 -0
- package/dist/tools/generate-video.d.ts.map +1 -0
- package/dist/tools/generate-video.js +178 -0
- package/dist/tools/generate-video.js.map +1 -0
- package/dist/tools/google-maps.d.ts +11 -0
- package/dist/tools/google-maps.d.ts.map +1 -0
- package/dist/tools/google-maps.js +285 -0
- package/dist/tools/google-maps.js.map +1 -0
- package/dist/tools/image.d.ts +9 -0
- package/dist/tools/image.d.ts.map +1 -0
- package/dist/tools/image.js +124 -0
- package/dist/tools/image.js.map +1 -0
- package/dist/tools/index.d.ts +40 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +104 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/memory.d.ts +16 -0
- package/dist/tools/memory.d.ts.map +1 -0
- package/dist/tools/memory.js +118 -0
- package/dist/tools/memory.js.map +1 -0
- package/dist/tools/message.d.ts +8 -0
- package/dist/tools/message.d.ts.map +1 -0
- package/dist/tools/message.js +60 -0
- package/dist/tools/message.js.map +1 -0
- package/dist/tools/process-registry.d.ts +73 -0
- package/dist/tools/process-registry.d.ts.map +1 -0
- package/dist/tools/process-registry.js +185 -0
- package/dist/tools/process-registry.js.map +1 -0
- package/dist/tools/process.d.ts +24 -0
- package/dist/tools/process.d.ts.map +1 -0
- package/dist/tools/process.js +586 -0
- package/dist/tools/process.js.map +1 -0
- package/dist/tools/pty-dsr.d.ts +12 -0
- package/dist/tools/pty-dsr.d.ts.map +1 -0
- package/dist/tools/pty-dsr.js +20 -0
- package/dist/tools/pty-dsr.js.map +1 -0
- package/dist/tools/pty-keys.d.ts +20 -0
- package/dist/tools/pty-keys.d.ts.map +1 -0
- package/dist/tools/pty-keys.js +242 -0
- package/dist/tools/pty-keys.js.map +1 -0
- package/dist/tools/session-slug.d.ts +8 -0
- package/dist/tools/session-slug.d.ts.map +1 -0
- package/dist/tools/session-slug.js +136 -0
- package/dist/tools/session-slug.js.map +1 -0
- package/dist/tools/session-status.d.ts +7 -0
- package/dist/tools/session-status.d.ts.map +1 -0
- package/dist/tools/session-status.js +55 -0
- package/dist/tools/session-status.js.map +1 -0
- package/dist/tools/shell-utils.d.ts +13 -0
- package/dist/tools/shell-utils.d.ts.map +1 -0
- package/dist/tools/shell-utils.js +106 -0
- package/dist/tools/shell-utils.js.map +1 -0
- package/dist/tools/tts.d.ts +9 -0
- package/dist/tools/tts.d.ts.map +1 -0
- package/dist/tools/tts.js +102 -0
- package/dist/tools/tts.js.map +1 -0
- package/dist/tools/web-fetch.d.ts +9 -0
- package/dist/tools/web-fetch.d.ts.map +1 -0
- package/dist/tools/web-fetch.js +129 -0
- package/dist/tools/web-fetch.js.map +1 -0
- package/dist/tools/web-search.d.ts +15 -0
- package/dist/tools/web-search.d.ts.map +1 -0
- package/dist/tools/web-search.js +119 -0
- package/dist/tools/web-search.js.map +1 -0
- package/dist/types/tool.d.ts +31 -0
- package/dist/types/tool.d.ts.map +1 -0
- package/dist/types/tool.js +5 -0
- package/dist/types/tool.js.map +1 -0
- package/dist/updates/checker.d.ts +51 -0
- package/dist/updates/checker.d.ts.map +1 -0
- package/dist/updates/checker.js +237 -0
- package/dist/updates/checker.js.map +1 -0
- package/dist/updates/index.d.ts +6 -0
- package/dist/updates/index.d.ts.map +1 -0
- package/dist/updates/index.js +6 -0
- package/dist/updates/index.js.map +1 -0
- package/dist/updates/notifier.d.ts +17 -0
- package/dist/updates/notifier.d.ts.map +1 -0
- package/dist/updates/notifier.js +44 -0
- package/dist/updates/notifier.js.map +1 -0
- package/dist/utils/google-oauth.d.ts +58 -0
- package/dist/utils/google-oauth.d.ts.map +1 -0
- package/dist/utils/google-oauth.js +161 -0
- package/dist/utils/google-oauth.js.map +1 -0
- package/dist/utils/log-buffer.d.ts +35 -0
- package/dist/utils/log-buffer.d.ts.map +1 -0
- package/dist/utils/log-buffer.js +100 -0
- package/dist/utils/log-buffer.js.map +1 -0
- package/dist/utils/tool-helpers.d.ts +48 -0
- package/dist/utils/tool-helpers.d.ts.map +1 -0
- package/dist/utils/tool-helpers.js +125 -0
- package/dist/utils/tool-helpers.js.map +1 -0
- package/dist/utils/utils.d.ts +44 -0
- package/dist/utils/utils.d.ts.map +1 -0
- package/dist/utils/utils.js +257 -0
- package/dist/utils/utils.js.map +1 -0
- package/dist/web-server.d.ts +30 -0
- package/dist/web-server.d.ts.map +1 -0
- package/dist/web-server.js +367 -0
- package/dist/web-server.js.map +1 -0
- package/dist/workspace/context.d.ts +23 -0
- package/dist/workspace/context.d.ts.map +1 -0
- package/dist/workspace/context.js +88 -0
- package/dist/workspace/context.js.map +1 -0
- package/dist/workspace/generator.d.ts +47 -0
- package/dist/workspace/generator.d.ts.map +1 -0
- package/dist/workspace/generator.js +261 -0
- package/dist/workspace/generator.js.map +1 -0
- package/dist/workspace/index.d.ts +9 -0
- package/dist/workspace/index.d.ts.map +1 -0
- package/dist/workspace/index.js +9 -0
- package/dist/workspace/index.js.map +1 -0
- package/dist/workspace/templates.d.ts +36 -0
- package/dist/workspace/templates.d.ts.map +1 -0
- package/dist/workspace/templates.js +280 -0
- package/dist/workspace/templates.js.map +1 -0
- package/dist/workspace/workspace.d.ts +79 -0
- package/dist/workspace/workspace.d.ts.map +1 -0
- package/dist/workspace/workspace.js +234 -0
- package/dist/workspace/workspace.js.map +1 -0
- package/package.json +98 -0
- package/public/index.html +1625 -0
- package/scripts/install.sh +311 -0
- package/scripts/postinstall.js +135 -0
- package/skills/commit/SKILL.md +69 -0
- package/skills/review-pr/SKILL.md +105 -0
- package/skills/skill-creator/SKILL.md +236 -0
- package/skills/test/SKILL.md +57 -0
|
@@ -0,0 +1,1629 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CoStar Server Executor - Complete Browser Tool
|
|
3
|
+
* Replicates OpenClaw's browser-tool.ts behavior using direct Playwright
|
|
4
|
+
*
|
|
5
|
+
* Implements all 15 actions with AI snapshots, labeled screenshots, and full automation
|
|
6
|
+
*/
|
|
7
|
+
import { Type } from "@sinclair/typebox";
|
|
8
|
+
import { chromium } from "playwright";
|
|
9
|
+
import { jsonResult, readStringParam, readBooleanParam, readNumberParam, readArrayParam, } from "../utils/tool-helpers.js";
|
|
10
|
+
// OpenClaw exact BROWSER_ACT_KINDS (from browser-tool.schema.ts)
|
|
11
|
+
const BROWSER_ACT_KINDS = [
|
|
12
|
+
"click",
|
|
13
|
+
"type",
|
|
14
|
+
"press",
|
|
15
|
+
"hover",
|
|
16
|
+
"drag",
|
|
17
|
+
"select",
|
|
18
|
+
"fill",
|
|
19
|
+
"resize",
|
|
20
|
+
"wait",
|
|
21
|
+
"evaluate",
|
|
22
|
+
"close",
|
|
23
|
+
];
|
|
24
|
+
// OpenClaw exact BROWSER_TOOL_ACTIONS (from browser-tool.schema.ts)
|
|
25
|
+
const BROWSER_TOOL_ACTIONS = [
|
|
26
|
+
"status",
|
|
27
|
+
"start",
|
|
28
|
+
"stop",
|
|
29
|
+
"profiles",
|
|
30
|
+
"tabs",
|
|
31
|
+
"open",
|
|
32
|
+
"focus",
|
|
33
|
+
"close",
|
|
34
|
+
"snapshot",
|
|
35
|
+
"screenshot",
|
|
36
|
+
"navigate",
|
|
37
|
+
"console",
|
|
38
|
+
"pdf",
|
|
39
|
+
"upload",
|
|
40
|
+
"dialog",
|
|
41
|
+
"act",
|
|
42
|
+
];
|
|
43
|
+
// OpenClaw exact BrowserActSchema (from browser-tool.schema.ts)
|
|
44
|
+
const BrowserActSchema = Type.Object({
|
|
45
|
+
kind: Type.Union(BROWSER_ACT_KINDS.map(k => Type.Literal(k))),
|
|
46
|
+
// Common fields
|
|
47
|
+
targetId: Type.Optional(Type.String()),
|
|
48
|
+
ref: Type.Optional(Type.String()),
|
|
49
|
+
// click
|
|
50
|
+
doubleClick: Type.Optional(Type.Boolean()),
|
|
51
|
+
button: Type.Optional(Type.String()),
|
|
52
|
+
modifiers: Type.Optional(Type.Array(Type.String())),
|
|
53
|
+
// type
|
|
54
|
+
text: Type.Optional(Type.String()),
|
|
55
|
+
submit: Type.Optional(Type.Boolean()),
|
|
56
|
+
slowly: Type.Optional(Type.Boolean()),
|
|
57
|
+
// press
|
|
58
|
+
key: Type.Optional(Type.String()),
|
|
59
|
+
// drag
|
|
60
|
+
startRef: Type.Optional(Type.String()),
|
|
61
|
+
endRef: Type.Optional(Type.String()),
|
|
62
|
+
// select
|
|
63
|
+
values: Type.Optional(Type.Array(Type.String())),
|
|
64
|
+
// fill - use permissive array of objects
|
|
65
|
+
fields: Type.Optional(Type.Array(Type.Object({}, { additionalProperties: true }))),
|
|
66
|
+
// resize
|
|
67
|
+
width: Type.Optional(Type.Number()),
|
|
68
|
+
height: Type.Optional(Type.Number()),
|
|
69
|
+
// wait
|
|
70
|
+
timeMs: Type.Optional(Type.Number()),
|
|
71
|
+
textGone: Type.Optional(Type.String()),
|
|
72
|
+
// evaluate
|
|
73
|
+
fn: Type.Optional(Type.String()),
|
|
74
|
+
});
|
|
75
|
+
// OpenClaw exact BrowserToolSchema (from browser-tool.schema.ts)
|
|
76
|
+
const BrowserSchema = Type.Object({
|
|
77
|
+
action: Type.Union(BROWSER_TOOL_ACTIONS.map(a => Type.Literal(a))),
|
|
78
|
+
profile: Type.Optional(Type.String()),
|
|
79
|
+
targetUrl: Type.Optional(Type.String()),
|
|
80
|
+
targetId: Type.Optional(Type.String()),
|
|
81
|
+
limit: Type.Optional(Type.Number()),
|
|
82
|
+
maxChars: Type.Optional(Type.Number()),
|
|
83
|
+
mode: Type.Optional(Type.String()), // "efficient"
|
|
84
|
+
refs: Type.Optional(Type.String()), // "role" or "aria"
|
|
85
|
+
interactive: Type.Optional(Type.Boolean()),
|
|
86
|
+
compact: Type.Optional(Type.Boolean()),
|
|
87
|
+
depth: Type.Optional(Type.Number()),
|
|
88
|
+
selector: Type.Optional(Type.String()),
|
|
89
|
+
frame: Type.Optional(Type.String()),
|
|
90
|
+
labels: Type.Optional(Type.Boolean()),
|
|
91
|
+
fullPage: Type.Optional(Type.Boolean()),
|
|
92
|
+
ref: Type.Optional(Type.String()),
|
|
93
|
+
element: Type.Optional(Type.String()),
|
|
94
|
+
type: Type.Optional(Type.String()), // "png" or "jpeg"
|
|
95
|
+
level: Type.Optional(Type.String()),
|
|
96
|
+
paths: Type.Optional(Type.Array(Type.String())),
|
|
97
|
+
inputRef: Type.Optional(Type.String()),
|
|
98
|
+
timeoutMs: Type.Optional(Type.Number()),
|
|
99
|
+
accept: Type.Optional(Type.Boolean()),
|
|
100
|
+
promptText: Type.Optional(Type.String()),
|
|
101
|
+
request: Type.Optional(BrowserActSchema),
|
|
102
|
+
});
|
|
103
|
+
// OpenClaw's INTERACTIVE_ROLES - elements that get refs
|
|
104
|
+
const INTERACTIVE_ROLES = new Set([
|
|
105
|
+
"button",
|
|
106
|
+
"link",
|
|
107
|
+
"textbox",
|
|
108
|
+
"checkbox",
|
|
109
|
+
"radio",
|
|
110
|
+
"combobox",
|
|
111
|
+
"listbox",
|
|
112
|
+
"menuitem",
|
|
113
|
+
"menuitemcheckbox",
|
|
114
|
+
"menuitemradio",
|
|
115
|
+
"option",
|
|
116
|
+
"searchbox",
|
|
117
|
+
"slider",
|
|
118
|
+
"spinbutton",
|
|
119
|
+
"switch",
|
|
120
|
+
"tab",
|
|
121
|
+
"treeitem",
|
|
122
|
+
]);
|
|
123
|
+
const CONTENT_ROLES = new Set([
|
|
124
|
+
"heading",
|
|
125
|
+
"cell",
|
|
126
|
+
"gridcell",
|
|
127
|
+
"columnheader",
|
|
128
|
+
"rowheader",
|
|
129
|
+
"listitem",
|
|
130
|
+
"article",
|
|
131
|
+
"region",
|
|
132
|
+
"main",
|
|
133
|
+
"navigation",
|
|
134
|
+
]);
|
|
135
|
+
/**
|
|
136
|
+
* Parse Playwright's ariaSnapshot output and build refs map (OpenClaw style)
|
|
137
|
+
*/
|
|
138
|
+
function buildRoleSnapshotFromAriaSnapshot(ariaSnapshot, options = {}) {
|
|
139
|
+
const lines = ariaSnapshot.split("\n");
|
|
140
|
+
const refs = {};
|
|
141
|
+
// Track role+name combinations for nth handling
|
|
142
|
+
const counts = new Map();
|
|
143
|
+
const refsByKey = new Map();
|
|
144
|
+
const getKey = (role, name) => `${role}:${name ?? ""}`;
|
|
145
|
+
let counter = 0;
|
|
146
|
+
const nextRef = () => {
|
|
147
|
+
counter += 1;
|
|
148
|
+
return `e${counter}`;
|
|
149
|
+
};
|
|
150
|
+
const getIndentLevel = (line) => {
|
|
151
|
+
const match = line.match(/^(\s*)/);
|
|
152
|
+
return match ? Math.floor(match[1].length / 2) : 0;
|
|
153
|
+
};
|
|
154
|
+
const result = [];
|
|
155
|
+
for (const line of lines) {
|
|
156
|
+
const depth = getIndentLevel(line);
|
|
157
|
+
if (options.maxDepth !== undefined && depth > options.maxDepth)
|
|
158
|
+
continue;
|
|
159
|
+
// Parse line: "- role "name" [other stuff]"
|
|
160
|
+
const match = line.match(/^(\s*-\s*)(\w+)(?:\s+"([^"]*)")?(.*)$/);
|
|
161
|
+
if (!match) {
|
|
162
|
+
if (!options.interactive)
|
|
163
|
+
result.push(line);
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
const [, prefix, roleRaw, name, suffix] = match;
|
|
167
|
+
if (roleRaw.startsWith("/")) {
|
|
168
|
+
if (!options.interactive)
|
|
169
|
+
result.push(line);
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
const role = roleRaw.toLowerCase();
|
|
173
|
+
const isInteractive = INTERACTIVE_ROLES.has(role);
|
|
174
|
+
const isContent = CONTENT_ROLES.has(role);
|
|
175
|
+
// If interactive-only mode, skip non-interactive
|
|
176
|
+
if (options.interactive && !isInteractive)
|
|
177
|
+
continue;
|
|
178
|
+
// Determine if this element should have a ref
|
|
179
|
+
const shouldHaveRef = isInteractive || (isContent && name);
|
|
180
|
+
if (!shouldHaveRef) {
|
|
181
|
+
if (!options.interactive)
|
|
182
|
+
result.push(line);
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
const ref = nextRef();
|
|
186
|
+
const key = getKey(role, name);
|
|
187
|
+
const nth = counts.get(key) ?? 0;
|
|
188
|
+
counts.set(key, nth + 1);
|
|
189
|
+
const keyRefs = refsByKey.get(key) ?? [];
|
|
190
|
+
keyRefs.push(ref);
|
|
191
|
+
refsByKey.set(key, keyRefs);
|
|
192
|
+
refs[ref] = { role, name, nth };
|
|
193
|
+
// Build enhanced line with ref
|
|
194
|
+
let enhanced = `${prefix}${roleRaw}`;
|
|
195
|
+
if (name)
|
|
196
|
+
enhanced += ` "${name}"`;
|
|
197
|
+
enhanced += ` [ref=${ref}]`;
|
|
198
|
+
if (nth > 0)
|
|
199
|
+
enhanced += ` [nth=${nth}]`;
|
|
200
|
+
if (suffix && suffix.includes("["))
|
|
201
|
+
enhanced += suffix;
|
|
202
|
+
result.push(enhanced);
|
|
203
|
+
}
|
|
204
|
+
// Remove nth from non-duplicates
|
|
205
|
+
for (const [_key, keyRefs] of refsByKey) {
|
|
206
|
+
if (keyRefs.length === 1) {
|
|
207
|
+
const ref = keyRefs[0];
|
|
208
|
+
if (refs[ref])
|
|
209
|
+
delete refs[ref].nth;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return {
|
|
213
|
+
snapshot: result.join("\n") || "(empty)",
|
|
214
|
+
refs,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
// OpenClaw-style WeakMap to store state per Page object
|
|
218
|
+
const pageStates = new WeakMap();
|
|
219
|
+
// Global cache by targetId (backup for when Playwright returns different Page object)
|
|
220
|
+
const roleRefsByTarget = new Map();
|
|
221
|
+
const MAX_ROLE_REFS_CACHE = 50;
|
|
222
|
+
// Ensure page has a state object (OpenClaw-style)
|
|
223
|
+
function ensurePageState(page) {
|
|
224
|
+
const existing = pageStates.get(page);
|
|
225
|
+
if (existing)
|
|
226
|
+
return existing;
|
|
227
|
+
const newState = {
|
|
228
|
+
console: [],
|
|
229
|
+
errors: [],
|
|
230
|
+
requests: [],
|
|
231
|
+
};
|
|
232
|
+
pageStates.set(page, newState);
|
|
233
|
+
return newState;
|
|
234
|
+
}
|
|
235
|
+
// Global browser state (singleton)
|
|
236
|
+
const state = {
|
|
237
|
+
browser: null,
|
|
238
|
+
context: null,
|
|
239
|
+
pages: new Map(),
|
|
240
|
+
consoleLogs: new Map(),
|
|
241
|
+
networkRequests: new Map(),
|
|
242
|
+
pageErrors: new Map(),
|
|
243
|
+
running: false,
|
|
244
|
+
connectionMode: "launched",
|
|
245
|
+
};
|
|
246
|
+
/**
|
|
247
|
+
* Get the page to use for an action, tracking last active (OpenClaw-style)
|
|
248
|
+
*/
|
|
249
|
+
function getPageForAction(targetId) {
|
|
250
|
+
if (targetId) {
|
|
251
|
+
const existingPage = state.pages.get(targetId);
|
|
252
|
+
if (!existingPage) {
|
|
253
|
+
throw new Error(`Tab ${targetId} not found. Run action=tabs to see available tabs.`);
|
|
254
|
+
}
|
|
255
|
+
state.lastActiveTargetId = targetId;
|
|
256
|
+
return { page: existingPage, usedTargetId: targetId };
|
|
257
|
+
}
|
|
258
|
+
if (state.pages.size === 0) {
|
|
259
|
+
throw new Error("No tabs open. Use action=open to open a URL first.");
|
|
260
|
+
}
|
|
261
|
+
// Prefer last active tab (the one most recently used for snapshot/action)
|
|
262
|
+
if (state.lastActiveTargetId && state.pages.has(state.lastActiveTargetId)) {
|
|
263
|
+
const page = state.pages.get(state.lastActiveTargetId);
|
|
264
|
+
return { page, usedTargetId: state.lastActiveTargetId };
|
|
265
|
+
}
|
|
266
|
+
// Fall back to first tab
|
|
267
|
+
const firstEntry = Array.from(state.pages.entries())[0];
|
|
268
|
+
state.lastActiveTargetId = firstEntry[0];
|
|
269
|
+
return { page: firstEntry[1], usedTargetId: firstEntry[0] };
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Restore role refs for a target (OpenClaw-style)
|
|
273
|
+
* This ensures refs are available for the page even if they were stored under a different targetId
|
|
274
|
+
*/
|
|
275
|
+
/**
|
|
276
|
+
* Store role refs for a target (OpenClaw-style)
|
|
277
|
+
* Stores BOTH on page's WeakMap state AND in global cache
|
|
278
|
+
*/
|
|
279
|
+
function storeRoleRefsForTarget(opts) {
|
|
280
|
+
// Store on page's WeakMap state
|
|
281
|
+
const pageState = ensurePageState(opts.page);
|
|
282
|
+
pageState.roleRefs = opts.refs;
|
|
283
|
+
pageState.roleRefsFrameSelector = opts.frameSelector;
|
|
284
|
+
pageState.roleRefsMode = opts.mode;
|
|
285
|
+
// Store in global cache by targetId (for backup)
|
|
286
|
+
const targetId = opts.targetId?.trim();
|
|
287
|
+
if (!targetId)
|
|
288
|
+
return;
|
|
289
|
+
roleRefsByTarget.set(targetId, {
|
|
290
|
+
refs: opts.refs,
|
|
291
|
+
...(opts.frameSelector ? { frameSelector: opts.frameSelector } : {}),
|
|
292
|
+
mode: opts.mode,
|
|
293
|
+
});
|
|
294
|
+
// Limit cache size
|
|
295
|
+
while (roleRefsByTarget.size > MAX_ROLE_REFS_CACHE) {
|
|
296
|
+
const first = roleRefsByTarget.keys().next();
|
|
297
|
+
if (first.done)
|
|
298
|
+
break;
|
|
299
|
+
roleRefsByTarget.delete(first.value);
|
|
300
|
+
}
|
|
301
|
+
console.log(`[BROWSER] Stored ${Object.keys(opts.refs).length} refs for targetId "${targetId}"`);
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Restore role refs for a target (OpenClaw-style)
|
|
305
|
+
* Copies from global cache to page's WeakMap state
|
|
306
|
+
*/
|
|
307
|
+
function restoreRoleRefsForTarget(page, targetId) {
|
|
308
|
+
const tid = targetId?.trim() || "";
|
|
309
|
+
if (!tid)
|
|
310
|
+
return;
|
|
311
|
+
// Check if page already has refs (no need to restore)
|
|
312
|
+
const pageState = ensurePageState(page);
|
|
313
|
+
if (pageState.roleRefs) {
|
|
314
|
+
console.log(`[BROWSER] Page already has ${Object.keys(pageState.roleRefs).length} refs`);
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
// Try to restore from global cache
|
|
318
|
+
const cached = roleRefsByTarget.get(tid);
|
|
319
|
+
if (cached) {
|
|
320
|
+
pageState.roleRefs = cached.refs;
|
|
321
|
+
pageState.roleRefsFrameSelector = cached.frameSelector;
|
|
322
|
+
pageState.roleRefsMode = cached.mode;
|
|
323
|
+
console.log(`[BROWSER] Restored ${Object.keys(cached.refs).length} refs from cache for "${tid}"`);
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
// Fallback: try any targetId that has refs
|
|
327
|
+
for (const [storedTargetId, storedData] of roleRefsByTarget.entries()) {
|
|
328
|
+
if (Object.keys(storedData.refs).length > 0) {
|
|
329
|
+
pageState.roleRefs = storedData.refs;
|
|
330
|
+
pageState.roleRefsFrameSelector = storedData.frameSelector;
|
|
331
|
+
pageState.roleRefsMode = storedData.mode;
|
|
332
|
+
console.log(`[BROWSER] Restored ${Object.keys(storedData.refs).length} refs from "${storedTargetId}" (fallback)`);
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
console.log(`[BROWSER] No refs available to restore`);
|
|
337
|
+
}
|
|
338
|
+
function generateTargetId() {
|
|
339
|
+
return `page-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
340
|
+
}
|
|
341
|
+
async function startBrowser(options = {}) {
|
|
342
|
+
if (state.running) {
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
// Check if we should run in headless mode (default true, can be overridden by env var or param)
|
|
346
|
+
const headlessMode = options.headless ?? process.env.BROWSER_HEADLESS !== "false";
|
|
347
|
+
const launchOptions = {
|
|
348
|
+
headless: headlessMode,
|
|
349
|
+
args: ["--no-sandbox", "--disable-setuid-sandbox"],
|
|
350
|
+
};
|
|
351
|
+
// Support persistent profile directory
|
|
352
|
+
if (options.profilePath) {
|
|
353
|
+
console.log(`[BROWSER] Using profile: ${options.profilePath}`);
|
|
354
|
+
// For persistent context, we use launchPersistentContext instead
|
|
355
|
+
state.context = await chromium.launchPersistentContext(options.profilePath, {
|
|
356
|
+
...launchOptions,
|
|
357
|
+
viewport: { width: 1280, height: 720 },
|
|
358
|
+
userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",
|
|
359
|
+
});
|
|
360
|
+
state.browser = null; // Persistent context doesn't have separate browser
|
|
361
|
+
state.running = true;
|
|
362
|
+
state.connectionMode = "launched";
|
|
363
|
+
console.log(`[BROWSER] Started with persistent profile (headless: ${headlessMode})`);
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
console.log(`[BROWSER] Starting Chromium... (headless: ${headlessMode})`);
|
|
367
|
+
state.browser = await chromium.launch(launchOptions);
|
|
368
|
+
state.context = await state.browser.newContext({
|
|
369
|
+
viewport: { width: 1280, height: 720 },
|
|
370
|
+
userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",
|
|
371
|
+
});
|
|
372
|
+
state.running = true;
|
|
373
|
+
state.connectionMode = "launched";
|
|
374
|
+
console.log("[BROWSER] Started");
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Set up page event listeners (extracted for reuse)
|
|
378
|
+
*/
|
|
379
|
+
function setupPageListeners(page, targetId) {
|
|
380
|
+
let nextRequestId = 0;
|
|
381
|
+
const requestIds = new WeakMap();
|
|
382
|
+
// Capture console logs
|
|
383
|
+
page.on("console", (msg) => {
|
|
384
|
+
const logs = state.consoleLogs.get(targetId) || [];
|
|
385
|
+
logs.push(msg);
|
|
386
|
+
if (logs.length > 500)
|
|
387
|
+
logs.shift();
|
|
388
|
+
state.consoleLogs.set(targetId, logs);
|
|
389
|
+
});
|
|
390
|
+
// Capture page errors
|
|
391
|
+
page.on("pageerror", (err) => {
|
|
392
|
+
const errors = state.pageErrors.get(targetId) || [];
|
|
393
|
+
errors.push({
|
|
394
|
+
message: err?.message || String(err),
|
|
395
|
+
name: err?.name,
|
|
396
|
+
stack: err?.stack,
|
|
397
|
+
timestamp: new Date().toISOString(),
|
|
398
|
+
});
|
|
399
|
+
if (errors.length > 200)
|
|
400
|
+
errors.shift();
|
|
401
|
+
state.pageErrors.set(targetId, errors);
|
|
402
|
+
});
|
|
403
|
+
// Capture network requests
|
|
404
|
+
page.on("request", (req) => {
|
|
405
|
+
nextRequestId += 1;
|
|
406
|
+
const id = `r${nextRequestId}`;
|
|
407
|
+
requestIds.set(req, id);
|
|
408
|
+
const requests = state.networkRequests.get(targetId) || [];
|
|
409
|
+
requests.push({
|
|
410
|
+
id,
|
|
411
|
+
timestamp: new Date().toISOString(),
|
|
412
|
+
method: req.method(),
|
|
413
|
+
url: req.url(),
|
|
414
|
+
resourceType: req.resourceType(),
|
|
415
|
+
});
|
|
416
|
+
if (requests.length > 500)
|
|
417
|
+
requests.shift();
|
|
418
|
+
state.networkRequests.set(targetId, requests);
|
|
419
|
+
});
|
|
420
|
+
page.on("response", (resp) => {
|
|
421
|
+
const req = resp.request();
|
|
422
|
+
const id = requestIds.get(req);
|
|
423
|
+
if (!id)
|
|
424
|
+
return;
|
|
425
|
+
const requests = state.networkRequests.get(targetId) || [];
|
|
426
|
+
const rec = requests.find((r) => r.id === id);
|
|
427
|
+
if (rec) {
|
|
428
|
+
rec.status = resp.status();
|
|
429
|
+
rec.ok = resp.ok();
|
|
430
|
+
}
|
|
431
|
+
});
|
|
432
|
+
page.on("requestfailed", (req) => {
|
|
433
|
+
const id = requestIds.get(req);
|
|
434
|
+
if (!id)
|
|
435
|
+
return;
|
|
436
|
+
const requests = state.networkRequests.get(targetId) || [];
|
|
437
|
+
const rec = requests.find((r) => r.id === id);
|
|
438
|
+
if (rec) {
|
|
439
|
+
rec.failureText = req.failure()?.errorText;
|
|
440
|
+
rec.ok = false;
|
|
441
|
+
}
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
async function stopBrowser() {
|
|
445
|
+
if (!state.running) {
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
const isConnected = state.connectionMode === "connected";
|
|
449
|
+
console.log(`[BROWSER] Stopping... (mode: ${state.connectionMode})`);
|
|
450
|
+
// Close all pages we opened (but not pre-existing pages in CDP mode)
|
|
451
|
+
for (const [id, page] of state.pages.entries()) {
|
|
452
|
+
try {
|
|
453
|
+
await page.close();
|
|
454
|
+
}
|
|
455
|
+
catch (err) {
|
|
456
|
+
console.warn(`[BROWSER] Error closing page ${id}:`, err);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
state.pages.clear();
|
|
460
|
+
state.consoleLogs.clear();
|
|
461
|
+
state.networkRequests.clear();
|
|
462
|
+
state.pageErrors.clear();
|
|
463
|
+
roleRefsByTarget.clear(); // Clear the OpenClaw-style global cache
|
|
464
|
+
// For CDP connections, we disconnect but don't close the browser
|
|
465
|
+
if (isConnected) {
|
|
466
|
+
if (state.browser) {
|
|
467
|
+
// disconnect() keeps the browser running
|
|
468
|
+
state.browser.close(); // This disconnects for CDP
|
|
469
|
+
state.browser = null;
|
|
470
|
+
}
|
|
471
|
+
state.context = null;
|
|
472
|
+
state.wsEndpoint = undefined;
|
|
473
|
+
console.log("[BROWSER] Disconnected from CDP");
|
|
474
|
+
}
|
|
475
|
+
else {
|
|
476
|
+
// For launched browsers, close everything
|
|
477
|
+
if (state.context) {
|
|
478
|
+
await state.context.close();
|
|
479
|
+
state.context = null;
|
|
480
|
+
}
|
|
481
|
+
if (state.browser) {
|
|
482
|
+
await state.browser.close();
|
|
483
|
+
state.browser = null;
|
|
484
|
+
}
|
|
485
|
+
console.log("[BROWSER] Stopped");
|
|
486
|
+
}
|
|
487
|
+
state.running = false;
|
|
488
|
+
state.connectionMode = "launched";
|
|
489
|
+
}
|
|
490
|
+
async function openPage(url) {
|
|
491
|
+
if (!state.running || !state.context) {
|
|
492
|
+
await startBrowser();
|
|
493
|
+
}
|
|
494
|
+
const page = await state.context.newPage();
|
|
495
|
+
const targetId = generateTargetId();
|
|
496
|
+
state.pages.set(targetId, page);
|
|
497
|
+
state.consoleLogs.set(targetId, []);
|
|
498
|
+
state.networkRequests.set(targetId, []);
|
|
499
|
+
state.pageErrors.set(targetId, []);
|
|
500
|
+
// Track as last active tab
|
|
501
|
+
state.lastActiveTargetId = targetId;
|
|
502
|
+
// Set up event listeners
|
|
503
|
+
setupPageListeners(page, targetId);
|
|
504
|
+
await page.goto(url, { waitUntil: "domcontentloaded", timeout: 30000 });
|
|
505
|
+
return { targetId, page };
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Build role snapshot from Playwright's AI snapshot output (OpenClaw style)
|
|
509
|
+
* Preserves Playwright's own aria-ref ids (e.g. ref=e13)
|
|
510
|
+
*/
|
|
511
|
+
function buildRoleSnapshotFromAiSnapshot(aiSnapshot, options = {}) {
|
|
512
|
+
const lines = String(aiSnapshot ?? "").split("\n");
|
|
513
|
+
const refs = {};
|
|
514
|
+
const getIndentLevel = (line) => {
|
|
515
|
+
const match = line.match(/^(\s*)/);
|
|
516
|
+
return match ? Math.floor(match[1].length / 2) : 0;
|
|
517
|
+
};
|
|
518
|
+
const parseAiSnapshotRef = (suffix) => {
|
|
519
|
+
const match = suffix.match(/\[ref=(e\d+)\]/i);
|
|
520
|
+
return match ? match[1] : null;
|
|
521
|
+
};
|
|
522
|
+
if (options.interactive) {
|
|
523
|
+
const out = [];
|
|
524
|
+
for (const line of lines) {
|
|
525
|
+
const depth = getIndentLevel(line);
|
|
526
|
+
if (options.maxDepth !== undefined && depth > options.maxDepth)
|
|
527
|
+
continue;
|
|
528
|
+
const match = line.match(/^(\s*-\s*)(\w+)(?:\s+"([^"]*)")?(.*)$/);
|
|
529
|
+
if (!match)
|
|
530
|
+
continue;
|
|
531
|
+
const [, , roleRaw, name, suffix] = match;
|
|
532
|
+
if (roleRaw.startsWith("/"))
|
|
533
|
+
continue;
|
|
534
|
+
const role = roleRaw.toLowerCase();
|
|
535
|
+
if (!INTERACTIVE_ROLES.has(role))
|
|
536
|
+
continue;
|
|
537
|
+
const ref = parseAiSnapshotRef(suffix);
|
|
538
|
+
if (!ref)
|
|
539
|
+
continue;
|
|
540
|
+
refs[ref] = { role, ...(name ? { name } : {}) };
|
|
541
|
+
out.push(`- ${roleRaw}${name ? ` "${name}"` : ""}${suffix}`);
|
|
542
|
+
}
|
|
543
|
+
return {
|
|
544
|
+
snapshot: out.join("\n") || "(no interactive elements)",
|
|
545
|
+
refs,
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
const out = [];
|
|
549
|
+
for (const line of lines) {
|
|
550
|
+
const depth = getIndentLevel(line);
|
|
551
|
+
if (options.maxDepth !== undefined && depth > options.maxDepth)
|
|
552
|
+
continue;
|
|
553
|
+
const match = line.match(/^(\s*-\s*)(\w+)(?:\s+"([^"]*)")?(.*)$/);
|
|
554
|
+
if (!match) {
|
|
555
|
+
out.push(line);
|
|
556
|
+
continue;
|
|
557
|
+
}
|
|
558
|
+
const [, , roleRaw, name, suffix] = match;
|
|
559
|
+
if (roleRaw.startsWith("/")) {
|
|
560
|
+
out.push(line);
|
|
561
|
+
continue;
|
|
562
|
+
}
|
|
563
|
+
const role = roleRaw.toLowerCase();
|
|
564
|
+
const ref = parseAiSnapshotRef(suffix);
|
|
565
|
+
if (ref)
|
|
566
|
+
refs[ref] = { role, ...(name ? { name } : {}) };
|
|
567
|
+
out.push(line);
|
|
568
|
+
}
|
|
569
|
+
const tree = out.join("\n") || "(empty)";
|
|
570
|
+
return { snapshot: tree, refs };
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Get AI-formatted snapshot of page (OpenClaw-style)
|
|
574
|
+
* Uses Playwright's _snapshotForAI() for accurate role detection and ref building
|
|
575
|
+
* This captures the FULL accessibility tree including modals/overlays
|
|
576
|
+
*
|
|
577
|
+
* Ref modes:
|
|
578
|
+
* - "role" (default): Generates refs based on role+name from ariaSnapshot, requires snapshot context
|
|
579
|
+
* - "aria": Uses Playwright's aria-ref IDs, self-resolving across calls
|
|
580
|
+
*/
|
|
581
|
+
async function getAISnapshot(page, targetId, options) {
|
|
582
|
+
const maxChars = options.maxChars || 50000;
|
|
583
|
+
const labels = options.labels || false;
|
|
584
|
+
const refsMode = options.refs || "role";
|
|
585
|
+
let ariaSnapshotText = "";
|
|
586
|
+
let refsMap;
|
|
587
|
+
let roleSnapshot;
|
|
588
|
+
// OpenClaw-style: Two separate modes, NO fallback
|
|
589
|
+
if (refsMode === "aria") {
|
|
590
|
+
// refs="aria" mode: Use _snapshotForAI for self-resolving refs
|
|
591
|
+
// This captures the FULL accessibility tree including modals/overlays
|
|
592
|
+
if (options.selector || options.frame) {
|
|
593
|
+
throw new Error("refs=aria does not support selector/frame snapshots yet.");
|
|
594
|
+
}
|
|
595
|
+
const maybePage = page;
|
|
596
|
+
if (!maybePage._snapshotForAI) {
|
|
597
|
+
throw new Error("refs=aria requires Playwright _snapshotForAI support. Upgrade playwright-core.");
|
|
598
|
+
}
|
|
599
|
+
console.log(`[BROWSER] Using _snapshotForAI for aria mode (captures modals/overlays)`);
|
|
600
|
+
const result = await maybePage._snapshotForAI({
|
|
601
|
+
timeout: 5000,
|
|
602
|
+
track: "response",
|
|
603
|
+
});
|
|
604
|
+
ariaSnapshotText = String(result?.full ?? "");
|
|
605
|
+
console.log(`[BROWSER] _snapshotForAI returned ${ariaSnapshotText.length} chars`);
|
|
606
|
+
// Parse AI snapshot - refs are self-resolving via aria-ref=
|
|
607
|
+
const built = buildRoleSnapshotFromAiSnapshot(ariaSnapshotText, {
|
|
608
|
+
interactive: options.interactive,
|
|
609
|
+
maxDepth: options.maxDepth,
|
|
610
|
+
compact: options.compact,
|
|
611
|
+
});
|
|
612
|
+
refsMap = built.refs;
|
|
613
|
+
roleSnapshot = built.snapshot;
|
|
614
|
+
console.log(`[BROWSER] Aria mode - refs are self-resolving via aria-ref=`);
|
|
615
|
+
}
|
|
616
|
+
else {
|
|
617
|
+
// refs="role" mode (default): Use locator.ariaSnapshot()
|
|
618
|
+
// Refs are resolved via getByRole with the stored ref map
|
|
619
|
+
const frameSelector = options.frame?.trim() || "";
|
|
620
|
+
const selector = options.selector?.trim() || "";
|
|
621
|
+
const locator = frameSelector
|
|
622
|
+
? selector
|
|
623
|
+
? page.frameLocator(frameSelector).locator(selector)
|
|
624
|
+
: page.frameLocator(frameSelector).locator(":root")
|
|
625
|
+
: selector
|
|
626
|
+
? page.locator(selector)
|
|
627
|
+
: page.locator(":root");
|
|
628
|
+
console.log(`[BROWSER] Using ariaSnapshot() for role mode`);
|
|
629
|
+
ariaSnapshotText = await locator.ariaSnapshot();
|
|
630
|
+
console.log(`[BROWSER] ariaSnapshot() returned ${ariaSnapshotText.length} chars`);
|
|
631
|
+
// Parse aria snapshot - we generate refs that require role map for resolution
|
|
632
|
+
const built = buildRoleSnapshotFromAriaSnapshot(ariaSnapshotText, {
|
|
633
|
+
interactive: options.interactive,
|
|
634
|
+
maxDepth: options.maxDepth,
|
|
635
|
+
compact: options.compact,
|
|
636
|
+
});
|
|
637
|
+
refsMap = built.refs;
|
|
638
|
+
roleSnapshot = built.snapshot;
|
|
639
|
+
console.log(`[BROWSER] Role mode - refs require role map for resolution`);
|
|
640
|
+
}
|
|
641
|
+
// Step 2: Store refs using OpenClaw-style function (stores to BOTH WeakMap and global cache)
|
|
642
|
+
console.log(`[BROWSER] Snapshot generated ${Object.keys(refsMap).length} refs for targetId "${targetId}"`);
|
|
643
|
+
if (Object.keys(refsMap).length > 0) {
|
|
644
|
+
storeRoleRefsForTarget({
|
|
645
|
+
page,
|
|
646
|
+
targetId,
|
|
647
|
+
refs: refsMap,
|
|
648
|
+
frameSelector: options.frame,
|
|
649
|
+
mode: refsMode,
|
|
650
|
+
});
|
|
651
|
+
console.log(`[BROWSER] Stored refs with mode="${refsMode}". Sample: ${Object.keys(refsMap).slice(0, 5).join(", ")}`);
|
|
652
|
+
}
|
|
653
|
+
else {
|
|
654
|
+
console.log(`[BROWSER] WARNING: No refs generated from snapshot. Snapshot length: ${ariaSnapshotText.length}`);
|
|
655
|
+
console.log(`[BROWSER] Snapshot preview: ${ariaSnapshotText.slice(0, 500)}`);
|
|
656
|
+
}
|
|
657
|
+
// Step 4: If labels requested, create labeled screenshot using stored refs
|
|
658
|
+
let imagePath;
|
|
659
|
+
let labelsCount = 0;
|
|
660
|
+
if (labels && Object.keys(refsMap).length > 0) {
|
|
661
|
+
const maxLabels = 150;
|
|
662
|
+
const viewport = await page.evaluate(() => ({
|
|
663
|
+
scrollX: window.scrollX || 0,
|
|
664
|
+
scrollY: window.scrollY || 0,
|
|
665
|
+
width: window.innerWidth || 0,
|
|
666
|
+
height: window.innerHeight || 0,
|
|
667
|
+
}));
|
|
668
|
+
const refs = Object.keys(refsMap);
|
|
669
|
+
const boxes = [];
|
|
670
|
+
let skipped = 0;
|
|
671
|
+
// Get bounding boxes using role-based locators (OpenClaw style)
|
|
672
|
+
for (const ref of refs) {
|
|
673
|
+
if (boxes.length >= maxLabels) {
|
|
674
|
+
skipped += 1;
|
|
675
|
+
continue;
|
|
676
|
+
}
|
|
677
|
+
try {
|
|
678
|
+
const info = refsMap[ref];
|
|
679
|
+
let refLocator;
|
|
680
|
+
if (info.name) {
|
|
681
|
+
refLocator = page.getByRole(info.role, { name: info.name, exact: true });
|
|
682
|
+
if (info.nth !== undefined)
|
|
683
|
+
refLocator = refLocator.nth(info.nth);
|
|
684
|
+
}
|
|
685
|
+
else {
|
|
686
|
+
refLocator = page.getByRole(info.role);
|
|
687
|
+
if (info.nth !== undefined)
|
|
688
|
+
refLocator = refLocator.nth(info.nth);
|
|
689
|
+
}
|
|
690
|
+
const box = await refLocator.boundingBox();
|
|
691
|
+
if (!box) {
|
|
692
|
+
skipped += 1;
|
|
693
|
+
continue;
|
|
694
|
+
}
|
|
695
|
+
// Check if in viewport
|
|
696
|
+
const x0 = box.x;
|
|
697
|
+
const y0 = box.y;
|
|
698
|
+
const x1 = box.x + box.width;
|
|
699
|
+
const y1 = box.y + box.height;
|
|
700
|
+
const vx0 = viewport.scrollX;
|
|
701
|
+
const vy0 = viewport.scrollY;
|
|
702
|
+
const vx1 = viewport.scrollX + viewport.width;
|
|
703
|
+
const vy1 = viewport.scrollY + viewport.height;
|
|
704
|
+
if (x1 < vx0 || x0 > vx1 || y1 < vy0 || y0 > vy1) {
|
|
705
|
+
skipped += 1;
|
|
706
|
+
continue;
|
|
707
|
+
}
|
|
708
|
+
boxes.push({
|
|
709
|
+
ref,
|
|
710
|
+
x: x0 - viewport.scrollX,
|
|
711
|
+
y: y0 - viewport.scrollY,
|
|
712
|
+
w: Math.max(1, box.width),
|
|
713
|
+
h: Math.max(1, box.height),
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
catch {
|
|
717
|
+
skipped += 1;
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
labelsCount = boxes.length;
|
|
721
|
+
try {
|
|
722
|
+
if (boxes.length > 0) {
|
|
723
|
+
// Inject labels overlay (OpenClaw style)
|
|
724
|
+
await page.evaluate((labelBoxes) => {
|
|
725
|
+
const existing = document.querySelectorAll("[data-browser-labels]");
|
|
726
|
+
existing.forEach((el) => el.remove());
|
|
727
|
+
const root = document.createElement("div");
|
|
728
|
+
root.setAttribute("data-browser-labels", "1");
|
|
729
|
+
root.style.position = "fixed";
|
|
730
|
+
root.style.left = "0";
|
|
731
|
+
root.style.top = "0";
|
|
732
|
+
root.style.zIndex = "2147483647";
|
|
733
|
+
root.style.pointerEvents = "none";
|
|
734
|
+
root.style.fontFamily = '"SF Mono","SFMono-Regular",Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace';
|
|
735
|
+
for (const label of labelBoxes) {
|
|
736
|
+
const box = document.createElement("div");
|
|
737
|
+
box.setAttribute("data-browser-labels", "1");
|
|
738
|
+
box.style.position = "absolute";
|
|
739
|
+
box.style.left = `${label.x}px`;
|
|
740
|
+
box.style.top = `${label.y}px`;
|
|
741
|
+
box.style.width = `${label.w}px`;
|
|
742
|
+
box.style.height = `${label.h}px`;
|
|
743
|
+
box.style.border = "2px solid #ffb020";
|
|
744
|
+
box.style.boxSizing = "border-box";
|
|
745
|
+
const tag = document.createElement("div");
|
|
746
|
+
tag.setAttribute("data-browser-labels", "1");
|
|
747
|
+
tag.textContent = label.ref;
|
|
748
|
+
tag.style.position = "absolute";
|
|
749
|
+
tag.style.left = `${label.x}px`;
|
|
750
|
+
tag.style.top = `${Math.min(20000, Math.max(0, label.y - 18))}px`;
|
|
751
|
+
tag.style.background = "#ffb020";
|
|
752
|
+
tag.style.color = "#1a1a1a";
|
|
753
|
+
tag.style.fontSize = "12px";
|
|
754
|
+
tag.style.lineHeight = "14px";
|
|
755
|
+
tag.style.padding = "1px 4px";
|
|
756
|
+
tag.style.borderRadius = "3px";
|
|
757
|
+
tag.style.boxShadow = "0 1px 2px rgba(0,0,0,0.35)";
|
|
758
|
+
tag.style.whiteSpace = "nowrap";
|
|
759
|
+
root.appendChild(box);
|
|
760
|
+
root.appendChild(tag);
|
|
761
|
+
}
|
|
762
|
+
document.documentElement.appendChild(root);
|
|
763
|
+
}, boxes);
|
|
764
|
+
}
|
|
765
|
+
// Take screenshot
|
|
766
|
+
const screenshot = await page.screenshot({ type: "png" });
|
|
767
|
+
// Save to temp file
|
|
768
|
+
const fs = await import("fs/promises");
|
|
769
|
+
const path = await import("path");
|
|
770
|
+
const tmpDir = await import("os").then((os) => os.tmpdir());
|
|
771
|
+
const filename = `browser-snapshot-${Date.now()}.png`;
|
|
772
|
+
imagePath = path.join(tmpDir, filename);
|
|
773
|
+
await fs.writeFile(imagePath, screenshot);
|
|
774
|
+
}
|
|
775
|
+
finally {
|
|
776
|
+
// Clean up labels
|
|
777
|
+
await page.evaluate(() => {
|
|
778
|
+
const existing = document.querySelectorAll("[data-browser-labels]");
|
|
779
|
+
existing.forEach((el) => el.remove());
|
|
780
|
+
}).catch(() => { });
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
// Step 5: Build final snapshot text
|
|
784
|
+
const title = await page.title().catch(() => "");
|
|
785
|
+
const url = page.url();
|
|
786
|
+
let snapshot = `# ${title}\n\nURL: ${url}\n\n`;
|
|
787
|
+
if (roleSnapshot && roleSnapshot !== "(empty)") {
|
|
788
|
+
snapshot += "## Accessibility Tree\n";
|
|
789
|
+
snapshot += roleSnapshot;
|
|
790
|
+
snapshot += "\n\n";
|
|
791
|
+
}
|
|
792
|
+
// Truncate if needed
|
|
793
|
+
if (snapshot.length > maxChars) {
|
|
794
|
+
snapshot = snapshot.slice(0, maxChars) + "\n\n... (content truncated)";
|
|
795
|
+
}
|
|
796
|
+
return {
|
|
797
|
+
snapshot,
|
|
798
|
+
imagePath,
|
|
799
|
+
labelsCount,
|
|
800
|
+
refs: Object.keys(refsMap).length > 0 ? refsMap : undefined,
|
|
801
|
+
targetId,
|
|
802
|
+
};
|
|
803
|
+
}
|
|
804
|
+
/**
|
|
805
|
+
* Resolve a ref to a Playwright locator (OpenClaw-style)
|
|
806
|
+
* Uses stored role+name info instead of DOM attributes for stability across navigation
|
|
807
|
+
*/
|
|
808
|
+
/**
|
|
809
|
+
* Normalize timeout to safe range (OpenClaw-style exact copy)
|
|
810
|
+
* From: pw-tools-core.shared.ts - uses 120s max instead of 60s
|
|
811
|
+
*/
|
|
812
|
+
function normalizeTimeoutMs(timeoutMs, fallback) {
|
|
813
|
+
return Math.max(500, Math.min(120_000, timeoutMs ?? fallback));
|
|
814
|
+
}
|
|
815
|
+
/**
|
|
816
|
+
* Resolve ref to locator (OpenClaw-style)
|
|
817
|
+
* Reads from page's WeakMap state (restoreRoleRefsForTarget must be called first)
|
|
818
|
+
*/
|
|
819
|
+
function refLocator(page, ref) {
|
|
820
|
+
// Normalize ref (remove @ or ref= prefix if present) - OpenClaw style
|
|
821
|
+
const normalized = ref.startsWith("@")
|
|
822
|
+
? ref.slice(1)
|
|
823
|
+
: ref.startsWith("ref=")
|
|
824
|
+
? ref.slice(4)
|
|
825
|
+
: ref;
|
|
826
|
+
// Check if it's an element ref (e1, e2, etc.)
|
|
827
|
+
if (/^e\d+$/.test(normalized)) {
|
|
828
|
+
// Read from page's WeakMap state (OpenClaw-style)
|
|
829
|
+
const pageState = pageStates.get(page);
|
|
830
|
+
// Handle aria mode - refs are self-resolving via aria-ref= syntax
|
|
831
|
+
if (pageState?.roleRefsMode === "aria") {
|
|
832
|
+
const scope = pageState.roleRefsFrameSelector
|
|
833
|
+
? page.frameLocator(pageState.roleRefsFrameSelector)
|
|
834
|
+
: page;
|
|
835
|
+
return scope.locator(`aria-ref=${normalized}`);
|
|
836
|
+
}
|
|
837
|
+
// Role mode: Get ref info from page state
|
|
838
|
+
const info = pageState?.roleRefs?.[normalized];
|
|
839
|
+
if (!info) {
|
|
840
|
+
throw new Error(`Element "${normalized}" not found or not visible. ` +
|
|
841
|
+
`Run a new snapshot to see current page elements.`);
|
|
842
|
+
}
|
|
843
|
+
// Build locator using getByRole (OpenClaw-style)
|
|
844
|
+
const scope = pageState?.roleRefsFrameSelector
|
|
845
|
+
? page.frameLocator(pageState.roleRefsFrameSelector)
|
|
846
|
+
: page;
|
|
847
|
+
const locAny = scope;
|
|
848
|
+
const locator = info.name
|
|
849
|
+
? locAny.getByRole(info.role, { name: info.name, exact: true })
|
|
850
|
+
: locAny.getByRole(info.role);
|
|
851
|
+
return info.nth !== undefined ? locator.nth(info.nth) : locator;
|
|
852
|
+
}
|
|
853
|
+
// Not an element ref - treat as aria-ref (OpenClaw-style)
|
|
854
|
+
return page.locator(`aria-ref=${normalized}`);
|
|
855
|
+
}
|
|
856
|
+
/**
|
|
857
|
+
* Transform Playwright errors into AI-friendly messages (OpenClaw-style exact copy)
|
|
858
|
+
* From: pw-tools-core.shared.ts
|
|
859
|
+
*/
|
|
860
|
+
function toAIFriendlyError(error, selector) {
|
|
861
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
862
|
+
// Multiple elements matched
|
|
863
|
+
if (message.includes("strict mode violation")) {
|
|
864
|
+
const countMatch = message.match(/resolved to (\d+) elements/);
|
|
865
|
+
const count = countMatch ? countMatch[1] : "multiple";
|
|
866
|
+
return new Error(`Selector "${selector}" matched ${count} elements. ` +
|
|
867
|
+
`Run a new snapshot to get updated refs, or use a different ref.`);
|
|
868
|
+
}
|
|
869
|
+
// Element not found or not visible
|
|
870
|
+
if ((message.includes("Timeout") || message.includes("waiting for")) &&
|
|
871
|
+
(message.includes("to be visible") || message.includes("not visible"))) {
|
|
872
|
+
return new Error(`Element "${selector}" not found or not visible. ` +
|
|
873
|
+
`Run a new snapshot to see current page elements.`);
|
|
874
|
+
}
|
|
875
|
+
// Element covered by overlay or not interactable (OpenClaw exact)
|
|
876
|
+
if (message.includes("intercepts pointer events") ||
|
|
877
|
+
message.includes("not visible") ||
|
|
878
|
+
message.includes("not receive pointer events")) {
|
|
879
|
+
return new Error(`Element "${selector}" is not interactable (hidden or covered). ` +
|
|
880
|
+
`Try scrolling it into view, closing overlays, or re-snapshotting.`);
|
|
881
|
+
}
|
|
882
|
+
return error instanceof Error ? error : new Error(message);
|
|
883
|
+
}
|
|
884
|
+
/**
|
|
885
|
+
* Execute browser automation action (act)
|
|
886
|
+
*/
|
|
887
|
+
async function executeBrowserAct(page, request, targetId = "default") {
|
|
888
|
+
const kind = request.kind;
|
|
889
|
+
// OpenClaw-style: Restore refs for this target before any action
|
|
890
|
+
restoreRoleRefsForTarget(page, targetId);
|
|
891
|
+
switch (kind) {
|
|
892
|
+
case "click": {
|
|
893
|
+
const ref = request.ref;
|
|
894
|
+
const doubleClick = request.doubleClick;
|
|
895
|
+
const button = request.button || "left";
|
|
896
|
+
const modifiers = request.modifiers || [];
|
|
897
|
+
const force = request.force;
|
|
898
|
+
// OpenClaw uses normalizeTimeoutMs with 8000ms default
|
|
899
|
+
const timeout = normalizeTimeoutMs(request.timeoutMs, 8000);
|
|
900
|
+
if (!ref)
|
|
901
|
+
throw new Error("ref is required for click action");
|
|
902
|
+
const locator = refLocator(page, ref);
|
|
903
|
+
try {
|
|
904
|
+
if (doubleClick) {
|
|
905
|
+
await locator.dblclick({
|
|
906
|
+
timeout,
|
|
907
|
+
button: button,
|
|
908
|
+
modifiers: modifiers,
|
|
909
|
+
force: force ?? false,
|
|
910
|
+
});
|
|
911
|
+
}
|
|
912
|
+
else {
|
|
913
|
+
await locator.click({
|
|
914
|
+
timeout,
|
|
915
|
+
button: button,
|
|
916
|
+
modifiers: modifiers,
|
|
917
|
+
force: force ?? false,
|
|
918
|
+
});
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
catch (err) {
|
|
922
|
+
throw toAIFriendlyError(err, ref);
|
|
923
|
+
}
|
|
924
|
+
return { ok: true };
|
|
925
|
+
}
|
|
926
|
+
case "type": {
|
|
927
|
+
const ref = request.ref;
|
|
928
|
+
const text = String(request.text ?? "");
|
|
929
|
+
const submit = request.submit;
|
|
930
|
+
const slowly = request.slowly;
|
|
931
|
+
const timeout = normalizeTimeoutMs(request.timeoutMs, 8000);
|
|
932
|
+
if (!ref)
|
|
933
|
+
throw new Error("ref is required for type action");
|
|
934
|
+
const locator = refLocator(page, ref);
|
|
935
|
+
try {
|
|
936
|
+
// OpenClaw: slowly mode clicks first, then types with delay
|
|
937
|
+
if (slowly) {
|
|
938
|
+
await locator.click({ timeout });
|
|
939
|
+
await locator.type(text, { timeout, delay: 75 });
|
|
940
|
+
}
|
|
941
|
+
else {
|
|
942
|
+
await locator.fill(text, { timeout });
|
|
943
|
+
}
|
|
944
|
+
if (submit) {
|
|
945
|
+
await locator.press("Enter", { timeout });
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
catch (err) {
|
|
949
|
+
throw toAIFriendlyError(err, ref);
|
|
950
|
+
}
|
|
951
|
+
return { ok: true };
|
|
952
|
+
}
|
|
953
|
+
case "press": {
|
|
954
|
+
const key = String(request.key ?? "").trim();
|
|
955
|
+
if (!key)
|
|
956
|
+
throw new Error("key is required for press action");
|
|
957
|
+
const delayMs = Math.max(0, Math.floor(request.delayMs ?? 0));
|
|
958
|
+
await page.keyboard.press(key, { delay: delayMs });
|
|
959
|
+
return { ok: true };
|
|
960
|
+
}
|
|
961
|
+
case "hover": {
|
|
962
|
+
const ref = request.ref;
|
|
963
|
+
const timeout = normalizeTimeoutMs(request.timeoutMs, 8000);
|
|
964
|
+
if (!ref)
|
|
965
|
+
throw new Error("ref is required for hover action");
|
|
966
|
+
const locator = refLocator(page, ref);
|
|
967
|
+
try {
|
|
968
|
+
await locator.hover({ timeout });
|
|
969
|
+
}
|
|
970
|
+
catch (err) {
|
|
971
|
+
throw toAIFriendlyError(err, ref);
|
|
972
|
+
}
|
|
973
|
+
return { ok: true };
|
|
974
|
+
}
|
|
975
|
+
case "drag": {
|
|
976
|
+
const startRef = request.startRef;
|
|
977
|
+
const endRef = request.endRef;
|
|
978
|
+
const timeout = normalizeTimeoutMs(request.timeoutMs, 8000);
|
|
979
|
+
if (!startRef)
|
|
980
|
+
throw new Error("startRef is required for drag action");
|
|
981
|
+
if (!endRef)
|
|
982
|
+
throw new Error("endRef is required for drag action");
|
|
983
|
+
const startLocator = refLocator(page, startRef);
|
|
984
|
+
const endLocator = refLocator(page, endRef);
|
|
985
|
+
try {
|
|
986
|
+
// OpenClaw uses dragTo() method
|
|
987
|
+
await startLocator.dragTo(endLocator, { timeout });
|
|
988
|
+
}
|
|
989
|
+
catch (err) {
|
|
990
|
+
throw toAIFriendlyError(err, `${startRef} -> ${endRef}`);
|
|
991
|
+
}
|
|
992
|
+
return { ok: true };
|
|
993
|
+
}
|
|
994
|
+
case "select": {
|
|
995
|
+
const ref = request.ref;
|
|
996
|
+
const values = request.values;
|
|
997
|
+
const timeout = normalizeTimeoutMs(request.timeoutMs, 8000);
|
|
998
|
+
if (!ref)
|
|
999
|
+
throw new Error("ref is required for select action");
|
|
1000
|
+
if (!values || !Array.isArray(values))
|
|
1001
|
+
throw new Error("values array is required for select action");
|
|
1002
|
+
const locator = refLocator(page, ref);
|
|
1003
|
+
try {
|
|
1004
|
+
await locator.selectOption(values, { timeout });
|
|
1005
|
+
}
|
|
1006
|
+
catch (err) {
|
|
1007
|
+
throw toAIFriendlyError(err, ref);
|
|
1008
|
+
}
|
|
1009
|
+
return { ok: true };
|
|
1010
|
+
}
|
|
1011
|
+
case "fill": {
|
|
1012
|
+
// OpenClaw-style form filling with checkbox/radio support
|
|
1013
|
+
const fields = request.fields;
|
|
1014
|
+
if (!fields || !Array.isArray(fields))
|
|
1015
|
+
throw new Error("fields array is required for fill action");
|
|
1016
|
+
const timeout = normalizeTimeoutMs(request.timeoutMs, 8000);
|
|
1017
|
+
for (const field of fields) {
|
|
1018
|
+
const ref = String(field.ref ?? "").trim();
|
|
1019
|
+
const type = String(field.type ?? "").trim();
|
|
1020
|
+
const rawValue = field.value;
|
|
1021
|
+
const value = typeof rawValue === "string"
|
|
1022
|
+
? rawValue
|
|
1023
|
+
: typeof rawValue === "number" || typeof rawValue === "boolean"
|
|
1024
|
+
? String(rawValue)
|
|
1025
|
+
: "";
|
|
1026
|
+
if (!ref)
|
|
1027
|
+
continue;
|
|
1028
|
+
const locator = refLocator(page, ref);
|
|
1029
|
+
try {
|
|
1030
|
+
// OpenClaw: handle checkbox/radio with setChecked
|
|
1031
|
+
if (type === "checkbox" || type === "radio") {
|
|
1032
|
+
const checked = rawValue === true || rawValue === 1 || rawValue === "1" || rawValue === "true";
|
|
1033
|
+
await locator.setChecked(checked, { timeout });
|
|
1034
|
+
continue;
|
|
1035
|
+
}
|
|
1036
|
+
await locator.fill(value, { timeout });
|
|
1037
|
+
}
|
|
1038
|
+
catch (err) {
|
|
1039
|
+
throw toAIFriendlyError(err, ref);
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
return { ok: true };
|
|
1043
|
+
}
|
|
1044
|
+
case "resize": {
|
|
1045
|
+
const width = request.width;
|
|
1046
|
+
const height = request.height;
|
|
1047
|
+
await page.setViewportSize({ width, height });
|
|
1048
|
+
return { ok: true };
|
|
1049
|
+
}
|
|
1050
|
+
case "wait": {
|
|
1051
|
+
const timeMs = request.timeMs;
|
|
1052
|
+
const text = request.text;
|
|
1053
|
+
const textGone = request.textGone;
|
|
1054
|
+
const selector = request.selector;
|
|
1055
|
+
const url = request.url;
|
|
1056
|
+
const loadState = request.loadState;
|
|
1057
|
+
const fn = request.fn;
|
|
1058
|
+
// OpenClaw uses 20000ms default for wait (normalizeTimeoutMs uses 120s max)
|
|
1059
|
+
const timeout = normalizeTimeoutMs(request.timeoutMs, 20000);
|
|
1060
|
+
if (typeof timeMs === "number" && Number.isFinite(timeMs)) {
|
|
1061
|
+
// Wait for specific time
|
|
1062
|
+
await page.waitForTimeout(Math.max(0, timeMs));
|
|
1063
|
+
}
|
|
1064
|
+
if (text) {
|
|
1065
|
+
// Wait for text to appear (OpenClaw uses getByText, not waitForSelector)
|
|
1066
|
+
await page.getByText(text).first().waitFor({ state: "visible", timeout });
|
|
1067
|
+
}
|
|
1068
|
+
if (textGone) {
|
|
1069
|
+
// Wait for text to disappear
|
|
1070
|
+
await page.getByText(textGone).first().waitFor({ state: "hidden", timeout });
|
|
1071
|
+
}
|
|
1072
|
+
if (selector) {
|
|
1073
|
+
// Wait for selector
|
|
1074
|
+
const sel = String(selector).trim();
|
|
1075
|
+
if (sel) {
|
|
1076
|
+
await page.locator(sel).first().waitFor({ state: "visible", timeout });
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
if (url) {
|
|
1080
|
+
// Wait for URL pattern
|
|
1081
|
+
const urlPattern = String(url).trim();
|
|
1082
|
+
if (urlPattern) {
|
|
1083
|
+
await page.waitForURL(urlPattern, { timeout });
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
if (fn) {
|
|
1087
|
+
// Wait for JavaScript function to return true
|
|
1088
|
+
const fnStr = String(fn).trim();
|
|
1089
|
+
if (fnStr) {
|
|
1090
|
+
await page.waitForFunction(fnStr, { timeout });
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
if (loadState) {
|
|
1094
|
+
// Wait for specific load state
|
|
1095
|
+
await page.waitForLoadState(loadState, { timeout });
|
|
1096
|
+
}
|
|
1097
|
+
return { ok: true };
|
|
1098
|
+
}
|
|
1099
|
+
case "evaluate": {
|
|
1100
|
+
// OpenClaw-style evaluate using Function constructor
|
|
1101
|
+
// This avoids esbuild adding __name helper which doesn't exist in browser
|
|
1102
|
+
const fnText = String(request.fn ?? "").trim();
|
|
1103
|
+
const ref = request.ref;
|
|
1104
|
+
if (!fnText)
|
|
1105
|
+
throw new Error("fn is required for evaluate action");
|
|
1106
|
+
if (ref) {
|
|
1107
|
+
// Evaluate with element context
|
|
1108
|
+
const locator = refLocator(page, ref);
|
|
1109
|
+
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
|
1110
|
+
const elementEvaluator = new Function("el", "fnBody", `
|
|
1111
|
+
"use strict";
|
|
1112
|
+
try {
|
|
1113
|
+
var candidate = eval("(" + fnBody + ")");
|
|
1114
|
+
return typeof candidate === "function" ? candidate(el) : candidate;
|
|
1115
|
+
} catch (err) {
|
|
1116
|
+
throw new Error("Invalid evaluate function: " + (err && err.message ? err.message : String(err)));
|
|
1117
|
+
}
|
|
1118
|
+
`);
|
|
1119
|
+
const result = await locator.evaluate(elementEvaluator, fnText);
|
|
1120
|
+
return { ok: true, result };
|
|
1121
|
+
}
|
|
1122
|
+
// Evaluate in page context (no element)
|
|
1123
|
+
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
|
1124
|
+
const browserEvaluator = new Function("fnBody", `
|
|
1125
|
+
"use strict";
|
|
1126
|
+
try {
|
|
1127
|
+
var candidate = eval("(" + fnBody + ")");
|
|
1128
|
+
return typeof candidate === "function" ? candidate() : candidate;
|
|
1129
|
+
} catch (err) {
|
|
1130
|
+
throw new Error("Invalid evaluate function: " + (err && err.message ? err.message : String(err)));
|
|
1131
|
+
}
|
|
1132
|
+
`);
|
|
1133
|
+
const result = await page.evaluate(browserEvaluator, fnText);
|
|
1134
|
+
return { ok: true, result };
|
|
1135
|
+
}
|
|
1136
|
+
case "close": {
|
|
1137
|
+
await page.close();
|
|
1138
|
+
return { ok: true };
|
|
1139
|
+
}
|
|
1140
|
+
default:
|
|
1141
|
+
throw new Error(`Unknown act kind: ${kind}`);
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
/**
|
|
1145
|
+
* Create image result from file (base64 encoded)
|
|
1146
|
+
*/
|
|
1147
|
+
async function imageResultFromFile(options) {
|
|
1148
|
+
const fs = await import("fs/promises");
|
|
1149
|
+
const buffer = await fs.readFile(options.path);
|
|
1150
|
+
const base64 = buffer.toString("base64");
|
|
1151
|
+
const content = [];
|
|
1152
|
+
if (options.extraText) {
|
|
1153
|
+
content.push({
|
|
1154
|
+
type: "text",
|
|
1155
|
+
text: options.extraText,
|
|
1156
|
+
});
|
|
1157
|
+
}
|
|
1158
|
+
content.push({
|
|
1159
|
+
type: "image",
|
|
1160
|
+
data: base64,
|
|
1161
|
+
mimeType: "image/png",
|
|
1162
|
+
});
|
|
1163
|
+
return {
|
|
1164
|
+
content,
|
|
1165
|
+
details: options.details,
|
|
1166
|
+
};
|
|
1167
|
+
}
|
|
1168
|
+
export function createBrowserTool() {
|
|
1169
|
+
return {
|
|
1170
|
+
name: "browser",
|
|
1171
|
+
label: "Browser",
|
|
1172
|
+
// OpenClaw exact description (from browser-tool.ts)
|
|
1173
|
+
description: [
|
|
1174
|
+
"Control the browser via Playwright (status/start/stop/profiles/tabs/open/snapshot/screenshot/actions).",
|
|
1175
|
+
"When using refs from snapshot (e.g. e12), keep the same tab: prefer passing targetId from the snapshot response into subsequent actions (act/click/type/etc).",
|
|
1176
|
+
'For stable, self-resolving refs across calls, use snapshot with refs="aria" (Playwright aria-ref ids). Default refs="role" are role+name-based.',
|
|
1177
|
+
"Use snapshot+act for UI automation. Avoid act:wait by default; use only in exceptional cases when no reliable UI state exists.",
|
|
1178
|
+
].join(" "),
|
|
1179
|
+
parameters: BrowserSchema,
|
|
1180
|
+
execute: async (_toolCallId, params) => {
|
|
1181
|
+
const action = readStringParam(params, "action", { required: true });
|
|
1182
|
+
try {
|
|
1183
|
+
switch (action) {
|
|
1184
|
+
case "status":
|
|
1185
|
+
return jsonResult({
|
|
1186
|
+
running: state.running,
|
|
1187
|
+
connectionMode: state.connectionMode,
|
|
1188
|
+
wsEndpoint: state.wsEndpoint,
|
|
1189
|
+
tabCount: state.pages.size,
|
|
1190
|
+
tabs: Array.from(state.pages.keys()),
|
|
1191
|
+
});
|
|
1192
|
+
case "start": {
|
|
1193
|
+
const headless = readBooleanParam(params, "headless");
|
|
1194
|
+
const profilePath = readStringParam(params, "profilePath");
|
|
1195
|
+
await startBrowser({
|
|
1196
|
+
headless: headless ?? undefined,
|
|
1197
|
+
profilePath: profilePath ?? undefined,
|
|
1198
|
+
});
|
|
1199
|
+
return jsonResult({
|
|
1200
|
+
running: state.running,
|
|
1201
|
+
connectionMode: state.connectionMode,
|
|
1202
|
+
message: profilePath
|
|
1203
|
+
? `Browser started with profile: ${profilePath}`
|
|
1204
|
+
: "Browser started successfully",
|
|
1205
|
+
});
|
|
1206
|
+
}
|
|
1207
|
+
case "stop":
|
|
1208
|
+
await stopBrowser();
|
|
1209
|
+
return jsonResult({
|
|
1210
|
+
running: state.running,
|
|
1211
|
+
message: state.connectionMode === "connected"
|
|
1212
|
+
? "Disconnected from browser"
|
|
1213
|
+
: "Browser stopped successfully",
|
|
1214
|
+
});
|
|
1215
|
+
case "profiles": {
|
|
1216
|
+
// OpenClaw has profiles - we just return a simple response
|
|
1217
|
+
return jsonResult({
|
|
1218
|
+
profiles: ["default"],
|
|
1219
|
+
message: "Single default profile available",
|
|
1220
|
+
});
|
|
1221
|
+
}
|
|
1222
|
+
case "tabs": {
|
|
1223
|
+
if (!state.running || state.pages.size === 0) {
|
|
1224
|
+
return jsonResult({ tabs: [], message: "No tabs open" });
|
|
1225
|
+
}
|
|
1226
|
+
const tabs = await Promise.all(Array.from(state.pages.entries()).map(async ([id, page]) => {
|
|
1227
|
+
try {
|
|
1228
|
+
return {
|
|
1229
|
+
targetId: id,
|
|
1230
|
+
title: await page.title(),
|
|
1231
|
+
url: page.url(),
|
|
1232
|
+
};
|
|
1233
|
+
}
|
|
1234
|
+
catch (err) {
|
|
1235
|
+
return {
|
|
1236
|
+
targetId: id,
|
|
1237
|
+
title: "(error)",
|
|
1238
|
+
url: "(error)",
|
|
1239
|
+
error: String(err),
|
|
1240
|
+
};
|
|
1241
|
+
}
|
|
1242
|
+
}));
|
|
1243
|
+
return jsonResult({ tabs });
|
|
1244
|
+
}
|
|
1245
|
+
case "open": {
|
|
1246
|
+
const targetUrl = readStringParam(params, "targetUrl", { required: true });
|
|
1247
|
+
const { targetId: newTargetId, page } = await openPage(targetUrl);
|
|
1248
|
+
return jsonResult({
|
|
1249
|
+
targetId: newTargetId,
|
|
1250
|
+
url: page.url(),
|
|
1251
|
+
title: await page.title(),
|
|
1252
|
+
message: `Opened ${targetUrl} in new tab`,
|
|
1253
|
+
});
|
|
1254
|
+
}
|
|
1255
|
+
case "focus": {
|
|
1256
|
+
const targetId = readStringParam(params, "targetId", { required: true });
|
|
1257
|
+
const page = state.pages.get(targetId);
|
|
1258
|
+
if (!page) {
|
|
1259
|
+
throw new Error(`Tab ${targetId} not found. Run action=tabs to see available tabs.`);
|
|
1260
|
+
}
|
|
1261
|
+
await page.bringToFront();
|
|
1262
|
+
return jsonResult({
|
|
1263
|
+
ok: true,
|
|
1264
|
+
targetId,
|
|
1265
|
+
message: `Focused tab ${targetId}`,
|
|
1266
|
+
});
|
|
1267
|
+
}
|
|
1268
|
+
case "navigate": {
|
|
1269
|
+
const targetUrl = readStringParam(params, "targetUrl", { required: true });
|
|
1270
|
+
const targetId = readStringParam(params, "targetId");
|
|
1271
|
+
let page;
|
|
1272
|
+
let usedTargetId;
|
|
1273
|
+
if (targetId) {
|
|
1274
|
+
const existingPage = state.pages.get(targetId);
|
|
1275
|
+
if (!existingPage) {
|
|
1276
|
+
throw new Error(`Tab ${targetId} not found. Run action=tabs to see available tabs or use action=open to create a new tab.`);
|
|
1277
|
+
}
|
|
1278
|
+
page = existingPage;
|
|
1279
|
+
usedTargetId = targetId;
|
|
1280
|
+
}
|
|
1281
|
+
else {
|
|
1282
|
+
// Use first page or create new one
|
|
1283
|
+
if (state.pages.size > 0) {
|
|
1284
|
+
const firstEntry = Array.from(state.pages.entries())[0];
|
|
1285
|
+
page = firstEntry[1];
|
|
1286
|
+
usedTargetId = firstEntry[0];
|
|
1287
|
+
}
|
|
1288
|
+
else {
|
|
1289
|
+
const result = await openPage(targetUrl);
|
|
1290
|
+
return jsonResult({
|
|
1291
|
+
targetId: result.targetId,
|
|
1292
|
+
url: result.page.url(),
|
|
1293
|
+
title: await result.page.title(),
|
|
1294
|
+
message: `Created new tab and navigated to ${targetUrl}`,
|
|
1295
|
+
});
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
await page.goto(targetUrl, { waitUntil: "domcontentloaded", timeout: 30000 });
|
|
1299
|
+
return jsonResult({
|
|
1300
|
+
targetId: usedTargetId,
|
|
1301
|
+
url: page.url(),
|
|
1302
|
+
title: await page.title(),
|
|
1303
|
+
message: `Navigated to ${targetUrl}`,
|
|
1304
|
+
});
|
|
1305
|
+
}
|
|
1306
|
+
case "snapshot": {
|
|
1307
|
+
if (!state.running || state.pages.size === 0) {
|
|
1308
|
+
throw new Error("No tabs open. Use action=open to open a URL first.");
|
|
1309
|
+
}
|
|
1310
|
+
const targetId = readStringParam(params, "targetId");
|
|
1311
|
+
const maxChars = readNumberParam(params, "maxChars") || 50000;
|
|
1312
|
+
const labels = readBooleanParam(params, "labels", false);
|
|
1313
|
+
const refs = (readStringParam(params, "refs") || "role");
|
|
1314
|
+
const selector = readStringParam(params, "selector");
|
|
1315
|
+
const frame = readStringParam(params, "frame");
|
|
1316
|
+
const interactive = readBooleanParam(params, "interactive", false);
|
|
1317
|
+
// Use helper to get page and track last active
|
|
1318
|
+
const { page, usedTargetId } = getPageForAction(targetId ?? undefined);
|
|
1319
|
+
// OpenClaw-style: Only generate screenshot if labels explicitly requested
|
|
1320
|
+
const snapshotResult = await getAISnapshot(page, usedTargetId, {
|
|
1321
|
+
maxChars,
|
|
1322
|
+
labels, // Only generate screenshot when explicitly requested
|
|
1323
|
+
refs,
|
|
1324
|
+
selector,
|
|
1325
|
+
frame,
|
|
1326
|
+
interactive,
|
|
1327
|
+
});
|
|
1328
|
+
// If labels requested, return image with text
|
|
1329
|
+
if (labels && snapshotResult.imagePath) {
|
|
1330
|
+
return await imageResultFromFile({
|
|
1331
|
+
path: snapshotResult.imagePath,
|
|
1332
|
+
extraText: snapshotResult.snapshot,
|
|
1333
|
+
details: {
|
|
1334
|
+
targetId: usedTargetId,
|
|
1335
|
+
url: page.url(),
|
|
1336
|
+
title: await page.title(),
|
|
1337
|
+
format: "ai",
|
|
1338
|
+
labels: true,
|
|
1339
|
+
labelsCount: snapshotResult.labelsCount,
|
|
1340
|
+
refs: snapshotResult.refs,
|
|
1341
|
+
contentLength: snapshotResult.snapshot.length,
|
|
1342
|
+
truncated: snapshotResult.snapshot.includes("(content truncated"),
|
|
1343
|
+
},
|
|
1344
|
+
});
|
|
1345
|
+
}
|
|
1346
|
+
// Default: Return tree only (no screenshot)
|
|
1347
|
+
return {
|
|
1348
|
+
content: [
|
|
1349
|
+
{
|
|
1350
|
+
type: "text",
|
|
1351
|
+
text: snapshotResult.snapshot,
|
|
1352
|
+
},
|
|
1353
|
+
],
|
|
1354
|
+
details: {
|
|
1355
|
+
targetId: usedTargetId,
|
|
1356
|
+
url: page.url(),
|
|
1357
|
+
title: await page.title(),
|
|
1358
|
+
format: "ai",
|
|
1359
|
+
refs: snapshotResult.refs,
|
|
1360
|
+
contentLength: snapshotResult.snapshot.length,
|
|
1361
|
+
truncated: snapshotResult.snapshot.includes("(content truncated"),
|
|
1362
|
+
},
|
|
1363
|
+
};
|
|
1364
|
+
}
|
|
1365
|
+
case "screenshot": {
|
|
1366
|
+
if (!state.running || state.pages.size === 0) {
|
|
1367
|
+
throw new Error("No tabs open. Use action=open to open a URL first.");
|
|
1368
|
+
}
|
|
1369
|
+
const targetId = readStringParam(params, "targetId");
|
|
1370
|
+
const fullPage = readBooleanParam(params, "fullPage", false);
|
|
1371
|
+
let page;
|
|
1372
|
+
let usedTargetId;
|
|
1373
|
+
if (targetId) {
|
|
1374
|
+
const existingPage = state.pages.get(targetId);
|
|
1375
|
+
if (!existingPage) {
|
|
1376
|
+
throw new Error(`Tab ${targetId} not found. Run action=tabs to see available tabs.`);
|
|
1377
|
+
}
|
|
1378
|
+
page = existingPage;
|
|
1379
|
+
usedTargetId = targetId;
|
|
1380
|
+
}
|
|
1381
|
+
else {
|
|
1382
|
+
const firstEntry = Array.from(state.pages.entries())[0];
|
|
1383
|
+
page = firstEntry[1];
|
|
1384
|
+
usedTargetId = firstEntry[0];
|
|
1385
|
+
}
|
|
1386
|
+
const screenshot = await page.screenshot({
|
|
1387
|
+
fullPage,
|
|
1388
|
+
type: "png",
|
|
1389
|
+
});
|
|
1390
|
+
// Save screenshot to temp file
|
|
1391
|
+
const fs = await import("fs/promises");
|
|
1392
|
+
const path = await import("path");
|
|
1393
|
+
const tmpDir = await import("os").then((os) => os.tmpdir());
|
|
1394
|
+
const filename = `browser-screenshot-${Date.now()}.png`;
|
|
1395
|
+
const filepath = path.join(tmpDir, filename);
|
|
1396
|
+
await fs.writeFile(filepath, screenshot);
|
|
1397
|
+
return await imageResultFromFile({
|
|
1398
|
+
path: filepath,
|
|
1399
|
+
details: {
|
|
1400
|
+
targetId: usedTargetId,
|
|
1401
|
+
url: page.url(),
|
|
1402
|
+
title: await page.title(),
|
|
1403
|
+
path: filepath,
|
|
1404
|
+
fullPage,
|
|
1405
|
+
},
|
|
1406
|
+
});
|
|
1407
|
+
}
|
|
1408
|
+
case "console": {
|
|
1409
|
+
const targetId = readStringParam(params, "targetId");
|
|
1410
|
+
const level = readStringParam(params, "level");
|
|
1411
|
+
let usedTargetId;
|
|
1412
|
+
let messages;
|
|
1413
|
+
if (targetId) {
|
|
1414
|
+
if (!state.consoleLogs.has(targetId)) {
|
|
1415
|
+
throw new Error(`Tab ${targetId} not found. Run action=tabs to see available tabs.`);
|
|
1416
|
+
}
|
|
1417
|
+
messages = state.consoleLogs.get(targetId);
|
|
1418
|
+
usedTargetId = targetId;
|
|
1419
|
+
}
|
|
1420
|
+
else {
|
|
1421
|
+
if (state.pages.size === 0) {
|
|
1422
|
+
throw new Error("No tabs open. Use action=open to open a URL first.");
|
|
1423
|
+
}
|
|
1424
|
+
const firstId = Array.from(state.pages.keys())[0];
|
|
1425
|
+
messages = state.consoleLogs.get(firstId) || [];
|
|
1426
|
+
usedTargetId = firstId;
|
|
1427
|
+
}
|
|
1428
|
+
// Filter by level if specified
|
|
1429
|
+
if (level) {
|
|
1430
|
+
messages = messages.filter((msg) => msg.type() === level);
|
|
1431
|
+
}
|
|
1432
|
+
const formattedMessages = messages.map((msg) => ({
|
|
1433
|
+
type: msg.type(),
|
|
1434
|
+
text: msg.text(),
|
|
1435
|
+
location: msg.location(),
|
|
1436
|
+
}));
|
|
1437
|
+
return jsonResult({
|
|
1438
|
+
ok: true,
|
|
1439
|
+
targetId: usedTargetId,
|
|
1440
|
+
messages: formattedMessages,
|
|
1441
|
+
});
|
|
1442
|
+
}
|
|
1443
|
+
case "pdf": {
|
|
1444
|
+
const targetId = readStringParam(params, "targetId");
|
|
1445
|
+
let page;
|
|
1446
|
+
let usedTargetId;
|
|
1447
|
+
if (targetId) {
|
|
1448
|
+
const existingPage = state.pages.get(targetId);
|
|
1449
|
+
if (!existingPage) {
|
|
1450
|
+
throw new Error(`Tab ${targetId} not found. Run action=tabs to see available tabs.`);
|
|
1451
|
+
}
|
|
1452
|
+
page = existingPage;
|
|
1453
|
+
usedTargetId = targetId;
|
|
1454
|
+
}
|
|
1455
|
+
else {
|
|
1456
|
+
if (state.pages.size === 0) {
|
|
1457
|
+
throw new Error("No tabs open. Use action=open to open a URL first.");
|
|
1458
|
+
}
|
|
1459
|
+
const firstEntry = Array.from(state.pages.entries())[0];
|
|
1460
|
+
page = firstEntry[1];
|
|
1461
|
+
usedTargetId = firstEntry[0];
|
|
1462
|
+
}
|
|
1463
|
+
const path = await import("path");
|
|
1464
|
+
const tmpDir = await import("os").then((os) => os.tmpdir());
|
|
1465
|
+
const filename = `browser-pdf-${Date.now()}.pdf`;
|
|
1466
|
+
const filepath = path.join(tmpDir, filename);
|
|
1467
|
+
await page.pdf({
|
|
1468
|
+
path: filepath,
|
|
1469
|
+
format: "A4",
|
|
1470
|
+
});
|
|
1471
|
+
return {
|
|
1472
|
+
content: [
|
|
1473
|
+
{
|
|
1474
|
+
type: "text",
|
|
1475
|
+
text: `PDF saved to ${filepath}`,
|
|
1476
|
+
},
|
|
1477
|
+
],
|
|
1478
|
+
details: {
|
|
1479
|
+
ok: true,
|
|
1480
|
+
targetId: usedTargetId,
|
|
1481
|
+
path: filepath,
|
|
1482
|
+
},
|
|
1483
|
+
};
|
|
1484
|
+
}
|
|
1485
|
+
case "upload": {
|
|
1486
|
+
const paths = readArrayParam(params, "paths", { required: true });
|
|
1487
|
+
const targetId = readStringParam(params, "targetId");
|
|
1488
|
+
const timeoutMs = readNumberParam(params, "timeoutMs") || 30000;
|
|
1489
|
+
let page;
|
|
1490
|
+
let usedTargetId;
|
|
1491
|
+
if (targetId) {
|
|
1492
|
+
const existingPage = state.pages.get(targetId);
|
|
1493
|
+
if (!existingPage) {
|
|
1494
|
+
throw new Error(`Tab ${targetId} not found. Run action=tabs to see available tabs.`);
|
|
1495
|
+
}
|
|
1496
|
+
page = existingPage;
|
|
1497
|
+
usedTargetId = targetId;
|
|
1498
|
+
}
|
|
1499
|
+
else {
|
|
1500
|
+
if (state.pages.size === 0) {
|
|
1501
|
+
throw new Error("No tabs open. Use action=open to open a URL first.");
|
|
1502
|
+
}
|
|
1503
|
+
const firstEntry = Array.from(state.pages.entries())[0];
|
|
1504
|
+
page = firstEntry[1];
|
|
1505
|
+
usedTargetId = firstEntry[0];
|
|
1506
|
+
}
|
|
1507
|
+
// Set up file chooser handler
|
|
1508
|
+
const fileChooserPromise = page.waitForEvent("filechooser", { timeout: timeoutMs });
|
|
1509
|
+
// Wait for file chooser to appear (user must trigger it)
|
|
1510
|
+
const fileChooser = await fileChooserPromise;
|
|
1511
|
+
await fileChooser.setFiles(paths);
|
|
1512
|
+
return jsonResult({
|
|
1513
|
+
ok: true,
|
|
1514
|
+
targetId: usedTargetId,
|
|
1515
|
+
filesUploaded: paths.length,
|
|
1516
|
+
message: `File chooser armed and files uploaded: ${paths.join(", ")}`,
|
|
1517
|
+
});
|
|
1518
|
+
}
|
|
1519
|
+
case "dialog": {
|
|
1520
|
+
const accept = readBooleanParam(params, "accept", true);
|
|
1521
|
+
const promptText = readStringParam(params, "promptText");
|
|
1522
|
+
const targetId = readStringParam(params, "targetId");
|
|
1523
|
+
const timeoutMs = readNumberParam(params, "timeoutMs") || 30000;
|
|
1524
|
+
let page;
|
|
1525
|
+
let usedTargetId;
|
|
1526
|
+
if (targetId) {
|
|
1527
|
+
const existingPage = state.pages.get(targetId);
|
|
1528
|
+
if (!existingPage) {
|
|
1529
|
+
throw new Error(`Tab ${targetId} not found. Run action=tabs to see available tabs.`);
|
|
1530
|
+
}
|
|
1531
|
+
page = existingPage;
|
|
1532
|
+
usedTargetId = targetId;
|
|
1533
|
+
}
|
|
1534
|
+
else {
|
|
1535
|
+
if (state.pages.size === 0) {
|
|
1536
|
+
throw new Error("No tabs open. Use action=open to open a URL first.");
|
|
1537
|
+
}
|
|
1538
|
+
const firstEntry = Array.from(state.pages.entries())[0];
|
|
1539
|
+
page = firstEntry[1];
|
|
1540
|
+
usedTargetId = firstEntry[0];
|
|
1541
|
+
}
|
|
1542
|
+
// Set up dialog handler
|
|
1543
|
+
const dialogPromise = page.waitForEvent("dialog", { timeout: timeoutMs });
|
|
1544
|
+
// Wait for dialog to appear
|
|
1545
|
+
const dialog = await dialogPromise;
|
|
1546
|
+
if (accept) {
|
|
1547
|
+
await dialog.accept(promptText);
|
|
1548
|
+
}
|
|
1549
|
+
else {
|
|
1550
|
+
await dialog.dismiss();
|
|
1551
|
+
}
|
|
1552
|
+
return jsonResult({
|
|
1553
|
+
ok: true,
|
|
1554
|
+
targetId: usedTargetId,
|
|
1555
|
+
dialogType: dialog.type(),
|
|
1556
|
+
dialogMessage: dialog.message(),
|
|
1557
|
+
accepted: accept,
|
|
1558
|
+
});
|
|
1559
|
+
}
|
|
1560
|
+
case "close": {
|
|
1561
|
+
const targetId = readStringParam(params, "targetId");
|
|
1562
|
+
if (!targetId) {
|
|
1563
|
+
throw new Error("targetId is required for close action. Run action=tabs to see available targetIds.");
|
|
1564
|
+
}
|
|
1565
|
+
const page = state.pages.get(targetId);
|
|
1566
|
+
if (!page) {
|
|
1567
|
+
throw new Error(`Tab ${targetId} not found. Run action=tabs to see available tabs.`);
|
|
1568
|
+
}
|
|
1569
|
+
await page.close();
|
|
1570
|
+
state.pages.delete(targetId);
|
|
1571
|
+
state.consoleLogs.delete(targetId);
|
|
1572
|
+
return jsonResult({
|
|
1573
|
+
targetId,
|
|
1574
|
+
message: `Closed tab ${targetId}`,
|
|
1575
|
+
remainingTabs: state.pages.size,
|
|
1576
|
+
});
|
|
1577
|
+
}
|
|
1578
|
+
case "act": {
|
|
1579
|
+
// Support both OpenClaw-style (request object) and direct parameters
|
|
1580
|
+
const request = params.request;
|
|
1581
|
+
const actParams = request || params;
|
|
1582
|
+
// Check if we have act parameters (either kind or any act-specific param)
|
|
1583
|
+
if (!actParams.kind && !actParams.ref && !actParams.text && !actParams.key) {
|
|
1584
|
+
throw new Error("act action requires 'kind' parameter or use 'request' object with act parameters");
|
|
1585
|
+
}
|
|
1586
|
+
const targetId = readStringParam(actParams, "targetId");
|
|
1587
|
+
// Use helper to get page and track last active
|
|
1588
|
+
const { page, usedTargetId } = getPageForAction(targetId ?? undefined);
|
|
1589
|
+
const result = await executeBrowserAct(page, actParams, usedTargetId);
|
|
1590
|
+
return jsonResult({
|
|
1591
|
+
ok: result.ok,
|
|
1592
|
+
targetId: usedTargetId,
|
|
1593
|
+
url: page.url(),
|
|
1594
|
+
result: result.result,
|
|
1595
|
+
});
|
|
1596
|
+
}
|
|
1597
|
+
default:
|
|
1598
|
+
throw new Error(`Unknown action: ${action}. Valid actions: ${BROWSER_TOOL_ACTIONS.join(", ")}`);
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
catch (error) {
|
|
1602
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1603
|
+
console.error(`[BROWSER] Error in action ${action}:`, message);
|
|
1604
|
+
// Return structured error
|
|
1605
|
+
return {
|
|
1606
|
+
content: [
|
|
1607
|
+
{
|
|
1608
|
+
type: "text",
|
|
1609
|
+
text: `Browser error in action "${action}": ${message}`,
|
|
1610
|
+
},
|
|
1611
|
+
],
|
|
1612
|
+
details: {
|
|
1613
|
+
error: "browser_error",
|
|
1614
|
+
action,
|
|
1615
|
+
message,
|
|
1616
|
+
},
|
|
1617
|
+
};
|
|
1618
|
+
}
|
|
1619
|
+
},
|
|
1620
|
+
};
|
|
1621
|
+
}
|
|
1622
|
+
// Cleanup on process exit
|
|
1623
|
+
process.on("SIGINT", async () => {
|
|
1624
|
+
await stopBrowser();
|
|
1625
|
+
});
|
|
1626
|
+
process.on("SIGTERM", async () => {
|
|
1627
|
+
await stopBrowser();
|
|
1628
|
+
});
|
|
1629
|
+
//# sourceMappingURL=browser.js.map
|