@zenalexa/unicli 0.219.0 → 0.220.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +15 -24
- package/README.md +62 -250
- package/README.zh-CN.md +62 -250
- 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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/daemon-client.js +2 -2
- package/dist/browser/daemon-client.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/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/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 +4 -2
- 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/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/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/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/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/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/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/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 +428 -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/steps/download.d.ts +1 -0
- package/dist/engine/steps/download.d.ts.map +1 -1
- package/dist/engine/steps/download.js +10 -6
- package/dist/engine/steps/download.js.map +1 -1
- package/dist/fast-path/render.js +1 -1
- package/dist/fast-path/render.js.map +1 -1
- package/dist/manifest-compact.txt +10 -10
- package/dist/manifest-search.json +1 -1
- package/dist/manifest.json +8421 -332
- 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/error-map.d.ts.map +1 -1
- package/dist/output/error-map.js +1 -1
- package/dist/output/error-map.js.map +1 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +2 -1
- package/dist/registry.js.map +1 -1
- 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/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/arxiv/papers.test.ts +59 -0
- package/src/adapters/arxiv/papers.ts +226 -0
- package/src/adapters/bangumi/web.test.ts +109 -0
- package/src/adapters/bangumi/web.ts +295 -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/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/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/dlsite/web.test.ts +132 -0
- package/src/adapters/dlsite/web.ts +557 -0
- package/src/adapters/dockerhub/registry.test.ts +97 -0
- package/src/adapters/dockerhub/registry.ts +223 -0
- package/src/adapters/ehentai/web.test.ts +157 -0
- package/src/adapters/ehentai/web.ts +750 -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/jikan/web.test.ts +50 -0
- package/src/adapters/jikan/web.ts +177 -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/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/mangadex/web.test.ts +46 -0
- package/src/adapters/mangadex/web.ts +210 -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/moegirl/web.test.ts +87 -0
- package/src/adapters/moegirl/web.ts +343 -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/pdf/read.yaml +49 -0
- package/src/adapters/pixiv/download.yaml +15 -2
- 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/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/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/vndb/web.test.ts +86 -0
- package/src/adapters/vndb/web.ts +393 -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/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/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,684 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @owner src/adapters/claude/web.ts
|
|
3
|
+
* @does Register agent-facing Claude web chat commands implemented with site-specific safety checks.
|
|
4
|
+
* @needs Logged-in claude.ai browser session, Claude chat DOM, optional local file upload path.
|
|
5
|
+
* @feeds surface coverage ledger and Claude ask/read/send/history/detail/new/status workflows.
|
|
6
|
+
* @breaks Claude DOM drift, login redirects, or invalid conversation IDs can block chat automation.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { existsSync, statSync } from "node:fs";
|
|
10
|
+
import { resolve } from "node:path";
|
|
11
|
+
import { cli, Strategy } from "../../registry.js";
|
|
12
|
+
import type { IPage } from "../../types.js";
|
|
13
|
+
import { js, str } from "../_shared/browser-tools.js";
|
|
14
|
+
|
|
15
|
+
const CLAUDE_HOME = "https://claude.ai";
|
|
16
|
+
const CLAUDE_NEW = `${CLAUDE_HOME}/new`;
|
|
17
|
+
const COMPOSER_SELECTOR = '[data-testid="chat-input"]';
|
|
18
|
+
const MESSAGE_SELECTOR = ".font-claude-response";
|
|
19
|
+
const MODEL_DROPDOWN_SELECTOR = '[data-testid="model-selector-dropdown"]';
|
|
20
|
+
const FILE_INPUT_SELECTOR = 'input[data-testid="file-upload"]';
|
|
21
|
+
const CONVERSATION_ID_RE =
|
|
22
|
+
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
23
|
+
const MODEL_DISPLAY_NAMES: Record<string, string> = {
|
|
24
|
+
sonnet: "Sonnet 4.6",
|
|
25
|
+
opus: "Opus 4.7",
|
|
26
|
+
haiku: "Haiku 4.5",
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
interface ClaudePageState {
|
|
30
|
+
url?: unknown;
|
|
31
|
+
title?: unknown;
|
|
32
|
+
hasComposer?: unknown;
|
|
33
|
+
isLoggedIn?: unknown;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface ClaudeMessage {
|
|
37
|
+
role?: unknown;
|
|
38
|
+
text?: unknown;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface ClaudeConversation {
|
|
42
|
+
Id?: unknown;
|
|
43
|
+
Title?: unknown;
|
|
44
|
+
Url?: unknown;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function normalizeClaudeBoolean(value: unknown): boolean {
|
|
48
|
+
if (typeof value === "boolean") return value;
|
|
49
|
+
return str(value).trim().toLowerCase() === "true";
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function requireClaudePrompt(value: unknown, label: string): string {
|
|
53
|
+
const prompt = str(value).trim();
|
|
54
|
+
if (!prompt) throw new Error(`${label} prompt cannot be empty.`);
|
|
55
|
+
return prompt;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function requireClaudePositiveInt(
|
|
59
|
+
value: unknown,
|
|
60
|
+
fallback: number,
|
|
61
|
+
label: string,
|
|
62
|
+
): number {
|
|
63
|
+
const raw = value ?? fallback;
|
|
64
|
+
const n = Number(raw);
|
|
65
|
+
if (!Number.isInteger(n) || n <= 0) {
|
|
66
|
+
throw new Error(`${label} must be a positive integer.`);
|
|
67
|
+
}
|
|
68
|
+
return n;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function parseClaudeConversationId(value: unknown): string {
|
|
72
|
+
const raw = str(value).trim();
|
|
73
|
+
if (!raw) throw new Error("Claude conversation ID cannot be empty.");
|
|
74
|
+
const urlMatch = raw.match(/claude\.ai\/chat\/([0-9a-f-]{36})(?:[/?#]|$)/i);
|
|
75
|
+
const candidate = urlMatch?.[1] ?? raw;
|
|
76
|
+
if (!CONVERSATION_ID_RE.test(candidate)) {
|
|
77
|
+
throw new Error(
|
|
78
|
+
`Invalid Claude conversation ID: ${raw}. Expected UUID or https://claude.ai/chat/<uuid>.`,
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
return candidate.toLowerCase();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function mapClaudeMessages(
|
|
85
|
+
messages: ClaudeMessage[],
|
|
86
|
+
): Record<string, unknown>[] {
|
|
87
|
+
return messages
|
|
88
|
+
.map((message, index) => ({
|
|
89
|
+
Index: index + 1,
|
|
90
|
+
Role: str(message.role),
|
|
91
|
+
Text: str(message.text).trim(),
|
|
92
|
+
}))
|
|
93
|
+
.filter((row) => row.Text);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function mapClaudeConversations(
|
|
97
|
+
conversations: ClaudeConversation[],
|
|
98
|
+
limit: number,
|
|
99
|
+
): Record<string, unknown>[] {
|
|
100
|
+
return conversations
|
|
101
|
+
.map((conversation, index) => ({
|
|
102
|
+
Index: index + 1,
|
|
103
|
+
Id: str(conversation.Id),
|
|
104
|
+
Title: str(conversation.Title, "(untitled)").trim() || "(untitled)",
|
|
105
|
+
Url: str(conversation.Url),
|
|
106
|
+
}))
|
|
107
|
+
.filter((row) => row.Id && row.Url)
|
|
108
|
+
.slice(0, limit);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async function currentUrl(page: IPage): Promise<string> {
|
|
112
|
+
const value = await page.evaluate("window.location.href").catch(() => "");
|
|
113
|
+
return typeof value === "string" ? value : "";
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async function ensureOnClaude(page: IPage): Promise<boolean> {
|
|
117
|
+
const url = await currentUrl(page);
|
|
118
|
+
try {
|
|
119
|
+
const host = new URL(url).hostname.toLowerCase();
|
|
120
|
+
if (host === "claude.ai" || host.endsWith(".claude.ai")) return false;
|
|
121
|
+
} catch {
|
|
122
|
+
await page.goto(CLAUDE_NEW, { waitUntil: "load", settleMs: 2500 });
|
|
123
|
+
try {
|
|
124
|
+
await page.waitForSelector(COMPOSER_SELECTOR, 8);
|
|
125
|
+
} catch {
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
await page.goto(CLAUDE_NEW, { waitUntil: "load", settleMs: 2500 });
|
|
131
|
+
try {
|
|
132
|
+
await page.waitForSelector(COMPOSER_SELECTOR, 8);
|
|
133
|
+
} catch {
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async function getPageState(page: IPage): Promise<ClaudePageState> {
|
|
140
|
+
const state = await page.evaluate(`(() => {
|
|
141
|
+
const composer = document.querySelector(${js(COMPOSER_SELECTOR)});
|
|
142
|
+
const userMenu = document.querySelector('[data-testid="user-menu-button"]');
|
|
143
|
+
return {
|
|
144
|
+
url: window.location.href,
|
|
145
|
+
title: document.title,
|
|
146
|
+
hasComposer: Boolean(composer),
|
|
147
|
+
isLoggedIn: Boolean(userMenu),
|
|
148
|
+
};
|
|
149
|
+
})()`);
|
|
150
|
+
return typeof state === "object" && state !== null
|
|
151
|
+
? (state as ClaudePageState)
|
|
152
|
+
: {};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async function ensureClaudeLogin(
|
|
156
|
+
page: IPage,
|
|
157
|
+
message: string,
|
|
158
|
+
): Promise<ClaudePageState> {
|
|
159
|
+
const state = await getPageState(page);
|
|
160
|
+
if (!state.isLoggedIn) throw new Error(message);
|
|
161
|
+
return state;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async function ensureClaudeComposer(
|
|
165
|
+
page: IPage,
|
|
166
|
+
message: string,
|
|
167
|
+
): Promise<ClaudePageState> {
|
|
168
|
+
const state = await ensureClaudeLogin(page, message);
|
|
169
|
+
if (!state.hasComposer) throw new Error(message);
|
|
170
|
+
return state;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
async function readVisibleMessages(
|
|
174
|
+
page: IPage,
|
|
175
|
+
): Promise<Record<string, unknown>[]> {
|
|
176
|
+
const result = await page.evaluate(`(() => {
|
|
177
|
+
const nodes = document.querySelectorAll('[data-testid="user-message"], ${MESSAGE_SELECTOR}');
|
|
178
|
+
const rows = [];
|
|
179
|
+
Array.from(nodes).forEach((el) => {
|
|
180
|
+
const isUser = el.getAttribute('data-testid') === 'user-message';
|
|
181
|
+
let raw = (el.innerText || '').trim();
|
|
182
|
+
if (!isUser) {
|
|
183
|
+
const parts = raw.split(/\\n\\n+/);
|
|
184
|
+
while (parts.length > 1 && /^(Thought|View)\\b/i.test(parts[0])) parts.shift();
|
|
185
|
+
raw = parts.join('\\n\\n').trim();
|
|
186
|
+
}
|
|
187
|
+
if (raw) rows.push({ role: isUser ? 'user' : 'assistant', text: raw });
|
|
188
|
+
});
|
|
189
|
+
return rows;
|
|
190
|
+
})()`);
|
|
191
|
+
const rows = Array.isArray(result) ? (result as ClaudeMessage[]) : [];
|
|
192
|
+
return mapClaudeMessages(rows);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async function getConversationList(
|
|
196
|
+
page: IPage,
|
|
197
|
+
limit: number,
|
|
198
|
+
): Promise<Record<string, unknown>[]> {
|
|
199
|
+
const url = await currentUrl(page);
|
|
200
|
+
if (!url.includes("/recents")) {
|
|
201
|
+
await page.goto(`${CLAUDE_HOME}/recents`, {
|
|
202
|
+
waitUntil: "load",
|
|
203
|
+
settleMs: 2500,
|
|
204
|
+
});
|
|
205
|
+
try {
|
|
206
|
+
await page.waitForSelector('a[href*="/chat/"]', 8);
|
|
207
|
+
} catch {
|
|
208
|
+
await page.wait(0.5);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
const result = await page.evaluate(`(() => {
|
|
212
|
+
const links = Array.from(document.querySelectorAll('a[href*="/chat/"]'));
|
|
213
|
+
const seen = new Set();
|
|
214
|
+
const rows = [];
|
|
215
|
+
for (const link of links) {
|
|
216
|
+
const href = link.getAttribute('href') || '';
|
|
217
|
+
const idMatch = href.match(/\\/chat\\/([a-f0-9-]{36})/i);
|
|
218
|
+
if (!idMatch || seen.has(idMatch[1])) continue;
|
|
219
|
+
seen.add(idMatch[1]);
|
|
220
|
+
rows.push({
|
|
221
|
+
Id: idMatch[1].toLowerCase(),
|
|
222
|
+
Title: (link.innerText || '').trim().split('\\n')[0].trim() || '(untitled)',
|
|
223
|
+
Url: href.startsWith('http') ? href : (${js(CLAUDE_HOME)} + href),
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
return rows;
|
|
227
|
+
})()`);
|
|
228
|
+
const rows = mapClaudeConversations(
|
|
229
|
+
Array.isArray(result) ? (result as ClaudeConversation[]) : [],
|
|
230
|
+
limit,
|
|
231
|
+
);
|
|
232
|
+
if (!rows.length)
|
|
233
|
+
throw new Error("No Claude conversation history was visible on /recents.");
|
|
234
|
+
return rows;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
async function selectModel(
|
|
238
|
+
page: IPage,
|
|
239
|
+
modelName: unknown,
|
|
240
|
+
): Promise<{ ok?: boolean; upgrade?: boolean }> {
|
|
241
|
+
const key = str(modelName, "sonnet").toLowerCase();
|
|
242
|
+
const display = MODEL_DISPLAY_NAMES[key];
|
|
243
|
+
if (!display) return { ok: false };
|
|
244
|
+
const opened = (await page.evaluate(`(() => {
|
|
245
|
+
const trigger = document.querySelector(${js(MODEL_DROPDOWN_SELECTOR)});
|
|
246
|
+
if (!trigger) return { ok: false };
|
|
247
|
+
const label = trigger.getAttribute('aria-label') || '';
|
|
248
|
+
if (label.includes(${js(display)})) return { ok: true };
|
|
249
|
+
trigger.click();
|
|
250
|
+
return { ok: true, opened: true };
|
|
251
|
+
})()`)) as { ok?: boolean; opened?: boolean };
|
|
252
|
+
if (!opened?.ok || !opened.opened) return opened;
|
|
253
|
+
try {
|
|
254
|
+
await page.waitForSelector('div[role="menuitemradio"]', 3);
|
|
255
|
+
} catch {
|
|
256
|
+
await page.wait(0.3);
|
|
257
|
+
}
|
|
258
|
+
return (await page.evaluate(`(() => {
|
|
259
|
+
const items = Array.from(document.querySelectorAll('div[role="menuitemradio"]'));
|
|
260
|
+
const target = items.find((el) => (el.innerText || '').includes(${js(display)}));
|
|
261
|
+
if (!target) return { ok: false };
|
|
262
|
+
const upgrade = target.querySelector('button');
|
|
263
|
+
if (upgrade && (upgrade.innerText || '').toLowerCase().includes('upgrade')) {
|
|
264
|
+
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
|
265
|
+
return { ok: false, upgrade: true };
|
|
266
|
+
}
|
|
267
|
+
if (target.getAttribute('aria-checked') !== 'true') target.click();
|
|
268
|
+
else document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
|
269
|
+
return { ok: true };
|
|
270
|
+
})()`)) as { ok?: boolean; upgrade?: boolean };
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
async function setAdaptiveThinking(
|
|
274
|
+
page: IPage,
|
|
275
|
+
enabled: boolean,
|
|
276
|
+
): Promise<{ ok?: boolean }> {
|
|
277
|
+
const opened = (await page.evaluate(`(() => {
|
|
278
|
+
const trigger = document.querySelector(${js(MODEL_DROPDOWN_SELECTOR)});
|
|
279
|
+
if (!trigger) return { ok: false };
|
|
280
|
+
trigger.click();
|
|
281
|
+
return { ok: true };
|
|
282
|
+
})()`)) as { ok?: boolean };
|
|
283
|
+
if (!opened?.ok) return { ok: false };
|
|
284
|
+
try {
|
|
285
|
+
await page.waitForSelector('div[role="menuitem"]', 3);
|
|
286
|
+
} catch {
|
|
287
|
+
await page.wait(0.3);
|
|
288
|
+
}
|
|
289
|
+
return (await page.evaluate(`(() => {
|
|
290
|
+
const items = Array.from(document.querySelectorAll('div[role="menuitem"]'));
|
|
291
|
+
const target = items.find((el) => (el.innerText || '').includes('Adaptive thinking'));
|
|
292
|
+
if (!target) {
|
|
293
|
+
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
|
294
|
+
return { ok: false };
|
|
295
|
+
}
|
|
296
|
+
const isActive = target.getAttribute('aria-checked') === 'true';
|
|
297
|
+
if (${JSON.stringify(enabled)} !== isActive) target.click();
|
|
298
|
+
else document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
|
299
|
+
return { ok: true };
|
|
300
|
+
})()`)) as { ok?: boolean };
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
async function sendMessage(
|
|
304
|
+
page: IPage,
|
|
305
|
+
prompt: string,
|
|
306
|
+
): Promise<{ ok?: boolean; method?: string; reason?: string }> {
|
|
307
|
+
const composerReady = await page.evaluate(`(() => {
|
|
308
|
+
const box = document.querySelector(${js(COMPOSER_SELECTOR)});
|
|
309
|
+
if (!box) return false;
|
|
310
|
+
box.focus();
|
|
311
|
+
const selection = window.getSelection();
|
|
312
|
+
const range = document.createRange();
|
|
313
|
+
range.selectNodeContents(box);
|
|
314
|
+
selection?.removeAllRanges();
|
|
315
|
+
selection?.addRange(range);
|
|
316
|
+
document.execCommand('delete', false);
|
|
317
|
+
return true;
|
|
318
|
+
})()`);
|
|
319
|
+
if (!composerReady) return { ok: false, reason: "composer not found" };
|
|
320
|
+
await page.insertText(prompt);
|
|
321
|
+
await page.wait(1.2);
|
|
322
|
+
return (await page.evaluate(`(() => {
|
|
323
|
+
const ariaCandidates = [
|
|
324
|
+
'button[aria-label="Send Message"]',
|
|
325
|
+
'button[aria-label="Send message"]',
|
|
326
|
+
'button[aria-label="Send"]',
|
|
327
|
+
'button[aria-label*="Send"]',
|
|
328
|
+
];
|
|
329
|
+
for (const selector of ariaCandidates) {
|
|
330
|
+
const button = document.querySelector(selector);
|
|
331
|
+
if (button && !button.disabled) {
|
|
332
|
+
button.click();
|
|
333
|
+
return { ok: true, method: 'send-button' };
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
return { ok: false, reason: 'send button not found' };
|
|
337
|
+
})()`)) as { ok?: boolean; method?: string; reason?: string };
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
async function getBubbleCount(page: IPage): Promise<number> {
|
|
341
|
+
const count = await page.evaluate(
|
|
342
|
+
`document.querySelectorAll(${js(MESSAGE_SELECTOR)}).length`,
|
|
343
|
+
);
|
|
344
|
+
return Number(count) || 0;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
async function waitForResponse(
|
|
348
|
+
page: IPage,
|
|
349
|
+
baselineCount: number,
|
|
350
|
+
prompt: string,
|
|
351
|
+
timeoutMs: number,
|
|
352
|
+
): Promise<string | null> {
|
|
353
|
+
const startedAt = Date.now();
|
|
354
|
+
let lastText = "";
|
|
355
|
+
let stableCount = 0;
|
|
356
|
+
while (Date.now() - startedAt < timeoutMs) {
|
|
357
|
+
await page.wait(3);
|
|
358
|
+
const result = (await page.evaluate(`(() => {
|
|
359
|
+
const bubbles = document.querySelectorAll(${js(MESSAGE_SELECTOR)});
|
|
360
|
+
const texts = Array.from(bubbles).map((bubble) => {
|
|
361
|
+
let raw = (bubble.innerText || '').trim();
|
|
362
|
+
const parts = raw.split(/\\n\\n+/);
|
|
363
|
+
while (parts.length > 1 && /^(Thought|View)\\b/i.test(parts[0])) parts.shift();
|
|
364
|
+
return parts.join('\\n\\n').trim();
|
|
365
|
+
}).filter(Boolean);
|
|
366
|
+
return {
|
|
367
|
+
count: texts.length,
|
|
368
|
+
last: texts[texts.length - 1] || '',
|
|
369
|
+
streaming: Boolean(document.querySelector('[data-is-streaming="true"]')),
|
|
370
|
+
};
|
|
371
|
+
})()`)) as { count?: number; last?: string; streaming?: boolean };
|
|
372
|
+
const candidate = str(result?.last).trim();
|
|
373
|
+
if (
|
|
374
|
+
!candidate ||
|
|
375
|
+
candidate === prompt.trim() ||
|
|
376
|
+
Number(result?.count) <= baselineCount
|
|
377
|
+
)
|
|
378
|
+
continue;
|
|
379
|
+
if (result?.streaming) {
|
|
380
|
+
lastText = candidate;
|
|
381
|
+
stableCount = 0;
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
if (candidate === lastText) {
|
|
385
|
+
stableCount += 1;
|
|
386
|
+
if (stableCount >= 3) return candidate;
|
|
387
|
+
} else {
|
|
388
|
+
stableCount = 0;
|
|
389
|
+
lastText = candidate;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
return lastText || null;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function resolveUploadFile(value: unknown): string {
|
|
396
|
+
const file = resolve(str(value).trim());
|
|
397
|
+
if (!existsSync(file))
|
|
398
|
+
throw new Error(`Claude upload file not found: ${file}`);
|
|
399
|
+
const stats = statSync(file);
|
|
400
|
+
if (stats.size > 30 * 1024 * 1024) {
|
|
401
|
+
throw new Error(
|
|
402
|
+
`Claude upload file is too large (${(stats.size / 1024 / 1024).toFixed(1)} MB). Max: 30 MB.`,
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
return file;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
async function sendWithFile(
|
|
409
|
+
page: IPage,
|
|
410
|
+
fileValue: unknown,
|
|
411
|
+
prompt: string,
|
|
412
|
+
): Promise<{ ok?: boolean; method?: string; reason?: string }> {
|
|
413
|
+
const file = resolveUploadFile(fileValue);
|
|
414
|
+
await page.setFileInput(FILE_INPUT_SELECTOR, [file]);
|
|
415
|
+
const ready = await waitForFilePreview(page);
|
|
416
|
+
if (!ready) return { ok: false, reason: "file preview did not appear" };
|
|
417
|
+
return sendMessage(page, prompt);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
async function waitForFilePreview(page: IPage): Promise<boolean> {
|
|
421
|
+
for (let attempt = 0; attempt < 12; attempt += 1) {
|
|
422
|
+
await page.wait(1);
|
|
423
|
+
const ready = await page.evaluate(`(() => {
|
|
424
|
+
if (document.querySelector('[data-testid="file-thumbnail"]')) return true;
|
|
425
|
+
return Array.from(document.querySelectorAll('button')).some((button) => (button.getAttribute('aria-label') || '') === 'Remove');
|
|
426
|
+
})()`);
|
|
427
|
+
if (ready) return true;
|
|
428
|
+
}
|
|
429
|
+
return false;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
async function navigateNew(page: IPage): Promise<void> {
|
|
433
|
+
await page.goto(CLAUDE_NEW, { waitUntil: "load", settleMs: 2500 });
|
|
434
|
+
try {
|
|
435
|
+
await page.waitForSelector(COMPOSER_SELECTOR, 8);
|
|
436
|
+
} catch {
|
|
437
|
+
await page.wait(0.5);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
async function maybeResumeRecentConversation(page: IPage): Promise<void> {
|
|
442
|
+
const navigated = await ensureOnClaude(page);
|
|
443
|
+
if (!navigated) return;
|
|
444
|
+
await page.evaluate(`(() => {
|
|
445
|
+
const link = document.querySelector('a[href*="/chat/"]');
|
|
446
|
+
if (link instanceof HTMLElement) link.click();
|
|
447
|
+
})()`);
|
|
448
|
+
try {
|
|
449
|
+
await page.waitForSelector(MESSAGE_SELECTOR, 5);
|
|
450
|
+
} catch {
|
|
451
|
+
await page.wait(0.5);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
cli({
|
|
456
|
+
site: "claude",
|
|
457
|
+
name: "ask",
|
|
458
|
+
description: "Send a prompt to Claude and return the assistant response",
|
|
459
|
+
domain: "claude.ai",
|
|
460
|
+
strategy: Strategy.COOKIE,
|
|
461
|
+
browser: true,
|
|
462
|
+
args: [
|
|
463
|
+
{ name: "prompt", type: "str", required: true, positional: true },
|
|
464
|
+
{ name: "timeout", type: "int", default: 120 },
|
|
465
|
+
{ name: "new", type: "bool", default: false },
|
|
466
|
+
{
|
|
467
|
+
name: "model",
|
|
468
|
+
type: "str",
|
|
469
|
+
default: "sonnet",
|
|
470
|
+
choices: ["sonnet", "opus", "haiku"],
|
|
471
|
+
},
|
|
472
|
+
{ name: "think", type: "bool", default: false },
|
|
473
|
+
{ name: "file", type: "str" },
|
|
474
|
+
],
|
|
475
|
+
columns: ["response"],
|
|
476
|
+
func: async (page, kwargs) => {
|
|
477
|
+
const p = page as IPage;
|
|
478
|
+
const prompt = requireClaudePrompt(kwargs.prompt, "Claude ask");
|
|
479
|
+
const timeoutSeconds = requireClaudePositiveInt(
|
|
480
|
+
kwargs.timeout,
|
|
481
|
+
120,
|
|
482
|
+
"Claude ask timeout",
|
|
483
|
+
);
|
|
484
|
+
const wantThink = normalizeClaudeBoolean(kwargs.think);
|
|
485
|
+
if (normalizeClaudeBoolean(kwargs.new)) await navigateNew(p);
|
|
486
|
+
else await maybeResumeRecentConversation(p);
|
|
487
|
+
await ensureClaudeComposer(
|
|
488
|
+
p,
|
|
489
|
+
"Claude ask requires a visible composer in a logged-in Claude session.",
|
|
490
|
+
);
|
|
491
|
+
const current = await currentUrl(p);
|
|
492
|
+
const inConversation = current.includes("/chat/");
|
|
493
|
+
const model = str(kwargs.model, "sonnet").toLowerCase();
|
|
494
|
+
if (inConversation && kwargs.model && kwargs.model !== "sonnet") {
|
|
495
|
+
throw new Error(
|
|
496
|
+
`Cannot switch to ${model} model inside an existing Claude conversation. Start with --new.`,
|
|
497
|
+
);
|
|
498
|
+
}
|
|
499
|
+
if (!inConversation) {
|
|
500
|
+
const modelResult = await selectModel(p, model);
|
|
501
|
+
if (!modelResult?.ok) {
|
|
502
|
+
if (modelResult?.upgrade)
|
|
503
|
+
throw new Error(`${model} model requires a paid Claude plan.`);
|
|
504
|
+
throw new Error(`Could not switch to Claude ${model} model.`);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
const thinkResult = await setAdaptiveThinking(p, wantThink);
|
|
508
|
+
if (!thinkResult?.ok && wantThink)
|
|
509
|
+
throw new Error("Could not enable Claude Adaptive thinking.");
|
|
510
|
+
const baseline = await getBubbleCount(p);
|
|
511
|
+
const sendResult = kwargs.file
|
|
512
|
+
? await sendWithFile(p, kwargs.file, prompt)
|
|
513
|
+
: await sendMessage(p, prompt);
|
|
514
|
+
if (!sendResult?.ok)
|
|
515
|
+
throw new Error(sendResult?.reason || "Failed to send Claude message.");
|
|
516
|
+
const response = await waitForResponse(
|
|
517
|
+
p,
|
|
518
|
+
baseline,
|
|
519
|
+
prompt,
|
|
520
|
+
timeoutSeconds * 1000,
|
|
521
|
+
);
|
|
522
|
+
if (!response)
|
|
523
|
+
throw new Error(`No Claude response appeared within ${timeoutSeconds}s.`);
|
|
524
|
+
return [{ response }];
|
|
525
|
+
},
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
cli({
|
|
529
|
+
site: "claude",
|
|
530
|
+
name: "send",
|
|
531
|
+
description: "Send a prompt to Claude without waiting for a response",
|
|
532
|
+
domain: "claude.ai",
|
|
533
|
+
strategy: Strategy.COOKIE,
|
|
534
|
+
browser: true,
|
|
535
|
+
args: [
|
|
536
|
+
{ name: "prompt", type: "str", required: true, positional: true },
|
|
537
|
+
{ name: "new", type: "bool", default: false },
|
|
538
|
+
],
|
|
539
|
+
columns: ["Status", "SubmittedBy", "InjectedText"],
|
|
540
|
+
func: async (page, kwargs) => {
|
|
541
|
+
const p = page as IPage;
|
|
542
|
+
const prompt = requireClaudePrompt(kwargs.prompt, "Claude send");
|
|
543
|
+
if (normalizeClaudeBoolean(kwargs.new)) await navigateNew(p);
|
|
544
|
+
else await ensureOnClaude(p);
|
|
545
|
+
await ensureClaudeComposer(
|
|
546
|
+
p,
|
|
547
|
+
"Claude send requires a visible composer in a logged-in Claude session.",
|
|
548
|
+
);
|
|
549
|
+
const result = await sendMessage(p, prompt);
|
|
550
|
+
if (!result?.ok)
|
|
551
|
+
throw new Error(result?.reason || "Failed to send Claude message.");
|
|
552
|
+
return [
|
|
553
|
+
{
|
|
554
|
+
Status: "Success",
|
|
555
|
+
SubmittedBy: result.method || "send-button",
|
|
556
|
+
InjectedText: prompt,
|
|
557
|
+
},
|
|
558
|
+
];
|
|
559
|
+
},
|
|
560
|
+
});
|
|
561
|
+
|
|
562
|
+
cli({
|
|
563
|
+
site: "claude",
|
|
564
|
+
name: "new",
|
|
565
|
+
description: "Start a new conversation in Claude",
|
|
566
|
+
domain: "claude.ai",
|
|
567
|
+
strategy: Strategy.COOKIE,
|
|
568
|
+
browser: true,
|
|
569
|
+
columns: ["Status"],
|
|
570
|
+
func: async (page) => {
|
|
571
|
+
const p = page as IPage;
|
|
572
|
+
await navigateNew(p);
|
|
573
|
+
await ensureClaudeComposer(
|
|
574
|
+
p,
|
|
575
|
+
"Claude new requires a logged-in Claude session with a visible composer.",
|
|
576
|
+
);
|
|
577
|
+
return [{ Status: "New chat started" }];
|
|
578
|
+
},
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
cli({
|
|
582
|
+
site: "claude",
|
|
583
|
+
name: "status",
|
|
584
|
+
description: "Check Claude page availability and login state",
|
|
585
|
+
domain: "claude.ai",
|
|
586
|
+
strategy: Strategy.COOKIE,
|
|
587
|
+
browser: true,
|
|
588
|
+
columns: ["Status", "Login", "Url"],
|
|
589
|
+
func: async (page) => {
|
|
590
|
+
const p = page as IPage;
|
|
591
|
+
await ensureOnClaude(p);
|
|
592
|
+
const state = await getPageState(p);
|
|
593
|
+
return [
|
|
594
|
+
{
|
|
595
|
+
Status: state.hasComposer ? "Connected" : "Page not ready",
|
|
596
|
+
Login: state.isLoggedIn ? "Yes" : "No",
|
|
597
|
+
Url: str(state.url),
|
|
598
|
+
},
|
|
599
|
+
];
|
|
600
|
+
},
|
|
601
|
+
});
|
|
602
|
+
|
|
603
|
+
cli({
|
|
604
|
+
site: "claude",
|
|
605
|
+
name: "read",
|
|
606
|
+
description: "Read the current Claude conversation",
|
|
607
|
+
domain: "claude.ai",
|
|
608
|
+
strategy: Strategy.COOKIE,
|
|
609
|
+
browser: true,
|
|
610
|
+
columns: ["Index", "Role", "Text"],
|
|
611
|
+
func: async (page) => {
|
|
612
|
+
const p = page as IPage;
|
|
613
|
+
await ensureOnClaude(p);
|
|
614
|
+
await ensureClaudeLogin(
|
|
615
|
+
p,
|
|
616
|
+
"Claude read requires a logged-in Claude session.",
|
|
617
|
+
);
|
|
618
|
+
const rows = await readVisibleMessages(p);
|
|
619
|
+
if (!rows.length)
|
|
620
|
+
throw new Error(
|
|
621
|
+
"No visible Claude messages were found in the current conversation.",
|
|
622
|
+
);
|
|
623
|
+
return rows;
|
|
624
|
+
},
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
cli({
|
|
628
|
+
site: "claude",
|
|
629
|
+
name: "history",
|
|
630
|
+
description: "List conversation history from Claude /recents",
|
|
631
|
+
domain: "claude.ai",
|
|
632
|
+
strategy: Strategy.COOKIE,
|
|
633
|
+
browser: true,
|
|
634
|
+
args: [{ name: "limit", type: "int", default: 20 }],
|
|
635
|
+
columns: ["Index", "Id", "Title", "Url"],
|
|
636
|
+
func: async (page, kwargs) => {
|
|
637
|
+
const p = page as IPage;
|
|
638
|
+
const limit = requireClaudePositiveInt(
|
|
639
|
+
kwargs.limit,
|
|
640
|
+
20,
|
|
641
|
+
"Claude history limit",
|
|
642
|
+
);
|
|
643
|
+
const rows = await getConversationList(p, limit);
|
|
644
|
+
await ensureClaudeLogin(
|
|
645
|
+
p,
|
|
646
|
+
"Claude history requires a logged-in Claude session.",
|
|
647
|
+
);
|
|
648
|
+
return rows;
|
|
649
|
+
},
|
|
650
|
+
});
|
|
651
|
+
|
|
652
|
+
cli({
|
|
653
|
+
site: "claude",
|
|
654
|
+
name: "detail",
|
|
655
|
+
description: "Open a Claude conversation by ID and read its messages",
|
|
656
|
+
domain: "claude.ai",
|
|
657
|
+
strategy: Strategy.COOKIE,
|
|
658
|
+
browser: true,
|
|
659
|
+
args: [{ name: "id", type: "str", required: true, positional: true }],
|
|
660
|
+
columns: ["Index", "Role", "Text"],
|
|
661
|
+
func: async (page, kwargs) => {
|
|
662
|
+
const p = page as IPage;
|
|
663
|
+
const id = parseClaudeConversationId(kwargs.id);
|
|
664
|
+
await p.goto(`${CLAUDE_HOME}/chat/${id}`, {
|
|
665
|
+
waitUntil: "load",
|
|
666
|
+
settleMs: 2500,
|
|
667
|
+
});
|
|
668
|
+
try {
|
|
669
|
+
await p.waitForSelector(MESSAGE_SELECTOR, 10);
|
|
670
|
+
} catch {
|
|
671
|
+
await p.wait(0.5);
|
|
672
|
+
}
|
|
673
|
+
await ensureClaudeLogin(
|
|
674
|
+
p,
|
|
675
|
+
"Claude detail requires a logged-in Claude session.",
|
|
676
|
+
);
|
|
677
|
+
const rows = await readVisibleMessages(p);
|
|
678
|
+
if (!rows.length)
|
|
679
|
+
throw new Error(
|
|
680
|
+
`No visible Claude messages were found for conversation ${id}.`,
|
|
681
|
+
);
|
|
682
|
+
return rows;
|
|
683
|
+
},
|
|
684
|
+
});
|