@agentrhq/webcmd 0.1.2 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +196 -219
- package/cli-manifest.json +16205 -34869
- package/clis/_atlassian/shared.js +1 -1
- package/clis/booking/search.js +4 -4
- package/clis/chatgpt/ask.js +2 -2
- package/clis/chatgpt/utils.js +41 -42
- package/clis/chatgpt/utils.test.js +23 -23
- package/clis/chatgpt-app/ax.js +5 -5
- package/clis/chatgpt-app/ax.test.js +8 -8
- package/clis/chatgpt-app/new.js +2 -2
- package/clis/codex/sidebar.js +1 -1
- package/clis/codex/sidebar.test.js +12 -12
- package/clis/coingecko/top.js +3 -3
- package/clis/dblp/dblp.test.js +1 -1
- package/clis/discord-app/search.js +1 -1
- package/clis/discord-app/utils.js +6 -6
- package/clis/facebook/__fixtures__/notifications-page.html +6 -6
- package/clis/facebook/add-friend.js +2 -2
- package/clis/facebook/feed.js +18 -18
- package/clis/facebook/friends.js +4 -4
- package/clis/facebook/groups.js +3 -3
- package/clis/facebook/join-group.js +2 -2
- package/clis/facebook/marketplace-inbox.js +3 -3
- package/clis/facebook/marketplace-listings.js +1 -1
- package/clis/facebook/notifications.js +14 -15
- package/clis/facebook/notifications.test.js +28 -29
- package/clis/gemini/ask.test.js +12 -12
- package/clis/gemini/deep-research-result.js +2 -2
- package/clis/gemini/deep-research-result.test.js +2 -2
- package/clis/gemini/deep-research.js +2 -2
- package/clis/gemini/deep-research.test.js +1 -1
- package/clis/gemini/models.js +11 -11
- package/clis/gemini/models.test.js +1 -1
- package/clis/gemini/reply-state.test.js +89 -89
- package/clis/gemini/utils.js +41 -41
- package/clis/gemini/utils.test.js +30 -30
- package/clis/geogebra/utils.js +1 -1
- package/clis/google-scholar/search.js +3 -3
- package/clis/grok/delete.js +1 -1
- package/clis/grok/export-all.js +2 -2
- package/clis/grok/export.js +2 -2
- package/clis/grok/pin.js +3 -3
- package/clis/grok/utils.js +12 -12
- package/clis/grok/utils.test.js +2 -2
- package/clis/indeed/indeed.test.js +3 -3
- package/clis/indeed/utils.js +1 -1
- package/clis/instagram/post.js +19 -19
- package/clis/instagram/post.test.js +2 -2
- package/clis/instagram/reel.js +6 -6
- package/clis/linkedin/connect.js +3 -3
- package/clis/linkedin/people-search.js +4 -4
- package/clis/linkedin/profile-experience.js +6 -6
- package/clis/linkedin/profile-experience.test.js +10 -10
- package/clis/linkedin/profile-read.js +1 -1
- package/clis/linkedin/safe-send.js +1 -1
- package/clis/linkedin/search.js +1 -1
- package/clis/linkedin/shared.js +2 -2
- package/clis/linkedin/timeline.js +5 -5
- package/clis/manus/manus.test.js +2 -2
- package/clis/medium/feed.js +3 -3
- package/clis/medium/search.js +3 -3
- package/clis/medium/user.js +3 -3
- package/clis/notebooklm/auth.js +2 -2
- package/clis/notebooklm/note-list.test.js +4 -4
- package/clis/notebooklm/notes-get.test.js +8 -8
- package/clis/notebooklm/source-fulltext.test.js +11 -11
- package/clis/notebooklm/utils.js +28 -28
- package/clis/notebooklm/utils.test.js +10 -10
- package/clis/pixiv/search.test.js +3 -3
- package/clis/qoder/quest.js +2 -2
- package/clis/reddit/home.js +2 -2
- package/clis/reddit/hot.js +1 -1
- package/clis/reddit/read.js +2 -2
- package/clis/reddit/read.test.js +1 -1
- package/clis/reddit/reply.js +2 -2
- package/clis/reddit/whoami.js +2 -2
- package/clis/reuters/article-detail.js +1 -1
- package/clis/reuters/search.js +1 -1
- package/clis/slock/attachment-upload.test.js +1 -1
- package/clis/slock/task-convert.js +1 -1
- package/clis/substack/feed.js +3 -3
- package/clis/substack/publication.js +3 -3
- package/clis/substack/search.js +4 -4
- package/clis/tiktok/comment.js +2 -2
- package/clis/tiktok/follow.js +4 -4
- package/clis/tiktok/like.js +1 -1
- package/clis/tiktok/save.js +1 -1
- package/clis/tiktok/unfollow.js +4 -4
- package/clis/tiktok/unlike.js +1 -1
- package/clis/tiktok/unsave.js +2 -2
- package/clis/tiktok/write-refactor.test.js +5 -5
- package/clis/twitter/accept.js +3 -3
- package/clis/twitter/delete.js +14 -6
- package/clis/twitter/delete.test.js +74 -1
- package/clis/twitter/followers.js +1 -1
- package/clis/twitter/list-remove-core.js +2 -2
- package/clis/twitter/list-tweets.test.js +3 -3
- package/clis/twitter/lists.js +6 -6
- package/clis/twitter/lists.test.js +2 -2
- package/clis/twitter/reply-dm.js +1 -1
- package/clis/twitter/shared.test.js +4 -5
- package/clis/twitter/timeline.js +3 -1
- package/clis/twitter/timeline.test.js +4 -0
- package/clis/twitter/trending.js +1 -1
- package/clis/twitter/utils.js +1 -1
- package/clis/web/read.js +1 -1
- package/clis/web/read.test.js +2 -2
- package/clis/yahoo-finance/quote.js +1 -1
- package/clis/youtube/history.js +4 -4
- package/clis/youtube/transcript-group.js +1 -1
- package/clis/youtube/transcript-group.test.js +5 -5
- package/clis/youtube/transcript.js +5 -5
- package/clis/youtube/video.js +4 -4
- package/clis/youtube/video.test.js +6 -6
- package/dist/src/browser/analyze.test.js +13 -13
- package/dist/src/browser/bridge-readiness.d.ts +1 -1
- package/dist/src/browser/bridge-readiness.test.js +1 -1
- package/dist/src/browser/bridge.d.ts +1 -0
- package/dist/src/browser/bridge.js +6 -4
- package/dist/src/browser/cdp.d.ts +1 -0
- package/dist/src/browser/daemon-client.d.ts +2 -0
- package/dist/src/browser/daemon-client.js +108 -51
- package/dist/src/browser/daemon-client.test.js +135 -47
- package/dist/src/browser/daemon-transport.js +3 -19
- package/dist/src/browser/errors.js +11 -0
- package/dist/src/browser/page.d.ts +2 -1
- package/dist/src/browser/page.js +5 -1
- package/dist/src/browser/profile.d.ts +9 -0
- package/dist/src/browser/profile.js +18 -7
- package/dist/src/browser/profile.test.js +44 -0
- package/dist/src/browser/protocol.d.ts +3 -0
- package/dist/src/browser/runtime/local-cloak/actions.js +24 -10
- package/dist/src/browser/runtime/local-cloak/session-manager.d.ts +1 -0
- package/dist/src/browser/runtime/local-cloak/session-manager.js +3 -0
- package/dist/src/browser/runtime/local-cloak/session-manager.test.js +87 -0
- package/dist/src/browser.test.js +2 -2
- package/dist/src/cli-argv-preprocess.d.ts +2 -2
- package/dist/src/cli-argv-preprocess.js +2 -2
- package/dist/src/cli-argv-preprocess.test.js +35 -35
- package/dist/src/cli.js +24 -19
- package/dist/src/cli.test.js +59 -59
- package/dist/src/commanderAdapter.test.js +19 -19
- package/dist/src/commands/daemon.test.js +13 -13
- package/dist/src/constants.d.ts +2 -3
- package/dist/src/constants.js +3 -10
- package/dist/src/convention-audit.js +1 -1
- package/dist/src/daemon/server.js +28 -23
- package/dist/src/daemon/server.test.js +52 -0
- package/dist/src/daemon-utils.d.ts +1 -0
- package/dist/src/daemon-utils.js +9 -0
- package/dist/src/daemon.js +1 -5
- package/dist/src/daemon.test.js +10 -1
- package/dist/src/doctor.js +19 -1
- package/dist/src/doctor.test.js +38 -4
- package/dist/src/download/article-download.d.ts +3 -3
- package/dist/src/download/article-download.js +7 -7
- package/dist/src/download/article-download.test.js +6 -6
- package/dist/src/download/index.js +1 -1
- package/dist/src/download/index.test.js +1 -2
- package/dist/src/download/media-download.d.ts +1 -1
- package/dist/src/download/media-download.js +1 -1
- package/dist/src/electron-apps.js +0 -8
- package/dist/src/electron-apps.test.js +2 -11
- package/dist/src/errors.test.js +9 -9
- package/dist/src/execution.js +7 -3
- package/dist/src/execution.test.js +12 -0
- package/dist/src/external-clis.yaml +0 -37
- package/dist/src/external.d.ts +1 -1
- package/dist/src/external.js +19 -1
- package/dist/src/external.test.js +39 -18
- package/dist/src/generate-release-notes-cli.test.js +140 -0
- package/dist/src/help.d.ts +3 -3
- package/dist/src/help.test.js +8 -8
- package/dist/src/main.js +1 -6
- package/dist/src/manifest-types.d.ts +1 -1
- package/dist/src/node-network.test.js +5 -5
- package/dist/src/output.js +1 -1
- package/dist/src/pipeline/steps/download.test.js +3 -3
- package/dist/src/registry.test.js +2 -2
- package/dist/src/release-notes.d.ts +38 -0
- package/dist/src/release-notes.js +99 -0
- package/dist/src/release-notes.test.d.ts +1 -0
- package/dist/src/release-notes.test.js +61 -0
- package/dist/src/runtime-identity.test.js +0 -8
- package/dist/src/runtime.d.ts +2 -0
- package/dist/src/runtime.js +1 -0
- package/dist/src/serialization.test.js +7 -7
- package/dist/src/snapshotFormatter.js +3 -5
- package/dist/src/snapshotFormatter.test.d.ts +1 -1
- package/dist/src/snapshotFormatter.test.js +50 -50
- package/dist/src/tui.js +1 -1
- package/package.json +5 -2
- package/scripts/generate-release-notes.ts +234 -0
- package/scripts/postinstall.js +1 -1
- package/scripts/silent-column-drop-baseline.json +0 -498
- package/scripts/typed-error-lint-baseline.json +0 -464
- package/skills/webcmd-adapter-author/SKILL.md +216 -213
- package/skills/webcmd-adapter-author/references/adapter-template.md +206 -399
- package/skills/webcmd-adapter-author/references/api-discovery.md +111 -220
- package/skills/webcmd-adapter-author/references/coverage-matrix.md +34 -68
- package/skills/webcmd-adapter-author/references/field-conventions.md +84 -167
- package/skills/webcmd-adapter-author/references/field-decode-playbook.md +60 -146
- package/skills/webcmd-adapter-author/references/jsdom-fixture-pattern.md +111 -178
- package/skills/webcmd-adapter-author/references/output-design.md +47 -125
- package/skills/webcmd-adapter-author/references/site-memory.md +116 -166
- package/skills/webcmd-adapter-author/references/site-recon.md +74 -78
- package/skills/webcmd-adapter-author/references/strategy-selection.md +80 -124
- package/skills/webcmd-adapter-author/references/success-rate-pitfalls.md +80 -105
- package/skills/webcmd-adapter-author/references/typed-errors.md +87 -178
- package/skills/webcmd-autofix/SKILL.md +136 -143
- package/skills/webcmd-sitemap-author/SKILL.md +58 -67
- package/skills/webcmd-sitemap-author/references/sitemap-schema.md +354 -494
- package/skills/webcmd-usage/SKILL.md +106 -97
- package/clis/12306/auth.js +0 -59
- package/clis/12306/me.js +0 -73
- package/clis/12306/orders.js +0 -96
- package/clis/12306/passengers.js +0 -90
- package/clis/12306/price.js +0 -166
- package/clis/12306/stations.js +0 -66
- package/clis/12306/train.js +0 -91
- package/clis/12306/trains.js +0 -166
- package/clis/12306/utils.js +0 -272
- package/clis/12306/utils.test.js +0 -424
- package/clis/1688/assets.js +0 -205
- package/clis/1688/assets.test.js +0 -39
- package/clis/1688/auth.js +0 -46
- package/clis/1688/download.js +0 -77
- package/clis/1688/download.test.js +0 -31
- package/clis/1688/item.js +0 -188
- package/clis/1688/item.test.js +0 -67
- package/clis/1688/search.js +0 -310
- package/clis/1688/search.test.js +0 -75
- package/clis/1688/shared.js +0 -557
- package/clis/1688/shared.test.js +0 -57
- package/clis/1688/store.js +0 -227
- package/clis/1688/store.test.js +0 -62
- package/clis/1point3acres/auth.js +0 -52
- package/clis/1point3acres/digest.js +0 -35
- package/clis/1point3acres/forum.js +0 -51
- package/clis/1point3acres/forums.js +0 -44
- package/clis/1point3acres/hot.js +0 -35
- package/clis/1point3acres/latest.js +0 -35
- package/clis/1point3acres/notifications.js +0 -64
- package/clis/1point3acres/search.js +0 -71
- package/clis/1point3acres/thread.js +0 -117
- package/clis/1point3acres/user.js +0 -77
- package/clis/1point3acres/utils.js +0 -247
- package/clis/36kr/article.js +0 -66
- package/clis/36kr/article.test.js +0 -46
- package/clis/36kr/hot.js +0 -87
- package/clis/36kr/hot.test.js +0 -15
- package/clis/36kr/news.js +0 -52
- package/clis/36kr/news.test.js +0 -85
- package/clis/36kr/search.js +0 -79
- package/clis/51job/company.js +0 -126
- package/clis/51job/detail.js +0 -109
- package/clis/51job/hot.js +0 -56
- package/clis/51job/search.js +0 -80
- package/clis/51job/utils.js +0 -302
- package/clis/51job/utils.test.js +0 -69
- package/clis/aibase/news.js +0 -110
- package/clis/aibase/news.test.js +0 -59
- package/clis/autohome/__fixtures__/catalog.html +0 -11
- package/clis/autohome/__fixtures__/koubei.json +0 -116
- package/clis/autohome/autohome.test.js +0 -115
- package/clis/autohome/brand.js +0 -108
- package/clis/autohome/score.js +0 -103
- package/clis/autohome/utils.js +0 -157
- package/clis/baidu-scholar/search.js +0 -87
- package/clis/baidu-scholar/search.test.js +0 -23
- package/clis/bilibili/auth.js +0 -36
- package/clis/bilibili/comment.js +0 -107
- package/clis/bilibili/comment.test.js +0 -153
- package/clis/bilibili/comments.js +0 -136
- package/clis/bilibili/comments.test.js +0 -142
- package/clis/bilibili/download.js +0 -178
- package/clis/bilibili/download.test.js +0 -173
- package/clis/bilibili/dynamic.js +0 -34
- package/clis/bilibili/dynamic.test.js +0 -68
- package/clis/bilibili/favorite.js +0 -47
- package/clis/bilibili/feed.js +0 -220
- package/clis/bilibili/follow.js +0 -140
- package/clis/bilibili/follow.test.js +0 -203
- package/clis/bilibili/following.js +0 -44
- package/clis/bilibili/history.js +0 -45
- package/clis/bilibili/hot.js +0 -40
- package/clis/bilibili/hot.test.js +0 -17
- package/clis/bilibili/me.js +0 -13
- package/clis/bilibili/ranking.js +0 -25
- package/clis/bilibili/search.js +0 -24
- package/clis/bilibili/subtitle.js +0 -141
- package/clis/bilibili/subtitle.test.js +0 -240
- package/clis/bilibili/summary.js +0 -167
- package/clis/bilibili/summary.test.js +0 -210
- package/clis/bilibili/unfollow.js +0 -121
- package/clis/bilibili/user-videos.js +0 -39
- package/clis/bilibili/utils.js +0 -273
- package/clis/bilibili/utils.test.js +0 -97
- package/clis/bilibili/video.js +0 -155
- package/clis/bilibili/video.test.js +0 -308
- package/clis/boss/auth.js +0 -47
- package/clis/boss/batchgreet.js +0 -61
- package/clis/boss/chatlist.js +0 -116
- package/clis/boss/chatlist.test.js +0 -211
- package/clis/boss/chatmsg.js +0 -117
- package/clis/boss/chatmsg.test.js +0 -230
- package/clis/boss/detail.js +0 -63
- package/clis/boss/exchange.js +0 -46
- package/clis/boss/greet.js +0 -49
- package/clis/boss/invite.js +0 -64
- package/clis/boss/joblist.js +0 -31
- package/clis/boss/mark.js +0 -70
- package/clis/boss/recommend.js +0 -45
- package/clis/boss/resume.js +0 -150
- package/clis/boss/search.js +0 -197
- package/clis/boss/search.test.js +0 -78
- package/clis/boss/send.js +0 -44
- package/clis/boss/stats.js +0 -66
- package/clis/boss/utils.js +0 -468
- package/clis/boss/utils.test.js +0 -34
- package/clis/chaoxing/assignments.js +0 -76
- package/clis/chaoxing/auth.js +0 -54
- package/clis/chaoxing/exams.js +0 -75
- package/clis/chaoxing/utils.js +0 -223
- package/clis/chaoxing/utils.test.js +0 -45
- package/clis/cnki/search.js +0 -61
- package/clis/cnki/search.test.js +0 -18
- package/clis/ctrip/auth.js +0 -50
- package/clis/ctrip/ctrip.test.js +0 -719
- package/clis/ctrip/flight.js +0 -136
- package/clis/ctrip/hotel-search.js +0 -132
- package/clis/ctrip/hotel-suggest.js +0 -45
- package/clis/ctrip/search.js +0 -41
- package/clis/ctrip/utils.js +0 -473
- package/clis/deepseek/ask.js +0 -158
- package/clis/deepseek/ask.test.js +0 -399
- package/clis/deepseek/auth.js +0 -54
- package/clis/deepseek/detail.js +0 -46
- package/clis/deepseek/detail.test.js +0 -81
- package/clis/deepseek/history.js +0 -27
- package/clis/deepseek/new.js +0 -33
- package/clis/deepseek/read.js +0 -25
- package/clis/deepseek/send.js +0 -140
- package/clis/deepseek/send.test.js +0 -107
- package/clis/deepseek/status.js +0 -26
- package/clis/deepseek/utils.js +0 -487
- package/clis/deepseek/utils.test.js +0 -370
- package/clis/dianping/__fixtures__/search.html +0 -168
- package/clis/dianping/__fixtures__/shop.html +0 -6
- package/clis/dianping/auth.js +0 -49
- package/clis/dianping/cityResolver.js +0 -185
- package/clis/dianping/dianping.test.js +0 -578
- package/clis/dianping/search.js +0 -157
- package/clis/dianping/shop.js +0 -173
- package/clis/dianping/utils.js +0 -157
- package/clis/dongchedi/__fixtures__/search.json +0 -60
- package/clis/dongchedi/__fixtures__/series-detail.json +0 -911
- package/clis/dongchedi/__fixtures__/series-score.json +0 -1396
- package/clis/dongchedi/dongchedi.test.js +0 -191
- package/clis/dongchedi/koubei.js +0 -85
- package/clis/dongchedi/models.js +0 -91
- package/clis/dongchedi/score.js +0 -83
- package/clis/dongchedi/search.js +0 -83
- package/clis/dongchedi/series.js +0 -87
- package/clis/dongchedi/specs.js +0 -115
- package/clis/dongchedi/utils.js +0 -180
- package/clis/douban/auth.js +0 -50
- package/clis/douban/book-hot.js +0 -15
- package/clis/douban/download.js +0 -68
- package/clis/douban/download.test.js +0 -170
- package/clis/douban/marks.js +0 -116
- package/clis/douban/movie-hot.js +0 -15
- package/clis/douban/movie-hot.test.js +0 -14
- package/clis/douban/photos.js +0 -35
- package/clis/douban/reviews.js +0 -107
- package/clis/douban/search.js +0 -18
- package/clis/douban/search.test.js +0 -11
- package/clis/douban/subject.js +0 -46
- package/clis/douban/subject.test.js +0 -11
- package/clis/douban/top250.js +0 -68
- package/clis/douban/utils.js +0 -657
- package/clis/douban/utils.test.js +0 -488
- package/clis/doubao/ask.js +0 -40
- package/clis/doubao/auth.js +0 -66
- package/clis/doubao/detail.js +0 -35
- package/clis/doubao/detail.test.js +0 -42
- package/clis/doubao/history.js +0 -30
- package/clis/doubao/history.test.js +0 -37
- package/clis/doubao/meeting-summary.js +0 -41
- package/clis/doubao/meeting-transcript.js +0 -38
- package/clis/doubao/new.js +0 -22
- package/clis/doubao/read.js +0 -21
- package/clis/doubao/send.js +0 -24
- package/clis/doubao/status.js +0 -26
- package/clis/doubao/utils.js +0 -1156
- package/clis/doubao/utils.test.js +0 -396
- package/clis/doubao-app/ask.js +0 -54
- package/clis/doubao-app/dump.js +0 -25
- package/clis/doubao-app/new.js +0 -21
- package/clis/doubao-app/read.js +0 -19
- package/clis/doubao-app/screenshot.js +0 -19
- package/clis/doubao-app/send.js +0 -28
- package/clis/doubao-app/status.js +0 -17
- package/clis/doubao-app/utils.js +0 -110
- package/clis/douyin/_shared/browser-fetch.js +0 -66
- package/clis/douyin/_shared/browser-fetch.test.js +0 -64
- package/clis/douyin/_shared/creation-id.js +0 -5
- package/clis/douyin/_shared/creation-id.test.js +0 -22
- package/clis/douyin/_shared/evaluate-result.js +0 -16
- package/clis/douyin/_shared/imagex-upload.js +0 -53
- package/clis/douyin/_shared/imagex-upload.test.js +0 -87
- package/clis/douyin/_shared/public-api.js +0 -29
- package/clis/douyin/_shared/sts2.js +0 -21
- package/clis/douyin/_shared/sts2.test.js +0 -27
- package/clis/douyin/_shared/text-extra.js +0 -15
- package/clis/douyin/_shared/text-extra.test.js +0 -37
- package/clis/douyin/_shared/timing.js +0 -22
- 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.js +0 -331
- package/clis/douyin/_shared/tos-upload.test.js +0 -229
- package/clis/douyin/_shared/transcode.js +0 -45
- package/clis/douyin/_shared/transcode.test.js +0 -91
- package/clis/douyin/_shared/vod-upload.js +0 -212
- package/clis/douyin/_shared/vod-upload.test.js +0 -38
- package/clis/douyin/activities.js +0 -23
- package/clis/douyin/activities.test.js +0 -55
- package/clis/douyin/auth.js +0 -39
- package/clis/douyin/collections.js +0 -23
- package/clis/douyin/collections.test.js +0 -45
- package/clis/douyin/delete.js +0 -152
- package/clis/douyin/delete.test.js +0 -100
- package/clis/douyin/draft.js +0 -355
- package/clis/douyin/draft.test.js +0 -335
- package/clis/douyin/drafts.js +0 -24
- package/clis/douyin/drafts.test.js +0 -11
- package/clis/douyin/hashtag.js +0 -114
- package/clis/douyin/hashtag.test.js +0 -171
- package/clis/douyin/location.js +0 -25
- package/clis/douyin/location.test.js +0 -23
- package/clis/douyin/profile.js +0 -29
- package/clis/douyin/profile.test.js +0 -46
- package/clis/douyin/publish-upload-id.test.js +0 -206
- package/clis/douyin/publish.js +0 -341
- package/clis/douyin/publish.test.js +0 -38
- package/clis/douyin/search.js +0 -308
- package/clis/douyin/search.test.js +0 -307
- package/clis/douyin/stats.js +0 -28
- package/clis/douyin/stats.test.js +0 -22
- package/clis/douyin/update.js +0 -32
- package/clis/douyin/update.test.js +0 -11
- package/clis/douyin/user-videos.js +0 -82
- package/clis/douyin/user-videos.test.js +0 -151
- package/clis/douyin/videos.js +0 -52
- package/clis/douyin/videos.test.js +0 -54
- package/clis/eastmoney/_secid.js +0 -78
- package/clis/eastmoney/announcement.js +0 -53
- package/clis/eastmoney/convertible.js +0 -74
- package/clis/eastmoney/etf.js +0 -66
- package/clis/eastmoney/holders.js +0 -79
- package/clis/eastmoney/hot-rank.js +0 -51
- package/clis/eastmoney/hot-rank.test.js +0 -59
- package/clis/eastmoney/index-board.js +0 -97
- package/clis/eastmoney/kline.js +0 -88
- package/clis/eastmoney/kuaixun.js +0 -55
- package/clis/eastmoney/longhu.js +0 -68
- package/clis/eastmoney/money-flow.js +0 -79
- package/clis/eastmoney/northbound.js +0 -58
- package/clis/eastmoney/quote.js +0 -108
- package/clis/eastmoney/rank.js +0 -95
- package/clis/eastmoney/sectors.js +0 -77
- package/clis/flomo/auth.js +0 -55
- package/clis/flomo/memos.js +0 -228
- package/clis/flomo/memos.test.js +0 -144
- package/clis/gitee/auth.js +0 -41
- package/clis/gitee/index.js +0 -3
- package/clis/gitee/search.js +0 -137
- package/clis/gitee/search.test.js +0 -65
- package/clis/gitee/trending.js +0 -568
- package/clis/gitee/user.js +0 -200
- package/clis/gitee/user.test.js +0 -63
- package/clis/gov-law/commands.test.js +0 -39
- package/clis/gov-law/recent.js +0 -22
- package/clis/gov-law/search.js +0 -41
- package/clis/gov-law/shared.js +0 -51
- package/clis/gov-policy/__fixtures__/recent.html +0 -16
- package/clis/gov-policy/__fixtures__/search.html +0 -41
- package/clis/gov-policy/gov-policy.test.js +0 -224
- package/clis/gov-policy/recent.js +0 -90
- package/clis/gov-policy/search.js +0 -91
- package/clis/gov-policy/utils.js +0 -54
- package/clis/guazi/__fixtures__/detail.html +0 -7
- package/clis/guazi/__fixtures__/list.html +0 -5
- package/clis/guazi/browse.js +0 -95
- package/clis/guazi/car.js +0 -110
- package/clis/guazi/guazi.test.js +0 -126
- package/clis/guazi/utils.js +0 -133
- package/clis/huodongxing/events.js +0 -322
- package/clis/huodongxing/events.test.js +0 -296
- package/clis/hupu/__fixtures__/hot-home.html +0 -64
- package/clis/hupu/auth.js +0 -47
- package/clis/hupu/detail.js +0 -72
- package/clis/hupu/hot.js +0 -163
- package/clis/hupu/hot.test.js +0 -224
- package/clis/hupu/like.js +0 -76
- package/clis/hupu/mentions.js +0 -160
- package/clis/hupu/reply.js +0 -72
- package/clis/hupu/search.js +0 -60
- package/clis/hupu/unlike.js +0 -76
- package/clis/hupu/utils.js +0 -319
- package/clis/jd/add-cart.js +0 -72
- package/clis/jd/auth.js +0 -46
- package/clis/jd/cart.js +0 -80
- package/clis/jd/commands.test.js +0 -41
- package/clis/jd/detail.js +0 -63
- package/clis/jd/item.js +0 -730
- package/clis/jd/item.test.js +0 -354
- package/clis/jd/item.test.ts +0 -517
- package/clis/jd/reviews.js +0 -55
- package/clis/jd/search.js +0 -66
- package/clis/jianyu/auth.js +0 -62
- package/clis/jianyu/detail.js +0 -21
- package/clis/jianyu/search.js +0 -634
- package/clis/jianyu/search.test.js +0 -153
- package/clis/jianyu/shared/china-bid-search.js +0 -165
- package/clis/jianyu/shared/procurement-contract.js +0 -324
- package/clis/jianyu/shared/procurement-contract.test.js +0 -72
- package/clis/jianyu/shared/procurement-detail.js +0 -107
- package/clis/jianyu/shared/procurement-detail.test.js +0 -84
- package/clis/jike/auth.js +0 -48
- package/clis/jike/comment.js +0 -107
- package/clis/jike/create.js +0 -106
- package/clis/jike/feed.js +0 -68
- package/clis/jike/like.js +0 -61
- package/clis/jike/notifications.js +0 -169
- package/clis/jike/post.js +0 -72
- package/clis/jike/read.test.js +0 -86
- package/clis/jike/repost.js +0 -103
- package/clis/jike/search.js +0 -68
- package/clis/jike/topic.js +0 -65
- package/clis/jike/user.js +0 -65
- package/clis/jike/utils.js +0 -25
- package/clis/jimeng/auth.js +0 -46
- package/clis/jimeng/generate.js +0 -84
- package/clis/jimeng/history.js +0 -48
- package/clis/jimeng/new.js +0 -44
- package/clis/jimeng/workspaces.js +0 -42
- package/clis/juejin/hot.js +0 -37
- package/clis/juejin/juejin.test.js +0 -241
- package/clis/juejin/recommend.js +0 -61
- package/clis/juejin/utils.js +0 -199
- package/clis/ke/auth.js +0 -46
- package/clis/ke/chengjiao.js +0 -78
- package/clis/ke/ershoufang.js +0 -101
- package/clis/ke/utils.js +0 -104
- package/clis/ke/xiaoqu.js +0 -78
- package/clis/ke/zufang.js +0 -95
- package/clis/kimi/_utils.js +0 -110
- package/clis/kimi/audit-extras.js +0 -268
- package/clis/kimi/auth.js +0 -57
- package/clis/kimi/chat.js +0 -470
- package/clis/kimi/kimi.test.js +0 -187
- package/clis/kimi/storage.js +0 -169
- package/clis/kimi/ui.js +0 -314
- package/clis/kimi/usage.js +0 -144
- package/clis/linux-do/auth.js +0 -55
- package/clis/linux-do/categories.js +0 -50
- package/clis/linux-do/feed.js +0 -395
- package/clis/linux-do/feed.test.js +0 -153
- package/clis/linux-do/search.js +0 -29
- package/clis/linux-do/tags.js +0 -28
- package/clis/linux-do/topic-content.js +0 -155
- package/clis/linux-do/topic-content.test.js +0 -59
- package/clis/linux-do/topic.js +0 -53
- package/clis/linux-do/user-posts.js +0 -57
- package/clis/linux-do/user-topics.js +0 -37
- package/clis/maimai/auth.js +0 -47
- package/clis/maimai/search-talents.js +0 -192
- package/clis/maimai/search-talents.test.js +0 -29
- package/clis/mubu/doc.js +0 -41
- package/clis/mubu/docs.js +0 -44
- package/clis/mubu/notes.js +0 -245
- package/clis/mubu/recent.js +0 -28
- package/clis/mubu/search.js +0 -63
- package/clis/mubu/utils.js +0 -304
- package/clis/nowcoder/auth.js +0 -65
- package/clis/nowcoder/companies.js +0 -24
- package/clis/nowcoder/creators.js +0 -28
- package/clis/nowcoder/detail.js +0 -62
- package/clis/nowcoder/experience.js +0 -37
- package/clis/nowcoder/hot.js +0 -25
- package/clis/nowcoder/jobs.js +0 -22
- package/clis/nowcoder/notifications.js +0 -30
- package/clis/nowcoder/papers.js +0 -41
- package/clis/nowcoder/practice.js +0 -38
- package/clis/nowcoder/recommend.js +0 -31
- package/clis/nowcoder/referral.js +0 -40
- package/clis/nowcoder/salary.js +0 -41
- package/clis/nowcoder/search.js +0 -50
- package/clis/nowcoder/suggest.js +0 -34
- package/clis/nowcoder/topics.js +0 -28
- package/clis/nowcoder/trending.js +0 -26
- package/clis/ones/common.js +0 -144
- package/clis/ones/enrich-tasks.js +0 -37
- package/clis/ones/login.js +0 -81
- package/clis/ones/logout.js +0 -18
- package/clis/ones/me.js +0 -31
- package/clis/ones/my-tasks.js +0 -121
- package/clis/ones/resolve-labels.js +0 -64
- package/clis/ones/task-helpers.js +0 -212
- package/clis/ones/task-helpers.test.js +0 -12
- package/clis/ones/task.js +0 -67
- package/clis/ones/tasks.js +0 -80
- package/clis/ones/token-info.js +0 -43
- package/clis/ones/worklog.js +0 -268
- package/clis/ones/worklog.test.js +0 -20
- package/clis/powerchina/auth.js +0 -52
- package/clis/powerchina/search.js +0 -251
- package/clis/powerchina/search.test.js +0 -93
- package/clis/quark/auth.js +0 -47
- package/clis/quark/ls.js +0 -64
- package/clis/quark/mkdir.js +0 -37
- package/clis/quark/mv.js +0 -54
- package/clis/quark/rename.js +0 -27
- package/clis/quark/rm.js +0 -25
- package/clis/quark/save.js +0 -81
- package/clis/quark/share-tree.js +0 -46
- package/clis/quark/utils.js +0 -146
- package/clis/quark/utils.test.js +0 -58
- package/clis/qwen/ask.js +0 -104
- package/clis/qwen/ask.test.js +0 -36
- package/clis/qwen/auth.js +0 -56
- package/clis/qwen/detail.js +0 -62
- package/clis/qwen/history.js +0 -61
- package/clis/qwen/image.js +0 -179
- package/clis/qwen/new.js +0 -23
- package/clis/qwen/read.js +0 -41
- package/clis/qwen/send.js +0 -55
- package/clis/qwen/status.js +0 -37
- package/clis/qwen/utils.js +0 -461
- package/clis/qwen/utils.test.js +0 -128
- package/clis/rednote/auth.js +0 -52
- package/clis/rednote/comments.js +0 -85
- package/clis/rednote/download.js +0 -59
- package/clis/rednote/feed.js +0 -27
- package/clis/rednote/navigation.test.js +0 -26
- package/clis/rednote/note.js +0 -68
- package/clis/rednote/notifications.js +0 -139
- package/clis/rednote/rednote.test.js +0 -240
- package/clis/rednote/search.js +0 -107
- package/clis/rednote/user.js +0 -55
- package/clis/sinablog/article.js +0 -15
- package/clis/sinablog/hot.js +0 -15
- package/clis/sinablog/search.js +0 -52
- package/clis/sinablog/user.js +0 -16
- package/clis/sinablog/utils.js +0 -186
- package/clis/sinafinance/news.js +0 -62
- package/clis/sinafinance/rolling-news.js +0 -41
- package/clis/sinafinance/stock-rank.js +0 -66
- package/clis/sinafinance/stock.js +0 -121
- package/clis/sinafinance/stock.test.js +0 -59
- package/clis/smzdm/search.js +0 -149
- package/clis/smzdm/search.test.js +0 -114
- package/clis/taobao/add-cart.js +0 -150
- package/clis/taobao/auth.js +0 -58
- package/clis/taobao/cart.js +0 -96
- package/clis/taobao/commands.test.js +0 -41
- package/clis/taobao/detail.js +0 -71
- package/clis/taobao/reviews.js +0 -77
- package/clis/taobao/search.js +0 -97
- package/clis/tdx/hot-rank.js +0 -48
- package/clis/tdx/hot-rank.test.js +0 -59
- package/clis/ths/hot-rank.js +0 -50
- package/clis/ths/hot-rank.test.js +0 -64
- package/clis/tieba/commands.test.js +0 -79
- package/clis/tieba/hot.js +0 -48
- package/clis/tieba/posts.js +0 -86
- package/clis/tieba/read.js +0 -141
- package/clis/tieba/search.js +0 -109
- package/clis/tieba/utils.js +0 -240
- package/clis/tieba/utils.test.js +0 -290
- package/clis/toutiao/articles.js +0 -55
- package/clis/toutiao/auth.js +0 -70
- package/clis/toutiao/hot.js +0 -63
- package/clis/toutiao/toutiao.test.js +0 -378
- package/clis/toutiao/utils.js +0 -161
- package/clis/trae-cn/activity.js +0 -22
- package/clis/trae-cn/approve.js +0 -52
- package/clis/trae-cn/ask.js +0 -99
- package/clis/trae-cn/dump.js +0 -5
- package/clis/trae-cn/export.js +0 -40
- package/clis/trae-cn/model.js +0 -22
- package/clis/trae-cn/new.js +0 -63
- package/clis/trae-cn/read.js +0 -23
- package/clis/trae-cn/screenshot.js +0 -5
- package/clis/trae-cn/select-model.js +0 -25
- package/clis/trae-cn/send.js +0 -23
- package/clis/trae-cn/setup.js +0 -75
- package/clis/trae-cn/status.js +0 -27
- package/clis/trae-cn/targets.js +0 -96
- package/clis/trae-cn/trae-cn.test.js +0 -412
- package/clis/trae-cn/utils.js +0 -750
- package/clis/trae-cn/watch.js +0 -119
- package/clis/uisdc/news.js +0 -105
- package/clis/uisdc/news.test.js +0 -66
- package/clis/v2ex/auth.js +0 -44
- package/clis/v2ex/daily.js +0 -99
- package/clis/v2ex/hot.js +0 -26
- package/clis/v2ex/latest.js +0 -26
- package/clis/v2ex/me.js +0 -100
- package/clis/v2ex/member.js +0 -28
- package/clis/v2ex/node.js +0 -39
- package/clis/v2ex/nodes.js +0 -26
- package/clis/v2ex/notifications.js +0 -72
- package/clis/v2ex/replies.js +0 -27
- package/clis/v2ex/topic.js +0 -31
- package/clis/v2ex/user.js +0 -34
- package/clis/wanfang/search.js +0 -66
- package/clis/wanfang/search.test.js +0 -23
- package/clis/wechat-channels/auth.js +0 -62
- package/clis/wechat-channels/publish.js +0 -732
- package/clis/wechat-channels/publish.test.js +0 -144
- package/clis/weibo/auth.js +0 -53
- package/clis/weibo/comments.js +0 -53
- package/clis/weibo/delete.js +0 -172
- package/clis/weibo/delete.test.js +0 -94
- package/clis/weibo/envelope.test.js +0 -85
- package/clis/weibo/favorites.js +0 -170
- package/clis/weibo/favorites.test.js +0 -114
- package/clis/weibo/feed.js +0 -69
- package/clis/weibo/hot.js +0 -39
- package/clis/weibo/me.js +0 -75
- package/clis/weibo/post.js +0 -75
- package/clis/weibo/publish.js +0 -306
- package/clis/weibo/publish.test.js +0 -192
- package/clis/weibo/search.js +0 -80
- package/clis/weibo/user-posts.js +0 -234
- package/clis/weibo/user-posts.test.js +0 -92
- package/clis/weibo/user.js +0 -63
- package/clis/weibo/utils.js +0 -59
- package/clis/weibo/utils.test.js +0 -36
- package/clis/weixin/create-draft.js +0 -226
- package/clis/weixin/download.js +0 -371
- package/clis/weixin/download.test.js +0 -106
- package/clis/weixin/drafts.js +0 -66
- package/clis/weixin/drafts.test.js +0 -69
- package/clis/weixin/search.js +0 -157
- package/clis/weixin/search.test.js +0 -227
- package/clis/weread/ai-outline.js +0 -171
- package/clis/weread/ai-outline.test.js +0 -83
- package/clis/weread/auth.js +0 -59
- package/clis/weread/book-search.js +0 -438
- package/clis/weread/book-search.test.js +0 -242
- package/clis/weread/book.js +0 -233
- package/clis/weread/commands.test.js +0 -398
- package/clis/weread/highlights.js +0 -24
- package/clis/weread/notebooks.js +0 -22
- package/clis/weread/notes.js +0 -30
- package/clis/weread/private-api-regression.test.js +0 -369
- package/clis/weread/ranking.js +0 -29
- package/clis/weread/search-regression.test.js +0 -494
- package/clis/weread/search.js +0 -186
- package/clis/weread/shelf.js +0 -66
- package/clis/weread/utils.js +0 -321
- package/clis/weread/utils.test.js +0 -128
- package/clis/weread-official/book.js +0 -135
- package/clis/weread-official/commands.test.js +0 -385
- package/clis/weread-official/discover.js +0 -107
- package/clis/weread-official/list-apis.js +0 -95
- package/clis/weread-official/notes.js +0 -171
- package/clis/weread-official/readdata.js +0 -158
- package/clis/weread-official/review.js +0 -93
- package/clis/weread-official/search.js +0 -106
- package/clis/weread-official/shelf.js +0 -97
- package/clis/weread-official/utils.js +0 -293
- package/clis/weread-official/utils.test.js +0 -242
- package/clis/xianyu/auth.js +0 -68
- package/clis/xianyu/chat.js +0 -74
- package/clis/xianyu/chat.test.js +0 -84
- package/clis/xianyu/im.js +0 -322
- package/clis/xianyu/im.test.js +0 -253
- package/clis/xianyu/inbox.js +0 -96
- package/clis/xianyu/item.js +0 -153
- package/clis/xianyu/item.test.js +0 -56
- package/clis/xianyu/messages.js +0 -91
- package/clis/xianyu/publish.js +0 -485
- package/clis/xianyu/publish.test.js +0 -220
- package/clis/xianyu/reply.js +0 -82
- package/clis/xianyu/search.js +0 -262
- package/clis/xianyu/search.test.js +0 -104
- package/clis/xianyu/utils.js +0 -8
- package/clis/xiaoe/auth.js +0 -55
- package/clis/xiaoe/catalog.js +0 -227
- package/clis/xiaoe/content.js +0 -175
- package/clis/xiaoe/courses.js +0 -127
- package/clis/xiaoe/detail.js +0 -36
- package/clis/xiaoe/play-url.js +0 -121
- package/clis/xiaoe/xiaoe.test.js +0 -486
- package/clis/xiaohongshu/ask.js +0 -426
- package/clis/xiaohongshu/ask.test.js +0 -271
- package/clis/xiaohongshu/auth.js +0 -53
- package/clis/xiaohongshu/collection-helpers.js +0 -283
- package/clis/xiaohongshu/collection-helpers.test.js +0 -125
- package/clis/xiaohongshu/comments.js +0 -228
- package/clis/xiaohongshu/comments.test.js +0 -320
- package/clis/xiaohongshu/creator-note-detail.js +0 -482
- package/clis/xiaohongshu/creator-note-detail.test.js +0 -451
- package/clis/xiaohongshu/creator-notes-summary.js +0 -98
- package/clis/xiaohongshu/creator-notes-summary.test.js +0 -94
- package/clis/xiaohongshu/creator-notes.js +0 -479
- package/clis/xiaohongshu/creator-notes.test.js +0 -281
- package/clis/xiaohongshu/creator-profile.js +0 -55
- package/clis/xiaohongshu/creator-stats.js +0 -76
- package/clis/xiaohongshu/creator-stats.test.js +0 -24
- package/clis/xiaohongshu/delete-note.js +0 -260
- package/clis/xiaohongshu/delete-note.test.js +0 -172
- package/clis/xiaohongshu/download.js +0 -249
- package/clis/xiaohongshu/download.test.js +0 -339
- package/clis/xiaohongshu/draft-clear.js +0 -91
- package/clis/xiaohongshu/draft-delete.js +0 -103
- package/clis/xiaohongshu/draft-open.js +0 -43
- package/clis/xiaohongshu/draft-utils.js +0 -142
- package/clis/xiaohongshu/drafts.js +0 -28
- package/clis/xiaohongshu/drafts.test.js +0 -172
- package/clis/xiaohongshu/feed.js +0 -163
- package/clis/xiaohongshu/feed.test.js +0 -126
- package/clis/xiaohongshu/follow.js +0 -226
- package/clis/xiaohongshu/follow.test.js +0 -211
- package/clis/xiaohongshu/liked.js +0 -29
- package/clis/xiaohongshu/liked.test.js +0 -82
- package/clis/xiaohongshu/navigation.test.js +0 -38
- package/clis/xiaohongshu/note-helpers.js +0 -69
- package/clis/xiaohongshu/note.js +0 -104
- package/clis/xiaohongshu/note.test.js +0 -249
- package/clis/xiaohongshu/notifications.js +0 -46
- package/clis/xiaohongshu/publish.js +0 -1423
- package/clis/xiaohongshu/publish.test.js +0 -1141
- package/clis/xiaohongshu/saved.js +0 -29
- package/clis/xiaohongshu/saved.test.js +0 -143
- package/clis/xiaohongshu/search.js +0 -330
- package/clis/xiaohongshu/search.test.js +0 -325
- package/clis/xiaohongshu/unfollow.js +0 -285
- package/clis/xiaohongshu/user-helpers.js +0 -78
- package/clis/xiaohongshu/user-helpers.test.js +0 -160
- package/clis/xiaohongshu/user.js +0 -140
- package/clis/xiaohongshu/user.test.js +0 -141
- package/clis/xiaoyuzhou/auth.js +0 -303
- package/clis/xiaoyuzhou/auth.test.js +0 -124
- package/clis/xiaoyuzhou/download.js +0 -54
- package/clis/xiaoyuzhou/download.test.js +0 -135
- package/clis/xiaoyuzhou/episode.js +0 -34
- package/clis/xiaoyuzhou/podcast-episodes.js +0 -41
- package/clis/xiaoyuzhou/podcast-episodes.test.js +0 -78
- package/clis/xiaoyuzhou/podcast.js +0 -33
- package/clis/xiaoyuzhou/transcript.js +0 -77
- package/clis/xiaoyuzhou/transcript.test.js +0 -195
- package/clis/xiaoyuzhou/utils.js +0 -15
- package/clis/xiaoyuzhou/utils.test.js +0 -39
- package/clis/xueqiu/auth.js +0 -63
- package/clis/xueqiu/comments.js +0 -355
- package/clis/xueqiu/comments.test.js +0 -696
- package/clis/xueqiu/danjuan-utils.js +0 -126
- package/clis/xueqiu/danjuan-utils.test.js +0 -41
- package/clis/xueqiu/earnings-date.js +0 -45
- package/clis/xueqiu/feed.js +0 -39
- package/clis/xueqiu/fund-holdings.js +0 -29
- package/clis/xueqiu/fund-snapshot.js +0 -26
- package/clis/xueqiu/groups.js +0 -23
- package/clis/xueqiu/hot-stock.js +0 -32
- package/clis/xueqiu/hot.js +0 -37
- package/clis/xueqiu/kline.js +0 -44
- package/clis/xueqiu/search.js +0 -37
- package/clis/xueqiu/stock.js +0 -65
- package/clis/xueqiu/utils.js +0 -48
- package/clis/xueqiu/utils.test.js +0 -26
- package/clis/xueqiu/watchlist.js +0 -37
- package/clis/youdao/note.js +0 -258
- package/clis/youdao/note.test.js +0 -99
- package/clis/yuanbao/ask.js +0 -362
- package/clis/yuanbao/ask.test.js +0 -124
- package/clis/yuanbao/auth.js +0 -59
- package/clis/yuanbao/detail.js +0 -65
- package/clis/yuanbao/history.js +0 -51
- package/clis/yuanbao/new.js +0 -72
- package/clis/yuanbao/new.test.js +0 -30
- package/clis/yuanbao/read.js +0 -38
- package/clis/yuanbao/send.js +0 -57
- package/clis/yuanbao/shared.js +0 -341
- package/clis/yuanbao/shared.test.js +0 -80
- package/clis/yuanbao/status.js +0 -44
- package/clis/zhihu/answer-comments.js +0 -280
- package/clis/zhihu/answer-comments.test.js +0 -287
- package/clis/zhihu/answer-detail.js +0 -216
- package/clis/zhihu/answer-detail.test.js +0 -338
- package/clis/zhihu/answer.js +0 -54
- package/clis/zhihu/answer.test.js +0 -54
- package/clis/zhihu/auth.js +0 -59
- package/clis/zhihu/collection.js +0 -199
- package/clis/zhihu/collection.test.js +0 -337
- package/clis/zhihu/collections.js +0 -128
- package/clis/zhihu/collections.test.js +0 -182
- package/clis/zhihu/comment.js +0 -55
- package/clis/zhihu/comment.test.js +0 -50
- package/clis/zhihu/download.js +0 -80
- package/clis/zhihu/download.test.js +0 -12
- package/clis/zhihu/favorite.js +0 -87
- package/clis/zhihu/favorite.test.js +0 -59
- package/clis/zhihu/follow.js +0 -50
- package/clis/zhihu/follow.test.js +0 -42
- package/clis/zhihu/followers.js +0 -40
- package/clis/zhihu/followers.test.js +0 -42
- package/clis/zhihu/following.js +0 -40
- package/clis/zhihu/following.test.js +0 -44
- package/clis/zhihu/hot.js +0 -44
- package/clis/zhihu/like.js +0 -47
- package/clis/zhihu/like.test.js +0 -41
- package/clis/zhihu/paginate.js +0 -128
- package/clis/zhihu/pins.js +0 -41
- package/clis/zhihu/pins.test.js +0 -44
- package/clis/zhihu/question.js +0 -113
- package/clis/zhihu/question.test.js +0 -251
- package/clis/zhihu/recommend.js +0 -103
- package/clis/zhihu/recommend.test.js +0 -143
- package/clis/zhihu/search.js +0 -206
- package/clis/zhihu/search.test.js +0 -198
- package/clis/zhihu/target.js +0 -91
- package/clis/zhihu/target.test.js +0 -77
- package/clis/zhihu/text.js +0 -29
- package/clis/zhihu/text.test.js +0 -24
- package/clis/zhihu/user-answers.js +0 -41
- package/clis/zhihu/user-answers.test.js +0 -69
- package/clis/zhihu/user-arg.js +0 -34
- package/clis/zhihu/user-articles.js +0 -40
- package/clis/zhihu/user-articles.test.js +0 -44
- package/clis/zhihu/user.js +0 -59
- package/clis/zhihu/user.test.js +0 -73
- package/clis/zhihu/write-shared.js +0 -228
- package/clis/zhihu/write-shared.test.js +0 -176
- package/clis/zsxq/auth.js +0 -68
- package/clis/zsxq/dynamics.js +0 -48
- package/clis/zsxq/groups.js +0 -33
- package/clis/zsxq/search.js +0 -44
- package/clis/zsxq/search.test.js +0 -24
- package/clis/zsxq/topic.js +0 -50
- package/clis/zsxq/topic.test.js +0 -30
- package/clis/zsxq/topics.js +0 -26
- package/clis/zsxq/topics.test.js +0 -24
- package/clis/zsxq/utils.js +0 -233
- package/clis/zsxq/utils.test.js +0 -31
- package/dist/src/weixin-download.test.js +0 -45
- package/skills/webcmd-adapter-author/references/site-memory/bilibili.md +0 -70
- package/skills/webcmd-adapter-author/references/site-memory/eastmoney.md +0 -70
- package/skills/webcmd-adapter-author/references/site-memory/tonghuashun.md +0 -51
- package/skills/webcmd-adapter-author/references/site-memory/xueqiu.md +0 -58
- /package/{clis/douyin/_shared/types.js → dist/src/browser/profile.test.d.ts} +0 -0
- /package/dist/src/{weixin-download.test.d.ts → generate-release-notes-cli.test.d.ts} +0 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Browser session manager — auto-spawns daemon and provides IPage.
|
|
3
3
|
*/
|
|
4
4
|
import { Page } from './page.js';
|
|
5
|
-
import {
|
|
5
|
+
import { profileRouteParams, resolveProfileSelection } from './profile.js';
|
|
6
6
|
import { ensureBrowserBridgeReady } from './daemon-lifecycle.js';
|
|
7
7
|
const DAEMON_SPAWN_TIMEOUT = 10000; // 10s to wait for daemon + extension
|
|
8
8
|
/**
|
|
@@ -26,11 +26,13 @@ export class BrowserBridge {
|
|
|
26
26
|
throw new Error('Session is closed');
|
|
27
27
|
this._state = 'connecting';
|
|
28
28
|
try {
|
|
29
|
-
const
|
|
30
|
-
|
|
29
|
+
const routing = opts.contextId || opts.preferredContextId
|
|
30
|
+
? { contextId: opts.contextId, preferredContextId: opts.preferredContextId }
|
|
31
|
+
: profileRouteParams(resolveProfileSelection());
|
|
32
|
+
await this._ensureDaemon(opts.timeout, routing.contextId);
|
|
31
33
|
if (!opts.session?.trim())
|
|
32
34
|
throw new Error('Browser session is required');
|
|
33
|
-
this._page = new Page(opts.session.trim(), opts.idleTimeout, contextId, opts.windowMode, opts.surface, opts.siteSession);
|
|
35
|
+
this._page = new Page(opts.session.trim(), opts.idleTimeout, routing.contextId, opts.windowMode, opts.surface, opts.siteSession, routing.preferredContextId);
|
|
34
36
|
this._state = 'connected';
|
|
35
37
|
return this._page;
|
|
36
38
|
}
|
|
@@ -26,6 +26,7 @@ export declare class CDPBridge implements IBrowserFactory {
|
|
|
26
26
|
session?: string;
|
|
27
27
|
cdpEndpoint?: string;
|
|
28
28
|
contextId?: string;
|
|
29
|
+
preferredContextId?: string;
|
|
29
30
|
idleTimeout?: number;
|
|
30
31
|
windowMode?: 'foreground' | 'background';
|
|
31
32
|
surface?: 'browser' | 'adapter';
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { fetchDaemonStatus, getDaemonHealth, requestDaemonShutdown, type BrowserProfileStatus, type DaemonHealth, type DaemonStatus } from './daemon-transport.js';
|
|
7
7
|
import type { BrowserRuntimeCommand, BrowserRuntimeResult } from './protocol.js';
|
|
8
|
+
export declare function setDaemonCommandTimeoutSeconds(seconds: number | null): void;
|
|
8
9
|
export type DaemonCommand = BrowserRuntimeCommand;
|
|
9
10
|
export type DaemonResult = BrowserRuntimeResult;
|
|
10
11
|
export declare class BrowserCommandError extends Error {
|
|
@@ -27,6 +28,7 @@ export declare function sendCommandFull(action: DaemonCommand['action'], params?
|
|
|
27
28
|
}>;
|
|
28
29
|
export declare function bindTab(session: string, opts?: {
|
|
29
30
|
contextId?: string;
|
|
31
|
+
preferredContextId?: string;
|
|
30
32
|
page?: string;
|
|
31
33
|
index?: number;
|
|
32
34
|
}): Promise<unknown>;
|
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { sleep } from '../utils.js';
|
|
7
7
|
import { BrowserConnectError } from '../errors.js';
|
|
8
|
+
import { COMMAND_RESULT_UNKNOWN_CODE, COMMAND_RESULT_UNKNOWN_HINT } from '../daemon-utils.js';
|
|
8
9
|
import { classifyBrowserError } from './errors.js';
|
|
9
|
-
import {
|
|
10
|
+
import { profileRouteParams, resolveProfileSelection } from './profile.js';
|
|
10
11
|
import { DEFAULT_BROWSER_CONNECT_TIMEOUT } from './config.js';
|
|
11
12
|
import { ensureBrowserBridgeReady } from './daemon-lifecycle.js';
|
|
12
13
|
import { isPreDispatchError } from './bridge-readiness.js';
|
|
@@ -15,6 +16,51 @@ let _idCounter = 0;
|
|
|
15
16
|
function generateId() {
|
|
16
17
|
return `cmd_${process.pid}_${Date.now()}_${++_idCounter}`;
|
|
17
18
|
}
|
|
19
|
+
const DEFAULT_COMMAND_TIMEOUT_SECONDS = 120;
|
|
20
|
+
const RUNTIME_OP_TIMEOUT_MARGIN_MS = 15_000;
|
|
21
|
+
const HTTP_TIMEOUT_MARGIN_MS = 10_000;
|
|
22
|
+
const TRANSPORT_MAX_ATTEMPTS = 4;
|
|
23
|
+
let _userCommandTimeoutSeconds = null;
|
|
24
|
+
export function setDaemonCommandTimeoutSeconds(seconds) {
|
|
25
|
+
_userCommandTimeoutSeconds = typeof seconds === 'number' && seconds > 0 ? Math.ceil(seconds) : null;
|
|
26
|
+
}
|
|
27
|
+
function effectiveCommandTimeoutSeconds(params) {
|
|
28
|
+
const base = _userCommandTimeoutSeconds ?? DEFAULT_COMMAND_TIMEOUT_SECONDS;
|
|
29
|
+
if (typeof params.timeoutMs === 'number' && params.timeoutMs > 0) {
|
|
30
|
+
return Math.max(base, Math.ceil((params.timeoutMs + RUNTIME_OP_TIMEOUT_MARGIN_MS) / 1000));
|
|
31
|
+
}
|
|
32
|
+
return base;
|
|
33
|
+
}
|
|
34
|
+
const UNKNOWN_OUTCOME_CODES = new Set([
|
|
35
|
+
COMMAND_RESULT_UNKNOWN_CODE,
|
|
36
|
+
'command_lost',
|
|
37
|
+
'result_evicted',
|
|
38
|
+
]);
|
|
39
|
+
const PRE_CONNECT_ERROR_CODES = new Set([
|
|
40
|
+
'ECONNREFUSED',
|
|
41
|
+
'UND_ERR_CONNECT_TIMEOUT',
|
|
42
|
+
'EHOSTUNREACH',
|
|
43
|
+
'ENETUNREACH',
|
|
44
|
+
'ENOTFOUND',
|
|
45
|
+
]);
|
|
46
|
+
function isPreConnectFetchError(err) {
|
|
47
|
+
const queue = [err];
|
|
48
|
+
const seen = new Set();
|
|
49
|
+
while (queue.length) {
|
|
50
|
+
const current = queue.pop();
|
|
51
|
+
if (!current || typeof current !== 'object' || seen.has(current))
|
|
52
|
+
continue;
|
|
53
|
+
seen.add(current);
|
|
54
|
+
const { code, cause, errors } = current;
|
|
55
|
+
if (typeof code === 'string' && PRE_CONNECT_ERROR_CODES.has(code))
|
|
56
|
+
return true;
|
|
57
|
+
if (cause)
|
|
58
|
+
queue.push(cause);
|
|
59
|
+
if (Array.isArray(errors))
|
|
60
|
+
queue.push(...errors);
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
18
64
|
export class BrowserCommandError extends Error {
|
|
19
65
|
code;
|
|
20
66
|
hint;
|
|
@@ -30,58 +76,80 @@ export { fetchDaemonStatus, getDaemonHealth, requestDaemonShutdown, };
|
|
|
30
76
|
* Internal: send a command to the daemon and return the raw `DaemonResult`.
|
|
31
77
|
*
|
|
32
78
|
* Retry policy is explicit:
|
|
33
|
-
* - pre-dispatch bridge/profile errors
|
|
34
|
-
* path, then resend
|
|
35
|
-
* -
|
|
36
|
-
*
|
|
37
|
-
* - `command_result_unknown
|
|
79
|
+
* - pre-dispatch bridge/profile errors and pre-connect fetch failures run the
|
|
80
|
+
* full daemon/runtime ensure path, then resend the same command id;
|
|
81
|
+
* - executor-transient errors that happened before page code ran get one new
|
|
82
|
+
* logical attempt with a fresh id;
|
|
83
|
+
* - `command_result_unknown`, duplicate pending ids from old daemons,
|
|
84
|
+
* post-connect drops, and AbortError are never retried automatically.
|
|
38
85
|
*/
|
|
39
86
|
async function sendCommandRaw(action, params) {
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
87
|
+
const timeoutSeconds = effectiveCommandTimeoutSeconds(params);
|
|
88
|
+
const deadlineAt = Date.now() + timeoutSeconds * 1000;
|
|
89
|
+
const rawWindowMode = process.env.WEBCMD_WINDOW;
|
|
90
|
+
const envWindowMode = rawWindowMode === 'foreground' || rawWindowMode === 'background'
|
|
91
|
+
? rawWindowMode
|
|
92
|
+
: undefined;
|
|
93
|
+
const routing = params.contextId || params.preferredContextId
|
|
94
|
+
? { contextId: params.contextId, preferredContextId: params.preferredContextId }
|
|
95
|
+
: profileRouteParams(resolveProfileSelection());
|
|
96
|
+
const contextId = routing.contextId;
|
|
97
|
+
const preferredContextId = routing.preferredContextId;
|
|
98
|
+
const windowMode = params.windowMode ?? envWindowMode;
|
|
99
|
+
let id = generateId();
|
|
100
|
+
let ensureUsed = false;
|
|
101
|
+
let semanticRetryUsed = false;
|
|
102
|
+
const ensureBridge = async () => {
|
|
103
|
+
const remainingSeconds = Math.ceil((deadlineAt - Date.now()) / 1000);
|
|
104
|
+
await ensureBrowserBridgeReady({
|
|
105
|
+
timeoutSeconds: Math.max(1, Math.min(DEFAULT_BROWSER_CONNECT_TIMEOUT, remainingSeconds)),
|
|
106
|
+
contextId,
|
|
107
|
+
verbose: false,
|
|
108
|
+
});
|
|
109
|
+
};
|
|
110
|
+
for (let attempt = 1; attempt <= TRANSPORT_MAX_ATTEMPTS; attempt++) {
|
|
111
|
+
if (attempt > 1 && Date.now() >= deadlineAt) {
|
|
112
|
+
throw new BrowserCommandError('Browser command deadline exhausted across transport retries.', COMMAND_RESULT_UNKNOWN_CODE, COMMAND_RESULT_UNKNOWN_HINT);
|
|
113
|
+
}
|
|
114
|
+
const remainingMs = Math.max(1000, deadlineAt - Date.now());
|
|
115
|
+
const command = {
|
|
116
|
+
id,
|
|
117
|
+
action,
|
|
118
|
+
...params,
|
|
119
|
+
timeout: timeoutSeconds,
|
|
120
|
+
deadlineAt,
|
|
121
|
+
...(contextId && { contextId }),
|
|
122
|
+
...(preferredContextId && { preferredContextId }),
|
|
123
|
+
...(windowMode && { windowMode }),
|
|
124
|
+
};
|
|
53
125
|
try {
|
|
54
126
|
const res = await requestDaemon('/command', {
|
|
55
127
|
method: 'POST',
|
|
56
128
|
headers: { 'Content-Type': 'application/json' },
|
|
57
129
|
body: JSON.stringify(command),
|
|
58
|
-
timeout:
|
|
130
|
+
timeout: remainingMs + HTTP_TIMEOUT_MARGIN_MS,
|
|
59
131
|
});
|
|
60
132
|
const result = (await res.json());
|
|
61
133
|
if (result.ok)
|
|
62
134
|
return result;
|
|
63
|
-
if (result.errorCode
|
|
135
|
+
if (result.errorCode && UNKNOWN_OUTCOME_CODES.has(result.errorCode)) {
|
|
64
136
|
throw new BrowserCommandError(result.error ?? 'Browser command result is unknown', result.errorCode, result.errorHint);
|
|
65
137
|
}
|
|
66
|
-
if (!dispatchRecoveryUsed && isPreDispatchError(result.errorCode)) {
|
|
67
|
-
dispatchRecoveryUsed = true;
|
|
68
|
-
await ensureBrowserBridgeReady({
|
|
69
|
-
timeoutSeconds: DEFAULT_BROWSER_CONNECT_TIMEOUT,
|
|
70
|
-
contextId,
|
|
71
|
-
verbose: false,
|
|
72
|
-
});
|
|
73
|
-
continue;
|
|
74
|
-
}
|
|
75
138
|
const isDuplicateCommandId = res.status === 409
|
|
76
139
|
&& !result.errorCode
|
|
77
140
|
&& (result.error ?? '').includes('Duplicate command id');
|
|
78
|
-
if (isDuplicateCommandId
|
|
79
|
-
|
|
141
|
+
if (isDuplicateCommandId) {
|
|
142
|
+
throw new BrowserCommandError('Daemon already has this command id pending; the command may already be running.', COMMAND_RESULT_UNKNOWN_CODE, COMMAND_RESULT_UNKNOWN_HINT);
|
|
143
|
+
}
|
|
144
|
+
if (isPreDispatchError(result.errorCode) && !ensureUsed) {
|
|
145
|
+
ensureUsed = true;
|
|
146
|
+
await ensureBridge();
|
|
80
147
|
continue;
|
|
81
148
|
}
|
|
82
|
-
const advice = classifyBrowserError(new
|
|
83
|
-
if (advice.
|
|
84
|
-
|
|
149
|
+
const advice = classifyBrowserError(new BrowserCommandError(result.error ?? '', result.errorCode));
|
|
150
|
+
if (advice.kind === 'extension-transient' && !semanticRetryUsed) {
|
|
151
|
+
semanticRetryUsed = true;
|
|
152
|
+
id = generateId();
|
|
85
153
|
await sleep(advice.delayMs);
|
|
86
154
|
continue;
|
|
87
155
|
}
|
|
@@ -91,24 +159,13 @@ async function sendCommandRaw(action, params) {
|
|
|
91
159
|
if (err instanceof BrowserCommandError || err instanceof BrowserConnectError)
|
|
92
160
|
throw err;
|
|
93
161
|
if (err instanceof Error && err.name === 'AbortError') {
|
|
94
|
-
throw new BrowserCommandError('Browser command timed out client-side; the page may still have applied it.',
|
|
95
|
-
}
|
|
96
|
-
if (!dispatchRecoveryUsed && err instanceof TypeError) {
|
|
97
|
-
dispatchRecoveryUsed = true;
|
|
98
|
-
await ensureBrowserBridgeReady({
|
|
99
|
-
timeoutSeconds: DEFAULT_BROWSER_CONNECT_TIMEOUT,
|
|
100
|
-
contextId,
|
|
101
|
-
verbose: false,
|
|
102
|
-
});
|
|
103
|
-
continue;
|
|
162
|
+
throw new BrowserCommandError('Browser command timed out client-side; the page may still have applied it.', COMMAND_RESULT_UNKNOWN_CODE, COMMAND_RESULT_UNKNOWN_HINT);
|
|
104
163
|
}
|
|
105
|
-
if (err instanceof
|
|
106
|
-
|
|
107
|
-
if (
|
|
108
|
-
transientRetryUsed = true;
|
|
109
|
-
await sleep(advice.delayMs);
|
|
164
|
+
if (err instanceof TypeError) {
|
|
165
|
+
await ensureBridge();
|
|
166
|
+
if (isPreConnectFetchError(err))
|
|
110
167
|
continue;
|
|
111
|
-
|
|
168
|
+
throw new BrowserCommandError('Connection to the daemon was lost mid-command; it may have already been applied.', COMMAND_RESULT_UNKNOWN_CODE, COMMAND_RESULT_UNKNOWN_HINT);
|
|
112
169
|
}
|
|
113
170
|
throw err;
|
|
114
171
|
}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import { fetchDaemonStatus, getDaemonHealth, requestDaemonShutdown, sendCommand, } from './daemon-client.js';
|
|
2
|
+
import { fetchDaemonStatus, getDaemonHealth, requestDaemonShutdown, sendCommand, setDaemonCommandTimeoutSeconds, } from './daemon-client.js';
|
|
3
3
|
import * as daemonLifecycle from './daemon-lifecycle.js';
|
|
4
4
|
describe('daemon-client', () => {
|
|
5
5
|
beforeEach(() => {
|
|
6
6
|
vi.stubGlobal('fetch', vi.fn());
|
|
7
7
|
});
|
|
8
8
|
afterEach(() => {
|
|
9
|
+
if (typeof setDaemonCommandTimeoutSeconds === 'function') {
|
|
10
|
+
setDaemonCommandTimeoutSeconds(null);
|
|
11
|
+
}
|
|
9
12
|
vi.restoreAllMocks();
|
|
10
13
|
vi.unstubAllEnvs();
|
|
11
14
|
});
|
|
@@ -19,7 +22,7 @@ describe('daemon-client', () => {
|
|
|
19
22
|
runtimeVersion: '1.2.3',
|
|
20
23
|
pending: 0,
|
|
21
24
|
memoryMB: 32,
|
|
22
|
-
port:
|
|
25
|
+
port: 9777,
|
|
23
26
|
};
|
|
24
27
|
const fetchMock = vi.mocked(fetch);
|
|
25
28
|
fetchMock.mockResolvedValue({
|
|
@@ -57,7 +60,7 @@ describe('daemon-client', () => {
|
|
|
57
60
|
runtimeName: 'fake',
|
|
58
61
|
pending: 0,
|
|
59
62
|
memoryMB: 16,
|
|
60
|
-
port:
|
|
63
|
+
port: 9777,
|
|
61
64
|
};
|
|
62
65
|
vi.mocked(fetch).mockResolvedValue({
|
|
63
66
|
ok: true,
|
|
@@ -75,7 +78,7 @@ describe('daemon-client', () => {
|
|
|
75
78
|
runtimeVersion: '1.2.3',
|
|
76
79
|
pending: 0,
|
|
77
80
|
memoryMB: 32,
|
|
78
|
-
port:
|
|
81
|
+
port: 9777,
|
|
79
82
|
};
|
|
80
83
|
vi.mocked(fetch).mockResolvedValue({
|
|
81
84
|
ok: true,
|
|
@@ -97,7 +100,7 @@ describe('daemon-client', () => {
|
|
|
97
100
|
],
|
|
98
101
|
pending: 0,
|
|
99
102
|
memoryMB: 32,
|
|
100
|
-
port:
|
|
103
|
+
port: 9777,
|
|
101
104
|
};
|
|
102
105
|
vi.mocked(fetch).mockResolvedValue({
|
|
103
106
|
ok: true,
|
|
@@ -116,32 +119,12 @@ describe('daemon-client', () => {
|
|
|
116
119
|
runtimeName: 'fake',
|
|
117
120
|
pending: 0,
|
|
118
121
|
memoryMB: 1,
|
|
119
|
-
port:
|
|
122
|
+
port: 9777,
|
|
120
123
|
}),
|
|
121
124
|
});
|
|
122
125
|
await fetchDaemonStatus({ contextId: 'work' });
|
|
123
126
|
expect(vi.mocked(fetch).mock.calls[0][0]).toMatch(/\/status\?contextId=work$/);
|
|
124
127
|
});
|
|
125
|
-
it('rejects WEBCMD_DAEMON_PORT so CLI and extension cannot split bridge ports', async () => {
|
|
126
|
-
vi.resetModules();
|
|
127
|
-
vi.stubEnv('WEBCMD_DAEMON_PORT', '19999');
|
|
128
|
-
vi.mocked(fetch).mockResolvedValue({
|
|
129
|
-
ok: true,
|
|
130
|
-
json: () => Promise.resolve({
|
|
131
|
-
ok: true,
|
|
132
|
-
pid: 1,
|
|
133
|
-
uptime: 0,
|
|
134
|
-
runtimeConnected: true,
|
|
135
|
-
runtimeName: 'fake',
|
|
136
|
-
pending: 0,
|
|
137
|
-
memoryMB: 1,
|
|
138
|
-
port: 19825,
|
|
139
|
-
}),
|
|
140
|
-
});
|
|
141
|
-
const freshClient = await import('./daemon-client.js');
|
|
142
|
-
await expect(freshClient.fetchDaemonStatus()).rejects.toThrow('WEBCMD_DAEMON_PORT is no longer supported');
|
|
143
|
-
expect(vi.mocked(fetch)).not.toHaveBeenCalled();
|
|
144
|
-
});
|
|
145
128
|
it('sendCommand includes the current pid in generated command ids', async () => {
|
|
146
129
|
vi.spyOn(Date, 'now').mockReturnValue(1_763_000_000_000);
|
|
147
130
|
vi.mocked(fetch).mockResolvedValue({
|
|
@@ -159,7 +142,7 @@ describe('daemon-client', () => {
|
|
|
159
142
|
expect(ids[1]).toMatch(new RegExp(`^cmd_${process.pid}_1763000000000_\\d+$`));
|
|
160
143
|
expect(ids[0]).not.toBe(ids[1]);
|
|
161
144
|
});
|
|
162
|
-
it('sendCommand forwards WEBCMD_PROFILE as
|
|
145
|
+
it('sendCommand forwards WEBCMD_PROFILE as a hard contextId requirement', async () => {
|
|
163
146
|
vi.stubEnv('WEBCMD_PROFILE', 'work');
|
|
164
147
|
vi.spyOn(Date, 'now').mockReturnValue(1_763_000_000_000);
|
|
165
148
|
vi.mocked(fetch).mockResolvedValue({
|
|
@@ -169,6 +152,29 @@ describe('daemon-client', () => {
|
|
|
169
152
|
await sendCommand('exec', { code: '1 + 1' });
|
|
170
153
|
const body = JSON.parse(String(vi.mocked(fetch).mock.calls[0][1]?.body));
|
|
171
154
|
expect(body.contextId).toBe('work');
|
|
155
|
+
expect(body.preferredContextId).toBeUndefined();
|
|
156
|
+
});
|
|
157
|
+
it('sendCommand forwards the config default as preferredContextId', async () => {
|
|
158
|
+
const fs = await import('node:fs');
|
|
159
|
+
const os = await import('node:os');
|
|
160
|
+
const path = await import('node:path');
|
|
161
|
+
const configDir = fs.mkdtempSync(path.join(os.tmpdir(), 'webcmd-dc-profile-'));
|
|
162
|
+
fs.writeFileSync(path.join(configDir, 'browser-profiles.json'), JSON.stringify({ version: 1, aliases: {}, defaultContextId: 'profile-default' }));
|
|
163
|
+
vi.stubEnv('WEBCMD_CONFIG_DIR', configDir);
|
|
164
|
+
vi.stubEnv('WEBCMD_PROFILE', '');
|
|
165
|
+
try {
|
|
166
|
+
vi.mocked(fetch).mockResolvedValue({
|
|
167
|
+
status: 200,
|
|
168
|
+
json: () => Promise.resolve({ id: 'server', ok: true, data: 'ok' }),
|
|
169
|
+
});
|
|
170
|
+
await sendCommand('exec', { code: '1 + 1' });
|
|
171
|
+
const body = JSON.parse(String(vi.mocked(fetch).mock.calls[0][1]?.body));
|
|
172
|
+
expect(body.contextId).toBeUndefined();
|
|
173
|
+
expect(body.preferredContextId).toBe('profile-default');
|
|
174
|
+
}
|
|
175
|
+
finally {
|
|
176
|
+
fs.rmSync(configDir, { recursive: true, force: true });
|
|
177
|
+
}
|
|
172
178
|
});
|
|
173
179
|
it('sendCommand uses explicit windowMode before WEBCMD_WINDOW env fallback', async () => {
|
|
174
180
|
vi.stubEnv('WEBCMD_WINDOW', 'foreground');
|
|
@@ -180,27 +186,19 @@ describe('daemon-client', () => {
|
|
|
180
186
|
const body = JSON.parse(String(vi.mocked(fetch).mock.calls[0][1]?.body));
|
|
181
187
|
expect(body.windowMode).toBe('background');
|
|
182
188
|
});
|
|
183
|
-
it('sendCommand
|
|
189
|
+
it('sendCommand treats duplicate pending ids from an old daemon as unknown instead of minting a new id', async () => {
|
|
184
190
|
vi.spyOn(Date, 'now').mockReturnValue(1_763_000_000_123);
|
|
185
191
|
const fetchMock = vi.mocked(fetch);
|
|
186
|
-
fetchMock
|
|
187
|
-
.mockResolvedValueOnce({
|
|
192
|
+
fetchMock.mockResolvedValueOnce({
|
|
188
193
|
ok: false,
|
|
189
194
|
status: 409,
|
|
190
195
|
json: () => Promise.resolve({ ok: false, error: 'Duplicate command id already pending; retry' }),
|
|
191
|
-
})
|
|
192
|
-
.mockResolvedValueOnce({
|
|
193
|
-
ok: true,
|
|
194
|
-
status: 200,
|
|
195
|
-
json: () => Promise.resolve({ id: 'server', ok: true, data: 42 }),
|
|
196
196
|
});
|
|
197
|
-
await expect(sendCommand('exec', { code: '6 * 7' })).
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
const body = JSON.parse(String(init?.body));
|
|
201
|
-
return body.id;
|
|
197
|
+
await expect(sendCommand('exec', { code: '6 * 7' })).rejects.toMatchObject({
|
|
198
|
+
name: 'BrowserCommandError',
|
|
199
|
+
code: 'command_result_unknown',
|
|
202
200
|
});
|
|
203
|
-
expect(
|
|
201
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
204
202
|
});
|
|
205
203
|
it('sendCommand does not retry command_result_unknown even when the message looks transient', async () => {
|
|
206
204
|
const fetchMock = vi.mocked(fetch);
|
|
@@ -222,7 +220,7 @@ describe('daemon-client', () => {
|
|
|
222
220
|
});
|
|
223
221
|
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
224
222
|
});
|
|
225
|
-
it('sendCommand runs full bridge ensure on a pre-dispatch failure, then resends with
|
|
223
|
+
it('sendCommand runs full bridge ensure on a pre-dispatch failure, then resends with the same id', async () => {
|
|
226
224
|
vi.spyOn(Date, 'now').mockReturnValue(1_763_000_000_321);
|
|
227
225
|
const ensureSpy = vi.spyOn(daemonLifecycle, 'ensureBrowserBridgeReady').mockResolvedValue({
|
|
228
226
|
health: {
|
|
@@ -235,7 +233,7 @@ describe('daemon-client', () => {
|
|
|
235
233
|
runtimeName: 'fake',
|
|
236
234
|
pending: 0,
|
|
237
235
|
memoryMB: 0,
|
|
238
|
-
port:
|
|
236
|
+
port: 9777,
|
|
239
237
|
},
|
|
240
238
|
},
|
|
241
239
|
spawnedProcess: null,
|
|
@@ -260,9 +258,9 @@ describe('daemon-client', () => {
|
|
|
260
258
|
expect(ensureSpy).toHaveBeenCalledWith(expect.objectContaining({ contextId: 'work', verbose: false }));
|
|
261
259
|
const ids = fetchMock.mock.calls.map(([, init]) => JSON.parse(String(init?.body)).id);
|
|
262
260
|
expect(ids).toHaveLength(2);
|
|
263
|
-
expect(ids[0]).
|
|
261
|
+
expect(ids[0]).toBe(ids[1]);
|
|
264
262
|
});
|
|
265
|
-
it('sendCommand runs full bridge ensure on a
|
|
263
|
+
it('sendCommand runs full bridge ensure on a pre-connect TypeError before resending', async () => {
|
|
266
264
|
const ensureSpy = vi.spyOn(daemonLifecycle, 'ensureBrowserBridgeReady').mockResolvedValue({
|
|
267
265
|
health: {
|
|
268
266
|
state: 'ready',
|
|
@@ -274,14 +272,16 @@ describe('daemon-client', () => {
|
|
|
274
272
|
runtimeName: 'fake',
|
|
275
273
|
pending: 0,
|
|
276
274
|
memoryMB: 0,
|
|
277
|
-
port:
|
|
275
|
+
port: 9777,
|
|
278
276
|
},
|
|
279
277
|
},
|
|
280
278
|
spawnedProcess: null,
|
|
281
279
|
});
|
|
280
|
+
const refused = new TypeError('fetch failed');
|
|
281
|
+
refused.cause = Object.assign(new Error('connect ECONNREFUSED 127.0.0.1:9777'), { code: 'ECONNREFUSED' });
|
|
282
282
|
const fetchMock = vi.mocked(fetch);
|
|
283
283
|
fetchMock
|
|
284
|
-
.mockRejectedValueOnce(
|
|
284
|
+
.mockRejectedValueOnce(refused)
|
|
285
285
|
.mockResolvedValueOnce({
|
|
286
286
|
ok: true,
|
|
287
287
|
status: 200,
|
|
@@ -291,6 +291,33 @@ describe('daemon-client', () => {
|
|
|
291
291
|
expect(ensureSpy).toHaveBeenCalledWith(expect.objectContaining({ verbose: false }));
|
|
292
292
|
expect(fetchMock).toHaveBeenCalledTimes(2);
|
|
293
293
|
});
|
|
294
|
+
it('sendCommand does not resend a post-connect TypeError because the command may have been dispatched', async () => {
|
|
295
|
+
const ensureSpy = vi.spyOn(daemonLifecycle, 'ensureBrowserBridgeReady').mockResolvedValue({
|
|
296
|
+
health: {
|
|
297
|
+
state: 'ready',
|
|
298
|
+
status: {
|
|
299
|
+
ok: true,
|
|
300
|
+
pid: 1,
|
|
301
|
+
uptime: 1,
|
|
302
|
+
runtimeConnected: true,
|
|
303
|
+
runtimeName: 'fake',
|
|
304
|
+
pending: 0,
|
|
305
|
+
memoryMB: 0,
|
|
306
|
+
port: 9777,
|
|
307
|
+
},
|
|
308
|
+
},
|
|
309
|
+
spawnedProcess: null,
|
|
310
|
+
});
|
|
311
|
+
const reset = new TypeError('fetch failed');
|
|
312
|
+
reset.cause = Object.assign(new Error('read ECONNRESET'), { code: 'ECONNRESET' });
|
|
313
|
+
vi.mocked(fetch).mockRejectedValueOnce(reset);
|
|
314
|
+
await expect(sendCommand('navigate', { url: 'https://example.com' })).rejects.toMatchObject({
|
|
315
|
+
name: 'BrowserCommandError',
|
|
316
|
+
code: 'command_result_unknown',
|
|
317
|
+
});
|
|
318
|
+
expect(ensureSpy).toHaveBeenCalledTimes(1);
|
|
319
|
+
expect(fetch).toHaveBeenCalledTimes(1);
|
|
320
|
+
});
|
|
294
321
|
it('sendCommand does NOT wait when the bridge reports profile_required', async () => {
|
|
295
322
|
const ensureSpy = vi.spyOn(daemonLifecycle, 'ensureBrowserBridgeReady');
|
|
296
323
|
const fetchMock = vi.mocked(fetch);
|
|
@@ -323,4 +350,65 @@ describe('daemon-client', () => {
|
|
|
323
350
|
expect(ensureSpy).not.toHaveBeenCalled();
|
|
324
351
|
expect(fetch).toHaveBeenCalledTimes(1);
|
|
325
352
|
});
|
|
353
|
+
it('sendCommand plumbs the default command timeout and absolute deadline into the request body', async () => {
|
|
354
|
+
vi.spyOn(Date, 'now').mockReturnValue(1_763_000_000_000);
|
|
355
|
+
const fetchMock = vi.mocked(fetch);
|
|
356
|
+
fetchMock.mockResolvedValueOnce({
|
|
357
|
+
ok: true,
|
|
358
|
+
status: 200,
|
|
359
|
+
json: () => Promise.resolve({ id: 'server', ok: true, data: 1 }),
|
|
360
|
+
});
|
|
361
|
+
await expect(sendCommand('exec', { code: '1' })).resolves.toBe(1);
|
|
362
|
+
const body = JSON.parse(String(fetchMock.mock.calls[0][1]?.body));
|
|
363
|
+
expect(body.timeout).toBe(120);
|
|
364
|
+
expect(body.deadlineAt).toBe(1_763_000_120_000);
|
|
365
|
+
});
|
|
366
|
+
it('sendCommand extends the daemon deadline past a runtime-side timeoutMs', async () => {
|
|
367
|
+
const fetchMock = vi.mocked(fetch);
|
|
368
|
+
fetchMock.mockResolvedValueOnce({
|
|
369
|
+
ok: true,
|
|
370
|
+
status: 200,
|
|
371
|
+
json: () => Promise.resolve({ id: 'server', ok: true, data: { downloaded: true } }),
|
|
372
|
+
});
|
|
373
|
+
await sendCommand('wait-download', { timeoutMs: 240_000 });
|
|
374
|
+
const body = JSON.parse(String(fetchMock.mock.calls[0][1]?.body));
|
|
375
|
+
expect(body.timeout).toBe(255);
|
|
376
|
+
});
|
|
377
|
+
it('setDaemonCommandTimeoutSeconds raises the transport deadline for a user timeout', async () => {
|
|
378
|
+
const fetchMock = vi.mocked(fetch);
|
|
379
|
+
fetchMock.mockResolvedValueOnce({
|
|
380
|
+
ok: true,
|
|
381
|
+
status: 200,
|
|
382
|
+
json: () => Promise.resolve({ id: 'server', ok: true, data: 1 }),
|
|
383
|
+
});
|
|
384
|
+
setDaemonCommandTimeoutSeconds(300);
|
|
385
|
+
await sendCommand('exec', { code: '1' });
|
|
386
|
+
const body = JSON.parse(String(fetchMock.mock.calls[0][1]?.body));
|
|
387
|
+
expect(body.timeout).toBe(300);
|
|
388
|
+
});
|
|
389
|
+
it('client HTTP abort fires only after the daemon timeout margin', async () => {
|
|
390
|
+
vi.useFakeTimers();
|
|
391
|
+
try {
|
|
392
|
+
const fetchMock = vi.mocked(fetch);
|
|
393
|
+
let aborted = false;
|
|
394
|
+
fetchMock.mockImplementationOnce((_url, init) => new Promise((_, reject) => {
|
|
395
|
+
init?.signal?.addEventListener('abort', () => {
|
|
396
|
+
aborted = true;
|
|
397
|
+
reject(Object.assign(new Error('This operation was aborted'), { name: 'AbortError' }));
|
|
398
|
+
});
|
|
399
|
+
}));
|
|
400
|
+
const pending = sendCommand('exec', { code: '1' }).catch((err) => err);
|
|
401
|
+
await vi.advanceTimersByTimeAsync(120_000 + 9_999);
|
|
402
|
+
expect(aborted).toBe(false);
|
|
403
|
+
await vi.advanceTimersByTimeAsync(1);
|
|
404
|
+
expect(aborted).toBe(true);
|
|
405
|
+
await expect(pending).resolves.toMatchObject({
|
|
406
|
+
name: 'BrowserCommandError',
|
|
407
|
+
code: 'command_result_unknown',
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
finally {
|
|
411
|
+
vi.useRealTimers();
|
|
412
|
+
}
|
|
413
|
+
});
|
|
326
414
|
});
|
|
@@ -1,20 +1,8 @@
|
|
|
1
|
-
import { DAEMON_HEADER_NAME, DEFAULT_DAEMON_PORT
|
|
1
|
+
import { DAEMON_HEADER_NAME, DEFAULT_DAEMON_PORT } from '../constants.js';
|
|
2
2
|
const DAEMON_PORT = DEFAULT_DAEMON_PORT;
|
|
3
3
|
const DAEMON_URL = `http://127.0.0.1:${DAEMON_PORT}`;
|
|
4
4
|
const WEBCMD_HEADERS = { [DAEMON_HEADER_NAME]: '1' };
|
|
5
|
-
class UnsupportedDaemonPortEnvError extends Error {
|
|
6
|
-
constructor(value) {
|
|
7
|
-
super(unsupportedDaemonPortEnvMessage(value));
|
|
8
|
-
this.name = 'UnsupportedDaemonPortEnvError';
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
function assertSupportedDaemonPortEnv() {
|
|
12
|
-
const value = process.env.WEBCMD_DAEMON_PORT;
|
|
13
|
-
if (value !== undefined && value !== '')
|
|
14
|
-
throw new UnsupportedDaemonPortEnvError(value);
|
|
15
|
-
}
|
|
16
5
|
export async function requestDaemon(pathname, init) {
|
|
17
|
-
assertSupportedDaemonPortEnv();
|
|
18
6
|
const { timeout = 2000, headers, ...rest } = init ?? {};
|
|
19
7
|
const controller = new AbortController();
|
|
20
8
|
const timer = setTimeout(() => controller.abort(), timeout);
|
|
@@ -37,9 +25,7 @@ export async function fetchDaemonStatus(opts) {
|
|
|
37
25
|
return null;
|
|
38
26
|
return await res.json();
|
|
39
27
|
}
|
|
40
|
-
catch
|
|
41
|
-
if (err instanceof UnsupportedDaemonPortEnvError)
|
|
42
|
-
throw err;
|
|
28
|
+
catch {
|
|
43
29
|
return null;
|
|
44
30
|
}
|
|
45
31
|
}
|
|
@@ -60,9 +46,7 @@ export async function requestDaemonShutdown(opts) {
|
|
|
60
46
|
const res = await requestDaemon('/shutdown', { method: 'POST', timeout: opts?.timeout ?? 5000 });
|
|
61
47
|
return res.ok;
|
|
62
48
|
}
|
|
63
|
-
catch
|
|
64
|
-
if (err instanceof UnsupportedDaemonPortEnvError)
|
|
65
|
-
throw err;
|
|
49
|
+
catch {
|
|
66
50
|
return false;
|
|
67
51
|
}
|
|
68
52
|
}
|
|
@@ -34,12 +34,23 @@ const TARGET_NAVIGATION_PATTERNS = [
|
|
|
34
34
|
function errorMessage(err) {
|
|
35
35
|
return err instanceof Error ? err.message : String(err);
|
|
36
36
|
}
|
|
37
|
+
const ERROR_CODE_ADVICE = {
|
|
38
|
+
attach_failed: { kind: 'extension-transient', retryable: true, delayMs: 1500 },
|
|
39
|
+
tab_gone: { kind: 'extension-transient', retryable: true, delayMs: 1500 },
|
|
40
|
+
target_navigated: { kind: 'target-navigation', retryable: true, delayMs: 200 },
|
|
41
|
+
detached_mid_command: { kind: 'non-retryable', retryable: false, delayMs: 0 },
|
|
42
|
+
cdp_timeout: { kind: 'non-retryable', retryable: false, delayMs: 0 },
|
|
43
|
+
};
|
|
37
44
|
/**
|
|
38
45
|
* Classify a browser error and return retry advice.
|
|
39
46
|
*
|
|
40
47
|
* Single source of truth for "is this error transient?" across all layers.
|
|
41
48
|
*/
|
|
42
49
|
export function classifyBrowserError(err) {
|
|
50
|
+
const code = err && typeof err === 'object' ? err.code : undefined;
|
|
51
|
+
if (typeof code === 'string' && ERROR_CODE_ADVICE[code]) {
|
|
52
|
+
return ERROR_CODE_ADVICE[code];
|
|
53
|
+
}
|
|
43
54
|
const msg = errorMessage(err);
|
|
44
55
|
// Runtime/daemon transient errors — longer recovery time
|
|
45
56
|
if (EXTENSION_TRANSIENT_PATTERNS.some(p => msg.includes(p))) {
|
|
@@ -19,8 +19,9 @@ export declare class Page extends BasePage {
|
|
|
19
19
|
private readonly windowMode?;
|
|
20
20
|
private readonly surface;
|
|
21
21
|
private readonly siteSession?;
|
|
22
|
+
readonly preferredContextId?: string | undefined;
|
|
22
23
|
private readonly _idleTimeout;
|
|
23
|
-
constructor(session: string, idleTimeout?: number, contextId?: string | undefined, windowMode?: "foreground" | "background" | undefined, surface?: 'browser' | 'adapter', siteSession?: "ephemeral" | "persistent" | undefined);
|
|
24
|
+
constructor(session: string, idleTimeout?: number, contextId?: string | undefined, windowMode?: "foreground" | "background" | undefined, surface?: 'browser' | 'adapter', siteSession?: "ephemeral" | "persistent" | undefined, preferredContextId?: string | undefined);
|
|
24
25
|
/** Active page identity (targetId), set after navigate and used in all subsequent commands */
|
|
25
26
|
private _page;
|
|
26
27
|
private _networkCaptureUnsupported;
|