@sovovs/bycli 1.8.0 → 2.1.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/clis/twitter/search.js +3 -3
- 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 +67 -7
- package/dist/src/browser/daemon-client.d.ts +2 -0
- package/dist/src/browser/daemon-client.js +1 -1
- package/dist/src/browser/extension-capabilities.d.ts +13 -0
- package/dist/src/browser/extension-capabilities.js +22 -0
- package/dist/src/browser/extension-capabilities.test.d.ts +1 -0
- package/dist/src/browser/extension-version-metadata.test.d.ts +1 -0
- 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/page.d.ts +1 -0
- package/dist/src/browser/page.js +20 -1
- 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/build-manifest.js +4 -2
- package/dist/src/capabilityRouting.d.ts +3 -2
- package/dist/src/capabilityRouting.js +10 -2
- package/dist/src/cli.js +11 -14
- package/dist/src/commanderAdapter.js +5 -5
- package/dist/src/config-paths.d.ts +19 -0
- package/dist/src/config-paths.js +31 -0
- package/dist/src/daemon.js +256 -0
- package/dist/src/discovery.d.ts +10 -3
- package/dist/src/discovery.js +20 -10
- package/dist/src/discovery.test.d.ts +1 -0
- package/dist/src/execution.d.ts +5 -0
- package/dist/src/execution.js +272 -48
- package/dist/src/help.js +8 -8
- package/dist/src/main.js +18 -2
- package/dist/src/manifest-schema.d.ts +9 -0
- package/dist/src/manifest-schema.js +162 -0
- package/dist/src/manifest-schema.test.d.ts +1 -0
- package/dist/src/manifest-types.d.ts +1 -1
- package/dist/src/observation/redaction.js +10 -4
- 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 +96 -0
- package/dist/src/recorder/runner/verify-runner-main.js +292 -0
- package/dist/src/recorder/runner/verify-runner-main.test.d.ts +1 -0
- package/dist/src/registry-api.d.ts +1 -1
- package/dist/src/registry-api.types.test.d.ts +1 -0
- package/dist/src/registry-transaction.d.ts +42 -0
- package/dist/src/registry-transaction.js +194 -0
- package/dist/src/registry-transaction.test.d.ts +1 -0
- package/dist/src/registry.d.ts +58 -16
- package/dist/src/registry.js +131 -15
- package/dist/src/serialization.d.ts +1 -1
- package/dist/src/serialization.js +3 -3
- package/dist/src/types.d.ts +2 -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/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
package/dist/src/registry.d.ts
CHANGED
|
@@ -20,7 +20,11 @@ export interface Arg {
|
|
|
20
20
|
choices?: string[];
|
|
21
21
|
}
|
|
22
22
|
export type CommandArgs = Record<string, any>;
|
|
23
|
+
export type BrowserRequirementResolver = (args: CommandArgs) => boolean;
|
|
24
|
+
export type BrowserDeclaration = boolean | BrowserRequirementResolver;
|
|
25
|
+
export type NormalizedBrowserRequirement = boolean | 'conditional';
|
|
23
26
|
export type BrowserCommandFunc = (page: IPage, kwargs: CommandArgs, debug?: boolean) => Promise<unknown>;
|
|
27
|
+
export type ConditionalBrowserCommandFunc = (page: IPage | null, kwargs: CommandArgs, debug?: boolean) => Promise<unknown>;
|
|
24
28
|
export type NonBrowserCommandFunc = (kwargs: CommandArgs, debug?: boolean) => Promise<unknown>;
|
|
25
29
|
export type CommandAccess = 'read' | 'write';
|
|
26
30
|
export type SiteSessionMode = 'ephemeral' | 'persistent';
|
|
@@ -28,8 +32,9 @@ export type SiteSessionMode = 'ephemeral' | 'persistent';
|
|
|
28
32
|
* 所有已注册 adapter command 的共享元数据和运行选项。
|
|
29
33
|
*
|
|
30
34
|
* 这里故意不包含 `browser` 和 `func` 这类执行形态字段,因为浏览器命令和
|
|
31
|
-
*
|
|
32
|
-
* 会在 normalize
|
|
35
|
+
* 非浏览器命令、条件浏览器命令的执行签名不同。`BrowserCliCommand`、
|
|
36
|
+
* `NonBrowserCliCommand` 和 `ConditionalBrowserCliCommand` 会在 normalize 之后
|
|
37
|
+
* 扩展这个共同底座,形成最终可执行的命令类型。
|
|
33
38
|
*/
|
|
34
39
|
interface BaseCliCommand {
|
|
35
40
|
/** 站点或命名空间名称,对应命令中的 `<site>`,例如 `devto`、`brave`。 */
|
|
@@ -81,8 +86,8 @@ interface BaseCliCommand {
|
|
|
81
86
|
defaultFormat?: 'table' | 'plain' | 'json' | 'yaml' | 'yml' | 'md' | 'markdown' | 'csv';
|
|
82
87
|
}
|
|
83
88
|
export interface BrowserCliCommand extends BaseCliCommand {
|
|
84
|
-
/** Browser commands receive an IPage.
|
|
85
|
-
browser
|
|
89
|
+
/** Browser commands receive an IPage. */
|
|
90
|
+
browser: true;
|
|
86
91
|
func?: BrowserCommandFunc;
|
|
87
92
|
}
|
|
88
93
|
export interface NonBrowserCliCommand extends BaseCliCommand {
|
|
@@ -90,25 +95,50 @@ export interface NonBrowserCliCommand extends BaseCliCommand {
|
|
|
90
95
|
browser: false;
|
|
91
96
|
func?: NonBrowserCommandFunc;
|
|
92
97
|
}
|
|
93
|
-
export
|
|
98
|
+
export interface ConditionalBrowserCliCommand extends BaseCliCommand {
|
|
99
|
+
/** Browser use is resolved from the final command arguments at execution time. */
|
|
100
|
+
browser: 'conditional';
|
|
101
|
+
requiresBrowser: BrowserRequirementResolver;
|
|
102
|
+
func?: ConditionalBrowserCommandFunc;
|
|
103
|
+
}
|
|
104
|
+
export type CliCommand = BrowserCliCommand | NonBrowserCliCommand | ConditionalBrowserCliCommand;
|
|
94
105
|
/**
|
|
95
106
|
* `cli()` 注册 adapter 时使用的内部预归一化命令形态。
|
|
96
107
|
*
|
|
97
108
|
* adapter 作者传入的是 `CliOptions`,它的 TypeScript union 会保证公开调用点足够精确。
|
|
98
|
-
* registry
|
|
99
|
-
* 根据 `strategy` 推导 `browser`、`navigateBefore`
|
|
100
|
-
* `CliCommand`。
|
|
109
|
+
* registry 内部会先把这些选项复制成对应的预归一化分支,再交给
|
|
110
|
+
* `normalizeCommand()` 根据 `strategy` 推导 `browser`、`navigateBefore` 等运行时意图,
|
|
111
|
+
* 最后存成具体的 `CliCommand`。
|
|
101
112
|
*/
|
|
102
|
-
type
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
113
|
+
type RawCliCommandBase = Omit<BaseCliCommand, 'strategy'>;
|
|
114
|
+
type RawBrowserCliCommand = RawCliCommandBase & {
|
|
115
|
+
func?: BrowserCommandFunc;
|
|
116
|
+
} & ({
|
|
117
|
+
browser: true;
|
|
118
|
+
strategy?: Strategy;
|
|
119
|
+
} | {
|
|
120
|
+
browser?: true;
|
|
121
|
+
strategy?: BrowserStrategy;
|
|
122
|
+
});
|
|
123
|
+
type RawNonBrowserCliCommand = RawCliCommandBase & {
|
|
124
|
+
func?: NonBrowserCommandFunc;
|
|
125
|
+
} & ({
|
|
126
|
+
browser: false;
|
|
127
|
+
strategy?: Strategy;
|
|
128
|
+
} | {
|
|
129
|
+
browser?: false;
|
|
130
|
+
strategy: Strategy.PUBLIC | Strategy.LOCAL;
|
|
131
|
+
});
|
|
132
|
+
type RawConditionalBrowserCliCommand = RawCliCommandBase & {
|
|
133
|
+
browser: BrowserRequirementResolver;
|
|
134
|
+
strategy?: Strategy;
|
|
135
|
+
func?: ConditionalBrowserCommandFunc;
|
|
107
136
|
};
|
|
108
137
|
/** Internal extension for lazy-loaded TS modules (not exposed in public API) */
|
|
109
138
|
export type InternalCliCommand = CliCommand & {
|
|
110
139
|
_lazy?: boolean;
|
|
111
140
|
_modulePath?: string;
|
|
141
|
+
_hydrateBeforeBrowserRouting?: boolean;
|
|
112
142
|
};
|
|
113
143
|
type RequiredCliOptions = {
|
|
114
144
|
site: string;
|
|
@@ -131,13 +161,25 @@ type NonBrowserCliOptions = Partial<Omit<NonBrowserCliCommand, 'args' | 'descrip
|
|
|
131
161
|
strategy: Strategy.PUBLIC | Strategy.LOCAL;
|
|
132
162
|
browser?: false;
|
|
133
163
|
});
|
|
134
|
-
|
|
164
|
+
type ConditionalBrowserCliOptions = Partial<Omit<ConditionalBrowserCliCommand, 'args' | 'description' | 'browser' | 'requiresBrowser'>> & RequiredCliOptions & {
|
|
165
|
+
browser: BrowserRequirementResolver;
|
|
166
|
+
};
|
|
167
|
+
export type CliOptions = BrowserCliOptions | NonBrowserCliOptions | ConditionalBrowserCliOptions;
|
|
135
168
|
declare global {
|
|
136
169
|
var __bycli_registry__: Map<string, CliCommand> | undefined;
|
|
137
170
|
}
|
|
138
|
-
export declare function cli(opts:
|
|
171
|
+
export declare function cli(opts: ConditionalBrowserCliOptions): ConditionalBrowserCliCommand;
|
|
172
|
+
export declare function cli(opts: NonBrowserCliOptions): NonBrowserCliCommand;
|
|
173
|
+
export declare function cli(opts: BrowserCliOptions): BrowserCliCommand;
|
|
139
174
|
export declare function getRegistry(): Map<string, CliCommand>;
|
|
140
175
|
export declare function fullName(cmd: Pick<BaseCliCommand, 'site' | 'name'>): string;
|
|
141
176
|
export declare function strategyLabel(cmd: CliCommand): string;
|
|
142
|
-
|
|
177
|
+
/** Whether a command may use browser-backed execution for some invocation. */
|
|
178
|
+
export declare function hasBrowserCapability(cmd: CliCommand): boolean;
|
|
179
|
+
/** Stable human-readable label for the normalized browser requirement. */
|
|
180
|
+
export declare function browserRequirementLabel(cmd: CliCommand): 'yes' | 'no' | 'conditional';
|
|
181
|
+
export declare function registerCommand(cmd: RawConditionalBrowserCliCommand): void;
|
|
182
|
+
export declare function registerCommand(cmd: RawNonBrowserCliCommand): void;
|
|
183
|
+
export declare function registerCommand(cmd: RawBrowserCliCommand): void;
|
|
184
|
+
export declare function registerCommand(cmd: CliCommand): void;
|
|
143
185
|
export {};
|
package/dist/src/registry.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Core registry: Strategy enum, Arg/CliCommand interfaces, cli() registration.
|
|
3
3
|
*/
|
|
4
|
+
import { pruneRegistryMutationKey, recordRegistryMutation, registryMutationKeys, withRegistryMutationGroup, } from './registry-transaction.js';
|
|
4
5
|
export var Strategy;
|
|
5
6
|
(function (Strategy) {
|
|
6
7
|
Strategy["PUBLIC"] = "public";
|
|
@@ -9,9 +10,77 @@ export var Strategy;
|
|
|
9
10
|
Strategy["INTERCEPT"] = "intercept";
|
|
10
11
|
Strategy["UI"] = "ui";
|
|
11
12
|
})(Strategy || (Strategy = {}));
|
|
12
|
-
const
|
|
13
|
+
const TRACKED_REGISTRY_MARKER = Symbol.for('@sovovs/bycli/tracked-registry');
|
|
14
|
+
function isTrackedRegistry(registry) {
|
|
15
|
+
return registry !== undefined
|
|
16
|
+
&& registry[TRACKED_REGISTRY_MARKER] === true;
|
|
17
|
+
}
|
|
18
|
+
function instrumentRegistry(registry) {
|
|
19
|
+
if (isTrackedRegistry(registry))
|
|
20
|
+
return registry;
|
|
21
|
+
Object.defineProperties(registry, {
|
|
22
|
+
set: {
|
|
23
|
+
value(key, value) {
|
|
24
|
+
const before = { present: this.has(key), value: this.get(key) };
|
|
25
|
+
recordRegistryMutation(key, before, { present: true, value });
|
|
26
|
+
return Map.prototype.set.call(this, key, value);
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
delete: {
|
|
30
|
+
value(key) {
|
|
31
|
+
const before = { present: this.has(key), value: this.get(key) };
|
|
32
|
+
recordRegistryMutation(key, before, { present: false, value: undefined });
|
|
33
|
+
const deleted = Map.prototype.delete.call(this, key);
|
|
34
|
+
pruneRegistryMutationKey(key, this);
|
|
35
|
+
return deleted;
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
clear: {
|
|
39
|
+
value() {
|
|
40
|
+
const keys = new Set([...this.keys(), ...registryMutationKeys()]);
|
|
41
|
+
if (keys.size === 0)
|
|
42
|
+
return;
|
|
43
|
+
withRegistryMutationGroup(() => {
|
|
44
|
+
for (const key of keys) {
|
|
45
|
+
const present = this.has(key);
|
|
46
|
+
recordRegistryMutation(key, { present, value: present ? this.get(key) : undefined }, { present: false, value: undefined });
|
|
47
|
+
}
|
|
48
|
+
Map.prototype.clear.call(this);
|
|
49
|
+
for (const key of keys)
|
|
50
|
+
pruneRegistryMutationKey(key, this);
|
|
51
|
+
});
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
[TRACKED_REGISTRY_MARKER]: { value: true },
|
|
55
|
+
});
|
|
56
|
+
return registry;
|
|
57
|
+
}
|
|
58
|
+
const existingRegistry = globalThis.__bycli_registry__ ?? new Map();
|
|
59
|
+
const _registry = instrumentRegistry(existingRegistry);
|
|
60
|
+
globalThis.__bycli_registry__ = _registry;
|
|
13
61
|
export function cli(opts) {
|
|
14
|
-
const
|
|
62
|
+
const base = rawCommandBase(opts);
|
|
63
|
+
let cmd;
|
|
64
|
+
if (typeof opts.browser === 'function') {
|
|
65
|
+
cmd = { ...base, strategy: opts.strategy, browser: opts.browser, func: opts.func };
|
|
66
|
+
}
|
|
67
|
+
else if (opts.browser === false) {
|
|
68
|
+
cmd = { ...base, strategy: opts.strategy, browser: false, func: opts.func };
|
|
69
|
+
}
|
|
70
|
+
else if (opts.browser === true) {
|
|
71
|
+
cmd = { ...base, strategy: opts.strategy, browser: true, func: opts.func };
|
|
72
|
+
}
|
|
73
|
+
else if (isImplicitNonBrowserOptions(opts)) {
|
|
74
|
+
cmd = { ...base, strategy: opts.strategy, browser: opts.browser, func: opts.func };
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
cmd = { ...base, strategy: opts.strategy, browser: opts.browser, func: opts.func };
|
|
78
|
+
}
|
|
79
|
+
registerCommandInput(cmd);
|
|
80
|
+
return _registry.get(fullName(cmd));
|
|
81
|
+
}
|
|
82
|
+
function rawCommandBase(opts) {
|
|
83
|
+
return {
|
|
15
84
|
site: opts.site,
|
|
16
85
|
name: opts.name,
|
|
17
86
|
aliases: opts.aliases,
|
|
@@ -19,11 +88,8 @@ export function cli(opts) {
|
|
|
19
88
|
access: opts.access,
|
|
20
89
|
example: opts.example,
|
|
21
90
|
domain: opts.domain,
|
|
22
|
-
strategy: opts.strategy,
|
|
23
|
-
browser: opts.browser,
|
|
24
91
|
args: opts.args ?? [],
|
|
25
92
|
columns: opts.columns,
|
|
26
|
-
func: opts.func,
|
|
27
93
|
pipeline: opts.pipeline,
|
|
28
94
|
footerExtra: opts.footerExtra,
|
|
29
95
|
validateArgs: opts.validateArgs,
|
|
@@ -31,8 +97,10 @@ export function cli(opts) {
|
|
|
31
97
|
siteSession: opts.siteSession,
|
|
32
98
|
defaultFormat: opts.defaultFormat,
|
|
33
99
|
};
|
|
34
|
-
|
|
35
|
-
|
|
100
|
+
}
|
|
101
|
+
function isImplicitNonBrowserOptions(opts) {
|
|
102
|
+
return opts.browser === undefined
|
|
103
|
+
&& (opts.strategy === Strategy.PUBLIC || opts.strategy === Strategy.LOCAL);
|
|
36
104
|
}
|
|
37
105
|
export function getRegistry() {
|
|
38
106
|
return _registry;
|
|
@@ -43,6 +111,14 @@ export function fullName(cmd) {
|
|
|
43
111
|
export function strategyLabel(cmd) {
|
|
44
112
|
return cmd.strategy ?? Strategy.PUBLIC;
|
|
45
113
|
}
|
|
114
|
+
/** Whether a command may use browser-backed execution for some invocation. */
|
|
115
|
+
export function hasBrowserCapability(cmd) {
|
|
116
|
+
return cmd.browser !== false;
|
|
117
|
+
}
|
|
118
|
+
/** Stable human-readable label for the normalized browser requirement. */
|
|
119
|
+
export function browserRequirementLabel(cmd) {
|
|
120
|
+
return cmd.browser === 'conditional' ? 'conditional' : cmd.browser ? 'yes' : 'no';
|
|
121
|
+
}
|
|
46
122
|
/**
|
|
47
123
|
* Normalize a command's runtime fields. This is the single place where
|
|
48
124
|
* `strategy` is decoded into the concrete fields that the execution path
|
|
@@ -57,10 +133,8 @@ export function strategyLabel(cmd) {
|
|
|
57
133
|
* 2. Derived from strategy + domain (the defaults below)
|
|
58
134
|
*/
|
|
59
135
|
function normalizeCommand(cmd) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const strategy = cmd.strategy ?? (cmd.browser === false ? Strategy.PUBLIC : Strategy.COOKIE);
|
|
63
|
-
const browser = cmd.browser ?? (strategy !== Strategy.PUBLIC && strategy !== Strategy.LOCAL);
|
|
136
|
+
const declaredBrowser = cmd.browser;
|
|
137
|
+
const strategy = cmd.strategy ?? (declaredBrowser === false ? Strategy.PUBLIC : Strategy.COOKIE);
|
|
64
138
|
let navigateBefore = cmd.navigateBefore;
|
|
65
139
|
if (navigateBefore === undefined) {
|
|
66
140
|
if (strategy === Strategy.COOKIE && cmd.domain) {
|
|
@@ -73,9 +147,34 @@ function normalizeCommand(cmd) {
|
|
|
73
147
|
navigateBefore = true;
|
|
74
148
|
}
|
|
75
149
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
150
|
+
if (typeof cmd.browser === 'function') {
|
|
151
|
+
const normalized = {
|
|
152
|
+
...cmd,
|
|
153
|
+
strategy,
|
|
154
|
+
browser: 'conditional',
|
|
155
|
+
requiresBrowser: cmd.browser,
|
|
156
|
+
navigateBefore,
|
|
157
|
+
};
|
|
158
|
+
return normalized;
|
|
159
|
+
}
|
|
160
|
+
if (cmd.browser === false) {
|
|
161
|
+
const normalized = { ...cmd, strategy, browser: false, navigateBefore };
|
|
162
|
+
return normalized;
|
|
163
|
+
}
|
|
164
|
+
if (cmd.browser === true) {
|
|
165
|
+
const normalized = { ...cmd, strategy, browser: true, navigateBefore };
|
|
166
|
+
return normalized;
|
|
167
|
+
}
|
|
168
|
+
if (isImplicitNonBrowserCommand(cmd)) {
|
|
169
|
+
const normalized = { ...cmd, strategy, browser: false, navigateBefore };
|
|
170
|
+
return normalized;
|
|
171
|
+
}
|
|
172
|
+
const normalized = { ...cmd, strategy, browser: true, navigateBefore };
|
|
173
|
+
return normalized;
|
|
174
|
+
}
|
|
175
|
+
function isImplicitNonBrowserCommand(cmd) {
|
|
176
|
+
return cmd.browser === undefined
|
|
177
|
+
&& (cmd.strategy === Strategy.PUBLIC || cmd.strategy === Strategy.LOCAL);
|
|
79
178
|
}
|
|
80
179
|
function assertCommandAccess(cmd) {
|
|
81
180
|
if (cmd.access === 'read' || cmd.access === 'write')
|
|
@@ -92,7 +191,24 @@ function assertSiteSession(cmd) {
|
|
|
92
191
|
}
|
|
93
192
|
}
|
|
94
193
|
export function registerCommand(cmd) {
|
|
95
|
-
|
|
194
|
+
registerCommandInput(cmd);
|
|
195
|
+
}
|
|
196
|
+
function registerCommandInput(cmd) {
|
|
197
|
+
withRegistryMutationGroup(() => {
|
|
198
|
+
assertCommandAccess(cmd);
|
|
199
|
+
assertSiteSession(cmd);
|
|
200
|
+
if (cmd.browser === 'conditional') {
|
|
201
|
+
if (typeof cmd.requiresBrowser !== 'function') {
|
|
202
|
+
const key = `${cmd.site}/${cmd.name}`;
|
|
203
|
+
throw new Error(`Command ${key} requiresBrowser must be a function`);
|
|
204
|
+
}
|
|
205
|
+
insertNormalizedCommand(cmd);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
insertNormalizedCommand(normalizeCommand(cmd));
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
function insertNormalizedCommand(normalized) {
|
|
96
212
|
const canonicalKey = fullName(normalized);
|
|
97
213
|
const existing = _registry.get(canonicalKey);
|
|
98
214
|
if (existing?.aliases) {
|
|
@@ -26,7 +26,7 @@ export declare function serializeCommand(cmd: CliCommand): {
|
|
|
26
26
|
description: string;
|
|
27
27
|
access: import("./registry.js").CommandAccess;
|
|
28
28
|
strategy: string;
|
|
29
|
-
browser: boolean;
|
|
29
|
+
browser: boolean | "conditional";
|
|
30
30
|
args: SerializedArg[];
|
|
31
31
|
columns: string[];
|
|
32
32
|
domain: string | null;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Used by the `list` command, Commander --help, and build-manifest.
|
|
5
5
|
* Separated from registry.ts to keep the registry focused on types + registration.
|
|
6
6
|
*/
|
|
7
|
-
import { fullName, strategyLabel } from './registry.js';
|
|
7
|
+
import { browserRequirementLabel, fullName, strategyLabel } from './registry.js';
|
|
8
8
|
/** Stable arg schema — every field is always present (no sparse objects). */
|
|
9
9
|
export function serializeArg(a) {
|
|
10
10
|
return {
|
|
@@ -28,7 +28,7 @@ export function serializeCommand(cmd) {
|
|
|
28
28
|
description: cmd.description,
|
|
29
29
|
access: cmd.access,
|
|
30
30
|
strategy: strategyLabel(cmd),
|
|
31
|
-
browser:
|
|
31
|
+
browser: cmd.browser,
|
|
32
32
|
args: cmd.args.map(serializeArg),
|
|
33
33
|
columns: cmd.columns ?? [],
|
|
34
34
|
domain: cmd.domain ?? null,
|
|
@@ -87,7 +87,7 @@ export function formatRegistryHelpText(cmd) {
|
|
|
87
87
|
}
|
|
88
88
|
const meta = [];
|
|
89
89
|
meta.push(`Access: ${cmd.access}`);
|
|
90
|
-
meta.push(`Browser: ${cmd
|
|
90
|
+
meta.push(`Browser: ${browserRequirementLabel(cmd)}`);
|
|
91
91
|
if (cmd.domain)
|
|
92
92
|
meta.push(`Domain: ${cmd.domain}`);
|
|
93
93
|
if (cmd.defaultFormat)
|
package/dist/src/types.d.ts
CHANGED
|
@@ -207,6 +207,8 @@ export interface IPage {
|
|
|
207
207
|
* Useful for rich editors that ignore synthetic DOM value/text mutations.
|
|
208
208
|
*/
|
|
209
209
|
insertText?(text: string): Promise<void>;
|
|
210
|
+
/** Focus the browser window containing the active page for interactive login. */
|
|
211
|
+
focusWindow?(): Promise<void>;
|
|
210
212
|
closeWindow?(): Promise<void>;
|
|
211
213
|
/** Returns the current page URL, or null if unavailable. */
|
|
212
214
|
getCurrentUrl?(): Promise<string | null>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sovovs/bycli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -9,6 +9,10 @@
|
|
|
9
9
|
"node": ">=20.0.0"
|
|
10
10
|
},
|
|
11
11
|
"type": "module",
|
|
12
|
+
"workspaces": [
|
|
13
|
+
"packages/*",
|
|
14
|
+
"dashboard-be"
|
|
15
|
+
],
|
|
12
16
|
"main": "dist/src/main.js",
|
|
13
17
|
"bin": {
|
|
14
18
|
"bycli": "dist/src/main.js"
|
|
@@ -38,25 +42,24 @@
|
|
|
38
42
|
"README.md",
|
|
39
43
|
"README.zh-CN.md",
|
|
40
44
|
"LICENSE",
|
|
41
|
-
"NOTICE"
|
|
45
|
+
"NOTICE",
|
|
46
|
+
"!**/*.test.js",
|
|
47
|
+
"!**/*.e2e.test.js"
|
|
42
48
|
],
|
|
43
49
|
"scripts": {
|
|
44
50
|
"dev": "tsx src/main.ts",
|
|
45
|
-
"dev:bun": "bun src/main.ts",
|
|
46
51
|
"build": "npm run clean-dist && npm run copy-yaml && npm run build-manifest",
|
|
47
52
|
"prebuild-manifest": "tsc --build && node -e \"require('fs').chmodSync('dist/src/main.js', 0o755)\"",
|
|
48
53
|
"build-manifest": "tsx src/build-manifest.ts",
|
|
49
54
|
"clean-dist": "node scripts/clean-dist.cjs",
|
|
50
55
|
"copy-yaml": "node scripts/copy-yaml.cjs",
|
|
51
56
|
"start": "node dist/src/main.js",
|
|
52
|
-
"start:bun": "bun dist/src/main.js",
|
|
53
57
|
"preuninstall": "node -e \"fetch('http://127.0.0.1:'+(process.env.BYCLI_DAEMON_PORT||'19825')+'/shutdown',{method:'POST',headers:{'X-byCLI':'1'},signal:AbortSignal.timeout(3000)}).catch(()=>{})\" || true",
|
|
54
58
|
"postinstall": "node scripts/postinstall.js || true; node scripts/fetch-adapters.js || true",
|
|
55
59
|
"typecheck": "tsc --noEmit",
|
|
56
60
|
"prepare": "[ -d src ] && npm run build || true",
|
|
57
61
|
"prepublishOnly": "npm run build",
|
|
58
62
|
"test": "vitest run --project unit --project extension --project adapter",
|
|
59
|
-
"test:bun": "bun vitest run --project unit --project extension --project adapter",
|
|
60
63
|
"test:adapter": "vitest run --project adapter",
|
|
61
64
|
"test:all": "vitest run",
|
|
62
65
|
"test:e2e": "vitest run --project e2e",
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* M1 P0-1 semi-auto live driver (#1, extension form, full chain).
|
|
3
|
+
*
|
|
4
|
+
* Drives a REAL daemon → byCLI extension → chrome.debugger Fetch interception and
|
|
5
|
+
* asserts a 302 redirect to a forbidden target reaches it ZERO times. This is the
|
|
6
|
+
* extension-form counterpart to scripts/m1-live-spike.mjs (direct CDP).
|
|
7
|
+
*
|
|
8
|
+
* MANUAL PREREQUISITES (this script does NOT automate them):
|
|
9
|
+
* 1. Build + load the extension: (cd extension && npm run build) then load
|
|
10
|
+
* extension/ as an unpacked extension at chrome://extensions (Developer Mode).
|
|
11
|
+
* 2. Start the daemon: bycli daemon start (or run any bycli browser command
|
|
12
|
+
* once so the daemon auto-spawns and the extension connects).
|
|
13
|
+
* 3. Make sure the extension shows "connected" (bycli doctor / daemon status).
|
|
14
|
+
*
|
|
15
|
+
* Then run: node scripts/m1-daemon-navigate-drive.mjs
|
|
16
|
+
*
|
|
17
|
+
* HOW THE NO-HIT TEST IS CONSTRUCTED (and what it proves):
|
|
18
|
+
* - Navigate target = http://<sub>.localtest.me:<R>/start. localtest.me publicly
|
|
19
|
+
* resolves to 127.0.0.1, so it passes the extension's syntax-only policy (a
|
|
20
|
+
* domain, not a literal) and the browser connects to our local redirector.
|
|
21
|
+
* - The redirector 302s to http://127.0.0.1:<F>/secret — a LITERAL loopback.
|
|
22
|
+
* - The extension's armed Fetch guard re-checks that redirected main-frame request
|
|
23
|
+
* and failRequest's it before send → the forbidden server gets 0 requests.
|
|
24
|
+
* This proves before-send interception in the real extension runtime + daemon chain.
|
|
25
|
+
* It does NOT prove DNS-rebinding closure: a redirect to a DOMAIN that resolves to
|
|
26
|
+
* loopback would NOT be caught (ip-observed-only, ADR-0006) — that needs the proxy.
|
|
27
|
+
*
|
|
28
|
+
* Requires DNS resolution of *.localtest.me (needs network). If offline, add a hosts
|
|
29
|
+
* entry mapping a test host to 127.0.0.1 and pass it via PROBE_HOST.
|
|
30
|
+
*/
|
|
31
|
+
import http from 'node:http';
|
|
32
|
+
|
|
33
|
+
const DAEMON = process.env.BYCLI_DAEMON || 'http://127.0.0.1:19825';
|
|
34
|
+
const PROBE_HOST = process.env.PROBE_HOST || 'probe.localtest.me';
|
|
35
|
+
const SESSION = process.env.SESSION || 'm1-drive';
|
|
36
|
+
const log = (...a) => console.log('[m1-drive]', ...a);
|
|
37
|
+
|
|
38
|
+
let forbiddenHits = 0;
|
|
39
|
+
let redirectHits = 0;
|
|
40
|
+
|
|
41
|
+
const forbidden = http.createServer((req, res) => {
|
|
42
|
+
forbiddenHits++;
|
|
43
|
+
log(`!!! FORBIDDEN target HIT: ${req.method} ${req.url}`);
|
|
44
|
+
res.end('forbidden-body');
|
|
45
|
+
});
|
|
46
|
+
const redirector = http.createServer((req, res) => {
|
|
47
|
+
redirectHits++;
|
|
48
|
+
res.writeHead(302, { Location: `http://127.0.0.1:${forbidden.address().port}/secret` });
|
|
49
|
+
res.end();
|
|
50
|
+
});
|
|
51
|
+
const listen = (srv) => new Promise((r) => srv.listen(0, '127.0.0.1', () => r()));
|
|
52
|
+
|
|
53
|
+
async function daemonCommand(cmd) {
|
|
54
|
+
const res = await fetch(`${DAEMON}/command`, {
|
|
55
|
+
method: 'POST',
|
|
56
|
+
headers: { 'Content-Type': 'application/json', 'X-byCLI': '1' },
|
|
57
|
+
body: JSON.stringify(cmd),
|
|
58
|
+
});
|
|
59
|
+
const text = await res.text();
|
|
60
|
+
let json;
|
|
61
|
+
try { json = JSON.parse(text); } catch { json = { raw: text }; }
|
|
62
|
+
return { status: res.status, json };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function main() {
|
|
66
|
+
// 0. Daemon reachable + extension connected?
|
|
67
|
+
let status;
|
|
68
|
+
try {
|
|
69
|
+
const r = await fetch(`${DAEMON}/status`, { headers: { 'X-byCLI': '1' } });
|
|
70
|
+
status = await r.json();
|
|
71
|
+
} catch (e) {
|
|
72
|
+
log(`ERROR: daemon not reachable at ${DAEMON}. Start it first (see header comment).`);
|
|
73
|
+
process.exitCode = 1;
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
log('daemon status:', JSON.stringify(status));
|
|
77
|
+
if (status.state && status.state !== 'ready') {
|
|
78
|
+
log(`WARNING: daemon state is "${status.state}" (need "ready" with the extension connected).`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
await listen(forbidden);
|
|
82
|
+
await listen(redirector);
|
|
83
|
+
const R = redirector.address().port;
|
|
84
|
+
const F = forbidden.address().port;
|
|
85
|
+
const target = `http://${PROBE_HOST}:${R}/start`;
|
|
86
|
+
log(`forbidden=127.0.0.1:${F} redirector=127.0.0.1:${R} navigate target=${target}`);
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
// 1. Drive a guarded navigation through the daemon → extension chain.
|
|
90
|
+
const { status: httpStatus, json } = await daemonCommand({
|
|
91
|
+
id: `m1-${Date.now()}`,
|
|
92
|
+
action: 'navigate',
|
|
93
|
+
surface: 'browser',
|
|
94
|
+
session: SESSION,
|
|
95
|
+
url: target,
|
|
96
|
+
timeout: 30,
|
|
97
|
+
});
|
|
98
|
+
log(`navigate HTTP ${httpStatus}, result:`, JSON.stringify(json));
|
|
99
|
+
|
|
100
|
+
// 2. Settle for redirect + any blocked follow-up.
|
|
101
|
+
await new Promise((r) => setTimeout(r, 2000));
|
|
102
|
+
|
|
103
|
+
// A blocked redirect can surface two equally-correct ways:
|
|
104
|
+
// (a) ok:false with errorCode 'navigation_blocked_by_policy' (the redirect was
|
|
105
|
+
// blocked, so the navigation as a whole failed) — the deterministic path; or
|
|
106
|
+
// (b) ok:true with data.interception.blocked listing the forbidden URL (the page
|
|
107
|
+
// still settled, e.g. on an error/blank page, but the request was blocked).
|
|
108
|
+
const interception = json?.data?.interception;
|
|
109
|
+
const blockedList = interception?.blocked ?? [];
|
|
110
|
+
const errBlockedForbidden = json?.errorCode === 'navigation_blocked_by_policy'
|
|
111
|
+
&& typeof json?.error === 'string' && json.error.includes(`127.0.0.1:${F}`);
|
|
112
|
+
const dataBlockedForbidden = blockedList.some((u) => u.includes(`127.0.0.1:${F}`));
|
|
113
|
+
const blockedForbidden = errBlockedForbidden || dataBlockedForbidden;
|
|
114
|
+
|
|
115
|
+
log('--- RESULTS ---');
|
|
116
|
+
log(`navigate ok = ${json?.ok}`);
|
|
117
|
+
log(`errorCode = ${json?.errorCode ?? '(none)'}`);
|
|
118
|
+
log(`interception.tier = ${interception?.tier ?? '(n/a on blocked path)'}`);
|
|
119
|
+
log(`blocked (data|error) = ${JSON.stringify(blockedList)} | ${errBlockedForbidden}`);
|
|
120
|
+
log(`redirector hits = ${redirectHits} (expect >=1)`);
|
|
121
|
+
log(`forbidden hits = ${forbiddenHits} (expect 0)`);
|
|
122
|
+
|
|
123
|
+
// The security invariant: the forbidden target received 0 requests AND the
|
|
124
|
+
// redirect was actually attempted (proving the guard, not a no-op) AND we have
|
|
125
|
+
// explicit evidence the forbidden URL was blocked before send.
|
|
126
|
+
const pass = forbiddenHits === 0 && redirectHits >= 1 && blockedForbidden;
|
|
127
|
+
log(pass
|
|
128
|
+
? '✅ PASS: daemon→extension blocked the forbidden redirect before send (forbidden target got 0 requests)'
|
|
129
|
+
: '❌ FAIL: see counts above (if redirector hits=0, the browser never reached the local redirector — check *.localtest.me DNS / PROBE_HOST)');
|
|
130
|
+
process.exitCode = pass ? 0 : 1;
|
|
131
|
+
} finally {
|
|
132
|
+
// Best-effort: close the owned tab/session we created.
|
|
133
|
+
await daemonCommand({ id: `m1-close-${Date.now()}`, action: 'close-window', surface: 'browser', session: SESSION }).catch(() => {});
|
|
134
|
+
forbidden.close(); redirector.close();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
main().catch((e) => { log('ERROR', e.message); process.exitCode = 1; forbidden.close(); redirector.close(); });
|