@zenalexa/unicli 0.219.0 → 0.220.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 +9 -9
- package/README.md +55 -249
- package/README.zh-CN.md +55 -249
- package/dist/adapters/1point3acres/forum.d.ts +58 -0
- package/dist/adapters/1point3acres/forum.d.ts.map +1 -0
- package/dist/adapters/1point3acres/forum.js +708 -0
- package/dist/adapters/1point3acres/forum.js.map +1 -0
- package/dist/adapters/aibase/news.d.ts +21 -0
- package/dist/adapters/aibase/news.d.ts.map +1 -0
- package/dist/adapters/aibase/news.js +96 -0
- package/dist/adapters/aibase/news.js.map +1 -0
- package/dist/adapters/arxiv/papers.d.ts +27 -0
- package/dist/adapters/arxiv/papers.d.ts.map +1 -0
- package/dist/adapters/arxiv/papers.js +193 -0
- package/dist/adapters/arxiv/papers.js.map +1 -0
- package/dist/adapters/bbc/topic.d.ts +24 -0
- package/dist/adapters/bbc/topic.d.ts.map +1 -0
- package/dist/adapters/bbc/topic.js +122 -0
- package/dist/adapters/bbc/topic.js.map +1 -0
- package/dist/adapters/chatgpt/web.d.ts +24 -0
- package/dist/adapters/chatgpt/web.d.ts.map +1 -0
- package/dist/adapters/chatgpt/web.js +242 -0
- package/dist/adapters/chatgpt/web.js.map +1 -0
- package/dist/adapters/claude/web.d.ts +24 -0
- package/dist/adapters/claude/web.d.ts.map +1 -0
- package/dist/adapters/claude/web.js +575 -0
- package/dist/adapters/claude/web.js.map +1 -0
- package/dist/adapters/codex/projects.d.ts +27 -0
- package/dist/adapters/codex/projects.d.ts.map +1 -0
- package/dist/adapters/codex/projects.js +147 -0
- package/dist/adapters/codex/projects.js.map +1 -0
- package/dist/adapters/coingecko/markets.d.ts +19 -0
- package/dist/adapters/coingecko/markets.d.ts.map +1 -0
- package/dist/adapters/coingecko/markets.js +474 -0
- package/dist/adapters/coingecko/markets.js.map +1 -0
- package/dist/adapters/coupang/product.d.ts +27 -0
- package/dist/adapters/coupang/product.d.ts.map +1 -0
- package/dist/adapters/coupang/product.js +211 -0
- package/dist/adapters/coupang/product.js.map +1 -0
- package/dist/adapters/crates/registry.d.ts +44 -0
- package/dist/adapters/crates/registry.d.ts.map +1 -0
- package/dist/adapters/crates/registry.js +186 -0
- package/dist/adapters/crates/registry.js.map +1 -0
- package/dist/adapters/ctrip/travel.d.ts +83 -0
- package/dist/adapters/ctrip/travel.d.ts.map +1 -0
- package/dist/adapters/ctrip/travel.js +630 -0
- package/dist/adapters/ctrip/travel.js.map +1 -0
- package/dist/adapters/dblp/publications.d.ts +41 -0
- package/dist/adapters/dblp/publications.d.ts.map +1 -0
- package/dist/adapters/dblp/publications.js +409 -0
- package/dist/adapters/dblp/publications.js.map +1 -0
- package/dist/adapters/deepseek/web.d.ts +1 -1
- package/dist/adapters/deepseek/web.d.ts.map +1 -1
- package/dist/adapters/deepseek/web.js +66 -1
- package/dist/adapters/deepseek/web.js.map +1 -1
- package/dist/adapters/defillama/protocols.d.ts +13 -0
- package/dist/adapters/defillama/protocols.d.ts.map +1 -0
- package/dist/adapters/defillama/protocols.js +218 -0
- package/dist/adapters/defillama/protocols.js.map +1 -0
- package/dist/adapters/devto/read.d.ts +26 -0
- package/dist/adapters/devto/read.d.ts.map +1 -0
- package/dist/adapters/devto/read.js +110 -0
- package/dist/adapters/devto/read.js.map +1 -0
- package/dist/adapters/dianping/shop.d.ts +38 -0
- package/dist/adapters/dianping/shop.d.ts.map +1 -0
- package/dist/adapters/dianping/shop.js +194 -0
- package/dist/adapters/dianping/shop.js.map +1 -0
- package/dist/adapters/dockerhub/registry.d.ts +36 -0
- package/dist/adapters/dockerhub/registry.d.ts.map +1 -0
- package/dist/adapters/dockerhub/registry.js +172 -0
- package/dist/adapters/dockerhub/registry.js.map +1 -0
- package/dist/adapters/endoflife/product.d.ts +11 -0
- package/dist/adapters/endoflife/product.d.ts.map +1 -0
- package/dist/adapters/endoflife/product.js +113 -0
- package/dist/adapters/endoflife/product.js.map +1 -0
- package/dist/adapters/facebook/marketplace-extra.d.ts +9 -0
- package/dist/adapters/facebook/marketplace-extra.d.ts.map +1 -0
- package/dist/adapters/facebook/marketplace-extra.js +170 -0
- package/dist/adapters/facebook/marketplace-extra.js.map +1 -0
- package/dist/adapters/flathub/apps.d.ts +17 -0
- package/dist/adapters/flathub/apps.d.ts.map +1 -0
- package/dist/adapters/flathub/apps.js +220 -0
- package/dist/adapters/flathub/apps.js.map +1 -0
- package/dist/adapters/goproxy/module.d.ts +24 -0
- package/dist/adapters/goproxy/module.d.ts.map +1 -0
- package/dist/adapters/goproxy/module.js +221 -0
- package/dist/adapters/goproxy/module.js.map +1 -0
- package/dist/adapters/grok/web.d.ts +29 -0
- package/dist/adapters/grok/web.d.ts.map +1 -0
- package/dist/adapters/grok/web.js +553 -0
- package/dist/adapters/grok/web.js.map +1 -0
- package/dist/adapters/hackernews/read.d.ts +31 -0
- package/dist/adapters/hackernews/read.d.ts.map +1 -0
- package/dist/adapters/hackernews/read.js +201 -0
- package/dist/adapters/hackernews/read.js.map +1 -0
- package/dist/adapters/hf/paper.d.ts +22 -0
- package/dist/adapters/hf/paper.d.ts.map +1 -0
- package/dist/adapters/hf/paper.js +112 -0
- package/dist/adapters/hf/paper.js.map +1 -0
- package/dist/adapters/homebrew/packages.d.ts +52 -0
- package/dist/adapters/homebrew/packages.d.ts.map +1 -0
- package/dist/adapters/homebrew/packages.js +240 -0
- package/dist/adapters/homebrew/packages.js.map +1 -0
- package/dist/adapters/indeed/jobs.d.ts +38 -0
- package/dist/adapters/indeed/jobs.d.ts.map +1 -0
- package/dist/adapters/indeed/jobs.js +300 -0
- package/dist/adapters/indeed/jobs.js.map +1 -0
- package/dist/adapters/instagram/collections.d.ts +9 -0
- package/dist/adapters/instagram/collections.d.ts.map +1 -0
- package/dist/adapters/instagram/collections.js +174 -0
- package/dist/adapters/instagram/collections.js.map +1 -0
- package/dist/adapters/lichess/players.d.ts +46 -0
- package/dist/adapters/lichess/players.d.ts.map +1 -0
- package/dist/adapters/lichess/players.js +221 -0
- package/dist/adapters/lichess/players.js.map +1 -0
- package/dist/adapters/lobsters/read-domain.d.ts +35 -0
- package/dist/adapters/lobsters/read-domain.d.ts.map +1 -0
- package/dist/adapters/lobsters/read-domain.js +306 -0
- package/dist/adapters/lobsters/read-domain.js.map +1 -0
- package/dist/adapters/maven/artifact.d.ts +30 -0
- package/dist/adapters/maven/artifact.d.ts.map +1 -0
- package/dist/adapters/maven/artifact.js +121 -0
- package/dist/adapters/maven/artifact.js.map +1 -0
- package/dist/adapters/mdn/search.d.ts +11 -0
- package/dist/adapters/mdn/search.d.ts.map +1 -0
- package/dist/adapters/mdn/search.js +115 -0
- package/dist/adapters/mdn/search.js.map +1 -0
- package/dist/adapters/medium/tag.d.ts +15 -0
- package/dist/adapters/medium/tag.d.ts.map +1 -0
- package/dist/adapters/medium/tag.js +148 -0
- package/dist/adapters/medium/tag.js.map +1 -0
- package/dist/adapters/npm/package.d.ts +32 -0
- package/dist/adapters/npm/package.d.ts.map +1 -0
- package/dist/adapters/npm/package.js +141 -0
- package/dist/adapters/npm/package.js.map +1 -0
- package/dist/adapters/nuget/package.d.ts +34 -0
- package/dist/adapters/nuget/package.d.ts.map +1 -0
- package/dist/adapters/nuget/package.js +135 -0
- package/dist/adapters/nuget/package.js.map +1 -0
- package/dist/adapters/nvd/cve.d.ts +42 -0
- package/dist/adapters/nvd/cve.d.ts.map +1 -0
- package/dist/adapters/nvd/cve.js +132 -0
- package/dist/adapters/nvd/cve.js.map +1 -0
- package/dist/adapters/oeis/sequences.d.ts +14 -0
- package/dist/adapters/oeis/sequences.d.ts.map +1 -0
- package/dist/adapters/oeis/sequences.js +219 -0
- package/dist/adapters/oeis/sequences.js.map +1 -0
- package/dist/adapters/openalex/works.d.ts +43 -0
- package/dist/adapters/openalex/works.d.ts.map +1 -0
- package/dist/adapters/openalex/works.js +267 -0
- package/dist/adapters/openalex/works.js.map +1 -0
- package/dist/adapters/openfda/records.d.ts +18 -0
- package/dist/adapters/openfda/records.d.ts.map +1 -0
- package/dist/adapters/openfda/records.js +209 -0
- package/dist/adapters/openfda/records.js.map +1 -0
- package/dist/adapters/openreview/papers.d.ts +34 -0
- package/dist/adapters/openreview/papers.d.ts.map +1 -0
- package/dist/adapters/openreview/papers.js +463 -0
- package/dist/adapters/openreview/papers.js.map +1 -0
- package/dist/adapters/osv/security.d.ts +36 -0
- package/dist/adapters/osv/security.d.ts.map +1 -0
- package/dist/adapters/osv/security.js +247 -0
- package/dist/adapters/osv/security.js.map +1 -0
- package/dist/adapters/packagist/package.d.ts +31 -0
- package/dist/adapters/packagist/package.d.ts.map +1 -0
- package/dist/adapters/packagist/package.js +108 -0
- package/dist/adapters/packagist/package.js.map +1 -0
- package/dist/adapters/pubmed/articles.d.ts +31 -0
- package/dist/adapters/pubmed/articles.d.ts.map +1 -0
- package/dist/adapters/pubmed/articles.js +385 -0
- package/dist/adapters/pubmed/articles.js.map +1 -0
- package/dist/adapters/pypi/package.d.ts +38 -0
- package/dist/adapters/pypi/package.d.ts.map +1 -0
- package/dist/adapters/pypi/package.js +235 -0
- package/dist/adapters/pypi/package.js.map +1 -0
- package/dist/adapters/qwen/web.d.ts +26 -0
- package/dist/adapters/qwen/web.d.ts.map +1 -0
- package/dist/adapters/qwen/web.js +672 -0
- package/dist/adapters/qwen/web.js.map +1 -0
- package/dist/adapters/reddit/account.d.ts +12 -0
- package/dist/adapters/reddit/account.d.ts.map +1 -0
- package/dist/adapters/reddit/account.js +409 -0
- package/dist/adapters/reddit/account.js.map +1 -0
- package/dist/adapters/rednote/web.d.ts +30 -0
- package/dist/adapters/rednote/web.d.ts.map +1 -0
- package/dist/adapters/rednote/web.js +858 -0
- package/dist/adapters/rednote/web.js.map +1 -0
- package/dist/adapters/rest-countries/countries.d.ts +14 -0
- package/dist/adapters/rest-countries/countries.d.ts.map +1 -0
- package/dist/adapters/rest-countries/countries.js +231 -0
- package/dist/adapters/rest-countries/countries.js.map +1 -0
- package/dist/adapters/reuters/article-detail.d.ts +37 -0
- package/dist/adapters/reuters/article-detail.d.ts.map +1 -0
- package/dist/adapters/reuters/article-detail.js +139 -0
- package/dist/adapters/reuters/article-detail.js.map +1 -0
- package/dist/adapters/rfc/rfc.d.ts +11 -0
- package/dist/adapters/rfc/rfc.d.ts.map +1 -0
- package/dist/adapters/rfc/rfc.js +121 -0
- package/dist/adapters/rfc/rfc.js.map +1 -0
- package/dist/adapters/rubygems/gem.d.ts +26 -0
- package/dist/adapters/rubygems/gem.d.ts.map +1 -0
- package/dist/adapters/rubygems/gem.js +96 -0
- package/dist/adapters/rubygems/gem.js.map +1 -0
- package/dist/adapters/stackoverflow/questions.d.ts +79 -0
- package/dist/adapters/stackoverflow/questions.d.ts.map +1 -0
- package/dist/adapters/stackoverflow/questions.js +504 -0
- package/dist/adapters/stackoverflow/questions.js.map +1 -0
- package/dist/adapters/steam/app.d.ts +39 -0
- package/dist/adapters/steam/app.d.ts.map +1 -0
- package/dist/adapters/steam/app.js +165 -0
- package/dist/adapters/steam/app.js.map +1 -0
- package/dist/adapters/tiktok/creator-videos.d.ts +52 -0
- package/dist/adapters/tiktok/creator-videos.d.ts.map +1 -0
- package/dist/adapters/tiktok/creator-videos.js +267 -0
- package/dist/adapters/tiktok/creator-videos.js.map +1 -0
- package/dist/adapters/tvmaze/shows.d.ts +13 -0
- package/dist/adapters/tvmaze/shows.d.ts.map +1 -0
- package/dist/adapters/tvmaze/shows.js +240 -0
- package/dist/adapters/tvmaze/shows.js.map +1 -0
- package/dist/adapters/twitter/bookmark-folders.d.ts +33 -0
- package/dist/adapters/twitter/bookmark-folders.d.ts.map +1 -0
- package/dist/adapters/twitter/bookmark-folders.js +290 -0
- package/dist/adapters/twitter/bookmark-folders.js.map +1 -0
- package/dist/adapters/twitter/quote.d.ts +18 -0
- package/dist/adapters/twitter/quote.d.ts.map +1 -0
- package/dist/adapters/twitter/quote.js +285 -0
- package/dist/adapters/twitter/quote.js.map +1 -0
- package/dist/adapters/twitter/tweet-actions.d.ts +12 -0
- package/dist/adapters/twitter/tweet-actions.d.ts.map +1 -0
- package/dist/adapters/twitter/tweet-actions.js +145 -0
- package/dist/adapters/twitter/tweet-actions.js.map +1 -0
- package/dist/adapters/twitter/tweet-url.d.ts +15 -0
- package/dist/adapters/twitter/tweet-url.d.ts.map +1 -0
- package/dist/adapters/twitter/tweet-url.js +57 -0
- package/dist/adapters/twitter/tweet-url.js.map +1 -0
- package/dist/adapters/uisdc/news.d.ts +22 -0
- package/dist/adapters/uisdc/news.d.ts.map +1 -0
- package/dist/adapters/uisdc/news.js +91 -0
- package/dist/adapters/uisdc/news.js.map +1 -0
- package/dist/adapters/weibo/favorites-publish.d.ts +28 -0
- package/dist/adapters/weibo/favorites-publish.d.ts.map +1 -0
- package/dist/adapters/weibo/favorites-publish.js +356 -0
- package/dist/adapters/weibo/favorites-publish.js.map +1 -0
- package/dist/adapters/wikidata/entities.d.ts +15 -0
- package/dist/adapters/wikidata/entities.d.ts.map +1 -0
- package/dist/adapters/wikidata/entities.js +219 -0
- package/dist/adapters/wikidata/entities.js.map +1 -0
- package/dist/adapters/wikipedia/page.d.ts +21 -0
- package/dist/adapters/wikipedia/page.d.ts.map +1 -0
- package/dist/adapters/wikipedia/page.js +116 -0
- package/dist/adapters/wikipedia/page.js.map +1 -0
- package/dist/adapters/wttr/weather.d.ts +12 -0
- package/dist/adapters/wttr/weather.d.ts.map +1 -0
- package/dist/adapters/wttr/weather.js +207 -0
- package/dist/adapters/wttr/weather.js.map +1 -0
- package/dist/adapters/xianyu/publish.d.ts +31 -0
- package/dist/adapters/xianyu/publish.d.ts.map +1 -0
- package/dist/adapters/xianyu/publish.js +349 -0
- package/dist/adapters/xianyu/publish.js.map +1 -0
- package/dist/adapters/xiaohongshu/user-helpers.d.ts +2 -2
- package/dist/adapters/xiaohongshu/user-helpers.d.ts.map +1 -1
- package/dist/adapters/xiaohongshu/user-helpers.js +5 -4
- package/dist/adapters/xiaohongshu/user-helpers.js.map +1 -1
- package/dist/adapters/yuanbao/web.d.ts +27 -0
- package/dist/adapters/yuanbao/web.d.ts.map +1 -0
- package/dist/adapters/yuanbao/web.js +365 -0
- package/dist/adapters/yuanbao/web.js.map +1 -0
- package/dist/adapters/zhihu/collection.d.ts +33 -0
- package/dist/adapters/zhihu/collection.d.ts.map +1 -0
- package/dist/adapters/zhihu/collection.js +185 -0
- package/dist/adapters/zhihu/collection.js.map +1 -0
- package/dist/adapters/zlibrary/web.d.ts +19 -0
- package/dist/adapters/zlibrary/web.d.ts.map +1 -0
- package/dist/adapters/zlibrary/web.js +153 -0
- package/dist/adapters/zlibrary/web.js.map +1 -0
- package/dist/browser/daemon-client.js +2 -2
- package/dist/browser/daemon-client.js.map +1 -1
- package/dist/discovery/macos-dynamic.d.ts.map +1 -1
- package/dist/discovery/macos-dynamic.js +17 -3
- package/dist/discovery/macos-dynamic.js.map +1 -1
- package/dist/manifest-compact.txt +10 -10
- package/dist/manifest-search.json +1 -1
- package/dist/manifest.json +5130 -112
- package/dist/transport/refs.d.ts +5 -3
- package/dist/transport/refs.d.ts.map +1 -1
- package/dist/transport/refs.js +8 -1
- package/dist/transport/refs.js.map +1 -1
- package/dist/transport/sidecar-binary.d.ts +7 -0
- package/dist/transport/sidecar-binary.d.ts.map +1 -1
- package/dist/transport/sidecar-binary.js +28 -8
- package/dist/transport/sidecar-binary.js.map +1 -1
- package/package.json +4 -3
- 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/1point3acres/forum.test.ts +300 -0
- package/src/adapters/1point3acres/forum.ts +852 -0
- package/src/adapters/aibase/news.test.ts +42 -0
- package/src/adapters/aibase/news.ts +118 -0
- package/src/adapters/arxiv/papers.test.ts +59 -0
- package/src/adapters/arxiv/papers.ts +226 -0
- package/src/adapters/bbc/topic.test.ts +52 -0
- package/src/adapters/bbc/topic.ts +149 -0
- package/src/adapters/chatgpt/web.test.ts +121 -0
- package/src/adapters/chatgpt/web.ts +286 -0
- package/src/adapters/claude/web.test.ts +206 -0
- package/src/adapters/claude/web.ts +684 -0
- package/src/adapters/codex/projects.test.ts +77 -0
- package/src/adapters/codex/projects.ts +178 -0
- package/src/adapters/coingecko/markets.test.ts +156 -0
- package/src/adapters/coingecko/markets.ts +574 -0
- package/src/adapters/coupang/product.test.ts +111 -0
- package/src/adapters/coupang/product.ts +256 -0
- package/src/adapters/crates/registry.test.ts +89 -0
- package/src/adapters/crates/registry.ts +247 -0
- package/src/adapters/ctrip/travel.test.ts +359 -0
- package/src/adapters/ctrip/travel.ts +792 -0
- package/src/adapters/dblp/publications.test.ts +123 -0
- package/src/adapters/dblp/publications.ts +494 -0
- package/src/adapters/deepseek/web.test.ts +69 -0
- package/src/adapters/deepseek/web.ts +78 -1
- package/src/adapters/defillama/protocols.test.ts +75 -0
- package/src/adapters/defillama/protocols.ts +253 -0
- package/src/adapters/devto/read.test.ts +49 -0
- package/src/adapters/devto/read.ts +145 -0
- package/src/adapters/dianping/shop.test.ts +134 -0
- package/src/adapters/dianping/shop.ts +261 -0
- package/src/adapters/dockerhub/registry.test.ts +97 -0
- package/src/adapters/dockerhub/registry.ts +223 -0
- package/src/adapters/endoflife/product.test.ts +50 -0
- package/src/adapters/endoflife/product.ts +128 -0
- package/src/adapters/facebook/marketplace-extra.test.ts +132 -0
- package/src/adapters/facebook/marketplace-extra.ts +213 -0
- package/src/adapters/flathub/apps.test.ts +85 -0
- package/src/adapters/flathub/apps.ts +254 -0
- package/src/adapters/goproxy/module.test.ts +72 -0
- package/src/adapters/goproxy/module.ts +258 -0
- package/src/adapters/grok/web.test.ts +181 -0
- package/src/adapters/grok/web.ts +640 -0
- package/src/adapters/hackernews/read.test.ts +68 -0
- package/src/adapters/hackernews/read.ts +265 -0
- package/src/adapters/hf/paper.test.ts +48 -0
- package/src/adapters/hf/paper.ts +138 -0
- package/src/adapters/homebrew/packages.test.ts +109 -0
- package/src/adapters/homebrew/packages.ts +304 -0
- package/src/adapters/indeed/jobs.test.ts +230 -0
- package/src/adapters/indeed/jobs.ts +375 -0
- package/src/adapters/instagram/collections.test.ts +94 -0
- package/src/adapters/instagram/collections.ts +206 -0
- package/src/adapters/lichess/players.test.ts +99 -0
- package/src/adapters/lichess/players.ts +277 -0
- package/src/adapters/lobsters/read-domain.test.ts +121 -0
- package/src/adapters/lobsters/read-domain.ts +400 -0
- package/src/adapters/maven/artifact.test.ts +67 -0
- package/src/adapters/maven/artifact.ts +155 -0
- package/src/adapters/mdn/search.test.ts +39 -0
- package/src/adapters/mdn/search.ts +133 -0
- package/src/adapters/medium/tag.test.ts +64 -0
- package/src/adapters/medium/tag.ts +164 -0
- package/src/adapters/npm/package.test.ts +53 -0
- package/src/adapters/npm/package.ts +177 -0
- package/src/adapters/nuget/package.test.ts +102 -0
- package/src/adapters/nuget/package.ts +193 -0
- package/src/adapters/nvd/cve.test.ts +66 -0
- package/src/adapters/nvd/cve.ts +182 -0
- package/src/adapters/oeis/sequences.test.ts +71 -0
- package/src/adapters/oeis/sequences.ts +234 -0
- package/src/adapters/openalex/works.test.ts +99 -0
- package/src/adapters/openalex/works.ts +319 -0
- package/src/adapters/openfda/records.test.ts +90 -0
- package/src/adapters/openfda/records.ts +239 -0
- package/src/adapters/openreview/papers.test.ts +139 -0
- package/src/adapters/openreview/papers.ts +560 -0
- package/src/adapters/osv/security.test.ts +91 -0
- package/src/adapters/osv/security.ts +298 -0
- package/src/adapters/packagist/package.test.ts +62 -0
- package/src/adapters/packagist/package.ts +146 -0
- package/src/adapters/pubmed/articles.test.ts +96 -0
- package/src/adapters/pubmed/articles.ts +497 -0
- package/src/adapters/pypi/package.test.ts +131 -0
- package/src/adapters/pypi/package.ts +297 -0
- package/src/adapters/qwen/web.test.ts +176 -0
- package/src/adapters/qwen/web.ts +758 -0
- package/src/adapters/reddit/account.test.ts +56 -0
- package/src/adapters/reddit/account.ts +493 -0
- package/src/adapters/rednote/web.test.ts +354 -0
- package/src/adapters/rednote/web.ts +968 -0
- package/src/adapters/rest-countries/countries.test.ts +80 -0
- package/src/adapters/rest-countries/countries.ts +271 -0
- package/src/adapters/reuters/article-detail.test.ts +65 -0
- package/src/adapters/reuters/article-detail.ts +186 -0
- package/src/adapters/rfc/rfc.test.ts +37 -0
- package/src/adapters/rfc/rfc.ts +133 -0
- package/src/adapters/rubygems/gem.test.ts +43 -0
- package/src/adapters/rubygems/gem.ts +126 -0
- package/src/adapters/stackoverflow/questions.test.ts +207 -0
- package/src/adapters/stackoverflow/questions.ts +765 -0
- package/src/adapters/steam/app.test.ts +68 -0
- package/src/adapters/steam/app.ts +218 -0
- package/src/adapters/tiktok/creator-videos.test.ts +158 -0
- package/src/adapters/tiktok/creator-videos.ts +370 -0
- package/src/adapters/tvmaze/shows.test.ts +93 -0
- package/src/adapters/tvmaze/shows.ts +271 -0
- package/src/adapters/twitter/bookmark-folders.test.ts +164 -0
- package/src/adapters/twitter/bookmark-folders.ts +366 -0
- package/src/adapters/twitter/quote.test.ts +157 -0
- package/src/adapters/twitter/quote.ts +332 -0
- package/src/adapters/twitter/tweet-actions.test.ts +51 -0
- package/src/adapters/twitter/tweet-actions.ts +187 -0
- package/src/adapters/twitter/tweet-url.ts +65 -0
- package/src/adapters/uisdc/news.test.ts +46 -0
- package/src/adapters/uisdc/news.ts +111 -0
- package/src/adapters/weibo/favorites-publish.test.ts +177 -0
- package/src/adapters/weibo/favorites-publish.ts +426 -0
- package/src/adapters/wikidata/entities.test.ts +103 -0
- package/src/adapters/wikidata/entities.ts +253 -0
- package/src/adapters/wikipedia/page.test.ts +49 -0
- package/src/adapters/wikipedia/page.ts +158 -0
- package/src/adapters/wttr/weather.test.ts +99 -0
- package/src/adapters/wttr/weather.ts +239 -0
- package/src/adapters/xianyu/publish.test.ts +210 -0
- package/src/adapters/xianyu/publish.ts +420 -0
- package/src/adapters/xiaohongshu/user-helpers.ts +5 -2
- package/src/adapters/yuanbao/web.test.ts +144 -0
- package/src/adapters/yuanbao/web.ts +435 -0
- package/src/adapters/zhihu/collection.test.ts +96 -0
- package/src/adapters/zhihu/collection.ts +239 -0
- package/src/adapters/zlibrary/web.test.ts +104 -0
- package/src/adapters/zlibrary/web.ts +192 -0
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @owner src/adapters/yuanbao/web.ts
|
|
3
|
+
* @does Register agent-facing Yuanbao web conversation commands implemented with site-specific safety checks.
|
|
4
|
+
* @needs Logged-in yuanbao.tencent.com browser session, Yuanbao chat DOM, complete agent/session identifiers.
|
|
5
|
+
* @feeds surface coverage ledger, Yuanbao read/send/history/detail/status workflows.
|
|
6
|
+
* @breaks Yuanbao DOM selector drift or accepting bare UUIDs can read/send the wrong session.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { cli, Strategy } from "../../registry.js";
|
|
10
|
+
import { intArg, js, str } from "../_shared/browser-tools.js";
|
|
11
|
+
|
|
12
|
+
const YUANBAO_HOME = "https://yuanbao.tencent.com/";
|
|
13
|
+
const AGENT_ID_RE = /^[A-Za-z0-9_-]{4,40}$/;
|
|
14
|
+
const CONV_ID_RE =
|
|
15
|
+
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
16
|
+
const VISIBLE_JS = `const isVisible = (node) => {
|
|
17
|
+
if (!(node instanceof HTMLElement)) return false;
|
|
18
|
+
const rect = node.getBoundingClientRect();
|
|
19
|
+
const style = window.getComputedStyle(node);
|
|
20
|
+
return rect.width > 0 && rect.height > 0 && style.display !== 'none' && style.visibility !== 'hidden';
|
|
21
|
+
};`;
|
|
22
|
+
|
|
23
|
+
interface YuanbaoBrowserPage {
|
|
24
|
+
goto: (url: string, opts?: Record<string, unknown>) => Promise<unknown>;
|
|
25
|
+
wait: (args: unknown) => Promise<unknown>;
|
|
26
|
+
evaluate: (script: string) => Promise<unknown>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface YuanbaoSession {
|
|
30
|
+
agentId: string;
|
|
31
|
+
convId: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface YuanbaoBubble {
|
|
35
|
+
role?: unknown;
|
|
36
|
+
text?: unknown;
|
|
37
|
+
html?: unknown;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface YuanbaoSessionRow {
|
|
41
|
+
cid?: unknown;
|
|
42
|
+
agentId?: unknown;
|
|
43
|
+
title?: unknown;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function parseYuanbaoSessionId(value: unknown): YuanbaoSession {
|
|
47
|
+
const raw = str(value).trim();
|
|
48
|
+
if (!raw) {
|
|
49
|
+
throw new Error(
|
|
50
|
+
'Yuanbao id must be a non-empty chat URL or "<agentId>/<convId>" pair.',
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
const urlMatch = raw.match(
|
|
54
|
+
/yuanbao\.tencent\.com\/chat\/([A-Za-z0-9_-]+)\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:[/?#]|$)/i,
|
|
55
|
+
);
|
|
56
|
+
if (urlMatch?.[1] && urlMatch[2]) {
|
|
57
|
+
return validateYuanbaoSession(urlMatch[1], urlMatch[2], raw);
|
|
58
|
+
}
|
|
59
|
+
const pairMatch = raw.match(/^([A-Za-z0-9_-]+)\/([0-9a-f-]{36})$/i);
|
|
60
|
+
if (pairMatch?.[1] && pairMatch[2]) {
|
|
61
|
+
return validateYuanbaoSession(pairMatch[1], pairMatch[2], raw);
|
|
62
|
+
}
|
|
63
|
+
throw new Error(
|
|
64
|
+
`Invalid Yuanbao session reference: ${raw}. Pass https://yuanbao.tencent.com/chat/<agentId>/<convId> or "<agentId>/<convId>"; a UUID alone is not enough.`,
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function validateYuanbaoSession(
|
|
69
|
+
agentId: string,
|
|
70
|
+
convId: string,
|
|
71
|
+
source: string,
|
|
72
|
+
): YuanbaoSession {
|
|
73
|
+
if (!AGENT_ID_RE.test(agentId) || !CONV_ID_RE.test(convId)) {
|
|
74
|
+
throw new Error(`Invalid Yuanbao session reference: ${source}.`);
|
|
75
|
+
}
|
|
76
|
+
return { agentId, convId: convId.toLowerCase() };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function yuanbaoSessionUrl(session: YuanbaoSession): string {
|
|
80
|
+
return `${YUANBAO_HOME}chat/${session.agentId}/${session.convId}`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function yuanbaoHtmlToMarkdown(value: unknown): string {
|
|
84
|
+
return str(value)
|
|
85
|
+
.replace(/<br\s*\/?>/gi, "\n")
|
|
86
|
+
.replace(/<\/(p|div|li|h[1-6]|pre)>/gi, "\n")
|
|
87
|
+
.replace(/<[^>]+>/g, " ")
|
|
88
|
+
.replace(/ /g, " ")
|
|
89
|
+
.replace(/</g, "<")
|
|
90
|
+
.replace(/>/g, ">")
|
|
91
|
+
.replace(/&/g, "&")
|
|
92
|
+
.replace(/"/g, '"')
|
|
93
|
+
.replace(/'/g, "'")
|
|
94
|
+
.replace(/[ \t]+\n/g, "\n")
|
|
95
|
+
.replace(/\n{3,}/g, "\n\n")
|
|
96
|
+
.replace(/[ \t]{2,}/g, " ")
|
|
97
|
+
.trim();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function mapYuanbaoBubbles(
|
|
101
|
+
bubbles: YuanbaoBubble[],
|
|
102
|
+
): Record<string, unknown>[] {
|
|
103
|
+
return bubbles
|
|
104
|
+
.map((bubble) => {
|
|
105
|
+
const role = str(bubble.role) === "Assistant" ? "Assistant" : "User";
|
|
106
|
+
const text =
|
|
107
|
+
role === "Assistant" && str(bubble.html).trim()
|
|
108
|
+
? yuanbaoHtmlToMarkdown(bubble.html) || str(bubble.text)
|
|
109
|
+
: str(bubble.text);
|
|
110
|
+
return {
|
|
111
|
+
Role: role,
|
|
112
|
+
Text: text.trim(),
|
|
113
|
+
};
|
|
114
|
+
})
|
|
115
|
+
.filter((row) => row.Text);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function mapYuanbaoSessions(
|
|
119
|
+
sessions: YuanbaoSessionRow[],
|
|
120
|
+
): Record<string, unknown>[] {
|
|
121
|
+
return sessions
|
|
122
|
+
.map((session, index) => {
|
|
123
|
+
const cid = str(session.cid).toLowerCase();
|
|
124
|
+
const agentId = str(session.agentId);
|
|
125
|
+
return {
|
|
126
|
+
Index: index + 1,
|
|
127
|
+
Title: str(session.title, "(untitled)").trim() || "(untitled)",
|
|
128
|
+
AgentId: agentId,
|
|
129
|
+
SessionId: cid,
|
|
130
|
+
Url: `${YUANBAO_HOME}chat/${agentId}/${cid}`,
|
|
131
|
+
};
|
|
132
|
+
})
|
|
133
|
+
.filter(
|
|
134
|
+
(row) =>
|
|
135
|
+
AGENT_ID_RE.test(str(row.AgentId)) &&
|
|
136
|
+
CONV_ID_RE.test(str(row.SessionId)),
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async function currentUrl(page: YuanbaoBrowserPage): Promise<string> {
|
|
141
|
+
const value = await page.evaluate("window.location.href").catch(() => "");
|
|
142
|
+
return typeof value === "string" ? value : "";
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async function ensureYuanbaoPage(page: YuanbaoBrowserPage): Promise<void> {
|
|
146
|
+
const url = await currentUrl(page);
|
|
147
|
+
let onYuanbao = false;
|
|
148
|
+
try {
|
|
149
|
+
const hostname = new URL(url).hostname;
|
|
150
|
+
onYuanbao =
|
|
151
|
+
hostname === "yuanbao.tencent.com" ||
|
|
152
|
+
hostname.endsWith(".yuanbao.tencent.com");
|
|
153
|
+
} catch {
|
|
154
|
+
onYuanbao = false;
|
|
155
|
+
}
|
|
156
|
+
if (!onYuanbao) {
|
|
157
|
+
await page.goto(YUANBAO_HOME, { waitUntil: "load", settleMs: 2500 });
|
|
158
|
+
await page.wait(1);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async function hasLoginGate(page: YuanbaoBrowserPage): Promise<boolean> {
|
|
163
|
+
const result = await page.evaluate(`(() => {
|
|
164
|
+
const bodyText = document.body?.innerText || '';
|
|
165
|
+
const hasWechatLoginText = bodyText.includes('微信扫码登录');
|
|
166
|
+
const hasWechatIframe = Array.from(document.querySelectorAll('iframe'))
|
|
167
|
+
.some((frame) => (frame.getAttribute('src') || '').includes('open.weixin.qq.com/connect/qrconnect'));
|
|
168
|
+
return hasWechatLoginText || hasWechatIframe;
|
|
169
|
+
})()`);
|
|
170
|
+
return Boolean(result);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
async function readBubbles(page: YuanbaoBrowserPage): Promise<YuanbaoBubble[]> {
|
|
174
|
+
const result = await page.evaluate(`(() => {
|
|
175
|
+
${VISIBLE_JS}
|
|
176
|
+
const items = Array.from(document.querySelectorAll('.agent-chat__list__item--human, .agent-chat__list__item--ai'))
|
|
177
|
+
.filter((node) => isVisible(node));
|
|
178
|
+
return items.map((node) => {
|
|
179
|
+
const isAi = node.classList.contains('agent-chat__list__item--ai');
|
|
180
|
+
const contentNode = isAi
|
|
181
|
+
? (node.querySelector('.hyc-content-md-done')
|
|
182
|
+
|| node.querySelector('.hyc-content-md')
|
|
183
|
+
|| node.querySelector('.agent-chat__speech-text')
|
|
184
|
+
|| node.querySelector('.agent-chat__bubble__content'))
|
|
185
|
+
: (node.querySelector('.hyc-component-text .hyc-content-text')
|
|
186
|
+
|| node.querySelector('.hyc-content-text')
|
|
187
|
+
|| node.querySelector('.agent-chat__bubble__content'));
|
|
188
|
+
const html = contentNode instanceof HTMLElement ? (contentNode.innerHTML || '') : '';
|
|
189
|
+
const text = contentNode instanceof HTMLElement
|
|
190
|
+
? (contentNode.innerText || contentNode.textContent || '')
|
|
191
|
+
: ((node.innerText || node.textContent) || '');
|
|
192
|
+
return {
|
|
193
|
+
role: isAi ? 'Assistant' : 'User',
|
|
194
|
+
text: String(text || '').replace(/\\u00a0/g, ' ').trim(),
|
|
195
|
+
html,
|
|
196
|
+
};
|
|
197
|
+
});
|
|
198
|
+
})()`);
|
|
199
|
+
return Array.isArray(result) ? (result as YuanbaoBubble[]) : [];
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async function readCurrentConversation(
|
|
203
|
+
page: YuanbaoBrowserPage,
|
|
204
|
+
): Promise<Record<string, unknown>[]> {
|
|
205
|
+
await ensureYuanbaoPage(page);
|
|
206
|
+
await page.wait(1.5);
|
|
207
|
+
if (await hasLoginGate(page)) {
|
|
208
|
+
throw new Error("Yuanbao login is required before reading messages.");
|
|
209
|
+
}
|
|
210
|
+
const rows = mapYuanbaoBubbles(await readBubbles(page));
|
|
211
|
+
if (!rows.length) throw new Error("No visible Yuanbao messages found.");
|
|
212
|
+
return rows;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
async function listSessions(
|
|
216
|
+
page: YuanbaoBrowserPage,
|
|
217
|
+
limit: number,
|
|
218
|
+
): Promise<Record<string, unknown>[]> {
|
|
219
|
+
await ensureYuanbaoPage(page);
|
|
220
|
+
if (await hasLoginGate(page)) {
|
|
221
|
+
throw new Error("Yuanbao login is required before reading history.");
|
|
222
|
+
}
|
|
223
|
+
await page.wait(1.5);
|
|
224
|
+
const raw = await page.evaluate(`(() => {
|
|
225
|
+
${VISIBLE_JS}
|
|
226
|
+
const nodes = Array.from(document.querySelectorAll('.yb-recent-conv-list__item'))
|
|
227
|
+
.filter((node) => isVisible(node));
|
|
228
|
+
return nodes.map((node) => {
|
|
229
|
+
const cid = node.getAttribute('dt-cid') || '';
|
|
230
|
+
const agentId = node.getAttribute('dt-agent-id') || '';
|
|
231
|
+
const titleEl = node.querySelector('[data-item-name]');
|
|
232
|
+
const title = (titleEl?.getAttribute('data-item-name') || titleEl?.textContent || '').trim();
|
|
233
|
+
return { cid, agentId, title };
|
|
234
|
+
});
|
|
235
|
+
})()`);
|
|
236
|
+
const rows = Array.isArray(raw)
|
|
237
|
+
? mapYuanbaoSessions(raw as YuanbaoSessionRow[])
|
|
238
|
+
: [];
|
|
239
|
+
if (!rows.length)
|
|
240
|
+
throw new Error("No Yuanbao conversations found in the sidebar.");
|
|
241
|
+
return rows.slice(0, limit);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
async function sendYuanbaoPrompt(
|
|
245
|
+
page: YuanbaoBrowserPage,
|
|
246
|
+
prompt: string,
|
|
247
|
+
): Promise<Record<string, unknown>> {
|
|
248
|
+
const result = (await page.evaluate(`(async () => {
|
|
249
|
+
const waitFor = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
250
|
+
${VISIBLE_JS}
|
|
251
|
+
const composer = Array.from(document.querySelectorAll('.ql-editor[contenteditable="true"], .ql-editor, [contenteditable="true"]'))
|
|
252
|
+
.find(isVisible);
|
|
253
|
+
if (!(composer instanceof HTMLElement)) return { ok: false, reason: 'Yuanbao composer was not found.' };
|
|
254
|
+
composer.focus();
|
|
255
|
+
const selection = window.getSelection();
|
|
256
|
+
const range = document.createRange();
|
|
257
|
+
range.selectNodeContents(composer);
|
|
258
|
+
range.collapse(false);
|
|
259
|
+
selection?.removeAllRanges();
|
|
260
|
+
selection?.addRange(range);
|
|
261
|
+
composer.textContent = '';
|
|
262
|
+
document.execCommand('insertText', false, ${js(prompt)});
|
|
263
|
+
composer.dispatchEvent(new InputEvent('input', { bubbles: true, data: ${js(prompt)}, inputType: 'insertText' }));
|
|
264
|
+
const findEnabledSubmit = () => Array.from(document.querySelectorAll('a[class*="send-btn"], button[class*="send-btn"], button[class*="submit"]'))
|
|
265
|
+
.find((node) => {
|
|
266
|
+
if (!(node instanceof HTMLElement) || !isVisible(node)) return false;
|
|
267
|
+
const className = typeof node.className === 'string' ? node.className : '';
|
|
268
|
+
return !className.includes('send-btn--disabled') && !className.includes('disabled');
|
|
269
|
+
});
|
|
270
|
+
let submit = null;
|
|
271
|
+
const deadline = Date.now() + 3000;
|
|
272
|
+
while (Date.now() < deadline) {
|
|
273
|
+
submit = findEnabledSubmit();
|
|
274
|
+
if (submit) break;
|
|
275
|
+
await waitFor(150);
|
|
276
|
+
}
|
|
277
|
+
if (submit instanceof HTMLElement) {
|
|
278
|
+
submit.click();
|
|
279
|
+
return { ok: true, action: 'click' };
|
|
280
|
+
}
|
|
281
|
+
composer.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', code: 'Enter', keyCode: 13, bubbles: true }));
|
|
282
|
+
composer.dispatchEvent(new KeyboardEvent('keyup', { key: 'Enter', code: 'Enter', keyCode: 13, bubbles: true }));
|
|
283
|
+
return { ok: true, action: 'enter' };
|
|
284
|
+
})()`)) as Record<string, unknown>;
|
|
285
|
+
if (!result?.ok) {
|
|
286
|
+
throw new Error(str(result?.reason, "Failed to send Yuanbao prompt."));
|
|
287
|
+
}
|
|
288
|
+
return result;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
cli({
|
|
292
|
+
site: "yuanbao",
|
|
293
|
+
name: "read",
|
|
294
|
+
description: "Read messages in the current Yuanbao conversation",
|
|
295
|
+
domain: "yuanbao.tencent.com",
|
|
296
|
+
strategy: Strategy.COOKIE,
|
|
297
|
+
browser: true,
|
|
298
|
+
columns: ["Role", "Text"],
|
|
299
|
+
func: async (page) => readCurrentConversation(page as YuanbaoBrowserPage),
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
cli({
|
|
303
|
+
site: "yuanbao",
|
|
304
|
+
name: "send",
|
|
305
|
+
description: "Send a prompt to Yuanbao without waiting for the reply",
|
|
306
|
+
domain: "yuanbao.tencent.com",
|
|
307
|
+
strategy: Strategy.COOKIE,
|
|
308
|
+
browser: true,
|
|
309
|
+
args: [
|
|
310
|
+
{ name: "prompt", type: "str", required: true, positional: true },
|
|
311
|
+
{ name: "new", type: "bool", default: false },
|
|
312
|
+
],
|
|
313
|
+
columns: ["Status", "Prompt"],
|
|
314
|
+
func: async (page, kwargs) => {
|
|
315
|
+
const prompt = str(kwargs.prompt).trim();
|
|
316
|
+
if (!prompt) throw new Error("Yuanbao prompt cannot be empty.");
|
|
317
|
+
const p = page as YuanbaoBrowserPage;
|
|
318
|
+
await ensureYuanbaoPage(p);
|
|
319
|
+
if (await hasLoginGate(p)) {
|
|
320
|
+
throw new Error("Yuanbao login is required before sending prompts.");
|
|
321
|
+
}
|
|
322
|
+
if (kwargs.new === true || kwargs.new === "true" || kwargs.new === "1") {
|
|
323
|
+
await p.goto(YUANBAO_HOME, { waitUntil: "load", settleMs: 2500 });
|
|
324
|
+
await p.wait(1);
|
|
325
|
+
}
|
|
326
|
+
await sendYuanbaoPrompt(p, prompt);
|
|
327
|
+
return [{ Status: "sent", Prompt: prompt }];
|
|
328
|
+
},
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
cli({
|
|
332
|
+
site: "yuanbao",
|
|
333
|
+
name: "history",
|
|
334
|
+
description: "List recent Yuanbao conversations from the sidebar",
|
|
335
|
+
domain: "yuanbao.tencent.com",
|
|
336
|
+
strategy: Strategy.COOKIE,
|
|
337
|
+
browser: true,
|
|
338
|
+
args: [{ name: "limit", type: "int", default: 20 }],
|
|
339
|
+
columns: ["Index", "Title", "AgentId", "SessionId", "Url"],
|
|
340
|
+
func: async (page, kwargs) => {
|
|
341
|
+
const limit = intArg(kwargs.limit, 20, 100);
|
|
342
|
+
return listSessions(page as YuanbaoBrowserPage, limit);
|
|
343
|
+
},
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
cli({
|
|
347
|
+
site: "yuanbao",
|
|
348
|
+
name: "detail",
|
|
349
|
+
description: "Open a Yuanbao conversation by ID and read its messages",
|
|
350
|
+
domain: "yuanbao.tencent.com",
|
|
351
|
+
strategy: Strategy.COOKIE,
|
|
352
|
+
browser: true,
|
|
353
|
+
args: [{ name: "id", type: "str", required: true, positional: true }],
|
|
354
|
+
columns: ["Role", "Text"],
|
|
355
|
+
func: async (page, kwargs) => {
|
|
356
|
+
const p = page as YuanbaoBrowserPage;
|
|
357
|
+
const session = parseYuanbaoSessionId(kwargs.id);
|
|
358
|
+
await p.goto(yuanbaoSessionUrl(session), {
|
|
359
|
+
waitUntil: "load",
|
|
360
|
+
settleMs: 2500,
|
|
361
|
+
});
|
|
362
|
+
await p.wait(2);
|
|
363
|
+
if (await hasLoginGate(p)) {
|
|
364
|
+
throw new Error("Yuanbao login is required before reading detail.");
|
|
365
|
+
}
|
|
366
|
+
const startedAt = Date.now();
|
|
367
|
+
while (Date.now() - startedAt < 20_000) {
|
|
368
|
+
const rows = mapYuanbaoBubbles(await readBubbles(p));
|
|
369
|
+
if (rows.length) return rows;
|
|
370
|
+
await p.wait(1);
|
|
371
|
+
}
|
|
372
|
+
throw new Error(
|
|
373
|
+
`No visible Yuanbao messages found for conversation ${session.agentId}/${session.convId}.`,
|
|
374
|
+
);
|
|
375
|
+
},
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
cli({
|
|
379
|
+
site: "yuanbao",
|
|
380
|
+
name: "status",
|
|
381
|
+
description:
|
|
382
|
+
"Check Yuanbao page availability, login state, current session and model",
|
|
383
|
+
domain: "yuanbao.tencent.com",
|
|
384
|
+
strategy: Strategy.COOKIE,
|
|
385
|
+
browser: true,
|
|
386
|
+
columns: [
|
|
387
|
+
"Status",
|
|
388
|
+
"Login",
|
|
389
|
+
"Model",
|
|
390
|
+
"ModelId",
|
|
391
|
+
"AgentId",
|
|
392
|
+
"SessionId",
|
|
393
|
+
"Url",
|
|
394
|
+
],
|
|
395
|
+
func: async (page) => {
|
|
396
|
+
const p = page as YuanbaoBrowserPage;
|
|
397
|
+
await ensureYuanbaoPage(p);
|
|
398
|
+
await p.wait(1.5);
|
|
399
|
+
const [loginGate, session, model, url] = await Promise.all([
|
|
400
|
+
hasLoginGate(p),
|
|
401
|
+
p.evaluate(`(() => {
|
|
402
|
+
const match = window.location.href.match(/yuanbao\\.tencent\\.com\\/chat\\/([A-Za-z0-9_-]+)\\/([0-9a-f-]{36})(?:[/?#]|$)/i);
|
|
403
|
+
if (!match) return null;
|
|
404
|
+
return { agentId: match[1], convId: match[2].toLowerCase() };
|
|
405
|
+
})()`),
|
|
406
|
+
p.evaluate(`(() => {
|
|
407
|
+
const button = document.querySelector('[dt-button-id="model_switch"]');
|
|
408
|
+
if (!(button instanceof HTMLElement)) return { label: null, modelId: null };
|
|
409
|
+
const label = (button.querySelector('.t-button__text')?.textContent || button.textContent || '').trim() || null;
|
|
410
|
+
const modelId = button.getAttribute('dt-model-id') || null;
|
|
411
|
+
return { label, modelId };
|
|
412
|
+
})()`),
|
|
413
|
+
currentUrl(p),
|
|
414
|
+
]);
|
|
415
|
+
const typedSession =
|
|
416
|
+
session && typeof session === "object"
|
|
417
|
+
? (session as { agentId?: unknown; convId?: unknown })
|
|
418
|
+
: null;
|
|
419
|
+
const typedModel =
|
|
420
|
+
model && typeof model === "object"
|
|
421
|
+
? (model as { label?: unknown; modelId?: unknown })
|
|
422
|
+
: null;
|
|
423
|
+
return [
|
|
424
|
+
{
|
|
425
|
+
Status: "Connected",
|
|
426
|
+
Login: loginGate ? "No (login gate)" : "Yes",
|
|
427
|
+
Model: typedModel?.label ?? null,
|
|
428
|
+
ModelId: typedModel?.modelId ?? null,
|
|
429
|
+
AgentId: typedSession?.agentId ?? null,
|
|
430
|
+
SessionId: typedSession?.convId ?? null,
|
|
431
|
+
Url: url,
|
|
432
|
+
},
|
|
433
|
+
];
|
|
434
|
+
},
|
|
435
|
+
});
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
mapZhihuCollectionItem,
|
|
4
|
+
requireZhihuCollectionId,
|
|
5
|
+
requireZhihuNonNegativeInt,
|
|
6
|
+
requireZhihuPositiveInt,
|
|
7
|
+
stripZhihuHtml,
|
|
8
|
+
zhihuCollectionItemKey,
|
|
9
|
+
} from "./collection.js";
|
|
10
|
+
|
|
11
|
+
describe("zhihu agent-facing collection command", () => {
|
|
12
|
+
it("validates collection ids and pagination args", () => {
|
|
13
|
+
expect(requireZhihuCollectionId(" 83283292 ")).toBe("83283292");
|
|
14
|
+
expect(() => requireZhihuCollectionId("abc")).toThrow("numeric");
|
|
15
|
+
expect(requireZhihuPositiveInt(20, "limit")).toBe(20);
|
|
16
|
+
expect(() => requireZhihuPositiveInt(0, "limit")).toThrow("positive");
|
|
17
|
+
expect(requireZhihuNonNegativeInt(0, "offset")).toBe(0);
|
|
18
|
+
expect(() => requireZhihuNonNegativeInt(-1, "offset")).toThrow(
|
|
19
|
+
"non-negative",
|
|
20
|
+
);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("strips Zhihu HTML entities", () => {
|
|
24
|
+
expect(stripZhihuHtml("<p>A <B>&C</p>")).toBe("A <B>&C");
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("maps answer, article, and pin items to stable columns", () => {
|
|
28
|
+
expect(
|
|
29
|
+
mapZhihuCollectionItem(
|
|
30
|
+
{
|
|
31
|
+
content: {
|
|
32
|
+
type: "answer",
|
|
33
|
+
id: 2,
|
|
34
|
+
content: "<p>Answer body</p>",
|
|
35
|
+
question: { id: 1, title: "Question title" },
|
|
36
|
+
author: { name: "Alice" },
|
|
37
|
+
voteup_count: 42,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
1,
|
|
41
|
+
),
|
|
42
|
+
).toEqual({
|
|
43
|
+
rank: 1,
|
|
44
|
+
type: "answer",
|
|
45
|
+
title: "Question title",
|
|
46
|
+
author: "Alice",
|
|
47
|
+
votes: 42,
|
|
48
|
+
excerpt: "Answer body",
|
|
49
|
+
url: "https://www.zhihu.com/question/1/answer/2",
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
expect(
|
|
53
|
+
mapZhihuCollectionItem(
|
|
54
|
+
{
|
|
55
|
+
content: {
|
|
56
|
+
type: "article",
|
|
57
|
+
id: 3,
|
|
58
|
+
title: "Article",
|
|
59
|
+
content: "Article body",
|
|
60
|
+
author: { name: "Bob" },
|
|
61
|
+
voteup_count: 7,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
2,
|
|
65
|
+
).url,
|
|
66
|
+
).toBe("https://zhuanlan.zhihu.com/p/3");
|
|
67
|
+
|
|
68
|
+
expect(
|
|
69
|
+
mapZhihuCollectionItem(
|
|
70
|
+
{
|
|
71
|
+
content: {
|
|
72
|
+
type: "pin",
|
|
73
|
+
id: 4,
|
|
74
|
+
content: [{ content: "Pin body" }],
|
|
75
|
+
author: { name: "Carol" },
|
|
76
|
+
reaction_count: 5,
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
3,
|
|
80
|
+
),
|
|
81
|
+
).toMatchObject({
|
|
82
|
+
rank: 3,
|
|
83
|
+
type: "pin",
|
|
84
|
+
title: "想法",
|
|
85
|
+
author: "Carol",
|
|
86
|
+
votes: 5,
|
|
87
|
+
excerpt: "Pin body",
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("creates stable item keys", () => {
|
|
92
|
+
expect(zhihuCollectionItemKey({ content: { type: "answer", id: 2 } })).toBe(
|
|
93
|
+
"answer:2",
|
|
94
|
+
);
|
|
95
|
+
});
|
|
96
|
+
});
|