@jackwener/opencli 1.3.3 → 1.4.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/.github/pull_request_template.md +3 -1
- package/.github/workflows/build-extension.yml +7 -1
- package/.github/workflows/ci.yml +29 -3
- package/.github/workflows/docs.yml +1 -1
- package/.github/workflows/e2e-headed.yml +20 -0
- package/.github/workflows/release.yml +1 -1
- package/.github/workflows/security.yml +0 -3
- package/CHANGELOG.md +55 -0
- package/CONTRIBUTING.md +6 -3
- package/README.md +30 -3
- package/README.zh-CN.md +30 -3
- package/SKILL.md +7 -1
- package/TESTING.md +1 -0
- package/chatwise-opencli.ps1 +82 -0
- package/dist/analysis.d.ts +38 -0
- package/dist/analysis.js +166 -0
- package/dist/browser/cdp.d.ts +0 -4
- package/dist/browser/cdp.js +53 -41
- package/dist/browser/cdp.test.d.ts +1 -0
- package/dist/browser/cdp.test.js +52 -0
- package/dist/browser/dom-snapshot.d.ts +2 -2
- package/dist/browser/dom-snapshot.js +54 -1
- package/dist/browser/dom-snapshot.test.js +36 -0
- package/dist/browser/index.d.ts +2 -2
- package/dist/browser/index.js +1 -1
- package/dist/browser/mcp.d.ts +0 -2
- package/dist/browser/mcp.js +2 -3
- package/dist/browser/page.d.ts +4 -3
- package/dist/browser/page.js +34 -37
- package/dist/browser/stealth.d.ts +0 -2
- package/dist/browser/stealth.js +24 -9
- package/dist/browser.test.js +2 -2
- package/dist/build-manifest.js +15 -9
- package/dist/build-manifest.test.js +12 -0
- package/dist/cascade.js +4 -2
- package/dist/cli-manifest.json +639 -258
- package/dist/cli.js +57 -29
- package/dist/clis/_shared/desktop-commands.d.ts +22 -0
- package/dist/clis/_shared/desktop-commands.js +108 -0
- package/dist/clis/antigravity/serve.js +5 -2
- package/dist/clis/arxiv/search.js +1 -1
- package/dist/clis/bilibili/dynamic.test.d.ts +1 -0
- package/dist/clis/bilibili/dynamic.test.js +68 -0
- package/dist/clis/bilibili/favorite.js +4 -2
- package/dist/clis/bilibili/following.js +3 -2
- package/dist/clis/bilibili/subtitle.js +8 -7
- package/dist/clis/bilibili/utils.js +2 -2
- package/dist/clis/boss/batchgreet.js +1 -1
- package/dist/clis/boss/chatlist.js +1 -1
- package/dist/clis/boss/chatmsg.js +1 -1
- package/dist/clis/boss/detail.js +1 -1
- package/dist/clis/boss/exchange.js +1 -1
- package/dist/clis/boss/greet.js +1 -1
- package/dist/clis/boss/invite.js +1 -1
- package/dist/clis/boss/joblist.js +1 -1
- package/dist/clis/boss/mark.js +4 -3
- package/dist/clis/boss/recommend.js +1 -1
- package/dist/clis/boss/resume.js +1 -1
- package/dist/clis/boss/search.js +1 -1
- package/dist/clis/boss/send.js +5 -4
- package/dist/clis/boss/stats.js +1 -1
- package/dist/clis/chatgpt/ask.js +4 -0
- package/dist/clis/chatgpt/new.js +5 -1
- package/dist/clis/chatgpt/read.js +5 -1
- package/dist/clis/chatgpt/send.js +2 -1
- package/dist/clis/chatgpt/status.js +5 -1
- package/dist/clis/chatwise/ask.js +8 -2
- package/dist/clis/chatwise/export.js +2 -0
- package/dist/clis/chatwise/history.js +2 -0
- package/dist/clis/chatwise/model.js +8 -3
- package/dist/clis/chatwise/new.js +3 -18
- package/dist/clis/chatwise/read.js +2 -0
- package/dist/clis/chatwise/screenshot.js +3 -27
- package/dist/clis/chatwise/send.js +8 -2
- package/dist/clis/chatwise/shared.d.ts +2 -0
- package/dist/clis/chatwise/shared.js +6 -0
- package/dist/clis/chatwise/status.js +3 -22
- package/dist/clis/codex/ask.js +6 -2
- package/dist/clis/codex/dump.js +2 -25
- package/dist/clis/codex/new.js +2 -25
- package/dist/clis/codex/screenshot.js +2 -27
- package/dist/clis/codex/send.js +6 -4
- package/dist/clis/codex/status.js +2 -22
- package/dist/clis/cursor/ask.js +2 -1
- package/dist/clis/cursor/composer.js +2 -1
- package/dist/clis/cursor/dump.js +2 -25
- package/dist/clis/cursor/new.js +2 -18
- package/dist/clis/cursor/read.js +2 -1
- package/dist/clis/cursor/screenshot.js +1 -30
- package/dist/clis/cursor/send.js +2 -1
- package/dist/clis/cursor/status.js +2 -21
- package/dist/clis/dictionary/examples.yaml +25 -0
- package/dist/clis/dictionary/search.yaml +27 -0
- package/dist/clis/dictionary/synonyms.yaml +25 -0
- package/dist/clis/douban/book-hot.js +1 -1
- package/dist/clis/douban/movie-hot.js +1 -1
- package/dist/clis/douban/search.js +1 -1
- package/dist/clis/douban/utils.d.ts +4 -1
- package/dist/clis/douban/utils.js +156 -1
- package/dist/clis/doubao/ask.js +1 -1
- package/dist/clis/doubao/new.js +1 -1
- package/dist/clis/doubao/read.js +1 -1
- package/dist/clis/doubao/send.js +1 -1
- package/dist/clis/doubao/status.js +1 -1
- package/dist/clis/doubao-app/ask.js +1 -1
- package/dist/clis/doubao-app/new.js +1 -1
- package/dist/clis/doubao-app/read.js +1 -1
- package/dist/clis/doubao-app/send.js +1 -1
- package/dist/clis/grok/ask.d.ts +4 -0
- package/dist/clis/grok/ask.js +28 -10
- package/dist/clis/grok/ask.test.js +18 -0
- package/dist/clis/jd/item.d.ts +1 -0
- package/dist/clis/jd/item.js +96 -0
- package/dist/clis/jd/item.test.d.ts +1 -0
- package/dist/clis/jd/item.test.js +28 -0
- package/dist/clis/jike/feed.js +1 -1
- package/dist/clis/jike/search.js +1 -1
- package/dist/clis/linkedin/search.js +5 -4
- package/dist/clis/linkedin/timeline.d.ts +21 -0
- package/dist/clis/linkedin/timeline.js +503 -0
- package/dist/clis/linkedin/timeline.test.d.ts +1 -0
- package/dist/clis/linkedin/timeline.test.js +81 -0
- package/dist/clis/medium/feed.js +1 -1
- package/dist/clis/medium/search.js +1 -1
- package/dist/clis/medium/user.js +1 -1
- package/dist/clis/medium/{shared.js → utils.js} +2 -1
- package/dist/clis/pixiv/detail.yaml +49 -0
- package/dist/clis/pixiv/download.d.ts +7 -0
- package/dist/clis/pixiv/download.js +78 -0
- package/dist/clis/pixiv/download.test.d.ts +1 -0
- package/dist/clis/pixiv/download.test.js +87 -0
- package/dist/clis/pixiv/illusts.d.ts +8 -0
- package/dist/clis/pixiv/illusts.js +65 -0
- package/dist/clis/pixiv/illusts.test.d.ts +1 -0
- package/dist/clis/pixiv/illusts.test.js +99 -0
- package/dist/clis/pixiv/ranking.yaml +53 -0
- package/dist/clis/pixiv/search.d.ts +6 -0
- package/dist/clis/pixiv/search.js +43 -0
- package/dist/clis/pixiv/search.test.d.ts +1 -0
- package/dist/clis/pixiv/search.test.js +83 -0
- package/dist/clis/pixiv/test-utils.d.ts +12 -0
- package/dist/clis/pixiv/test-utils.js +23 -0
- package/dist/clis/pixiv/user.yaml +46 -0
- package/dist/clis/pixiv/utils.d.ts +27 -0
- package/dist/clis/pixiv/utils.js +49 -0
- package/dist/clis/reddit/comment.js +2 -1
- package/dist/clis/reddit/read.js +4 -3
- package/dist/clis/reddit/read.test.d.ts +1 -0
- package/dist/clis/reddit/read.test.js +28 -0
- package/dist/clis/reddit/save.js +2 -1
- package/dist/clis/reddit/saved.js +7 -3
- package/dist/clis/reddit/subscribe.js +2 -1
- package/dist/clis/reddit/upvote.js +2 -1
- package/dist/clis/reddit/upvoted.js +7 -3
- package/dist/clis/sinablog/article.js +1 -1
- package/dist/clis/sinablog/hot.js +1 -1
- package/dist/clis/sinablog/user.js +1 -1
- package/dist/clis/substack/feed.js +1 -1
- package/dist/clis/substack/publication.js +1 -1
- package/dist/clis/substack/search.js +3 -2
- package/dist/clis/substack/{shared.js → utils.js} +3 -2
- package/dist/clis/tiktok/search.yaml +2 -1
- package/dist/clis/twitter/accept.js +2 -1
- package/dist/clis/twitter/article.js +4 -1
- package/dist/clis/twitter/block.js +2 -1
- package/dist/clis/twitter/bookmark.js +2 -1
- package/dist/clis/twitter/bookmarks.js +3 -2
- package/dist/clis/twitter/delete.js +2 -1
- package/dist/clis/twitter/follow.js +2 -1
- package/dist/clis/twitter/followers.js +3 -2
- package/dist/clis/twitter/following.js +3 -2
- package/dist/clis/twitter/hide-reply.js +2 -1
- package/dist/clis/twitter/like.js +2 -1
- package/dist/clis/twitter/notifications.js +2 -1
- package/dist/clis/twitter/post.js +2 -1
- package/dist/clis/twitter/profile.js +5 -2
- package/dist/clis/twitter/reply-dm.js +2 -1
- package/dist/clis/twitter/reply.js +2 -1
- package/dist/clis/twitter/search.js +30 -13
- package/dist/clis/twitter/search.test.d.ts +1 -0
- package/dist/clis/twitter/search.test.js +104 -0
- package/dist/clis/twitter/thread.js +2 -2
- package/dist/clis/twitter/timeline.js +3 -2
- package/dist/clis/twitter/trending.js +3 -2
- package/dist/clis/twitter/unblock.js +2 -1
- package/dist/clis/twitter/unbookmark.js +2 -1
- package/dist/clis/twitter/unfollow.js +2 -1
- package/dist/clis/v2ex/daily.js +3 -2
- package/dist/clis/v2ex/me.js +3 -2
- package/dist/clis/v2ex/notifications.js +4 -4
- package/dist/clis/web/read.d.ts +16 -0
- package/dist/clis/web/read.js +202 -0
- package/dist/clis/xueqiu/danjuan-utils.d.ts +55 -0
- package/dist/clis/xueqiu/danjuan-utils.js +126 -0
- package/dist/clis/xueqiu/danjuan-utils.test.d.ts +1 -0
- package/dist/clis/xueqiu/danjuan-utils.test.js +41 -0
- package/dist/clis/xueqiu/fund-holdings.d.ts +1 -0
- package/dist/clis/xueqiu/fund-holdings.js +28 -0
- package/dist/clis/xueqiu/fund-snapshot.d.ts +1 -0
- package/dist/clis/xueqiu/fund-snapshot.js +25 -0
- package/dist/clis/youtube/transcript.js +5 -4
- package/dist/clis/youtube/video.js +3 -2
- package/dist/daemon.js +7 -3
- package/dist/discovery.js +11 -10
- package/dist/doctor.js +2 -1
- package/dist/download/index.d.ts +4 -12
- package/dist/download/index.js +33 -12
- package/dist/download/index.test.js +79 -2
- package/dist/download/media-download.js +4 -2
- package/dist/engine.test.js +76 -4
- package/dist/execution.d.ts +1 -9
- package/dist/execution.js +56 -46
- package/dist/explore.js +12 -111
- package/dist/external-clis.yaml +0 -8
- package/dist/external.js +7 -5
- package/dist/external.test.js +4 -0
- package/dist/generate.d.ts +0 -9
- package/dist/generate.js +4 -20
- package/dist/hooks.d.ts +46 -0
- package/dist/hooks.js +56 -0
- package/dist/hooks.test.d.ts +4 -0
- package/dist/hooks.test.js +92 -0
- package/dist/interceptor.js +70 -23
- package/dist/main.js +2 -0
- package/dist/output.js +12 -6
- package/dist/pipeline/executor.js +1 -1
- package/dist/pipeline/steps/browser.js +1 -3
- package/dist/pipeline/steps/download.js +42 -26
- package/dist/pipeline/steps/download.test.d.ts +1 -0
- package/dist/pipeline/steps/download.test.js +101 -0
- package/dist/pipeline/steps/fetch.js +40 -22
- package/dist/pipeline/steps/fetch.test.d.ts +1 -0
- package/dist/pipeline/steps/fetch.test.js +123 -0
- package/dist/pipeline/steps/transform.js +2 -6
- package/dist/pipeline/template.js +66 -52
- package/dist/pipeline/template.test.js +28 -0
- package/dist/pipeline/transform.test.js +18 -0
- package/dist/plugin.d.ts +40 -1
- package/dist/plugin.js +214 -17
- package/dist/plugin.test.d.ts +1 -1
- package/dist/plugin.test.js +219 -3
- package/dist/record.js +6 -98
- package/dist/registry-api.d.ts +2 -0
- package/dist/registry-api.js +1 -0
- package/dist/registry.d.ts +5 -2
- package/dist/registry.js +1 -2
- package/dist/runtime.d.ts +0 -1
- package/dist/runtime.js +14 -4
- package/dist/snapshotFormatter.d.ts +7 -14
- package/dist/snapshotFormatter.js +38 -78
- package/dist/utils.d.ts +9 -0
- package/dist/utils.js +29 -0
- package/dist/validate.js +3 -5
- package/dist/yaml-schema.d.ts +26 -0
- package/dist/yaml-schema.js +5 -0
- package/docs/.vitepress/config.mts +3 -0
- package/docs/adapters/browser/dictionary.md +27 -0
- package/docs/adapters/browser/jd.md +27 -0
- package/docs/adapters/browser/linkedin.md +6 -0
- package/docs/adapters/browser/pixiv.md +92 -0
- package/docs/adapters/browser/web.md +30 -0
- package/docs/adapters/browser/xueqiu.md +27 -9
- package/docs/adapters/index.md +3 -1
- package/docs/comparison.md +125 -0
- package/docs/developer/contributing.md +21 -2
- package/docs/developer/testing.md +14 -8
- package/docs/developer/ts-adapter.md +18 -0
- package/docs/developer/yaml-adapter.md +16 -0
- package/docs/guide/plugins.md +10 -0
- package/docs/zh/guide/plugins.md +10 -0
- package/extension/dist/background.js +519 -444
- package/extension/manifest.json +1 -1
- package/extension/package.json +1 -1
- package/extension/src/background.test.ts +46 -1
- package/extension/src/background.ts +108 -33
- package/extension/src/cdp.ts +9 -9
- package/package.json +3 -2
- package/scripts/check-doc-coverage.sh +2 -0
- package/src/analysis.ts +170 -0
- package/src/browser/cdp.test.ts +66 -0
- package/src/browser/cdp.ts +59 -44
- package/src/browser/dom-snapshot.test.ts +42 -0
- package/src/browser/dom-snapshot.ts +56 -3
- package/src/browser/index.ts +2 -2
- package/src/browser/mcp.ts +2 -4
- package/src/browser/page.ts +34 -37
- package/src/browser/stealth.ts +24 -10
- package/src/browser.test.ts +2 -2
- package/src/build-manifest.test.ts +14 -0
- package/src/build-manifest.ts +13 -31
- package/src/cascade.ts +5 -3
- package/src/cli.ts +66 -34
- package/src/clis/_shared/desktop-commands.ts +121 -0
- package/src/clis/antigravity/serve.ts +6 -3
- package/src/clis/arxiv/search.ts +1 -1
- package/src/clis/bilibili/dynamic.test.ts +79 -0
- package/src/clis/bilibili/favorite.ts +5 -2
- package/src/clis/bilibili/following.ts +3 -2
- package/src/clis/bilibili/subtitle.ts +8 -7
- package/src/clis/bilibili/utils.ts +2 -2
- package/src/clis/boss/batchgreet.ts +1 -1
- package/src/clis/boss/chatlist.ts +1 -1
- package/src/clis/boss/chatmsg.ts +1 -1
- package/src/clis/boss/detail.ts +1 -1
- package/src/clis/boss/exchange.ts +1 -1
- package/src/clis/boss/greet.ts +1 -1
- package/src/clis/boss/invite.ts +1 -1
- package/src/clis/boss/joblist.ts +1 -1
- package/src/clis/boss/mark.ts +4 -3
- package/src/clis/boss/recommend.ts +1 -1
- package/src/clis/boss/resume.ts +1 -1
- package/src/clis/boss/search.ts +1 -1
- package/src/clis/boss/send.ts +5 -4
- package/src/clis/boss/stats.ts +1 -1
- package/src/clis/chatgpt/ask.ts +5 -0
- package/src/clis/chatgpt/new.ts +7 -2
- package/src/clis/chatgpt/read.ts +7 -2
- package/src/clis/chatgpt/send.ts +3 -2
- package/src/clis/chatgpt/status.ts +6 -1
- package/src/clis/chatwise/ask.ts +7 -2
- package/src/clis/chatwise/export.ts +2 -0
- package/src/clis/chatwise/history.ts +2 -0
- package/src/clis/chatwise/model.ts +7 -3
- package/src/clis/chatwise/new.ts +3 -20
- package/src/clis/chatwise/read.ts +2 -0
- package/src/clis/chatwise/screenshot.ts +3 -32
- package/src/clis/chatwise/send.ts +7 -2
- package/src/clis/chatwise/shared.ts +8 -0
- package/src/clis/chatwise/status.ts +3 -24
- package/src/clis/codex/ask.ts +5 -2
- package/src/clis/codex/dump.ts +2 -27
- package/src/clis/codex/new.ts +2 -28
- package/src/clis/codex/screenshot.ts +2 -32
- package/src/clis/codex/send.ts +5 -4
- package/src/clis/codex/status.ts +2 -24
- package/src/clis/cursor/ask.ts +2 -1
- package/src/clis/cursor/composer.ts +2 -1
- package/src/clis/cursor/dump.ts +2 -27
- package/src/clis/cursor/new.ts +2 -20
- package/src/clis/cursor/read.ts +2 -1
- package/src/clis/cursor/screenshot.ts +1 -36
- package/src/clis/cursor/send.ts +2 -1
- package/src/clis/cursor/status.ts +2 -22
- package/src/clis/dictionary/examples.yaml +25 -0
- package/src/clis/dictionary/search.yaml +27 -0
- package/src/clis/dictionary/synonyms.yaml +25 -0
- package/src/clis/douban/book-hot.ts +1 -1
- package/src/clis/douban/movie-hot.ts +1 -1
- package/src/clis/douban/search.ts +1 -1
- package/src/clis/douban/utils.ts +165 -1
- package/src/clis/doubao/ask.ts +1 -1
- package/src/clis/doubao/new.ts +1 -1
- package/src/clis/doubao/read.ts +1 -1
- package/src/clis/doubao/send.ts +1 -1
- package/src/clis/doubao/status.ts +1 -1
- package/src/clis/doubao-app/ask.ts +1 -1
- package/src/clis/doubao-app/new.ts +1 -1
- package/src/clis/doubao-app/read.ts +1 -1
- package/src/clis/doubao-app/send.ts +1 -1
- package/src/clis/grok/ask.test.ts +25 -0
- package/src/clis/grok/ask.ts +25 -12
- package/src/clis/jd/item.test.ts +35 -0
- package/src/clis/jd/item.ts +101 -0
- package/src/clis/jike/feed.ts +1 -1
- package/src/clis/jike/search.ts +1 -1
- package/src/clis/linkedin/search.ts +5 -4
- package/src/clis/linkedin/timeline.test.ts +99 -0
- package/src/clis/linkedin/timeline.ts +532 -0
- package/src/clis/medium/feed.ts +1 -1
- package/src/clis/medium/search.ts +1 -1
- package/src/clis/medium/user.ts +1 -1
- package/src/clis/medium/{shared.ts → utils.ts} +2 -1
- package/src/clis/pixiv/detail.yaml +49 -0
- package/src/clis/pixiv/download.test.ts +114 -0
- package/src/clis/pixiv/download.ts +91 -0
- package/src/clis/pixiv/illusts.test.ts +115 -0
- package/src/clis/pixiv/illusts.ts +78 -0
- package/src/clis/pixiv/ranking.yaml +53 -0
- package/src/clis/pixiv/search.test.ts +97 -0
- package/src/clis/pixiv/search.ts +53 -0
- package/src/clis/pixiv/test-utils.ts +29 -0
- package/src/clis/pixiv/user.yaml +46 -0
- package/src/clis/pixiv/utils.ts +62 -0
- package/src/clis/reddit/comment.ts +2 -1
- package/src/clis/reddit/read.test.ts +34 -0
- package/src/clis/reddit/read.ts +4 -3
- package/src/clis/reddit/save.ts +2 -1
- package/src/clis/reddit/saved.ts +6 -2
- package/src/clis/reddit/subscribe.ts +2 -1
- package/src/clis/reddit/upvote.ts +2 -1
- package/src/clis/reddit/upvoted.ts +6 -2
- package/src/clis/sinablog/article.ts +1 -1
- package/src/clis/sinablog/hot.ts +1 -1
- package/src/clis/sinablog/user.ts +1 -1
- package/src/clis/substack/feed.ts +1 -1
- package/src/clis/substack/publication.ts +1 -1
- package/src/clis/substack/search.ts +3 -2
- package/src/clis/substack/{shared.ts → utils.ts} +3 -2
- package/src/clis/tiktok/search.yaml +2 -1
- package/src/clis/twitter/accept.ts +2 -1
- package/src/clis/twitter/article.ts +3 -1
- package/src/clis/twitter/block.ts +2 -1
- package/src/clis/twitter/bookmark.ts +2 -1
- package/src/clis/twitter/bookmarks.ts +3 -2
- package/src/clis/twitter/delete.ts +2 -1
- package/src/clis/twitter/follow.ts +2 -1
- package/src/clis/twitter/followers.ts +3 -2
- package/src/clis/twitter/following.ts +3 -2
- package/src/clis/twitter/hide-reply.ts +2 -1
- package/src/clis/twitter/like.ts +2 -1
- package/src/clis/twitter/notifications.ts +2 -1
- package/src/clis/twitter/post.ts +2 -1
- package/src/clis/twitter/profile.ts +4 -2
- package/src/clis/twitter/reply-dm.ts +2 -1
- package/src/clis/twitter/reply.ts +2 -1
- package/src/clis/twitter/search.test.ts +113 -0
- package/src/clis/twitter/search.ts +38 -14
- package/src/clis/twitter/thread.ts +2 -2
- package/src/clis/twitter/timeline.ts +3 -2
- package/src/clis/twitter/trending.ts +3 -2
- package/src/clis/twitter/unblock.ts +2 -1
- package/src/clis/twitter/unbookmark.ts +2 -1
- package/src/clis/twitter/unfollow.ts +2 -1
- package/src/clis/v2ex/daily.ts +3 -2
- package/src/clis/v2ex/me.ts +3 -2
- package/src/clis/v2ex/notifications.ts +3 -4
- package/src/clis/web/read.ts +210 -0
- package/src/clis/xueqiu/danjuan-utils.test.ts +49 -0
- package/src/clis/xueqiu/danjuan-utils.ts +176 -0
- package/src/clis/xueqiu/fund-holdings.ts +32 -0
- package/src/clis/xueqiu/fund-snapshot.ts +27 -0
- package/src/clis/youtube/transcript.ts +5 -4
- package/src/clis/youtube/video.ts +3 -2
- package/src/daemon.ts +5 -4
- package/src/discovery.ts +12 -34
- package/src/doctor.ts +3 -2
- package/src/download/index.test.ts +93 -2
- package/src/download/index.ts +44 -23
- package/src/download/media-download.ts +5 -3
- package/src/engine.test.ts +84 -3
- package/src/execution.ts +62 -46
- package/src/explore.ts +21 -90
- package/src/external-clis.yaml +0 -8
- package/src/external.test.ts +9 -0
- package/src/external.ts +12 -10
- package/src/generate.ts +4 -41
- package/src/hooks.test.ts +126 -0
- package/src/hooks.ts +90 -0
- package/src/interceptor.ts +73 -23
- package/src/main.ts +2 -0
- package/src/output.ts +14 -6
- package/src/pipeline/executor.ts +1 -1
- package/src/pipeline/steps/browser.ts +1 -3
- package/src/pipeline/steps/download.test.ts +136 -0
- package/src/pipeline/steps/download.ts +47 -34
- package/src/pipeline/steps/fetch.test.ts +179 -0
- package/src/pipeline/steps/fetch.ts +39 -23
- package/src/pipeline/steps/transform.ts +2 -6
- package/src/pipeline/template.test.ts +28 -0
- package/src/pipeline/template.ts +67 -79
- package/src/pipeline/transform.test.ts +20 -0
- package/src/plugin.test.ts +251 -3
- package/src/plugin.ts +265 -21
- package/src/record.ts +12 -84
- package/src/registry-api.ts +2 -0
- package/src/registry.ts +7 -4
- package/src/runtime.ts +14 -4
- package/src/snapshotFormatter.ts +43 -121
- package/src/utils.ts +39 -0
- package/src/validate.ts +3 -5
- package/src/yaml-schema.ts +28 -0
- package/tests/e2e/browser-auth.test.ts +25 -0
- package/tests/e2e/plugin-management.test.ts +137 -0
- package/tests/e2e/public-commands.test.ts +34 -1
- package/vitest.config.ts +19 -1
- package/.github/workflows/pkg-pr-new.yml +0 -30
- package/dist/clis/douban/shared.d.ts +0 -4
- package/dist/clis/douban/shared.js +0 -155
- package/src/clis/douban/shared.ts +0 -165
- /package/dist/clis/boss/{common.d.ts → utils.d.ts} +0 -0
- /package/dist/clis/boss/{common.js → utils.js} +0 -0
- /package/dist/clis/doubao/{common.d.ts → utils.d.ts} +0 -0
- /package/dist/clis/doubao/{common.js → utils.js} +0 -0
- /package/dist/clis/doubao-app/{common.d.ts → utils.d.ts} +0 -0
- /package/dist/clis/doubao-app/{common.js → utils.js} +0 -0
- /package/dist/clis/jike/{shared.d.ts → utils.d.ts} +0 -0
- /package/dist/clis/jike/{shared.js → utils.js} +0 -0
- /package/dist/clis/medium/{shared.d.ts → utils.d.ts} +0 -0
- /package/dist/clis/sinablog/{shared.d.ts → utils.d.ts} +0 -0
- /package/dist/clis/sinablog/{shared.js → utils.js} +0 -0
- /package/dist/clis/substack/{shared.d.ts → utils.d.ts} +0 -0
- /package/src/clis/boss/{common.ts → utils.ts} +0 -0
- /package/src/clis/doubao/{common.ts → utils.ts} +0 -0
- /package/src/clis/doubao-app/{common.ts → utils.ts} +0 -0
- /package/src/clis/jike/{shared.ts → utils.ts} +0 -0
- /package/src/clis/sinablog/{shared.ts → utils.ts} +0 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pixiv shared helpers: authenticated Ajax fetch with standard error handling.
|
|
3
|
+
*
|
|
4
|
+
* All Pixiv Ajax APIs return `{ error: false, body: ... }` on success.
|
|
5
|
+
* On failure the HTTP status code is used to distinguish auth (401/403),
|
|
6
|
+
* not-found (404), and other errors.
|
|
7
|
+
*/
|
|
8
|
+
import { AuthRequiredError, CommandExecutionError } from '../../errors.js';
|
|
9
|
+
const PIXIV_DOMAIN = 'www.pixiv.net';
|
|
10
|
+
/**
|
|
11
|
+
* Navigate to Pixiv (to attach cookies) then fetch a Pixiv Ajax API endpoint.
|
|
12
|
+
*
|
|
13
|
+
* Handles the common navigate → evaluate(fetch) → error-check pattern used
|
|
14
|
+
* by every Pixiv TS adapter.
|
|
15
|
+
*
|
|
16
|
+
* @param page - Browser page instance
|
|
17
|
+
* @param path - API path, e.g. '/ajax/illust/12345'
|
|
18
|
+
* @param opts - Optional query params
|
|
19
|
+
* @returns - The parsed `body` from the JSON response
|
|
20
|
+
* @throws AuthRequiredError on 401/403
|
|
21
|
+
* @throws CommandExecutionError on 404 or other HTTP errors
|
|
22
|
+
*/
|
|
23
|
+
export async function pixivFetch(page, path, opts = {}) {
|
|
24
|
+
await page.goto(`https://${PIXIV_DOMAIN}`);
|
|
25
|
+
const qs = opts.params
|
|
26
|
+
? '?' + Object.entries(opts.params).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&')
|
|
27
|
+
: '';
|
|
28
|
+
const url = `https://${PIXIV_DOMAIN}${path}${qs}`;
|
|
29
|
+
const data = await page.evaluate(`
|
|
30
|
+
(async () => {
|
|
31
|
+
const res = await fetch(${JSON.stringify(url)}, { credentials: 'include' });
|
|
32
|
+
if (!res.ok) return { __httpError: res.status };
|
|
33
|
+
return await res.json();
|
|
34
|
+
})()
|
|
35
|
+
`);
|
|
36
|
+
if (data?.__httpError) {
|
|
37
|
+
const status = data.__httpError;
|
|
38
|
+
if (status === 401 || status === 403) {
|
|
39
|
+
throw new AuthRequiredError(PIXIV_DOMAIN, 'Authentication required — please log in to Pixiv in Chrome');
|
|
40
|
+
}
|
|
41
|
+
if (status === 404) {
|
|
42
|
+
throw new CommandExecutionError(opts.notFoundMsg || `Pixiv resource not found (HTTP 404)`);
|
|
43
|
+
}
|
|
44
|
+
throw new CommandExecutionError(`Pixiv request failed (HTTP ${status})`);
|
|
45
|
+
}
|
|
46
|
+
return data?.body;
|
|
47
|
+
}
|
|
48
|
+
/** Maximum number of illust IDs per batch detail request (Pixiv server limit). */
|
|
49
|
+
export const BATCH_SIZE = 48;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CommandExecutionError } from '../../errors.js';
|
|
1
2
|
import { cli, Strategy } from '../../registry.js';
|
|
2
3
|
cli({
|
|
3
4
|
site: 'reddit',
|
|
@@ -13,7 +14,7 @@ cli({
|
|
|
13
14
|
columns: ['status', 'message'],
|
|
14
15
|
func: async (page, kwargs) => {
|
|
15
16
|
if (!page)
|
|
16
|
-
throw new
|
|
17
|
+
throw new CommandExecutionError('Browser session required');
|
|
17
18
|
await page.goto('https://www.reddit.com');
|
|
18
19
|
const result = await page.evaluate(`(async () => {
|
|
19
20
|
try {
|
package/dist/clis/reddit/read.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* - Indented output showing conversation threads
|
|
8
8
|
*/
|
|
9
9
|
import { cli, Strategy } from '../../registry.js';
|
|
10
|
+
import { CommandExecutionError } from '../../errors.js';
|
|
10
11
|
cli({
|
|
11
12
|
site: 'reddit',
|
|
12
13
|
name: 'read',
|
|
@@ -173,11 +174,11 @@ cli({
|
|
|
173
174
|
})()
|
|
174
175
|
`);
|
|
175
176
|
if (!data || typeof data !== 'object')
|
|
176
|
-
throw new
|
|
177
|
+
throw new CommandExecutionError('Failed to fetch post data');
|
|
177
178
|
if (!Array.isArray(data) && data.error)
|
|
178
|
-
throw new
|
|
179
|
+
throw new CommandExecutionError(data.error);
|
|
179
180
|
if (!Array.isArray(data))
|
|
180
|
-
throw new
|
|
181
|
+
throw new CommandExecutionError('Unexpected response');
|
|
181
182
|
return data;
|
|
182
183
|
},
|
|
183
184
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import './read.js';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { getRegistry } from '../../registry.js';
|
|
3
|
+
import './read.js';
|
|
4
|
+
describe('reddit read adapter', () => {
|
|
5
|
+
const command = getRegistry().get('reddit/read');
|
|
6
|
+
it('returns threaded rows from the browser-evaluated payload', async () => {
|
|
7
|
+
const page = {
|
|
8
|
+
goto: vi.fn().mockResolvedValue(undefined),
|
|
9
|
+
evaluate: vi.fn().mockResolvedValue([
|
|
10
|
+
{ type: 'POST', author: 'alice', score: 10, text: 'Title' },
|
|
11
|
+
{ type: 'L0', author: 'bob', score: 5, text: 'Comment' },
|
|
12
|
+
]),
|
|
13
|
+
};
|
|
14
|
+
const result = await command.func(page, { 'post-id': 'abc123', limit: 5 });
|
|
15
|
+
expect(page.goto).toHaveBeenCalledWith('https://www.reddit.com');
|
|
16
|
+
expect(result).toEqual([
|
|
17
|
+
{ type: 'POST', author: 'alice', score: 10, text: 'Title' },
|
|
18
|
+
{ type: 'L0', author: 'bob', score: 5, text: 'Comment' },
|
|
19
|
+
]);
|
|
20
|
+
});
|
|
21
|
+
it('surfaces adapter-level API errors clearly', async () => {
|
|
22
|
+
const page = {
|
|
23
|
+
goto: vi.fn().mockResolvedValue(undefined),
|
|
24
|
+
evaluate: vi.fn().mockResolvedValue({ error: 'Reddit API returned HTTP 403' }),
|
|
25
|
+
};
|
|
26
|
+
await expect(command.func(page, { 'post-id': 'abc123' })).rejects.toThrow('Reddit API returned HTTP 403');
|
|
27
|
+
});
|
|
28
|
+
});
|
package/dist/clis/reddit/save.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CommandExecutionError } from '../../errors.js';
|
|
1
2
|
import { cli, Strategy } from '../../registry.js';
|
|
2
3
|
cli({
|
|
3
4
|
site: 'reddit',
|
|
@@ -13,7 +14,7 @@ cli({
|
|
|
13
14
|
columns: ['status', 'message'],
|
|
14
15
|
func: async (page, kwargs) => {
|
|
15
16
|
if (!page)
|
|
16
|
-
throw new
|
|
17
|
+
throw new CommandExecutionError('Browser session required');
|
|
17
18
|
await page.goto('https://www.reddit.com');
|
|
18
19
|
const result = await page.evaluate(`(async () => {
|
|
19
20
|
try {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AuthRequiredError, CommandExecutionError } from '../../errors.js';
|
|
1
2
|
import { cli, Strategy } from '../../registry.js';
|
|
2
3
|
cli({
|
|
3
4
|
site: 'reddit',
|
|
@@ -12,7 +13,7 @@ cli({
|
|
|
12
13
|
columns: ['title', 'subreddit', 'score', 'comments', 'url'],
|
|
13
14
|
func: async (page, kwargs) => {
|
|
14
15
|
if (!page)
|
|
15
|
-
throw new
|
|
16
|
+
throw new CommandExecutionError('Browser session required');
|
|
16
17
|
await page.goto('https://www.reddit.com');
|
|
17
18
|
const result = await page.evaluate(`(async () => {
|
|
18
19
|
try {
|
|
@@ -38,8 +39,11 @@ cli({
|
|
|
38
39
|
return { error: e.toString() };
|
|
39
40
|
}
|
|
40
41
|
})()`);
|
|
41
|
-
if (result?.error)
|
|
42
|
-
|
|
42
|
+
if (result?.error) {
|
|
43
|
+
if (String(result.error).includes('Not logged in'))
|
|
44
|
+
throw new AuthRequiredError('reddit.com', result.error);
|
|
45
|
+
throw new CommandExecutionError(result.error);
|
|
46
|
+
}
|
|
43
47
|
return (result || []).slice(0, kwargs.limit);
|
|
44
48
|
}
|
|
45
49
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CommandExecutionError } from '../../errors.js';
|
|
1
2
|
import { cli, Strategy } from '../../registry.js';
|
|
2
3
|
cli({
|
|
3
4
|
site: 'reddit',
|
|
@@ -13,7 +14,7 @@ cli({
|
|
|
13
14
|
columns: ['status', 'message'],
|
|
14
15
|
func: async (page, kwargs) => {
|
|
15
16
|
if (!page)
|
|
16
|
-
throw new
|
|
17
|
+
throw new CommandExecutionError('Browser session required');
|
|
17
18
|
await page.goto('https://www.reddit.com');
|
|
18
19
|
const result = await page.evaluate(`(async () => {
|
|
19
20
|
try {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CommandExecutionError } from '../../errors.js';
|
|
1
2
|
import { cli, Strategy } from '../../registry.js';
|
|
2
3
|
cli({
|
|
3
4
|
site: 'reddit',
|
|
@@ -13,7 +14,7 @@ cli({
|
|
|
13
14
|
columns: ['status', 'message'],
|
|
14
15
|
func: async (page, kwargs) => {
|
|
15
16
|
if (!page)
|
|
16
|
-
throw new
|
|
17
|
+
throw new CommandExecutionError('Browser session required');
|
|
17
18
|
await page.goto('https://www.reddit.com');
|
|
18
19
|
const result = await page.evaluate(`(async () => {
|
|
19
20
|
try {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AuthRequiredError, CommandExecutionError } from '../../errors.js';
|
|
1
2
|
import { cli, Strategy } from '../../registry.js';
|
|
2
3
|
cli({
|
|
3
4
|
site: 'reddit',
|
|
@@ -12,7 +13,7 @@ cli({
|
|
|
12
13
|
columns: ['title', 'subreddit', 'score', 'comments', 'url'],
|
|
13
14
|
func: async (page, kwargs) => {
|
|
14
15
|
if (!page)
|
|
15
|
-
throw new
|
|
16
|
+
throw new CommandExecutionError('Browser session required');
|
|
16
17
|
await page.goto('https://www.reddit.com');
|
|
17
18
|
const result = await page.evaluate(`(async () => {
|
|
18
19
|
try {
|
|
@@ -38,8 +39,11 @@ cli({
|
|
|
38
39
|
return { error: e.toString() };
|
|
39
40
|
}
|
|
40
41
|
})()`);
|
|
41
|
-
if (result?.error)
|
|
42
|
-
|
|
42
|
+
if (result?.error) {
|
|
43
|
+
if (String(result.error).includes('Not logged in'))
|
|
44
|
+
throw new AuthRequiredError('reddit.com', result.error);
|
|
45
|
+
throw new CommandExecutionError(result.error);
|
|
46
|
+
}
|
|
43
47
|
return (result || []).slice(0, kwargs.limit);
|
|
44
48
|
}
|
|
45
49
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CommandExecutionError } from '../../errors.js';
|
|
1
2
|
import { cli, Strategy } from '../../registry.js';
|
|
2
3
|
function headers() {
|
|
3
4
|
return {
|
|
@@ -22,7 +23,7 @@ async function searchPosts(keyword, limit) {
|
|
|
22
23
|
url.searchParams.set('includePlatformResults', 'true');
|
|
23
24
|
const resp = await fetch(url, { headers: headers() });
|
|
24
25
|
if (!resp.ok)
|
|
25
|
-
throw new
|
|
26
|
+
throw new CommandExecutionError(`Substack post search failed: HTTP ${resp.status}`);
|
|
26
27
|
const data = await resp.json();
|
|
27
28
|
const results = Array.isArray(data?.results) ? data.results : [];
|
|
28
29
|
return results.slice(0, limit).map((item, index) => ({
|
|
@@ -40,7 +41,7 @@ async function searchPublications(keyword, limit) {
|
|
|
40
41
|
url.searchParams.set('page', '0');
|
|
41
42
|
const resp = await fetch(url, { headers: headers() });
|
|
42
43
|
if (!resp.ok)
|
|
43
|
-
throw new
|
|
44
|
+
throw new CommandExecutionError(`Substack publication search failed: HTTP ${resp.status}`);
|
|
44
45
|
const data = await resp.json();
|
|
45
46
|
const results = Array.isArray(data?.results) ? data.results : [];
|
|
46
47
|
return results.slice(0, limit).map((item, index) => {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CommandExecutionError } from '../../errors.js';
|
|
1
2
|
export function buildSubstackBrowseUrl(category) {
|
|
2
3
|
if (!category || category === 'all')
|
|
3
4
|
return 'https://substack.com/';
|
|
@@ -6,7 +7,7 @@ export function buildSubstackBrowseUrl(category) {
|
|
|
6
7
|
}
|
|
7
8
|
export async function loadSubstackFeed(page, url, limit) {
|
|
8
9
|
if (!page)
|
|
9
|
-
throw new
|
|
10
|
+
throw new CommandExecutionError('Browser session required for substack feed');
|
|
10
11
|
await page.goto(url);
|
|
11
12
|
await page.wait(5);
|
|
12
13
|
const data = await page.evaluate(`
|
|
@@ -74,7 +75,7 @@ export async function loadSubstackFeed(page, url, limit) {
|
|
|
74
75
|
}
|
|
75
76
|
export async function loadSubstackArchive(page, baseUrl, limit) {
|
|
76
77
|
if (!page)
|
|
77
|
-
throw new
|
|
78
|
+
throw new CommandExecutionError('Browser session required for substack archive');
|
|
78
79
|
await page.goto(`${baseUrl}/archive`);
|
|
79
80
|
await page.wait(5);
|
|
80
81
|
const data = await page.evaluate(`
|
|
@@ -35,6 +35,7 @@ pipeline:
|
|
|
35
35
|
rank: idx + 1,
|
|
36
36
|
desc: (v.desc || '').replace(/\n/g, ' ').substring(0, 100),
|
|
37
37
|
author: a.uniqueId || '',
|
|
38
|
+
url: (a.uniqueId && v.id) ? 'https://www.tiktok.com/@' + a.uniqueId + '/video/' + v.id : '',
|
|
38
39
|
plays: s.playCount || 0,
|
|
39
40
|
likes: s.diggCount || 0,
|
|
40
41
|
comments: s.commentCount || 0,
|
|
@@ -43,4 +44,4 @@ pipeline:
|
|
|
43
44
|
});
|
|
44
45
|
})()
|
|
45
46
|
|
|
46
|
-
columns: [rank, desc, author, plays, likes, comments, shares]
|
|
47
|
+
columns: [rank, desc, author, url, plays, likes, comments, shares]
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CommandExecutionError } from '../../errors.js';
|
|
1
2
|
import { cli, Strategy } from '../../registry.js';
|
|
2
3
|
cli({
|
|
3
4
|
site: 'twitter',
|
|
@@ -14,7 +15,7 @@ cli({
|
|
|
14
15
|
columns: ['index', 'status', 'user', 'message'],
|
|
15
16
|
func: async (page, kwargs) => {
|
|
16
17
|
if (!page)
|
|
17
|
-
throw new
|
|
18
|
+
throw new CommandExecutionError('Browser session required for twitter accept');
|
|
18
19
|
const keywords = kwargs.query.split(',').map((k) => k.trim()).filter(Boolean);
|
|
19
20
|
const maxAccepts = kwargs.max ?? 20;
|
|
20
21
|
const results = [];
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AuthRequiredError, CommandExecutionError } from '../../errors.js';
|
|
1
2
|
import { cli, Strategy } from '../../registry.js';
|
|
2
3
|
cli({
|
|
3
4
|
site: 'twitter',
|
|
@@ -150,7 +151,9 @@ cli({
|
|
|
150
151
|
}
|
|
151
152
|
`);
|
|
152
153
|
if (result?.error) {
|
|
153
|
-
|
|
154
|
+
if (String(result.error).includes('No ct0 cookie'))
|
|
155
|
+
throw new AuthRequiredError('x.com', result.error);
|
|
156
|
+
throw new CommandExecutionError(result.error + (result.hint ? ` (${result.hint})` : ''));
|
|
154
157
|
}
|
|
155
158
|
return result || [];
|
|
156
159
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CommandExecutionError } from '../../errors.js';
|
|
1
2
|
import { cli, Strategy } from '../../registry.js';
|
|
2
3
|
cli({
|
|
3
4
|
site: 'twitter',
|
|
@@ -12,7 +13,7 @@ cli({
|
|
|
12
13
|
columns: ['status', 'message'],
|
|
13
14
|
func: async (page, kwargs) => {
|
|
14
15
|
if (!page)
|
|
15
|
-
throw new
|
|
16
|
+
throw new CommandExecutionError('Browser session required for twitter block');
|
|
16
17
|
const username = kwargs.username.replace(/^@/, '');
|
|
17
18
|
await page.goto(`https://x.com/${username}`);
|
|
18
19
|
await page.wait(5);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CommandExecutionError } from '../../errors.js';
|
|
1
2
|
import { cli, Strategy } from '../../registry.js';
|
|
2
3
|
cli({
|
|
3
4
|
site: 'twitter',
|
|
@@ -12,7 +13,7 @@ cli({
|
|
|
12
13
|
columns: ['status', 'message'],
|
|
13
14
|
func: async (page, kwargs) => {
|
|
14
15
|
if (!page)
|
|
15
|
-
throw new
|
|
16
|
+
throw new CommandExecutionError('Browser session required for twitter bookmark');
|
|
16
17
|
await page.goto(kwargs.url);
|
|
17
18
|
await page.wait(5);
|
|
18
19
|
const result = await page.evaluate(`(async () => {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { cli, Strategy } from '../../registry.js';
|
|
2
|
+
import { AuthRequiredError, CommandExecutionError } from '../../errors.js';
|
|
2
3
|
const BEARER_TOKEN = 'AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA';
|
|
3
4
|
const BOOKMARKS_QUERY_ID = 'Fy0QMy4q_aZCpkO0PnyLYw';
|
|
4
5
|
const FEATURES = {
|
|
@@ -114,7 +115,7 @@ cli({
|
|
|
114
115
|
return document.cookie.split(';').map(c => c.trim()).find(c => c.startsWith('ct0='))?.split('=')[1] || null;
|
|
115
116
|
}`);
|
|
116
117
|
if (!ct0)
|
|
117
|
-
throw new
|
|
118
|
+
throw new AuthRequiredError('x.com', 'Not logged into x.com (no ct0 cookie)');
|
|
118
119
|
const queryId = await page.evaluate(`async () => {
|
|
119
120
|
try {
|
|
120
121
|
const ghResp = await fetch('https://raw.githubusercontent.com/fa0311/twitter-openapi/refs/heads/main/src/config/placeholder.json');
|
|
@@ -157,7 +158,7 @@ cli({
|
|
|
157
158
|
}`);
|
|
158
159
|
if (data?.error) {
|
|
159
160
|
if (allTweets.length === 0)
|
|
160
|
-
throw new
|
|
161
|
+
throw new CommandExecutionError(`HTTP ${data.error}: Failed to fetch bookmarks. queryId may have expired.`);
|
|
161
162
|
break;
|
|
162
163
|
}
|
|
163
164
|
const { tweets, nextCursor } = parseBookmarks(data, seen);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { cli, Strategy } from '../../registry.js';
|
|
2
|
+
import { CommandExecutionError } from '../../errors.js';
|
|
2
3
|
cli({
|
|
3
4
|
site: 'twitter',
|
|
4
5
|
name: 'delete',
|
|
@@ -12,7 +13,7 @@ cli({
|
|
|
12
13
|
columns: ['status', 'message'],
|
|
13
14
|
func: async (page, kwargs) => {
|
|
14
15
|
if (!page)
|
|
15
|
-
throw new
|
|
16
|
+
throw new CommandExecutionError('Browser session required for twitter delete');
|
|
16
17
|
await page.goto(kwargs.url);
|
|
17
18
|
await page.wait(5); // Wait for tweet to load completely
|
|
18
19
|
const result = await page.evaluate(`(async () => {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CommandExecutionError } from '../../errors.js';
|
|
1
2
|
import { cli, Strategy } from '../../registry.js';
|
|
2
3
|
cli({
|
|
3
4
|
site: 'twitter',
|
|
@@ -12,7 +13,7 @@ cli({
|
|
|
12
13
|
columns: ['status', 'message'],
|
|
13
14
|
func: async (page, kwargs) => {
|
|
14
15
|
if (!page)
|
|
15
|
-
throw new
|
|
16
|
+
throw new CommandExecutionError('Browser session required for twitter follow');
|
|
16
17
|
const username = kwargs.username.replace(/^@/, '');
|
|
17
18
|
await page.goto(`https://x.com/${username}`);
|
|
18
19
|
await page.wait(5);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AuthRequiredError, SelectorError } from '../../errors.js';
|
|
1
2
|
import { cli, Strategy } from '../../registry.js';
|
|
2
3
|
cli({
|
|
3
4
|
site: 'twitter',
|
|
@@ -22,7 +23,7 @@ cli({
|
|
|
22
23
|
return link ? link.getAttribute('href') : null;
|
|
23
24
|
}`);
|
|
24
25
|
if (!href) {
|
|
25
|
-
throw new
|
|
26
|
+
throw new AuthRequiredError('x.com', 'Could not find logged-in user profile link. Are you logged in?');
|
|
26
27
|
}
|
|
27
28
|
targetUser = href.replace('/', '');
|
|
28
29
|
}
|
|
@@ -48,7 +49,7 @@ cli({
|
|
|
48
49
|
return false;
|
|
49
50
|
}`);
|
|
50
51
|
if (!clicked) {
|
|
51
|
-
throw new
|
|
52
|
+
throw new SelectorError('Twitter followers link', 'Twitter may have changed the layout.');
|
|
52
53
|
}
|
|
53
54
|
await page.wait(5);
|
|
54
55
|
// 4. Scroll to trigger pagination API calls
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AuthRequiredError, SelectorError } from '../../errors.js';
|
|
1
2
|
import { cli, Strategy } from '../../registry.js';
|
|
2
3
|
cli({
|
|
3
4
|
site: 'twitter',
|
|
@@ -22,7 +23,7 @@ cli({
|
|
|
22
23
|
return link ? link.getAttribute('href') : null;
|
|
23
24
|
}`);
|
|
24
25
|
if (!href) {
|
|
25
|
-
throw new
|
|
26
|
+
throw new AuthRequiredError('x.com', 'Could not find logged-in user profile link. Are you logged in?');
|
|
26
27
|
}
|
|
27
28
|
targetUser = href.replace('/', '');
|
|
28
29
|
}
|
|
@@ -41,7 +42,7 @@ cli({
|
|
|
41
42
|
return false;
|
|
42
43
|
}`);
|
|
43
44
|
if (!clicked) {
|
|
44
|
-
throw new
|
|
45
|
+
throw new SelectorError('Twitter following link', 'Twitter may have changed the layout.');
|
|
45
46
|
}
|
|
46
47
|
await page.wait(5);
|
|
47
48
|
// 4. Scroll to trigger pagination API calls
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CommandExecutionError } from '../../errors.js';
|
|
1
2
|
import { cli, Strategy } from '../../registry.js';
|
|
2
3
|
cli({
|
|
3
4
|
site: 'twitter',
|
|
@@ -12,7 +13,7 @@ cli({
|
|
|
12
13
|
columns: ['status', 'message'],
|
|
13
14
|
func: async (page, kwargs) => {
|
|
14
15
|
if (!page)
|
|
15
|
-
throw new
|
|
16
|
+
throw new CommandExecutionError('Browser session required for twitter hide-reply');
|
|
16
17
|
await page.goto(kwargs.url);
|
|
17
18
|
await page.wait(5);
|
|
18
19
|
const result = await page.evaluate(`(async () => {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CommandExecutionError } from '../../errors.js';
|
|
1
2
|
import { cli, Strategy } from '../../registry.js';
|
|
2
3
|
cli({
|
|
3
4
|
site: 'twitter',
|
|
@@ -12,7 +13,7 @@ cli({
|
|
|
12
13
|
columns: ['status', 'message'],
|
|
13
14
|
func: async (page, kwargs) => {
|
|
14
15
|
if (!page)
|
|
15
|
-
throw new
|
|
16
|
+
throw new CommandExecutionError('Browser session required for twitter like');
|
|
16
17
|
await page.goto(kwargs.url);
|
|
17
18
|
await page.wait(5); // Wait for tweet to load completely
|
|
18
19
|
const result = await page.evaluate(`(async () => {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CommandExecutionError } from '../../errors.js';
|
|
1
2
|
import { cli, Strategy } from '../../registry.js';
|
|
2
3
|
cli({
|
|
3
4
|
site: 'twitter',
|
|
@@ -25,7 +26,7 @@ cli({
|
|
|
25
26
|
// Verify SPA navigation succeeded
|
|
26
27
|
const currentUrl = await page.evaluate('() => window.location.pathname');
|
|
27
28
|
if (currentUrl !== '/notifications') {
|
|
28
|
-
throw new
|
|
29
|
+
throw new CommandExecutionError('SPA navigation to notifications failed. Twitter may have changed its routing.');
|
|
29
30
|
}
|
|
30
31
|
// 4. Scroll to trigger pagination
|
|
31
32
|
await page.autoScroll({ times: 2, delayMs: 2000 });
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { cli, Strategy } from '../../registry.js';
|
|
2
|
+
import { CommandExecutionError } from '../../errors.js';
|
|
2
3
|
cli({
|
|
3
4
|
site: 'twitter',
|
|
4
5
|
name: 'post',
|
|
@@ -12,7 +13,7 @@ cli({
|
|
|
12
13
|
columns: ['status', 'message', 'text'],
|
|
13
14
|
func: async (page, kwargs) => {
|
|
14
15
|
if (!page)
|
|
15
|
-
throw new
|
|
16
|
+
throw new CommandExecutionError('Browser session required for twitter post');
|
|
16
17
|
// 1. Navigate directly to the compose tweet modal
|
|
17
18
|
await page.goto('https://x.com/compose/tweet');
|
|
18
19
|
await page.wait(3); // Wait for the modal and React app to hydrate
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AuthRequiredError, CommandExecutionError } from '../../errors.js';
|
|
1
2
|
import { cli, Strategy } from '../../registry.js';
|
|
2
3
|
cli({
|
|
3
4
|
site: 'twitter',
|
|
@@ -21,7 +22,7 @@ cli({
|
|
|
21
22
|
return link ? link.getAttribute('href') : null;
|
|
22
23
|
}`);
|
|
23
24
|
if (!href)
|
|
24
|
-
throw new
|
|
25
|
+
throw new AuthRequiredError('x.com', 'Could not detect logged-in user. Are you logged in?');
|
|
25
26
|
username = href.replace('/', '');
|
|
26
27
|
}
|
|
27
28
|
// Navigate directly to the user's profile page (gives us cookie context)
|
|
@@ -117,7 +118,9 @@ cli({
|
|
|
117
118
|
}
|
|
118
119
|
`);
|
|
119
120
|
if (result?.error) {
|
|
120
|
-
|
|
121
|
+
if (String(result.error).includes('No ct0 cookie'))
|
|
122
|
+
throw new AuthRequiredError('x.com', result.error);
|
|
123
|
+
throw new CommandExecutionError(result.error + (result.hint ? ` (${result.hint})` : ''));
|
|
121
124
|
}
|
|
122
125
|
return result || [];
|
|
123
126
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CommandExecutionError } from '../../errors.js';
|
|
1
2
|
import { cli, Strategy } from '../../registry.js';
|
|
2
3
|
cli({
|
|
3
4
|
site: 'twitter',
|
|
@@ -15,7 +16,7 @@ cli({
|
|
|
15
16
|
columns: ['index', 'status', 'user', 'message'],
|
|
16
17
|
func: async (page, kwargs) => {
|
|
17
18
|
if (!page)
|
|
18
|
-
throw new
|
|
19
|
+
throw new CommandExecutionError('Browser session required for twitter reply-dm');
|
|
19
20
|
const messageText = kwargs.text;
|
|
20
21
|
const maxSend = kwargs.max ?? 20;
|
|
21
22
|
const skipReplied = kwargs['skip-replied'] !== false;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CommandExecutionError } from '../../errors.js';
|
|
1
2
|
import { cli, Strategy } from '../../registry.js';
|
|
2
3
|
cli({
|
|
3
4
|
site: 'twitter',
|
|
@@ -13,7 +14,7 @@ cli({
|
|
|
13
14
|
columns: ['status', 'message', 'text'],
|
|
14
15
|
func: async (page, kwargs) => {
|
|
15
16
|
if (!page)
|
|
16
|
-
throw new
|
|
17
|
+
throw new CommandExecutionError('Browser session required for twitter reply');
|
|
17
18
|
// 1. Navigate to the tweet page
|
|
18
19
|
await page.goto(kwargs.url);
|
|
19
20
|
await page.wait(5); // Wait for the react application to hydrate
|