@jackwener/opencli 1.6.9 → 1.7.0
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 +128 -59
- package/README.zh-CN.md +134 -78
- package/dist/clis/_shared/common.d.ts +3 -0
- package/dist/clis/_shared/common.js +22 -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/detail.d.ts +1 -0
- package/dist/clis/jianyu/detail.js +20 -0
- package/dist/clis/jianyu/search.d.ts +41 -4
- package/dist/clis/jianyu/search.js +458 -96
- package/dist/clis/jianyu/search.test.js +105 -0
- package/dist/clis/jianyu/shared/china-bid-search.d.ts +12 -0
- package/dist/clis/jianyu/shared/china-bid-search.js +165 -0
- package/dist/clis/jianyu/shared/procurement-contract.d.ts +68 -0
- package/dist/clis/jianyu/shared/procurement-contract.js +324 -0
- package/dist/clis/jianyu/shared/procurement-contract.test.d.ts +1 -0
- package/dist/clis/jianyu/shared/procurement-contract.test.js +72 -0
- package/dist/clis/jianyu/shared/procurement-detail.d.ts +6 -0
- package/dist/clis/jianyu/shared/procurement-detail.js +92 -0
- package/dist/clis/jianyu/shared/procurement-detail.test.d.ts +1 -0
- package/dist/clis/jianyu/shared/procurement-detail.test.js +72 -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/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/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 +161 -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/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/hot.d.ts +1 -0
- package/dist/clis/zhihu/hot.js +43 -0
- package/dist/clis/zhihu/search.d.ts +1 -0
- package/dist/clis/zhihu/search.js +52 -0
- package/dist/src/browser/bridge.js +1 -1
- package/dist/src/browser/daemon-client.d.ts +16 -4
- package/dist/src/browser/daemon-client.js +33 -15
- package/dist/src/browser/daemon-client.test.js +0 -3
- 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/page.d.ts +9 -8
- package/dist/src/browser/page.js +33 -31
- package/dist/src/browser.test.js +25 -6
- 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 +71 -71
- 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 -1
- package/dist/src/clis/binance/commands.test.js +10 -6
- 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/commands/daemon.d.ts +2 -6
- package/dist/src/commands/daemon.js +2 -58
- package/dist/src/commands/daemon.test.js +24 -120
- 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/constants.d.ts +0 -2
- package/dist/src/constants.js +0 -2
- package/dist/src/daemon.d.ts +1 -1
- package/dist/src/daemon.js +2 -15
- package/dist/src/diagnostic.test.js +2 -2
- package/dist/src/discovery.d.ts +3 -3
- package/dist/src/discovery.js +34 -97
- package/dist/src/download/index.d.ts +1 -1
- package/dist/src/engine.test.js +4 -19
- package/dist/src/execution.js +5 -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 +9 -1
- package/dist/src/generate.js +2 -2
- 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 +1 -1
- package/dist/src/plugin.js +4 -6
- package/dist/src/plugin.test.js +31 -31
- 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 +4 -3
- 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/daemon.test.js +0 -65
- package/dist/src/idle-manager.d.ts +0 -19
- package/dist/src/idle-manager.js +0 -54
- package/dist/src/yaml-schema.d.ts +0 -29
- package/dist/src/yaml-schema.js +0 -22
- /package/dist/{src/daemon.test.d.ts → clis/bilibili/hot.d.ts} +0 -0
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Build-time CLI manifest compiler.
|
|
4
4
|
*
|
|
5
|
-
* Scans all
|
|
6
|
-
* manifest.json for instant cold-start registration
|
|
5
|
+
* Scans all TS CLI definitions and pre-compiles them into a single
|
|
6
|
+
* manifest.json for instant cold-start registration.
|
|
7
7
|
*
|
|
8
8
|
* Usage: npx tsx src/build-manifest.ts
|
|
9
9
|
* Output: cli-manifest.json at the package root
|
|
@@ -11,14 +11,12 @@
|
|
|
11
11
|
import * as fs from 'node:fs';
|
|
12
12
|
import * as path from 'node:path';
|
|
13
13
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
14
|
-
import yaml from 'js-yaml';
|
|
15
14
|
import { getErrorMessage } from './errors.js';
|
|
16
15
|
import { fullName, getRegistry } from './registry.js';
|
|
17
16
|
import { findPackageRoot, getCliManifestPath } from './package-paths.js';
|
|
18
17
|
const PACKAGE_ROOT = findPackageRoot(fileURLToPath(import.meta.url));
|
|
19
18
|
const CLIS_DIR = path.join(PACKAGE_ROOT, 'clis');
|
|
20
19
|
const OUTPUT = getCliManifestPath(CLIS_DIR);
|
|
21
|
-
import { parseYamlArgs } from './yaml-schema.js';
|
|
22
20
|
import { isRecord } from './utils.js';
|
|
23
21
|
const CLI_MODULE_PATTERN = /\bcli\s*\(/;
|
|
24
22
|
function toManifestArgs(args) {
|
|
@@ -64,43 +62,6 @@ function toManifestEntry(cmd, modulePath, sourceFile) {
|
|
|
64
62
|
navigateBefore: cmd.navigateBefore,
|
|
65
63
|
};
|
|
66
64
|
}
|
|
67
|
-
function scanYaml(filePath, site) {
|
|
68
|
-
try {
|
|
69
|
-
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
70
|
-
const def = yaml.load(raw);
|
|
71
|
-
if (!isRecord(def))
|
|
72
|
-
return null;
|
|
73
|
-
const cliDef = def;
|
|
74
|
-
const strategyStr = cliDef.strategy ?? (cliDef.browser === false ? 'public' : 'cookie');
|
|
75
|
-
const strategy = strategyStr.toUpperCase();
|
|
76
|
-
const browser = cliDef.browser ?? (strategy !== 'PUBLIC');
|
|
77
|
-
const args = parseYamlArgs(cliDef.args);
|
|
78
|
-
return {
|
|
79
|
-
site: cliDef.site ?? site,
|
|
80
|
-
name: cliDef.name ?? path.basename(filePath, path.extname(filePath)),
|
|
81
|
-
description: cliDef.description ?? '',
|
|
82
|
-
domain: cliDef.domain,
|
|
83
|
-
strategy: strategy.toLowerCase(),
|
|
84
|
-
browser,
|
|
85
|
-
aliases: isRecord(cliDef) && Array.isArray(cliDef.aliases)
|
|
86
|
-
? cliDef.aliases.filter((value) => typeof value === 'string')
|
|
87
|
-
: undefined,
|
|
88
|
-
args,
|
|
89
|
-
columns: cliDef.columns,
|
|
90
|
-
pipeline: cliDef.pipeline,
|
|
91
|
-
timeout: cliDef.timeout,
|
|
92
|
-
deprecated: cliDef.deprecated,
|
|
93
|
-
replacedBy: cliDef.replacedBy,
|
|
94
|
-
type: 'yaml',
|
|
95
|
-
sourceFile: path.relative(CLIS_DIR, filePath),
|
|
96
|
-
navigateBefore: cliDef.navigateBefore,
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
catch (err) {
|
|
100
|
-
process.stderr.write(`Warning: failed to parse ${filePath}: ${getErrorMessage(err)}\n`);
|
|
101
|
-
return null;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
65
|
export async function loadTsManifestEntries(filePath, site, importer = moduleHref => import(moduleHref)) {
|
|
105
66
|
try {
|
|
106
67
|
const src = fs.readFileSync(filePath, 'utf-8');
|
|
@@ -141,15 +102,6 @@ export async function loadTsManifestEntries(filePath, site, importer = moduleHre
|
|
|
141
102
|
return [];
|
|
142
103
|
}
|
|
143
104
|
}
|
|
144
|
-
/**
|
|
145
|
-
* When both YAML and TS adapters exist for the same site/name,
|
|
146
|
-
* prefer the TS version (it self-registers and typically has richer logic).
|
|
147
|
-
*/
|
|
148
|
-
export function shouldReplaceManifestEntry(current, next) {
|
|
149
|
-
if (current.type === next.type)
|
|
150
|
-
return false;
|
|
151
|
-
return current.type === 'yaml' && next.type === 'ts';
|
|
152
|
-
}
|
|
153
105
|
export async function buildManifest() {
|
|
154
106
|
const manifest = new Map();
|
|
155
107
|
if (fs.existsSync(CLIS_DIR)) {
|
|
@@ -158,32 +110,13 @@ export async function buildManifest() {
|
|
|
158
110
|
if (!fs.statSync(siteDir).isDirectory())
|
|
159
111
|
continue;
|
|
160
112
|
for (const file of fs.readdirSync(siteDir)) {
|
|
161
|
-
|
|
162
|
-
if (file.endsWith('.yaml') || file.endsWith('.yml')) {
|
|
163
|
-
const entry = scanYaml(filePath, site);
|
|
164
|
-
if (entry) {
|
|
165
|
-
const key = `${entry.site}/${entry.name}`;
|
|
166
|
-
const existing = manifest.get(key);
|
|
167
|
-
if (!existing || shouldReplaceManifestEntry(existing, entry)) {
|
|
168
|
-
if (existing && existing.type !== entry.type) {
|
|
169
|
-
process.stderr.write(`⚠️ Duplicate adapter ${key}: ${existing.type} superseded by ${entry.type}\n`);
|
|
170
|
-
}
|
|
171
|
-
manifest.set(key, entry);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
else if ((file.endsWith('.ts') && !file.endsWith('.d.ts') && !file.endsWith('.test.ts') && file !== 'index.ts') ||
|
|
113
|
+
if ((file.endsWith('.ts') && !file.endsWith('.d.ts') && !file.endsWith('.test.ts') && file !== 'index.ts') ||
|
|
176
114
|
(file.endsWith('.js') && !file.endsWith('.d.js') && !file.endsWith('.test.js') && file !== 'index.js')) {
|
|
115
|
+
const filePath = path.join(siteDir, file);
|
|
177
116
|
const entries = await loadTsManifestEntries(filePath, site);
|
|
178
117
|
for (const entry of entries) {
|
|
179
118
|
const key = `${entry.site}/${entry.name}`;
|
|
180
|
-
|
|
181
|
-
if (!existing || shouldReplaceManifestEntry(existing, entry)) {
|
|
182
|
-
if (existing && existing.type !== entry.type) {
|
|
183
|
-
process.stderr.write(`⚠️ Duplicate adapter ${key}: ${existing.type} superseded by ${entry.type}\n`);
|
|
184
|
-
}
|
|
185
|
-
manifest.set(key, entry);
|
|
186
|
-
}
|
|
119
|
+
manifest.set(key, entry);
|
|
187
120
|
}
|
|
188
121
|
}
|
|
189
122
|
}
|
|
@@ -195,9 +128,7 @@ async function main() {
|
|
|
195
128
|
const manifest = await buildManifest();
|
|
196
129
|
fs.mkdirSync(path.dirname(OUTPUT), { recursive: true });
|
|
197
130
|
fs.writeFileSync(OUTPUT, JSON.stringify(manifest, null, 2));
|
|
198
|
-
|
|
199
|
-
const tsCount = manifest.filter(e => e.type === 'ts').length;
|
|
200
|
-
console.log(`✅ Manifest compiled: ${manifest.length} entries (${yamlCount} YAML, ${tsCount} TS) → ${OUTPUT}`);
|
|
131
|
+
console.log(`✅ Manifest compiled: ${manifest.length} entries → ${OUTPUT}`);
|
|
201
132
|
// Restore executable permissions on bin entries.
|
|
202
133
|
// tsc does not preserve the +x bit, so after a clean rebuild the CLI
|
|
203
134
|
// entry-point loses its executable permission, causing "Permission denied".
|
|
@@ -3,7 +3,7 @@ import * as fs from 'node:fs';
|
|
|
3
3
|
import * as os from 'node:os';
|
|
4
4
|
import * as path from 'node:path';
|
|
5
5
|
import { cli, getRegistry, Strategy } from './registry.js';
|
|
6
|
-
import { loadTsManifestEntries
|
|
6
|
+
import { loadTsManifestEntries } from './build-manifest.js';
|
|
7
7
|
describe('manifest helper rules', () => {
|
|
8
8
|
const tempDirs = [];
|
|
9
9
|
afterEach(() => {
|
|
@@ -11,44 +11,6 @@ describe('manifest helper rules', () => {
|
|
|
11
11
|
fs.rmSync(dir, { recursive: true, force: true });
|
|
12
12
|
}
|
|
13
13
|
});
|
|
14
|
-
it('prefers TS adapters over duplicate YAML adapters', () => {
|
|
15
|
-
expect(shouldReplaceManifestEntry({
|
|
16
|
-
site: 'demo',
|
|
17
|
-
name: 'search',
|
|
18
|
-
description: 'yaml',
|
|
19
|
-
strategy: 'public',
|
|
20
|
-
browser: false,
|
|
21
|
-
args: [],
|
|
22
|
-
type: 'yaml',
|
|
23
|
-
}, {
|
|
24
|
-
site: 'demo',
|
|
25
|
-
name: 'search',
|
|
26
|
-
description: 'ts',
|
|
27
|
-
strategy: 'public',
|
|
28
|
-
browser: false,
|
|
29
|
-
args: [],
|
|
30
|
-
type: 'ts',
|
|
31
|
-
modulePath: 'demo/search.js',
|
|
32
|
-
})).toBe(true);
|
|
33
|
-
expect(shouldReplaceManifestEntry({
|
|
34
|
-
site: 'demo',
|
|
35
|
-
name: 'search',
|
|
36
|
-
description: 'ts',
|
|
37
|
-
strategy: 'public',
|
|
38
|
-
browser: false,
|
|
39
|
-
args: [],
|
|
40
|
-
type: 'ts',
|
|
41
|
-
modulePath: 'demo/search.js',
|
|
42
|
-
}, {
|
|
43
|
-
site: 'demo',
|
|
44
|
-
name: 'search',
|
|
45
|
-
description: 'yaml',
|
|
46
|
-
strategy: 'public',
|
|
47
|
-
browser: false,
|
|
48
|
-
args: [],
|
|
49
|
-
type: 'yaml',
|
|
50
|
-
})).toBe(false);
|
|
51
|
-
});
|
|
52
14
|
it('skips TS files that do not register a cli', () => {
|
|
53
15
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'opencli-manifest-'));
|
|
54
16
|
tempDirs.push(dir);
|
package/dist/src/cascade.js
CHANGED
|
@@ -72,13 +72,14 @@ export async function probeEndpoint(page, url, strategy, _opts = {}) {
|
|
|
72
72
|
try {
|
|
73
73
|
const opts = PROBE_OPTIONS[strategy];
|
|
74
74
|
if (opts) {
|
|
75
|
-
const resp = await page.evaluate(buildFetchProbeJs(url, opts));
|
|
75
|
+
const resp = (await page.evaluate(buildFetchProbeJs(url, opts)));
|
|
76
76
|
result.statusCode = resp?.status;
|
|
77
|
-
result.success = resp?.ok && resp?.hasData;
|
|
77
|
+
result.success = !!(resp?.ok && resp?.hasData);
|
|
78
78
|
result.hasData = resp?.hasData;
|
|
79
79
|
result.responsePreview = resp?.preview;
|
|
80
80
|
}
|
|
81
81
|
else {
|
|
82
|
+
// INTERCEPT / UI require site-specific implementation.
|
|
82
83
|
result.error = `Strategy ${strategy} requires site-specific implementation`;
|
|
83
84
|
}
|
|
84
85
|
}
|
package/dist/src/cli.d.ts
CHANGED
|
@@ -8,16 +8,16 @@ import { Command } from 'commander';
|
|
|
8
8
|
import { findPackageRoot } from './package-paths.js';
|
|
9
9
|
export declare function createProgram(BUILTIN_CLIS: string, USER_CLIS: string): Command;
|
|
10
10
|
export declare function runCli(BUILTIN_CLIS: string, USER_CLIS: string): void;
|
|
11
|
-
export interface
|
|
11
|
+
export interface BrowserVerifyInvocation {
|
|
12
12
|
binary: string;
|
|
13
13
|
args: string[];
|
|
14
14
|
cwd: string;
|
|
15
15
|
shell?: boolean;
|
|
16
16
|
}
|
|
17
17
|
export { findPackageRoot };
|
|
18
|
-
export declare function
|
|
18
|
+
export declare function resolveBrowserVerifyInvocation(opts?: {
|
|
19
19
|
projectRoot?: string;
|
|
20
20
|
platform?: NodeJS.Platform;
|
|
21
21
|
fileExists?: (path: string) => boolean;
|
|
22
22
|
readFile?: (path: string) => string;
|
|
23
|
-
}):
|
|
23
|
+
}): BrowserVerifyInvocation;
|
package/dist/src/cli.js
CHANGED
|
@@ -19,13 +19,13 @@ import { printCompletionScript } from './completion.js';
|
|
|
19
19
|
import { loadExternalClis, executeExternalCli, installExternalCli, registerExternalCli, isBinaryInstalled } from './external.js';
|
|
20
20
|
import { registerAllCommands } from './commanderAdapter.js';
|
|
21
21
|
import { EXIT_CODES, getErrorMessage } from './errors.js';
|
|
22
|
-
import {
|
|
22
|
+
import { daemonStop } from './commands/daemon.js';
|
|
23
23
|
const CLI_FILE = fileURLToPath(import.meta.url);
|
|
24
|
-
/** Create a browser page for
|
|
25
|
-
async function
|
|
24
|
+
/** Create a browser page for browser commands. Uses a dedicated browser workspace for session persistence. */
|
|
25
|
+
async function getBrowserPage() {
|
|
26
26
|
const { BrowserBridge } = await import('./browser/index.js');
|
|
27
27
|
const bridge = new BrowserBridge();
|
|
28
|
-
return bridge.connect({ timeout: 30, workspace: '
|
|
28
|
+
return bridge.connect({ timeout: 30, workspace: 'browser:default' });
|
|
29
29
|
}
|
|
30
30
|
function applyVerbose(opts) {
|
|
31
31
|
if (opts.verbose)
|
|
@@ -171,24 +171,30 @@ export function createProgram(BUILTIN_CLIS, USER_CLIS) {
|
|
|
171
171
|
});
|
|
172
172
|
program
|
|
173
173
|
.command('generate')
|
|
174
|
-
.description('One-shot: explore → synthesize → register')
|
|
174
|
+
.description('One-shot: explore → synthesize → verify → register')
|
|
175
175
|
.argument('<url>')
|
|
176
176
|
.option('--goal <text>')
|
|
177
177
|
.option('--site <name>')
|
|
178
|
+
.option('--format <fmt>', 'Output format: table, json', 'table')
|
|
179
|
+
.option('--no-register', 'Verify the generated adapter without registering it')
|
|
178
180
|
.option('-v, --verbose', 'Debug output')
|
|
179
181
|
.action(async (url, opts) => {
|
|
180
182
|
applyVerbose(opts);
|
|
181
|
-
const {
|
|
183
|
+
const { generateVerifiedFromUrl, renderGenerateVerifiedSummary } = await import('./generate-verified.js');
|
|
182
184
|
const workspace = `generate:${inferHost(url, opts.site)}`;
|
|
183
|
-
const r = await
|
|
185
|
+
const r = await generateVerifiedFromUrl({
|
|
184
186
|
url,
|
|
185
187
|
BrowserFactory: getBrowserFactory(),
|
|
186
188
|
goal: opts.goal,
|
|
187
189
|
site: opts.site,
|
|
188
190
|
workspace,
|
|
191
|
+
noRegister: opts.register === false,
|
|
189
192
|
});
|
|
190
|
-
|
|
191
|
-
|
|
193
|
+
if (opts.format === 'json')
|
|
194
|
+
console.log(JSON.stringify(r, null, 2));
|
|
195
|
+
else
|
|
196
|
+
console.log(renderGenerateVerifiedSummary(r));
|
|
197
|
+
process.exitCode = r.status === 'success' ? EXIT_CODES.SUCCESS : EXIT_CODES.GENERIC_ERROR;
|
|
192
198
|
});
|
|
193
199
|
// ── Built-in: record ─────────────────────────────────────────────────────
|
|
194
200
|
program
|
|
@@ -235,22 +241,22 @@ export function createProgram(BUILTIN_CLIS, USER_CLIS) {
|
|
|
235
241
|
}, { workspace });
|
|
236
242
|
console.log(renderCascadeResult(result));
|
|
237
243
|
});
|
|
238
|
-
// ── Built-in:
|
|
244
|
+
// ── Built-in: browser (browser control for Claude Code skill) ───────────────
|
|
239
245
|
//
|
|
240
246
|
// Make websites accessible for AI agents.
|
|
241
|
-
// All commands wrapped in
|
|
242
|
-
const
|
|
243
|
-
.command('
|
|
247
|
+
// All commands wrapped in browserAction() for consistent error handling.
|
|
248
|
+
const browser = program
|
|
249
|
+
.command('browser')
|
|
244
250
|
.description('Browser control — navigate, click, type, extract, wait (no LLM needed)');
|
|
245
|
-
/** Wrap
|
|
246
|
-
function
|
|
251
|
+
/** Wrap browser actions with error handling and optional --json output */
|
|
252
|
+
function browserAction(fn) {
|
|
247
253
|
return async (...args) => {
|
|
248
254
|
try {
|
|
249
|
-
const page = await
|
|
255
|
+
const page = await getBrowserPage();
|
|
250
256
|
await fn(page, ...args);
|
|
251
257
|
}
|
|
252
258
|
catch (err) {
|
|
253
|
-
const msg =
|
|
259
|
+
const msg = getErrorMessage(err);
|
|
254
260
|
if (msg.includes('Extension not connected') || msg.includes('Daemon')) {
|
|
255
261
|
console.error(`Browser not connected. Run 'opencli doctor' to diagnose.`);
|
|
256
262
|
}
|
|
@@ -267,8 +273,8 @@ export function createProgram(BUILTIN_CLIS, USER_CLIS) {
|
|
|
267
273
|
// ── Navigation ──
|
|
268
274
|
/** Network interceptor JS — injected on every open/navigate to capture fetch/XHR */
|
|
269
275
|
const NETWORK_INTERCEPTOR_JS = `(function(){if(window.__opencli_net)return;window.__opencli_net=[];var M=200,B=50000,F=window.fetch;window.fetch=async function(){var r=await F.apply(this,arguments);try{var ct=r.headers.get('content-type')||'';if(ct.includes('json')||ct.includes('text')){var c=r.clone(),t=await c.text();if(window.__opencli_net.length<M){var b=null;if(t.length<=B)try{b=JSON.parse(t)}catch(e){b=t}window.__opencli_net.push({url:r.url||(arguments[0]&&arguments[0].url)||String(arguments[0]),method:(arguments[1]&&arguments[1].method)||'GET',status:r.status,size:t.length,ct:ct,body:b})}}}catch(e){}return r};var X=XMLHttpRequest.prototype,O=X.open,S=X.send;X.open=function(m,u){this._om=m;this._ou=u;return O.apply(this,arguments)};X.send=function(){var x=this;x.addEventListener('load',function(){try{var ct=x.getResponseHeader('content-type')||'';if((ct.includes('json')||ct.includes('text'))&&window.__opencli_net.length<M){var t=x.responseText,b=null;if(t&&t.length<=B)try{b=JSON.parse(t)}catch(e){b=t}window.__opencli_net.push({url:x._ou,method:x._om||'GET',status:x.status,size:t?t.length:0,ct:ct,body:b})}}catch(e){}});return S.apply(this,arguments)}})()`;
|
|
270
|
-
|
|
271
|
-
.action(
|
|
276
|
+
browser.command('open').argument('<url>').description('Open URL in automation window')
|
|
277
|
+
.action(browserAction(async (page, url) => {
|
|
272
278
|
// Start session-level capture before navigation (catches initial requests)
|
|
273
279
|
const hasSessionCapture = await page.startNetworkCapture?.().then(() => true).catch(() => false);
|
|
274
280
|
await page.goto(url);
|
|
@@ -282,15 +288,15 @@ export function createProgram(BUILTIN_CLIS, USER_CLIS) {
|
|
|
282
288
|
}
|
|
283
289
|
console.log(`Navigated to: ${await page.getCurrentUrl?.() ?? url}`);
|
|
284
290
|
}));
|
|
285
|
-
|
|
286
|
-
.action(
|
|
291
|
+
browser.command('back').description('Go back in browser history')
|
|
292
|
+
.action(browserAction(async (page) => {
|
|
287
293
|
await page.evaluate('history.back()');
|
|
288
294
|
await page.wait(2);
|
|
289
295
|
console.log('Navigated back');
|
|
290
296
|
}));
|
|
291
|
-
|
|
297
|
+
browser.command('scroll').argument('<direction>', 'up or down').option('--amount <pixels>', 'Pixels to scroll', '500')
|
|
292
298
|
.description('Scroll page')
|
|
293
|
-
.action(
|
|
299
|
+
.action(browserAction(async (page, direction, opts) => {
|
|
294
300
|
if (direction !== 'up' && direction !== 'down') {
|
|
295
301
|
console.error(`Invalid direction "${direction}". Use "up" or "down".`);
|
|
296
302
|
process.exitCode = EXIT_CODES.USAGE_ERROR;
|
|
@@ -300,16 +306,16 @@ export function createProgram(BUILTIN_CLIS, USER_CLIS) {
|
|
|
300
306
|
console.log(`Scrolled ${direction}`);
|
|
301
307
|
}));
|
|
302
308
|
// ── Inspect ──
|
|
303
|
-
|
|
304
|
-
.action(
|
|
309
|
+
browser.command('state').description('Page state: URL, title, interactive elements with [N] indices')
|
|
310
|
+
.action(browserAction(async (page) => {
|
|
305
311
|
const snapshot = await page.snapshot({ viewportExpand: 2000 });
|
|
306
312
|
const url = await page.getCurrentUrl?.() ?? '';
|
|
307
313
|
console.log(`URL: ${url}\n`);
|
|
308
314
|
console.log(typeof snapshot === 'string' ? snapshot : JSON.stringify(snapshot, null, 2));
|
|
309
315
|
}));
|
|
310
|
-
|
|
316
|
+
browser.command('screenshot').argument('[path]', 'Save to file (base64 if omitted)')
|
|
311
317
|
.description('Take screenshot')
|
|
312
|
-
.action(
|
|
318
|
+
.action(browserAction(async (page, path) => {
|
|
313
319
|
if (path) {
|
|
314
320
|
await page.screenshot({ path });
|
|
315
321
|
console.log(`Screenshot saved to: ${path}`);
|
|
@@ -319,45 +325,45 @@ export function createProgram(BUILTIN_CLIS, USER_CLIS) {
|
|
|
319
325
|
}
|
|
320
326
|
}));
|
|
321
327
|
// ── Get commands (structured data extraction) ──
|
|
322
|
-
const get =
|
|
328
|
+
const get = browser.command('get').description('Get page properties');
|
|
323
329
|
get.command('title').description('Page title')
|
|
324
|
-
.action(
|
|
330
|
+
.action(browserAction(async (page) => {
|
|
325
331
|
console.log(await page.evaluate('document.title'));
|
|
326
332
|
}));
|
|
327
333
|
get.command('url').description('Current page URL')
|
|
328
|
-
.action(
|
|
334
|
+
.action(browserAction(async (page) => {
|
|
329
335
|
console.log(await page.getCurrentUrl?.() ?? await page.evaluate('location.href'));
|
|
330
336
|
}));
|
|
331
337
|
get.command('text').argument('<index>', 'Element index').description('Element text content')
|
|
332
|
-
.action(
|
|
338
|
+
.action(browserAction(async (page, index) => {
|
|
333
339
|
const text = await page.evaluate(`document.querySelector('[data-opencli-ref="${index}"]')?.textContent?.trim()`);
|
|
334
340
|
console.log(text ?? '(empty)');
|
|
335
341
|
}));
|
|
336
342
|
get.command('value').argument('<index>', 'Element index').description('Input/textarea value')
|
|
337
|
-
.action(
|
|
343
|
+
.action(browserAction(async (page, index) => {
|
|
338
344
|
const val = await page.evaluate(`document.querySelector('[data-opencli-ref="${index}"]')?.value`);
|
|
339
345
|
console.log(val ?? '(empty)');
|
|
340
346
|
}));
|
|
341
347
|
get.command('html').option('--selector <css>', 'CSS selector scope').description('Page HTML (or scoped)')
|
|
342
|
-
.action(
|
|
348
|
+
.action(browserAction(async (page, opts) => {
|
|
343
349
|
const sel = opts.selector ? JSON.stringify(opts.selector) : 'null';
|
|
344
350
|
const html = await page.evaluate(`(${sel} ? document.querySelector(${sel})?.outerHTML : document.documentElement.outerHTML)?.slice(0, 50000)`);
|
|
345
351
|
console.log(html ?? '(empty)');
|
|
346
352
|
}));
|
|
347
353
|
get.command('attributes').argument('<index>', 'Element index').description('Element attributes')
|
|
348
|
-
.action(
|
|
354
|
+
.action(browserAction(async (page, index) => {
|
|
349
355
|
const attrs = await page.evaluate(`JSON.stringify(Object.fromEntries([...document.querySelector('[data-opencli-ref="${index}"]')?.attributes].map(a=>[a.name,a.value])))`);
|
|
350
356
|
console.log(attrs ?? '{}');
|
|
351
357
|
}));
|
|
352
358
|
// ── Interact ──
|
|
353
|
-
|
|
354
|
-
.action(
|
|
359
|
+
browser.command('click').argument('<index>', 'Element index from state').description('Click element by index')
|
|
360
|
+
.action(browserAction(async (page, index) => {
|
|
355
361
|
await page.click(index);
|
|
356
362
|
console.log(`Clicked element [${index}]`);
|
|
357
363
|
}));
|
|
358
|
-
|
|
364
|
+
browser.command('type').argument('<index>', 'Element index').argument('<text>', 'Text to type')
|
|
359
365
|
.description('Click element, then type text')
|
|
360
|
-
.action(
|
|
366
|
+
.action(browserAction(async (page, index, text) => {
|
|
361
367
|
await page.click(index);
|
|
362
368
|
await page.wait(0.3);
|
|
363
369
|
await page.typeText(index, text);
|
|
@@ -380,9 +386,9 @@ export function createProgram(BUILTIN_CLIS, USER_CLIS) {
|
|
|
380
386
|
console.log(`Typed "${text}" into element [${index}]`);
|
|
381
387
|
}
|
|
382
388
|
}));
|
|
383
|
-
|
|
389
|
+
browser.command('select').argument('<index>', 'Element index of <select>').argument('<option>', 'Option text')
|
|
384
390
|
.description('Select dropdown option')
|
|
385
|
-
.action(
|
|
391
|
+
.action(browserAction(async (page, index, option) => {
|
|
386
392
|
const result = await page.evaluate(`
|
|
387
393
|
(function() {
|
|
388
394
|
var sel = document.querySelector('[data-opencli-ref="${index}"]');
|
|
@@ -404,19 +410,19 @@ export function createProgram(BUILTIN_CLIS, USER_CLIS) {
|
|
|
404
410
|
console.log(`Selected "${result?.selected}" in element [${index}]`);
|
|
405
411
|
}
|
|
406
412
|
}));
|
|
407
|
-
|
|
413
|
+
browser.command('keys').argument('<key>', 'Key to press (Enter, Escape, Tab, Control+a)')
|
|
408
414
|
.description('Press keyboard key')
|
|
409
|
-
.action(
|
|
415
|
+
.action(browserAction(async (page, key) => {
|
|
410
416
|
await page.pressKey(key);
|
|
411
417
|
console.log(`Pressed: ${key}`);
|
|
412
418
|
}));
|
|
413
419
|
// ── Wait commands ──
|
|
414
|
-
|
|
420
|
+
browser.command('wait')
|
|
415
421
|
.argument('<type>', 'selector, text, or time')
|
|
416
422
|
.argument('[value]', 'CSS selector, text string, or seconds')
|
|
417
423
|
.option('--timeout <ms>', 'Timeout in milliseconds', '10000')
|
|
418
424
|
.description('Wait for selector, text, or time (e.g. wait selector ".loaded", wait text "Success", wait time 3)')
|
|
419
|
-
.action(
|
|
425
|
+
.action(browserAction(async (page, type, value, opts) => {
|
|
420
426
|
const timeout = parseInt(opts.timeout, 10);
|
|
421
427
|
if (type === 'time') {
|
|
422
428
|
const seconds = parseFloat(value ?? '2');
|
|
@@ -447,8 +453,8 @@ export function createProgram(BUILTIN_CLIS, USER_CLIS) {
|
|
|
447
453
|
}
|
|
448
454
|
}));
|
|
449
455
|
// ── Extract ──
|
|
450
|
-
|
|
451
|
-
.action(
|
|
456
|
+
browser.command('eval').argument('<js>', 'JavaScript code').description('Execute JS in page context, return result')
|
|
457
|
+
.action(browserAction(async (page, js) => {
|
|
452
458
|
const result = await page.evaluate(js);
|
|
453
459
|
if (typeof result === 'string')
|
|
454
460
|
console.log(result);
|
|
@@ -456,11 +462,11 @@ export function createProgram(BUILTIN_CLIS, USER_CLIS) {
|
|
|
456
462
|
console.log(JSON.stringify(result, null, 2));
|
|
457
463
|
}));
|
|
458
464
|
// ── Network (API discovery) ──
|
|
459
|
-
|
|
465
|
+
browser.command('network')
|
|
460
466
|
.option('--detail <index>', 'Show full response body of request at index')
|
|
461
467
|
.option('--all', 'Show all requests including static resources')
|
|
462
468
|
.description('Show captured network requests (auto-captured since last open)')
|
|
463
|
-
.action(
|
|
469
|
+
.action(browserAction(async (page, opts) => {
|
|
464
470
|
let items = [];
|
|
465
471
|
if (page.readNetworkCapture) {
|
|
466
472
|
const raw = await page.readNetworkCapture();
|
|
@@ -498,7 +504,7 @@ export function createProgram(BUILTIN_CLIS, USER_CLIS) {
|
|
|
498
504
|
items = JSON.parse(requests);
|
|
499
505
|
}
|
|
500
506
|
catch {
|
|
501
|
-
console.log('No network data captured. Run "
|
|
507
|
+
console.log('No network data captured. Run "browser open <url>" first.');
|
|
502
508
|
return;
|
|
503
509
|
}
|
|
504
510
|
}
|
|
@@ -537,7 +543,7 @@ export function createProgram(BUILTIN_CLIS, USER_CLIS) {
|
|
|
537
543
|
}
|
|
538
544
|
}));
|
|
539
545
|
// ── Init (adapter scaffolding) ──
|
|
540
|
-
|
|
546
|
+
browser.command('init')
|
|
541
547
|
.argument('<name>', 'Adapter name in site/command format (e.g. hn/top)')
|
|
542
548
|
.description('Generate adapter scaffold in ~/.opencli/clis/')
|
|
543
549
|
.action(async (name) => {
|
|
@@ -563,10 +569,10 @@ export function createProgram(BUILTIN_CLIS, USER_CLIS) {
|
|
|
563
569
|
console.log(`Adapter already exists: ${filePath}`);
|
|
564
570
|
return;
|
|
565
571
|
}
|
|
566
|
-
// Try to detect domain from last
|
|
572
|
+
// Try to detect domain from the last browser session
|
|
567
573
|
let domain = site;
|
|
568
574
|
try {
|
|
569
|
-
const page = await
|
|
575
|
+
const page = await getBrowserPage();
|
|
570
576
|
const url = await page.getCurrentUrl?.();
|
|
571
577
|
if (url) {
|
|
572
578
|
try {
|
|
@@ -600,7 +606,7 @@ cli({
|
|
|
600
606
|
fs.mkdirSync(dir, { recursive: true });
|
|
601
607
|
fs.writeFileSync(filePath, template, 'utf-8');
|
|
602
608
|
console.log(`Created: ${filePath}`);
|
|
603
|
-
console.log(`Edit the file to implement your adapter, then run: opencli
|
|
609
|
+
console.log(`Edit the file to implement your adapter, then run: opencli browser verify ${name}`);
|
|
604
610
|
}
|
|
605
611
|
catch (err) {
|
|
606
612
|
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -608,7 +614,7 @@ cli({
|
|
|
608
614
|
}
|
|
609
615
|
});
|
|
610
616
|
// ── Verify (test adapter) ──
|
|
611
|
-
|
|
617
|
+
browser.command('verify')
|
|
612
618
|
.argument('<name>', 'Adapter name in site/command format (e.g. hn/top)')
|
|
613
619
|
.description('Execute an adapter and show results')
|
|
614
620
|
.action(async (name) => {
|
|
@@ -630,7 +636,7 @@ cli({
|
|
|
630
636
|
const filePath = path.join(os.homedir(), '.opencli', 'clis', site, `${command}.ts`);
|
|
631
637
|
if (!fs.existsSync(filePath)) {
|
|
632
638
|
console.error(`Adapter not found: ${filePath}`);
|
|
633
|
-
console.error(`Run "opencli
|
|
639
|
+
console.error(`Run "opencli browser init ${name}" to create it.`);
|
|
634
640
|
process.exitCode = EXIT_CODES.GENERIC_ERROR;
|
|
635
641
|
return;
|
|
636
642
|
}
|
|
@@ -641,7 +647,7 @@ cli({
|
|
|
641
647
|
const hasLimitArg = /['"]limit['"]/.test(adapterSrc);
|
|
642
648
|
const limitFlag = hasLimitArg ? ' --limit 3' : '';
|
|
643
649
|
const limitArgs = hasLimitArg ? ['--limit', '3'] : [];
|
|
644
|
-
const invocation =
|
|
650
|
+
const invocation = resolveBrowserVerifyInvocation();
|
|
645
651
|
try {
|
|
646
652
|
const output = execFileSync(invocation.binary, [...invocation.args, site, command, ...limitArgs], {
|
|
647
653
|
cwd: invocation.cwd,
|
|
@@ -657,10 +663,12 @@ cli({
|
|
|
657
663
|
}
|
|
658
664
|
catch (err) {
|
|
659
665
|
console.log(` Executing: opencli ${site} ${command}${limitFlag}\n`);
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
if (
|
|
663
|
-
console.
|
|
666
|
+
// execFileSync attaches captured stdout/stderr on its thrown Error.
|
|
667
|
+
const execErr = err;
|
|
668
|
+
if (execErr.stdout)
|
|
669
|
+
console.log(String(execErr.stdout));
|
|
670
|
+
if (execErr.stderr)
|
|
671
|
+
console.error(String(execErr.stderr).slice(0, 500));
|
|
664
672
|
console.log(`\n ✗ Adapter failed. Fix the code and try again.`);
|
|
665
673
|
process.exitCode = EXIT_CODES.GENERIC_ERROR;
|
|
666
674
|
}
|
|
@@ -671,8 +679,8 @@ cli({
|
|
|
671
679
|
}
|
|
672
680
|
});
|
|
673
681
|
// ── Session ──
|
|
674
|
-
|
|
675
|
-
.action(
|
|
682
|
+
browser.command('close').description('Close the automation window')
|
|
683
|
+
.action(browserAction(async (page) => {
|
|
676
684
|
await page.closeWindow?.();
|
|
677
685
|
console.log('Automation window closed');
|
|
678
686
|
}));
|
|
@@ -884,18 +892,10 @@ cli({
|
|
|
884
892
|
});
|
|
885
893
|
// ── Built-in: daemon ──────────────────────────────────────────────────────
|
|
886
894
|
const daemonCmd = program.command('daemon').description('Manage the opencli daemon');
|
|
887
|
-
daemonCmd
|
|
888
|
-
.command('status')
|
|
889
|
-
.description('Show daemon status')
|
|
890
|
-
.action(async () => { await daemonStatus(); });
|
|
891
895
|
daemonCmd
|
|
892
896
|
.command('stop')
|
|
893
897
|
.description('Stop the daemon')
|
|
894
898
|
.action(async () => { await daemonStop(); });
|
|
895
|
-
daemonCmd
|
|
896
|
-
.command('restart')
|
|
897
|
-
.description('Restart the daemon')
|
|
898
|
-
.action(async () => { await daemonRestart(); });
|
|
899
899
|
// ── External CLIs ─────────────────────────────────────────────────────────
|
|
900
900
|
const externalClis = loadExternalClis();
|
|
901
901
|
program
|
|
@@ -978,7 +978,7 @@ export function runCli(BUILTIN_CLIS, USER_CLIS) {
|
|
|
978
978
|
createProgram(BUILTIN_CLIS, USER_CLIS).parse();
|
|
979
979
|
}
|
|
980
980
|
export { findPackageRoot };
|
|
981
|
-
export function
|
|
981
|
+
export function resolveBrowserVerifyInvocation(opts = {}) {
|
|
982
982
|
const platform = opts.platform ?? process.platform;
|
|
983
983
|
const fileExists = opts.fileExists ?? fs.existsSync;
|
|
984
984
|
const readFile = opts.readFile ?? ((filePath) => fs.readFileSync(filePath, 'utf-8'));
|