@jackwener/opencli 1.7.12 → 1.7.14
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 +8 -7
- package/README.zh-CN.md +9 -8
- package/cli-manifest.json +12128 -6665
- package/clis/1point3acres/digest.js +35 -0
- package/clis/1point3acres/forum.js +51 -0
- package/clis/1point3acres/forums.js +44 -0
- package/clis/1point3acres/hot.js +35 -0
- package/clis/1point3acres/latest.js +35 -0
- package/clis/1point3acres/notifications.js +64 -0
- package/clis/1point3acres/search.js +71 -0
- package/clis/1point3acres/thread.js +117 -0
- package/clis/1point3acres/user.js +77 -0
- package/clis/1point3acres/utils.js +247 -0
- package/clis/_shared/desktop-commands.js +4 -0
- package/clis/aibase/news.js +110 -0
- package/clis/aibase/news.test.js +59 -0
- package/clis/amazon/discussion.test.js +1 -28
- package/clis/antigravity/watch.js +3 -2
- package/clis/arxiv/author.js +44 -0
- package/clis/baidu-scholar/search.js +0 -1
- package/clis/bbc/topic.js +57 -0
- package/clis/bbc/utils.js +79 -0
- package/clis/chaoxing/assignments.js +1 -1
- package/clis/chaoxing/exams.js +1 -1
- package/clis/chatgpt/ask.js +57 -0
- package/clis/chatgpt/commands.test.js +45 -0
- package/clis/chatgpt/detail.js +46 -0
- package/clis/chatgpt/history.js +39 -0
- package/clis/chatgpt/image.js +12 -11
- package/clis/chatgpt/image.test.js +23 -0
- package/clis/chatgpt/new.js +25 -0
- package/clis/chatgpt/read.js +43 -0
- package/clis/chatgpt/send.js +46 -0
- package/clis/chatgpt/status.js +29 -0
- package/clis/chatgpt/utils.js +294 -4
- package/clis/chatgpt/utils.test.js +13 -0
- package/clis/chatgpt-app/ask.js +6 -3
- package/clis/chatwise/ask.js +16 -43
- package/clis/chatwise/composer.test.js +186 -0
- package/clis/chatwise/send.js +2 -24
- package/clis/chatwise/utils.js +143 -0
- package/clis/claude/ask.js +1 -1
- package/clis/claude/detail.js +1 -0
- package/clis/claude/history.js +1 -0
- package/clis/claude/new.js +1 -0
- package/clis/claude/read.js +1 -0
- package/clis/claude/send.js +1 -0
- package/clis/claude/status.js +1 -0
- package/clis/codex/ask.js +15 -9
- package/clis/codex/history.js +16 -33
- package/clis/codex/projects.js +28 -0
- package/clis/codex/read.js +10 -4
- package/clis/codex/send.js +10 -3
- package/clis/codex/sidebar.js +356 -0
- package/clis/codex/sidebar.test.js +329 -0
- package/clis/coingecko/categories.js +75 -0
- package/clis/coingecko/coin.js +107 -0
- package/clis/coingecko/coingecko.test.js +109 -0
- package/clis/coingecko/derivatives.js +84 -0
- package/clis/coingecko/exchanges.js +74 -0
- package/clis/coingecko/global.js +71 -0
- package/clis/coingecko/top.js +64 -0
- package/clis/coingecko/trending.js +55 -0
- package/clis/coupang/add-to-cart.js +21 -13
- package/clis/coupang/coupang.test.js +159 -0
- package/clis/coupang/product.js +257 -0
- package/clis/coupang/search.js +38 -16
- package/clis/coupang/utils.js +55 -1
- package/clis/crates/crate.js +62 -0
- package/clis/crates/search.js +44 -0
- package/clis/crates/utils.js +72 -0
- package/clis/ctrip/ctrip.test.js +234 -0
- package/clis/ctrip/hotel-suggest.js +45 -0
- package/clis/ctrip/search.js +22 -68
- package/clis/ctrip/utils.js +175 -0
- package/clis/cursor/ask.js +6 -3
- package/clis/dblp/author.js +133 -0
- package/clis/dblp/venue.js +64 -0
- package/clis/deepseek/ask.js +12 -7
- package/clis/deepseek/ask.test.js +13 -13
- package/clis/deepseek/detail.js +38 -0
- package/clis/deepseek/detail.test.js +81 -0
- package/clis/deepseek/history.js +1 -0
- package/clis/deepseek/new.js +1 -0
- package/clis/deepseek/read.js +1 -0
- package/clis/deepseek/send.js +140 -0
- package/clis/deepseek/send.test.js +107 -0
- package/clis/deepseek/status.js +1 -0
- package/clis/deepseek/utils.js +66 -0
- package/clis/deepseek/utils.test.js +107 -1
- package/clis/defillama/defillama.test.js +99 -0
- package/clis/defillama/protocol.js +84 -0
- package/clis/defillama/protocols.js +55 -0
- package/clis/defillama/utils.js +99 -0
- package/clis/devto/latest.js +74 -0
- package/clis/dockerhub/image.js +52 -0
- package/clis/dockerhub/search.js +47 -0
- package/clis/dockerhub/utils.js +100 -0
- package/clis/doubao/ask.js +7 -3
- package/clis/doubao/detail.js +1 -0
- package/clis/doubao/history.js +1 -0
- package/clis/doubao/meeting-summary.js +1 -0
- package/clis/doubao/meeting-transcript.js +1 -0
- package/clis/doubao/new.js +1 -0
- package/clis/doubao/read.js +1 -0
- package/clis/doubao/send.js +1 -0
- package/clis/doubao/status.js +1 -0
- package/clis/douyin/draft.test.js +1 -30
- package/clis/endoflife/endoflife.test.js +51 -0
- package/clis/endoflife/product.js +55 -0
- package/clis/endoflife/utils.js +89 -0
- package/clis/facebook/__fixtures__/notifications-page.html +13 -0
- package/clis/facebook/notifications.js +326 -30
- package/clis/facebook/notifications.test.js +458 -0
- package/clis/flathub/app.js +71 -0
- package/clis/flathub/flathub.test.js +90 -0
- package/clis/flathub/search.js +80 -0
- package/clis/flathub/utils.js +114 -0
- package/clis/gemini/ask.js +7 -3
- package/clis/gemini/ask.test.js +2 -2
- package/clis/gemini/deep-research-result.js +6 -2
- package/clis/gemini/deep-research-result.test.js +15 -14
- package/clis/gemini/deep-research.js +8 -4
- package/clis/gemini/deep-research.test.js +15 -18
- package/clis/gemini/image.js +7 -2
- package/clis/gemini/new.js +1 -0
- package/clis/gemini/utils.js +0 -4
- package/clis/google-scholar/cite.js +0 -1
- package/clis/google-scholar/profile.js +0 -1
- package/clis/google-scholar/search.js +0 -1
- package/clis/goproxy/goproxy.test.js +103 -0
- package/clis/goproxy/module.js +47 -0
- package/clis/goproxy/utils.js +165 -0
- package/clis/goproxy/versions.js +59 -0
- package/clis/gov-law/recent.js +0 -1
- package/clis/gov-law/search.js +0 -1
- package/clis/gov-policy/__fixtures__/recent.html +16 -0
- package/clis/gov-policy/__fixtures__/search.html +41 -0
- package/clis/gov-policy/gov-policy.test.js +224 -0
- package/clis/gov-policy/recent.js +66 -24
- package/clis/gov-policy/search.js +65 -23
- package/clis/gov-policy/utils.js +54 -0
- package/clis/grok/ask.js +49 -265
- package/clis/grok/ask.test.js +21 -46
- package/clis/grok/detail.js +60 -0
- package/clis/grok/history.js +48 -0
- package/clis/grok/{image.ts → image.js} +56 -70
- package/clis/grok/image.test.ts +20 -0
- package/clis/grok/new.js +20 -0
- package/clis/grok/read.js +39 -0
- package/clis/grok/send.js +50 -0
- package/clis/grok/status.js +41 -0
- package/clis/grok/utils.js +326 -0
- package/clis/grok/utils.test.js +103 -0
- package/clis/hf/datasets.js +88 -0
- package/clis/hf/hf.test.js +16 -0
- package/clis/hf/models.js +91 -0
- package/clis/hf/paper.js +79 -0
- package/clis/hf/spaces.js +101 -0
- package/clis/hf/top.js +1 -0
- package/clis/homebrew/cask.js +39 -0
- package/clis/homebrew/formula.js +41 -0
- package/clis/homebrew/popular.js +54 -0
- package/clis/homebrew/utils.js +100 -0
- package/clis/hupu/__fixtures__/hot-home.html +64 -0
- package/clis/hupu/detail.js +0 -1
- package/clis/hupu/hot.js +156 -35
- package/clis/hupu/hot.test.js +224 -0
- package/clis/hupu/search.js +0 -1
- package/clis/instagram/note.js +1 -1
- package/clis/instagram/note.test.js +1 -29
- package/clis/instagram/post.js +1 -1
- package/clis/instagram/post.test.js +1 -1
- package/clis/instagram/reel.js +1 -1
- package/clis/instagram/story.js +1 -1
- package/clis/instagram/story.test.js +1 -34
- package/clis/jd/commands.test.js +1 -24
- package/clis/lichess/lichess.test.js +85 -0
- package/clis/lichess/top.js +46 -0
- package/clis/lichess/user.js +91 -0
- package/clis/lichess/utils.js +97 -0
- package/clis/linkedin/search.js +107 -10
- package/clis/linkedin/search.test.js +222 -0
- package/clis/linux-do/feed.js +2 -5
- package/clis/linux-do/feed.test.js +35 -0
- package/clis/lobsters/domain.js +92 -0
- package/clis/maven/artifact.js +49 -0
- package/clis/maven/search.js +51 -0
- package/clis/maven/utils.js +110 -0
- package/clis/mdn/search.js +97 -0
- package/clis/medium/tag.js +135 -0
- package/clis/npm/downloads.js +59 -0
- package/clis/npm/package.js +70 -0
- package/clis/npm/search.js +49 -0
- package/clis/npm/utils.js +76 -0
- package/clis/nuget/nuget.test.js +111 -0
- package/clis/nuget/package.js +101 -0
- package/clis/nuget/search.js +69 -0
- package/clis/nuget/utils.js +87 -0
- package/clis/nvd/cve.js +121 -0
- package/clis/oeis/oeis.test.js +88 -0
- package/clis/oeis/search.js +63 -0
- package/clis/oeis/sequence.js +71 -0
- package/clis/oeis/utils.js +88 -0
- package/clis/openalex/search.js +69 -0
- package/clis/openalex/utils.js +160 -0
- package/clis/openalex/work.js +65 -0
- package/clis/openfda/drug-label.js +74 -0
- package/clis/openfda/food-recall.js +65 -0
- package/clis/openfda/openfda.test.js +114 -0
- package/clis/openfda/utils.js +67 -0
- package/clis/osv/osv.test.js +97 -0
- package/clis/osv/query.js +72 -0
- package/clis/osv/utils.js +169 -0
- package/clis/osv/vulnerability.js +54 -0
- package/clis/packagist/package.js +49 -0
- package/clis/packagist/search.js +43 -0
- package/clis/packagist/utils.js +113 -0
- package/clis/paperreview/feedback.js +1 -1
- package/clis/paperreview/review.js +1 -1
- package/clis/paperreview/submit.js +1 -1
- package/clis/pixiv/download.test.js +1 -1
- package/clis/pixiv/illusts.test.js +1 -1
- package/clis/pixiv/search.test.js +1 -1
- package/clis/pubmed/article.js +50 -0
- package/clis/pubmed/author.js +64 -0
- package/clis/pubmed/citations.js +36 -0
- package/clis/pubmed/pubmed.test.js +276 -0
- package/clis/pubmed/related.js +45 -0
- package/clis/pubmed/search.js +75 -0
- package/clis/pubmed/utils.js +309 -0
- package/clis/pypi/downloads.js +66 -0
- package/clis/pypi/package.js +79 -0
- package/clis/pypi/utils.js +55 -0
- package/clis/quark/mv.js +1 -1
- package/clis/quark/save.js +1 -1
- package/clis/qwen/ask.js +85 -0
- package/clis/qwen/detail.js +62 -0
- package/clis/qwen/history.js +61 -0
- package/clis/qwen/image.js +179 -0
- package/clis/qwen/new.js +23 -0
- package/clis/qwen/read.js +41 -0
- package/clis/qwen/send.js +55 -0
- package/clis/qwen/status.js +37 -0
- package/clis/qwen/utils.js +409 -0
- package/clis/qwen/utils.test.js +45 -0
- package/clis/rest-countries/country.js +65 -0
- package/clis/rest-countries/region.js +64 -0
- package/clis/rest-countries/rest-countries.test.js +83 -0
- package/clis/rest-countries/utils.js +126 -0
- package/clis/reuters/article-detail.js +53 -0
- package/clis/reuters/reuters.test.js +299 -0
- package/clis/reuters/search.js +45 -34
- package/clis/reuters/utils.js +159 -0
- package/clis/rfc/rfc.js +52 -0
- package/clis/rfc/rfc.test.js +74 -0
- package/clis/rfc/utils.js +72 -0
- package/clis/rubygems/gem.js +42 -0
- package/clis/rubygems/search.js +47 -0
- package/clis/rubygems/utils.js +86 -0
- package/clis/stackoverflow/related.js +66 -0
- package/clis/stackoverflow/stackoverflow.test.js +58 -0
- package/clis/stackoverflow/tag.js +60 -0
- package/clis/stackoverflow/user.js +50 -0
- package/clis/stackoverflow/utils.js +118 -0
- package/clis/steam/app.js +67 -0
- package/clis/steam/search.js +58 -0
- package/clis/steam/steam.test.js +46 -0
- package/clis/steam/utils.js +107 -0
- package/clis/taobao/commands.test.js +1 -24
- package/clis/test-utils.js +61 -0
- package/clis/tieba/hot.js +0 -1
- package/clis/tiktok/comment.js +128 -41
- package/clis/tiktok/creator-videos.js +270 -0
- package/clis/tiktok/creator-videos.test.js +113 -0
- package/clis/tiktok/explore.js +137 -29
- package/clis/tiktok/follow.js +115 -33
- package/clis/tiktok/following.js +157 -36
- package/clis/tiktok/friends.js +139 -37
- package/clis/tiktok/live.js +137 -41
- package/clis/tiktok/notifications.js +141 -38
- package/clis/tiktok/refactor.test.js +389 -0
- package/clis/tiktok/unfollow.js +124 -38
- package/clis/tiktok/user.js +203 -29
- package/clis/tiktok/utils.js +505 -0
- package/clis/tiktok/write-refactor.test.js +370 -0
- package/clis/toutiao/articles.js +36 -62
- package/clis/toutiao/hot.js +63 -0
- package/clis/toutiao/toutiao.test.js +378 -0
- package/clis/toutiao/utils.js +161 -0
- package/clis/tvmaze/search.js +61 -0
- package/clis/tvmaze/show.js +60 -0
- package/clis/tvmaze/tvmaze.test.js +93 -0
- package/clis/tvmaze/utils.js +110 -0
- package/clis/twitter/accept.js +1 -1
- package/clis/twitter/followers.js +134 -69
- package/clis/twitter/quote.js +139 -0
- package/clis/twitter/quote.test.js +106 -0
- package/clis/twitter/reply-dm.js +1 -1
- package/clis/twitter/reply.test.js +1 -29
- package/clis/twitter/retweet.js +99 -0
- package/clis/twitter/retweet.test.js +69 -0
- package/clis/twitter/shared.js +38 -0
- package/clis/twitter/shared.test.js +28 -1
- package/clis/twitter/unlike.js +87 -0
- package/clis/twitter/unlike.test.js +72 -0
- package/clis/twitter/unretweet.js +99 -0
- package/clis/twitter/unretweet.test.js +69 -0
- package/clis/uisdc/news.js +105 -0
- package/clis/uisdc/news.test.js +66 -0
- package/clis/wanfang/search.js +0 -1
- package/clis/web/read.js +47 -17
- package/clis/web/read.test.js +101 -1
- package/clis/weixin/create-draft.js +1 -1
- package/clis/weixin/drafts.js +1 -1
- package/clis/weixin/drafts.test.js +5 -1
- package/clis/weixin/search.js +157 -0
- package/clis/weixin/search.test.js +227 -0
- package/clis/wikidata/entity.js +60 -0
- package/clis/wikidata/search.js +50 -0
- package/clis/wikidata/utils.js +117 -0
- package/clis/wikidata/wikidata.test.js +83 -0
- package/clis/wikipedia/page.js +95 -0
- package/clis/wttr/current.js +63 -0
- package/clis/wttr/forecast.js +71 -0
- package/clis/wttr/utils.js +50 -0
- package/clis/wttr/wttr.test.js +84 -0
- package/clis/xianyu/chat.js +16 -4
- package/clis/xianyu/chat.test.js +64 -0
- package/clis/xianyu/publish.js +485 -0
- package/clis/xianyu/publish.test.js +220 -0
- package/clis/xiaoe/catalog.js +105 -40
- package/clis/xiaoe/content.js +164 -29
- package/clis/xiaoe/courses.js +86 -29
- package/clis/xiaoe/xiaoe.test.js +486 -0
- package/clis/xiaohongshu/creator-notes-summary.js +1 -1
- package/clis/xiaohongshu/publish.js +16 -3
- package/clis/xiaohongshu/publish.test.js +46 -1
- package/clis/youtube/transcript.js +13 -19
- package/clis/youtube/transcript.test.js +17 -0
- package/clis/yuanbao/ask.js +17 -66
- package/clis/yuanbao/ask.test.js +5 -5
- package/clis/yuanbao/detail.js +65 -0
- package/clis/yuanbao/history.js +51 -0
- package/clis/yuanbao/new.js +1 -0
- package/clis/yuanbao/read.js +38 -0
- package/clis/yuanbao/send.js +57 -0
- package/clis/yuanbao/shared.js +297 -5
- package/clis/yuanbao/shared.test.js +80 -0
- package/clis/yuanbao/status.js +44 -0
- package/clis/zlibrary/commands.test.js +1 -11
- package/dist/src/browser/base-page.d.ts +9 -0
- package/dist/src/browser/base-page.js +44 -1
- package/dist/src/browser/base-page.test.js +66 -0
- package/dist/src/browser/bridge.js +47 -45
- package/dist/src/browser/cdp.d.ts +1 -0
- package/dist/src/browser/cdp.js +51 -9
- package/dist/src/browser/daemon-client.d.ts +4 -0
- package/dist/src/browser/errors.js +1 -1
- package/dist/src/browser/page.d.ts +1 -1
- package/dist/src/browser/page.js +3 -1
- package/dist/src/browser/page.test.js +29 -0
- package/dist/src/browser/target-errors.d.ts +2 -1
- package/dist/src/browser/target-errors.js +1 -0
- package/dist/src/browser/target-resolver.d.ts +25 -0
- package/dist/src/browser/target-resolver.js +43 -0
- package/dist/src/browser.test.js +18 -0
- package/dist/src/build-manifest.js +9 -4
- package/dist/src/build-manifest.test.js +2 -8
- package/dist/src/capabilityRouting.d.ts +16 -1
- package/dist/src/capabilityRouting.js +24 -1
- package/dist/src/capabilityRouting.test.js +19 -1
- package/dist/src/cli.js +76 -11
- package/dist/src/cli.test.js +241 -1
- package/dist/src/commanderAdapter.js +23 -9
- package/dist/src/commanderAdapter.test.js +0 -1
- package/dist/src/discovery.js +2 -5
- package/dist/src/errors.js +1 -1
- package/dist/src/execution.d.ts +1 -1
- package/dist/src/execution.js +111 -27
- package/dist/src/execution.test.js +326 -17
- package/dist/src/help.d.ts +27 -2
- package/dist/src/help.js +196 -23
- package/dist/src/help.test.d.ts +1 -0
- package/dist/src/help.test.js +54 -0
- package/dist/src/main.js +14 -1
- package/dist/src/manifest-types.d.ts +5 -3
- package/dist/src/pipeline/executor.js +1 -1
- package/dist/src/pipeline/executor.test.js +8 -0
- package/dist/src/pipeline/registry.d.ts +9 -0
- package/dist/src/pipeline/registry.js +13 -1
- package/dist/src/pipeline/steps/browser.d.ts +1 -0
- package/dist/src/pipeline/steps/browser.js +10 -0
- package/dist/src/pipeline/steps/download.test.js +1 -0
- package/dist/src/registry-api.d.ts +1 -1
- package/dist/src/registry.d.ts +12 -11
- package/dist/src/registry.js +16 -6
- package/dist/src/registry.test.js +2 -2
- package/dist/src/runtime.d.ts +2 -1
- package/dist/src/runtime.js +1 -1
- package/dist/src/serialization.d.ts +2 -2
- package/dist/src/serialization.js +4 -6
- package/dist/src/serialization.test.js +17 -0
- package/dist/src/types.d.ts +17 -0
- package/dist/src/validate.js +15 -11
- package/dist/src/validate.test.d.ts +9 -0
- package/dist/src/validate.test.js +90 -0
- package/package.json +1 -1
- package/scripts/fetch-adapters.js +1 -1
- package/scripts/typed-error-lint-baseline.json +5 -77
- package/clis/ctrip/search.test.js +0 -64
- package/clis/gov-policy/commands.test.js +0 -27
- package/clis/linux-do/category.js +0 -37
- package/clis/linux-do/hot.js +0 -26
- package/clis/linux-do/latest.js +0 -19
- package/clis/pixiv/test-utils.js +0 -23
- package/clis/toutiao/articles.test.js +0 -30
- package/dist/src/analysis.d.ts +0 -40
- package/dist/src/analysis.js +0 -172
package/dist/src/help.js
CHANGED
|
@@ -1,6 +1,33 @@
|
|
|
1
1
|
import yaml from 'js-yaml';
|
|
2
2
|
import { fullName } from './registry.js';
|
|
3
3
|
import { formatCommandExample } from './serialization.js';
|
|
4
|
+
const COMMON_OPTIONS = [
|
|
5
|
+
{
|
|
6
|
+
flags: '-f, --format <fmt>',
|
|
7
|
+
name: 'format',
|
|
8
|
+
help: 'Output format: table, plain, json, yaml, md, csv',
|
|
9
|
+
default: 'table',
|
|
10
|
+
choices: ['table', 'plain', 'json', 'yaml', 'md', 'csv'],
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
flags: '--trace <mode>',
|
|
14
|
+
name: 'trace',
|
|
15
|
+
help: 'Trace capture: off, on, retain-on-failure',
|
|
16
|
+
default: 'off',
|
|
17
|
+
choices: ['off', 'on', 'retain-on-failure'],
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
flags: '-v, --verbose',
|
|
21
|
+
name: 'verbose',
|
|
22
|
+
help: 'Debug output',
|
|
23
|
+
default: false,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
flags: '-h, --help',
|
|
27
|
+
name: 'help',
|
|
28
|
+
help: 'display help for command',
|
|
29
|
+
},
|
|
30
|
+
];
|
|
4
31
|
function normalizeStructuredHelpFormat(value) {
|
|
5
32
|
const normalized = value?.toLowerCase();
|
|
6
33
|
if (normalized === 'yaml' || normalized === 'yml')
|
|
@@ -50,18 +77,32 @@ export function wrapCommaList(items, opts = {}) {
|
|
|
50
77
|
lines.push(line);
|
|
51
78
|
return lines.join('\n');
|
|
52
79
|
}
|
|
53
|
-
export function
|
|
54
|
-
if (
|
|
55
|
-
return '';
|
|
80
|
+
export function classifyAdapter(domain) {
|
|
81
|
+
if (!domain)
|
|
82
|
+
return 'site';
|
|
83
|
+
return domain.includes('.') ? 'site' : 'app';
|
|
84
|
+
}
|
|
85
|
+
function formatGroupSection(label, names) {
|
|
86
|
+
if (names.length === 0)
|
|
87
|
+
return [];
|
|
56
88
|
return [
|
|
89
|
+
`${label} (${names.length}):`,
|
|
90
|
+
wrapCommaList(names),
|
|
57
91
|
'',
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
''
|
|
64
|
-
|
|
92
|
+
];
|
|
93
|
+
}
|
|
94
|
+
export function formatRootAdapterHelpText(groups) {
|
|
95
|
+
const total = groups.external.length + groups.apps.length + groups.sites.length;
|
|
96
|
+
if (total === 0)
|
|
97
|
+
return '';
|
|
98
|
+
const lines = [''];
|
|
99
|
+
lines.push(...formatGroupSection('External CLIs', groups.external));
|
|
100
|
+
lines.push(...formatGroupSection('App adapters', groups.apps));
|
|
101
|
+
lines.push(...formatGroupSection('Site adapters', groups.sites));
|
|
102
|
+
lines.push("Run 'opencli list' for full command details, or 'opencli <site> --help' to inspect one site.");
|
|
103
|
+
lines.push("Agent tip: use 'opencli <site> --help -f yaml' for all command args/options in one structured response.");
|
|
104
|
+
lines.push('');
|
|
105
|
+
return lines.join('\n');
|
|
65
106
|
}
|
|
66
107
|
function compactArg(arg) {
|
|
67
108
|
return {
|
|
@@ -75,35 +116,82 @@ function compactArg(arg) {
|
|
|
75
116
|
...(arg.help ? { help: arg.help } : {}),
|
|
76
117
|
};
|
|
77
118
|
}
|
|
78
|
-
function
|
|
119
|
+
function compactCommonOption(option) {
|
|
120
|
+
return {
|
|
121
|
+
name: option.name,
|
|
122
|
+
flags: option.flags,
|
|
123
|
+
help: option.help,
|
|
124
|
+
...('default' in option ? { default: option.default } : {}),
|
|
125
|
+
...('choices' in option ? { choices: option.choices } : {}),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function positionals(cmd) {
|
|
129
|
+
return cmd.args.filter(arg => arg.positional);
|
|
130
|
+
}
|
|
131
|
+
function commandOptions(cmd) {
|
|
132
|
+
return cmd.args.filter(arg => !arg.positional);
|
|
133
|
+
}
|
|
134
|
+
function formatPositionals(args) {
|
|
135
|
+
return args
|
|
136
|
+
.map(arg => arg.required ? `<${arg.name}>` : `[${arg.name}]`)
|
|
137
|
+
.join(' ');
|
|
138
|
+
}
|
|
139
|
+
function formatCommandOptionTerm(arg) {
|
|
140
|
+
if (arg.required || arg.valueRequired)
|
|
141
|
+
return `--${arg.name} <value>`;
|
|
142
|
+
return `--${arg.name} [value]`;
|
|
143
|
+
}
|
|
144
|
+
export function formatCommandListTerm(cmd) {
|
|
145
|
+
const positionalText = formatPositionals(positionals(cmd));
|
|
146
|
+
const optionText = commandOptions(cmd).length > 0 ? ' [options]' : '';
|
|
147
|
+
return `${cmd.name}${positionalText ? ` ${positionalText}` : ''}${optionText}`;
|
|
148
|
+
}
|
|
149
|
+
function formatUsage(cmd) {
|
|
150
|
+
const positionalText = formatPositionals(positionals(cmd));
|
|
151
|
+
return `opencli ${cmd.site} ${cmd.name}${positionalText ? ` ${positionalText}` : ''} [options]`;
|
|
152
|
+
}
|
|
153
|
+
function compactCommand(cmd) {
|
|
79
154
|
return {
|
|
80
155
|
name: cmd.name,
|
|
81
156
|
command: `opencli ${cmd.site} ${cmd.name}`,
|
|
157
|
+
usage: formatUsage(cmd),
|
|
82
158
|
access: cmd.access,
|
|
83
159
|
description: cmd.description,
|
|
160
|
+
browser: !!cmd.browser,
|
|
161
|
+
...(cmd.domain ? { domain: cmd.domain } : {}),
|
|
84
162
|
...(cmd.aliases?.length ? { aliases: cmd.aliases } : {}),
|
|
85
|
-
|
|
163
|
+
positionals: positionals(cmd).map(compactArg),
|
|
164
|
+
command_options: commandOptions(cmd).map(compactArg),
|
|
86
165
|
example: formatCommandExample(cmd),
|
|
87
|
-
...(
|
|
88
|
-
...(cmd.
|
|
89
|
-
...(cmd.
|
|
166
|
+
...(cmd.browserSession ? { browserSession: cmd.browserSession } : {}),
|
|
167
|
+
...(cmd.defaultFormat ? { defaultFormat: cmd.defaultFormat } : {}),
|
|
168
|
+
...(cmd.columns?.length ? { columns: cmd.columns } : {}),
|
|
90
169
|
};
|
|
91
170
|
}
|
|
92
|
-
export function rootHelpData(program,
|
|
93
|
-
const
|
|
171
|
+
export function rootHelpData(program, groups) {
|
|
172
|
+
const adapterNames = new Set([...groups.external, ...groups.apps, ...groups.sites]);
|
|
94
173
|
const commands = program.commands
|
|
95
|
-
.filter(command => !
|
|
174
|
+
.filter(command => !adapterNames.has(command.name()))
|
|
96
175
|
.map(command => ({
|
|
97
176
|
name: command.name(),
|
|
98
177
|
description: command.description(),
|
|
99
178
|
}));
|
|
179
|
+
const sortLocale = (a, b) => a.localeCompare(b);
|
|
100
180
|
return {
|
|
101
181
|
name: program.name(),
|
|
102
182
|
description: program.description(),
|
|
103
183
|
commands,
|
|
184
|
+
external_clis: {
|
|
185
|
+
count: groups.external.length,
|
|
186
|
+
clis: [...groups.external].sort(sortLocale),
|
|
187
|
+
},
|
|
188
|
+
app_adapters: {
|
|
189
|
+
count: groups.apps.length,
|
|
190
|
+
apps: [...groups.apps].sort(sortLocale),
|
|
191
|
+
},
|
|
104
192
|
site_adapters: {
|
|
105
|
-
count:
|
|
106
|
-
sites: [...
|
|
193
|
+
count: groups.sites.length,
|
|
194
|
+
sites: [...groups.sites].sort(sortLocale),
|
|
107
195
|
},
|
|
108
196
|
next: [
|
|
109
197
|
'opencli <site> --help -f yaml',
|
|
@@ -119,6 +207,7 @@ export function siteHelpData(site, commands) {
|
|
|
119
207
|
site,
|
|
120
208
|
command_count: unique.length,
|
|
121
209
|
commands: unique.map(cmd => compactCommand(cmd)),
|
|
210
|
+
common_options: COMMON_OPTIONS.map(compactCommonOption),
|
|
122
211
|
next: [
|
|
123
212
|
`opencli ${site} <command> --help -f yaml`,
|
|
124
213
|
`opencli ${site} <command> -f yaml`,
|
|
@@ -128,10 +217,95 @@ export function siteHelpData(site, commands) {
|
|
|
128
217
|
export function commandHelpData(cmd) {
|
|
129
218
|
return {
|
|
130
219
|
site: cmd.site,
|
|
131
|
-
...compactCommand(cmd
|
|
220
|
+
...compactCommand(cmd),
|
|
221
|
+
common_options: COMMON_OPTIONS.map(compactCommonOption),
|
|
132
222
|
output_formats: ['table', 'plain', 'yaml', 'json', 'md', 'csv'],
|
|
133
223
|
};
|
|
134
224
|
}
|
|
225
|
+
function formatRows(rows) {
|
|
226
|
+
if (rows.length === 0)
|
|
227
|
+
return [];
|
|
228
|
+
const width = Math.min(Math.max(...rows.map(([left]) => left.length)), 34);
|
|
229
|
+
return rows.map(([left, right]) => ` ${left.padEnd(width + 2)}${right}`);
|
|
230
|
+
}
|
|
231
|
+
function formatArgHelp(arg) {
|
|
232
|
+
const parts = [];
|
|
233
|
+
if (arg.help)
|
|
234
|
+
parts.push(arg.help);
|
|
235
|
+
if (arg.default !== undefined)
|
|
236
|
+
parts.push(`default: ${arg.default}`);
|
|
237
|
+
if (arg.choices?.length)
|
|
238
|
+
parts.push(`choices: ${arg.choices.join(', ')}`);
|
|
239
|
+
return parts.join(' ');
|
|
240
|
+
}
|
|
241
|
+
export function formatCommonOptionsHelpText() {
|
|
242
|
+
const rows = COMMON_OPTIONS.map(option => {
|
|
243
|
+
const details = [option.help];
|
|
244
|
+
if ('default' in option)
|
|
245
|
+
details.push(`default: ${option.default}`);
|
|
246
|
+
if ('choices' in option)
|
|
247
|
+
details.push(`choices: ${option.choices.join(', ')}`);
|
|
248
|
+
return [option.flags, details.join(' ')];
|
|
249
|
+
});
|
|
250
|
+
return ['Common options:', ...formatRows(rows)].join('\n');
|
|
251
|
+
}
|
|
252
|
+
export function formatSiteHelpText(site, commands) {
|
|
253
|
+
const unique = [...new Map(commands.map(cmd => [fullName(cmd), cmd])).values()]
|
|
254
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
255
|
+
const lines = [
|
|
256
|
+
`Usage: opencli ${site} <command> [args] [options]`,
|
|
257
|
+
'',
|
|
258
|
+
wrapCommaList(unique.map(cmd => cmd.name), { indent: '' }),
|
|
259
|
+
'',
|
|
260
|
+
'Commands:',
|
|
261
|
+
...formatRows(unique.map(cmd => [formatCommandListTerm(cmd), formatSiteCommandDescription(cmd)])),
|
|
262
|
+
'',
|
|
263
|
+
formatCommonOptionsHelpText(),
|
|
264
|
+
'',
|
|
265
|
+
`Agent tip: use 'opencli ${site} --help -f yaml' to get all command args/options in one structured response.`,
|
|
266
|
+
'',
|
|
267
|
+
];
|
|
268
|
+
return lines.join('\n');
|
|
269
|
+
}
|
|
270
|
+
export function formatCommandHelpText(cmd) {
|
|
271
|
+
const lines = [
|
|
272
|
+
`Usage: ${formatUsage(cmd)}`,
|
|
273
|
+
'',
|
|
274
|
+
cmd.description,
|
|
275
|
+
'',
|
|
276
|
+
];
|
|
277
|
+
const positionalRows = positionals(cmd).map(arg => [
|
|
278
|
+
arg.name,
|
|
279
|
+
formatArgHelp(arg),
|
|
280
|
+
]);
|
|
281
|
+
if (positionalRows.length) {
|
|
282
|
+
lines.push('Arguments:', ...formatRows(positionalRows), '');
|
|
283
|
+
}
|
|
284
|
+
const optionRows = commandOptions(cmd).map(arg => [
|
|
285
|
+
formatCommandOptionTerm(arg),
|
|
286
|
+
formatArgHelp(arg),
|
|
287
|
+
]);
|
|
288
|
+
if (optionRows.length) {
|
|
289
|
+
lines.push('Command options:', ...formatRows(optionRows), '');
|
|
290
|
+
}
|
|
291
|
+
lines.push(formatCommonOptionsHelpText(), '');
|
|
292
|
+
const meta = [];
|
|
293
|
+
meta.push(`Access: ${cmd.access}`);
|
|
294
|
+
meta.push(`Browser: ${cmd.browser ? 'yes' : 'no'}`);
|
|
295
|
+
if (cmd.domain)
|
|
296
|
+
meta.push(`Domain: ${cmd.domain}`);
|
|
297
|
+
if (cmd.defaultFormat)
|
|
298
|
+
meta.push(`Default format: ${cmd.defaultFormat}`);
|
|
299
|
+
if (cmd.aliases?.length)
|
|
300
|
+
meta.push(`Aliases: ${cmd.aliases.join(', ')}`);
|
|
301
|
+
lines.push(meta.join(' | '));
|
|
302
|
+
lines.push(`Example: ${formatCommandExample(cmd)}`);
|
|
303
|
+
if (cmd.columns?.length)
|
|
304
|
+
lines.push(`Output columns: ${cmd.columns.join(', ')}`);
|
|
305
|
+
lines.push("Agent tip: use '--help -f yaml' for structured args/options.");
|
|
306
|
+
lines.push('');
|
|
307
|
+
return lines.join('\n');
|
|
308
|
+
}
|
|
135
309
|
export function installStructuredHelp(command, data, textSuffix) {
|
|
136
310
|
const original = command.helpInformation.bind(command);
|
|
137
311
|
command.helpInformation = ((contextOptions) => {
|
|
@@ -144,6 +318,5 @@ export function installStructuredHelp(command, data, textSuffix) {
|
|
|
144
318
|
}
|
|
145
319
|
export function formatSiteCommandDescription(cmd) {
|
|
146
320
|
const access = cmd.access === 'write' ? '[write]' : '[read]';
|
|
147
|
-
|
|
148
|
-
return `${access} ${cmd.description}${deprecatedSuffix}`;
|
|
321
|
+
return `${access} ${cmd.description}`;
|
|
149
322
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { classifyAdapter, formatRootAdapterHelpText } from './help.js';
|
|
3
|
+
describe('classifyAdapter', () => {
|
|
4
|
+
it('classifies DNS-style domains as site', () => {
|
|
5
|
+
expect(classifyAdapter('www.bilibili.com')).toBe('site');
|
|
6
|
+
expect(classifyAdapter('chatgpt.com')).toBe('site');
|
|
7
|
+
expect(classifyAdapter('claude.ai')).toBe('site');
|
|
8
|
+
expect(classifyAdapter('grok.com')).toBe('site');
|
|
9
|
+
});
|
|
10
|
+
it('classifies localhost as app (Electron / osascript desktop integrations)', () => {
|
|
11
|
+
expect(classifyAdapter('localhost')).toBe('app');
|
|
12
|
+
});
|
|
13
|
+
it('classifies non-DNS domain strings as app (e.g. literal "doubao-app")', () => {
|
|
14
|
+
expect(classifyAdapter('doubao-app')).toBe('app');
|
|
15
|
+
});
|
|
16
|
+
it('defaults missing domain to site (most adapters without explicit domain are public web scrapers)', () => {
|
|
17
|
+
expect(classifyAdapter(undefined)).toBe('site');
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
describe('formatRootAdapterHelpText', () => {
|
|
21
|
+
it('renders all three sections in External / App / Site order when populated', () => {
|
|
22
|
+
const text = formatRootAdapterHelpText({
|
|
23
|
+
external: ['gh', 'docker'],
|
|
24
|
+
apps: ['chatwise', 'codex'],
|
|
25
|
+
sites: ['bilibili'],
|
|
26
|
+
});
|
|
27
|
+
expect(text).toContain('External CLIs (2):');
|
|
28
|
+
expect(text).toContain('App adapters (2):');
|
|
29
|
+
expect(text).toContain('Site adapters (1):');
|
|
30
|
+
expect(text.indexOf('External CLIs')).toBeLessThan(text.indexOf('App adapters'));
|
|
31
|
+
expect(text.indexOf('App adapters')).toBeLessThan(text.indexOf('Site adapters'));
|
|
32
|
+
});
|
|
33
|
+
it('omits empty sections instead of rendering a (0) header', () => {
|
|
34
|
+
const text = formatRootAdapterHelpText({
|
|
35
|
+
external: [],
|
|
36
|
+
apps: [],
|
|
37
|
+
sites: ['bilibili'],
|
|
38
|
+
});
|
|
39
|
+
expect(text).not.toContain('External CLIs');
|
|
40
|
+
expect(text).not.toContain('App adapters');
|
|
41
|
+
expect(text).toContain('Site adapters (1):');
|
|
42
|
+
});
|
|
43
|
+
it('returns empty string when all groups are empty', () => {
|
|
44
|
+
expect(formatRootAdapterHelpText({ external: [], apps: [], sites: [] })).toBe('');
|
|
45
|
+
});
|
|
46
|
+
it('always renders the agent discovery hint when any section is populated', () => {
|
|
47
|
+
const text = formatRootAdapterHelpText({
|
|
48
|
+
external: [],
|
|
49
|
+
apps: [],
|
|
50
|
+
sites: ['bilibili'],
|
|
51
|
+
});
|
|
52
|
+
expect(text).toContain("'opencli <site> --help -f yaml'");
|
|
53
|
+
});
|
|
54
|
+
});
|
package/dist/src/main.js
CHANGED
|
@@ -28,7 +28,7 @@ const __dirname = path.dirname(__filename);
|
|
|
28
28
|
const BUILTIN_CLIS = path.join(findPackageRoot(__filename), 'clis');
|
|
29
29
|
const USER_CLIS = path.join(os.homedir(), '.opencli', 'clis');
|
|
30
30
|
// ── Session lifecycle flags ──────────────────────────────────────────────
|
|
31
|
-
// `--live` / `--focus` are top-level-ish toggles that tweak the automation
|
|
31
|
+
// `--live` / `--focus` / `--reuse` are top-level-ish toggles that tweak the automation
|
|
32
32
|
// window's lifecycle. We strip them from argv before Commander runs so they
|
|
33
33
|
// can be placed anywhere and work on any subcommand (adapter or browser).
|
|
34
34
|
{
|
|
@@ -42,6 +42,19 @@ const USER_CLIS = path.join(os.homedir(), '.opencli', 'clis');
|
|
|
42
42
|
process.env.OPENCLI_WINDOW_FOCUSED = '1';
|
|
43
43
|
process.argv.splice(focusIdx, 1);
|
|
44
44
|
}
|
|
45
|
+
const reuseIdx = process.argv.findIndex(arg => arg === '--reuse' || arg.startsWith('--reuse='));
|
|
46
|
+
if (reuseIdx !== -1) {
|
|
47
|
+
const arg = process.argv[reuseIdx];
|
|
48
|
+
const value = arg.startsWith('--reuse=')
|
|
49
|
+
? arg.slice('--reuse='.length)
|
|
50
|
+
: process.argv[reuseIdx + 1];
|
|
51
|
+
if (value !== 'none' && value !== 'site') {
|
|
52
|
+
process.stderr.write(`--reuse must be one of: none, site. Received: "${value ?? ''}"\n`);
|
|
53
|
+
process.exit(EXIT_CODES.USAGE_ERROR);
|
|
54
|
+
}
|
|
55
|
+
process.env.OPENCLI_BROWSER_REUSE = value;
|
|
56
|
+
process.argv.splice(reuseIdx, arg.startsWith('--reuse=') ? 1 : 2);
|
|
57
|
+
}
|
|
45
58
|
}
|
|
46
59
|
// ── Ultra-fast path: lightweight commands bypass full discovery ──────────
|
|
47
60
|
// These are high-frequency or trivial paths that must not pay the startup tax.
|
|
@@ -28,9 +28,7 @@ export interface ManifestEntry {
|
|
|
28
28
|
}>;
|
|
29
29
|
columns?: string[];
|
|
30
30
|
pipeline?: Record<string, unknown>[];
|
|
31
|
-
|
|
32
|
-
deprecated?: boolean | string;
|
|
33
|
-
replacedBy?: string;
|
|
31
|
+
defaultFormat?: 'table' | 'plain' | 'json' | 'yaml' | 'yml' | 'md' | 'markdown' | 'csv';
|
|
34
32
|
type: 'js';
|
|
35
33
|
/** Relative path from clis/ dir, e.g. 'bilibili/search.js' */
|
|
36
34
|
modulePath?: string;
|
|
@@ -38,4 +36,8 @@ export interface ManifestEntry {
|
|
|
38
36
|
sourceFile?: string;
|
|
39
37
|
/** Pre-navigation control — see CliCommand.navigateBefore */
|
|
40
38
|
navigateBefore?: boolean | string;
|
|
39
|
+
/** Browser session lifecycle defaults — see CliCommand.browserSession */
|
|
40
|
+
browserSession?: {
|
|
41
|
+
reuse?: 'none' | 'site';
|
|
42
|
+
};
|
|
41
43
|
}
|
|
@@ -32,7 +32,7 @@ export async function executePipeline(page, pipeline, ctx = {}) {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
catch (err) {
|
|
35
|
-
// Attempt cleanup:
|
|
35
|
+
// Attempt cleanup: release automation tab lease on pipeline failure.
|
|
36
36
|
if (page?.closeWindow) {
|
|
37
37
|
try {
|
|
38
38
|
await page.closeWindow();
|
|
@@ -14,6 +14,7 @@ function createMockPage(overrides = {}) {
|
|
|
14
14
|
snapshot: vi.fn().mockResolvedValue(''),
|
|
15
15
|
click: vi.fn(),
|
|
16
16
|
typeText: vi.fn(),
|
|
17
|
+
fillText: vi.fn(),
|
|
17
18
|
pressKey: vi.fn(),
|
|
18
19
|
getFormState: vi.fn().mockResolvedValue({}),
|
|
19
20
|
wait: vi.fn(),
|
|
@@ -159,6 +160,13 @@ describe('executePipeline', () => {
|
|
|
159
160
|
]);
|
|
160
161
|
expect(page.click).toHaveBeenCalledWith('5');
|
|
161
162
|
});
|
|
163
|
+
it('fill step calls page.fillText with raw rendered text', async () => {
|
|
164
|
+
const page = createMockPage();
|
|
165
|
+
await executePipeline(page, [
|
|
166
|
+
{ fill: { ref: '@5', text: 'line1\\n/ / ${{ args.tail }}' } },
|
|
167
|
+
], { args: { tail: 'raw' } });
|
|
168
|
+
expect(page.fillText).toHaveBeenCalledWith('5', 'line1\\n/ / raw');
|
|
169
|
+
});
|
|
162
170
|
it('navigate preserves existing data through pipeline', async () => {
|
|
163
171
|
const page = createMockPage({
|
|
164
172
|
evaluate: vi.fn().mockResolvedValue([{ a: 1 }]),
|
|
@@ -13,6 +13,15 @@ export type StepHandler<TData = unknown, TResult = unknown, TParams = unknown> =
|
|
|
13
13
|
* Get a registered step handler by name.
|
|
14
14
|
*/
|
|
15
15
|
export declare function getStep(name: string): StepHandler | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* List all currently registered step names. Used by `validate.ts` to allowlist
|
|
18
|
+
* step names without maintaining a parallel hand-coded list.
|
|
19
|
+
*
|
|
20
|
+
* Note: this depends on registerStep() side effects below already having run.
|
|
21
|
+
* Importing this module triggers all core registrations at the bottom of the
|
|
22
|
+
* file, so the returned array reflects every core + plugin step at call time.
|
|
23
|
+
*/
|
|
24
|
+
export declare function getRegisteredStepNames(): string[];
|
|
16
25
|
/**
|
|
17
26
|
* Register a new custom step handler for the YAML pipeline.
|
|
18
27
|
*/
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Allows core and third-party plugins to register custom YAML operations.
|
|
4
4
|
*/
|
|
5
5
|
// Import core steps
|
|
6
|
-
import { stepNavigate, stepClick, stepType, stepWait, stepPress, stepSnapshot, stepEvaluate } from './steps/browser.js';
|
|
6
|
+
import { stepNavigate, stepClick, stepType, stepFill, stepWait, stepPress, stepSnapshot, stepEvaluate } from './steps/browser.js';
|
|
7
7
|
import { stepFetch } from './steps/fetch.js';
|
|
8
8
|
import { stepSelect, stepMap, stepFilter, stepSort, stepLimit } from './steps/transform.js';
|
|
9
9
|
import { stepIntercept } from './steps/intercept.js';
|
|
@@ -16,6 +16,17 @@ const _stepRegistry = new Map();
|
|
|
16
16
|
export function getStep(name) {
|
|
17
17
|
return _stepRegistry.get(name);
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* List all currently registered step names. Used by `validate.ts` to allowlist
|
|
21
|
+
* step names without maintaining a parallel hand-coded list.
|
|
22
|
+
*
|
|
23
|
+
* Note: this depends on registerStep() side effects below already having run.
|
|
24
|
+
* Importing this module triggers all core registrations at the bottom of the
|
|
25
|
+
* file, so the returned array reflects every core + plugin step at call time.
|
|
26
|
+
*/
|
|
27
|
+
export function getRegisteredStepNames() {
|
|
28
|
+
return [..._stepRegistry.keys()];
|
|
29
|
+
}
|
|
19
30
|
/**
|
|
20
31
|
* Register a new custom step handler for the YAML pipeline.
|
|
21
32
|
*/
|
|
@@ -32,6 +43,7 @@ registerStep('evaluate', stepEvaluate);
|
|
|
32
43
|
registerStep('snapshot', stepSnapshot);
|
|
33
44
|
registerStep('click', stepClick);
|
|
34
45
|
registerStep('type', stepType);
|
|
46
|
+
registerStep('fill', stepFill);
|
|
35
47
|
registerStep('wait', stepWait);
|
|
36
48
|
registerStep('press', stepPress);
|
|
37
49
|
registerStep('map', stepMap);
|
|
@@ -6,6 +6,7 @@ import type { IPage } from '../../types.js';
|
|
|
6
6
|
export declare function stepNavigate(page: IPage | null, params: unknown, data: unknown, args: Record<string, unknown>): Promise<unknown>;
|
|
7
7
|
export declare function stepClick(page: IPage | null, params: unknown, data: unknown, args: Record<string, unknown>): Promise<unknown>;
|
|
8
8
|
export declare function stepType(page: IPage | null, params: unknown, data: unknown, args: Record<string, unknown>): Promise<unknown>;
|
|
9
|
+
export declare function stepFill(page: IPage | null, params: unknown, data: unknown, args: Record<string, unknown>): Promise<unknown>;
|
|
9
10
|
export declare function stepWait(page: IPage | null, params: unknown, data: unknown, args: Record<string, unknown>): Promise<unknown>;
|
|
10
11
|
export declare function stepPress(page: IPage | null, params: unknown, data: unknown, args: Record<string, unknown>): Promise<unknown>;
|
|
11
12
|
export declare function stepSnapshot(page: IPage | null, params: unknown, _data: unknown, _args: Record<string, unknown>): Promise<unknown>;
|
|
@@ -29,6 +29,16 @@ export async function stepType(page, params, data, args) {
|
|
|
29
29
|
}
|
|
30
30
|
return data;
|
|
31
31
|
}
|
|
32
|
+
export async function stepFill(page, params, data, args) {
|
|
33
|
+
if (isRecord(params)) {
|
|
34
|
+
const ref = String(render(params.ref ?? '', { args, data })).replace(/^@/, '');
|
|
35
|
+
const text = String(render(params.text ?? '', { args, data }));
|
|
36
|
+
await page.fillText(ref, text);
|
|
37
|
+
if (params.submit)
|
|
38
|
+
await page.pressKey('Enter');
|
|
39
|
+
}
|
|
40
|
+
return data;
|
|
41
|
+
}
|
|
32
42
|
export async function stepWait(page, params, data, args) {
|
|
33
43
|
if (typeof params === 'number')
|
|
34
44
|
await page.wait(params);
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* plugins are dynamically imported during discoverPlugins().
|
|
8
8
|
*/
|
|
9
9
|
export { cli, Strategy, getRegistry, fullName, registerCommand } from './registry.js';
|
|
10
|
-
export type { CliCommand, Arg, CliOptions, CommandArgs } from './registry.js';
|
|
10
|
+
export type { CliCommand, Arg, CliOptions, CommandArgs, BrowserSessionOptions, BrowserSessionReuse } from './registry.js';
|
|
11
11
|
export type { IPage } from './types.js';
|
|
12
12
|
export { onStartup, onBeforeExecute, onAfterExecute } from './hooks.js';
|
|
13
13
|
export type { HookFn, HookContext, HookName } from './hooks.js';
|
package/dist/src/registry.d.ts
CHANGED
|
@@ -6,7 +6,6 @@ export declare enum Strategy {
|
|
|
6
6
|
PUBLIC = "public",
|
|
7
7
|
LOCAL = "local",
|
|
8
8
|
COOKIE = "cookie",
|
|
9
|
-
HEADER = "header",
|
|
10
9
|
INTERCEPT = "intercept",
|
|
11
10
|
UI = "ui"
|
|
12
11
|
}
|
|
@@ -20,14 +19,20 @@ export interface Arg {
|
|
|
20
19
|
help?: string;
|
|
21
20
|
choices?: string[];
|
|
22
21
|
}
|
|
23
|
-
export interface RequiredEnv {
|
|
24
|
-
name: string;
|
|
25
|
-
help?: string;
|
|
26
|
-
}
|
|
27
22
|
export type CommandArgs = Record<string, any>;
|
|
28
23
|
export type BrowserCommandFunc = (page: IPage, kwargs: CommandArgs, debug?: boolean) => Promise<unknown>;
|
|
29
24
|
export type NonBrowserCommandFunc = (kwargs: CommandArgs, debug?: boolean) => Promise<unknown>;
|
|
30
25
|
export type CommandAccess = 'read' | 'write';
|
|
26
|
+
export type BrowserSessionReuse = 'none' | 'site';
|
|
27
|
+
export interface BrowserSessionOptions {
|
|
28
|
+
/**
|
|
29
|
+
* Control whether browser-backed adapter commands reuse a stable tab lease.
|
|
30
|
+
*
|
|
31
|
+
* - `none`: one-shot workspace per command execution (default)
|
|
32
|
+
* - `site`: all commands for this site share `site:<site>` until idle expiry
|
|
33
|
+
*/
|
|
34
|
+
reuse?: BrowserSessionReuse;
|
|
35
|
+
}
|
|
31
36
|
interface BaseCliCommand {
|
|
32
37
|
site: string;
|
|
33
38
|
name: string;
|
|
@@ -41,16 +46,10 @@ interface BaseCliCommand {
|
|
|
41
46
|
args: Arg[];
|
|
42
47
|
columns?: string[];
|
|
43
48
|
pipeline?: Record<string, unknown>[];
|
|
44
|
-
timeoutSeconds?: number;
|
|
45
49
|
/** Origin of this command: 'yaml', 'ts', or plugin name. */
|
|
46
50
|
source?: string;
|
|
47
51
|
footerExtra?: (kwargs: CommandArgs) => string | undefined;
|
|
48
|
-
requiredEnv?: RequiredEnv[];
|
|
49
52
|
validateArgs?: (kwargs: CommandArgs) => void;
|
|
50
|
-
/** Deprecation note shown in help / execution warnings. */
|
|
51
|
-
deprecated?: boolean | string;
|
|
52
|
-
/** Preferred replacement command, if any. */
|
|
53
|
-
replacedBy?: string;
|
|
54
53
|
/**
|
|
55
54
|
* Control pre-navigation and browser-session requirement.
|
|
56
55
|
*
|
|
@@ -67,6 +66,8 @@ interface BaseCliCommand {
|
|
|
67
66
|
* Adapter authors can set this explicitly to override the strategy-based default.
|
|
68
67
|
*/
|
|
69
68
|
navigateBefore?: boolean | string;
|
|
69
|
+
/** Browser session lifecycle defaults for adapter commands. */
|
|
70
|
+
browserSession?: BrowserSessionOptions;
|
|
70
71
|
/** Override the default CLI output format when the user does not pass -f/--format. */
|
|
71
72
|
defaultFormat?: 'table' | 'plain' | 'json' | 'yaml' | 'yml' | 'md' | 'markdown' | 'csv';
|
|
72
73
|
}
|
package/dist/src/registry.js
CHANGED
|
@@ -6,7 +6,6 @@ export var Strategy;
|
|
|
6
6
|
Strategy["PUBLIC"] = "public";
|
|
7
7
|
Strategy["LOCAL"] = "local";
|
|
8
8
|
Strategy["COOKIE"] = "cookie";
|
|
9
|
-
Strategy["HEADER"] = "header";
|
|
10
9
|
Strategy["INTERCEPT"] = "intercept";
|
|
11
10
|
Strategy["UI"] = "ui";
|
|
12
11
|
})(Strategy || (Strategy = {}));
|
|
@@ -18,6 +17,7 @@ export function cli(opts) {
|
|
|
18
17
|
aliases: opts.aliases,
|
|
19
18
|
description: opts.description ?? '',
|
|
20
19
|
access: opts.access,
|
|
20
|
+
example: opts.example,
|
|
21
21
|
domain: opts.domain,
|
|
22
22
|
strategy: opts.strategy,
|
|
23
23
|
browser: opts.browser,
|
|
@@ -25,12 +25,9 @@ export function cli(opts) {
|
|
|
25
25
|
columns: opts.columns,
|
|
26
26
|
func: opts.func,
|
|
27
27
|
pipeline: opts.pipeline,
|
|
28
|
-
timeoutSeconds: opts.timeoutSeconds,
|
|
29
28
|
footerExtra: opts.footerExtra,
|
|
30
|
-
requiredEnv: opts.requiredEnv,
|
|
31
|
-
deprecated: opts.deprecated,
|
|
32
|
-
replacedBy: opts.replacedBy,
|
|
33
29
|
navigateBefore: opts.navigateBefore,
|
|
30
|
+
browserSession: opts.browserSession,
|
|
34
31
|
defaultFormat: opts.defaultFormat,
|
|
35
32
|
};
|
|
36
33
|
registerCommand(cmd);
|
|
@@ -60,11 +57,12 @@ export function strategyLabel(cmd) {
|
|
|
60
57
|
*/
|
|
61
58
|
function normalizeCommand(cmd) {
|
|
62
59
|
assertCommandAccess(cmd);
|
|
60
|
+
assertBrowserSessionOptions(cmd);
|
|
63
61
|
const strategy = cmd.strategy ?? (cmd.browser === false ? Strategy.PUBLIC : Strategy.COOKIE);
|
|
64
62
|
const browser = cmd.browser ?? (strategy !== Strategy.PUBLIC && strategy !== Strategy.LOCAL);
|
|
65
63
|
let navigateBefore = cmd.navigateBefore;
|
|
66
64
|
if (navigateBefore === undefined) {
|
|
67
|
-
if (
|
|
65
|
+
if (strategy === Strategy.COOKIE && cmd.domain) {
|
|
68
66
|
navigateBefore = `https://${cmd.domain}`;
|
|
69
67
|
}
|
|
70
68
|
else if (strategy !== Strategy.PUBLIC && strategy !== Strategy.LOCAL) {
|
|
@@ -84,6 +82,18 @@ function assertCommandAccess(cmd) {
|
|
|
84
82
|
const key = `${cmd.site}/${cmd.name}`;
|
|
85
83
|
throw new Error(`Command ${key} must declare access: 'read' | 'write'`);
|
|
86
84
|
}
|
|
85
|
+
function assertBrowserSessionOptions(cmd) {
|
|
86
|
+
if (cmd.browserSession === undefined)
|
|
87
|
+
return;
|
|
88
|
+
const key = `${cmd.site}/${cmd.name}`;
|
|
89
|
+
if (cmd.browserSession === null || typeof cmd.browserSession !== 'object' || Array.isArray(cmd.browserSession)) {
|
|
90
|
+
throw new Error(`Command ${key} browserSession must be an object`);
|
|
91
|
+
}
|
|
92
|
+
const reuse = cmd.browserSession.reuse;
|
|
93
|
+
if (reuse !== undefined && reuse !== 'none' && reuse !== 'site') {
|
|
94
|
+
throw new Error(`Command ${key} browserSession.reuse must be one of: none, site`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
87
97
|
export function registerCommand(cmd) {
|
|
88
98
|
const normalized = normalizeCommand(cmd);
|
|
89
99
|
const canonicalKey = fullName(normalized);
|
|
@@ -121,12 +121,12 @@ describe('registerCommand', () => {
|
|
|
121
121
|
name: 'direct-reg', access: 'read',
|
|
122
122
|
description: 'directly registered',
|
|
123
123
|
args: [],
|
|
124
|
-
strategy: Strategy.
|
|
124
|
+
strategy: Strategy.COOKIE,
|
|
125
125
|
browser: true,
|
|
126
126
|
};
|
|
127
127
|
registerCommand(cmd);
|
|
128
128
|
const reg = getRegistry();
|
|
129
|
-
expect(reg.get('test-registry/direct-reg')?.strategy).toBe(Strategy.
|
|
129
|
+
expect(reg.get('test-registry/direct-reg')?.strategy).toBe(Strategy.COOKIE);
|
|
130
130
|
});
|
|
131
131
|
});
|
|
132
132
|
describe('normalizeCommand (via registerCommand)', () => {
|