@agentrhq/webcmd 0.1.1 → 0.1.2
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/README.md +317 -24
- package/dist/src/adapter-shadow.d.ts +11 -0
- package/dist/src/adapter-shadow.js +72 -0
- package/dist/src/adapter-shadow.test.d.ts +1 -0
- package/dist/src/adapter-shadow.test.js +49 -0
- package/dist/src/adapter-source.d.ts +11 -0
- package/dist/src/adapter-source.js +24 -0
- package/dist/src/adapter-source.test.d.ts +1 -0
- package/dist/src/adapter-source.test.js +29 -0
- package/dist/src/brand.d.ts +9 -0
- package/dist/src/brand.js +9 -0
- package/dist/src/brand.test.d.ts +1 -0
- package/dist/src/brand.test.js +15 -0
- package/dist/src/browser/analyze.d.ts +118 -0
- package/dist/src/browser/analyze.js +405 -0
- package/dist/src/browser/analyze.test.d.ts +1 -0
- package/dist/src/browser/analyze.test.js +209 -0
- package/dist/src/browser/article-extract.d.ts +57 -0
- package/dist/src/browser/article-extract.e2e.test.d.ts +1 -0
- package/dist/src/browser/article-extract.e2e.test.js +105 -0
- package/dist/src/browser/article-extract.js +169 -0
- package/dist/src/browser/article-extract.test.d.ts +1 -0
- package/dist/src/browser/article-extract.test.js +94 -0
- package/dist/src/browser/ax-snapshot.d.ts +37 -0
- package/dist/src/browser/ax-snapshot.js +217 -0
- package/dist/src/browser/ax-snapshot.test.d.ts +1 -0
- package/dist/src/browser/ax-snapshot.test.js +91 -0
- package/dist/src/browser/base-page.d.ts +151 -0
- package/dist/src/browser/base-page.js +1060 -0
- package/dist/src/browser/base-page.test.d.ts +1 -0
- package/dist/src/browser/base-page.test.js +803 -0
- package/dist/src/browser/bridge-readiness.d.ts +14 -0
- package/dist/src/browser/bridge-readiness.js +24 -0
- package/dist/src/browser/bridge-readiness.test.d.ts +1 -0
- package/dist/src/browser/bridge-readiness.test.js +58 -0
- package/dist/src/browser/bridge.d.ts +26 -0
- package/dist/src/browser/bridge.js +58 -0
- package/dist/src/browser/cdp-click-fixture.test.d.ts +1 -0
- package/dist/src/browser/cdp-click-fixture.test.js +87 -0
- package/dist/src/browser/cdp.d.ts +46 -0
- package/dist/src/browser/cdp.js +536 -0
- package/dist/src/browser/cdp.test.d.ts +1 -0
- package/dist/src/browser/cdp.test.js +79 -0
- package/dist/src/browser/compound.d.ts +59 -0
- package/dist/src/browser/compound.js +112 -0
- package/dist/src/browser/compound.test.d.ts +1 -0
- package/dist/src/browser/compound.test.js +175 -0
- package/dist/src/browser/config.d.ts +2 -0
- package/dist/src/browser/config.js +14 -0
- package/dist/src/browser/daemon-client.d.ts +32 -0
- package/dist/src/browser/daemon-client.js +135 -0
- package/dist/src/browser/daemon-client.test.d.ts +1 -0
- package/dist/src/browser/daemon-client.test.js +326 -0
- package/dist/src/browser/daemon-lifecycle.d.ts +37 -0
- package/dist/src/browser/daemon-lifecycle.js +147 -0
- package/dist/src/browser/daemon-transport.d.ts +54 -0
- package/dist/src/browser/daemon-transport.js +68 -0
- package/dist/src/browser/daemon-version.d.ts +4 -0
- package/dist/src/browser/daemon-version.js +12 -0
- package/dist/src/browser/dom-helpers.d.ts +41 -0
- package/dist/src/browser/dom-helpers.js +239 -0
- package/dist/src/browser/dom-helpers.test.d.ts +1 -0
- package/dist/src/browser/dom-helpers.test.js +106 -0
- package/dist/src/browser/dom-snapshot.d.ts +93 -0
- package/dist/src/browser/dom-snapshot.js +894 -0
- package/dist/src/browser/dom-snapshot.test.d.ts +11 -0
- package/dist/src/browser/dom-snapshot.test.js +313 -0
- package/dist/src/browser/errors.d.ts +38 -0
- package/dist/src/browser/errors.js +79 -0
- package/dist/src/browser/errors.test.d.ts +1 -0
- package/dist/src/browser/errors.test.js +60 -0
- package/dist/src/browser/extract.d.ts +69 -0
- package/dist/src/browser/extract.js +132 -0
- package/dist/src/browser/extract.test.d.ts +1 -0
- package/dist/src/browser/extract.test.js +129 -0
- package/dist/src/browser/find.d.ts +84 -0
- package/dist/src/browser/find.js +398 -0
- package/dist/src/browser/find.test.d.ts +1 -0
- package/dist/src/browser/find.test.js +180 -0
- package/dist/src/browser/html-tree.d.ts +75 -0
- package/dist/src/browser/html-tree.js +112 -0
- package/dist/src/browser/html-tree.test.d.ts +1 -0
- package/dist/src/browser/html-tree.test.js +181 -0
- package/dist/src/browser/index.d.ts +14 -0
- package/dist/src/browser/index.js +12 -0
- package/dist/src/browser/network-cache.d.ts +49 -0
- package/dist/src/browser/network-cache.js +78 -0
- package/dist/src/browser/network-cache.test.d.ts +1 -0
- package/dist/src/browser/network-cache.test.js +75 -0
- package/dist/src/browser/network-interceptor.d.ts +11 -0
- package/dist/src/browser/network-interceptor.js +11 -0
- package/dist/src/browser/network-key.d.ts +22 -0
- package/dist/src/browser/network-key.js +66 -0
- package/dist/src/browser/network-key.test.d.ts +1 -0
- package/dist/src/browser/network-key.test.js +49 -0
- package/dist/src/browser/page.d.ts +83 -0
- package/dist/src/browser/page.js +453 -0
- package/dist/src/browser/page.test.d.ts +1 -0
- package/dist/src/browser/page.test.js +406 -0
- package/dist/src/browser/profile.d.ts +14 -0
- package/dist/src/browser/profile.js +86 -0
- package/dist/src/browser/protocol.d.ts +63 -0
- package/dist/src/browser/protocol.js +1 -0
- package/dist/src/browser/runtime/local-cloak/actions.d.ts +3 -0
- package/dist/src/browser/runtime/local-cloak/actions.js +240 -0
- package/dist/src/browser/runtime/local-cloak/downloads.d.ts +3 -0
- package/dist/src/browser/runtime/local-cloak/downloads.js +28 -0
- package/dist/src/browser/runtime/local-cloak/network.d.ts +28 -0
- package/dist/src/browser/runtime/local-cloak/network.js +120 -0
- package/dist/src/browser/runtime/local-cloak/network.test.d.ts +1 -0
- package/dist/src/browser/runtime/local-cloak/network.test.js +124 -0
- package/dist/src/browser/runtime/local-cloak/profiles.d.ts +6 -0
- package/dist/src/browser/runtime/local-cloak/profiles.js +17 -0
- package/dist/src/browser/runtime/local-cloak/profiles.test.d.ts +1 -0
- package/dist/src/browser/runtime/local-cloak/profiles.test.js +19 -0
- package/dist/src/browser/runtime/local-cloak/provider.d.ts +15 -0
- package/dist/src/browser/runtime/local-cloak/provider.js +27 -0
- package/dist/src/browser/runtime/local-cloak/provider.test.d.ts +1 -0
- package/dist/src/browser/runtime/local-cloak/provider.test.js +244 -0
- package/dist/src/browser/runtime/local-cloak/session-manager.d.ts +77 -0
- package/dist/src/browser/runtime/local-cloak/session-manager.js +280 -0
- package/dist/src/browser/runtime/local-cloak/session-manager.test.d.ts +1 -0
- package/dist/src/browser/runtime/local-cloak/session-manager.test.js +92 -0
- package/dist/src/browser/runtime/provider.d.ts +9 -0
- package/dist/src/browser/runtime/provider.js +1 -0
- package/dist/src/browser/runtime/provider.test.d.ts +2 -0
- package/dist/src/browser/runtime/provider.test.js +49 -0
- package/dist/src/browser/shape-filter.d.ts +52 -0
- package/dist/src/browser/shape-filter.js +101 -0
- package/dist/src/browser/shape-filter.test.d.ts +1 -0
- package/dist/src/browser/shape-filter.test.js +101 -0
- package/dist/src/browser/shape.d.ts +23 -0
- package/dist/src/browser/shape.js +95 -0
- package/dist/src/browser/shape.test.d.ts +1 -0
- package/dist/src/browser/shape.test.js +82 -0
- package/dist/src/browser/stealth.d.ts +11 -0
- package/dist/src/browser/stealth.js +359 -0
- package/dist/src/browser/stealth.test.d.ts +1 -0
- package/dist/src/browser/stealth.test.js +134 -0
- package/dist/src/browser/tabs.d.ts +13 -0
- package/dist/src/browser/tabs.js +70 -0
- package/dist/src/browser/target-errors.d.ts +39 -0
- package/dist/src/browser/target-errors.js +45 -0
- package/dist/src/browser/target-errors.test.d.ts +1 -0
- package/dist/src/browser/target-errors.test.js +94 -0
- package/dist/src/browser/target-resolver.d.ts +158 -0
- package/dist/src/browser/target-resolver.js +570 -0
- package/dist/src/browser/target-resolver.test.d.ts +1 -0
- package/dist/src/browser/target-resolver.test.js +118 -0
- package/dist/src/browser/utils.d.ts +20 -0
- package/dist/src/browser/utils.js +64 -0
- package/dist/src/browser/utils.test.d.ts +1 -0
- package/dist/src/browser/utils.test.js +29 -0
- package/dist/src/browser/verify-fixture.d.ts +65 -0
- package/dist/src/browser/verify-fixture.js +318 -0
- package/dist/src/browser/verify-fixture.test.d.ts +1 -0
- package/dist/src/browser/verify-fixture.test.js +219 -0
- package/dist/src/browser/visual-refs.d.ts +11 -0
- package/dist/src/browser/visual-refs.js +108 -0
- package/dist/src/browser.test.d.ts +1 -0
- package/dist/src/browser.test.js +297 -0
- package/dist/src/build-manifest.d.ts +103 -0
- package/dist/src/build-manifest.js +363 -0
- package/dist/src/build-manifest.test.d.ts +1 -0
- package/dist/src/build-manifest.test.js +341 -0
- package/dist/src/capabilityRouting.d.ts +19 -0
- package/dist/src/capabilityRouting.js +56 -0
- package/dist/src/capabilityRouting.test.d.ts +1 -0
- package/dist/src/capabilityRouting.test.js +63 -0
- package/dist/src/cli-argv-preprocess.d.ts +63 -0
- package/dist/src/cli-argv-preprocess.js +303 -0
- package/dist/src/cli-argv-preprocess.test.d.ts +1 -0
- package/dist/src/cli-argv-preprocess.test.js +304 -0
- package/dist/src/cli.d.ts +79 -0
- package/dist/src/cli.js +3350 -0
- package/dist/src/cli.test.d.ts +1 -0
- package/dist/src/cli.test.js +3041 -0
- package/dist/src/commanderAdapter.d.ts +21 -0
- package/dist/src/commanderAdapter.js +208 -0
- package/dist/src/commanderAdapter.test.d.ts +1 -0
- package/dist/src/commanderAdapter.test.js +352 -0
- package/dist/src/commands/auth.d.ts +40 -0
- package/dist/src/commands/auth.js +434 -0
- package/dist/src/commands/auth.test.d.ts +1 -0
- package/dist/src/commands/auth.test.js +252 -0
- package/dist/src/commands/daemon.d.ts +9 -0
- package/dist/src/commands/daemon.js +91 -0
- package/dist/src/commands/daemon.test.d.ts +1 -0
- package/dist/src/commands/daemon.test.js +293 -0
- package/dist/src/completion-fast.d.ts +22 -0
- package/dist/src/completion-fast.js +88 -0
- package/dist/src/completion-shared.d.ts +13 -0
- package/dist/src/completion-shared.js +61 -0
- package/dist/src/completion.d.ts +21 -0
- package/dist/src/completion.js +68 -0
- package/dist/src/completion.test.d.ts +1 -0
- package/dist/src/completion.test.js +24 -0
- package/dist/src/constants.d.ts +18 -0
- package/dist/src/constants.js +41 -0
- package/dist/src/convention-audit.d.ts +50 -0
- package/dist/src/convention-audit.js +553 -0
- package/dist/src/convention-audit.test.d.ts +1 -0
- package/dist/src/convention-audit.test.js +255 -0
- package/dist/src/daemon/server.d.ts +13 -0
- package/dist/src/daemon/server.js +185 -0
- package/dist/src/daemon/server.test.d.ts +1 -0
- package/dist/src/daemon/server.test.js +132 -0
- package/dist/src/daemon-utils.d.ts +18 -0
- package/dist/src/daemon-utils.js +37 -0
- package/dist/src/daemon.d.ts +1 -0
- package/dist/src/daemon.js +27 -0
- package/dist/src/daemon.test.d.ts +1 -0
- package/dist/src/daemon.test.js +60 -0
- package/dist/src/discovery.d.ts +46 -0
- package/dist/src/discovery.js +341 -0
- package/dist/src/doctor.d.ts +39 -0
- package/dist/src/doctor.js +168 -0
- package/dist/src/doctor.test.d.ts +1 -0
- package/dist/src/doctor.test.js +302 -0
- package/dist/src/download/article-download.d.ts +72 -0
- package/dist/src/download/article-download.js +305 -0
- package/dist/src/download/article-download.test.d.ts +1 -0
- package/dist/src/download/article-download.test.js +235 -0
- package/dist/src/download/index.d.ts +71 -0
- package/dist/src/download/index.js +363 -0
- package/dist/src/download/index.test.d.ts +1 -0
- package/dist/src/download/index.test.js +174 -0
- package/dist/src/download/media-download.d.ts +49 -0
- package/dist/src/download/media-download.js +127 -0
- package/dist/src/download/media-download.test.d.ts +1 -0
- package/dist/src/download/media-download.test.js +112 -0
- package/dist/src/download/progress.d.ts +36 -0
- package/dist/src/download/progress.js +120 -0
- package/dist/src/download/progress.test.d.ts +1 -0
- package/dist/src/download/progress.test.js +36 -0
- package/dist/src/electron-apps.d.ts +31 -0
- package/dist/src/electron-apps.js +91 -0
- package/dist/src/electron-apps.test.d.ts +1 -0
- package/dist/src/electron-apps.test.js +76 -0
- package/dist/src/engine.test.d.ts +1 -0
- package/dist/src/engine.test.js +312 -0
- package/dist/src/errors.d.ts +114 -0
- package/dist/src/errors.js +174 -0
- package/dist/src/errors.test.d.ts +1 -0
- package/dist/src/errors.test.js +109 -0
- package/dist/src/execution.d.ts +24 -0
- package/dist/src/execution.js +509 -0
- package/dist/src/execution.test.d.ts +1 -0
- package/dist/src/execution.test.js +645 -0
- package/dist/src/external.d.ts +49 -0
- package/dist/src/external.js +211 -0
- package/dist/src/external.test.d.ts +1 -0
- package/dist/src/external.test.js +110 -0
- package/dist/src/help.d.ts +88 -0
- package/dist/src/help.js +556 -0
- package/dist/src/help.test.d.ts +1 -0
- package/dist/src/help.test.js +58 -0
- package/dist/src/hooks.d.ts +46 -0
- package/dist/src/hooks.js +58 -0
- package/dist/src/hooks.test.d.ts +4 -0
- package/dist/src/hooks.test.js +92 -0
- package/dist/src/interceptor.d.ts +44 -0
- package/dist/src/interceptor.js +183 -0
- package/dist/src/interceptor.test.d.ts +4 -0
- package/dist/src/interceptor.test.js +81 -0
- package/dist/src/launcher.d.ts +41 -0
- package/dist/src/launcher.js +226 -0
- package/dist/src/launcher.test.d.ts +1 -0
- package/dist/src/launcher.test.js +153 -0
- package/dist/src/logger.d.ts +26 -0
- package/dist/src/logger.js +49 -0
- package/dist/src/main.d.ts +5 -0
- package/dist/src/main.js +177 -0
- package/dist/src/manifest-types.d.ts +43 -0
- package/dist/src/manifest-types.js +9 -0
- package/dist/src/node-network.d.ts +10 -0
- package/dist/src/node-network.js +174 -0
- package/dist/src/node-network.test.d.ts +1 -0
- package/dist/src/node-network.test.js +55 -0
- package/dist/src/observation/artifact.d.ts +16 -0
- package/dist/src/observation/artifact.js +260 -0
- package/dist/src/observation/artifact.test.d.ts +1 -0
- package/dist/src/observation/artifact.test.js +121 -0
- package/dist/src/observation/events.d.ts +89 -0
- package/dist/src/observation/events.js +1 -0
- package/dist/src/observation/index.d.ts +7 -0
- package/dist/src/observation/index.js +7 -0
- package/dist/src/observation/manager.d.ts +9 -0
- package/dist/src/observation/manager.js +27 -0
- package/dist/src/observation/manager.test.d.ts +1 -0
- package/dist/src/observation/manager.test.js +13 -0
- package/dist/src/observation/redaction.d.ts +11 -0
- package/dist/src/observation/redaction.js +81 -0
- package/dist/src/observation/redaction.test.d.ts +1 -0
- package/dist/src/observation/redaction.test.js +32 -0
- package/dist/src/observation/retention.d.ts +32 -0
- package/dist/src/observation/retention.js +160 -0
- package/dist/src/observation/retention.test.d.ts +1 -0
- package/dist/src/observation/retention.test.js +118 -0
- package/dist/src/observation/ring-buffer.d.ts +22 -0
- package/dist/src/observation/ring-buffer.js +45 -0
- package/dist/src/observation/ring-buffer.test.d.ts +1 -0
- package/dist/src/observation/ring-buffer.test.js +22 -0
- package/dist/src/observation/session.d.ts +25 -0
- package/dist/src/observation/session.js +50 -0
- package/dist/src/output.d.ts +14 -0
- package/dist/src/output.js +152 -0
- package/dist/src/output.test.d.ts +1 -0
- package/dist/src/output.test.js +53 -0
- package/dist/src/package-exports.test.d.ts +1 -0
- package/dist/src/package-exports.test.js +112 -0
- package/dist/src/package-paths.d.ts +8 -0
- package/dist/src/package-paths.js +41 -0
- package/dist/src/pipeline/executor.d.ts +11 -0
- package/dist/src/pipeline/executor.js +93 -0
- package/dist/src/pipeline/executor.test.d.ts +4 -0
- package/dist/src/pipeline/executor.test.js +182 -0
- package/dist/src/pipeline/index.d.ts +5 -0
- package/dist/src/pipeline/index.js +5 -0
- package/dist/src/pipeline/registry.d.ts +28 -0
- package/dist/src/pipeline/registry.js +55 -0
- package/dist/src/pipeline/steps/browser.d.ts +13 -0
- package/dist/src/pipeline/steps/browser.js +86 -0
- package/dist/src/pipeline/steps/download.d.ts +18 -0
- package/dist/src/pipeline/steps/download.js +252 -0
- package/dist/src/pipeline/steps/download.test.d.ts +1 -0
- package/dist/src/pipeline/steps/download.test.js +102 -0
- package/dist/src/pipeline/steps/fetch.d.ts +5 -0
- package/dist/src/pipeline/steps/fetch.js +122 -0
- package/dist/src/pipeline/steps/fetch.test.d.ts +1 -0
- package/dist/src/pipeline/steps/fetch.test.js +117 -0
- package/dist/src/pipeline/steps/intercept.d.ts +5 -0
- package/dist/src/pipeline/steps/intercept.js +50 -0
- package/dist/src/pipeline/steps/tap.d.ts +12 -0
- package/dist/src/pipeline/steps/tap.js +93 -0
- package/dist/src/pipeline/steps/transform.d.ts +9 -0
- package/dist/src/pipeline/steps/transform.js +70 -0
- package/dist/src/pipeline/template.d.ts +17 -0
- package/dist/src/pipeline/template.js +344 -0
- package/dist/src/pipeline/template.test.d.ts +4 -0
- package/dist/src/pipeline/template.test.js +197 -0
- package/dist/src/pipeline/transform.test.d.ts +4 -0
- package/dist/src/pipeline/transform.test.js +133 -0
- package/dist/src/plugin-manifest.d.ts +70 -0
- package/dist/src/plugin-manifest.js +160 -0
- package/dist/src/plugin-manifest.test.d.ts +4 -0
- package/dist/src/plugin-manifest.test.js +179 -0
- package/dist/src/plugin-scaffold.d.ts +28 -0
- package/dist/src/plugin-scaffold.js +143 -0
- package/dist/src/plugin-scaffold.test.d.ts +4 -0
- package/dist/src/plugin-scaffold.test.js +83 -0
- package/dist/src/plugin.d.ts +146 -0
- package/dist/src/plugin.js +1303 -0
- package/dist/src/plugin.test.d.ts +4 -0
- package/dist/src/plugin.test.js +1363 -0
- package/dist/src/registry-api.d.ts +13 -0
- package/dist/src/registry-api.js +10 -0
- package/dist/src/registry.d.ts +123 -0
- package/dist/src/registry.js +125 -0
- package/dist/src/registry.test.d.ts +4 -0
- package/dist/src/registry.test.js +209 -0
- package/dist/src/runtime-copy.test.d.ts +1 -0
- package/dist/src/runtime-copy.test.js +29 -0
- package/dist/src/runtime-detect.d.ts +31 -0
- package/dist/src/runtime-detect.js +47 -0
- package/dist/src/runtime-detect.test.d.ts +1 -0
- package/dist/src/runtime-detect.test.js +39 -0
- package/dist/src/runtime-identity.test.d.ts +1 -0
- package/dist/src/runtime-identity.test.js +18 -0
- package/dist/src/runtime.d.ts +47 -0
- package/dist/src/runtime.js +54 -0
- package/dist/src/scripts/framework.d.ts +7 -0
- package/dist/src/scripts/framework.js +25 -0
- package/dist/src/scripts/interact.d.ts +4 -0
- package/dist/src/scripts/interact.js +20 -0
- package/dist/src/scripts/store.d.ts +13 -0
- package/dist/src/scripts/store.js +48 -0
- package/dist/src/serialization.d.ts +42 -0
- package/dist/src/serialization.js +103 -0
- package/dist/src/serialization.test.d.ts +1 -0
- package/dist/src/serialization.test.js +78 -0
- package/dist/src/skills.d.ts +14 -0
- package/dist/src/skills.js +127 -0
- package/dist/src/skills.test.d.ts +1 -0
- package/dist/src/skills.test.js +71 -0
- package/dist/src/snapshotFormatter.d.ts +11 -0
- package/dist/src/snapshotFormatter.js +338 -0
- package/dist/src/snapshotFormatter.test.d.ts +7 -0
- package/dist/src/snapshotFormatter.test.js +521 -0
- package/dist/src/tui.d.ts +28 -0
- package/dist/src/tui.js +179 -0
- package/dist/src/tui.test.d.ts +1 -0
- package/dist/src/tui.test.js +19 -0
- package/dist/src/types.d.ts +236 -0
- package/dist/src/types.js +7 -0
- package/dist/src/update-check.d.ts +66 -0
- package/dist/src/update-check.js +206 -0
- package/dist/src/update-check.test.d.ts +1 -0
- package/dist/src/update-check.test.js +117 -0
- package/dist/src/utils.d.ts +57 -0
- package/dist/src/utils.js +152 -0
- package/dist/src/utils.test.d.ts +1 -0
- package/dist/src/utils.test.js +155 -0
- package/dist/src/validate.d.ts +21 -0
- package/dist/src/validate.js +130 -0
- package/dist/src/validate.test.d.ts +9 -0
- package/dist/src/validate.test.js +90 -0
- package/dist/src/verify.d.ts +26 -0
- package/dist/src/verify.js +67 -0
- package/dist/src/version.d.ts +4 -0
- package/dist/src/version.js +22 -0
- package/dist/src/weixin-download.test.d.ts +1 -0
- package/dist/src/weixin-download.test.js +45 -0
- package/package.json +4 -3
- package/scripts/check-package-bin.mjs +95 -0
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Command execution: validates args, manages browser sessions, runs commands.
|
|
3
|
+
*
|
|
4
|
+
* This is the single entry point for executing any CLI command. It handles:
|
|
5
|
+
* 1. Argument validation and coercion
|
|
6
|
+
* 2. Browser session lifecycle (if needed)
|
|
7
|
+
* 3. Domain pre-navigation for cookie strategies
|
|
8
|
+
* 4. Timeout enforcement
|
|
9
|
+
* 5. Lazy-loading of TS modules from manifest
|
|
10
|
+
* 6. Lifecycle hooks (onBeforeExecute / onAfterExecute)
|
|
11
|
+
*/
|
|
12
|
+
import { getRegistry, fullName, } from './registry.js';
|
|
13
|
+
import { pathToFileURL } from 'node:url';
|
|
14
|
+
import * as crypto from 'node:crypto';
|
|
15
|
+
import * as fs from 'node:fs';
|
|
16
|
+
import * as os from 'node:os';
|
|
17
|
+
import { executePipeline } from './pipeline/index.js';
|
|
18
|
+
import { adapterLoadError, ArgumentError, CommandExecutionError, attachTraceReceipt, getErrorMessage } from './errors.js';
|
|
19
|
+
import { shouldUseBrowserSession } from './capabilityRouting.js';
|
|
20
|
+
import { getBrowserFactory, browserSession, runWithTimeout, DEFAULT_BROWSER_COMMAND_TIMEOUT } from './runtime.js';
|
|
21
|
+
import { resolveProfileContextId } from './browser/profile.js';
|
|
22
|
+
import { emitHook } from './hooks.js';
|
|
23
|
+
import { log } from './logger.js';
|
|
24
|
+
import { isElectronApp } from './electron-apps.js';
|
|
25
|
+
import { probeCDP, resolveElectronEndpoint } from './launcher.js';
|
|
26
|
+
import { ObservationSession, exportObservationSession } from './observation/index.js';
|
|
27
|
+
import { resolveAdapterSourcePath } from './adapter-source.js';
|
|
28
|
+
const _loadedModules = new Map();
|
|
29
|
+
/** Track mtime of loaded user adapter files for hot-reload in daemon mode. */
|
|
30
|
+
const _moduleMtimes = new Map();
|
|
31
|
+
const _userClisDir = `${os.homedir()}/.webcmd/clis/`;
|
|
32
|
+
function normalizeTraceMode(raw) {
|
|
33
|
+
if (raw === undefined || raw === null || raw === '' || raw === 'off')
|
|
34
|
+
return 'off';
|
|
35
|
+
if (raw === 'on' || raw === 'retain-on-failure')
|
|
36
|
+
return raw;
|
|
37
|
+
throw new ArgumentError(`--trace must be one of: off, on, retain-on-failure. Received: "${String(raw)}"`);
|
|
38
|
+
}
|
|
39
|
+
export function coerceAndValidateArgs(cmdArgs, kwargs) {
|
|
40
|
+
const result = { ...kwargs };
|
|
41
|
+
for (const argDef of cmdArgs) {
|
|
42
|
+
const val = result[argDef.name];
|
|
43
|
+
if (argDef.required && (val === undefined || val === null || val === '')) {
|
|
44
|
+
throw new ArgumentError(`Argument "${argDef.name}" is required.`, argDef.help ?? `Provide a value for --${argDef.name}`);
|
|
45
|
+
}
|
|
46
|
+
if (val !== undefined && val !== null) {
|
|
47
|
+
if (argDef.type === 'int' || argDef.type === 'number') {
|
|
48
|
+
const num = Number(val);
|
|
49
|
+
if (Number.isNaN(num)) {
|
|
50
|
+
throw new ArgumentError(`Argument "${argDef.name}" must be a valid number. Received: "${val}"`);
|
|
51
|
+
}
|
|
52
|
+
result[argDef.name] = num;
|
|
53
|
+
}
|
|
54
|
+
else if (argDef.type === 'boolean' || argDef.type === 'bool') {
|
|
55
|
+
if (typeof val === 'string') {
|
|
56
|
+
const lower = val.toLowerCase();
|
|
57
|
+
if (lower === 'true' || lower === '1')
|
|
58
|
+
result[argDef.name] = true;
|
|
59
|
+
else if (lower === 'false' || lower === '0')
|
|
60
|
+
result[argDef.name] = false;
|
|
61
|
+
else
|
|
62
|
+
throw new ArgumentError(`Argument "${argDef.name}" must be a boolean (true/false). Received: "${val}"`);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
result[argDef.name] = Boolean(val);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const coercedVal = result[argDef.name];
|
|
69
|
+
if (argDef.choices && argDef.choices.length > 0) {
|
|
70
|
+
if (!argDef.choices.map(String).includes(String(coercedVal))) {
|
|
71
|
+
throw new ArgumentError(`Argument "${argDef.name}" must be one of: ${argDef.choices.join(', ')}. Received: "${coercedVal}"`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
else if (argDef.default !== undefined) {
|
|
76
|
+
result[argDef.name] = argDef.default;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
async function runCommand(cmd, page, kwargs, debug) {
|
|
82
|
+
const internal = cmd;
|
|
83
|
+
if (internal._lazy && internal._modulePath) {
|
|
84
|
+
const modulePath = internal._modulePath;
|
|
85
|
+
// Hot-reload: if a user adapter's file has changed on disk, invalidate cache
|
|
86
|
+
const isUserAdapter = modulePath.startsWith(_userClisDir);
|
|
87
|
+
if (isUserAdapter && _loadedModules.has(modulePath)) {
|
|
88
|
+
try {
|
|
89
|
+
const stat = fs.statSync(modulePath);
|
|
90
|
+
const prevMtime = _moduleMtimes.get(modulePath);
|
|
91
|
+
if (prevMtime !== undefined && stat.mtimeMs !== prevMtime) {
|
|
92
|
+
_loadedModules.delete(modulePath);
|
|
93
|
+
_moduleMtimes.delete(modulePath);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch { /* file may have been deleted; let import below handle it */ }
|
|
97
|
+
}
|
|
98
|
+
if (!_loadedModules.has(modulePath)) {
|
|
99
|
+
const url = pathToFileURL(modulePath).href;
|
|
100
|
+
const importUrl = _moduleMtimes.has(modulePath) ? `${url}?t=${Date.now()}` : url;
|
|
101
|
+
const loadPromise = import(importUrl).then(() => {
|
|
102
|
+
try {
|
|
103
|
+
_moduleMtimes.set(modulePath, fs.statSync(modulePath).mtimeMs);
|
|
104
|
+
}
|
|
105
|
+
catch { }
|
|
106
|
+
}, (err) => {
|
|
107
|
+
_loadedModules.delete(modulePath);
|
|
108
|
+
throw adapterLoadError(`Failed to load adapter module ${modulePath}: ${getErrorMessage(err)}`, 'Check that the adapter file exists and has no syntax errors.');
|
|
109
|
+
});
|
|
110
|
+
_loadedModules.set(modulePath, loadPromise);
|
|
111
|
+
}
|
|
112
|
+
await _loadedModules.get(modulePath);
|
|
113
|
+
const updated = getRegistry().get(fullName(cmd));
|
|
114
|
+
if (updated?.func) {
|
|
115
|
+
return runCommandFunc(updated, page, kwargs, debug);
|
|
116
|
+
}
|
|
117
|
+
if (updated?.pipeline)
|
|
118
|
+
return executePipeline(page, updated.pipeline, { args: kwargs, debug });
|
|
119
|
+
}
|
|
120
|
+
if (cmd.func)
|
|
121
|
+
return runCommandFunc(cmd, page, kwargs, debug);
|
|
122
|
+
if (cmd.pipeline)
|
|
123
|
+
return executePipeline(page, cmd.pipeline, { args: kwargs, debug });
|
|
124
|
+
throw new CommandExecutionError(`Command ${fullName(cmd)} has no func or pipeline`, 'This is likely a bug in the adapter definition. Please report this issue.');
|
|
125
|
+
}
|
|
126
|
+
function runCommandFunc(cmd, page, kwargs, debug) {
|
|
127
|
+
if (cmd.browser === false)
|
|
128
|
+
return cmd.func(kwargs, debug);
|
|
129
|
+
if (!page) {
|
|
130
|
+
throw new CommandExecutionError(`Command ${fullName(cmd)} requires a browser session but none was provided`);
|
|
131
|
+
}
|
|
132
|
+
return cmd.func(page, kwargs, debug);
|
|
133
|
+
}
|
|
134
|
+
function resolvePreNav(cmd) {
|
|
135
|
+
if (cmd.navigateBefore === false)
|
|
136
|
+
return null;
|
|
137
|
+
if (typeof cmd.navigateBefore === 'string')
|
|
138
|
+
return cmd.navigateBefore;
|
|
139
|
+
// strategy → navigateBefore expansion already happened in normalizeCommand().
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
function urlMatchesDomain(url, domain) {
|
|
143
|
+
if (!url || !domain)
|
|
144
|
+
return false;
|
|
145
|
+
try {
|
|
146
|
+
const hostname = new URL(url).hostname;
|
|
147
|
+
return hostname === domain || hostname.endsWith(`.${domain}`);
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function isDomainRootPreNav(preNavUrl, domain) {
|
|
154
|
+
if (!domain)
|
|
155
|
+
return false;
|
|
156
|
+
try {
|
|
157
|
+
const parsed = new URL(preNavUrl);
|
|
158
|
+
const hostnameMatches = parsed.hostname === domain || parsed.hostname.endsWith(`.${domain}`);
|
|
159
|
+
const rootPath = parsed.pathname === '' || parsed.pathname === '/';
|
|
160
|
+
return hostnameMatches && rootPath && parsed.search === '' && parsed.hash === '';
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
async function shouldRunPreNav(cmd, page, siteSession, preNavUrl) {
|
|
167
|
+
if (siteSession !== 'persistent' || !cmd.domain)
|
|
168
|
+
return true;
|
|
169
|
+
if (!isDomainRootPreNav(preNavUrl, cmd.domain))
|
|
170
|
+
return true;
|
|
171
|
+
const currentUrl = await page.getCurrentUrl?.().catch(() => null);
|
|
172
|
+
return !urlMatchesDomain(currentUrl, cmd.domain);
|
|
173
|
+
}
|
|
174
|
+
export async function executeCommand(cmd, rawKwargs, debug = false, opts = {}) {
|
|
175
|
+
let kwargs;
|
|
176
|
+
try {
|
|
177
|
+
kwargs = opts.prepared ? rawKwargs : prepareCommandArgs(cmd, rawKwargs);
|
|
178
|
+
}
|
|
179
|
+
catch (err) {
|
|
180
|
+
if (err instanceof ArgumentError)
|
|
181
|
+
throw err;
|
|
182
|
+
throw new ArgumentError(getErrorMessage(err));
|
|
183
|
+
}
|
|
184
|
+
const userTimeoutSec = readUserTimeoutSeconds(cmd, kwargs);
|
|
185
|
+
const traceMode = normalizeTraceMode(opts.trace);
|
|
186
|
+
const hookCtx = {
|
|
187
|
+
command: fullName(cmd),
|
|
188
|
+
args: kwargs,
|
|
189
|
+
startedAt: Date.now(),
|
|
190
|
+
};
|
|
191
|
+
await emitHook('onBeforeExecute', hookCtx);
|
|
192
|
+
let result;
|
|
193
|
+
try {
|
|
194
|
+
if (shouldUseBrowserSession(cmd)) {
|
|
195
|
+
const electron = isElectronApp(cmd.site);
|
|
196
|
+
let cdpEndpoint;
|
|
197
|
+
if (electron) {
|
|
198
|
+
// Electron apps: respect manual endpoint override, then try auto-detect
|
|
199
|
+
const manualEndpoint = process.env.WEBCMD_CDP_ENDPOINT;
|
|
200
|
+
if (manualEndpoint) {
|
|
201
|
+
const port = Number(new URL(manualEndpoint).port);
|
|
202
|
+
if (!await probeCDP(port)) {
|
|
203
|
+
throw new CommandExecutionError(`CDP not reachable at ${manualEndpoint}`, 'Check that the app is running with --remote-debugging-port and the endpoint is correct.');
|
|
204
|
+
}
|
|
205
|
+
cdpEndpoint = manualEndpoint;
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
cdpEndpoint = await resolveElectronEndpoint(cmd.site);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
const BrowserFactory = getBrowserFactory(cmd.site);
|
|
212
|
+
const contextId = resolveProfileContextId(opts.profile);
|
|
213
|
+
const internal = cmd;
|
|
214
|
+
const siteSession = resolveSiteSession(cmd, opts.siteSession);
|
|
215
|
+
const session = resolveAdapterBrowserSession(cmd, siteSession);
|
|
216
|
+
const keepTab = resolveKeepTab(siteSession, opts.keepTab);
|
|
217
|
+
const windowMode = resolveBrowserWindowMode(cmd.defaultWindowMode ?? 'background', opts.windowMode);
|
|
218
|
+
result = await browserSession(BrowserFactory, async (page) => {
|
|
219
|
+
const observation = traceMode === 'off'
|
|
220
|
+
? null
|
|
221
|
+
: new ObservationSession({
|
|
222
|
+
scope: {
|
|
223
|
+
contextId,
|
|
224
|
+
session,
|
|
225
|
+
target: page.getActivePage?.(),
|
|
226
|
+
site: cmd.site,
|
|
227
|
+
command: fullName(cmd),
|
|
228
|
+
adapterSourcePath: resolveAdapterSourcePath(internal),
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
if (observation) {
|
|
232
|
+
observation.record({
|
|
233
|
+
stream: 'action',
|
|
234
|
+
name: 'command',
|
|
235
|
+
phase: 'start',
|
|
236
|
+
data: { args: kwargs },
|
|
237
|
+
});
|
|
238
|
+
await page.startNetworkCapture?.().catch(() => false);
|
|
239
|
+
}
|
|
240
|
+
const preNavUrl = resolvePreNav(cmd);
|
|
241
|
+
if (preNavUrl && await shouldRunPreNav(cmd, page, siteSession, preNavUrl)) {
|
|
242
|
+
observation?.record({
|
|
243
|
+
stream: 'action',
|
|
244
|
+
name: 'pre_navigate',
|
|
245
|
+
phase: 'start',
|
|
246
|
+
data: { url: preNavUrl },
|
|
247
|
+
});
|
|
248
|
+
// Navigate directly — the extension's handleNavigate already has a fast-path
|
|
249
|
+
// that skips navigation if the tab is already at the target URL.
|
|
250
|
+
// This avoids an extra exec round-trip (getCurrentUrl) on first command and
|
|
251
|
+
// lets the extension create the automation window with the target URL directly
|
|
252
|
+
// instead of about:blank.
|
|
253
|
+
try {
|
|
254
|
+
await page.goto(preNavUrl);
|
|
255
|
+
observation?.record({
|
|
256
|
+
stream: 'action',
|
|
257
|
+
name: 'pre_navigate',
|
|
258
|
+
phase: 'end',
|
|
259
|
+
data: { url: preNavUrl },
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
catch (err) {
|
|
263
|
+
observation?.record({
|
|
264
|
+
stream: 'action',
|
|
265
|
+
name: 'pre_navigate',
|
|
266
|
+
phase: 'error',
|
|
267
|
+
data: { url: preNavUrl, error: err instanceof Error ? err.message : String(err) },
|
|
268
|
+
});
|
|
269
|
+
const wrapped = new CommandExecutionError(`Pre-navigation to ${preNavUrl} failed: ${err instanceof Error ? err.message : err}`, 'Check that the site is reachable and the browser extension is running.');
|
|
270
|
+
if (observation && (traceMode === 'on' || traceMode === 'retain-on-failure')) {
|
|
271
|
+
observation.record({
|
|
272
|
+
stream: 'error',
|
|
273
|
+
message: wrapped.message,
|
|
274
|
+
stack: wrapped.stack,
|
|
275
|
+
code: wrapped.code,
|
|
276
|
+
hint: wrapped.hint,
|
|
277
|
+
});
|
|
278
|
+
await collectObservationEvidence(observation, page).catch(() => { });
|
|
279
|
+
exportTraceArtifact(observation, 'failure', wrapped, opts.onTraceExport);
|
|
280
|
+
}
|
|
281
|
+
throw wrapped;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
try {
|
|
285
|
+
const browserTimeout = userTimeoutSec !== null
|
|
286
|
+
? userTimeoutSec + RUNTIME_TIMEOUT_PADDING_SECONDS
|
|
287
|
+
: DEFAULT_BROWSER_COMMAND_TIMEOUT;
|
|
288
|
+
const result = await runWithTimeout(runCommand(cmd, page, kwargs, debug), {
|
|
289
|
+
timeout: browserTimeout,
|
|
290
|
+
label: fullName(cmd),
|
|
291
|
+
});
|
|
292
|
+
observation?.record({
|
|
293
|
+
stream: 'action',
|
|
294
|
+
name: 'command',
|
|
295
|
+
phase: 'end',
|
|
296
|
+
});
|
|
297
|
+
if (observation && traceMode === 'on') {
|
|
298
|
+
await collectObservationEvidence(observation, page).catch(() => { });
|
|
299
|
+
exportTraceArtifact(observation, 'success', undefined, opts.onTraceExport);
|
|
300
|
+
}
|
|
301
|
+
// Adapter commands are one-shot — release the current tab lease immediately
|
|
302
|
+
// instead of waiting for the 30s idle timeout. The automation container
|
|
303
|
+
// window stays open for reuse.
|
|
304
|
+
if (!keepTab)
|
|
305
|
+
await page.closeWindow?.().catch(() => { });
|
|
306
|
+
return result;
|
|
307
|
+
}
|
|
308
|
+
catch (err) {
|
|
309
|
+
if (observation) {
|
|
310
|
+
observation.record({
|
|
311
|
+
stream: 'action',
|
|
312
|
+
name: 'command',
|
|
313
|
+
phase: 'error',
|
|
314
|
+
data: { error: err instanceof Error ? err.message : String(err) },
|
|
315
|
+
});
|
|
316
|
+
observation.record({
|
|
317
|
+
stream: 'error',
|
|
318
|
+
message: err instanceof Error ? err.message : String(err),
|
|
319
|
+
stack: err instanceof Error ? err.stack : undefined,
|
|
320
|
+
});
|
|
321
|
+
if (traceMode === 'on' || traceMode === 'retain-on-failure') {
|
|
322
|
+
await collectObservationEvidence(observation, page).catch(() => { });
|
|
323
|
+
exportTraceArtifact(observation, 'failure', err, opts.onTraceExport);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
// Release the tab lease on failure too — without this, the lease lingers
|
|
327
|
+
// until the extension's idle timer fires (unreliable on Windows where
|
|
328
|
+
// MV3 service workers may be suspended before setTimeout triggers).
|
|
329
|
+
if (!keepTab)
|
|
330
|
+
await page.closeWindow?.().catch(() => { });
|
|
331
|
+
throw err;
|
|
332
|
+
}
|
|
333
|
+
}, { session, cdpEndpoint, contextId, windowMode, surface: 'adapter', siteSession });
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
// Non-browser commands: enforce a timeout only when the command exposes
|
|
337
|
+
// a `--timeout` arg (and the resolved value is positive). Without that
|
|
338
|
+
// arg there is no meaningful default — non-browser cmds are diverse
|
|
339
|
+
// enough that a hard cap would do more harm than good.
|
|
340
|
+
if (userTimeoutSec !== null) {
|
|
341
|
+
const ceiling = userTimeoutSec + RUNTIME_TIMEOUT_PADDING_SECONDS;
|
|
342
|
+
result = await runWithTimeout(runCommand(cmd, null, kwargs, debug), {
|
|
343
|
+
timeout: ceiling,
|
|
344
|
+
label: fullName(cmd),
|
|
345
|
+
hint: `Pass a higher --timeout value (currently ${userTimeoutSec}s)`,
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
result = await runCommand(cmd, null, kwargs, debug);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
catch (err) {
|
|
354
|
+
hookCtx.error = err;
|
|
355
|
+
hookCtx.finishedAt = Date.now();
|
|
356
|
+
await emitHook('onAfterExecute', hookCtx);
|
|
357
|
+
throw err;
|
|
358
|
+
}
|
|
359
|
+
hookCtx.finishedAt = Date.now();
|
|
360
|
+
await emitHook('onAfterExecute', hookCtx, result);
|
|
361
|
+
return result;
|
|
362
|
+
}
|
|
363
|
+
async function collectObservationEvidence(session, page) {
|
|
364
|
+
const target = page.getActivePage?.() ?? session.scope.target;
|
|
365
|
+
const [url, snapshot, networkEntries, consoleMessages, screenshot] = await Promise.all([
|
|
366
|
+
page.getCurrentUrl?.().catch(() => null) ?? Promise.resolve(null),
|
|
367
|
+
page.snapshot().catch(() => undefined),
|
|
368
|
+
page.readNetworkCapture?.().catch(() => []) ?? Promise.resolve([]),
|
|
369
|
+
page.consoleMessages('all').catch(() => []),
|
|
370
|
+
page.screenshot({ format: 'png' }).catch(() => undefined),
|
|
371
|
+
]);
|
|
372
|
+
if (snapshot !== undefined || url !== undefined) {
|
|
373
|
+
session.record({ stream: 'state', url, target, snapshot, label: 'final' });
|
|
374
|
+
}
|
|
375
|
+
for (const entry of Array.isArray(networkEntries) ? networkEntries : []) {
|
|
376
|
+
const record = entry;
|
|
377
|
+
session.record({
|
|
378
|
+
stream: 'network',
|
|
379
|
+
url: String(record.url ?? ''),
|
|
380
|
+
method: typeof record.method === 'string' ? record.method : undefined,
|
|
381
|
+
status: typeof record.responseStatus === 'number' ? record.responseStatus : undefined,
|
|
382
|
+
contentType: typeof record.responseContentType === 'string' ? record.responseContentType : undefined,
|
|
383
|
+
size: typeof record.responseBodyFullSize === 'number' ? record.responseBodyFullSize : undefined,
|
|
384
|
+
requestHeaders: record.requestHeaders,
|
|
385
|
+
responseHeaders: record.responseHeaders,
|
|
386
|
+
requestBody: record.requestBodyPreview,
|
|
387
|
+
responseBody: record.responsePreview,
|
|
388
|
+
ts: typeof record.timestamp === 'number' ? record.timestamp : undefined,
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
for (const message of Array.isArray(consoleMessages) ? consoleMessages : []) {
|
|
392
|
+
if (message && typeof message === 'object') {
|
|
393
|
+
const record = message;
|
|
394
|
+
session.record({
|
|
395
|
+
stream: 'console',
|
|
396
|
+
level: String(record.type ?? record.level ?? 'log'),
|
|
397
|
+
text: String(record.text ?? record.message ?? ''),
|
|
398
|
+
ts: typeof record.timestamp === 'number' ? record.timestamp : undefined,
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
else {
|
|
402
|
+
session.record({ stream: 'console', level: 'log', text: String(message) });
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
if (typeof screenshot === 'string' && screenshot) {
|
|
406
|
+
session.record({ stream: 'screenshot', format: 'png', data: screenshot, label: 'final' });
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
function exportTraceArtifact(session, status, error, onTraceExport) {
|
|
410
|
+
try {
|
|
411
|
+
const trace = exportObservationSession(session, { error, status });
|
|
412
|
+
if (status === 'failure' && error !== undefined) {
|
|
413
|
+
attachTraceReceipt(error, trace.receipt);
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
process.stderr.write(`Webcmd trace artifact: ${trace.dir}\n`);
|
|
417
|
+
}
|
|
418
|
+
try {
|
|
419
|
+
onTraceExport?.(trace);
|
|
420
|
+
}
|
|
421
|
+
catch (err) {
|
|
422
|
+
log.warn(`[trace] Trace export callback failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
423
|
+
}
|
|
424
|
+
return trace;
|
|
425
|
+
}
|
|
426
|
+
catch (err) {
|
|
427
|
+
log.warn(`[trace] Failed to export trace artifact: ${err instanceof Error ? err.message : String(err)}`);
|
|
428
|
+
return undefined;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
export function prepareCommandArgs(cmd, rawKwargs) {
|
|
432
|
+
const kwargs = coerceAndValidateArgs(cmd.args, rawKwargs);
|
|
433
|
+
cmd.validateArgs?.(kwargs);
|
|
434
|
+
return kwargs;
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Runtime ceiling padding (seconds) added on top of the user's `--timeout`.
|
|
438
|
+
* The adapter's polling loop typically uses the full user value; the padding
|
|
439
|
+
* gives us room for the adapter to return + closeWindow + trace export before
|
|
440
|
+
* the runtime kills the Promise.
|
|
441
|
+
*/
|
|
442
|
+
const RUNTIME_TIMEOUT_PADDING_SECONDS = 30;
|
|
443
|
+
function normalizeSiteSession(raw) {
|
|
444
|
+
if (raw === undefined || raw === null || raw === '')
|
|
445
|
+
return null;
|
|
446
|
+
if (raw === 'ephemeral' || raw === 'persistent')
|
|
447
|
+
return raw;
|
|
448
|
+
throw new ArgumentError(`--site-session must be one of: ephemeral, persistent. Received: "${String(raw)}"`);
|
|
449
|
+
}
|
|
450
|
+
function resolveSiteSession(cmd, rawOption) {
|
|
451
|
+
return normalizeSiteSession(rawOption) ?? cmd.siteSession ?? 'ephemeral';
|
|
452
|
+
}
|
|
453
|
+
function resolveAdapterBrowserSession(cmd, siteSession) {
|
|
454
|
+
if (siteSession === 'persistent')
|
|
455
|
+
return `site:${cmd.site}`;
|
|
456
|
+
return `site:${cmd.site}:${crypto.randomUUID()}`;
|
|
457
|
+
}
|
|
458
|
+
function normalizeBooleanOption(name, raw) {
|
|
459
|
+
if (raw === undefined || raw === '')
|
|
460
|
+
return null;
|
|
461
|
+
if (raw === 'true')
|
|
462
|
+
return true;
|
|
463
|
+
if (raw === 'false')
|
|
464
|
+
return false;
|
|
465
|
+
throw new ArgumentError(`${name} must be one of: true, false. Received: "${String(raw)}"`);
|
|
466
|
+
}
|
|
467
|
+
function resolveKeepTab(siteSession, rawOption) {
|
|
468
|
+
if (siteSession === 'persistent')
|
|
469
|
+
return true;
|
|
470
|
+
return normalizeBooleanOption('--keep-tab', rawOption) ?? false;
|
|
471
|
+
}
|
|
472
|
+
function normalizeWindowMode(name, raw) {
|
|
473
|
+
if (raw === undefined || raw === '')
|
|
474
|
+
return null;
|
|
475
|
+
if (raw === 'foreground' || raw === 'background')
|
|
476
|
+
return raw;
|
|
477
|
+
throw new ArgumentError(`${name} must be one of: foreground, background. Received: "${String(raw)}"`);
|
|
478
|
+
}
|
|
479
|
+
function resolveBrowserWindowMode(defaultMode = 'background', rawOption) {
|
|
480
|
+
return normalizeWindowMode('--window', rawOption)
|
|
481
|
+
?? normalizeWindowMode('WEBCMD_WINDOW', process.env.WEBCMD_WINDOW)
|
|
482
|
+
?? defaultMode;
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Resolve the user-controllable `--timeout` arg, in seconds.
|
|
486
|
+
*
|
|
487
|
+
* Convention: a command opts into runtime-enforced timeouts by declaring an
|
|
488
|
+
* arg named `timeout`. The arg's `default` flows through `prepareCommandArgs`
|
|
489
|
+
* into `kwargs.timeout`, so by the time runtime enforcement runs, the value
|
|
490
|
+
* is the merged user-supplied-or-default seconds.
|
|
491
|
+
*
|
|
492
|
+
* Returns the parsed positive integer (seconds), or null if the command does
|
|
493
|
+
* not expose a `timeout` arg. Declaring `timeout` opts into runtime timeout
|
|
494
|
+
* enforcement, so invalid values must fail upfront instead of silently
|
|
495
|
+
* disabling the runtime ceiling.
|
|
496
|
+
*/
|
|
497
|
+
function readUserTimeoutSeconds(cmd, kwargs) {
|
|
498
|
+
if (!cmd.args.some(a => a.name === 'timeout'))
|
|
499
|
+
return null;
|
|
500
|
+
const raw = kwargs.timeout;
|
|
501
|
+
if (raw === undefined || raw === null || raw === '') {
|
|
502
|
+
throw new ArgumentError(`Argument "timeout" must be a positive integer. Received: "${String(raw)}"`);
|
|
503
|
+
}
|
|
504
|
+
const parsed = Number(raw);
|
|
505
|
+
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
506
|
+
throw new ArgumentError(`Argument "timeout" must be a positive integer. Received: "${String(raw)}"`);
|
|
507
|
+
}
|
|
508
|
+
return parsed;
|
|
509
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|