@jackwener/opencli 1.7.10 → 1.7.12
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 +3 -3
- package/README.zh-CN.md +5 -4
- package/cli-manifest.json +1443 -24
- 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/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/amazon/bestsellers.js +1 -0
- package/clis/amazon/discussion.js +1 -0
- 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 +1 -0
- 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/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 -0
- 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/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 +1 -0
- package/clis/chaoxing/exams.js +1 -0
- package/clis/chatgpt/image.js +1 -0
- package/clis/chatgpt-app/ask.js +1 -0
- 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 +1 -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 +1 -0
- package/clis/claude/ask.js +1 -0
- package/clis/claude/detail.js +1 -0
- package/clis/claude/history.js +1 -0
- package/clis/claude/new.js +1 -0
- package/clis/claude/read.js +1 -0
- package/clis/claude/send.js +1 -0
- package/clis/claude/status.js +1 -0
- package/clis/cnki/search.js +1 -0
- package/clis/codex/ask.js +1 -0
- package/clis/codex/export.js +1 -0
- package/clis/codex/extract-diff.js +1 -0
- package/clis/codex/history.js +1 -0
- package/clis/codex/model.js +1 -0
- package/clis/codex/read.js +1 -0
- package/clis/codex/send.js +1 -0
- package/clis/coupang/add-to-cart.js +1 -0
- package/clis/coupang/search.js +1 -0
- package/clis/ctrip/search.js +1 -0
- package/clis/cursor/ask.js +1 -0
- 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/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/deepseek/ask.js +1 -0
- package/clis/deepseek/history.js +1 -0
- package/clis/deepseek/new.js +1 -0
- package/clis/deepseek/read.js +1 -0
- package/clis/deepseek/status.js +1 -0
- package/clis/devto/devto.test.js +236 -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/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 +1 -0
- package/clis/doubao/detail.js +1 -0
- package/clis/doubao/history.js +1 -0
- package/clis/doubao/meeting-summary.js +1 -0
- package/clis/doubao/meeting-transcript.js +1 -0
- package/clis/doubao/new.js +1 -0
- package/clis/doubao/read.js +1 -0
- package/clis/doubao/send.js +1 -0
- package/clis/doubao/status.js +1 -0
- package/clis/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/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/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 +1 -0
- package/clis/facebook/profile.js +1 -0
- package/clis/facebook/search.js +1 -0
- package/clis/gemini/ask.js +1 -0
- package/clis/gemini/deep-research-result.js +1 -0
- package/clis/gemini/deep-research.js +1 -0
- package/clis/gemini/image.js +1 -0
- package/clis/gemini/new.js +1 -0
- 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 -0
- package/clis/google-scholar/profile.js +1 -0
- package/clis/google-scholar/search.js +1 -0
- package/clis/gov-law/recent.js +1 -0
- package/clis/gov-law/search.js +1 -0
- package/clis/gov-policy/recent.js +1 -0
- package/clis/gov-policy/search.js +1 -0
- package/clis/grok/ask.js +1 -0
- package/clis/grok/image.ts +1 -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/top.js +1 -0
- package/clis/hupu/detail.js +1 -0
- package/clis/hupu/hot.js +3 -1
- 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 -1
- 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 +92 -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 +1 -0
- package/clis/instagram/post.js +1 -0
- package/clis/instagram/profile.js +1 -0
- package/clis/instagram/reel.js +1 -0
- 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 +1 -0
- 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/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/linkedin/search.js +1 -0
- package/clis/linkedin/timeline.js +1 -0
- package/clis/linux-do/categories.js +1 -0
- package/clis/linux-do/category.js +1 -0
- package/clis/linux-do/feed.js +1 -0
- package/clis/linux-do/hot.js +1 -0
- package/clis/linux-do/latest.js +1 -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/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/medium/feed.js +1 -0
- package/clis/medium/search.js +1 -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/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/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/paperreview/feedback.js +1 -0
- package/clis/paperreview/review.js +1 -0
- package/clis/paperreview/submit.js +1 -0
- package/clis/pixiv/detail.js +1 -0
- package/clis/pixiv/download.js +1 -0
- package/clis/pixiv/illusts.js +2 -1
- package/clis/pixiv/ranking.js +2 -1
- package/clis/pixiv/search.js +2 -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/quark/ls.js +1 -0
- package/clis/quark/mkdir.js +1 -0
- package/clis/quark/mv.js +1 -0
- package/clis/quark/rename.js +1 -0
- package/clis/quark/rm.js +1 -0
- package/clis/quark/save.js +1 -0
- package/clis/quark/share-tree.js +1 -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/reuters/search.js +1 -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/search.js +10 -2
- package/clis/stackoverflow/stackoverflow.test.js +346 -0
- package/clis/stackoverflow/unanswered.js +9 -2
- package/clis/steam/top-sellers.js +1 -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/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/ths/hot-rank.js +1 -0
- package/clis/tieba/hot.js +2 -1
- 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 +1 -0
- package/clis/tiktok/explore.js +1 -0
- package/clis/tiktok/follow.js +1 -0
- package/clis/tiktok/following.js +1 -0
- package/clis/tiktok/friends.js +1 -0
- package/clis/tiktok/like.js +1 -0
- package/clis/tiktok/live.js +1 -0
- package/clis/tiktok/notifications.js +1 -0
- package/clis/tiktok/profile.js +1 -0
- package/clis/tiktok/save.js +1 -0
- package/clis/tiktok/search.js +1 -0
- package/clis/tiktok/unfollow.js +1 -0
- package/clis/tiktok/unlike.js +1 -0
- package/clis/tiktok/unsave.js +1 -0
- package/clis/tiktok/user.js +1 -0
- package/clis/toutiao/articles.js +1 -0
- package/clis/twitter/accept.js +1 -0
- 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 +1 -0
- 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 +1 -0
- package/clis/twitter/reply.js +1 -0
- 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/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 -0
- package/clis/web/read.js +1 -0
- 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 +1 -0
- package/clis/weixin/download.js +1 -0
- package/clis/weixin/drafts.js +1 -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/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/xianyu/chat.js +1 -0
- package/clis/xianyu/item.js +1 -0
- package/clis/xianyu/search.js +1 -0
- package/clis/xiaoe/catalog.js +2 -1
- package/clis/xiaoe/content.js +1 -0
- package/clis/xiaoe/courses.js +1 -0
- package/clis/xiaoe/detail.js +1 -0
- package/clis/xiaoe/play-url.js +1 -0
- package/clis/xiaohongshu/comments.js +1 -0
- package/clis/xiaohongshu/creator-note-detail.js +1 -0
- package/clis/xiaohongshu/creator-notes-summary.js +1 -0
- 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 +1 -0
- 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 +1 -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 +1 -0
- package/clis/yuanbao/new.js +1 -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/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-shadow.d.ts +11 -0
- package/dist/src/adapter-shadow.js +72 -0
- package/dist/src/adapter-shadow.test.d.ts +1 -0
- package/dist/src/adapter-shadow.test.js +49 -0
- package/dist/src/adapter-source.test.js +1 -1
- package/dist/src/browser/analyze.test.js +2 -0
- package/dist/src/browser/base-page.d.ts +15 -2
- package/dist/src/browser/base-page.js +159 -8
- package/dist/src/browser/base-page.test.js +103 -1
- package/dist/src/browser/cdp.js +54 -0
- package/dist/src/browser/cdp.test.js +26 -0
- package/dist/src/browser/dom-helpers.d.ts +1 -1
- package/dist/src/browser/dom-helpers.js +15 -3
- package/dist/src/browser/page.d.ts +1 -0
- package/dist/src/browser/page.js +7 -1
- package/dist/src/browser/page.test.js +17 -0
- package/dist/src/browser/target-resolver.d.ts +17 -2
- package/dist/src/browser/target-resolver.js +85 -4
- package/dist/src/browser/verify-fixture.d.ts +7 -1
- package/dist/src/browser/verify-fixture.js +105 -0
- package/dist/src/browser/verify-fixture.test.js +59 -1
- package/dist/src/build-manifest.d.ts +68 -33
- package/dist/src/build-manifest.js +178 -29
- package/dist/src/build-manifest.test.js +85 -5
- package/dist/src/capabilityRouting.test.js +1 -1
- package/dist/src/cli.js +150 -11
- package/dist/src/cli.test.js +237 -0
- package/dist/src/commanderAdapter.d.ts +1 -1
- package/dist/src/commanderAdapter.js +17 -7
- package/dist/src/commanderAdapter.test.js +7 -6
- 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 +2 -0
- package/dist/src/doctor.d.ts +2 -0
- package/dist/src/doctor.js +6 -0
- package/dist/src/doctor.test.js +36 -1
- package/dist/src/engine.test.js +10 -10
- package/dist/src/execution.js +1 -1
- package/dist/src/execution.test.js +9 -9
- package/dist/src/help.d.ts +15 -0
- package/dist/src/help.js +149 -0
- package/dist/src/main.js +13 -7
- package/dist/src/manifest-types.d.ts +41 -0
- package/dist/src/manifest-types.js +9 -0
- package/dist/src/plugin.test.js +26 -26
- package/dist/src/registry.d.ts +5 -0
- package/dist/src/registry.js +8 -0
- package/dist/src/registry.test.js +27 -20
- package/dist/src/serialization.d.ts +4 -0
- package/dist/src/serialization.js +27 -1
- package/dist/src/serialization.test.js +24 -2
- package/dist/src/types.d.ts +2 -0
- package/package.json +5 -2
- 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/silent-column-drop-baseline.json +962 -0
- package/scripts/typed-error-lint-baseline.json +1586 -0
|
@@ -7,13 +7,14 @@ describe('cli() registration', () => {
|
|
|
7
7
|
it('registers a command and returns it', () => {
|
|
8
8
|
const cmd = cli({
|
|
9
9
|
site: 'test-registry',
|
|
10
|
-
name: 'hello',
|
|
10
|
+
name: 'hello', access: 'read',
|
|
11
11
|
description: 'A test command',
|
|
12
12
|
strategy: Strategy.PUBLIC,
|
|
13
13
|
browser: false,
|
|
14
14
|
});
|
|
15
15
|
expect(cmd.site).toBe('test-registry');
|
|
16
16
|
expect(cmd.name).toBe('hello');
|
|
17
|
+
expect(cmd.access).toBe('read');
|
|
17
18
|
expect(cmd.strategy).toBe(Strategy.PUBLIC);
|
|
18
19
|
expect(cmd.browser).toBe(false);
|
|
19
20
|
expect(cmd.args).toEqual([]);
|
|
@@ -21,7 +22,7 @@ describe('cli() registration', () => {
|
|
|
21
22
|
it('puts registered command in the registry', () => {
|
|
22
23
|
cli({
|
|
23
24
|
site: 'test-registry',
|
|
24
|
-
name: 'registered',
|
|
25
|
+
name: 'registered', access: 'read',
|
|
25
26
|
description: 'test',
|
|
26
27
|
});
|
|
27
28
|
const registry = getRegistry();
|
|
@@ -30,7 +31,7 @@ describe('cli() registration', () => {
|
|
|
30
31
|
it('defaults strategy to COOKIE when browser is true', () => {
|
|
31
32
|
const cmd = cli({
|
|
32
33
|
site: 'test-registry',
|
|
33
|
-
name: 'default-strategy',
|
|
34
|
+
name: 'default-strategy', access: 'read',
|
|
34
35
|
});
|
|
35
36
|
expect(cmd.strategy).toBe(Strategy.COOKIE);
|
|
36
37
|
expect(cmd.browser).toBe(true);
|
|
@@ -38,7 +39,7 @@ describe('cli() registration', () => {
|
|
|
38
39
|
it('defaults strategy to PUBLIC when browser is false', () => {
|
|
39
40
|
const cmd = cli({
|
|
40
41
|
site: 'test-registry',
|
|
41
|
-
name: 'no-browser',
|
|
42
|
+
name: 'no-browser', access: 'read',
|
|
42
43
|
browser: false,
|
|
43
44
|
});
|
|
44
45
|
expect(cmd.strategy).toBe(Strategy.PUBLIC);
|
|
@@ -46,7 +47,7 @@ describe('cli() registration', () => {
|
|
|
46
47
|
it('preserves LOCAL strategy on registration', () => {
|
|
47
48
|
const cmd = cli({
|
|
48
49
|
site: 'test-registry',
|
|
49
|
-
name: 'local-strategy',
|
|
50
|
+
name: 'local-strategy', access: 'read',
|
|
50
51
|
description: 'reads local credentials',
|
|
51
52
|
strategy: Strategy.LOCAL,
|
|
52
53
|
browser: false,
|
|
@@ -55,15 +56,15 @@ describe('cli() registration', () => {
|
|
|
55
56
|
expect(cmd.browser).toBe(false);
|
|
56
57
|
});
|
|
57
58
|
it('overwrites existing command on re-registration', () => {
|
|
58
|
-
cli({ site: 'test-registry', name: 'overwrite', description: 'v1' });
|
|
59
|
-
cli({ site: 'test-registry', name: 'overwrite', description: 'v2' });
|
|
59
|
+
cli({ site: 'test-registry', name: 'overwrite', access: 'read', description: 'v1' });
|
|
60
|
+
cli({ site: 'test-registry', name: 'overwrite', access: 'read', description: 'v2' });
|
|
60
61
|
const reg = getRegistry();
|
|
61
62
|
expect(reg.get('test-registry/overwrite')?.description).toBe('v2');
|
|
62
63
|
});
|
|
63
64
|
it('registers aliases as alternate registry keys for the same command', () => {
|
|
64
65
|
const cmd = cli({
|
|
65
66
|
site: 'test-registry',
|
|
66
|
-
name: 'canonical',
|
|
67
|
+
name: 'canonical', access: 'read',
|
|
67
68
|
description: 'test aliases',
|
|
68
69
|
aliases: ['compat', 'legacy-name'],
|
|
69
70
|
});
|
|
@@ -76,18 +77,24 @@ describe('cli() registration', () => {
|
|
|
76
77
|
it('preserves defaultFormat on the registered command', () => {
|
|
77
78
|
const cmd = cli({
|
|
78
79
|
site: 'test-registry',
|
|
79
|
-
name: 'plain-default',
|
|
80
|
+
name: 'plain-default', access: 'read',
|
|
80
81
|
description: 'prefers plain output',
|
|
81
82
|
defaultFormat: 'plain',
|
|
82
83
|
});
|
|
83
84
|
expect(cmd.defaultFormat).toBe('plain');
|
|
84
85
|
expect(getRegistry().get('test-registry/plain-default')?.defaultFormat).toBe('plain');
|
|
85
86
|
});
|
|
87
|
+
it('rejects commands without explicit access metadata', () => {
|
|
88
|
+
expect(() => cli({
|
|
89
|
+
site: 'test-registry',
|
|
90
|
+
name: 'missing-access',
|
|
91
|
+
})).toThrow("Command test-registry/missing-access must declare access: 'read' | 'write'");
|
|
92
|
+
});
|
|
86
93
|
});
|
|
87
94
|
describe('fullName', () => {
|
|
88
95
|
it('returns site/name', () => {
|
|
89
96
|
const cmd = {
|
|
90
|
-
site: 'bilibili', name: 'hot', description: '', args: [],
|
|
97
|
+
site: 'bilibili', name: 'hot', access: 'read', description: '', args: [],
|
|
91
98
|
};
|
|
92
99
|
expect(fullName(cmd)).toBe('bilibili/hot');
|
|
93
100
|
});
|
|
@@ -95,14 +102,14 @@ describe('fullName', () => {
|
|
|
95
102
|
describe('strategyLabel', () => {
|
|
96
103
|
it('returns strategy string', () => {
|
|
97
104
|
const cmd = {
|
|
98
|
-
site: 'test', name: 'test', description: '', args: [],
|
|
105
|
+
site: 'test', name: 'test', access: 'read', description: '', args: [],
|
|
99
106
|
strategy: Strategy.INTERCEPT,
|
|
100
107
|
};
|
|
101
108
|
expect(strategyLabel(cmd)).toBe('intercept');
|
|
102
109
|
});
|
|
103
110
|
it('returns public when no strategy set', () => {
|
|
104
111
|
const cmd = {
|
|
105
|
-
site: 'test', name: 'test', description: '', args: [],
|
|
112
|
+
site: 'test', name: 'test', access: 'read', description: '', args: [],
|
|
106
113
|
};
|
|
107
114
|
expect(strategyLabel(cmd)).toBe('public');
|
|
108
115
|
});
|
|
@@ -111,7 +118,7 @@ describe('registerCommand', () => {
|
|
|
111
118
|
it('registers a pre-built command', () => {
|
|
112
119
|
const cmd = {
|
|
113
120
|
site: 'test-registry',
|
|
114
|
-
name: 'direct-reg',
|
|
121
|
+
name: 'direct-reg', access: 'read',
|
|
115
122
|
description: 'directly registered',
|
|
116
123
|
args: [],
|
|
117
124
|
strategy: Strategy.HEADER,
|
|
@@ -125,7 +132,7 @@ describe('registerCommand', () => {
|
|
|
125
132
|
describe('normalizeCommand (via registerCommand)', () => {
|
|
126
133
|
it('COOKIE + domain → navigateBefore is the domain URL', () => {
|
|
127
134
|
registerCommand({
|
|
128
|
-
site: 'test-norm', name: 'cookie-domain', description: '', args: [],
|
|
135
|
+
site: 'test-norm', name: 'cookie-domain', access: 'read', description: '', args: [],
|
|
129
136
|
strategy: Strategy.COOKIE, domain: 'x.com',
|
|
130
137
|
});
|
|
131
138
|
const cmd = getRegistry().get('test-norm/cookie-domain');
|
|
@@ -134,7 +141,7 @@ describe('normalizeCommand (via registerCommand)', () => {
|
|
|
134
141
|
});
|
|
135
142
|
it('COOKIE without domain → navigateBefore is true (auth context, no URL)', () => {
|
|
136
143
|
registerCommand({
|
|
137
|
-
site: 'test-norm', name: 'cookie-nodomain', description: '', args: [],
|
|
144
|
+
site: 'test-norm', name: 'cookie-nodomain', access: 'read', description: '', args: [],
|
|
138
145
|
strategy: Strategy.COOKIE,
|
|
139
146
|
});
|
|
140
147
|
const cmd = getRegistry().get('test-norm/cookie-nodomain');
|
|
@@ -143,7 +150,7 @@ describe('normalizeCommand (via registerCommand)', () => {
|
|
|
143
150
|
});
|
|
144
151
|
it('INTERCEPT → navigateBefore is true (auth context)', () => {
|
|
145
152
|
registerCommand({
|
|
146
|
-
site: 'test-norm', name: 'intercept', description: '', args: [],
|
|
153
|
+
site: 'test-norm', name: 'intercept', access: 'read', description: '', args: [],
|
|
147
154
|
strategy: Strategy.INTERCEPT, domain: 'example.com',
|
|
148
155
|
});
|
|
149
156
|
const cmd = getRegistry().get('test-norm/intercept');
|
|
@@ -152,7 +159,7 @@ describe('normalizeCommand (via registerCommand)', () => {
|
|
|
152
159
|
});
|
|
153
160
|
it('PUBLIC → browser false, navigateBefore undefined', () => {
|
|
154
161
|
registerCommand({
|
|
155
|
-
site: 'test-norm', name: 'public', description: '', args: [],
|
|
162
|
+
site: 'test-norm', name: 'public', access: 'read', description: '', args: [],
|
|
156
163
|
strategy: Strategy.PUBLIC,
|
|
157
164
|
});
|
|
158
165
|
const cmd = getRegistry().get('test-norm/public');
|
|
@@ -161,7 +168,7 @@ describe('normalizeCommand (via registerCommand)', () => {
|
|
|
161
168
|
});
|
|
162
169
|
it('LOCAL → browser false, navigateBefore undefined', () => {
|
|
163
170
|
registerCommand({
|
|
164
|
-
site: 'test-norm', name: 'local', description: '', args: [],
|
|
171
|
+
site: 'test-norm', name: 'local', access: 'read', description: '', args: [],
|
|
165
172
|
strategy: Strategy.LOCAL,
|
|
166
173
|
});
|
|
167
174
|
const cmd = getRegistry().get('test-norm/local');
|
|
@@ -172,7 +179,7 @@ describe('normalizeCommand (via registerCommand)', () => {
|
|
|
172
179
|
});
|
|
173
180
|
it('explicit navigateBefore: false overrides COOKIE + domain', () => {
|
|
174
181
|
registerCommand({
|
|
175
|
-
site: 'test-norm', name: 'cookie-override', description: '', args: [],
|
|
182
|
+
site: 'test-norm', name: 'cookie-override', access: 'read', description: '', args: [],
|
|
176
183
|
strategy: Strategy.COOKIE, domain: 'amazon.com', navigateBefore: false,
|
|
177
184
|
});
|
|
178
185
|
const cmd = getRegistry().get('test-norm/cookie-override');
|
|
@@ -181,7 +188,7 @@ describe('normalizeCommand (via registerCommand)', () => {
|
|
|
181
188
|
});
|
|
182
189
|
it('explicit navigateBefore URL overrides strategy default', () => {
|
|
183
190
|
registerCommand({
|
|
184
|
-
site: 'test-norm', name: 'explicit-url', description: '', args: [],
|
|
191
|
+
site: 'test-norm', name: 'explicit-url', access: 'read', description: '', args: [],
|
|
185
192
|
strategy: Strategy.COOKIE, domain: 'x.com',
|
|
186
193
|
navigateBefore: 'https://x.com/explore',
|
|
187
194
|
});
|
|
@@ -24,15 +24,19 @@ export declare function serializeCommand(cmd: CliCommand): {
|
|
|
24
24
|
name: string;
|
|
25
25
|
aliases: string[];
|
|
26
26
|
description: string;
|
|
27
|
+
access: import("./registry.js").CommandAccess;
|
|
27
28
|
strategy: string;
|
|
28
29
|
browser: boolean;
|
|
29
30
|
args: SerializedArg[];
|
|
30
31
|
columns: string[];
|
|
31
32
|
domain: string | null;
|
|
33
|
+
example: string;
|
|
32
34
|
deprecated: string | boolean | null;
|
|
33
35
|
replacedBy: string | null;
|
|
34
36
|
};
|
|
35
37
|
/** Human-readable arg summary: `<required> [optional]` style. */
|
|
36
38
|
export declare function formatArgSummary(args: Arg[]): string;
|
|
39
|
+
/** Agent-facing canonical invocation. Adapter authors may override with `example`. */
|
|
40
|
+
export declare function formatCommandExample(cmd: CliCommand): string;
|
|
37
41
|
/** Generate the --help appendix showing registry metadata not exposed by Commander. */
|
|
38
42
|
export declare function formatRegistryHelpText(cmd: CliCommand): string;
|
|
@@ -26,11 +26,13 @@ export function serializeCommand(cmd) {
|
|
|
26
26
|
name: cmd.name,
|
|
27
27
|
aliases: cmd.aliases ?? [],
|
|
28
28
|
description: cmd.description,
|
|
29
|
+
access: cmd.access,
|
|
29
30
|
strategy: strategyLabel(cmd),
|
|
30
31
|
browser: !!cmd.browser,
|
|
31
32
|
args: cmd.args.map(serializeArg),
|
|
32
33
|
columns: cmd.columns ?? [],
|
|
33
34
|
domain: cmd.domain ?? null,
|
|
35
|
+
example: formatCommandExample(cmd),
|
|
34
36
|
deprecated: cmd.deprecated ?? null,
|
|
35
37
|
replacedBy: cmd.replacedBy ?? null,
|
|
36
38
|
};
|
|
@@ -51,6 +53,29 @@ function summarizeChoices(choices) {
|
|
|
51
53
|
return choices.join(', ');
|
|
52
54
|
return `${choices.slice(0, 4).join(', ')}, ... (+${choices.length - 4} more)`;
|
|
53
55
|
}
|
|
56
|
+
function formatValuePlaceholder(name) {
|
|
57
|
+
return `<${name}>`;
|
|
58
|
+
}
|
|
59
|
+
/** Agent-facing canonical invocation. Adapter authors may override with `example`. */
|
|
60
|
+
export function formatCommandExample(cmd) {
|
|
61
|
+
if (cmd.example?.trim())
|
|
62
|
+
return cmd.example.trim();
|
|
63
|
+
const parts = ['opencli', cmd.site, cmd.name];
|
|
64
|
+
for (const arg of cmd.args) {
|
|
65
|
+
if (arg.positional && arg.required) {
|
|
66
|
+
parts.push(formatValuePlaceholder(arg.name));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
for (const arg of cmd.args) {
|
|
70
|
+
if (arg.positional || !arg.required)
|
|
71
|
+
continue;
|
|
72
|
+
parts.push(`--${arg.name}`);
|
|
73
|
+
if (arg.type !== 'bool' && arg.type !== 'boolean')
|
|
74
|
+
parts.push(formatValuePlaceholder(arg.name));
|
|
75
|
+
}
|
|
76
|
+
parts.push('-f', 'yaml');
|
|
77
|
+
return parts.join(' ');
|
|
78
|
+
}
|
|
54
79
|
/** Generate the --help appendix showing registry metadata not exposed by Commander. */
|
|
55
80
|
export function formatRegistryHelpText(cmd) {
|
|
56
81
|
const lines = [];
|
|
@@ -61,7 +86,7 @@ export function formatRegistryHelpText(cmd) {
|
|
|
61
86
|
lines.push(` ${prefix}: ${summarizeChoices(a.choices)}${def}`);
|
|
62
87
|
}
|
|
63
88
|
const meta = [];
|
|
64
|
-
meta.push(`
|
|
89
|
+
meta.push(`Access: ${cmd.access}`);
|
|
65
90
|
meta.push(`Browser: ${cmd.browser ? 'yes' : 'no'}`);
|
|
66
91
|
if (cmd.domain)
|
|
67
92
|
meta.push(`Domain: ${cmd.domain}`);
|
|
@@ -72,6 +97,7 @@ export function formatRegistryHelpText(cmd) {
|
|
|
72
97
|
if (cmd.aliases?.length)
|
|
73
98
|
meta.push(`Aliases: ${cmd.aliases.join(', ')}`);
|
|
74
99
|
lines.push(meta.join(' | '));
|
|
100
|
+
lines.push(`Example: ${formatCommandExample(cmd)}`);
|
|
75
101
|
if (cmd.columns?.length)
|
|
76
102
|
lines.push(`Output columns: ${cmd.columns.join(', ')}`);
|
|
77
103
|
return '\n' + lines.join('\n') + '\n';
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
2
|
import { Strategy } from './registry.js';
|
|
3
|
-
import { formatRegistryHelpText, serializeCommand } from './serialization.js';
|
|
3
|
+
import { formatCommandExample, formatRegistryHelpText, serializeCommand } from './serialization.js';
|
|
4
4
|
describe('formatRegistryHelpText', () => {
|
|
5
5
|
it('summarizes long choices lists so help text stays readable', () => {
|
|
6
6
|
const cmd = {
|
|
7
7
|
site: 'demo',
|
|
8
|
-
name: 'dynamic',
|
|
8
|
+
name: 'dynamic', access: 'read',
|
|
9
9
|
description: 'Demo command',
|
|
10
10
|
strategy: Strategy.PUBLIC,
|
|
11
11
|
browser: false,
|
|
@@ -24,6 +24,7 @@ describe('formatRegistryHelpText', () => {
|
|
|
24
24
|
const cmd = {
|
|
25
25
|
site: 'demo',
|
|
26
26
|
name: 'get',
|
|
27
|
+
access: 'read',
|
|
27
28
|
aliases: ['metadata'],
|
|
28
29
|
description: 'Demo command',
|
|
29
30
|
strategy: Strategy.COOKIE,
|
|
@@ -32,8 +33,29 @@ describe('formatRegistryHelpText', () => {
|
|
|
32
33
|
};
|
|
33
34
|
expect(serializeCommand(cmd)).toMatchObject({
|
|
34
35
|
command: 'demo/get',
|
|
36
|
+
access: 'read',
|
|
35
37
|
aliases: ['metadata'],
|
|
36
38
|
});
|
|
37
39
|
expect(formatRegistryHelpText(cmd)).toContain('Aliases: metadata');
|
|
38
40
|
});
|
|
41
|
+
it('surfaces access and canonical examples instead of strategy as primary help metadata', () => {
|
|
42
|
+
const cmd = {
|
|
43
|
+
site: 'bilibili',
|
|
44
|
+
name: 'hot',
|
|
45
|
+
access: 'read',
|
|
46
|
+
description: 'Bilibili hot videos',
|
|
47
|
+
strategy: Strategy.COOKIE,
|
|
48
|
+
browser: true,
|
|
49
|
+
args: [],
|
|
50
|
+
};
|
|
51
|
+
expect(formatCommandExample(cmd)).toBe('opencli bilibili hot -f yaml');
|
|
52
|
+
expect(serializeCommand(cmd)).toMatchObject({
|
|
53
|
+
command: 'bilibili/hot',
|
|
54
|
+
access: 'read',
|
|
55
|
+
example: 'opencli bilibili hot -f yaml',
|
|
56
|
+
});
|
|
57
|
+
expect(formatRegistryHelpText(cmd)).toContain('Access: read');
|
|
58
|
+
expect(formatRegistryHelpText(cmd)).toContain('Example: opencli bilibili hot -f yaml');
|
|
59
|
+
expect(formatRegistryHelpText(cmd)).not.toContain('Strategy:');
|
|
60
|
+
});
|
|
39
61
|
});
|
package/dist/src/types.d.ts
CHANGED
|
@@ -130,6 +130,8 @@ export interface IPage {
|
|
|
130
130
|
setActivePage?(page?: string): void;
|
|
131
131
|
/** Send a raw CDP command via chrome.debugger passthrough. */
|
|
132
132
|
cdp?(method: string, params?: Record<string, unknown>): Promise<unknown>;
|
|
133
|
+
/** Accept or dismiss the currently open JavaScript alert/confirm/prompt dialog. */
|
|
134
|
+
handleJavaScriptDialog?(accept: boolean, promptText?: string): Promise<void>;
|
|
133
135
|
/** List cross-origin iframe targets in snapshot order. */
|
|
134
136
|
frames?(): Promise<Array<{
|
|
135
137
|
index: number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jackwener/opencli",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.12",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"dev": "tsx src/main.ts",
|
|
43
43
|
"dev:bun": "bun src/main.ts",
|
|
44
44
|
"build": "npm run clean-dist && tsc && npm run copy-yaml && npm run build-manifest",
|
|
45
|
-
"build-manifest": "
|
|
45
|
+
"build-manifest": "tsx src/build-manifest.ts",
|
|
46
46
|
"clean-dist": "node scripts/clean-dist.cjs",
|
|
47
47
|
"copy-yaml": "node scripts/copy-yaml.cjs",
|
|
48
48
|
"start": "node dist/src/main.js",
|
|
@@ -57,6 +57,9 @@
|
|
|
57
57
|
"test:adapter": "vitest run --project adapter",
|
|
58
58
|
"test:all": "vitest run",
|
|
59
59
|
"test:e2e": "vitest run --project e2e",
|
|
60
|
+
"advise:listing-id-pairing": "node scripts/check-listing-id-pairing.mjs",
|
|
61
|
+
"check:silent-column-drop": "node scripts/check-silent-column-drop.mjs",
|
|
62
|
+
"check:typed-error-lint": "node scripts/check-typed-error-lint.mjs",
|
|
60
63
|
"docs:dev": "vitepress dev docs",
|
|
61
64
|
"docs:build": "vitepress build docs",
|
|
62
65
|
"docs:preview": "vitepress preview docs"
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* check-listing-id-pairing.mjs — advisory report on listing↔detail id round-tripping.
|
|
4
|
+
*
|
|
5
|
+
* Soft convention (NOT a CI gate): when a site exposes both a listing-class
|
|
6
|
+
* command (search / hot / recent / trending / top / feed / popular / new /
|
|
7
|
+
* list) AND a detail-class command (read / article / paper / post / detail /
|
|
8
|
+
* view / job / page / book / movie / show / chapter / question / answer /
|
|
9
|
+
* tweet / video / track), it's usually nicer for agents if every listing row
|
|
10
|
+
* carries an id-shaped column whose value round-trips into the detail
|
|
11
|
+
* command. Without that, the agent has to re-search by title or scrape a URL
|
|
12
|
+
* to follow up.
|
|
13
|
+
*
|
|
14
|
+
* Why advisory and not a gate: whether a listing should pair with a detail
|
|
15
|
+
* is a case-by-case product/UX call (topic-string trending, profile-attribute
|
|
16
|
+
* key/value rows, UI-only sessions etc. legitimately don't pair). Forcing
|
|
17
|
+
* authors through an exempt list every PR was higher cognitive cost than the
|
|
18
|
+
* silent-loss bugs the rule actually catches. See PR #1311 thread for the
|
|
19
|
+
* "anti-pattern vs case-by-case" filter.
|
|
20
|
+
*
|
|
21
|
+
* What this script does:
|
|
22
|
+
* 1. Group cli-manifest.json entries by site.
|
|
23
|
+
* 2. For each site that has both classes, walk every listing entry and
|
|
24
|
+
* check `columns` for at least one id-shaped name.
|
|
25
|
+
* 3. Print a report. Always exits 0 — never fails CI.
|
|
26
|
+
*
|
|
27
|
+
* Usage:
|
|
28
|
+
* node scripts/check-listing-id-pairing.mjs # print advisory report
|
|
29
|
+
* npm run advise:listing-id-pairing
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import { readFileSync } from 'node:fs';
|
|
33
|
+
import { fileURLToPath } from 'node:url';
|
|
34
|
+
import { dirname, resolve } from 'node:path';
|
|
35
|
+
|
|
36
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
37
|
+
const MANIFEST = resolve(__dirname, '..', 'cli-manifest.json');
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Listing-class commands. Each row represents a single fetchable entity
|
|
41
|
+
* (post / paper / job / ...). The id of that entity must round-trip into
|
|
42
|
+
* the site's detail command.
|
|
43
|
+
*/
|
|
44
|
+
const LISTING_NAMES = new Set([
|
|
45
|
+
'search', 'hot', 'recent', 'trending', 'top', 'feed', 'popular',
|
|
46
|
+
'list', 'best', 'newest', 'latest', 'rising', 'controversial',
|
|
47
|
+
'home', 'timeline', 'browse', 'discover', 'jobs',
|
|
48
|
+
'unanswered', 'bounties', 'tag', 'user', 'venue',
|
|
49
|
+
'category', 'subreddit', 'question',
|
|
50
|
+
]);
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Listing-class commands whose rows are sub-resources within a parent
|
|
54
|
+
* thread/session, NOT independently fetchable. Excluded from the rule:
|
|
55
|
+
*
|
|
56
|
+
* - `comments` / `replies` / `reviews` / `answer-list` / `thread-list`
|
|
57
|
+
* — rows are comments under a parent post; the detail command fetches
|
|
58
|
+
* the parent, not the comment
|
|
59
|
+
* - `ask` / `new` / `show` for AI-chat / agent-session sites — rows are
|
|
60
|
+
* conversation turns within one session, not separately addressable
|
|
61
|
+
*
|
|
62
|
+
* These are intentionally NOT in `LISTING_NAMES` so the rule doesn't
|
|
63
|
+
* fire on them.
|
|
64
|
+
*/
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
const DETAIL_NAMES = new Set([
|
|
68
|
+
'read', 'article', 'paper', 'post', 'detail', 'view', 'job',
|
|
69
|
+
'page', 'book', 'movie', 'show-detail', 'chapter', 'tweet',
|
|
70
|
+
'video', 'track', 'note', 'review', 'item', 'product', 'episode',
|
|
71
|
+
'thread', 'comment-detail', 'profile-detail', 'shop',
|
|
72
|
+
]);
|
|
73
|
+
|
|
74
|
+
/** Columns whose name implies "this is an id you can pass to detail". */
|
|
75
|
+
const ID_COLUMN_PATTERNS = [
|
|
76
|
+
/^id$/i,
|
|
77
|
+
/_id$/i,
|
|
78
|
+
/Id$/,
|
|
79
|
+
/^short_id$/i,
|
|
80
|
+
/^jk$/i, // indeed
|
|
81
|
+
/^tid$/i, // hupu / thread id
|
|
82
|
+
/^bvid$/i, // bilibili
|
|
83
|
+
/^aid$/i, // anime / bilibili av
|
|
84
|
+
/^asin$/i, // amazon
|
|
85
|
+
/^sku$/i, // jd / retail product SKU
|
|
86
|
+
/^isbn$/i, // book sites
|
|
87
|
+
/^doi$/i, // arxiv / openreview
|
|
88
|
+
/^slug$/i, // dev.to / lobsters short slug
|
|
89
|
+
/^hn_id$/i,
|
|
90
|
+
/^username$/i, // user-keyed detail (profile commands)
|
|
91
|
+
/^handle$/i,
|
|
92
|
+
/^uri$/i, // bluesky AT URI (at://did:.../...)
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
function isUrlDetailCommand(entry) {
|
|
96
|
+
const args = Array.isArray(entry.args) ? entry.args : [];
|
|
97
|
+
const primaryArg = args.find((arg) => arg?.positional || arg?.required) ?? args[0];
|
|
98
|
+
if (!primaryArg) return false;
|
|
99
|
+
const name = String(primaryArg.name ?? '').toLowerCase();
|
|
100
|
+
if (name === 'url' || name === 'url-or-id') return true;
|
|
101
|
+
|
|
102
|
+
const help = String(primaryArg.help ?? '').toLowerCase();
|
|
103
|
+
if (!help) return false;
|
|
104
|
+
|
|
105
|
+
// Accept only explicit "this argument may be a URL" wording. Phrases
|
|
106
|
+
// like "id from URL" mean callers must extract an id before invoking
|
|
107
|
+
// the detail command, so listing.url must not satisfy the id-pair gate.
|
|
108
|
+
return (
|
|
109
|
+
/^full\b[^()]*\burl\b/.test(help) ||
|
|
110
|
+
/\burl\s+or\s+[^()]*\bid\b/.test(help) ||
|
|
111
|
+
/\bor\s+(?:a\s+)?full\b[^()]*\burl\b/.test(help) ||
|
|
112
|
+
/\bor\s+url\b/.test(help) ||
|
|
113
|
+
/\burl\s*,\s*or\b/.test(help)
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function isIdColumn(col, detailCommands) {
|
|
118
|
+
if (ID_COLUMN_PATTERNS.some((re) => re.test(col))) return true;
|
|
119
|
+
if (/^url$/i.test(col)) {
|
|
120
|
+
return detailCommands.some(isUrlDetailCommand);
|
|
121
|
+
}
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function classify(name) {
|
|
126
|
+
if (LISTING_NAMES.has(name)) return 'listing';
|
|
127
|
+
if (DETAIL_NAMES.has(name)) return 'detail';
|
|
128
|
+
return 'other';
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function main() {
|
|
132
|
+
const manifest = JSON.parse(readFileSync(MANIFEST, 'utf8'));
|
|
133
|
+
|
|
134
|
+
const bySite = new Map();
|
|
135
|
+
for (const entry of manifest) {
|
|
136
|
+
if (!entry?.site || !entry?.name) continue;
|
|
137
|
+
if (!bySite.has(entry.site)) bySite.set(entry.site, []);
|
|
138
|
+
bySite.get(entry.site).push(entry);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const findings = [];
|
|
142
|
+
let scannedSites = 0;
|
|
143
|
+
let scannedListings = 0;
|
|
144
|
+
|
|
145
|
+
for (const [site, entries] of bySite) {
|
|
146
|
+
// Only `access: 'read'` detail commands count — write commands like
|
|
147
|
+
// `instagram/post` or `instagram/note` create remote state, they don't
|
|
148
|
+
// fetch by id, so the listing→detail pairing rule doesn't apply.
|
|
149
|
+
const readDetail = entries.filter(
|
|
150
|
+
(e) => classify(e.name) === 'detail' && e.access === 'read',
|
|
151
|
+
);
|
|
152
|
+
const hasListing = entries.some((e) => classify(e.name) === 'listing');
|
|
153
|
+
if (!hasListing || readDetail.length === 0) continue;
|
|
154
|
+
scannedSites++;
|
|
155
|
+
|
|
156
|
+
for (const entry of entries) {
|
|
157
|
+
if (classify(entry.name) !== 'listing') continue;
|
|
158
|
+
scannedListings++;
|
|
159
|
+
const columns = Array.isArray(entry.columns) ? entry.columns : [];
|
|
160
|
+
if (!columns.some((col) => isIdColumn(col, readDetail))) {
|
|
161
|
+
findings.push({
|
|
162
|
+
site,
|
|
163
|
+
name: entry.name,
|
|
164
|
+
columns,
|
|
165
|
+
detail: readDetail.map((e) => e.name),
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
console.log(`Scanned ${scannedSites} site(s) with both listing and read-detail commands.`);
|
|
172
|
+
console.log(`Checked ${scannedListings} listing command(s).`);
|
|
173
|
+
|
|
174
|
+
if (findings.length === 0) {
|
|
175
|
+
console.log('OK — every listing carries an id-shaped column.');
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
console.log('');
|
|
180
|
+
console.log(`Advisory: ${findings.length} listing(s) without a round-trippable id column.`);
|
|
181
|
+
console.log('Some of these are legitimate (topic strings, profile-attribute rows, UI-only');
|
|
182
|
+
console.log('sessions); others may be worth adding an id to. Use judgment, not a gate.');
|
|
183
|
+
console.log('');
|
|
184
|
+
for (const v of findings) {
|
|
185
|
+
console.log(` • ${v.site}/${v.name}`);
|
|
186
|
+
console.log(` columns: [${v.columns.join(', ')}]`);
|
|
187
|
+
console.log(` detail commands on this site: ${v.detail.join(', ')}`);
|
|
188
|
+
}
|
|
189
|
+
console.log('');
|
|
190
|
+
console.log('See docs/conventions/listing-detail-id-pairing.md for context and patterns.');
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
main();
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* check-silent-column-drop.mjs — CI gate for newly introduced table-output loss.
|
|
4
|
+
*
|
|
5
|
+
* This gate intentionally uses a baseline. The repo currently has known
|
|
6
|
+
* silent-column-drop findings, and blocking every existing violation would make
|
|
7
|
+
* the first CI adoption PR too large. The invariant enforced here is:
|
|
8
|
+
*
|
|
9
|
+
* no new silent-column-drop signatures beyond scripts/silent-column-drop-baseline.json
|
|
10
|
+
*
|
|
11
|
+
* When a follow-up sweep fixes existing violations, run:
|
|
12
|
+
*
|
|
13
|
+
* node scripts/check-silent-column-drop.mjs --update-baseline
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
17
|
+
import { dirname, resolve } from 'node:path';
|
|
18
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
19
|
+
|
|
20
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
21
|
+
const PROJECT_ROOT = resolve(__dirname, '..');
|
|
22
|
+
const DIST_AUDIT = resolve(PROJECT_ROOT, 'dist', 'src', 'convention-audit.js');
|
|
23
|
+
const BASELINE_PATH = resolve(__dirname, 'silent-column-drop-baseline.json');
|
|
24
|
+
const UPDATE = process.argv.includes('--update-baseline');
|
|
25
|
+
|
|
26
|
+
if (!existsSync(DIST_AUDIT)) {
|
|
27
|
+
console.error('dist/src/convention-audit.js not found. Run npm run build before this check.');
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const { runConventionAudit } = await import(pathToFileURL(DIST_AUDIT).href);
|
|
32
|
+
const report = runConventionAudit({ projectRoot: PROJECT_ROOT });
|
|
33
|
+
const category = report.categories.find((item) => item.rule === 'silent-column-drop');
|
|
34
|
+
const current = sortRecords((category?.violations ?? []).map(toBaselineRecord));
|
|
35
|
+
|
|
36
|
+
if (UPDATE) {
|
|
37
|
+
writeFileSync(BASELINE_PATH, `${JSON.stringify(current, null, 2)}\n`);
|
|
38
|
+
console.log(`Updated ${relative(BASELINE_PATH)} with ${current.length} silent-column-drop baseline entr${current.length === 1 ? 'y' : 'ies'}.`);
|
|
39
|
+
process.exit(0);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!existsSync(BASELINE_PATH)) {
|
|
43
|
+
console.error(`${relative(BASELINE_PATH)} not found. Run node scripts/check-silent-column-drop.mjs --update-baseline.`);
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const baseline = sortRecords(JSON.parse(readFileSync(BASELINE_PATH, 'utf-8')));
|
|
48
|
+
const baselineSignatures = new Set(baseline.map(signature));
|
|
49
|
+
const currentSignatures = new Set(current.map(signature));
|
|
50
|
+
const added = current.filter((record) => !baselineSignatures.has(signature(record)));
|
|
51
|
+
const resolved = baseline.filter((record) => !currentSignatures.has(signature(record)));
|
|
52
|
+
|
|
53
|
+
console.log(`Silent-column-drop gate: current=${current.length}, baseline=${baseline.length}, new=${added.length}, resolved=${resolved.length}`);
|
|
54
|
+
|
|
55
|
+
if (resolved.length > 0) {
|
|
56
|
+
console.log('');
|
|
57
|
+
console.log('Resolved baseline entries detected. Consider shrinking the baseline:');
|
|
58
|
+
for (const record of resolved) {
|
|
59
|
+
console.log(` - ${record.command} ${record.file} missing=[${record.missing.join(', ')}]`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (added.length === 0) {
|
|
64
|
+
console.log('OK - no new silent-column-drop violations.');
|
|
65
|
+
process.exit(0);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
console.log('');
|
|
69
|
+
console.log('New silent-column-drop violations:');
|
|
70
|
+
for (const record of added) {
|
|
71
|
+
console.log(` - ${record.command} ${record.file} missing=[${record.missing.join(', ')}]`);
|
|
72
|
+
}
|
|
73
|
+
console.log('');
|
|
74
|
+
console.log('Fix the adapter columns, or if this is an intentional baseline adoption, run:');
|
|
75
|
+
console.log(' node scripts/check-silent-column-drop.mjs --update-baseline');
|
|
76
|
+
process.exit(1);
|
|
77
|
+
|
|
78
|
+
function toBaselineRecord(violation) {
|
|
79
|
+
const missing = Array.isArray(violation.details?.missing)
|
|
80
|
+
? violation.details.missing.map(String).sort()
|
|
81
|
+
: [];
|
|
82
|
+
return {
|
|
83
|
+
command: String(violation.command ?? ''),
|
|
84
|
+
file: String(violation.file ?? ''),
|
|
85
|
+
missing,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function signature(record) {
|
|
90
|
+
return `${record.command}\0${record.file}\0${record.missing.join('\0')}`;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function sortRecords(records) {
|
|
94
|
+
return records
|
|
95
|
+
.map((record) => ({
|
|
96
|
+
command: String(record.command),
|
|
97
|
+
file: String(record.file),
|
|
98
|
+
missing: Array.isArray(record.missing) ? record.missing.map(String).sort() : [],
|
|
99
|
+
}))
|
|
100
|
+
.sort((a, b) => signature(a).localeCompare(signature(b)));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function relative(file) {
|
|
104
|
+
return file.replace(`${PROJECT_ROOT}/`, '');
|
|
105
|
+
}
|