@jackwener/opencli 1.7.11 → 1.7.13
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 +11 -9
- package/cli-manifest.json +12952 -6208
- package/clis/1688/assets.js +1 -0
- package/clis/1688/download.js +1 -0
- package/clis/1688/item.js +1 -0
- package/clis/1688/search.js +2 -1
- package/clis/1688/store.js +1 -0
- 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/36kr/article.js +1 -0
- package/clis/36kr/hot.js +1 -0
- package/clis/36kr/news.js +1 -0
- package/clis/36kr/search.js +1 -0
- package/clis/51job/company.js +1 -0
- package/clis/51job/detail.js +1 -0
- package/clis/51job/hot.js +1 -0
- package/clis/51job/search.js +1 -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/bestsellers.js +1 -0
- package/clis/amazon/discussion.js +1 -0
- package/clis/amazon/discussion.test.js +1 -28
- package/clis/amazon/movers-shakers.js +1 -0
- package/clis/amazon/new-releases.js +1 -0
- package/clis/amazon/offer.js +1 -0
- package/clis/amazon/product.js +1 -0
- package/clis/amazon/rankings.js +1 -0
- package/clis/amazon/search.js +1 -0
- package/clis/antigravity/dump.js +1 -0
- package/clis/antigravity/extract-code.js +1 -0
- package/clis/antigravity/model.js +1 -0
- package/clis/antigravity/new.js +1 -0
- package/clis/antigravity/read.js +1 -0
- package/clis/antigravity/send.js +1 -0
- package/clis/antigravity/status.js +1 -0
- package/clis/antigravity/watch.js +4 -2
- package/clis/apple-podcasts/episodes.js +1 -0
- package/clis/apple-podcasts/search.js +1 -0
- package/clis/apple-podcasts/top.js +1 -0
- package/clis/arxiv/arxiv.test.js +112 -0
- package/clis/arxiv/author.js +44 -0
- package/clis/arxiv/paper.js +4 -3
- package/clis/arxiv/recent.js +33 -0
- package/clis/arxiv/search.js +19 -7
- package/clis/arxiv/utils.js +68 -5
- package/clis/baidu-scholar/search.js +1 -1
- package/clis/band/bands.js +1 -0
- package/clis/band/mentions.js +1 -0
- package/clis/band/post.js +1 -0
- package/clis/band/posts.js +1 -0
- package/clis/barchart/flow.js +1 -0
- package/clis/barchart/greeks.js +1 -0
- package/clis/barchart/options.js +1 -0
- package/clis/barchart/quote.js +1 -0
- package/clis/bbc/news.js +1 -0
- package/clis/bbc/topic.js +57 -0
- package/clis/bbc/utils.js +79 -0
- package/clis/bilibili/comments.js +1 -0
- package/clis/bilibili/download.js +1 -0
- package/clis/bilibili/dynamic.js +1 -0
- package/clis/bilibili/favorite.js +1 -0
- package/clis/bilibili/feed.js +2 -0
- package/clis/bilibili/following.js +1 -0
- package/clis/bilibili/history.js +1 -0
- package/clis/bilibili/hot.js +6 -1
- package/clis/bilibili/hot.test.js +17 -0
- package/clis/bilibili/me.js +1 -1
- package/clis/bilibili/ranking.js +1 -0
- package/clis/bilibili/search.js +1 -1
- package/clis/bilibili/subtitle.js +1 -0
- package/clis/bilibili/user-videos.js +1 -0
- package/clis/bilibili/video.js +1 -0
- package/clis/binance/asks.js +1 -0
- package/clis/binance/depth.js +1 -0
- package/clis/binance/gainers.js +1 -0
- package/clis/binance/klines.js +1 -0
- package/clis/binance/losers.js +1 -0
- package/clis/binance/pairs.js +1 -0
- package/clis/binance/price.js +1 -0
- package/clis/binance/prices.js +1 -0
- package/clis/binance/ticker.js +1 -0
- package/clis/binance/top.js +1 -0
- package/clis/binance/trades.js +1 -0
- package/clis/bloomberg/businessweek.js +1 -0
- package/clis/bloomberg/economics.js +1 -0
- package/clis/bloomberg/feeds.js +1 -0
- package/clis/bloomberg/industries.js +1 -0
- package/clis/bloomberg/main.js +1 -0
- package/clis/bloomberg/markets.js +1 -0
- package/clis/bloomberg/news.js +1 -0
- package/clis/bloomberg/opinions.js +1 -0
- package/clis/bloomberg/politics.js +1 -0
- package/clis/bloomberg/tech.js +1 -0
- package/clis/bluesky/feeds.js +1 -0
- package/clis/bluesky/followers.js +1 -0
- package/clis/bluesky/following.js +1 -0
- package/clis/bluesky/profile.js +1 -0
- package/clis/bluesky/search.js +1 -0
- package/clis/bluesky/starter-packs.js +1 -0
- package/clis/bluesky/thread.js +1 -0
- package/clis/bluesky/trending.js +1 -0
- package/clis/bluesky/user.js +3 -1
- package/clis/boss/batchgreet.js +1 -0
- package/clis/boss/chatlist.js +1 -0
- package/clis/boss/chatmsg.js +1 -0
- package/clis/boss/detail.js +1 -0
- package/clis/boss/exchange.js +1 -0
- package/clis/boss/greet.js +1 -0
- package/clis/boss/invite.js +1 -0
- package/clis/boss/joblist.js +1 -0
- package/clis/boss/mark.js +1 -0
- package/clis/boss/recommend.js +1 -0
- package/clis/boss/resume.js +1 -0
- package/clis/boss/search.js +1 -0
- package/clis/boss/send.js +1 -0
- package/clis/boss/stats.js +1 -0
- package/clis/chaoxing/assignments.js +2 -1
- package/clis/chaoxing/exams.js +2 -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 +13 -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 +7 -3
- package/clis/chatgpt-app/model.js +1 -0
- package/clis/chatgpt-app/new.js +1 -0
- package/clis/chatgpt-app/read.js +1 -0
- package/clis/chatgpt-app/send.js +1 -0
- package/clis/chatgpt-app/status.js +1 -0
- package/clis/chatwise/ask.js +17 -43
- package/clis/chatwise/composer.test.js +186 -0
- package/clis/chatwise/export.js +1 -0
- package/clis/chatwise/history.js +1 -0
- package/clis/chatwise/model.js +1 -0
- package/clis/chatwise/read.js +1 -0
- package/clis/chatwise/send.js +3 -24
- package/clis/chatwise/utils.js +143 -0
- package/clis/claude/ask.js +2 -1
- package/clis/claude/detail.js +2 -0
- package/clis/claude/history.js +2 -0
- package/clis/claude/new.js +2 -0
- package/clis/claude/read.js +2 -0
- package/clis/claude/send.js +2 -0
- package/clis/claude/status.js +2 -0
- package/clis/cnki/search.js +1 -0
- package/clis/codex/ask.js +16 -9
- package/clis/codex/export.js +1 -0
- package/clis/codex/extract-diff.js +1 -0
- package/clis/codex/history.js +17 -33
- package/clis/codex/model.js +1 -0
- package/clis/codex/projects.js +28 -0
- package/clis/codex/read.js +11 -4
- package/clis/codex/send.js +11 -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 +22 -13
- package/clis/coupang/coupang.test.js +159 -0
- package/clis/coupang/product.js +257 -0
- package/clis/coupang/search.js +39 -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 +23 -68
- package/clis/ctrip/utils.js +175 -0
- package/clis/cursor/ask.js +7 -3
- package/clis/cursor/composer.js +1 -0
- package/clis/cursor/export.js +1 -0
- package/clis/cursor/extract-code.js +1 -0
- package/clis/cursor/history.js +1 -0
- package/clis/cursor/model.js +1 -0
- package/clis/cursor/read.js +1 -0
- package/clis/cursor/send.js +1 -0
- package/clis/dblp/author.js +133 -0
- package/clis/dblp/dblp.test.js +397 -0
- package/clis/dblp/paper.js +40 -0
- package/clis/dblp/search.js +45 -0
- package/clis/dblp/utils.js +290 -0
- package/clis/dblp/venue.js +64 -0
- package/clis/deepseek/ask.js +13 -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 +2 -0
- package/clis/deepseek/new.js +2 -0
- package/clis/deepseek/read.js +2 -0
- package/clis/deepseek/send.js +140 -0
- package/clis/deepseek/send.test.js +107 -0
- package/clis/deepseek/status.js +2 -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/devto.test.js +236 -0
- package/clis/devto/latest.js +74 -0
- package/clis/devto/read.js +103 -0
- package/clis/devto/tag.js +5 -1
- package/clis/devto/top.js +5 -1
- package/clis/devto/user.js +5 -1
- package/clis/dianping/__fixtures__/search.html +168 -0
- package/clis/dianping/__fixtures__/shop.html +6 -0
- package/clis/dianping/dianping.test.js +424 -0
- package/clis/dianping/search.js +154 -0
- package/clis/dianping/shop.js +173 -0
- package/clis/dianping/utils.js +157 -0
- package/clis/dictionary/examples.js +1 -0
- package/clis/dictionary/search.js +1 -0
- package/clis/dictionary/synonyms.js +1 -0
- package/clis/discord-app/channels.js +1 -0
- package/clis/discord-app/delete.js +1 -0
- package/clis/discord-app/members.js +1 -0
- package/clis/discord-app/read.js +1 -0
- package/clis/discord-app/search.js +1 -0
- package/clis/discord-app/send.js +1 -0
- package/clis/discord-app/servers.js +1 -0
- package/clis/discord-app/status.js +1 -0
- package/clis/dockerhub/image.js +52 -0
- package/clis/dockerhub/search.js +47 -0
- package/clis/dockerhub/utils.js +100 -0
- package/clis/douban/book-hot.js +1 -0
- package/clis/douban/download.js +1 -0
- package/clis/douban/marks.js +1 -0
- package/clis/douban/movie-hot.js +2 -1
- package/clis/douban/movie-hot.test.js +14 -0
- package/clis/douban/photos.js +2 -1
- package/clis/douban/reviews.js +1 -0
- package/clis/douban/search.js +1 -0
- package/clis/douban/subject.js +1 -0
- package/clis/douban/top250.js +1 -0
- package/clis/douban/utils.js +11 -13
- package/clis/douban/utils.test.js +79 -0
- package/clis/doubao/ask.js +8 -3
- package/clis/doubao/detail.js +2 -0
- package/clis/doubao/history.js +2 -0
- package/clis/doubao/meeting-summary.js +2 -0
- package/clis/doubao/meeting-transcript.js +2 -0
- package/clis/doubao/new.js +2 -0
- package/clis/doubao/read.js +2 -0
- package/clis/doubao/send.js +2 -0
- package/clis/doubao/status.js +2 -0
- package/clis/doubao-app/ask.js +1 -0
- package/clis/doubao-app/dump.js +1 -0
- package/clis/doubao-app/new.js +1 -0
- package/clis/doubao-app/read.js +1 -0
- package/clis/doubao-app/screenshot.js +1 -0
- package/clis/doubao-app/send.js +1 -0
- package/clis/doubao-app/status.js +1 -0
- package/clis/douyin/activities.js +1 -0
- package/clis/douyin/collections.js +1 -0
- package/clis/douyin/delete.js +1 -0
- package/clis/douyin/draft.js +1 -0
- package/clis/douyin/draft.test.js +1 -30
- package/clis/douyin/drafts.js +1 -0
- package/clis/douyin/hashtag.js +1 -0
- package/clis/douyin/location.js +1 -0
- package/clis/douyin/profile.js +1 -0
- package/clis/douyin/publish.js +1 -0
- package/clis/douyin/stats.js +1 -0
- package/clis/douyin/update.js +1 -0
- package/clis/douyin/user-videos.js +1 -0
- package/clis/douyin/videos.js +1 -0
- package/clis/eastmoney/announcement.js +1 -0
- package/clis/eastmoney/convertible.js +1 -0
- package/clis/eastmoney/etf.js +1 -0
- package/clis/eastmoney/holders.js +1 -0
- package/clis/eastmoney/hot-rank.js +1 -0
- package/clis/eastmoney/index-board.js +1 -0
- package/clis/eastmoney/kline.js +1 -0
- package/clis/eastmoney/kuaixun.js +1 -0
- package/clis/eastmoney/longhu.js +1 -0
- package/clis/eastmoney/money-flow.js +1 -0
- package/clis/eastmoney/northbound.js +1 -0
- package/clis/eastmoney/quote.js +1 -0
- package/clis/eastmoney/rank.js +1 -0
- package/clis/eastmoney/sectors.js +1 -0
- 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/add-friend.js +1 -0
- package/clis/facebook/events.js +1 -0
- package/clis/facebook/feed.js +1 -0
- package/clis/facebook/friends.js +1 -0
- package/clis/facebook/groups.js +1 -0
- package/clis/facebook/join-group.js +1 -0
- package/clis/facebook/marketplace-inbox.js +1 -0
- package/clis/facebook/marketplace-listings.js +1 -0
- package/clis/facebook/memories.js +1 -0
- package/clis/facebook/notifications.js +327 -30
- package/clis/facebook/notifications.test.js +458 -0
- package/clis/facebook/profile.js +1 -0
- package/clis/facebook/search.js +1 -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 +8 -3
- package/clis/gemini/ask.test.js +2 -2
- package/clis/gemini/deep-research-result.js +7 -2
- package/clis/gemini/deep-research-result.test.js +15 -14
- package/clis/gemini/deep-research.js +9 -4
- package/clis/gemini/deep-research.test.js +15 -18
- package/clis/gemini/image.js +8 -2
- package/clis/gemini/new.js +2 -0
- package/clis/gemini/utils.js +0 -4
- package/clis/gitee/search.js +1 -0
- package/clis/gitee/trending.js +1 -0
- package/clis/gitee/user.js +1 -0
- package/clis/google/news.js +1 -0
- package/clis/google/search.js +1 -0
- package/clis/google/suggest.js +1 -0
- package/clis/google/trends.js +1 -0
- package/clis/google-scholar/cite.js +1 -1
- package/clis/google-scholar/profile.js +1 -1
- package/clis/google-scholar/search.js +1 -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 +1 -1
- package/clis/gov-law/search.js +1 -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 +67 -24
- package/clis/gov-policy/search.js +66 -23
- package/clis/gov-policy/utils.js +54 -0
- package/clis/grok/ask.js +50 -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} +57 -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/hackernews/ask.js +3 -1
- package/clis/hackernews/best.js +3 -1
- package/clis/hackernews/hackernews.test.js +132 -0
- package/clis/hackernews/jobs.js +3 -1
- package/clis/hackernews/new.js +3 -1
- package/clis/hackernews/read.js +188 -0
- package/clis/hackernews/search.js +3 -1
- package/clis/hackernews/show.js +3 -1
- package/clis/hackernews/top.js +3 -1
- package/clis/hackernews/user.js +1 -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 +2 -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 +1 -1
- package/clis/hupu/hot.js +157 -34
- package/clis/hupu/hot.test.js +224 -0
- package/clis/hupu/like.js +1 -0
- package/clis/hupu/mentions.js +2 -1
- package/clis/hupu/reply.js +1 -0
- package/clis/hupu/search.js +3 -2
- package/clis/hupu/unlike.js +1 -0
- package/clis/imdb/person.js +1 -0
- package/clis/imdb/reviews.js +1 -0
- package/clis/imdb/search.js +1 -0
- package/clis/imdb/title.js +1 -0
- package/clis/imdb/top.js +1 -0
- package/clis/imdb/trending.js +1 -0
- package/clis/indeed/indeed.test.js +375 -0
- package/clis/indeed/job.js +86 -0
- package/clis/indeed/search.js +110 -0
- package/clis/indeed/utils.js +152 -0
- package/clis/instagram/collection-create.js +1 -0
- package/clis/instagram/collection-delete.js +1 -0
- package/clis/instagram/comment.js +1 -0
- package/clis/instagram/download.js +1 -0
- package/clis/instagram/explore.js +1 -0
- package/clis/instagram/follow.js +1 -0
- package/clis/instagram/followers.js +1 -0
- package/clis/instagram/following.js +1 -0
- package/clis/instagram/like.js +1 -0
- package/clis/instagram/note.js +2 -1
- package/clis/instagram/note.test.js +1 -29
- package/clis/instagram/post.js +2 -1
- package/clis/instagram/post.test.js +1 -1
- package/clis/instagram/profile.js +1 -0
- package/clis/instagram/reel.js +2 -1
- package/clis/instagram/save.js +1 -0
- package/clis/instagram/saved.js +1 -0
- package/clis/instagram/search.js +1 -0
- package/clis/instagram/story.js +2 -1
- package/clis/instagram/story.test.js +1 -34
- package/clis/instagram/unfollow.js +1 -0
- package/clis/instagram/unlike.js +1 -0
- package/clis/instagram/unsave.js +1 -0
- package/clis/instagram/user.js +1 -0
- package/clis/jd/add-cart.js +1 -0
- package/clis/jd/cart.js +1 -0
- package/clis/jd/commands.test.js +1 -24
- package/clis/jd/detail.js +1 -0
- package/clis/jd/item.js +1 -0
- package/clis/jd/reviews.js +1 -0
- package/clis/jd/search.js +1 -0
- package/clis/jianyu/detail.js +1 -0
- package/clis/jianyu/search.js +1 -0
- package/clis/jike/comment.js +1 -0
- package/clis/jike/create.js +1 -0
- package/clis/jike/feed.js +3 -1
- package/clis/jike/like.js +1 -0
- package/clis/jike/notifications.js +1 -0
- package/clis/jike/post.js +1 -0
- package/clis/jike/repost.js +1 -0
- package/clis/jike/search.js +3 -1
- package/clis/jike/topic.js +1 -0
- package/clis/jike/user.js +3 -1
- package/clis/jimeng/generate.js +1 -0
- package/clis/jimeng/history.js +1 -0
- package/clis/jimeng/new.js +1 -0
- package/clis/jimeng/workspaces.js +1 -0
- package/clis/ke/chengjiao.js +1 -0
- package/clis/ke/ershoufang.js +1 -0
- package/clis/ke/xiaoqu.js +1 -0
- package/clis/ke/zufang.js +1 -0
- package/clis/lesswrong/comments.js +1 -0
- package/clis/lesswrong/curated.js +1 -0
- package/clis/lesswrong/frontpage.js +1 -0
- package/clis/lesswrong/new.js +1 -0
- package/clis/lesswrong/read.js +1 -0
- package/clis/lesswrong/sequences.js +1 -0
- package/clis/lesswrong/shortform.js +1 -0
- package/clis/lesswrong/tag.js +1 -0
- package/clis/lesswrong/tags.js +1 -0
- package/clis/lesswrong/top-month.js +1 -0
- package/clis/lesswrong/top-week.js +1 -0
- package/clis/lesswrong/top-year.js +1 -0
- package/clis/lesswrong/top.js +1 -0
- package/clis/lesswrong/user-posts.js +1 -0
- package/clis/lesswrong/user.js +1 -0
- 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 +108 -10
- package/clis/linkedin/search.test.js +222 -0
- package/clis/linkedin/timeline.js +1 -0
- package/clis/linux-do/categories.js +1 -0
- package/clis/linux-do/feed.js +3 -5
- package/clis/linux-do/feed.test.js +35 -0
- package/clis/linux-do/search.js +1 -0
- package/clis/linux-do/tags.js +2 -1
- package/clis/linux-do/topic-content.js +1 -0
- package/clis/linux-do/topic.js +1 -0
- package/clis/linux-do/user-posts.js +1 -0
- package/clis/linux-do/user-topics.js +1 -0
- package/clis/lobsters/active.js +4 -1
- package/clis/lobsters/domain.js +92 -0
- package/clis/lobsters/hot.js +4 -1
- package/clis/lobsters/lobsters.test.js +169 -0
- package/clis/lobsters/newest.js +4 -1
- package/clis/lobsters/read.js +196 -0
- package/clis/lobsters/tag.js +4 -1
- package/clis/maimai/search-talents.js +1 -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/feed.js +1 -0
- package/clis/medium/search.js +1 -0
- package/clis/medium/tag.js +135 -0
- package/clis/medium/user.js +1 -0
- package/clis/mubu/doc.js +1 -0
- package/clis/mubu/docs.js +1 -0
- package/clis/mubu/notes.js +1 -0
- package/clis/mubu/recent.js +1 -0
- package/clis/mubu/search.js +1 -0
- package/clis/notebooklm/current.js +1 -0
- package/clis/notebooklm/get.js +1 -0
- package/clis/notebooklm/history.js +1 -0
- package/clis/notebooklm/list.js +1 -0
- package/clis/notebooklm/note-list.js +1 -0
- package/clis/notebooklm/notes-get.js +1 -0
- package/clis/notebooklm/open.js +1 -0
- package/clis/notebooklm/source-fulltext.js +1 -0
- package/clis/notebooklm/source-get.js +1 -0
- package/clis/notebooklm/source-guide.js +1 -0
- package/clis/notebooklm/source-list.js +1 -0
- package/clis/notebooklm/status.js +1 -0
- package/clis/notebooklm/summary.js +1 -0
- package/clis/notion/export.js +1 -0
- package/clis/notion/favorites.js +1 -0
- package/clis/notion/new.js +1 -0
- package/clis/notion/read.js +1 -0
- package/clis/notion/search.js +1 -0
- package/clis/notion/sidebar.js +1 -0
- package/clis/notion/status.js +1 -0
- package/clis/notion/write.js +1 -0
- package/clis/nowcoder/companies.js +1 -0
- package/clis/nowcoder/creators.js +1 -0
- package/clis/nowcoder/detail.js +1 -0
- package/clis/nowcoder/experience.js +1 -0
- package/clis/nowcoder/hot.js +1 -0
- package/clis/nowcoder/jobs.js +1 -0
- package/clis/nowcoder/notifications.js +1 -0
- package/clis/nowcoder/papers.js +1 -0
- package/clis/nowcoder/practice.js +1 -0
- package/clis/nowcoder/recommend.js +1 -0
- package/clis/nowcoder/referral.js +1 -0
- package/clis/nowcoder/salary.js +1 -0
- package/clis/nowcoder/search.js +1 -0
- package/clis/nowcoder/suggest.js +1 -0
- package/clis/nowcoder/topics.js +1 -0
- package/clis/nowcoder/trending.js +1 -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/ones/login.js +1 -0
- package/clis/ones/logout.js +1 -0
- package/clis/ones/me.js +1 -0
- package/clis/ones/my-tasks.js +1 -0
- package/clis/ones/task.js +1 -0
- package/clis/ones/tasks.js +1 -0
- package/clis/ones/token-info.js +1 -0
- package/clis/ones/worklog.js +1 -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/openreview/openreview.test.js +345 -0
- package/clis/openreview/paper.js +43 -0
- package/clis/openreview/reviews.js +131 -0
- package/clis/openreview/search.js +46 -0
- package/clis/openreview/utils.js +158 -0
- package/clis/openreview/venue.js +63 -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 +2 -1
- package/clis/paperreview/review.js +2 -1
- package/clis/paperreview/submit.js +2 -1
- package/clis/pixiv/detail.js +1 -0
- package/clis/pixiv/download.js +1 -0
- package/clis/pixiv/download.test.js +1 -1
- package/clis/pixiv/illusts.js +2 -1
- package/clis/pixiv/illusts.test.js +1 -1
- package/clis/pixiv/ranking.js +2 -1
- package/clis/pixiv/search.js +2 -1
- package/clis/pixiv/search.test.js +1 -1
- package/clis/pixiv/user.js +2 -0
- package/clis/powerchina/search.js +1 -0
- package/clis/producthunt/browse.js +1 -0
- package/clis/producthunt/hot.js +1 -0
- package/clis/producthunt/posts.js +1 -0
- package/clis/producthunt/today.js +1 -0
- 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/ls.js +1 -0
- package/clis/quark/mkdir.js +1 -0
- package/clis/quark/mv.js +2 -1
- package/clis/quark/rename.js +1 -0
- package/clis/quark/rm.js +1 -0
- package/clis/quark/save.js +2 -1
- package/clis/quark/share-tree.js +1 -0
- 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/reddit/comment.js +1 -0
- package/clis/reddit/frontpage.js +1 -0
- package/clis/reddit/hot.js +6 -1
- package/clis/reddit/hot.test.js +18 -0
- package/clis/reddit/popular.js +1 -0
- package/clis/reddit/read.js +1 -0
- package/clis/reddit/save.js +1 -0
- package/clis/reddit/saved.js +1 -0
- package/clis/reddit/search.js +1 -0
- package/clis/reddit/subreddit.js +1 -0
- package/clis/reddit/subscribe.js +1 -0
- package/clis/reddit/upvote.js +1 -0
- package/clis/reddit/upvoted.js +1 -0
- package/clis/reddit/user-comments.js +1 -0
- package/clis/reddit/user-posts.js +1 -0
- package/clis/reddit/user.js +1 -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 +46 -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/sinablog/article.js +1 -0
- package/clis/sinablog/hot.js +1 -0
- package/clis/sinablog/search.js +1 -0
- package/clis/sinablog/user.js +1 -0
- package/clis/sinafinance/news.js +1 -0
- package/clis/sinafinance/rolling-news.js +1 -0
- package/clis/sinafinance/stock-rank.js +1 -0
- package/clis/sinafinance/stock.js +1 -0
- package/clis/smzdm/search.js +1 -0
- package/clis/spotify/spotify.js +11 -0
- package/clis/stackoverflow/bounties.js +11 -3
- package/clis/stackoverflow/hot.js +10 -2
- package/clis/stackoverflow/read.js +314 -0
- package/clis/stackoverflow/related.js +66 -0
- package/clis/stackoverflow/search.js +10 -2
- package/clis/stackoverflow/stackoverflow.test.js +404 -0
- package/clis/stackoverflow/tag.js +60 -0
- package/clis/stackoverflow/unanswered.js +9 -2
- 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/top-sellers.js +1 -0
- package/clis/steam/utils.js +107 -0
- package/clis/substack/feed.js +1 -0
- package/clis/substack/publication.js +1 -0
- package/clis/substack/search.js +1 -0
- package/clis/taobao/add-cart.js +1 -0
- package/clis/taobao/cart.js +1 -0
- package/clis/taobao/commands.test.js +1 -24
- package/clis/taobao/detail.js +1 -0
- package/clis/taobao/reviews.js +1 -0
- package/clis/taobao/search.js +1 -0
- package/clis/tdx/hot-rank.js +1 -0
- package/clis/test-utils.js +61 -0
- package/clis/ths/hot-rank.js +1 -0
- package/clis/tieba/hot.js +2 -2
- package/clis/tieba/posts.js +1 -0
- package/clis/tieba/read.js +1 -0
- package/clis/tieba/search.js +2 -1
- package/clis/tiktok/comment.js +128 -40
- package/clis/tiktok/creator-videos.js +270 -0
- package/clis/tiktok/creator-videos.test.js +113 -0
- package/clis/tiktok/explore.js +138 -29
- package/clis/tiktok/follow.js +116 -33
- package/clis/tiktok/following.js +157 -35
- package/clis/tiktok/friends.js +140 -37
- package/clis/tiktok/like.js +1 -0
- package/clis/tiktok/live.js +138 -41
- package/clis/tiktok/notifications.js +142 -38
- package/clis/tiktok/profile.js +1 -0
- package/clis/tiktok/refactor.test.js +389 -0
- package/clis/tiktok/save.js +1 -0
- package/clis/tiktok/search.js +1 -0
- package/clis/tiktok/unfollow.js +125 -38
- package/clis/tiktok/unlike.js +1 -0
- package/clis/tiktok/unsave.js +1 -0
- package/clis/tiktok/user.js +204 -29
- package/clis/tiktok/utils.js +505 -0
- package/clis/tiktok/write-refactor.test.js +370 -0
- package/clis/toutiao/articles.js +37 -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 +2 -1
- package/clis/twitter/article.js +1 -0
- package/clis/twitter/block.js +1 -0
- package/clis/twitter/bookmark.js +1 -0
- package/clis/twitter/bookmarks.js +2 -1
- package/clis/twitter/delete.js +1 -0
- package/clis/twitter/download.js +1 -0
- package/clis/twitter/follow.js +1 -0
- package/clis/twitter/followers.js +135 -69
- package/clis/twitter/following.js +1 -0
- package/clis/twitter/hide-reply.js +1 -0
- package/clis/twitter/like.js +1 -0
- package/clis/twitter/likes.js +2 -1
- package/clis/twitter/list-add.js +1 -0
- package/clis/twitter/list-remove.js +1 -0
- package/clis/twitter/list-tweets.js +1 -0
- package/clis/twitter/lists.js +1 -0
- package/clis/twitter/notifications.js +1 -0
- package/clis/twitter/post.js +1 -0
- package/clis/twitter/profile.js +1 -0
- package/clis/twitter/reply-dm.js +2 -1
- package/clis/twitter/reply.js +1 -0
- package/clis/twitter/reply.test.js +1 -29
- package/clis/twitter/search.js +1 -0
- package/clis/twitter/thread.js +1 -0
- package/clis/twitter/timeline.js +1 -0
- package/clis/twitter/trending.js +11 -12
- package/clis/twitter/trending.test.js +15 -0
- package/clis/twitter/tweets.js +2 -1
- package/clis/twitter/tweets.test.js +2 -2
- package/clis/twitter/unblock.js +1 -0
- package/clis/twitter/unbookmark.js +1 -0
- package/clis/twitter/unfollow.js +1 -0
- package/clis/uisdc/news.js +105 -0
- package/clis/uisdc/news.test.js +66 -0
- package/clis/uiverse/code.js +1 -0
- package/clis/uiverse/preview.js +1 -0
- package/clis/v2ex/daily.js +1 -0
- package/clis/v2ex/hot.js +1 -0
- package/clis/v2ex/latest.js +1 -0
- package/clis/v2ex/me.js +1 -0
- package/clis/v2ex/member.js +1 -0
- package/clis/v2ex/node.js +1 -0
- package/clis/v2ex/nodes.js +1 -0
- package/clis/v2ex/notifications.js +1 -0
- package/clis/v2ex/replies.js +1 -0
- package/clis/v2ex/topic.js +1 -0
- package/clis/v2ex/user.js +1 -0
- package/clis/wanfang/search.js +1 -1
- package/clis/web/read.js +48 -17
- package/clis/web/read.test.js +101 -1
- package/clis/weibo/comments.js +1 -0
- package/clis/weibo/favorites.js +1 -0
- package/clis/weibo/feed.js +3 -1
- package/clis/weibo/hot.js +1 -0
- package/clis/weibo/me.js +1 -0
- package/clis/weibo/post.js +1 -0
- package/clis/weibo/publish.js +1 -0
- package/clis/weibo/search.js +8 -2
- package/clis/weibo/user.js +1 -0
- package/clis/weixin/create-draft.js +2 -1
- package/clis/weixin/download.js +1 -0
- package/clis/weixin/drafts.js +2 -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/weread/ai-outline.js +1 -0
- package/clis/weread/book.js +1 -0
- package/clis/weread/highlights.js +1 -0
- package/clis/weread/notebooks.js +1 -0
- package/clis/weread/notes.js +1 -0
- package/clis/weread/ranking.js +1 -0
- package/clis/weread/search.js +1 -0
- package/clis/weread/shelf.js +1 -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/wikipedia/random.js +1 -0
- package/clis/wikipedia/search.js +1 -0
- package/clis/wikipedia/summary.js +1 -0
- package/clis/wikipedia/trending.js +1 -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 +17 -4
- package/clis/xianyu/chat.test.js +64 -0
- package/clis/xianyu/item.js +1 -0
- package/clis/xianyu/publish.js +485 -0
- package/clis/xianyu/publish.test.js +220 -0
- package/clis/xianyu/search.js +1 -0
- package/clis/xiaoe/catalog.js +105 -39
- package/clis/xiaoe/content.js +165 -29
- package/clis/xiaoe/courses.js +86 -28
- package/clis/xiaoe/detail.js +1 -0
- package/clis/xiaoe/play-url.js +1 -0
- package/clis/xiaoe/xiaoe.test.js +486 -0
- package/clis/xiaohongshu/comments.js +1 -0
- package/clis/xiaohongshu/creator-note-detail.js +1 -0
- package/clis/xiaohongshu/creator-notes-summary.js +2 -1
- package/clis/xiaohongshu/creator-notes.js +1 -0
- package/clis/xiaohongshu/creator-profile.js +1 -0
- package/clis/xiaohongshu/creator-stats.js +1 -0
- package/clis/xiaohongshu/download.js +1 -0
- package/clis/xiaohongshu/feed.js +2 -1
- package/clis/xiaohongshu/note.js +1 -0
- package/clis/xiaohongshu/notifications.js +1 -0
- package/clis/xiaohongshu/publish.js +17 -3
- package/clis/xiaohongshu/publish.test.js +46 -1
- package/clis/xiaohongshu/search.js +1 -0
- package/clis/xiaohongshu/user.js +1 -0
- package/clis/xiaoyuzhou/download.js +1 -0
- package/clis/xiaoyuzhou/episode.js +1 -0
- package/clis/xiaoyuzhou/podcast-episodes.js +1 -0
- package/clis/xiaoyuzhou/podcast.js +1 -0
- package/clis/xiaoyuzhou/transcript.js +1 -0
- package/clis/xueqiu/comments.js +1 -0
- package/clis/xueqiu/earnings-date.js +1 -0
- package/clis/xueqiu/feed.js +1 -0
- package/clis/xueqiu/fund-holdings.js +1 -0
- package/clis/xueqiu/fund-snapshot.js +1 -0
- package/clis/xueqiu/groups.js +1 -0
- package/clis/xueqiu/hot-stock.js +1 -0
- package/clis/xueqiu/hot.js +1 -0
- package/clis/xueqiu/kline.js +1 -0
- package/clis/xueqiu/search.js +1 -0
- package/clis/xueqiu/stock.js +1 -0
- package/clis/xueqiu/watchlist.js +1 -0
- package/clis/yahoo-finance/quote.js +1 -0
- package/clis/yollomi/background.js +1 -0
- package/clis/yollomi/edit.js +1 -0
- package/clis/yollomi/face-swap.js +1 -0
- package/clis/yollomi/generate.js +1 -0
- package/clis/yollomi/models.js +1 -0
- package/clis/yollomi/object-remover.js +1 -0
- package/clis/yollomi/remove-bg.js +1 -0
- package/clis/yollomi/restore.js +1 -0
- package/clis/yollomi/try-on.js +1 -0
- package/clis/yollomi/upload.js +1 -0
- package/clis/yollomi/upscale.js +1 -0
- package/clis/yollomi/video.js +1 -0
- package/clis/youtube/channel.js +1 -0
- package/clis/youtube/comments.js +1 -0
- package/clis/youtube/feed.js +8 -7
- package/clis/youtube/feed.test.js +131 -0
- package/clis/youtube/history.js +1 -0
- package/clis/youtube/like.js +1 -0
- package/clis/youtube/playlist.js +1 -0
- package/clis/youtube/search.js +1 -0
- package/clis/youtube/subscribe.js +1 -0
- package/clis/youtube/subscriptions.js +1 -0
- package/clis/youtube/transcript.js +14 -19
- package/clis/youtube/transcript.test.js +17 -0
- package/clis/youtube/unlike.js +1 -0
- package/clis/youtube/unsubscribe.js +1 -0
- package/clis/youtube/video.js +1 -0
- package/clis/youtube/watch-later.js +1 -0
- package/clis/yuanbao/ask.js +18 -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 +2 -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/zhihu/answer.js +1 -0
- package/clis/zhihu/collection.js +1 -0
- package/clis/zhihu/collections.js +1 -0
- package/clis/zhihu/comment.js +1 -0
- package/clis/zhihu/download.js +1 -0
- package/clis/zhihu/favorite.js +1 -0
- package/clis/zhihu/follow.js +1 -0
- package/clis/zhihu/hot.js +1 -0
- package/clis/zhihu/like.js +1 -0
- package/clis/zhihu/question.js +1 -0
- package/clis/zhihu/search.js +1 -0
- package/clis/zlibrary/commands.test.js +1 -11
- package/clis/zlibrary/info.js +1 -0
- package/clis/zlibrary/search.js +1 -0
- package/clis/zsxq/dynamics.js +1 -0
- package/clis/zsxq/groups.js +1 -0
- package/clis/zsxq/search.js +1 -0
- package/clis/zsxq/topic.js +1 -0
- package/clis/zsxq/topics.js +1 -0
- package/dist/src/adapter-source.test.js +1 -1
- package/dist/src/browser/analyze.test.js +2 -0
- package/dist/src/browser/base-page.d.ts +18 -0
- package/dist/src/browser/base-page.js +116 -4
- package/dist/src/browser/base-page.test.js +108 -0
- package/dist/src/browser/cdp.d.ts +1 -0
- package/dist/src/browser/cdp.js +57 -9
- package/dist/src/browser/cdp.test.js +3 -0
- 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 +2 -1
- package/dist/src/browser/page.js +9 -1
- package/dist/src/browser/page.test.js +46 -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 +35 -3
- package/dist/src/browser/target-resolver.js +59 -10
- package/dist/src/browser/verify-fixture.d.ts +6 -1
- package/dist/src/browser/verify-fixture.js +87 -0
- package/dist/src/browser/verify-fixture.test.js +44 -1
- package/dist/src/build-manifest.js +12 -4
- package/dist/src/build-manifest.test.js +20 -20
- package/dist/src/capabilityRouting.d.ts +16 -1
- package/dist/src/capabilityRouting.js +24 -1
- package/dist/src/capabilityRouting.test.js +20 -2
- package/dist/src/cli.js +213 -12
- package/dist/src/cli.test.js +329 -0
- package/dist/src/commanderAdapter.d.ts +1 -1
- package/dist/src/commanderAdapter.js +17 -12
- package/dist/src/commanderAdapter.test.js +7 -7
- package/dist/src/convention-audit.d.ts +50 -0
- package/dist/src/convention-audit.js +546 -0
- package/dist/src/convention-audit.test.d.ts +1 -0
- package/dist/src/convention-audit.test.js +226 -0
- package/dist/src/discovery.js +4 -5
- package/dist/src/doctor.js +0 -1
- package/dist/src/doctor.test.js +1 -1
- package/dist/src/engine.test.js +10 -10
- 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 +334 -25
- package/dist/src/help.d.ts +36 -0
- package/dist/src/help.js +171 -0
- package/dist/src/help.test.d.ts +1 -0
- package/dist/src/help.test.js +54 -0
- package/dist/src/main.js +27 -8
- package/dist/src/manifest-types.d.ts +7 -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/plugin.test.js +26 -26
- package/dist/src/registry-api.d.ts +1 -1
- package/dist/src/registry.d.ts +17 -11
- package/dist/src/registry.js +24 -6
- package/dist/src/registry.test.js +29 -22
- package/dist/src/runtime.d.ts +2 -1
- package/dist/src/runtime.js +1 -1
- package/dist/src/serialization.d.ts +6 -2
- package/dist/src/serialization.js +31 -7
- package/dist/src/serialization.test.js +41 -2
- package/dist/src/types.d.ts +19 -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 +4 -1
- package/scripts/check-listing-id-pairing.mjs +193 -0
- package/scripts/check-silent-column-drop.mjs +105 -0
- package/scripts/check-typed-error-lint.mjs +118 -0
- package/scripts/fetch-adapters.js +1 -1
- package/scripts/silent-column-drop-baseline.json +962 -0
- package/scripts/typed-error-lint-baseline.json +1514 -0
- package/clis/ctrip/search.test.js +0 -64
- package/clis/gov-policy/commands.test.js +0 -27
- package/clis/linux-do/category.js +0 -36
- package/clis/linux-do/hot.js +0 -25
- package/clis/linux-do/latest.js +0 -18
- 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
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as os from 'node:os';
|
|
4
|
+
import * as path from 'node:path';
|
|
5
|
+
import { renderConventionAuditText, runConventionAudit } from './convention-audit.js';
|
|
6
|
+
describe('convention audit', () => {
|
|
7
|
+
const tempDirs = [];
|
|
8
|
+
afterEach(() => {
|
|
9
|
+
for (const dir of tempDirs.splice(0)) {
|
|
10
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
function makeProject(manifest, files) {
|
|
14
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'opencli-convention-audit-'));
|
|
15
|
+
tempDirs.push(root);
|
|
16
|
+
fs.mkdirSync(path.join(root, 'clis'), { recursive: true });
|
|
17
|
+
fs.writeFileSync(path.join(root, 'cli-manifest.json'), JSON.stringify(manifest, null, 2));
|
|
18
|
+
for (const [relative, content] of Object.entries(files)) {
|
|
19
|
+
const file = path.join(root, 'clis', relative);
|
|
20
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
21
|
+
fs.writeFileSync(file, content);
|
|
22
|
+
}
|
|
23
|
+
return root;
|
|
24
|
+
}
|
|
25
|
+
it('reports column, metadata, typed-error, and write-pair violations', () => {
|
|
26
|
+
const root = makeProject([
|
|
27
|
+
{
|
|
28
|
+
site: 'demo',
|
|
29
|
+
name: 'search',
|
|
30
|
+
access: 'read',
|
|
31
|
+
columns: ['id', 'title', 'authorName'],
|
|
32
|
+
sourceFile: 'demo/search.js',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
site: 'demo',
|
|
36
|
+
name: 'like',
|
|
37
|
+
access: 'write',
|
|
38
|
+
sourceFile: 'demo/like.js',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
site: 'demo',
|
|
42
|
+
name: 'missing',
|
|
43
|
+
columns: [],
|
|
44
|
+
sourceFile: 'demo/missing.js',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
site: 'clean',
|
|
48
|
+
name: 'search',
|
|
49
|
+
access: 'read',
|
|
50
|
+
columns: ['id', 'title'],
|
|
51
|
+
sourceFile: 'clean/search.js',
|
|
52
|
+
},
|
|
53
|
+
], {
|
|
54
|
+
'demo/search.js': `
|
|
55
|
+
export async function run(kwargs) {
|
|
56
|
+
const limit = Math.min(kwargs.limit, 100);
|
|
57
|
+
try {
|
|
58
|
+
await fetch('/items');
|
|
59
|
+
} catch {
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
rows.push({
|
|
63
|
+
id: item.id,
|
|
64
|
+
title: item.title ?? 'unknown',
|
|
65
|
+
url: item.url,
|
|
66
|
+
authorName: item.authorName,
|
|
67
|
+
});
|
|
68
|
+
return limit;
|
|
69
|
+
}
|
|
70
|
+
`,
|
|
71
|
+
'demo/like.js': 'export async function run() { return { ok: true }; }',
|
|
72
|
+
'demo/missing.js': 'export async function run() { return { ok: true }; }',
|
|
73
|
+
'clean/search.js': 'export async function run() { rows.push({ id: item.id, title: item.title }); }',
|
|
74
|
+
});
|
|
75
|
+
const report = runConventionAudit({ projectRoot: root });
|
|
76
|
+
const category = (rule) => report.categories.find((item) => item.rule === rule);
|
|
77
|
+
expect(report.ok).toBe(false);
|
|
78
|
+
expect(category('silent-column-drop').violations[0]).toMatchObject({
|
|
79
|
+
command: 'demo/search',
|
|
80
|
+
details: expect.objectContaining({ missing: ['url'] }),
|
|
81
|
+
});
|
|
82
|
+
expect(category('camelCase-in-columns').violations[0]).toMatchObject({
|
|
83
|
+
command: 'demo/search',
|
|
84
|
+
details: { column: 'authorName' },
|
|
85
|
+
});
|
|
86
|
+
expect(category('missing-access-metadata').violations[0]).toMatchObject({ command: 'demo/missing' });
|
|
87
|
+
expect(category('silent-clamp').violations[0]).toMatchObject({ command: 'demo/search' });
|
|
88
|
+
expect(category('silent-empty-fallback').violations[0]).toMatchObject({ command: 'demo/search' });
|
|
89
|
+
expect(category('silent-sentinel').violations[0]).toMatchObject({ command: 'demo/search' });
|
|
90
|
+
expect(category('write-without-delete-pair').violations[0]).toMatchObject({
|
|
91
|
+
command: 'demo/like',
|
|
92
|
+
details: { expected_any_of: ['unlike'] },
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
it('supports site and command target filters', () => {
|
|
96
|
+
const root = makeProject([
|
|
97
|
+
{ site: 'demo', name: 'search', access: 'read', columns: ['id'], sourceFile: 'demo/search.js' },
|
|
98
|
+
{ site: 'other', name: 'search', access: 'read', columns: ['id'], sourceFile: 'other/search.js' },
|
|
99
|
+
], {
|
|
100
|
+
'demo/search.js': 'export async function run() { rows.push({ id: 1, hidden: true }); }',
|
|
101
|
+
'other/search.js': 'export async function run() { rows.push({ id: 1, hidden: true }); }',
|
|
102
|
+
});
|
|
103
|
+
expect(runConventionAudit({ projectRoot: root, site: 'demo' }).summary.commands).toBe(1);
|
|
104
|
+
expect(runConventionAudit({ projectRoot: root, target: 'other/search' }).summary.commands).toBe(1);
|
|
105
|
+
expect(runConventionAudit({ projectRoot: root, target: 'missing' }).summary.commands).toBe(0);
|
|
106
|
+
});
|
|
107
|
+
it('renders a compact text report', () => {
|
|
108
|
+
const root = makeProject([
|
|
109
|
+
{ site: 'demo', name: 'search', access: 'read', columns: ['id'], sourceFile: 'demo/search.js' },
|
|
110
|
+
], {
|
|
111
|
+
'demo/search.js': 'export async function run() { rows.push({ id: 1 }); }',
|
|
112
|
+
});
|
|
113
|
+
const text = renderConventionAuditText(runConventionAudit({ projectRoot: root }));
|
|
114
|
+
expect(text).toContain('Convention Audit Report');
|
|
115
|
+
expect(text).toContain('OK - no convention violations found.');
|
|
116
|
+
});
|
|
117
|
+
it('scans pipeline map blocks for silent column drops', () => {
|
|
118
|
+
const root = makeProject([
|
|
119
|
+
{ site: 'demo', name: 'feed', access: 'read', columns: ['id', 'title'], sourceFile: 'demo/feed.js' },
|
|
120
|
+
], {
|
|
121
|
+
'demo/feed.js': `
|
|
122
|
+
cli({
|
|
123
|
+
site: 'demo',
|
|
124
|
+
name: 'feed',
|
|
125
|
+
access: 'read',
|
|
126
|
+
columns: ['id', 'title'],
|
|
127
|
+
pipeline: [
|
|
128
|
+
{ map: {
|
|
129
|
+
id: '\${{ item.id }}',
|
|
130
|
+
title: '\${{ item.title }}',
|
|
131
|
+
url: '\${{ item.url }}',
|
|
132
|
+
} },
|
|
133
|
+
],
|
|
134
|
+
});
|
|
135
|
+
`,
|
|
136
|
+
});
|
|
137
|
+
const report = runConventionAudit({ projectRoot: root });
|
|
138
|
+
const violations = report.categories.find((item) => item.rule === 'silent-column-drop').violations;
|
|
139
|
+
expect(violations[0]).toMatchObject({
|
|
140
|
+
command: 'demo/feed',
|
|
141
|
+
details: expect.objectContaining({ missing: ['url'] }),
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
it('ignores ok:false diagnostic objects when checking emitted rows', () => {
|
|
145
|
+
const root = makeProject([
|
|
146
|
+
{ site: 'demo', name: 'search', access: 'read', columns: ['id', 'url'], sourceFile: 'demo/search.js' },
|
|
147
|
+
], {
|
|
148
|
+
'demo/search.js': `
|
|
149
|
+
export async function run() {
|
|
150
|
+
if (!document.querySelector('.items')) {
|
|
151
|
+
return { ok: false, bodyLen: document.body.innerText.length, sample: document.body.innerText.slice(0, 800), url: location.href };
|
|
152
|
+
}
|
|
153
|
+
return rows.map((row) => ({ id: row.id, url: row.url }));
|
|
154
|
+
}
|
|
155
|
+
`,
|
|
156
|
+
});
|
|
157
|
+
const report = runConventionAudit({ projectRoot: root });
|
|
158
|
+
const violations = report.categories.find((item) => item.rule === 'silent-column-drop').violations;
|
|
159
|
+
expect(violations).toEqual([]);
|
|
160
|
+
});
|
|
161
|
+
it('ignores raw intermediate keys when a final mapper converts them into columns', () => {
|
|
162
|
+
const root = makeProject([
|
|
163
|
+
{
|
|
164
|
+
site: 'demo',
|
|
165
|
+
name: 'search',
|
|
166
|
+
access: 'read',
|
|
167
|
+
columns: ['id', 'rating', 'reviews', 'price'],
|
|
168
|
+
sourceFile: 'demo/search.js',
|
|
169
|
+
},
|
|
170
|
+
], {
|
|
171
|
+
'demo/search.js': `
|
|
172
|
+
export async function run() {
|
|
173
|
+
rows.push({
|
|
174
|
+
id: item.id,
|
|
175
|
+
starClass: item.starClass,
|
|
176
|
+
reviewsRaw: item.reviewsRaw,
|
|
177
|
+
priceRaw: item.priceRaw,
|
|
178
|
+
});
|
|
179
|
+
return rows.map((r) => ({
|
|
180
|
+
id: r.id,
|
|
181
|
+
rating: r.starClass ? Number(r.starClass) / 10 : null,
|
|
182
|
+
reviews: parseReviewCount(r.reviewsRaw),
|
|
183
|
+
price: parsePrice(r.priceRaw),
|
|
184
|
+
}));
|
|
185
|
+
}
|
|
186
|
+
`,
|
|
187
|
+
});
|
|
188
|
+
const report = runConventionAudit({ projectRoot: root });
|
|
189
|
+
const violations = report.categories.find((item) => item.rule === 'silent-column-drop').violations;
|
|
190
|
+
expect(violations).toEqual([]);
|
|
191
|
+
});
|
|
192
|
+
it('still reports raw keys emitted directly without a final mapper', () => {
|
|
193
|
+
const root = makeProject([
|
|
194
|
+
{ site: 'demo', name: 'search', access: 'read', columns: ['id', 'title'], sourceFile: 'demo/search.js' },
|
|
195
|
+
], {
|
|
196
|
+
'demo/search.js': `
|
|
197
|
+
export async function run() {
|
|
198
|
+
rows.push({
|
|
199
|
+
id: item.id,
|
|
200
|
+
title: titleRaw,
|
|
201
|
+
titleRaw,
|
|
202
|
+
});
|
|
203
|
+
return rows;
|
|
204
|
+
}
|
|
205
|
+
`,
|
|
206
|
+
});
|
|
207
|
+
const report = runConventionAudit({ projectRoot: root });
|
|
208
|
+
const violations = report.categories.find((item) => item.rule === 'silent-column-drop').violations;
|
|
209
|
+
expect(violations[0]).toMatchObject({
|
|
210
|
+
command: 'demo/search',
|
|
211
|
+
details: expect.objectContaining({ missing: ['titleRaw'] }),
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
it('only reports empty array fallbacks inside catch blocks', () => {
|
|
215
|
+
const root = makeProject([
|
|
216
|
+
{ site: 'demo', name: 'guard', access: 'read', columns: ['id'], sourceFile: 'demo/guard.js' },
|
|
217
|
+
{ site: 'demo', name: 'catch', access: 'read', columns: ['id'], sourceFile: 'demo/catch.js' },
|
|
218
|
+
], {
|
|
219
|
+
'demo/guard.js': 'export async function run() { if (!store) return []; rows.push({ id: 1 }); }',
|
|
220
|
+
'demo/catch.js': 'export async function run() { try { await fetch("/"); } catch (err) { return []; } rows.push({ id: 1 }); }',
|
|
221
|
+
});
|
|
222
|
+
const report = runConventionAudit({ projectRoot: root });
|
|
223
|
+
const violations = report.categories.find((item) => item.rule === 'silent-empty-fallback').violations;
|
|
224
|
+
expect(violations.map((violation) => violation.command)).toEqual(['demo/catch']);
|
|
225
|
+
});
|
|
226
|
+
});
|
package/dist/src/discovery.js
CHANGED
|
@@ -124,17 +124,18 @@ async function loadFromManifest(manifestPath, clisDir) {
|
|
|
124
124
|
name: entry.name,
|
|
125
125
|
aliases: entry.aliases,
|
|
126
126
|
description: entry.description ?? '',
|
|
127
|
+
access: entry.access,
|
|
128
|
+
example: entry.example,
|
|
127
129
|
domain: entry.domain,
|
|
128
130
|
strategy: parseStrategy(entry.strategy),
|
|
129
131
|
browser: entry.browser,
|
|
130
132
|
args: entry.args ?? [],
|
|
131
133
|
columns: entry.columns,
|
|
134
|
+
defaultFormat: entry.defaultFormat,
|
|
132
135
|
pipeline: entry.pipeline,
|
|
133
|
-
timeoutSeconds: entry.timeout,
|
|
134
136
|
source: entry.sourceFile ? path.resolve(clisDir, entry.sourceFile) : modulePath,
|
|
135
|
-
deprecated: entry.deprecated,
|
|
136
|
-
replacedBy: entry.replacedBy,
|
|
137
137
|
navigateBefore: entry.navigateBefore,
|
|
138
|
+
browserSession: entry.browserSession,
|
|
138
139
|
_lazy: true,
|
|
139
140
|
_modulePath: modulePath,
|
|
140
141
|
};
|
|
@@ -168,7 +169,6 @@ async function discoverClisFromFs(dir) {
|
|
|
168
169
|
await Promise.all(files.map(async (file) => {
|
|
169
170
|
const filePath = path.join(siteDir, file);
|
|
170
171
|
if (file.endsWith('.yaml') || file.endsWith('.yml')) {
|
|
171
|
-
log.warn(`Ignoring YAML adapter ${filePath} — YAML format is no longer supported. Convert to JavaScript using cli() from '@jackwener/opencli/registry'.`);
|
|
172
172
|
return;
|
|
173
173
|
}
|
|
174
174
|
if (file.endsWith('.ts') && !file.endsWith('.d.ts') && !file.endsWith('.test.ts')) {
|
|
@@ -216,7 +216,6 @@ async function discoverPluginDir(dir, site) {
|
|
|
216
216
|
await Promise.all(files.map(async (file) => {
|
|
217
217
|
const filePath = path.join(dir, file);
|
|
218
218
|
if (file.endsWith('.yaml') || file.endsWith('.yml')) {
|
|
219
|
-
log.warn(`Ignoring YAML plugin ${filePath} — YAML format is no longer supported. Convert to JavaScript using cli() from '@jackwener/opencli/registry'.`);
|
|
220
219
|
return;
|
|
221
220
|
}
|
|
222
221
|
if (file.endsWith('.js') && !file.endsWith('.d.js')) {
|
package/dist/src/doctor.js
CHANGED
|
@@ -285,7 +285,6 @@ export function renderBrowserDoctorReport(report) {
|
|
|
285
285
|
}
|
|
286
286
|
else if (report.daemonRunning && report.extensionConnected) {
|
|
287
287
|
lines.push('', styleText('green', 'Everything looks good!'));
|
|
288
|
-
lines.push(styleText('dim', 'Tip: writing a new adapter? Run `opencli browser analyze <url>` for one-shot site recon.'));
|
|
289
288
|
}
|
|
290
289
|
return lines.join('\n');
|
|
291
290
|
}
|
package/dist/src/doctor.test.js
CHANGED
|
@@ -43,7 +43,7 @@ describe('doctor report rendering', () => {
|
|
|
43
43
|
expect(text).toContain('(v1.7.9)');
|
|
44
44
|
expect(text).toContain('[OK] Extension: connected (v1.6.8)');
|
|
45
45
|
expect(text).toContain('Everything looks good!');
|
|
46
|
-
expect(text).toContain('opencli browser analyze <url>');
|
|
46
|
+
expect(text).not.toContain('opencli browser analyze <url>');
|
|
47
47
|
});
|
|
48
48
|
it('renders a warning when daemon version is stale', () => {
|
|
49
49
|
const text = strip(renderBrowserDoctorReport({
|
package/dist/src/engine.test.js
CHANGED
|
@@ -27,7 +27,7 @@ export const helper = true;
|
|
|
27
27
|
import { cli, Strategy } from '${pathToFileURL(path.join(process.cwd(), 'src', 'registry.ts')).href}';
|
|
28
28
|
cli({
|
|
29
29
|
site: 'temp-site',
|
|
30
|
-
name: 'hello',
|
|
30
|
+
name: 'hello', access: 'read',
|
|
31
31
|
description: 'hello command',
|
|
32
32
|
strategy: Strategy.PUBLIC,
|
|
33
33
|
browser: false,
|
|
@@ -57,7 +57,7 @@ cli({
|
|
|
57
57
|
import { cli, Strategy } from '${pathToFileURL(path.join(process.cwd(), 'src', 'registry.ts')).href}';
|
|
58
58
|
cli({
|
|
59
59
|
site: 'fallback-site',
|
|
60
|
-
name: 'hello',
|
|
60
|
+
name: 'hello', access: 'read',
|
|
61
61
|
description: 'hello command',
|
|
62
62
|
strategy: Strategy.PUBLIC,
|
|
63
63
|
browser: false,
|
|
@@ -86,7 +86,7 @@ import { htmlToMarkdown } from '@jackwener/opencli/utils';
|
|
|
86
86
|
|
|
87
87
|
cli({
|
|
88
88
|
site: 'legacy-site',
|
|
89
|
-
name: 'hello',
|
|
89
|
+
name: 'hello', access: 'read',
|
|
90
90
|
description: 'hello command',
|
|
91
91
|
strategy: Strategy.PUBLIC,
|
|
92
92
|
browser: false,
|
|
@@ -204,7 +204,7 @@ describe('executeCommand', () => {
|
|
|
204
204
|
it('accepts kebab-case option names after Commander camelCases them', async () => {
|
|
205
205
|
const cmd = cli({
|
|
206
206
|
site: 'test-engine',
|
|
207
|
-
name: 'kebab-arg-test',
|
|
207
|
+
name: 'kebab-arg-test', access: 'read',
|
|
208
208
|
description: 'test command with kebab-case arg',
|
|
209
209
|
browser: false,
|
|
210
210
|
strategy: Strategy.PUBLIC,
|
|
@@ -219,7 +219,7 @@ describe('executeCommand', () => {
|
|
|
219
219
|
it('executes a command with func', async () => {
|
|
220
220
|
const cmd = cli({
|
|
221
221
|
site: 'test-engine',
|
|
222
|
-
name: 'func-test',
|
|
222
|
+
name: 'func-test', access: 'read',
|
|
223
223
|
description: 'test command with func',
|
|
224
224
|
browser: false,
|
|
225
225
|
strategy: Strategy.PUBLIC,
|
|
@@ -233,7 +233,7 @@ describe('executeCommand', () => {
|
|
|
233
233
|
it('executes a command with pipeline', async () => {
|
|
234
234
|
const cmd = cli({
|
|
235
235
|
site: 'test-engine',
|
|
236
|
-
name: 'pipe-test',
|
|
236
|
+
name: 'pipe-test', access: 'read',
|
|
237
237
|
description: 'test command with pipeline',
|
|
238
238
|
browser: false,
|
|
239
239
|
strategy: Strategy.PUBLIC,
|
|
@@ -248,7 +248,7 @@ describe('executeCommand', () => {
|
|
|
248
248
|
it('throws for command with no func or pipeline', async () => {
|
|
249
249
|
const cmd = cli({
|
|
250
250
|
site: 'test-engine',
|
|
251
|
-
name: 'empty-test',
|
|
251
|
+
name: 'empty-test', access: 'read',
|
|
252
252
|
description: 'empty command',
|
|
253
253
|
browser: false,
|
|
254
254
|
});
|
|
@@ -258,7 +258,7 @@ describe('executeCommand', () => {
|
|
|
258
258
|
let receivedDebug = false;
|
|
259
259
|
const cmd = cli({
|
|
260
260
|
site: 'test-engine',
|
|
261
|
-
name: 'debug-test',
|
|
261
|
+
name: 'debug-test', access: 'read',
|
|
262
262
|
description: 'debug test',
|
|
263
263
|
browser: false,
|
|
264
264
|
func: async (_kwargs, debug) => {
|
|
@@ -276,7 +276,7 @@ describe('executeCommand', () => {
|
|
|
276
276
|
});
|
|
277
277
|
const cmd = cli({
|
|
278
278
|
site: 'test-engine',
|
|
279
|
-
name: 'failing-test',
|
|
279
|
+
name: 'failing-test', access: 'read',
|
|
280
280
|
description: 'failing command',
|
|
281
281
|
browser: false,
|
|
282
282
|
strategy: Strategy.PUBLIC,
|
|
@@ -297,7 +297,7 @@ describe('executeCommand', () => {
|
|
|
297
297
|
.mockResolvedValue('http://127.0.0.1:9228');
|
|
298
298
|
const cmd = cli({
|
|
299
299
|
site: 'chatwise',
|
|
300
|
-
name: 'status',
|
|
300
|
+
name: 'status', access: 'read',
|
|
301
301
|
description: 'chatwise status',
|
|
302
302
|
browser: true,
|
|
303
303
|
strategy: Strategy.PUBLIC,
|
package/dist/src/errors.js
CHANGED
|
@@ -73,7 +73,7 @@ export class AuthRequiredError extends CliError {
|
|
|
73
73
|
}
|
|
74
74
|
export class TimeoutError extends CliError {
|
|
75
75
|
constructor(label, seconds, hint) {
|
|
76
|
-
super('TIMEOUT', `${label} timed out after ${seconds}s`, hint ?? 'Try again, or increase timeout with OPENCLI_BROWSER_COMMAND_TIMEOUT
|
|
76
|
+
super('TIMEOUT', `${label} timed out after ${seconds}s`, hint ?? 'Try again, or increase timeout with --timeout <seconds> (or OPENCLI_BROWSER_COMMAND_TIMEOUT for the global default)', EXIT_CODES.TEMPFAIL);
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
export class ArgumentError extends CliError {
|
package/dist/src/execution.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This is the single entry point for executing any CLI command. It handles:
|
|
5
5
|
* 1. Argument validation and coercion
|
|
6
6
|
* 2. Browser session lifecycle (if needed)
|
|
7
|
-
* 3. Domain pre-navigation for cookie
|
|
7
|
+
* 3. Domain pre-navigation for cookie strategies
|
|
8
8
|
* 4. Timeout enforcement
|
|
9
9
|
* 5. Lazy-loading of TS modules from manifest
|
|
10
10
|
* 6. Lifecycle hooks (onBeforeExecute / onAfterExecute)
|
package/dist/src/execution.js
CHANGED
|
@@ -4,13 +4,14 @@
|
|
|
4
4
|
* This is the single entry point for executing any CLI command. It handles:
|
|
5
5
|
* 1. Argument validation and coercion
|
|
6
6
|
* 2. Browser session lifecycle (if needed)
|
|
7
|
-
* 3. Domain pre-navigation for cookie
|
|
7
|
+
* 3. Domain pre-navigation for cookie strategies
|
|
8
8
|
* 4. Timeout enforcement
|
|
9
9
|
* 5. Lazy-loading of TS modules from manifest
|
|
10
10
|
* 6. Lifecycle hooks (onBeforeExecute / onAfterExecute)
|
|
11
11
|
*/
|
|
12
12
|
import { getRegistry, fullName, } from './registry.js';
|
|
13
13
|
import { pathToFileURL } from 'node:url';
|
|
14
|
+
import * as crypto from 'node:crypto';
|
|
14
15
|
import * as fs from 'node:fs';
|
|
15
16
|
import * as os from 'node:os';
|
|
16
17
|
import { executePipeline } from './pipeline/index.js';
|
|
@@ -28,6 +29,7 @@ const _loadedModules = new Map();
|
|
|
28
29
|
/** Track mtime of loaded user adapter files for hot-reload in daemon mode. */
|
|
29
30
|
const _moduleMtimes = new Map();
|
|
30
31
|
const _userClisDir = `${os.homedir()}/.opencli/clis/`;
|
|
32
|
+
const INTERACTIVE_BROWSER_IDLE_TIMEOUT_SECONDS = 600;
|
|
31
33
|
function normalizeTraceMode(raw) {
|
|
32
34
|
if (raw === undefined || raw === null || raw === '' || raw === 'off')
|
|
33
35
|
return 'off';
|
|
@@ -138,14 +140,37 @@ function resolvePreNav(cmd) {
|
|
|
138
140
|
// strategy → navigateBefore expansion already happened in normalizeCommand().
|
|
139
141
|
return null;
|
|
140
142
|
}
|
|
141
|
-
function
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
143
|
+
function urlMatchesDomain(url, domain) {
|
|
144
|
+
if (!url || !domain)
|
|
145
|
+
return false;
|
|
146
|
+
try {
|
|
147
|
+
const hostname = new URL(url).hostname;
|
|
148
|
+
return hostname === domain || hostname.endsWith(`.${domain}`);
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
function isDomainRootPreNav(preNavUrl, domain) {
|
|
155
|
+
if (!domain)
|
|
156
|
+
return false;
|
|
157
|
+
try {
|
|
158
|
+
const parsed = new URL(preNavUrl);
|
|
159
|
+
const hostnameMatches = parsed.hostname === domain || parsed.hostname.endsWith(`.${domain}`);
|
|
160
|
+
const rootPath = parsed.pathname === '' || parsed.pathname === '/';
|
|
161
|
+
return hostnameMatches && rootPath && parsed.search === '' && parsed.hash === '';
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
async function shouldRunPreNav(cmd, page, reuse, preNavUrl) {
|
|
168
|
+
if (reuse !== 'site' || !cmd.domain)
|
|
169
|
+
return true;
|
|
170
|
+
if (!isDomainRootPreNav(preNavUrl, cmd.domain))
|
|
171
|
+
return true;
|
|
172
|
+
const currentUrl = await page.getCurrentUrl?.().catch(() => null);
|
|
173
|
+
return !urlMatchesDomain(currentUrl, cmd.domain);
|
|
149
174
|
}
|
|
150
175
|
export async function executeCommand(cmd, rawKwargs, debug = false, opts = {}) {
|
|
151
176
|
let kwargs;
|
|
@@ -157,6 +182,7 @@ export async function executeCommand(cmd, rawKwargs, debug = false, opts = {}) {
|
|
|
157
182
|
throw err;
|
|
158
183
|
throw new ArgumentError(getErrorMessage(err));
|
|
159
184
|
}
|
|
185
|
+
const userTimeoutSec = readUserTimeoutSeconds(cmd, kwargs);
|
|
160
186
|
const traceMode = normalizeTraceMode(opts.trace);
|
|
161
187
|
const hookCtx = {
|
|
162
188
|
command: fullName(cmd),
|
|
@@ -183,17 +209,19 @@ export async function executeCommand(cmd, rawKwargs, debug = false, opts = {}) {
|
|
|
183
209
|
cdpEndpoint = await resolveElectronEndpoint(cmd.site);
|
|
184
210
|
}
|
|
185
211
|
}
|
|
186
|
-
ensureRequiredEnv(cmd);
|
|
187
212
|
const BrowserFactory = getBrowserFactory(cmd.site);
|
|
188
213
|
const contextId = resolveProfileContextId(opts.profile);
|
|
189
214
|
const internal = cmd;
|
|
215
|
+
const browserReuse = resolveBrowserSessionReuse(cmd);
|
|
216
|
+
const workspace = resolveBrowserWorkspace(cmd, browserReuse);
|
|
217
|
+
const idleTimeout = browserReuse === 'site' ? INTERACTIVE_BROWSER_IDLE_TIMEOUT_SECONDS : undefined;
|
|
190
218
|
result = await browserSession(BrowserFactory, async (page) => {
|
|
191
219
|
const observation = traceMode === 'off'
|
|
192
220
|
? null
|
|
193
221
|
: new ObservationSession({
|
|
194
222
|
scope: {
|
|
195
223
|
contextId,
|
|
196
|
-
workspace
|
|
224
|
+
workspace,
|
|
197
225
|
target: page.getActivePage?.(),
|
|
198
226
|
site: cmd.site,
|
|
199
227
|
command: fullName(cmd),
|
|
@@ -210,7 +238,7 @@ export async function executeCommand(cmd, rawKwargs, debug = false, opts = {}) {
|
|
|
210
238
|
await page.startNetworkCapture?.().catch(() => false);
|
|
211
239
|
}
|
|
212
240
|
const preNavUrl = resolvePreNav(cmd);
|
|
213
|
-
if (preNavUrl) {
|
|
241
|
+
if (preNavUrl && await shouldRunPreNav(cmd, page, browserReuse, preNavUrl)) {
|
|
214
242
|
observation?.record({
|
|
215
243
|
stream: 'action',
|
|
216
244
|
name: 'pre_navigate',
|
|
@@ -253,12 +281,15 @@ export async function executeCommand(cmd, rawKwargs, debug = false, opts = {}) {
|
|
|
253
281
|
throw wrapped;
|
|
254
282
|
}
|
|
255
283
|
}
|
|
256
|
-
// --live / OPENCLI_LIVE=1 keeps the automation
|
|
257
|
-
// command finishes, so agents (or humans) can inspect the page state.
|
|
258
|
-
const keepOpen = process.env.OPENCLI_LIVE === '1' || process.env.OPENCLI_LIVE === 'true';
|
|
284
|
+
// --live / OPENCLI_LIVE=1 keeps the current automation tab lease after
|
|
285
|
+
// the command finishes, so agents (or humans) can inspect the page state.
|
|
286
|
+
const keepOpen = browserReuse !== 'none' || process.env.OPENCLI_LIVE === '1' || process.env.OPENCLI_LIVE === 'true';
|
|
259
287
|
try {
|
|
288
|
+
const browserTimeout = userTimeoutSec !== null
|
|
289
|
+
? userTimeoutSec + RUNTIME_TIMEOUT_PADDING_SECONDS
|
|
290
|
+
: DEFAULT_BROWSER_COMMAND_TIMEOUT;
|
|
260
291
|
const result = await runWithTimeout(runCommand(cmd, page, kwargs, debug), {
|
|
261
|
-
timeout:
|
|
292
|
+
timeout: browserTimeout,
|
|
262
293
|
label: fullName(cmd),
|
|
263
294
|
});
|
|
264
295
|
observation?.record({
|
|
@@ -270,8 +301,9 @@ export async function executeCommand(cmd, rawKwargs, debug = false, opts = {}) {
|
|
|
270
301
|
await collectObservationEvidence(observation, page).catch(() => { });
|
|
271
302
|
exportTraceArtifact(observation, 'success', undefined, opts.onTraceExport);
|
|
272
303
|
}
|
|
273
|
-
// Adapter commands are one-shot —
|
|
274
|
-
// instead of waiting for the 30s idle timeout.
|
|
304
|
+
// Adapter commands are one-shot — release the current tab lease immediately
|
|
305
|
+
// instead of waiting for the 30s idle timeout. The automation container
|
|
306
|
+
// window stays open for reuse.
|
|
275
307
|
if (!keepOpen)
|
|
276
308
|
await page.closeWindow?.().catch(() => { });
|
|
277
309
|
return result;
|
|
@@ -294,23 +326,26 @@ export async function executeCommand(cmd, rawKwargs, debug = false, opts = {}) {
|
|
|
294
326
|
exportTraceArtifact(observation, 'failure', err, opts.onTraceExport);
|
|
295
327
|
}
|
|
296
328
|
}
|
|
297
|
-
//
|
|
298
|
-
//
|
|
299
|
-
//
|
|
329
|
+
// Release the tab lease on failure too — without this, the lease lingers
|
|
330
|
+
// until the extension's idle timer fires (unreliable on Windows where
|
|
331
|
+
// MV3 service workers may be suspended before setTimeout triggers).
|
|
300
332
|
if (!keepOpen)
|
|
301
333
|
await page.closeWindow?.().catch(() => { });
|
|
302
334
|
throw err;
|
|
303
335
|
}
|
|
304
|
-
}, { workspace
|
|
336
|
+
}, { workspace, cdpEndpoint, contextId, idleTimeout });
|
|
305
337
|
}
|
|
306
338
|
else {
|
|
307
|
-
// Non-browser commands:
|
|
308
|
-
|
|
309
|
-
|
|
339
|
+
// Non-browser commands: enforce a timeout only when the command exposes
|
|
340
|
+
// a `--timeout` arg (and the resolved value is positive). Without that
|
|
341
|
+
// arg there is no meaningful default — non-browser cmds are diverse
|
|
342
|
+
// enough that a hard cap would do more harm than good.
|
|
343
|
+
if (userTimeoutSec !== null) {
|
|
344
|
+
const ceiling = userTimeoutSec + RUNTIME_TIMEOUT_PADDING_SECONDS;
|
|
310
345
|
result = await runWithTimeout(runCommand(cmd, null, kwargs, debug), {
|
|
311
|
-
timeout,
|
|
346
|
+
timeout: ceiling,
|
|
312
347
|
label: fullName(cmd),
|
|
313
|
-
hint: `
|
|
348
|
+
hint: `Pass a higher --timeout value (currently ${userTimeoutSec}s)`,
|
|
314
349
|
});
|
|
315
350
|
}
|
|
316
351
|
else {
|
|
@@ -401,3 +436,52 @@ export function prepareCommandArgs(cmd, rawKwargs) {
|
|
|
401
436
|
cmd.validateArgs?.(kwargs);
|
|
402
437
|
return kwargs;
|
|
403
438
|
}
|
|
439
|
+
/**
|
|
440
|
+
* Runtime ceiling padding (seconds) added on top of the user's `--timeout`.
|
|
441
|
+
* The adapter's polling loop typically uses the full user value; the padding
|
|
442
|
+
* gives us room for the adapter to return + closeWindow + trace export before
|
|
443
|
+
* the runtime kills the Promise.
|
|
444
|
+
*/
|
|
445
|
+
const RUNTIME_TIMEOUT_PADDING_SECONDS = 30;
|
|
446
|
+
function readEnvBrowserSessionReuse() {
|
|
447
|
+
const raw = process.env.OPENCLI_BROWSER_REUSE;
|
|
448
|
+
if (raw === undefined || raw === '')
|
|
449
|
+
return null;
|
|
450
|
+
if (raw === 'none' || raw === 'site')
|
|
451
|
+
return raw;
|
|
452
|
+
throw new ArgumentError(`--reuse must be one of: none, site. Received: "${raw}"`);
|
|
453
|
+
}
|
|
454
|
+
function resolveBrowserSessionReuse(cmd) {
|
|
455
|
+
return readEnvBrowserSessionReuse() ?? cmd.browserSession?.reuse ?? 'none';
|
|
456
|
+
}
|
|
457
|
+
function resolveBrowserWorkspace(cmd, reuse) {
|
|
458
|
+
if (reuse === 'site')
|
|
459
|
+
return `site:${cmd.site}`;
|
|
460
|
+
return `site:${cmd.site}:${crypto.randomUUID()}`;
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Resolve the user-controllable `--timeout` arg, in seconds.
|
|
464
|
+
*
|
|
465
|
+
* Convention: a command opts into runtime-enforced timeouts by declaring an
|
|
466
|
+
* arg named `timeout`. The arg's `default` flows through `prepareCommandArgs`
|
|
467
|
+
* into `kwargs.timeout`, so by the time runtime enforcement runs, the value
|
|
468
|
+
* is the merged user-supplied-or-default seconds.
|
|
469
|
+
*
|
|
470
|
+
* Returns the parsed positive integer (seconds), or null if the command does
|
|
471
|
+
* not expose a `timeout` arg. Declaring `timeout` opts into runtime timeout
|
|
472
|
+
* enforcement, so invalid values must fail upfront instead of silently
|
|
473
|
+
* disabling the runtime ceiling.
|
|
474
|
+
*/
|
|
475
|
+
function readUserTimeoutSeconds(cmd, kwargs) {
|
|
476
|
+
if (!cmd.args.some(a => a.name === 'timeout'))
|
|
477
|
+
return null;
|
|
478
|
+
const raw = kwargs.timeout;
|
|
479
|
+
if (raw === undefined || raw === null || raw === '') {
|
|
480
|
+
throw new ArgumentError(`Argument "timeout" must be a positive integer. Received: "${String(raw)}"`);
|
|
481
|
+
}
|
|
482
|
+
const parsed = Number(raw);
|
|
483
|
+
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
484
|
+
throw new ArgumentError(`Argument "timeout" must be a positive integer. Received: "${String(raw)}"`);
|
|
485
|
+
}
|
|
486
|
+
return parsed;
|
|
487
|
+
}
|