@jackwener/opencli 1.1.1 → 1.2.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/CONTRIBUTING.md +39 -1
- package/README.md +9 -10
- package/README.zh-CN.md +39 -17
- package/SKILL.md +10 -5
- package/dist/browser/cdp.d.ts +4 -4
- package/dist/browser/cdp.js +39 -16
- package/dist/browser/daemon-client.d.ts +2 -1
- package/dist/browser/dom-helpers.js +38 -7
- package/dist/browser/dom-snapshot.d.ts +86 -0
- package/dist/browser/dom-snapshot.js +729 -0
- package/dist/browser/dom-snapshot.test.d.ts +11 -0
- package/dist/browser/dom-snapshot.test.js +212 -0
- package/dist/browser/index.d.ts +2 -0
- package/dist/browser/index.js +1 -0
- package/dist/browser/page.d.ts +14 -24
- package/dist/browser/page.js +37 -4
- package/dist/build-manifest.d.ts +11 -4
- package/dist/build-manifest.js +59 -21
- package/dist/build-manifest.test.js +58 -2
- package/dist/cli-manifest.json +3856 -1509
- package/dist/cli.js +66 -0
- package/dist/clis/barchart/greeks.js +1 -1
- package/dist/clis/barchart/options.js +1 -1
- package/dist/clis/barchart/quote.js +1 -1
- package/dist/clis/bilibili/download.js +1 -1
- package/dist/clis/bilibili/following.js +1 -1
- package/dist/clis/bilibili/subtitle.js +1 -1
- package/dist/clis/bilibili/user-videos.js +1 -1
- package/dist/clis/boss/batchgreet.js +10 -97
- package/dist/clis/boss/chatlist.js +8 -25
- package/dist/clis/boss/chatmsg.js +11 -42
- package/dist/clis/boss/common.d.ts +92 -0
- package/dist/clis/boss/common.js +223 -0
- package/dist/clis/boss/detail.js +7 -49
- package/dist/clis/boss/exchange.js +13 -79
- package/dist/clis/boss/greet.js +18 -145
- package/dist/clis/boss/invite.js +26 -121
- package/dist/clis/boss/joblist.js +6 -31
- package/dist/clis/boss/mark.js +12 -85
- package/dist/clis/boss/recommend.js +10 -49
- package/dist/clis/boss/resume.js +18 -118
- package/dist/clis/boss/search.js +12 -60
- package/dist/clis/boss/send.js +17 -151
- package/dist/clis/boss/stats.js +18 -69
- package/dist/clis/coupang/add-to-cart.js +1 -1
- package/dist/clis/devto/tag.yaml +34 -0
- package/dist/clis/devto/top.yaml +29 -0
- package/dist/clis/devto/user.yaml +33 -0
- package/dist/clis/douban/book-hot.d.ts +1 -0
- package/dist/clis/douban/book-hot.js +14 -0
- package/dist/clis/douban/marks.d.ts +1 -0
- package/dist/clis/douban/marks.js +115 -0
- package/dist/clis/douban/movie-hot.d.ts +1 -0
- package/dist/clis/douban/movie-hot.js +14 -0
- package/dist/clis/douban/reviews.d.ts +1 -0
- package/dist/clis/douban/reviews.js +106 -0
- package/dist/clis/douban/search.d.ts +1 -0
- package/dist/clis/douban/search.js +16 -0
- package/dist/clis/douban/shared.d.ts +4 -0
- package/dist/clis/douban/shared.js +155 -0
- package/dist/clis/douban/subject.yaml +76 -0
- package/dist/clis/douban/top250.yaml +70 -0
- package/dist/clis/douban/utils.d.ts +35 -0
- package/dist/clis/douban/utils.js +48 -0
- package/dist/clis/facebook/add-friend.yaml +43 -0
- package/dist/clis/facebook/events.yaml +44 -0
- package/dist/clis/facebook/feed.yaml +63 -0
- package/dist/clis/facebook/friends.yaml +42 -0
- package/dist/clis/facebook/groups.yaml +50 -0
- package/dist/clis/facebook/join-group.yaml +44 -0
- package/dist/clis/facebook/memories.yaml +39 -0
- package/dist/clis/facebook/notifications.yaml +40 -0
- package/dist/clis/facebook/profile.yaml +37 -0
- package/dist/clis/facebook/search.yaml +46 -0
- package/dist/clis/google/news.d.ts +5 -0
- package/dist/clis/google/news.js +58 -0
- package/dist/clis/google/search.d.ts +10 -0
- package/dist/clis/google/search.js +127 -0
- package/dist/clis/google/suggest.d.ts +5 -0
- package/dist/clis/google/suggest.js +34 -0
- package/dist/clis/google/trends.d.ts +5 -0
- package/dist/clis/google/trends.js +38 -0
- package/dist/clis/google/utils.d.ts +9 -0
- package/dist/clis/google/utils.js +23 -0
- package/dist/clis/google/utils.test.d.ts +1 -0
- package/dist/clis/google/utils.test.js +75 -0
- package/dist/clis/grok/ask.d.ts +14 -0
- package/dist/clis/grok/ask.js +257 -65
- package/dist/clis/grok/ask.test.d.ts +1 -0
- package/dist/clis/grok/ask.test.js +36 -0
- package/dist/clis/instagram/comment.yaml +52 -0
- package/dist/clis/instagram/explore.yaml +43 -0
- package/dist/clis/instagram/follow.yaml +41 -0
- package/dist/clis/instagram/followers.yaml +51 -0
- package/dist/clis/instagram/following.yaml +51 -0
- package/dist/clis/instagram/like.yaml +46 -0
- package/dist/clis/instagram/profile.yaml +42 -0
- package/dist/clis/instagram/save.yaml +46 -0
- package/dist/clis/instagram/saved.yaml +40 -0
- package/dist/clis/instagram/search.yaml +43 -0
- package/dist/clis/instagram/unfollow.yaml +38 -0
- package/dist/clis/instagram/unlike.yaml +46 -0
- package/dist/clis/instagram/unsave.yaml +46 -0
- package/dist/clis/instagram/user.yaml +54 -0
- package/dist/clis/jike/repost.js +1 -1
- package/dist/clis/jimeng/generate.yaml +1 -0
- package/dist/clis/linux-do/category.yaml +1 -0
- package/dist/clis/lobsters/active.yaml +29 -0
- package/dist/clis/lobsters/hot.yaml +29 -0
- package/dist/clis/lobsters/newest.yaml +29 -0
- package/dist/clis/lobsters/tag.yaml +34 -0
- package/dist/clis/medium/feed.d.ts +1 -0
- package/dist/clis/medium/feed.js +15 -0
- package/dist/clis/medium/search.d.ts +1 -0
- package/dist/clis/medium/search.js +15 -0
- package/dist/clis/medium/shared.d.ts +5 -0
- package/dist/clis/medium/shared.js +78 -0
- package/dist/clis/medium/user.d.ts +1 -0
- package/dist/clis/medium/user.js +15 -0
- package/dist/clis/reddit/comment.js +1 -1
- package/dist/clis/reddit/read.js +1 -1
- package/dist/clis/reddit/save.js +1 -1
- package/dist/clis/reddit/subreddit.yaml +1 -0
- package/dist/clis/reddit/subscribe.js +1 -1
- package/dist/clis/reddit/upvote.js +1 -1
- package/dist/clis/sinablog/article.d.ts +1 -0
- package/dist/clis/sinablog/article.js +14 -0
- package/dist/clis/sinablog/hot.d.ts +1 -0
- package/dist/clis/sinablog/hot.js +14 -0
- package/dist/clis/sinablog/search.d.ts +1 -0
- package/dist/clis/sinablog/search.js +51 -0
- package/dist/clis/sinablog/shared.d.ts +7 -0
- package/dist/clis/sinablog/shared.js +187 -0
- package/dist/clis/sinablog/user.d.ts +1 -0
- package/dist/clis/sinablog/user.js +15 -0
- package/dist/clis/substack/feed.d.ts +1 -0
- package/dist/clis/substack/feed.js +15 -0
- package/dist/clis/substack/publication.d.ts +1 -0
- package/dist/clis/substack/publication.js +15 -0
- package/dist/clis/substack/search.d.ts +1 -0
- package/dist/clis/substack/search.js +77 -0
- package/dist/clis/substack/shared.d.ts +4 -0
- package/dist/clis/substack/shared.js +129 -0
- package/dist/clis/tiktok/comment.yaml +66 -0
- package/dist/clis/tiktok/explore.yaml +39 -0
- package/dist/clis/tiktok/follow.yaml +39 -0
- package/dist/clis/tiktok/following.yaml +46 -0
- package/dist/clis/tiktok/friends.yaml +47 -0
- package/dist/clis/tiktok/like.yaml +38 -0
- package/dist/clis/tiktok/live.yaml +51 -0
- package/dist/clis/tiktok/notifications.yaml +52 -0
- package/dist/clis/tiktok/profile.yaml +45 -0
- package/dist/clis/tiktok/save.yaml +34 -0
- package/dist/clis/tiktok/search.yaml +46 -0
- package/dist/clis/tiktok/unfollow.yaml +44 -0
- package/dist/clis/tiktok/unlike.yaml +38 -0
- package/dist/clis/tiktok/unsave.yaml +36 -0
- package/dist/clis/tiktok/user.yaml +44 -0
- package/dist/clis/twitter/download.d.ts +1 -1
- package/dist/clis/twitter/download.js +3 -3
- package/dist/clis/twitter/followers.js +1 -1
- package/dist/clis/twitter/following.js +1 -1
- package/dist/clis/twitter/thread.js +1 -1
- package/dist/clis/twitter/timeline.d.ts +23 -0
- package/dist/clis/twitter/timeline.js +42 -14
- package/dist/clis/twitter/timeline.test.d.ts +1 -0
- package/dist/clis/twitter/timeline.test.js +102 -0
- package/dist/clis/wikipedia/random.d.ts +1 -0
- package/dist/clis/wikipedia/random.js +19 -0
- package/dist/clis/wikipedia/search.js +3 -3
- package/dist/clis/wikipedia/summary.js +4 -9
- package/dist/clis/wikipedia/trending.d.ts +1 -0
- package/dist/clis/wikipedia/trending.js +35 -0
- package/dist/clis/wikipedia/utils.d.ts +28 -0
- package/dist/clis/wikipedia/utils.js +13 -0
- package/dist/clis/xiaohongshu/creator-note-detail.js +1 -1
- package/dist/clis/xiaohongshu/creator-note-detail.test.js +2 -0
- package/dist/clis/xiaohongshu/creator-notes.test.js +2 -0
- package/dist/clis/xiaohongshu/download.js +1 -1
- package/dist/clis/xueqiu/earnings-date.yaml +69 -0
- package/dist/clis/xueqiu/search.yaml +2 -1
- package/dist/clis/xueqiu/stock.yaml +2 -0
- package/dist/clis/yahoo-finance/quote.js +1 -1
- package/dist/commanderAdapter.js +13 -7
- package/dist/discovery.d.ts +8 -0
- package/dist/discovery.js +105 -19
- package/dist/doctor.js +3 -1
- package/dist/doctor.test.js +46 -2
- package/dist/engine.test.d.ts +0 -3
- package/dist/engine.test.js +74 -6
- package/dist/execution.d.ts +4 -2
- package/dist/execution.js +31 -7
- package/dist/explore.d.ts +76 -3
- package/dist/explore.js +11 -4
- package/dist/generate.d.ts +41 -2
- package/dist/generate.js +5 -4
- package/dist/main.js +2 -1
- package/dist/pipeline/executor.d.ts +2 -2
- package/dist/pipeline/executor.js +2 -2
- package/dist/pipeline/executor.test.js +33 -6
- package/dist/pipeline/registry.d.ts +1 -1
- package/dist/pipeline/steps/browser.d.ts +7 -7
- package/dist/pipeline/steps/browser.js +15 -7
- package/dist/pipeline/steps/fetch.d.ts +1 -1
- package/dist/pipeline/steps/fetch.js +11 -7
- package/dist/pipeline/steps/transform.d.ts +6 -5
- package/dist/pipeline/steps/transform.js +30 -9
- package/dist/pipeline/template.d.ts +6 -6
- package/dist/pipeline/template.js +43 -5
- package/dist/pipeline/template.test.js +18 -0
- package/dist/pipeline/transform.test.js +11 -0
- package/dist/plugin.d.ts +31 -0
- package/dist/plugin.js +216 -0
- package/dist/plugin.test.d.ts +4 -0
- package/dist/plugin.test.js +76 -0
- package/dist/registry-api.d.ts +11 -0
- package/dist/registry-api.js +9 -0
- package/dist/registry.d.ts +11 -0
- package/dist/registry.js +6 -1
- package/dist/synthesize.d.ts +94 -4
- package/dist/synthesize.js +5 -4
- package/dist/types.d.ts +39 -26
- package/dist/validate.js +8 -2
- package/docs/.vitepress/config.mts +6 -4
- package/docs/adapters/browser/barchart.md +6 -5
- package/docs/adapters/browser/bilibili.md +9 -0
- package/docs/adapters/browser/devto.md +35 -0
- package/docs/adapters/browser/douban.md +38 -0
- package/docs/adapters/browser/facebook.md +36 -0
- package/docs/adapters/browser/google.md +62 -0
- package/docs/adapters/browser/grok.md +26 -8
- package/docs/adapters/browser/instagram.md +46 -0
- package/docs/adapters/browser/lobsters.md +32 -0
- package/docs/adapters/browser/medium.md +32 -0
- package/docs/adapters/browser/reddit.md +9 -0
- package/docs/adapters/browser/sinablog.md +36 -0
- package/docs/adapters/browser/substack.md +38 -0
- package/docs/adapters/browser/tiktok.md +68 -0
- package/docs/adapters/browser/wikipedia.md +11 -2
- package/docs/adapters/browser/xueqiu.md +10 -0
- package/docs/adapters/browser/yahoo-finance.md +6 -5
- package/docs/adapters/desktop/antigravity.md +6 -0
- package/docs/adapters/desktop/chatgpt.md +2 -1
- package/docs/adapters/desktop/codex.md +5 -1
- package/docs/adapters/desktop/cursor.md +4 -0
- package/docs/adapters/desktop/discord.md +7 -7
- package/docs/adapters/index.md +1 -4
- package/docs/guide/getting-started.md +1 -0
- package/docs/guide/plugins.md +153 -0
- package/docs/zh/guide/plugins.md +107 -0
- package/extension/src/background.ts +18 -11
- package/package.json +10 -5
- package/scripts/clean-dist.cjs +13 -0
- package/src/browser/cdp.ts +71 -31
- package/src/browser/daemon-client.ts +2 -1
- package/src/browser/dom-helpers.ts +38 -7
- package/src/browser/dom-snapshot.test.ts +249 -0
- package/src/browser/dom-snapshot.ts +770 -0
- package/src/browser/index.ts +2 -0
- package/src/browser/page.ts +50 -19
- package/src/build-manifest.test.ts +70 -2
- package/src/build-manifest.ts +94 -26
- package/src/cli.ts +71 -2
- package/src/clis/barchart/greeks.ts +1 -1
- package/src/clis/barchart/options.ts +1 -1
- package/src/clis/barchart/quote.ts +1 -1
- package/src/clis/bilibili/download.ts +1 -1
- package/src/clis/bilibili/following.ts +1 -1
- package/src/clis/bilibili/subtitle.ts +1 -1
- package/src/clis/bilibili/user-videos.ts +1 -1
- package/src/clis/boss/batchgreet.ts +14 -106
- package/src/clis/boss/chatlist.ts +12 -26
- package/src/clis/boss/chatmsg.ts +16 -40
- package/src/clis/boss/common.ts +287 -0
- package/src/clis/boss/detail.ts +8 -54
- package/src/clis/boss/exchange.ts +15 -89
- package/src/clis/boss/greet.ts +23 -160
- package/src/clis/boss/invite.ts +36 -133
- package/src/clis/boss/joblist.ts +7 -36
- package/src/clis/boss/mark.ts +13 -94
- package/src/clis/boss/recommend.ts +12 -57
- package/src/clis/boss/resume.ts +19 -124
- package/src/clis/boss/search.ts +13 -66
- package/src/clis/boss/send.ts +21 -161
- package/src/clis/boss/stats.ts +19 -74
- package/src/clis/coupang/add-to-cart.ts +1 -1
- package/src/clis/devto/tag.yaml +34 -0
- package/src/clis/devto/top.yaml +29 -0
- package/src/clis/devto/user.yaml +33 -0
- package/src/clis/douban/book-hot.ts +15 -0
- package/src/clis/douban/marks.ts +135 -0
- package/src/clis/douban/movie-hot.ts +15 -0
- package/src/clis/douban/reviews.ts +127 -0
- package/src/clis/douban/search.ts +17 -0
- package/src/clis/douban/shared.ts +165 -0
- package/src/clis/douban/subject.yaml +76 -0
- package/src/clis/douban/top250.yaml +70 -0
- package/src/clis/douban/utils.ts +81 -0
- package/src/clis/facebook/add-friend.yaml +43 -0
- package/src/clis/facebook/events.yaml +44 -0
- package/src/clis/facebook/feed.yaml +63 -0
- package/src/clis/facebook/friends.yaml +42 -0
- package/src/clis/facebook/groups.yaml +50 -0
- package/src/clis/facebook/join-group.yaml +44 -0
- package/src/clis/facebook/memories.yaml +39 -0
- package/src/clis/facebook/notifications.yaml +40 -0
- package/src/clis/facebook/profile.yaml +37 -0
- package/src/clis/facebook/search.yaml +46 -0
- package/src/clis/google/news.ts +66 -0
- package/src/clis/google/search.ts +133 -0
- package/src/clis/google/suggest.ts +40 -0
- package/src/clis/google/trends.ts +44 -0
- package/src/clis/google/utils.test.ts +82 -0
- package/src/clis/google/utils.ts +24 -0
- package/src/clis/grok/ask.test.ts +53 -0
- package/src/clis/grok/ask.ts +300 -69
- package/src/clis/instagram/comment.yaml +52 -0
- package/src/clis/instagram/explore.yaml +43 -0
- package/src/clis/instagram/follow.yaml +41 -0
- package/src/clis/instagram/followers.yaml +51 -0
- package/src/clis/instagram/following.yaml +51 -0
- package/src/clis/instagram/like.yaml +46 -0
- package/src/clis/instagram/profile.yaml +42 -0
- package/src/clis/instagram/save.yaml +46 -0
- package/src/clis/instagram/saved.yaml +40 -0
- package/src/clis/instagram/search.yaml +43 -0
- package/src/clis/instagram/unfollow.yaml +38 -0
- package/src/clis/instagram/unlike.yaml +46 -0
- package/src/clis/instagram/unsave.yaml +46 -0
- package/src/clis/instagram/user.yaml +54 -0
- package/src/clis/jike/repost.ts +1 -1
- package/src/clis/jimeng/generate.yaml +1 -0
- package/src/clis/linux-do/category.yaml +1 -0
- package/src/clis/lobsters/active.yaml +29 -0
- package/src/clis/lobsters/hot.yaml +29 -0
- package/src/clis/lobsters/newest.yaml +29 -0
- package/src/clis/lobsters/tag.yaml +34 -0
- package/src/clis/medium/feed.ts +16 -0
- package/src/clis/medium/search.ts +16 -0
- package/src/clis/medium/shared.ts +83 -0
- package/src/clis/medium/user.ts +16 -0
- package/src/clis/reddit/comment.ts +1 -1
- package/src/clis/reddit/read.ts +1 -1
- package/src/clis/reddit/save.ts +1 -1
- package/src/clis/reddit/subreddit.yaml +1 -0
- package/src/clis/reddit/subscribe.ts +1 -1
- package/src/clis/reddit/upvote.ts +1 -1
- package/src/clis/sinablog/article.ts +15 -0
- package/src/clis/sinablog/hot.ts +15 -0
- package/src/clis/sinablog/search.ts +56 -0
- package/src/clis/sinablog/shared.ts +198 -0
- package/src/clis/sinablog/user.ts +16 -0
- package/src/clis/substack/feed.ts +16 -0
- package/src/clis/substack/publication.ts +16 -0
- package/src/clis/substack/search.ts +91 -0
- package/src/clis/substack/shared.ts +132 -0
- package/src/clis/tiktok/comment.yaml +66 -0
- package/src/clis/tiktok/explore.yaml +39 -0
- package/src/clis/tiktok/follow.yaml +39 -0
- package/src/clis/tiktok/following.yaml +46 -0
- package/src/clis/tiktok/friends.yaml +47 -0
- package/src/clis/tiktok/like.yaml +38 -0
- package/src/clis/tiktok/live.yaml +51 -0
- package/src/clis/tiktok/notifications.yaml +52 -0
- package/src/clis/tiktok/profile.yaml +45 -0
- package/src/clis/tiktok/save.yaml +34 -0
- package/src/clis/tiktok/search.yaml +46 -0
- package/src/clis/tiktok/unfollow.yaml +44 -0
- package/src/clis/tiktok/unlike.yaml +38 -0
- package/src/clis/tiktok/unsave.yaml +36 -0
- package/src/clis/tiktok/user.yaml +44 -0
- package/src/clis/twitter/download.ts +3 -3
- package/src/clis/twitter/followers.ts +1 -1
- package/src/clis/twitter/following.ts +1 -1
- package/src/clis/twitter/thread.ts +1 -1
- package/src/clis/twitter/timeline.test.ts +109 -0
- package/src/clis/twitter/timeline.ts +59 -19
- package/src/clis/wikipedia/random.ts +19 -0
- package/src/clis/wikipedia/search.ts +10 -4
- package/src/clis/wikipedia/summary.ts +4 -9
- package/src/clis/wikipedia/trending.ts +41 -0
- package/src/clis/wikipedia/utils.ts +31 -0
- package/src/clis/xiaohongshu/creator-note-detail.test.ts +2 -0
- package/src/clis/xiaohongshu/creator-note-detail.ts +1 -1
- package/src/clis/xiaohongshu/creator-notes.test.ts +2 -0
- package/src/clis/xiaohongshu/download.ts +1 -1
- package/src/clis/xueqiu/earnings-date.yaml +69 -0
- package/src/clis/xueqiu/search.yaml +2 -1
- package/src/clis/xueqiu/stock.yaml +2 -0
- package/src/clis/yahoo-finance/quote.ts +1 -1
- package/src/commanderAdapter.ts +17 -10
- package/src/discovery.ts +134 -24
- package/src/doctor.test.ts +59 -2
- package/src/doctor.ts +4 -2
- package/src/engine.test.ts +79 -6
- package/src/execution.ts +42 -16
- package/src/explore.ts +77 -9
- package/src/generate.ts +58 -9
- package/src/main.ts +2 -1
- package/src/pipeline/executor.test.ts +35 -6
- package/src/pipeline/executor.ts +11 -7
- package/src/pipeline/registry.ts +3 -3
- package/src/pipeline/steps/browser.ts +24 -15
- package/src/pipeline/steps/fetch.ts +18 -13
- package/src/pipeline/steps/transform.ts +40 -15
- package/src/pipeline/template.test.ts +18 -0
- package/src/pipeline/template.ts +86 -13
- package/src/pipeline/transform.test.ts +15 -2
- package/src/plugin.test.ts +86 -0
- package/src/plugin.ts +254 -0
- package/src/registry-api.ts +12 -0
- package/src/registry.ts +19 -1
- package/src/synthesize.ts +102 -21
- package/src/types.ts +44 -12
- package/src/validate.ts +19 -4
- package/tests/e2e/browser-public.test.ts +11 -0
- package/tests/e2e/public-commands.test.ts +64 -0
- package/dist/clis/feishu/new.d.ts +0 -1
- package/dist/clis/feishu/new.js +0 -27
- package/dist/clis/feishu/read.d.ts +0 -1
- package/dist/clis/feishu/read.js +0 -40
- package/dist/clis/feishu/search.d.ts +0 -1
- package/dist/clis/feishu/search.js +0 -30
- package/dist/clis/feishu/send.d.ts +0 -1
- package/dist/clis/feishu/send.js +0 -39
- package/dist/clis/feishu/status.d.ts +0 -1
- package/dist/clis/feishu/status.js +0 -28
- package/dist/clis/neteasemusic/like.d.ts +0 -1
- package/dist/clis/neteasemusic/like.js +0 -25
- package/dist/clis/neteasemusic/lyrics.d.ts +0 -1
- package/dist/clis/neteasemusic/lyrics.js +0 -47
- package/dist/clis/neteasemusic/next.d.ts +0 -1
- package/dist/clis/neteasemusic/next.js +0 -26
- package/dist/clis/neteasemusic/play.d.ts +0 -1
- package/dist/clis/neteasemusic/play.js +0 -26
- package/dist/clis/neteasemusic/playing.d.ts +0 -1
- package/dist/clis/neteasemusic/playing.js +0 -59
- package/dist/clis/neteasemusic/playlist.d.ts +0 -1
- package/dist/clis/neteasemusic/playlist.js +0 -46
- package/dist/clis/neteasemusic/prev.d.ts +0 -1
- package/dist/clis/neteasemusic/prev.js +0 -25
- package/dist/clis/neteasemusic/search.d.ts +0 -1
- package/dist/clis/neteasemusic/search.js +0 -52
- package/dist/clis/neteasemusic/status.d.ts +0 -1
- package/dist/clis/neteasemusic/status.js +0 -16
- package/dist/clis/neteasemusic/volume.d.ts +0 -1
- package/dist/clis/neteasemusic/volume.js +0 -54
- package/dist/clis/wechat/chats.d.ts +0 -1
- package/dist/clis/wechat/chats.js +0 -28
- package/dist/clis/wechat/contacts.d.ts +0 -1
- package/dist/clis/wechat/contacts.js +0 -28
- package/dist/clis/wechat/read.d.ts +0 -1
- package/dist/clis/wechat/read.js +0 -58
- package/dist/clis/wechat/search.d.ts +0 -1
- package/dist/clis/wechat/search.js +0 -31
- package/dist/clis/wechat/send.d.ts +0 -1
- package/dist/clis/wechat/send.js +0 -42
- package/dist/clis/wechat/status.d.ts +0 -1
- package/dist/clis/wechat/status.js +0 -29
- package/dist/pipeline.d.ts +0 -7
- package/dist/pipeline.js +0 -7
- package/docs/adapters/browser/github.md +0 -26
- package/docs/adapters/desktop/feishu.md +0 -20
- package/docs/adapters/desktop/neteasemusic.md +0 -31
- package/docs/adapters/desktop/wechat.md +0 -28
- package/src/clis/antigravity/README.md +0 -5
- package/src/clis/antigravity/README.zh-CN.md +0 -51
- package/src/clis/chaoxing/README.md +0 -14
- package/src/clis/chaoxing/README.zh-CN.md +0 -35
- package/src/clis/chatgpt/README.md +0 -5
- package/src/clis/chatgpt/README.zh-CN.md +0 -44
- package/src/clis/chatwise/README.md +0 -5
- package/src/clis/chatwise/README.zh-CN.md +0 -38
- package/src/clis/codex/README.md +0 -5
- package/src/clis/codex/README.zh-CN.md +0 -33
- package/src/clis/cursor/README.md +0 -5
- package/src/clis/cursor/README.zh-CN.md +0 -33
- package/src/clis/discord-app/README.md +0 -5
- package/src/clis/discord-app/README.zh-CN.md +0 -28
- package/src/clis/feishu/README.md +0 -5
- package/src/clis/feishu/README.zh-CN.md +0 -20
- package/src/clis/feishu/new.ts +0 -32
- package/src/clis/feishu/read.ts +0 -48
- package/src/clis/feishu/search.ts +0 -35
- package/src/clis/feishu/send.ts +0 -46
- package/src/clis/feishu/status.ts +0 -34
- package/src/clis/neteasemusic/README.md +0 -5
- package/src/clis/neteasemusic/README.zh-CN.md +0 -31
- package/src/clis/neteasemusic/like.ts +0 -28
- package/src/clis/neteasemusic/lyrics.ts +0 -53
- package/src/clis/neteasemusic/next.ts +0 -30
- package/src/clis/neteasemusic/play.ts +0 -30
- package/src/clis/neteasemusic/playing.ts +0 -62
- package/src/clis/neteasemusic/playlist.ts +0 -51
- package/src/clis/neteasemusic/prev.ts +0 -29
- package/src/clis/neteasemusic/search.ts +0 -58
- package/src/clis/neteasemusic/status.ts +0 -18
- package/src/clis/neteasemusic/volume.ts +0 -61
- package/src/clis/notion/README.md +0 -5
- package/src/clis/notion/README.zh-CN.md +0 -29
- package/src/clis/wechat/README.md +0 -5
- package/src/clis/wechat/README.zh-CN.md +0 -28
- package/src/clis/wechat/chats.ts +0 -33
- package/src/clis/wechat/contacts.ts +0 -33
- package/src/clis/wechat/read.ts +0 -72
- package/src/clis/wechat/search.ts +0 -36
- package/src/clis/wechat/send.ts +0 -49
- package/src/clis/wechat/status.ts +0 -35
- package/src/pipeline.ts +0 -8
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for dom-snapshot.ts: DOM snapshot engine.
|
|
3
|
+
*
|
|
4
|
+
* Since the engine generates JavaScript strings for in-page evaluation,
|
|
5
|
+
* these tests validate:
|
|
6
|
+
* 1. The generated code is syntactically valid JS
|
|
7
|
+
* 2. Options are correctly embedded
|
|
8
|
+
* 3. The output structure matches expected format
|
|
9
|
+
* 4. All features are present (Shadow DOM, iframe, table, diff, etc.)
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for dom-snapshot.ts: DOM snapshot engine.
|
|
3
|
+
*
|
|
4
|
+
* Since the engine generates JavaScript strings for in-page evaluation,
|
|
5
|
+
* these tests validate:
|
|
6
|
+
* 1. The generated code is syntactically valid JS
|
|
7
|
+
* 2. Options are correctly embedded
|
|
8
|
+
* 3. The output structure matches expected format
|
|
9
|
+
* 4. All features are present (Shadow DOM, iframe, table, diff, etc.)
|
|
10
|
+
*/
|
|
11
|
+
import { describe, it, expect } from 'vitest';
|
|
12
|
+
import { generateSnapshotJs, scrollToRefJs, getFormStateJs } from './dom-snapshot.js';
|
|
13
|
+
describe('generateSnapshotJs', () => {
|
|
14
|
+
it('returns a non-empty string', () => {
|
|
15
|
+
const js = generateSnapshotJs();
|
|
16
|
+
expect(typeof js).toBe('string');
|
|
17
|
+
expect(js.length).toBeGreaterThan(100);
|
|
18
|
+
});
|
|
19
|
+
it('generates syntactically valid JS (can be parsed)', () => {
|
|
20
|
+
const js = generateSnapshotJs();
|
|
21
|
+
expect(() => new Function(js)).not.toThrow();
|
|
22
|
+
});
|
|
23
|
+
it('embeds default options correctly', () => {
|
|
24
|
+
const js = generateSnapshotJs();
|
|
25
|
+
expect(js).toContain('VIEWPORT_EXPAND = 800');
|
|
26
|
+
expect(js).toContain('MAX_DEPTH = 50');
|
|
27
|
+
expect(js).toContain('INTERACTIVE_ONLY = false');
|
|
28
|
+
expect(js).toContain('MAX_TEXT_LEN = 120');
|
|
29
|
+
expect(js).toContain('INCLUDE_SCROLL_INFO = true');
|
|
30
|
+
expect(js).toContain('BBOX_DEDUP = true');
|
|
31
|
+
expect(js).toContain('INCLUDE_SHADOW_DOM = true');
|
|
32
|
+
expect(js).toContain('INCLUDE_IFRAMES = true');
|
|
33
|
+
expect(js).toContain('PAINT_ORDER_CHECK = true');
|
|
34
|
+
expect(js).toContain('ANNOTATE_REFS = true');
|
|
35
|
+
expect(js).toContain('REPORT_HIDDEN = true');
|
|
36
|
+
expect(js).toContain('FILTER_ADS = true');
|
|
37
|
+
expect(js).toContain('MARKDOWN_TABLES = true');
|
|
38
|
+
expect(js).toContain('PREV_HASHES = null');
|
|
39
|
+
});
|
|
40
|
+
it('embeds custom options correctly', () => {
|
|
41
|
+
const js = generateSnapshotJs({
|
|
42
|
+
viewportExpand: 2000,
|
|
43
|
+
maxDepth: 30,
|
|
44
|
+
interactiveOnly: true,
|
|
45
|
+
maxTextLength: 200,
|
|
46
|
+
includeScrollInfo: false,
|
|
47
|
+
bboxDedup: false,
|
|
48
|
+
includeShadowDom: false,
|
|
49
|
+
includeIframes: false,
|
|
50
|
+
maxIframes: 3,
|
|
51
|
+
paintOrderCheck: false,
|
|
52
|
+
annotateRefs: false,
|
|
53
|
+
reportHidden: false,
|
|
54
|
+
filterAds: false,
|
|
55
|
+
markdownTables: false,
|
|
56
|
+
});
|
|
57
|
+
expect(js).toContain('VIEWPORT_EXPAND = 2000');
|
|
58
|
+
expect(js).toContain('MAX_DEPTH = 30');
|
|
59
|
+
expect(js).toContain('INTERACTIVE_ONLY = true');
|
|
60
|
+
expect(js).toContain('MAX_TEXT_LEN = 200');
|
|
61
|
+
expect(js).toContain('INCLUDE_SCROLL_INFO = false');
|
|
62
|
+
expect(js).toContain('BBOX_DEDUP = false');
|
|
63
|
+
expect(js).toContain('INCLUDE_SHADOW_DOM = false');
|
|
64
|
+
expect(js).toContain('INCLUDE_IFRAMES = false');
|
|
65
|
+
expect(js).toContain('MAX_IFRAMES = 3');
|
|
66
|
+
expect(js).toContain('PAINT_ORDER_CHECK = false');
|
|
67
|
+
expect(js).toContain('ANNOTATE_REFS = false');
|
|
68
|
+
expect(js).toContain('REPORT_HIDDEN = false');
|
|
69
|
+
expect(js).toContain('FILTER_ADS = false');
|
|
70
|
+
expect(js).toContain('MARKDOWN_TABLES = false');
|
|
71
|
+
});
|
|
72
|
+
it('clamps maxDepth between 1 and 200', () => {
|
|
73
|
+
expect(generateSnapshotJs({ maxDepth: -5 })).toContain('MAX_DEPTH = 1');
|
|
74
|
+
expect(generateSnapshotJs({ maxDepth: 999 })).toContain('MAX_DEPTH = 200');
|
|
75
|
+
expect(generateSnapshotJs({ maxDepth: 75 })).toContain('MAX_DEPTH = 75');
|
|
76
|
+
});
|
|
77
|
+
it('wraps output as an IIFE', () => {
|
|
78
|
+
const js = generateSnapshotJs();
|
|
79
|
+
expect(js.startsWith('(() =>')).toBe(true);
|
|
80
|
+
expect(js.trimEnd().endsWith(')()')).toBe(true);
|
|
81
|
+
});
|
|
82
|
+
it('embeds previousHashes for incremental diff', () => {
|
|
83
|
+
const hashes = JSON.stringify(['12345', '67890']);
|
|
84
|
+
const js = generateSnapshotJs({ previousHashes: hashes });
|
|
85
|
+
expect(js).toContain('new Set(["12345","67890"])');
|
|
86
|
+
});
|
|
87
|
+
it('includes all core features in generated code', () => {
|
|
88
|
+
const js = generateSnapshotJs();
|
|
89
|
+
// Tag filtering
|
|
90
|
+
expect(js).toContain('SKIP_TAGS');
|
|
91
|
+
expect(js).toContain("'script'");
|
|
92
|
+
expect(js).toContain("'style'");
|
|
93
|
+
// SVG collapsing
|
|
94
|
+
expect(js).toContain('SVG_CHILDREN');
|
|
95
|
+
// Interactive detection
|
|
96
|
+
expect(js).toContain('INTERACTIVE_TAGS');
|
|
97
|
+
expect(js).toContain('INTERACTIVE_ROLES');
|
|
98
|
+
expect(js).toContain('isInteractive');
|
|
99
|
+
// Visibility
|
|
100
|
+
expect(js).toContain('isVisibleByCSS');
|
|
101
|
+
expect(js).toContain('isInExpandedViewport');
|
|
102
|
+
// BBox dedup
|
|
103
|
+
expect(js).toContain('isContainedBy');
|
|
104
|
+
expect(js).toContain('PROPAGATING_TAGS');
|
|
105
|
+
// Shadow DOM
|
|
106
|
+
expect(js).toContain('shadowRoot');
|
|
107
|
+
expect(js).toContain('|shadow|');
|
|
108
|
+
// iframe
|
|
109
|
+
expect(js).toContain('walkIframe');
|
|
110
|
+
expect(js).toContain('|iframe|');
|
|
111
|
+
// Paint order
|
|
112
|
+
expect(js).toContain('isOccludedByOverlay');
|
|
113
|
+
expect(js).toContain('elementFromPoint');
|
|
114
|
+
// Ad filtering
|
|
115
|
+
expect(js).toContain('isAdElement');
|
|
116
|
+
expect(js).toContain('AD_PATTERNS');
|
|
117
|
+
// data-ref annotation
|
|
118
|
+
expect(js).toContain('data-opencli-ref');
|
|
119
|
+
// Hidden elements report
|
|
120
|
+
expect(js).toContain('hiddenInteractives');
|
|
121
|
+
expect(js).toContain('hidden_interactive');
|
|
122
|
+
// Incremental diff
|
|
123
|
+
expect(js).toContain('hashElement');
|
|
124
|
+
expect(js).toContain('currentHashes');
|
|
125
|
+
expect(js).toContain('__opencli_prev_hashes');
|
|
126
|
+
// Table serialization
|
|
127
|
+
expect(js).toContain('serializeTable');
|
|
128
|
+
expect(js).toContain('|table|');
|
|
129
|
+
// Synthetic attributes
|
|
130
|
+
expect(js).toContain("'YYYY-MM-DD'");
|
|
131
|
+
expect(js).toContain('value=••••');
|
|
132
|
+
// Page metadata
|
|
133
|
+
expect(js).toContain('location.href');
|
|
134
|
+
expect(js).toContain('document.title');
|
|
135
|
+
});
|
|
136
|
+
it('contains proper attribute whitelist', () => {
|
|
137
|
+
const js = generateSnapshotJs();
|
|
138
|
+
const expectedAttrs = [
|
|
139
|
+
'aria-label', 'aria-expanded', 'aria-checked', 'aria-selected',
|
|
140
|
+
'placeholder', 'href', 'role', 'data-testid', 'autocomplete',
|
|
141
|
+
];
|
|
142
|
+
for (const attr of expectedAttrs) {
|
|
143
|
+
expect(js).toContain(`'${attr}'`);
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
it('includes scroll info formatting', () => {
|
|
147
|
+
const js = generateSnapshotJs();
|
|
148
|
+
expect(js).toContain('scrollHeight');
|
|
149
|
+
expect(js).toContain('scrollTop');
|
|
150
|
+
expect(js).toContain('|scroll|');
|
|
151
|
+
expect(js).toContain('page_scroll');
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
describe('scrollToRefJs', () => {
|
|
155
|
+
it('generates valid JS', () => {
|
|
156
|
+
const js = scrollToRefJs('42');
|
|
157
|
+
expect(() => new Function(js)).not.toThrow();
|
|
158
|
+
});
|
|
159
|
+
it('targets data-opencli-ref', () => {
|
|
160
|
+
const js = scrollToRefJs('7');
|
|
161
|
+
expect(js).toContain('data-opencli-ref');
|
|
162
|
+
expect(js).toContain('scrollIntoView');
|
|
163
|
+
expect(js).toContain('"7"');
|
|
164
|
+
});
|
|
165
|
+
it('falls back to data-ref', () => {
|
|
166
|
+
const js = scrollToRefJs('3');
|
|
167
|
+
expect(js).toContain('data-ref');
|
|
168
|
+
});
|
|
169
|
+
it('returns scrolled info', () => {
|
|
170
|
+
const js = scrollToRefJs('1');
|
|
171
|
+
expect(js).toContain('scrolled: true');
|
|
172
|
+
expect(js).toContain('tag:');
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
describe('getFormStateJs', () => {
|
|
176
|
+
it('generates valid JS', () => {
|
|
177
|
+
const js = getFormStateJs();
|
|
178
|
+
expect(() => new Function(js)).not.toThrow();
|
|
179
|
+
});
|
|
180
|
+
it('collects form elements', () => {
|
|
181
|
+
const js = getFormStateJs();
|
|
182
|
+
expect(js).toContain('document.forms');
|
|
183
|
+
expect(js).toContain('form.elements');
|
|
184
|
+
});
|
|
185
|
+
it('collects orphan fields', () => {
|
|
186
|
+
const js = getFormStateJs();
|
|
187
|
+
expect(js).toContain('orphanFields');
|
|
188
|
+
expect(js).toContain('el.form');
|
|
189
|
+
});
|
|
190
|
+
it('handles different input types', () => {
|
|
191
|
+
const js = getFormStateJs();
|
|
192
|
+
expect(js).toContain('checkbox');
|
|
193
|
+
expect(js).toContain('radio');
|
|
194
|
+
expect(js).toContain('password');
|
|
195
|
+
expect(js).toContain('contenteditable');
|
|
196
|
+
});
|
|
197
|
+
it('extracts labels', () => {
|
|
198
|
+
const js = getFormStateJs();
|
|
199
|
+
expect(js).toContain('aria-label');
|
|
200
|
+
expect(js).toContain('label[for=');
|
|
201
|
+
expect(js).toContain('closest');
|
|
202
|
+
expect(js).toContain('placeholder');
|
|
203
|
+
});
|
|
204
|
+
it('masks passwords', () => {
|
|
205
|
+
const js = getFormStateJs();
|
|
206
|
+
expect(js).toContain('••••');
|
|
207
|
+
});
|
|
208
|
+
it('includes data-opencli-ref in output', () => {
|
|
209
|
+
const js = getFormStateJs();
|
|
210
|
+
expect(js).toContain('data-opencli-ref');
|
|
211
|
+
});
|
|
212
|
+
});
|
package/dist/browser/index.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ export { Page } from './page.js';
|
|
|
8
8
|
export { BrowserBridge, BrowserBridge as PlaywrightMCP } from './mcp.js';
|
|
9
9
|
export { CDPBridge } from './cdp.js';
|
|
10
10
|
export { isDaemonRunning } from './daemon-client.js';
|
|
11
|
+
export { generateSnapshotJs, scrollToRefJs, getFormStateJs } from './dom-snapshot.js';
|
|
12
|
+
export type { SnapshotOptions } from './dom-snapshot.js';
|
|
11
13
|
import { extractTabEntries, diffTabIndexes, appendLimited } from './tabs.js';
|
|
12
14
|
import { withTimeoutMs } from '../runtime.js';
|
|
13
15
|
export declare const __test__: {
|
package/dist/browser/index.js
CHANGED
|
@@ -8,6 +8,7 @@ export { Page } from './page.js';
|
|
|
8
8
|
export { BrowserBridge, BrowserBridge as PlaywrightMCP } from './mcp.js';
|
|
9
9
|
export { CDPBridge } from './cdp.js';
|
|
10
10
|
export { isDaemonRunning } from './daemon-client.js';
|
|
11
|
+
export { generateSnapshotJs, scrollToRefJs, getFormStateJs } from './dom-snapshot.js';
|
|
11
12
|
import { extractTabEntries, diffTabIndexes, appendLimited } from './tabs.js';
|
|
12
13
|
import { __test__ as cdpTest } from './cdp.js';
|
|
13
14
|
import { withTimeoutMs } from '../runtime.js';
|
package/dist/browser/page.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* where resolveTabId() in the extension picks a chrome:// or
|
|
10
10
|
* chrome-extension:// tab that can't be debugged.
|
|
11
11
|
*/
|
|
12
|
-
import type { IPage } from '../types.js';
|
|
12
|
+
import type { BrowserCookie, IPage, ScreenshotOptions, SnapshotOptions, WaitOptions } from '../types.js';
|
|
13
13
|
/**
|
|
14
14
|
* Page — implements IPage by talking to the daemon via HTTP.
|
|
15
15
|
*/
|
|
@@ -27,36 +27,31 @@ export declare class Page implements IPage {
|
|
|
27
27
|
}): Promise<void>;
|
|
28
28
|
/** Close the automation window in the extension */
|
|
29
29
|
closeWindow(): Promise<void>;
|
|
30
|
-
evaluate(js: string): Promise<
|
|
30
|
+
evaluate(js: string): Promise<unknown>;
|
|
31
31
|
getCookies(opts?: {
|
|
32
32
|
domain?: string;
|
|
33
33
|
url?: string;
|
|
34
|
-
}): Promise<
|
|
35
|
-
snapshot(opts?:
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
maxDepth?: number;
|
|
39
|
-
raw?: boolean;
|
|
40
|
-
}): Promise<any>;
|
|
34
|
+
}): Promise<BrowserCookie[]>;
|
|
35
|
+
snapshot(opts?: SnapshotOptions): Promise<unknown>;
|
|
36
|
+
/** Fallback basic snapshot — original buildTree approach */
|
|
37
|
+
private _basicSnapshot;
|
|
41
38
|
click(ref: string): Promise<void>;
|
|
42
39
|
typeText(ref: string, text: string): Promise<void>;
|
|
43
40
|
pressKey(key: string): Promise<void>;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}): Promise<void>;
|
|
49
|
-
tabs(): Promise<any>;
|
|
41
|
+
scrollTo(ref: string): Promise<unknown>;
|
|
42
|
+
getFormState(): Promise<Record<string, unknown>>;
|
|
43
|
+
wait(options: number | WaitOptions): Promise<void>;
|
|
44
|
+
tabs(): Promise<unknown[]>;
|
|
50
45
|
closeTab(index?: number): Promise<void>;
|
|
51
46
|
newTab(): Promise<void>;
|
|
52
47
|
selectTab(index: number): Promise<void>;
|
|
53
|
-
networkRequests(includeStatic?: boolean): Promise<
|
|
48
|
+
networkRequests(includeStatic?: boolean): Promise<unknown[]>;
|
|
54
49
|
/**
|
|
55
50
|
* Console messages are not available in lightweight daemon mode.
|
|
56
51
|
* Would require CDP Runtime.consoleAPICalled event listener.
|
|
57
52
|
* @returns Always returns empty array.
|
|
58
53
|
*/
|
|
59
|
-
consoleMessages(_level?: string): Promise<
|
|
54
|
+
consoleMessages(_level?: string): Promise<unknown[]>;
|
|
60
55
|
/**
|
|
61
56
|
* Capture a screenshot via CDP Page.captureScreenshot.
|
|
62
57
|
* @param options.format - 'png' (default) or 'jpeg'
|
|
@@ -64,17 +59,12 @@ export declare class Page implements IPage {
|
|
|
64
59
|
* @param options.fullPage - capture full scrollable page
|
|
65
60
|
* @param options.path - save to file path (returns base64 if omitted)
|
|
66
61
|
*/
|
|
67
|
-
screenshot(options?:
|
|
68
|
-
format?: 'png' | 'jpeg';
|
|
69
|
-
quality?: number;
|
|
70
|
-
fullPage?: boolean;
|
|
71
|
-
path?: string;
|
|
72
|
-
}): Promise<string>;
|
|
62
|
+
screenshot(options?: ScreenshotOptions): Promise<string>;
|
|
73
63
|
scroll(direction?: string, amount?: number): Promise<void>;
|
|
74
64
|
autoScroll(options?: {
|
|
75
65
|
times?: number;
|
|
76
66
|
delayMs?: number;
|
|
77
67
|
}): Promise<void>;
|
|
78
68
|
installInterceptor(pattern: string): Promise<void>;
|
|
79
|
-
getInterceptedRequests(): Promise<
|
|
69
|
+
getInterceptedRequests(): Promise<unknown[]>;
|
|
80
70
|
}
|
package/dist/browser/page.js
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
import { formatSnapshot } from '../snapshotFormatter.js';
|
|
13
13
|
import { sendCommand } from './daemon-client.js';
|
|
14
14
|
import { wrapForEval } from './utils.js';
|
|
15
|
+
import { generateSnapshotJs, scrollToRefJs, getFormStateJs } from './dom-snapshot.js';
|
|
15
16
|
import { clickJs, typeTextJs, pressKeyJs, waitForTextJs, scrollJs, autoScrollJs, networkRequestsJs, } from './dom-helpers.js';
|
|
16
17
|
/**
|
|
17
18
|
* Page — implements IPage by talking to the daemon via HTTP.
|
|
@@ -65,6 +66,28 @@ export class Page {
|
|
|
65
66
|
return Array.isArray(result) ? result : [];
|
|
66
67
|
}
|
|
67
68
|
async snapshot(opts = {}) {
|
|
69
|
+
// Primary: use the advanced DOM snapshot engine with multi-layer pruning
|
|
70
|
+
const snapshotJs = generateSnapshotJs({
|
|
71
|
+
viewportExpand: opts.viewportExpand ?? 800,
|
|
72
|
+
maxDepth: Math.max(1, Math.min(Number(opts.maxDepth) || 50, 200)),
|
|
73
|
+
interactiveOnly: opts.interactive ?? false,
|
|
74
|
+
maxTextLength: opts.maxTextLength ?? 120,
|
|
75
|
+
includeScrollInfo: true,
|
|
76
|
+
bboxDedup: true,
|
|
77
|
+
});
|
|
78
|
+
try {
|
|
79
|
+
const result = await sendCommand('exec', { code: snapshotJs, ...this._workspaceOpt(), ...this._tabOpt() });
|
|
80
|
+
// The advanced engine already produces a clean, pruned, LLM-friendly output.
|
|
81
|
+
// Do NOT pass through formatSnapshot — its format is incompatible.
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// Fallback: basic DOM snapshot (original implementation)
|
|
86
|
+
return this._basicSnapshot(opts);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/** Fallback basic snapshot — original buildTree approach */
|
|
90
|
+
async _basicSnapshot(opts = {}) {
|
|
68
91
|
const maxDepth = Math.max(1, Math.min(Number(opts.maxDepth) || 50, 200));
|
|
69
92
|
const code = `
|
|
70
93
|
(async () => {
|
|
@@ -78,7 +101,7 @@ export class Page {
|
|
|
78
101
|
|
|
79
102
|
let indent = ' '.repeat(depth);
|
|
80
103
|
let line = indent + role;
|
|
81
|
-
if (name) line += ' "' + name.replace(/"/g, '
|
|
104
|
+
if (name) line += ' "' + name.replace(/"/g, '\\\\\\"') + '"';
|
|
82
105
|
if (node.tagName?.toLowerCase() === 'a' && node.href) line += ' [' + node.href + ']';
|
|
83
106
|
if (node.tagName?.toLowerCase() === 'input') line += ' [' + (node.type || 'text') + ']';
|
|
84
107
|
|
|
@@ -112,6 +135,14 @@ export class Page {
|
|
|
112
135
|
const code = pressKeyJs(key);
|
|
113
136
|
await sendCommand('exec', { code, ...this._workspaceOpt(), ...this._tabOpt() });
|
|
114
137
|
}
|
|
138
|
+
async scrollTo(ref) {
|
|
139
|
+
const code = scrollToRefJs(ref);
|
|
140
|
+
return sendCommand('exec', { code, ...this._workspaceOpt(), ...this._tabOpt() });
|
|
141
|
+
}
|
|
142
|
+
async getFormState() {
|
|
143
|
+
const code = getFormStateJs();
|
|
144
|
+
return (await sendCommand('exec', { code, ...this._workspaceOpt(), ...this._tabOpt() }));
|
|
145
|
+
}
|
|
115
146
|
async wait(options) {
|
|
116
147
|
if (typeof options === 'number') {
|
|
117
148
|
await new Promise(resolve => setTimeout(resolve, options * 1000));
|
|
@@ -128,7 +159,8 @@ export class Page {
|
|
|
128
159
|
}
|
|
129
160
|
}
|
|
130
161
|
async tabs() {
|
|
131
|
-
|
|
162
|
+
const result = await sendCommand('tabs', { op: 'list', ...this._workspaceOpt() });
|
|
163
|
+
return Array.isArray(result) ? result : [];
|
|
132
164
|
}
|
|
133
165
|
async closeTab(index) {
|
|
134
166
|
await sendCommand('tabs', { op: 'close', ...this._workspaceOpt(), ...(index !== undefined ? { index } : {}) });
|
|
@@ -141,7 +173,8 @@ export class Page {
|
|
|
141
173
|
}
|
|
142
174
|
async networkRequests(includeStatic = false) {
|
|
143
175
|
const code = networkRequestsJs(includeStatic);
|
|
144
|
-
|
|
176
|
+
const result = await sendCommand('exec', { code, ...this._workspaceOpt(), ...this._tabOpt() });
|
|
177
|
+
return Array.isArray(result) ? result : [];
|
|
145
178
|
}
|
|
146
179
|
/**
|
|
147
180
|
* Console messages are not available in lightweight daemon mode.
|
|
@@ -198,7 +231,7 @@ export class Page {
|
|
|
198
231
|
const { generateReadInterceptedJs } = await import('../interceptor.js');
|
|
199
232
|
// Same as installInterceptor: must go through evaluate() for IIFE wrapping
|
|
200
233
|
const result = await this.evaluate(generateReadInterceptedJs('__opencli_xhr'));
|
|
201
|
-
return result
|
|
234
|
+
return Array.isArray(result) ? result : [];
|
|
202
235
|
}
|
|
203
236
|
}
|
|
204
237
|
// (End of file)
|
package/dist/build-manifest.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* Usage: npx tsx src/build-manifest.ts
|
|
9
9
|
* Output: dist/cli-manifest.json
|
|
10
10
|
*/
|
|
11
|
-
interface ManifestEntry {
|
|
11
|
+
export interface ManifestEntry {
|
|
12
12
|
site: string;
|
|
13
13
|
name: string;
|
|
14
14
|
description: string;
|
|
@@ -18,20 +18,27 @@ interface ManifestEntry {
|
|
|
18
18
|
args: Array<{
|
|
19
19
|
name: string;
|
|
20
20
|
type?: string;
|
|
21
|
-
default?:
|
|
21
|
+
default?: unknown;
|
|
22
22
|
required?: boolean;
|
|
23
23
|
positional?: boolean;
|
|
24
24
|
help?: string;
|
|
25
25
|
choices?: string[];
|
|
26
26
|
}>;
|
|
27
27
|
columns?: string[];
|
|
28
|
-
pipeline?:
|
|
28
|
+
pipeline?: Record<string, unknown>[];
|
|
29
29
|
timeout?: number;
|
|
30
30
|
/** 'yaml' or 'ts' — determines how executeCommand loads the handler */
|
|
31
31
|
type: 'yaml' | 'ts';
|
|
32
32
|
/** Relative path from clis/ dir, e.g. 'bilibili/hot.yaml' or 'bilibili/search.js' */
|
|
33
33
|
modulePath?: string;
|
|
34
|
+
/** Pre-navigation control — see CliCommand.navigateBefore */
|
|
35
|
+
navigateBefore?: boolean | string;
|
|
34
36
|
}
|
|
35
37
|
export declare function parseTsArgsBlock(argsBlock: string): ManifestEntry['args'];
|
|
38
|
+
export declare function scanTs(filePath: string, site: string): ManifestEntry | null;
|
|
39
|
+
/**
|
|
40
|
+
* When both YAML and TS adapters exist for the same site/name,
|
|
41
|
+
* prefer the TS version (it self-registers and typically has richer logic).
|
|
42
|
+
*/
|
|
43
|
+
export declare function shouldReplaceManifestEntry(current: ManifestEntry, next: ManifestEntry): boolean;
|
|
36
44
|
export declare function buildManifest(): ManifestEntry[];
|
|
37
|
-
export {};
|
package/dist/build-manifest.js
CHANGED
|
@@ -15,6 +15,12 @@ import yaml from 'js-yaml';
|
|
|
15
15
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
16
16
|
const CLIS_DIR = path.resolve(__dirname, 'clis');
|
|
17
17
|
const OUTPUT = path.resolve(__dirname, '..', 'dist', 'cli-manifest.json');
|
|
18
|
+
function isRecord(value) {
|
|
19
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
20
|
+
}
|
|
21
|
+
function getErrorMessage(error) {
|
|
22
|
+
return error instanceof Error ? error.message : String(error);
|
|
23
|
+
}
|
|
18
24
|
function extractBalancedBlock(source, startIndex, openChar, closeChar) {
|
|
19
25
|
let depth = 0;
|
|
20
26
|
let quote = null;
|
|
@@ -116,44 +122,47 @@ function scanYaml(filePath, site) {
|
|
|
116
122
|
try {
|
|
117
123
|
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
118
124
|
const def = yaml.load(raw);
|
|
119
|
-
if (!def
|
|
125
|
+
if (!isRecord(def))
|
|
120
126
|
return null;
|
|
121
|
-
const
|
|
127
|
+
const cliDef = def;
|
|
128
|
+
const strategyStr = cliDef.strategy ?? (cliDef.browser === false ? 'public' : 'cookie');
|
|
122
129
|
const strategy = strategyStr.toUpperCase();
|
|
123
|
-
const browser =
|
|
130
|
+
const browser = cliDef.browser ?? (strategy !== 'PUBLIC');
|
|
124
131
|
const args = [];
|
|
125
|
-
if (
|
|
126
|
-
for (const [argName, argDef] of Object.entries(
|
|
132
|
+
if (cliDef.args && typeof cliDef.args === 'object') {
|
|
133
|
+
for (const [argName, argDef] of Object.entries(cliDef.args)) {
|
|
127
134
|
args.push({
|
|
128
135
|
name: argName,
|
|
129
136
|
type: argDef?.type ?? 'str',
|
|
130
137
|
default: argDef?.default,
|
|
131
138
|
required: argDef?.required ?? false,
|
|
139
|
+
positional: argDef?.positional === true || undefined,
|
|
132
140
|
help: argDef?.description ?? argDef?.help ?? '',
|
|
133
141
|
choices: argDef?.choices,
|
|
134
142
|
});
|
|
135
143
|
}
|
|
136
144
|
}
|
|
137
145
|
return {
|
|
138
|
-
site:
|
|
139
|
-
name:
|
|
140
|
-
description:
|
|
141
|
-
domain:
|
|
146
|
+
site: cliDef.site ?? site,
|
|
147
|
+
name: cliDef.name ?? path.basename(filePath, path.extname(filePath)),
|
|
148
|
+
description: cliDef.description ?? '',
|
|
149
|
+
domain: cliDef.domain,
|
|
142
150
|
strategy: strategy.toLowerCase(),
|
|
143
151
|
browser,
|
|
144
152
|
args,
|
|
145
|
-
columns:
|
|
146
|
-
pipeline:
|
|
147
|
-
timeout:
|
|
153
|
+
columns: cliDef.columns,
|
|
154
|
+
pipeline: cliDef.pipeline,
|
|
155
|
+
timeout: cliDef.timeout,
|
|
148
156
|
type: 'yaml',
|
|
157
|
+
navigateBefore: cliDef.navigateBefore,
|
|
149
158
|
};
|
|
150
159
|
}
|
|
151
160
|
catch (err) {
|
|
152
|
-
process.stderr.write(`Warning: failed to parse ${filePath}: ${err
|
|
161
|
+
process.stderr.write(`Warning: failed to parse ${filePath}: ${getErrorMessage(err)}\n`);
|
|
153
162
|
return null;
|
|
154
163
|
}
|
|
155
164
|
}
|
|
156
|
-
function scanTs(filePath, site) {
|
|
165
|
+
export function scanTs(filePath, site) {
|
|
157
166
|
// TS adapters self-register via cli() at import time.
|
|
158
167
|
// We statically parse the source to extract metadata for the manifest stub.
|
|
159
168
|
const baseName = path.basename(filePath, path.extname(filePath));
|
|
@@ -201,16 +210,29 @@ function scanTs(filePath, site) {
|
|
|
201
210
|
if (argsBlock) {
|
|
202
211
|
entry.args = parseTsArgsBlock(argsBlock);
|
|
203
212
|
}
|
|
213
|
+
// Extract navigateBefore: false
|
|
214
|
+
const navMatch = src.match(/navigateBefore\s*:\s*(true|false)/);
|
|
215
|
+
if (navMatch)
|
|
216
|
+
entry.navigateBefore = navMatch[1] === 'true' ? true : false;
|
|
204
217
|
return entry;
|
|
205
218
|
}
|
|
206
219
|
catch (err) {
|
|
207
220
|
// If parsing fails, log a warning (matching scanYaml behaviour) and skip the entry.
|
|
208
|
-
process.stderr.write(`Warning: failed to scan ${filePath}: ${err
|
|
221
|
+
process.stderr.write(`Warning: failed to scan ${filePath}: ${getErrorMessage(err)}\n`);
|
|
209
222
|
return null;
|
|
210
223
|
}
|
|
211
224
|
}
|
|
225
|
+
/**
|
|
226
|
+
* When both YAML and TS adapters exist for the same site/name,
|
|
227
|
+
* prefer the TS version (it self-registers and typically has richer logic).
|
|
228
|
+
*/
|
|
229
|
+
export function shouldReplaceManifestEntry(current, next) {
|
|
230
|
+
if (current.type === next.type)
|
|
231
|
+
return true;
|
|
232
|
+
return current.type === 'yaml' && next.type === 'ts';
|
|
233
|
+
}
|
|
212
234
|
export function buildManifest() {
|
|
213
|
-
const manifest =
|
|
235
|
+
const manifest = new Map();
|
|
214
236
|
if (fs.existsSync(CLIS_DIR)) {
|
|
215
237
|
for (const site of fs.readdirSync(CLIS_DIR)) {
|
|
216
238
|
const siteDir = path.join(CLIS_DIR, site);
|
|
@@ -220,19 +242,35 @@ export function buildManifest() {
|
|
|
220
242
|
const filePath = path.join(siteDir, file);
|
|
221
243
|
if (file.endsWith('.yaml') || file.endsWith('.yml')) {
|
|
222
244
|
const entry = scanYaml(filePath, site);
|
|
223
|
-
if (entry)
|
|
224
|
-
|
|
245
|
+
if (entry) {
|
|
246
|
+
const key = `${entry.site}/${entry.name}`;
|
|
247
|
+
const existing = manifest.get(key);
|
|
248
|
+
if (!existing || shouldReplaceManifestEntry(existing, entry)) {
|
|
249
|
+
if (existing && existing.type !== entry.type) {
|
|
250
|
+
process.stderr.write(`⚠️ Duplicate adapter ${key}: ${existing.type} superseded by ${entry.type}\n`);
|
|
251
|
+
}
|
|
252
|
+
manifest.set(key, entry);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
225
255
|
}
|
|
226
256
|
else if ((file.endsWith('.ts') && !file.endsWith('.d.ts') && !file.endsWith('.test.ts') && file !== 'index.ts') ||
|
|
227
257
|
(file.endsWith('.js') && !file.endsWith('.d.js') && !file.endsWith('.test.js') && file !== 'index.js')) {
|
|
228
258
|
const entry = scanTs(filePath, site);
|
|
229
|
-
if (entry)
|
|
230
|
-
|
|
259
|
+
if (entry) {
|
|
260
|
+
const key = `${entry.site}/${entry.name}`;
|
|
261
|
+
const existing = manifest.get(key);
|
|
262
|
+
if (!existing || shouldReplaceManifestEntry(existing, entry)) {
|
|
263
|
+
if (existing && existing.type !== entry.type) {
|
|
264
|
+
process.stderr.write(`⚠️ Duplicate adapter ${key}: ${existing.type} superseded by ${entry.type}\n`);
|
|
265
|
+
}
|
|
266
|
+
manifest.set(key, entry);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
231
269
|
}
|
|
232
270
|
}
|
|
233
271
|
}
|
|
234
272
|
}
|
|
235
|
-
return manifest;
|
|
273
|
+
return [...manifest.values()];
|
|
236
274
|
}
|
|
237
275
|
function main() {
|
|
238
276
|
const manifest = buildManifest();
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import
|
|
1
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as os from 'node:os';
|
|
4
|
+
import * as path from 'node:path';
|
|
5
|
+
import { parseTsArgsBlock, scanTs, shouldReplaceManifestEntry } from './build-manifest.js';
|
|
3
6
|
describe('parseTsArgsBlock', () => {
|
|
4
7
|
it('keeps args with nested choices arrays', () => {
|
|
5
8
|
const args = parseTsArgsBlock(`
|
|
@@ -58,3 +61,56 @@ describe('parseTsArgsBlock', () => {
|
|
|
58
61
|
]);
|
|
59
62
|
});
|
|
60
63
|
});
|
|
64
|
+
describe('manifest helper rules', () => {
|
|
65
|
+
const tempDirs = [];
|
|
66
|
+
afterEach(() => {
|
|
67
|
+
for (const dir of tempDirs.splice(0)) {
|
|
68
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
it('prefers TS adapters over duplicate YAML adapters', () => {
|
|
72
|
+
expect(shouldReplaceManifestEntry({
|
|
73
|
+
site: 'demo',
|
|
74
|
+
name: 'search',
|
|
75
|
+
description: 'yaml',
|
|
76
|
+
strategy: 'public',
|
|
77
|
+
browser: false,
|
|
78
|
+
args: [],
|
|
79
|
+
type: 'yaml',
|
|
80
|
+
}, {
|
|
81
|
+
site: 'demo',
|
|
82
|
+
name: 'search',
|
|
83
|
+
description: 'ts',
|
|
84
|
+
strategy: 'public',
|
|
85
|
+
browser: false,
|
|
86
|
+
args: [],
|
|
87
|
+
type: 'ts',
|
|
88
|
+
modulePath: 'demo/search.js',
|
|
89
|
+
})).toBe(true);
|
|
90
|
+
expect(shouldReplaceManifestEntry({
|
|
91
|
+
site: 'demo',
|
|
92
|
+
name: 'search',
|
|
93
|
+
description: 'ts',
|
|
94
|
+
strategy: 'public',
|
|
95
|
+
browser: false,
|
|
96
|
+
args: [],
|
|
97
|
+
type: 'ts',
|
|
98
|
+
modulePath: 'demo/search.js',
|
|
99
|
+
}, {
|
|
100
|
+
site: 'demo',
|
|
101
|
+
name: 'search',
|
|
102
|
+
description: 'yaml',
|
|
103
|
+
strategy: 'public',
|
|
104
|
+
browser: false,
|
|
105
|
+
args: [],
|
|
106
|
+
type: 'yaml',
|
|
107
|
+
})).toBe(false);
|
|
108
|
+
});
|
|
109
|
+
it('skips TS files that do not register a cli', () => {
|
|
110
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'opencli-manifest-'));
|
|
111
|
+
tempDirs.push(dir);
|
|
112
|
+
const file = path.join(dir, 'utils.ts');
|
|
113
|
+
fs.writeFileSync(file, `export function helper() { return 'noop'; }`);
|
|
114
|
+
expect(scanTs(file, 'demo')).toBeNull();
|
|
115
|
+
});
|
|
116
|
+
});
|