@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,47 @@
|
|
|
1
|
+
import type { IPage } from './types.js';
|
|
2
|
+
import { DEFAULT_BROWSER_COMMAND_TIMEOUT, DEFAULT_BROWSER_CONNECT_TIMEOUT } from './browser/config.js';
|
|
3
|
+
export { DEFAULT_BROWSER_COMMAND_TIMEOUT, DEFAULT_BROWSER_CONNECT_TIMEOUT };
|
|
4
|
+
/**
|
|
5
|
+
* Returns the appropriate browser factory based on site type.
|
|
6
|
+
* Uses CDPBridge for registered Electron apps, otherwise BrowserBridge.
|
|
7
|
+
*/
|
|
8
|
+
export declare function getBrowserFactory(site?: string): new () => IBrowserFactory;
|
|
9
|
+
export type BrowserWindowMode = 'foreground' | 'background';
|
|
10
|
+
export type BrowserSurface = 'browser' | 'adapter';
|
|
11
|
+
/**
|
|
12
|
+
* Timeout with seconds unit. Used for high-level command timeouts.
|
|
13
|
+
*/
|
|
14
|
+
export declare function runWithTimeout<T>(promise: Promise<T>, opts: {
|
|
15
|
+
timeout: number;
|
|
16
|
+
label?: string;
|
|
17
|
+
hint?: string;
|
|
18
|
+
}): Promise<T>;
|
|
19
|
+
/**
|
|
20
|
+
* Timeout with milliseconds unit. Used for low-level internal timeouts.
|
|
21
|
+
* Accepts a factory function to create the rejection error, keeping this
|
|
22
|
+
* utility decoupled from specific error types.
|
|
23
|
+
*/
|
|
24
|
+
export declare function withTimeoutMs<T>(promise: Promise<T>, timeoutMs: number, makeError?: string | (() => Error)): Promise<T>;
|
|
25
|
+
/** Interface for browser factory (BrowserBridge or test mocks) */
|
|
26
|
+
export interface IBrowserFactory {
|
|
27
|
+
connect(opts?: {
|
|
28
|
+
timeout?: number;
|
|
29
|
+
session?: string;
|
|
30
|
+
cdpEndpoint?: string;
|
|
31
|
+
contextId?: string;
|
|
32
|
+
idleTimeout?: number;
|
|
33
|
+
windowMode?: BrowserWindowMode;
|
|
34
|
+
surface?: BrowserSurface;
|
|
35
|
+
siteSession?: 'ephemeral' | 'persistent';
|
|
36
|
+
}): Promise<IPage>;
|
|
37
|
+
close(): Promise<void>;
|
|
38
|
+
}
|
|
39
|
+
export declare function browserSession<T>(BrowserFactory: new () => IBrowserFactory, fn: (page: IPage) => Promise<T>, opts?: {
|
|
40
|
+
session?: string;
|
|
41
|
+
cdpEndpoint?: string;
|
|
42
|
+
contextId?: string;
|
|
43
|
+
idleTimeout?: number;
|
|
44
|
+
windowMode?: BrowserWindowMode;
|
|
45
|
+
surface?: BrowserSurface;
|
|
46
|
+
siteSession?: 'ephemeral' | 'persistent';
|
|
47
|
+
}): Promise<T>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { BrowserBridge, CDPBridge } from './browser/index.js';
|
|
2
|
+
import { TimeoutError } from './errors.js';
|
|
3
|
+
import { isElectronApp } from './electron-apps.js';
|
|
4
|
+
import { DEFAULT_BROWSER_COMMAND_TIMEOUT, DEFAULT_BROWSER_CONNECT_TIMEOUT } from './browser/config.js';
|
|
5
|
+
export { DEFAULT_BROWSER_COMMAND_TIMEOUT, DEFAULT_BROWSER_CONNECT_TIMEOUT };
|
|
6
|
+
/**
|
|
7
|
+
* Returns the appropriate browser factory based on site type.
|
|
8
|
+
* Uses CDPBridge for registered Electron apps, otherwise BrowserBridge.
|
|
9
|
+
*/
|
|
10
|
+
export function getBrowserFactory(site) {
|
|
11
|
+
if (site && isElectronApp(site))
|
|
12
|
+
return CDPBridge;
|
|
13
|
+
return BrowserBridge;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Timeout with seconds unit. Used for high-level command timeouts.
|
|
17
|
+
*/
|
|
18
|
+
export async function runWithTimeout(promise, opts) {
|
|
19
|
+
const label = opts.label ?? 'Operation';
|
|
20
|
+
return withTimeoutMs(promise, opts.timeout * 1000, () => new TimeoutError(label, opts.timeout, opts.hint));
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Timeout with milliseconds unit. Used for low-level internal timeouts.
|
|
24
|
+
* Accepts a factory function to create the rejection error, keeping this
|
|
25
|
+
* utility decoupled from specific error types.
|
|
26
|
+
*/
|
|
27
|
+
export function withTimeoutMs(promise, timeoutMs, makeError = 'Operation timed out') {
|
|
28
|
+
const reject_ = typeof makeError === 'string'
|
|
29
|
+
? () => new Error(makeError)
|
|
30
|
+
: makeError;
|
|
31
|
+
return new Promise((resolve, reject) => {
|
|
32
|
+
const timer = setTimeout(() => reject(reject_()), timeoutMs);
|
|
33
|
+
promise.then((value) => { clearTimeout(timer); resolve(value); }, (error) => { clearTimeout(timer); reject(error); });
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
export async function browserSession(BrowserFactory, fn, opts = {}) {
|
|
37
|
+
const browser = new BrowserFactory();
|
|
38
|
+
try {
|
|
39
|
+
const page = await browser.connect({
|
|
40
|
+
timeout: DEFAULT_BROWSER_CONNECT_TIMEOUT,
|
|
41
|
+
session: opts.session,
|
|
42
|
+
cdpEndpoint: opts.cdpEndpoint,
|
|
43
|
+
contextId: opts.contextId,
|
|
44
|
+
idleTimeout: opts.idleTimeout,
|
|
45
|
+
windowMode: opts.windowMode,
|
|
46
|
+
surface: opts.surface,
|
|
47
|
+
siteSession: opts.siteSession,
|
|
48
|
+
});
|
|
49
|
+
return await fn(page);
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
await browser.close().catch(() => { });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Injected script for detecting frontend frameworks (Vue, React, Next, Nuxt, etc.)
|
|
3
|
+
*
|
|
4
|
+
* Serialized via `.toString()` and evaluated in the page context. Types here are
|
|
5
|
+
* only for the TS boundary — see scripts/store.ts for the same pattern.
|
|
6
|
+
*/
|
|
7
|
+
export declare function detectFramework(): Record<string, boolean>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Injected script for detecting frontend frameworks (Vue, React, Next, Nuxt, etc.)
|
|
3
|
+
*
|
|
4
|
+
* Serialized via `.toString()` and evaluated in the page context. Types here are
|
|
5
|
+
* only for the TS boundary — see scripts/store.ts for the same pattern.
|
|
6
|
+
*/
|
|
7
|
+
export function detectFramework() {
|
|
8
|
+
const r = {};
|
|
9
|
+
try {
|
|
10
|
+
const app = document.querySelector('#app');
|
|
11
|
+
const w = window;
|
|
12
|
+
r.vue3 = !!(app && app.__vue_app__);
|
|
13
|
+
r.vue2 = !!(app && app.__vue__);
|
|
14
|
+
r.react = !!w.__REACT_DEVTOOLS_GLOBAL_HOOK__ || !!document.querySelector('[data-reactroot]');
|
|
15
|
+
r.nextjs = !!w.__NEXT_DATA__;
|
|
16
|
+
r.nuxt = !!w.__NUXT__;
|
|
17
|
+
if (r.vue3 && app?.__vue_app__) {
|
|
18
|
+
const gp = app.__vue_app__.config?.globalProperties;
|
|
19
|
+
r.pinia = !!(gp && gp.$pinia);
|
|
20
|
+
r.vuex = !!(gp && gp.$store);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
catch { }
|
|
24
|
+
return r;
|
|
25
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Injected script for interactive fuzzing (clicking elements to trigger lazy loading)
|
|
3
|
+
*/
|
|
4
|
+
export async function interactFuzz() {
|
|
5
|
+
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
|
|
6
|
+
const clickables = Array.from(document.querySelectorAll('button, [role="button"], [role="tab"], .tab, .btn, a[href="javascript:void(0)"], a[href="#"]')).slice(0, 15); // limit to a small number to avoid endless loops
|
|
7
|
+
let clicked = 0;
|
|
8
|
+
for (const el of clickables) {
|
|
9
|
+
try {
|
|
10
|
+
const rect = el.getBoundingClientRect();
|
|
11
|
+
if (rect.width > 0 && rect.height > 0) {
|
|
12
|
+
el.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }));
|
|
13
|
+
clicked++;
|
|
14
|
+
await sleep(300); // give it time to trigger network
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
catch { }
|
|
18
|
+
}
|
|
19
|
+
return clicked;
|
|
20
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Injected script for discovering Pinia or Vuex stores and their actions/state representations.
|
|
3
|
+
*
|
|
4
|
+
* This function is serialized via `.toString()` and evaluated inside the page context,
|
|
5
|
+
* so the types below only exist at the TS boundary — the runtime shapes are whatever
|
|
6
|
+
* Pinia/Vuex put on the Vue app. We use narrow structural types for the fields we touch.
|
|
7
|
+
*/
|
|
8
|
+
export declare function discoverStores(): {
|
|
9
|
+
type: string;
|
|
10
|
+
id: string;
|
|
11
|
+
actions: string[];
|
|
12
|
+
stateKeys: string[];
|
|
13
|
+
}[];
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Injected script for discovering Pinia or Vuex stores and their actions/state representations.
|
|
3
|
+
*
|
|
4
|
+
* This function is serialized via `.toString()` and evaluated inside the page context,
|
|
5
|
+
* so the types below only exist at the TS boundary — the runtime shapes are whatever
|
|
6
|
+
* Pinia/Vuex put on the Vue app. We use narrow structural types for the fields we touch.
|
|
7
|
+
*/
|
|
8
|
+
export function discoverStores() {
|
|
9
|
+
const stores = [];
|
|
10
|
+
try {
|
|
11
|
+
const app = document.querySelector('#app');
|
|
12
|
+
if (!app?.__vue_app__)
|
|
13
|
+
return stores;
|
|
14
|
+
const gp = app.__vue_app__.config?.globalProperties;
|
|
15
|
+
// Pinia stores
|
|
16
|
+
const pinia = gp?.$pinia;
|
|
17
|
+
if (pinia?._s) {
|
|
18
|
+
pinia._s.forEach((store, id) => {
|
|
19
|
+
const actions = [];
|
|
20
|
+
const stateKeys = [];
|
|
21
|
+
for (const k in store) {
|
|
22
|
+
try {
|
|
23
|
+
if (k.startsWith('$') || k.startsWith('_'))
|
|
24
|
+
continue;
|
|
25
|
+
if (typeof store[k] === 'function')
|
|
26
|
+
actions.push(k);
|
|
27
|
+
else
|
|
28
|
+
stateKeys.push(k);
|
|
29
|
+
}
|
|
30
|
+
catch { }
|
|
31
|
+
}
|
|
32
|
+
stores.push({ type: 'pinia', id, actions: actions.slice(0, 20), stateKeys: stateKeys.slice(0, 15) });
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
// Vuex store modules
|
|
36
|
+
const vuex = gp?.$store;
|
|
37
|
+
if (vuex?._modules?.root?._children) {
|
|
38
|
+
const children = vuex._modules.root._children;
|
|
39
|
+
for (const [modName, mod] of Object.entries(children)) {
|
|
40
|
+
const actions = Object.keys(mod._rawModule?.actions ?? {}).slice(0, 20);
|
|
41
|
+
const stateKeys = Object.keys(mod.state ?? {}).slice(0, 15);
|
|
42
|
+
stores.push({ type: 'vuex', id: modName, actions, stateKeys });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch { }
|
|
47
|
+
return stores;
|
|
48
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serialization and formatting helpers for CLI commands and args.
|
|
3
|
+
*
|
|
4
|
+
* Used by the `list` command, Commander --help, and build-manifest.
|
|
5
|
+
* Separated from registry.ts to keep the registry focused on types + registration.
|
|
6
|
+
*/
|
|
7
|
+
import type { Arg, CliCommand } from './registry.js';
|
|
8
|
+
export type SerializedArg = {
|
|
9
|
+
name: string;
|
|
10
|
+
type: string;
|
|
11
|
+
required: boolean;
|
|
12
|
+
valueRequired: boolean;
|
|
13
|
+
positional: boolean;
|
|
14
|
+
choices: string[];
|
|
15
|
+
default: unknown;
|
|
16
|
+
help: string;
|
|
17
|
+
};
|
|
18
|
+
/** Stable arg schema — every field is always present (no sparse objects). */
|
|
19
|
+
export declare function serializeArg(a: Arg): SerializedArg;
|
|
20
|
+
/** Full command metadata for structured output (json/yaml). */
|
|
21
|
+
export declare function serializeCommand(cmd: CliCommand): {
|
|
22
|
+
command: string;
|
|
23
|
+
site: string;
|
|
24
|
+
name: string;
|
|
25
|
+
aliases: string[];
|
|
26
|
+
description: string;
|
|
27
|
+
access: import("./registry.js").CommandAccess;
|
|
28
|
+
strategy: string;
|
|
29
|
+
browser: boolean;
|
|
30
|
+
args: SerializedArg[];
|
|
31
|
+
columns: string[];
|
|
32
|
+
domain: string | null;
|
|
33
|
+
example: string;
|
|
34
|
+
defaultFormat: "table" | "plain" | "json" | "yaml" | "yml" | "md" | "markdown" | "csv" | null;
|
|
35
|
+
siteSession: import("./registry.js").SiteSessionMode | null;
|
|
36
|
+
};
|
|
37
|
+
/** Human-readable arg summary: `<required> [optional]` style. */
|
|
38
|
+
export declare function formatArgSummary(args: Arg[]): string;
|
|
39
|
+
/** Agent-facing canonical invocation. Adapter authors may override with `example`. */
|
|
40
|
+
export declare function formatCommandExample(cmd: CliCommand): string;
|
|
41
|
+
/** Generate the --help appendix showing registry metadata not exposed by Commander. */
|
|
42
|
+
export declare function formatRegistryHelpText(cmd: CliCommand): string;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serialization and formatting helpers for CLI commands and args.
|
|
3
|
+
*
|
|
4
|
+
* Used by the `list` command, Commander --help, and build-manifest.
|
|
5
|
+
* Separated from registry.ts to keep the registry focused on types + registration.
|
|
6
|
+
*/
|
|
7
|
+
import { fullName, strategyLabel } from './registry.js';
|
|
8
|
+
import { CLI_COMMAND } from './brand.js';
|
|
9
|
+
/** Stable arg schema — every field is always present (no sparse objects). */
|
|
10
|
+
export function serializeArg(a) {
|
|
11
|
+
return {
|
|
12
|
+
name: a.name,
|
|
13
|
+
type: a.type ?? 'string',
|
|
14
|
+
required: !!a.required,
|
|
15
|
+
valueRequired: !!a.valueRequired,
|
|
16
|
+
positional: !!a.positional,
|
|
17
|
+
choices: a.choices ?? [],
|
|
18
|
+
default: a.default ?? null,
|
|
19
|
+
help: a.help ?? '',
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/** Full command metadata for structured output (json/yaml). */
|
|
23
|
+
export function serializeCommand(cmd) {
|
|
24
|
+
return {
|
|
25
|
+
command: fullName(cmd),
|
|
26
|
+
site: cmd.site,
|
|
27
|
+
name: cmd.name,
|
|
28
|
+
aliases: cmd.aliases ?? [],
|
|
29
|
+
description: cmd.description,
|
|
30
|
+
access: cmd.access,
|
|
31
|
+
strategy: strategyLabel(cmd),
|
|
32
|
+
browser: !!cmd.browser,
|
|
33
|
+
args: cmd.args.map(serializeArg),
|
|
34
|
+
columns: cmd.columns ?? [],
|
|
35
|
+
domain: cmd.domain ?? null,
|
|
36
|
+
example: formatCommandExample(cmd),
|
|
37
|
+
defaultFormat: cmd.defaultFormat ?? null,
|
|
38
|
+
siteSession: cmd.siteSession ?? null,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
// ── Formatting ──────────────────────────────────────────────────────────────
|
|
42
|
+
/** Human-readable arg summary: `<required> [optional]` style. */
|
|
43
|
+
export function formatArgSummary(args) {
|
|
44
|
+
return args
|
|
45
|
+
.map(a => {
|
|
46
|
+
if (a.positional)
|
|
47
|
+
return a.required ? `<${a.name}>` : `[${a.name}]`;
|
|
48
|
+
return a.required ? `--${a.name}` : `[--${a.name}]`;
|
|
49
|
+
})
|
|
50
|
+
.join(' ');
|
|
51
|
+
}
|
|
52
|
+
function summarizeChoices(choices) {
|
|
53
|
+
if (choices.length <= 4)
|
|
54
|
+
return choices.join(', ');
|
|
55
|
+
return `${choices.slice(0, 4).join(', ')}, ... (+${choices.length - 4} more)`;
|
|
56
|
+
}
|
|
57
|
+
function formatValuePlaceholder(name) {
|
|
58
|
+
return `<${name}>`;
|
|
59
|
+
}
|
|
60
|
+
/** Agent-facing canonical invocation. Adapter authors may override with `example`. */
|
|
61
|
+
export function formatCommandExample(cmd) {
|
|
62
|
+
if (cmd.example?.trim())
|
|
63
|
+
return cmd.example.trim();
|
|
64
|
+
const parts = [CLI_COMMAND, cmd.site, cmd.name];
|
|
65
|
+
for (const arg of cmd.args) {
|
|
66
|
+
if (arg.positional && arg.required) {
|
|
67
|
+
parts.push(formatValuePlaceholder(arg.name));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
for (const arg of cmd.args) {
|
|
71
|
+
if (arg.positional || !arg.required)
|
|
72
|
+
continue;
|
|
73
|
+
parts.push(`--${arg.name}`);
|
|
74
|
+
if (arg.type !== 'bool' && arg.type !== 'boolean')
|
|
75
|
+
parts.push(formatValuePlaceholder(arg.name));
|
|
76
|
+
}
|
|
77
|
+
parts.push('-f', 'yaml');
|
|
78
|
+
return parts.join(' ');
|
|
79
|
+
}
|
|
80
|
+
/** Generate the --help appendix showing registry metadata not exposed by Commander. */
|
|
81
|
+
export function formatRegistryHelpText(cmd) {
|
|
82
|
+
const lines = [];
|
|
83
|
+
const choicesArgs = cmd.args.filter(a => a.choices?.length);
|
|
84
|
+
for (const a of choicesArgs) {
|
|
85
|
+
const prefix = a.positional ? `<${a.name}>` : `--${a.name}`;
|
|
86
|
+
const def = a.default != null ? ` (default: ${a.default})` : '';
|
|
87
|
+
lines.push(` ${prefix}: ${summarizeChoices(a.choices)}${def}`);
|
|
88
|
+
}
|
|
89
|
+
const meta = [];
|
|
90
|
+
meta.push(`Access: ${cmd.access}`);
|
|
91
|
+
meta.push(`Browser: ${cmd.browser ? 'yes' : 'no'}`);
|
|
92
|
+
if (cmd.domain)
|
|
93
|
+
meta.push(`Domain: ${cmd.domain}`);
|
|
94
|
+
if (cmd.defaultFormat)
|
|
95
|
+
meta.push(`Default format: ${cmd.defaultFormat}`);
|
|
96
|
+
if (cmd.aliases?.length)
|
|
97
|
+
meta.push(`Aliases: ${cmd.aliases.join(', ')}`);
|
|
98
|
+
lines.push(meta.join(' | '));
|
|
99
|
+
lines.push(`Example: ${formatCommandExample(cmd)}`);
|
|
100
|
+
if (cmd.columns?.length)
|
|
101
|
+
lines.push(`Output columns: ${cmd.columns.join(', ')}`);
|
|
102
|
+
return '\n' + lines.join('\n') + '\n';
|
|
103
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { Strategy } from './registry.js';
|
|
3
|
+
import { formatCommandExample, formatRegistryHelpText, serializeCommand } from './serialization.js';
|
|
4
|
+
describe('formatRegistryHelpText', () => {
|
|
5
|
+
it('summarizes long choices lists so help text stays readable', () => {
|
|
6
|
+
const cmd = {
|
|
7
|
+
site: 'demo',
|
|
8
|
+
name: 'dynamic', access: 'read',
|
|
9
|
+
description: 'Demo command',
|
|
10
|
+
strategy: Strategy.PUBLIC,
|
|
11
|
+
browser: false,
|
|
12
|
+
args: [
|
|
13
|
+
{
|
|
14
|
+
name: 'field',
|
|
15
|
+
help: 'Field to use',
|
|
16
|
+
choices: ['all-fields', 'topic', 'title', 'author', 'publication-titles', 'year-published', 'doi'],
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
columns: ['field'],
|
|
20
|
+
};
|
|
21
|
+
expect(formatRegistryHelpText(cmd)).toContain('--field: all-fields, topic, title, author, ... (+3 more)');
|
|
22
|
+
});
|
|
23
|
+
it('includes aliases in structured serialization and help text', () => {
|
|
24
|
+
const cmd = {
|
|
25
|
+
site: 'demo',
|
|
26
|
+
name: 'get',
|
|
27
|
+
access: 'read',
|
|
28
|
+
aliases: ['metadata'],
|
|
29
|
+
description: 'Demo command',
|
|
30
|
+
strategy: Strategy.COOKIE,
|
|
31
|
+
browser: true,
|
|
32
|
+
args: [],
|
|
33
|
+
};
|
|
34
|
+
expect(serializeCommand(cmd)).toMatchObject({
|
|
35
|
+
command: 'demo/get',
|
|
36
|
+
access: 'read',
|
|
37
|
+
aliases: ['metadata'],
|
|
38
|
+
});
|
|
39
|
+
expect(formatRegistryHelpText(cmd)).toContain('Aliases: metadata');
|
|
40
|
+
});
|
|
41
|
+
it('surfaces access and canonical examples instead of strategy as primary help metadata', () => {
|
|
42
|
+
const cmd = {
|
|
43
|
+
site: 'bilibili',
|
|
44
|
+
name: 'hot',
|
|
45
|
+
access: 'read',
|
|
46
|
+
description: 'Bilibili hot videos',
|
|
47
|
+
strategy: Strategy.COOKIE,
|
|
48
|
+
browser: true,
|
|
49
|
+
args: [],
|
|
50
|
+
};
|
|
51
|
+
expect(formatCommandExample(cmd)).toBe('webcmd bilibili hot -f yaml');
|
|
52
|
+
expect(serializeCommand(cmd)).toMatchObject({
|
|
53
|
+
command: 'bilibili/hot',
|
|
54
|
+
access: 'read',
|
|
55
|
+
example: 'webcmd bilibili hot -f yaml',
|
|
56
|
+
});
|
|
57
|
+
expect(formatRegistryHelpText(cmd)).toContain('Access: read');
|
|
58
|
+
expect(formatRegistryHelpText(cmd)).toContain('Example: webcmd bilibili hot -f yaml');
|
|
59
|
+
expect(formatRegistryHelpText(cmd)).not.toContain('Strategy:');
|
|
60
|
+
});
|
|
61
|
+
it('surfaces command default output format in structured serialization and help text', () => {
|
|
62
|
+
const cmd = {
|
|
63
|
+
site: 'gemini',
|
|
64
|
+
name: 'ask',
|
|
65
|
+
access: 'read',
|
|
66
|
+
description: 'Ask Gemini',
|
|
67
|
+
strategy: Strategy.COOKIE,
|
|
68
|
+
browser: true,
|
|
69
|
+
args: [],
|
|
70
|
+
defaultFormat: 'plain',
|
|
71
|
+
};
|
|
72
|
+
expect(serializeCommand(cmd)).toMatchObject({
|
|
73
|
+
command: 'gemini/ask',
|
|
74
|
+
defaultFormat: 'plain',
|
|
75
|
+
});
|
|
76
|
+
expect(formatRegistryHelpText(cmd)).toContain('Default format: plain');
|
|
77
|
+
});
|
|
78
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface WebcmdSkillInfo {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
version: string;
|
|
5
|
+
path: string;
|
|
6
|
+
}
|
|
7
|
+
export interface WebcmdSkillReadResult {
|
|
8
|
+
skill: string;
|
|
9
|
+
path: string;
|
|
10
|
+
content: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function getSkillsRoot(packageRoot?: string): string;
|
|
13
|
+
export declare function listWebcmdSkills(packageRoot?: string): WebcmdSkillInfo[];
|
|
14
|
+
export declare function readWebcmdSkill(target: string, relpath?: string, packageRoot?: string): WebcmdSkillReadResult;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import yaml from 'js-yaml';
|
|
5
|
+
import { ArgumentError } from './errors.js';
|
|
6
|
+
import { findPackageRoot } from './package-paths.js';
|
|
7
|
+
const MODULE_FILE = fileURLToPath(import.meta.url);
|
|
8
|
+
export function getSkillsRoot(packageRoot = findPackageRoot(MODULE_FILE)) {
|
|
9
|
+
return path.join(packageRoot, 'skills');
|
|
10
|
+
}
|
|
11
|
+
export function listWebcmdSkills(packageRoot) {
|
|
12
|
+
const skillsRoot = getSkillsRoot(packageRoot);
|
|
13
|
+
if (!fs.existsSync(skillsRoot))
|
|
14
|
+
return [];
|
|
15
|
+
return fs.readdirSync(skillsRoot, { withFileTypes: true })
|
|
16
|
+
.filter((entry) => entry.isDirectory() && entry.name.startsWith('webcmd-'))
|
|
17
|
+
.map((entry) => readSkillInfo(skillsRoot, entry.name))
|
|
18
|
+
.filter((entry) => entry !== null)
|
|
19
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
20
|
+
}
|
|
21
|
+
export function readWebcmdSkill(target, relpath = '', packageRoot) {
|
|
22
|
+
const { name, pathInSkill } = parseSkillTarget(target, relpath);
|
|
23
|
+
if (!name.startsWith('webcmd-')) {
|
|
24
|
+
throw new ArgumentError(`Unknown Webcmd skill: ${name}`, 'Run "webcmd skills list" to see available Webcmd skills.');
|
|
25
|
+
}
|
|
26
|
+
const skillsRoot = getSkillsRoot(packageRoot);
|
|
27
|
+
const skillRoot = path.join(skillsRoot, name);
|
|
28
|
+
if (!isDirectory(skillRoot) || !fs.existsSync(path.join(skillRoot, 'SKILL.md'))) {
|
|
29
|
+
throw new ArgumentError(`Unknown Webcmd skill: ${name}`, 'Run "webcmd skills list" to see available Webcmd skills.');
|
|
30
|
+
}
|
|
31
|
+
const relativePath = normalizeSkillPath(pathInSkill || 'SKILL.md');
|
|
32
|
+
const absolutePath = path.resolve(skillRoot, relativePath);
|
|
33
|
+
const relativeToRoot = path.relative(skillRoot, absolutePath);
|
|
34
|
+
if (relativeToRoot.startsWith('..') || path.isAbsolute(relativeToRoot)) {
|
|
35
|
+
throw new ArgumentError(`Invalid skill path: ${relativePath}`, 'Skill paths must stay inside the selected Webcmd skill.');
|
|
36
|
+
}
|
|
37
|
+
if (!fs.existsSync(absolutePath) || !fs.statSync(absolutePath).isFile()) {
|
|
38
|
+
throw new ArgumentError(`Skill file not found: ${name}/${relativePath}`, 'Run "webcmd skills list <skill>" is not supported yet; read SKILL.md or a known references/... file.');
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
skill: name,
|
|
42
|
+
path: relativePath,
|
|
43
|
+
content: fs.readFileSync(absolutePath, 'utf8'),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function readSkillInfo(skillsRoot, name) {
|
|
47
|
+
const skillMdPath = path.join(skillsRoot, name, 'SKILL.md');
|
|
48
|
+
if (!fs.existsSync(skillMdPath))
|
|
49
|
+
return null;
|
|
50
|
+
const content = fs.readFileSync(skillMdPath, 'utf8');
|
|
51
|
+
const fm = parseFrontmatter(content);
|
|
52
|
+
return {
|
|
53
|
+
name: typeof fm.name === 'string' && fm.name ? fm.name : name,
|
|
54
|
+
description: typeof fm.description === 'string' ? fm.description : firstBodyParagraph(content),
|
|
55
|
+
version: typeof fm.version === 'string' || typeof fm.version === 'number' ? String(fm.version) : '',
|
|
56
|
+
path: `${name}/SKILL.md`,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function parseSkillTarget(target, relpath) {
|
|
60
|
+
const normalizedTarget = normalizeSkillPath(target);
|
|
61
|
+
if (relpath) {
|
|
62
|
+
return { name: normalizedTarget, pathInSkill: relpath };
|
|
63
|
+
}
|
|
64
|
+
const slash = normalizedTarget.indexOf('/');
|
|
65
|
+
if (slash === -1) {
|
|
66
|
+
return { name: normalizedTarget, pathInSkill: '' };
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
name: normalizedTarget.slice(0, slash),
|
|
70
|
+
pathInSkill: normalizedTarget.slice(slash + 1),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function normalizeSkillPath(raw) {
|
|
74
|
+
const normalized = raw.trim().replace(/\\/g, '/');
|
|
75
|
+
if (!normalized || normalized.includes('\0')) {
|
|
76
|
+
throw new ArgumentError('Skill path must be non-empty.');
|
|
77
|
+
}
|
|
78
|
+
if (normalized.startsWith('/') || normalized.split('/').some((part) => part === '..')) {
|
|
79
|
+
throw new ArgumentError(`Invalid skill path: ${raw}`, 'Use a path relative to a Webcmd skill directory.');
|
|
80
|
+
}
|
|
81
|
+
return path.posix.normalize(normalized);
|
|
82
|
+
}
|
|
83
|
+
function parseFrontmatter(content) {
|
|
84
|
+
if (!content.startsWith('---\n'))
|
|
85
|
+
return {};
|
|
86
|
+
const end = content.indexOf('\n---', 4);
|
|
87
|
+
if (end < 0)
|
|
88
|
+
return {};
|
|
89
|
+
try {
|
|
90
|
+
const parsed = yaml.load(content.slice(4, end));
|
|
91
|
+
return parsed && typeof parsed === 'object' ? parsed : {};
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return parseLooseFrontmatter(content.slice(4, end));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function parseLooseFrontmatter(raw) {
|
|
98
|
+
const out = {};
|
|
99
|
+
for (const line of raw.split('\n')) {
|
|
100
|
+
const match = /^([A-Za-z][A-Za-z0-9_-]*)\s*:\s*(.*)$/.exec(line);
|
|
101
|
+
if (!match)
|
|
102
|
+
continue;
|
|
103
|
+
const [, key, value] = match;
|
|
104
|
+
if (!['name', 'description', 'version'].includes(key))
|
|
105
|
+
continue;
|
|
106
|
+
out[key] = value.trim().replace(/^['"]|['"]$/g, '');
|
|
107
|
+
}
|
|
108
|
+
return out;
|
|
109
|
+
}
|
|
110
|
+
function firstBodyParagraph(content) {
|
|
111
|
+
const body = content.startsWith('---\n')
|
|
112
|
+
? content.slice(Math.max(content.indexOf('\n---', 4) + 4, 0))
|
|
113
|
+
: content;
|
|
114
|
+
const paragraph = body
|
|
115
|
+
.split(/\n\s*\n/)
|
|
116
|
+
.map((part) => part.replace(/^#+\s*/gm, '').trim())
|
|
117
|
+
.find(Boolean);
|
|
118
|
+
return paragraph ?? '';
|
|
119
|
+
}
|
|
120
|
+
function isDirectory(filePath) {
|
|
121
|
+
try {
|
|
122
|
+
return fs.statSync(filePath).isDirectory();
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as os from 'node:os';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import { describe, expect, it } from 'vitest';
|
|
5
|
+
import { ArgumentError } from './errors.js';
|
|
6
|
+
import { listWebcmdSkills, readWebcmdSkill } from './skills.js';
|
|
7
|
+
function makePackageRoot() {
|
|
8
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'webcmd-skills-'));
|
|
9
|
+
fs.mkdirSync(path.join(root, 'skills', 'webcmd-browser', 'references'), { recursive: true });
|
|
10
|
+
fs.mkdirSync(path.join(root, 'skills', 'webcmd-autofix'), { recursive: true });
|
|
11
|
+
fs.mkdirSync(path.join(root, 'skills', 'smart-search'), { recursive: true });
|
|
12
|
+
fs.writeFileSync(path.join(root, 'package.json'), '{"name":"@agentrhq/webcmd"}\n');
|
|
13
|
+
fs.writeFileSync(path.join(root, 'skills', 'webcmd-browser', 'SKILL.md'), [
|
|
14
|
+
'---',
|
|
15
|
+
'name: webcmd-browser',
|
|
16
|
+
'description: Browser control skill',
|
|
17
|
+
'version: 1.2.3',
|
|
18
|
+
'---',
|
|
19
|
+
'',
|
|
20
|
+
'# Browser',
|
|
21
|
+
'',
|
|
22
|
+
'Body.',
|
|
23
|
+
'',
|
|
24
|
+
].join('\n'));
|
|
25
|
+
fs.writeFileSync(path.join(root, 'skills', 'webcmd-browser', 'references', 'targets.md'), '# Targets\n');
|
|
26
|
+
fs.writeFileSync(path.join(root, 'skills', 'webcmd-autofix', 'SKILL.md'), [
|
|
27
|
+
'---',
|
|
28
|
+
'name: webcmd-autofix',
|
|
29
|
+
'description: Fix adapters: keep scope narrow',
|
|
30
|
+
'---',
|
|
31
|
+
'',
|
|
32
|
+
].join('\n'));
|
|
33
|
+
fs.writeFileSync(path.join(root, 'skills', 'smart-search', 'SKILL.md'), [
|
|
34
|
+
'---',
|
|
35
|
+
'name: smart-search',
|
|
36
|
+
'description: Search skill',
|
|
37
|
+
'---',
|
|
38
|
+
'',
|
|
39
|
+
].join('\n'));
|
|
40
|
+
return root;
|
|
41
|
+
}
|
|
42
|
+
describe('webcmd skills content', () => {
|
|
43
|
+
it('lists only webcmd-prefixed skills', () => {
|
|
44
|
+
const root = makePackageRoot();
|
|
45
|
+
expect(listWebcmdSkills(root).map((skill) => skill.name)).toEqual([
|
|
46
|
+
'webcmd-autofix',
|
|
47
|
+
'webcmd-browser',
|
|
48
|
+
]);
|
|
49
|
+
expect(listWebcmdSkills(root).find((skill) => skill.name === 'webcmd-autofix')?.description)
|
|
50
|
+
.toBe('Fix adapters: keep scope narrow');
|
|
51
|
+
});
|
|
52
|
+
it('reads a skill SKILL.md and reference file', () => {
|
|
53
|
+
const root = makePackageRoot();
|
|
54
|
+
expect(readWebcmdSkill('webcmd-browser', '', root)).toMatchObject({
|
|
55
|
+
skill: 'webcmd-browser',
|
|
56
|
+
path: 'SKILL.md',
|
|
57
|
+
});
|
|
58
|
+
expect(readWebcmdSkill('webcmd-browser/references/targets.md', '', root)).toMatchObject({
|
|
59
|
+
skill: 'webcmd-browser',
|
|
60
|
+
path: 'references/targets.md',
|
|
61
|
+
content: '# Targets\n',
|
|
62
|
+
});
|
|
63
|
+
expect(readWebcmdSkill('webcmd-browser', 'references/targets.md', root).content).toBe('# Targets\n');
|
|
64
|
+
});
|
|
65
|
+
it('rejects non-webcmd skills and path traversal', () => {
|
|
66
|
+
const root = makePackageRoot();
|
|
67
|
+
expect(() => readWebcmdSkill('smart-search', '', root)).toThrow(ArgumentError);
|
|
68
|
+
expect(() => readWebcmdSkill('webcmd-browser/../smart-search/SKILL.md', '', root)).toThrow(ArgumentError);
|
|
69
|
+
expect(() => readWebcmdSkill('webcmd-browser', '../../package.json', root)).toThrow(ArgumentError);
|
|
70
|
+
});
|
|
71
|
+
});
|