@sovovs/bycli 1.8.0 → 2.0.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/cli-manifest.json +0 -61
- package/dist/src/adapter-shadow.js +2 -2
- package/dist/src/browser/analyze.d.ts +10 -99
- package/dist/src/browser/analyze.js +10 -226
- package/dist/src/browser/cdp.js +64 -7
- package/dist/src/browser/navigation-guard.d.ts +78 -0
- package/dist/src/browser/navigation-guard.js +142 -0
- package/dist/src/browser/navigation-guard.test.d.ts +1 -0
- package/dist/src/browser/url-policy.d.ts +89 -0
- package/dist/src/browser/url-policy.js +311 -0
- package/dist/src/browser/url-policy.test.d.ts +1 -0
- package/dist/src/browser/verify-fixture.js +2 -2
- package/dist/src/cli.js +10 -13
- package/dist/src/config-paths.d.ts +19 -0
- package/dist/src/config-paths.js +31 -0
- package/dist/src/daemon.js +240 -0
- package/dist/src/discovery.d.ts +5 -3
- package/dist/src/discovery.js +8 -6
- package/dist/src/execution.js +8 -3
- package/dist/src/main.js +18 -2
- package/dist/src/plugin.js +11 -8
- package/dist/src/recorder/highlevel/analyze.d.ts +29 -0
- package/dist/src/recorder/highlevel/analyze.js +91 -0
- package/dist/src/recorder/highlevel/init.d.ts +125 -0
- package/dist/src/recorder/highlevel/init.js +279 -0
- package/dist/src/recorder/highlevel/init.test.d.ts +1 -0
- package/dist/src/recorder/highlevel/verify.d.ts +73 -0
- package/dist/src/recorder/highlevel/verify.js +74 -0
- package/dist/src/recorder/http/analyze-runner.d.ts +28 -0
- package/dist/src/recorder/http/analyze-runner.js +78 -0
- package/dist/src/recorder/http/analyze-runner.test.d.ts +1 -0
- package/dist/src/recorder/http/handlers.d.ts +51 -0
- package/dist/src/recorder/http/handlers.js +219 -0
- package/dist/src/recorder/http/wrapper-config.d.ts +20 -0
- package/dist/src/recorder/http/wrapper-config.js +82 -0
- package/dist/src/recorder/http/wrapper-envelope.d.ts +31 -0
- package/dist/src/recorder/http/wrapper-envelope.js +51 -0
- package/dist/src/recorder/http/wrapper-gates.d.ts +16 -0
- package/dist/src/recorder/http/wrapper-gates.js +28 -0
- package/dist/src/recorder/http/wrapper-metrics.d.ts +1 -0
- package/dist/src/recorder/http/wrapper-metrics.js +5 -0
- package/dist/src/recorder/http/wrapper-registry.d.ts +50 -0
- package/dist/src/recorder/http/wrapper-registry.js +98 -0
- package/dist/src/recorder/http/wrapper-server.d.ts +59 -0
- package/dist/src/recorder/http/wrapper-server.js +240 -0
- package/dist/src/recorder/http/wrapper.test.d.ts +1 -0
- package/dist/src/recorder/observability/logger.d.ts +5 -0
- package/dist/src/recorder/observability/logger.js +13 -0
- package/dist/src/recorder/runner/config.d.ts +34 -0
- package/dist/src/recorder/runner/config.js +84 -0
- package/dist/src/recorder/runner/config.test.d.ts +1 -0
- package/dist/src/recorder/runner/reap.d.ts +79 -0
- package/dist/src/recorder/runner/reap.js +230 -0
- package/dist/src/recorder/runner/reap.test.d.ts +1 -0
- package/dist/src/recorder/runner/runner-port.d.ts +95 -0
- package/dist/src/recorder/runner/runner-port.js +518 -0
- package/dist/src/recorder/runner/runner-port.test.d.ts +1 -0
- package/dist/src/recorder/runner/session-keys.d.ts +28 -0
- package/dist/src/recorder/runner/session-keys.js +72 -0
- package/dist/src/recorder/runner/session-keys.test.d.ts +1 -0
- package/dist/src/recorder/runner/verify-runner-main.d.ts +95 -0
- package/dist/src/recorder/runner/verify-runner-main.js +275 -0
- package/dist/src/recorder/runner/verify-runner-main.test.d.ts +1 -0
- package/package.json +8 -5
- package/scripts/m1-daemon-navigate-drive.mjs +138 -0
- package/scripts/m1-extension-spike.mjs +237 -0
- package/scripts/m1-live-spike.mjs +156 -0
- package/scripts/m6b-connect-back-spike.sh +31 -0
- package/scripts/recorder.sh +186 -0
- package/clis/12306/utils.test.js +0 -331
- package/clis/1688/assets.test.js +0 -39
- package/clis/1688/download.test.js +0 -31
- package/clis/1688/item.test.js +0 -67
- package/clis/1688/search.test.js +0 -75
- package/clis/1688/shared.test.js +0 -57
- package/clis/1688/store.test.js +0 -62
- package/clis/36kr/article.test.js +0 -46
- package/clis/36kr/hot.test.js +0 -15
- package/clis/36kr/news.test.js +0 -85
- package/clis/51job/utils.test.js +0 -69
- package/clis/_atlassian/shared.test.js +0 -170
- package/clis/aibase/news.test.js +0 -59
- package/clis/amazon/bestsellers.test.js +0 -29
- package/clis/amazon/discussion.test.js +0 -124
- package/clis/amazon/offer.test.js +0 -29
- package/clis/amazon/product.test.js +0 -24
- package/clis/amazon/rankings.test.js +0 -41
- package/clis/amazon/search.test.js +0 -22
- package/clis/amazon/shared.test.js +0 -44
- package/clis/apple-podcasts/commands.test.js +0 -119
- package/clis/apple-podcasts/utils.test.js +0 -57
- package/clis/arxiv/arxiv.test.js +0 -112
- package/clis/baidu-scholar/search.test.js +0 -23
- package/clis/barchart/greeks.test.js +0 -138
- package/clis/bilibili/comment.test.js +0 -153
- package/clis/bilibili/comments.test.js +0 -142
- package/clis/bilibili/dynamic.test.js +0 -68
- package/clis/bilibili/hot.test.js +0 -17
- package/clis/bilibili/subtitle.test.js +0 -196
- package/clis/bilibili/summary.test.js +0 -210
- package/clis/bilibili/utils.test.js +0 -61
- package/clis/bilibili/video.test.js +0 -132
- package/clis/binance/commands.test.js +0 -70
- package/clis/bloomberg/utils.test.js +0 -129
- package/clis/booking/booking.test.js +0 -356
- package/clis/boss/chatlist.test.js +0 -211
- package/clis/boss/chatmsg.test.js +0 -230
- package/clis/boss/search.test.js +0 -78
- package/clis/boss/utils.test.js +0 -34
- package/clis/brave/search.test.js +0 -76
- package/clis/chaoxing/utils.test.js +0 -45
- package/clis/chatgpt/commands.test.js +0 -45
- package/clis/chatgpt/envelope.test.js +0 -108
- package/clis/chatgpt/image.test.js +0 -188
- package/clis/chatgpt/utils.test.js +0 -330
- package/clis/chatgpt-app/ax.test.js +0 -35
- package/clis/chatwise/composer.test.js +0 -186
- package/clis/chess/analyze.test.js +0 -79
- package/clis/chess/game.test.js +0 -178
- package/clis/chess/games.test.js +0 -164
- package/clis/chess/stats.test.js +0 -79
- package/clis/chess/utils.test.js +0 -230
- package/clis/claude/ask.test.js +0 -338
- package/clis/claude/commands.test.js +0 -118
- package/clis/claude/utils.test.js +0 -148
- package/clis/cnki/search.test.js +0 -18
- package/clis/codex/sidebar.test.js +0 -329
- package/clis/coingecko/coingecko.test.js +0 -109
- package/clis/confluence/commands.test.js +0 -195
- package/clis/coupang/coupang.test.js +0 -159
- package/clis/coupang/utils.test.js +0 -62
- package/clis/ctrip/ctrip.test.js +0 -719
- package/clis/dblp/dblp.test.js +0 -397
- package/clis/deepseek/ask.test.js +0 -312
- package/clis/deepseek/detail.test.js +0 -81
- package/clis/deepseek/send.test.js +0 -107
- package/clis/deepseek/utils.test.js +0 -370
- package/clis/defillama/defillama.test.js +0 -99
- package/clis/devto/devto.test.js +0 -236
- package/clis/dianping/dianping.test.js +0 -578
- package/clis/douban/download.test.js +0 -170
- package/clis/douban/movie-hot.test.js +0 -14
- package/clis/douban/search.test.js +0 -11
- package/clis/douban/subject.test.js +0 -11
- package/clis/douban/utils.test.js +0 -438
- package/clis/doubao/detail.test.js +0 -42
- package/clis/doubao/history.test.js +0 -37
- package/clis/doubao/utils.test.js +0 -344
- package/clis/douyin/_shared/browser-fetch.test.js +0 -64
- package/clis/douyin/_shared/creation-id.test.js +0 -22
- package/clis/douyin/_shared/imagex-upload.test.js +0 -87
- package/clis/douyin/_shared/sts2.test.js +0 -27
- package/clis/douyin/_shared/text-extra.test.js +0 -37
- package/clis/douyin/_shared/timing.test.js +0 -28
- package/clis/douyin/_shared/tos-upload-short-read.test.js +0 -83
- package/clis/douyin/_shared/tos-upload.test.js +0 -229
- package/clis/douyin/_shared/transcode.test.js +0 -91
- package/clis/douyin/_shared/vod-upload.test.js +0 -38
- package/clis/douyin/activities.test.js +0 -55
- package/clis/douyin/collections.test.js +0 -45
- package/clis/douyin/delete.test.js +0 -100
- package/clis/douyin/draft.test.js +0 -335
- package/clis/douyin/drafts.test.js +0 -11
- package/clis/douyin/hashtag.test.js +0 -171
- package/clis/douyin/location.test.js +0 -23
- package/clis/douyin/profile.test.js +0 -46
- package/clis/douyin/publish-upload-id.test.js +0 -170
- package/clis/douyin/publish.test.js +0 -38
- package/clis/douyin/stats.test.js +0 -22
- package/clis/douyin/update.test.js +0 -11
- package/clis/douyin/user-videos.test.js +0 -151
- package/clis/douyin/videos.test.js +0 -54
- package/clis/duckduckgo/search.test.js +0 -128
- package/clis/duckduckgo/suggest.test.js +0 -66
- package/clis/eastmoney/hot-rank.test.js +0 -59
- package/clis/endoflife/endoflife.test.js +0 -51
- package/clis/facebook/feed.test.js +0 -169
- package/clis/facebook/marketplace.test.js +0 -91
- package/clis/facebook/notifications.test.js +0 -458
- package/clis/facebook/search.test.js +0 -55
- package/clis/flathub/flathub.test.js +0 -90
- package/clis/flomo/memos.test.js +0 -144
- package/clis/gemini/ask.test.js +0 -100
- package/clis/gemini/deep-research-result.test.js +0 -155
- package/clis/gemini/deep-research.test.js +0 -181
- package/clis/gemini/reply-state.test.js +0 -671
- package/clis/gemini/utils.test.js +0 -198
- package/clis/geogebra/geogebra.test.js +0 -175
- package/clis/gitee/search.test.js +0 -65
- package/clis/gitee/user.test.js +0 -63
- package/clis/google/utils.test.js +0 -75
- package/clis/google-scholar/cite.test.js +0 -47
- package/clis/google-scholar/profile.test.js +0 -49
- package/clis/google-scholar/search.test.js +0 -71
- package/clis/goproxy/goproxy.test.js +0 -103
- package/clis/gov-law/commands.test.js +0 -39
- package/clis/gov-policy/gov-policy.test.js +0 -224
- package/clis/grok/ask.test.js +0 -29
- package/clis/grok/utils.test.js +0 -103
- package/clis/hackernews/hackernews.test.js +0 -132
- package/clis/hf/hf.test.js +0 -16
- package/clis/hupu/hot.test.js +0 -224
- package/clis/imdb/utils.test.js +0 -88
- package/clis/indeed/indeed.test.js +0 -375
- package/clis/instagram/_shared/private-publish.test.js +0 -705
- package/clis/instagram/_shared/protocol-capture.test.js +0 -114
- package/clis/instagram/download.test.js +0 -118
- package/clis/instagram/note.test.js +0 -53
- package/clis/instagram/post.test.js +0 -1647
- package/clis/instagram/reel.test.js +0 -167
- package/clis/instagram/story.test.js +0 -134
- package/clis/jd/commands.test.js +0 -41
- package/clis/jd/item.test.js +0 -354
- package/clis/jianyu/search.test.js +0 -153
- package/clis/jianyu/shared/procurement-contract.test.js +0 -72
- package/clis/jianyu/shared/procurement-detail.test.js +0 -84
- package/clis/jike/read.test.js +0 -86
- package/clis/jira/commands.test.js +0 -287
- package/clis/juejin/search.js +0 -123
- package/clis/juejin/search.test.js +0 -98
- package/clis/lesswrong/frontpage.test.js +0 -37
- package/clis/lichess/lichess.test.js +0 -85
- package/clis/linkedin/connect.test.js +0 -213
- package/clis/linkedin/inbox.test.js +0 -152
- package/clis/linkedin/job-detail.test.js +0 -38
- package/clis/linkedin/jobs-preferences.test.js +0 -43
- package/clis/linkedin/people-search.test.js +0 -216
- package/clis/linkedin/post-analytics.test.js +0 -40
- package/clis/linkedin/posts.test.js +0 -40
- package/clis/linkedin/profile-analytics.test.js +0 -67
- package/clis/linkedin/profile-experience.test.js +0 -152
- package/clis/linkedin/profile-projects.test.js +0 -111
- package/clis/linkedin/profile-read.test.js +0 -77
- package/clis/linkedin/safe-send.test.js +0 -204
- package/clis/linkedin/salesnav-inbox.test.js +0 -113
- package/clis/linkedin/salesnav-message.test.js +0 -172
- package/clis/linkedin/salesnav-search.test.js +0 -76
- package/clis/linkedin/salesnav-thread.test.js +0 -79
- package/clis/linkedin/search.test.js +0 -222
- package/clis/linkedin/sent-invitations.test.js +0 -62
- package/clis/linkedin/services-read.test.js +0 -105
- package/clis/linkedin/thread-snapshot.test.js +0 -89
- package/clis/linkedin/timeline.test.js +0 -81
- package/clis/linkedin-learning/course.test.js +0 -114
- package/clis/linkedin-learning/search.test.js +0 -144
- package/clis/linkedin-learning/trending.test.js +0 -123
- package/clis/linux-do/feed.test.js +0 -153
- package/clis/linux-do/topic-content.test.js +0 -59
- package/clis/lobsters/lobsters.test.js +0 -169
- package/clis/notebooklm/add-source.test.js +0 -97
- package/clis/notebooklm/compat.test.js +0 -16
- package/clis/notebooklm/create.test.js +0 -58
- package/clis/notebooklm/generate-audio.test.js +0 -63
- package/clis/notebooklm/generate-slides.test.js +0 -75
- package/clis/notebooklm/history.test.js +0 -58
- package/clis/notebooklm/note-list.test.js +0 -56
- package/clis/notebooklm/notes-get.test.js +0 -72
- package/clis/notebooklm/open.test.js +0 -63
- package/clis/notebooklm/rpc.test.js +0 -131
- package/clis/notebooklm/source-fulltext.test.js +0 -106
- package/clis/notebooklm/source-get.test.js +0 -84
- package/clis/notebooklm/source-guide.test.js +0 -104
- package/clis/notebooklm/summary.test.js +0 -78
- package/clis/notebooklm/utils.test.js +0 -449
- package/clis/notebooklm/write-note.test.js +0 -70
- package/clis/nuget/nuget.test.js +0 -111
- package/clis/oeis/oeis.test.js +0 -88
- package/clis/ones/task-helpers.test.js +0 -12
- package/clis/ones/worklog.test.js +0 -20
- package/clis/openfda/openfda.test.js +0 -114
- package/clis/openreview/openreview.test.js +0 -427
- package/clis/osv/osv.test.js +0 -97
- package/clis/paperreview/commands.test.js +0 -243
- package/clis/paperreview/utils.test.js +0 -49
- package/clis/pixiv/download.test.js +0 -87
- package/clis/pixiv/illusts.test.js +0 -99
- package/clis/pixiv/search.test.js +0 -83
- package/clis/powerchina/search.test.js +0 -93
- package/clis/producthunt/utils.test.js +0 -64
- package/clis/pubmed/pubmed.test.js +0 -276
- package/clis/quark/utils.test.js +0 -58
- package/clis/qwen/utils.test.js +0 -45
- package/clis/reddit/extract-media.test.js +0 -149
- package/clis/reddit/frontpage.test.js +0 -34
- package/clis/reddit/home.test.js +0 -170
- package/clis/reddit/hot.test.js +0 -32
- package/clis/reddit/popular.test.js +0 -26
- package/clis/reddit/read.test.js +0 -335
- package/clis/reddit/reply.test.js +0 -89
- package/clis/reddit/search.test.js +0 -26
- package/clis/reddit/subreddit-info.test.js +0 -163
- package/clis/reddit/subreddit.test.js +0 -31
- package/clis/reddit/subscribed.test.js +0 -168
- package/clis/reddit/whoami.test.js +0 -105
- package/clis/rednote/navigation.test.js +0 -26
- package/clis/rednote/rednote.test.js +0 -222
- package/clis/rest-countries/rest-countries.test.js +0 -83
- package/clis/reuters/reuters.test.js +0 -299
- package/clis/rfc/rfc.test.js +0 -74
- package/clis/sinafinance/stock.test.js +0 -59
- package/clis/spotify/utils.test.js +0 -67
- package/clis/stackoverflow/stackoverflow.test.js +0 -404
- package/clis/steam/steam.test.js +0 -46
- package/clis/substack/utils.test.js +0 -44
- package/clis/suno/commands.test.js +0 -188
- package/clis/suno/download.test.js +0 -151
- package/clis/suno/generate.test.js +0 -252
- package/clis/suno/utils.test.js +0 -329
- package/clis/taobao/commands.test.js +0 -41
- package/clis/tdx/hot-rank.test.js +0 -59
- package/clis/ths/hot-rank.test.js +0 -64
- package/clis/tieba/commands.test.js +0 -79
- package/clis/tieba/utils.test.js +0 -290
- package/clis/tiktok/creator-videos.test.js +0 -113
- package/clis/tiktok/refactor.test.js +0 -389
- package/clis/tiktok/write-refactor.test.js +0 -370
- package/clis/toutiao/toutiao.test.js +0 -378
- package/clis/tvmaze/tvmaze.test.js +0 -93
- package/clis/twitter/bookmark-folder.test.js +0 -395
- package/clis/twitter/bookmark-folders.test.js +0 -152
- package/clis/twitter/bookmark.test.js +0 -74
- package/clis/twitter/bookmarks.test.js +0 -205
- package/clis/twitter/delete.test.js +0 -85
- package/clis/twitter/device-follow.test.js +0 -287
- package/clis/twitter/download.test.js +0 -457
- package/clis/twitter/followers.test.js +0 -62
- package/clis/twitter/following.test.js +0 -338
- package/clis/twitter/hide-reply.test.js +0 -76
- package/clis/twitter/like.test.js +0 -73
- package/clis/twitter/likes.test.js +0 -220
- package/clis/twitter/list-add.test.js +0 -133
- package/clis/twitter/list-create.test.js +0 -169
- package/clis/twitter/list-remove.test.js +0 -110
- package/clis/twitter/list-tweets.test.js +0 -196
- package/clis/twitter/lists.test.js +0 -253
- package/clis/twitter/post.test.js +0 -258
- package/clis/twitter/profile.test.js +0 -39
- package/clis/twitter/quote.test.js +0 -194
- package/clis/twitter/reply.test.js +0 -237
- package/clis/twitter/retweet.test.js +0 -73
- package/clis/twitter/search.test.js +0 -349
- package/clis/twitter/shared.test.js +0 -794
- package/clis/twitter/thread.test.js +0 -58
- package/clis/twitter/timeline.test.js +0 -104
- package/clis/twitter/trending.test.js +0 -15
- package/clis/twitter/tweets.test.js +0 -362
- package/clis/twitter/unbookmark.test.js +0 -73
- package/clis/twitter/unlike.test.js +0 -75
- package/clis/twitter/unretweet.test.js +0 -73
- package/clis/twitter/utils.test.js +0 -169
- package/clis/uisdc/news.test.js +0 -66
- package/clis/uiverse/_shared.test.js +0 -62
- package/clis/uiverse/navigation.test.js +0 -12
- package/clis/upwork/upwork.test.js +0 -566
- package/clis/wanfang/search.test.js +0 -23
- package/clis/web/read.test.js +0 -392
- package/clis/weibo/delete.test.js +0 -94
- package/clis/weibo/envelope.test.js +0 -85
- package/clis/weibo/favorites.test.js +0 -114
- package/clis/weibo/publish.test.js +0 -192
- package/clis/weibo/user-posts.test.js +0 -92
- package/clis/weibo/utils.test.js +0 -36
- package/clis/weixin/drafts.test.js +0 -69
- package/clis/weixin/search.test.js +0 -227
- package/clis/weread/ai-outline.test.js +0 -83
- package/clis/weread/book-search.test.js +0 -242
- package/clis/weread/commands.test.js +0 -398
- package/clis/weread/private-api-regression.test.js +0 -369
- package/clis/weread/search-regression.test.js +0 -494
- package/clis/weread/utils.test.js +0 -128
- package/clis/weread-official/commands.test.js +0 -385
- package/clis/weread-official/utils.test.js +0 -242
- package/clis/wikidata/wikidata.test.js +0 -83
- package/clis/wikipedia/trending.test.js +0 -57
- package/clis/wttr/wttr.test.js +0 -84
- package/clis/xianyu/chat.test.js +0 -84
- package/clis/xianyu/im.test.js +0 -253
- package/clis/xianyu/item.test.js +0 -56
- package/clis/xianyu/publish.test.js +0 -220
- package/clis/xianyu/search.test.js +0 -17
- package/clis/xiaoe/xiaoe.test.js +0 -486
- package/clis/xiaohongshu/comments.test.js +0 -258
- package/clis/xiaohongshu/creator-note-detail.test.js +0 -451
- package/clis/xiaohongshu/creator-notes-summary.test.js +0 -94
- package/clis/xiaohongshu/creator-notes.test.js +0 -281
- package/clis/xiaohongshu/creator-stats.test.js +0 -24
- package/clis/xiaohongshu/delete-note.test.js +0 -172
- package/clis/xiaohongshu/download.test.js +0 -316
- package/clis/xiaohongshu/navigation.test.js +0 -34
- package/clis/xiaohongshu/note.test.js +0 -249
- package/clis/xiaohongshu/publish.test.js +0 -608
- package/clis/xiaohongshu/search.test.js +0 -325
- package/clis/xiaohongshu/user-helpers.test.js +0 -160
- package/clis/xiaoyuzhou/auth.test.js +0 -124
- package/clis/xiaoyuzhou/download.test.js +0 -135
- package/clis/xiaoyuzhou/podcast-episodes.test.js +0 -78
- package/clis/xiaoyuzhou/transcript.test.js +0 -195
- package/clis/xiaoyuzhou/utils.test.js +0 -39
- package/clis/xueqiu/comments.test.js +0 -696
- package/clis/xueqiu/danjuan-utils.test.js +0 -41
- package/clis/xueqiu/utils.test.js +0 -26
- package/clis/yahoo/search.test.js +0 -94
- package/clis/youdao/note.test.js +0 -99
- package/clis/youtube/channel.test.js +0 -59
- package/clis/youtube/feed.test.js +0 -131
- package/clis/youtube/transcript-group.test.js +0 -99
- package/clis/youtube/transcript.test.js +0 -296
- package/clis/youtube/utils.test.js +0 -84
- package/clis/yuanbao/ask.test.js +0 -124
- package/clis/yuanbao/new.test.js +0 -30
- package/clis/yuanbao/shared.test.js +0 -80
- package/clis/zhihu/answer-comments.test.js +0 -287
- package/clis/zhihu/answer-detail.test.js +0 -338
- package/clis/zhihu/answer.test.js +0 -54
- package/clis/zhihu/collection.test.js +0 -337
- package/clis/zhihu/collections.test.js +0 -182
- package/clis/zhihu/comment.test.js +0 -50
- package/clis/zhihu/download.test.js +0 -12
- package/clis/zhihu/favorite.test.js +0 -59
- package/clis/zhihu/follow.test.js +0 -42
- package/clis/zhihu/like.test.js +0 -41
- package/clis/zhihu/question.test.js +0 -251
- package/clis/zhihu/recommend.test.js +0 -143
- package/clis/zhihu/search.test.js +0 -198
- package/clis/zhihu/target.test.js +0 -77
- package/clis/zhihu/text.test.js +0 -24
- package/clis/zhihu/write-shared.test.js +0 -176
- package/clis/zlibrary/commands.test.js +0 -65
- package/clis/zsxq/search.test.js +0 -24
- package/clis/zsxq/topic.test.js +0 -30
- package/clis/zsxq/topics.test.js +0 -24
- package/clis/zsxq/utils.test.js +0 -31
- package/dist/src/adapter-shadow.test.js +0 -49
- package/dist/src/adapter-source.test.js +0 -29
- package/dist/src/browser/analyze.test.js +0 -166
- package/dist/src/browser/article-extract.e2e.test.js +0 -105
- package/dist/src/browser/article-extract.test.js +0 -94
- package/dist/src/browser/ax-snapshot.test.js +0 -91
- package/dist/src/browser/base-page.test.js +0 -758
- package/dist/src/browser/cdp-click-fixture.test.js +0 -87
- package/dist/src/browser/cdp.test.js +0 -79
- package/dist/src/browser/compound.test.js +0 -175
- package/dist/src/browser/daemon-client.test.js +0 -199
- package/dist/src/browser/dom-helpers.test.js +0 -106
- package/dist/src/browser/dom-snapshot.test.js +0 -313
- package/dist/src/browser/errors.test.js +0 -60
- package/dist/src/browser/extract.test.js +0 -129
- package/dist/src/browser/find.test.js +0 -180
- package/dist/src/browser/html-tree.test.js +0 -181
- package/dist/src/browser/network-cache.test.js +0 -58
- package/dist/src/browser/network-key.test.js +0 -49
- package/dist/src/browser/page.test.js +0 -378
- package/dist/src/browser/shape-filter.test.js +0 -101
- package/dist/src/browser/shape.test.js +0 -82
- package/dist/src/browser/stealth.test.js +0 -134
- package/dist/src/browser/target-errors.test.js +0 -94
- package/dist/src/browser/target-resolver.test.js +0 -118
- package/dist/src/browser/utils.test.js +0 -29
- package/dist/src/browser/verify-fixture.test.js +0 -219
- package/dist/src/browser.test.js +0 -232
- package/dist/src/build-manifest.test.js +0 -341
- package/dist/src/capabilityRouting.test.js +0 -63
- package/dist/src/cli-argv-preprocess.test.js +0 -209
- package/dist/src/cli.test.js +0 -2803
- package/dist/src/commanderAdapter.test.js +0 -352
- package/dist/src/commands/daemon.test.js +0 -219
- package/dist/src/completion.test.js +0 -24
- package/dist/src/convention-audit.test.js +0 -247
- package/dist/src/daemon.test.js +0 -60
- package/dist/src/doctor.test.js +0 -263
- package/dist/src/download/article-download.test.js +0 -235
- package/dist/src/download/index.test.js +0 -140
- package/dist/src/download/media-download.test.js +0 -112
- package/dist/src/download/progress.test.js +0 -36
- package/dist/src/electron-apps.test.js +0 -49
- package/dist/src/engine.test.js +0 -312
- package/dist/src/errors.test.js +0 -109
- package/dist/src/execution.test.js +0 -623
- package/dist/src/extension-manifest-regression.test.js +0 -12
- package/dist/src/external.test.js +0 -146
- package/dist/src/help.test.js +0 -58
- package/dist/src/hooks.test.js +0 -92
- package/dist/src/interceptor.test.js +0 -81
- package/dist/src/launcher.test.js +0 -138
- package/dist/src/node-network.test.js +0 -55
- package/dist/src/observation/artifact.test.js +0 -121
- package/dist/src/observation/manager.test.js +0 -13
- package/dist/src/observation/redaction.test.js +0 -32
- package/dist/src/observation/retention.test.js +0 -118
- package/dist/src/observation/ring-buffer.test.js +0 -22
- package/dist/src/output.test.js +0 -53
- package/dist/src/package-exports.test.js +0 -112
- package/dist/src/pipeline/executor.test.js +0 -182
- package/dist/src/pipeline/steps/download.test.js +0 -102
- package/dist/src/pipeline/steps/fetch.test.js +0 -117
- package/dist/src/pipeline/template.test.js +0 -175
- package/dist/src/pipeline/transform.test.js +0 -133
- package/dist/src/plugin-manifest.test.js +0 -179
- package/dist/src/plugin-scaffold.test.js +0 -83
- package/dist/src/plugin.test.js +0 -1324
- package/dist/src/registry.test.js +0 -209
- package/dist/src/runtime-detect.test.js +0 -39
- package/dist/src/serialization.test.js +0 -78
- package/dist/src/snapshotFormatter.test.js +0 -521
- package/dist/src/tui.test.js +0 -19
- package/dist/src/update-check.test.js +0 -116
- package/dist/src/utils.test.js +0 -155
- package/dist/src/validate.test.js +0 -90
- package/dist/src/weixin-download.test.js +0 -45
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import * as fs from 'node:fs';
|
|
3
|
-
import * as path from 'node:path';
|
|
4
|
-
import { fileURLToPath } from 'node:url';
|
|
5
|
-
import yaml from 'js-yaml';
|
|
6
|
-
const { mockExecFileSync, mockPlatform, mockSpawnSync } = vi.hoisted(() => ({
|
|
7
|
-
mockExecFileSync: vi.fn(),
|
|
8
|
-
mockPlatform: vi.fn(() => 'darwin'),
|
|
9
|
-
mockSpawnSync: vi.fn(),
|
|
10
|
-
}));
|
|
11
|
-
vi.mock('node:child_process', () => ({
|
|
12
|
-
spawnSync: mockSpawnSync,
|
|
13
|
-
execFileSync: mockExecFileSync,
|
|
14
|
-
}));
|
|
15
|
-
vi.mock('node:os', async () => {
|
|
16
|
-
const actual = await vi.importActual('node:os');
|
|
17
|
-
return {
|
|
18
|
-
...actual,
|
|
19
|
-
platform: mockPlatform,
|
|
20
|
-
};
|
|
21
|
-
});
|
|
22
|
-
import { executeExternalCli, formatExternalCliLabel, installExternalCli, parseCommand } from './external.js';
|
|
23
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
24
|
-
describe('parseCommand', () => {
|
|
25
|
-
it('splits binaries and quoted arguments without invoking a shell', () => {
|
|
26
|
-
expect(parseCommand('npm install -g "@scope/tool name"')).toEqual({
|
|
27
|
-
binary: 'npm',
|
|
28
|
-
args: ['install', '-g', '@scope/tool name'],
|
|
29
|
-
});
|
|
30
|
-
});
|
|
31
|
-
it('rejects shell operators', () => {
|
|
32
|
-
expect(() => parseCommand('brew install gh && rm -rf /')).toThrow('Install command contains unsafe shell operators');
|
|
33
|
-
});
|
|
34
|
-
it('rejects command substitution and multiline input', () => {
|
|
35
|
-
expect(() => parseCommand('brew install $(whoami)')).toThrow('Install command contains unsafe shell operators');
|
|
36
|
-
expect(() => parseCommand('brew install gh\nrm -rf /')).toThrow('Install command contains unsafe shell operators');
|
|
37
|
-
});
|
|
38
|
-
it('keeps built-in install commands compatible with the shell-free parser', () => {
|
|
39
|
-
const raw = fs.readFileSync(path.join(__dirname, 'external-clis.yaml'), 'utf8');
|
|
40
|
-
const entries = (yaml.load(raw) || []);
|
|
41
|
-
for (const entry of entries) {
|
|
42
|
-
for (const command of Object.values(entry.install ?? {})) {
|
|
43
|
-
if (command)
|
|
44
|
-
expect(() => parseCommand(command)).not.toThrow();
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
it('registers Longbridge with safe package-manager installers only', () => {
|
|
49
|
-
const raw = fs.readFileSync(path.join(__dirname, 'external-clis.yaml'), 'utf8');
|
|
50
|
-
const entries = (yaml.load(raw) || []);
|
|
51
|
-
const longbridge = entries.find((entry) => entry.name === 'longbridge');
|
|
52
|
-
expect(longbridge).toMatchObject({
|
|
53
|
-
binary: 'longbridge',
|
|
54
|
-
homepage: 'https://open.longbridge.com/zh-CN/docs/cli/',
|
|
55
|
-
install: {
|
|
56
|
-
mac: 'brew install --cask longbridge/tap/longbridge-terminal',
|
|
57
|
-
windows: 'scoop install https://open.longbridge.com/longbridge/longbridge-terminal/longbridge.json',
|
|
58
|
-
},
|
|
59
|
-
});
|
|
60
|
-
expect(longbridge?.install?.linux).toBeUndefined();
|
|
61
|
-
expect(longbridge?.install?.default).toBeUndefined();
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
describe('formatExternalCliLabel', () => {
|
|
65
|
-
it('shows the package name when the executable name differs', () => {
|
|
66
|
-
expect(formatExternalCliLabel({ name: 'wx', binary: 'wx', package: 'wx-cli' })).toBe('wx(wx-cli)');
|
|
67
|
-
});
|
|
68
|
-
it('keeps the label compact when package and name match', () => {
|
|
69
|
-
expect(formatExternalCliLabel({ name: 'docker', binary: 'docker', package: 'docker' })).toBe('docker');
|
|
70
|
-
});
|
|
71
|
-
it('renders a human-readable brand alias for ambiguous executable names', () => {
|
|
72
|
-
expect(formatExternalCliLabel({ name: 'ntn', binary: 'ntn', package: 'notion' })).toBe('ntn(notion)');
|
|
73
|
-
expect(formatExternalCliLabel({ name: 'wecom-cli', binary: 'wecom-cli', package: '企业微信' })).toBe('wecom-cli(企业微信)');
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
describe('installExternalCli', () => {
|
|
77
|
-
const cli = {
|
|
78
|
-
name: 'readwise',
|
|
79
|
-
binary: 'readwise',
|
|
80
|
-
install: {
|
|
81
|
-
default: 'npm install -g @readwiseio/readwise-cli',
|
|
82
|
-
},
|
|
83
|
-
};
|
|
84
|
-
beforeEach(() => {
|
|
85
|
-
mockExecFileSync.mockReset();
|
|
86
|
-
mockSpawnSync.mockReset();
|
|
87
|
-
mockPlatform.mockReturnValue('darwin');
|
|
88
|
-
process.exitCode = undefined;
|
|
89
|
-
});
|
|
90
|
-
it('retries with .cmd on Windows when the bare binary is unavailable', () => {
|
|
91
|
-
mockPlatform.mockReturnValue('win32');
|
|
92
|
-
mockExecFileSync
|
|
93
|
-
.mockImplementationOnce(() => {
|
|
94
|
-
const err = new Error('not found');
|
|
95
|
-
err.code = 'ENOENT';
|
|
96
|
-
throw err;
|
|
97
|
-
})
|
|
98
|
-
.mockReturnValueOnce(Buffer.from(''));
|
|
99
|
-
expect(installExternalCli(cli)).toBe(true);
|
|
100
|
-
expect(mockExecFileSync).toHaveBeenNthCalledWith(1, 'npm', ['install', '-g', '@readwiseio/readwise-cli'], { stdio: 'inherit' });
|
|
101
|
-
expect(mockExecFileSync).toHaveBeenNthCalledWith(2, 'npm.cmd', ['install', '-g', '@readwiseio/readwise-cli'], { stdio: 'inherit' });
|
|
102
|
-
});
|
|
103
|
-
it('does not mask non-ENOENT failures', () => {
|
|
104
|
-
mockPlatform.mockReturnValue('win32');
|
|
105
|
-
mockExecFileSync.mockImplementationOnce(() => {
|
|
106
|
-
const err = new Error('permission denied');
|
|
107
|
-
err.code = 'EACCES';
|
|
108
|
-
throw err;
|
|
109
|
-
});
|
|
110
|
-
expect(installExternalCli(cli)).toBe(false);
|
|
111
|
-
expect(mockExecFileSync).toHaveBeenCalledTimes(1);
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
describe('executeExternalCli', () => {
|
|
115
|
-
beforeEach(() => {
|
|
116
|
-
mockExecFileSync.mockReset();
|
|
117
|
-
mockSpawnSync.mockReset();
|
|
118
|
-
mockPlatform.mockReturnValue('darwin');
|
|
119
|
-
process.exitCode = undefined;
|
|
120
|
-
});
|
|
121
|
-
it('does not spawn a binary that is still unavailable after auto-install', () => {
|
|
122
|
-
const docker = {
|
|
123
|
-
name: 'docker',
|
|
124
|
-
binary: 'docker',
|
|
125
|
-
install: { mac: 'brew install --cask docker' },
|
|
126
|
-
};
|
|
127
|
-
mockExecFileSync
|
|
128
|
-
.mockImplementationOnce(() => {
|
|
129
|
-
const err = new Error('docker not found');
|
|
130
|
-
err.code = 'ENOENT';
|
|
131
|
-
throw err;
|
|
132
|
-
})
|
|
133
|
-
.mockReturnValueOnce(Buffer.from(''))
|
|
134
|
-
.mockImplementationOnce(() => {
|
|
135
|
-
const err = new Error('docker still not found');
|
|
136
|
-
err.code = 'ENOENT';
|
|
137
|
-
throw err;
|
|
138
|
-
});
|
|
139
|
-
executeExternalCli('docker', [], [docker]);
|
|
140
|
-
expect(mockExecFileSync).toHaveBeenNthCalledWith(1, 'which', ['docker'], { stdio: 'ignore' });
|
|
141
|
-
expect(mockExecFileSync).toHaveBeenNthCalledWith(2, 'brew', ['install', '--cask', 'docker'], { stdio: 'inherit' });
|
|
142
|
-
expect(mockExecFileSync).toHaveBeenNthCalledWith(3, 'which', ['docker'], { stdio: 'ignore' });
|
|
143
|
-
expect(mockSpawnSync).not.toHaveBeenCalled();
|
|
144
|
-
expect(process.exitCode).toBe(69);
|
|
145
|
-
});
|
|
146
|
-
});
|
package/dist/src/help.test.js
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { classifyAdapter, formatRootAdapterHelpText } from './help.js';
|
|
3
|
-
describe('classifyAdapter', () => {
|
|
4
|
-
it('classifies DNS-style domains as site', () => {
|
|
5
|
-
expect(classifyAdapter('www.bilibili.com')).toBe('site');
|
|
6
|
-
expect(classifyAdapter('chatgpt.com')).toBe('site');
|
|
7
|
-
expect(classifyAdapter('claude.ai')).toBe('site');
|
|
8
|
-
expect(classifyAdapter('grok.com')).toBe('site');
|
|
9
|
-
});
|
|
10
|
-
it('classifies localhost as app (Electron / osascript desktop integrations)', () => {
|
|
11
|
-
expect(classifyAdapter('localhost')).toBe('app');
|
|
12
|
-
});
|
|
13
|
-
it('classifies non-DNS domain strings as app (e.g. literal "doubao-app")', () => {
|
|
14
|
-
expect(classifyAdapter('doubao-app')).toBe('app');
|
|
15
|
-
});
|
|
16
|
-
it('defaults missing domain to site (most adapters without explicit domain are public web scrapers)', () => {
|
|
17
|
-
expect(classifyAdapter(undefined)).toBe('site');
|
|
18
|
-
});
|
|
19
|
-
});
|
|
20
|
-
describe('formatRootAdapterHelpText', () => {
|
|
21
|
-
it('renders all three sections in External / App / Site order when populated', () => {
|
|
22
|
-
const text = formatRootAdapterHelpText({
|
|
23
|
-
external: [
|
|
24
|
-
{ name: 'gh', label: 'gh' },
|
|
25
|
-
{ name: 'wx', label: 'wx(wx-cli)' },
|
|
26
|
-
],
|
|
27
|
-
apps: ['chatwise', 'codex'],
|
|
28
|
-
sites: ['bilibili'],
|
|
29
|
-
});
|
|
30
|
-
expect(text).toContain('External CLIs (2):');
|
|
31
|
-
expect(text).toContain('App adapters (2):');
|
|
32
|
-
expect(text).toContain('Site adapters (1):');
|
|
33
|
-
expect(text).toContain('wx(wx-cli)');
|
|
34
|
-
expect(text.indexOf('External CLIs')).toBeLessThan(text.indexOf('App adapters'));
|
|
35
|
-
expect(text.indexOf('App adapters')).toBeLessThan(text.indexOf('Site adapters'));
|
|
36
|
-
});
|
|
37
|
-
it('omits empty sections instead of rendering a (0) header', () => {
|
|
38
|
-
const text = formatRootAdapterHelpText({
|
|
39
|
-
external: [],
|
|
40
|
-
apps: [],
|
|
41
|
-
sites: ['bilibili'],
|
|
42
|
-
});
|
|
43
|
-
expect(text).not.toContain('External CLIs');
|
|
44
|
-
expect(text).not.toContain('App adapters');
|
|
45
|
-
expect(text).toContain('Site adapters (1):');
|
|
46
|
-
});
|
|
47
|
-
it('returns empty string when all groups are empty', () => {
|
|
48
|
-
expect(formatRootAdapterHelpText({ external: [], apps: [], sites: [] })).toBe('');
|
|
49
|
-
});
|
|
50
|
-
it('always renders the agent discovery hint when any section is populated', () => {
|
|
51
|
-
const text = formatRootAdapterHelpText({
|
|
52
|
-
external: [],
|
|
53
|
-
apps: [],
|
|
54
|
-
sites: ['bilibili'],
|
|
55
|
-
});
|
|
56
|
-
expect(text).toContain("'bycli <site> --help -f yaml'");
|
|
57
|
-
});
|
|
58
|
-
});
|
package/dist/src/hooks.test.js
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for the plugin lifecycle hooks system.
|
|
3
|
-
*/
|
|
4
|
-
import { describe, it, expect, beforeEach } from 'vitest';
|
|
5
|
-
import { onStartup, onBeforeExecute, onAfterExecute, emitHook, clearAllHooks, } from './hooks.js';
|
|
6
|
-
beforeEach(() => {
|
|
7
|
-
clearAllHooks();
|
|
8
|
-
});
|
|
9
|
-
describe('hook registration and emission', () => {
|
|
10
|
-
it('onBeforeExecute hook is called with context', async () => {
|
|
11
|
-
const calls = [];
|
|
12
|
-
onBeforeExecute((ctx) => { calls.push({ ...ctx }); });
|
|
13
|
-
await emitHook('onBeforeExecute', { command: 'test/cmd', args: { limit: 5 }, startedAt: 100 });
|
|
14
|
-
expect(calls).toHaveLength(1);
|
|
15
|
-
expect(calls[0].command).toBe('test/cmd');
|
|
16
|
-
expect(calls[0].args).toEqual({ limit: 5 });
|
|
17
|
-
expect(calls[0].startedAt).toBe(100);
|
|
18
|
-
});
|
|
19
|
-
it('onAfterExecute hook receives result', async () => {
|
|
20
|
-
const results = [];
|
|
21
|
-
onAfterExecute((_ctx, result) => { results.push(result); });
|
|
22
|
-
const mockResult = [{ title: 'item1' }, { title: 'item2' }];
|
|
23
|
-
await emitHook('onAfterExecute', { command: 'test/cmd', args: {} }, mockResult);
|
|
24
|
-
expect(results).toHaveLength(1);
|
|
25
|
-
expect(results[0]).toEqual(mockResult);
|
|
26
|
-
});
|
|
27
|
-
it('onStartup hook fires', async () => {
|
|
28
|
-
let fired = false;
|
|
29
|
-
onStartup(() => { fired = true; });
|
|
30
|
-
await emitHook('onStartup', { command: '__startup__', args: {} });
|
|
31
|
-
expect(fired).toBe(true);
|
|
32
|
-
});
|
|
33
|
-
it('multiple hooks on the same event fire in order', async () => {
|
|
34
|
-
const order = [];
|
|
35
|
-
onBeforeExecute(() => { order.push(1); });
|
|
36
|
-
onBeforeExecute(() => { order.push(2); });
|
|
37
|
-
onBeforeExecute(() => { order.push(3); });
|
|
38
|
-
await emitHook('onBeforeExecute', { command: 'test/cmd', args: {} });
|
|
39
|
-
expect(order).toEqual([1, 2, 3]);
|
|
40
|
-
});
|
|
41
|
-
it('async hooks are awaited', async () => {
|
|
42
|
-
const order = [];
|
|
43
|
-
onBeforeExecute(async () => {
|
|
44
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
45
|
-
order.push('async-done');
|
|
46
|
-
});
|
|
47
|
-
onBeforeExecute(() => { order.push('sync'); });
|
|
48
|
-
await emitHook('onBeforeExecute', { command: 'test/cmd', args: {} });
|
|
49
|
-
expect(order).toEqual(['async-done', 'sync']);
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
describe('hook error isolation', () => {
|
|
53
|
-
it('failing hook does not prevent other hooks from running', async () => {
|
|
54
|
-
const calls = [];
|
|
55
|
-
onBeforeExecute(() => { calls.push('first'); });
|
|
56
|
-
onBeforeExecute(() => { throw new Error('boom'); });
|
|
57
|
-
onBeforeExecute(() => { calls.push('third'); });
|
|
58
|
-
await emitHook('onBeforeExecute', { command: 'test/cmd', args: {} });
|
|
59
|
-
// First and third should still run despite the second throwing
|
|
60
|
-
expect(calls).toEqual(['first', 'third']);
|
|
61
|
-
});
|
|
62
|
-
it('async hook rejection does not prevent other hooks', async () => {
|
|
63
|
-
const calls = [];
|
|
64
|
-
onAfterExecute(() => { calls.push('before-reject'); });
|
|
65
|
-
onAfterExecute(async () => { throw new Error('async boom'); });
|
|
66
|
-
onAfterExecute(() => { calls.push('after-reject'); });
|
|
67
|
-
await emitHook('onAfterExecute', { command: 'test/cmd', args: {} }, null);
|
|
68
|
-
expect(calls).toEqual(['before-reject', 'after-reject']);
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
describe('no-op when no hooks registered', () => {
|
|
72
|
-
it('emitHook with no registered hooks does nothing', async () => {
|
|
73
|
-
// Should not throw
|
|
74
|
-
await emitHook('onBeforeExecute', { command: 'test/cmd', args: {} });
|
|
75
|
-
await emitHook('onAfterExecute', { command: 'test/cmd', args: {} }, []);
|
|
76
|
-
await emitHook('onStartup', { command: '__startup__', args: {} });
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
describe('clearAllHooks', () => {
|
|
80
|
-
it('removes all hooks', async () => {
|
|
81
|
-
let called = false;
|
|
82
|
-
onStartup(() => { called = true; });
|
|
83
|
-
clearAllHooks();
|
|
84
|
-
await emitHook('onStartup', { command: '__startup__', args: {} });
|
|
85
|
-
expect(called).toBe(false);
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
describe('globalThis singleton', () => {
|
|
89
|
-
it('uses globalThis.__bycli_hooks__ for shared state', () => {
|
|
90
|
-
expect(globalThis.__bycli_hooks__).toBeInstanceOf(Map);
|
|
91
|
-
});
|
|
92
|
-
});
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for interceptor.ts: JavaScript code generators for XHR/Fetch interception.
|
|
3
|
-
*/
|
|
4
|
-
import { describe, it, expect } from 'vitest';
|
|
5
|
-
import { generateInterceptorJs, generateReadInterceptedJs, generateTapInterceptorJs } from './interceptor.js';
|
|
6
|
-
describe('generateInterceptorJs', () => {
|
|
7
|
-
it('generates valid JavaScript function source', () => {
|
|
8
|
-
const js = generateInterceptorJs('"api/search"');
|
|
9
|
-
expect(js).toContain('window.fetch');
|
|
10
|
-
expect(js).toContain('XMLHttpRequest');
|
|
11
|
-
expect(js).toContain('"api/search"');
|
|
12
|
-
// Should be a function expression wrapping
|
|
13
|
-
expect(js.trim()).toMatch(/^\(\)\s*=>/);
|
|
14
|
-
});
|
|
15
|
-
it('uses default array name and patch guard', () => {
|
|
16
|
-
const js = generateInterceptorJs('"test"');
|
|
17
|
-
expect(js).toContain('__bycli_intercepted');
|
|
18
|
-
expect(js).toContain('__bycli_interceptor_patched');
|
|
19
|
-
});
|
|
20
|
-
it('uses custom array name and patch guard', () => {
|
|
21
|
-
const js = generateInterceptorJs('"test"', {
|
|
22
|
-
arrayName: '__my_data',
|
|
23
|
-
patchGuard: '__my_guard',
|
|
24
|
-
});
|
|
25
|
-
expect(js).toContain('__my_data');
|
|
26
|
-
expect(js).toContain('__my_guard');
|
|
27
|
-
expect(js).not.toContain('__bycli_intercepted');
|
|
28
|
-
});
|
|
29
|
-
it('includes fetch clone and json parsing', () => {
|
|
30
|
-
const js = generateInterceptorJs('"api"');
|
|
31
|
-
expect(js).toContain('response.clone()');
|
|
32
|
-
expect(js).toContain('clone.json()');
|
|
33
|
-
});
|
|
34
|
-
it('includes XHR open and send patching', () => {
|
|
35
|
-
const js = generateInterceptorJs('"api"');
|
|
36
|
-
expect(js).toContain('XMLHttpRequest.prototype');
|
|
37
|
-
expect(js).toContain('__origOpen');
|
|
38
|
-
expect(js).toContain('__origSend');
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
|
-
describe('generateReadInterceptedJs', () => {
|
|
42
|
-
it('generates valid JavaScript to read and clear data', () => {
|
|
43
|
-
const js = generateReadInterceptedJs();
|
|
44
|
-
expect(js).toContain('__bycli_intercepted');
|
|
45
|
-
// Should clear the array after reading
|
|
46
|
-
expect(js).toContain('= []');
|
|
47
|
-
});
|
|
48
|
-
it('uses custom array name', () => {
|
|
49
|
-
const js = generateReadInterceptedJs('__custom_arr');
|
|
50
|
-
expect(js).toContain('__custom_arr');
|
|
51
|
-
expect(js).not.toContain('__bycli_intercepted');
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
describe('generateTapInterceptorJs', () => {
|
|
55
|
-
it('returns all required fields', () => {
|
|
56
|
-
const tap = generateTapInterceptorJs('"api/data"');
|
|
57
|
-
expect(tap.setupVar).toBeDefined();
|
|
58
|
-
expect(tap.capturedVar).toBe('captured');
|
|
59
|
-
expect(tap.promiseVar).toBe('capturePromise');
|
|
60
|
-
expect(tap.resolveVar).toBe('captureResolve');
|
|
61
|
-
expect(tap.fetchPatch).toBeDefined();
|
|
62
|
-
expect(tap.xhrPatch).toBeDefined();
|
|
63
|
-
expect(tap.restorePatch).toBeDefined();
|
|
64
|
-
});
|
|
65
|
-
it('contains the capture pattern in setup', () => {
|
|
66
|
-
const tap = generateTapInterceptorJs('"my-pattern"');
|
|
67
|
-
expect(tap.setupVar).toContain('"my-pattern"');
|
|
68
|
-
});
|
|
69
|
-
it('restores original fetch and XHR in restorePatch', () => {
|
|
70
|
-
const tap = generateTapInterceptorJs('"test"');
|
|
71
|
-
expect(tap.restorePatch).toContain('origFetch');
|
|
72
|
-
expect(tap.restorePatch).toContain('origXhrOpen');
|
|
73
|
-
expect(tap.restorePatch).toContain('origXhrSend');
|
|
74
|
-
});
|
|
75
|
-
it('uses first-match capture (only first response)', () => {
|
|
76
|
-
const tap = generateTapInterceptorJs('"test"');
|
|
77
|
-
// Both fetch and xhr patches should check !captured before storing
|
|
78
|
-
expect(tap.fetchPatch).toContain('!captured');
|
|
79
|
-
expect(tap.xhrPatch).toContain('!captured');
|
|
80
|
-
});
|
|
81
|
-
});
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
-
import { detectProcess, discoverAppPath, launchDetachedApp, launchElectronApp, probeCDP, resolveExecutableCandidates } from './launcher.js';
|
|
3
|
-
function createMockChildProcess() {
|
|
4
|
-
const listeners = new Map();
|
|
5
|
-
return {
|
|
6
|
-
once: vi.fn((event, handler) => {
|
|
7
|
-
listeners.set(event, [...(listeners.get(event) ?? []), handler]);
|
|
8
|
-
}),
|
|
9
|
-
off: vi.fn((event, handler) => {
|
|
10
|
-
listeners.set(event, (listeners.get(event) ?? []).filter((listener) => listener !== handler));
|
|
11
|
-
}),
|
|
12
|
-
unref: vi.fn(),
|
|
13
|
-
emit: (event, value) => {
|
|
14
|
-
for (const listener of listeners.get(event) ?? [])
|
|
15
|
-
listener(value);
|
|
16
|
-
},
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
vi.mock('node:child_process', () => ({
|
|
20
|
-
execFileSync: vi.fn(),
|
|
21
|
-
spawn: vi.fn(),
|
|
22
|
-
}));
|
|
23
|
-
const cp = vi.mocked(await import('node:child_process'));
|
|
24
|
-
describe('probeCDP', () => {
|
|
25
|
-
it('returns false when CDP endpoint is unreachable', async () => {
|
|
26
|
-
const result = await probeCDP(59999, 500);
|
|
27
|
-
expect(result).toBe(false);
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
|
-
describe('detectProcess', () => {
|
|
31
|
-
beforeEach(() => {
|
|
32
|
-
vi.restoreAllMocks();
|
|
33
|
-
});
|
|
34
|
-
it('returns false when pgrep finds no process', () => {
|
|
35
|
-
cp.execFileSync.mockImplementation(() => {
|
|
36
|
-
const err = new Error('exit 1');
|
|
37
|
-
err.status = 1;
|
|
38
|
-
throw err;
|
|
39
|
-
});
|
|
40
|
-
const result = detectProcess('NonExistentApp');
|
|
41
|
-
expect(result).toBe(false);
|
|
42
|
-
});
|
|
43
|
-
it.skipIf(process.platform === 'win32')('returns true when pgrep finds a process', () => {
|
|
44
|
-
cp.execFileSync.mockReturnValue('12345\n');
|
|
45
|
-
const result = detectProcess('Cursor');
|
|
46
|
-
expect(result).toBe(true);
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
|
-
describe('discoverAppPath', () => {
|
|
50
|
-
beforeEach(() => {
|
|
51
|
-
vi.restoreAllMocks();
|
|
52
|
-
});
|
|
53
|
-
it.skipIf(process.platform !== 'darwin')('returns path when osascript succeeds', () => {
|
|
54
|
-
cp.execFileSync.mockReturnValue('/Applications/Cursor.app/\n');
|
|
55
|
-
const result = discoverAppPath('Cursor');
|
|
56
|
-
expect(result).toBe('/Applications/Cursor.app');
|
|
57
|
-
});
|
|
58
|
-
it.skipIf(process.platform !== 'darwin')('returns null when osascript fails', () => {
|
|
59
|
-
cp.execFileSync.mockImplementation(() => {
|
|
60
|
-
throw new Error('app not found');
|
|
61
|
-
});
|
|
62
|
-
const result = discoverAppPath('NonExistent');
|
|
63
|
-
expect(result).toBeNull();
|
|
64
|
-
});
|
|
65
|
-
it.skipIf(process.platform === 'darwin')('returns null on non-darwin platform', () => {
|
|
66
|
-
const result = discoverAppPath('Cursor');
|
|
67
|
-
expect(result).toBeNull();
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
describe('launchDetachedApp', () => {
|
|
71
|
-
beforeEach(() => {
|
|
72
|
-
vi.restoreAllMocks();
|
|
73
|
-
cp.spawn.mockReset();
|
|
74
|
-
});
|
|
75
|
-
it('unrefs the process after spawn succeeds', async () => {
|
|
76
|
-
const child = createMockChildProcess();
|
|
77
|
-
cp.spawn.mockImplementation(() => {
|
|
78
|
-
queueMicrotask(() => child.emit('spawn'));
|
|
79
|
-
return child;
|
|
80
|
-
});
|
|
81
|
-
await expect(launchDetachedApp('/Applications/Antigravity.app/Contents/MacOS/Antigravity', ['--remote-debugging-port=9234'], 'Antigravity'))
|
|
82
|
-
.resolves
|
|
83
|
-
.toBeUndefined();
|
|
84
|
-
expect(child.unref).toHaveBeenCalledTimes(1);
|
|
85
|
-
});
|
|
86
|
-
it('converts ENOENT into a controlled launch error', async () => {
|
|
87
|
-
const child = createMockChildProcess();
|
|
88
|
-
cp.spawn.mockImplementation(() => {
|
|
89
|
-
queueMicrotask(() => child.emit('error', Object.assign(new Error('missing binary'), { code: 'ENOENT' })));
|
|
90
|
-
return child;
|
|
91
|
-
});
|
|
92
|
-
await expect(launchDetachedApp('/Applications/Antigravity.app/Contents/MacOS/Antigravity', ['--remote-debugging-port=9234'], 'Antigravity'))
|
|
93
|
-
.rejects
|
|
94
|
-
.toThrow('Could not launch Antigravity');
|
|
95
|
-
expect(child.unref).not.toHaveBeenCalled();
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
describe('resolveExecutableCandidates', () => {
|
|
99
|
-
it('prefers explicit executable candidates over processName', () => {
|
|
100
|
-
const app = {
|
|
101
|
-
port: 9234,
|
|
102
|
-
processName: 'Antigravity',
|
|
103
|
-
executableNames: ['Electron', 'Antigravity'],
|
|
104
|
-
};
|
|
105
|
-
expect(resolveExecutableCandidates('/Applications/Antigravity.app', app)).toEqual([
|
|
106
|
-
'/Applications/Antigravity.app/Contents/MacOS/Electron',
|
|
107
|
-
'/Applications/Antigravity.app/Contents/MacOS/Antigravity',
|
|
108
|
-
]);
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
describe('launchElectronApp', () => {
|
|
112
|
-
beforeEach(() => {
|
|
113
|
-
vi.restoreAllMocks();
|
|
114
|
-
cp.spawn.mockReset();
|
|
115
|
-
});
|
|
116
|
-
it('falls back to the next executable candidate when the first is missing', async () => {
|
|
117
|
-
const firstChild = createMockChildProcess();
|
|
118
|
-
const secondChild = createMockChildProcess();
|
|
119
|
-
const app = {
|
|
120
|
-
port: 9234,
|
|
121
|
-
processName: 'Antigravity',
|
|
122
|
-
executableNames: ['Electron', 'Antigravity'],
|
|
123
|
-
};
|
|
124
|
-
cp.spawn
|
|
125
|
-
.mockImplementationOnce(() => {
|
|
126
|
-
queueMicrotask(() => firstChild.emit('error', Object.assign(new Error('missing binary'), { code: 'ENOENT' })));
|
|
127
|
-
return firstChild;
|
|
128
|
-
})
|
|
129
|
-
.mockImplementationOnce(() => {
|
|
130
|
-
queueMicrotask(() => secondChild.emit('spawn'));
|
|
131
|
-
return secondChild;
|
|
132
|
-
});
|
|
133
|
-
await expect(launchElectronApp('/Applications/Antigravity.app', app, ['--remote-debugging-port=9234'], 'Antigravity')).resolves.toBeUndefined();
|
|
134
|
-
expect(cp.spawn).toHaveBeenNthCalledWith(1, '/Applications/Antigravity.app/Contents/MacOS/Electron', ['--remote-debugging-port=9234'], { detached: true, stdio: 'ignore' });
|
|
135
|
-
expect(cp.spawn).toHaveBeenNthCalledWith(2, '/Applications/Antigravity.app/Contents/MacOS/Antigravity', ['--remote-debugging-port=9234'], { detached: true, stdio: 'ignore' });
|
|
136
|
-
expect(secondChild.unref).toHaveBeenCalledTimes(1);
|
|
137
|
-
});
|
|
138
|
-
});
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { decideProxy, hasProxyEnv } from './node-network.js';
|
|
3
|
-
describe('node network proxy decisions', () => {
|
|
4
|
-
it('detects common proxy env variables', () => {
|
|
5
|
-
expect(hasProxyEnv({ https_proxy: 'http://127.0.0.1:7897' })).toBe(true);
|
|
6
|
-
expect(hasProxyEnv({ HTTP_PROXY: 'http://proxy.example:8080' })).toBe(true);
|
|
7
|
-
expect(hasProxyEnv({})).toBe(false);
|
|
8
|
-
});
|
|
9
|
-
it('routes external https traffic through https_proxy', () => {
|
|
10
|
-
const decision = decideProxy(new URL('https://www.v2ex.com/api/topics/latest.json'), { https_proxy: 'http://127.0.0.1:7897' });
|
|
11
|
-
expect(decision).toEqual({
|
|
12
|
-
mode: 'proxy',
|
|
13
|
-
proxyUrl: 'http://127.0.0.1:7897',
|
|
14
|
-
});
|
|
15
|
-
});
|
|
16
|
-
it('falls back to HTTP_PROXY for https traffic when HTTPS_PROXY is absent', () => {
|
|
17
|
-
const decision = decideProxy(new URL('https://www.v2ex.com/api/topics/latest.json'), { HTTP_PROXY: 'http://127.0.0.1:7897' });
|
|
18
|
-
expect(decision).toEqual({
|
|
19
|
-
mode: 'proxy',
|
|
20
|
-
proxyUrl: 'http://127.0.0.1:7897',
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
|
-
it('bypasses proxies for loopback addresses', () => {
|
|
24
|
-
const env = { https_proxy: 'http://127.0.0.1:7897', http_proxy: 'http://127.0.0.1:7897' };
|
|
25
|
-
expect(decideProxy(new URL('http://127.0.0.1:19825/status'), env)).toEqual({ mode: 'direct' });
|
|
26
|
-
expect(decideProxy(new URL('http://localhost:19825/status'), env)).toEqual({ mode: 'direct' });
|
|
27
|
-
expect(decideProxy(new URL('http://[::1]:19825/status'), env)).toEqual({ mode: 'direct' });
|
|
28
|
-
});
|
|
29
|
-
it('honors NO_PROXY domain matches', () => {
|
|
30
|
-
const decision = decideProxy(new URL('https://api.example.com/v1/items'), {
|
|
31
|
-
https_proxy: 'http://127.0.0.1:7897',
|
|
32
|
-
no_proxy: '.example.com',
|
|
33
|
-
});
|
|
34
|
-
expect(decision).toEqual({ mode: 'direct' });
|
|
35
|
-
});
|
|
36
|
-
it('supports wildcard-style NO_PROXY subdomain entries', () => {
|
|
37
|
-
const decision = decideProxy(new URL('https://api.example.com/v1/items'), {
|
|
38
|
-
https_proxy: 'http://127.0.0.1:7897',
|
|
39
|
-
no_proxy: '*.example.com',
|
|
40
|
-
});
|
|
41
|
-
expect(decision).toEqual({ mode: 'direct' });
|
|
42
|
-
});
|
|
43
|
-
it('matches NO_PROXY entries that rely on the default URL port', () => {
|
|
44
|
-
const env = { https_proxy: 'http://127.0.0.1:7897', http_proxy: 'http://127.0.0.1:7897' };
|
|
45
|
-
expect(decideProxy(new URL('https://example.com/'), { ...env, NO_PROXY: 'example.com:443' })).toEqual({ mode: 'direct' });
|
|
46
|
-
expect(decideProxy(new URL('http://example.com/health'), { ...env, NO_PROXY: 'example.com:80' })).toEqual({ mode: 'direct' });
|
|
47
|
-
});
|
|
48
|
-
it('falls back to ALL_PROXY when protocol-specific settings are absent', () => {
|
|
49
|
-
const decision = decideProxy(new URL('http://example.net/data'), { ALL_PROXY: 'socks5://127.0.0.1:1080' });
|
|
50
|
-
expect(decision).toEqual({
|
|
51
|
-
mode: 'proxy',
|
|
52
|
-
proxyUrl: 'socks5://127.0.0.1:1080',
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
});
|