@zenalexa/unicli 0.220.0 → 0.221.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/AGENTS.md +35 -22
- package/README.md +23 -17
- package/README.zh-CN.md +23 -17
- package/dist/adapters/anilist/web.d.ts +11 -0
- package/dist/adapters/anilist/web.d.ts.map +1 -0
- package/dist/adapters/anilist/web.js +284 -0
- package/dist/adapters/anilist/web.js.map +1 -0
- package/dist/adapters/bangumi/web.d.ts +14 -0
- package/dist/adapters/bangumi/web.d.ts.map +1 -0
- package/dist/adapters/bangumi/web.js +257 -0
- package/dist/adapters/bangumi/web.js.map +1 -0
- package/dist/adapters/bilibili/comments.js +66 -4
- package/dist/adapters/bilibili/comments.js.map +1 -1
- package/dist/adapters/bilibili/compat.js +2 -2
- package/dist/adapters/bilibili/compat.js.map +1 -1
- package/dist/adapters/bilibili/download.js +4 -4
- package/dist/adapters/bilibili/download.js.map +1 -1
- package/dist/adapters/bilibili/wbi.d.ts.map +1 -1
- package/dist/adapters/bilibili/wbi.js +3 -3
- package/dist/adapters/bilibili/wbi.js.map +1 -1
- package/dist/adapters/cipo/_shared.d.ts +21 -0
- package/dist/adapters/cipo/_shared.d.ts.map +1 -0
- package/dist/adapters/cipo/_shared.js +67 -0
- package/dist/adapters/cipo/_shared.js.map +1 -0
- package/dist/adapters/cipo/get.d.ts +19 -0
- package/dist/adapters/cipo/get.d.ts.map +1 -0
- package/dist/adapters/cipo/get.js +140 -0
- package/dist/adapters/cipo/get.js.map +1 -0
- package/dist/adapters/cipo/legal-status.d.ts +19 -0
- package/dist/adapters/cipo/legal-status.d.ts.map +1 -0
- package/dist/adapters/cipo/legal-status.js +111 -0
- package/dist/adapters/cipo/legal-status.js.map +1 -0
- package/dist/adapters/cipo/search.d.ts +20 -0
- package/dist/adapters/cipo/search.d.ts.map +1 -0
- package/dist/adapters/cipo/search.js +148 -0
- package/dist/adapters/cipo/search.js.map +1 -0
- package/dist/adapters/cnipa/_shared.d.ts +47 -0
- package/dist/adapters/cnipa/_shared.d.ts.map +1 -0
- package/dist/adapters/cnipa/_shared.js +97 -0
- package/dist/adapters/cnipa/_shared.js.map +1 -0
- package/dist/adapters/cnipa/get.d.ts +19 -0
- package/dist/adapters/cnipa/get.d.ts.map +1 -0
- package/dist/adapters/cnipa/get.js +149 -0
- package/dist/adapters/cnipa/get.js.map +1 -0
- package/dist/adapters/cnipa/legal-status.d.ts +19 -0
- package/dist/adapters/cnipa/legal-status.d.ts.map +1 -0
- package/dist/adapters/cnipa/legal-status.js +119 -0
- package/dist/adapters/cnipa/legal-status.js.map +1 -0
- package/dist/adapters/cnipa/search.d.ts +21 -0
- package/dist/adapters/cnipa/search.d.ts.map +1 -0
- package/dist/adapters/cnipa/search.js +170 -0
- package/dist/adapters/cnipa/search.js.map +1 -0
- package/dist/adapters/dlsite/web.d.ts +31 -0
- package/dist/adapters/dlsite/web.d.ts.map +1 -0
- package/dist/adapters/dlsite/web.js +455 -0
- package/dist/adapters/dlsite/web.js.map +1 -0
- package/dist/adapters/ehentai/web.d.ts +66 -0
- package/dist/adapters/ehentai/web.d.ts.map +1 -0
- package/dist/adapters/ehentai/web.js +608 -0
- package/dist/adapters/ehentai/web.js.map +1 -0
- package/dist/adapters/espacenet/_shared.d.ts +21 -0
- package/dist/adapters/espacenet/_shared.d.ts.map +1 -0
- package/dist/adapters/espacenet/_shared.js +67 -0
- package/dist/adapters/espacenet/_shared.js.map +1 -0
- package/dist/adapters/espacenet/family.d.ts +19 -0
- package/dist/adapters/espacenet/family.d.ts.map +1 -0
- package/dist/adapters/espacenet/family.js +118 -0
- package/dist/adapters/espacenet/family.js.map +1 -0
- package/dist/adapters/espacenet/get.d.ts +19 -0
- package/dist/adapters/espacenet/get.d.ts.map +1 -0
- package/dist/adapters/espacenet/get.js +130 -0
- package/dist/adapters/espacenet/get.js.map +1 -0
- package/dist/adapters/espacenet/legal-status.d.ts +19 -0
- package/dist/adapters/espacenet/legal-status.d.ts.map +1 -0
- package/dist/adapters/espacenet/legal-status.js +110 -0
- package/dist/adapters/espacenet/legal-status.js.map +1 -0
- package/dist/adapters/espacenet/search.d.ts +20 -0
- package/dist/adapters/espacenet/search.d.ts.map +1 -0
- package/dist/adapters/espacenet/search.js +165 -0
- package/dist/adapters/espacenet/search.js.map +1 -0
- package/dist/adapters/facebook/subtitles.d.ts +9 -0
- package/dist/adapters/facebook/subtitles.d.ts.map +1 -0
- package/dist/adapters/facebook/subtitles.js +42 -0
- package/dist/adapters/facebook/subtitles.js.map +1 -0
- package/dist/adapters/fips/_shared.d.ts +21 -0
- package/dist/adapters/fips/_shared.d.ts.map +1 -0
- package/dist/adapters/fips/_shared.js +77 -0
- package/dist/adapters/fips/_shared.js.map +1 -0
- package/dist/adapters/fips/get.d.ts +19 -0
- package/dist/adapters/fips/get.d.ts.map +1 -0
- package/dist/adapters/fips/get.js +139 -0
- package/dist/adapters/fips/get.js.map +1 -0
- package/dist/adapters/fips/search.d.ts +20 -0
- package/dist/adapters/fips/search.d.ts.map +1 -0
- package/dist/adapters/fips/search.js +148 -0
- package/dist/adapters/fips/search.js.map +1 -0
- package/dist/adapters/freepatentsonline-web/_shared.d.ts +72 -0
- package/dist/adapters/freepatentsonline-web/_shared.d.ts.map +1 -0
- package/dist/adapters/freepatentsonline-web/_shared.js +216 -0
- package/dist/adapters/freepatentsonline-web/_shared.js.map +1 -0
- package/dist/adapters/freepatentsonline-web/get.d.ts +21 -0
- package/dist/adapters/freepatentsonline-web/get.d.ts.map +1 -0
- package/dist/adapters/freepatentsonline-web/get.js +127 -0
- package/dist/adapters/freepatentsonline-web/get.js.map +1 -0
- package/dist/adapters/freepatentsonline-web/search.d.ts +22 -0
- package/dist/adapters/freepatentsonline-web/search.d.ts.map +1 -0
- package/dist/adapters/freepatentsonline-web/search.js +149 -0
- package/dist/adapters/freepatentsonline-web/search.js.map +1 -0
- package/dist/adapters/google-patents-web/_shared.d.ts +110 -0
- package/dist/adapters/google-patents-web/_shared.d.ts.map +1 -0
- package/dist/adapters/google-patents-web/_shared.js +164 -0
- package/dist/adapters/google-patents-web/_shared.js.map +1 -0
- package/dist/adapters/google-patents-web/get.d.ts +36 -0
- package/dist/adapters/google-patents-web/get.d.ts.map +1 -0
- package/dist/adapters/google-patents-web/get.js +187 -0
- package/dist/adapters/google-patents-web/get.js.map +1 -0
- package/dist/adapters/google-patents-web/search.d.ts +23 -0
- package/dist/adapters/google-patents-web/search.d.ts.map +1 -0
- package/dist/adapters/google-patents-web/search.js +169 -0
- package/dist/adapters/google-patents-web/search.js.map +1 -0
- package/dist/adapters/inpi-br/_shared.d.ts +21 -0
- package/dist/adapters/inpi-br/_shared.d.ts.map +1 -0
- package/dist/adapters/inpi-br/_shared.js +67 -0
- package/dist/adapters/inpi-br/_shared.js.map +1 -0
- package/dist/adapters/inpi-br/get.d.ts +19 -0
- package/dist/adapters/inpi-br/get.d.ts.map +1 -0
- package/dist/adapters/inpi-br/get.js +142 -0
- package/dist/adapters/inpi-br/get.js.map +1 -0
- package/dist/adapters/inpi-br/search.d.ts +20 -0
- package/dist/adapters/inpi-br/search.d.ts.map +1 -0
- package/dist/adapters/inpi-br/search.js +154 -0
- package/dist/adapters/inpi-br/search.js.map +1 -0
- package/dist/adapters/instagram/subtitles.d.ts +9 -0
- package/dist/adapters/instagram/subtitles.d.ts.map +1 -0
- package/dist/adapters/instagram/subtitles.js +42 -0
- package/dist/adapters/instagram/subtitles.js.map +1 -0
- package/dist/adapters/jikan/web.d.ts +9 -0
- package/dist/adapters/jikan/web.d.ts.map +1 -0
- package/dist/adapters/jikan/web.js +154 -0
- package/dist/adapters/jikan/web.js.map +1 -0
- package/dist/adapters/kitsu/web.d.ts +9 -0
- package/dist/adapters/kitsu/web.d.ts.map +1 -0
- package/dist/adapters/kitsu/web.js +97 -0
- package/dist/adapters/kitsu/web.js.map +1 -0
- package/dist/adapters/mangadex/web.d.ts +10 -0
- package/dist/adapters/mangadex/web.d.ts.map +1 -0
- package/dist/adapters/mangadex/web.js +188 -0
- package/dist/adapters/mangadex/web.js.map +1 -0
- package/dist/adapters/mastodon/statuses.d.ts +40 -0
- package/dist/adapters/mastodon/statuses.d.ts.map +1 -0
- package/dist/adapters/mastodon/statuses.js +153 -0
- package/dist/adapters/mastodon/statuses.js.map +1 -0
- package/dist/adapters/moegirl/web.d.ts +23 -0
- package/dist/adapters/moegirl/web.d.ts.map +1 -0
- package/dist/adapters/moegirl/web.js +269 -0
- package/dist/adapters/moegirl/web.js.map +1 -0
- package/dist/adapters/reddit/comments.d.ts +9 -0
- package/dist/adapters/reddit/comments.d.ts.map +1 -0
- package/dist/adapters/reddit/comments.js +124 -0
- package/dist/adapters/reddit/comments.js.map +1 -0
- package/dist/adapters/safebooru/web.d.ts +10 -0
- package/dist/adapters/safebooru/web.d.ts.map +1 -0
- package/dist/adapters/safebooru/web.js +120 -0
- package/dist/adapters/safebooru/web.js.map +1 -0
- package/dist/adapters/threads/post.d.ts +32 -0
- package/dist/adapters/threads/post.d.ts.map +1 -0
- package/dist/adapters/threads/post.js +287 -0
- package/dist/adapters/threads/post.js.map +1 -0
- package/dist/adapters/tiktok/subtitles.d.ts +9 -0
- package/dist/adapters/tiktok/subtitles.d.ts.map +1 -0
- package/dist/adapters/tiktok/subtitles.js +42 -0
- package/dist/adapters/tiktok/subtitles.js.map +1 -0
- package/dist/adapters/twitter/accept.js +2 -2
- package/dist/adapters/twitter/accept.js.map +1 -1
- package/dist/adapters/twitter/browser-fallback.d.ts +26 -0
- package/dist/adapters/twitter/browser-fallback.d.ts.map +1 -0
- package/dist/adapters/twitter/browser-fallback.js +93 -0
- package/dist/adapters/twitter/browser-fallback.js.map +1 -0
- package/dist/adapters/twitter/browser-state.d.ts +11 -0
- package/dist/adapters/twitter/browser-state.d.ts.map +1 -0
- package/dist/adapters/twitter/browser-state.js +46 -0
- package/dist/adapters/twitter/browser-state.js.map +1 -0
- package/dist/adapters/twitter/client.d.ts.map +1 -1
- package/dist/adapters/twitter/client.js +36 -13
- package/dist/adapters/twitter/client.js.map +1 -1
- package/dist/adapters/twitter/reply-dm.js +2 -2
- package/dist/adapters/twitter/reply-dm.js.map +1 -1
- package/dist/adapters/twitter/reply.js +1 -0
- package/dist/adapters/twitter/reply.js.map +1 -1
- package/dist/adapters/twitter/search.js +11 -18
- package/dist/adapters/twitter/search.js.map +1 -1
- package/dist/adapters/twitter/thread.d.ts +14 -0
- package/dist/adapters/twitter/thread.d.ts.map +1 -1
- package/dist/adapters/twitter/thread.js +28 -2
- package/dist/adapters/twitter/thread.js.map +1 -1
- package/dist/adapters/twitter/trending.js +13 -59
- package/dist/adapters/twitter/trending.js.map +1 -1
- package/dist/adapters/vndb/web.d.ts +10 -0
- package/dist/adapters/vndb/web.d.ts.map +1 -0
- package/dist/adapters/vndb/web.js +321 -0
- package/dist/adapters/vndb/web.js.map +1 -0
- package/dist/adapters/xiaohongshu/browser-state.d.ts +19 -0
- package/dist/adapters/xiaohongshu/browser-state.d.ts.map +1 -0
- package/dist/adapters/xiaohongshu/browser-state.js +67 -0
- package/dist/adapters/xiaohongshu/browser-state.js.map +1 -0
- package/dist/adapters/xiaohongshu/comments.js +28 -5
- package/dist/adapters/xiaohongshu/comments.js.map +1 -1
- package/dist/adapters/xiaohongshu/download.js +49 -11
- package/dist/adapters/xiaohongshu/download.js.map +1 -1
- package/dist/adapters/xiaohongshu/search.d.ts.map +1 -1
- package/dist/adapters/xiaohongshu/search.js +11 -5
- package/dist/adapters/xiaohongshu/search.js.map +1 -1
- package/dist/adapters/xiaohongshu/trending.d.ts +9 -0
- package/dist/adapters/xiaohongshu/trending.d.ts.map +1 -0
- package/dist/adapters/xiaohongshu/trending.js +94 -0
- package/dist/adapters/xiaohongshu/trending.js.map +1 -0
- package/dist/adapters/youtube/comments.d.ts +80 -0
- package/dist/adapters/youtube/comments.d.ts.map +1 -1
- package/dist/adapters/youtube/comments.js +108 -12
- package/dist/adapters/youtube/comments.js.map +1 -1
- package/dist/adapters/youtube/subtitles.d.ts +9 -0
- package/dist/adapters/youtube/subtitles.d.ts.map +1 -0
- package/dist/adapters/youtube/subtitles.js +42 -0
- package/dist/adapters/youtube/subtitles.js.map +1 -0
- package/dist/adapters/yt-dlp/subtitles.d.ts +9 -0
- package/dist/adapters/yt-dlp/subtitles.d.ts.map +1 -0
- package/dist/adapters/yt-dlp/subtitles.js +41 -0
- package/dist/adapters/yt-dlp/subtitles.js.map +1 -0
- package/dist/adapters/zhihu/answer-detail.d.ts +39 -0
- package/dist/adapters/zhihu/answer-detail.d.ts.map +1 -0
- package/dist/adapters/zhihu/answer-detail.js +204 -0
- package/dist/adapters/zhihu/answer-detail.js.map +1 -0
- package/dist/adapters/zhihu/comment.d.ts +9 -0
- package/dist/adapters/zhihu/comment.d.ts.map +1 -0
- package/dist/adapters/zhihu/comment.js +149 -0
- package/dist/adapters/zhihu/comment.js.map +1 -0
- package/dist/adapters/zhihu/recommend.d.ts +36 -0
- package/dist/adapters/zhihu/recommend.d.ts.map +1 -0
- package/dist/adapters/zhihu/recommend.js +151 -0
- package/dist/adapters/zhihu/recommend.js.map +1 -0
- package/dist/agents/codex-pack.d.ts +62 -0
- package/dist/agents/codex-pack.d.ts.map +1 -0
- package/dist/agents/codex-pack.js +163 -0
- package/dist/agents/codex-pack.js.map +1 -0
- package/dist/browser/bridge.d.ts.map +1 -1
- package/dist/browser/bridge.js +14 -3
- package/dist/browser/bridge.js.map +1 -1
- package/dist/browser/daemon-client.d.ts +6 -0
- package/dist/browser/daemon-client.d.ts.map +1 -1
- package/dist/browser/daemon-client.js +75 -15
- package/dist/browser/daemon-client.js.map +1 -1
- package/dist/browser/daemon.js +39 -15
- package/dist/browser/daemon.js.map +1 -1
- package/dist/browser/protocol.d.ts +1 -0
- package/dist/browser/protocol.d.ts.map +1 -1
- package/dist/browser/protocol.js +1 -0
- package/dist/browser/protocol.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +6 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +6 -43
- package/dist/commands/agents.js.map +1 -1
- package/dist/commands/approvals.d.ts.map +1 -1
- package/dist/commands/approvals.js +1 -37
- package/dist/commands/approvals.js.map +1 -1
- package/dist/commands/browser/adapter.d.ts.map +1 -1
- package/dist/commands/browser/adapter.js +17 -3
- package/dist/commands/browser/adapter.js.map +1 -1
- package/dist/commands/browser/index.d.ts.map +1 -1
- package/dist/commands/browser/index.js +7 -2
- package/dist/commands/browser/index.js.map +1 -1
- package/dist/commands/daemon.d.ts.map +1 -1
- package/dist/commands/daemon.js +7 -3
- package/dist/commands/daemon.js.map +1 -1
- package/dist/commands/describe.d.ts.map +1 -1
- package/dist/commands/describe.js +6 -7
- package/dist/commands/describe.js.map +1 -1
- package/dist/commands/dispatch.d.ts +1 -1
- package/dist/commands/dispatch.d.ts.map +1 -1
- package/dist/commands/dispatch.js +31 -5
- package/dist/commands/dispatch.js.map +1 -1
- package/dist/commands/mcp.d.ts +1 -1
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +10 -5
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/patent-doctor.d.ts +48 -0
- package/dist/commands/patent-doctor.d.ts.map +1 -0
- package/dist/commands/patent-doctor.js +109 -0
- package/dist/commands/patent-doctor.js.map +1 -0
- package/dist/commands/patent.d.ts +78 -0
- package/dist/commands/patent.d.ts.map +1 -0
- package/dist/commands/patent.js +919 -0
- package/dist/commands/patent.js.map +1 -0
- package/dist/commands/social.d.ts +19 -0
- package/dist/commands/social.d.ts.map +1 -0
- package/dist/commands/social.js +236 -0
- package/dist/commands/social.js.map +1 -0
- package/dist/core/command-contract-lint.d.ts +10 -0
- package/dist/core/command-contract-lint.d.ts.map +1 -0
- package/dist/core/command-contract-lint.js +41 -0
- package/dist/core/command-contract-lint.js.map +1 -0
- package/dist/core/command-contract.d.ts +100 -0
- package/dist/core/command-contract.d.ts.map +1 -0
- package/dist/core/command-contract.js +174 -0
- package/dist/core/command-contract.js.map +1 -0
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/registry.d.ts +1 -1
- package/dist/core/registry.d.ts.map +1 -1
- package/dist/core/registry.js +11 -2
- package/dist/core/registry.js.map +1 -1
- package/dist/discovery/aliases.d.ts +2 -2
- package/dist/discovery/aliases.d.ts.map +1 -1
- package/dist/discovery/aliases.js +464 -6
- package/dist/discovery/aliases.js.map +1 -1
- package/dist/discovery/loader.d.ts.map +1 -1
- package/dist/discovery/loader.js +4 -0
- package/dist/discovery/loader.js.map +1 -1
- package/dist/discovery/search.d.ts.map +1 -1
- package/dist/discovery/search.js +147 -2
- package/dist/discovery/search.js.map +1 -1
- package/dist/engine/approval-presenter.d.ts +10 -0
- package/dist/engine/approval-presenter.d.ts.map +1 -0
- package/dist/engine/approval-presenter.js +45 -0
- package/dist/engine/approval-presenter.js.map +1 -0
- package/dist/engine/approval-store.d.ts +4 -0
- package/dist/engine/approval-store.d.ts.map +1 -1
- package/dist/engine/approval-store.js +85 -11
- package/dist/engine/approval-store.js.map +1 -1
- package/dist/engine/args.d.ts.map +1 -1
- package/dist/engine/args.js +18 -1
- package/dist/engine/args.js.map +1 -1
- package/dist/engine/artifact-validation.d.ts +29 -0
- package/dist/engine/artifact-validation.d.ts.map +1 -0
- package/dist/engine/artifact-validation.js +211 -0
- package/dist/engine/artifact-validation.js.map +1 -0
- package/dist/engine/auth/oauth2-cc.d.ts +67 -0
- package/dist/engine/auth/oauth2-cc.d.ts.map +1 -0
- package/dist/engine/auth/oauth2-cc.js +120 -0
- package/dist/engine/auth/oauth2-cc.js.map +1 -0
- package/dist/engine/browser/diagnostics.d.ts +38 -0
- package/dist/engine/browser/diagnostics.d.ts.map +1 -0
- package/dist/engine/browser/diagnostics.js +40 -0
- package/dist/engine/browser/diagnostics.js.map +1 -0
- package/dist/engine/cookies.d.ts +10 -0
- package/dist/engine/cookies.d.ts.map +1 -1
- package/dist/engine/cookies.js +64 -0
- package/dist/engine/cookies.js.map +1 -1
- package/dist/engine/download.d.ts +5 -0
- package/dist/engine/download.d.ts.map +1 -1
- package/dist/engine/download.js +11 -4
- package/dist/engine/download.js.map +1 -1
- package/dist/engine/executor.d.ts +1 -0
- package/dist/engine/executor.d.ts.map +1 -1
- package/dist/engine/executor.js +25 -0
- package/dist/engine/executor.js.map +1 -1
- package/dist/engine/framework.d.ts +5 -5
- package/dist/engine/framework.js +5 -5
- package/dist/engine/harden.d.ts +1 -1
- package/dist/engine/harden.js +1 -1
- package/dist/engine/invoke.d.ts +1 -0
- package/dist/engine/invoke.d.ts.map +1 -1
- package/dist/engine/invoke.js +1 -0
- package/dist/engine/invoke.js.map +1 -1
- package/dist/engine/kernel/errors.d.ts +11 -0
- package/dist/engine/kernel/errors.d.ts.map +1 -0
- package/dist/engine/kernel/errors.js +15 -0
- package/dist/engine/kernel/errors.js.map +1 -0
- package/dist/engine/kernel/execute.d.ts +7 -18
- package/dist/engine/kernel/execute.d.ts.map +1 -1
- package/dist/engine/kernel/execute.js +25 -410
- package/dist/engine/kernel/execute.js.map +1 -1
- package/dist/engine/kernel/stages.d.ts +44 -0
- package/dist/engine/kernel/stages.d.ts.map +1 -0
- package/dist/engine/kernel/stages.js +429 -0
- package/dist/engine/kernel/stages.js.map +1 -0
- package/dist/engine/kernel/types.d.ts +21 -1
- package/dist/engine/kernel/types.d.ts.map +1 -1
- package/dist/engine/normalizer/patent-envelope.d.ts +61 -0
- package/dist/engine/normalizer/patent-envelope.d.ts.map +1 -0
- package/dist/engine/normalizer/patent-envelope.js +132 -0
- package/dist/engine/normalizer/patent-envelope.js.map +1 -0
- package/dist/engine/research.d.ts +5 -7
- package/dist/engine/research.d.ts.map +1 -1
- package/dist/engine/research.js +6 -9
- package/dist/engine/research.js.map +1 -1
- package/dist/engine/steps/browser-helpers.d.ts +2 -2
- package/dist/engine/steps/browser-helpers.d.ts.map +1 -1
- package/dist/engine/steps/browser-helpers.js +39 -16
- package/dist/engine/steps/browser-helpers.js.map +1 -1
- package/dist/engine/steps/download.d.ts +2 -0
- package/dist/engine/steps/download.d.ts.map +1 -1
- package/dist/engine/steps/download.js +13 -7
- package/dist/engine/steps/download.js.map +1 -1
- package/dist/engine/steps/index.d.ts +2 -0
- package/dist/engine/steps/index.d.ts.map +1 -1
- package/dist/engine/steps/index.js +2 -0
- package/dist/engine/steps/index.js.map +1 -1
- package/dist/engine/steps/oauth2-token.d.ts +41 -0
- package/dist/engine/steps/oauth2-token.d.ts.map +1 -0
- package/dist/engine/steps/oauth2-token.js +115 -0
- package/dist/engine/steps/oauth2-token.js.map +1 -0
- package/dist/engine/steps/select-xml.d.ts +34 -0
- package/dist/engine/steps/select-xml.d.ts.map +1 -0
- package/dist/engine/steps/select-xml.js +222 -0
- package/dist/engine/steps/select-xml.js.map +1 -0
- package/dist/engine/template.d.ts.map +1 -1
- package/dist/engine/template.js +7 -0
- package/dist/engine/template.js.map +1 -1
- package/dist/engine/transport/mcp-browser.d.ts +128 -0
- package/dist/engine/transport/mcp-browser.d.ts.map +1 -0
- package/dist/engine/transport/mcp-browser.js +120 -0
- package/dist/engine/transport/mcp-browser.js.map +1 -0
- package/dist/fast-path/handlers/approvals.d.ts +11 -0
- package/dist/fast-path/handlers/approvals.d.ts.map +1 -0
- package/dist/fast-path/handlers/approvals.js +136 -0
- package/dist/fast-path/handlers/approvals.js.map +1 -0
- package/dist/fast-path/manifest.d.ts +1 -0
- package/dist/fast-path/manifest.d.ts.map +1 -1
- package/dist/fast-path/manifest.js.map +1 -1
- package/dist/fast-path/render.js +1 -1
- package/dist/fast-path/render.js.map +1 -1
- package/dist/fast-path.d.ts.map +1 -1
- package/dist/fast-path.js +3 -0
- package/dist/fast-path.js.map +1 -1
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest-compact.txt +5 -5
- package/dist/manifest-search.json +1 -1
- package/dist/manifest.json +5189 -55
- package/dist/mcp/handler.d.ts.map +1 -1
- package/dist/mcp/handler.js +11 -1
- package/dist/mcp/handler.js.map +1 -1
- package/dist/mcp/server.d.ts +1 -1
- package/dist/mcp/server.js +1 -1
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +18 -10
- package/dist/mcp/tools.js.map +1 -1
- package/dist/output/auth-guidance.d.ts +14 -0
- package/dist/output/auth-guidance.d.ts.map +1 -0
- package/dist/output/auth-guidance.js +50 -0
- package/dist/output/auth-guidance.js.map +1 -0
- package/dist/output/error-map.d.ts +1 -1
- package/dist/output/error-map.d.ts.map +1 -1
- package/dist/output/error-map.js +29 -5
- package/dist/output/error-map.js.map +1 -1
- package/dist/output/next-actions.d.ts.map +1 -1
- package/dist/output/next-actions.js +19 -3
- package/dist/output/next-actions.js.map +1 -1
- package/dist/registry.d.ts +18 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +7 -1
- package/dist/registry.js.map +1 -1
- package/dist/social/browser-errors.d.ts +13 -0
- package/dist/social/browser-errors.d.ts.map +1 -0
- package/dist/social/browser-errors.js +36 -0
- package/dist/social/browser-errors.js.map +1 -0
- package/dist/social/capabilities.d.ts +29 -0
- package/dist/social/capabilities.d.ts.map +1 -0
- package/dist/social/capabilities.js +448 -0
- package/dist/social/capabilities.js.map +1 -0
- package/dist/social/comments.d.ts +26 -0
- package/dist/social/comments.d.ts.map +1 -0
- package/dist/social/comments.js +97 -0
- package/dist/social/comments.js.map +1 -0
- package/dist/social/video-text.d.ts +27 -0
- package/dist/social/video-text.d.ts.map +1 -0
- package/dist/social/video-text.js +140 -0
- package/dist/social/video-text.js.map +1 -0
- package/dist/types/patent.d.ts +160 -0
- package/dist/types/patent.d.ts.map +1 -0
- package/dist/types/patent.js +16 -0
- package/dist/types/patent.js.map +1 -0
- package/dist/types.d.ts +12 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +10 -5
- package/server.json +3 -3
- package/skills/unicli/SKILL.md +1 -1
- package/skills/unicli-claude-code/SKILL.md +1 -1
- package/skills/unicli-hermes/SKILL.md +1 -1
- package/src/adapters/anilist/web.test.ts +93 -0
- package/src/adapters/anilist/web.ts +341 -0
- package/src/adapters/arxiv/download.yaml +53 -0
- package/src/adapters/bangumi/web.test.ts +109 -0
- package/src/adapters/bangumi/web.ts +295 -0
- package/src/adapters/bilibili/comments-tree.test.ts +41 -0
- package/src/adapters/bilibili/comments.ts +78 -4
- package/src/adapters/bilibili/compat.ts +5 -2
- package/src/adapters/bilibili/download.ts +7 -4
- package/src/adapters/bilibili/wbi.ts +6 -3
- package/src/adapters/brave/search.yaml +53 -0
- package/src/adapters/cipo/_shared.ts +98 -0
- package/src/adapters/cipo/get.ts +188 -0
- package/src/adapters/cipo/legal-status.ts +148 -0
- package/src/adapters/cipo/search.ts +195 -0
- package/src/adapters/cnipa/_shared.ts +138 -0
- package/src/adapters/cnipa/get.ts +199 -0
- package/src/adapters/cnipa/legal-status.ts +162 -0
- package/src/adapters/cnipa/search.ts +229 -0
- package/src/adapters/danbooru/artists.yaml +44 -0
- package/src/adapters/danbooru/comments.yaml +45 -0
- package/src/adapters/danbooru/detail.yaml +78 -0
- package/src/adapters/danbooru/download.yaml +51 -0
- package/src/adapters/danbooru/pools.yaml +56 -0
- package/src/adapters/danbooru/search.yaml +69 -0
- package/src/adapters/danbooru/tags.yaml +42 -0
- package/src/adapters/danbooru/wiki.yaml +44 -0
- package/src/adapters/dlsite/web.test.ts +132 -0
- package/src/adapters/dlsite/web.ts +557 -0
- package/src/adapters/dpma/get.yaml +67 -0
- package/src/adapters/dpma/search.yaml +77 -0
- package/src/adapters/duckduckgo/search.yaml +54 -0
- package/src/adapters/duckduckgo/suggest.yaml +52 -0
- package/src/adapters/ehentai/web.test.ts +157 -0
- package/src/adapters/ehentai/web.ts +750 -0
- package/src/adapters/epo/family.yaml +69 -0
- package/src/adapters/epo/get.yaml +74 -0
- package/src/adapters/epo/legal-status.yaml +63 -0
- package/src/adapters/epo/search.yaml +84 -0
- package/src/adapters/espacenet/_shared.ts +98 -0
- package/src/adapters/espacenet/family.ts +161 -0
- package/src/adapters/espacenet/get.ts +185 -0
- package/src/adapters/espacenet/legal-status.ts +151 -0
- package/src/adapters/espacenet/search.ts +229 -0
- package/src/adapters/facebook/subtitles.ts +44 -0
- package/src/adapters/fips/_shared.ts +109 -0
- package/src/adapters/fips/get.ts +186 -0
- package/src/adapters/fips/search.ts +195 -0
- package/src/adapters/freepatentsonline-web/_shared.ts +273 -0
- package/src/adapters/freepatentsonline-web/get.ts +144 -0
- package/src/adapters/freepatentsonline-web/search.ts +170 -0
- package/src/adapters/google-patents-bq/prior-art.yaml +80 -0
- package/src/adapters/google-patents-bq/search.yaml +97 -0
- package/src/adapters/google-patents-web/_shared.ts +242 -0
- package/src/adapters/google-patents-web/get.ts +224 -0
- package/src/adapters/google-patents-web/search.ts +196 -0
- package/src/adapters/inpi-br/_shared.ts +98 -0
- package/src/adapters/inpi-br/get.ts +193 -0
- package/src/adapters/inpi-br/search.ts +206 -0
- package/src/adapters/inpi-fr/get.yaml +62 -0
- package/src/adapters/inpi-fr/search.yaml +74 -0
- package/src/adapters/instagram/subtitles.ts +44 -0
- package/src/adapters/ipaustralia/get.yaml +67 -0
- package/src/adapters/ipaustralia/search.yaml +74 -0
- package/src/adapters/jikan/web.test.ts +50 -0
- package/src/adapters/jikan/web.ts +177 -0
- package/src/adapters/jpo/get.yaml +63 -0
- package/src/adapters/jpo/search.yaml +76 -0
- package/src/adapters/kipris/get.yaml +69 -0
- package/src/adapters/kipris/legal-status.yaml +58 -0
- package/src/adapters/kipris/search.yaml +79 -0
- package/src/adapters/kitsu/web.test.ts +29 -0
- package/src/adapters/kitsu/web.ts +109 -0
- package/src/adapters/konachan/detail.yaml +62 -0
- package/src/adapters/konachan/download.yaml +55 -0
- package/src/adapters/konachan/search.yaml +65 -0
- package/src/adapters/konachan/tags.yaml +40 -0
- package/src/adapters/lens/get.yaml +64 -0
- package/src/adapters/lens/search.yaml +82 -0
- package/src/adapters/mangadex/web.test.ts +46 -0
- package/src/adapters/mangadex/web.ts +210 -0
- package/src/adapters/mastodon/statuses.test.ts +82 -0
- package/src/adapters/mastodon/statuses.ts +208 -0
- package/src/adapters/moegirl/web.test.ts +87 -0
- package/src/adapters/moegirl/web.ts +343 -0
- package/src/adapters/patsnap/get.yaml +65 -0
- package/src/adapters/patsnap/search.yaml +77 -0
- package/src/adapters/pdf/read.yaml +49 -0
- package/src/adapters/pixiv/download.yaml +15 -2
- package/src/adapters/pqai/prior-art.yaml +59 -0
- package/src/adapters/pqai/search.yaml +60 -0
- package/src/adapters/reddit/comments-tree.test.ts +79 -0
- package/src/adapters/reddit/comments.ts +159 -0
- package/src/adapters/safebooru/detail.yaml +63 -0
- package/src/adapters/safebooru/download.yaml +58 -0
- package/src/adapters/safebooru/search.yaml +69 -0
- package/src/adapters/safebooru/web.test.ts +60 -0
- package/src/adapters/safebooru/web.ts +130 -0
- package/src/adapters/threads/post.test.ts +64 -0
- package/src/adapters/threads/post.ts +366 -0
- package/src/adapters/threads/user.yaml +73 -0
- package/src/adapters/tiktok/subtitles.ts +44 -0
- package/src/adapters/twitter/accept.ts +5 -2
- package/src/adapters/twitter/browser-fallback.ts +138 -0
- package/src/adapters/twitter/browser-state.ts +74 -0
- package/src/adapters/twitter/client.ts +51 -21
- package/src/adapters/twitter/reply-dm.ts +5 -2
- package/src/adapters/twitter/reply.ts +1 -0
- package/src/adapters/twitter/search.ts +12 -38
- package/src/adapters/twitter/thread.test.ts +43 -0
- package/src/adapters/twitter/thread.ts +44 -2
- package/src/adapters/twitter/trending.ts +14 -95
- package/src/adapters/ukipo/info.yaml +43 -0
- package/src/adapters/uspto/get.yaml +67 -0
- package/src/adapters/uspto/legal-status.yaml +58 -0
- package/src/adapters/uspto/search.yaml +88 -0
- package/src/adapters/vndb/web.test.ts +86 -0
- package/src/adapters/vndb/web.ts +393 -0
- package/src/adapters/wipo-patentscope/info.yaml +43 -0
- package/src/adapters/xiaohongshu/browser-state.ts +95 -0
- package/src/adapters/xiaohongshu/comments.ts +29 -6
- package/src/adapters/xiaohongshu/download.ts +60 -11
- package/src/adapters/xiaohongshu/search.ts +18 -6
- package/src/adapters/xiaohongshu/trending.ts +112 -0
- package/src/adapters/yahoo/search.yaml +52 -0
- package/src/adapters/yandere/detail.yaml +61 -0
- package/src/adapters/yandere/download.yaml +56 -0
- package/src/adapters/yandere/search.yaml +67 -0
- package/src/adapters/yandere/tags.yaml +41 -0
- package/src/adapters/youtube/comments-microformat.test.ts +35 -0
- package/src/adapters/youtube/comments-tree.test.ts +74 -0
- package/src/adapters/youtube/comments.ts +166 -12
- package/src/adapters/youtube/subtitles.ts +44 -0
- package/src/adapters/yt-dlp/subtitles.ts +43 -0
- package/src/adapters/zhihu/answer-detail.test.ts +83 -0
- package/src/adapters/zhihu/answer-detail.ts +275 -0
- package/src/adapters/zhihu/comment-tree.test.ts +57 -0
- package/src/adapters/zhihu/comment.ts +186 -0
- package/src/adapters/zhihu/recommend.test.ts +65 -0
- package/src/adapters/zhihu/recommend.ts +207 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @owner Twitter browser fallback extraction.
|
|
3
|
+
* @does Reads X/Twitter search and trend results from the logged-in web UI.
|
|
4
|
+
* @needs A user-owned Chrome session reachable by Uni-CLI's browser layer.
|
|
5
|
+
* @feeds twitter.search and twitter.trending.
|
|
6
|
+
* @breaks X/Twitter DOM changes can reduce parseable rows.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { IPage } from "../../types.js";
|
|
10
|
+
import { socialEmptyError } from "../../social/browser-errors.js";
|
|
11
|
+
import { assertTwitterReadable, gotoTwitterPage } from "./browser-state.js";
|
|
12
|
+
|
|
13
|
+
export interface TwitterTweetRow {
|
|
14
|
+
id: string;
|
|
15
|
+
author: string;
|
|
16
|
+
text: string;
|
|
17
|
+
likes: string;
|
|
18
|
+
retweets: string;
|
|
19
|
+
views: string;
|
|
20
|
+
url: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface TwitterTrendRow {
|
|
24
|
+
name: string;
|
|
25
|
+
tweet_count: string;
|
|
26
|
+
description: string;
|
|
27
|
+
url: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export async function browserSearchTweets(
|
|
31
|
+
page: IPage,
|
|
32
|
+
query: string,
|
|
33
|
+
limit: number,
|
|
34
|
+
): Promise<TwitterTweetRow[]> {
|
|
35
|
+
await gotoTwitterPage(
|
|
36
|
+
page,
|
|
37
|
+
`https://x.com/search?q=${encodeURIComponent(query)}&src=typed_query&f=live`,
|
|
38
|
+
"search",
|
|
39
|
+
);
|
|
40
|
+
await page.autoScroll({ maxScrolls: 2, delay: 1000 });
|
|
41
|
+
await assertTwitterReadable(page, "search");
|
|
42
|
+
|
|
43
|
+
const raw = await page.evaluate(`
|
|
44
|
+
(() => {
|
|
45
|
+
const clean = (value) => (value || '').replace(/\\s+/g, ' ').trim();
|
|
46
|
+
const rows = [];
|
|
47
|
+
const seen = new Set();
|
|
48
|
+
for (const article of document.querySelectorAll('article[data-testid="tweet"]')) {
|
|
49
|
+
const status = article.querySelector('a[href*="/status/"]');
|
|
50
|
+
const href = status?.getAttribute('href') || '';
|
|
51
|
+
const id = (href.match(/\\/status\\/(\\d+)/) || [])[1] || '';
|
|
52
|
+
if (!id || seen.has(id)) continue;
|
|
53
|
+
seen.add(id);
|
|
54
|
+
const text = Array.from(article.querySelectorAll('[data-testid="tweetText"]'))
|
|
55
|
+
.map((el) => clean(el.textContent || ''))
|
|
56
|
+
.filter(Boolean)
|
|
57
|
+
.join('\\n');
|
|
58
|
+
if (!text) continue;
|
|
59
|
+
const userName = clean(article.querySelector('[data-testid="User-Name"]')?.textContent || '');
|
|
60
|
+
const author = userName.split('@')[0] || userName;
|
|
61
|
+
const metric = (name) => clean(article.querySelector('[data-testid="' + name + '"]')?.textContent || '');
|
|
62
|
+
rows.push({
|
|
63
|
+
id,
|
|
64
|
+
author,
|
|
65
|
+
text,
|
|
66
|
+
likes: metric('like'),
|
|
67
|
+
retweets: metric('retweet'),
|
|
68
|
+
views: clean(article.querySelector('a[href$="/analytics"]')?.textContent || ''),
|
|
69
|
+
url: 'https://x.com' + href.split('?')[0],
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return rows;
|
|
73
|
+
})()
|
|
74
|
+
`);
|
|
75
|
+
|
|
76
|
+
const rows = Array.isArray(raw)
|
|
77
|
+
? (raw as TwitterTweetRow[]).slice(0, limit)
|
|
78
|
+
: [];
|
|
79
|
+
if (rows.length > 0) return rows;
|
|
80
|
+
throw socialEmptyError(
|
|
81
|
+
"twitter",
|
|
82
|
+
"search",
|
|
83
|
+
`Twitter/X search loaded no parseable tweets for "${query}".`,
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export async function browserTrendingTopics(
|
|
88
|
+
page: IPage,
|
|
89
|
+
limit: number,
|
|
90
|
+
): Promise<TwitterTrendRow[]> {
|
|
91
|
+
await gotoTwitterPage(
|
|
92
|
+
page,
|
|
93
|
+
"https://x.com/explore/tabs/trending",
|
|
94
|
+
"trending",
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
const raw = await page.evaluate(`
|
|
98
|
+
(() => {
|
|
99
|
+
const clean = (value) => (value || '').replace(/\\s+/g, ' ').trim();
|
|
100
|
+
const rows = [];
|
|
101
|
+
const seen = new Set();
|
|
102
|
+
for (const link of document.querySelectorAll('a[href*="/search?q="]')) {
|
|
103
|
+
const href = link.getAttribute('href') || '';
|
|
104
|
+
let name = '';
|
|
105
|
+
try {
|
|
106
|
+
name = new URL(href, 'https://x.com').searchParams.get('q') || '';
|
|
107
|
+
} catch {}
|
|
108
|
+
const lines = clean(link.textContent || '')
|
|
109
|
+
.split(/(?=Trending|[0-9,.]+\\s+posts)/)
|
|
110
|
+
.map(clean)
|
|
111
|
+
.filter(Boolean);
|
|
112
|
+
if (!name) {
|
|
113
|
+
name = lines.find((line) => !/^Trending/i.test(line) && !/posts$/i.test(line)) || '';
|
|
114
|
+
}
|
|
115
|
+
if (!name || seen.has(name)) continue;
|
|
116
|
+
seen.add(name);
|
|
117
|
+
const meta = lines.find((line) => /posts$/i.test(line)) || '';
|
|
118
|
+
rows.push({
|
|
119
|
+
name,
|
|
120
|
+
tweet_count: meta,
|
|
121
|
+
description: lines.find((line) => /^Trending/i.test(line)) || '',
|
|
122
|
+
url: 'https://x.com' + href,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
return rows;
|
|
126
|
+
})()
|
|
127
|
+
`);
|
|
128
|
+
|
|
129
|
+
const rows = Array.isArray(raw)
|
|
130
|
+
? (raw as TwitterTrendRow[]).slice(0, limit)
|
|
131
|
+
: [];
|
|
132
|
+
if (rows.length > 0) return rows;
|
|
133
|
+
throw socialEmptyError(
|
|
134
|
+
"twitter",
|
|
135
|
+
"trending",
|
|
136
|
+
"Twitter/X explore loaded no parseable trend rows.",
|
|
137
|
+
);
|
|
138
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @owner Twitter browser adapters.
|
|
3
|
+
* @does Detects X/Twitter login and challenge pages in browser fallback flows.
|
|
4
|
+
* @needs Browser-backed IPage from Uni-CLI runtime.
|
|
5
|
+
* @feeds twitter.search and twitter.trending.
|
|
6
|
+
* @breaks X/Twitter copy or route changes can require updating page-state detection.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { IPage } from "../../types.js";
|
|
10
|
+
import {
|
|
11
|
+
socialAuthError,
|
|
12
|
+
socialChallengeError,
|
|
13
|
+
} from "../../social/browser-errors.js";
|
|
14
|
+
|
|
15
|
+
interface TwitterPageState {
|
|
16
|
+
url: string;
|
|
17
|
+
title: string;
|
|
18
|
+
text: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function readTwitterPageState(page: IPage): Promise<TwitterPageState> {
|
|
22
|
+
const raw = await page.evaluate(`
|
|
23
|
+
(() => ({
|
|
24
|
+
url: window.location.href,
|
|
25
|
+
title: document.title || '',
|
|
26
|
+
text: (document.body?.innerText || '').replace(/\\s+/g, ' ').slice(0, 2000)
|
|
27
|
+
}))()
|
|
28
|
+
`);
|
|
29
|
+
const state = raw as Partial<TwitterPageState>;
|
|
30
|
+
return {
|
|
31
|
+
url: String(state.url ?? ""),
|
|
32
|
+
title: String(state.title ?? ""),
|
|
33
|
+
text: String(state.text ?? ""),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function gotoTwitterPage(
|
|
38
|
+
page: IPage,
|
|
39
|
+
url: string,
|
|
40
|
+
command: string,
|
|
41
|
+
): Promise<void> {
|
|
42
|
+
try {
|
|
43
|
+
await page.goto(url, { settleMs: 2500 });
|
|
44
|
+
} catch (err) {
|
|
45
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
46
|
+
if (!/net::ERR_ABORTED/i.test(message)) throw err;
|
|
47
|
+
}
|
|
48
|
+
await page.wait(2);
|
|
49
|
+
await assertTwitterReadable(page, command);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export async function assertTwitterReadable(
|
|
53
|
+
page: IPage,
|
|
54
|
+
command: string,
|
|
55
|
+
): Promise<void> {
|
|
56
|
+
const state = await readTwitterPageState(page);
|
|
57
|
+
const haystack = `${state.url}\n${state.title}\n${state.text}`;
|
|
58
|
+
if (
|
|
59
|
+
/captcha|cloudflare|challenge|verify you are human|unusual traffic/i.test(
|
|
60
|
+
haystack,
|
|
61
|
+
)
|
|
62
|
+
) {
|
|
63
|
+
throw socialChallengeError(
|
|
64
|
+
"twitter",
|
|
65
|
+
command,
|
|
66
|
+
`Twitter/X is showing a challenge page: ${state.title || state.url}`,
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
if (
|
|
70
|
+
/\/i\/flow\/login|Sign in to X|Log in to X|登录 X|登录后/i.test(haystack)
|
|
71
|
+
) {
|
|
72
|
+
throw socialAuthError("twitter", command);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
* Requires ct0 (CSRF token) and auth_token cookies in ~/.unicli/cookies/twitter.json
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
loadCookiesWithCDP,
|
|
10
|
+
formatCookieHeader,
|
|
11
|
+
} from "../../engine/cookies.js";
|
|
9
12
|
import { USER_AGENT } from "../../constants.js";
|
|
10
13
|
|
|
11
14
|
// Public bearer token — same for all Twitter web clients, not a secret
|
|
@@ -14,6 +17,45 @@ const BEARER_TOKEN =
|
|
|
14
17
|
|
|
15
18
|
const GRAPHQL_BASE = "https://x.com/i/api/graphql";
|
|
16
19
|
|
|
20
|
+
function throwTwitterApiError(
|
|
21
|
+
label: string,
|
|
22
|
+
status: number,
|
|
23
|
+
preview: string,
|
|
24
|
+
): never {
|
|
25
|
+
const err = new Error(
|
|
26
|
+
`Twitter API error: HTTP ${status} on ${label}\n${preview.slice(0, 200)}`,
|
|
27
|
+
) as Error & {
|
|
28
|
+
code?: string;
|
|
29
|
+
suggestion?: string;
|
|
30
|
+
retryable?: boolean;
|
|
31
|
+
alternatives?: string[];
|
|
32
|
+
};
|
|
33
|
+
err.code =
|
|
34
|
+
status === 401 || status === 403
|
|
35
|
+
? "auth_required"
|
|
36
|
+
: status === 404
|
|
37
|
+
? "upstream_error"
|
|
38
|
+
: status === 429
|
|
39
|
+
? "rate_limited"
|
|
40
|
+
: status >= 500
|
|
41
|
+
? "upstream_error"
|
|
42
|
+
: "api_error";
|
|
43
|
+
err.retryable = status === 429 || status >= 500;
|
|
44
|
+
err.suggestion =
|
|
45
|
+
status === 404
|
|
46
|
+
? "Twitter/X changed or removed this web API operation. Run `unicli repair twitter <command>` or use a browser-backed command while the GraphQL operation is refreshed."
|
|
47
|
+
: status === 401 || status === 403
|
|
48
|
+
? "Refresh X login state with `unicli --auth-retry twitter <command> --args-file <path.json>`, or open https://x.com in Chrome and sign in."
|
|
49
|
+
: status === 429
|
|
50
|
+
? "Twitter/X rate-limited the request. Wait, reduce limit, then retry."
|
|
51
|
+
: "Twitter/X API returned an upstream error. Retry once; if it persists, run `unicli repair twitter <command>`.";
|
|
52
|
+
err.alternatives = [
|
|
53
|
+
"unicli auth import twitter --domain x.com",
|
|
54
|
+
"unicli browser open https://x.com",
|
|
55
|
+
];
|
|
56
|
+
throw err;
|
|
57
|
+
}
|
|
58
|
+
|
|
17
59
|
/** Standard Twitter GraphQL feature flags */
|
|
18
60
|
export const FEATURES: Record<string, boolean> = {
|
|
19
61
|
rweb_tipjar_consumption_enabled: true,
|
|
@@ -56,7 +98,7 @@ export async function twitterFetch(
|
|
|
56
98
|
variables: Record<string, unknown>,
|
|
57
99
|
features: Record<string, boolean> = FEATURES,
|
|
58
100
|
): Promise<unknown> {
|
|
59
|
-
const cookies =
|
|
101
|
+
const cookies = await loadCookiesWithCDP("twitter", "x.com");
|
|
60
102
|
if (!cookies) {
|
|
61
103
|
throw new Error(
|
|
62
104
|
'No cookies found for "twitter". Run: unicli auth setup twitter',
|
|
@@ -92,10 +134,7 @@ export async function twitterFetch(
|
|
|
92
134
|
|
|
93
135
|
if (!resp.ok) {
|
|
94
136
|
const preview = await resp.text().catch(() => "");
|
|
95
|
-
|
|
96
|
-
`Twitter API error: HTTP ${resp.status} on ${endpoint}\n` +
|
|
97
|
-
`${preview.slice(0, 200)}`,
|
|
98
|
-
);
|
|
137
|
+
throwTwitterApiError(endpoint, resp.status, preview);
|
|
99
138
|
}
|
|
100
139
|
|
|
101
140
|
return resp.json();
|
|
@@ -110,7 +149,7 @@ export async function twitterPostFetch(
|
|
|
110
149
|
variables: Record<string, unknown>,
|
|
111
150
|
features: Record<string, boolean> = FEATURES,
|
|
112
151
|
): Promise<unknown> {
|
|
113
|
-
const cookies =
|
|
152
|
+
const cookies = await loadCookiesWithCDP("twitter", "x.com");
|
|
114
153
|
if (!cookies) {
|
|
115
154
|
throw new Error(
|
|
116
155
|
'No cookies found for "twitter". Run: unicli auth setup twitter',
|
|
@@ -143,10 +182,7 @@ export async function twitterPostFetch(
|
|
|
143
182
|
|
|
144
183
|
if (!resp.ok) {
|
|
145
184
|
const preview = await resp.text().catch(() => "");
|
|
146
|
-
|
|
147
|
-
`Twitter API error: HTTP ${resp.status} on ${endpoint}\n` +
|
|
148
|
-
`${preview.slice(0, 200)}`,
|
|
149
|
-
);
|
|
185
|
+
throwTwitterApiError(endpoint, resp.status, preview);
|
|
150
186
|
}
|
|
151
187
|
|
|
152
188
|
return resp.json();
|
|
@@ -163,7 +199,7 @@ export async function twitterRestFetch(
|
|
|
163
199
|
path: string,
|
|
164
200
|
params: Record<string, string> = {},
|
|
165
201
|
): Promise<unknown> {
|
|
166
|
-
const cookies =
|
|
202
|
+
const cookies = await loadCookiesWithCDP("twitter", "x.com");
|
|
167
203
|
if (!cookies) {
|
|
168
204
|
throw new Error(
|
|
169
205
|
'No cookies found for "twitter". Run: unicli auth setup twitter',
|
|
@@ -195,10 +231,7 @@ export async function twitterRestFetch(
|
|
|
195
231
|
|
|
196
232
|
if (!resp.ok) {
|
|
197
233
|
const preview = await resp.text().catch(() => "");
|
|
198
|
-
|
|
199
|
-
`Twitter REST API error: HTTP ${resp.status} on ${path}\n` +
|
|
200
|
-
`${preview.slice(0, 200)}`,
|
|
201
|
-
);
|
|
234
|
+
throwTwitterApiError(path, resp.status, preview);
|
|
202
235
|
}
|
|
203
236
|
|
|
204
237
|
return resp.json();
|
|
@@ -215,7 +248,7 @@ export async function twitterGuideFetch(
|
|
|
215
248
|
url: string,
|
|
216
249
|
params: Record<string, string> = {},
|
|
217
250
|
): Promise<unknown> {
|
|
218
|
-
const cookies =
|
|
251
|
+
const cookies = await loadCookiesWithCDP("twitter", "x.com");
|
|
219
252
|
if (!cookies) {
|
|
220
253
|
throw new Error(
|
|
221
254
|
'No cookies found for "twitter". Run: unicli auth setup twitter',
|
|
@@ -247,10 +280,7 @@ export async function twitterGuideFetch(
|
|
|
247
280
|
|
|
248
281
|
if (!resp.ok) {
|
|
249
282
|
const preview = await resp.text().catch(() => "");
|
|
250
|
-
|
|
251
|
-
`Twitter Guide API error: HTTP ${resp.status}\n` +
|
|
252
|
-
`${preview.slice(0, 200)}`,
|
|
253
|
-
);
|
|
283
|
+
throwTwitterApiError("guide", resp.status, preview);
|
|
254
284
|
}
|
|
255
285
|
|
|
256
286
|
return resp.json();
|
|
@@ -6,7 +6,10 @@
|
|
|
6
6
|
|
|
7
7
|
import { cli } from "../../registry.js";
|
|
8
8
|
import { Strategy } from "../../types.js";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
loadCookiesWithCDP,
|
|
11
|
+
formatCookieHeader,
|
|
12
|
+
} from "../../engine/cookies.js";
|
|
10
13
|
import { USER_AGENT } from "../../constants.js";
|
|
11
14
|
|
|
12
15
|
const BEARER_TOKEN =
|
|
@@ -36,7 +39,7 @@ cli({
|
|
|
36
39
|
const conversationId = String(kwargs.conversation_id);
|
|
37
40
|
const text = kwargs.text as string;
|
|
38
41
|
|
|
39
|
-
const cookies =
|
|
42
|
+
const cookies = await loadCookiesWithCDP("twitter", "x.com");
|
|
40
43
|
if (!cookies) {
|
|
41
44
|
throw new Error(
|
|
42
45
|
'No cookies found for "twitter". Run: unicli auth setup twitter',
|
|
@@ -4,14 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
import { cli } from "../../registry.js";
|
|
6
6
|
import { Strategy } from "../../types.js";
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
FEATURES,
|
|
10
|
-
extractTweetsFromInstructions,
|
|
11
|
-
} from "./client.js";
|
|
12
|
-
|
|
13
|
-
const QUERY_ID = "nK1dw4oV3k4w5TdtcAdSww";
|
|
14
|
-
const ENDPOINT = "SearchTimeline";
|
|
7
|
+
import { browserSearchTweets } from "./browser-fallback.js";
|
|
8
|
+
import type { IPage } from "../../types.js";
|
|
15
9
|
|
|
16
10
|
cli({
|
|
17
11
|
site: "twitter",
|
|
@@ -19,6 +13,8 @@ cli({
|
|
|
19
13
|
description: "Search tweets by keyword",
|
|
20
14
|
domain: "x.com",
|
|
21
15
|
strategy: Strategy.COOKIE,
|
|
16
|
+
browser: true,
|
|
17
|
+
browserSession: "user",
|
|
22
18
|
args: [
|
|
23
19
|
{
|
|
24
20
|
name: "query",
|
|
@@ -26,39 +22,17 @@ cli({
|
|
|
26
22
|
positional: true,
|
|
27
23
|
description: "Search query",
|
|
28
24
|
},
|
|
25
|
+
{
|
|
26
|
+
name: "limit",
|
|
27
|
+
type: "int",
|
|
28
|
+
default: 20,
|
|
29
|
+
description: "Number of tweets",
|
|
30
|
+
},
|
|
29
31
|
],
|
|
30
32
|
columns: ["id", "author", "text", "likes", "retweets", "views", "url"],
|
|
31
|
-
func: async (
|
|
33
|
+
func: async (page, kwargs) => {
|
|
32
34
|
const query = kwargs.query as string;
|
|
33
35
|
const count = Math.min((kwargs.limit as number) ?? 20, 50);
|
|
34
|
-
|
|
35
|
-
const variables = {
|
|
36
|
-
rawQuery: query,
|
|
37
|
-
count,
|
|
38
|
-
querySource: "typed_query",
|
|
39
|
-
product: "Latest",
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const data = (await twitterFetch(
|
|
43
|
-
ENDPOINT,
|
|
44
|
-
QUERY_ID,
|
|
45
|
-
variables,
|
|
46
|
-
FEATURES,
|
|
47
|
-
)) as Record<string, unknown>;
|
|
48
|
-
|
|
49
|
-
// Navigate: data.search_by_raw_query.search_timeline.timeline.instructions
|
|
50
|
-
const searchByRawQuery = data.data as Record<string, unknown> | undefined;
|
|
51
|
-
const searchResult = searchByRawQuery?.search_by_raw_query as
|
|
52
|
-
| Record<string, unknown>
|
|
53
|
-
| undefined;
|
|
54
|
-
const searchTimeline = searchResult?.search_timeline as
|
|
55
|
-
| Record<string, unknown>
|
|
56
|
-
| undefined;
|
|
57
|
-
const timeline = searchTimeline?.timeline as
|
|
58
|
-
| Record<string, unknown>
|
|
59
|
-
| undefined;
|
|
60
|
-
const instructions = (timeline?.instructions as unknown[]) ?? [];
|
|
61
|
-
|
|
62
|
-
return extractTweetsFromInstructions(instructions);
|
|
36
|
+
return browserSearchTweets(page as IPage, query, count);
|
|
63
37
|
},
|
|
64
38
|
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { normalizeTwitterThreadRows } from "./thread.js";
|
|
4
|
+
|
|
5
|
+
describe("normalizeTwitterThreadRows", () => {
|
|
6
|
+
it("adds normalized comment hierarchy fields to thread rows", () => {
|
|
7
|
+
const rows = normalizeTwitterThreadRows("root", [
|
|
8
|
+
{
|
|
9
|
+
id: "root",
|
|
10
|
+
author: "Root",
|
|
11
|
+
text: "Root tweet",
|
|
12
|
+
likes: 10,
|
|
13
|
+
retweets: 2,
|
|
14
|
+
views: "100",
|
|
15
|
+
url: "https://x.com/i/status/root",
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
id: "reply-1",
|
|
19
|
+
author: "Reply",
|
|
20
|
+
text: "Reply tweet",
|
|
21
|
+
likes: 1,
|
|
22
|
+
retweets: 0,
|
|
23
|
+
views: "5",
|
|
24
|
+
url: "https://x.com/i/status/reply-1",
|
|
25
|
+
},
|
|
26
|
+
]);
|
|
27
|
+
|
|
28
|
+
expect(rows).toEqual([
|
|
29
|
+
expect.objectContaining({
|
|
30
|
+
id: "root",
|
|
31
|
+
parent_id: "",
|
|
32
|
+
depth: 0,
|
|
33
|
+
path: "0001",
|
|
34
|
+
}),
|
|
35
|
+
expect.objectContaining({
|
|
36
|
+
id: "reply-1",
|
|
37
|
+
parent_id: "root",
|
|
38
|
+
depth: 1,
|
|
39
|
+
path: "0001.0001",
|
|
40
|
+
}),
|
|
41
|
+
]);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -13,12 +13,40 @@ import {
|
|
|
13
13
|
const QUERY_ID = "B9_KmbkLhXt6jRwGjJrweg";
|
|
14
14
|
const ENDPOINT = "TweetDetail";
|
|
15
15
|
|
|
16
|
+
interface TweetRow {
|
|
17
|
+
id: string;
|
|
18
|
+
author: string;
|
|
19
|
+
text: string;
|
|
20
|
+
likes: number;
|
|
21
|
+
retweets: number;
|
|
22
|
+
views: string;
|
|
23
|
+
url: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function normalizeTwitterThreadRows(
|
|
27
|
+
tweetId: string,
|
|
28
|
+
tweets: TweetRow[],
|
|
29
|
+
): Array<TweetRow & { parent_id: string; depth: number; path: string }> {
|
|
30
|
+
let replyRank = 0;
|
|
31
|
+
return tweets.map((tweet) => {
|
|
32
|
+
const isRoot = tweet.id === tweetId;
|
|
33
|
+
if (!isRoot) replyRank += 1;
|
|
34
|
+
return {
|
|
35
|
+
...tweet,
|
|
36
|
+
parent_id: isRoot ? "" : tweetId,
|
|
37
|
+
depth: isRoot ? 0 : 1,
|
|
38
|
+
path: isRoot ? "0001" : `0001.${String(replyRank).padStart(4, "0")}`,
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
16
43
|
cli({
|
|
17
44
|
site: "twitter",
|
|
18
45
|
name: "thread",
|
|
19
46
|
description: "Get a tweet and its conversation thread",
|
|
20
47
|
domain: "x.com",
|
|
21
48
|
strategy: Strategy.COOKIE,
|
|
49
|
+
socialCapabilities: ["read", "comments", "comment_replies"],
|
|
22
50
|
args: [
|
|
23
51
|
{
|
|
24
52
|
name: "tweet_id",
|
|
@@ -27,7 +55,18 @@ cli({
|
|
|
27
55
|
description: "Tweet ID (numeric)",
|
|
28
56
|
},
|
|
29
57
|
],
|
|
30
|
-
columns: [
|
|
58
|
+
columns: [
|
|
59
|
+
"id",
|
|
60
|
+
"parent_id",
|
|
61
|
+
"author",
|
|
62
|
+
"text",
|
|
63
|
+
"likes",
|
|
64
|
+
"retweets",
|
|
65
|
+
"views",
|
|
66
|
+
"url",
|
|
67
|
+
"depth",
|
|
68
|
+
"path",
|
|
69
|
+
],
|
|
31
70
|
func: async (_page, kwargs) => {
|
|
32
71
|
const tweetId = String(kwargs.tweet_id);
|
|
33
72
|
|
|
@@ -56,6 +95,9 @@ cli({
|
|
|
56
95
|
| undefined;
|
|
57
96
|
const instructions = (conversation?.instructions as unknown[]) ?? [];
|
|
58
97
|
|
|
59
|
-
return
|
|
98
|
+
return normalizeTwitterThreadRows(
|
|
99
|
+
tweetId,
|
|
100
|
+
extractTweetsFromInstructions(instructions),
|
|
101
|
+
);
|
|
60
102
|
},
|
|
61
103
|
});
|
|
@@ -4,9 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
import { cli } from "../../registry.js";
|
|
6
6
|
import { Strategy } from "../../types.js";
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
const GUIDE_URL = "https://x.com/i/api/2/guide.json";
|
|
7
|
+
import { browserTrendingTopics } from "./browser-fallback.js";
|
|
8
|
+
import type { IPage } from "../../types.js";
|
|
10
9
|
|
|
11
10
|
cli({
|
|
12
11
|
site: "twitter",
|
|
@@ -14,99 +13,19 @@ cli({
|
|
|
14
13
|
description: "Get trending topics",
|
|
15
14
|
domain: "x.com",
|
|
16
15
|
strategy: Strategy.COOKIE,
|
|
16
|
+
browser: true,
|
|
17
|
+
browserSession: "user",
|
|
18
|
+
args: [
|
|
19
|
+
{
|
|
20
|
+
name: "limit",
|
|
21
|
+
type: "int",
|
|
22
|
+
default: 20,
|
|
23
|
+
description: "Number of trends",
|
|
24
|
+
},
|
|
25
|
+
],
|
|
17
26
|
columns: ["name", "tweet_count", "description", "url"],
|
|
18
|
-
func: async (
|
|
27
|
+
func: async (page, kwargs) => {
|
|
19
28
|
const count = (kwargs.limit as number) ?? 20;
|
|
20
|
-
|
|
21
|
-
const data = (await twitterGuideFetch(GUIDE_URL, {
|
|
22
|
-
count: String(count),
|
|
23
|
-
include_page_configuration: "false",
|
|
24
|
-
})) as Record<string, unknown>;
|
|
25
|
-
|
|
26
|
-
// Navigate: data.timeline.instructions[0].addEntries.entries
|
|
27
|
-
const timeline = data.timeline as Record<string, unknown> | undefined;
|
|
28
|
-
const instructions = (timeline?.instructions as unknown[]) ?? [];
|
|
29
|
-
|
|
30
|
-
const trends: Array<{
|
|
31
|
-
name: string;
|
|
32
|
-
tweet_count: string;
|
|
33
|
-
description: string;
|
|
34
|
-
url: string;
|
|
35
|
-
}> = [];
|
|
36
|
-
|
|
37
|
-
for (const instruction of instructions) {
|
|
38
|
-
const inst = instruction as Record<string, unknown>;
|
|
39
|
-
const addEntries = inst.addEntries as Record<string, unknown> | undefined;
|
|
40
|
-
if (!addEntries) continue;
|
|
41
|
-
|
|
42
|
-
const entries = (addEntries.entries as unknown[]) ?? [];
|
|
43
|
-
|
|
44
|
-
for (const entry of entries) {
|
|
45
|
-
const e = entry as Record<string, unknown>;
|
|
46
|
-
const content = e.content as Record<string, unknown> | undefined;
|
|
47
|
-
if (!content) continue;
|
|
48
|
-
|
|
49
|
-
// Trend items are nested in timelineModule or timelineItem
|
|
50
|
-
const items =
|
|
51
|
-
(content.items as unknown[]) ??
|
|
52
|
-
(content.item ? [{ item: content.item }] : []);
|
|
53
|
-
|
|
54
|
-
for (const item of items) {
|
|
55
|
-
const i = item as Record<string, unknown>;
|
|
56
|
-
const itemObj = (i.item ?? i) as Record<string, unknown>;
|
|
57
|
-
const clientEventInfo = itemObj.clientEventInfo as
|
|
58
|
-
| Record<string, unknown>
|
|
59
|
-
| undefined;
|
|
60
|
-
const details = clientEventInfo?.details as
|
|
61
|
-
| Record<string, unknown>
|
|
62
|
-
| undefined;
|
|
63
|
-
const guideDetails = details?.guideDetails as
|
|
64
|
-
| Record<string, unknown>
|
|
65
|
-
| undefined;
|
|
66
|
-
const transparentGuideDetails =
|
|
67
|
-
guideDetails?.transparentGuideDetails as
|
|
68
|
-
| Record<string, unknown>
|
|
69
|
-
| undefined;
|
|
70
|
-
const trendMetadata = transparentGuideDetails?.trendMetadata as
|
|
71
|
-
| Record<string, unknown>
|
|
72
|
-
| undefined;
|
|
73
|
-
|
|
74
|
-
// Also try direct content path
|
|
75
|
-
const itemContent = (
|
|
76
|
-
itemObj as Record<string, Record<string, unknown>>
|
|
77
|
-
).content;
|
|
78
|
-
const trend = itemContent?.trend as
|
|
79
|
-
| Record<string, unknown>
|
|
80
|
-
| undefined;
|
|
81
|
-
|
|
82
|
-
const name =
|
|
83
|
-
(trendMetadata?.trendName as string) ??
|
|
84
|
-
(trend?.name as string) ??
|
|
85
|
-
"";
|
|
86
|
-
if (!name) continue;
|
|
87
|
-
|
|
88
|
-
const tweetCount =
|
|
89
|
-
(trendMetadata?.metaDescription as string) ??
|
|
90
|
-
(trend?.tweetCount as string) ??
|
|
91
|
-
"";
|
|
92
|
-
const desc =
|
|
93
|
-
(trend?.description as string) ??
|
|
94
|
-
(trendMetadata?.metaDescription as string) ??
|
|
95
|
-
"";
|
|
96
|
-
const trendUrl = trend?.url as Record<string, unknown> | undefined;
|
|
97
|
-
|
|
98
|
-
trends.push({
|
|
99
|
-
name,
|
|
100
|
-
tweet_count: tweetCount,
|
|
101
|
-
description: desc,
|
|
102
|
-
url:
|
|
103
|
-
(trendUrl?.url as string) ??
|
|
104
|
-
`https://x.com/search?q=${encodeURIComponent(name)}`,
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return trends.slice(0, count);
|
|
29
|
+
return browserTrendingTopics(page as IPage, count);
|
|
111
30
|
},
|
|
112
31
|
});
|