@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,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for plugin manifest: reading, validating, and compatibility checks.
|
|
3
|
+
*/
|
|
4
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
5
|
+
import * as fs from 'node:fs';
|
|
6
|
+
import * as path from 'node:path';
|
|
7
|
+
import * as os from 'node:os';
|
|
8
|
+
import { _readPluginManifest as readPluginManifest, _isMonorepo as isMonorepo, _getEnabledPlugins as getEnabledPlugins, _parseVersion as parseVersion, _satisfiesRange as satisfiesRange, MANIFEST_FILENAME, } from './plugin-manifest.js';
|
|
9
|
+
// ── readPluginManifest ──────────────────────────────────────────────────────
|
|
10
|
+
describe('readPluginManifest', () => {
|
|
11
|
+
let tmpDir;
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'webcmd-manifest-test-'));
|
|
14
|
+
});
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
17
|
+
});
|
|
18
|
+
it('returns null when no manifest file exists', () => {
|
|
19
|
+
expect(readPluginManifest(tmpDir)).toBeNull();
|
|
20
|
+
});
|
|
21
|
+
it('returns null for malformed JSON', () => {
|
|
22
|
+
fs.writeFileSync(path.join(tmpDir, MANIFEST_FILENAME), 'not json {{{');
|
|
23
|
+
expect(readPluginManifest(tmpDir)).toBeNull();
|
|
24
|
+
});
|
|
25
|
+
it('returns null for non-object JSON (array)', () => {
|
|
26
|
+
fs.writeFileSync(path.join(tmpDir, MANIFEST_FILENAME), '["a","b"]');
|
|
27
|
+
expect(readPluginManifest(tmpDir)).toBeNull();
|
|
28
|
+
});
|
|
29
|
+
it('returns null for non-object JSON (string)', () => {
|
|
30
|
+
fs.writeFileSync(path.join(tmpDir, MANIFEST_FILENAME), '"hello"');
|
|
31
|
+
expect(readPluginManifest(tmpDir)).toBeNull();
|
|
32
|
+
});
|
|
33
|
+
it('reads a single-plugin manifest', () => {
|
|
34
|
+
const manifest = {
|
|
35
|
+
name: 'polymarket',
|
|
36
|
+
version: '1.2.0',
|
|
37
|
+
webcmd: '>=1.0.0',
|
|
38
|
+
description: 'Prediction market analysis',
|
|
39
|
+
};
|
|
40
|
+
fs.writeFileSync(path.join(tmpDir, MANIFEST_FILENAME), JSON.stringify(manifest));
|
|
41
|
+
const result = readPluginManifest(tmpDir);
|
|
42
|
+
expect(result).toEqual(manifest);
|
|
43
|
+
});
|
|
44
|
+
it('reads a monorepo manifest', () => {
|
|
45
|
+
const manifest = {
|
|
46
|
+
version: '1.0.0',
|
|
47
|
+
webcmd: '>=0.9.0',
|
|
48
|
+
description: 'My plugin collection',
|
|
49
|
+
plugins: {
|
|
50
|
+
polymarket: {
|
|
51
|
+
path: 'packages/polymarket',
|
|
52
|
+
description: 'Prediction market',
|
|
53
|
+
version: '1.2.0',
|
|
54
|
+
},
|
|
55
|
+
defi: {
|
|
56
|
+
path: 'packages/defi',
|
|
57
|
+
description: 'DeFi data',
|
|
58
|
+
version: '0.8.0',
|
|
59
|
+
disabled: true,
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
fs.writeFileSync(path.join(tmpDir, MANIFEST_FILENAME), JSON.stringify(manifest));
|
|
64
|
+
const result = readPluginManifest(tmpDir);
|
|
65
|
+
expect(result).toEqual(manifest);
|
|
66
|
+
expect(result.plugins.polymarket.path).toBe('packages/polymarket');
|
|
67
|
+
expect(result.plugins.defi.disabled).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
// ── isMonorepo ──────────────────────────────────────────────────────────────
|
|
71
|
+
describe('isMonorepo', () => {
|
|
72
|
+
it('returns false for single-plugin manifest', () => {
|
|
73
|
+
expect(isMonorepo({ name: 'test', version: '1.0.0' })).toBe(false);
|
|
74
|
+
});
|
|
75
|
+
it('returns false for empty plugins object', () => {
|
|
76
|
+
expect(isMonorepo({ plugins: {} })).toBe(false);
|
|
77
|
+
});
|
|
78
|
+
it('returns true for manifest with plugins', () => {
|
|
79
|
+
expect(isMonorepo({
|
|
80
|
+
plugins: {
|
|
81
|
+
foo: { path: 'packages/foo' },
|
|
82
|
+
},
|
|
83
|
+
})).toBe(true);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
// ── getEnabledPlugins ───────────────────────────────────────────────────────
|
|
87
|
+
describe('getEnabledPlugins', () => {
|
|
88
|
+
it('returns empty array for no plugins', () => {
|
|
89
|
+
expect(getEnabledPlugins({ name: 'test' })).toEqual([]);
|
|
90
|
+
});
|
|
91
|
+
it('filters out disabled plugins', () => {
|
|
92
|
+
const manifest = {
|
|
93
|
+
plugins: {
|
|
94
|
+
foo: { path: 'packages/foo' },
|
|
95
|
+
bar: { path: 'packages/bar', disabled: true },
|
|
96
|
+
baz: { path: 'packages/baz' },
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
const result = getEnabledPlugins(manifest);
|
|
100
|
+
expect(result).toHaveLength(2);
|
|
101
|
+
expect(result.map((r) => r.name)).toEqual(['baz', 'foo']); // sorted
|
|
102
|
+
});
|
|
103
|
+
it('returns all when none disabled', () => {
|
|
104
|
+
const manifest = {
|
|
105
|
+
plugins: {
|
|
106
|
+
charlie: { path: 'packages/charlie' },
|
|
107
|
+
alpha: { path: 'packages/alpha' },
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
const result = getEnabledPlugins(manifest);
|
|
111
|
+
expect(result).toHaveLength(2);
|
|
112
|
+
expect(result[0].name).toBe('alpha');
|
|
113
|
+
expect(result[1].name).toBe('charlie');
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
// ── parseVersion ────────────────────────────────────────────────────────────
|
|
117
|
+
describe('parseVersion', () => {
|
|
118
|
+
it('parses standard versions', () => {
|
|
119
|
+
expect(parseVersion('1.2.3')).toEqual([1, 2, 3]);
|
|
120
|
+
expect(parseVersion('0.0.0')).toEqual([0, 0, 0]);
|
|
121
|
+
expect(parseVersion('10.20.30')).toEqual([10, 20, 30]);
|
|
122
|
+
});
|
|
123
|
+
it('parses versions with prerelease suffix', () => {
|
|
124
|
+
expect(parseVersion('1.2.3-beta.1')).toEqual([1, 2, 3]);
|
|
125
|
+
});
|
|
126
|
+
it('returns null for invalid versions', () => {
|
|
127
|
+
expect(parseVersion('abc')).toBeNull();
|
|
128
|
+
expect(parseVersion('')).toBeNull();
|
|
129
|
+
expect(parseVersion('1.2')).toBeNull();
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
// ── satisfiesRange ──────────────────────────────────────────────────────────
|
|
133
|
+
describe('satisfiesRange', () => {
|
|
134
|
+
it('handles >= constraint', () => {
|
|
135
|
+
expect(satisfiesRange('1.4.1', '>=1.0.0')).toBe(true);
|
|
136
|
+
expect(satisfiesRange('1.0.0', '>=1.0.0')).toBe(true);
|
|
137
|
+
expect(satisfiesRange('0.9.9', '>=1.0.0')).toBe(false);
|
|
138
|
+
});
|
|
139
|
+
it('handles <= constraint', () => {
|
|
140
|
+
expect(satisfiesRange('1.0.0', '<=1.0.0')).toBe(true);
|
|
141
|
+
expect(satisfiesRange('0.9.0', '<=1.0.0')).toBe(true);
|
|
142
|
+
expect(satisfiesRange('1.0.1', '<=1.0.0')).toBe(false);
|
|
143
|
+
});
|
|
144
|
+
it('handles > constraint', () => {
|
|
145
|
+
expect(satisfiesRange('1.0.1', '>1.0.0')).toBe(true);
|
|
146
|
+
expect(satisfiesRange('1.0.0', '>1.0.0')).toBe(false);
|
|
147
|
+
});
|
|
148
|
+
it('handles < constraint', () => {
|
|
149
|
+
expect(satisfiesRange('0.9.9', '<1.0.0')).toBe(true);
|
|
150
|
+
expect(satisfiesRange('1.0.0', '<1.0.0')).toBe(false);
|
|
151
|
+
});
|
|
152
|
+
it('handles ^ (caret) constraint', () => {
|
|
153
|
+
expect(satisfiesRange('1.2.0', '^1.2.0')).toBe(true);
|
|
154
|
+
expect(satisfiesRange('1.9.9', '^1.2.0')).toBe(true);
|
|
155
|
+
expect(satisfiesRange('2.0.0', '^1.2.0')).toBe(false);
|
|
156
|
+
expect(satisfiesRange('1.1.0', '^1.2.0')).toBe(false);
|
|
157
|
+
});
|
|
158
|
+
it('handles ~ (tilde) constraint', () => {
|
|
159
|
+
expect(satisfiesRange('1.2.0', '~1.2.0')).toBe(true);
|
|
160
|
+
expect(satisfiesRange('1.2.9', '~1.2.0')).toBe(true);
|
|
161
|
+
expect(satisfiesRange('1.3.0', '~1.2.0')).toBe(false);
|
|
162
|
+
});
|
|
163
|
+
it('handles exact match', () => {
|
|
164
|
+
expect(satisfiesRange('1.2.3', '1.2.3')).toBe(true);
|
|
165
|
+
expect(satisfiesRange('1.2.4', '1.2.3')).toBe(false);
|
|
166
|
+
});
|
|
167
|
+
it('handles compound range (AND)', () => {
|
|
168
|
+
expect(satisfiesRange('1.5.0', '>=1.0.0 <2.0.0')).toBe(true);
|
|
169
|
+
expect(satisfiesRange('2.0.0', '>=1.0.0 <2.0.0')).toBe(false);
|
|
170
|
+
expect(satisfiesRange('0.9.0', '>=1.0.0 <2.0.0')).toBe(false);
|
|
171
|
+
});
|
|
172
|
+
it('returns true for empty range', () => {
|
|
173
|
+
expect(satisfiesRange('1.0.0', '')).toBe(true);
|
|
174
|
+
expect(satisfiesRange('1.0.0', ' ')).toBe(true);
|
|
175
|
+
});
|
|
176
|
+
it('returns true for unparseable version', () => {
|
|
177
|
+
expect(satisfiesRange('dev', '>=1.0.0')).toBe(true);
|
|
178
|
+
});
|
|
179
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin scaffold: generates a ready-to-develop plugin directory.
|
|
3
|
+
*
|
|
4
|
+
* Usage: webcmd plugin create <name> [--dir <path>]
|
|
5
|
+
*
|
|
6
|
+
* Creates:
|
|
7
|
+
* <name>/
|
|
8
|
+
* webcmd-plugin.json — manifest with name, version, description
|
|
9
|
+
* package.json — ESM package with webcmd peer dependency
|
|
10
|
+
* hello.ts — sample pipeline command
|
|
11
|
+
* greet.ts — sample TS command using func()
|
|
12
|
+
* README.md — basic documentation
|
|
13
|
+
*/
|
|
14
|
+
export interface ScaffoldOptions {
|
|
15
|
+
/** Directory to create the plugin in. Defaults to `./<name>` */
|
|
16
|
+
dir?: string;
|
|
17
|
+
/** Plugin description */
|
|
18
|
+
description?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface ScaffoldResult {
|
|
21
|
+
name: string;
|
|
22
|
+
dir: string;
|
|
23
|
+
files: string[];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Create a new plugin scaffold directory.
|
|
27
|
+
*/
|
|
28
|
+
export declare function createPluginScaffold(name: string, opts?: ScaffoldOptions): ScaffoldResult;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin scaffold: generates a ready-to-develop plugin directory.
|
|
3
|
+
*
|
|
4
|
+
* Usage: webcmd plugin create <name> [--dir <path>]
|
|
5
|
+
*
|
|
6
|
+
* Creates:
|
|
7
|
+
* <name>/
|
|
8
|
+
* webcmd-plugin.json — manifest with name, version, description
|
|
9
|
+
* package.json — ESM package with webcmd peer dependency
|
|
10
|
+
* hello.ts — sample pipeline command
|
|
11
|
+
* greet.ts — sample TS command using func()
|
|
12
|
+
* README.md — basic documentation
|
|
13
|
+
*/
|
|
14
|
+
import * as fs from 'node:fs';
|
|
15
|
+
import * as path from 'node:path';
|
|
16
|
+
import { PKG_VERSION } from './version.js';
|
|
17
|
+
/**
|
|
18
|
+
* Create a new plugin scaffold directory.
|
|
19
|
+
*/
|
|
20
|
+
export function createPluginScaffold(name, opts = {}) {
|
|
21
|
+
// Validate name
|
|
22
|
+
if (!/^[a-z][a-z0-9-]*$/.test(name)) {
|
|
23
|
+
throw new Error(`Invalid plugin name "${name}". ` +
|
|
24
|
+
`Plugin names must start with a lowercase letter and contain only lowercase letters, digits, and hyphens.`);
|
|
25
|
+
}
|
|
26
|
+
const targetDir = opts.dir
|
|
27
|
+
? path.resolve(opts.dir)
|
|
28
|
+
: path.resolve(name);
|
|
29
|
+
if (fs.existsSync(targetDir) && fs.readdirSync(targetDir).length > 0) {
|
|
30
|
+
throw new Error(`Directory "${targetDir}" already exists and is not empty.`);
|
|
31
|
+
}
|
|
32
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
33
|
+
const files = [];
|
|
34
|
+
// webcmd-plugin.json
|
|
35
|
+
const manifest = {
|
|
36
|
+
name,
|
|
37
|
+
version: '0.1.0',
|
|
38
|
+
description: opts.description ?? `A webcmd plugin: ${name}`,
|
|
39
|
+
webcmd: `>=${PKG_VERSION}`,
|
|
40
|
+
};
|
|
41
|
+
writeFile(targetDir, 'webcmd-plugin.json', JSON.stringify(manifest, null, 2) + '\n');
|
|
42
|
+
files.push('webcmd-plugin.json');
|
|
43
|
+
// package.json
|
|
44
|
+
const pkg = {
|
|
45
|
+
name: `webcmd-plugin-${name}`,
|
|
46
|
+
version: '0.1.0',
|
|
47
|
+
type: 'module',
|
|
48
|
+
description: opts.description ?? `A webcmd plugin: ${name}`,
|
|
49
|
+
peerDependencies: {
|
|
50
|
+
'@agentrhq/webcmd': `>=${PKG_VERSION}`,
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
writeFile(targetDir, 'package.json', JSON.stringify(pkg, null, 2) + '\n');
|
|
54
|
+
files.push('package.json');
|
|
55
|
+
// hello.ts — sample pipeline command
|
|
56
|
+
const helloContent = `/**
|
|
57
|
+
* Sample pipeline command for ${name}.
|
|
58
|
+
* Demonstrates the declarative pipeline API.
|
|
59
|
+
*/
|
|
60
|
+
|
|
61
|
+
import { cli, Strategy } from '@agentrhq/webcmd/registry';
|
|
62
|
+
|
|
63
|
+
cli({
|
|
64
|
+
site: '${name}',
|
|
65
|
+
name: 'hello',
|
|
66
|
+
description: 'A sample pipeline command',
|
|
67
|
+
strategy: Strategy.PUBLIC,
|
|
68
|
+
browser: false,
|
|
69
|
+
columns: ['greeting'],
|
|
70
|
+
pipeline: [
|
|
71
|
+
{ fetch: { url: 'https://httpbin.org/get?greeting=hello' } },
|
|
72
|
+
{ select: 'args' },
|
|
73
|
+
],
|
|
74
|
+
});
|
|
75
|
+
`;
|
|
76
|
+
writeFile(targetDir, 'hello.ts', helloContent);
|
|
77
|
+
files.push('hello.ts');
|
|
78
|
+
// greet.ts — sample TS command using registry API
|
|
79
|
+
const tsContent = `/**
|
|
80
|
+
* Sample TypeScript command for ${name}.
|
|
81
|
+
* Demonstrates the programmatic cli() registration API.
|
|
82
|
+
*/
|
|
83
|
+
|
|
84
|
+
import { cli, Strategy } from '@agentrhq/webcmd/registry';
|
|
85
|
+
|
|
86
|
+
cli({
|
|
87
|
+
site: '${name}',
|
|
88
|
+
name: 'greet',
|
|
89
|
+
description: 'Greet someone by name',
|
|
90
|
+
strategy: Strategy.PUBLIC,
|
|
91
|
+
browser: false,
|
|
92
|
+
args: [
|
|
93
|
+
{ name: 'name', positional: true, required: true, help: 'Name to greet' },
|
|
94
|
+
],
|
|
95
|
+
columns: ['greeting'],
|
|
96
|
+
func: async (kwargs) => [{ greeting: \`Hello, \${String(kwargs.name ?? 'World')}!\` }],
|
|
97
|
+
});
|
|
98
|
+
`;
|
|
99
|
+
writeFile(targetDir, 'greet.ts', tsContent);
|
|
100
|
+
files.push('greet.ts');
|
|
101
|
+
// README.md
|
|
102
|
+
const readme = `# webcmd-plugin-${name}
|
|
103
|
+
|
|
104
|
+
${opts.description ?? `A webcmd plugin: ${name}`}
|
|
105
|
+
|
|
106
|
+
## Install
|
|
107
|
+
|
|
108
|
+
\`\`\`bash
|
|
109
|
+
# From local development directory
|
|
110
|
+
webcmd plugin install file://${targetDir}
|
|
111
|
+
|
|
112
|
+
# From GitHub (after publishing)
|
|
113
|
+
webcmd plugin install github:<user>/webcmd-plugin-${name}
|
|
114
|
+
\`\`\`
|
|
115
|
+
|
|
116
|
+
## Commands
|
|
117
|
+
|
|
118
|
+
| Command | Type | Description |
|
|
119
|
+
|---------|------|-------------|
|
|
120
|
+
| \`${name}/hello\` | Pipeline | Sample pipeline command |
|
|
121
|
+
| \`${name}/greet\` | TypeScript | Sample TS command with func() |
|
|
122
|
+
|
|
123
|
+
## Development
|
|
124
|
+
|
|
125
|
+
\`\`\`bash
|
|
126
|
+
# Install locally for development (symlinked, changes reflect immediately)
|
|
127
|
+
webcmd plugin install file://${targetDir}
|
|
128
|
+
|
|
129
|
+
# Verify commands are registered
|
|
130
|
+
webcmd list | grep ${name}
|
|
131
|
+
|
|
132
|
+
# Run a command
|
|
133
|
+
webcmd ${name} hello
|
|
134
|
+
webcmd ${name} greet --name World
|
|
135
|
+
\`\`\`
|
|
136
|
+
`;
|
|
137
|
+
writeFile(targetDir, 'README.md', readme);
|
|
138
|
+
files.push('README.md');
|
|
139
|
+
return { name, dir: targetDir, files };
|
|
140
|
+
}
|
|
141
|
+
function writeFile(dir, name, content) {
|
|
142
|
+
fs.writeFileSync(path.join(dir, name), content);
|
|
143
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for plugin scaffold: create new plugin directories.
|
|
3
|
+
*/
|
|
4
|
+
import { describe, it, expect, afterEach } from 'vitest';
|
|
5
|
+
import * as fs from 'node:fs';
|
|
6
|
+
import * as os from 'node:os';
|
|
7
|
+
import * as path from 'node:path';
|
|
8
|
+
import { createPluginScaffold } from './plugin-scaffold.js';
|
|
9
|
+
describe('createPluginScaffold', () => {
|
|
10
|
+
const createdDirs = [];
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
for (const dir of createdDirs) {
|
|
13
|
+
try {
|
|
14
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
15
|
+
}
|
|
16
|
+
catch { }
|
|
17
|
+
}
|
|
18
|
+
createdDirs.length = 0;
|
|
19
|
+
});
|
|
20
|
+
it('creates all expected files', () => {
|
|
21
|
+
const dir = path.join(os.tmpdir(), `webcmd-scaffold-${Date.now()}`);
|
|
22
|
+
createdDirs.push(dir);
|
|
23
|
+
const result = createPluginScaffold('my-test', { dir });
|
|
24
|
+
expect(result.name).toBe('my-test');
|
|
25
|
+
expect(result.dir).toBe(dir);
|
|
26
|
+
expect(result.files).toContain('webcmd-plugin.json');
|
|
27
|
+
expect(result.files).toContain('package.json');
|
|
28
|
+
expect(result.files).toContain('hello.ts');
|
|
29
|
+
expect(result.files).toContain('greet.ts');
|
|
30
|
+
expect(result.files).toContain('README.md');
|
|
31
|
+
// All files exist
|
|
32
|
+
for (const f of result.files) {
|
|
33
|
+
expect(fs.existsSync(path.join(dir, f))).toBe(true);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
it('generates valid webcmd-plugin.json', () => {
|
|
37
|
+
const dir = path.join(os.tmpdir(), `webcmd-scaffold-${Date.now()}`);
|
|
38
|
+
createdDirs.push(dir);
|
|
39
|
+
createPluginScaffold('test-manifest', { dir, description: 'Test desc' });
|
|
40
|
+
const manifest = JSON.parse(fs.readFileSync(path.join(dir, 'webcmd-plugin.json'), 'utf-8'));
|
|
41
|
+
expect(manifest.name).toBe('test-manifest');
|
|
42
|
+
expect(manifest.version).toBe('0.1.0');
|
|
43
|
+
expect(manifest.description).toBe('Test desc');
|
|
44
|
+
expect(manifest.webcmd).toMatch(/^>=/);
|
|
45
|
+
});
|
|
46
|
+
it('generates ESM package.json', () => {
|
|
47
|
+
const dir = path.join(os.tmpdir(), `webcmd-scaffold-${Date.now()}`);
|
|
48
|
+
createdDirs.push(dir);
|
|
49
|
+
createPluginScaffold('test-pkg', { dir });
|
|
50
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf-8'));
|
|
51
|
+
expect(pkg.type).toBe('module');
|
|
52
|
+
expect(pkg.peerDependencies?.['@agentrhq/webcmd']).toBeDefined();
|
|
53
|
+
});
|
|
54
|
+
it('generates a TS sample that matches the current plugin API', () => {
|
|
55
|
+
const dir = path.join(os.tmpdir(), `webcmd-scaffold-${Date.now()}`);
|
|
56
|
+
createdDirs.push(dir);
|
|
57
|
+
createPluginScaffold('test-ts', { dir });
|
|
58
|
+
const tsSample = fs.readFileSync(path.join(dir, 'greet.ts'), 'utf-8');
|
|
59
|
+
expect(tsSample).toContain(`import { cli, Strategy } from '@agentrhq/webcmd/registry';`);
|
|
60
|
+
expect(tsSample).toContain(`strategy: Strategy.PUBLIC`);
|
|
61
|
+
expect(tsSample).toContain(`help: 'Name to greet'`);
|
|
62
|
+
expect(tsSample).toContain(`func: async (kwargs)`);
|
|
63
|
+
expect(tsSample).not.toContain('async run(');
|
|
64
|
+
});
|
|
65
|
+
it('documents a supported local install flow', () => {
|
|
66
|
+
const dir = path.join(os.tmpdir(), `webcmd-scaffold-${Date.now()}`);
|
|
67
|
+
createdDirs.push(dir);
|
|
68
|
+
createPluginScaffold('test-readme', { dir });
|
|
69
|
+
const readme = fs.readFileSync(path.join(dir, 'README.md'), 'utf-8');
|
|
70
|
+
expect(readme).toContain(`webcmd plugin install file://${dir}`);
|
|
71
|
+
});
|
|
72
|
+
it('rejects invalid names', () => {
|
|
73
|
+
expect(() => createPluginScaffold('Bad_Name')).toThrow('Invalid plugin name');
|
|
74
|
+
expect(() => createPluginScaffold('123start')).toThrow('Invalid plugin name');
|
|
75
|
+
});
|
|
76
|
+
it('rejects non-empty directory', () => {
|
|
77
|
+
const dir = path.join(os.tmpdir(), `webcmd-scaffold-${Date.now()}`);
|
|
78
|
+
createdDirs.push(dir);
|
|
79
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
80
|
+
fs.writeFileSync(path.join(dir, 'existing.txt'), 'x');
|
|
81
|
+
expect(() => createPluginScaffold('test', { dir })).toThrow('not empty');
|
|
82
|
+
});
|
|
83
|
+
});
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin management: install, uninstall, and list plugins.
|
|
3
|
+
*
|
|
4
|
+
* Plugins live in ~/.webcmd/plugins/<name>/.
|
|
5
|
+
* Monorepo clones live in ~/.webcmd/monorepos/<repo-name>/.
|
|
6
|
+
* Install source format: "github:user/repo", "github:user/repo/subplugin",
|
|
7
|
+
* "https://github.com/user/repo", "file:///local/plugin", or a local directory path.
|
|
8
|
+
*/
|
|
9
|
+
import * as fs from 'node:fs';
|
|
10
|
+
/** Path to the lock file that tracks installed plugin versions. */
|
|
11
|
+
export declare function getLockFilePath(): string;
|
|
12
|
+
/** Monorepo clones directory: ~/.webcmd/monorepos/ */
|
|
13
|
+
export declare function getMonoreposDir(): string;
|
|
14
|
+
export type PluginSourceRecord = {
|
|
15
|
+
kind: 'git';
|
|
16
|
+
url: string;
|
|
17
|
+
} | {
|
|
18
|
+
kind: 'local';
|
|
19
|
+
path: string;
|
|
20
|
+
} | {
|
|
21
|
+
kind: 'monorepo';
|
|
22
|
+
url: string;
|
|
23
|
+
repoName: string;
|
|
24
|
+
subPath: string;
|
|
25
|
+
};
|
|
26
|
+
export interface LockEntry {
|
|
27
|
+
source: PluginSourceRecord;
|
|
28
|
+
commitHash: string;
|
|
29
|
+
installedAt: string;
|
|
30
|
+
updatedAt?: string;
|
|
31
|
+
}
|
|
32
|
+
export interface PluginInfo {
|
|
33
|
+
name: string;
|
|
34
|
+
path: string;
|
|
35
|
+
commands: string[];
|
|
36
|
+
source?: string;
|
|
37
|
+
version?: string;
|
|
38
|
+
installedAt?: string;
|
|
39
|
+
/** If from a monorepo, the monorepo name. */
|
|
40
|
+
monorepoName?: string;
|
|
41
|
+
/** Description from webcmd-plugin.json. */
|
|
42
|
+
description?: string;
|
|
43
|
+
}
|
|
44
|
+
interface ParsedSource {
|
|
45
|
+
type: 'git' | 'local';
|
|
46
|
+
name: string;
|
|
47
|
+
subPlugin?: string;
|
|
48
|
+
cloneUrl?: string;
|
|
49
|
+
localPath?: string;
|
|
50
|
+
}
|
|
51
|
+
declare function isLocalPluginSource(source?: string): boolean;
|
|
52
|
+
declare function toStoredPluginSource(source: PluginSourceRecord): string;
|
|
53
|
+
declare function toLocalPluginSource(pluginDir: string): string;
|
|
54
|
+
declare function resolvePluginSource(lockEntry: LockEntry | undefined, pluginDir: string): PluginSourceRecord | undefined;
|
|
55
|
+
declare function resolveStoredPluginSource(lockEntry: LockEntry | undefined, pluginDir: string): string | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* Move a directory, with EXDEV fallback.
|
|
58
|
+
* fs.renameSync fails when source and destination are on different
|
|
59
|
+
* filesystems (e.g. /tmp → ~/.webcmd). In that case we copy then remove.
|
|
60
|
+
*/
|
|
61
|
+
type MoveDirFsOps = Pick<typeof fs, 'renameSync' | 'cpSync' | 'rmSync'>;
|
|
62
|
+
declare function moveDir(src: string, dest: string, fsOps?: MoveDirFsOps): void;
|
|
63
|
+
export interface ValidationResult {
|
|
64
|
+
valid: boolean;
|
|
65
|
+
errors: string[];
|
|
66
|
+
}
|
|
67
|
+
declare function readLockFileWithWriter(writeLock?: (lock: Record<string, LockEntry>) => void): Record<string, LockEntry>;
|
|
68
|
+
export declare function readLockFile(): Record<string, LockEntry>;
|
|
69
|
+
type WriteLockFileFsOps = Pick<typeof fs, 'mkdirSync' | 'writeFileSync' | 'renameSync' | 'rmSync'>;
|
|
70
|
+
declare function writeLockFileWithFs(lock: Record<string, LockEntry>, fsOps?: WriteLockFileFsOps): void;
|
|
71
|
+
export declare function writeLockFile(lock: Record<string, LockEntry>): void;
|
|
72
|
+
/** Get the HEAD commit hash of a git repo directory. */
|
|
73
|
+
export declare function getCommitHash(dir: string): string | undefined;
|
|
74
|
+
/**
|
|
75
|
+
* Validate that a downloaded plugin directory is a structurally valid plugin.
|
|
76
|
+
* Checks for at least one command file (.ts, .js) and a valid
|
|
77
|
+
* package.json if it contains .ts files.
|
|
78
|
+
*/
|
|
79
|
+
export declare function validatePluginStructure(pluginDir: string): ValidationResult;
|
|
80
|
+
declare function installDependencies(dir: string): void;
|
|
81
|
+
/**
|
|
82
|
+
* Monorepo lifecycle: install shared deps at repo root, then install and finalize each sub-plugin.
|
|
83
|
+
*
|
|
84
|
+
* The root install covers monorepos that use npm workspaces to hoist dependencies.
|
|
85
|
+
* For monorepos that do NOT use workspaces, sub-plugins may declare their own
|
|
86
|
+
* production dependencies in their package.json. We install those per sub-plugin
|
|
87
|
+
* so that runtime imports (e.g. `undici`) can be resolved from the sub-plugin
|
|
88
|
+
* directory. When the root already satisfies all deps this is a fast no-op.
|
|
89
|
+
*/
|
|
90
|
+
declare function postInstallMonorepoLifecycle(repoDir: string, pluginDirs: string[]): void;
|
|
91
|
+
/**
|
|
92
|
+
* Install a plugin from a source.
|
|
93
|
+
* Supports:
|
|
94
|
+
* "github:user/repo" — single plugin or full monorepo
|
|
95
|
+
* "github:user/repo/subplugin" — specific sub-plugin from a monorepo
|
|
96
|
+
* "https://github.com/user/repo"
|
|
97
|
+
* "file:///absolute/path" — local plugin directory (symlinked)
|
|
98
|
+
* "/absolute/path" — local plugin directory (symlinked)
|
|
99
|
+
*
|
|
100
|
+
* Returns the installed plugin name(s).
|
|
101
|
+
*/
|
|
102
|
+
export declare function installPlugin(source: string): string | string[];
|
|
103
|
+
/**
|
|
104
|
+
* Install a local plugin by creating a symlink.
|
|
105
|
+
* Used for plugin development: the source directory is symlinked into
|
|
106
|
+
* the plugins dir so changes are reflected immediately.
|
|
107
|
+
*/
|
|
108
|
+
declare function installLocalPlugin(localPath: string, name: string): string;
|
|
109
|
+
/**
|
|
110
|
+
* Uninstall a plugin by name.
|
|
111
|
+
* For monorepo sub-plugins: removes symlink and cleans up the monorepo
|
|
112
|
+
* directory when no more sub-plugins reference it.
|
|
113
|
+
*/
|
|
114
|
+
export declare function uninstallPlugin(name: string): void;
|
|
115
|
+
/** Synchronous check if a path is a symlink. */
|
|
116
|
+
declare function isSymlinkSync(p: string): boolean;
|
|
117
|
+
/**
|
|
118
|
+
* Update a plugin by name (git pull + re-install lifecycle).
|
|
119
|
+
* For monorepo sub-plugins: pulls the monorepo root and re-runs lifecycle
|
|
120
|
+
* for all sub-plugins from the same monorepo.
|
|
121
|
+
*/
|
|
122
|
+
export declare function updatePlugin(name: string): void;
|
|
123
|
+
export interface UpdateResult {
|
|
124
|
+
name: string;
|
|
125
|
+
success: boolean;
|
|
126
|
+
error?: string;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Update all installed plugins.
|
|
130
|
+
* Continues even if individual plugin updates fail.
|
|
131
|
+
*/
|
|
132
|
+
export declare function updateAllPlugins(): UpdateResult[];
|
|
133
|
+
/**
|
|
134
|
+
* List all installed plugins.
|
|
135
|
+
* Reads webcmd-plugin.json for description/version when available.
|
|
136
|
+
*/
|
|
137
|
+
export declare function listPlugins(): PluginInfo[];
|
|
138
|
+
/** Parse a plugin source string into clone URL, repo name, and optional sub-plugin. */
|
|
139
|
+
declare function parseSource(source: string): ParsedSource | null;
|
|
140
|
+
declare function ensureHostWebcmdPackageLink(targetLink: string, hostRoot: string): void;
|
|
141
|
+
/**
|
|
142
|
+
* Resolve the path to the esbuild CLI executable with fallback strategies.
|
|
143
|
+
*/
|
|
144
|
+
export declare function resolveEsbuildBin(): string | null;
|
|
145
|
+
declare function resolveHostWebcmdRoot(startFile?: string): string;
|
|
146
|
+
export { ensureHostWebcmdPackageLink as _ensureHostWebcmdPackageLink, resolveHostWebcmdRoot as _resolveHostWebcmdRoot, resolveEsbuildBin as _resolveEsbuildBin, getCommitHash as _getCommitHash, installDependencies as _installDependencies, parseSource as _parseSource, postInstallMonorepoLifecycle as _postInstallMonorepoLifecycle, readLockFile as _readLockFile, readLockFileWithWriter as _readLockFileWithWriter, updateAllPlugins as _updateAllPlugins, validatePluginStructure as _validatePluginStructure, writeLockFile as _writeLockFile, writeLockFileWithFs as _writeLockFileWithFs, isSymlinkSync as _isSymlinkSync, getMonoreposDir as _getMonoreposDir, installLocalPlugin as _installLocalPlugin, isLocalPluginSource as _isLocalPluginSource, moveDir as _moveDir, resolvePluginSource as _resolvePluginSource, resolveStoredPluginSource as _resolveStoredPluginSource, toStoredPluginSource as _toStoredPluginSource, toLocalPluginSource as _toLocalPluginSource, };
|