@agentrhq/webcmd 0.1.1 → 0.2.0
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 +278 -20
- package/cli-manifest.json +16247 -34913
- package/clis/_atlassian/shared.js +1 -1
- package/clis/booking/search.js +4 -4
- package/clis/chatgpt/ask.js +2 -2
- package/clis/chatgpt/utils.js +41 -42
- package/clis/chatgpt/utils.test.js +23 -23
- package/clis/chatgpt-app/ax.js +5 -5
- package/clis/chatgpt-app/ax.test.js +8 -8
- package/clis/chatgpt-app/new.js +2 -2
- package/clis/codex/sidebar.js +1 -1
- package/clis/codex/sidebar.test.js +12 -12
- package/clis/coingecko/top.js +3 -3
- package/clis/dblp/dblp.test.js +1 -1
- package/clis/discord-app/search.js +1 -1
- package/clis/discord-app/utils.js +6 -6
- package/clis/facebook/__fixtures__/notifications-page.html +6 -6
- package/clis/facebook/add-friend.js +2 -2
- package/clis/facebook/feed.js +18 -18
- package/clis/facebook/friends.js +4 -4
- package/clis/facebook/groups.js +3 -3
- package/clis/facebook/join-group.js +2 -2
- package/clis/facebook/marketplace-inbox.js +3 -3
- package/clis/facebook/marketplace-listings.js +1 -1
- package/clis/facebook/notifications.js +14 -15
- package/clis/facebook/notifications.test.js +28 -29
- package/clis/gemini/ask.test.js +12 -12
- package/clis/gemini/deep-research-result.js +2 -2
- package/clis/gemini/deep-research-result.test.js +2 -2
- package/clis/gemini/deep-research.js +2 -2
- package/clis/gemini/deep-research.test.js +1 -1
- package/clis/gemini/models.js +11 -11
- package/clis/gemini/models.test.js +1 -1
- package/clis/gemini/reply-state.test.js +89 -89
- package/clis/gemini/utils.js +41 -41
- package/clis/gemini/utils.test.js +30 -30
- package/clis/geogebra/utils.js +1 -1
- package/clis/google-scholar/search.js +3 -3
- package/clis/grok/delete.js +1 -1
- package/clis/grok/export-all.js +2 -2
- package/clis/grok/export.js +2 -2
- package/clis/grok/pin.js +3 -3
- package/clis/grok/utils.js +12 -12
- package/clis/grok/utils.test.js +2 -2
- package/clis/indeed/indeed.test.js +3 -3
- package/clis/indeed/utils.js +1 -1
- package/clis/instagram/post.js +19 -19
- package/clis/instagram/post.test.js +2 -2
- package/clis/instagram/reel.js +6 -6
- package/clis/linkedin/connect.js +3 -3
- package/clis/linkedin/people-search.js +4 -4
- package/clis/linkedin/profile-experience.js +6 -6
- package/clis/linkedin/profile-experience.test.js +10 -10
- package/clis/linkedin/profile-read.js +1 -1
- package/clis/linkedin/safe-send.js +1 -1
- package/clis/linkedin/search.js +1 -1
- package/clis/linkedin/shared.js +2 -2
- package/clis/linkedin/timeline.js +5 -5
- package/clis/manus/manus.test.js +2 -2
- package/clis/medium/feed.js +3 -3
- package/clis/medium/search.js +3 -3
- package/clis/medium/user.js +3 -3
- package/clis/notebooklm/auth.js +2 -2
- package/clis/notebooklm/note-list.test.js +4 -4
- package/clis/notebooklm/notes-get.test.js +8 -8
- package/clis/notebooklm/source-fulltext.test.js +11 -11
- package/clis/notebooklm/utils.js +28 -28
- package/clis/notebooklm/utils.test.js +10 -10
- package/clis/pixiv/search.test.js +3 -3
- package/clis/qoder/quest.js +2 -2
- package/clis/reddit/home.js +2 -2
- package/clis/reddit/hot.js +1 -1
- package/clis/reddit/read.js +2 -2
- package/clis/reddit/read.test.js +1 -1
- package/clis/reddit/reply.js +2 -2
- package/clis/reddit/whoami.js +2 -2
- package/clis/reuters/article-detail.js +1 -1
- package/clis/reuters/search.js +1 -1
- package/clis/slock/attachment-upload.test.js +1 -1
- package/clis/slock/task-convert.js +1 -1
- package/clis/substack/feed.js +3 -3
- package/clis/substack/publication.js +3 -3
- package/clis/substack/search.js +4 -4
- package/clis/tiktok/comment.js +2 -2
- package/clis/tiktok/follow.js +4 -4
- package/clis/tiktok/like.js +1 -1
- package/clis/tiktok/save.js +1 -1
- package/clis/tiktok/unfollow.js +4 -4
- package/clis/tiktok/unlike.js +1 -1
- package/clis/tiktok/unsave.js +2 -2
- package/clis/tiktok/write-refactor.test.js +5 -5
- package/clis/twitter/accept.js +3 -3
- package/clis/twitter/followers.js +1 -1
- package/clis/twitter/list-remove-core.js +2 -2
- package/clis/twitter/list-tweets.test.js +3 -3
- package/clis/twitter/lists.js +6 -6
- package/clis/twitter/lists.test.js +2 -2
- package/clis/twitter/reply-dm.js +1 -1
- package/clis/twitter/shared.test.js +4 -5
- package/clis/twitter/trending.js +1 -1
- package/clis/twitter/utils.js +1 -1
- package/clis/web/read.js +1 -1
- package/clis/web/read.test.js +2 -2
- package/clis/yahoo-finance/quote.js +1 -1
- package/clis/youtube/history.js +4 -4
- package/clis/youtube/transcript-group.js +1 -1
- package/clis/youtube/transcript-group.test.js +5 -5
- package/clis/youtube/transcript.js +5 -5
- package/clis/youtube/video.js +4 -4
- package/clis/youtube/video.test.js +6 -6
- package/dist/src/adapter-shadow.d.ts +11 -0
- package/dist/src/adapter-shadow.js +72 -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 +33 -0
- package/dist/src/browser/daemon-client.js +187 -0
- package/dist/src/browser/daemon-client.test.d.ts +1 -0
- package/dist/src/browser/daemon-client.test.js +411 -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 +90 -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 +65 -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 +190 -0
- package/dist/src/daemon/server.test.d.ts +1 -0
- package/dist/src/daemon/server.test.js +184 -0
- package/dist/src/daemon-utils.d.ts +19 -0
- package/dist/src/daemon-utils.js +46 -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 +69 -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 +174 -0
- package/dist/src/doctor.test.d.ts +1 -0
- package/dist/src/doctor.test.js +309 -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 +173 -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 +83 -0
- package/dist/src/electron-apps.test.d.ts +1 -0
- package/dist/src/electron-apps.test.js +67 -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 +511 -0
- package/dist/src/execution.test.d.ts +1 -0
- package/dist/src/execution.test.js +657 -0
- package/dist/src/external-clis.yaml +0 -37
- 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 +95 -0
- package/dist/src/generate-release-notes-cli.test.d.ts +1 -0
- package/dist/src/generate-release-notes-cli.test.js +140 -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/release-notes.d.ts +38 -0
- package/dist/src/release-notes.js +99 -0
- package/dist/src/release-notes.test.d.ts +1 -0
- package/dist/src/release-notes.test.js +61 -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 +336 -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/package.json +7 -3
- package/scripts/check-package-bin.mjs +95 -0
- package/scripts/generate-release-notes.ts +234 -0
- package/scripts/postinstall.js +1 -1
- package/scripts/silent-column-drop-baseline.json +0 -498
- package/scripts/typed-error-lint-baseline.json +0 -464
- package/skills/webcmd-adapter-author/SKILL.md +216 -213
- package/skills/webcmd-adapter-author/references/adapter-template.md +206 -399
- package/skills/webcmd-adapter-author/references/api-discovery.md +111 -220
- package/skills/webcmd-adapter-author/references/coverage-matrix.md +34 -68
- package/skills/webcmd-adapter-author/references/field-conventions.md +84 -167
- package/skills/webcmd-adapter-author/references/field-decode-playbook.md +60 -146
- package/skills/webcmd-adapter-author/references/jsdom-fixture-pattern.md +111 -178
- package/skills/webcmd-adapter-author/references/output-design.md +47 -125
- package/skills/webcmd-adapter-author/references/site-memory.md +116 -166
- package/skills/webcmd-adapter-author/references/site-recon.md +74 -78
- package/skills/webcmd-adapter-author/references/strategy-selection.md +80 -124
- package/skills/webcmd-adapter-author/references/success-rate-pitfalls.md +80 -105
- package/skills/webcmd-adapter-author/references/typed-errors.md +87 -178
- package/skills/webcmd-autofix/SKILL.md +136 -143
- package/skills/webcmd-sitemap-author/SKILL.md +58 -67
- package/skills/webcmd-sitemap-author/references/sitemap-schema.md +354 -494
- package/skills/webcmd-usage/SKILL.md +106 -97
- package/clis/12306/auth.js +0 -59
- package/clis/12306/me.js +0 -73
- package/clis/12306/orders.js +0 -96
- package/clis/12306/passengers.js +0 -90
- package/clis/12306/price.js +0 -166
- package/clis/12306/stations.js +0 -66
- package/clis/12306/train.js +0 -91
- package/clis/12306/trains.js +0 -166
- package/clis/12306/utils.js +0 -272
- package/clis/12306/utils.test.js +0 -424
- package/clis/1688/assets.js +0 -205
- package/clis/1688/assets.test.js +0 -39
- package/clis/1688/auth.js +0 -46
- package/clis/1688/download.js +0 -77
- package/clis/1688/download.test.js +0 -31
- package/clis/1688/item.js +0 -188
- package/clis/1688/item.test.js +0 -67
- package/clis/1688/search.js +0 -310
- package/clis/1688/search.test.js +0 -75
- package/clis/1688/shared.js +0 -557
- package/clis/1688/shared.test.js +0 -57
- package/clis/1688/store.js +0 -227
- package/clis/1688/store.test.js +0 -62
- package/clis/1point3acres/auth.js +0 -52
- package/clis/1point3acres/digest.js +0 -35
- package/clis/1point3acres/forum.js +0 -51
- package/clis/1point3acres/forums.js +0 -44
- package/clis/1point3acres/hot.js +0 -35
- package/clis/1point3acres/latest.js +0 -35
- package/clis/1point3acres/notifications.js +0 -64
- package/clis/1point3acres/search.js +0 -71
- package/clis/1point3acres/thread.js +0 -117
- package/clis/1point3acres/user.js +0 -77
- package/clis/1point3acres/utils.js +0 -247
- package/clis/36kr/article.js +0 -66
- package/clis/36kr/article.test.js +0 -46
- package/clis/36kr/hot.js +0 -87
- package/clis/36kr/hot.test.js +0 -15
- package/clis/36kr/news.js +0 -52
- package/clis/36kr/news.test.js +0 -85
- package/clis/36kr/search.js +0 -79
- package/clis/51job/company.js +0 -126
- package/clis/51job/detail.js +0 -109
- package/clis/51job/hot.js +0 -56
- package/clis/51job/search.js +0 -80
- package/clis/51job/utils.js +0 -302
- package/clis/51job/utils.test.js +0 -69
- package/clis/aibase/news.js +0 -110
- package/clis/aibase/news.test.js +0 -59
- package/clis/autohome/__fixtures__/catalog.html +0 -11
- package/clis/autohome/__fixtures__/koubei.json +0 -116
- package/clis/autohome/autohome.test.js +0 -115
- package/clis/autohome/brand.js +0 -108
- package/clis/autohome/score.js +0 -103
- package/clis/autohome/utils.js +0 -157
- package/clis/baidu-scholar/search.js +0 -87
- package/clis/baidu-scholar/search.test.js +0 -23
- package/clis/bilibili/auth.js +0 -36
- package/clis/bilibili/comment.js +0 -107
- package/clis/bilibili/comment.test.js +0 -153
- package/clis/bilibili/comments.js +0 -136
- package/clis/bilibili/comments.test.js +0 -142
- package/clis/bilibili/download.js +0 -178
- package/clis/bilibili/download.test.js +0 -173
- package/clis/bilibili/dynamic.js +0 -34
- package/clis/bilibili/dynamic.test.js +0 -68
- package/clis/bilibili/favorite.js +0 -47
- package/clis/bilibili/feed.js +0 -220
- package/clis/bilibili/follow.js +0 -140
- package/clis/bilibili/follow.test.js +0 -203
- package/clis/bilibili/following.js +0 -44
- package/clis/bilibili/history.js +0 -45
- package/clis/bilibili/hot.js +0 -40
- package/clis/bilibili/hot.test.js +0 -17
- package/clis/bilibili/me.js +0 -13
- package/clis/bilibili/ranking.js +0 -25
- package/clis/bilibili/search.js +0 -24
- package/clis/bilibili/subtitle.js +0 -141
- package/clis/bilibili/subtitle.test.js +0 -240
- package/clis/bilibili/summary.js +0 -167
- package/clis/bilibili/summary.test.js +0 -210
- package/clis/bilibili/unfollow.js +0 -121
- package/clis/bilibili/user-videos.js +0 -39
- package/clis/bilibili/utils.js +0 -273
- package/clis/bilibili/utils.test.js +0 -97
- package/clis/bilibili/video.js +0 -155
- package/clis/bilibili/video.test.js +0 -308
- package/clis/boss/auth.js +0 -47
- package/clis/boss/batchgreet.js +0 -61
- package/clis/boss/chatlist.js +0 -116
- package/clis/boss/chatlist.test.js +0 -211
- package/clis/boss/chatmsg.js +0 -117
- package/clis/boss/chatmsg.test.js +0 -230
- package/clis/boss/detail.js +0 -63
- package/clis/boss/exchange.js +0 -46
- package/clis/boss/greet.js +0 -49
- package/clis/boss/invite.js +0 -64
- package/clis/boss/joblist.js +0 -31
- package/clis/boss/mark.js +0 -70
- package/clis/boss/recommend.js +0 -45
- package/clis/boss/resume.js +0 -150
- package/clis/boss/search.js +0 -197
- package/clis/boss/search.test.js +0 -78
- package/clis/boss/send.js +0 -44
- package/clis/boss/stats.js +0 -66
- package/clis/boss/utils.js +0 -468
- package/clis/boss/utils.test.js +0 -34
- package/clis/chaoxing/assignments.js +0 -76
- package/clis/chaoxing/auth.js +0 -54
- package/clis/chaoxing/exams.js +0 -75
- package/clis/chaoxing/utils.js +0 -223
- package/clis/chaoxing/utils.test.js +0 -45
- package/clis/cnki/search.js +0 -61
- package/clis/cnki/search.test.js +0 -18
- package/clis/ctrip/auth.js +0 -50
- package/clis/ctrip/ctrip.test.js +0 -719
- package/clis/ctrip/flight.js +0 -136
- package/clis/ctrip/hotel-search.js +0 -132
- package/clis/ctrip/hotel-suggest.js +0 -45
- package/clis/ctrip/search.js +0 -41
- package/clis/ctrip/utils.js +0 -473
- package/clis/deepseek/ask.js +0 -158
- package/clis/deepseek/ask.test.js +0 -399
- package/clis/deepseek/auth.js +0 -54
- package/clis/deepseek/detail.js +0 -46
- package/clis/deepseek/detail.test.js +0 -81
- package/clis/deepseek/history.js +0 -27
- package/clis/deepseek/new.js +0 -33
- package/clis/deepseek/read.js +0 -25
- package/clis/deepseek/send.js +0 -140
- package/clis/deepseek/send.test.js +0 -107
- package/clis/deepseek/status.js +0 -26
- package/clis/deepseek/utils.js +0 -487
- package/clis/deepseek/utils.test.js +0 -370
- package/clis/dianping/__fixtures__/search.html +0 -168
- package/clis/dianping/__fixtures__/shop.html +0 -6
- package/clis/dianping/auth.js +0 -49
- package/clis/dianping/cityResolver.js +0 -185
- package/clis/dianping/dianping.test.js +0 -578
- package/clis/dianping/search.js +0 -157
- package/clis/dianping/shop.js +0 -173
- package/clis/dianping/utils.js +0 -157
- package/clis/dongchedi/__fixtures__/search.json +0 -60
- package/clis/dongchedi/__fixtures__/series-detail.json +0 -911
- package/clis/dongchedi/__fixtures__/series-score.json +0 -1396
- package/clis/dongchedi/dongchedi.test.js +0 -191
- package/clis/dongchedi/koubei.js +0 -85
- package/clis/dongchedi/models.js +0 -91
- package/clis/dongchedi/score.js +0 -83
- package/clis/dongchedi/search.js +0 -83
- package/clis/dongchedi/series.js +0 -87
- package/clis/dongchedi/specs.js +0 -115
- package/clis/dongchedi/utils.js +0 -180
- package/clis/douban/auth.js +0 -50
- package/clis/douban/book-hot.js +0 -15
- package/clis/douban/download.js +0 -68
- package/clis/douban/download.test.js +0 -170
- package/clis/douban/marks.js +0 -116
- package/clis/douban/movie-hot.js +0 -15
- package/clis/douban/movie-hot.test.js +0 -14
- package/clis/douban/photos.js +0 -35
- package/clis/douban/reviews.js +0 -107
- package/clis/douban/search.js +0 -18
- package/clis/douban/search.test.js +0 -11
- package/clis/douban/subject.js +0 -46
- package/clis/douban/subject.test.js +0 -11
- package/clis/douban/top250.js +0 -68
- package/clis/douban/utils.js +0 -657
- package/clis/douban/utils.test.js +0 -488
- package/clis/doubao/ask.js +0 -40
- package/clis/doubao/auth.js +0 -66
- package/clis/doubao/detail.js +0 -35
- package/clis/doubao/detail.test.js +0 -42
- package/clis/doubao/history.js +0 -30
- package/clis/doubao/history.test.js +0 -37
- package/clis/doubao/meeting-summary.js +0 -41
- package/clis/doubao/meeting-transcript.js +0 -38
- package/clis/doubao/new.js +0 -22
- package/clis/doubao/read.js +0 -21
- package/clis/doubao/send.js +0 -24
- package/clis/doubao/status.js +0 -26
- package/clis/doubao/utils.js +0 -1156
- package/clis/doubao/utils.test.js +0 -396
- package/clis/doubao-app/ask.js +0 -54
- package/clis/doubao-app/dump.js +0 -25
- package/clis/doubao-app/new.js +0 -21
- package/clis/doubao-app/read.js +0 -19
- package/clis/doubao-app/screenshot.js +0 -19
- package/clis/doubao-app/send.js +0 -28
- package/clis/doubao-app/status.js +0 -17
- package/clis/doubao-app/utils.js +0 -110
- package/clis/douyin/_shared/browser-fetch.js +0 -66
- package/clis/douyin/_shared/browser-fetch.test.js +0 -64
- package/clis/douyin/_shared/creation-id.js +0 -5
- package/clis/douyin/_shared/creation-id.test.js +0 -22
- package/clis/douyin/_shared/evaluate-result.js +0 -16
- package/clis/douyin/_shared/imagex-upload.js +0 -53
- package/clis/douyin/_shared/imagex-upload.test.js +0 -87
- package/clis/douyin/_shared/public-api.js +0 -29
- package/clis/douyin/_shared/sts2.js +0 -21
- package/clis/douyin/_shared/sts2.test.js +0 -27
- package/clis/douyin/_shared/text-extra.js +0 -15
- package/clis/douyin/_shared/text-extra.test.js +0 -37
- package/clis/douyin/_shared/timing.js +0 -22
- package/clis/douyin/_shared/timing.test.js +0 -28
- package/clis/douyin/_shared/tos-upload-short-read.test.js +0 -83
- package/clis/douyin/_shared/tos-upload.js +0 -331
- package/clis/douyin/_shared/tos-upload.test.js +0 -229
- package/clis/douyin/_shared/transcode.js +0 -45
- package/clis/douyin/_shared/transcode.test.js +0 -91
- package/clis/douyin/_shared/vod-upload.js +0 -212
- package/clis/douyin/_shared/vod-upload.test.js +0 -38
- package/clis/douyin/activities.js +0 -23
- package/clis/douyin/activities.test.js +0 -55
- package/clis/douyin/auth.js +0 -39
- package/clis/douyin/collections.js +0 -23
- package/clis/douyin/collections.test.js +0 -45
- package/clis/douyin/delete.js +0 -152
- package/clis/douyin/delete.test.js +0 -100
- package/clis/douyin/draft.js +0 -355
- package/clis/douyin/draft.test.js +0 -335
- package/clis/douyin/drafts.js +0 -24
- package/clis/douyin/drafts.test.js +0 -11
- package/clis/douyin/hashtag.js +0 -114
- package/clis/douyin/hashtag.test.js +0 -171
- package/clis/douyin/location.js +0 -25
- package/clis/douyin/location.test.js +0 -23
- package/clis/douyin/profile.js +0 -29
- package/clis/douyin/profile.test.js +0 -46
- package/clis/douyin/publish-upload-id.test.js +0 -206
- package/clis/douyin/publish.js +0 -341
- package/clis/douyin/publish.test.js +0 -38
- package/clis/douyin/search.js +0 -308
- package/clis/douyin/search.test.js +0 -307
- package/clis/douyin/stats.js +0 -28
- package/clis/douyin/stats.test.js +0 -22
- package/clis/douyin/update.js +0 -32
- package/clis/douyin/update.test.js +0 -11
- package/clis/douyin/user-videos.js +0 -82
- package/clis/douyin/user-videos.test.js +0 -151
- package/clis/douyin/videos.js +0 -52
- package/clis/douyin/videos.test.js +0 -54
- package/clis/eastmoney/_secid.js +0 -78
- package/clis/eastmoney/announcement.js +0 -53
- package/clis/eastmoney/convertible.js +0 -74
- package/clis/eastmoney/etf.js +0 -66
- package/clis/eastmoney/holders.js +0 -79
- package/clis/eastmoney/hot-rank.js +0 -51
- package/clis/eastmoney/hot-rank.test.js +0 -59
- package/clis/eastmoney/index-board.js +0 -97
- package/clis/eastmoney/kline.js +0 -88
- package/clis/eastmoney/kuaixun.js +0 -55
- package/clis/eastmoney/longhu.js +0 -68
- package/clis/eastmoney/money-flow.js +0 -79
- package/clis/eastmoney/northbound.js +0 -58
- package/clis/eastmoney/quote.js +0 -108
- package/clis/eastmoney/rank.js +0 -95
- package/clis/eastmoney/sectors.js +0 -77
- package/clis/flomo/auth.js +0 -55
- package/clis/flomo/memos.js +0 -228
- package/clis/flomo/memos.test.js +0 -144
- package/clis/gitee/auth.js +0 -41
- package/clis/gitee/index.js +0 -3
- package/clis/gitee/search.js +0 -137
- package/clis/gitee/search.test.js +0 -65
- package/clis/gitee/trending.js +0 -568
- package/clis/gitee/user.js +0 -200
- package/clis/gitee/user.test.js +0 -63
- package/clis/gov-law/commands.test.js +0 -39
- package/clis/gov-law/recent.js +0 -22
- package/clis/gov-law/search.js +0 -41
- package/clis/gov-law/shared.js +0 -51
- package/clis/gov-policy/__fixtures__/recent.html +0 -16
- package/clis/gov-policy/__fixtures__/search.html +0 -41
- package/clis/gov-policy/gov-policy.test.js +0 -224
- package/clis/gov-policy/recent.js +0 -90
- package/clis/gov-policy/search.js +0 -91
- package/clis/gov-policy/utils.js +0 -54
- package/clis/guazi/__fixtures__/detail.html +0 -7
- package/clis/guazi/__fixtures__/list.html +0 -5
- package/clis/guazi/browse.js +0 -95
- package/clis/guazi/car.js +0 -110
- package/clis/guazi/guazi.test.js +0 -126
- package/clis/guazi/utils.js +0 -133
- package/clis/huodongxing/events.js +0 -322
- package/clis/huodongxing/events.test.js +0 -296
- package/clis/hupu/__fixtures__/hot-home.html +0 -64
- package/clis/hupu/auth.js +0 -47
- package/clis/hupu/detail.js +0 -72
- package/clis/hupu/hot.js +0 -163
- package/clis/hupu/hot.test.js +0 -224
- package/clis/hupu/like.js +0 -76
- package/clis/hupu/mentions.js +0 -160
- package/clis/hupu/reply.js +0 -72
- package/clis/hupu/search.js +0 -60
- package/clis/hupu/unlike.js +0 -76
- package/clis/hupu/utils.js +0 -319
- package/clis/jd/add-cart.js +0 -72
- package/clis/jd/auth.js +0 -46
- package/clis/jd/cart.js +0 -80
- package/clis/jd/commands.test.js +0 -41
- package/clis/jd/detail.js +0 -63
- package/clis/jd/item.js +0 -730
- package/clis/jd/item.test.js +0 -354
- package/clis/jd/item.test.ts +0 -517
- package/clis/jd/reviews.js +0 -55
- package/clis/jd/search.js +0 -66
- package/clis/jianyu/auth.js +0 -62
- package/clis/jianyu/detail.js +0 -21
- package/clis/jianyu/search.js +0 -634
- package/clis/jianyu/search.test.js +0 -153
- package/clis/jianyu/shared/china-bid-search.js +0 -165
- package/clis/jianyu/shared/procurement-contract.js +0 -324
- package/clis/jianyu/shared/procurement-contract.test.js +0 -72
- package/clis/jianyu/shared/procurement-detail.js +0 -107
- package/clis/jianyu/shared/procurement-detail.test.js +0 -84
- package/clis/jike/auth.js +0 -48
- package/clis/jike/comment.js +0 -107
- package/clis/jike/create.js +0 -106
- package/clis/jike/feed.js +0 -68
- package/clis/jike/like.js +0 -61
- package/clis/jike/notifications.js +0 -169
- package/clis/jike/post.js +0 -72
- package/clis/jike/read.test.js +0 -86
- package/clis/jike/repost.js +0 -103
- package/clis/jike/search.js +0 -68
- package/clis/jike/topic.js +0 -65
- package/clis/jike/user.js +0 -65
- package/clis/jike/utils.js +0 -25
- package/clis/jimeng/auth.js +0 -46
- package/clis/jimeng/generate.js +0 -84
- package/clis/jimeng/history.js +0 -48
- package/clis/jimeng/new.js +0 -44
- package/clis/jimeng/workspaces.js +0 -42
- package/clis/juejin/hot.js +0 -37
- package/clis/juejin/juejin.test.js +0 -241
- package/clis/juejin/recommend.js +0 -61
- package/clis/juejin/utils.js +0 -199
- package/clis/ke/auth.js +0 -46
- package/clis/ke/chengjiao.js +0 -78
- package/clis/ke/ershoufang.js +0 -101
- package/clis/ke/utils.js +0 -104
- package/clis/ke/xiaoqu.js +0 -78
- package/clis/ke/zufang.js +0 -95
- package/clis/kimi/_utils.js +0 -110
- package/clis/kimi/audit-extras.js +0 -268
- package/clis/kimi/auth.js +0 -57
- package/clis/kimi/chat.js +0 -470
- package/clis/kimi/kimi.test.js +0 -187
- package/clis/kimi/storage.js +0 -169
- package/clis/kimi/ui.js +0 -314
- package/clis/kimi/usage.js +0 -144
- package/clis/linux-do/auth.js +0 -55
- package/clis/linux-do/categories.js +0 -50
- package/clis/linux-do/feed.js +0 -395
- package/clis/linux-do/feed.test.js +0 -153
- package/clis/linux-do/search.js +0 -29
- package/clis/linux-do/tags.js +0 -28
- package/clis/linux-do/topic-content.js +0 -155
- package/clis/linux-do/topic-content.test.js +0 -59
- package/clis/linux-do/topic.js +0 -53
- package/clis/linux-do/user-posts.js +0 -57
- package/clis/linux-do/user-topics.js +0 -37
- package/clis/maimai/auth.js +0 -47
- package/clis/maimai/search-talents.js +0 -192
- package/clis/maimai/search-talents.test.js +0 -29
- package/clis/mubu/doc.js +0 -41
- package/clis/mubu/docs.js +0 -44
- package/clis/mubu/notes.js +0 -245
- package/clis/mubu/recent.js +0 -28
- package/clis/mubu/search.js +0 -63
- package/clis/mubu/utils.js +0 -304
- package/clis/nowcoder/auth.js +0 -65
- package/clis/nowcoder/companies.js +0 -24
- package/clis/nowcoder/creators.js +0 -28
- package/clis/nowcoder/detail.js +0 -62
- package/clis/nowcoder/experience.js +0 -37
- package/clis/nowcoder/hot.js +0 -25
- package/clis/nowcoder/jobs.js +0 -22
- package/clis/nowcoder/notifications.js +0 -30
- package/clis/nowcoder/papers.js +0 -41
- package/clis/nowcoder/practice.js +0 -38
- package/clis/nowcoder/recommend.js +0 -31
- package/clis/nowcoder/referral.js +0 -40
- package/clis/nowcoder/salary.js +0 -41
- package/clis/nowcoder/search.js +0 -50
- package/clis/nowcoder/suggest.js +0 -34
- package/clis/nowcoder/topics.js +0 -28
- package/clis/nowcoder/trending.js +0 -26
- package/clis/ones/common.js +0 -144
- package/clis/ones/enrich-tasks.js +0 -37
- package/clis/ones/login.js +0 -81
- package/clis/ones/logout.js +0 -18
- package/clis/ones/me.js +0 -31
- package/clis/ones/my-tasks.js +0 -121
- package/clis/ones/resolve-labels.js +0 -64
- package/clis/ones/task-helpers.js +0 -212
- package/clis/ones/task-helpers.test.js +0 -12
- package/clis/ones/task.js +0 -67
- package/clis/ones/tasks.js +0 -80
- package/clis/ones/token-info.js +0 -43
- package/clis/ones/worklog.js +0 -268
- package/clis/ones/worklog.test.js +0 -20
- package/clis/powerchina/auth.js +0 -52
- package/clis/powerchina/search.js +0 -251
- package/clis/powerchina/search.test.js +0 -93
- package/clis/quark/auth.js +0 -47
- package/clis/quark/ls.js +0 -64
- package/clis/quark/mkdir.js +0 -37
- package/clis/quark/mv.js +0 -54
- package/clis/quark/rename.js +0 -27
- package/clis/quark/rm.js +0 -25
- package/clis/quark/save.js +0 -81
- package/clis/quark/share-tree.js +0 -46
- package/clis/quark/utils.js +0 -146
- package/clis/quark/utils.test.js +0 -58
- package/clis/qwen/ask.js +0 -104
- package/clis/qwen/ask.test.js +0 -36
- package/clis/qwen/auth.js +0 -56
- package/clis/qwen/detail.js +0 -62
- package/clis/qwen/history.js +0 -61
- package/clis/qwen/image.js +0 -179
- package/clis/qwen/new.js +0 -23
- package/clis/qwen/read.js +0 -41
- package/clis/qwen/send.js +0 -55
- package/clis/qwen/status.js +0 -37
- package/clis/qwen/utils.js +0 -461
- package/clis/qwen/utils.test.js +0 -128
- package/clis/rednote/auth.js +0 -52
- package/clis/rednote/comments.js +0 -85
- package/clis/rednote/download.js +0 -59
- package/clis/rednote/feed.js +0 -27
- package/clis/rednote/navigation.test.js +0 -26
- package/clis/rednote/note.js +0 -68
- package/clis/rednote/notifications.js +0 -139
- package/clis/rednote/rednote.test.js +0 -240
- package/clis/rednote/search.js +0 -107
- package/clis/rednote/user.js +0 -55
- package/clis/sinablog/article.js +0 -15
- package/clis/sinablog/hot.js +0 -15
- package/clis/sinablog/search.js +0 -52
- package/clis/sinablog/user.js +0 -16
- package/clis/sinablog/utils.js +0 -186
- package/clis/sinafinance/news.js +0 -62
- package/clis/sinafinance/rolling-news.js +0 -41
- package/clis/sinafinance/stock-rank.js +0 -66
- package/clis/sinafinance/stock.js +0 -121
- package/clis/sinafinance/stock.test.js +0 -59
- package/clis/smzdm/search.js +0 -149
- package/clis/smzdm/search.test.js +0 -114
- package/clis/taobao/add-cart.js +0 -150
- package/clis/taobao/auth.js +0 -58
- package/clis/taobao/cart.js +0 -96
- package/clis/taobao/commands.test.js +0 -41
- package/clis/taobao/detail.js +0 -71
- package/clis/taobao/reviews.js +0 -77
- package/clis/taobao/search.js +0 -97
- package/clis/tdx/hot-rank.js +0 -48
- package/clis/tdx/hot-rank.test.js +0 -59
- package/clis/ths/hot-rank.js +0 -50
- package/clis/ths/hot-rank.test.js +0 -64
- package/clis/tieba/commands.test.js +0 -79
- package/clis/tieba/hot.js +0 -48
- package/clis/tieba/posts.js +0 -86
- package/clis/tieba/read.js +0 -141
- package/clis/tieba/search.js +0 -109
- package/clis/tieba/utils.js +0 -240
- package/clis/tieba/utils.test.js +0 -290
- package/clis/toutiao/articles.js +0 -55
- package/clis/toutiao/auth.js +0 -70
- package/clis/toutiao/hot.js +0 -63
- package/clis/toutiao/toutiao.test.js +0 -378
- package/clis/toutiao/utils.js +0 -161
- package/clis/trae-cn/activity.js +0 -22
- package/clis/trae-cn/approve.js +0 -52
- package/clis/trae-cn/ask.js +0 -99
- package/clis/trae-cn/dump.js +0 -5
- package/clis/trae-cn/export.js +0 -40
- package/clis/trae-cn/model.js +0 -22
- package/clis/trae-cn/new.js +0 -63
- package/clis/trae-cn/read.js +0 -23
- package/clis/trae-cn/screenshot.js +0 -5
- package/clis/trae-cn/select-model.js +0 -25
- package/clis/trae-cn/send.js +0 -23
- package/clis/trae-cn/setup.js +0 -75
- package/clis/trae-cn/status.js +0 -27
- package/clis/trae-cn/targets.js +0 -96
- package/clis/trae-cn/trae-cn.test.js +0 -412
- package/clis/trae-cn/utils.js +0 -750
- package/clis/trae-cn/watch.js +0 -119
- package/clis/uisdc/news.js +0 -105
- package/clis/uisdc/news.test.js +0 -66
- package/clis/v2ex/auth.js +0 -44
- package/clis/v2ex/daily.js +0 -99
- package/clis/v2ex/hot.js +0 -26
- package/clis/v2ex/latest.js +0 -26
- package/clis/v2ex/me.js +0 -100
- package/clis/v2ex/member.js +0 -28
- package/clis/v2ex/node.js +0 -39
- package/clis/v2ex/nodes.js +0 -26
- package/clis/v2ex/notifications.js +0 -72
- package/clis/v2ex/replies.js +0 -27
- package/clis/v2ex/topic.js +0 -31
- package/clis/v2ex/user.js +0 -34
- package/clis/wanfang/search.js +0 -66
- package/clis/wanfang/search.test.js +0 -23
- package/clis/wechat-channels/auth.js +0 -62
- package/clis/wechat-channels/publish.js +0 -732
- package/clis/wechat-channels/publish.test.js +0 -144
- package/clis/weibo/auth.js +0 -53
- package/clis/weibo/comments.js +0 -53
- package/clis/weibo/delete.js +0 -172
- package/clis/weibo/delete.test.js +0 -94
- package/clis/weibo/envelope.test.js +0 -85
- package/clis/weibo/favorites.js +0 -170
- package/clis/weibo/favorites.test.js +0 -114
- package/clis/weibo/feed.js +0 -69
- package/clis/weibo/hot.js +0 -39
- package/clis/weibo/me.js +0 -75
- package/clis/weibo/post.js +0 -75
- package/clis/weibo/publish.js +0 -306
- package/clis/weibo/publish.test.js +0 -192
- package/clis/weibo/search.js +0 -80
- package/clis/weibo/user-posts.js +0 -234
- package/clis/weibo/user-posts.test.js +0 -92
- package/clis/weibo/user.js +0 -63
- package/clis/weibo/utils.js +0 -59
- package/clis/weibo/utils.test.js +0 -36
- package/clis/weixin/create-draft.js +0 -226
- package/clis/weixin/download.js +0 -371
- package/clis/weixin/download.test.js +0 -106
- package/clis/weixin/drafts.js +0 -66
- package/clis/weixin/drafts.test.js +0 -69
- package/clis/weixin/search.js +0 -157
- package/clis/weixin/search.test.js +0 -227
- package/clis/weread/ai-outline.js +0 -171
- package/clis/weread/ai-outline.test.js +0 -83
- package/clis/weread/auth.js +0 -59
- package/clis/weread/book-search.js +0 -438
- package/clis/weread/book-search.test.js +0 -242
- package/clis/weread/book.js +0 -233
- package/clis/weread/commands.test.js +0 -398
- package/clis/weread/highlights.js +0 -24
- package/clis/weread/notebooks.js +0 -22
- package/clis/weread/notes.js +0 -30
- package/clis/weread/private-api-regression.test.js +0 -369
- package/clis/weread/ranking.js +0 -29
- package/clis/weread/search-regression.test.js +0 -494
- package/clis/weread/search.js +0 -186
- package/clis/weread/shelf.js +0 -66
- package/clis/weread/utils.js +0 -321
- package/clis/weread/utils.test.js +0 -128
- package/clis/weread-official/book.js +0 -135
- package/clis/weread-official/commands.test.js +0 -385
- package/clis/weread-official/discover.js +0 -107
- package/clis/weread-official/list-apis.js +0 -95
- package/clis/weread-official/notes.js +0 -171
- package/clis/weread-official/readdata.js +0 -158
- package/clis/weread-official/review.js +0 -93
- package/clis/weread-official/search.js +0 -106
- package/clis/weread-official/shelf.js +0 -97
- package/clis/weread-official/utils.js +0 -293
- package/clis/weread-official/utils.test.js +0 -242
- package/clis/xianyu/auth.js +0 -68
- package/clis/xianyu/chat.js +0 -74
- package/clis/xianyu/chat.test.js +0 -84
- package/clis/xianyu/im.js +0 -322
- package/clis/xianyu/im.test.js +0 -253
- package/clis/xianyu/inbox.js +0 -96
- package/clis/xianyu/item.js +0 -153
- package/clis/xianyu/item.test.js +0 -56
- package/clis/xianyu/messages.js +0 -91
- package/clis/xianyu/publish.js +0 -485
- package/clis/xianyu/publish.test.js +0 -220
- package/clis/xianyu/reply.js +0 -82
- package/clis/xianyu/search.js +0 -262
- package/clis/xianyu/search.test.js +0 -104
- package/clis/xianyu/utils.js +0 -8
- package/clis/xiaoe/auth.js +0 -55
- package/clis/xiaoe/catalog.js +0 -227
- package/clis/xiaoe/content.js +0 -175
- package/clis/xiaoe/courses.js +0 -127
- package/clis/xiaoe/detail.js +0 -36
- package/clis/xiaoe/play-url.js +0 -121
- package/clis/xiaoe/xiaoe.test.js +0 -486
- package/clis/xiaohongshu/ask.js +0 -426
- package/clis/xiaohongshu/ask.test.js +0 -271
- package/clis/xiaohongshu/auth.js +0 -53
- package/clis/xiaohongshu/collection-helpers.js +0 -283
- package/clis/xiaohongshu/collection-helpers.test.js +0 -125
- package/clis/xiaohongshu/comments.js +0 -228
- package/clis/xiaohongshu/comments.test.js +0 -320
- package/clis/xiaohongshu/creator-note-detail.js +0 -482
- package/clis/xiaohongshu/creator-note-detail.test.js +0 -451
- package/clis/xiaohongshu/creator-notes-summary.js +0 -98
- package/clis/xiaohongshu/creator-notes-summary.test.js +0 -94
- package/clis/xiaohongshu/creator-notes.js +0 -479
- package/clis/xiaohongshu/creator-notes.test.js +0 -281
- package/clis/xiaohongshu/creator-profile.js +0 -55
- package/clis/xiaohongshu/creator-stats.js +0 -76
- package/clis/xiaohongshu/creator-stats.test.js +0 -24
- package/clis/xiaohongshu/delete-note.js +0 -260
- package/clis/xiaohongshu/delete-note.test.js +0 -172
- package/clis/xiaohongshu/download.js +0 -249
- package/clis/xiaohongshu/download.test.js +0 -339
- package/clis/xiaohongshu/draft-clear.js +0 -91
- package/clis/xiaohongshu/draft-delete.js +0 -103
- package/clis/xiaohongshu/draft-open.js +0 -43
- package/clis/xiaohongshu/draft-utils.js +0 -142
- package/clis/xiaohongshu/drafts.js +0 -28
- package/clis/xiaohongshu/drafts.test.js +0 -172
- package/clis/xiaohongshu/feed.js +0 -163
- package/clis/xiaohongshu/feed.test.js +0 -126
- package/clis/xiaohongshu/follow.js +0 -226
- package/clis/xiaohongshu/follow.test.js +0 -211
- package/clis/xiaohongshu/liked.js +0 -29
- package/clis/xiaohongshu/liked.test.js +0 -82
- package/clis/xiaohongshu/navigation.test.js +0 -38
- package/clis/xiaohongshu/note-helpers.js +0 -69
- package/clis/xiaohongshu/note.js +0 -104
- package/clis/xiaohongshu/note.test.js +0 -249
- package/clis/xiaohongshu/notifications.js +0 -46
- package/clis/xiaohongshu/publish.js +0 -1423
- package/clis/xiaohongshu/publish.test.js +0 -1141
- package/clis/xiaohongshu/saved.js +0 -29
- package/clis/xiaohongshu/saved.test.js +0 -143
- package/clis/xiaohongshu/search.js +0 -330
- package/clis/xiaohongshu/search.test.js +0 -325
- package/clis/xiaohongshu/unfollow.js +0 -285
- package/clis/xiaohongshu/user-helpers.js +0 -78
- package/clis/xiaohongshu/user-helpers.test.js +0 -160
- package/clis/xiaohongshu/user.js +0 -140
- package/clis/xiaohongshu/user.test.js +0 -141
- package/clis/xiaoyuzhou/auth.js +0 -303
- package/clis/xiaoyuzhou/auth.test.js +0 -124
- package/clis/xiaoyuzhou/download.js +0 -54
- package/clis/xiaoyuzhou/download.test.js +0 -135
- package/clis/xiaoyuzhou/episode.js +0 -34
- package/clis/xiaoyuzhou/podcast-episodes.js +0 -41
- package/clis/xiaoyuzhou/podcast-episodes.test.js +0 -78
- package/clis/xiaoyuzhou/podcast.js +0 -33
- package/clis/xiaoyuzhou/transcript.js +0 -77
- package/clis/xiaoyuzhou/transcript.test.js +0 -195
- package/clis/xiaoyuzhou/utils.js +0 -15
- package/clis/xiaoyuzhou/utils.test.js +0 -39
- package/clis/xueqiu/auth.js +0 -63
- package/clis/xueqiu/comments.js +0 -355
- package/clis/xueqiu/comments.test.js +0 -696
- package/clis/xueqiu/danjuan-utils.js +0 -126
- package/clis/xueqiu/danjuan-utils.test.js +0 -41
- package/clis/xueqiu/earnings-date.js +0 -45
- package/clis/xueqiu/feed.js +0 -39
- package/clis/xueqiu/fund-holdings.js +0 -29
- package/clis/xueqiu/fund-snapshot.js +0 -26
- package/clis/xueqiu/groups.js +0 -23
- package/clis/xueqiu/hot-stock.js +0 -32
- package/clis/xueqiu/hot.js +0 -37
- package/clis/xueqiu/kline.js +0 -44
- package/clis/xueqiu/search.js +0 -37
- package/clis/xueqiu/stock.js +0 -65
- package/clis/xueqiu/utils.js +0 -48
- package/clis/xueqiu/utils.test.js +0 -26
- package/clis/xueqiu/watchlist.js +0 -37
- package/clis/youdao/note.js +0 -258
- package/clis/youdao/note.test.js +0 -99
- package/clis/yuanbao/ask.js +0 -362
- package/clis/yuanbao/ask.test.js +0 -124
- package/clis/yuanbao/auth.js +0 -59
- package/clis/yuanbao/detail.js +0 -65
- package/clis/yuanbao/history.js +0 -51
- package/clis/yuanbao/new.js +0 -72
- package/clis/yuanbao/new.test.js +0 -30
- package/clis/yuanbao/read.js +0 -38
- package/clis/yuanbao/send.js +0 -57
- package/clis/yuanbao/shared.js +0 -341
- package/clis/yuanbao/shared.test.js +0 -80
- package/clis/yuanbao/status.js +0 -44
- package/clis/zhihu/answer-comments.js +0 -280
- package/clis/zhihu/answer-comments.test.js +0 -287
- package/clis/zhihu/answer-detail.js +0 -216
- package/clis/zhihu/answer-detail.test.js +0 -338
- package/clis/zhihu/answer.js +0 -54
- package/clis/zhihu/answer.test.js +0 -54
- package/clis/zhihu/auth.js +0 -59
- package/clis/zhihu/collection.js +0 -199
- package/clis/zhihu/collection.test.js +0 -337
- package/clis/zhihu/collections.js +0 -128
- package/clis/zhihu/collections.test.js +0 -182
- package/clis/zhihu/comment.js +0 -55
- package/clis/zhihu/comment.test.js +0 -50
- package/clis/zhihu/download.js +0 -80
- package/clis/zhihu/download.test.js +0 -12
- package/clis/zhihu/favorite.js +0 -87
- package/clis/zhihu/favorite.test.js +0 -59
- package/clis/zhihu/follow.js +0 -50
- package/clis/zhihu/follow.test.js +0 -42
- package/clis/zhihu/followers.js +0 -40
- package/clis/zhihu/followers.test.js +0 -42
- package/clis/zhihu/following.js +0 -40
- package/clis/zhihu/following.test.js +0 -44
- package/clis/zhihu/hot.js +0 -44
- package/clis/zhihu/like.js +0 -47
- package/clis/zhihu/like.test.js +0 -41
- package/clis/zhihu/paginate.js +0 -128
- package/clis/zhihu/pins.js +0 -41
- package/clis/zhihu/pins.test.js +0 -44
- package/clis/zhihu/question.js +0 -113
- package/clis/zhihu/question.test.js +0 -251
- package/clis/zhihu/recommend.js +0 -103
- package/clis/zhihu/recommend.test.js +0 -143
- package/clis/zhihu/search.js +0 -206
- package/clis/zhihu/search.test.js +0 -198
- package/clis/zhihu/target.js +0 -91
- package/clis/zhihu/target.test.js +0 -77
- package/clis/zhihu/text.js +0 -29
- package/clis/zhihu/text.test.js +0 -24
- package/clis/zhihu/user-answers.js +0 -41
- package/clis/zhihu/user-answers.test.js +0 -69
- package/clis/zhihu/user-arg.js +0 -34
- package/clis/zhihu/user-articles.js +0 -40
- package/clis/zhihu/user-articles.test.js +0 -44
- package/clis/zhihu/user.js +0 -59
- package/clis/zhihu/user.test.js +0 -73
- package/clis/zhihu/write-shared.js +0 -228
- package/clis/zhihu/write-shared.test.js +0 -176
- package/clis/zsxq/auth.js +0 -68
- package/clis/zsxq/dynamics.js +0 -48
- package/clis/zsxq/groups.js +0 -33
- package/clis/zsxq/search.js +0 -44
- package/clis/zsxq/search.test.js +0 -24
- package/clis/zsxq/topic.js +0 -50
- package/clis/zsxq/topic.test.js +0 -30
- package/clis/zsxq/topics.js +0 -26
- package/clis/zsxq/topics.test.js +0 -24
- package/clis/zsxq/utils.js +0 -233
- package/clis/zsxq/utils.test.js +0 -31
- package/skills/webcmd-adapter-author/references/site-memory/bilibili.md +0 -70
- package/skills/webcmd-adapter-author/references/site-memory/eastmoney.md +0 -70
- package/skills/webcmd-adapter-author/references/site-memory/tonghuashun.md +0 -51
- package/skills/webcmd-adapter-author/references/site-memory/xueqiu.md +0 -58
- /package/{clis/douyin/_shared/types.js → dist/src/adapter-shadow.test.d.ts} +0 -0
|
@@ -0,0 +1,1303 @@
|
|
|
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
|
+
import * as os from 'node:os';
|
|
11
|
+
import * as path from 'node:path';
|
|
12
|
+
import { execSync, execFileSync } from 'node:child_process';
|
|
13
|
+
import { fileURLToPath } from 'node:url';
|
|
14
|
+
import { PLUGINS_DIR } from './discovery.js';
|
|
15
|
+
import { getErrorMessage, PluginError } from './errors.js';
|
|
16
|
+
import { log } from './logger.js';
|
|
17
|
+
import { isRecord } from './utils.js';
|
|
18
|
+
import { PACKAGE_NAME } from './brand.js';
|
|
19
|
+
import { readPluginManifest, isMonorepo, getEnabledPlugins, checkCompatibility, } from './plugin-manifest.js';
|
|
20
|
+
const isWindows = process.platform === 'win32';
|
|
21
|
+
const LOCAL_PLUGIN_SOURCE_PREFIX = 'local:';
|
|
22
|
+
/** Get home directory, respecting HOME environment variable for test isolation. */
|
|
23
|
+
function getHomeDir() {
|
|
24
|
+
return process.env.HOME || process.env.USERPROFILE || os.homedir();
|
|
25
|
+
}
|
|
26
|
+
/** Path to the lock file that tracks installed plugin versions. */
|
|
27
|
+
export function getLockFilePath() {
|
|
28
|
+
return path.join(getHomeDir(), '.webcmd', 'plugins.lock.json');
|
|
29
|
+
}
|
|
30
|
+
/** Monorepo clones directory: ~/.webcmd/monorepos/ */
|
|
31
|
+
export function getMonoreposDir() {
|
|
32
|
+
return path.join(getHomeDir(), '.webcmd', 'monorepos');
|
|
33
|
+
}
|
|
34
|
+
function parseStoredPluginSource(source) {
|
|
35
|
+
if (!source)
|
|
36
|
+
return undefined;
|
|
37
|
+
if (source.startsWith(LOCAL_PLUGIN_SOURCE_PREFIX)) {
|
|
38
|
+
return {
|
|
39
|
+
kind: 'local',
|
|
40
|
+
path: path.resolve(source.slice(LOCAL_PLUGIN_SOURCE_PREFIX.length)),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return { kind: 'git', url: source };
|
|
44
|
+
}
|
|
45
|
+
function isLocalPluginSource(source) {
|
|
46
|
+
return parseStoredPluginSource(source)?.kind === 'local';
|
|
47
|
+
}
|
|
48
|
+
function toStoredPluginSource(source) {
|
|
49
|
+
if (source.kind === 'local') {
|
|
50
|
+
return `${LOCAL_PLUGIN_SOURCE_PREFIX}${path.resolve(source.path)}`;
|
|
51
|
+
}
|
|
52
|
+
return source.url;
|
|
53
|
+
}
|
|
54
|
+
function toLocalPluginSource(pluginDir) {
|
|
55
|
+
return toStoredPluginSource({ kind: 'local', path: pluginDir });
|
|
56
|
+
}
|
|
57
|
+
// isRecord is imported from './utils.js'
|
|
58
|
+
function normalizeLegacyMonorepo(value) {
|
|
59
|
+
if (!isRecord(value))
|
|
60
|
+
return undefined;
|
|
61
|
+
if (typeof value.name !== 'string' || typeof value.subPath !== 'string')
|
|
62
|
+
return undefined;
|
|
63
|
+
return { name: value.name, subPath: value.subPath };
|
|
64
|
+
}
|
|
65
|
+
function normalizePluginSource(source, legacyMonorepo) {
|
|
66
|
+
if (typeof source === 'string') {
|
|
67
|
+
const parsed = parseStoredPluginSource(source);
|
|
68
|
+
if (!parsed)
|
|
69
|
+
return undefined;
|
|
70
|
+
if (parsed.kind === 'git' && legacyMonorepo) {
|
|
71
|
+
return {
|
|
72
|
+
kind: 'monorepo',
|
|
73
|
+
url: parsed.url,
|
|
74
|
+
repoName: legacyMonorepo.name,
|
|
75
|
+
subPath: legacyMonorepo.subPath,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return parsed;
|
|
79
|
+
}
|
|
80
|
+
if (!isRecord(source) || typeof source.kind !== 'string')
|
|
81
|
+
return undefined;
|
|
82
|
+
switch (source.kind) {
|
|
83
|
+
case 'git':
|
|
84
|
+
return typeof source.url === 'string'
|
|
85
|
+
? { kind: 'git', url: source.url }
|
|
86
|
+
: undefined;
|
|
87
|
+
case 'local':
|
|
88
|
+
return typeof source.path === 'string'
|
|
89
|
+
? { kind: 'local', path: path.resolve(source.path) }
|
|
90
|
+
: undefined;
|
|
91
|
+
case 'monorepo':
|
|
92
|
+
return typeof source.url === 'string'
|
|
93
|
+
&& typeof source.repoName === 'string'
|
|
94
|
+
&& typeof source.subPath === 'string'
|
|
95
|
+
? {
|
|
96
|
+
kind: 'monorepo',
|
|
97
|
+
url: source.url,
|
|
98
|
+
repoName: source.repoName,
|
|
99
|
+
subPath: source.subPath,
|
|
100
|
+
}
|
|
101
|
+
: undefined;
|
|
102
|
+
default:
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function normalizeLockEntry(value) {
|
|
107
|
+
if (!isRecord(value))
|
|
108
|
+
return undefined;
|
|
109
|
+
const legacyMonorepo = normalizeLegacyMonorepo(value.monorepo);
|
|
110
|
+
const source = normalizePluginSource(value.source, legacyMonorepo);
|
|
111
|
+
if (!source)
|
|
112
|
+
return undefined;
|
|
113
|
+
if (typeof value.commitHash !== 'string' || typeof value.installedAt !== 'string') {
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
const entry = {
|
|
117
|
+
source,
|
|
118
|
+
commitHash: value.commitHash,
|
|
119
|
+
installedAt: value.installedAt,
|
|
120
|
+
};
|
|
121
|
+
if (typeof value.updatedAt === 'string') {
|
|
122
|
+
entry.updatedAt = value.updatedAt;
|
|
123
|
+
}
|
|
124
|
+
return entry;
|
|
125
|
+
}
|
|
126
|
+
function resolvePluginSource(lockEntry, pluginDir) {
|
|
127
|
+
if (lockEntry) {
|
|
128
|
+
return lockEntry.source;
|
|
129
|
+
}
|
|
130
|
+
return parseStoredPluginSource(getPluginSource(pluginDir));
|
|
131
|
+
}
|
|
132
|
+
function resolveStoredPluginSource(lockEntry, pluginDir) {
|
|
133
|
+
const source = resolvePluginSource(lockEntry, pluginDir);
|
|
134
|
+
return source ? toStoredPluginSource(source) : undefined;
|
|
135
|
+
}
|
|
136
|
+
function moveDir(src, dest, fsOps = fs) {
|
|
137
|
+
try {
|
|
138
|
+
fsOps.renameSync(src, dest);
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
if (err.code === 'EXDEV') {
|
|
142
|
+
try {
|
|
143
|
+
fsOps.cpSync(src, dest, { recursive: true });
|
|
144
|
+
}
|
|
145
|
+
catch (copyErr) {
|
|
146
|
+
try {
|
|
147
|
+
fsOps.rmSync(dest, { recursive: true, force: true });
|
|
148
|
+
}
|
|
149
|
+
catch { }
|
|
150
|
+
throw copyErr;
|
|
151
|
+
}
|
|
152
|
+
fsOps.rmSync(src, { recursive: true, force: true });
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
throw err;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function createSiblingTempPath(dest, kind) {
|
|
160
|
+
const suffix = `${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
161
|
+
return path.join(path.dirname(dest), `.${path.basename(dest)}.${kind}-${suffix}`);
|
|
162
|
+
}
|
|
163
|
+
function cloneRepoToTemp(cloneUrl) {
|
|
164
|
+
const tmpCloneDir = path.join(os.tmpdir(), `webcmd-clone-${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`);
|
|
165
|
+
try {
|
|
166
|
+
execFileSync('git', ['clone', '--depth', '1', cloneUrl, tmpCloneDir], {
|
|
167
|
+
encoding: 'utf-8',
|
|
168
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
throw new PluginError(`Failed to clone plugin: ${getErrorMessage(err)}`, 'Check the repository URL and your network connection.');
|
|
173
|
+
}
|
|
174
|
+
return tmpCloneDir;
|
|
175
|
+
}
|
|
176
|
+
function withTempClone(cloneUrl, work) {
|
|
177
|
+
const tmpCloneDir = cloneRepoToTemp(cloneUrl);
|
|
178
|
+
try {
|
|
179
|
+
return work(tmpCloneDir);
|
|
180
|
+
}
|
|
181
|
+
finally {
|
|
182
|
+
try {
|
|
183
|
+
fs.rmSync(tmpCloneDir, { recursive: true, force: true });
|
|
184
|
+
}
|
|
185
|
+
catch { }
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
function resolveRemotePluginSource(lockEntry, dir) {
|
|
189
|
+
const source = resolvePluginSource(lockEntry, dir);
|
|
190
|
+
if (!source || source.kind === 'local') {
|
|
191
|
+
throw new Error(`Unable to determine remote source for plugin at ${dir}`);
|
|
192
|
+
}
|
|
193
|
+
return source.url;
|
|
194
|
+
}
|
|
195
|
+
function pathExistsSync(p) {
|
|
196
|
+
try {
|
|
197
|
+
fs.lstatSync(p);
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
function resolveRepoContainedPath(repoRoot, subPath) {
|
|
205
|
+
const resolved = path.resolve(repoRoot, subPath);
|
|
206
|
+
if (!resolved.startsWith(repoRoot + path.sep) && resolved !== repoRoot) {
|
|
207
|
+
throw new PluginError(`Plugin path "${subPath}" escapes repo root.`);
|
|
208
|
+
}
|
|
209
|
+
return resolved;
|
|
210
|
+
}
|
|
211
|
+
function removePathSync(p) {
|
|
212
|
+
try {
|
|
213
|
+
const stat = fs.lstatSync(p);
|
|
214
|
+
if (stat.isSymbolicLink()) {
|
|
215
|
+
fs.unlinkSync(p);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
fs.rmSync(p, { recursive: true, force: true });
|
|
219
|
+
}
|
|
220
|
+
catch { }
|
|
221
|
+
}
|
|
222
|
+
class Transaction {
|
|
223
|
+
#handles = [];
|
|
224
|
+
#settled = false;
|
|
225
|
+
track(handle) {
|
|
226
|
+
this.#handles.push(handle);
|
|
227
|
+
return handle;
|
|
228
|
+
}
|
|
229
|
+
commit() {
|
|
230
|
+
if (this.#settled)
|
|
231
|
+
return;
|
|
232
|
+
this.#settled = true;
|
|
233
|
+
for (const handle of this.#handles) {
|
|
234
|
+
handle.finalize();
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
rollback() {
|
|
238
|
+
if (this.#settled)
|
|
239
|
+
return;
|
|
240
|
+
this.#settled = true;
|
|
241
|
+
for (const handle of [...this.#handles].reverse()) {
|
|
242
|
+
handle.rollback();
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
function runTransaction(work) {
|
|
247
|
+
const tx = new Transaction();
|
|
248
|
+
try {
|
|
249
|
+
const result = work(tx);
|
|
250
|
+
tx.commit();
|
|
251
|
+
return result;
|
|
252
|
+
}
|
|
253
|
+
catch (err) {
|
|
254
|
+
tx.rollback();
|
|
255
|
+
throw err;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
function beginReplaceDir(stagingDir, dest, fsOps = fs) {
|
|
259
|
+
const destExisted = fsOps.existsSync(dest);
|
|
260
|
+
fsOps.mkdirSync(path.dirname(dest), { recursive: true });
|
|
261
|
+
const tempDest = createSiblingTempPath(dest, 'tmp');
|
|
262
|
+
const backupDest = destExisted ? createSiblingTempPath(dest, 'bak') : null;
|
|
263
|
+
let settled = false;
|
|
264
|
+
try {
|
|
265
|
+
moveDir(stagingDir, tempDest, fsOps);
|
|
266
|
+
if (backupDest) {
|
|
267
|
+
fsOps.renameSync(dest, backupDest);
|
|
268
|
+
}
|
|
269
|
+
fsOps.renameSync(tempDest, dest);
|
|
270
|
+
}
|
|
271
|
+
catch (err) {
|
|
272
|
+
try {
|
|
273
|
+
fsOps.rmSync(tempDest, { recursive: true, force: true });
|
|
274
|
+
}
|
|
275
|
+
catch { }
|
|
276
|
+
if (backupDest && !fsOps.existsSync(dest)) {
|
|
277
|
+
try {
|
|
278
|
+
fsOps.renameSync(backupDest, dest);
|
|
279
|
+
}
|
|
280
|
+
catch { }
|
|
281
|
+
}
|
|
282
|
+
throw err;
|
|
283
|
+
}
|
|
284
|
+
return {
|
|
285
|
+
finalize() {
|
|
286
|
+
if (settled)
|
|
287
|
+
return;
|
|
288
|
+
settled = true;
|
|
289
|
+
if (backupDest) {
|
|
290
|
+
try {
|
|
291
|
+
fsOps.rmSync(backupDest, { recursive: true, force: true });
|
|
292
|
+
}
|
|
293
|
+
catch { }
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
rollback() {
|
|
297
|
+
if (settled)
|
|
298
|
+
return;
|
|
299
|
+
settled = true;
|
|
300
|
+
try {
|
|
301
|
+
fsOps.rmSync(dest, { recursive: true, force: true });
|
|
302
|
+
}
|
|
303
|
+
catch { }
|
|
304
|
+
if (backupDest) {
|
|
305
|
+
try {
|
|
306
|
+
fsOps.renameSync(backupDest, dest);
|
|
307
|
+
}
|
|
308
|
+
catch { }
|
|
309
|
+
}
|
|
310
|
+
try {
|
|
311
|
+
fsOps.rmSync(tempDest, { recursive: true, force: true });
|
|
312
|
+
}
|
|
313
|
+
catch { }
|
|
314
|
+
},
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
function beginReplaceSymlink(target, linkPath) {
|
|
318
|
+
const linkExists = pathExistsSync(linkPath);
|
|
319
|
+
if (linkExists && !isSymlinkSync(linkPath)) {
|
|
320
|
+
throw new Error(`Expected monorepo plugin link at ${linkPath} to be a symlink`);
|
|
321
|
+
}
|
|
322
|
+
fs.mkdirSync(path.dirname(linkPath), { recursive: true });
|
|
323
|
+
const tempLink = createSiblingTempPath(linkPath, 'tmp');
|
|
324
|
+
const backupLink = linkExists ? createSiblingTempPath(linkPath, 'bak') : null;
|
|
325
|
+
const linkType = isWindows ? 'junction' : 'dir';
|
|
326
|
+
let settled = false;
|
|
327
|
+
try {
|
|
328
|
+
fs.symlinkSync(target, tempLink, linkType);
|
|
329
|
+
if (backupLink) {
|
|
330
|
+
fs.renameSync(linkPath, backupLink);
|
|
331
|
+
}
|
|
332
|
+
fs.renameSync(tempLink, linkPath);
|
|
333
|
+
}
|
|
334
|
+
catch (err) {
|
|
335
|
+
removePathSync(tempLink);
|
|
336
|
+
if (backupLink && !pathExistsSync(linkPath)) {
|
|
337
|
+
try {
|
|
338
|
+
fs.renameSync(backupLink, linkPath);
|
|
339
|
+
}
|
|
340
|
+
catch { }
|
|
341
|
+
}
|
|
342
|
+
throw err;
|
|
343
|
+
}
|
|
344
|
+
return {
|
|
345
|
+
finalize() {
|
|
346
|
+
if (settled)
|
|
347
|
+
return;
|
|
348
|
+
settled = true;
|
|
349
|
+
if (backupLink) {
|
|
350
|
+
removePathSync(backupLink);
|
|
351
|
+
}
|
|
352
|
+
},
|
|
353
|
+
rollback() {
|
|
354
|
+
if (settled)
|
|
355
|
+
return;
|
|
356
|
+
settled = true;
|
|
357
|
+
removePathSync(linkPath);
|
|
358
|
+
if (backupLink && !pathExistsSync(linkPath)) {
|
|
359
|
+
try {
|
|
360
|
+
fs.renameSync(backupLink, linkPath);
|
|
361
|
+
}
|
|
362
|
+
catch { }
|
|
363
|
+
}
|
|
364
|
+
removePathSync(tempLink);
|
|
365
|
+
},
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
// ── Lock file helpers ───────────────────────────────────────────────────────
|
|
369
|
+
function readLockFileWithWriter(writeLock = writeLockFile) {
|
|
370
|
+
try {
|
|
371
|
+
const raw = fs.readFileSync(getLockFilePath(), 'utf-8');
|
|
372
|
+
const parsed = JSON.parse(raw);
|
|
373
|
+
if (!isRecord(parsed))
|
|
374
|
+
return {};
|
|
375
|
+
const lock = {};
|
|
376
|
+
let changed = false;
|
|
377
|
+
for (const [name, entry] of Object.entries(parsed)) {
|
|
378
|
+
const normalized = normalizeLockEntry(entry);
|
|
379
|
+
if (!normalized) {
|
|
380
|
+
changed = true;
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
lock[name] = normalized;
|
|
384
|
+
if (JSON.stringify(entry) !== JSON.stringify(normalized)) {
|
|
385
|
+
changed = true;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
if (changed) {
|
|
389
|
+
try {
|
|
390
|
+
writeLock(lock);
|
|
391
|
+
}
|
|
392
|
+
catch { }
|
|
393
|
+
}
|
|
394
|
+
return lock;
|
|
395
|
+
}
|
|
396
|
+
catch {
|
|
397
|
+
return {};
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
export function readLockFile() {
|
|
401
|
+
return readLockFileWithWriter(writeLockFile);
|
|
402
|
+
}
|
|
403
|
+
function writeLockFileWithFs(lock, fsOps = fs) {
|
|
404
|
+
const lockPath = getLockFilePath();
|
|
405
|
+
fsOps.mkdirSync(path.dirname(lockPath), { recursive: true });
|
|
406
|
+
const tempPath = createSiblingTempPath(lockPath, 'tmp');
|
|
407
|
+
try {
|
|
408
|
+
fsOps.writeFileSync(tempPath, JSON.stringify(lock, null, 2) + '\n');
|
|
409
|
+
fsOps.renameSync(tempPath, lockPath);
|
|
410
|
+
}
|
|
411
|
+
catch (err) {
|
|
412
|
+
try {
|
|
413
|
+
fsOps.rmSync(tempPath, { force: true });
|
|
414
|
+
}
|
|
415
|
+
catch { }
|
|
416
|
+
throw err;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
export function writeLockFile(lock) {
|
|
420
|
+
writeLockFileWithFs(lock, fs);
|
|
421
|
+
}
|
|
422
|
+
/** Get the HEAD commit hash of a git repo directory. */
|
|
423
|
+
export function getCommitHash(dir) {
|
|
424
|
+
try {
|
|
425
|
+
return execFileSync('git', ['rev-parse', 'HEAD'], {
|
|
426
|
+
cwd: dir,
|
|
427
|
+
encoding: 'utf-8',
|
|
428
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
429
|
+
}).trim();
|
|
430
|
+
}
|
|
431
|
+
catch {
|
|
432
|
+
return undefined;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Validate that a downloaded plugin directory is a structurally valid plugin.
|
|
437
|
+
* Checks for at least one command file (.ts, .js) and a valid
|
|
438
|
+
* package.json if it contains .ts files.
|
|
439
|
+
*/
|
|
440
|
+
export function validatePluginStructure(pluginDir) {
|
|
441
|
+
const errors = [];
|
|
442
|
+
if (!fs.existsSync(pluginDir)) {
|
|
443
|
+
return { valid: false, errors: ['Plugin directory does not exist'] };
|
|
444
|
+
}
|
|
445
|
+
const files = fs.readdirSync(pluginDir);
|
|
446
|
+
const hasTs = files.some(f => f.endsWith('.ts') && !f.endsWith('.d.ts') && !f.endsWith('.test.ts'));
|
|
447
|
+
const hasJs = files.some(f => f.endsWith('.js') && !f.endsWith('.d.js'));
|
|
448
|
+
if (!hasTs && !hasJs) {
|
|
449
|
+
errors.push('No command files found in plugin directory. A plugin must contain at least one .ts or .js command file.');
|
|
450
|
+
}
|
|
451
|
+
if (hasTs) {
|
|
452
|
+
const pkgJsonPath = path.join(pluginDir, 'package.json');
|
|
453
|
+
if (!fs.existsSync(pkgJsonPath)) {
|
|
454
|
+
errors.push('Plugin contains .ts files but no package.json. A package.json with "type": "module" and "@agentrhq/webcmd" peer dependency is required for TS plugins.');
|
|
455
|
+
}
|
|
456
|
+
else {
|
|
457
|
+
try {
|
|
458
|
+
const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));
|
|
459
|
+
if (pkg.type !== 'module') {
|
|
460
|
+
errors.push('Plugin package.json must have "type": "module" for TypeScript plugins.');
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
catch {
|
|
464
|
+
errors.push('Plugin package.json is malformed or invalid JSON.');
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
return { valid: errors.length === 0, errors };
|
|
469
|
+
}
|
|
470
|
+
/** Check whether a directory has its own production dependencies in package.json. */
|
|
471
|
+
function hasOwnDependencies(dir) {
|
|
472
|
+
const pkgPath = path.join(dir, 'package.json');
|
|
473
|
+
if (!fs.existsSync(pkgPath))
|
|
474
|
+
return false;
|
|
475
|
+
try {
|
|
476
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
477
|
+
return pkg.dependencies != null && Object.keys(pkg.dependencies).length > 0;
|
|
478
|
+
}
|
|
479
|
+
catch {
|
|
480
|
+
return false;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
function installDependencies(dir) {
|
|
484
|
+
const pkgJsonPath = path.join(dir, 'package.json');
|
|
485
|
+
if (!fs.existsSync(pkgJsonPath))
|
|
486
|
+
return;
|
|
487
|
+
try {
|
|
488
|
+
execFileSync('npm', ['install', '--omit=dev'], {
|
|
489
|
+
cwd: dir,
|
|
490
|
+
encoding: 'utf-8',
|
|
491
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
492
|
+
...(isWindows && { shell: true }),
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
catch (err) {
|
|
496
|
+
throw new PluginError(`npm install failed in ${dir}: ${getErrorMessage(err)}`, 'Check your network connection and npm configuration.');
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
function finalizePluginRuntime(pluginDir) {
|
|
500
|
+
// Symlink host webcmd so TS plugins resolve '@agentrhq/webcmd/registry'
|
|
501
|
+
// against the running host, not a stale npm-published version.
|
|
502
|
+
linkHostWebcmd(pluginDir);
|
|
503
|
+
// Transpile .ts → .js via esbuild (production node can't load .ts directly).
|
|
504
|
+
transpilePluginTs(pluginDir);
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Shared post-install lifecycle for standalone plugins.
|
|
508
|
+
*/
|
|
509
|
+
function postInstallLifecycle(pluginDir) {
|
|
510
|
+
installDependencies(pluginDir);
|
|
511
|
+
finalizePluginRuntime(pluginDir);
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* Monorepo lifecycle: install shared deps at repo root, then install and finalize each sub-plugin.
|
|
515
|
+
*
|
|
516
|
+
* The root install covers monorepos that use npm workspaces to hoist dependencies.
|
|
517
|
+
* For monorepos that do NOT use workspaces, sub-plugins may declare their own
|
|
518
|
+
* production dependencies in their package.json. We install those per sub-plugin
|
|
519
|
+
* so that runtime imports (e.g. `undici`) can be resolved from the sub-plugin
|
|
520
|
+
* directory. When the root already satisfies all deps this is a fast no-op.
|
|
521
|
+
*/
|
|
522
|
+
function postInstallMonorepoLifecycle(repoDir, pluginDirs) {
|
|
523
|
+
installDependencies(repoDir);
|
|
524
|
+
for (const pluginDir of pluginDirs) {
|
|
525
|
+
if (pluginDir !== repoDir && hasOwnDependencies(pluginDir)) {
|
|
526
|
+
installDependencies(pluginDir);
|
|
527
|
+
}
|
|
528
|
+
finalizePluginRuntime(pluginDir);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
function ensureStandalonePluginReady(pluginDir) {
|
|
532
|
+
const validation = validatePluginStructure(pluginDir);
|
|
533
|
+
if (!validation.valid) {
|
|
534
|
+
throw new PluginError(`Invalid plugin structure:\n- ${validation.errors.join('\n- ')}`);
|
|
535
|
+
}
|
|
536
|
+
postInstallLifecycle(pluginDir);
|
|
537
|
+
}
|
|
538
|
+
function upsertLockEntry(lock, name, entry) {
|
|
539
|
+
lock[name] = {
|
|
540
|
+
...entry,
|
|
541
|
+
installedAt: entry.installedAt ?? new Date().toISOString(),
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
function publishStandalonePlugin(stagingDir, targetDir, writeLock) {
|
|
545
|
+
runTransaction((tx) => {
|
|
546
|
+
tx.track(beginReplaceDir(stagingDir, targetDir));
|
|
547
|
+
writeLock(getCommitHash(targetDir));
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
function publishMonorepoPlugins(repoDir, pluginsDir, plugins, publishRepo, writeLock) {
|
|
551
|
+
runTransaction((tx) => {
|
|
552
|
+
if (publishRepo) {
|
|
553
|
+
fs.mkdirSync(publishRepo.parentDir, { recursive: true });
|
|
554
|
+
tx.track(beginReplaceDir(publishRepo.stagingDir, repoDir));
|
|
555
|
+
}
|
|
556
|
+
const commitHash = getCommitHash(repoDir);
|
|
557
|
+
for (const plugin of plugins) {
|
|
558
|
+
const linkPath = path.join(pluginsDir, plugin.name);
|
|
559
|
+
const subDir = resolveRepoContainedPath(repoDir, plugin.subPath);
|
|
560
|
+
tx.track(beginReplaceSymlink(subDir, linkPath));
|
|
561
|
+
}
|
|
562
|
+
writeLock?.(commitHash);
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* Install a plugin from a source.
|
|
567
|
+
* Supports:
|
|
568
|
+
* "github:user/repo" — single plugin or full monorepo
|
|
569
|
+
* "github:user/repo/subplugin" — specific sub-plugin from a monorepo
|
|
570
|
+
* "https://github.com/user/repo"
|
|
571
|
+
* "file:///absolute/path" — local plugin directory (symlinked)
|
|
572
|
+
* "/absolute/path" — local plugin directory (symlinked)
|
|
573
|
+
*
|
|
574
|
+
* Returns the installed plugin name(s).
|
|
575
|
+
*/
|
|
576
|
+
export function installPlugin(source) {
|
|
577
|
+
const parsed = parseSource(source);
|
|
578
|
+
if (!parsed) {
|
|
579
|
+
throw new Error(`Invalid plugin source: "${source}"\n` +
|
|
580
|
+
`Supported formats:\n` +
|
|
581
|
+
` github:user/repo\n` +
|
|
582
|
+
` github:user/repo/subplugin\n` +
|
|
583
|
+
` https://github.com/user/repo\n` +
|
|
584
|
+
` https://<host>/<path>/repo.git\n` +
|
|
585
|
+
` ssh://git@<host>/<path>/repo.git\n` +
|
|
586
|
+
` git@<host>:user/repo.git\n` +
|
|
587
|
+
` file:///absolute/path\n` +
|
|
588
|
+
` /absolute/path`);
|
|
589
|
+
}
|
|
590
|
+
const { name: repoName, subPlugin } = parsed;
|
|
591
|
+
if (parsed.type === 'local') {
|
|
592
|
+
return installLocalPlugin(parsed.localPath, repoName);
|
|
593
|
+
}
|
|
594
|
+
return withTempClone(parsed.cloneUrl, (tmpCloneDir) => {
|
|
595
|
+
const manifest = readPluginManifest(tmpCloneDir);
|
|
596
|
+
// Check top-level compatibility
|
|
597
|
+
if (manifest?.webcmd && !checkCompatibility(manifest.webcmd)) {
|
|
598
|
+
throw new Error(`Plugin requires webcmd ${manifest.webcmd}, but current version is incompatible.`);
|
|
599
|
+
}
|
|
600
|
+
if (manifest && isMonorepo(manifest)) {
|
|
601
|
+
return installMonorepo(tmpCloneDir, parsed.cloneUrl, repoName, manifest, subPlugin);
|
|
602
|
+
}
|
|
603
|
+
// Single plugin mode
|
|
604
|
+
return installSinglePlugin(tmpCloneDir, parsed.cloneUrl, repoName, manifest);
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
/** Install a single (non-monorepo) plugin. */
|
|
608
|
+
function installSinglePlugin(cloneDir, cloneUrl, name, manifest) {
|
|
609
|
+
const pluginName = manifest?.name ?? name;
|
|
610
|
+
const targetDir = path.join(PLUGINS_DIR, pluginName);
|
|
611
|
+
if (fs.existsSync(targetDir)) {
|
|
612
|
+
throw new PluginError(`Plugin "${pluginName}" is already installed at ${targetDir}`, 'Use "webcmd plugin uninstall" first, or pick a different name.');
|
|
613
|
+
}
|
|
614
|
+
ensureStandalonePluginReady(cloneDir);
|
|
615
|
+
publishStandalonePlugin(cloneDir, targetDir, (commitHash) => {
|
|
616
|
+
const lock = readLockFile();
|
|
617
|
+
if (commitHash) {
|
|
618
|
+
upsertLockEntry(lock, pluginName, {
|
|
619
|
+
source: { kind: 'git', url: cloneUrl },
|
|
620
|
+
commitHash,
|
|
621
|
+
});
|
|
622
|
+
writeLockFile(lock);
|
|
623
|
+
}
|
|
624
|
+
});
|
|
625
|
+
return pluginName;
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* Install a local plugin by creating a symlink.
|
|
629
|
+
* Used for plugin development: the source directory is symlinked into
|
|
630
|
+
* the plugins dir so changes are reflected immediately.
|
|
631
|
+
*/
|
|
632
|
+
function installLocalPlugin(localPath, name) {
|
|
633
|
+
if (!fs.existsSync(localPath)) {
|
|
634
|
+
throw new PluginError(`Local plugin path does not exist: ${localPath}`);
|
|
635
|
+
}
|
|
636
|
+
const stat = fs.statSync(localPath);
|
|
637
|
+
if (!stat.isDirectory()) {
|
|
638
|
+
throw new PluginError(`Local plugin path is not a directory: ${localPath}`);
|
|
639
|
+
}
|
|
640
|
+
const manifest = readPluginManifest(localPath);
|
|
641
|
+
if (manifest?.webcmd && !checkCompatibility(manifest.webcmd)) {
|
|
642
|
+
throw new PluginError(`Plugin requires webcmd ${manifest.webcmd}, but current version is incompatible.`, 'Upgrade webcmd to a compatible version.');
|
|
643
|
+
}
|
|
644
|
+
const pluginName = manifest?.name ?? name;
|
|
645
|
+
const targetDir = path.join(PLUGINS_DIR, pluginName);
|
|
646
|
+
if (fs.existsSync(targetDir)) {
|
|
647
|
+
throw new PluginError(`Plugin "${pluginName}" is already installed at ${targetDir}`, 'Use "webcmd plugin uninstall" first, or pick a different name.');
|
|
648
|
+
}
|
|
649
|
+
const validation = validatePluginStructure(localPath);
|
|
650
|
+
if (!validation.valid) {
|
|
651
|
+
throw new PluginError(`Invalid plugin structure:\n- ${validation.errors.join('\n- ')}`);
|
|
652
|
+
}
|
|
653
|
+
fs.mkdirSync(PLUGINS_DIR, { recursive: true });
|
|
654
|
+
const resolvedPath = path.resolve(localPath);
|
|
655
|
+
const linkType = isWindows ? 'junction' : 'dir';
|
|
656
|
+
fs.symlinkSync(resolvedPath, targetDir, linkType);
|
|
657
|
+
installDependencies(localPath);
|
|
658
|
+
finalizePluginRuntime(localPath);
|
|
659
|
+
const lock = readLockFile();
|
|
660
|
+
const commitHash = getCommitHash(localPath);
|
|
661
|
+
upsertLockEntry(lock, pluginName, {
|
|
662
|
+
source: { kind: 'local', path: resolvedPath },
|
|
663
|
+
commitHash: commitHash ?? 'local',
|
|
664
|
+
});
|
|
665
|
+
writeLockFile(lock);
|
|
666
|
+
return pluginName;
|
|
667
|
+
}
|
|
668
|
+
function updateLocalPlugin(name, targetDir, lock, lockEntry) {
|
|
669
|
+
const pluginDir = fs.realpathSync(targetDir);
|
|
670
|
+
const validation = validatePluginStructure(pluginDir);
|
|
671
|
+
if (!validation.valid) {
|
|
672
|
+
log.warn(`Plugin "${name}" structure invalid:\n- ${validation.errors.join('\n- ')}`);
|
|
673
|
+
}
|
|
674
|
+
postInstallLifecycle(pluginDir);
|
|
675
|
+
upsertLockEntry(lock, name, {
|
|
676
|
+
source: lockEntry?.source ?? { kind: 'local', path: pluginDir },
|
|
677
|
+
commitHash: getCommitHash(pluginDir) ?? 'local',
|
|
678
|
+
installedAt: lockEntry?.installedAt ?? new Date().toISOString(),
|
|
679
|
+
updatedAt: new Date().toISOString(),
|
|
680
|
+
});
|
|
681
|
+
writeLockFile(lock);
|
|
682
|
+
}
|
|
683
|
+
/** Install sub-plugins from a monorepo. */
|
|
684
|
+
function installMonorepo(cloneDir, cloneUrl, repoName, manifest, subPlugin) {
|
|
685
|
+
const monoreposDir = getMonoreposDir();
|
|
686
|
+
const repoDir = path.join(monoreposDir, repoName);
|
|
687
|
+
const repoAlreadyInstalled = fs.existsSync(repoDir);
|
|
688
|
+
const repoRoot = repoAlreadyInstalled ? repoDir : cloneDir;
|
|
689
|
+
const effectiveManifest = repoAlreadyInstalled ? readPluginManifest(repoDir) : manifest;
|
|
690
|
+
if (!effectiveManifest || !isMonorepo(effectiveManifest)) {
|
|
691
|
+
throw new PluginError(`Monorepo manifest missing or invalid at ${repoRoot}`);
|
|
692
|
+
}
|
|
693
|
+
let pluginsToInstall = getEnabledPlugins(effectiveManifest);
|
|
694
|
+
// If a specific sub-plugin was requested, filter to just that one
|
|
695
|
+
if (subPlugin) {
|
|
696
|
+
pluginsToInstall = pluginsToInstall.filter((p) => p.name === subPlugin);
|
|
697
|
+
if (pluginsToInstall.length === 0) {
|
|
698
|
+
// Check if it exists but is disabled
|
|
699
|
+
const disabled = effectiveManifest.plugins?.[subPlugin];
|
|
700
|
+
if (disabled) {
|
|
701
|
+
throw new PluginError(`Sub-plugin "${subPlugin}" is disabled in the manifest.`);
|
|
702
|
+
}
|
|
703
|
+
throw new PluginError(`Sub-plugin "${subPlugin}" not found in monorepo. Available: ${Object.keys(effectiveManifest.plugins ?? {}).join(', ')}`);
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
const installedNames = [];
|
|
707
|
+
const lock = readLockFile();
|
|
708
|
+
const eligiblePlugins = [];
|
|
709
|
+
fs.mkdirSync(PLUGINS_DIR, { recursive: true });
|
|
710
|
+
for (const { name, entry } of pluginsToInstall) {
|
|
711
|
+
// Check sub-plugin level compatibility (overrides top-level)
|
|
712
|
+
if (entry.webcmd && !checkCompatibility(entry.webcmd)) {
|
|
713
|
+
log.warn(`Skipping "${name}": requires webcmd ${entry.webcmd}`);
|
|
714
|
+
continue;
|
|
715
|
+
}
|
|
716
|
+
let subDir;
|
|
717
|
+
try {
|
|
718
|
+
subDir = resolveRepoContainedPath(repoRoot, entry.path);
|
|
719
|
+
}
|
|
720
|
+
catch {
|
|
721
|
+
log.warn(`Skipping "${name}": path "${entry.path}" escapes repo root.`);
|
|
722
|
+
continue;
|
|
723
|
+
}
|
|
724
|
+
if (!fs.existsSync(subDir)) {
|
|
725
|
+
log.warn(`Skipping "${name}": path "${entry.path}" not found in repo.`);
|
|
726
|
+
continue;
|
|
727
|
+
}
|
|
728
|
+
const validation = validatePluginStructure(subDir);
|
|
729
|
+
if (!validation.valid) {
|
|
730
|
+
log.warn(`Skipping "${name}": invalid structure — ${validation.errors.join(', ')}`);
|
|
731
|
+
continue;
|
|
732
|
+
}
|
|
733
|
+
const linkPath = path.join(PLUGINS_DIR, name);
|
|
734
|
+
if (fs.existsSync(linkPath)) {
|
|
735
|
+
log.warn(`Skipping "${name}": already installed at ${linkPath}`);
|
|
736
|
+
continue;
|
|
737
|
+
}
|
|
738
|
+
eligiblePlugins.push({ name, entry });
|
|
739
|
+
}
|
|
740
|
+
if (eligiblePlugins.length === 0) {
|
|
741
|
+
return installedNames;
|
|
742
|
+
}
|
|
743
|
+
const publishPlugins = eligiblePlugins.map(({ name, entry }) => ({ name, subPath: entry.path }));
|
|
744
|
+
if (repoAlreadyInstalled) {
|
|
745
|
+
postInstallMonorepoLifecycle(repoDir, eligiblePlugins.map((p) => resolveRepoContainedPath(repoDir, p.entry.path)));
|
|
746
|
+
}
|
|
747
|
+
else {
|
|
748
|
+
postInstallMonorepoLifecycle(cloneDir, eligiblePlugins.map((p) => resolveRepoContainedPath(cloneDir, p.entry.path)));
|
|
749
|
+
}
|
|
750
|
+
publishMonorepoPlugins(repoDir, PLUGINS_DIR, publishPlugins, repoAlreadyInstalled ? undefined : { stagingDir: cloneDir, parentDir: monoreposDir }, (commitHash) => {
|
|
751
|
+
for (const { name, entry } of eligiblePlugins) {
|
|
752
|
+
if (commitHash) {
|
|
753
|
+
upsertLockEntry(lock, name, {
|
|
754
|
+
source: {
|
|
755
|
+
kind: 'monorepo',
|
|
756
|
+
url: cloneUrl,
|
|
757
|
+
repoName,
|
|
758
|
+
subPath: entry.path,
|
|
759
|
+
},
|
|
760
|
+
commitHash,
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
installedNames.push(name);
|
|
764
|
+
}
|
|
765
|
+
writeLockFile(lock);
|
|
766
|
+
});
|
|
767
|
+
return installedNames;
|
|
768
|
+
}
|
|
769
|
+
function collectUpdatedMonorepoPlugins(monoName, lock, manifest, cloneUrl, tmpCloneDir) {
|
|
770
|
+
const updatedPlugins = [];
|
|
771
|
+
for (const [pluginName, entry] of Object.entries(lock)) {
|
|
772
|
+
if (entry.source.kind !== 'monorepo' || entry.source.repoName !== monoName)
|
|
773
|
+
continue;
|
|
774
|
+
const manifestEntry = manifest.plugins?.[pluginName];
|
|
775
|
+
if (!manifestEntry || manifestEntry.disabled) {
|
|
776
|
+
throw new Error(`Installed sub-plugin "${pluginName}" no longer exists in ${cloneUrl}`);
|
|
777
|
+
}
|
|
778
|
+
if (manifestEntry.webcmd && !checkCompatibility(manifestEntry.webcmd)) {
|
|
779
|
+
throw new Error(`Sub-plugin "${pluginName}" requires webcmd ${manifestEntry.webcmd}`);
|
|
780
|
+
}
|
|
781
|
+
const subDir = resolveRepoContainedPath(tmpCloneDir, manifestEntry.path);
|
|
782
|
+
const validation = validatePluginStructure(subDir);
|
|
783
|
+
if (!validation.valid) {
|
|
784
|
+
throw new Error(`Updated sub-plugin "${pluginName}" is invalid:\n- ${validation.errors.join('\n- ')}`);
|
|
785
|
+
}
|
|
786
|
+
updatedPlugins.push({ name: pluginName, lockEntry: entry, manifestEntry });
|
|
787
|
+
}
|
|
788
|
+
return updatedPlugins;
|
|
789
|
+
}
|
|
790
|
+
function updateMonorepoLockEntries(lock, plugins, cloneUrl, monoName, commitHash) {
|
|
791
|
+
for (const plugin of plugins) {
|
|
792
|
+
if (!commitHash)
|
|
793
|
+
continue;
|
|
794
|
+
upsertLockEntry(lock, plugin.name, {
|
|
795
|
+
...plugin.lockEntry,
|
|
796
|
+
source: {
|
|
797
|
+
kind: 'monorepo',
|
|
798
|
+
url: cloneUrl,
|
|
799
|
+
repoName: monoName,
|
|
800
|
+
subPath: plugin.manifestEntry.path,
|
|
801
|
+
},
|
|
802
|
+
commitHash,
|
|
803
|
+
updatedAt: new Date().toISOString(),
|
|
804
|
+
});
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
function updateStandaloneLockEntry(lock, name, cloneUrl, existing, commitHash) {
|
|
808
|
+
if (!commitHash)
|
|
809
|
+
return;
|
|
810
|
+
upsertLockEntry(lock, name, {
|
|
811
|
+
source: { kind: 'git', url: cloneUrl },
|
|
812
|
+
commitHash,
|
|
813
|
+
installedAt: existing?.installedAt ?? new Date().toISOString(),
|
|
814
|
+
updatedAt: new Date().toISOString(),
|
|
815
|
+
});
|
|
816
|
+
}
|
|
817
|
+
/**
|
|
818
|
+
* Uninstall a plugin by name.
|
|
819
|
+
* For monorepo sub-plugins: removes symlink and cleans up the monorepo
|
|
820
|
+
* directory when no more sub-plugins reference it.
|
|
821
|
+
*/
|
|
822
|
+
export function uninstallPlugin(name) {
|
|
823
|
+
const targetDir = path.join(PLUGINS_DIR, name);
|
|
824
|
+
if (!fs.existsSync(targetDir)) {
|
|
825
|
+
throw new Error(`Plugin "${name}" is not installed.`);
|
|
826
|
+
}
|
|
827
|
+
const lock = readLockFile();
|
|
828
|
+
const lockEntry = lock[name];
|
|
829
|
+
// Check if this is a symlink (monorepo sub-plugin)
|
|
830
|
+
const isSymlink = isSymlinkSync(targetDir);
|
|
831
|
+
if (isSymlink) {
|
|
832
|
+
// Remove symlink only (not the actual directory)
|
|
833
|
+
fs.unlinkSync(targetDir);
|
|
834
|
+
}
|
|
835
|
+
else {
|
|
836
|
+
fs.rmSync(targetDir, { recursive: true, force: true });
|
|
837
|
+
}
|
|
838
|
+
// Clean up monorepo directory if no more sub-plugins reference it
|
|
839
|
+
if (lockEntry?.source.kind === 'monorepo') {
|
|
840
|
+
delete lock[name];
|
|
841
|
+
const monoName = lockEntry.source.repoName;
|
|
842
|
+
const stillReferenced = Object.values(lock).some((entry) => entry.source.kind === 'monorepo' && entry.source.repoName === monoName);
|
|
843
|
+
if (!stillReferenced) {
|
|
844
|
+
const monoDir = path.join(getMonoreposDir(), monoName);
|
|
845
|
+
try {
|
|
846
|
+
fs.rmSync(monoDir, { recursive: true, force: true });
|
|
847
|
+
}
|
|
848
|
+
catch { }
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
else if (lock[name]) {
|
|
852
|
+
delete lock[name];
|
|
853
|
+
}
|
|
854
|
+
writeLockFile(lock);
|
|
855
|
+
}
|
|
856
|
+
/** Synchronous check if a path is a symlink. */
|
|
857
|
+
function isSymlinkSync(p) {
|
|
858
|
+
try {
|
|
859
|
+
return fs.lstatSync(p).isSymbolicLink();
|
|
860
|
+
}
|
|
861
|
+
catch {
|
|
862
|
+
return false;
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
/**
|
|
866
|
+
* Update a plugin by name (git pull + re-install lifecycle).
|
|
867
|
+
* For monorepo sub-plugins: pulls the monorepo root and re-runs lifecycle
|
|
868
|
+
* for all sub-plugins from the same monorepo.
|
|
869
|
+
*/
|
|
870
|
+
export function updatePlugin(name) {
|
|
871
|
+
const targetDir = path.join(PLUGINS_DIR, name);
|
|
872
|
+
if (!fs.existsSync(targetDir)) {
|
|
873
|
+
throw new Error(`Plugin "${name}" is not installed.`);
|
|
874
|
+
}
|
|
875
|
+
const lock = readLockFile();
|
|
876
|
+
const lockEntry = lock[name];
|
|
877
|
+
const source = resolvePluginSource(lockEntry, targetDir);
|
|
878
|
+
if (source?.kind === 'local') {
|
|
879
|
+
updateLocalPlugin(name, targetDir, lock, lockEntry);
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
if (source?.kind === 'monorepo') {
|
|
883
|
+
const monoDir = path.join(getMonoreposDir(), source.repoName);
|
|
884
|
+
const monoName = source.repoName;
|
|
885
|
+
const cloneUrl = source.url;
|
|
886
|
+
withTempClone(cloneUrl, (tmpCloneDir) => {
|
|
887
|
+
const manifest = readPluginManifest(tmpCloneDir);
|
|
888
|
+
if (!manifest || !isMonorepo(manifest)) {
|
|
889
|
+
throw new Error(`Updated source is no longer a monorepo: ${cloneUrl}`);
|
|
890
|
+
}
|
|
891
|
+
if (manifest.webcmd && !checkCompatibility(manifest.webcmd)) {
|
|
892
|
+
throw new Error(`Plugin requires webcmd ${manifest.webcmd}, but current version is incompatible.`);
|
|
893
|
+
}
|
|
894
|
+
const updatedPlugins = collectUpdatedMonorepoPlugins(monoName, lock, manifest, cloneUrl, tmpCloneDir);
|
|
895
|
+
if (updatedPlugins.length > 0) {
|
|
896
|
+
postInstallMonorepoLifecycle(tmpCloneDir, updatedPlugins.map((plugin) => resolveRepoContainedPath(tmpCloneDir, plugin.manifestEntry.path)));
|
|
897
|
+
}
|
|
898
|
+
publishMonorepoPlugins(monoDir, PLUGINS_DIR, updatedPlugins.map((plugin) => ({ name: plugin.name, subPath: plugin.manifestEntry.path })), { stagingDir: tmpCloneDir, parentDir: path.dirname(monoDir) }, (commitHash) => {
|
|
899
|
+
updateMonorepoLockEntries(lock, updatedPlugins, cloneUrl, monoName, commitHash);
|
|
900
|
+
writeLockFile(lock);
|
|
901
|
+
});
|
|
902
|
+
});
|
|
903
|
+
return;
|
|
904
|
+
}
|
|
905
|
+
const cloneUrl = resolveRemotePluginSource(lockEntry, targetDir);
|
|
906
|
+
withTempClone(cloneUrl, (tmpCloneDir) => {
|
|
907
|
+
const manifest = readPluginManifest(tmpCloneDir);
|
|
908
|
+
if (manifest && isMonorepo(manifest)) {
|
|
909
|
+
throw new Error(`Updated source is now a monorepo: ${cloneUrl}`);
|
|
910
|
+
}
|
|
911
|
+
if (manifest?.webcmd && !checkCompatibility(manifest.webcmd)) {
|
|
912
|
+
throw new Error(`Plugin requires webcmd ${manifest.webcmd}, but current version is incompatible.`);
|
|
913
|
+
}
|
|
914
|
+
ensureStandalonePluginReady(tmpCloneDir);
|
|
915
|
+
publishStandalonePlugin(tmpCloneDir, targetDir, (commitHash) => {
|
|
916
|
+
updateStandaloneLockEntry(lock, name, cloneUrl, lock[name], commitHash);
|
|
917
|
+
if (commitHash) {
|
|
918
|
+
writeLockFile(lock);
|
|
919
|
+
}
|
|
920
|
+
});
|
|
921
|
+
});
|
|
922
|
+
}
|
|
923
|
+
/**
|
|
924
|
+
* Update all installed plugins.
|
|
925
|
+
* Continues even if individual plugin updates fail.
|
|
926
|
+
*/
|
|
927
|
+
export function updateAllPlugins() {
|
|
928
|
+
return listPlugins().map((plugin) => {
|
|
929
|
+
try {
|
|
930
|
+
updatePlugin(plugin.name);
|
|
931
|
+
return { name: plugin.name, success: true };
|
|
932
|
+
}
|
|
933
|
+
catch (err) {
|
|
934
|
+
return {
|
|
935
|
+
name: plugin.name,
|
|
936
|
+
success: false,
|
|
937
|
+
error: getErrorMessage(err),
|
|
938
|
+
};
|
|
939
|
+
}
|
|
940
|
+
});
|
|
941
|
+
}
|
|
942
|
+
/**
|
|
943
|
+
* List all installed plugins.
|
|
944
|
+
* Reads webcmd-plugin.json for description/version when available.
|
|
945
|
+
*/
|
|
946
|
+
export function listPlugins() {
|
|
947
|
+
if (!fs.existsSync(PLUGINS_DIR))
|
|
948
|
+
return [];
|
|
949
|
+
const entries = fs.readdirSync(PLUGINS_DIR, { withFileTypes: true });
|
|
950
|
+
const lock = readLockFile();
|
|
951
|
+
const plugins = [];
|
|
952
|
+
for (const entry of entries) {
|
|
953
|
+
// Accept both real directories and symlinks (monorepo sub-plugins)
|
|
954
|
+
const pluginDir = path.join(PLUGINS_DIR, entry.name);
|
|
955
|
+
const isDir = entry.isDirectory() || isSymlinkSync(pluginDir);
|
|
956
|
+
if (!isDir)
|
|
957
|
+
continue;
|
|
958
|
+
const commands = scanPluginCommands(pluginDir);
|
|
959
|
+
const lockEntry = lock[entry.name];
|
|
960
|
+
// Try to read manifest for metadata
|
|
961
|
+
const manifest = readPluginManifest(pluginDir);
|
|
962
|
+
// For monorepo sub-plugins, also check the monorepo root manifest
|
|
963
|
+
let description = manifest?.description;
|
|
964
|
+
let version = manifest?.version;
|
|
965
|
+
if (lockEntry?.source.kind === 'monorepo' && !description) {
|
|
966
|
+
const monoDir = path.join(getMonoreposDir(), lockEntry.source.repoName);
|
|
967
|
+
const monoManifest = readPluginManifest(monoDir);
|
|
968
|
+
const subEntry = monoManifest?.plugins?.[entry.name];
|
|
969
|
+
if (subEntry) {
|
|
970
|
+
description = description ?? subEntry.description;
|
|
971
|
+
version = version ?? subEntry.version;
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
const source = resolveStoredPluginSource(lockEntry, pluginDir);
|
|
975
|
+
plugins.push({
|
|
976
|
+
name: entry.name,
|
|
977
|
+
path: pluginDir,
|
|
978
|
+
commands,
|
|
979
|
+
source,
|
|
980
|
+
version: version ?? lockEntry?.commitHash?.slice(0, 7),
|
|
981
|
+
installedAt: lockEntry?.installedAt,
|
|
982
|
+
monorepoName: lockEntry?.source.kind === 'monorepo' ? lockEntry.source.repoName : undefined,
|
|
983
|
+
description,
|
|
984
|
+
});
|
|
985
|
+
}
|
|
986
|
+
return plugins;
|
|
987
|
+
}
|
|
988
|
+
/** Scan a plugin directory for command files */
|
|
989
|
+
function scanPluginCommands(dir) {
|
|
990
|
+
try {
|
|
991
|
+
const files = fs.readdirSync(dir);
|
|
992
|
+
const names = new Set(files
|
|
993
|
+
.filter(f => (f.endsWith('.ts') && !f.endsWith('.d.ts') && !f.endsWith('.test.ts')) ||
|
|
994
|
+
(f.endsWith('.js') && !f.endsWith('.d.js')))
|
|
995
|
+
.map(f => path.basename(f, path.extname(f))));
|
|
996
|
+
return [...names];
|
|
997
|
+
}
|
|
998
|
+
catch {
|
|
999
|
+
return [];
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
/** Get git remote origin URL */
|
|
1003
|
+
function getPluginSource(dir) {
|
|
1004
|
+
try {
|
|
1005
|
+
return execFileSync('git', ['config', '--get', 'remote.origin.url'], {
|
|
1006
|
+
cwd: dir,
|
|
1007
|
+
encoding: 'utf-8',
|
|
1008
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
1009
|
+
}).trim();
|
|
1010
|
+
}
|
|
1011
|
+
catch {
|
|
1012
|
+
return undefined;
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
/** Parse a plugin source string into clone URL, repo name, and optional sub-plugin. */
|
|
1016
|
+
function parseSource(source) {
|
|
1017
|
+
if (source.startsWith('file://')) {
|
|
1018
|
+
try {
|
|
1019
|
+
const localPath = path.resolve(fileURLToPath(source));
|
|
1020
|
+
return {
|
|
1021
|
+
type: 'local',
|
|
1022
|
+
localPath,
|
|
1023
|
+
name: path.basename(localPath).replace(/^webcmd-plugin-/, ''),
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
catch {
|
|
1027
|
+
return null;
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
if (path.isAbsolute(source)) {
|
|
1031
|
+
const localPath = path.resolve(source);
|
|
1032
|
+
return {
|
|
1033
|
+
type: 'local',
|
|
1034
|
+
localPath,
|
|
1035
|
+
name: path.basename(localPath).replace(/^webcmd-plugin-/, ''),
|
|
1036
|
+
};
|
|
1037
|
+
}
|
|
1038
|
+
// github:user/repo/subplugin (monorepo specific sub-plugin)
|
|
1039
|
+
const githubSubMatch = source.match(/^github:([\w.-]+)\/([\w.-]+)\/([\w.-]+)$/);
|
|
1040
|
+
if (githubSubMatch) {
|
|
1041
|
+
const [, user, repo, sub] = githubSubMatch;
|
|
1042
|
+
const name = repo.replace(/^webcmd-plugin-/, '');
|
|
1043
|
+
return {
|
|
1044
|
+
type: 'git',
|
|
1045
|
+
cloneUrl: `https://github.com/${user}/${repo}.git`,
|
|
1046
|
+
name,
|
|
1047
|
+
subPlugin: sub,
|
|
1048
|
+
};
|
|
1049
|
+
}
|
|
1050
|
+
// github:user/repo
|
|
1051
|
+
const githubMatch = source.match(/^github:([\w.-]+)\/([\w.-]+)$/);
|
|
1052
|
+
if (githubMatch) {
|
|
1053
|
+
const [, user, repo] = githubMatch;
|
|
1054
|
+
const name = repo.replace(/^webcmd-plugin-/, '');
|
|
1055
|
+
return {
|
|
1056
|
+
type: 'git',
|
|
1057
|
+
cloneUrl: `https://github.com/${user}/${repo}.git`,
|
|
1058
|
+
name,
|
|
1059
|
+
};
|
|
1060
|
+
}
|
|
1061
|
+
// https://github.com/user/repo (or .git)
|
|
1062
|
+
const urlMatch = source.match(/^https?:\/\/github\.com\/([\w.-]+)\/([\w.-]+?)(?:\.git)?$/);
|
|
1063
|
+
if (urlMatch) {
|
|
1064
|
+
const [, user, repo] = urlMatch;
|
|
1065
|
+
const name = repo.replace(/^webcmd-plugin-/, '');
|
|
1066
|
+
return {
|
|
1067
|
+
type: 'git',
|
|
1068
|
+
cloneUrl: `https://github.com/${user}/${repo}.git`,
|
|
1069
|
+
name,
|
|
1070
|
+
};
|
|
1071
|
+
}
|
|
1072
|
+
// ── Generic git URL support ─────────────────────────────────────────────
|
|
1073
|
+
// ssh://git@host/path/to/repo.git
|
|
1074
|
+
const sshUrlMatch = source.match(/^ssh:\/\/[^/]+\/(.*?)(?:\.git)?$/);
|
|
1075
|
+
if (sshUrlMatch) {
|
|
1076
|
+
const pathPart = sshUrlMatch[1];
|
|
1077
|
+
const segments = pathPart.split('/');
|
|
1078
|
+
const repoSegment = segments.pop();
|
|
1079
|
+
const name = repoSegment.replace(/^webcmd-plugin-/, '');
|
|
1080
|
+
return { type: 'git', cloneUrl: source, name };
|
|
1081
|
+
}
|
|
1082
|
+
// git@host:user/repo.git (SCP-style)
|
|
1083
|
+
const scpMatch = source.match(/^git@[^:]+:(.+?)(?:\.git)?$/);
|
|
1084
|
+
if (scpMatch) {
|
|
1085
|
+
const pathPart = scpMatch[1];
|
|
1086
|
+
const segments = pathPart.split('/');
|
|
1087
|
+
const repoSegment = segments.pop();
|
|
1088
|
+
const name = repoSegment.replace(/^webcmd-plugin-/, '');
|
|
1089
|
+
return { type: 'git', cloneUrl: source, name };
|
|
1090
|
+
}
|
|
1091
|
+
// Generic https/http git URL (non-GitHub hosts)
|
|
1092
|
+
const genericHttpMatch = source.match(/^https?:\/\/[^/]+\/(.+?)(?:\.git)?$/);
|
|
1093
|
+
if (genericHttpMatch) {
|
|
1094
|
+
const pathPart = genericHttpMatch[1];
|
|
1095
|
+
const segments = pathPart.split('/');
|
|
1096
|
+
const repoSegment = segments.pop();
|
|
1097
|
+
const name = repoSegment.replace(/^webcmd-plugin-/, '');
|
|
1098
|
+
// Ensure clone URL ends with .git
|
|
1099
|
+
const cloneUrl = source.endsWith('.git') ? source : `${source}.git`;
|
|
1100
|
+
return { type: 'git', cloneUrl, name };
|
|
1101
|
+
}
|
|
1102
|
+
return null;
|
|
1103
|
+
}
|
|
1104
|
+
/**
|
|
1105
|
+
* Symlink the host webcmd package into a plugin's node_modules.
|
|
1106
|
+
* This ensures TS plugins resolve '@agentrhq/webcmd/registry' against
|
|
1107
|
+
* the running host installation rather than a stale npm-published version.
|
|
1108
|
+
*/
|
|
1109
|
+
function linkHostWebcmd(pluginDir) {
|
|
1110
|
+
try {
|
|
1111
|
+
const hostRoot = resolveHostWebcmdRoot();
|
|
1112
|
+
const targetLink = path.join(pluginDir, 'node_modules', '@agentrhq', 'webcmd');
|
|
1113
|
+
ensureHostWebcmdPackageLink(targetLink, hostRoot);
|
|
1114
|
+
log.debug(`Linked host webcmd into plugin: ${targetLink} → ${hostRoot}`);
|
|
1115
|
+
}
|
|
1116
|
+
catch (err) {
|
|
1117
|
+
log.warn(`Failed to link host webcmd into plugin: ${getErrorMessage(err)}`);
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
function getHostSourcePackageExports(hostRoot) {
|
|
1121
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(hostRoot, 'package.json'), 'utf-8'));
|
|
1122
|
+
const exports = pkg.exports ?? {};
|
|
1123
|
+
return Object.fromEntries(Object.entries(exports).map(([key, target]) => [
|
|
1124
|
+
key,
|
|
1125
|
+
target
|
|
1126
|
+
.replace(/^\.\/dist\//, './')
|
|
1127
|
+
.replace(/\.js$/, '.ts'),
|
|
1128
|
+
]));
|
|
1129
|
+
}
|
|
1130
|
+
function writeFileIfChanged(filePath, content) {
|
|
1131
|
+
try {
|
|
1132
|
+
if (fs.readFileSync(filePath, 'utf-8') === content)
|
|
1133
|
+
return;
|
|
1134
|
+
}
|
|
1135
|
+
catch { }
|
|
1136
|
+
fs.writeFileSync(filePath, content, 'utf-8');
|
|
1137
|
+
}
|
|
1138
|
+
function ensureSourcePackageShim(targetLink, hostRoot) {
|
|
1139
|
+
const srcLink = path.join(targetLink, 'src');
|
|
1140
|
+
const srcTarget = path.join(hostRoot, 'src');
|
|
1141
|
+
const pkgJsonContent = `${JSON.stringify({
|
|
1142
|
+
name: PACKAGE_NAME,
|
|
1143
|
+
private: true,
|
|
1144
|
+
type: 'module',
|
|
1145
|
+
exports: getHostSourcePackageExports(hostRoot),
|
|
1146
|
+
}, null, 2)}\n`;
|
|
1147
|
+
if (pathExistsSync(targetLink) && !fs.lstatSync(targetLink).isDirectory()) {
|
|
1148
|
+
removePathSync(targetLink);
|
|
1149
|
+
}
|
|
1150
|
+
fs.mkdirSync(targetLink, { recursive: true });
|
|
1151
|
+
writeFileIfChanged(path.join(targetLink, 'package.json'), pkgJsonContent);
|
|
1152
|
+
let needsSrcLink = true;
|
|
1153
|
+
try {
|
|
1154
|
+
if (fs.readlinkSync(srcLink) === srcTarget)
|
|
1155
|
+
needsSrcLink = false;
|
|
1156
|
+
}
|
|
1157
|
+
catch { }
|
|
1158
|
+
if (needsSrcLink) {
|
|
1159
|
+
removePathSync(srcLink);
|
|
1160
|
+
const linkType = isWindows ? 'junction' : 'dir';
|
|
1161
|
+
fs.symlinkSync(srcTarget, srcLink, linkType);
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
function ensureHostWebcmdPackageLink(targetLink, hostRoot) {
|
|
1165
|
+
const hasBuiltExports = fs.existsSync(path.join(hostRoot, 'dist', 'src', 'registry-api.js'));
|
|
1166
|
+
if (!hasBuiltExports) {
|
|
1167
|
+
if (pathExistsSync(targetLink) && fs.lstatSync(targetLink).isSymbolicLink()) {
|
|
1168
|
+
removePathSync(targetLink);
|
|
1169
|
+
}
|
|
1170
|
+
ensureSourcePackageShim(targetLink, hostRoot);
|
|
1171
|
+
return;
|
|
1172
|
+
}
|
|
1173
|
+
let needsUpdate = true;
|
|
1174
|
+
try {
|
|
1175
|
+
if (fs.readlinkSync(targetLink) === hostRoot)
|
|
1176
|
+
needsUpdate = false;
|
|
1177
|
+
}
|
|
1178
|
+
catch { }
|
|
1179
|
+
if (!needsUpdate)
|
|
1180
|
+
return;
|
|
1181
|
+
removePathSync(targetLink);
|
|
1182
|
+
fs.mkdirSync(path.dirname(targetLink), { recursive: true });
|
|
1183
|
+
const linkType = isWindows ? 'junction' : 'dir';
|
|
1184
|
+
fs.symlinkSync(hostRoot, targetLink, linkType);
|
|
1185
|
+
}
|
|
1186
|
+
/**
|
|
1187
|
+
* Resolve the path to the esbuild CLI executable with fallback strategies.
|
|
1188
|
+
*/
|
|
1189
|
+
export function resolveEsbuildBin() {
|
|
1190
|
+
const hostRoot = resolveHostWebcmdRoot();
|
|
1191
|
+
// Strategy 1 (Windows): prefer the .cmd wrapper which is executable via shell
|
|
1192
|
+
if (isWindows) {
|
|
1193
|
+
const cmdPath = path.join(hostRoot, 'node_modules', '.bin', 'esbuild.cmd');
|
|
1194
|
+
if (fs.existsSync(cmdPath)) {
|
|
1195
|
+
return cmdPath;
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
// Strategy 2: resolve esbuild binary via import.meta.resolve
|
|
1199
|
+
// (On Unix, shebang scripts are directly executable; on Windows they are not,
|
|
1200
|
+
// so this strategy is skipped on Windows in favour of the .cmd wrapper above.)
|
|
1201
|
+
if (!isWindows) {
|
|
1202
|
+
try {
|
|
1203
|
+
const pkgUrl = import.meta.resolve('esbuild/package.json');
|
|
1204
|
+
if (pkgUrl.startsWith('file://')) {
|
|
1205
|
+
const pkgPath = fileURLToPath(pkgUrl);
|
|
1206
|
+
const pkgRaw = fs.readFileSync(pkgPath, 'utf8');
|
|
1207
|
+
const pkg = JSON.parse(pkgRaw);
|
|
1208
|
+
if (pkg.bin && typeof pkg.bin === 'object' && pkg.bin.esbuild) {
|
|
1209
|
+
const binPath = path.resolve(path.dirname(pkgPath), pkg.bin.esbuild);
|
|
1210
|
+
if (fs.existsSync(binPath))
|
|
1211
|
+
return binPath;
|
|
1212
|
+
}
|
|
1213
|
+
else if (typeof pkg.bin === 'string') {
|
|
1214
|
+
const binPath = path.resolve(path.dirname(pkgPath), pkg.bin);
|
|
1215
|
+
if (fs.existsSync(binPath))
|
|
1216
|
+
return binPath;
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
catch {
|
|
1221
|
+
// ignore package resolution failures
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
// Strategy 3: fallback to node_modules/.bin/esbuild (Unix)
|
|
1225
|
+
const binFallback = path.join(hostRoot, 'node_modules', '.bin', 'esbuild');
|
|
1226
|
+
if (fs.existsSync(binFallback)) {
|
|
1227
|
+
return binFallback;
|
|
1228
|
+
}
|
|
1229
|
+
// Strategy 4: global esbuild in PATH
|
|
1230
|
+
try {
|
|
1231
|
+
const lookupCmd = isWindows ? 'where esbuild' : 'which esbuild';
|
|
1232
|
+
// `where` on Windows may return multiple lines; take only the first match.
|
|
1233
|
+
const globalBin = execSync(lookupCmd, { encoding: 'utf-8', stdio: 'pipe' }).trim().split('\n')[0].trim();
|
|
1234
|
+
if (globalBin && fs.existsSync(globalBin)) {
|
|
1235
|
+
return globalBin;
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
catch {
|
|
1239
|
+
// ignore PATH lookup failures
|
|
1240
|
+
}
|
|
1241
|
+
return null;
|
|
1242
|
+
}
|
|
1243
|
+
function resolveHostWebcmdRoot(startFile = fileURLToPath(import.meta.url)) {
|
|
1244
|
+
let dir = path.dirname(startFile);
|
|
1245
|
+
while (true) {
|
|
1246
|
+
const pkgPath = path.join(dir, 'package.json');
|
|
1247
|
+
if (fs.existsSync(pkgPath)) {
|
|
1248
|
+
try {
|
|
1249
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
1250
|
+
if (pkg?.name === '@agentrhq/webcmd') {
|
|
1251
|
+
return dir;
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
catch {
|
|
1255
|
+
// Keep walking; a malformed package.json should not hide an ancestor package root.
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
const parent = path.dirname(dir);
|
|
1259
|
+
if (parent === dir)
|
|
1260
|
+
break;
|
|
1261
|
+
dir = parent;
|
|
1262
|
+
}
|
|
1263
|
+
return path.resolve(path.dirname(startFile), '..');
|
|
1264
|
+
}
|
|
1265
|
+
/**
|
|
1266
|
+
* Transpile TS plugin files to JS so they work in production mode.
|
|
1267
|
+
* Uses esbuild from the host webcmd's node_modules for fast single-file transpilation.
|
|
1268
|
+
*/
|
|
1269
|
+
function transpilePluginTs(pluginDir) {
|
|
1270
|
+
try {
|
|
1271
|
+
const esbuildBin = resolveEsbuildBin();
|
|
1272
|
+
if (!esbuildBin) {
|
|
1273
|
+
log.warn('esbuild not found. TS plugin files will not be transpiled and may fail to load. ' +
|
|
1274
|
+
'Install esbuild (`npm i -g esbuild`) or ensure it is available in the webcmd host node_modules.');
|
|
1275
|
+
return;
|
|
1276
|
+
}
|
|
1277
|
+
const files = fs.readdirSync(pluginDir);
|
|
1278
|
+
const tsFiles = files.filter(f => f.endsWith('.ts') && !f.endsWith('.d.ts') && !f.endsWith('.test.ts'));
|
|
1279
|
+
for (const tsFile of tsFiles) {
|
|
1280
|
+
const jsFile = tsFile.replace(/\.ts$/, '.js');
|
|
1281
|
+
const jsPath = path.join(pluginDir, jsFile);
|
|
1282
|
+
// Skip if .js already exists (plugin may ship pre-compiled)
|
|
1283
|
+
if (fs.existsSync(jsPath))
|
|
1284
|
+
continue;
|
|
1285
|
+
try {
|
|
1286
|
+
execFileSync(esbuildBin, [tsFile, `--outfile=${jsFile}`, '--format=esm', '--platform=node'], {
|
|
1287
|
+
cwd: pluginDir,
|
|
1288
|
+
encoding: 'utf-8',
|
|
1289
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
1290
|
+
...(isWindows && { shell: true }),
|
|
1291
|
+
});
|
|
1292
|
+
log.debug(`Transpiled plugin file: ${tsFile} → ${jsFile}`);
|
|
1293
|
+
}
|
|
1294
|
+
catch (err) {
|
|
1295
|
+
log.warn(`Failed to transpile ${tsFile}: ${getErrorMessage(err)}`);
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
catch (err) {
|
|
1300
|
+
log.warn(`TS transpilation setup failed: ${getErrorMessage(err)}`);
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
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, };
|