@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
package/clis/zsxq/groups.js
CHANGED
package/clis/zsxq/search.js
CHANGED
package/clis/zsxq/topic.js
CHANGED
package/clis/zsxq/topics.js
CHANGED
|
@@ -19,10 +19,19 @@ export interface ResolveSuccess {
|
|
|
19
19
|
*/
|
|
20
20
|
match_level: TargetMatchLevel;
|
|
21
21
|
}
|
|
22
|
+
export interface FillTextResult extends ResolveSuccess {
|
|
23
|
+
filled: boolean;
|
|
24
|
+
verified: boolean;
|
|
25
|
+
expected: string;
|
|
26
|
+
actual: string;
|
|
27
|
+
length: number;
|
|
28
|
+
mode?: 'input' | 'textarea' | 'contenteditable';
|
|
29
|
+
}
|
|
22
30
|
export declare abstract class BasePage implements IPage {
|
|
23
31
|
protected _lastUrl: string | null;
|
|
24
32
|
/** Cached previous snapshot hashes for incremental diff marking */
|
|
25
33
|
private _prevSnapshotHashes;
|
|
34
|
+
private _cdpTargetMarkerSeq;
|
|
26
35
|
abstract goto(url: string, options?: {
|
|
27
36
|
waitUntil?: 'load' | 'none';
|
|
28
37
|
settleMs?: number;
|
|
@@ -53,7 +62,16 @@ export declare abstract class BasePage implements IPage {
|
|
|
53
62
|
protected tryNativeType(text: string): Promise<boolean>;
|
|
54
63
|
/** Uses native CDP key events when the concrete page exposes them. */
|
|
55
64
|
protected tryNativeKeyPress(key: string, modifiers: string[]): Promise<boolean>;
|
|
65
|
+
/**
|
|
66
|
+
* Run a DOM-domain CDP command against `window.__resolved`.
|
|
67
|
+
*
|
|
68
|
+
* CDP DOM.focus / DOM.scrollIntoViewIfNeeded need a nodeId, while our
|
|
69
|
+
* resolver stores the live Element in page JS. Bridge the two worlds with a
|
|
70
|
+
* short-lived marker attribute, then query it through CDP.
|
|
71
|
+
*/
|
|
72
|
+
protected tryCdpOnResolvedElement(method: 'DOM.focus' | 'DOM.scrollIntoViewIfNeeded'): Promise<boolean>;
|
|
56
73
|
typeText(ref: string, text: string, opts?: ResolveOptions): Promise<ResolveSuccess>;
|
|
74
|
+
fillText(ref: string, text: string, opts?: ResolveOptions): Promise<FillTextResult>;
|
|
57
75
|
pressKey(key: string): Promise<void>;
|
|
58
76
|
scrollTo(ref: string, opts?: ResolveOptions): Promise<unknown>;
|
|
59
77
|
getFormState(): Promise<Record<string, unknown>>;
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { generateSnapshotJs, getFormStateJs } from './dom-snapshot.js';
|
|
12
12
|
import { pressKeyJs, waitForTextJs, waitForCaptureJs, waitForSelectorJs, scrollJs, autoScrollJs, networkRequestsJs, waitForDomStableJs, } from './dom-helpers.js';
|
|
13
|
-
import { resolveTargetJs, clickResolvedJs, typeResolvedJs, prepareNativeTypeResolvedJs, scrollResolvedJs, } from './target-resolver.js';
|
|
13
|
+
import { resolveTargetJs, clickResolvedJs, typeResolvedJs, prepareNativeTypeResolvedJs, verifyFilledResolvedJs, scrollResolvedJs, } from './target-resolver.js';
|
|
14
14
|
import { TargetError } from './target-errors.js';
|
|
15
15
|
import { CliError } from '../errors.js';
|
|
16
16
|
import { formatSnapshot } from '../snapshotFormatter.js';
|
|
@@ -61,6 +61,7 @@ export class BasePage {
|
|
|
61
61
|
_lastUrl = null;
|
|
62
62
|
/** Cached previous snapshot hashes for incremental diff marking */
|
|
63
63
|
_prevSnapshotHashes = null;
|
|
64
|
+
_cdpTargetMarkerSeq = 0;
|
|
64
65
|
/**
|
|
65
66
|
* Safely evaluate JS with pre-serialized arguments.
|
|
66
67
|
* Each key in `args` becomes a `const` declaration with JSON-serialized value,
|
|
@@ -154,8 +155,9 @@ export class BasePage {
|
|
|
154
155
|
async click(ref, opts = {}) {
|
|
155
156
|
// Phase 1: Resolve target with fingerprint verification
|
|
156
157
|
const resolved = await runResolve(this, ref, opts);
|
|
158
|
+
const nativeScrolled = await this.tryCdpOnResolvedElement('DOM.scrollIntoViewIfNeeded');
|
|
157
159
|
// Phase 2: Execute click on resolved element
|
|
158
|
-
const result = await this.evaluate(clickResolvedJs());
|
|
160
|
+
const result = await this.evaluate(clickResolvedJs({ skipScroll: nativeScrolled }));
|
|
159
161
|
if (typeof result === 'string' || result == null)
|
|
160
162
|
return resolved;
|
|
161
163
|
if (result.status === 'clicked')
|
|
@@ -217,12 +219,78 @@ export class BasePage {
|
|
|
217
219
|
return false;
|
|
218
220
|
}
|
|
219
221
|
}
|
|
222
|
+
/**
|
|
223
|
+
* Run a DOM-domain CDP command against `window.__resolved`.
|
|
224
|
+
*
|
|
225
|
+
* CDP DOM.focus / DOM.scrollIntoViewIfNeeded need a nodeId, while our
|
|
226
|
+
* resolver stores the live Element in page JS. Bridge the two worlds with a
|
|
227
|
+
* short-lived marker attribute, then query it through CDP.
|
|
228
|
+
*/
|
|
229
|
+
async tryCdpOnResolvedElement(method) {
|
|
230
|
+
const cdp = this.cdp;
|
|
231
|
+
if (typeof cdp !== 'function')
|
|
232
|
+
return false;
|
|
233
|
+
const markerAttr = 'data-opencli-cdp-target';
|
|
234
|
+
const markerValue = `${Date.now().toString(36)}-${++this._cdpTargetMarkerSeq}`;
|
|
235
|
+
const selector = `[${markerAttr}="${markerValue}"]`;
|
|
236
|
+
let marked = false;
|
|
237
|
+
try {
|
|
238
|
+
const marker = await this.evaluateWithArgs(`
|
|
239
|
+
(() => {
|
|
240
|
+
const el = window.__resolved;
|
|
241
|
+
if (!el || el.nodeType !== 1 || typeof el.setAttribute !== 'function') {
|
|
242
|
+
return { ok: false };
|
|
243
|
+
}
|
|
244
|
+
el.setAttribute(markerAttr, markerValue);
|
|
245
|
+
return { ok: true };
|
|
246
|
+
})()
|
|
247
|
+
`, { markerAttr, markerValue });
|
|
248
|
+
marked = marker?.ok === true;
|
|
249
|
+
if (!marked)
|
|
250
|
+
return false;
|
|
251
|
+
await cdp.call(this, 'DOM.enable', {}).catch(() => undefined);
|
|
252
|
+
const doc = await cdp.call(this, 'DOM.getDocument', {});
|
|
253
|
+
const rootNodeId = doc?.root?.nodeId;
|
|
254
|
+
if (typeof rootNodeId !== 'number')
|
|
255
|
+
return false;
|
|
256
|
+
const query = await cdp.call(this, 'DOM.querySelector', {
|
|
257
|
+
nodeId: rootNodeId,
|
|
258
|
+
selector,
|
|
259
|
+
});
|
|
260
|
+
const nodeId = query?.nodeId;
|
|
261
|
+
if (typeof nodeId !== 'number' || nodeId <= 0)
|
|
262
|
+
return false;
|
|
263
|
+
await cdp.call(this, method, { nodeId });
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
finally {
|
|
270
|
+
if (marked) {
|
|
271
|
+
await this.evaluateWithArgs(`
|
|
272
|
+
(() => {
|
|
273
|
+
for (const el of document.querySelectorAll(selector)) {
|
|
274
|
+
el.removeAttribute(markerAttr);
|
|
275
|
+
}
|
|
276
|
+
})()
|
|
277
|
+
`, { selector, markerAttr }).catch(() => undefined);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
220
281
|
async typeText(ref, text, opts = {}) {
|
|
221
282
|
const resolved = await runResolve(this, ref, opts);
|
|
222
283
|
let typed = false;
|
|
284
|
+
let nativeScrolled = false;
|
|
285
|
+
let nativeFocused = false;
|
|
223
286
|
if (typeof this.nativeType === 'function' || typeof this.insertText === 'function') {
|
|
224
287
|
try {
|
|
225
|
-
|
|
288
|
+
nativeScrolled = await this.tryCdpOnResolvedElement('DOM.scrollIntoViewIfNeeded');
|
|
289
|
+
nativeFocused = await this.tryCdpOnResolvedElement('DOM.focus');
|
|
290
|
+
const preparation = await this.evaluate(prepareNativeTypeResolvedJs({
|
|
291
|
+
skipScroll: nativeScrolled,
|
|
292
|
+
skipFocus: nativeFocused,
|
|
293
|
+
}));
|
|
226
294
|
typed = preparation?.ok === true && await this.tryNativeType(text);
|
|
227
295
|
}
|
|
228
296
|
catch {
|
|
@@ -235,6 +303,49 @@ export class BasePage {
|
|
|
235
303
|
}
|
|
236
304
|
return resolved;
|
|
237
305
|
}
|
|
306
|
+
async fillText(ref, text, opts = {}) {
|
|
307
|
+
const resolved = await runResolve(this, ref, opts);
|
|
308
|
+
let nativeScrolled = false;
|
|
309
|
+
let nativeFocused = false;
|
|
310
|
+
try {
|
|
311
|
+
nativeScrolled = await this.tryCdpOnResolvedElement('DOM.scrollIntoViewIfNeeded');
|
|
312
|
+
nativeFocused = await this.tryCdpOnResolvedElement('DOM.focus');
|
|
313
|
+
}
|
|
314
|
+
catch {
|
|
315
|
+
// CDP focus/scroll is best-effort; DOM preparation below remains authoritative.
|
|
316
|
+
}
|
|
317
|
+
const preparation = await this.evaluate(prepareNativeTypeResolvedJs({
|
|
318
|
+
skipScroll: nativeScrolled,
|
|
319
|
+
skipFocus: nativeFocused,
|
|
320
|
+
}));
|
|
321
|
+
if (preparation?.ok !== true) {
|
|
322
|
+
throw new TargetError({
|
|
323
|
+
code: 'not_editable',
|
|
324
|
+
message: `Target "${ref}" is not a fillable input, textarea, or contenteditable element.`,
|
|
325
|
+
hint: 'Use `opencli browser state` to pick an editable target, or use `browser type` for keyboard-like interactions.',
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
const usedNativeInput = await this.tryNativeType(text);
|
|
329
|
+
if (!usedNativeInput) {
|
|
330
|
+
await this.evaluate(typeResolvedJs(text));
|
|
331
|
+
}
|
|
332
|
+
let verification = await this.evaluate(verifyFilledResolvedJs(text));
|
|
333
|
+
if (usedNativeInput && verification?.ok !== true) {
|
|
334
|
+
await this.evaluate(typeResolvedJs(text));
|
|
335
|
+
verification = await this.evaluate(verifyFilledResolvedJs(text));
|
|
336
|
+
}
|
|
337
|
+
const actual = verification && 'actual' in verification ? verification.actual : '';
|
|
338
|
+
const mode = verification && 'mode' in verification ? verification.mode : undefined;
|
|
339
|
+
return {
|
|
340
|
+
...resolved,
|
|
341
|
+
filled: true,
|
|
342
|
+
verified: verification?.ok === true,
|
|
343
|
+
expected: text,
|
|
344
|
+
actual,
|
|
345
|
+
length: actual.length,
|
|
346
|
+
...(mode ? { mode } : {}),
|
|
347
|
+
};
|
|
348
|
+
}
|
|
238
349
|
async pressKey(key) {
|
|
239
350
|
const parsed = parseKeyChord(key);
|
|
240
351
|
if (!await this.tryNativeKeyPress(parsed.key, parsed.modifiers)) {
|
|
@@ -243,7 +354,8 @@ export class BasePage {
|
|
|
243
354
|
}
|
|
244
355
|
async scrollTo(ref, opts = {}) {
|
|
245
356
|
const resolved = await runResolve(this, ref, opts);
|
|
246
|
-
const
|
|
357
|
+
const nativeScrolled = await this.tryCdpOnResolvedElement('DOM.scrollIntoViewIfNeeded');
|
|
358
|
+
const result = (await this.evaluate(scrollResolvedJs({ skipScroll: nativeScrolled })));
|
|
247
359
|
// Fold match_level into the scroll payload so the user-facing envelope
|
|
248
360
|
// carries it the same way click / type do.
|
|
249
361
|
if (result && typeof result === 'object') {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from 'vitest';
|
|
2
2
|
import { CliError } from '../errors.js';
|
|
3
3
|
import { BasePage } from './base-page.js';
|
|
4
|
+
import { TargetError } from './target-errors.js';
|
|
4
5
|
class TestPage extends BasePage {
|
|
5
6
|
result;
|
|
6
7
|
args;
|
|
@@ -17,15 +18,23 @@ class TestPage extends BasePage {
|
|
|
17
18
|
}
|
|
18
19
|
class ActionPage extends BasePage {
|
|
19
20
|
results = [];
|
|
21
|
+
withArgsResults = [];
|
|
20
22
|
scripts = [];
|
|
23
|
+
withArgs = [];
|
|
21
24
|
nativeType;
|
|
22
25
|
insertText;
|
|
23
26
|
nativeKeyPress;
|
|
27
|
+
cdp;
|
|
24
28
|
async goto() { }
|
|
25
29
|
async evaluate(js) {
|
|
26
30
|
this.scripts.push(js);
|
|
27
31
|
return this.results.shift() ?? null;
|
|
28
32
|
}
|
|
33
|
+
async evaluateWithArgs(js, args) {
|
|
34
|
+
this.scripts.push(js);
|
|
35
|
+
this.withArgs.push(args);
|
|
36
|
+
return this.withArgsResults.shift() ?? null;
|
|
37
|
+
}
|
|
29
38
|
async getCookies() { return []; }
|
|
30
39
|
async screenshot() { return ''; }
|
|
31
40
|
async tabs() { return []; }
|
|
@@ -100,6 +109,27 @@ describe('BasePage native input routing', () => {
|
|
|
100
109
|
expect(page.scripts[1]).toContain('nearestContentEditableHost');
|
|
101
110
|
expect(page.scripts.join('\n')).not.toContain("return 'typed'");
|
|
102
111
|
});
|
|
112
|
+
it('uses CDP DOM focus and scroll before native text insertion when available', async () => {
|
|
113
|
+
const page = new ActionPage();
|
|
114
|
+
page.nativeType = vi.fn().mockResolvedValue(undefined);
|
|
115
|
+
page.cdp = vi.fn()
|
|
116
|
+
.mockResolvedValueOnce({})
|
|
117
|
+
.mockResolvedValueOnce({ root: { nodeId: 1 } })
|
|
118
|
+
.mockResolvedValueOnce({ nodeId: 7 })
|
|
119
|
+
.mockResolvedValueOnce({})
|
|
120
|
+
.mockResolvedValueOnce({})
|
|
121
|
+
.mockResolvedValueOnce({ root: { nodeId: 1 } })
|
|
122
|
+
.mockResolvedValueOnce({ nodeId: 7 })
|
|
123
|
+
.mockResolvedValueOnce({});
|
|
124
|
+
page.results = [resolveOk, { ok: true, mode: 'input' }];
|
|
125
|
+
page.withArgsResults = [{ ok: true }, undefined, { ok: true }, undefined];
|
|
126
|
+
await page.typeText('#q', 'hello');
|
|
127
|
+
expect(page.cdp).toHaveBeenCalledWith('DOM.scrollIntoViewIfNeeded', { nodeId: 7 });
|
|
128
|
+
expect(page.cdp).toHaveBeenCalledWith('DOM.focus', { nodeId: 7 });
|
|
129
|
+
expect(page.nativeType).toHaveBeenCalledWith('hello');
|
|
130
|
+
expect(page.scripts.at(-1)).toContain('if (false) el.scrollIntoView');
|
|
131
|
+
expect(page.scripts.at(-1)).toContain('if (false) {');
|
|
132
|
+
});
|
|
103
133
|
it('keeps the DOM setter fallback when native text insertion is unavailable', async () => {
|
|
104
134
|
const page = new ActionPage();
|
|
105
135
|
page.results = [resolveOk, 'typed'];
|
|
@@ -117,6 +147,84 @@ describe('BasePage native input routing', () => {
|
|
|
117
147
|
expect(page.scripts).toHaveLength(3);
|
|
118
148
|
expect(page.scripts[2]).toContain("return 'typed'");
|
|
119
149
|
});
|
|
150
|
+
it('fills text through the native input path and verifies the exact value', async () => {
|
|
151
|
+
const page = new ActionPage();
|
|
152
|
+
page.nativeType = vi.fn().mockResolvedValue(undefined);
|
|
153
|
+
page.results = [
|
|
154
|
+
resolveOk,
|
|
155
|
+
{ ok: true, mode: 'textarea' },
|
|
156
|
+
{ ok: true, actual: 'line1\\n/ / raw', expected: 'line1\\n/ / raw', length: 14, mode: 'textarea' },
|
|
157
|
+
];
|
|
158
|
+
await expect(page.fillText('#message', 'line1\\n/ / raw')).resolves.toEqual({
|
|
159
|
+
filled: true,
|
|
160
|
+
verified: true,
|
|
161
|
+
expected: 'line1\\n/ / raw',
|
|
162
|
+
actual: 'line1\\n/ / raw',
|
|
163
|
+
length: 14,
|
|
164
|
+
matches_n: 1,
|
|
165
|
+
match_level: 'exact',
|
|
166
|
+
mode: 'textarea',
|
|
167
|
+
});
|
|
168
|
+
expect(page.nativeType).toHaveBeenCalledWith('line1\\n/ / raw');
|
|
169
|
+
expect(page.scripts).toHaveLength(3);
|
|
170
|
+
expect(page.scripts[2]).toContain('actual ===');
|
|
171
|
+
});
|
|
172
|
+
it('falls back to the DOM setter when native fill insertion is unavailable', async () => {
|
|
173
|
+
const page = new ActionPage();
|
|
174
|
+
page.results = [
|
|
175
|
+
resolveOk,
|
|
176
|
+
{ ok: true, mode: 'input' },
|
|
177
|
+
'typed',
|
|
178
|
+
{ ok: true, actual: 'hello', expected: 'hello', length: 5, mode: 'input' },
|
|
179
|
+
];
|
|
180
|
+
await expect(page.fillText('#q', 'hello')).resolves.toEqual(expect.objectContaining({
|
|
181
|
+
filled: true,
|
|
182
|
+
verified: true,
|
|
183
|
+
actual: 'hello',
|
|
184
|
+
mode: 'input',
|
|
185
|
+
}));
|
|
186
|
+
expect(page.scripts).toHaveLength(4);
|
|
187
|
+
expect(page.scripts[2]).toContain("return 'typed'");
|
|
188
|
+
});
|
|
189
|
+
it('falls back to DOM fill if native insertion does not verify', async () => {
|
|
190
|
+
const page = new ActionPage();
|
|
191
|
+
page.nativeType = vi.fn().mockResolvedValue(undefined);
|
|
192
|
+
page.results = [
|
|
193
|
+
resolveOk,
|
|
194
|
+
{ ok: true, mode: 'input' },
|
|
195
|
+
{ ok: false, actual: '', expected: 'hello', length: 0, mode: 'input' },
|
|
196
|
+
'typed',
|
|
197
|
+
{ ok: true, actual: 'hello', expected: 'hello', length: 5, mode: 'input' },
|
|
198
|
+
];
|
|
199
|
+
await expect(page.fillText('#q', 'hello')).resolves.toEqual(expect.objectContaining({
|
|
200
|
+
filled: true,
|
|
201
|
+
verified: true,
|
|
202
|
+
actual: 'hello',
|
|
203
|
+
}));
|
|
204
|
+
expect(page.nativeType).toHaveBeenCalledWith('hello');
|
|
205
|
+
expect(page.scripts).toHaveLength(5);
|
|
206
|
+
expect(page.scripts[3]).toContain("return 'typed'");
|
|
207
|
+
});
|
|
208
|
+
it('throws a structured not_editable error for non-fillable targets', async () => {
|
|
209
|
+
const page = new ActionPage();
|
|
210
|
+
page.results = [resolveOk, { ok: false, reason: 'not_editable', tag: 'button' }];
|
|
211
|
+
const err = await page.fillText('button', 'hello').catch((error) => error);
|
|
212
|
+
expect(err).toBeInstanceOf(TargetError);
|
|
213
|
+
expect(err.code).toBe('not_editable');
|
|
214
|
+
});
|
|
215
|
+
it('uses CDP DOM scrollIntoViewIfNeeded before JS click when available', async () => {
|
|
216
|
+
const page = new ActionPage();
|
|
217
|
+
page.cdp = vi.fn()
|
|
218
|
+
.mockResolvedValueOnce({})
|
|
219
|
+
.mockResolvedValueOnce({ root: { nodeId: 1 } })
|
|
220
|
+
.mockResolvedValueOnce({ nodeId: 9 })
|
|
221
|
+
.mockResolvedValueOnce({});
|
|
222
|
+
page.results = [resolveOk, { status: 'clicked', x: 1, y: 2 }];
|
|
223
|
+
page.withArgsResults = [{ ok: true }, undefined];
|
|
224
|
+
await page.click('#save');
|
|
225
|
+
expect(page.cdp).toHaveBeenCalledWith('DOM.scrollIntoViewIfNeeded', { nodeId: 9 });
|
|
226
|
+
expect(page.scripts.at(-1)).toContain('if (false) el.scrollIntoView');
|
|
227
|
+
});
|
|
120
228
|
it('presses key chords through native CDP key events when available', async () => {
|
|
121
229
|
const page = new ActionPage();
|
|
122
230
|
page.nativeKeyPress = vi.fn().mockResolvedValue(undefined);
|
|
@@ -26,6 +26,7 @@ export declare class CDPBridge implements IBrowserFactory {
|
|
|
26
26
|
workspace?: string;
|
|
27
27
|
cdpEndpoint?: string;
|
|
28
28
|
contextId?: string;
|
|
29
|
+
idleTimeout?: number;
|
|
29
30
|
}): Promise<IPage>;
|
|
30
31
|
close(): Promise<void>;
|
|
31
32
|
send(method: string, params?: Record<string, unknown>, timeoutMs?: number): Promise<unknown>;
|
package/dist/src/browser/cdp.js
CHANGED
|
@@ -202,16 +202,58 @@ class CDPPage extends BasePage {
|
|
|
202
202
|
: cookies;
|
|
203
203
|
}
|
|
204
204
|
async screenshot(options = {}) {
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
205
|
+
const fullPage = options.fullPage === true;
|
|
206
|
+
const overrideWidth = options.width && options.width > 0 ? Math.ceil(options.width) : undefined;
|
|
207
|
+
// height is ignored under fullPage so the captureBeyondViewport path stays unchanged for users who pass --height alongside --full-page.
|
|
208
|
+
const overrideHeight = !fullPage && options.height && options.height > 0 ? Math.ceil(options.height) : undefined;
|
|
209
|
+
const needsOverride = overrideWidth !== undefined || overrideHeight !== undefined;
|
|
210
|
+
if (needsOverride) {
|
|
211
|
+
if (overrideWidth !== undefined && fullPage) {
|
|
212
|
+
await this.bridge.send('Emulation.setDeviceMetricsOverride', {
|
|
213
|
+
mobile: false,
|
|
214
|
+
width: overrideWidth,
|
|
215
|
+
height: 0,
|
|
216
|
+
deviceScaleFactor: 1,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
let finalWidth = overrideWidth ?? 0;
|
|
220
|
+
let finalHeight = overrideHeight ?? 0;
|
|
221
|
+
if (fullPage) {
|
|
222
|
+
const metrics = await this.bridge.send('Page.getLayoutMetrics');
|
|
223
|
+
const m = isRecord(metrics) ? metrics : {};
|
|
224
|
+
const css = isRecord(m.cssContentSize) ? m.cssContentSize : undefined;
|
|
225
|
+
const fb = isRecord(m.contentSize) ? m.contentSize : undefined;
|
|
226
|
+
const size = css ?? fb;
|
|
227
|
+
if (size && typeof size.width === 'number' && typeof size.height === 'number') {
|
|
228
|
+
if (finalWidth === 0)
|
|
229
|
+
finalWidth = Math.ceil(size.width);
|
|
230
|
+
finalHeight = Math.ceil(size.height);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
await this.bridge.send('Emulation.setDeviceMetricsOverride', {
|
|
234
|
+
mobile: false,
|
|
235
|
+
width: finalWidth,
|
|
236
|
+
height: finalHeight,
|
|
237
|
+
deviceScaleFactor: 1,
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
try {
|
|
241
|
+
const result = await this.bridge.send('Page.captureScreenshot', {
|
|
242
|
+
format: options.format ?? 'png',
|
|
243
|
+
quality: options.format === 'jpeg' ? (options.quality ?? 80) : undefined,
|
|
244
|
+
captureBeyondViewport: !needsOverride && fullPage,
|
|
245
|
+
});
|
|
246
|
+
const base64 = isRecord(result) && typeof result.data === 'string' ? result.data : '';
|
|
247
|
+
if (options.path) {
|
|
248
|
+
await saveBase64ToFile(base64, options.path);
|
|
249
|
+
}
|
|
250
|
+
return base64;
|
|
251
|
+
}
|
|
252
|
+
finally {
|
|
253
|
+
if (needsOverride) {
|
|
254
|
+
await this.bridge.send('Emulation.clearDeviceMetricsOverride').catch(() => { });
|
|
255
|
+
}
|
|
213
256
|
}
|
|
214
|
-
return base64;
|
|
215
257
|
}
|
|
216
258
|
async startNetworkCapture(pattern = '') {
|
|
217
259
|
// Always update the filter pattern
|
|
@@ -320,6 +362,12 @@ class CDPPage extends BasePage {
|
|
|
320
362
|
async cdp(method, params = {}) {
|
|
321
363
|
return this.bridge.send(method, params);
|
|
322
364
|
}
|
|
365
|
+
async handleJavaScriptDialog(accept, promptText) {
|
|
366
|
+
await this.cdp('Page.handleJavaScriptDialog', {
|
|
367
|
+
accept,
|
|
368
|
+
...(promptText !== undefined && { promptText }),
|
|
369
|
+
});
|
|
370
|
+
}
|
|
323
371
|
async nativeClick(x, y) {
|
|
324
372
|
await this.cdp('Input.dispatchMouseEvent', {
|
|
325
373
|
type: 'mousePressed',
|
|
@@ -58,10 +58,12 @@ describe('CDPBridge cookies', () => {
|
|
|
58
58
|
expect(page.nativeType).toBeTypeOf('function');
|
|
59
59
|
expect(page.nativeKeyPress).toBeTypeOf('function');
|
|
60
60
|
expect(page.nativeClick).toBeTypeOf('function');
|
|
61
|
+
expect(page.handleJavaScriptDialog).toBeTypeOf('function');
|
|
61
62
|
expect(page.cdp).toBeTypeOf('function');
|
|
62
63
|
await page.nativeType('hello');
|
|
63
64
|
await page.nativeKeyPress('a', ['Ctrl']);
|
|
64
65
|
await page.nativeClick(10, 20);
|
|
66
|
+
await page.handleJavaScriptDialog(true, 'ok');
|
|
65
67
|
await page.cdp('Page.getLayoutMetrics', {});
|
|
66
68
|
expect(send.mock.calls).toEqual([
|
|
67
69
|
['Input.insertText', { text: 'hello' }],
|
|
@@ -69,6 +71,7 @@ describe('CDPBridge cookies', () => {
|
|
|
69
71
|
['Input.dispatchKeyEvent', { type: 'keyUp', key: 'a', modifiers: 2 }],
|
|
70
72
|
['Input.dispatchMouseEvent', { type: 'mousePressed', x: 10, y: 20, button: 'left', clickCount: 1 }],
|
|
71
73
|
['Input.dispatchMouseEvent', { type: 'mouseReleased', x: 10, y: 20, button: 'left', clickCount: 1 }],
|
|
74
|
+
['Page.handleJavaScriptDialog', { accept: true, promptText: 'ok' }],
|
|
72
75
|
['Page.getLayoutMetrics', {}],
|
|
73
76
|
]);
|
|
74
77
|
});
|
|
@@ -20,6 +20,10 @@ export interface DaemonCommand {
|
|
|
20
20
|
format?: 'png' | 'jpeg';
|
|
21
21
|
quality?: number;
|
|
22
22
|
fullPage?: boolean;
|
|
23
|
+
/** Override viewport width in CSS pixels for screenshot (0 / undefined = use current) */
|
|
24
|
+
width?: number;
|
|
25
|
+
/** Override viewport height in CSS pixels for screenshot (0 / undefined = use current; ignored when fullPage) */
|
|
26
|
+
height?: number;
|
|
23
27
|
/** Local file paths for set-file-input action */
|
|
24
28
|
files?: string[];
|
|
25
29
|
/** CSS selector for file input element (set-file-input action) */
|
|
@@ -65,7 +65,7 @@ export function isTransientBrowserError(err) {
|
|
|
65
65
|
export function formatBrowserConnectError(kind, detail) {
|
|
66
66
|
switch (kind) {
|
|
67
67
|
case 'daemon-not-running':
|
|
68
|
-
return new BrowserConnectError('Cannot connect to opencli daemon.' + (detail ? `\n\n${detail}` : ''), `
|
|
68
|
+
return new BrowserConnectError('Cannot connect to opencli daemon.' + (detail ? `\n\n${detail}` : ''), `Run \`opencli doctor\` to diagnose, or \`opencli daemon restart\` to force a fresh daemon. Default port is ${DEFAULT_DAEMON_PORT}.`, kind);
|
|
69
69
|
case 'extension-not-connected':
|
|
70
70
|
return new BrowserConnectError('Browser Bridge extension is not connected.' + (detail ? `\n\n${detail}` : ''), 'Install the extension from GitHub Releases, then reload.', kind);
|
|
71
71
|
case 'command-failed':
|
|
@@ -41,7 +41,7 @@ export declare class Page extends BasePage {
|
|
|
41
41
|
domain?: string;
|
|
42
42
|
url?: string;
|
|
43
43
|
}): Promise<BrowserCookie[]>;
|
|
44
|
-
/**
|
|
44
|
+
/** Release the current automation tab lease in the extension */
|
|
45
45
|
closeWindow(): Promise<void>;
|
|
46
46
|
tabs(): Promise<unknown[]>;
|
|
47
47
|
newTab(url?: string): Promise<string | undefined>;
|
|
@@ -68,6 +68,7 @@ export declare class Page extends BasePage {
|
|
|
68
68
|
}>>;
|
|
69
69
|
evaluateInFrame(js: string, frameIndex: number): Promise<unknown>;
|
|
70
70
|
cdp(method: string, params?: Record<string, unknown>): Promise<unknown>;
|
|
71
|
+
handleJavaScriptDialog(accept: boolean, promptText?: string): Promise<void>;
|
|
71
72
|
/** CDP native click fallback — called when JS el.click() fails */
|
|
72
73
|
protected tryNativeClick(x: number, y: number): Promise<boolean>;
|
|
73
74
|
/** Precise click using DOM.getContentQuads/getBoxModel for inline elements */
|
package/dist/src/browser/page.js
CHANGED
|
@@ -143,7 +143,7 @@ export class Page extends BasePage {
|
|
|
143
143
|
const result = await sendCommand('cookies', { ...this._wsOpt(), ...opts });
|
|
144
144
|
return Array.isArray(result) ? result : [];
|
|
145
145
|
}
|
|
146
|
-
/**
|
|
146
|
+
/** Release the current automation tab lease in the extension */
|
|
147
147
|
async closeWindow() {
|
|
148
148
|
try {
|
|
149
149
|
await sendCommand('close-window', { ...this._wsOpt() });
|
|
@@ -205,6 +205,8 @@ export class Page extends BasePage {
|
|
|
205
205
|
format: options.format,
|
|
206
206
|
quality: options.quality,
|
|
207
207
|
fullPage: options.fullPage,
|
|
208
|
+
width: options.width,
|
|
209
|
+
height: options.height,
|
|
208
210
|
});
|
|
209
211
|
if (options.path) {
|
|
210
212
|
await saveBase64ToFile(base64, options.path);
|
|
@@ -283,6 +285,12 @@ export class Page extends BasePage {
|
|
|
283
285
|
...this._cmdOpts(),
|
|
284
286
|
});
|
|
285
287
|
}
|
|
288
|
+
async handleJavaScriptDialog(accept, promptText) {
|
|
289
|
+
await this.cdp('Page.handleJavaScriptDialog', {
|
|
290
|
+
accept,
|
|
291
|
+
...(promptText !== undefined && { promptText }),
|
|
292
|
+
});
|
|
293
|
+
}
|
|
286
294
|
/** CDP native click fallback — called when JS el.click() fails */
|
|
287
295
|
async tryNativeClick(x, y) {
|
|
288
296
|
try {
|
|
@@ -102,6 +102,23 @@ describe('Page network capture compatibility', () => {
|
|
|
102
102
|
expect(warnMock).toHaveBeenCalledTimes(1);
|
|
103
103
|
});
|
|
104
104
|
});
|
|
105
|
+
describe('Page CDP helpers', () => {
|
|
106
|
+
beforeEach(() => {
|
|
107
|
+
sendCommandMock.mockReset();
|
|
108
|
+
sendCommandFullMock.mockReset();
|
|
109
|
+
warnMock.mockReset();
|
|
110
|
+
});
|
|
111
|
+
it('handles JavaScript dialogs through the CDP passthrough', async () => {
|
|
112
|
+
sendCommandMock.mockResolvedValueOnce({});
|
|
113
|
+
const page = new Page('browser:default');
|
|
114
|
+
await page.handleJavaScriptDialog(true, 'confirm');
|
|
115
|
+
expect(sendCommandMock).toHaveBeenCalledWith('cdp', expect.objectContaining({
|
|
116
|
+
workspace: 'browser:default',
|
|
117
|
+
cdpMethod: 'Page.handleJavaScriptDialog',
|
|
118
|
+
cdpParams: { accept: true, promptText: 'confirm' },
|
|
119
|
+
}));
|
|
120
|
+
});
|
|
121
|
+
});
|
|
105
122
|
describe('Page active target tracking', () => {
|
|
106
123
|
beforeEach(() => {
|
|
107
124
|
sendCommandMock.mockReset();
|
|
@@ -199,3 +216,32 @@ describe('Page active target tracking', () => {
|
|
|
199
216
|
expect(evalCall?.[1]).not.toHaveProperty('page');
|
|
200
217
|
});
|
|
201
218
|
});
|
|
219
|
+
describe('Page.screenshot', () => {
|
|
220
|
+
beforeEach(() => {
|
|
221
|
+
sendCommandMock.mockReset();
|
|
222
|
+
sendCommandFullMock.mockReset();
|
|
223
|
+
warnMock.mockReset();
|
|
224
|
+
});
|
|
225
|
+
it('forwards width / height / fullPage options to the bridge', async () => {
|
|
226
|
+
sendCommandMock.mockResolvedValueOnce('BASE64');
|
|
227
|
+
const page = new Page('browser:default');
|
|
228
|
+
const data = await page.screenshot({ fullPage: true, width: 1080 });
|
|
229
|
+
expect(data).toBe('BASE64');
|
|
230
|
+
expect(sendCommandMock).toHaveBeenCalledWith('screenshot', expect.objectContaining({
|
|
231
|
+
workspace: 'browser:default',
|
|
232
|
+
fullPage: true,
|
|
233
|
+
width: 1080,
|
|
234
|
+
}));
|
|
235
|
+
});
|
|
236
|
+
it('omits viewport overrides when none are set', async () => {
|
|
237
|
+
sendCommandMock.mockResolvedValueOnce('BASE64');
|
|
238
|
+
const page = new Page('browser:default');
|
|
239
|
+
await page.screenshot();
|
|
240
|
+
const call = sendCommandMock.mock.calls.at(-1);
|
|
241
|
+
expect(call?.[0]).toBe('screenshot');
|
|
242
|
+
const args = call?.[1];
|
|
243
|
+
expect(args.width).toBeUndefined();
|
|
244
|
+
expect(args.height).toBeUndefined();
|
|
245
|
+
expect(args.fullPage).toBeUndefined();
|
|
246
|
+
});
|
|
247
|
+
});
|
|
@@ -15,8 +15,9 @@
|
|
|
15
15
|
* - selector_not_found: 0 matches
|
|
16
16
|
* - selector_ambiguous: >1 matches for a write op without --nth
|
|
17
17
|
* - selector_nth_out_of_range: --nth beyond matches_n
|
|
18
|
+
* - not_editable: target exists but cannot accept text input
|
|
18
19
|
*/
|
|
19
|
-
export type TargetErrorCode = 'not_found' | 'stale_ref' | 'invalid_selector' | 'selector_not_found' | 'selector_ambiguous' | 'selector_nth_out_of_range';
|
|
20
|
+
export type TargetErrorCode = 'not_found' | 'stale_ref' | 'invalid_selector' | 'selector_not_found' | 'selector_ambiguous' | 'selector_nth_out_of_range' | 'not_editable';
|
|
20
21
|
export interface TargetErrorInfo {
|
|
21
22
|
code: TargetErrorCode;
|
|
22
23
|
message: string;
|