@jackwener/opencli 1.6.8 → 1.6.10
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 +117 -59
- package/README.zh-CN.md +123 -79
- package/dist/clis/_shared/common.d.ts +3 -0
- package/dist/clis/_shared/common.js +22 -0
- package/dist/clis/bilibili/hot.d.ts +1 -0
- package/dist/clis/bilibili/hot.js +35 -0
- package/dist/clis/bluesky/feeds.d.ts +1 -0
- package/dist/clis/bluesky/feeds.js +27 -0
- package/dist/clis/bluesky/followers.d.ts +1 -0
- package/dist/clis/bluesky/followers.js +27 -0
- package/dist/clis/bluesky/following.d.ts +1 -0
- package/dist/clis/bluesky/following.js +27 -0
- package/dist/clis/bluesky/profile.d.ts +1 -0
- package/dist/clis/bluesky/profile.js +29 -0
- package/dist/clis/bluesky/search.d.ts +1 -0
- package/dist/clis/bluesky/search.js +28 -0
- package/dist/clis/bluesky/starter-packs.d.ts +1 -0
- package/dist/clis/bluesky/starter-packs.js +28 -0
- package/dist/clis/bluesky/thread.d.ts +1 -0
- package/dist/clis/bluesky/thread.js +30 -0
- package/dist/clis/bluesky/trending.d.ts +1 -0
- package/dist/clis/bluesky/trending.js +19 -0
- package/dist/clis/bluesky/user.d.ts +1 -0
- package/dist/clis/bluesky/user.js +33 -0
- package/dist/clis/cnki/search.d.ts +1 -0
- package/dist/clis/cnki/search.js +60 -0
- package/dist/clis/cnki/search.test.d.ts +1 -0
- package/dist/clis/cnki/search.test.js +18 -0
- package/dist/clis/devto/tag.d.ts +1 -0
- package/dist/clis/devto/tag.js +32 -0
- package/dist/clis/devto/top.d.ts +1 -0
- package/dist/clis/devto/top.js +26 -0
- package/dist/clis/devto/user.d.ts +1 -0
- package/dist/clis/devto/user.js +31 -0
- package/dist/clis/dictionary/examples.d.ts +1 -0
- package/dist/clis/dictionary/examples.js +27 -0
- package/dist/clis/dictionary/search.d.ts +1 -0
- package/dist/clis/dictionary/search.js +29 -0
- package/dist/clis/dictionary/synonyms.d.ts +1 -0
- package/dist/clis/dictionary/synonyms.js +27 -0
- package/dist/clis/douban/subject.d.ts +1 -0
- package/dist/clis/douban/subject.js +118 -0
- package/dist/clis/douban/top250.d.ts +1 -0
- package/dist/clis/douban/top250.js +67 -0
- package/dist/clis/facebook/add-friend.d.ts +1 -0
- package/dist/clis/facebook/add-friend.js +43 -0
- package/dist/clis/facebook/events.d.ts +1 -0
- package/dist/clis/facebook/events.js +40 -0
- package/dist/clis/facebook/feed.d.ts +1 -0
- package/dist/clis/facebook/feed.js +59 -0
- package/dist/clis/facebook/friends.d.ts +1 -0
- package/dist/clis/facebook/friends.js +38 -0
- package/dist/clis/facebook/groups.d.ts +1 -0
- package/dist/clis/facebook/groups.js +46 -0
- package/dist/clis/facebook/join-group.d.ts +1 -0
- package/dist/clis/facebook/join-group.js +44 -0
- package/dist/clis/facebook/memories.d.ts +1 -0
- package/dist/clis/facebook/memories.js +35 -0
- package/dist/clis/facebook/notifications.d.ts +1 -0
- package/dist/clis/facebook/notifications.js +36 -0
- package/dist/clis/facebook/profile.d.ts +1 -0
- package/dist/clis/facebook/profile.js +37 -0
- package/dist/clis/facebook/search.d.ts +1 -0
- package/dist/clis/facebook/search.js +38 -0
- package/dist/clis/facebook/search.test.d.ts +1 -1
- package/dist/clis/facebook/search.test.js +6 -9
- package/dist/clis/gitee/index.d.ts +3 -0
- package/dist/clis/gitee/index.js +3 -0
- package/dist/clis/gitee/search.d.ts +1 -0
- package/dist/clis/gitee/search.js +136 -0
- package/dist/clis/gitee/trending.d.ts +1 -0
- package/dist/clis/gitee/trending.js +567 -0
- package/dist/clis/gitee/user.d.ts +1 -0
- package/dist/clis/gitee/user.js +199 -0
- package/dist/clis/gitee/user.test.d.ts +1 -0
- package/dist/clis/gitee/user.test.js +63 -0
- package/dist/clis/hackernews/ask.d.ts +1 -0
- package/dist/clis/hackernews/ask.js +29 -0
- package/dist/clis/hackernews/best.d.ts +1 -0
- package/dist/clis/hackernews/best.js +29 -0
- package/dist/clis/hackernews/jobs.d.ts +1 -0
- package/dist/clis/hackernews/jobs.js +27 -0
- package/dist/clis/hackernews/new.d.ts +1 -0
- package/dist/clis/hackernews/new.js +29 -0
- package/dist/clis/hackernews/search.d.ts +1 -0
- package/dist/clis/hackernews/search.js +36 -0
- package/dist/clis/hackernews/show.d.ts +1 -0
- package/dist/clis/hackernews/show.js +29 -0
- package/dist/clis/hackernews/top.d.ts +1 -0
- package/dist/clis/hackernews/top.js +29 -0
- package/dist/clis/hackernews/user.d.ts +1 -0
- package/dist/clis/hackernews/user.js +22 -0
- package/dist/clis/hupu/hot.d.ts +1 -0
- package/dist/clis/hupu/hot.js +40 -0
- package/dist/clis/instagram/comment.d.ts +1 -0
- package/dist/clis/instagram/comment.js +47 -0
- package/dist/clis/instagram/explore.d.ts +1 -0
- package/dist/clis/instagram/explore.js +41 -0
- package/dist/clis/instagram/follow.d.ts +1 -0
- package/dist/clis/instagram/follow.js +43 -0
- package/dist/clis/instagram/followers.d.ts +1 -0
- package/dist/clis/instagram/followers.js +45 -0
- package/dist/clis/instagram/following.d.ts +1 -0
- package/dist/clis/instagram/following.js +45 -0
- package/dist/clis/instagram/like.d.ts +1 -0
- package/dist/clis/instagram/like.js +45 -0
- package/dist/clis/instagram/profile.d.ts +1 -0
- package/dist/clis/instagram/profile.js +39 -0
- package/dist/clis/instagram/save.d.ts +1 -0
- package/dist/clis/instagram/save.js +45 -0
- package/dist/clis/instagram/saved.d.ts +1 -0
- package/dist/clis/instagram/saved.js +38 -0
- package/dist/clis/instagram/search.d.ts +1 -0
- package/dist/clis/instagram/search.js +38 -0
- package/dist/clis/instagram/unfollow.d.ts +1 -0
- package/dist/clis/instagram/unfollow.js +40 -0
- package/dist/clis/instagram/unlike.d.ts +1 -0
- package/dist/clis/instagram/unlike.js +45 -0
- package/dist/clis/instagram/unsave.d.ts +1 -0
- package/dist/clis/instagram/unsave.js +45 -0
- package/dist/clis/instagram/user.d.ts +1 -0
- package/dist/clis/instagram/user.js +48 -0
- package/dist/clis/jd/add-cart.d.ts +1 -0
- package/dist/clis/jd/add-cart.js +71 -0
- package/dist/clis/jd/cart.d.ts +1 -0
- package/dist/clis/jd/cart.js +79 -0
- package/dist/clis/jd/commands.test.d.ts +5 -0
- package/dist/clis/jd/commands.test.js +64 -0
- package/dist/clis/jd/detail.d.ts +1 -0
- package/dist/clis/jd/detail.js +62 -0
- package/dist/clis/jd/reviews.d.ts +1 -0
- package/dist/clis/jd/reviews.js +54 -0
- package/dist/clis/jd/search.d.ts +1 -0
- package/dist/clis/jd/search.js +65 -0
- package/dist/clis/jianyu/search.d.ts +14 -0
- package/dist/clis/jianyu/search.js +135 -0
- package/dist/clis/jianyu/search.test.d.ts +1 -0
- package/dist/clis/jianyu/search.test.js +23 -0
- package/dist/clis/jike/post.d.ts +1 -0
- package/dist/clis/jike/post.js +61 -0
- package/dist/clis/jike/topic.d.ts +1 -0
- package/dist/clis/jike/topic.js +51 -0
- package/dist/clis/jike/user.d.ts +1 -0
- package/dist/clis/jike/user.js +50 -0
- package/dist/clis/jimeng/generate.d.ts +1 -0
- package/dist/clis/jimeng/generate.js +83 -0
- package/dist/clis/jimeng/history.d.ts +1 -0
- package/dist/clis/jimeng/history.js +47 -0
- package/dist/clis/jimeng/new.d.ts +1 -0
- package/dist/clis/jimeng/new.js +43 -0
- package/dist/clis/jimeng/workspaces.d.ts +1 -0
- package/dist/clis/jimeng/workspaces.js +41 -0
- package/dist/clis/linux-do/categories.d.ts +1 -0
- package/dist/clis/linux-do/categories.js +65 -0
- package/dist/clis/linux-do/search.d.ts +1 -0
- package/dist/clis/linux-do/search.js +41 -0
- package/dist/clis/linux-do/tags.d.ts +1 -0
- package/dist/clis/linux-do/tags.js +39 -0
- package/dist/clis/linux-do/topic-content.test.js +5 -5
- package/dist/clis/linux-do/topic.d.ts +1 -0
- package/dist/clis/linux-do/topic.js +56 -0
- package/dist/clis/linux-do/user-posts.d.ts +1 -0
- package/dist/clis/linux-do/user-posts.js +61 -0
- package/dist/clis/linux-do/user-topics.d.ts +1 -0
- package/dist/clis/linux-do/user-topics.js +48 -0
- package/dist/clis/lobsters/active.d.ts +1 -0
- package/dist/clis/lobsters/active.js +26 -0
- package/dist/clis/lobsters/hot.d.ts +1 -0
- package/dist/clis/lobsters/hot.js +26 -0
- package/dist/clis/lobsters/newest.d.ts +1 -0
- package/dist/clis/lobsters/newest.js +26 -0
- package/dist/clis/lobsters/tag.d.ts +1 -0
- package/dist/clis/lobsters/tag.js +32 -0
- package/dist/clis/pixiv/detail.d.ts +1 -0
- package/dist/clis/pixiv/detail.js +58 -0
- package/dist/clis/pixiv/ranking.d.ts +1 -0
- package/dist/clis/pixiv/ranking.js +59 -0
- package/dist/clis/pixiv/user.d.ts +1 -0
- package/dist/clis/pixiv/user.js +52 -0
- package/dist/clis/quark/ls.d.ts +1 -0
- package/dist/clis/quark/ls.js +63 -0
- package/dist/clis/quark/mkdir.d.ts +1 -0
- package/dist/clis/quark/mkdir.js +36 -0
- package/dist/clis/quark/mv.d.ts +1 -0
- package/dist/clis/quark/mv.js +53 -0
- package/dist/clis/quark/rename.d.ts +1 -0
- package/dist/clis/quark/rename.js +26 -0
- package/dist/clis/quark/rm.d.ts +1 -0
- package/dist/clis/quark/rm.js +24 -0
- package/dist/clis/quark/save.d.ts +1 -0
- package/dist/clis/quark/save.js +80 -0
- package/dist/clis/quark/share-tree.d.ts +1 -0
- package/dist/clis/quark/share-tree.js +45 -0
- package/dist/clis/quark/utils.d.ts +50 -0
- package/dist/clis/quark/utils.js +146 -0
- package/dist/clis/quark/utils.test.d.ts +1 -0
- package/dist/clis/quark/utils.test.js +58 -0
- package/dist/clis/reddit/frontpage.d.ts +1 -0
- package/dist/clis/reddit/frontpage.js +31 -0
- package/dist/clis/reddit/hot.d.ts +1 -0
- package/dist/clis/reddit/hot.js +45 -0
- package/dist/clis/reddit/popular.d.ts +1 -0
- package/dist/clis/reddit/popular.js +41 -0
- package/dist/clis/reddit/search.d.ts +1 -0
- package/dist/clis/reddit/search.js +65 -0
- package/dist/clis/reddit/subreddit.d.ts +1 -0
- package/dist/clis/reddit/subreddit.js +52 -0
- package/dist/clis/reddit/user-comments.d.ts +1 -0
- package/dist/clis/reddit/user-comments.js +44 -0
- package/dist/clis/reddit/user-posts.d.ts +1 -0
- package/dist/clis/reddit/user-posts.js +42 -0
- package/dist/clis/reddit/user.d.ts +1 -0
- package/dist/clis/reddit/user.js +37 -0
- package/dist/clis/stackoverflow/bounties.d.ts +1 -0
- package/dist/clis/stackoverflow/bounties.js +27 -0
- package/dist/clis/stackoverflow/hot.d.ts +1 -0
- package/dist/clis/stackoverflow/hot.js +24 -0
- package/dist/clis/stackoverflow/search.d.ts +1 -0
- package/dist/clis/stackoverflow/search.js +27 -0
- package/dist/clis/stackoverflow/unanswered.d.ts +1 -0
- package/dist/clis/stackoverflow/unanswered.js +26 -0
- package/dist/clis/steam/top-sellers.d.ts +1 -0
- package/dist/clis/steam/top-sellers.js +25 -0
- package/dist/clis/taobao/add-cart.d.ts +1 -0
- package/dist/clis/taobao/add-cart.js +149 -0
- package/dist/clis/taobao/cart.d.ts +1 -0
- package/dist/clis/taobao/cart.js +95 -0
- package/dist/clis/taobao/commands.test.d.ts +5 -0
- package/dist/clis/taobao/commands.test.js +64 -0
- package/dist/clis/taobao/detail.d.ts +1 -0
- package/dist/clis/taobao/detail.js +70 -0
- package/dist/clis/taobao/reviews.d.ts +1 -0
- package/dist/clis/taobao/reviews.js +76 -0
- package/dist/clis/taobao/search.d.ts +1 -0
- package/dist/clis/taobao/search.js +96 -0
- package/dist/clis/tiktok/comment.d.ts +1 -0
- package/dist/clis/tiktok/comment.js +57 -0
- package/dist/clis/tiktok/explore.d.ts +1 -0
- package/dist/clis/tiktok/explore.js +35 -0
- package/dist/clis/tiktok/follow.d.ts +1 -0
- package/dist/clis/tiktok/follow.js +39 -0
- package/dist/clis/tiktok/following.d.ts +1 -0
- package/dist/clis/tiktok/following.js +42 -0
- package/dist/clis/tiktok/friends.d.ts +1 -0
- package/dist/clis/tiktok/friends.js +43 -0
- package/dist/clis/tiktok/like.d.ts +1 -0
- package/dist/clis/tiktok/like.js +33 -0
- package/dist/clis/tiktok/live.d.ts +1 -0
- package/dist/clis/tiktok/live.js +47 -0
- package/dist/clis/tiktok/notifications.d.ts +1 -0
- package/dist/clis/tiktok/notifications.js +49 -0
- package/dist/clis/tiktok/profile.d.ts +1 -0
- package/dist/clis/tiktok/profile.js +54 -0
- package/dist/clis/tiktok/save.d.ts +1 -0
- package/dist/clis/tiktok/save.js +29 -0
- package/dist/clis/tiktok/search.d.ts +1 -0
- package/dist/clis/tiktok/search.js +39 -0
- package/dist/clis/tiktok/unfollow.d.ts +1 -0
- package/dist/clis/tiktok/unfollow.js +44 -0
- package/dist/clis/tiktok/unlike.d.ts +1 -0
- package/dist/clis/tiktok/unlike.js +33 -0
- package/dist/clis/tiktok/unsave.d.ts +1 -0
- package/dist/clis/tiktok/unsave.js +31 -0
- package/dist/clis/tiktok/user.d.ts +1 -0
- package/dist/clis/tiktok/user.js +41 -0
- package/dist/clis/twitter/reply.js +3 -8
- package/dist/clis/twitter/reply.test.js +5 -5
- package/dist/clis/v2ex/hot.d.ts +1 -0
- package/dist/clis/v2ex/hot.js +25 -0
- package/dist/clis/v2ex/latest.d.ts +1 -0
- package/dist/clis/v2ex/latest.js +25 -0
- package/dist/clis/v2ex/member.d.ts +1 -0
- package/dist/clis/v2ex/member.js +27 -0
- package/dist/clis/v2ex/node.d.ts +1 -0
- package/dist/clis/v2ex/node.js +38 -0
- package/dist/clis/v2ex/nodes.d.ts +1 -0
- package/dist/clis/v2ex/nodes.js +25 -0
- package/dist/clis/v2ex/replies.d.ts +1 -0
- package/dist/clis/v2ex/replies.js +26 -0
- package/dist/clis/v2ex/topic.d.ts +1 -0
- package/dist/clis/v2ex/topic.js +30 -0
- package/dist/clis/v2ex/user.d.ts +1 -0
- package/dist/clis/v2ex/user.js +33 -0
- package/dist/clis/xiaoe/catalog.d.ts +1 -0
- package/dist/clis/xiaoe/catalog.js +125 -0
- package/dist/clis/xiaoe/content.d.ts +1 -0
- package/dist/clis/xiaoe/content.js +39 -0
- package/dist/clis/xiaoe/courses.d.ts +1 -0
- package/dist/clis/xiaoe/courses.js +69 -0
- package/dist/clis/xiaoe/detail.d.ts +1 -0
- package/dist/clis/xiaoe/detail.js +35 -0
- package/dist/clis/xiaoe/play-url.d.ts +1 -0
- package/dist/clis/xiaoe/play-url.js +120 -0
- package/dist/clis/xiaohongshu/feed.d.ts +1 -0
- package/dist/clis/xiaohongshu/feed.js +32 -0
- package/dist/clis/xiaohongshu/note.js +8 -3
- package/dist/clis/xiaohongshu/note.test.js +11 -0
- package/dist/clis/xiaohongshu/notifications.d.ts +1 -0
- package/dist/clis/xiaohongshu/notifications.js +38 -0
- package/dist/clis/xueqiu/earnings-date.d.ts +1 -0
- package/dist/clis/xueqiu/earnings-date.js +61 -0
- package/dist/clis/xueqiu/feed.d.ts +1 -0
- package/dist/clis/xueqiu/feed.js +48 -0
- package/dist/clis/xueqiu/groups.d.ts +1 -0
- package/dist/clis/xueqiu/groups.js +25 -0
- package/dist/clis/xueqiu/hot-stock.d.ts +1 -0
- package/dist/clis/xueqiu/hot-stock.js +44 -0
- package/dist/clis/xueqiu/hot.d.ts +1 -0
- package/dist/clis/xueqiu/hot.js +44 -0
- package/dist/clis/xueqiu/kline.d.ts +1 -0
- package/dist/clis/xueqiu/kline.js +64 -0
- package/dist/clis/xueqiu/search.d.ts +1 -0
- package/dist/clis/xueqiu/search.js +49 -0
- package/dist/clis/xueqiu/stock.d.ts +1 -0
- package/dist/clis/xueqiu/stock.js +72 -0
- package/dist/clis/xueqiu/watchlist.d.ts +1 -0
- package/dist/clis/xueqiu/watchlist.js +45 -0
- package/dist/clis/zhihu/answer.d.ts +1 -0
- package/dist/clis/zhihu/answer.js +194 -0
- package/dist/clis/zhihu/answer.test.d.ts +1 -0
- package/dist/clis/zhihu/answer.test.js +81 -0
- package/dist/clis/zhihu/comment.d.ts +1 -0
- package/dist/clis/zhihu/comment.js +335 -0
- package/dist/clis/zhihu/comment.test.d.ts +1 -0
- package/dist/clis/zhihu/comment.test.js +54 -0
- package/dist/clis/zhihu/favorite.d.ts +1 -0
- package/dist/clis/zhihu/favorite.js +224 -0
- package/dist/clis/zhihu/favorite.test.d.ts +1 -0
- package/dist/clis/zhihu/favorite.test.js +196 -0
- package/dist/clis/zhihu/follow.d.ts +1 -0
- package/dist/clis/zhihu/follow.js +80 -0
- package/dist/clis/zhihu/follow.test.d.ts +1 -0
- package/dist/clis/zhihu/follow.test.js +45 -0
- package/dist/clis/zhihu/hot.d.ts +1 -0
- package/dist/clis/zhihu/hot.js +43 -0
- package/dist/clis/zhihu/like.d.ts +1 -0
- package/dist/clis/zhihu/like.js +91 -0
- package/dist/clis/zhihu/like.test.d.ts +1 -0
- package/dist/clis/zhihu/like.test.js +64 -0
- package/dist/clis/zhihu/search.d.ts +1 -0
- package/dist/clis/zhihu/search.js +52 -0
- package/dist/clis/zhihu/target.d.ts +24 -0
- package/dist/clis/zhihu/target.js +91 -0
- package/dist/clis/zhihu/target.test.d.ts +1 -0
- package/dist/clis/zhihu/target.test.js +77 -0
- package/dist/clis/zhihu/write-shared.d.ts +32 -0
- package/dist/clis/zhihu/write-shared.js +221 -0
- package/dist/clis/zhihu/write-shared.test.d.ts +1 -0
- package/dist/clis/zhihu/write-shared.test.js +175 -0
- package/dist/src/browser/bridge.d.ts +2 -0
- package/dist/src/browser/bridge.js +30 -24
- package/dist/src/browser/daemon-client.d.ts +30 -10
- package/dist/src/browser/daemon-client.js +42 -27
- package/dist/src/browser/daemon-client.test.js +32 -25
- package/dist/src/browser/dom-helpers.test.js +3 -2
- package/dist/src/browser/errors.d.ts +26 -1
- package/dist/src/browser/errors.js +40 -7
- package/dist/src/browser/errors.test.d.ts +1 -0
- package/dist/src/browser/errors.test.js +51 -0
- package/dist/src/browser/index.d.ts +2 -1
- package/dist/src/browser/index.js +1 -1
- package/dist/src/browser/page.d.ts +9 -8
- package/dist/src/browser/page.js +33 -31
- package/dist/src/browser.test.js +27 -8
- package/dist/src/build-manifest.d.ts +5 -11
- package/dist/src/build-manifest.js +6 -75
- package/dist/src/build-manifest.test.js +1 -39
- package/dist/src/cascade.js +3 -2
- package/dist/src/cli.d.ts +3 -3
- package/dist/src/cli.js +73 -65
- package/dist/src/cli.test.js +20 -15
- package/dist/src/clis/binance/asks.d.ts +1 -0
- package/dist/src/clis/binance/asks.js +20 -0
- package/dist/src/clis/binance/commands.test.d.ts +3 -0
- package/dist/src/clis/binance/commands.test.js +58 -0
- package/dist/src/clis/binance/depth.d.ts +1 -0
- package/dist/src/clis/binance/depth.js +20 -0
- package/dist/src/clis/binance/gainers.d.ts +1 -0
- package/dist/src/clis/binance/gainers.js +21 -0
- package/dist/src/clis/binance/klines.d.ts +1 -0
- package/dist/src/clis/binance/klines.js +20 -0
- package/dist/src/clis/binance/losers.d.ts +1 -0
- package/dist/src/clis/binance/losers.js +21 -0
- package/dist/src/clis/binance/pairs.d.ts +1 -0
- package/dist/src/clis/binance/pairs.js +20 -0
- package/dist/src/clis/binance/price.d.ts +1 -0
- package/dist/src/clis/binance/price.js +17 -0
- package/dist/src/clis/binance/prices.d.ts +1 -0
- package/dist/src/clis/binance/prices.js +18 -0
- package/dist/src/clis/binance/ticker.d.ts +1 -0
- package/dist/src/clis/binance/ticker.js +20 -0
- package/dist/src/clis/binance/top.d.ts +1 -0
- package/dist/src/clis/binance/top.js +20 -0
- package/dist/src/clis/binance/trades.d.ts +1 -0
- package/dist/src/clis/binance/trades.js +19 -0
- package/dist/src/commanderAdapter.js +19 -6
- package/dist/src/completion-fast.d.ts +25 -0
- package/dist/src/completion-fast.js +140 -0
- package/dist/src/completion.d.ts +1 -0
- package/dist/src/completion.js +1 -0
- package/dist/src/diagnostic.d.ts +1 -0
- package/dist/src/diagnostic.js +64 -2
- package/dist/src/diagnostic.test.js +93 -3
- package/dist/src/discovery.d.ts +3 -3
- package/dist/src/discovery.js +34 -97
- package/dist/src/doctor.d.ts +2 -0
- package/dist/src/doctor.js +59 -31
- package/dist/src/doctor.test.js +89 -16
- package/dist/src/download/index.d.ts +1 -1
- package/dist/src/engine.test.js +4 -19
- package/dist/src/execution.js +1 -13
- package/dist/src/explore.js +1 -1
- package/dist/src/generate-verified.d.ts +105 -0
- package/dist/src/generate-verified.js +696 -0
- package/dist/src/generate-verified.test.d.ts +1 -0
- package/dist/src/generate-verified.test.js +925 -0
- package/dist/src/generate.d.ts +11 -6
- package/dist/src/generate.js +4 -7
- package/dist/src/main.js +65 -12
- package/dist/src/pipeline/steps/download.d.ts +1 -17
- package/dist/src/pipeline/steps/download.js +20 -31
- package/dist/src/pipeline/steps/intercept.d.ts +1 -1
- package/dist/src/pipeline/steps/intercept.js +1 -1
- package/dist/src/pipeline/steps/tap.d.ts +1 -1
- package/dist/src/pipeline/steps/tap.js +1 -1
- package/dist/src/plugin-scaffold.d.ts +2 -2
- package/dist/src/plugin-scaffold.js +24 -21
- package/dist/src/plugin-scaffold.test.js +1 -1
- package/dist/src/plugin.d.ts +3 -2
- package/dist/src/plugin.js +29 -14
- package/dist/src/plugin.test.js +47 -32
- package/dist/src/record.js +26 -25
- package/dist/src/runtime-detect.js +3 -7
- package/dist/src/scripts/framework.d.ts +3 -0
- package/dist/src/scripts/framework.js +8 -4
- package/dist/src/scripts/store.d.ts +5 -1
- package/dist/src/scripts/store.js +5 -1
- package/dist/src/skill-generate.d.ts +30 -0
- package/dist/src/skill-generate.js +75 -0
- package/dist/src/skill-generate.test.d.ts +1 -0
- package/dist/src/skill-generate.test.js +173 -0
- package/dist/src/synthesize.d.ts +1 -1
- package/dist/src/synthesize.js +7 -8
- package/dist/src/types.d.ts +3 -1
- package/package.json +5 -5
- package/dist/clis/bilibili/hot.yaml +0 -38
- package/dist/clis/bluesky/feeds.yaml +0 -29
- package/dist/clis/bluesky/followers.yaml +0 -33
- package/dist/clis/bluesky/following.yaml +0 -33
- package/dist/clis/bluesky/profile.yaml +0 -27
- package/dist/clis/bluesky/search.yaml +0 -34
- package/dist/clis/bluesky/starter-packs.yaml +0 -34
- package/dist/clis/bluesky/thread.yaml +0 -32
- package/dist/clis/bluesky/trending.yaml +0 -27
- package/dist/clis/bluesky/user.yaml +0 -34
- package/dist/clis/devto/tag.yaml +0 -34
- package/dist/clis/devto/top.yaml +0 -29
- package/dist/clis/devto/user.yaml +0 -33
- package/dist/clis/dictionary/examples.yaml +0 -25
- package/dist/clis/dictionary/search.yaml +0 -27
- package/dist/clis/dictionary/synonyms.yaml +0 -25
- package/dist/clis/douban/subject.yaml +0 -107
- package/dist/clis/douban/top250.yaml +0 -70
- package/dist/clis/facebook/add-friend.yaml +0 -43
- package/dist/clis/facebook/events.yaml +0 -44
- package/dist/clis/facebook/feed.yaml +0 -63
- package/dist/clis/facebook/friends.yaml +0 -42
- package/dist/clis/facebook/groups.yaml +0 -50
- package/dist/clis/facebook/join-group.yaml +0 -44
- package/dist/clis/facebook/memories.yaml +0 -39
- package/dist/clis/facebook/notifications.yaml +0 -40
- package/dist/clis/facebook/profile.yaml +0 -37
- package/dist/clis/facebook/search.yaml +0 -47
- package/dist/clis/hackernews/ask.yaml +0 -38
- package/dist/clis/hackernews/best.yaml +0 -38
- package/dist/clis/hackernews/jobs.yaml +0 -36
- package/dist/clis/hackernews/new.yaml +0 -38
- package/dist/clis/hackernews/search.yaml +0 -44
- package/dist/clis/hackernews/show.yaml +0 -38
- package/dist/clis/hackernews/top.yaml +0 -38
- package/dist/clis/hackernews/user.yaml +0 -25
- package/dist/clis/hupu/hot.yaml +0 -43
- package/dist/clis/instagram/comment.yaml +0 -52
- package/dist/clis/instagram/explore.yaml +0 -43
- package/dist/clis/instagram/follow.yaml +0 -41
- package/dist/clis/instagram/followers.yaml +0 -51
- package/dist/clis/instagram/following.yaml +0 -51
- package/dist/clis/instagram/like.yaml +0 -46
- package/dist/clis/instagram/profile.yaml +0 -42
- package/dist/clis/instagram/save.yaml +0 -46
- package/dist/clis/instagram/saved.yaml +0 -40
- package/dist/clis/instagram/search.yaml +0 -44
- package/dist/clis/instagram/unfollow.yaml +0 -38
- package/dist/clis/instagram/unlike.yaml +0 -46
- package/dist/clis/instagram/unsave.yaml +0 -46
- package/dist/clis/instagram/user.yaml +0 -54
- package/dist/clis/jike/post.yaml +0 -59
- package/dist/clis/jike/topic.yaml +0 -53
- package/dist/clis/jike/user.yaml +0 -52
- package/dist/clis/jimeng/generate.yaml +0 -85
- package/dist/clis/jimeng/history.yaml +0 -46
- package/dist/clis/linux-do/categories.yaml +0 -70
- package/dist/clis/linux-do/search.yaml +0 -48
- package/dist/clis/linux-do/tags.yaml +0 -41
- package/dist/clis/linux-do/topic.yaml +0 -62
- package/dist/clis/linux-do/user-posts.yaml +0 -67
- package/dist/clis/linux-do/user-topics.yaml +0 -54
- package/dist/clis/lobsters/active.yaml +0 -29
- package/dist/clis/lobsters/hot.yaml +0 -29
- package/dist/clis/lobsters/newest.yaml +0 -29
- package/dist/clis/lobsters/tag.yaml +0 -34
- package/dist/clis/pixiv/detail.yaml +0 -49
- package/dist/clis/pixiv/ranking.yaml +0 -53
- package/dist/clis/pixiv/user.yaml +0 -46
- package/dist/clis/reddit/frontpage.yaml +0 -30
- package/dist/clis/reddit/hot.yaml +0 -47
- package/dist/clis/reddit/popular.yaml +0 -40
- package/dist/clis/reddit/search.yaml +0 -61
- package/dist/clis/reddit/subreddit.yaml +0 -50
- package/dist/clis/reddit/user-comments.yaml +0 -46
- package/dist/clis/reddit/user-posts.yaml +0 -44
- package/dist/clis/reddit/user.yaml +0 -40
- package/dist/clis/stackoverflow/bounties.yaml +0 -29
- package/dist/clis/stackoverflow/hot.yaml +0 -28
- package/dist/clis/stackoverflow/search.yaml +0 -33
- package/dist/clis/stackoverflow/unanswered.yaml +0 -28
- package/dist/clis/steam/top-sellers.yaml +0 -29
- package/dist/clis/tiktok/comment.yaml +0 -66
- package/dist/clis/tiktok/explore.yaml +0 -39
- package/dist/clis/tiktok/follow.yaml +0 -39
- package/dist/clis/tiktok/following.yaml +0 -46
- package/dist/clis/tiktok/friends.yaml +0 -47
- package/dist/clis/tiktok/like.yaml +0 -38
- package/dist/clis/tiktok/live.yaml +0 -51
- package/dist/clis/tiktok/notifications.yaml +0 -52
- package/dist/clis/tiktok/profile.yaml +0 -45
- package/dist/clis/tiktok/save.yaml +0 -34
- package/dist/clis/tiktok/search.yaml +0 -47
- package/dist/clis/tiktok/unfollow.yaml +0 -44
- package/dist/clis/tiktok/unlike.yaml +0 -38
- package/dist/clis/tiktok/unsave.yaml +0 -36
- package/dist/clis/tiktok/user.yaml +0 -44
- package/dist/clis/v2ex/hot.yaml +0 -28
- package/dist/clis/v2ex/latest.yaml +0 -28
- package/dist/clis/v2ex/member.yaml +0 -29
- package/dist/clis/v2ex/node.yaml +0 -34
- package/dist/clis/v2ex/nodes.yaml +0 -31
- package/dist/clis/v2ex/replies.yaml +0 -32
- package/dist/clis/v2ex/topic.yaml +0 -33
- package/dist/clis/v2ex/user.yaml +0 -34
- package/dist/clis/xiaoe/catalog.yaml +0 -129
- package/dist/clis/xiaoe/content.yaml +0 -43
- package/dist/clis/xiaoe/courses.yaml +0 -73
- package/dist/clis/xiaoe/detail.yaml +0 -39
- package/dist/clis/xiaoe/play-url.yaml +0 -124
- package/dist/clis/xiaohongshu/feed.yaml +0 -31
- package/dist/clis/xiaohongshu/notifications.yaml +0 -37
- package/dist/clis/xueqiu/earnings-date.yaml +0 -69
- package/dist/clis/xueqiu/feed.yaml +0 -53
- package/dist/clis/xueqiu/groups.yaml +0 -23
- package/dist/clis/xueqiu/hot-stock.yaml +0 -49
- package/dist/clis/xueqiu/hot.yaml +0 -46
- package/dist/clis/xueqiu/kline.yaml +0 -65
- package/dist/clis/xueqiu/search.yaml +0 -55
- package/dist/clis/xueqiu/stock.yaml +0 -69
- package/dist/clis/xueqiu/watchlist.yaml +0 -46
- package/dist/clis/zhihu/hot.yaml +0 -46
- package/dist/clis/zhihu/search.yaml +0 -59
- package/dist/src/browser/discover.d.ts +0 -15
- package/dist/src/browser/discover.js +0 -19
- package/dist/src/yaml-schema.d.ts +0 -29
- package/dist/src/yaml-schema.js +0 -22
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { cli, Strategy } from '@jackwener/opencli/registry';
|
|
2
|
+
cli({
|
|
3
|
+
site: 'binance',
|
|
4
|
+
name: 'losers',
|
|
5
|
+
description: 'Top losing trading pairs by 24h price change',
|
|
6
|
+
domain: 'data-api.binance.vision',
|
|
7
|
+
strategy: Strategy.PUBLIC,
|
|
8
|
+
browser: false,
|
|
9
|
+
args: [
|
|
10
|
+
{ name: 'limit', type: 'int', default: 10, help: 'Number of trading pairs' },
|
|
11
|
+
],
|
|
12
|
+
columns: ['rank', 'symbol', 'price', 'change_24h', 'volume'],
|
|
13
|
+
pipeline: [
|
|
14
|
+
{ fetch: { url: 'https://data-api.binance.vision/api/v3/ticker/24hr' } },
|
|
15
|
+
{ filter: 'item.priceChangePercent' },
|
|
16
|
+
{ map: { symbol: '${{ item.symbol }}', price: '${{ item.lastPrice }}', change_24h: '${{ item.priceChangePercent }}', volume: '${{ item.quoteVolume }}', sort_change: '${{ Number(item.priceChangePercent) }}' } },
|
|
17
|
+
{ sort: { by: 'sort_change' } },
|
|
18
|
+
{ map: { rank: '${{ index + 1 }}', symbol: '${{ item.symbol }}', price: '${{ item.lastPrice }}', change_24h: '${{ item.priceChangePercent }}', volume: '${{ item.quoteVolume }}' } },
|
|
19
|
+
{ limit: '${{ args.limit }}' },
|
|
20
|
+
],
|
|
21
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { cli, Strategy } from '@jackwener/opencli/registry';
|
|
2
|
+
cli({
|
|
3
|
+
site: 'binance',
|
|
4
|
+
name: 'pairs',
|
|
5
|
+
description: 'List active trading pairs on Binance',
|
|
6
|
+
domain: 'data-api.binance.vision',
|
|
7
|
+
strategy: Strategy.PUBLIC,
|
|
8
|
+
browser: false,
|
|
9
|
+
args: [
|
|
10
|
+
{ name: 'limit', type: 'int', default: 20, help: 'Number of trading pairs' },
|
|
11
|
+
],
|
|
12
|
+
columns: ['symbol', 'base', 'quote', 'status'],
|
|
13
|
+
pipeline: [
|
|
14
|
+
{ fetch: { url: 'https://data-api.binance.vision/api/v3/exchangeInfo' } },
|
|
15
|
+
{ select: 'symbols' },
|
|
16
|
+
{ filter: 'item.status === \'TRADING\'' },
|
|
17
|
+
{ map: { symbol: '${{ item.symbol }}', base: '${{ item.baseAsset }}', quote: '${{ item.quoteAsset }}', status: '${{ item.status }}' } },
|
|
18
|
+
{ limit: '${{ args.limit }}' },
|
|
19
|
+
],
|
|
20
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { cli, Strategy } from '@jackwener/opencli/registry';
|
|
2
|
+
cli({
|
|
3
|
+
site: 'binance',
|
|
4
|
+
name: 'price',
|
|
5
|
+
description: 'Quick price check for a trading pair',
|
|
6
|
+
domain: 'data-api.binance.vision',
|
|
7
|
+
strategy: Strategy.PUBLIC,
|
|
8
|
+
browser: false,
|
|
9
|
+
args: [
|
|
10
|
+
{ name: 'symbol', type: 'str', required: true, positional: true, help: 'Trading pair symbol (e.g. BTCUSDT, ETHUSDT)' },
|
|
11
|
+
],
|
|
12
|
+
columns: ['symbol', 'price', 'change', 'change_pct', 'high', 'low', 'volume', 'quote_volume', 'trades'],
|
|
13
|
+
pipeline: [
|
|
14
|
+
{ fetch: { url: 'https://data-api.binance.vision/api/v3/ticker/24hr?symbol=${{ args.symbol }}' } },
|
|
15
|
+
{ map: { symbol: '${{ item.symbol }}', price: '${{ item.lastPrice }}', change: '${{ item.priceChange }}', change_pct: '${{ item.priceChangePercent }}', high: '${{ item.highPrice }}', low: '${{ item.lowPrice }}', volume: '${{ item.volume }}', quote_volume: '${{ item.quoteVolume }}', trades: '${{ item.count }}' } },
|
|
16
|
+
],
|
|
17
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { cli, Strategy } from '@jackwener/opencli/registry';
|
|
2
|
+
cli({
|
|
3
|
+
site: 'binance',
|
|
4
|
+
name: 'prices',
|
|
5
|
+
description: 'Latest prices for all trading pairs',
|
|
6
|
+
domain: 'data-api.binance.vision',
|
|
7
|
+
strategy: Strategy.PUBLIC,
|
|
8
|
+
browser: false,
|
|
9
|
+
args: [
|
|
10
|
+
{ name: 'limit', type: 'int', default: 20, help: 'Number of prices' },
|
|
11
|
+
],
|
|
12
|
+
columns: ['rank', 'symbol', 'price'],
|
|
13
|
+
pipeline: [
|
|
14
|
+
{ fetch: { url: 'https://data-api.binance.vision/api/v3/ticker/price' } },
|
|
15
|
+
{ map: { rank: '${{ index + 1 }}', symbol: '${{ item.symbol }}', price: '${{ item.price }}' } },
|
|
16
|
+
{ limit: '${{ args.limit }}' },
|
|
17
|
+
],
|
|
18
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { cli, Strategy } from '@jackwener/opencli/registry';
|
|
2
|
+
cli({
|
|
3
|
+
site: 'binance',
|
|
4
|
+
name: 'ticker',
|
|
5
|
+
description: '24h ticker statistics for top trading pairs by volume',
|
|
6
|
+
domain: 'data-api.binance.vision',
|
|
7
|
+
strategy: Strategy.PUBLIC,
|
|
8
|
+
browser: false,
|
|
9
|
+
args: [
|
|
10
|
+
{ name: 'limit', type: 'int', default: 20, help: 'Number of tickers' },
|
|
11
|
+
],
|
|
12
|
+
columns: ['symbol', 'price', 'change_pct', 'high', 'low', 'volume', 'quote_vol', 'trades'],
|
|
13
|
+
pipeline: [
|
|
14
|
+
{ fetch: { url: 'https://data-api.binance.vision/api/v3/ticker/24hr' } },
|
|
15
|
+
{ map: { symbol: '${{ item.symbol }}', price: '${{ item.lastPrice }}', change_pct: '${{ item.priceChangePercent }}', high: '${{ item.highPrice }}', low: '${{ item.lowPrice }}', volume: '${{ item.volume }}', quote_vol: '${{ item.quoteVolume }}', trades: '${{ item.count }}', sort_volume: '${{ Number(item.quoteVolume) }}' } },
|
|
16
|
+
{ sort: { by: 'sort_volume', order: 'desc' } },
|
|
17
|
+
{ map: { symbol: '${{ item.symbol }}', price: '${{ item.lastPrice }}', change_pct: '${{ item.priceChangePercent }}', high: '${{ item.highPrice }}', low: '${{ item.lowPrice }}', volume: '${{ item.volume }}', quote_vol: '${{ item.quoteVolume }}', trades: '${{ item.count }}' } },
|
|
18
|
+
{ limit: '${{ args.limit }}' },
|
|
19
|
+
],
|
|
20
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { cli, Strategy } from '@jackwener/opencli/registry';
|
|
2
|
+
cli({
|
|
3
|
+
site: 'binance',
|
|
4
|
+
name: 'top',
|
|
5
|
+
description: 'Top trading pairs by 24h volume on Binance',
|
|
6
|
+
domain: 'data-api.binance.vision',
|
|
7
|
+
strategy: Strategy.PUBLIC,
|
|
8
|
+
browser: false,
|
|
9
|
+
args: [
|
|
10
|
+
{ name: 'limit', type: 'int', default: 20, help: 'Number of trading pairs' },
|
|
11
|
+
],
|
|
12
|
+
columns: ['rank', 'symbol', 'price', 'change_24h', 'high', 'low', 'volume'],
|
|
13
|
+
pipeline: [
|
|
14
|
+
{ fetch: { url: 'https://data-api.binance.vision/api/v3/ticker/24hr' } },
|
|
15
|
+
{ map: { symbol: '${{ item.symbol }}', price: '${{ item.lastPrice }}', change_24h: '${{ item.priceChangePercent }}', high: '${{ item.highPrice }}', low: '${{ item.lowPrice }}', volume: '${{ item.quoteVolume }}', sort_volume: '${{ Number(item.quoteVolume) }}' } },
|
|
16
|
+
{ sort: { by: 'sort_volume', order: 'desc' } },
|
|
17
|
+
{ map: { rank: '${{ index + 1 }}', symbol: '${{ item.symbol }}', price: '${{ item.lastPrice }}', change_24h: '${{ item.priceChangePercent }}', high: '${{ item.highPrice }}', low: '${{ item.lowPrice }}', volume: '${{ item.quoteVolume }}' } },
|
|
18
|
+
{ limit: '${{ args.limit }}' },
|
|
19
|
+
],
|
|
20
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { cli, Strategy } from '@jackwener/opencli/registry';
|
|
2
|
+
cli({
|
|
3
|
+
site: 'binance',
|
|
4
|
+
name: 'trades',
|
|
5
|
+
description: 'Recent trades for a trading pair',
|
|
6
|
+
domain: 'data-api.binance.vision',
|
|
7
|
+
strategy: Strategy.PUBLIC,
|
|
8
|
+
browser: false,
|
|
9
|
+
args: [
|
|
10
|
+
{ name: 'symbol', type: 'str', required: true, positional: true, help: 'Trading pair symbol (e.g. BTCUSDT, ETHUSDT)' },
|
|
11
|
+
{ name: 'limit', type: 'int', default: 20, help: 'Number of trades (max 1000)' },
|
|
12
|
+
],
|
|
13
|
+
columns: ['id', 'price', 'qty', 'quote_qty', 'buyer_maker'],
|
|
14
|
+
pipeline: [
|
|
15
|
+
{ fetch: { url: 'https://data-api.binance.vision/api/v3/trades?symbol=${{ args.symbol }}&limit=${{ args.limit }}' } },
|
|
16
|
+
{ map: { id: '${{ item.id }}', price: '${{ item.price }}', qty: '${{ item.qty }}', quote_qty: '${{ item.quoteQty }}', buyer_maker: '${{ item.isBuyerMaker }}' } },
|
|
17
|
+
{ limit: '${{ args.limit }}' },
|
|
18
|
+
],
|
|
19
|
+
});
|
|
@@ -15,7 +15,8 @@ import { formatRegistryHelpText } from './serialization.js';
|
|
|
15
15
|
import { render as renderOutput } from './output.js';
|
|
16
16
|
import { executeCommand } from './execution.js';
|
|
17
17
|
import { CliError, EXIT_CODES, ERROR_ICONS, getErrorMessage, BrowserConnectError, AuthRequiredError, TimeoutError, SelectorError, EmptyResultError, ArgumentError, AdapterLoadError, CommandExecutionError, } from './errors.js';
|
|
18
|
-
import {
|
|
18
|
+
import { getDaemonHealth } from './browser/daemon-client.js';
|
|
19
|
+
import { isDiagnosticEnabled } from './diagnostic.js';
|
|
19
20
|
export function normalizeArgValue(argType, value, name) {
|
|
20
21
|
if (argType !== 'bool' && argType !== 'boolean')
|
|
21
22
|
return value;
|
|
@@ -169,18 +170,27 @@ function renderBridgeStatus(running, extensionConnected) {
|
|
|
169
170
|
console.error(chalk.dim(' Try reloading the extension, or run: opencli doctor'));
|
|
170
171
|
}
|
|
171
172
|
}
|
|
173
|
+
/** Emit AutoFix hint for repairable adapter errors (skipped if already in diagnostic mode). */
|
|
174
|
+
function emitAutoFixHint(cmdName) {
|
|
175
|
+
if (isDiagnosticEnabled())
|
|
176
|
+
return; // Already collecting diagnostics, don't repeat
|
|
177
|
+
console.error();
|
|
178
|
+
console.error(chalk.cyan('💡 AutoFix: re-run with OPENCLI_DIAGNOSTIC=1 for repair context.'));
|
|
179
|
+
console.error(chalk.dim(` OPENCLI_DIAGNOSTIC=1 ${cmdName}`));
|
|
180
|
+
}
|
|
172
181
|
async function renderError(err, cmdName, verbose) {
|
|
173
182
|
// ── BrowserConnectError: real-time diagnosis, kind as fallback ────────
|
|
174
183
|
if (err instanceof BrowserConnectError) {
|
|
175
|
-
console.error(chalk.red(
|
|
184
|
+
console.error(chalk.red(`🔌 ${err.message}`));
|
|
185
|
+
if (err.hint)
|
|
186
|
+
console.error(chalk.yellow(`→ ${err.hint}`));
|
|
176
187
|
console.error();
|
|
177
188
|
try {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
renderBridgeStatus(status.running, status.extensionConnected);
|
|
189
|
+
const health = await getDaemonHealth({ timeout: 300 });
|
|
190
|
+
renderBridgeStatus(health.state !== 'stopped', health.state === 'ready');
|
|
181
191
|
}
|
|
182
192
|
catch (_statusErr) {
|
|
183
|
-
//
|
|
193
|
+
// getDaemonHealth itself failed — derive best-guess state from kind.
|
|
184
194
|
const running = err.kind !== 'daemon-not-running';
|
|
185
195
|
const extensionConnected = err.kind === 'command-failed';
|
|
186
196
|
renderBridgeStatus(running, extensionConnected);
|
|
@@ -208,6 +218,7 @@ async function renderError(err, cmdName, verbose) {
|
|
|
208
218
|
console.error(chalk.yellow(`→ ${err.hint ?? 'The page structure may have changed — this adapter may be outdated.'}`));
|
|
209
219
|
console.error(chalk.dim(` Debug: ${cmdName} --verbose`));
|
|
210
220
|
console.error(chalk.dim(` Report: ${ISSUES_URL}`));
|
|
221
|
+
emitAutoFixHint(cmdName);
|
|
211
222
|
return;
|
|
212
223
|
}
|
|
213
224
|
// ── ArgumentError ─────────────────────────────────────────────────────
|
|
@@ -251,6 +262,8 @@ async function renderError(err, cmdName, verbose) {
|
|
|
251
262
|
console.error(chalk.yellow(`→ ${classified.hint}`));
|
|
252
263
|
if (classified.kind === 'not-found')
|
|
253
264
|
console.error(chalk.dim(` Report: ${ISSUES_URL}`));
|
|
265
|
+
if (classified.kind === 'not-found')
|
|
266
|
+
emitAutoFixHint(cmdName);
|
|
254
267
|
return;
|
|
255
268
|
}
|
|
256
269
|
// ── Unknown error: show stack in verbose mode ─────────────────────────
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight manifest-based completion for the fast path.
|
|
3
|
+
*
|
|
4
|
+
* This module MUST NOT import registry, discovery, or any heavy module.
|
|
5
|
+
* It only reads pre-compiled cli-manifest.json files synchronously.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Returns true only if ALL manifest files exist and are readable.
|
|
9
|
+
* If any source lacks a manifest (e.g. user adapters without a compiled manifest),
|
|
10
|
+
* the fast path must not be used — otherwise those adapters would silently
|
|
11
|
+
* disappear from completion results.
|
|
12
|
+
*/
|
|
13
|
+
export declare function hasAllManifests(manifestPaths: string[]): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Lightweight completion that reads directly from manifest JSON files,
|
|
16
|
+
* bypassing full CLI discovery and adapter loading.
|
|
17
|
+
*/
|
|
18
|
+
export declare function getCompletionsFromManifest(words: string[], cursor: number, manifestPaths: string[]): string[];
|
|
19
|
+
export declare function bashCompletionScript(): string;
|
|
20
|
+
export declare function zshCompletionScript(): string;
|
|
21
|
+
export declare function fishCompletionScript(): string;
|
|
22
|
+
/**
|
|
23
|
+
* Print completion script for the given shell. Returns true if handled, false if unknown shell.
|
|
24
|
+
*/
|
|
25
|
+
export declare function printCompletionScriptFast(shell: string): boolean;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight manifest-based completion for the fast path.
|
|
3
|
+
*
|
|
4
|
+
* This module MUST NOT import registry, discovery, or any heavy module.
|
|
5
|
+
* It only reads pre-compiled cli-manifest.json files synchronously.
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from 'node:fs';
|
|
8
|
+
const BUILTIN_COMMANDS = [
|
|
9
|
+
'list',
|
|
10
|
+
'validate',
|
|
11
|
+
'verify',
|
|
12
|
+
'explore',
|
|
13
|
+
'probe',
|
|
14
|
+
'synthesize',
|
|
15
|
+
'generate',
|
|
16
|
+
'cascade',
|
|
17
|
+
'doctor',
|
|
18
|
+
'plugin',
|
|
19
|
+
'install',
|
|
20
|
+
'register',
|
|
21
|
+
'completion',
|
|
22
|
+
];
|
|
23
|
+
/**
|
|
24
|
+
* Returns true only if ALL manifest files exist and are readable.
|
|
25
|
+
* If any source lacks a manifest (e.g. user adapters without a compiled manifest),
|
|
26
|
+
* the fast path must not be used — otherwise those adapters would silently
|
|
27
|
+
* disappear from completion results.
|
|
28
|
+
*/
|
|
29
|
+
export function hasAllManifests(manifestPaths) {
|
|
30
|
+
for (const p of manifestPaths) {
|
|
31
|
+
try {
|
|
32
|
+
fs.accessSync(p);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return manifestPaths.length > 0;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Lightweight completion that reads directly from manifest JSON files,
|
|
42
|
+
* bypassing full CLI discovery and adapter loading.
|
|
43
|
+
*/
|
|
44
|
+
export function getCompletionsFromManifest(words, cursor, manifestPaths) {
|
|
45
|
+
const entries = loadManifestEntries(manifestPaths);
|
|
46
|
+
if (entries === null) {
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
if (cursor <= 1) {
|
|
50
|
+
const sites = new Set();
|
|
51
|
+
for (const entry of entries) {
|
|
52
|
+
sites.add(entry.site);
|
|
53
|
+
}
|
|
54
|
+
return [...BUILTIN_COMMANDS, ...sites].sort();
|
|
55
|
+
}
|
|
56
|
+
const site = words[0];
|
|
57
|
+
if (BUILTIN_COMMANDS.includes(site)) {
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
if (cursor === 2) {
|
|
61
|
+
const subcommands = [];
|
|
62
|
+
for (const entry of entries) {
|
|
63
|
+
if (entry.site === site) {
|
|
64
|
+
subcommands.push(entry.name);
|
|
65
|
+
if (entry.aliases?.length)
|
|
66
|
+
subcommands.push(...entry.aliases);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return [...new Set(subcommands)].sort();
|
|
70
|
+
}
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
// ── Shell script generators (pure strings, no registry dependency) ───────
|
|
74
|
+
export function bashCompletionScript() {
|
|
75
|
+
return `# Bash completion for opencli
|
|
76
|
+
# Add to ~/.bashrc: eval "$(opencli completion bash)"
|
|
77
|
+
_opencli_completions() {
|
|
78
|
+
local cur words cword
|
|
79
|
+
_get_comp_words_by_ref -n : cur words cword
|
|
80
|
+
|
|
81
|
+
local completions
|
|
82
|
+
completions=$(opencli --get-completions --cursor "$cword" "\${words[@]:1}" 2>/dev/null)
|
|
83
|
+
|
|
84
|
+
COMPREPLY=( $(compgen -W "$completions" -- "$cur") )
|
|
85
|
+
__ltrim_colon_completions "$cur"
|
|
86
|
+
}
|
|
87
|
+
complete -F _opencli_completions opencli
|
|
88
|
+
`;
|
|
89
|
+
}
|
|
90
|
+
export function zshCompletionScript() {
|
|
91
|
+
return `# Zsh completion for opencli
|
|
92
|
+
# Add to ~/.zshrc: eval "$(opencli completion zsh)"
|
|
93
|
+
_opencli() {
|
|
94
|
+
local -a completions
|
|
95
|
+
local cword=$((CURRENT - 1))
|
|
96
|
+
completions=(\${(f)"$(opencli --get-completions --cursor "$cword" "\${words[@]:1}" 2>/dev/null)"})
|
|
97
|
+
compadd -a completions
|
|
98
|
+
}
|
|
99
|
+
compdef _opencli opencli
|
|
100
|
+
`;
|
|
101
|
+
}
|
|
102
|
+
export function fishCompletionScript() {
|
|
103
|
+
return `# Fish completion for opencli
|
|
104
|
+
# Add to ~/.config/fish/config.fish: opencli completion fish | source
|
|
105
|
+
complete -c opencli -f -a '(
|
|
106
|
+
set -l tokens (commandline -cop)
|
|
107
|
+
set -l cursor (count (commandline -cop))
|
|
108
|
+
opencli --get-completions --cursor $cursor $tokens[2..] 2>/dev/null
|
|
109
|
+
)'
|
|
110
|
+
`;
|
|
111
|
+
}
|
|
112
|
+
const SHELL_SCRIPTS = {
|
|
113
|
+
bash: bashCompletionScript,
|
|
114
|
+
zsh: zshCompletionScript,
|
|
115
|
+
fish: fishCompletionScript,
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* Print completion script for the given shell. Returns true if handled, false if unknown shell.
|
|
119
|
+
*/
|
|
120
|
+
export function printCompletionScriptFast(shell) {
|
|
121
|
+
const gen = SHELL_SCRIPTS[shell];
|
|
122
|
+
if (!gen)
|
|
123
|
+
return false;
|
|
124
|
+
process.stdout.write(gen());
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
function loadManifestEntries(manifestPaths) {
|
|
128
|
+
const entries = [];
|
|
129
|
+
let found = false;
|
|
130
|
+
for (const manifestPath of manifestPaths) {
|
|
131
|
+
try {
|
|
132
|
+
const raw = fs.readFileSync(manifestPath, 'utf-8');
|
|
133
|
+
const manifest = JSON.parse(raw);
|
|
134
|
+
entries.push(...manifest);
|
|
135
|
+
found = true;
|
|
136
|
+
}
|
|
137
|
+
catch { /* skip missing/unreadable */ }
|
|
138
|
+
}
|
|
139
|
+
return found ? entries : null;
|
|
140
|
+
}
|
package/dist/src/completion.d.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
/**
|
|
9
9
|
* Return completion candidates given the current command-line words and cursor index.
|
|
10
|
+
* Requires full CLI discovery to have been run (uses getRegistry()).
|
|
10
11
|
*
|
|
11
12
|
* @param words - The argv after 'opencli' (words[0] is the first arg, e.g. site name)
|
|
12
13
|
* @param cursor - 1-based position of the word being completed (1 = first arg)
|
package/dist/src/completion.js
CHANGED
|
@@ -28,6 +28,7 @@ const BUILTIN_COMMANDS = [
|
|
|
28
28
|
];
|
|
29
29
|
/**
|
|
30
30
|
* Return completion candidates given the current command-line words and cursor index.
|
|
31
|
+
* Requires full CLI discovery to have been run (uses getRegistry()).
|
|
31
32
|
*
|
|
32
33
|
* @param words - The argv after 'opencli' (words[0] is the first arg, e.g. site name)
|
|
33
34
|
* @param cursor - 1-based position of the word being completed (1 = first arg)
|
package/dist/src/diagnostic.d.ts
CHANGED
package/dist/src/diagnostic.js
CHANGED
|
@@ -24,10 +24,16 @@ const MAX_SNAPSHOT_CHARS = 100_000;
|
|
|
24
24
|
const MAX_SOURCE_CHARS = 50_000;
|
|
25
25
|
/** Maximum number of network requests to include. */
|
|
26
26
|
const MAX_NETWORK_REQUESTS = 50;
|
|
27
|
+
/** Maximum number of captured interceptor payloads to include. */
|
|
28
|
+
const MAX_CAPTURED_PAYLOADS = 20;
|
|
27
29
|
/** Maximum characters for a single network request body. */
|
|
28
30
|
const MAX_REQUEST_BODY_CHARS = 4_000;
|
|
29
31
|
/** Maximum characters for error stack trace. */
|
|
30
32
|
const MAX_STACK_CHARS = 5_000;
|
|
33
|
+
/** Maximum nesting depth for arbitrary captured payloads. */
|
|
34
|
+
const MAX_CAPTURED_DEPTH = 4;
|
|
35
|
+
/** Maximum object keys or array items to keep per nesting level. */
|
|
36
|
+
const MAX_CAPTURED_CHILDREN = 20;
|
|
31
37
|
// ── Sensitive data patterns ──────────────────────────────────────────────────
|
|
32
38
|
const SENSITIVE_HEADERS = new Set([
|
|
33
39
|
'authorization',
|
|
@@ -82,6 +88,39 @@ function redactHeaders(headers) {
|
|
|
82
88
|
}
|
|
83
89
|
return result;
|
|
84
90
|
}
|
|
91
|
+
/** Recursively sanitize arbitrary captured response content for diagnostic output. */
|
|
92
|
+
function sanitizeCapturedValue(value, depth = 0) {
|
|
93
|
+
if (typeof value === 'string') {
|
|
94
|
+
return redactText(truncate(value, MAX_REQUEST_BODY_CHARS));
|
|
95
|
+
}
|
|
96
|
+
if (value === null || typeof value === 'number' || typeof value === 'boolean') {
|
|
97
|
+
return value;
|
|
98
|
+
}
|
|
99
|
+
if (depth >= MAX_CAPTURED_DEPTH) {
|
|
100
|
+
return '[truncated: max depth reached]';
|
|
101
|
+
}
|
|
102
|
+
if (Array.isArray(value)) {
|
|
103
|
+
const items = value
|
|
104
|
+
.slice(0, MAX_CAPTURED_CHILDREN)
|
|
105
|
+
.map(item => sanitizeCapturedValue(item, depth + 1));
|
|
106
|
+
if (value.length > MAX_CAPTURED_CHILDREN) {
|
|
107
|
+
items.push(`[truncated, ${value.length - MAX_CAPTURED_CHILDREN} items omitted]`);
|
|
108
|
+
}
|
|
109
|
+
return items;
|
|
110
|
+
}
|
|
111
|
+
if (!value || typeof value !== 'object') {
|
|
112
|
+
return value;
|
|
113
|
+
}
|
|
114
|
+
const entries = Object.entries(value);
|
|
115
|
+
const result = {};
|
|
116
|
+
for (const [key, child] of entries.slice(0, MAX_CAPTURED_CHILDREN)) {
|
|
117
|
+
result[key] = sanitizeCapturedValue(child, depth + 1);
|
|
118
|
+
}
|
|
119
|
+
if (entries.length > MAX_CAPTURED_CHILDREN) {
|
|
120
|
+
result.__truncated__ = `[${entries.length - MAX_CAPTURED_CHILDREN} fields omitted]`;
|
|
121
|
+
}
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
85
124
|
/** Redact sensitive data from a single network request entry. */
|
|
86
125
|
function redactNetworkRequest(req) {
|
|
87
126
|
if (!req || typeof req !== 'object')
|
|
@@ -106,6 +145,12 @@ function redactNetworkRequest(req) {
|
|
|
106
145
|
if (typeof redacted.body === 'string') {
|
|
107
146
|
redacted.body = truncate(redacted.body, MAX_REQUEST_BODY_CHARS);
|
|
108
147
|
}
|
|
148
|
+
if ('responseBody' in redacted) {
|
|
149
|
+
redacted.responseBody = sanitizeCapturedValue(redacted.responseBody);
|
|
150
|
+
}
|
|
151
|
+
if ('responsePreview' in redacted) {
|
|
152
|
+
redacted.responsePreview = sanitizeCapturedValue(redacted.responsePreview);
|
|
153
|
+
}
|
|
109
154
|
return redacted;
|
|
110
155
|
}
|
|
111
156
|
// ── Timeout helper ───────────────────────────────────────────────────────────
|
|
@@ -163,23 +208,32 @@ function mapDistToSource(filePath) {
|
|
|
163
208
|
export function isDiagnosticEnabled() {
|
|
164
209
|
return process.env.OPENCLI_DIAGNOSTIC === '1';
|
|
165
210
|
}
|
|
211
|
+
function normalizeInterceptedRequests(interceptedRequests) {
|
|
212
|
+
return interceptedRequests.slice(0, MAX_CAPTURED_PAYLOADS).map(responseBody => ({
|
|
213
|
+
source: 'interceptor',
|
|
214
|
+
responseBody: sanitizeCapturedValue(responseBody),
|
|
215
|
+
}));
|
|
216
|
+
}
|
|
166
217
|
/** Safely collect page diagnostic state with redaction, size caps, and timeout. */
|
|
167
218
|
async function collectPageState(page) {
|
|
168
219
|
const collect = async () => {
|
|
169
220
|
try {
|
|
170
|
-
const [url, snapshot, networkRequests, consoleErrors] = await Promise.all([
|
|
221
|
+
const [url, snapshot, networkRequests, interceptedRequests, consoleErrors] = await Promise.all([
|
|
171
222
|
page.getCurrentUrl?.().catch(() => null) ?? Promise.resolve(null),
|
|
172
223
|
page.snapshot().catch(() => '(snapshot unavailable)'),
|
|
173
224
|
page.networkRequests().catch(() => []),
|
|
225
|
+
page.getInterceptedRequests().catch(() => []),
|
|
174
226
|
page.consoleMessages('error').catch(() => []),
|
|
175
227
|
]);
|
|
176
228
|
const rawUrl = url ?? 'unknown';
|
|
229
|
+
const capturedResponses = normalizeInterceptedRequests(interceptedRequests);
|
|
177
230
|
return {
|
|
178
231
|
url: redactUrl(rawUrl),
|
|
179
232
|
snapshot: redactText(truncate(snapshot, MAX_SNAPSHOT_CHARS)),
|
|
180
233
|
networkRequests: networkRequests
|
|
181
234
|
.slice(0, MAX_NETWORK_REQUESTS)
|
|
182
235
|
.map(redactNetworkRequest),
|
|
236
|
+
capturedPayloads: capturedResponses,
|
|
183
237
|
consoleErrors: consoleErrors
|
|
184
238
|
.slice(0, 50)
|
|
185
239
|
.map(e => typeof e === 'string' ? redactText(e) : e),
|
|
@@ -235,7 +289,15 @@ export function emitDiagnostic(ctx) {
|
|
|
235
289
|
let json = JSON.stringify(ctx);
|
|
236
290
|
// Enforce total output budget — drop page state (largest section) first if over budget
|
|
237
291
|
if (json.length > MAX_DIAGNOSTIC_BYTES && ctx.page) {
|
|
238
|
-
const trimmed = {
|
|
292
|
+
const trimmed = {
|
|
293
|
+
...ctx,
|
|
294
|
+
page: {
|
|
295
|
+
...ctx.page,
|
|
296
|
+
snapshot: '[omitted: over size budget]',
|
|
297
|
+
networkRequests: [],
|
|
298
|
+
capturedPayloads: [],
|
|
299
|
+
},
|
|
300
|
+
};
|
|
239
301
|
json = JSON.stringify(trimmed);
|
|
240
302
|
}
|
|
241
303
|
// If still over budget, drop page entirely
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect, vi, afterEach } from 'vitest';
|
|
2
|
-
import { buildRepairContext, isDiagnosticEnabled, emitDiagnostic, truncate, redactUrl, redactText, resolveAdapterSourcePath, MAX_DIAGNOSTIC_BYTES, } from './diagnostic.js';
|
|
2
|
+
import { buildRepairContext, collectDiagnostic, isDiagnosticEnabled, emitDiagnostic, truncate, redactUrl, redactText, resolveAdapterSourcePath, MAX_DIAGNOSTIC_BYTES, } from './diagnostic.js';
|
|
3
3
|
import { SelectorError, CommandExecutionError } from './errors.js';
|
|
4
4
|
function makeCmd(overrides = {}) {
|
|
5
5
|
return {
|
|
@@ -83,8 +83,8 @@ describe('redactText', () => {
|
|
|
83
83
|
});
|
|
84
84
|
describe('resolveAdapterSourcePath', () => {
|
|
85
85
|
it('returns source when it is a real file path (not manifest:)', () => {
|
|
86
|
-
const cmd = makeCmd({ source: '/home/user/.opencli/clis/arxiv/search.
|
|
87
|
-
expect(resolveAdapterSourcePath(cmd)).toBe('/home/user/.opencli/clis/arxiv/search.
|
|
86
|
+
const cmd = makeCmd({ source: '/home/user/.opencli/clis/arxiv/search.ts' });
|
|
87
|
+
expect(resolveAdapterSourcePath(cmd)).toBe('/home/user/.opencli/clis/arxiv/search.ts');
|
|
88
88
|
});
|
|
89
89
|
it('skips manifest: pseudo-paths and falls back to _modulePath', () => {
|
|
90
90
|
const cmd = makeCmd({ source: 'manifest:arxiv/search', _modulePath: '/pkg/dist/clis/arxiv/search.js' });
|
|
@@ -211,3 +211,93 @@ describe('emitDiagnostic', () => {
|
|
|
211
211
|
expect(redactUrl('https://api.com/data?token=secret123')).toContain('[REDACTED]');
|
|
212
212
|
});
|
|
213
213
|
});
|
|
214
|
+
function makePage(overrides = {}) {
|
|
215
|
+
return {
|
|
216
|
+
goto: vi.fn(),
|
|
217
|
+
evaluate: vi.fn(),
|
|
218
|
+
getCookies: vi.fn(),
|
|
219
|
+
snapshot: vi.fn().mockResolvedValue('<div>...</div>'),
|
|
220
|
+
click: vi.fn(),
|
|
221
|
+
typeText: vi.fn(),
|
|
222
|
+
pressKey: vi.fn(),
|
|
223
|
+
scrollTo: vi.fn(),
|
|
224
|
+
getFormState: vi.fn(),
|
|
225
|
+
wait: vi.fn(),
|
|
226
|
+
tabs: vi.fn(),
|
|
227
|
+
selectTab: vi.fn(),
|
|
228
|
+
networkRequests: vi.fn().mockResolvedValue([]),
|
|
229
|
+
consoleMessages: vi.fn().mockResolvedValue([]),
|
|
230
|
+
scroll: vi.fn(),
|
|
231
|
+
autoScroll: vi.fn(),
|
|
232
|
+
installInterceptor: vi.fn(),
|
|
233
|
+
getInterceptedRequests: vi.fn().mockResolvedValue([]),
|
|
234
|
+
waitForCapture: vi.fn(),
|
|
235
|
+
screenshot: vi.fn(),
|
|
236
|
+
getCurrentUrl: vi.fn().mockResolvedValue('https://example.com/page'),
|
|
237
|
+
...overrides,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
describe('collectDiagnostic', () => {
|
|
241
|
+
it('keeps intercepted payloads in a dedicated capturedPayloads field', async () => {
|
|
242
|
+
const page = makePage({
|
|
243
|
+
networkRequests: vi.fn().mockResolvedValue([{ url: '/api/data', status: 200 }]),
|
|
244
|
+
getInterceptedRequests: vi.fn().mockResolvedValue([{ items: [{ id: 1 }] }]),
|
|
245
|
+
});
|
|
246
|
+
const ctx = await collectDiagnostic(new Error('boom'), makeCmd(), page);
|
|
247
|
+
expect(ctx.page?.networkRequests).toEqual([
|
|
248
|
+
{ url: '/api/data', status: 200 },
|
|
249
|
+
]);
|
|
250
|
+
expect(ctx.page?.capturedPayloads).toEqual([
|
|
251
|
+
{ source: 'interceptor', responseBody: { items: [{ id: 1 }] } },
|
|
252
|
+
]);
|
|
253
|
+
});
|
|
254
|
+
it('preserves the previous network request output when interception is empty', async () => {
|
|
255
|
+
const page = makePage({
|
|
256
|
+
networkRequests: vi.fn().mockResolvedValue([{ url: '/api/data', status: 200 }]),
|
|
257
|
+
getInterceptedRequests: vi.fn().mockResolvedValue([]),
|
|
258
|
+
});
|
|
259
|
+
const ctx = await collectDiagnostic(new Error('boom'), makeCmd(), page);
|
|
260
|
+
expect(ctx.page?.networkRequests).toEqual([{ url: '/api/data', status: 200 }]);
|
|
261
|
+
expect(ctx.page?.capturedPayloads).toEqual([]);
|
|
262
|
+
});
|
|
263
|
+
it('swallows intercepted request failures and still returns page state', async () => {
|
|
264
|
+
const page = makePage({
|
|
265
|
+
networkRequests: vi.fn().mockResolvedValue([{ url: '/api/data', status: 200 }]),
|
|
266
|
+
getInterceptedRequests: vi.fn().mockRejectedValue(new Error('interceptor unavailable')),
|
|
267
|
+
});
|
|
268
|
+
const ctx = await collectDiagnostic(new Error('boom'), makeCmd(), page);
|
|
269
|
+
expect(ctx.page).toEqual({
|
|
270
|
+
url: 'https://example.com/page',
|
|
271
|
+
snapshot: '<div>...</div>',
|
|
272
|
+
networkRequests: [{ url: '/api/data', status: 200 }],
|
|
273
|
+
capturedPayloads: [],
|
|
274
|
+
consoleErrors: [],
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
it('redacts and truncates intercepted payloads recursively', async () => {
|
|
278
|
+
const page = makePage({
|
|
279
|
+
getInterceptedRequests: vi.fn().mockResolvedValue([{
|
|
280
|
+
token: 'token=abc123def456ghi789',
|
|
281
|
+
nested: {
|
|
282
|
+
cookie: 'cookie: session=super-secret-cookie-value',
|
|
283
|
+
body: 'x'.repeat(5000),
|
|
284
|
+
},
|
|
285
|
+
}]),
|
|
286
|
+
});
|
|
287
|
+
const ctx = await collectDiagnostic(new Error('boom'), makeCmd(), page);
|
|
288
|
+
const payload = ctx.page?.capturedPayloads?.[0];
|
|
289
|
+
const body = payload.responseBody.nested.body;
|
|
290
|
+
expect(payload).toEqual({
|
|
291
|
+
source: 'interceptor',
|
|
292
|
+
responseBody: {
|
|
293
|
+
token: 'token=[REDACTED]',
|
|
294
|
+
nested: {
|
|
295
|
+
cookie: 'cookie: [REDACTED]',
|
|
296
|
+
body,
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
});
|
|
300
|
+
expect(body).toContain('[truncated,');
|
|
301
|
+
expect(body.length).toBeLessThan(5000);
|
|
302
|
+
});
|
|
303
|
+
});
|