@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,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared manifest types — kept in their own module so both runtime code
|
|
3
|
+
* (discovery.ts) and the build-time compiler (build-manifest.ts) can
|
|
4
|
+
* import them without pulling each other in. This is what lets us
|
|
5
|
+
* exclude `src/build-manifest.ts` from `tsc`'s emit set: the only thing
|
|
6
|
+
* runtime code needs from build-manifest is the `ManifestEntry` type,
|
|
7
|
+
* and that lives here.
|
|
8
|
+
*/
|
|
9
|
+
export interface ManifestEntry {
|
|
10
|
+
site: string;
|
|
11
|
+
name: string;
|
|
12
|
+
aliases?: string[];
|
|
13
|
+
description: string;
|
|
14
|
+
access: 'read' | 'write';
|
|
15
|
+
example?: string;
|
|
16
|
+
domain?: string;
|
|
17
|
+
strategy: string;
|
|
18
|
+
browser: boolean;
|
|
19
|
+
args: Array<{
|
|
20
|
+
name: string;
|
|
21
|
+
type?: string;
|
|
22
|
+
default?: unknown;
|
|
23
|
+
required?: boolean;
|
|
24
|
+
valueRequired?: boolean;
|
|
25
|
+
positional?: boolean;
|
|
26
|
+
help?: string;
|
|
27
|
+
choices?: string[];
|
|
28
|
+
}>;
|
|
29
|
+
columns?: string[];
|
|
30
|
+
pipeline?: Record<string, unknown>[];
|
|
31
|
+
defaultFormat?: 'table' | 'plain' | 'json' | 'yaml' | 'yml' | 'md' | 'markdown' | 'csv';
|
|
32
|
+
type: 'js';
|
|
33
|
+
/** Relative path from clis/ dir, e.g. 'bilibili/search.js' */
|
|
34
|
+
modulePath?: string;
|
|
35
|
+
/** Relative path to the source file from clis/ dir (e.g. 'site/cmd.js') */
|
|
36
|
+
sourceFile?: string;
|
|
37
|
+
/** Pre-navigation control — see CliCommand.navigateBefore */
|
|
38
|
+
navigateBefore?: boolean | string;
|
|
39
|
+
/** Site session lifecycle defaults — see CliCommand.siteSession */
|
|
40
|
+
siteSession?: 'ephemeral' | 'persistent';
|
|
41
|
+
/** Default browser window visibility — see CliCommand.defaultWindowMode */
|
|
42
|
+
defaultWindowMode?: 'foreground' | 'background';
|
|
43
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared manifest types — kept in their own module so both runtime code
|
|
3
|
+
* (discovery.ts) and the build-time compiler (build-manifest.ts) can
|
|
4
|
+
* import them without pulling each other in. This is what lets us
|
|
5
|
+
* exclude `src/build-manifest.ts` from `tsc`'s emit set: the only thing
|
|
6
|
+
* runtime code needs from build-manifest is the `ManifestEntry` type,
|
|
7
|
+
* and that lives here.
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Dispatcher } from 'undici';
|
|
2
|
+
export interface ProxyDecision {
|
|
3
|
+
mode: 'direct' | 'proxy';
|
|
4
|
+
proxyUrl?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function hasProxyEnv(env?: NodeJS.ProcessEnv): boolean;
|
|
7
|
+
export declare function decideProxy(url: URL, env?: NodeJS.ProcessEnv): ProxyDecision;
|
|
8
|
+
export declare function getDispatcherForUrl(url: URL, env?: NodeJS.ProcessEnv): Dispatcher;
|
|
9
|
+
export declare function fetchWithNodeNetwork(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
|
|
10
|
+
export declare function installNodeNetwork(): void;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { Agent, EnvHttpProxyAgent, fetch as undiciFetch } from 'undici';
|
|
2
|
+
const LOOPBACK_NO_PROXY_ENTRIES = ['127.0.0.1', 'localhost', '::1'];
|
|
3
|
+
const PROXY_ENV_BY_PROTOCOL = {
|
|
4
|
+
'http:': ['http_proxy', 'HTTP_PROXY', 'all_proxy', 'ALL_PROXY'],
|
|
5
|
+
'https:': ['https_proxy', 'HTTPS_PROXY', 'all_proxy', 'ALL_PROXY'],
|
|
6
|
+
};
|
|
7
|
+
const DEFAULT_PORT_BY_PROTOCOL = {
|
|
8
|
+
'http:': '80',
|
|
9
|
+
'https:': '443',
|
|
10
|
+
};
|
|
11
|
+
let installed = false;
|
|
12
|
+
const directDispatcher = new Agent();
|
|
13
|
+
const proxyDispatcherCache = new Map();
|
|
14
|
+
const nativeFetch = globalThis.fetch.bind(globalThis);
|
|
15
|
+
function readEnv(env, lower, upper) {
|
|
16
|
+
const lowerValue = env[lower];
|
|
17
|
+
if (typeof lowerValue === 'string' && lowerValue.trim() !== '')
|
|
18
|
+
return lowerValue;
|
|
19
|
+
const upperValue = env[upper];
|
|
20
|
+
if (typeof upperValue === 'string' && upperValue.trim() !== '')
|
|
21
|
+
return upperValue;
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
function readProxyEnv(env, keys) {
|
|
25
|
+
for (const key of keys) {
|
|
26
|
+
const value = env[key];
|
|
27
|
+
if (typeof value === 'string' && value.trim() !== '')
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
function normalizeHostname(hostname) {
|
|
33
|
+
return hostname.replace(/^\[(.*)\]$/, '$1').toLowerCase();
|
|
34
|
+
}
|
|
35
|
+
function splitNoProxy(raw) {
|
|
36
|
+
return (raw ?? '')
|
|
37
|
+
.split(/[,\s]+/)
|
|
38
|
+
.map((token) => token.trim())
|
|
39
|
+
.filter(Boolean);
|
|
40
|
+
}
|
|
41
|
+
function parseNoProxyEntry(entry) {
|
|
42
|
+
if (entry === '*')
|
|
43
|
+
return { host: '*' };
|
|
44
|
+
const trimmed = entry.trim().replace(/^\*?\./, '');
|
|
45
|
+
if (trimmed.startsWith('[')) {
|
|
46
|
+
const end = trimmed.indexOf(']');
|
|
47
|
+
if (end !== -1) {
|
|
48
|
+
const host = trimmed.slice(1, end);
|
|
49
|
+
const rest = trimmed.slice(end + 1);
|
|
50
|
+
if (rest.startsWith(':'))
|
|
51
|
+
return { host: normalizeHostname(host), port: rest.slice(1) };
|
|
52
|
+
return { host: normalizeHostname(host) };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const colonCount = (trimmed.match(/:/g) ?? []).length;
|
|
56
|
+
if (colonCount === 1) {
|
|
57
|
+
const [host, port] = trimmed.split(':');
|
|
58
|
+
return { host: normalizeHostname(host), port };
|
|
59
|
+
}
|
|
60
|
+
return { host: normalizeHostname(trimmed) };
|
|
61
|
+
}
|
|
62
|
+
function effectiveNoProxyEntries(env) {
|
|
63
|
+
const raw = readEnv(env, 'no_proxy', 'NO_PROXY');
|
|
64
|
+
const entries = splitNoProxy(raw).map(parseNoProxyEntry);
|
|
65
|
+
const seen = new Set(entries.map((entry) => `${entry.host}:${entry.port ?? ''}`));
|
|
66
|
+
for (const rawEntry of LOOPBACK_NO_PROXY_ENTRIES) {
|
|
67
|
+
const entry = parseNoProxyEntry(rawEntry);
|
|
68
|
+
const key = `${entry.host}:${entry.port ?? ''}`;
|
|
69
|
+
if (seen.has(key))
|
|
70
|
+
continue;
|
|
71
|
+
entries.push(entry);
|
|
72
|
+
seen.add(key);
|
|
73
|
+
}
|
|
74
|
+
return entries;
|
|
75
|
+
}
|
|
76
|
+
function serializeNoProxyEntry(entry) {
|
|
77
|
+
if (entry.host === '*')
|
|
78
|
+
return '*';
|
|
79
|
+
const host = entry.host.includes(':') ? `[${entry.host}]` : entry.host;
|
|
80
|
+
return entry.port ? `${host}:${entry.port}` : host;
|
|
81
|
+
}
|
|
82
|
+
function effectiveNoProxyValue(entries) {
|
|
83
|
+
if (entries.length === 0)
|
|
84
|
+
return undefined;
|
|
85
|
+
return entries.map(serializeNoProxyEntry).join(',');
|
|
86
|
+
}
|
|
87
|
+
function matchesNoProxyEntry(url, entry) {
|
|
88
|
+
const { host, port } = entry;
|
|
89
|
+
if (host === '*')
|
|
90
|
+
return true;
|
|
91
|
+
const hostname = normalizeHostname(url.hostname);
|
|
92
|
+
const urlPort = url.port || DEFAULT_PORT_BY_PROTOCOL[url.protocol] || undefined;
|
|
93
|
+
if (port && port !== urlPort)
|
|
94
|
+
return false;
|
|
95
|
+
return hostname === host || hostname.endsWith(`.${host}`);
|
|
96
|
+
}
|
|
97
|
+
function resolveProxyConfig(env = process.env) {
|
|
98
|
+
const noProxyEntries = effectiveNoProxyEntries(env);
|
|
99
|
+
return {
|
|
100
|
+
httpProxy: readProxyEnv(env, PROXY_ENV_BY_PROTOCOL['http:']),
|
|
101
|
+
httpsProxy: readProxyEnv(env, [
|
|
102
|
+
'https_proxy',
|
|
103
|
+
'HTTPS_PROXY',
|
|
104
|
+
'http_proxy',
|
|
105
|
+
'HTTP_PROXY',
|
|
106
|
+
'all_proxy',
|
|
107
|
+
'ALL_PROXY',
|
|
108
|
+
]),
|
|
109
|
+
noProxy: effectiveNoProxyValue(noProxyEntries),
|
|
110
|
+
noProxyEntries,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function createProxyDispatcher(config) {
|
|
114
|
+
const cacheKey = JSON.stringify([
|
|
115
|
+
config.httpProxy ?? '',
|
|
116
|
+
config.httpsProxy ?? '',
|
|
117
|
+
config.noProxy ?? '',
|
|
118
|
+
]);
|
|
119
|
+
const cached = proxyDispatcherCache.get(cacheKey);
|
|
120
|
+
if (cached)
|
|
121
|
+
return cached;
|
|
122
|
+
const dispatcher = new EnvHttpProxyAgent({
|
|
123
|
+
httpProxy: config.httpProxy,
|
|
124
|
+
httpsProxy: config.httpsProxy,
|
|
125
|
+
noProxy: config.noProxy,
|
|
126
|
+
});
|
|
127
|
+
proxyDispatcherCache.set(cacheKey, dispatcher);
|
|
128
|
+
return dispatcher;
|
|
129
|
+
}
|
|
130
|
+
function resolveUrl(input) {
|
|
131
|
+
if (typeof input === 'string')
|
|
132
|
+
return new URL(input);
|
|
133
|
+
if (input instanceof URL)
|
|
134
|
+
return input;
|
|
135
|
+
if (typeof Request !== 'undefined' && input instanceof Request)
|
|
136
|
+
return new URL(input.url);
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
export function hasProxyEnv(env = process.env) {
|
|
140
|
+
const config = resolveProxyConfig(env);
|
|
141
|
+
return Boolean(config.httpProxy || config.httpsProxy);
|
|
142
|
+
}
|
|
143
|
+
export function decideProxy(url, env = process.env) {
|
|
144
|
+
const config = resolveProxyConfig(env);
|
|
145
|
+
if (config.noProxyEntries.some((entry) => matchesNoProxyEntry(url, entry))) {
|
|
146
|
+
return { mode: 'direct' };
|
|
147
|
+
}
|
|
148
|
+
const proxyUrl = url.protocol === 'https:' ? config.httpsProxy : config.httpProxy;
|
|
149
|
+
if (!proxyUrl)
|
|
150
|
+
return { mode: 'direct' };
|
|
151
|
+
return { mode: 'proxy', proxyUrl };
|
|
152
|
+
}
|
|
153
|
+
export function getDispatcherForUrl(url, env = process.env) {
|
|
154
|
+
const config = resolveProxyConfig(env);
|
|
155
|
+
if (!config.httpProxy && !config.httpsProxy)
|
|
156
|
+
return directDispatcher;
|
|
157
|
+
return createProxyDispatcher(config);
|
|
158
|
+
}
|
|
159
|
+
export async function fetchWithNodeNetwork(input, init = {}) {
|
|
160
|
+
const url = resolveUrl(input);
|
|
161
|
+
if (!url || !hasProxyEnv()) {
|
|
162
|
+
return nativeFetch(input, init);
|
|
163
|
+
}
|
|
164
|
+
return (await undiciFetch(input, {
|
|
165
|
+
...init,
|
|
166
|
+
dispatcher: getDispatcherForUrl(url),
|
|
167
|
+
}));
|
|
168
|
+
}
|
|
169
|
+
export function installNodeNetwork() {
|
|
170
|
+
if (installed)
|
|
171
|
+
return;
|
|
172
|
+
globalThis.fetch = ((input, init) => (fetchWithNodeNetwork(input, init)));
|
|
173
|
+
installed = true;
|
|
174
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { decideProxy, hasProxyEnv } from './node-network.js';
|
|
3
|
+
describe('node network proxy decisions', () => {
|
|
4
|
+
it('detects common proxy env variables', () => {
|
|
5
|
+
expect(hasProxyEnv({ https_proxy: 'http://127.0.0.1:7897' })).toBe(true);
|
|
6
|
+
expect(hasProxyEnv({ HTTP_PROXY: 'http://proxy.example:8080' })).toBe(true);
|
|
7
|
+
expect(hasProxyEnv({})).toBe(false);
|
|
8
|
+
});
|
|
9
|
+
it('routes external https traffic through https_proxy', () => {
|
|
10
|
+
const decision = decideProxy(new URL('https://www.v2ex.com/api/topics/latest.json'), { https_proxy: 'http://127.0.0.1:7897' });
|
|
11
|
+
expect(decision).toEqual({
|
|
12
|
+
mode: 'proxy',
|
|
13
|
+
proxyUrl: 'http://127.0.0.1:7897',
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
it('falls back to HTTP_PROXY for https traffic when HTTPS_PROXY is absent', () => {
|
|
17
|
+
const decision = decideProxy(new URL('https://www.v2ex.com/api/topics/latest.json'), { HTTP_PROXY: 'http://127.0.0.1:7897' });
|
|
18
|
+
expect(decision).toEqual({
|
|
19
|
+
mode: 'proxy',
|
|
20
|
+
proxyUrl: 'http://127.0.0.1:7897',
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
it('bypasses proxies for loopback addresses', () => {
|
|
24
|
+
const env = { https_proxy: 'http://127.0.0.1:7897', http_proxy: 'http://127.0.0.1:7897' };
|
|
25
|
+
expect(decideProxy(new URL('http://127.0.0.1:19825/status'), env)).toEqual({ mode: 'direct' });
|
|
26
|
+
expect(decideProxy(new URL('http://localhost:19825/status'), env)).toEqual({ mode: 'direct' });
|
|
27
|
+
expect(decideProxy(new URL('http://[::1]:19825/status'), env)).toEqual({ mode: 'direct' });
|
|
28
|
+
});
|
|
29
|
+
it('honors NO_PROXY domain matches', () => {
|
|
30
|
+
const decision = decideProxy(new URL('https://api.example.com/v1/items'), {
|
|
31
|
+
https_proxy: 'http://127.0.0.1:7897',
|
|
32
|
+
no_proxy: '.example.com',
|
|
33
|
+
});
|
|
34
|
+
expect(decision).toEqual({ mode: 'direct' });
|
|
35
|
+
});
|
|
36
|
+
it('supports wildcard-style NO_PROXY subdomain entries', () => {
|
|
37
|
+
const decision = decideProxy(new URL('https://api.example.com/v1/items'), {
|
|
38
|
+
https_proxy: 'http://127.0.0.1:7897',
|
|
39
|
+
no_proxy: '*.example.com',
|
|
40
|
+
});
|
|
41
|
+
expect(decision).toEqual({ mode: 'direct' });
|
|
42
|
+
});
|
|
43
|
+
it('matches NO_PROXY entries that rely on the default URL port', () => {
|
|
44
|
+
const env = { https_proxy: 'http://127.0.0.1:7897', http_proxy: 'http://127.0.0.1:7897' };
|
|
45
|
+
expect(decideProxy(new URL('https://example.com/'), { ...env, NO_PROXY: 'example.com:443' })).toEqual({ mode: 'direct' });
|
|
46
|
+
expect(decideProxy(new URL('http://example.com/health'), { ...env, NO_PROXY: 'example.com:80' })).toEqual({ mode: 'direct' });
|
|
47
|
+
});
|
|
48
|
+
it('falls back to ALL_PROXY when protocol-specific settings are absent', () => {
|
|
49
|
+
const decision = decideProxy(new URL('http://example.net/data'), { ALL_PROXY: 'socks5://127.0.0.1:1080' });
|
|
50
|
+
expect(decision).toEqual({
|
|
51
|
+
mode: 'proxy',
|
|
52
|
+
proxyUrl: 'socks5://127.0.0.1:1080',
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ObservationExportResult, ObservationExportStatus, ObservationTraceReceipt } from './events.js';
|
|
2
|
+
import { ObservationSession } from './session.js';
|
|
3
|
+
import { type TraceRetentionPolicyInput } from './retention.js';
|
|
4
|
+
export interface ExportObservationOptions {
|
|
5
|
+
baseDir?: string;
|
|
6
|
+
error?: unknown;
|
|
7
|
+
status?: ObservationExportStatus;
|
|
8
|
+
retentionPolicy?: TraceRetentionPolicyInput;
|
|
9
|
+
}
|
|
10
|
+
export declare function getTraceDirectory(contextId: string | undefined, traceId: string, baseDir?: string): string;
|
|
11
|
+
export declare function exportObservationSession(session: ObservationSession, opts?: ExportObservationOptions): ObservationExportResult;
|
|
12
|
+
export declare function buildTraceReceipt(result: Pick<ObservationExportResult, 'traceId' | 'dir' | 'summaryPath' | 'receiptPath'>, status: ObservationExportStatus, error?: unknown, opts?: {
|
|
13
|
+
createdAt?: string;
|
|
14
|
+
scope?: ObservationSession['scope'];
|
|
15
|
+
retentionPolicy?: TraceRetentionPolicyInput;
|
|
16
|
+
}): ObservationTraceReceipt;
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as os from 'node:os';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import { redactValue } from './redaction.js';
|
|
5
|
+
import { pruneTraceArtifacts, traceExpiresAt } from './retention.js';
|
|
6
|
+
import { CliError, getErrorMessage } from '../errors.js';
|
|
7
|
+
import { log } from '../logger.js';
|
|
8
|
+
import { PKG_VERSION } from '../version.js';
|
|
9
|
+
function baseWebcmdDir() {
|
|
10
|
+
return process.env.WEBCMD_CONFIG_DIR || path.join(os.homedir(), '.webcmd');
|
|
11
|
+
}
|
|
12
|
+
function safeSegment(value) {
|
|
13
|
+
const safe = (value || 'default').replace(/[^a-zA-Z0-9_-]+/g, '_');
|
|
14
|
+
return safe || 'default';
|
|
15
|
+
}
|
|
16
|
+
export function getTraceDirectory(contextId, traceId, baseDir = baseWebcmdDir()) {
|
|
17
|
+
return path.join(baseDir, 'profiles', safeSegment(contextId), 'traces', safeSegment(traceId));
|
|
18
|
+
}
|
|
19
|
+
export function exportObservationSession(session, opts = {}) {
|
|
20
|
+
const dir = getTraceDirectory(session.scope.contextId, session.id, opts.baseDir);
|
|
21
|
+
const status = opts.status ?? (opts.error === undefined ? 'success' : 'failure');
|
|
22
|
+
const createdAt = new Date().toISOString();
|
|
23
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
24
|
+
fs.mkdirSync(path.join(dir, 'screenshots'), { recursive: true });
|
|
25
|
+
fs.mkdirSync(path.join(dir, 'state'), { recursive: true });
|
|
26
|
+
const originalEvents = session.events();
|
|
27
|
+
const sanitizedEvents = originalEvents.map((event) => redactObservationEvent(event));
|
|
28
|
+
const traceLines = [];
|
|
29
|
+
const networkLines = [];
|
|
30
|
+
const consoleLines = [];
|
|
31
|
+
let screenshotIndex = 0;
|
|
32
|
+
let stateIndex = 0;
|
|
33
|
+
for (let i = 0; i < sanitizedEvents.length; i++) {
|
|
34
|
+
const originalEvent = originalEvents[i];
|
|
35
|
+
const event = sanitizedEvents[i];
|
|
36
|
+
const serializable = { ...event };
|
|
37
|
+
if (event.stream === 'screenshot' && originalEvent.stream === 'screenshot' && typeof originalEvent.data === 'string') {
|
|
38
|
+
const ext = event.format === 'jpeg' ? 'jpg' : 'png';
|
|
39
|
+
const file = `screenshots/${String(++screenshotIndex).padStart(4, '0')}.${ext}`;
|
|
40
|
+
fs.writeFileSync(path.join(dir, file), originalEvent.data, 'base64');
|
|
41
|
+
serializable.path = file;
|
|
42
|
+
delete serializable.data;
|
|
43
|
+
}
|
|
44
|
+
if (event.stream === 'state' && serializable.snapshot !== undefined) {
|
|
45
|
+
const file = `state/${String(++stateIndex).padStart(4, '0')}.json`;
|
|
46
|
+
fs.writeFileSync(path.join(dir, file), JSON.stringify(serializable.snapshot, null, 2), 'utf-8');
|
|
47
|
+
serializable.snapshotPath = file;
|
|
48
|
+
delete serializable.snapshot;
|
|
49
|
+
}
|
|
50
|
+
const line = JSON.stringify(serializable);
|
|
51
|
+
traceLines.push(line);
|
|
52
|
+
if (event.stream === 'network')
|
|
53
|
+
networkLines.push(line);
|
|
54
|
+
if (event.stream === 'console')
|
|
55
|
+
consoleLines.push(line);
|
|
56
|
+
}
|
|
57
|
+
fs.writeFileSync(path.join(dir, 'trace.jsonl'), traceLines.join('\n') + (traceLines.length ? '\n' : ''), 'utf-8');
|
|
58
|
+
fs.writeFileSync(path.join(dir, 'network.jsonl'), networkLines.join('\n') + (networkLines.length ? '\n' : ''), 'utf-8');
|
|
59
|
+
fs.writeFileSync(path.join(dir, 'console.jsonl'), consoleLines.join('\n') + (consoleLines.length ? '\n' : ''), 'utf-8');
|
|
60
|
+
const summaryPath = path.join(dir, 'summary.md');
|
|
61
|
+
fs.writeFileSync(summaryPath, renderSummary(session, sanitizedEvents, {
|
|
62
|
+
error: opts.error,
|
|
63
|
+
status,
|
|
64
|
+
dir,
|
|
65
|
+
createdAt,
|
|
66
|
+
retentionPolicy: opts.retentionPolicy,
|
|
67
|
+
}), 'utf-8');
|
|
68
|
+
const receiptPath = path.join(dir, 'receipt.json');
|
|
69
|
+
const resultBase = { traceId: session.id, dir, summaryPath, receiptPath };
|
|
70
|
+
const receipt = buildTraceReceipt(resultBase, status, opts.error, {
|
|
71
|
+
createdAt,
|
|
72
|
+
scope: session.scope,
|
|
73
|
+
retentionPolicy: opts.retentionPolicy,
|
|
74
|
+
});
|
|
75
|
+
fs.writeFileSync(receiptPath, JSON.stringify(receipt, null, 2), 'utf-8');
|
|
76
|
+
pruneTraceArtifactsBestEffort(path.dirname(dir), dir, opts.retentionPolicy);
|
|
77
|
+
return { ...resultBase, receipt };
|
|
78
|
+
}
|
|
79
|
+
function redactObservationEvent(event) {
|
|
80
|
+
return redactValue(event);
|
|
81
|
+
}
|
|
82
|
+
export function buildTraceReceipt(result, status, error, opts = {}) {
|
|
83
|
+
const maybeCliError = error instanceof CliError ? error : undefined;
|
|
84
|
+
const createdAt = opts.createdAt ?? new Date().toISOString();
|
|
85
|
+
return {
|
|
86
|
+
schemaVersion: 1,
|
|
87
|
+
webcmdVersion: PKG_VERSION,
|
|
88
|
+
traceId: result.traceId,
|
|
89
|
+
traceDir: result.dir,
|
|
90
|
+
summaryPath: result.summaryPath,
|
|
91
|
+
receiptPath: result.receiptPath,
|
|
92
|
+
status,
|
|
93
|
+
createdAt,
|
|
94
|
+
expiresAt: traceExpiresAt(createdAt, opts.retentionPolicy),
|
|
95
|
+
...(opts.scope ? { scope: opts.scope } : {}),
|
|
96
|
+
...(error === undefined ? {} : {
|
|
97
|
+
error: {
|
|
98
|
+
...(error instanceof Error ? { name: error.name } : {}),
|
|
99
|
+
...(maybeCliError ? { code: maybeCliError.code, hint: maybeCliError.hint, exitCode: maybeCliError.exitCode } : {}),
|
|
100
|
+
message: String(redactValue(getErrorMessage(error))),
|
|
101
|
+
},
|
|
102
|
+
}),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function pruneTraceArtifactsBestEffort(tracesDir, protectedTraceDir, retentionPolicy) {
|
|
106
|
+
try {
|
|
107
|
+
pruneTraceArtifacts(tracesDir, {
|
|
108
|
+
policy: retentionPolicy,
|
|
109
|
+
protectedTraceDirs: [protectedTraceDir],
|
|
110
|
+
warn: (message) => log.warn(`[trace] ${message}`),
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
log.warn(`[trace] Failed to prune trace artifacts: ${err instanceof Error ? err.message : String(err)}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function renderSummary(session, events, opts) {
|
|
118
|
+
const counts = events.reduce((acc, event) => {
|
|
119
|
+
acc[event.stream] = (acc[event.stream] ?? 0) + 1;
|
|
120
|
+
return acc;
|
|
121
|
+
}, {});
|
|
122
|
+
const error = serializeSummaryError(opts.error);
|
|
123
|
+
const errorEvents = events.filter((event) => event.stream === 'error').slice(-20).reverse();
|
|
124
|
+
const failedNetwork = events
|
|
125
|
+
.filter((event) => event.stream === 'network')
|
|
126
|
+
.filter((event) => event.status === undefined || event.status === 0 || event.status >= 400)
|
|
127
|
+
.slice(-20)
|
|
128
|
+
.reverse();
|
|
129
|
+
const suspiciousConsole = events
|
|
130
|
+
.filter((event) => event.stream === 'console')
|
|
131
|
+
.filter((event) => /^(error|warning|warn|assert)$/i.test(event.level))
|
|
132
|
+
.slice(-20)
|
|
133
|
+
.reverse();
|
|
134
|
+
const actions = events
|
|
135
|
+
.filter((event) => event.stream === 'action')
|
|
136
|
+
.slice(-30);
|
|
137
|
+
const lines = [
|
|
138
|
+
'---',
|
|
139
|
+
'schemaVersion: 1',
|
|
140
|
+
`webcmdVersion: ${yamlScalar(PKG_VERSION)}`,
|
|
141
|
+
`traceId: ${yamlScalar(session.id)}`,
|
|
142
|
+
`status: ${opts.status}`,
|
|
143
|
+
`contextId: ${yamlScalar(session.scope.contextId ?? 'default')}`,
|
|
144
|
+
`session: ${yamlScalar(session.scope.session)}`,
|
|
145
|
+
...(session.scope.target ? [`target: ${yamlScalar(session.scope.target)}`] : []),
|
|
146
|
+
...(session.scope.site ? [`site: ${yamlScalar(session.scope.site)}`] : []),
|
|
147
|
+
...(session.scope.command ? [`command: ${yamlScalar(session.scope.command)}`] : []),
|
|
148
|
+
...(session.scope.adapterSourcePath ? [`adapterSourcePath: ${yamlScalar(session.scope.adapterSourcePath)}`] : []),
|
|
149
|
+
...(session.scope.adapterSourcePath ? [`adapterSourcePathExists: ${fs.existsSync(session.scope.adapterSourcePath)}`] : []),
|
|
150
|
+
`traceDir: ${yamlScalar(opts.dir)}`,
|
|
151
|
+
`startedAt: ${yamlScalar(new Date(session.startedAt).toISOString())}`,
|
|
152
|
+
`exportedAt: ${yamlScalar(opts.createdAt)}`,
|
|
153
|
+
`expiresAt: ${yamlScalar(traceExpiresAt(opts.createdAt, opts.retentionPolicy))}`,
|
|
154
|
+
...(error ? [
|
|
155
|
+
`errorCode: ${yamlScalar(error.code ?? 'UNKNOWN')}`,
|
|
156
|
+
`errorMessage: ${yamlScalar(error.message)}`,
|
|
157
|
+
] : []),
|
|
158
|
+
'---',
|
|
159
|
+
'',
|
|
160
|
+
'# Webcmd Trace Summary',
|
|
161
|
+
'',
|
|
162
|
+
'## How To Use',
|
|
163
|
+
'',
|
|
164
|
+
'- Start with this summary, then inspect `trace.jsonl` only when the evidence below is insufficient.',
|
|
165
|
+
'- For adapter repair policy and retry limits, use the `webcmd-autofix` skill.',
|
|
166
|
+
'- `adapterSourcePathExists: false` means the path is a best-effort hint, not a confirmed editable file.',
|
|
167
|
+
'',
|
|
168
|
+
'## Error',
|
|
169
|
+
'',
|
|
170
|
+
...renderErrorSection(error, errorEvents),
|
|
171
|
+
'',
|
|
172
|
+
'## Failed Network',
|
|
173
|
+
'',
|
|
174
|
+
...renderNetworkSection(failedNetwork),
|
|
175
|
+
'',
|
|
176
|
+
'## Suspicious Console',
|
|
177
|
+
'',
|
|
178
|
+
...renderConsoleSection(suspiciousConsole),
|
|
179
|
+
'',
|
|
180
|
+
'## Action Timeline',
|
|
181
|
+
'',
|
|
182
|
+
...renderActionSection(actions),
|
|
183
|
+
'',
|
|
184
|
+
'## Event Counts',
|
|
185
|
+
'',
|
|
186
|
+
...Object.entries(counts).map(([stream, count]) => `- ${stream}: ${count}`),
|
|
187
|
+
'',
|
|
188
|
+
'## Artifact Files',
|
|
189
|
+
'',
|
|
190
|
+
'- `trace.jsonl`: full redacted event timeline',
|
|
191
|
+
'- `network.jsonl`: redacted network events',
|
|
192
|
+
'- `console.jsonl`: redacted console events',
|
|
193
|
+
'- `state/`: final state snapshots when available',
|
|
194
|
+
'- `screenshots/`: final screenshots when available',
|
|
195
|
+
'',
|
|
196
|
+
];
|
|
197
|
+
return lines.join('\n');
|
|
198
|
+
}
|
|
199
|
+
function serializeSummaryError(error) {
|
|
200
|
+
if (error === undefined)
|
|
201
|
+
return undefined;
|
|
202
|
+
if (error instanceof CliError) {
|
|
203
|
+
return {
|
|
204
|
+
code: error.code,
|
|
205
|
+
message: String(redactValue(error.message)),
|
|
206
|
+
...(error.hint ? { hint: String(redactValue(error.hint)) } : {}),
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
return { message: String(redactValue(getErrorMessage(error))) };
|
|
210
|
+
}
|
|
211
|
+
function yamlScalar(value) {
|
|
212
|
+
return JSON.stringify(value);
|
|
213
|
+
}
|
|
214
|
+
function renderErrorSection(error, errorEvents) {
|
|
215
|
+
const lines = [];
|
|
216
|
+
if (error) {
|
|
217
|
+
lines.push(`- ${error.code ?? 'UNKNOWN'}: ${error.message}`);
|
|
218
|
+
if (error.hint)
|
|
219
|
+
lines.push(`- hint: ${error.hint}`);
|
|
220
|
+
}
|
|
221
|
+
for (const event of errorEvents) {
|
|
222
|
+
if (event.stream !== 'error')
|
|
223
|
+
continue;
|
|
224
|
+
lines.push(`- ${formatTs(event.ts)} ${event.code ?? 'ERROR'}: ${event.message}`);
|
|
225
|
+
}
|
|
226
|
+
return lines.length ? lines : ['- none'];
|
|
227
|
+
}
|
|
228
|
+
function renderNetworkSection(events) {
|
|
229
|
+
if (!events.length)
|
|
230
|
+
return ['- none'];
|
|
231
|
+
return events.map((event) => {
|
|
232
|
+
const status = event.status ?? 'unknown';
|
|
233
|
+
const method = event.method ?? 'GET';
|
|
234
|
+
const contentType = event.contentType ? ` ${event.contentType}` : '';
|
|
235
|
+
return `- ${formatTs(event.ts)} ${status} ${method} ${event.url}${contentType}`;
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
function renderConsoleSection(events) {
|
|
239
|
+
if (!events.length)
|
|
240
|
+
return ['- none'];
|
|
241
|
+
return events.map((event) => `- ${formatTs(event.ts)} ${event.level}: ${trimLine(event.text, 240)}`);
|
|
242
|
+
}
|
|
243
|
+
function renderActionSection(events) {
|
|
244
|
+
if (!events.length)
|
|
245
|
+
return ['- none'];
|
|
246
|
+
return events.map((event) => {
|
|
247
|
+
const phase = event.phase ? ` ${event.phase}` : '';
|
|
248
|
+
const data = event.data && Object.keys(event.data).length
|
|
249
|
+
? ` ${trimLine(JSON.stringify(redactValue(event.data)), 240)}`
|
|
250
|
+
: '';
|
|
251
|
+
return `- ${formatTs(event.ts)} ${event.name}${phase}${data}`;
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
function formatTs(ts) {
|
|
255
|
+
return new Date(ts).toISOString();
|
|
256
|
+
}
|
|
257
|
+
function trimLine(value, max) {
|
|
258
|
+
const compact = value.replace(/\s+/g, ' ').trim();
|
|
259
|
+
return compact.length > max ? `${compact.slice(0, max)}...` : compact;
|
|
260
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|