browxai 0.7.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/LICENSE +21 -0
- package/README.md +139 -0
- package/THIRD_PARTY_NOTICES.md +45 -0
- package/dist/cli/chrome.d.ts +1 -0
- package/dist/cli/chrome.js +130 -0
- package/dist/cli/command-registry.d.ts +15 -0
- package/dist/cli/command-registry.js +35 -0
- package/dist/cli/doctor-plugins.d.ts +18 -0
- package/dist/cli/doctor-plugins.js +338 -0
- package/dist/cli/doctor.d.ts +9 -0
- package/dist/cli/doctor.js +407 -0
- package/dist/cli/init.d.ts +1 -0
- package/dist/cli/init.js +200 -0
- package/dist/cli/register-commands.d.ts +1 -0
- package/dist/cli/register-commands.js +22 -0
- package/dist/cli/serve.d.ts +14 -0
- package/dist/cli/serve.js +151 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +129 -0
- package/dist/engine/adapters/adb.d.ts +72 -0
- package/dist/engine/adapters/adb.js +200 -0
- package/dist/engine/adapters/android-cdp.d.ts +54 -0
- package/dist/engine/adapters/android-cdp.js +110 -0
- package/dist/engine/adapters/android.engine.d.ts +1 -0
- package/dist/engine/adapters/android.engine.js +31 -0
- package/dist/engine/adapters/chromium.engine.d.ts +1 -0
- package/dist/engine/adapters/chromium.engine.js +44 -0
- package/dist/engine/adapters/firefox.engine.d.ts +1 -0
- package/dist/engine/adapters/firefox.engine.js +43 -0
- package/dist/engine/adapters/playwright-chromium.d.ts +43 -0
- package/dist/engine/adapters/playwright-chromium.js +56 -0
- package/dist/engine/adapters/playwright-firefox.d.ts +52 -0
- package/dist/engine/adapters/playwright-firefox.js +97 -0
- package/dist/engine/adapters/playwright-webkit.d.ts +40 -0
- package/dist/engine/adapters/playwright-webkit.js +79 -0
- package/dist/engine/adapters/safari/bidi-client.d.ts +46 -0
- package/dist/engine/adapters/safari/bidi-client.js +130 -0
- package/dist/engine/adapters/safari/launch.d.ts +56 -0
- package/dist/engine/adapters/safari/launch.js +104 -0
- package/dist/engine/adapters/safari/webdriver-client.d.ts +102 -0
- package/dist/engine/adapters/safari/webdriver-client.js +175 -0
- package/dist/engine/adapters/safari.engine.d.ts +1 -0
- package/dist/engine/adapters/safari.engine.js +52 -0
- package/dist/engine/adapters/safaridriver-hybrid.d.ts +56 -0
- package/dist/engine/adapters/safaridriver-hybrid.js +127 -0
- package/dist/engine/adapters/webkit.engine.d.ts +1 -0
- package/dist/engine/adapters/webkit.engine.js +47 -0
- package/dist/engine/capabilities.d.ts +53 -0
- package/dist/engine/capabilities.js +122 -0
- package/dist/engine/capability-registry.d.ts +9 -0
- package/dist/engine/capability-registry.js +20 -0
- package/dist/engine/index.d.ts +18 -0
- package/dist/engine/index.js +14 -0
- package/dist/engine/register-engines.d.ts +5 -0
- package/dist/engine/register-engines.js +16 -0
- package/dist/engine/registry.d.ts +145 -0
- package/dist/engine/registry.js +67 -0
- package/dist/engine/select.d.ts +48 -0
- package/dist/engine/select.js +128 -0
- package/dist/engine/session-cdp.d.ts +13 -0
- package/dist/engine/session-cdp.js +22 -0
- package/dist/engine/tool-gate.d.ts +19 -0
- package/dist/engine/tool-gate.js +226 -0
- package/dist/engine/types.d.ts +71 -0
- package/dist/engine/types.js +16 -0
- package/dist/helper/bridge.d.ts +48 -0
- package/dist/helper/bridge.js +200 -0
- package/dist/helper/browx-page.d.ts +1 -0
- package/dist/helper/browx-page.js +47 -0
- package/dist/helper/overlay-hide.d.ts +9 -0
- package/dist/helper/overlay-hide.js +49 -0
- package/dist/helper/stealth.d.ts +10 -0
- package/dist/helper/stealth.js +88 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +15 -0
- package/dist/page/a11y.d.ts +81 -0
- package/dist/page/a11y.js +219 -0
- package/dist/page/action-substrate.d.ts +64 -0
- package/dist/page/action-substrate.js +118 -0
- package/dist/page/actionresult-blocks.d.ts +99 -0
- package/dist/page/actionresult-blocks.js +144 -0
- package/dist/page/actionresult-shape.d.ts +48 -0
- package/dist/page/actionresult-shape.js +155 -0
- package/dist/page/actionresult-types.d.ts +368 -0
- package/dist/page/actionresult-types.js +4 -0
- package/dist/page/actionresult.d.ts +4 -0
- package/dist/page/actionresult.js +299 -0
- package/dist/page/actions-probe.d.ts +32 -0
- package/dist/page/actions-probe.js +294 -0
- package/dist/page/actions-scroll.d.ts +40 -0
- package/dist/page/actions-scroll.js +53 -0
- package/dist/page/actions.d.ts +132 -0
- package/dist/page/actions.js +453 -0
- package/dist/page/archive-assets.d.ts +39 -0
- package/dist/page/archive-assets.js +187 -0
- package/dist/page/archive.d.ts +47 -0
- package/dist/page/archive.js +349 -0
- package/dist/page/asset-export.d.ts +122 -0
- package/dist/page/asset-export.js +376 -0
- package/dist/page/await_network.d.ts +16 -0
- package/dist/page/await_network.js +23 -0
- package/dist/page/bbox.d.ts +37 -0
- package/dist/page/bbox.js +115 -0
- package/dist/page/canvas-capture.d.ts +82 -0
- package/dist/page/canvas-capture.js +257 -0
- package/dist/page/canvas-diff.d.ts +51 -0
- package/dist/page/canvas-diff.js +131 -0
- package/dist/page/canvas-gesture.d.ts +53 -0
- package/dist/page/canvas-gesture.js +167 -0
- package/dist/page/canvas-transform.d.ts +96 -0
- package/dist/page/canvas-transform.js +150 -0
- package/dist/page/canvas.d.ts +8 -0
- package/dist/page/canvas.js +50 -0
- package/dist/page/capture-substrate.d.ts +111 -0
- package/dist/page/capture-substrate.js +139 -0
- package/dist/page/clipboard.d.ts +25 -0
- package/dist/page/clipboard.js +50 -0
- package/dist/page/clock.d.ts +36 -0
- package/dist/page/clock.js +167 -0
- package/dist/page/compose.d.ts +55 -0
- package/dist/page/compose.js +169 -0
- package/dist/page/console.d.ts +39 -0
- package/dist/page/console.js +73 -0
- package/dist/page/coverage.d.ts +97 -0
- package/dist/page/coverage.js +280 -0
- package/dist/page/dom-export.d.ts +41 -0
- package/dist/page/dom-export.js +193 -0
- package/dist/page/dom-walk.d.ts +91 -0
- package/dist/page/dom-walk.js +267 -0
- package/dist/page/dom_diff.d.ts +48 -0
- package/dist/page/dom_diff.js +121 -0
- package/dist/page/downloads.d.ts +80 -0
- package/dist/page/downloads.js +244 -0
- package/dist/page/drop-files.d.ts +78 -0
- package/dist/page/drop-files.js +310 -0
- package/dist/page/element-export-discovery.d.ts +64 -0
- package/dist/page/element-export-discovery.js +346 -0
- package/dist/page/element-export.d.ts +46 -0
- package/dist/page/element-export.js +251 -0
- package/dist/page/emulation-substrate.d.ts +53 -0
- package/dist/page/emulation-substrate.js +87 -0
- package/dist/page/emulation.d.ts +60 -0
- package/dist/page/emulation.js +162 -0
- package/dist/page/export-playwright-script.d.ts +47 -0
- package/dist/page/export-playwright-script.js +304 -0
- package/dist/page/extract-resolve.d.ts +22 -0
- package/dist/page/extract-resolve.js +341 -0
- package/dist/page/extract-schema.d.ts +20 -0
- package/dist/page/extract-schema.js +200 -0
- package/dist/page/extract-types.d.ts +127 -0
- package/dist/page/extract-types.js +8 -0
- package/dist/page/extract-warnings.d.ts +8 -0
- package/dist/page/extract-warnings.js +56 -0
- package/dist/page/extract.d.ts +9 -0
- package/dist/page/extract.js +174 -0
- package/dist/page/fill-form.d.ts +58 -0
- package/dist/page/fill-form.js +261 -0
- package/dist/page/find.d.ts +158 -0
- package/dist/page/find.js +470 -0
- package/dist/page/frames.d.ts +45 -0
- package/dist/page/frames.js +133 -0
- package/dist/page/generate-locator.d.ts +57 -0
- package/dist/page/generate-locator.js +136 -0
- package/dist/page/gestures.d.ts +128 -0
- package/dist/page/gestures.js +198 -0
- package/dist/page/har.d.ts +91 -0
- package/dist/page/har.js +174 -0
- package/dist/page/heap.d.ts +97 -0
- package/dist/page/heap.js +285 -0
- package/dist/page/inspect.d.ts +34 -0
- package/dist/page/inspect.js +75 -0
- package/dist/page/layout-thrash.d.ts +34 -0
- package/dist/page/layout-thrash.js +232 -0
- package/dist/page/learning.d.ts +21 -0
- package/dist/page/learning.js +84 -0
- package/dist/page/locator.d.ts +54 -0
- package/dist/page/locator.js +142 -0
- package/dist/page/memory-diff.d.ts +48 -0
- package/dist/page/memory-diff.js +105 -0
- package/dist/page/network-mask.d.ts +8 -0
- package/dist/page/network-mask.js +18 -0
- package/dist/page/network-playwright.d.ts +96 -0
- package/dist/page/network-playwright.js +353 -0
- package/dist/page/network-substrate-select.d.ts +18 -0
- package/dist/page/network-substrate-select.js +32 -0
- package/dist/page/network-substrate.d.ts +109 -0
- package/dist/page/network-substrate.js +161 -0
- package/dist/page/network-ws.d.ts +46 -0
- package/dist/page/network-ws.js +113 -0
- package/dist/page/network.d.ts +194 -0
- package/dist/page/network.js +415 -0
- package/dist/page/overflow-detect.d.ts +102 -0
- package/dist/page/overflow-detect.js +449 -0
- package/dist/page/pdf.d.ts +69 -0
- package/dist/page/pdf.js +109 -0
- package/dist/page/perf-audit-analysers.d.ts +40 -0
- package/dist/page/perf-audit-analysers.js +369 -0
- package/dist/page/perf-audit-runner.d.ts +20 -0
- package/dist/page/perf-audit-runner.js +195 -0
- package/dist/page/perf-audit-types.d.ts +41 -0
- package/dist/page/perf-audit-types.js +5 -0
- package/dist/page/perf-audit.d.ts +37 -0
- package/dist/page/perf-audit.js +377 -0
- package/dist/page/perf.d.ts +127 -0
- package/dist/page/perf.js +373 -0
- package/dist/page/plan.d.ts +192 -0
- package/dist/page/plan.js +308 -0
- package/dist/page/point_probe.d.ts +46 -0
- package/dist/page/point_probe.js +99 -0
- package/dist/page/recording.d.ts +67 -0
- package/dist/page/recording.js +172 -0
- package/dist/page/refs.d.ts +92 -0
- package/dist/page/refs.js +134 -0
- package/dist/page/regions.d.ts +23 -0
- package/dist/page/regions.js +32 -0
- package/dist/page/routes.d.ts +40 -0
- package/dist/page/routes.js +87 -0
- package/dist/page/safari-actions.d.ts +12 -0
- package/dist/page/safari-actions.js +144 -0
- package/dist/page/sample.d.ts +64 -0
- package/dist/page/sample.js +216 -0
- package/dist/page/screenshot-on.d.ts +51 -0
- package/dist/page/screenshot-on.js +150 -0
- package/dist/page/screenshot-save.d.ts +36 -0
- package/dist/page/screenshot-save.js +53 -0
- package/dist/page/screenshot-schedule.d.ts +50 -0
- package/dist/page/screenshot-schedule.js +155 -0
- package/dist/page/script-substrate.d.ts +32 -0
- package/dist/page/script-substrate.js +47 -0
- package/dist/page/seed-random.d.ts +45 -0
- package/dist/page/seed-random.js +144 -0
- package/dist/page/set-of-marks.d.ts +96 -0
- package/dist/page/set-of-marks.js +245 -0
- package/dist/page/shadow.d.ts +136 -0
- package/dist/page/shadow.js +400 -0
- package/dist/page/shortcut.d.ts +50 -0
- package/dist/page/shortcut.js +147 -0
- package/dist/page/snapshot-substrate-safari.d.ts +30 -0
- package/dist/page/snapshot-substrate-safari.js +84 -0
- package/dist/page/snapshot-substrate-select.d.ts +24 -0
- package/dist/page/snapshot-substrate-select.js +34 -0
- package/dist/page/snapshot-substrate.d.ts +58 -0
- package/dist/page/snapshot-substrate.js +135 -0
- package/dist/page/snapshot.d.ts +24 -0
- package/dist/page/snapshot.js +162 -0
- package/dist/page/solve-captcha.d.ts +76 -0
- package/dist/page/solve-captcha.js +286 -0
- package/dist/page/storage-substrate-types.d.ts +221 -0
- package/dist/page/storage-substrate-types.js +6 -0
- package/dist/page/storage-substrate.d.ts +215 -0
- package/dist/page/storage-substrate.js +280 -0
- package/dist/page/structural.d.ts +9 -0
- package/dist/page/structural.js +152 -0
- package/dist/page/substrate-bundle-safari.d.ts +8 -0
- package/dist/page/substrate-bundle-safari.js +42 -0
- package/dist/page/substrate-bundle.d.ts +6 -0
- package/dist/page/substrate-bundle.js +53 -0
- package/dist/page/text_search.d.ts +44 -0
- package/dist/page/text_search.js +90 -0
- package/dist/page/upload.d.ts +28 -0
- package/dist/page/upload.js +62 -0
- package/dist/page/verify.d.ts +63 -0
- package/dist/page/verify.js +451 -0
- package/dist/page/video.d.ts +115 -0
- package/dist/page/video.js +169 -0
- package/dist/page/visibility.d.ts +22 -0
- package/dist/page/visibility.js +94 -0
- package/dist/page/watch.d.ts +29 -0
- package/dist/page/watch.js +99 -0
- package/dist/page/workers.d.ts +126 -0
- package/dist/page/workers.js +490 -0
- package/dist/page/ws-interactive.d.ts +82 -0
- package/dist/page/ws-interactive.js +318 -0
- package/dist/plugin/cli.d.ts +45 -0
- package/dist/plugin/cli.js +496 -0
- package/dist/plugin/command-registry.d.ts +9 -0
- package/dist/plugin/command-registry.js +23 -0
- package/dist/plugin/depgraph.d.ts +37 -0
- package/dist/plugin/depgraph.js +186 -0
- package/dist/plugin/manifest.d.ts +182 -0
- package/dist/plugin/manifest.js +219 -0
- package/dist/plugin/package-manager.d.ts +22 -0
- package/dist/plugin/package-manager.js +40 -0
- package/dist/plugin/resolver.d.ts +85 -0
- package/dist/plugin/resolver.js +166 -0
- package/dist/plugin/runtime.d.ts +77 -0
- package/dist/plugin/runtime.js +402 -0
- package/dist/plugin/types.d.ts +113 -0
- package/dist/plugin/types.js +4 -0
- package/dist/policy/confirm.d.ts +76 -0
- package/dist/policy/confirm.js +162 -0
- package/dist/policy/origin.d.ts +17 -0
- package/dist/policy/origin.js +79 -0
- package/dist/sdk/client.d.ts +21 -0
- package/dist/sdk/client.js +174 -0
- package/dist/sdk/index.d.ts +32 -0
- package/dist/sdk/index.js +61 -0
- package/dist/sdk/plugin-types.d.ts +33 -0
- package/dist/sdk/plugin-types.js +22 -0
- package/dist/sdk/registry.d.ts +17 -0
- package/dist/sdk/registry.js +94 -0
- package/dist/sdk/socket-transport.d.ts +20 -0
- package/dist/sdk/socket-transport.js +90 -0
- package/dist/sdk/tool-types.d.ts +634 -0
- package/dist/sdk/tool-types.js +28 -0
- package/dist/sdk/transport-in-process.d.ts +21 -0
- package/dist/sdk/transport-in-process.js +44 -0
- package/dist/sdk/transport-registry.d.ts +19 -0
- package/dist/sdk/transport-registry.js +31 -0
- package/dist/sdk/transport-socket.d.ts +12 -0
- package/dist/sdk/transport-socket.js +77 -0
- package/dist/sdk/transport-stdio-child.d.ts +10 -0
- package/dist/sdk/transport-stdio-child.js +47 -0
- package/dist/sdk/transport.d.ts +10 -0
- package/dist/sdk/transport.js +35 -0
- package/dist/sdk/types.d.ts +176 -0
- package/dist/sdk/types.js +10 -0
- package/dist/server.d.ts +33 -0
- package/dist/server.js +327 -0
- package/dist/session/artifacts.d.ts +52 -0
- package/dist/session/artifacts.js +177 -0
- package/dist/session/byob-attach.d.ts +26 -0
- package/dist/session/byob-attach.js +187 -0
- package/dist/session/byob.d.ts +8 -0
- package/dist/session/byob.js +20 -0
- package/dist/session/cache-storage.d.ts +100 -0
- package/dist/session/cache-storage.js +166 -0
- package/dist/session/device-emu.d.ts +149 -0
- package/dist/session/device-emu.js +545 -0
- package/dist/session/device.d.ts +14 -0
- package/dist/session/device.js +44 -0
- package/dist/session/dialog.d.ts +62 -0
- package/dist/session/dialog.js +164 -0
- package/dist/session/emulation.d.ts +69 -0
- package/dist/session/emulation.js +168 -0
- package/dist/session/extensions.d.ts +113 -0
- package/dist/session/extensions.js +237 -0
- package/dist/session/fs-picker.d.ts +144 -0
- package/dist/session/fs-picker.js +666 -0
- package/dist/session/idb-storage.d.ts +86 -0
- package/dist/session/idb-storage.js +229 -0
- package/dist/session/incognito.d.ts +3 -0
- package/dist/session/incognito.js +20 -0
- package/dist/session/launch-options.d.ts +41 -0
- package/dist/session/launch-options.js +200 -0
- package/dist/session/managed.d.ts +3 -0
- package/dist/session/managed.js +16 -0
- package/dist/session/metrics.d.ts +45 -0
- package/dist/session/metrics.js +75 -0
- package/dist/session/notification.d.ts +122 -0
- package/dist/session/notification.js +426 -0
- package/dist/session/permission.d.ts +144 -0
- package/dist/session/permission.js +600 -0
- package/dist/session/playwright-post-wire.d.ts +8 -0
- package/dist/session/playwright-post-wire.js +148 -0
- package/dist/session/policy-buffer.d.ts +21 -0
- package/dist/session/policy-buffer.js +47 -0
- package/dist/session/profile-snapshot.d.ts +11 -0
- package/dist/session/profile-snapshot.js +53 -0
- package/dist/session/registry.d.ts +365 -0
- package/dist/session/registry.js +98 -0
- package/dist/session/safari-post-wire.d.ts +8 -0
- package/dist/session/safari-post-wire.js +28 -0
- package/dist/session/safari-session.d.ts +10 -0
- package/dist/session/safari-session.js +39 -0
- package/dist/session/storage.d.ts +148 -0
- package/dist/session/storage.js +350 -0
- package/dist/session/types.d.ts +113 -0
- package/dist/session/types.js +5 -0
- package/dist/session/wedge.d.ts +15 -0
- package/dist/session/wedge.js +41 -0
- package/dist/tools/action-core-tools.d.ts +13 -0
- package/dist/tools/action-core-tools.js +156 -0
- package/dist/tools/action-form-tools.d.ts +12 -0
- package/dist/tools/action-form-tools.js +179 -0
- package/dist/tools/action-gesture-tools.d.ts +9 -0
- package/dist/tools/action-gesture-tools.js +115 -0
- package/dist/tools/action-history-tools.d.ts +8 -0
- package/dist/tools/action-history-tools.js +67 -0
- package/dist/tools/action-tool.d.ts +42 -0
- package/dist/tools/action-tool.js +58 -0
- package/dist/tools/action-tools.d.ts +20 -0
- package/dist/tools/action-tools.js +28 -0
- package/dist/tools/batch-act-tools.d.ts +10 -0
- package/dist/tools/batch-act-tools.js +276 -0
- package/dist/tools/batch-human-tools.d.ts +8 -0
- package/dist/tools/batch-human-tools.js +148 -0
- package/dist/tools/canvas-tools.d.ts +40 -0
- package/dist/tools/canvas-tools.js +368 -0
- package/dist/tools/capture-report-diagnostics-tools.d.ts +7 -0
- package/dist/tools/capture-report-diagnostics-tools.js +318 -0
- package/dist/tools/capture-report-element-export-tools.d.ts +8 -0
- package/dist/tools/capture-report-element-export-tools.js +197 -0
- package/dist/tools/capture-report-export-tools.d.ts +8 -0
- package/dist/tools/capture-report-export-tools.js +246 -0
- package/dist/tools/capture-report-marks-tools.d.ts +9 -0
- package/dist/tools/capture-report-marks-tools.js +221 -0
- package/dist/tools/capture-report-upload-tools.d.ts +8 -0
- package/dist/tools/capture-report-upload-tools.js +277 -0
- package/dist/tools/config-approval-tools.d.ts +8 -0
- package/dist/tools/config-approval-tools.js +166 -0
- package/dist/tools/deep-coverage-tools.d.ts +8 -0
- package/dist/tools/deep-coverage-tools.js +325 -0
- package/dist/tools/deep-determinism-tools.d.ts +8 -0
- package/dist/tools/deep-determinism-tools.js +276 -0
- package/dist/tools/deep-perf-tools.d.ts +19 -0
- package/dist/tools/deep-perf-tools.js +324 -0
- package/dist/tools/device-emulation-tools.d.ts +9 -0
- package/dist/tools/device-emulation-tools.js +137 -0
- package/dist/tools/extensions-batch-tools.d.ts +18 -0
- package/dist/tools/extensions-batch-tools.js +24 -0
- package/dist/tools/extensions-rebuild.d.ts +22 -0
- package/dist/tools/extensions-rebuild.js +208 -0
- package/dist/tools/extensions-tools.d.ts +2 -0
- package/dist/tools/extensions-tools.js +331 -0
- package/dist/tools/forms-fill-tools.d.ts +8 -0
- package/dist/tools/forms-fill-tools.js +109 -0
- package/dist/tools/forms-plan-tools.d.ts +7 -0
- package/dist/tools/forms-plan-tools.js +159 -0
- package/dist/tools/forms-recording-mode-tools.d.ts +8 -0
- package/dist/tools/forms-recording-mode-tools.js +71 -0
- package/dist/tools/forms-recording-tools.d.ts +14 -0
- package/dist/tools/forms-recording-tools.js +22 -0
- package/dist/tools/forms-refs-tools.d.ts +8 -0
- package/dist/tools/forms-refs-tools.js +90 -0
- package/dist/tools/gesture-coord-tools.d.ts +8 -0
- package/dist/tools/gesture-coord-tools.js +168 -0
- package/dist/tools/gesture-emulation-tools.d.ts +8 -0
- package/dist/tools/gesture-emulation-tools.js +135 -0
- package/dist/tools/gesture-network-tools.d.ts +17 -0
- package/dist/tools/gesture-network-tools.js +27 -0
- package/dist/tools/gesture-route-tools.d.ts +8 -0
- package/dist/tools/gesture-route-tools.js +142 -0
- package/dist/tools/gesture-websocket-tools.d.ts +8 -0
- package/dist/tools/gesture-websocket-tools.js +122 -0
- package/dist/tools/gesture-worker-tools.d.ts +9 -0
- package/dist/tools/gesture-worker-tools.js +200 -0
- package/dist/tools/host-build.d.ts +76 -0
- package/dist/tools/host-build.js +516 -0
- package/dist/tools/host.d.ts +287 -0
- package/dist/tools/host.js +1 -0
- package/dist/tools/input-tools.d.ts +10 -0
- package/dist/tools/input-tools.js +176 -0
- package/dist/tools/live-emulation-tools.d.ts +9 -0
- package/dist/tools/live-emulation-tools.js +353 -0
- package/dist/tools/plugin-runtime.d.ts +36 -0
- package/dist/tools/plugin-runtime.js +274 -0
- package/dist/tools/read-observe-buffer-tools.d.ts +9 -0
- package/dist/tools/read-observe-buffer-tools.js +385 -0
- package/dist/tools/read-observe-capture-tools.d.ts +12 -0
- package/dist/tools/read-observe-capture-tools.js +376 -0
- package/dist/tools/read-observe-dom-tools.d.ts +8 -0
- package/dist/tools/read-observe-dom-tools.js +308 -0
- package/dist/tools/read-observe-extract-tools.d.ts +8 -0
- package/dist/tools/read-observe-extract-tools.js +232 -0
- package/dist/tools/read-observe-verify-tools.d.ts +8 -0
- package/dist/tools/read-observe-verify-tools.js +316 -0
- package/dist/tools/schemas.d.ts +29 -0
- package/dist/tools/schemas.js +58 -0
- package/dist/tools/secrets-captcha-tools.d.ts +9 -0
- package/dist/tools/secrets-captcha-tools.js +231 -0
- package/dist/tools/session-dialog-permission-tools.d.ts +9 -0
- package/dist/tools/session-dialog-permission-tools.js +287 -0
- package/dist/tools/session-lifecycle-tools.d.ts +8 -0
- package/dist/tools/session-lifecycle-tools.js +314 -0
- package/dist/tools/session-notification-device-tools.d.ts +9 -0
- package/dist/tools/session-notification-device-tools.js +156 -0
- package/dist/tools/session-policy-tools.d.ts +16 -0
- package/dist/tools/session-policy-tools.js +22 -0
- package/dist/tools/session-registry.d.ts +28 -0
- package/dist/tools/session-registry.js +427 -0
- package/dist/tools/storage-artifact-har-video-tools.d.ts +8 -0
- package/dist/tools/storage-artifact-har-video-tools.js +311 -0
- package/dist/tools/storage-cache-idb-tools.d.ts +8 -0
- package/dist/tools/storage-cache-idb-tools.js +347 -0
- package/dist/tools/storage-state-cookies-tools.d.ts +8 -0
- package/dist/tools/storage-state-cookies-tools.js +223 -0
- package/dist/tools/storage-tools.d.ts +17 -0
- package/dist/tools/storage-tools.js +25 -0
- package/dist/tools/storage-web-auth-tools.d.ts +10 -0
- package/dist/tools/storage-web-auth-tools.js +230 -0
- package/dist/tools/tool-metadata.d.ts +8 -0
- package/dist/tools/tool-metadata.js +185 -0
- package/dist/util/batch.d.ts +83 -0
- package/dist/util/batch.js +191 -0
- package/dist/util/capabilities.d.ts +504 -0
- package/dist/util/capabilities.js +254 -0
- package/dist/util/config-store.d.ts +103 -0
- package/dist/util/config-store.js +206 -0
- package/dist/util/config.d.ts +11 -0
- package/dist/util/config.js +28 -0
- package/dist/util/credentials.d.ts +136 -0
- package/dist/util/credentials.js +622 -0
- package/dist/util/deadline.d.ts +22 -0
- package/dist/util/deadline.js +62 -0
- package/dist/util/diagnostics.d.ts +161 -0
- package/dist/util/diagnostics.js +579 -0
- package/dist/util/egress-sanitiser.d.ts +29 -0
- package/dist/util/egress-sanitiser.js +52 -0
- package/dist/util/failure.d.ts +8 -0
- package/dist/util/failure.js +50 -0
- package/dist/util/flake-check.d.ts +109 -0
- package/dist/util/flake-check.js +342 -0
- package/dist/util/invariant.d.ts +25 -0
- package/dist/util/invariant.js +66 -0
- package/dist/util/logging.d.ts +6 -0
- package/dist/util/logging.js +12 -0
- package/dist/util/predicates.d.ts +62 -0
- package/dist/util/predicates.js +340 -0
- package/dist/util/secrets.d.ts +104 -0
- package/dist/util/secrets.js +219 -0
- package/dist/util/tokens.d.ts +6 -0
- package/dist/util/tokens.js +24 -0
- package/dist/util/url-sanitizer.d.ts +19 -0
- package/dist/util/url-sanitizer.js +70 -0
- package/dist/util/version.d.ts +2 -0
- package/dist/util/version.js +21 -0
- package/dist/util/workspace.d.ts +7 -0
- package/dist/util/workspace.js +22 -0
- package/package.json +120 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// `browxai serve --socket /tmp/foo.sock` — long-running server that listens
|
|
2
|
+
// on a Unix domain socket (or named pipe on Windows) and accepts MCP-over-
|
|
3
|
+
// socket connections. The wire framing is byte-identical to the stdio path
|
|
4
|
+
// (same JSON-lines + ReadBuffer), but the listener lets multiple SDK
|
|
5
|
+
// clients attach to ONE browser/session registry — the wrightxai
|
|
6
|
+
// loop-plus-script scenario.
|
|
7
|
+
//
|
|
8
|
+
// Off by default: there is no `serve` exposed unless the operator explicitly
|
|
9
|
+
// runs this subcommand and passes `--socket`. There is no auto-discovery; an
|
|
10
|
+
// SDK client must be given the endpoint URL out-of-band.
|
|
11
|
+
//
|
|
12
|
+
// Security posture: the socket is created with restrictive perms (0700) so
|
|
13
|
+
// only the owning user can connect. Capability gates are enforced at the
|
|
14
|
+
// server, identical to stdio.
|
|
15
|
+
import { chmodSync, existsSync, unlinkSync } from "node:fs";
|
|
16
|
+
import { createServer as createNetServer } from "node:net";
|
|
17
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
18
|
+
import { createServer } from "../server.js";
|
|
19
|
+
import { SocketTransport } from "../sdk/socket-transport.js";
|
|
20
|
+
import { log } from "../util/logging.js";
|
|
21
|
+
function parseFlagString(args, flag) {
|
|
22
|
+
const i = args.indexOf(flag);
|
|
23
|
+
if (i === -1)
|
|
24
|
+
return undefined;
|
|
25
|
+
const v = args[i + 1];
|
|
26
|
+
if (!v || v.startsWith("--"))
|
|
27
|
+
return undefined;
|
|
28
|
+
return v;
|
|
29
|
+
}
|
|
30
|
+
export async function runServe(rawArgs) {
|
|
31
|
+
const socketPath = parseFlagString(rawArgs, "--socket");
|
|
32
|
+
if (!socketPath) {
|
|
33
|
+
process.stderr.write("usage: browxai serve --socket <unix-socket-path-or-windows-pipe-name>\n" +
|
|
34
|
+
" Example (macOS/Linux): browxai serve --socket /tmp/browxai.sock\n" +
|
|
35
|
+
" Example (Windows): browxai serve --socket \\\\\\\\.\\\\pipe\\\\browxai\n");
|
|
36
|
+
return 2;
|
|
37
|
+
}
|
|
38
|
+
const attachCdp = process.env.BROWX_ATTACH_CDP?.trim() || undefined;
|
|
39
|
+
const headless = process.env.BROWX_HEADLESS === "1";
|
|
40
|
+
const code = await startServe({ socketPath, attachCdp, headless });
|
|
41
|
+
return code;
|
|
42
|
+
}
|
|
43
|
+
/** Exposed for tests — programmatic `browxai serve` startup that returns the
|
|
44
|
+
* underlying net.Server so a test can `close()` it cleanly. */
|
|
45
|
+
export async function startServeForTests(opts) {
|
|
46
|
+
// Existing socket file → remove. A stale socket left over from a crashed
|
|
47
|
+
// run would otherwise block .listen() with EADDRINUSE.
|
|
48
|
+
if (opts.socketPath.startsWith("/") && existsSync(opts.socketPath)) {
|
|
49
|
+
try {
|
|
50
|
+
unlinkSync(opts.socketPath);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
/* race; the listen() below will fail loudly if it actually mattered */
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const browxai = await createServer({ attachCdp: opts.attachCdp, headless: opts.headless });
|
|
57
|
+
// We share ONE McpServer per attached client connection by creating a
|
|
58
|
+
// fresh adapter per connection. The simplest correct approach: each
|
|
59
|
+
// connection gets its OWN McpServer instance that re-registers against
|
|
60
|
+
// the SAME `browxai.handlers` map. Since `handlers` is shared,
|
|
61
|
+
// session-state isolation is the SessionRegistry's job (already true),
|
|
62
|
+
// and the per-connection McpServer just routes the JSON-RPC.
|
|
63
|
+
//
|
|
64
|
+
// Implementation detail: re-creating tools from scratch on every connect
|
|
65
|
+
// would require duplicating server.ts's input schemas. Instead we expose
|
|
66
|
+
// a thin tool-call proxy: the connection's McpServer registers a single
|
|
67
|
+
// catch-all? No — the MCP SDK requires tools to be registered by name.
|
|
68
|
+
// The cleanest path is: register the same tool names that the in-process
|
|
69
|
+
// server already has, with `inputSchema: { additionalProperties: true }`
|
|
70
|
+
// (open schema — the underlying handler still validates). Each tool's
|
|
71
|
+
// handler delegates to `browxai.handlers[name]`.
|
|
72
|
+
const liveConnections = new Set();
|
|
73
|
+
const netServer = createNetServer((socket) => {
|
|
74
|
+
void (async () => {
|
|
75
|
+
try {
|
|
76
|
+
const mcp = new McpServer({ name: "browxai", version: "0.2.3" });
|
|
77
|
+
for (const [name, handler] of Object.entries(browxai.handlers)) {
|
|
78
|
+
mcp.registerTool(name, { description: `browxai/${name}`, inputSchema: {} }, async (args) => handler(args));
|
|
79
|
+
}
|
|
80
|
+
const transport = new SocketTransport(socket);
|
|
81
|
+
await mcp.connect(transport);
|
|
82
|
+
const conn = {
|
|
83
|
+
close: async () => {
|
|
84
|
+
await mcp.close().catch(() => undefined);
|
|
85
|
+
await transport.close().catch(() => undefined);
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
liveConnections.add(conn);
|
|
89
|
+
socket.on("close", () => {
|
|
90
|
+
liveConnections.delete(conn);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
log.error("browxai serve: connection setup failed", {
|
|
95
|
+
error: err instanceof Error ? err.message : String(err),
|
|
96
|
+
});
|
|
97
|
+
socket.destroy();
|
|
98
|
+
}
|
|
99
|
+
})();
|
|
100
|
+
});
|
|
101
|
+
await new Promise((resolve, reject) => {
|
|
102
|
+
netServer.once("error", reject);
|
|
103
|
+
netServer.listen(opts.socketPath, () => resolve());
|
|
104
|
+
});
|
|
105
|
+
// Tighten perms on the listening socket (POSIX only — chmod is a no-op /
|
|
106
|
+
// throws on Windows pipes).
|
|
107
|
+
if (opts.socketPath.startsWith("/")) {
|
|
108
|
+
try {
|
|
109
|
+
chmodSync(opts.socketPath, 0o700);
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
/* best-effort; on macOS the socket inherits umask which is usually fine */
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const shutdown = async () => {
|
|
116
|
+
for (const conn of liveConnections) {
|
|
117
|
+
await conn.close().catch(() => undefined);
|
|
118
|
+
}
|
|
119
|
+
liveConnections.clear();
|
|
120
|
+
await new Promise((resolve) => {
|
|
121
|
+
netServer.close(() => resolve());
|
|
122
|
+
});
|
|
123
|
+
await browxai.shutdown().catch(() => undefined);
|
|
124
|
+
if (opts.socketPath.startsWith("/") && existsSync(opts.socketPath)) {
|
|
125
|
+
try {
|
|
126
|
+
unlinkSync(opts.socketPath);
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
/* tolerated */
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
return { server: netServer, shutdown };
|
|
134
|
+
}
|
|
135
|
+
async function startServe(opts) {
|
|
136
|
+
const { shutdown } = await startServeForTests(opts);
|
|
137
|
+
log.info("browxai: serve listening", { socket: opts.socketPath });
|
|
138
|
+
// Keep the process alive until a signal.
|
|
139
|
+
const onSignal = async (sig) => {
|
|
140
|
+
log.info(`browxai: serve shutdown (${sig})`);
|
|
141
|
+
await shutdown();
|
|
142
|
+
process.exit(0);
|
|
143
|
+
};
|
|
144
|
+
process.on("SIGINT", () => void onSignal("SIGINT"));
|
|
145
|
+
process.on("SIGTERM", () => void onSignal("SIGTERM"));
|
|
146
|
+
// Block indefinitely.
|
|
147
|
+
await new Promise(() => {
|
|
148
|
+
/* never resolves; signals exit */
|
|
149
|
+
});
|
|
150
|
+
return 0;
|
|
151
|
+
}
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// browxai canonical entrypoint. See USAGE below for the sub-command surface.
|
|
3
|
+
//
|
|
4
|
+
// All transient state lives at $BROWX_WORKSPACE (default ~/.browxai/). NEVER cwd.
|
|
5
|
+
// RFC 0004 P2 / D1 (SECURITY-CRITICAL): EAGERLY populate the derived
|
|
6
|
+
// `TOOL_CAPABILITY` / `DEEP_TOOLS` maps for every CLI sub-command. `doctor` reads
|
|
7
|
+
// `resolveCapabilities` without building a server, so it must reach the
|
|
8
|
+
// tool-metadata bootstrap; importing it here covers the whole CLI surface, not
|
|
9
|
+
// only the default `createServer` path.
|
|
10
|
+
import "./tools/tool-metadata.js";
|
|
11
|
+
import { createServer } from "./server.js";
|
|
12
|
+
// RFC 0004 P4 / D6 — the extensibility subcommands (doctor/chrome/init/serve/
|
|
13
|
+
// plugin) dispatch through an add-only registry. Importing the registrations
|
|
14
|
+
// for their side effect populates the map; `commandFor` resolves the SAME
|
|
15
|
+
// handler the old `switch (subcommand)` case did.
|
|
16
|
+
import "./cli/register-commands.js";
|
|
17
|
+
import { commandFor, registeredCommands } from "./cli/command-registry.js";
|
|
18
|
+
import { log } from "./util/logging.js";
|
|
19
|
+
import { resolveConfig } from "./util/config.js";
|
|
20
|
+
import { resolveWorkspace } from "./util/workspace.js";
|
|
21
|
+
import { PACKAGE_VERSION } from "./util/version.js";
|
|
22
|
+
import { resolveEngineSelection, UnknownEngineError } from "./engine/index.js";
|
|
23
|
+
const USAGE = `Usage: browxai [subcommand]
|
|
24
|
+
|
|
25
|
+
browxai start the MCP server (stdio) — default
|
|
26
|
+
browxai doctor env + connectivity health-check
|
|
27
|
+
browxai chrome start [opts] launch an attachable Chrome (BYOB host)
|
|
28
|
+
browxai chrome stop kill the Chrome that \`chrome start\` launched
|
|
29
|
+
browxai init <workspace> bootstrap a per-app workspace (.mcp.json + sniff)
|
|
30
|
+
browxai serve --socket <p> long-running server on a Unix socket / named pipe
|
|
31
|
+
— accepts MCP-over-socket connections from SDK clients
|
|
32
|
+
(\`createBrowxai({ endpoint: "unix:///..." })\`).
|
|
33
|
+
Off-by-default; explicit operator opt-in.
|
|
34
|
+
browxai plugin <sub> install / remove / list / info / upgrade / sync
|
|
35
|
+
plugins. All ops are workspace-rooted.
|
|
36
|
+
|
|
37
|
+
--engine <kind> browser engine for the MCP server: chromium
|
|
38
|
+
(default) | firefox | webkit | android. Overrides
|
|
39
|
+
BROWX_ENGINE. android implies attach-mode (real
|
|
40
|
+
Chrome-on-Android over adb — no BROWX_ATTACH_CDP).
|
|
41
|
+
--version, -v print the browxai version
|
|
42
|
+
--help, -h print this usage text
|
|
43
|
+
|
|
44
|
+
All transient state lives at $BROWX_WORKSPACE (default ~/.browxai/).
|
|
45
|
+
`;
|
|
46
|
+
async function main() {
|
|
47
|
+
const [, , subcommand, ...rest] = process.argv;
|
|
48
|
+
// Sub-command dispatch. The extensibility subcommands resolve through the
|
|
49
|
+
// add-only registry; the `--version` / `--help` literal fast paths and the
|
|
50
|
+
// `undefined` / `--engine` server-fallthrough stay inline (they are the bin's
|
|
51
|
+
// own argv contract, not extension points). Resolving the registry FIRST keeps
|
|
52
|
+
// the same precedence the old `switch` encoded by case order: a registered
|
|
53
|
+
// subcommand wins, then the flag literals, then the server fallthrough.
|
|
54
|
+
if (subcommand !== undefined) {
|
|
55
|
+
const handler = commandFor(subcommand);
|
|
56
|
+
if (handler) {
|
|
57
|
+
process.exit(await handler(rest));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
switch (subcommand) {
|
|
61
|
+
case "--version":
|
|
62
|
+
case "-v":
|
|
63
|
+
process.stdout.write(`${PACKAGE_VERSION}\n`);
|
|
64
|
+
process.exit(0);
|
|
65
|
+
break;
|
|
66
|
+
case "--help":
|
|
67
|
+
case "-h":
|
|
68
|
+
process.stdout.write(USAGE);
|
|
69
|
+
process.exit(0);
|
|
70
|
+
break;
|
|
71
|
+
case undefined:
|
|
72
|
+
break; // fall through to MCP server
|
|
73
|
+
default:
|
|
74
|
+
// `--engine <kind>` / `--engine=<kind>` is a SERVER-mode flag, not a
|
|
75
|
+
// subcommand — when it appears first (`browxai --engine firefox`) it lands
|
|
76
|
+
// in `subcommand`, so fall through to the MCP server path (which parses the
|
|
77
|
+
// full argv for it) instead of treating it as unknown.
|
|
78
|
+
if (subcommand === "--engine" || subcommand.startsWith("--engine="))
|
|
79
|
+
break;
|
|
80
|
+
// Unknown subcommand — print help and exit non-zero (don't silently start the
|
|
81
|
+
// MCP server, since stdout is the MCP wire and we'd corrupt any caller's expectation).
|
|
82
|
+
// The valid-subcommand list is derived from the registry so it can't drift.
|
|
83
|
+
process.stderr.write(`unknown subcommand "${subcommand}". Valid: ${registeredCommands().join(" | ")} | (no args = start MCP server). Run \`browxai --help\` for details.\n`);
|
|
84
|
+
process.exit(2);
|
|
85
|
+
}
|
|
86
|
+
// Default: MCP server.
|
|
87
|
+
const workspace = resolveWorkspace();
|
|
88
|
+
const config = resolveConfig();
|
|
89
|
+
const attachCdp = process.env.BROWX_ATTACH_CDP?.trim() || undefined;
|
|
90
|
+
const headless = process.env.BROWX_HEADLESS === "1";
|
|
91
|
+
// Engine selection: explicit `--engine <kind>` > `BROWX_ENGINE` env > default
|
|
92
|
+
// chromium (left to server.ts when this resolves undefined — byte-identical to
|
|
93
|
+
// never passing browserType). An unknown engine fails loudly here, before the
|
|
94
|
+
// server starts, with a structured message listing the implemented engines —
|
|
95
|
+
// never a stack trace, never a silent fallback to chromium.
|
|
96
|
+
let browserType;
|
|
97
|
+
try {
|
|
98
|
+
browserType = resolveEngineSelection(process.argv.slice(2));
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
if (err instanceof UnknownEngineError ||
|
|
102
|
+
(err instanceof Error && err.message.includes("--engine"))) {
|
|
103
|
+
process.stderr.write(`${err.message}\n`);
|
|
104
|
+
process.exit(2);
|
|
105
|
+
}
|
|
106
|
+
throw err;
|
|
107
|
+
}
|
|
108
|
+
log.info("browxai: starting", {
|
|
109
|
+
workspace: workspace.root,
|
|
110
|
+
mode: attachCdp ? "byob" : "managed",
|
|
111
|
+
attachCdp,
|
|
112
|
+
headless,
|
|
113
|
+
engine: browserType ?? "chromium",
|
|
114
|
+
testAttributes: config.testAttributes,
|
|
115
|
+
});
|
|
116
|
+
const server = await createServer({ attachCdp, headless, browserType });
|
|
117
|
+
const shutdown = async (signal) => {
|
|
118
|
+
log.info(`browxai: shutdown (${signal})`);
|
|
119
|
+
await server.shutdown();
|
|
120
|
+
process.exit(0);
|
|
121
|
+
};
|
|
122
|
+
process.on("SIGINT", () => void shutdown("SIGINT"));
|
|
123
|
+
process.on("SIGTERM", () => void shutdown("SIGTERM"));
|
|
124
|
+
await server.start();
|
|
125
|
+
}
|
|
126
|
+
main().catch((err) => {
|
|
127
|
+
log.error("browxai: fatal", { error: err instanceof Error ? err.message : String(err) });
|
|
128
|
+
process.exit(1);
|
|
129
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/** The abstract-namespace socket Chrome-on-Android publishes its DevTools
|
|
2
|
+
* endpoint on. WebView publishes per-process `webview_devtools_remote_<pid>`
|
|
3
|
+
* sockets; this adapter targets the browser socket (the user's real Chrome). */
|
|
4
|
+
export declare const CHROME_ANDROID_SOCKET = "localabstract:chrome_devtools_remote";
|
|
5
|
+
/** A connected adb device row. `state` is `device` for a ready, authorized
|
|
6
|
+
* device; `unauthorized` / `offline` are surfaced so the caller can tell the
|
|
7
|
+
* user to accept the on-device RSA prompt rather than fail opaquely. */
|
|
8
|
+
export interface AdbDevice {
|
|
9
|
+
serial: string;
|
|
10
|
+
state: string;
|
|
11
|
+
}
|
|
12
|
+
/** Runs an adb command and resolves its stdout. Injected so the pure command-
|
|
13
|
+
* construction + parsing logic is unit-testable without a device or a binary. */
|
|
14
|
+
export type AdbRunner = (args: readonly string[]) => Promise<string>;
|
|
15
|
+
/** GETs a URL and resolves the parsed JSON body. Injected for the same reason —
|
|
16
|
+
* the /json/version → wsUrl extraction is testable with a mock. */
|
|
17
|
+
export type Fetcher = (url: string) => Promise<unknown>;
|
|
18
|
+
/** adb is not installed / not on PATH. Structured (names the requirement), not a
|
|
19
|
+
* raw ENOENT crash. */
|
|
20
|
+
export declare class AdbNotInstalledError extends Error {
|
|
21
|
+
constructor(detail?: string);
|
|
22
|
+
}
|
|
23
|
+
/** No usable Android device is connected (none listed, or all unauthorized /
|
|
24
|
+
* offline). Structured — names exactly what the user must do. */
|
|
25
|
+
export declare class NoAndroidDeviceError extends Error {
|
|
26
|
+
readonly devices: readonly AdbDevice[];
|
|
27
|
+
constructor(devices: readonly AdbDevice[]);
|
|
28
|
+
}
|
|
29
|
+
/** The Chrome DevTools socket couldn't be reached on the forwarded port — Chrome
|
|
30
|
+
* isn't open on the device, or web-debugging isn't enabled. Structured. */
|
|
31
|
+
export declare class ChromeSocketUnreachableError extends Error {
|
|
32
|
+
constructor(detail: string);
|
|
33
|
+
}
|
|
34
|
+
/** `adb [-s serial] devices` argv. */
|
|
35
|
+
export declare function devicesArgs(): readonly string[];
|
|
36
|
+
/** `adb [-s serial] forward tcp:<localPort> localabstract:chrome_devtools_remote` argv. */
|
|
37
|
+
export declare function forwardArgs(localPort: number, serial?: string, socket?: string): readonly string[];
|
|
38
|
+
/** `adb [-s serial] forward --remove tcp:<localPort>` argv — the cleanup. */
|
|
39
|
+
export declare function forwardRemoveArgs(localPort: number, serial?: string): readonly string[];
|
|
40
|
+
/** Parse the multi-line `adb devices` output into rows. The first line is the
|
|
41
|
+
* "List of devices attached" header; each subsequent non-empty line is
|
|
42
|
+
* `<serial>\t<state>`. Blank lines + the header are skipped. */
|
|
43
|
+
export declare function parseDevices(stdout: string): AdbDevice[];
|
|
44
|
+
/** Choose the device to attach to. Prefers the requested `serial` if given and
|
|
45
|
+
* ready; else the single ready (`state === "device"`) device. Throws
|
|
46
|
+
* `NoAndroidDeviceError` (naming the unauthorized/offline rows) when no ready
|
|
47
|
+
* device exists, or a structured ambiguity error when several are ready and no
|
|
48
|
+
* serial was specified. */
|
|
49
|
+
export declare function selectDevice(devices: readonly AdbDevice[], serial?: string): AdbDevice;
|
|
50
|
+
/** The DevTools HTTP base URL for a forwarded local port (loopback by
|
|
51
|
+
* construction — adb forwards to 127.0.0.1, reusing byob.ts's loopback policy). */
|
|
52
|
+
export declare function devToolsBaseUrl(localPort: number): string;
|
|
53
|
+
/** The /json/version probe URL for a forwarded local port. */
|
|
54
|
+
export declare function versionUrl(localPort: number): string;
|
|
55
|
+
/** Extract the `webSocketDebuggerUrl` from a parsed /json/version body. Throws
|
|
56
|
+
* `ChromeSocketUnreachableError` when the field is absent (Chrome closed, or an
|
|
57
|
+
* HTML error page came back instead of JSON). This is the field
|
|
58
|
+
* `chromium.connectOverCDP` attaches to — the same browser-level ws endpoint the
|
|
59
|
+
* desktop BYOB path uses. */
|
|
60
|
+
export declare function extractWsUrl(versionBody: unknown): string;
|
|
61
|
+
/** The default adb runner — `execFile("adb", args)`. Maps ENOENT to the
|
|
62
|
+
* structured `AdbNotInstalledError`, and a non-zero exit (with adb present) to a
|
|
63
|
+
* message carrying adb's own stderr. No shell → no injection. */
|
|
64
|
+
export declare const defaultAdbRunner: AdbRunner;
|
|
65
|
+
/** The default fetcher — a JSON GET with a short timeout. A non-OK status or a
|
|
66
|
+
* non-JSON body surfaces as `ChromeSocketUnreachableError` at the call site. */
|
|
67
|
+
export declare const defaultFetcher: Fetcher;
|
|
68
|
+
/** Pick a free local TCP port (loopback) for the adb forward. Lets the OS choose
|
|
69
|
+
* by binding to port 0, then releases it — there's an inherent TOCTOU window,
|
|
70
|
+
* but adb's `forward tcp:<port>` re-binds immediately after, and a clash surfaces
|
|
71
|
+
* as a loud adb error rather than a silent wrong-port attach. */
|
|
72
|
+
export declare function pickFreePort(): Promise<number>;
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
// adb plumbing for the Android engine — discover the Chrome
|
|
2
|
+
// DevTools socket on a USB-connected device and forward it to a loopback port so
|
|
3
|
+
// `chromium.connectOverCDP` can attach to the user's REAL Chrome-on-Android.
|
|
4
|
+
//
|
|
5
|
+
// This module is split into PURE logic (command construction, `adb devices`
|
|
6
|
+
// parsing, the /json/version → webSocketDebuggerUrl extraction, free-port pick)
|
|
7
|
+
// and a thin IO seam (the `AdbRunner` that actually shells out to `adb`, the
|
|
8
|
+
// `Fetcher` that GETs the DevTools HTTP endpoint). The pure half is unit-tested
|
|
9
|
+
// WITHOUT a device; the IO half is exercised by the device-gated keystone.
|
|
10
|
+
//
|
|
11
|
+
// The Chrome-136 default-profile-attach block does NOT apply here. That block
|
|
12
|
+
// targets the DESKTOP `--remote-debugging-port` switch when combined with the
|
|
13
|
+
// default `--user-data-dir`. Android does not use that switch at all: the
|
|
14
|
+
// DevTools endpoint is exposed by the OS as an abstract-namespace unix socket
|
|
15
|
+
// (`localabstract:chrome_devtools_remote`), reachable only after the user
|
|
16
|
+
// enables USB debugging + on-device USB web-debugging. So the full-fidelity
|
|
17
|
+
// BYOB-to-the-real-profile win survives on Android — this is the one
|
|
18
|
+
// place real-profile attach still works post-Chrome-136. See
|
|
19
|
+
// developer.chrome.com/blog/remote-debugging-port (desktop-only) and
|
|
20
|
+
// developer.chrome.com/docs/devtools/remote-debugging (the Android adb path).
|
|
21
|
+
import { execFile } from "node:child_process";
|
|
22
|
+
import { createServer } from "node:net";
|
|
23
|
+
/** The abstract-namespace socket Chrome-on-Android publishes its DevTools
|
|
24
|
+
* endpoint on. WebView publishes per-process `webview_devtools_remote_<pid>`
|
|
25
|
+
* sockets; this adapter targets the browser socket (the user's real Chrome). */
|
|
26
|
+
export const CHROME_ANDROID_SOCKET = "localabstract:chrome_devtools_remote";
|
|
27
|
+
/** adb is not installed / not on PATH. Structured (names the requirement), not a
|
|
28
|
+
* raw ENOENT crash. */
|
|
29
|
+
export class AdbNotInstalledError extends Error {
|
|
30
|
+
constructor(detail) {
|
|
31
|
+
super("adb-missing: the Android Debug Bridge (`adb`) was not found on PATH. The android " +
|
|
32
|
+
"engine attaches to real Chrome-on-Android over adb + CDP. Install the " +
|
|
33
|
+
"Android platform-tools (https://developer.android.com/tools/releases/platform-tools) " +
|
|
34
|
+
"and ensure `adb` is on PATH" +
|
|
35
|
+
(detail ? ` (${detail})` : "") +
|
|
36
|
+
".");
|
|
37
|
+
this.name = "AdbNotInstalledError";
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/** No usable Android device is connected (none listed, or all unauthorized /
|
|
41
|
+
* offline). Structured — names exactly what the user must do. */
|
|
42
|
+
export class NoAndroidDeviceError extends Error {
|
|
43
|
+
devices;
|
|
44
|
+
constructor(devices) {
|
|
45
|
+
const seen = devices.length
|
|
46
|
+
? `adb sees ${devices.length} device entr${devices.length === 1 ? "y" : "ies"}: ` +
|
|
47
|
+
devices.map((d) => `${d.serial} (${d.state})`).join(", ") +
|
|
48
|
+
". An `unauthorized` device needs you to accept the USB-debugging RSA prompt on the " +
|
|
49
|
+
"phone; an `offline` device needs a re-plug."
|
|
50
|
+
: "adb sees no connected devices.";
|
|
51
|
+
super("no-device: no ready Android device is connected. " +
|
|
52
|
+
seen +
|
|
53
|
+
" Connect a phone over USB, enable Developer Options → USB debugging, open Chrome, and " +
|
|
54
|
+
"(for web debugging) enable Chrome → Settings → Developer tools / the on-device USB " +
|
|
55
|
+
"web-debugging toggle.");
|
|
56
|
+
this.name = "NoAndroidDeviceError";
|
|
57
|
+
this.devices = devices;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/** The Chrome DevTools socket couldn't be reached on the forwarded port — Chrome
|
|
61
|
+
* isn't open on the device, or web-debugging isn't enabled. Structured. */
|
|
62
|
+
export class ChromeSocketUnreachableError extends Error {
|
|
63
|
+
constructor(detail) {
|
|
64
|
+
super("chrome-socket-unreachable: forwarded the adb socket but the Chrome DevTools endpoint did " +
|
|
65
|
+
`not answer (${detail}). Open Chrome on the device and enable USB web-debugging ` +
|
|
66
|
+
"(chrome://inspect from the desktop should list the device's tabs).");
|
|
67
|
+
this.name = "ChromeSocketUnreachableError";
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// ─── PURE: adb argv construction ──────────────────────────────────────────────
|
|
71
|
+
// `adb -s <serial>` scopes a command to one device; omitted when no serial (adb
|
|
72
|
+
// targets the single connected device, or errors if ambiguous — which we pre-empt
|
|
73
|
+
// by always resolving a serial first). These build argv arrays for `execFile`
|
|
74
|
+
// (no shell, no injection surface) — they are the unit-tested core.
|
|
75
|
+
/** `adb [-s serial] devices` argv. */
|
|
76
|
+
export function devicesArgs() {
|
|
77
|
+
return ["devices"];
|
|
78
|
+
}
|
|
79
|
+
/** `adb [-s serial] forward tcp:<localPort> localabstract:chrome_devtools_remote` argv. */
|
|
80
|
+
export function forwardArgs(localPort, serial, socket = CHROME_ANDROID_SOCKET) {
|
|
81
|
+
return [...serialFlag(serial), "forward", `tcp:${localPort}`, socket];
|
|
82
|
+
}
|
|
83
|
+
/** `adb [-s serial] forward --remove tcp:<localPort>` argv — the cleanup. */
|
|
84
|
+
export function forwardRemoveArgs(localPort, serial) {
|
|
85
|
+
return [...serialFlag(serial), "forward", "--remove", `tcp:${localPort}`];
|
|
86
|
+
}
|
|
87
|
+
function serialFlag(serial) {
|
|
88
|
+
return serial ? ["-s", serial] : [];
|
|
89
|
+
}
|
|
90
|
+
// ─── PURE: parsers + extractors ───────────────────────────────────────────────
|
|
91
|
+
/** Parse the multi-line `adb devices` output into rows. The first line is the
|
|
92
|
+
* "List of devices attached" header; each subsequent non-empty line is
|
|
93
|
+
* `<serial>\t<state>`. Blank lines + the header are skipped. */
|
|
94
|
+
export function parseDevices(stdout) {
|
|
95
|
+
const rows = [];
|
|
96
|
+
for (const line of stdout.split("\n")) {
|
|
97
|
+
const trimmed = line.trim();
|
|
98
|
+
if (!trimmed)
|
|
99
|
+
continue;
|
|
100
|
+
if (trimmed.toLowerCase().startsWith("list of devices"))
|
|
101
|
+
continue;
|
|
102
|
+
// serial and state are whitespace/tab separated; serial has no spaces.
|
|
103
|
+
const parts = trimmed.split(/\s+/);
|
|
104
|
+
const serial = parts[0];
|
|
105
|
+
const state = parts[1];
|
|
106
|
+
if (!serial || !state)
|
|
107
|
+
continue;
|
|
108
|
+
rows.push({ serial, state });
|
|
109
|
+
}
|
|
110
|
+
return rows;
|
|
111
|
+
}
|
|
112
|
+
/** Choose the device to attach to. Prefers the requested `serial` if given and
|
|
113
|
+
* ready; else the single ready (`state === "device"`) device. Throws
|
|
114
|
+
* `NoAndroidDeviceError` (naming the unauthorized/offline rows) when no ready
|
|
115
|
+
* device exists, or a structured ambiguity error when several are ready and no
|
|
116
|
+
* serial was specified. */
|
|
117
|
+
export function selectDevice(devices, serial) {
|
|
118
|
+
const ready = devices.filter((d) => d.state === "device");
|
|
119
|
+
if (serial) {
|
|
120
|
+
const match = ready.find((d) => d.serial === serial);
|
|
121
|
+
if (match)
|
|
122
|
+
return match;
|
|
123
|
+
throw new NoAndroidDeviceError(devices);
|
|
124
|
+
}
|
|
125
|
+
if (ready.length === 1)
|
|
126
|
+
return ready[0];
|
|
127
|
+
if (ready.length === 0)
|
|
128
|
+
throw new NoAndroidDeviceError(devices);
|
|
129
|
+
throw new Error(`ambiguous-device: ${ready.length} ready Android devices are connected ` +
|
|
130
|
+
`(${ready.map((d) => d.serial).join(", ")}). Pass a serial via BROWX_ANDROID_SERIAL ` +
|
|
131
|
+
"to pick one.");
|
|
132
|
+
}
|
|
133
|
+
/** The DevTools HTTP base URL for a forwarded local port (loopback by
|
|
134
|
+
* construction — adb forwards to 127.0.0.1, reusing byob.ts's loopback policy). */
|
|
135
|
+
export function devToolsBaseUrl(localPort) {
|
|
136
|
+
return `http://127.0.0.1:${localPort}`;
|
|
137
|
+
}
|
|
138
|
+
/** The /json/version probe URL for a forwarded local port. */
|
|
139
|
+
export function versionUrl(localPort) {
|
|
140
|
+
return `${devToolsBaseUrl(localPort)}/json/version`;
|
|
141
|
+
}
|
|
142
|
+
/** Extract the `webSocketDebuggerUrl` from a parsed /json/version body. Throws
|
|
143
|
+
* `ChromeSocketUnreachableError` when the field is absent (Chrome closed, or an
|
|
144
|
+
* HTML error page came back instead of JSON). This is the field
|
|
145
|
+
* `chromium.connectOverCDP` attaches to — the same browser-level ws endpoint the
|
|
146
|
+
* desktop BYOB path uses. */
|
|
147
|
+
export function extractWsUrl(versionBody) {
|
|
148
|
+
const ws = versionBody?.webSocketDebuggerUrl;
|
|
149
|
+
if (typeof ws !== "string" || !ws) {
|
|
150
|
+
throw new ChromeSocketUnreachableError("/json/version returned no webSocketDebuggerUrl (Chrome may be closed or web-debugging off)");
|
|
151
|
+
}
|
|
152
|
+
return ws;
|
|
153
|
+
}
|
|
154
|
+
// ─── IO seam: the default runners ─────────────────────────────────────────────
|
|
155
|
+
/** The default adb runner — `execFile("adb", args)`. Maps ENOENT to the
|
|
156
|
+
* structured `AdbNotInstalledError`, and a non-zero exit (with adb present) to a
|
|
157
|
+
* message carrying adb's own stderr. No shell → no injection. */
|
|
158
|
+
export const defaultAdbRunner = (args) => new Promise((resolve, reject) => {
|
|
159
|
+
execFile("adb", [...args], { timeout: 10_000 }, (err, stdout, stderr) => {
|
|
160
|
+
if (err) {
|
|
161
|
+
const code = err.code;
|
|
162
|
+
if (code === "ENOENT") {
|
|
163
|
+
reject(new AdbNotInstalledError());
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
reject(new Error(`adb ${args.join(" ")} failed: ${stderr || err.message}`));
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
resolve(stdout);
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
/** The default fetcher — a JSON GET with a short timeout. A non-OK status or a
|
|
173
|
+
* non-JSON body surfaces as `ChromeSocketUnreachableError` at the call site. */
|
|
174
|
+
export const defaultFetcher = async (url) => {
|
|
175
|
+
const res = await fetch(url, { signal: AbortSignal.timeout(3000) });
|
|
176
|
+
if (!res.ok) {
|
|
177
|
+
throw new ChromeSocketUnreachableError(`HTTP ${res.status} from ${url}`);
|
|
178
|
+
}
|
|
179
|
+
return res.json();
|
|
180
|
+
};
|
|
181
|
+
/** Pick a free local TCP port (loopback) for the adb forward. Lets the OS choose
|
|
182
|
+
* by binding to port 0, then releases it — there's an inherent TOCTOU window,
|
|
183
|
+
* but adb's `forward tcp:<port>` re-binds immediately after, and a clash surfaces
|
|
184
|
+
* as a loud adb error rather than a silent wrong-port attach. */
|
|
185
|
+
export function pickFreePort() {
|
|
186
|
+
return new Promise((resolve, reject) => {
|
|
187
|
+
const srv = createServer();
|
|
188
|
+
srv.once("error", reject);
|
|
189
|
+
srv.listen(0, "127.0.0.1", () => {
|
|
190
|
+
const addr = srv.address();
|
|
191
|
+
if (addr && typeof addr === "object") {
|
|
192
|
+
const port = addr.port;
|
|
193
|
+
srv.close(() => resolve(port));
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
srv.close(() => reject(new Error("could not determine a free local port for adb forward")));
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { Browser, CDPSession, Page } from "playwright-core";
|
|
2
|
+
import type { EngineCapabilities, EngineKind } from "../types.js";
|
|
3
|
+
import { type AdbRunner, type Fetcher } from "./adb.js";
|
|
4
|
+
/** The handles an Android attach surfaces — the same shape as the Chromium
|
|
5
|
+
* adapter's (a `Browser` + an eager `CDPSession`), plus the bookkeeping the
|
|
6
|
+
* session layer needs to tear the adb forward down on close. */
|
|
7
|
+
export interface AndroidAttachHandles {
|
|
8
|
+
browser: Browser;
|
|
9
|
+
page: Page;
|
|
10
|
+
cdp: CDPSession;
|
|
11
|
+
/** The loopback port the device socket was forwarded to. */
|
|
12
|
+
localPort: number;
|
|
13
|
+
/** The device serial the forward was scoped to (for `forward --remove`). */
|
|
14
|
+
serial: string;
|
|
15
|
+
/** Tears down the adb forward (`adb forward --remove tcp:<port>`). Best-effort;
|
|
16
|
+
* resolves even if the device was unplugged (the forward dies with it). */
|
|
17
|
+
removeForward(): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
/** Injectable dependencies — the IO seam. Defaults shell out to real adb + a real
|
|
20
|
+
* HTTP GET; the unit tests pass mocks so the orchestration is tested device-free. */
|
|
21
|
+
export interface AndroidAdapterDeps {
|
|
22
|
+
runAdb?: AdbRunner;
|
|
23
|
+
fetchJson?: Fetcher;
|
|
24
|
+
pickPort?: () => Promise<number>;
|
|
25
|
+
}
|
|
26
|
+
export declare class AndroidCdpAdapter {
|
|
27
|
+
readonly engine: EngineKind;
|
|
28
|
+
readonly capabilities: EngineCapabilities;
|
|
29
|
+
private readonly runAdb;
|
|
30
|
+
private readonly fetchJson;
|
|
31
|
+
private readonly pickPort;
|
|
32
|
+
constructor(deps?: AndroidAdapterDeps);
|
|
33
|
+
/** Discover a ready device. Lists devices via adb, parses, and selects (the
|
|
34
|
+
* requested serial if given, else the single ready one — structured errors
|
|
35
|
+
* otherwise). Surfaces `adb-missing` / `no-device` without a device crash. */
|
|
36
|
+
discoverDevice(serial?: string): Promise<string>;
|
|
37
|
+
/** The real BYOB path: discover device → forward the Chrome DevTools socket to
|
|
38
|
+
* a free loopback port → GET /json/version → webSocketDebuggerUrl →
|
|
39
|
+
* `chromium.connectOverCDP(wsUrl)`. Returns the `Browser` + eager `CDPSession`
|
|
40
|
+
* the session layer wires its bookkeeping onto, exactly like the Chromium
|
|
41
|
+
* attach, plus the forward-teardown handle. On any failure after the forward
|
|
42
|
+
* is established, the forward is removed before the error propagates (no leaked
|
|
43
|
+
* adb forwards). */
|
|
44
|
+
attach(opts?: {
|
|
45
|
+
serial?: string;
|
|
46
|
+
}): Promise<AndroidAttachHandles>;
|
|
47
|
+
/** Managed / ephemeral LAUNCH is not supported on Android. A phone's Chrome is
|
|
48
|
+
* the user's to open; browxai cannot spawn a browser process it owns on the
|
|
49
|
+
* device. Per the doctrine's no-silent-no-op rule this rejects with a
|
|
50
|
+
* structured, RFC-naming error rather than pretending. Promise-returning (not
|
|
51
|
+
* `async`) so the eslint require-await rule is honest — there is no awaited
|
|
52
|
+
* work, it is a structured refusal. */
|
|
53
|
+
launch(): Promise<never>;
|
|
54
|
+
}
|