@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
package/src/browser/cdp.ts
CHANGED
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { WebSocket, type RawData } from 'ws';
|
|
12
|
-
import type { IPage } from '../types.js';
|
|
12
|
+
import type { BrowserCookie, IPage, ScreenshotOptions, SnapshotOptions, WaitOptions } from '../types.js';
|
|
13
13
|
import { wrapForEval } from './utils.js';
|
|
14
|
+
import { generateSnapshotJs, scrollToRefJs, getFormStateJs } from './dom-snapshot.js';
|
|
14
15
|
import {
|
|
15
16
|
clickJs,
|
|
16
17
|
typeTextJs,
|
|
@@ -28,13 +29,24 @@ export interface CDPTarget {
|
|
|
28
29
|
webSocketDebuggerUrl?: string;
|
|
29
30
|
}
|
|
30
31
|
|
|
32
|
+
interface RuntimeEvaluateResult {
|
|
33
|
+
result?: {
|
|
34
|
+
value?: unknown;
|
|
35
|
+
};
|
|
36
|
+
exceptionDetails?: {
|
|
37
|
+
exception?: {
|
|
38
|
+
description?: string;
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
31
43
|
const CDP_SEND_TIMEOUT = 30_000; // 30s per command
|
|
32
44
|
|
|
33
45
|
export class CDPBridge {
|
|
34
46
|
private _ws: WebSocket | null = null;
|
|
35
47
|
private _idCounter = 0;
|
|
36
|
-
private _pending = new Map<number, { resolve: (val:
|
|
37
|
-
private _eventListeners = new Map<string, Set<(params:
|
|
48
|
+
private _pending = new Map<number, { resolve: (val: unknown) => void; reject: (err: Error) => void; timer: ReturnType<typeof setTimeout> }>();
|
|
49
|
+
private _eventListeners = new Map<string, Set<(params: unknown) => void>>();
|
|
38
50
|
|
|
39
51
|
async connect(opts?: { timeout?: number; workspace?: string }): Promise<IPage> {
|
|
40
52
|
const endpoint = process.env.OPENCLI_CDP_ENDPOINT;
|
|
@@ -55,7 +67,8 @@ export class CDPBridge {
|
|
|
55
67
|
|
|
56
68
|
return new Promise((resolve, reject) => {
|
|
57
69
|
const ws = new WebSocket(wsUrl);
|
|
58
|
-
const
|
|
70
|
+
const timeoutMs = (opts?.timeout ?? 10) * 1000; // opts.timeout is in seconds
|
|
71
|
+
const timeout = setTimeout(() => reject(new Error('CDP connect timeout')), timeoutMs);
|
|
59
72
|
|
|
60
73
|
ws.on('open', () => {
|
|
61
74
|
clearTimeout(timeout);
|
|
@@ -110,7 +123,7 @@ export class CDPBridge {
|
|
|
110
123
|
}
|
|
111
124
|
|
|
112
125
|
/** Send a CDP command with timeout guard (P0 fix #4) */
|
|
113
|
-
async send(method: string, params:
|
|
126
|
+
async send(method: string, params: Record<string, unknown> = {}, timeoutMs: number = CDP_SEND_TIMEOUT): Promise<unknown> {
|
|
114
127
|
if (!this._ws || this._ws.readyState !== WebSocket.OPEN) {
|
|
115
128
|
throw new Error('CDP connection is not open');
|
|
116
129
|
}
|
|
@@ -126,25 +139,25 @@ export class CDPBridge {
|
|
|
126
139
|
}
|
|
127
140
|
|
|
128
141
|
/** Listen for a CDP event */
|
|
129
|
-
on(event: string, handler: (params:
|
|
142
|
+
on(event: string, handler: (params: unknown) => void): void {
|
|
130
143
|
let set = this._eventListeners.get(event);
|
|
131
144
|
if (!set) { set = new Set(); this._eventListeners.set(event, set); }
|
|
132
145
|
set.add(handler);
|
|
133
146
|
}
|
|
134
147
|
|
|
135
148
|
/** Remove a CDP event listener */
|
|
136
|
-
off(event: string, handler: (params:
|
|
149
|
+
off(event: string, handler: (params: unknown) => void): void {
|
|
137
150
|
this._eventListeners.get(event)?.delete(handler);
|
|
138
151
|
}
|
|
139
152
|
|
|
140
153
|
/** Wait for a CDP event to fire (one-shot) */
|
|
141
|
-
waitForEvent(event: string, timeoutMs: number = 15_000): Promise<
|
|
154
|
+
waitForEvent(event: string, timeoutMs: number = 15_000): Promise<unknown> {
|
|
142
155
|
return new Promise((resolve, reject) => {
|
|
143
156
|
const timer = setTimeout(() => {
|
|
144
157
|
this.off(event, handler);
|
|
145
158
|
reject(new Error(`Timed out waiting for CDP event '${event}'`));
|
|
146
159
|
}, timeoutMs);
|
|
147
|
-
const handler = (params:
|
|
160
|
+
const handler = (params: unknown) => {
|
|
148
161
|
clearTimeout(timer);
|
|
149
162
|
this.off(event, handler);
|
|
150
163
|
resolve(params);
|
|
@@ -171,30 +184,38 @@ class CDPPage implements IPage {
|
|
|
171
184
|
}
|
|
172
185
|
}
|
|
173
186
|
|
|
174
|
-
async evaluate(js: string): Promise<
|
|
187
|
+
async evaluate(js: string): Promise<unknown> {
|
|
175
188
|
const expression = wrapForEval(js);
|
|
176
189
|
const result = await this.bridge.send('Runtime.evaluate', {
|
|
177
190
|
expression,
|
|
178
191
|
returnByValue: true,
|
|
179
192
|
awaitPromise: true
|
|
180
|
-
});
|
|
193
|
+
}) as RuntimeEvaluateResult;
|
|
181
194
|
if (result.exceptionDetails) {
|
|
182
195
|
throw new Error('Evaluate error: ' + (result.exceptionDetails.exception?.description || 'Unknown exception'));
|
|
183
196
|
}
|
|
184
197
|
return result.result?.value;
|
|
185
198
|
}
|
|
186
199
|
|
|
187
|
-
async getCookies(opts: { domain?: string; url?: string } = {}): Promise<
|
|
200
|
+
async getCookies(opts: { domain?: string; url?: string } = {}): Promise<BrowserCookie[]> {
|
|
188
201
|
const result = await this.bridge.send('Network.getCookies', opts.url ? { urls: [opts.url] } : {});
|
|
189
|
-
const cookies = Array.isArray(result
|
|
190
|
-
|
|
191
|
-
|
|
202
|
+
const cookies = isRecord(result) && Array.isArray(result.cookies) ? result.cookies : [];
|
|
203
|
+
const domain = opts.domain;
|
|
204
|
+
return domain
|
|
205
|
+
? cookies.filter((cookie): cookie is BrowserCookie => isCookie(cookie) && cookie.domain.includes(domain))
|
|
192
206
|
: cookies;
|
|
193
207
|
}
|
|
194
208
|
|
|
195
|
-
async snapshot(
|
|
196
|
-
|
|
197
|
-
|
|
209
|
+
async snapshot(opts: SnapshotOptions = {}): Promise<unknown> {
|
|
210
|
+
const snapshotJs = generateSnapshotJs({
|
|
211
|
+
viewportExpand: opts.viewportExpand ?? 800,
|
|
212
|
+
maxDepth: Math.max(1, Math.min(Number(opts.maxDepth) || 50, 200)),
|
|
213
|
+
interactiveOnly: opts.interactive ?? false,
|
|
214
|
+
maxTextLength: opts.maxTextLength ?? 120,
|
|
215
|
+
includeScrollInfo: true,
|
|
216
|
+
bboxDedup: true,
|
|
217
|
+
});
|
|
218
|
+
return this.evaluate(snapshotJs);
|
|
198
219
|
}
|
|
199
220
|
|
|
200
221
|
// ── Shared DOM operations (P1 fix #5 — using dom-helpers.ts) ──
|
|
@@ -211,13 +232,22 @@ class CDPPage implements IPage {
|
|
|
211
232
|
await this.evaluate(pressKeyJs(key));
|
|
212
233
|
}
|
|
213
234
|
|
|
214
|
-
async
|
|
235
|
+
async scrollTo(ref: string): Promise<unknown> {
|
|
236
|
+
return this.evaluate(scrollToRefJs(ref));
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
async getFormState(): Promise<Record<string, unknown>> {
|
|
240
|
+
return (await this.evaluate(getFormStateJs())) as Record<string, unknown>;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
async wait(options: number | WaitOptions): Promise<void> {
|
|
215
244
|
if (typeof options === 'number') {
|
|
216
245
|
await new Promise(resolve => setTimeout(resolve, options * 1000));
|
|
217
246
|
return;
|
|
218
247
|
}
|
|
219
|
-
if (options.time) {
|
|
220
|
-
|
|
248
|
+
if (typeof options.time === 'number') {
|
|
249
|
+
const waitTime = options.time;
|
|
250
|
+
await new Promise(resolve => setTimeout(resolve, waitTime * 1000));
|
|
221
251
|
return;
|
|
222
252
|
}
|
|
223
253
|
if (options.text) {
|
|
@@ -238,13 +268,13 @@ class CDPPage implements IPage {
|
|
|
238
268
|
await this.evaluate(autoScrollJs(times, delayMs));
|
|
239
269
|
}
|
|
240
270
|
|
|
241
|
-
async screenshot(options:
|
|
271
|
+
async screenshot(options: ScreenshotOptions = {}): Promise<string> {
|
|
242
272
|
const result = await this.bridge.send('Page.captureScreenshot', {
|
|
243
273
|
format: options.format ?? 'png',
|
|
244
274
|
quality: options.format === 'jpeg' ? (options.quality ?? 80) : undefined,
|
|
245
275
|
captureBeyondViewport: options.fullPage ?? false,
|
|
246
276
|
});
|
|
247
|
-
const base64 = result.data;
|
|
277
|
+
const base64 = isRecord(result) && typeof result.data === 'string' ? result.data : '';
|
|
248
278
|
if (options.path) {
|
|
249
279
|
const fs = await import('node:fs');
|
|
250
280
|
const path = await import('node:path');
|
|
@@ -255,11 +285,12 @@ class CDPPage implements IPage {
|
|
|
255
285
|
return base64;
|
|
256
286
|
}
|
|
257
287
|
|
|
258
|
-
async networkRequests(includeStatic: boolean = false): Promise<
|
|
259
|
-
|
|
288
|
+
async networkRequests(includeStatic: boolean = false): Promise<unknown[]> {
|
|
289
|
+
const result = await this.evaluate(networkRequestsJs(includeStatic));
|
|
290
|
+
return Array.isArray(result) ? result : [];
|
|
260
291
|
}
|
|
261
292
|
|
|
262
|
-
async tabs(): Promise<
|
|
293
|
+
async tabs(): Promise<unknown[]> {
|
|
263
294
|
return [];
|
|
264
295
|
}
|
|
265
296
|
|
|
@@ -275,7 +306,7 @@ class CDPPage implements IPage {
|
|
|
275
306
|
// Not supported in direct CDP mode
|
|
276
307
|
}
|
|
277
308
|
|
|
278
|
-
async consoleMessages(_level?: string): Promise<
|
|
309
|
+
async consoleMessages(_level?: string): Promise<unknown[]> {
|
|
279
310
|
return [];
|
|
280
311
|
}
|
|
281
312
|
|
|
@@ -287,13 +318,24 @@ class CDPPage implements IPage {
|
|
|
287
318
|
}));
|
|
288
319
|
}
|
|
289
320
|
|
|
290
|
-
async getInterceptedRequests(): Promise<
|
|
321
|
+
async getInterceptedRequests(): Promise<unknown[]> {
|
|
291
322
|
const { generateReadInterceptedJs } = await import('../interceptor.js');
|
|
292
323
|
const result = await this.evaluate(generateReadInterceptedJs('__opencli_xhr'));
|
|
293
|
-
return (result
|
|
324
|
+
return Array.isArray(result) ? result : [];
|
|
294
325
|
}
|
|
295
326
|
}
|
|
296
327
|
|
|
328
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
329
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function isCookie(value: unknown): value is BrowserCookie {
|
|
333
|
+
return isRecord(value)
|
|
334
|
+
&& typeof value.name === 'string'
|
|
335
|
+
&& typeof value.value === 'string'
|
|
336
|
+
&& typeof value.domain === 'string';
|
|
337
|
+
}
|
|
338
|
+
|
|
297
339
|
// ── CDP target selection (unchanged) ──
|
|
298
340
|
|
|
299
341
|
function selectCDPTarget(targets: CDPTarget[]): CDPTarget | undefined {
|
|
@@ -343,7 +385,6 @@ function scoreCDPTarget(target: CDPTarget, preferredPattern?: RegExp): number {
|
|
|
343
385
|
if (title.includes('chatwise')) score += 120;
|
|
344
386
|
if (title.includes('notion')) score += 120;
|
|
345
387
|
if (title.includes('discord')) score += 120;
|
|
346
|
-
if (title.includes('netease')) score += 120;
|
|
347
388
|
|
|
348
389
|
if (url.includes('antigravity')) score += 100;
|
|
349
390
|
if (url.includes('codex')) score += 100;
|
|
@@ -351,7 +392,6 @@ function scoreCDPTarget(target: CDPTarget, preferredPattern?: RegExp): number {
|
|
|
351
392
|
if (url.includes('chatwise')) score += 100;
|
|
352
393
|
if (url.includes('notion')) score += 100;
|
|
353
394
|
if (url.includes('discord')) score += 100;
|
|
354
|
-
if (url.includes('netease')) score += 100;
|
|
355
395
|
|
|
356
396
|
return score;
|
|
357
397
|
}
|
|
@@ -113,7 +113,8 @@ export async function sendCommand(
|
|
|
113
113
|
throw new Error('sendCommand: max retries exhausted');
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
export async function listSessions(): Promise<
|
|
116
|
+
export async function listSessions(): Promise<BrowserSessionInfo[]> {
|
|
117
117
|
const result = await sendCommand('sessions');
|
|
118
118
|
return Array.isArray(result) ? result : [];
|
|
119
119
|
}
|
|
120
|
+
import type { BrowserSessionInfo } from '../types.js';
|
|
@@ -11,8 +11,21 @@ export function clickJs(ref: string): string {
|
|
|
11
11
|
return `
|
|
12
12
|
(() => {
|
|
13
13
|
const ref = ${safeRef};
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
// 1. data-opencli-ref (set by snapshot engine)
|
|
15
|
+
let el = document.querySelector('[data-opencli-ref="' + ref + '"]');
|
|
16
|
+
// 2. data-ref (legacy)
|
|
17
|
+
if (!el) el = document.querySelector('[data-ref="' + ref + '"]');
|
|
18
|
+
// 3. CSS selector
|
|
19
|
+
if (!el && ref.match(/^[a-zA-Z#.\\[]/)) {
|
|
20
|
+
try { el = document.querySelector(ref); } catch {}
|
|
21
|
+
}
|
|
22
|
+
// 4. Numeric index into interactive elements
|
|
23
|
+
if (!el) {
|
|
24
|
+
const idx = parseInt(ref, 10);
|
|
25
|
+
if (!isNaN(idx)) {
|
|
26
|
+
el = document.querySelectorAll('a, button, input, select, textarea, [role="button"], [tabindex]:not([tabindex="-1"])')[idx];
|
|
27
|
+
}
|
|
28
|
+
}
|
|
16
29
|
if (!el) throw new Error('Element not found: ' + ref);
|
|
17
30
|
el.scrollIntoView({ behavior: 'instant', block: 'center' });
|
|
18
31
|
el.click();
|
|
@@ -28,13 +41,31 @@ export function typeTextJs(ref: string, text: string): string {
|
|
|
28
41
|
return `
|
|
29
42
|
(() => {
|
|
30
43
|
const ref = ${safeRef};
|
|
31
|
-
|
|
32
|
-
|
|
44
|
+
// 1. data-opencli-ref (set by snapshot engine)
|
|
45
|
+
let el = document.querySelector('[data-opencli-ref="' + ref + '"]');
|
|
46
|
+
// 2. data-ref (legacy)
|
|
47
|
+
if (!el) el = document.querySelector('[data-ref="' + ref + '"]');
|
|
48
|
+
// 3. CSS selector
|
|
49
|
+
if (!el && ref.match(/^[a-zA-Z#.\\[]/)) {
|
|
50
|
+
try { el = document.querySelector(ref); } catch {}
|
|
51
|
+
}
|
|
52
|
+
// 4. Numeric index into typeable elements
|
|
53
|
+
if (!el) {
|
|
54
|
+
const idx = parseInt(ref, 10);
|
|
55
|
+
if (!isNaN(idx)) {
|
|
56
|
+
el = document.querySelectorAll('input, textarea, [contenteditable="true"]')[idx];
|
|
57
|
+
}
|
|
58
|
+
}
|
|
33
59
|
if (!el) throw new Error('Element not found: ' + ref);
|
|
34
60
|
el.focus();
|
|
35
|
-
el.
|
|
36
|
-
|
|
37
|
-
|
|
61
|
+
if (el.isContentEditable) {
|
|
62
|
+
el.textContent = ${safeText};
|
|
63
|
+
el.dispatchEvent(new Event('input', { bubbles: true }));
|
|
64
|
+
} else {
|
|
65
|
+
el.value = ${safeText};
|
|
66
|
+
el.dispatchEvent(new Event('input', { bubbles: true }));
|
|
67
|
+
el.dispatchEvent(new Event('change', { bubbles: true }));
|
|
68
|
+
}
|
|
38
69
|
return 'typed';
|
|
39
70
|
})()
|
|
40
71
|
`;
|
|
@@ -0,0 +1,249 @@
|
|
|
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
|
+
|
|
12
|
+
import { describe, it, expect } from 'vitest';
|
|
13
|
+
import { generateSnapshotJs, scrollToRefJs, getFormStateJs } from './dom-snapshot.js';
|
|
14
|
+
|
|
15
|
+
describe('generateSnapshotJs', () => {
|
|
16
|
+
it('returns a non-empty string', () => {
|
|
17
|
+
const js = generateSnapshotJs();
|
|
18
|
+
expect(typeof js).toBe('string');
|
|
19
|
+
expect(js.length).toBeGreaterThan(100);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('generates syntactically valid JS (can be parsed)', () => {
|
|
23
|
+
const js = generateSnapshotJs();
|
|
24
|
+
expect(() => new Function(js)).not.toThrow();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('embeds default options correctly', () => {
|
|
28
|
+
const js = generateSnapshotJs();
|
|
29
|
+
expect(js).toContain('VIEWPORT_EXPAND = 800');
|
|
30
|
+
expect(js).toContain('MAX_DEPTH = 50');
|
|
31
|
+
expect(js).toContain('INTERACTIVE_ONLY = false');
|
|
32
|
+
expect(js).toContain('MAX_TEXT_LEN = 120');
|
|
33
|
+
expect(js).toContain('INCLUDE_SCROLL_INFO = true');
|
|
34
|
+
expect(js).toContain('BBOX_DEDUP = true');
|
|
35
|
+
expect(js).toContain('INCLUDE_SHADOW_DOM = true');
|
|
36
|
+
expect(js).toContain('INCLUDE_IFRAMES = true');
|
|
37
|
+
expect(js).toContain('PAINT_ORDER_CHECK = true');
|
|
38
|
+
expect(js).toContain('ANNOTATE_REFS = true');
|
|
39
|
+
expect(js).toContain('REPORT_HIDDEN = true');
|
|
40
|
+
expect(js).toContain('FILTER_ADS = true');
|
|
41
|
+
expect(js).toContain('MARKDOWN_TABLES = true');
|
|
42
|
+
expect(js).toContain('PREV_HASHES = null');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('embeds custom options correctly', () => {
|
|
46
|
+
const js = generateSnapshotJs({
|
|
47
|
+
viewportExpand: 2000,
|
|
48
|
+
maxDepth: 30,
|
|
49
|
+
interactiveOnly: true,
|
|
50
|
+
maxTextLength: 200,
|
|
51
|
+
includeScrollInfo: false,
|
|
52
|
+
bboxDedup: false,
|
|
53
|
+
includeShadowDom: false,
|
|
54
|
+
includeIframes: false,
|
|
55
|
+
maxIframes: 3,
|
|
56
|
+
paintOrderCheck: false,
|
|
57
|
+
annotateRefs: false,
|
|
58
|
+
reportHidden: false,
|
|
59
|
+
filterAds: false,
|
|
60
|
+
markdownTables: false,
|
|
61
|
+
});
|
|
62
|
+
expect(js).toContain('VIEWPORT_EXPAND = 2000');
|
|
63
|
+
expect(js).toContain('MAX_DEPTH = 30');
|
|
64
|
+
expect(js).toContain('INTERACTIVE_ONLY = true');
|
|
65
|
+
expect(js).toContain('MAX_TEXT_LEN = 200');
|
|
66
|
+
expect(js).toContain('INCLUDE_SCROLL_INFO = false');
|
|
67
|
+
expect(js).toContain('BBOX_DEDUP = false');
|
|
68
|
+
expect(js).toContain('INCLUDE_SHADOW_DOM = false');
|
|
69
|
+
expect(js).toContain('INCLUDE_IFRAMES = false');
|
|
70
|
+
expect(js).toContain('MAX_IFRAMES = 3');
|
|
71
|
+
expect(js).toContain('PAINT_ORDER_CHECK = false');
|
|
72
|
+
expect(js).toContain('ANNOTATE_REFS = false');
|
|
73
|
+
expect(js).toContain('REPORT_HIDDEN = false');
|
|
74
|
+
expect(js).toContain('FILTER_ADS = false');
|
|
75
|
+
expect(js).toContain('MARKDOWN_TABLES = false');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('clamps maxDepth between 1 and 200', () => {
|
|
79
|
+
expect(generateSnapshotJs({ maxDepth: -5 })).toContain('MAX_DEPTH = 1');
|
|
80
|
+
expect(generateSnapshotJs({ maxDepth: 999 })).toContain('MAX_DEPTH = 200');
|
|
81
|
+
expect(generateSnapshotJs({ maxDepth: 75 })).toContain('MAX_DEPTH = 75');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('wraps output as an IIFE', () => {
|
|
85
|
+
const js = generateSnapshotJs();
|
|
86
|
+
expect(js.startsWith('(() =>')).toBe(true);
|
|
87
|
+
expect(js.trimEnd().endsWith(')()')).toBe(true);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('embeds previousHashes for incremental diff', () => {
|
|
91
|
+
const hashes = JSON.stringify(['12345', '67890']);
|
|
92
|
+
const js = generateSnapshotJs({ previousHashes: hashes });
|
|
93
|
+
expect(js).toContain('new Set(["12345","67890"])');
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('includes all core features in generated code', () => {
|
|
97
|
+
const js = generateSnapshotJs();
|
|
98
|
+
|
|
99
|
+
// Tag filtering
|
|
100
|
+
expect(js).toContain('SKIP_TAGS');
|
|
101
|
+
expect(js).toContain("'script'");
|
|
102
|
+
expect(js).toContain("'style'");
|
|
103
|
+
|
|
104
|
+
// SVG collapsing
|
|
105
|
+
expect(js).toContain('SVG_CHILDREN');
|
|
106
|
+
|
|
107
|
+
// Interactive detection
|
|
108
|
+
expect(js).toContain('INTERACTIVE_TAGS');
|
|
109
|
+
expect(js).toContain('INTERACTIVE_ROLES');
|
|
110
|
+
expect(js).toContain('isInteractive');
|
|
111
|
+
|
|
112
|
+
// Visibility
|
|
113
|
+
expect(js).toContain('isVisibleByCSS');
|
|
114
|
+
expect(js).toContain('isInExpandedViewport');
|
|
115
|
+
|
|
116
|
+
// BBox dedup
|
|
117
|
+
expect(js).toContain('isContainedBy');
|
|
118
|
+
expect(js).toContain('PROPAGATING_TAGS');
|
|
119
|
+
|
|
120
|
+
// Shadow DOM
|
|
121
|
+
expect(js).toContain('shadowRoot');
|
|
122
|
+
expect(js).toContain('|shadow|');
|
|
123
|
+
|
|
124
|
+
// iframe
|
|
125
|
+
expect(js).toContain('walkIframe');
|
|
126
|
+
expect(js).toContain('|iframe|');
|
|
127
|
+
|
|
128
|
+
// Paint order
|
|
129
|
+
expect(js).toContain('isOccludedByOverlay');
|
|
130
|
+
expect(js).toContain('elementFromPoint');
|
|
131
|
+
|
|
132
|
+
// Ad filtering
|
|
133
|
+
expect(js).toContain('isAdElement');
|
|
134
|
+
expect(js).toContain('AD_PATTERNS');
|
|
135
|
+
|
|
136
|
+
// data-ref annotation
|
|
137
|
+
expect(js).toContain('data-opencli-ref');
|
|
138
|
+
|
|
139
|
+
// Hidden elements report
|
|
140
|
+
expect(js).toContain('hiddenInteractives');
|
|
141
|
+
expect(js).toContain('hidden_interactive');
|
|
142
|
+
|
|
143
|
+
// Incremental diff
|
|
144
|
+
expect(js).toContain('hashElement');
|
|
145
|
+
expect(js).toContain('currentHashes');
|
|
146
|
+
expect(js).toContain('__opencli_prev_hashes');
|
|
147
|
+
|
|
148
|
+
// Table serialization
|
|
149
|
+
expect(js).toContain('serializeTable');
|
|
150
|
+
expect(js).toContain('|table|');
|
|
151
|
+
|
|
152
|
+
// Synthetic attributes
|
|
153
|
+
expect(js).toContain("'YYYY-MM-DD'");
|
|
154
|
+
expect(js).toContain('value=••••');
|
|
155
|
+
|
|
156
|
+
// Page metadata
|
|
157
|
+
expect(js).toContain('location.href');
|
|
158
|
+
expect(js).toContain('document.title');
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('contains proper attribute whitelist', () => {
|
|
162
|
+
const js = generateSnapshotJs();
|
|
163
|
+
const expectedAttrs = [
|
|
164
|
+
'aria-label', 'aria-expanded', 'aria-checked', 'aria-selected',
|
|
165
|
+
'placeholder', 'href', 'role', 'data-testid', 'autocomplete',
|
|
166
|
+
];
|
|
167
|
+
for (const attr of expectedAttrs) {
|
|
168
|
+
expect(js).toContain(`'${attr}'`);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('includes scroll info formatting', () => {
|
|
173
|
+
const js = generateSnapshotJs();
|
|
174
|
+
expect(js).toContain('scrollHeight');
|
|
175
|
+
expect(js).toContain('scrollTop');
|
|
176
|
+
expect(js).toContain('|scroll|');
|
|
177
|
+
expect(js).toContain('page_scroll');
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
describe('scrollToRefJs', () => {
|
|
182
|
+
it('generates valid JS', () => {
|
|
183
|
+
const js = scrollToRefJs('42');
|
|
184
|
+
expect(() => new Function(js)).not.toThrow();
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('targets data-opencli-ref', () => {
|
|
188
|
+
const js = scrollToRefJs('7');
|
|
189
|
+
expect(js).toContain('data-opencli-ref');
|
|
190
|
+
expect(js).toContain('scrollIntoView');
|
|
191
|
+
expect(js).toContain('"7"');
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('falls back to data-ref', () => {
|
|
195
|
+
const js = scrollToRefJs('3');
|
|
196
|
+
expect(js).toContain('data-ref');
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('returns scrolled info', () => {
|
|
200
|
+
const js = scrollToRefJs('1');
|
|
201
|
+
expect(js).toContain('scrolled: true');
|
|
202
|
+
expect(js).toContain('tag:');
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
describe('getFormStateJs', () => {
|
|
207
|
+
it('generates valid JS', () => {
|
|
208
|
+
const js = getFormStateJs();
|
|
209
|
+
expect(() => new Function(js)).not.toThrow();
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it('collects form elements', () => {
|
|
213
|
+
const js = getFormStateJs();
|
|
214
|
+
expect(js).toContain('document.forms');
|
|
215
|
+
expect(js).toContain('form.elements');
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it('collects orphan fields', () => {
|
|
219
|
+
const js = getFormStateJs();
|
|
220
|
+
expect(js).toContain('orphanFields');
|
|
221
|
+
expect(js).toContain('el.form');
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it('handles different input types', () => {
|
|
225
|
+
const js = getFormStateJs();
|
|
226
|
+
expect(js).toContain('checkbox');
|
|
227
|
+
expect(js).toContain('radio');
|
|
228
|
+
expect(js).toContain('password');
|
|
229
|
+
expect(js).toContain('contenteditable');
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it('extracts labels', () => {
|
|
233
|
+
const js = getFormStateJs();
|
|
234
|
+
expect(js).toContain('aria-label');
|
|
235
|
+
expect(js).toContain('label[for=');
|
|
236
|
+
expect(js).toContain('closest');
|
|
237
|
+
expect(js).toContain('placeholder');
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('masks passwords', () => {
|
|
241
|
+
const js = getFormStateJs();
|
|
242
|
+
expect(js).toContain('••••');
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it('includes data-opencli-ref in output', () => {
|
|
246
|
+
const js = getFormStateJs();
|
|
247
|
+
expect(js).toContain('data-opencli-ref');
|
|
248
|
+
});
|
|
249
|
+
});
|