@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 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { COMMAND_RESULT_UNKNOWN_CODE, COMMAND_RESULT_UNKNOWN_HINT, buildCommandDispatchFailure, buildExtensionDisconnectFailure, commandResultUnknownMessage, getResponseCorsHeaders, } from './daemon-utils.js';
|
|
3
|
+
describe('getResponseCorsHeaders', () => {
|
|
4
|
+
it('allows the packaged runtime origin to read /ping', () => {
|
|
5
|
+
expect(getResponseCorsHeaders('/ping', 'chrome-extension://abc123')).toEqual({
|
|
6
|
+
'Access-Control-Allow-Origin': 'chrome-extension://abc123',
|
|
7
|
+
Vary: 'Origin',
|
|
8
|
+
});
|
|
9
|
+
});
|
|
10
|
+
it('does not add CORS headers for ordinary web origins', () => {
|
|
11
|
+
expect(getResponseCorsHeaders('/ping', 'https://example.com')).toBeUndefined();
|
|
12
|
+
});
|
|
13
|
+
it('does not add CORS headers when origin is absent', () => {
|
|
14
|
+
expect(getResponseCorsHeaders('/ping')).toBeUndefined();
|
|
15
|
+
});
|
|
16
|
+
it('does not add CORS headers for command endpoints even from the packaged runtime origin', () => {
|
|
17
|
+
expect(getResponseCorsHeaders('/command', 'chrome-extension://abc123')).toBeUndefined();
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
describe('daemon command dispatch', () => {
|
|
21
|
+
it('uses a distinct command_result_unknown contract for ambiguous dispatched commands', () => {
|
|
22
|
+
expect(COMMAND_RESULT_UNKNOWN_CODE).toBe('command_result_unknown');
|
|
23
|
+
expect(commandResultUnknownMessage('navigate')).toContain('navigate command was dispatched');
|
|
24
|
+
expect(COMMAND_RESULT_UNKNOWN_HINT).toContain('Inspect the browser/session state');
|
|
25
|
+
expect(COMMAND_RESULT_UNKNOWN_HINT).toContain('Do not blindly retry write commands');
|
|
26
|
+
});
|
|
27
|
+
it('classifies dispatched extension disconnects as command_result_unknown', () => {
|
|
28
|
+
expect(buildExtensionDisconnectFailure({
|
|
29
|
+
contextId: 'work',
|
|
30
|
+
action: 'navigate',
|
|
31
|
+
dispatched: true,
|
|
32
|
+
})).toEqual({
|
|
33
|
+
message: 'Browser connection dropped after the navigate command was dispatched; it may have completed.',
|
|
34
|
+
errorCode: 'command_result_unknown',
|
|
35
|
+
errorHint: COMMAND_RESULT_UNKNOWN_HINT,
|
|
36
|
+
status: 503,
|
|
37
|
+
countAsCommandResultUnknown: true,
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
it('classifies pre-dispatch extension disconnects as profile_disconnected', () => {
|
|
41
|
+
expect(buildExtensionDisconnectFailure({
|
|
42
|
+
contextId: 'work',
|
|
43
|
+
action: 'navigate',
|
|
44
|
+
dispatched: false,
|
|
45
|
+
})).toMatchObject({
|
|
46
|
+
message: 'Browser profile "work" disconnected before command dispatch',
|
|
47
|
+
errorCode: 'profile_disconnected',
|
|
48
|
+
status: 503,
|
|
49
|
+
countAsCommandResultUnknown: false,
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
it('classifies ws.send dispatch failures as profile_disconnected', () => {
|
|
53
|
+
expect(buildCommandDispatchFailure('work')).toMatchObject({
|
|
54
|
+
message: 'Browser profile "work" disconnected before command dispatch',
|
|
55
|
+
errorCode: 'profile_disconnected',
|
|
56
|
+
status: 503,
|
|
57
|
+
countAsCommandResultUnknown: false,
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI discovery: finds JS CLI definitions and registers them.
|
|
3
|
+
*
|
|
4
|
+
* Supports two modes:
|
|
5
|
+
* 1. FAST PATH (manifest): If a pre-compiled cli-manifest.json exists,
|
|
6
|
+
* registers commands instantly. JS modules are loaded lazily only
|
|
7
|
+
* when their command is executed.
|
|
8
|
+
* 2. FALLBACK (filesystem scan): Traditional runtime discovery for development.
|
|
9
|
+
*/
|
|
10
|
+
/** User runtime directory: ~/.webcmd */
|
|
11
|
+
export declare function getUserWebcmdDir(homeDir?: string): string;
|
|
12
|
+
export declare function getUserClisDir(homeDir?: string): string;
|
|
13
|
+
export declare function getPluginsDir(homeDir?: string): string;
|
|
14
|
+
/** User runtime directory: ~/.webcmd */
|
|
15
|
+
export declare const USER_WEBCMD_DIR: string;
|
|
16
|
+
/** User CLIs directory: ~/.webcmd/clis */
|
|
17
|
+
export declare const USER_CLIS_DIR: string;
|
|
18
|
+
/** Plugins directory: ~/.webcmd/plugins/ */
|
|
19
|
+
export declare const PLUGINS_DIR: string;
|
|
20
|
+
/**
|
|
21
|
+
* Ensure ~/.webcmd/node_modules/<package> symlink exists so user CLIs can
|
|
22
|
+
* import runtime exports from the installed package.
|
|
23
|
+
*
|
|
24
|
+
* This is the sole resolution mechanism — adapters use package exports and
|
|
25
|
+
* Node.js resolves them through this symlink.
|
|
26
|
+
*/
|
|
27
|
+
export declare function ensureUserCliCompatShims(baseDir?: string): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Ensure the user adapters directory exists.
|
|
30
|
+
*
|
|
31
|
+
* With smart sync, ~/.webcmd/clis/ only holds files that differ from the
|
|
32
|
+
* package baseline (upstream-synced cache + autofix output + user overrides).
|
|
33
|
+
* Built-in adapters are loaded directly from the installed package.
|
|
34
|
+
*/
|
|
35
|
+
export declare function ensureUserAdapters(): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Discover and register CLI commands.
|
|
38
|
+
* Uses pre-compiled manifest when available for instant startup.
|
|
39
|
+
*/
|
|
40
|
+
export declare function discoverClis(...dirs: string[]): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Discover and register plugins from ~/.webcmd/plugins/.
|
|
43
|
+
* Each subdirectory is treated as a plugin (site = directory name).
|
|
44
|
+
* Files inside are scanned flat (no nested site subdirs).
|
|
45
|
+
*/
|
|
46
|
+
export declare function discoverPlugins(): Promise<void>;
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI discovery: finds JS CLI definitions and registers them.
|
|
3
|
+
*
|
|
4
|
+
* Supports two modes:
|
|
5
|
+
* 1. FAST PATH (manifest): If a pre-compiled cli-manifest.json exists,
|
|
6
|
+
* registers commands instantly. JS modules are loaded lazily only
|
|
7
|
+
* when their command is executed.
|
|
8
|
+
* 2. FALLBACK (filesystem scan): Traditional runtime discovery for development.
|
|
9
|
+
*/
|
|
10
|
+
import * as fs from 'node:fs';
|
|
11
|
+
import * as os from 'node:os';
|
|
12
|
+
import * as path from 'node:path';
|
|
13
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
14
|
+
import { Strategy, registerCommand } from './registry.js';
|
|
15
|
+
import { getErrorMessage } from './errors.js';
|
|
16
|
+
import { log } from './logger.js';
|
|
17
|
+
import { findPackageRoot, getCliManifestPath } from './package-paths.js';
|
|
18
|
+
import { CONFIG_DIR_NAME, PACKAGE_NAME, PRODUCT_NAME } from './brand.js';
|
|
19
|
+
/** User runtime directory: ~/.webcmd */
|
|
20
|
+
export function getUserWebcmdDir(homeDir = os.homedir()) {
|
|
21
|
+
return path.join(homeDir, CONFIG_DIR_NAME);
|
|
22
|
+
}
|
|
23
|
+
export function getUserClisDir(homeDir = os.homedir()) {
|
|
24
|
+
return path.join(getUserWebcmdDir(homeDir), 'clis');
|
|
25
|
+
}
|
|
26
|
+
export function getPluginsDir(homeDir = os.homedir()) {
|
|
27
|
+
return path.join(getUserWebcmdDir(homeDir), 'plugins');
|
|
28
|
+
}
|
|
29
|
+
/** User runtime directory: ~/.webcmd */
|
|
30
|
+
export const USER_WEBCMD_DIR = getUserWebcmdDir();
|
|
31
|
+
/** User CLIs directory: ~/.webcmd/clis */
|
|
32
|
+
export const USER_CLIS_DIR = getUserClisDir();
|
|
33
|
+
/** Plugins directory: ~/.webcmd/plugins/ */
|
|
34
|
+
export const PLUGINS_DIR = getPluginsDir();
|
|
35
|
+
/** Matches files that register commands via cli() or lifecycle hooks */
|
|
36
|
+
const PLUGIN_MODULE_PATTERN = /\b(?:cli|registerSiteAuthCommands|onStartup|onBeforeExecute|onAfterExecute)\s*\(/;
|
|
37
|
+
function parseStrategy(rawStrategy, fallback = Strategy.COOKIE) {
|
|
38
|
+
if (!rawStrategy)
|
|
39
|
+
return fallback;
|
|
40
|
+
const key = rawStrategy.toUpperCase();
|
|
41
|
+
return Strategy[key] ?? fallback;
|
|
42
|
+
}
|
|
43
|
+
const PACKAGE_ROOT = findPackageRoot(fileURLToPath(import.meta.url));
|
|
44
|
+
function getSourcePackageExports() {
|
|
45
|
+
const pkgPath = path.join(PACKAGE_ROOT, 'package.json');
|
|
46
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
47
|
+
const exports = pkg.exports ?? {};
|
|
48
|
+
return Object.fromEntries(Object.entries(exports).map(([key, target]) => [
|
|
49
|
+
key,
|
|
50
|
+
target
|
|
51
|
+
.replace(/^\.\/dist\//, './')
|
|
52
|
+
.replace(/\.js$/, '.ts'),
|
|
53
|
+
]));
|
|
54
|
+
}
|
|
55
|
+
async function pathIsSymlink(targetPath) {
|
|
56
|
+
try {
|
|
57
|
+
return (await fs.promises.lstat(targetPath)).isSymbolicLink();
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async function ensureSourcePackageShim(packageDir) {
|
|
64
|
+
const srcLink = path.join(packageDir, 'src');
|
|
65
|
+
const srcTarget = path.join(PACKAGE_ROOT, 'src');
|
|
66
|
+
const pkgJsonPath = path.join(packageDir, 'package.json');
|
|
67
|
+
const pkgJsonContent = `${JSON.stringify({
|
|
68
|
+
name: PACKAGE_NAME,
|
|
69
|
+
private: true,
|
|
70
|
+
type: 'module',
|
|
71
|
+
exports: getSourcePackageExports(),
|
|
72
|
+
}, null, 2)}\n`;
|
|
73
|
+
await fs.promises.mkdir(packageDir, { recursive: true });
|
|
74
|
+
try {
|
|
75
|
+
const existing = await fs.promises.readFile(pkgJsonPath, 'utf-8');
|
|
76
|
+
if (existing !== pkgJsonContent)
|
|
77
|
+
await fs.promises.writeFile(pkgJsonPath, pkgJsonContent, 'utf-8');
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
await fs.promises.writeFile(pkgJsonPath, pkgJsonContent, 'utf-8');
|
|
81
|
+
}
|
|
82
|
+
let needsSrcLink = true;
|
|
83
|
+
try {
|
|
84
|
+
const existing = await fs.promises.readlink(srcLink);
|
|
85
|
+
if (existing === srcTarget)
|
|
86
|
+
needsSrcLink = false;
|
|
87
|
+
}
|
|
88
|
+
catch { /* doesn't exist */ }
|
|
89
|
+
if (needsSrcLink) {
|
|
90
|
+
try {
|
|
91
|
+
await fs.promises.rm(srcLink, { recursive: true, force: true });
|
|
92
|
+
}
|
|
93
|
+
catch { /* doesn't exist */ }
|
|
94
|
+
const symlinkType = process.platform === 'win32' ? 'junction' : 'dir';
|
|
95
|
+
await fs.promises.symlink(srcTarget, srcLink, symlinkType);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Ensure ~/.webcmd/node_modules/<package> symlink exists so user CLIs can
|
|
100
|
+
* import runtime exports from the installed package.
|
|
101
|
+
*
|
|
102
|
+
* This is the sole resolution mechanism — adapters use package exports and
|
|
103
|
+
* Node.js resolves them through this symlink.
|
|
104
|
+
*/
|
|
105
|
+
export async function ensureUserCliCompatShims(baseDir = USER_WEBCMD_DIR) {
|
|
106
|
+
await fs.promises.mkdir(baseDir, { recursive: true });
|
|
107
|
+
// package.json for ESM resolution in ~/.webcmd/
|
|
108
|
+
const pkgJsonPath = path.join(baseDir, 'package.json');
|
|
109
|
+
const pkgJsonContent = `${JSON.stringify({ name: `${PRODUCT_NAME}-user-runtime`, private: true, type: 'module' }, null, 2)}\n`;
|
|
110
|
+
try {
|
|
111
|
+
const existing = await fs.promises.readFile(pkgJsonPath, 'utf-8');
|
|
112
|
+
if (existing !== pkgJsonContent)
|
|
113
|
+
await fs.promises.writeFile(pkgJsonPath, pkgJsonContent, 'utf-8');
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
await fs.promises.writeFile(pkgJsonPath, pkgJsonContent, 'utf-8');
|
|
117
|
+
}
|
|
118
|
+
// Create node_modules/<package> resolution pointing to the installed package root.
|
|
119
|
+
// Source checkouts do not have dist/, so they need a tiny package shim whose
|
|
120
|
+
// exports target src/ files instead.
|
|
121
|
+
const packageRoot = PACKAGE_ROOT;
|
|
122
|
+
const [scope, name] = PACKAGE_NAME.split('/');
|
|
123
|
+
const symlinkDir = path.join(baseDir, 'node_modules', scope);
|
|
124
|
+
const symlinkPath = path.join(symlinkDir, name);
|
|
125
|
+
const hasBuiltExports = fs.existsSync(path.join(packageRoot, 'dist', 'src', 'registry-api.js'));
|
|
126
|
+
try {
|
|
127
|
+
if (!hasBuiltExports) {
|
|
128
|
+
if (await pathIsSymlink(symlinkPath)) {
|
|
129
|
+
await fs.promises.rm(symlinkPath, { recursive: true, force: true });
|
|
130
|
+
}
|
|
131
|
+
await ensureSourcePackageShim(symlinkPath);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
let needsUpdate = true;
|
|
135
|
+
try {
|
|
136
|
+
const existing = await fs.promises.readlink(symlinkPath);
|
|
137
|
+
if (existing === packageRoot)
|
|
138
|
+
needsUpdate = false;
|
|
139
|
+
}
|
|
140
|
+
catch { /* doesn't exist */ }
|
|
141
|
+
if (needsUpdate) {
|
|
142
|
+
await fs.promises.mkdir(symlinkDir, { recursive: true });
|
|
143
|
+
try {
|
|
144
|
+
await fs.promises.rm(symlinkPath, { recursive: true, force: true });
|
|
145
|
+
}
|
|
146
|
+
catch { /* doesn't exist */ }
|
|
147
|
+
const symlinkType = process.platform === 'win32' ? 'junction' : 'dir';
|
|
148
|
+
await fs.promises.symlink(packageRoot, symlinkPath, symlinkType);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch (err) {
|
|
152
|
+
log.warn(`Could not create symlink at ${symlinkPath}: ${getErrorMessage(err)}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Ensure the user adapters directory exists.
|
|
157
|
+
*
|
|
158
|
+
* With smart sync, ~/.webcmd/clis/ only holds files that differ from the
|
|
159
|
+
* package baseline (upstream-synced cache + autofix output + user overrides).
|
|
160
|
+
* Built-in adapters are loaded directly from the installed package.
|
|
161
|
+
*/
|
|
162
|
+
export async function ensureUserAdapters() {
|
|
163
|
+
await fs.promises.mkdir(USER_CLIS_DIR, { recursive: true });
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Discover and register CLI commands.
|
|
167
|
+
* Uses pre-compiled manifest when available for instant startup.
|
|
168
|
+
*/
|
|
169
|
+
export async function discoverClis(...dirs) {
|
|
170
|
+
// Fast path: try manifest first (production / post-build)
|
|
171
|
+
for (const dir of dirs) {
|
|
172
|
+
const manifestPath = getCliManifestPath(dir);
|
|
173
|
+
try {
|
|
174
|
+
await fs.promises.access(manifestPath);
|
|
175
|
+
const loaded = await loadFromManifest(manifestPath, dir);
|
|
176
|
+
if (loaded)
|
|
177
|
+
continue; // Skip filesystem scan only when manifest is usable
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
// Fall through to filesystem scan
|
|
181
|
+
}
|
|
182
|
+
await discoverClisFromFs(dir);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Fast-path: register commands from pre-compiled manifest.
|
|
187
|
+
* TS modules are deferred — loaded lazily on first execution.
|
|
188
|
+
*/
|
|
189
|
+
async function loadFromManifest(manifestPath, clisDir) {
|
|
190
|
+
try {
|
|
191
|
+
const raw = await fs.promises.readFile(manifestPath, 'utf-8');
|
|
192
|
+
const manifest = JSON.parse(raw);
|
|
193
|
+
for (const entry of manifest) {
|
|
194
|
+
if (!entry.modulePath)
|
|
195
|
+
continue;
|
|
196
|
+
const modulePath = path.resolve(clisDir, entry.modulePath);
|
|
197
|
+
const cmd = {
|
|
198
|
+
site: entry.site,
|
|
199
|
+
name: entry.name,
|
|
200
|
+
aliases: entry.aliases,
|
|
201
|
+
description: entry.description ?? '',
|
|
202
|
+
access: entry.access,
|
|
203
|
+
example: entry.example,
|
|
204
|
+
domain: entry.domain,
|
|
205
|
+
strategy: parseStrategy(entry.strategy),
|
|
206
|
+
browser: entry.browser,
|
|
207
|
+
args: entry.args ?? [],
|
|
208
|
+
columns: entry.columns,
|
|
209
|
+
defaultFormat: entry.defaultFormat,
|
|
210
|
+
pipeline: entry.pipeline,
|
|
211
|
+
source: entry.sourceFile ? path.resolve(clisDir, entry.sourceFile) : modulePath,
|
|
212
|
+
navigateBefore: entry.navigateBefore,
|
|
213
|
+
siteSession: entry.siteSession,
|
|
214
|
+
defaultWindowMode: entry.defaultWindowMode,
|
|
215
|
+
_lazy: true,
|
|
216
|
+
_modulePath: modulePath,
|
|
217
|
+
};
|
|
218
|
+
// normalizeCommand inside registerCommand handles strategy → browser/navigateBefore
|
|
219
|
+
registerCommand(cmd);
|
|
220
|
+
}
|
|
221
|
+
return true;
|
|
222
|
+
}
|
|
223
|
+
catch (err) {
|
|
224
|
+
log.warn(`Failed to load manifest ${manifestPath}: ${getErrorMessage(err)}`);
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Fallback: traditional filesystem scan (used during development with tsx).
|
|
230
|
+
*/
|
|
231
|
+
async function discoverClisFromFs(dir) {
|
|
232
|
+
try {
|
|
233
|
+
await fs.promises.access(dir);
|
|
234
|
+
}
|
|
235
|
+
catch {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
const entries = await fs.promises.readdir(dir, { withFileTypes: true });
|
|
239
|
+
const sitePromises = entries
|
|
240
|
+
.filter(entry => entry.isDirectory())
|
|
241
|
+
.map(async (entry) => {
|
|
242
|
+
const site = entry.name;
|
|
243
|
+
const siteDir = path.join(dir, site);
|
|
244
|
+
const files = await fs.promises.readdir(siteDir);
|
|
245
|
+
await Promise.all(files.map(async (file) => {
|
|
246
|
+
const filePath = path.join(siteDir, file);
|
|
247
|
+
if (file.endsWith('.yaml') || file.endsWith('.yml')) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
if (file.endsWith('.ts') && !file.endsWith('.d.ts') && !file.endsWith('.test.ts')) {
|
|
251
|
+
log.warn(`Ignoring TypeScript adapter ${filePath} — .ts adapters are no longer loaded. Rename to .js or convert to JavaScript.`);
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
if (file.endsWith('.js') && !file.endsWith('.d.js') && !file.endsWith('.test.js')) {
|
|
255
|
+
if (!(await isCliModule(filePath)))
|
|
256
|
+
return;
|
|
257
|
+
await import(pathToFileURL(filePath).href).catch((err) => {
|
|
258
|
+
log.warn(`Failed to load module ${filePath}: ${getErrorMessage(err)}`);
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
}));
|
|
262
|
+
});
|
|
263
|
+
await Promise.all(sitePromises);
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Discover and register plugins from ~/.webcmd/plugins/.
|
|
267
|
+
* Each subdirectory is treated as a plugin (site = directory name).
|
|
268
|
+
* Files inside are scanned flat (no nested site subdirs).
|
|
269
|
+
*/
|
|
270
|
+
export async function discoverPlugins() {
|
|
271
|
+
try {
|
|
272
|
+
await fs.promises.access(PLUGINS_DIR);
|
|
273
|
+
}
|
|
274
|
+
catch {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
const entries = await fs.promises.readdir(PLUGINS_DIR, { withFileTypes: true });
|
|
278
|
+
await Promise.all(entries.map(async (entry) => {
|
|
279
|
+
const pluginDir = path.join(PLUGINS_DIR, entry.name);
|
|
280
|
+
if (!(await isDiscoverablePluginDir(entry, pluginDir)))
|
|
281
|
+
return;
|
|
282
|
+
await discoverPluginDir(pluginDir, entry.name);
|
|
283
|
+
}));
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Flat scan: read ts/js files directly in a plugin directory.
|
|
287
|
+
* Unlike discoverClisFromFs, this does NOT expect nested site subdirectories.
|
|
288
|
+
*/
|
|
289
|
+
async function discoverPluginDir(dir, site) {
|
|
290
|
+
const files = await fs.promises.readdir(dir);
|
|
291
|
+
const fileSet = new Set(files);
|
|
292
|
+
await Promise.all(files.map(async (file) => {
|
|
293
|
+
const filePath = path.join(dir, file);
|
|
294
|
+
if (file.endsWith('.yaml') || file.endsWith('.yml')) {
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
if (file.endsWith('.js') && !file.endsWith('.d.js')) {
|
|
298
|
+
if (!(await isCliModule(filePath)))
|
|
299
|
+
return;
|
|
300
|
+
await import(pathToFileURL(filePath).href).catch((err) => {
|
|
301
|
+
log.warn(`Plugin ${site}/${file}: ${getErrorMessage(err)}`);
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
else if (file.endsWith('.ts') && !file.endsWith('.d.ts') && !file.endsWith('.test.ts')) {
|
|
305
|
+
const jsFile = file.replace(/\.ts$/, '.js');
|
|
306
|
+
// Prefer compiled .js — skip the .ts source file
|
|
307
|
+
if (fileSet.has(jsFile))
|
|
308
|
+
return;
|
|
309
|
+
// No compiled .js found — cannot import raw .ts in production Node.js.
|
|
310
|
+
// This typically means esbuild transpilation failed during plugin install.
|
|
311
|
+
log.warn(`Plugin ${site}/${file}: no compiled .js found. ` +
|
|
312
|
+
`Run "webcmd plugin update ${site}" to re-transpile, or install esbuild.`);
|
|
313
|
+
}
|
|
314
|
+
}));
|
|
315
|
+
}
|
|
316
|
+
async function isCliModule(filePath) {
|
|
317
|
+
try {
|
|
318
|
+
const source = await fs.promises.readFile(filePath, 'utf-8');
|
|
319
|
+
return PLUGIN_MODULE_PATTERN.test(source);
|
|
320
|
+
}
|
|
321
|
+
catch (err) {
|
|
322
|
+
log.warn(`Failed to inspect module ${filePath}: ${getErrorMessage(err)}`);
|
|
323
|
+
return false;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
async function isDiscoverablePluginDir(entry, pluginDir) {
|
|
327
|
+
if (entry.isDirectory())
|
|
328
|
+
return true;
|
|
329
|
+
if (!entry.isSymbolicLink())
|
|
330
|
+
return false;
|
|
331
|
+
try {
|
|
332
|
+
return (await fs.promises.stat(pluginDir)).isDirectory();
|
|
333
|
+
}
|
|
334
|
+
catch (err) {
|
|
335
|
+
const code = err.code;
|
|
336
|
+
if (code !== 'ENOENT' && code !== 'ENOTDIR') {
|
|
337
|
+
log.warn(`Failed to inspect plugin link ${pluginDir}: ${getErrorMessage(err)}`);
|
|
338
|
+
}
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* webcmd doctor — diagnose browser connectivity.
|
|
3
|
+
*
|
|
4
|
+
* Simplified for the daemon-based architecture.
|
|
5
|
+
*/
|
|
6
|
+
import type { BrowserProfileStatus } from './browser/daemon-transport.js';
|
|
7
|
+
import { type AdapterShadow } from './adapter-shadow.js';
|
|
8
|
+
export type DoctorOptions = {
|
|
9
|
+
yes?: boolean;
|
|
10
|
+
cliVersion?: string;
|
|
11
|
+
};
|
|
12
|
+
export type ConnectivityResult = {
|
|
13
|
+
ok: boolean;
|
|
14
|
+
error?: string;
|
|
15
|
+
durationMs: number;
|
|
16
|
+
};
|
|
17
|
+
export type DoctorReport = {
|
|
18
|
+
cliVersion?: string;
|
|
19
|
+
daemonRunning: boolean;
|
|
20
|
+
daemonFlaky?: boolean;
|
|
21
|
+
daemonStale?: boolean;
|
|
22
|
+
daemonVersion?: string;
|
|
23
|
+
runtimeConnected: boolean;
|
|
24
|
+
runtimeFlaky?: boolean;
|
|
25
|
+
runtimeName?: string;
|
|
26
|
+
runtimeVersion?: string;
|
|
27
|
+
connectivity?: ConnectivityResult;
|
|
28
|
+
profiles?: BrowserProfileStatus[];
|
|
29
|
+
adapterShadows?: AdapterShadow[];
|
|
30
|
+
issues: string[];
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Test connectivity by attempting a real browser command.
|
|
34
|
+
*/
|
|
35
|
+
export declare function checkConnectivity(opts?: {
|
|
36
|
+
timeout?: number;
|
|
37
|
+
}): Promise<ConnectivityResult>;
|
|
38
|
+
export declare function runBrowserDoctor(opts?: DoctorOptions): Promise<DoctorReport>;
|
|
39
|
+
export declare function renderBrowserDoctorReport(report: DoctorReport): string;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* webcmd doctor — diagnose browser connectivity.
|
|
3
|
+
*
|
|
4
|
+
* Simplified for the daemon-based architecture.
|
|
5
|
+
*/
|
|
6
|
+
import { DEFAULT_DAEMON_PORT } from './constants.js';
|
|
7
|
+
import { BrowserBridge } from './browser/index.js';
|
|
8
|
+
import { getDaemonHealth } from './browser/daemon-transport.js';
|
|
9
|
+
import { getErrorMessage } from './errors.js';
|
|
10
|
+
import { getRuntimeLabel } from './runtime-detect.js';
|
|
11
|
+
import { aliasForContextId, loadProfileConfig } from './browser/profile.js';
|
|
12
|
+
import { formatDaemonVersion, isDaemonStale, staleDaemonIssue } from './browser/daemon-version.js';
|
|
13
|
+
import { findShadowedUserAdapters, formatAdapterShadowIssue } from './adapter-shadow.js';
|
|
14
|
+
const DOCTOR_LIVE_TIMEOUT_SECONDS = 8;
|
|
15
|
+
const DOCTOR_SESSION = '__doctor__';
|
|
16
|
+
/**
|
|
17
|
+
* Test connectivity by attempting a real browser command.
|
|
18
|
+
*/
|
|
19
|
+
export async function checkConnectivity(opts) {
|
|
20
|
+
const start = Date.now();
|
|
21
|
+
try {
|
|
22
|
+
const bridge = new BrowserBridge();
|
|
23
|
+
const page = await bridge.connect({
|
|
24
|
+
timeout: opts?.timeout ?? DOCTOR_LIVE_TIMEOUT_SECONDS,
|
|
25
|
+
session: DOCTOR_SESSION,
|
|
26
|
+
surface: 'browser',
|
|
27
|
+
});
|
|
28
|
+
try {
|
|
29
|
+
// Try a simple eval to verify end-to-end connectivity.
|
|
30
|
+
await page.evaluate('1 + 1');
|
|
31
|
+
await page.closeWindow?.();
|
|
32
|
+
}
|
|
33
|
+
finally {
|
|
34
|
+
await bridge.close();
|
|
35
|
+
}
|
|
36
|
+
return { ok: true, durationMs: Date.now() - start };
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
return { ok: false, error: getErrorMessage(err), durationMs: Date.now() - start };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export async function runBrowserDoctor(opts = {}) {
|
|
43
|
+
// Live connectivity check is the core of doctor — it doubles as auto-start
|
|
44
|
+
// (bridge.connect spawns daemon) and validates end-to-end browser bridge health.
|
|
45
|
+
const connectivity = await checkConnectivity();
|
|
46
|
+
// Single status read *after* connectivity side-effects settle.
|
|
47
|
+
const health = await getDaemonHealth();
|
|
48
|
+
const daemonRunning = health.state !== 'stopped';
|
|
49
|
+
const runtimeConnected = health.state === 'ready';
|
|
50
|
+
const daemonFlaky = connectivity.ok && !daemonRunning;
|
|
51
|
+
const runtimeFlaky = connectivity.ok && daemonRunning && !runtimeConnected;
|
|
52
|
+
const daemonStale = isDaemonStale(health.status, opts.cliVersion);
|
|
53
|
+
const profiles = health.status?.profiles;
|
|
54
|
+
const runtimeName = health.status?.runtimeName;
|
|
55
|
+
const runtimeVersion = health.status?.runtimeVersion;
|
|
56
|
+
const adapterShadows = findShadowedUserAdapters();
|
|
57
|
+
const issues = [];
|
|
58
|
+
if (daemonFlaky) {
|
|
59
|
+
issues.push('Daemon connectivity is unstable. The live browser test succeeded, but the daemon was no longer running immediately afterward.\n' +
|
|
60
|
+
'This usually means the daemon crashed or exited right after serving the live probe.');
|
|
61
|
+
}
|
|
62
|
+
else if (!daemonRunning) {
|
|
63
|
+
issues.push('Daemon is not running. It should start automatically when you run a webcmd browser command.');
|
|
64
|
+
}
|
|
65
|
+
if (daemonStale && opts.cliVersion) {
|
|
66
|
+
issues.push(staleDaemonIssue(health.status, opts.cliVersion));
|
|
67
|
+
}
|
|
68
|
+
if (runtimeFlaky) {
|
|
69
|
+
issues.push('Cloak runtime connection is unstable. The live browser test succeeded, but the daemon reported the runtime disconnected immediately afterward.\n' +
|
|
70
|
+
'This usually means Chrome/Chromium or the Cloak runtime is still starting, reconnecting, or was suspended.');
|
|
71
|
+
}
|
|
72
|
+
else if (daemonRunning && !runtimeConnected) {
|
|
73
|
+
if (health.state === 'profile-required') {
|
|
74
|
+
issues.push('Multiple Chrome profiles are connected to the daemon, but no default profile was selected.\n' +
|
|
75
|
+
' Run webcmd profile list, then webcmd profile use <name>, or pass --profile <name>.');
|
|
76
|
+
}
|
|
77
|
+
else if (health.state === 'profile-disconnected') {
|
|
78
|
+
issues.push(`Selected browser profile is not connected: ${health.status?.contextId ?? 'unknown'}.\n` +
|
|
79
|
+
' Open that Chrome profile and make sure Cloak is enabled.');
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
issues.push('Daemon is running but the Cloak runtime is not connected.\n' +
|
|
83
|
+
' Make sure Chrome/Chromium is open and Cloak is enabled.\n' +
|
|
84
|
+
' If Chrome is already open, try: webcmd daemon restart');
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (!connectivity.ok) {
|
|
88
|
+
issues.push(`Browser connectivity test failed: ${connectivity.error ?? 'unknown'}`);
|
|
89
|
+
}
|
|
90
|
+
if (adapterShadows.length > 0) {
|
|
91
|
+
issues.push(formatAdapterShadowIssue(adapterShadows));
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
cliVersion: opts.cliVersion,
|
|
95
|
+
daemonRunning,
|
|
96
|
+
daemonFlaky,
|
|
97
|
+
daemonStale,
|
|
98
|
+
daemonVersion: health.status?.daemonVersion,
|
|
99
|
+
runtimeConnected,
|
|
100
|
+
runtimeFlaky,
|
|
101
|
+
runtimeName,
|
|
102
|
+
runtimeVersion,
|
|
103
|
+
connectivity,
|
|
104
|
+
profiles,
|
|
105
|
+
adapterShadows,
|
|
106
|
+
issues,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
export function renderBrowserDoctorReport(report) {
|
|
110
|
+
const lines = [`webcmd v${report.cliVersion ?? 'unknown'} doctor` + ` (${getRuntimeLabel()})`, ''];
|
|
111
|
+
// Daemon status
|
|
112
|
+
const daemonIcon = report.daemonFlaky
|
|
113
|
+
? '[WARN]'
|
|
114
|
+
: report.daemonStale
|
|
115
|
+
? '[WARN]'
|
|
116
|
+
: report.daemonRunning ? '[OK]' : '[MISSING]';
|
|
117
|
+
const daemonLabel = report.daemonFlaky
|
|
118
|
+
? 'unstable (running during live check, then stopped)'
|
|
119
|
+
: report.daemonRunning
|
|
120
|
+
? `running on port ${DEFAULT_DAEMON_PORT} (${report.daemonStale
|
|
121
|
+
? `${formatDaemonVersion(report)}, stale; CLI v${report.cliVersion ?? 'unknown'}`
|
|
122
|
+
: formatDaemonVersion(report)})`
|
|
123
|
+
: 'not running';
|
|
124
|
+
lines.push(`${daemonIcon} Daemon: ${daemonLabel}`);
|
|
125
|
+
// Runtime status
|
|
126
|
+
const runtimeIcon = report.runtimeFlaky
|
|
127
|
+
? '[WARN]'
|
|
128
|
+
: report.runtimeConnected ? '[OK]' : '[MISSING]';
|
|
129
|
+
const runtimeVersion = !report.runtimeConnected
|
|
130
|
+
? ''
|
|
131
|
+
: report.runtimeVersion
|
|
132
|
+
? ` (v${report.runtimeVersion})`
|
|
133
|
+
: ' (version unknown)';
|
|
134
|
+
const runtimeName = report.runtimeName ?? 'Cloak';
|
|
135
|
+
const runtimeLabel = report.runtimeFlaky
|
|
136
|
+
? 'unstable (connected during live check, then disconnected)'
|
|
137
|
+
: report.runtimeConnected ? 'connected' : 'not connected';
|
|
138
|
+
lines.push(`${runtimeIcon} Runtime: ${runtimeName} ${runtimeLabel}${runtimeVersion}`);
|
|
139
|
+
if (report.profiles && report.profiles.length > 0) {
|
|
140
|
+
const config = loadProfileConfig();
|
|
141
|
+
lines.push('', 'Profiles:');
|
|
142
|
+
for (const profile of report.profiles) {
|
|
143
|
+
const alias = aliasForContextId(config, profile.contextId);
|
|
144
|
+
const aliasText = alias ? ` (${alias})` : '';
|
|
145
|
+
const defaultText = config.defaultContextId === profile.contextId ? ', default' : '';
|
|
146
|
+
const version = profile.runtimeVersion ? `v${profile.runtimeVersion}` : 'version unknown';
|
|
147
|
+
lines.push(` • ${profile.contextId}${aliasText}: connected ${version}${defaultText}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// Connectivity
|
|
151
|
+
if (report.connectivity) {
|
|
152
|
+
const connIcon = report.connectivity.ok ? '[OK]' : '[FAIL]';
|
|
153
|
+
const detail = report.connectivity.ok
|
|
154
|
+
? `connected in ${(report.connectivity.durationMs / 1000).toFixed(1)}s`
|
|
155
|
+
: `failed (${report.connectivity.error ?? 'unknown'})`;
|
|
156
|
+
lines.push(`${connIcon} Connectivity: ${detail}`);
|
|
157
|
+
}
|
|
158
|
+
if (report.issues.length) {
|
|
159
|
+
lines.push('', 'Issues:');
|
|
160
|
+
for (const issue of report.issues) {
|
|
161
|
+
lines.push(` • ${issue}`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
else if (report.daemonRunning && report.runtimeConnected) {
|
|
165
|
+
lines.push('', 'Everything looks good!');
|
|
166
|
+
}
|
|
167
|
+
return lines.join('\n');
|
|
168
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|