publishport-opencli 1.0.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/LICENSE +214 -0
- package/README.md +299 -0
- package/README.zh-CN.md +341 -0
- package/cli-manifest.json +51513 -0
- package/clis/12306/auth.js +25 -0
- package/clis/12306/me.js +9 -0
- package/clis/12306/orders.js +13 -0
- package/clis/12306/passengers.js +14 -0
- package/clis/12306/price.js +1 -0
- package/clis/12306/stations.js +1 -0
- package/clis/12306/train.js +1 -0
- package/clis/12306/trains.js +1 -0
- package/clis/12306/utils.js +1 -0
- package/clis/1688/assets.js +127 -0
- package/clis/1688/auth.js +1 -0
- package/clis/1688/download.js +1 -0
- package/clis/1688/item.js +21 -0
- package/clis/1688/search.js +129 -0
- package/clis/1688/shared.js +11 -0
- package/clis/1688/store.js +26 -0
- package/clis/1point3acres/auth.js +18 -0
- package/clis/1point3acres/digest.js +1 -0
- package/clis/1point3acres/forum.js +1 -0
- package/clis/1point3acres/forums.js +1 -0
- package/clis/1point3acres/hot.js +1 -0
- package/clis/1point3acres/latest.js +1 -0
- package/clis/1point3acres/notifications.js +1 -0
- package/clis/1point3acres/search.js +1 -0
- package/clis/1point3acres/thread.js +2 -0
- package/clis/1point3acres/user.js +1 -0
- package/clis/1point3acres/utils.js +6 -0
- package/clis/36kr/article.js +20 -0
- package/clis/36kr/hot.js +16 -0
- package/clis/36kr/news.js +1 -0
- package/clis/36kr/search.js +36 -0
- package/clis/51job/company.js +36 -0
- package/clis/51job/detail.js +35 -0
- package/clis/51job/hot.js +1 -0
- package/clis/51job/search.js +1 -0
- package/clis/51job/utils.js +21 -0
- package/clis/_atlassian/shared.js +21 -0
- package/clis/_shared/article/auth.js +16 -0
- package/clis/_shared/article/douban-md2draft.js +4 -0
- package/clis/_shared/article/format.js +1 -0
- package/clis/_shared/article/images.js +95 -0
- package/clis/_shared/article/login.js +1 -0
- package/clis/_shared/article/page-runtime.js +745 -0
- package/clis/_shared/article/publish.js +34 -0
- package/clis/_shared/common.js +1 -0
- package/clis/_shared/content-guard.js +1 -0
- package/clis/_shared/desktop-commands.js +1 -0
- package/clis/_shared/search-adapter.js +1 -0
- package/clis/_shared/site-auth.js +1 -0
- package/clis/_shared/token-auth.js +2 -0
- package/clis/_shared/video-publish.js +62 -0
- package/clis/aibase/news.js +31 -0
- package/clis/amazon/auth.js +19 -0
- package/clis/amazon/bestsellers.js +1 -0
- package/clis/amazon/discussion.js +20 -0
- package/clis/amazon/movers-shakers.js +1 -0
- package/clis/amazon/new-releases.js +1 -0
- package/clis/amazon/offer.js +29 -0
- package/clis/amazon/product.js +25 -0
- package/clis/amazon/rankings.js +68 -0
- package/clis/amazon/search.js +16 -0
- package/clis/amazon/shared.js +11 -0
- package/clis/antigravity/SKILL.md +38 -0
- package/clis/antigravity/_actions.js +201 -0
- package/clis/antigravity/audit-extras.js +78 -0
- package/clis/antigravity/delete.js +1 -0
- package/clis/antigravity/dump.js +1 -0
- package/clis/antigravity/extract-code.js +18 -0
- package/clis/antigravity/history.js +1 -0
- package/clis/antigravity/mark-read.js +1 -0
- package/clis/antigravity/model.js +90 -0
- package/clis/antigravity/new.js +9 -0
- package/clis/antigravity/read.js +10 -0
- package/clis/antigravity/rename.js +1 -0
- package/clis/antigravity/send.js +11 -0
- package/clis/antigravity/serve.js +97 -0
- package/clis/antigravity/status.js +1 -0
- package/clis/antigravity/storage.js +12 -0
- package/clis/antigravity/watch.js +6 -0
- package/clis/apple-podcasts/episodes.js +1 -0
- package/clis/apple-podcasts/search.js +1 -0
- package/clis/apple-podcasts/top.js +1 -0
- package/clis/apple-podcasts/utils.js +1 -0
- package/clis/archive/item.js +1 -0
- package/clis/archive/search.js +1 -0
- package/clis/archive/snapshots.js +1 -0
- package/clis/archive/wayback.js +1 -0
- package/clis/arxiv/author.js +1 -0
- package/clis/arxiv/paper.js +1 -0
- package/clis/arxiv/recent.js +1 -0
- package/clis/arxiv/search.js +1 -0
- package/clis/arxiv/utils.js +1 -0
- package/clis/autohome/__fixtures__/catalog.html +11 -0
- package/clis/autohome/__fixtures__/koubei.json +116 -0
- package/clis/autohome/brand.js +1 -0
- package/clis/autohome/score.js +1 -0
- package/clis/autohome/utils.js +1 -0
- package/clis/baidu-scholar/search.js +63 -0
- package/clis/baijiahao/article.js +1 -0
- package/clis/baijiahao/lists.js +1 -0
- package/clis/baijiahao/login.js +1 -0
- package/clis/baijiahao/publish.js +57 -0
- package/clis/baijiahao/stats.js +1 -0
- package/clis/baijiahao/whoami.js +1 -0
- package/clis/band/auth.js +29 -0
- package/clis/band/bands.js +37 -0
- package/clis/band/mentions.js +6 -0
- package/clis/band/post.js +76 -0
- package/clis/band/posts.js +50 -0
- package/clis/barchart/flow.js +70 -0
- package/clis/barchart/greeks.js +88 -0
- package/clis/barchart/options.js +61 -0
- package/clis/barchart/quote.js +87 -0
- package/clis/bbc/news.js +1 -0
- package/clis/bbc/topic.js +1 -0
- package/clis/bbc/utils.js +1 -0
- package/clis/bilibili/article.js +1 -0
- package/clis/bilibili/auth.js +1 -0
- package/clis/bilibili/categories.js +1 -0
- package/clis/bilibili/coin.js +1 -0
- package/clis/bilibili/comment-del.js +1 -0
- package/clis/bilibili/comment-like.js +1 -0
- package/clis/bilibili/comment.js +1 -0
- package/clis/bilibili/comments.js +1 -0
- package/clis/bilibili/dm-list.js +1 -0
- package/clis/bilibili/dm-read.js +1 -0
- package/clis/bilibili/dm-send.js +1 -0
- package/clis/bilibili/download.js +7 -0
- package/clis/bilibili/drafts.js +1 -0
- package/clis/bilibili/dynamic-post.js +24 -0
- package/clis/bilibili/dynamic.js +1 -0
- package/clis/bilibili/favorite-add.js +1 -0
- package/clis/bilibili/favorite.js +1 -0
- package/clis/bilibili/feed.js +2 -0
- package/clis/bilibili/follow.js +1 -0
- package/clis/bilibili/following.js +1 -0
- package/clis/bilibili/history.js +1 -0
- package/clis/bilibili/hot.js +15 -0
- package/clis/bilibili/like.js +1 -0
- package/clis/bilibili/me.js +1 -0
- package/clis/bilibili/partitions.js +1 -0
- package/clis/bilibili/ranking.js +1 -0
- package/clis/bilibili/search.js +1 -0
- package/clis/bilibili/stats.js +1 -0
- package/clis/bilibili/subtitle.js +21 -0
- package/clis/bilibili/summary.js +1 -0
- package/clis/bilibili/topics.js +1 -0
- package/clis/bilibili/unfollow.js +1 -0
- package/clis/bilibili/upload.js +1 -0
- package/clis/bilibili/user-videos.js +1 -0
- package/clis/bilibili/utils.js +50 -0
- package/clis/bilibili/video-drafts.js +1 -0
- package/clis/bilibili/video.js +1 -0
- package/clis/binance/asks.js +1 -0
- package/clis/binance/depth.js +1 -0
- package/clis/binance/gainers.js +1 -0
- package/clis/binance/klines.js +1 -0
- package/clis/binance/losers.js +1 -0
- package/clis/binance/pairs.js +1 -0
- package/clis/binance/price.js +1 -0
- package/clis/binance/prices.js +1 -0
- package/clis/binance/ticker.js +1 -0
- package/clis/binance/top.js +1 -0
- package/clis/binance/trades.js +1 -0
- package/clis/bloomberg/businessweek.js +12 -0
- package/clis/bloomberg/crypto.js +1 -0
- package/clis/bloomberg/economics.js +1 -0
- package/clis/bloomberg/feeds.js +1 -0
- package/clis/bloomberg/green.js +1 -0
- package/clis/bloomberg/industries.js +1 -0
- package/clis/bloomberg/main.js +1 -0
- package/clis/bloomberg/markets.js +1 -0
- package/clis/bloomberg/news.js +57 -0
- package/clis/bloomberg/opinions.js +1 -0
- package/clis/bloomberg/politics.js +1 -0
- package/clis/bloomberg/pursuits.js +1 -0
- package/clis/bloomberg/tech.js +1 -0
- package/clis/bloomberg/utils.js +17 -0
- package/clis/bluesky/post.js +1 -0
- package/clis/bluesky/shared.js +56 -0
- package/clis/bluesky/whoami.js +1 -0
- package/clis/booking/search.js +93 -0
- package/clis/boss/auth.js +13 -0
- package/clis/boss/batchgreet.js +1 -0
- package/clis/boss/chatlist.js +1 -0
- package/clis/boss/chatmsg.js +1 -0
- package/clis/boss/detail.js +1 -0
- package/clis/boss/exchange.js +1 -0
- package/clis/boss/greet.js +1 -0
- package/clis/boss/invite.js +4 -0
- package/clis/boss/joblist.js +1 -0
- package/clis/boss/mark.js +1 -0
- package/clis/boss/recommend.js +1 -0
- package/clis/boss/resume.js +90 -0
- package/clis/boss/search.js +1 -0
- package/clis/boss/send.js +1 -0
- package/clis/boss/stats.js +1 -0
- package/clis/boss/utils.js +161 -0
- package/clis/brave/search.js +23 -0
- package/clis/chaoxing/assignments.js +1 -0
- package/clis/chaoxing/auth.js +21 -0
- package/clis/chaoxing/exams.js +1 -0
- package/clis/chaoxing/utils.js +58 -0
- package/clis/chatgpt/ask.js +1 -0
- package/clis/chatgpt/auth.js +17 -0
- package/clis/chatgpt/detail.js +1 -0
- package/clis/chatgpt/history.js +1 -0
- package/clis/chatgpt/image.js +1 -0
- package/clis/chatgpt/model.js +1 -0
- package/clis/chatgpt/new.js +1 -0
- package/clis/chatgpt/project-file-add.js +1 -0
- package/clis/chatgpt/project-list.js +1 -0
- package/clis/chatgpt/read.js +1 -0
- package/clis/chatgpt/send.js +1 -0
- package/clis/chatgpt/status.js +1 -0
- package/clis/chatgpt/utils.js +1092 -0
- package/clis/chatgpt-app/ask.js +1 -0
- package/clis/chatgpt-app/ax.js +512 -0
- package/clis/chatgpt-app/model.js +1 -0
- package/clis/chatgpt-app/new.js +1 -0
- package/clis/chatgpt-app/read.js +1 -0
- package/clis/chatgpt-app/send.js +1 -0
- package/clis/chatgpt-app/status.js +1 -0
- package/clis/chatwise/ask.js +1 -0
- package/clis/chatwise/export.js +21 -0
- package/clis/chatwise/history.js +26 -0
- package/clis/chatwise/model.js +48 -0
- package/clis/chatwise/new.js +1 -0
- package/clis/chatwise/read.js +25 -0
- package/clis/chatwise/screenshot.js +1 -0
- package/clis/chatwise/send.js +1 -0
- package/clis/chatwise/status.js +1 -0
- package/clis/chatwise/utils.js +75 -0
- package/clis/chess/analyze.js +1 -0
- package/clis/chess/game.js +1 -0
- package/clis/chess/games.js +1 -0
- package/clis/chess/stats.js +1 -0
- package/clis/chess/utils.js +1 -0
- package/clis/claude/ask.js +4 -0
- package/clis/claude/auth.js +19 -0
- package/clis/claude/detail.js +1 -0
- package/clis/claude/history.js +1 -0
- package/clis/claude/new.js +1 -0
- package/clis/claude/read.js +1 -0
- package/clis/claude/send.js +1 -0
- package/clis/claude/status.js +1 -0
- package/clis/claude/utils.js +179 -0
- package/clis/cnblogs/article.js +1 -0
- package/clis/cnblogs/login.js +1 -0
- package/clis/cnblogs/stats.js +37 -0
- package/clis/cnblogs/whoami.js +1 -0
- package/clis/cnki/search.js +38 -0
- package/clis/codex/_actions.js +72 -0
- package/clis/codex/archive.js +1 -0
- package/clis/codex/ask.js +23 -0
- package/clis/codex/dump.js +1 -0
- package/clis/codex/export.js +12 -0
- package/clis/codex/extract-diff.js +28 -0
- package/clis/codex/history.js +1 -0
- package/clis/codex/model.js +118 -0
- package/clis/codex/new.js +1 -0
- package/clis/codex/pin.js +1 -0
- package/clis/codex/projects.js +1 -0
- package/clis/codex/read.js +16 -0
- package/clis/codex/rename.js +34 -0
- package/clis/codex/screenshot.js +1 -0
- package/clis/codex/send.js +16 -0
- package/clis/codex/sidebar.js +1 -0
- package/clis/codex/status.js +1 -0
- package/clis/coingecko/categories.js +1 -0
- package/clis/coingecko/coin.js +1 -0
- package/clis/coingecko/derivatives.js +1 -0
- package/clis/coingecko/exchanges.js +1 -0
- package/clis/coingecko/global.js +1 -0
- package/clis/coingecko/top.js +1 -0
- package/clis/coingecko/trending.js +1 -0
- package/clis/confluence/create.js +1 -0
- package/clis/confluence/page.js +1 -0
- package/clis/confluence/search.js +1 -0
- package/clis/confluence/shared.js +1 -0
- package/clis/confluence/update.js +1 -0
- package/clis/coupang/add-to-cart.js +86 -0
- package/clis/coupang/auth.js +16 -0
- package/clis/coupang/product.js +161 -0
- package/clis/coupang/search.js +385 -0
- package/clis/coupang/utils.js +1 -0
- package/clis/crates/crate.js +1 -0
- package/clis/crates/search.js +1 -0
- package/clis/crates/utils.js +1 -0
- package/clis/csdn/article.js +29 -0
- package/clis/csdn/columns.js +1 -0
- package/clis/csdn/login.js +1 -0
- package/clis/csdn/stats.js +71 -0
- package/clis/csdn/whoami.js +1 -0
- package/clis/cto51/article.js +1 -0
- package/clis/cto51/whoami.js +1 -0
- package/clis/ctrip/auth.js +1 -0
- package/clis/ctrip/flight.js +17 -0
- package/clis/ctrip/hotel-search.js +24 -0
- package/clis/ctrip/hotel-suggest.js +1 -0
- package/clis/ctrip/search.js +1 -0
- package/clis/ctrip/utils.js +119 -0
- package/clis/cursor/ask.js +22 -0
- package/clis/cursor/composer.js +12 -0
- package/clis/cursor/dump.js +1 -0
- package/clis/cursor/export.js +23 -0
- package/clis/cursor/extract-code.js +18 -0
- package/clis/cursor/history.js +26 -0
- package/clis/cursor/model.js +18 -0
- package/clis/cursor/new.js +1 -0
- package/clis/cursor/read.js +27 -0
- package/clis/cursor/screenshot.js +1 -0
- package/clis/cursor/send.js +12 -0
- package/clis/cursor/status.js +1 -0
- package/clis/dblp/author.js +1 -0
- package/clis/dblp/paper.js +1 -0
- package/clis/dblp/search.js +1 -0
- package/clis/dblp/utils.js +1 -0
- package/clis/dblp/venue.js +1 -0
- package/clis/deepseek/ask.js +1 -0
- package/clis/deepseek/auth.js +22 -0
- package/clis/deepseek/detail.js +1 -0
- package/clis/deepseek/history.js +1 -0
- package/clis/deepseek/new.js +1 -0
- package/clis/deepseek/read.js +1 -0
- package/clis/deepseek/send.js +50 -0
- package/clis/deepseek/status.js +1 -0
- package/clis/deepseek/utils.js +202 -0
- package/clis/defillama/protocol.js +1 -0
- package/clis/defillama/protocols.js +1 -0
- package/clis/defillama/utils.js +1 -0
- package/clis/devto/auth.js +9 -0
- package/clis/devto/latest.js +1 -0
- package/clis/devto/publish.js +17 -0
- package/clis/devto/read.js +3 -0
- package/clis/devto/stats.js +27 -0
- package/clis/devto/tag.js +1 -0
- package/clis/devto/top.js +1 -0
- package/clis/devto/user.js +1 -0
- package/clis/dianping/__fixtures__/search.html +168 -0
- package/clis/dianping/__fixtures__/shop.html +6 -0
- package/clis/dianping/auth.js +10 -0
- package/clis/dianping/cityResolver.js +4 -0
- package/clis/dianping/search.js +1 -0
- package/clis/dianping/shop.js +1 -0
- package/clis/dianping/utils.js +1 -0
- package/clis/dictionary/examples.js +1 -0
- package/clis/dictionary/search.js +1 -0
- package/clis/dictionary/synonyms.js +1 -0
- package/clis/discord-app/channels.js +1 -0
- package/clis/discord-app/delete.js +66 -0
- package/clis/discord-app/goto.js +1 -0
- package/clis/discord-app/members.js +21 -0
- package/clis/discord-app/read.js +1 -0
- package/clis/discord-app/search.js +29 -0
- package/clis/discord-app/send.js +10 -0
- package/clis/discord-app/servers.js +1 -0
- package/clis/discord-app/status.js +1 -0
- package/clis/discord-app/thread-read.js +1 -0
- package/clis/discord-app/threads.js +1 -0
- package/clis/discord-app/utils.js +226 -0
- package/clis/discord-web/auth.js +10 -0
- package/clis/discord-web/send.js +13 -0
- package/clis/dockerhub/image.js +1 -0
- package/clis/dockerhub/search.js +1 -0
- package/clis/dockerhub/utils.js +1 -0
- package/clis/dongchedi/__fixtures__/search.json +60 -0
- package/clis/dongchedi/__fixtures__/series-detail.json +911 -0
- package/clis/dongchedi/__fixtures__/series-score.json +1396 -0
- package/clis/dongchedi/koubei.js +1 -0
- package/clis/dongchedi/models.js +1 -0
- package/clis/dongchedi/score.js +1 -0
- package/clis/dongchedi/search.js +1 -0
- package/clis/dongchedi/series.js +1 -0
- package/clis/dongchedi/specs.js +1 -0
- package/clis/dongchedi/utils.js +1 -0
- package/clis/douban/article.js +53 -0
- package/clis/douban/auth.js +21 -0
- package/clis/douban/book-hot.js +1 -0
- package/clis/douban/download.js +1 -0
- package/clis/douban/marks.js +59 -0
- package/clis/douban/movie-hot.js +1 -0
- package/clis/douban/photos.js +1 -0
- package/clis/douban/reviews.js +53 -0
- package/clis/douban/search.js +1 -0
- package/clis/douban/subject.js +1 -0
- package/clis/douban/top250.js +50 -0
- package/clis/douban/utils.js +344 -0
- package/clis/doubao/ask.js +1 -0
- package/clis/doubao/auth.js +28 -0
- package/clis/doubao/detail.js +1 -0
- package/clis/doubao/history.js +1 -0
- package/clis/doubao/meeting-summary.js +1 -0
- package/clis/doubao/meeting-transcript.js +1 -0
- package/clis/doubao/new.js +1 -0
- package/clis/doubao/read.js +1 -0
- package/clis/doubao/send.js +1 -0
- package/clis/doubao/status.js +1 -0
- package/clis/doubao/utils.js +704 -0
- package/clis/doubao-app/ask.js +1 -0
- package/clis/doubao-app/dump.js +1 -0
- package/clis/doubao-app/new.js +1 -0
- package/clis/doubao-app/read.js +1 -0
- package/clis/doubao-app/screenshot.js +1 -0
- package/clis/doubao-app/send.js +1 -0
- package/clis/doubao-app/status.js +1 -0
- package/clis/doubao-app/utils.js +64 -0
- package/clis/douyin/_shared/browser-fetch.js +28 -0
- package/clis/douyin/_shared/creation-id.js +1 -0
- package/clis/douyin/_shared/evaluate-result.js +1 -0
- package/clis/douyin/_shared/imagex-upload.js +1 -0
- package/clis/douyin/_shared/public-api.js +1 -0
- package/clis/douyin/_shared/sts2.js +1 -0
- package/clis/douyin/_shared/text-extra.js +1 -0
- package/clis/douyin/_shared/timing.js +1 -0
- package/clis/douyin/_shared/tos-upload.js +5 -0
- package/clis/douyin/_shared/transcode.js +1 -0
- package/clis/douyin/_shared/types.js +1 -0
- package/clis/douyin/_shared/vod-upload.js +5 -0
- package/clis/douyin/activities.js +1 -0
- package/clis/douyin/auth.js +1 -0
- package/clis/douyin/collections.js +1 -0
- package/clis/douyin/delete.js +76 -0
- package/clis/douyin/draft.js +166 -0
- package/clis/douyin/drafts.js +1 -0
- package/clis/douyin/hashtag.js +1 -0
- package/clis/douyin/location.js +1 -0
- package/clis/douyin/profile.js +1 -0
- package/clis/douyin/publish-image.js +64 -0
- package/clis/douyin/publish.js +14 -0
- package/clis/douyin/search.js +51 -0
- package/clis/douyin/stats.js +1 -0
- package/clis/douyin/update.js +1 -0
- package/clis/douyin/user-videos.js +1 -0
- package/clis/douyin/videos.js +1 -0
- package/clis/duckduckgo/search.js +1 -0
- package/clis/duckduckgo/suggest.js +1 -0
- package/clis/eastmoney/_secid.js +1 -0
- package/clis/eastmoney/announcement.js +1 -0
- package/clis/eastmoney/article.js +1 -0
- package/clis/eastmoney/convertible.js +1 -0
- package/clis/eastmoney/etf.js +1 -0
- package/clis/eastmoney/holders.js +1 -0
- package/clis/eastmoney/hot-rank.js +30 -0
- package/clis/eastmoney/index-board.js +1 -0
- package/clis/eastmoney/kline.js +1 -0
- package/clis/eastmoney/kuaixun.js +1 -0
- package/clis/eastmoney/longhu.js +1 -0
- package/clis/eastmoney/money-flow.js +1 -0
- package/clis/eastmoney/northbound.js +1 -0
- package/clis/eastmoney/quote.js +1 -0
- package/clis/eastmoney/rank.js +1 -0
- package/clis/eastmoney/sectors.js +1 -0
- package/clis/eastmoney/whoami.js +1 -0
- package/clis/endoflife/product.js +1 -0
- package/clis/endoflife/utils.js +1 -0
- package/clis/facebook/__fixtures__/notifications-page.html +13 -0
- package/clis/facebook/add-friend.js +24 -0
- package/clis/facebook/auth.js +1 -0
- package/clis/facebook/comment.js +18 -0
- package/clis/facebook/events.js +26 -0
- package/clis/facebook/feed.js +209 -0
- package/clis/facebook/friends.js +24 -0
- package/clis/facebook/groups.js +32 -0
- package/clis/facebook/join-group.js +25 -0
- package/clis/facebook/like.js +29 -0
- package/clis/facebook/marketplace-inbox.js +34 -0
- package/clis/facebook/marketplace-listings.js +33 -0
- package/clis/facebook/memories.js +21 -0
- package/clis/facebook/notifications.js +31 -0
- package/clis/facebook/post.js +88 -0
- package/clis/facebook/profile.js +18 -0
- package/clis/facebook/search.js +22 -0
- package/clis/flathub/app.js +1 -0
- package/clis/flathub/search.js +1 -0
- package/clis/flathub/utils.js +1 -0
- package/clis/flomo/auth.js +22 -0
- package/clis/flomo/memos.js +13 -0
- package/clis/gemini/ask.js +1 -0
- package/clis/gemini/auth.js +14 -0
- package/clis/gemini/deep-research-result.js +4 -0
- package/clis/gemini/deep-research.js +1 -0
- package/clis/gemini/detail.js +1 -0
- package/clis/gemini/history.js +1 -0
- package/clis/gemini/image.js +3 -0
- package/clis/gemini/new.js +1 -0
- package/clis/gemini/read.js +1 -0
- package/clis/gemini/status.js +1 -0
- package/clis/gemini/utils.js +1234 -0
- package/clis/geogebra/add-circle.js +1 -0
- package/clis/geogebra/add-line.js +1 -0
- package/clis/geogebra/add-point.js +1 -0
- package/clis/geogebra/add-polygon.js +1 -0
- package/clis/geogebra/eval.js +1 -0
- package/clis/geogebra/hexagon.js +1 -0
- package/clis/geogebra/info.js +13 -0
- package/clis/geogebra/list.js +1 -0
- package/clis/geogebra/triangle.js +1 -0
- package/clis/geogebra/utils.js +99 -0
- package/clis/ghost/publish.js +1 -0
- package/clis/ghost/shared.js +1 -0
- package/clis/ghost/whoami.js +1 -0
- package/clis/gitee/auth.js +12 -0
- package/clis/gitee/index.js +1 -0
- package/clis/gitee/search.js +1 -0
- package/clis/gitee/trending.js +240 -0
- package/clis/gitee/user.js +71 -0
- package/clis/github/auth.js +7 -0
- package/clis/github-trending/repos.js +1 -0
- package/clis/google/news.js +1 -0
- package/clis/google/search.js +90 -0
- package/clis/google/suggest.js +1 -0
- package/clis/google/trends.js +1 -0
- package/clis/google/utils.js +1 -0
- package/clis/google-scholar/cite.js +20 -0
- package/clis/google-scholar/profile.js +36 -0
- package/clis/google-scholar/search.js +35 -0
- package/clis/goproxy/module.js +1 -0
- package/clis/goproxy/utils.js +1 -0
- package/clis/goproxy/versions.js +1 -0
- package/clis/gov-law/recent.js +1 -0
- package/clis/gov-law/search.js +14 -0
- package/clis/gov-law/shared.js +29 -0
- package/clis/gov-policy/__fixtures__/recent.html +16 -0
- package/clis/gov-policy/__fixtures__/search.html +41 -0
- package/clis/gov-policy/recent.js +8 -0
- package/clis/gov-policy/search.js +8 -0
- package/clis/gov-policy/utils.js +1 -0
- package/clis/grok/ask.js +1 -0
- package/clis/grok/auth.js +17 -0
- package/clis/grok/delete.js +1 -0
- package/clis/grok/detail.js +1 -0
- package/clis/grok/export-all.js +170 -0
- package/clis/grok/export-utils.js +1 -0
- package/clis/grok/export.js +106 -0
- package/clis/grok/history.js +1 -0
- package/clis/grok/image.js +119 -0
- package/clis/grok/image.test.ts +127 -0
- package/clis/grok/new.js +1 -0
- package/clis/grok/pin.js +1 -0
- package/clis/grok/read.js +1 -0
- package/clis/grok/send.js +1 -0
- package/clis/grok/status.js +1 -0
- package/clis/grok/utils.js +337 -0
- package/clis/guazi/__fixtures__/detail.html +7 -0
- package/clis/guazi/__fixtures__/list.html +5 -0
- package/clis/guazi/browse.js +1 -0
- package/clis/guazi/car.js +1 -0
- package/clis/guazi/utils.js +1 -0
- package/clis/hackernews/ask.js +1 -0
- package/clis/hackernews/auth.js +9 -0
- package/clis/hackernews/best.js +1 -0
- package/clis/hackernews/comment.js +61 -0
- package/clis/hackernews/jobs.js +1 -0
- package/clis/hackernews/new.js +1 -0
- package/clis/hackernews/read.js +11 -0
- package/clis/hackernews/search.js +1 -0
- package/clis/hackernews/show.js +1 -0
- package/clis/hackernews/submit.js +65 -0
- package/clis/hackernews/top.js +1 -0
- package/clis/hackernews/user.js +1 -0
- package/clis/hashnode/auth.js +11 -0
- package/clis/hashnode/publish.js +92 -0
- package/clis/hf/auth.js +12 -0
- package/clis/hf/datasets.js +1 -0
- package/clis/hf/models.js +1 -0
- package/clis/hf/paper.js +1 -0
- package/clis/hf/spaces.js +1 -0
- package/clis/hf/top.js +1 -0
- package/clis/homebrew/cask.js +1 -0
- package/clis/homebrew/formula.js +1 -0
- package/clis/homebrew/popular.js +1 -0
- package/clis/homebrew/utils.js +1 -0
- package/clis/huodongxing/events.js +1 -0
- package/clis/hupu/__fixtures__/hot-home.html +64 -0
- package/clis/hupu/auth.js +14 -0
- package/clis/hupu/detail.js +7 -0
- package/clis/hupu/hot.js +14 -0
- package/clis/hupu/like.js +1 -0
- package/clis/hupu/mentions.js +91 -0
- package/clis/hupu/reply.js +1 -0
- package/clis/hupu/search.js +1 -0
- package/clis/hupu/unlike.js +1 -0
- package/clis/hupu/utils.js +243 -0
- package/clis/imdb/person.js +140 -0
- package/clis/imdb/reviews.js +40 -0
- package/clis/imdb/search.js +113 -0
- package/clis/imdb/title.js +1 -0
- package/clis/imdb/top.js +1 -0
- package/clis/imdb/trending.js +1 -0
- package/clis/imdb/utils.js +162 -0
- package/clis/imooc/article.js +59 -0
- package/clis/imooc/login.js +1 -0
- package/clis/imooc/whoami.js +1 -0
- package/clis/indeed/job.js +20 -0
- package/clis/indeed/search.js +37 -0
- package/clis/indeed/utils.js +1 -0
- package/clis/infoq/article.js +19 -0
- package/clis/infoq/login.js +1 -0
- package/clis/infoq/whoami.js +1 -0
- package/clis/instagram/_shared/private-publish.js +75 -0
- package/clis/instagram/_shared/protocol-capture.js +180 -0
- package/clis/instagram/_shared/runtime-info.js +33 -0
- package/clis/instagram/auth.js +22 -0
- package/clis/instagram/collection-create.js +38 -0
- package/clis/instagram/collection-delete.js +72 -0
- package/clis/instagram/comment.js +26 -0
- package/clis/instagram/detail.js +2 -0
- package/clis/instagram/download.js +83 -0
- package/clis/instagram/explore.js +27 -0
- package/clis/instagram/follow.js +24 -0
- package/clis/instagram/followers.js +30 -0
- package/clis/instagram/following.js +74 -0
- package/clis/instagram/like.js +25 -0
- package/clis/instagram/note.js +162 -0
- package/clis/instagram/post.js +718 -0
- package/clis/instagram/profile.js +25 -0
- package/clis/instagram/reel.js +452 -0
- package/clis/instagram/save.js +25 -0
- package/clis/instagram/saved.js +37 -0
- package/clis/instagram/search.js +23 -0
- package/clis/instagram/story.js +21 -0
- package/clis/instagram/unfollow.js +21 -0
- package/clis/instagram/unlike.js +25 -0
- package/clis/instagram/unsave.js +25 -0
- package/clis/instagram/user.js +1 -0
- package/clis/jd/add-cart.js +22 -0
- package/clis/jd/auth.js +12 -0
- package/clis/jd/cart.js +59 -0
- package/clis/jd/detail.js +42 -0
- package/clis/jd/item.js +98 -0
- package/clis/jd/item.test.ts +517 -0
- package/clis/jd/reviews.js +31 -0
- package/clis/jd/search.js +42 -0
- package/clis/jianshu/article.js +1 -0
- package/clis/jianshu/login.js +1 -0
- package/clis/jianshu/notebooks.js +1 -0
- package/clis/jianshu/whoami.js +1 -0
- package/clis/jianyu/auth.js +28 -0
- package/clis/jianyu/detail.js +1 -0
- package/clis/jianyu/search.js +73 -0
- package/clis/jianyu/shared/china-bid-search.js +86 -0
- package/clis/jianyu/shared/procurement-contract.js +1 -0
- package/clis/jianyu/shared/procurement-detail.js +18 -0
- package/clis/jike/auth.js +19 -0
- package/clis/jike/comment.js +82 -0
- package/clis/jike/create.js +83 -0
- package/clis/jike/feed.js +32 -0
- package/clis/jike/like.js +38 -0
- package/clis/jike/notifications.js +115 -0
- package/clis/jike/post.js +33 -0
- package/clis/jike/repost.js +67 -0
- package/clis/jike/search.js +29 -0
- package/clis/jike/topic.js +20 -0
- package/clis/jike/user.js +19 -0
- package/clis/jike/utils.js +15 -0
- package/clis/jimeng/auth.js +13 -0
- package/clis/jimeng/generate.js +60 -0
- package/clis/jimeng/history.js +32 -0
- package/clis/jimeng/new.js +26 -0
- package/clis/jimeng/workspaces.js +22 -0
- package/clis/jira/attachments.js +1 -0
- package/clis/jira/comments.js +1 -0
- package/clis/jira/issue.js +1 -0
- package/clis/jira/links.js +1 -0
- package/clis/jira/search.js +1 -0
- package/clis/jira/shared.js +1 -0
- package/clis/juejin/article.js +5 -0
- package/clis/juejin/categories.js +1 -0
- package/clis/juejin/hot.js +1 -0
- package/clis/juejin/login.js +1 -0
- package/clis/juejin/recommend.js +1 -0
- package/clis/juejin/stats.js +53 -0
- package/clis/juejin/tags.js +1 -0
- package/clis/juejin/utils.js +1 -0
- package/clis/juejin/whoami.js +1 -0
- package/clis/ke/auth.js +14 -0
- package/clis/ke/chengjiao.js +45 -0
- package/clis/ke/ershoufang.js +50 -0
- package/clis/ke/utils.js +21 -0
- package/clis/ke/xiaoqu.js +45 -0
- package/clis/ke/zufang.js +50 -0
- package/clis/kimi/_utils.js +38 -0
- package/clis/kimi/audit-extras.js +64 -0
- package/clis/kimi/auth.js +17 -0
- package/clis/kimi/chat.js +77 -0
- package/clis/kimi/storage.js +14 -0
- package/clis/kimi/ui.js +89 -0
- package/clis/kimi/usage.js +51 -0
- package/clis/kuaishou/auth.js +1 -0
- package/clis/kuaishou/publish.js +53 -0
- package/clis/lesswrong/_helpers.js +9 -0
- package/clis/lesswrong/comments.js +9 -0
- package/clis/lesswrong/curated.js +5 -0
- package/clis/lesswrong/frontpage.js +5 -0
- package/clis/lesswrong/new.js +5 -0
- package/clis/lesswrong/read.js +5 -0
- package/clis/lesswrong/sequences.js +5 -0
- package/clis/lesswrong/shortform.js +5 -0
- package/clis/lesswrong/tag.js +5 -0
- package/clis/lesswrong/tags.js +5 -0
- package/clis/lesswrong/top-month.js +5 -0
- package/clis/lesswrong/top-week.js +5 -0
- package/clis/lesswrong/top-year.js +5 -0
- package/clis/lesswrong/top.js +5 -0
- package/clis/lesswrong/user-posts.js +5 -0
- package/clis/lesswrong/user.js +5 -0
- package/clis/lichess/top.js +1 -0
- package/clis/lichess/user.js +1 -0
- package/clis/lichess/utils.js +1 -0
- package/clis/linkedin/auth.js +27 -0
- package/clis/linkedin/comment.js +1 -0
- package/clis/linkedin/connect.js +244 -0
- package/clis/linkedin/create.js +113 -0
- package/clis/linkedin/follow.js +1 -0
- package/clis/linkedin/inbox.js +1 -0
- package/clis/linkedin/job-detail.js +40 -0
- package/clis/linkedin/jobs-preferences.js +34 -0
- package/clis/linkedin/like.js +1 -0
- package/clis/linkedin/notifications.js +1 -0
- package/clis/linkedin/people-search.js +1 -0
- package/clis/linkedin/post-analytics.js +1 -0
- package/clis/linkedin/post-comments.js +1 -0
- package/clis/linkedin/post-detail.js +1 -0
- package/clis/linkedin/posts-core.js +138 -0
- package/clis/linkedin/posts.js +1 -0
- package/clis/linkedin/profile-analytics.js +1 -0
- package/clis/linkedin/profile-api.js +218 -0
- package/clis/linkedin/profile-experience.js +1 -0
- package/clis/linkedin/profile-projects.js +1 -0
- package/clis/linkedin/profile-read.js +3 -0
- package/clis/linkedin/reply.js +1 -0
- package/clis/linkedin/repost.js +1 -0
- package/clis/linkedin/safe-send.js +155 -0
- package/clis/linkedin/salesnav-inbox.js +21 -0
- package/clis/linkedin/salesnav-message.js +33 -0
- package/clis/linkedin/salesnav-search.js +15 -0
- package/clis/linkedin/salesnav-thread.js +1 -0
- package/clis/linkedin/search-api.js +42 -0
- package/clis/linkedin/search.js +50 -0
- package/clis/linkedin/sent-invitations.js +46 -0
- package/clis/linkedin/services-read.js +57 -0
- package/clis/linkedin/shared.js +10 -0
- package/clis/linkedin/social-api.js +260 -0
- package/clis/linkedin/thread-snapshot.js +81 -0
- package/clis/linkedin/timeline.js +37 -0
- package/clis/linkedin-learning/auth.js +27 -0
- package/clis/linkedin-learning/course.js +17 -0
- package/clis/linkedin-learning/search.js +17 -0
- package/clis/linkedin-learning/trending.js +17 -0
- package/clis/linux-do/auth.js +20 -0
- package/clis/linux-do/categories.js +1 -0
- package/clis/linux-do/feed.js +19 -0
- package/clis/linux-do/search.js +1 -0
- package/clis/linux-do/tags.js +1 -0
- package/clis/linux-do/topic-content.js +28 -0
- package/clis/linux-do/topic.js +1 -0
- package/clis/linux-do/user-posts.js +1 -0
- package/clis/linux-do/user-topics.js +1 -0
- package/clis/lobsters/active.js +1 -0
- package/clis/lobsters/domain.js +1 -0
- package/clis/lobsters/hot.js +1 -0
- package/clis/lobsters/newest.js +1 -0
- package/clis/lobsters/read.js +11 -0
- package/clis/lobsters/tag.js +1 -0
- package/clis/maimai/auth.js +19 -0
- package/clis/maimai/search-talents.js +37 -0
- package/clis/manus/_utils.js +28 -0
- package/clis/manus/auth.js +20 -0
- package/clis/manus/connectors.js +4 -0
- package/clis/manus/credits.js +4 -0
- package/clis/manus/list.js +7 -0
- package/clis/manus/read.js +7 -0
- package/clis/manus/skills.js +4 -0
- package/clis/manus/status.js +8 -0
- package/clis/mastodon/post.js +1 -0
- package/clis/mastodon/shared.js +48 -0
- package/clis/mastodon/whoami.js +1 -0
- package/clis/maven/artifact.js +1 -0
- package/clis/maven/search.js +1 -0
- package/clis/maven/utils.js +1 -0
- package/clis/mdn/search.js +1 -0
- package/clis/medium/article.js +12 -0
- package/clis/medium/feed.js +1 -0
- package/clis/medium/login.js +1 -0
- package/clis/medium/search.js +1 -0
- package/clis/medium/stats.js +56 -0
- package/clis/medium/tag.js +1 -0
- package/clis/medium/user.js +1 -0
- package/clis/medium/utils.js +62 -0
- package/clis/medium/whoami.js +1 -0
- package/clis/mubu/doc.js +1 -0
- package/clis/mubu/docs.js +1 -0
- package/clis/mubu/notes.js +1 -0
- package/clis/mubu/recent.js +1 -0
- package/clis/mubu/search.js +1 -0
- package/clis/mubu/utils.js +31 -0
- package/clis/note/auth.js +12 -0
- package/clis/note/note-utils.js +2 -0
- package/clis/note/publish.js +17 -0
- package/clis/notebooklm/add-source.js +46 -0
- package/clis/notebooklm/auth.js +21 -0
- package/clis/notebooklm/create.js +1 -0
- package/clis/notebooklm/current.js +1 -0
- package/clis/notebooklm/generate-audio.js +1 -0
- package/clis/notebooklm/generate-slides.js +1 -0
- package/clis/notebooklm/get.js +1 -0
- package/clis/notebooklm/history.js +1 -0
- package/clis/notebooklm/list.js +1 -0
- package/clis/notebooklm/note-list.js +1 -0
- package/clis/notebooklm/notes-get.js +1 -0
- package/clis/notebooklm/open.js +1 -0
- package/clis/notebooklm/rpc.js +36 -0
- package/clis/notebooklm/shared.js +1 -0
- package/clis/notebooklm/source-fulltext.js +1 -0
- package/clis/notebooklm/source-get.js +1 -0
- package/clis/notebooklm/source-guide.js +1 -0
- package/clis/notebooklm/source-list.js +1 -0
- package/clis/notebooklm/status.js +1 -0
- package/clis/notebooklm/summary.js +1 -0
- package/clis/notebooklm/utils.js +172 -0
- package/clis/notebooklm/write-note.js +1 -0
- package/clis/nowcoder/auth.js +24 -0
- package/clis/nowcoder/comment.js +1 -0
- package/clis/nowcoder/comments.js +1 -0
- package/clis/nowcoder/companies.js +1 -0
- package/clis/nowcoder/creators.js +1 -0
- package/clis/nowcoder/delete.js +1 -0
- package/clis/nowcoder/detail.js +46 -0
- package/clis/nowcoder/dm-list.js +1 -0
- package/clis/nowcoder/dm-read.js +1 -0
- package/clis/nowcoder/dm-send.js +1 -0
- package/clis/nowcoder/drafts.js +1 -0
- package/clis/nowcoder/experience.js +20 -0
- package/clis/nowcoder/hot.js +1 -0
- package/clis/nowcoder/inbox.js +1 -0
- package/clis/nowcoder/jobs.js +1 -0
- package/clis/nowcoder/like.js +1 -0
- package/clis/nowcoder/my.js +1 -0
- package/clis/nowcoder/notifications.js +16 -0
- package/clis/nowcoder/papers.js +22 -0
- package/clis/nowcoder/post.js +1 -0
- package/clis/nowcoder/practice.js +21 -0
- package/clis/nowcoder/recommend.js +1 -0
- package/clis/nowcoder/referral.js +21 -0
- package/clis/nowcoder/salary.js +22 -0
- package/clis/nowcoder/search.js +31 -0
- package/clis/nowcoder/suggest.js +17 -0
- package/clis/nowcoder/topics.js +1 -0
- package/clis/nowcoder/trending.js +1 -0
- package/clis/nowcoder/utils.js +68 -0
- package/clis/npm/downloads.js +1 -0
- package/clis/npm/package.js +1 -0
- package/clis/npm/search.js +1 -0
- package/clis/npm/utils.js +1 -0
- package/clis/nuget/package.js +1 -0
- package/clis/nuget/search.js +1 -0
- package/clis/nuget/utils.js +1 -0
- package/clis/nvd/cve.js +1 -0
- package/clis/oeis/search.js +1 -0
- package/clis/oeis/sequence.js +1 -0
- package/clis/oeis/utils.js +1 -0
- package/clis/ones/common.js +23 -0
- package/clis/ones/enrich-tasks.js +1 -0
- package/clis/ones/login.js +2 -0
- package/clis/ones/logout.js +1 -0
- package/clis/ones/me.js +1 -0
- package/clis/ones/my-tasks.js +1 -0
- package/clis/ones/resolve-labels.js +1 -0
- package/clis/ones/task-helpers.js +1 -0
- package/clis/ones/task.js +1 -0
- package/clis/ones/tasks.js +1 -0
- package/clis/ones/token-info.js +1 -0
- package/clis/ones/worklog.js +14 -0
- package/clis/openalex/search.js +1 -0
- package/clis/openalex/utils.js +1 -0
- package/clis/openalex/work.js +1 -0
- package/clis/openfda/drug-label.js +1 -0
- package/clis/openfda/food-recall.js +1 -0
- package/clis/openfda/utils.js +1 -0
- package/clis/openreview/author.js +1 -0
- package/clis/openreview/paper.js +1 -0
- package/clis/openreview/reviews.js +4 -0
- package/clis/openreview/search.js +1 -0
- package/clis/openreview/utils.js +1 -0
- package/clis/openreview/venue.js +1 -0
- package/clis/oschina/article.js +1 -0
- package/clis/oschina/catalogs.js +1 -0
- package/clis/oschina/login.js +1 -0
- package/clis/oschina/stats.js +54 -0
- package/clis/oschina/whoami.js +1 -0
- package/clis/osv/query.js +1 -0
- package/clis/osv/utils.js +1 -0
- package/clis/osv/vulnerability.js +1 -0
- package/clis/packagist/package.js +1 -0
- package/clis/packagist/search.js +1 -0
- package/clis/packagist/utils.js +1 -0
- package/clis/paperreview/feedback.js +1 -0
- package/clis/paperreview/review.js +1 -0
- package/clis/paperreview/submit.js +1 -0
- package/clis/paperreview/utils.js +1 -0
- package/clis/pinterest/api.js +1 -0
- package/clis/pinterest/auth.js +1 -0
- package/clis/pinterest/boards.js +1 -0
- package/clis/pinterest/client.js +20 -0
- package/clis/pinterest/publish.js +13 -0
- package/clis/pixiv/auth.js +17 -0
- package/clis/pixiv/detail.js +1 -0
- package/clis/pixiv/download.js +1 -0
- package/clis/pixiv/illusts.js +1 -0
- package/clis/pixiv/ranking.js +26 -0
- package/clis/pixiv/search.js +1 -0
- package/clis/pixiv/user.js +1 -0
- package/clis/pixiv/utils.js +18 -0
- package/clis/powerchina/auth.js +17 -0
- package/clis/powerchina/search.js +1 -0
- package/clis/producthunt/browse.js +54 -0
- package/clis/producthunt/hot.js +64 -0
- package/clis/producthunt/posts.js +1 -0
- package/clis/producthunt/today.js +1 -0
- package/clis/producthunt/utils.js +1 -0
- package/clis/pubmed/article.js +1 -0
- package/clis/pubmed/author.js +1 -0
- package/clis/pubmed/citations.js +1 -0
- package/clis/pubmed/clinical-trial.js +1 -0
- package/clis/pubmed/journal.js +1 -0
- package/clis/pubmed/mesh.js +1 -0
- package/clis/pubmed/related.js +1 -0
- package/clis/pubmed/review.js +1 -0
- package/clis/pubmed/search.js +1 -0
- package/clis/pubmed/utils.js +1 -0
- package/clis/pypi/downloads.js +1 -0
- package/clis/pypi/package.js +1 -0
- package/clis/pypi/utils.js +1 -0
- package/clis/qiita/auth.js +1 -0
- package/clis/qiita/gql.js +32 -0
- package/clis/qiita/publish.js +7 -0
- package/clis/qiita/stats.js +37 -0
- package/clis/qoder/_utils.js +113 -0
- package/clis/qoder/composer.js +1 -0
- package/clis/qoder/history.js +25 -0
- package/clis/qoder/quest.js +1 -0
- package/clis/qoder/read.js +1 -0
- package/clis/qoder/status.js +1 -0
- package/clis/qoder/ui.js +59 -0
- package/clis/quark/auth.js +16 -0
- package/clis/quark/ls.js +1 -0
- package/clis/quark/mkdir.js +1 -0
- package/clis/quark/mv.js +1 -0
- package/clis/quark/rename.js +1 -0
- package/clis/quark/rm.js +1 -0
- package/clis/quark/save.js +1 -0
- package/clis/quark/share-tree.js +1 -0
- package/clis/quark/utils.js +13 -0
- package/clis/quora/create-answer.js +22 -0
- package/clis/quora/create-question.js +24 -0
- package/clis/quora/shared.js +43 -0
- package/clis/quora/whoami.js +1 -0
- package/clis/qwen/ask.js +1 -0
- package/clis/qwen/auth.js +17 -0
- package/clis/qwen/detail.js +1 -0
- package/clis/qwen/history.js +1 -0
- package/clis/qwen/image.js +31 -0
- package/clis/qwen/new.js +1 -0
- package/clis/qwen/read.js +1 -0
- package/clis/qwen/send.js +1 -0
- package/clis/qwen/status.js +1 -0
- package/clis/qwen/utils.js +185 -0
- package/clis/reddit/auth.js +17 -0
- package/clis/reddit/comment.js +36 -0
- package/clis/reddit/frontpage.js +40 -0
- package/clis/reddit/home.js +32 -0
- package/clis/reddit/hot.js +46 -0
- package/clis/reddit/popular.js +46 -0
- package/clis/reddit/read.js +398 -0
- package/clis/reddit/reply.js +56 -0
- package/clis/reddit/save.js +30 -0
- package/clis/reddit/saved.js +24 -0
- package/clis/reddit/search.js +51 -0
- package/clis/reddit/submit.js +42 -0
- package/clis/reddit/subreddit-info.js +29 -0
- package/clis/reddit/subreddit.js +52 -0
- package/clis/reddit/subscribe.js +29 -0
- package/clis/reddit/subscribed.js +68 -0
- package/clis/reddit/upvote.js +43 -0
- package/clis/reddit/upvoted.js +24 -0
- package/clis/reddit/user-comments.js +20 -0
- package/clis/reddit/user-posts.js +17 -0
- package/clis/reddit/user.js +20 -0
- package/clis/reddit/whoami.js +19 -0
- package/clis/rednote/auth.js +19 -0
- package/clis/rednote/comments.js +1 -0
- package/clis/rednote/download.js +1 -0
- package/clis/rednote/feed.js +1 -0
- package/clis/rednote/note.js +1 -0
- package/clis/rednote/notifications.js +67 -0
- package/clis/rednote/search.js +32 -0
- package/clis/rednote/user.js +1 -0
- package/clis/rest-countries/country.js +1 -0
- package/clis/rest-countries/region.js +1 -0
- package/clis/rest-countries/utils.js +1 -0
- package/clis/reuters/article-detail.js +1 -0
- package/clis/reuters/auth.js +39 -0
- package/clis/reuters/search.js +1 -0
- package/clis/reuters/utils.js +50 -0
- package/clis/rfc/rfc.js +1 -0
- package/clis/rfc/utils.js +1 -0
- package/clis/rubygems/gem.js +1 -0
- package/clis/rubygems/search.js +1 -0
- package/clis/rubygems/utils.js +1 -0
- package/clis/segmentfault/_signed-request.js +43 -0
- package/clis/segmentfault/article.js +3 -0
- package/clis/segmentfault/channels.js +1 -0
- package/clis/segmentfault/login.js +1 -0
- package/clis/segmentfault/stats.js +82 -0
- package/clis/segmentfault/tags.js +1 -0
- package/clis/segmentfault/whoami.js +1 -0
- package/clis/semanticscholar/citations.js +1 -0
- package/clis/semanticscholar/paper.js +1 -0
- package/clis/semanticscholar/recommendations.js +1 -0
- package/clis/semanticscholar/search.js +1 -0
- package/clis/semanticscholar/utils.js +1 -0
- package/clis/sinablog/article.js +1 -0
- package/clis/sinablog/hot.js +1 -0
- package/clis/sinablog/search.js +1 -0
- package/clis/sinablog/user.js +1 -0
- package/clis/sinablog/utils.js +153 -0
- package/clis/sinafinance/news.js +1 -0
- package/clis/sinafinance/rolling-news.js +20 -0
- package/clis/sinafinance/stock-rank.js +41 -0
- package/clis/sinafinance/stock.js +1 -0
- package/clis/slock/attachment-download.js +1 -0
- package/clis/slock/attachment-upload.js +34 -0
- package/clis/slock/attachment-url.js +1 -0
- package/clis/slock/auth-verify.js +1 -0
- package/clis/slock/bookmark-add.js +11 -0
- package/clis/slock/bookmark-list.js +10 -0
- package/clis/slock/bookmark-remove.js +7 -0
- package/clis/slock/channel-action.js +1 -0
- package/clis/slock/channel-archive.js +1 -0
- package/clis/slock/channel-create.js +1 -0
- package/clis/slock/channel-files.js +1 -0
- package/clis/slock/channel-info.js +1 -0
- package/clis/slock/channel-join.js +1 -0
- package/clis/slock/channel-leave.js +1 -0
- package/clis/slock/channel-list.js +1 -0
- package/clis/slock/channel-mark.js +1 -0
- package/clis/slock/channel-members.js +1 -0
- package/clis/slock/channel-unarchive.js +1 -0
- package/clis/slock/dm-list.js +1 -0
- package/clis/slock/errors.js +1 -0
- package/clis/slock/in-page.js +113 -0
- package/clis/slock/inbox-done.js +9 -0
- package/clis/slock/inbox-read-all.js +1 -0
- package/clis/slock/inbox.js +1 -0
- package/clis/slock/login.js +1 -0
- package/clis/slock/message-read.js +61 -0
- package/clis/slock/message-search.js +24 -0
- package/clis/slock/message-send.js +55 -0
- package/clis/slock/reaction-add.js +1 -0
- package/clis/slock/reaction-remove.js +1 -0
- package/clis/slock/resolve.js +1 -0
- package/clis/slock/server-list.js +9 -0
- package/clis/slock/server-use.js +18 -0
- package/clis/slock/shared.js +1 -0
- package/clis/slock/task-claim.js +14 -0
- package/clis/slock/task-convert.js +35 -0
- package/clis/slock/task-create.js +24 -0
- package/clis/slock/task-delete.js +9 -0
- package/clis/slock/task-get.js +11 -0
- package/clis/slock/task-list-server.js +12 -0
- package/clis/slock/task-list.js +14 -0
- package/clis/slock/task-status.js +19 -0
- package/clis/slock/task-unclaim.js +13 -0
- package/clis/slock/thread-done.js +1 -0
- package/clis/slock/thread-follow.js +1 -0
- package/clis/slock/thread-list.js +1 -0
- package/clis/slock/thread-state.js +1 -0
- package/clis/slock/thread-undone.js +1 -0
- package/clis/slock/thread-unfollow.js +1 -0
- package/clis/slock/unread-summary.js +18 -0
- package/clis/slock/whoami.js +1 -0
- package/clis/smzdm/search.js +71 -0
- package/clis/sohu/article.js +1 -0
- package/clis/sohu/attributes.js +1 -0
- package/clis/sohu/categories.js +1 -0
- package/clis/sohu/channels.js +1 -0
- package/clis/sohu/columns.js +1 -0
- package/clis/sohu/login.js +1 -0
- package/clis/sohu/mpbp.js +1 -0
- package/clis/sohu/stats.js +95 -0
- package/clis/sohu/topics.js +1 -0
- package/clis/sohu/whoami.js +1 -0
- package/clis/spotify/spotify.js +1 -0
- package/clis/spotify/utils.js +8 -0
- package/clis/stackoverflow/bounties.js +1 -0
- package/clis/stackoverflow/hot.js +1 -0
- package/clis/stackoverflow/read.js +13 -0
- package/clis/stackoverflow/related.js +1 -0
- package/clis/stackoverflow/search.js +1 -0
- package/clis/stackoverflow/tag.js +1 -0
- package/clis/stackoverflow/unanswered.js +1 -0
- package/clis/stackoverflow/user.js +1 -0
- package/clis/stackoverflow/utils.js +1 -0
- package/clis/steam/app.js +1 -0
- package/clis/steam/search.js +1 -0
- package/clis/steam/top-sellers.js +1 -0
- package/clis/steam/utils.js +1 -0
- package/clis/substack/auth.js +11 -0
- package/clis/substack/feed.js +1 -0
- package/clis/substack/post-utils.js +2 -0
- package/clis/substack/publication.js +1 -0
- package/clis/substack/publish.js +10 -0
- package/clis/substack/search.js +1 -0
- package/clis/substack/utils.js +108 -0
- package/clis/suno/auth.js +21 -0
- package/clis/suno/download.js +17 -0
- package/clis/suno/generate.js +4 -0
- package/clis/suno/list.js +14 -0
- package/clis/suno/status.js +1 -0
- package/clis/suno/utils.js +102 -0
- package/clis/taobao/add-cart.js +93 -0
- package/clis/taobao/auth.js +8 -0
- package/clis/taobao/cart.js +68 -0
- package/clis/taobao/detail.js +48 -0
- package/clis/taobao/reviews.js +52 -0
- package/clis/taobao/search.js +64 -0
- package/clis/tdx/hot-rank.js +25 -0
- package/clis/telegram/send.js +18 -0
- package/clis/telegram/shared.js +21 -0
- package/clis/telegram/whoami.js +1 -0
- package/clis/test-utils.js +1 -0
- package/clis/threads/post.js +152 -0
- package/clis/threads/shared.js +27 -0
- package/clis/threads/whoami.js +1 -0
- package/clis/ths/hot-rank.js +27 -0
- package/clis/tieba/hot.js +16 -0
- package/clis/tieba/posts.js +1 -0
- package/clis/tieba/read.js +84 -0
- package/clis/tieba/search.js +54 -0
- package/clis/tieba/utils.js +1 -0
- package/clis/tiktok/auth.js +30 -0
- package/clis/tiktok/comment.js +69 -0
- package/clis/tiktok/creator-videos.js +45 -0
- package/clis/tiktok/explore.js +76 -0
- package/clis/tiktok/follow.js +49 -0
- package/clis/tiktok/following.js +103 -0
- package/clis/tiktok/friends.js +79 -0
- package/clis/tiktok/like.js +19 -0
- package/clis/tiktok/live.js +79 -0
- package/clis/tiktok/notifications.js +77 -0
- package/clis/tiktok/profile.js +26 -0
- package/clis/tiktok/publish.js +82 -0
- package/clis/tiktok/save.js +15 -0
- package/clis/tiktok/search.js +24 -0
- package/clis/tiktok/unfollow.js +59 -0
- package/clis/tiktok/unlike.js +19 -0
- package/clis/tiktok/unsave.js +17 -0
- package/clis/tiktok/user.js +143 -0
- package/clis/tiktok/utils.js +272 -0
- package/clis/toutiao/article.js +1 -0
- package/clis/toutiao/articles.js +6 -0
- package/clis/toutiao/auth.js +50 -0
- package/clis/toutiao/hot.js +1 -0
- package/clis/toutiao/utils.js +2 -0
- package/clis/trae-cn/activity.js +1 -0
- package/clis/trae-cn/approve.js +1 -0
- package/clis/trae-cn/ask.js +1 -0
- package/clis/trae-cn/dump.js +1 -0
- package/clis/trae-cn/export.js +3 -0
- package/clis/trae-cn/model.js +1 -0
- package/clis/trae-cn/new.js +1 -0
- package/clis/trae-cn/read.js +1 -0
- package/clis/trae-cn/screenshot.js +1 -0
- package/clis/trae-cn/select-model.js +1 -0
- package/clis/trae-cn/send.js +1 -0
- package/clis/trae-cn/setup.js +1 -0
- package/clis/trae-cn/status.js +1 -0
- package/clis/trae-cn/targets.js +1 -0
- package/clis/trae-cn/utils.js +456 -0
- package/clis/trae-cn/watch.js +3 -0
- package/clis/trae-solo/_actions.js +41 -0
- package/clis/trae-solo/_fs.js +6 -0
- package/clis/trae-solo/_state.js +2 -0
- package/clis/trae-solo/automation.js +43 -0
- package/clis/trae-solo/history.js +15 -0
- package/clis/trae-solo/mode.js +31 -0
- package/clis/trae-solo/model.js +50 -0
- package/clis/trae-solo/renderer-storage.js +11 -0
- package/clis/trae-solo/settings.js +1 -0
- package/clis/trae-solo/skill-fs.js +1 -0
- package/clis/trae-solo/skill.js +81 -0
- package/clis/trae-solo/state-fs.js +2 -0
- package/clis/trae-solo/status.js +1 -0
- package/clis/trae-solo/task-fs.js +5 -0
- package/clis/trae-solo/user-rules.js +1 -0
- package/clis/trae-solo/workspaces-fs.js +1 -0
- package/clis/tumblr/auth.js +24 -0
- package/clis/tumblr/publish.js +14 -0
- package/clis/tvmaze/search.js +1 -0
- package/clis/tvmaze/show.js +1 -0
- package/clis/tvmaze/utils.js +1 -0
- package/clis/twitter/accept.js +116 -0
- package/clis/twitter/article.js +116 -0
- package/clis/twitter/auth.js +4 -0
- package/clis/twitter/block.js +62 -0
- package/clis/twitter/bookmark-folder.js +4 -0
- package/clis/twitter/bookmark-folders.js +4 -0
- package/clis/twitter/bookmark.js +44 -0
- package/clis/twitter/bookmarks.js +27 -0
- package/clis/twitter/delete.js +36 -0
- package/clis/twitter/device-follow.js +13 -0
- package/clis/twitter/dm-list.js +1 -0
- package/clis/twitter/dm-read.js +1 -0
- package/clis/twitter/dm-send.js +13 -0
- package/clis/twitter/dm-shared.js +6 -0
- package/clis/twitter/download.js +38 -0
- package/clis/twitter/follow-batch.js +43 -0
- package/clis/twitter/follow.js +39 -0
- package/clis/twitter/followers.js +59 -0
- package/clis/twitter/following.js +4 -0
- package/clis/twitter/hide-reply.js +57 -0
- package/clis/twitter/like.js +48 -0
- package/clis/twitter/likes.js +14 -0
- package/clis/twitter/list-add-batch.js +1 -0
- package/clis/twitter/list-add-core.js +35 -0
- package/clis/twitter/list-add.js +1 -0
- package/clis/twitter/list-batch-utils.js +1 -0
- package/clis/twitter/list-create.js +12 -0
- package/clis/twitter/list-delete.js +36 -0
- package/clis/twitter/list-remove-batch.js +1 -0
- package/clis/twitter/list-remove-core.js +127 -0
- package/clis/twitter/list-remove.js +1 -0
- package/clis/twitter/list-tweets.js +27 -0
- package/clis/twitter/lists.js +27 -0
- package/clis/twitter/notifications.js +4 -0
- package/clis/twitter/post.js +158 -0
- package/clis/twitter/profile.js +66 -0
- package/clis/twitter/quote.js +123 -0
- package/clis/twitter/reply-dm.js +112 -0
- package/clis/twitter/reply.js +97 -0
- package/clis/twitter/retweet.js +62 -0
- package/clis/twitter/schedule.js +96 -0
- package/clis/twitter/scheduled-delete.js +60 -0
- package/clis/twitter/scheduled-list.js +15 -0
- package/clis/twitter/scheduled-utils.js +18 -0
- package/clis/twitter/search.js +12 -0
- package/clis/twitter/shared.js +76 -0
- package/clis/twitter/thread.js +4 -0
- package/clis/twitter/timeline.js +4 -0
- package/clis/twitter/trending.js +18 -0
- package/clis/twitter/tweets.js +12 -0
- package/clis/twitter/unblock.js +45 -0
- package/clis/twitter/unbookmark.js +41 -0
- package/clis/twitter/unfollow.js +45 -0
- package/clis/twitter/unlike.js +48 -0
- package/clis/twitter/unretweet.js +62 -0
- package/clis/twitter/utils.js +55 -0
- package/clis/uisdc/news.js +25 -0
- package/clis/uiverse/_shared.js +257 -0
- package/clis/uiverse/code.js +1 -0
- package/clis/uiverse/preview.js +1 -0
- package/clis/upwork/auth.js +19 -0
- package/clis/upwork/detail.js +22 -0
- package/clis/upwork/feed.js +21 -0
- package/clis/upwork/search.js +21 -0
- package/clis/upwork/utils.js +1 -0
- package/clis/v2ex/auth.js +10 -0
- package/clis/v2ex/daily.js +41 -0
- package/clis/v2ex/hot.js +1 -0
- package/clis/v2ex/latest.js +1 -0
- package/clis/v2ex/me.js +58 -0
- package/clis/v2ex/member.js +1 -0
- package/clis/v2ex/node.js +1 -0
- package/clis/v2ex/nodes.js +1 -0
- package/clis/v2ex/notifications.js +40 -0
- package/clis/v2ex/replies.js +1 -0
- package/clis/v2ex/topic.js +1 -0
- package/clis/v2ex/user.js +1 -0
- package/clis/vk/post.js +1 -0
- package/clis/vk/shared.js +8 -0
- package/clis/vk/whoami.js +1 -0
- package/clis/wanfang/search.js +42 -0
- package/clis/web/read.js +260 -0
- package/clis/wechat-channels/auth.js +31 -0
- package/clis/wechat-channels/publish.js +298 -0
- package/clis/weibo/article.js +1 -0
- package/clis/weibo/auth.js +17 -0
- package/clis/weibo/comments.js +28 -0
- package/clis/weibo/delete.js +84 -0
- package/clis/weibo/favorites.js +27 -0
- package/clis/weibo/feed.js +33 -0
- package/clis/weibo/hot.js +17 -0
- package/clis/weibo/me.js +51 -0
- package/clis/weibo/post.js +46 -0
- package/clis/weibo/publish.js +98 -0
- package/clis/weibo/search.js +47 -0
- package/clis/weibo/user-posts.js +92 -0
- package/clis/weibo/user.js +37 -0
- package/clis/weibo/utils.js +16 -0
- package/clis/weixin/article.js +1 -0
- package/clis/weixin/create-draft.js +152 -0
- package/clis/weixin/download.js +100 -0
- package/clis/weixin/drafts.js +27 -0
- package/clis/weixin/login.js +1 -0
- package/clis/weixin/search.js +44 -0
- package/clis/weixin/stats.js +43 -0
- package/clis/weixin/whoami.js +1 -0
- package/clis/weread/ai-outline.js +2 -0
- package/clis/weread/auth.js +24 -0
- package/clis/weread/book-search.js +2 -0
- package/clis/weread/book.js +3 -0
- package/clis/weread/highlights.js +1 -0
- package/clis/weread/notebooks.js +1 -0
- package/clis/weread/notes.js +1 -0
- package/clis/weread/ranking.js +1 -0
- package/clis/weread/search.js +1 -0
- package/clis/weread/shelf.js +1 -0
- package/clis/weread/utils.js +67 -0
- package/clis/weread-official/book.js +1 -0
- package/clis/weread-official/discover.js +1 -0
- package/clis/weread-official/list-apis.js +1 -0
- package/clis/weread-official/notes.js +1 -0
- package/clis/weread-official/readdata.js +1 -0
- package/clis/weread-official/review.js +1 -0
- package/clis/weread-official/search.js +1 -0
- package/clis/weread-official/shelf.js +1 -0
- package/clis/weread-official/utils.js +1 -0
- package/clis/wikidata/entity.js +1 -0
- package/clis/wikidata/search.js +1 -0
- package/clis/wikidata/utils.js +1 -0
- package/clis/wikipedia/page.js +3 -0
- package/clis/wikipedia/random.js +1 -0
- package/clis/wikipedia/search.js +1 -0
- package/clis/wikipedia/summary.js +1 -0
- package/clis/wikipedia/trending.js +1 -0
- package/clis/wikipedia/utils.js +1 -0
- package/clis/wordpress/login.js +1 -0
- package/clis/wordpress/publish.js +1 -0
- package/clis/wordpress/shared.js +54 -0
- package/clis/wordpress/whoami.js +1 -0
- package/clis/woshipm/article.js +1 -0
- package/clis/woshipm/login.js +1 -0
- package/clis/woshipm/stats.js +52 -0
- package/clis/woshipm/whoami.js +1 -0
- package/clis/wttr/current.js +1 -0
- package/clis/wttr/forecast.js +1 -0
- package/clis/wttr/utils.js +1 -0
- package/clis/xianyu/auth.js +11 -0
- package/clis/xianyu/chat.js +1 -0
- package/clis/xianyu/im.js +240 -0
- package/clis/xianyu/inbox.js +1 -0
- package/clis/xianyu/item.js +97 -0
- package/clis/xianyu/messages.js +1 -0
- package/clis/xianyu/publish.js +245 -0
- package/clis/xianyu/reply.js +1 -0
- package/clis/xianyu/search.js +141 -0
- package/clis/xianyu/utils.js +1 -0
- package/clis/xiaoe/auth.js +10 -0
- package/clis/xiaoe/catalog.js +134 -0
- package/clis/xiaoe/content.js +16 -0
- package/clis/xiaoe/courses.js +43 -0
- package/clis/xiaoe/detail.js +19 -0
- package/clis/xiaoe/play-url.js +97 -0
- package/clis/xiaohongshu/ask.js +130 -0
- package/clis/xiaohongshu/auth.js +13 -0
- package/clis/xiaohongshu/collection-helpers.js +64 -0
- package/clis/xiaohongshu/comments.js +89 -0
- package/clis/xiaohongshu/creator-note-detail.js +80 -0
- package/clis/xiaohongshu/creator-notes-summary.js +1 -0
- package/clis/xiaohongshu/creator-notes.js +107 -0
- package/clis/xiaohongshu/creator-profile.js +13 -0
- package/clis/xiaohongshu/creator-stats.js +13 -0
- package/clis/xiaohongshu/delete-note.js +69 -0
- package/clis/xiaohongshu/download.js +200 -0
- package/clis/xiaohongshu/draft-clear.js +44 -0
- package/clis/xiaohongshu/draft-delete.js +37 -0
- package/clis/xiaohongshu/draft-open.js +1 -0
- package/clis/xiaohongshu/draft-utils.js +36 -0
- package/clis/xiaohongshu/drafts.js +1 -0
- package/clis/xiaohongshu/feed.js +38 -0
- package/clis/xiaohongshu/follow.js +75 -0
- package/clis/xiaohongshu/liked.js +1 -0
- package/clis/xiaohongshu/note-helpers.js +1 -0
- package/clis/xiaohongshu/note.js +32 -0
- package/clis/xiaohongshu/notifications.js +1 -0
- package/clis/xiaohongshu/publish-video.js +87 -0
- package/clis/xiaohongshu/publish.js +637 -0
- package/clis/xiaohongshu/saved.js +1 -0
- package/clis/xiaohongshu/search.js +194 -0
- package/clis/xiaohongshu/unfollow.js +98 -0
- package/clis/xiaohongshu/user-helpers.js +1 -0
- package/clis/xiaohongshu/user.js +30 -0
- package/clis/xiaoyuzhou/auth.js +3 -0
- package/clis/xiaoyuzhou/download.js +1 -0
- package/clis/xiaoyuzhou/episode.js +1 -0
- package/clis/xiaoyuzhou/podcast-episodes.js +1 -0
- package/clis/xiaoyuzhou/podcast.js +1 -0
- package/clis/xiaoyuzhou/transcript.js +1 -0
- package/clis/xiaoyuzhou/utils.js +1 -0
- package/clis/xueqiu/article.js +4 -0
- package/clis/xueqiu/auth.js +27 -0
- package/clis/xueqiu/comments.js +38 -0
- package/clis/xueqiu/danjuan-utils.js +84 -0
- package/clis/xueqiu/earnings-date.js +1 -0
- package/clis/xueqiu/events.js +17 -0
- package/clis/xueqiu/feed.js +1 -0
- package/clis/xueqiu/fund-holdings.js +1 -0
- package/clis/xueqiu/fund-snapshot.js +1 -0
- package/clis/xueqiu/groups.js +1 -0
- package/clis/xueqiu/hashtags.js +26 -0
- package/clis/xueqiu/hot-stock.js +1 -0
- package/clis/xueqiu/hot.js +1 -0
- package/clis/xueqiu/kline.js +1 -0
- package/clis/xueqiu/search.js +1 -0
- package/clis/xueqiu/stock.js +1 -0
- package/clis/xueqiu/stocks.js +13 -0
- package/clis/xueqiu/users.js +12 -0
- package/clis/xueqiu/utils.js +9 -0
- package/clis/xueqiu/watchlist.js +1 -0
- package/clis/yahoo/search.js +21 -0
- package/clis/yahoo-finance/quote.js +50 -0
- package/clis/yollomi/background.js +1 -0
- package/clis/yollomi/edit.js +1 -0
- package/clis/yollomi/face-swap.js +1 -0
- package/clis/yollomi/generate.js +1 -0
- package/clis/yollomi/models.js +1 -0
- package/clis/yollomi/object-remover.js +1 -0
- package/clis/yollomi/remove-bg.js +1 -0
- package/clis/yollomi/restore.js +1 -0
- package/clis/yollomi/try-on.js +1 -0
- package/clis/yollomi/upload.js +17 -0
- package/clis/yollomi/upscale.js +1 -0
- package/clis/yollomi/utils.js +16 -0
- package/clis/yollomi/video.js +1 -0
- package/clis/youdao/note.js +113 -0
- package/clis/youtube/auth.js +20 -0
- package/clis/youtube/channel.js +118 -0
- package/clis/youtube/comments.js +64 -0
- package/clis/youtube/feed.js +89 -0
- package/clis/youtube/history.js +87 -0
- package/clis/youtube/like.js +33 -0
- package/clis/youtube/playlist.js +47 -0
- package/clis/youtube/publish.js +56 -0
- package/clis/youtube/search.js +39 -0
- package/clis/youtube/subscribe.js +42 -0
- package/clis/youtube/subscriptions.js +26 -0
- package/clis/youtube/transcript-group.js +2 -0
- package/clis/youtube/transcript.js +417 -0
- package/clis/youtube/unlike.js +33 -0
- package/clis/youtube/unsubscribe.js +42 -0
- package/clis/youtube/utils.js +34 -0
- package/clis/youtube/video.js +96 -0
- package/clis/youtube/watch-later.js +41 -0
- package/clis/yuanbao/ask.js +145 -0
- package/clis/yuanbao/auth.js +23 -0
- package/clis/yuanbao/detail.js +1 -0
- package/clis/yuanbao/history.js +1 -0
- package/clis/yuanbao/new.js +16 -0
- package/clis/yuanbao/read.js +1 -0
- package/clis/yuanbao/send.js +1 -0
- package/clis/yuanbao/shared.js +127 -0
- package/clis/yuanbao/status.js +1 -0
- package/clis/yuque/article.js +1 -0
- package/clis/yuque/whoami.js +1 -0
- package/clis/zhihu/answer-comments.js +11 -0
- package/clis/zhihu/answer-detail.js +11 -0
- package/clis/zhihu/answer.js +15 -0
- package/clis/zhihu/article-transform.js +1 -0
- package/clis/zhihu/article.js +7 -0
- package/clis/zhihu/auth.js +11 -0
- package/clis/zhihu/collection.js +7 -0
- package/clis/zhihu/collections.js +7 -0
- package/clis/zhihu/comment.js +17 -0
- package/clis/zhihu/download.js +39 -0
- package/clis/zhihu/favorite.js +39 -0
- package/clis/zhihu/follow.js +19 -0
- package/clis/zhihu/followers.js +1 -0
- package/clis/zhihu/following.js +1 -0
- package/clis/zhihu/hot.js +21 -0
- package/clis/zhihu/like.js +16 -0
- package/clis/zhihu/paginate.js +11 -0
- package/clis/zhihu/pin.js +24 -0
- package/clis/zhihu/pins.js +1 -0
- package/clis/zhihu/question.js +7 -0
- package/clis/zhihu/recommend.js +7 -0
- package/clis/zhihu/search.js +11 -0
- package/clis/zhihu/stats.js +41 -0
- package/clis/zhihu/target.js +1 -0
- package/clis/zhihu/text.js +6 -0
- package/clis/zhihu/user-answers.js +1 -0
- package/clis/zhihu/user-arg.js +1 -0
- package/clis/zhihu/user-articles.js +1 -0
- package/clis/zhihu/user.js +11 -0
- package/clis/zhihu/write-shared.js +71 -0
- package/clis/zlibrary/info.js +1 -0
- package/clis/zlibrary/search.js +1 -0
- package/clis/zlibrary/utils.js +48 -0
- package/clis/zsxq/auth.js +33 -0
- package/clis/zsxq/dynamics.js +1 -0
- package/clis/zsxq/groups.js +1 -0
- package/clis/zsxq/search.js +1 -0
- package/clis/zsxq/topic.js +1 -0
- package/clis/zsxq/topics.js +1 -0
- package/clis/zsxq/utils.js +72 -0
- package/dist/src/adapter-shadow.d.ts +11 -0
- package/dist/src/adapter-shadow.js +2 -0
- package/dist/src/adapter-shadow.test.d.ts +1 -0
- package/dist/src/adapter-source.d.ts +11 -0
- package/dist/src/adapter-source.js +1 -0
- package/dist/src/adapter-source.test.d.ts +1 -0
- package/dist/src/browser/analyze.d.ts +118 -0
- package/dist/src/browser/analyze.js +1 -0
- package/dist/src/browser/analyze.test.d.ts +1 -0
- package/dist/src/browser/article-extract.d.ts +57 -0
- package/dist/src/browser/article-extract.e2e.test.d.ts +1 -0
- package/dist/src/browser/article-extract.js +2 -0
- package/dist/src/browser/article-extract.test.d.ts +1 -0
- package/dist/src/browser/ax-snapshot.d.ts +37 -0
- package/dist/src/browser/ax-snapshot.js +2 -0
- package/dist/src/browser/ax-snapshot.test.d.ts +1 -0
- package/dist/src/browser/base-page.d.ts +151 -0
- package/dist/src/browser/base-page.js +225 -0
- package/dist/src/browser/base-page.test.d.ts +1 -0
- package/dist/src/browser/bridge-readiness.d.ts +14 -0
- package/dist/src/browser/bridge-readiness.js +1 -0
- package/dist/src/browser/bridge-readiness.test.d.ts +1 -0
- package/dist/src/browser/bridge.d.ts +26 -0
- package/dist/src/browser/bridge.js +1 -0
- package/dist/src/browser/cdp-click-fixture.test.d.ts +1 -0
- package/dist/src/browser/cdp.d.ts +51 -0
- package/dist/src/browser/cdp.js +1 -0
- package/dist/src/browser/cdp.test.d.ts +1 -0
- package/dist/src/browser/compound.d.ts +59 -0
- package/dist/src/browser/compound.js +82 -0
- package/dist/src/browser/compound.test.d.ts +1 -0
- package/dist/src/browser/config.d.ts +2 -0
- package/dist/src/browser/config.js +1 -0
- package/dist/src/browser/daemon-client.d.ts +79 -0
- package/dist/src/browser/daemon-client.js +1 -0
- package/dist/src/browser/daemon-client.test.d.ts +1 -0
- package/dist/src/browser/daemon-lifecycle.d.ts +37 -0
- package/dist/src/browser/daemon-lifecycle.js +12 -0
- package/dist/src/browser/daemon-transport.d.ts +55 -0
- package/dist/src/browser/daemon-transport.js +1 -0
- package/dist/src/browser/daemon-version.d.ts +4 -0
- package/dist/src/browser/daemon-version.js +2 -0
- package/dist/src/browser/dom-helpers.d.ts +41 -0
- package/dist/src/browser/dom-helpers.js +166 -0
- package/dist/src/browser/dom-helpers.test.d.ts +1 -0
- package/dist/src/browser/dom-snapshot.d.ts +93 -0
- package/dist/src/browser/dom-snapshot.js +809 -0
- package/dist/src/browser/dom-snapshot.test.d.ts +11 -0
- package/dist/src/browser/errors.d.ts +38 -0
- package/dist/src/browser/errors.js +5 -0
- package/dist/src/browser/errors.test.d.ts +1 -0
- package/dist/src/browser/extract.d.ts +69 -0
- package/dist/src/browser/extract.js +42 -0
- package/dist/src/browser/extract.test.d.ts +1 -0
- package/dist/src/browser/find.d.ts +84 -0
- package/dist/src/browser/find.js +328 -0
- package/dist/src/browser/find.test.d.ts +1 -0
- package/dist/src/browser/fingerprint.d.ts +44 -0
- package/dist/src/browser/fingerprint.js +82 -0
- package/dist/src/browser/html-tree.d.ts +75 -0
- package/dist/src/browser/html-tree.js +61 -0
- package/dist/src/browser/html-tree.test.d.ts +1 -0
- package/dist/src/browser/index.d.ts +14 -0
- package/dist/src/browser/index.js +1 -0
- package/dist/src/browser/managed-chrome.d.ts +89 -0
- package/dist/src/browser/managed-chrome.js +1 -0
- package/dist/src/browser/network-cache.d.ts +49 -0
- package/dist/src/browser/network-cache.js +1 -0
- package/dist/src/browser/network-cache.test.d.ts +1 -0
- package/dist/src/browser/network-key.d.ts +22 -0
- package/dist/src/browser/network-key.js +1 -0
- package/dist/src/browser/network-key.test.d.ts +1 -0
- package/dist/src/browser/page.d.ts +83 -0
- package/dist/src/browser/page.js +15 -0
- package/dist/src/browser/page.test.d.ts +1 -0
- package/dist/src/browser/profile.d.ts +96 -0
- package/dist/src/browser/profile.js +2 -0
- package/dist/src/browser/proxy-test.d.ts +28 -0
- package/dist/src/browser/proxy-test.js +12 -0
- package/dist/src/browser/shape-filter.d.ts +52 -0
- package/dist/src/browser/shape-filter.js +1 -0
- package/dist/src/browser/shape-filter.test.d.ts +1 -0
- package/dist/src/browser/shape.d.ts +23 -0
- package/dist/src/browser/shape.js +1 -0
- package/dist/src/browser/shape.test.d.ts +1 -0
- package/dist/src/browser/stealth.d.ts +18 -0
- package/dist/src/browser/stealth.js +391 -0
- package/dist/src/browser/stealth.test.d.ts +1 -0
- package/dist/src/browser/tabs.d.ts +13 -0
- package/dist/src/browser/tabs.js +2 -0
- package/dist/src/browser/target-errors.d.ts +39 -0
- package/dist/src/browser/target-errors.js +1 -0
- package/dist/src/browser/target-errors.test.d.ts +1 -0
- package/dist/src/browser/target-resolver.d.ts +158 -0
- package/dist/src/browser/target-resolver.js +423 -0
- package/dist/src/browser/target-resolver.test.d.ts +1 -0
- package/dist/src/browser/trace.d.ts +21 -0
- package/dist/src/browser/trace.js +2 -0
- package/dist/src/browser/utils.d.ts +20 -0
- package/dist/src/browser/utils.js +1 -0
- package/dist/src/browser/utils.test.d.ts +1 -0
- package/dist/src/browser/verify-fixture.d.ts +65 -0
- package/dist/src/browser/verify-fixture.js +2 -0
- package/dist/src/browser/verify-fixture.test.d.ts +1 -0
- package/dist/src/browser/visual-refs.d.ts +11 -0
- package/dist/src/browser/visual-refs.js +94 -0
- package/dist/src/browser-session-lock.d.ts +13 -0
- package/dist/src/browser-session-lock.js +1 -0
- package/dist/src/browser-session-lock.test.d.ts +1 -0
- package/dist/src/browser.test.d.ts +1 -0
- package/dist/src/build-manifest.d.ts +103 -0
- package/dist/src/build-manifest.js +16 -0
- package/dist/src/build-manifest.test.d.ts +1 -0
- package/dist/src/capabilityRouting.d.ts +19 -0
- package/dist/src/capabilityRouting.js +1 -0
- package/dist/src/capabilityRouting.test.d.ts +1 -0
- package/dist/src/cli-argv-preprocess.d.ts +63 -0
- package/dist/src/cli-argv-preprocess.js +1 -0
- package/dist/src/cli-argv-preprocess.test.d.ts +1 -0
- package/dist/src/cli.d.ts +79 -0
- package/dist/src/cli.js +132 -0
- package/dist/src/cli.test.d.ts +1 -0
- package/dist/src/commanderAdapter.d.ts +21 -0
- package/dist/src/commanderAdapter.js +3 -0
- package/dist/src/commanderAdapter.test.d.ts +1 -0
- package/dist/src/commands/auth.d.ts +40 -0
- package/dist/src/commands/auth.js +2 -0
- package/dist/src/commands/auth.test.d.ts +1 -0
- package/dist/src/commands/daemon.d.ts +25 -0
- package/dist/src/commands/daemon.js +1 -0
- package/dist/src/commands/daemon.test.d.ts +1 -0
- package/dist/src/completion-fast.d.ts +22 -0
- package/dist/src/completion-fast.js +1 -0
- package/dist/src/completion-shared.d.ts +13 -0
- package/dist/src/completion-shared.js +30 -0
- package/dist/src/completion.d.ts +21 -0
- package/dist/src/completion.js +1 -0
- package/dist/src/completion.test.d.ts +1 -0
- package/dist/src/constants.d.ts +22 -0
- package/dist/src/constants.js +1 -0
- package/dist/src/convention-audit.d.ts +50 -0
- package/dist/src/convention-audit.js +2 -0
- package/dist/src/convention-audit.test.d.ts +1 -0
- package/dist/src/daemon-utils.d.ts +18 -0
- package/dist/src/daemon-utils.js +1 -0
- package/dist/src/daemon.d.ts +22 -0
- package/dist/src/daemon.js +1 -0
- package/dist/src/daemon.test.d.ts +1 -0
- package/dist/src/discovery.d.ts +43 -0
- package/dist/src/discovery.js +2 -0
- package/dist/src/doctor.d.ts +38 -0
- package/dist/src/doctor.js +13 -0
- package/dist/src/doctor.test.d.ts +1 -0
- package/dist/src/download/article-download.d.ts +72 -0
- package/dist/src/download/article-download.js +21 -0
- package/dist/src/download/article-download.test.d.ts +1 -0
- package/dist/src/download/index.d.ts +71 -0
- package/dist/src/download/index.js +7 -0
- package/dist/src/download/index.test.d.ts +1 -0
- package/dist/src/download/media-download.d.ts +49 -0
- package/dist/src/download/media-download.js +1 -0
- package/dist/src/download/media-download.test.d.ts +1 -0
- package/dist/src/download/progress.d.ts +36 -0
- package/dist/src/download/progress.js +5 -0
- package/dist/src/download/progress.test.d.ts +1 -0
- package/dist/src/electron-apps.d.ts +31 -0
- package/dist/src/electron-apps.js +1 -0
- package/dist/src/electron-apps.test.d.ts +1 -0
- package/dist/src/engine.test.d.ts +1 -0
- package/dist/src/errors.d.ts +117 -0
- package/dist/src/errors.js +2 -0
- package/dist/src/errors.test.d.ts +1 -0
- package/dist/src/execution.d.ts +24 -0
- package/dist/src/execution.js +2 -0
- package/dist/src/execution.test.d.ts +1 -0
- package/dist/src/extension-manifest-regression.test.d.ts +1 -0
- package/dist/src/external-clis.yaml +109 -0
- package/dist/src/external.d.ts +49 -0
- package/dist/src/external.js +1 -0
- package/dist/src/external.test.d.ts +1 -0
- package/dist/src/help.d.ts +88 -0
- package/dist/src/help.js +8 -0
- package/dist/src/help.test.d.ts +1 -0
- package/dist/src/hooks.d.ts +46 -0
- package/dist/src/hooks.js +1 -0
- package/dist/src/hooks.test.d.ts +4 -0
- package/dist/src/interceptor.d.ts +44 -0
- package/dist/src/interceptor.js +123 -0
- package/dist/src/interceptor.test.d.ts +4 -0
- package/dist/src/launcher.d.ts +41 -0
- package/dist/src/launcher.js +7 -0
- package/dist/src/launcher.test.d.ts +1 -0
- package/dist/src/logger.d.ts +26 -0
- package/dist/src/logger.js +9 -0
- package/dist/src/main.d.ts +5 -0
- package/dist/src/main.js +10 -0
- package/dist/src/manifest-types.d.ts +43 -0
- package/dist/src/manifest-types.js +1 -0
- package/dist/src/node-network.d.ts +10 -0
- package/dist/src/node-network.js +1 -0
- package/dist/src/node-network.test.d.ts +1 -0
- package/dist/src/observation/artifact.d.ts +16 -0
- package/dist/src/observation/artifact.js +8 -0
- package/dist/src/observation/artifact.test.d.ts +1 -0
- package/dist/src/observation/events.d.ts +89 -0
- package/dist/src/observation/events.js +1 -0
- package/dist/src/observation/index.d.ts +7 -0
- package/dist/src/observation/index.js +1 -0
- package/dist/src/observation/manager.d.ts +9 -0
- package/dist/src/observation/manager.js +1 -0
- package/dist/src/observation/manager.test.d.ts +1 -0
- package/dist/src/observation/redaction.d.ts +11 -0
- package/dist/src/observation/redaction.js +2 -0
- package/dist/src/observation/redaction.test.d.ts +1 -0
- package/dist/src/observation/retention.d.ts +32 -0
- package/dist/src/observation/retention.js +1 -0
- package/dist/src/observation/retention.test.d.ts +1 -0
- package/dist/src/observation/ring-buffer.d.ts +22 -0
- package/dist/src/observation/ring-buffer.js +1 -0
- package/dist/src/observation/ring-buffer.test.d.ts +1 -0
- package/dist/src/observation/session.d.ts +25 -0
- package/dist/src/observation/session.js +1 -0
- package/dist/src/output.d.ts +14 -0
- package/dist/src/output.js +2 -0
- package/dist/src/output.test.d.ts +1 -0
- package/dist/src/package-exports.test.d.ts +1 -0
- package/dist/src/package-paths.d.ts +8 -0
- package/dist/src/package-paths.js +1 -0
- package/dist/src/pipeline/executor.d.ts +11 -0
- package/dist/src/pipeline/executor.js +1 -0
- package/dist/src/pipeline/executor.test.d.ts +4 -0
- package/dist/src/pipeline/index.d.ts +5 -0
- package/dist/src/pipeline/index.js +1 -0
- package/dist/src/pipeline/registry.d.ts +28 -0
- package/dist/src/pipeline/registry.js +1 -0
- package/dist/src/pipeline/steps/browser.d.ts +13 -0
- package/dist/src/pipeline/steps/browser.js +1 -0
- package/dist/src/pipeline/steps/download.d.ts +18 -0
- package/dist/src/pipeline/steps/download.js +1 -0
- package/dist/src/pipeline/steps/download.test.d.ts +1 -0
- package/dist/src/pipeline/steps/fetch.d.ts +5 -0
- package/dist/src/pipeline/steps/fetch.js +31 -0
- package/dist/src/pipeline/steps/fetch.test.d.ts +1 -0
- package/dist/src/pipeline/steps/intercept.d.ts +5 -0
- package/dist/src/pipeline/steps/intercept.js +1 -0
- package/dist/src/pipeline/steps/tap.d.ts +12 -0
- package/dist/src/pipeline/steps/tap.js +53 -0
- package/dist/src/pipeline/steps/transform.d.ts +9 -0
- package/dist/src/pipeline/steps/transform.js +1 -0
- package/dist/src/pipeline/template.d.ts +17 -0
- package/dist/src/pipeline/template.js +1 -0
- package/dist/src/pipeline/template.test.d.ts +4 -0
- package/dist/src/pipeline/transform.test.d.ts +4 -0
- package/dist/src/plugin-manifest.d.ts +70 -0
- package/dist/src/plugin-manifest.js +1 -0
- package/dist/src/plugin-manifest.test.d.ts +4 -0
- package/dist/src/plugin-scaffold.d.ts +28 -0
- package/dist/src/plugin-scaffold.js +75 -0
- package/dist/src/plugin-scaffold.test.d.ts +4 -0
- package/dist/src/plugin.d.ts +145 -0
- package/dist/src/plugin.js +20 -0
- package/dist/src/plugin.test.d.ts +4 -0
- package/dist/src/rate-limit.d.ts +15 -0
- package/dist/src/rate-limit.js +2 -0
- package/dist/src/rate-limit.test.d.ts +1 -0
- package/dist/src/registry-api.d.ts +13 -0
- package/dist/src/registry-api.js +1 -0
- package/dist/src/registry.d.ts +130 -0
- package/dist/src/registry.js +1 -0
- package/dist/src/registry.test.d.ts +4 -0
- package/dist/src/runtime-detect.d.ts +31 -0
- package/dist/src/runtime-detect.js +1 -0
- package/dist/src/runtime-detect.test.d.ts +1 -0
- package/dist/src/runtime.d.ts +57 -0
- package/dist/src/runtime.js +1 -0
- package/dist/src/scripts/framework.d.ts +7 -0
- package/dist/src/scripts/framework.js +1 -0
- package/dist/src/scripts/interact.d.ts +4 -0
- package/dist/src/scripts/interact.js +1 -0
- package/dist/src/scripts/store.d.ts +13 -0
- package/dist/src/scripts/store.js +1 -0
- package/dist/src/serialization.d.ts +42 -0
- package/dist/src/serialization.js +4 -0
- package/dist/src/serialization.test.d.ts +1 -0
- package/dist/src/skills.d.ts +14 -0
- package/dist/src/skills.js +6 -0
- package/dist/src/skills.test.d.ts +1 -0
- package/dist/src/snapshotFormatter.d.ts +11 -0
- package/dist/src/snapshotFormatter.js +3 -0
- package/dist/src/snapshotFormatter.test.d.ts +7 -0
- package/dist/src/tui.d.ts +28 -0
- package/dist/src/tui.js +16 -0
- package/dist/src/tui.test.d.ts +1 -0
- package/dist/src/types.d.ts +236 -0
- package/dist/src/types.js +1 -0
- package/dist/src/utils.d.ts +57 -0
- package/dist/src/utils.js +38 -0
- package/dist/src/utils.test.d.ts +1 -0
- package/dist/src/validate.d.ts +21 -0
- package/dist/src/validate.js +3 -0
- package/dist/src/validate.test.d.ts +9 -0
- package/dist/src/verify.d.ts +27 -0
- package/dist/src/verify.js +2 -0
- package/dist/src/verify.test.d.ts +8 -0
- package/dist/src/version.d.ts +4 -0
- package/dist/src/version.js +1 -0
- package/dist/src/weixin-download.test.d.ts +1 -0
- package/docs/guide/browser-bridge.md +94 -0
- package/docs/guide/electron-app-cli.md +199 -0
- package/docs/guide/exit-codes.md +24 -0
- package/docs/guide/extending-opencli.md +134 -0
- package/docs/guide/getting-started.md +81 -0
- package/docs/guide/installation.md +52 -0
- package/docs/guide/plugins.md +226 -0
- package/docs/guide/remote-orchestration.md +116 -0
- package/docs/guide/troubleshooting.md +69 -0
- package/package.json +116 -0
- package/scripts/check-doc-coverage.sh +81 -0
- package/scripts/check-listing-id-pairing.mjs +193 -0
- package/scripts/check-silent-column-drop.mjs +105 -0
- package/scripts/check-typed-error-lint.mjs +118 -0
- package/scripts/clean-dist.cjs +13 -0
- package/scripts/copy-yaml.cjs +12 -0
- package/scripts/fetch-adapters.js +293 -0
- package/scripts/minify-release.mjs +115 -0
- package/scripts/postinstall.js +174 -0
- package/scripts/silent-column-drop-baseline.json +910 -0
- package/scripts/typed-error-lint-baseline.json +1098 -0
- package/skills/opencli-adapter-author/SKILL.md +256 -0
- package/skills/opencli-adapter-author/references/adapter-template.md +471 -0
- package/skills/opencli-adapter-author/references/api-discovery.md +295 -0
- package/skills/opencli-adapter-author/references/coverage-matrix.md +81 -0
- package/skills/opencli-adapter-author/references/field-conventions.md +172 -0
- package/skills/opencli-adapter-author/references/field-decode-playbook.md +181 -0
- package/skills/opencli-adapter-author/references/jsdom-fixture-pattern.md +196 -0
- package/skills/opencli-adapter-author/references/output-design.md +149 -0
- package/skills/opencli-adapter-author/references/site-memory/bilibili.md +70 -0
- package/skills/opencli-adapter-author/references/site-memory/eastmoney.md +70 -0
- package/skills/opencli-adapter-author/references/site-memory/tonghuashun.md +51 -0
- package/skills/opencli-adapter-author/references/site-memory/xueqiu.md +58 -0
- package/skills/opencli-adapter-author/references/site-memory.md +231 -0
- package/skills/opencli-adapter-author/references/site-recon.md +134 -0
- package/skills/opencli-adapter-author/references/strategy-selection.md +169 -0
- package/skills/opencli-adapter-author/references/success-rate-pitfalls.md +162 -0
- package/skills/opencli-adapter-author/references/typed-errors.md +234 -0
- package/skills/opencli-autofix/SKILL.md +297 -0
- package/skills/opencli-browser/SKILL.md +468 -0
- package/skills/opencli-browser-sitemap/SKILL.md +96 -0
- package/skills/opencli-sitemap-author/SKILL.md +161 -0
- package/skills/opencli-sitemap-author/references/sitemap-schema.md +660 -0
- package/skills/opencli-usage/SKILL.md +168 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import{cli as h,Strategy as l}from"@jackwener/opencli/registry";import{ArgumentError as i}from"@jackwener/opencli/errors";import{authHeadersFragment as u,channelResolveFragment as p}from"./in-page.js";import{dispatchEvaluateResult as m}from"./errors.js";import{SLOCK_SITE as k,SLOCK_DOMAIN as f,SLOCK_HOME_URL as w,SLOCK_API_BASE as b}from"./shared.js";h({site:k,name:"task-create",access:"write",description:"Create a task in a channel (single title; batch 1-50 is server-supported but client surface is single — see backlog R4).",domain:f,strategy:l.COOKIE,browser:!0,siteSession:"persistent",args:[{name:"channel",positional:!0,required:!0,help:"channelId UUID or #name"},{name:"title",positional:!0,required:!0,help:"Task title (single; batch TODO via R4)"},{name:"desc",help:"Optional description body for the task"},{name:"server",help:"Override active server"}],columns:["id","taskNumber","title","taskStatus","channelId"],func:async(a,t)=>{const r=String(t.channel??"").trim();if(!r)throw new i("channel required");const s=String(t.title??"").trim();if(!s)throw new i("title required (non-empty)");const n=t.desc!=null?String(t.desc):"";await a.goto(w);const o=n?{title:s,description:n}:{title:s},c=`
|
|
2
|
+
${u({serverScoped:!0,serverIdOverride:t.server})}
|
|
3
|
+
${p(r)}
|
|
4
|
+
// Body is always a batch array — N=1 here because the CLI exposes one
|
|
5
|
+
// title at a time (R4 will widen this). Keep the wrapper so the server
|
|
6
|
+
// sees the same shape as a real batch and we don't fork the contract.
|
|
7
|
+
const body = { tasks: [${JSON.stringify(o)}] };
|
|
8
|
+
const res = await fetch('${b}/tasks/channel/' + encodeURIComponent(channelId), {
|
|
9
|
+
method:'POST', credentials:'include', headers, body: JSON.stringify(body),
|
|
10
|
+
});
|
|
11
|
+
if (res.status === 400) {
|
|
12
|
+
const j = await res.json().catch(() => ({}));
|
|
13
|
+
return { kind: 'http', status: 400, where: '/tasks/channel/:id (bad request: ' + (j.error || j.message || 'title/limit/shape') + ')' };
|
|
14
|
+
}
|
|
15
|
+
if (res.status === 403) return { kind: 'http', status: 403, where: '/tasks/channel/:id (forbidden — channel archived or not a member)' };
|
|
16
|
+
if (res.status === 404) return { kind: 'http', status: 404, where: '/tasks/channel/:id (channel not found)' };
|
|
17
|
+
if (res.status === 409) return { kind: 'http', status: 409, where: '/tasks/channel/:id (conflict — thread channels do not accept tasks; pick the parent channel)' };
|
|
18
|
+
if (!res.ok) return { kind: res.status===401?'auth':'http', status: res.status, where:'/tasks/channel/:id' };
|
|
19
|
+
const data = await res.json().catch(() => ({}));
|
|
20
|
+
if (!data || !Array.isArray(data.tasks)) {
|
|
21
|
+
return { kind: 'http', status: 200, where: '/tasks/channel/:id (expected {tasks:[]}, got drift)' };
|
|
22
|
+
}
|
|
23
|
+
return { kind: 'ok', rows: data.tasks };
|
|
24
|
+
`,d=await a.evaluate(`(async () => { ${c} })()`);return m(d).map((e)=>({id:e.id??"",taskNumber:e.taskNumber??null,title:e.content??e.title??s,taskStatus:e.taskStatus??"todo",channelId:e.channelId??null}))}});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import{cli as Q,Strategy as V}from"@jackwener/opencli/registry";import{ArgumentError as W}from"@jackwener/opencli/errors";import{authHeadersFragment as X}from"./in-page.js";import{dispatchEvaluateResult as Y}from"./errors.js";import{SLOCK_SITE as Z,SLOCK_DOMAIN as $,SLOCK_HOME_URL as x,SLOCK_API_BASE as B}from"./shared.js";import{assertMessageIdShape as D}from"./resolve.js";Q({site:Z,name:"task-delete",access:"write",description:"Delete a chat task (DELETE /tasks/:taskId). Requires --confirm — destructive, irreversible.",domain:$,strategy:V.COOKIE,browser:!0,siteSession:"persistent",args:[{name:"taskId",positional:!0,required:!0,help:"Full task UUID (= message id; short ids rejected)"},{name:"confirm",type:"bool",default:!1,help:"Required acknowledgement: deletion is irreversible"},{name:"server",help:"Override active server"}],columns:["taskId","deleted"],func:async(z,q)=>{let b;try{b=D(String(q.taskId??""))}catch(f){throw new W(f.message)}if(!q.confirm)return[{taskId:b,deleted:!1,note:"no-op: pass --confirm to actually delete (irreversible)"}];await z.goto(x);const G=`
|
|
2
|
+
${X({serverScoped:!0,serverIdOverride:q.server})}
|
|
3
|
+
const res = await fetch('${B}/tasks/' + encodeURIComponent(${JSON.stringify(b)}), { method:'DELETE', credentials:'include', headers });
|
|
4
|
+
if (res.status === 403) return { kind: 'http', status: 403, where: '/tasks/:taskId (forbidden — not the owner/admin or channel archived)' };
|
|
5
|
+
if (res.status === 404) return { kind: 'http', status: 404, where: '/tasks/:taskId (task not found)' };
|
|
6
|
+
if (!res.ok) return { kind: res.status===401?'auth':'http', status: res.status, where:'/tasks/:taskId' };
|
|
7
|
+
// 204 No Content is common for DELETE; tolerate empty body.
|
|
8
|
+
return { kind: 'ok', rows: [{ taskId: ${JSON.stringify(b)}, deleted: true }] };
|
|
9
|
+
`,J=await z.evaluate(`(async () => { ${G} })()`);return Y(J).map((f)=>({taskId:f.taskId??b,deleted:f.deleted??!0}))}});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import{cli as c,Strategy as m}from"@jackwener/opencli/registry";import{ArgumentError as i}from"@jackwener/opencli/errors";import{authHeadersFragment as d,channelResolveFragment as h}from"./in-page.js";import{dispatchEvaluateResult as l}from"./errors.js";import{SLOCK_SITE as k,SLOCK_DOMAIN as p,SLOCK_HOME_URL as b,SLOCK_API_BASE as g}from"./shared.js";import{parsePositiveInteger as S}from"./resolve.js";c({site:k,name:"task-get",access:"read",description:"Fetch a task by channel + taskNumber (GET /tasks/channel/:channelId/number/:taskNumber).",domain:p,strategy:m.COOKIE,browser:!0,siteSession:"persistent",args:[{name:"channel",positional:!0,required:!0,help:"channelId UUID or #name"},{name:"number",positional:!0,required:!0,help:'taskNumber (per-channel integer, as shown in "task #N")'},{name:"server",help:"Override active server"}],columns:["id","taskNumber","title","taskStatus","assigneeId"],func:async(r,t)=>{const s=String(t.channel??"").trim();if(!s)throw new i("channel required");const n=String(t.number??"").trim();if(!/^\d+$/.test(n))throw new i(`number "${n}" is not a positive integer`);const a=S(n,"number");await r.goto(b);const o=`
|
|
2
|
+
${d({serverScoped:!0,serverIdOverride:t.server})}
|
|
3
|
+
${h(s)}
|
|
4
|
+
const res = await fetch('${g}/tasks/channel/' + encodeURIComponent(channelId) + '/number/' + encodeURIComponent(${JSON.stringify(String(a))}), { credentials:'include', headers });
|
|
5
|
+
if (res.status === 404) return { kind: 'http', status: 404, where: '/tasks/channel/:id/number/:n (task #' + ${JSON.stringify(a)} + ' not found in channel)' };
|
|
6
|
+
if (!res.ok) return { kind: res.status===401?'auth':'http', status: res.status, where:'/tasks/channel/:id/number/:n' };
|
|
7
|
+
const data = await res.json().catch(() => ({}));
|
|
8
|
+
// Single object or {task: ...} wrapped — accept either.
|
|
9
|
+
const task = data && data.task ? data.task : data;
|
|
10
|
+
return { kind: 'ok', rows: [task] };
|
|
11
|
+
`,u=await r.evaluate(`(async () => { ${o} })()`);return l(u).map((e)=>({id:e.id??"",taskNumber:e.taskNumber??a,title:e.content??e.title??"",taskStatus:e.taskStatus??e.status??"",assigneeId:e.claimedById??e.assigneeId??null}))}});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import{cli as u,Strategy as c}from"@jackwener/opencli/registry";import{ArgumentError as d,CommandExecutionError as l}from"@jackwener/opencli/errors";import{authHeadersFragment as m}from"./in-page.js";import{dispatchEvaluateResult as h}from"./errors.js";import{SLOCK_SITE as p,SLOCK_DOMAIN as v,SLOCK_HOME_URL as k,SLOCK_API_BASE as f}from"./shared.js";const a=["todo","in_progress","in_review","done","closed"];u({site:p,name:"task-list-server",access:"read",description:"List tasks across all channels in the active server (GET /tasks/server). Optional --status filter.",domain:v,strategy:c.COOKIE,browser:!0,siteSession:"persistent",args:[{name:"status",help:`Filter by status: ${a.join("|")}`},{name:"server",help:"Override active server"}],columns:["id","taskNumber","title","taskStatus","channelId","assigneeId"],func:async(n,e)=>{const t=e.status?String(e.status).trim():"";if(t&&!a.includes(t))throw new d(`status "${t}" not in {${a.join("|")}}`);await n.goto(k);const i=`
|
|
2
|
+
${m({serverScoped:!0,serverIdOverride:e.server})}
|
|
3
|
+
const status = ${JSON.stringify(t)};
|
|
4
|
+
const qs = status ? ('?status=' + encodeURIComponent(status)) : '';
|
|
5
|
+
const res = await fetch('${f}/tasks/server' + qs, { credentials:'include', headers });
|
|
6
|
+
if (!res.ok) return { kind: res.status===401?'auth':'http', status: res.status, where: '/tasks/server' };
|
|
7
|
+
const data = await res.json();
|
|
8
|
+
if (!data || !Array.isArray(data.tasks)) {
|
|
9
|
+
return { kind: 'http', status: 200, where: '/tasks/server (expected {tasks:[]}, got drift)' };
|
|
10
|
+
}
|
|
11
|
+
return { kind: 'ok', rows: data.tasks };
|
|
12
|
+
`,o=await n.evaluate(`(async () => { ${i} })()`),r=h(o);if(!Array.isArray(r))throw new l(`expected array of rows from server, got ${typeof r} (contract drift?)`);return r.map((s)=>({id:s.id??"",taskNumber:s.taskNumber??null,title:s.content??s.title??"",taskStatus:s.taskStatus??s.status??"",channelId:s.channelId??null,assigneeId:s.claimedById??s.assigneeId??null}))}});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import{cli as u,Strategy as l}from"@jackwener/opencli/registry";import{ArgumentError as o,CommandExecutionError as h}from"@jackwener/opencli/errors";import{authHeadersFragment as m,channelResolveFragment as p}from"./in-page.js";import{dispatchEvaluateResult as k}from"./errors.js";import{SLOCK_SITE as f,SLOCK_DOMAIN as S,SLOCK_HOME_URL as v,SLOCK_API_BASE as w}from"./shared.js";const r=["todo","in_progress","in_review","done","closed"];u({site:f,name:"task-list",access:"read",description:"List tasks (chat tasks = messages with task fields) attached to a channel. Optional --status filter.",domain:S,strategy:l.COOKIE,browser:!0,siteSession:"persistent",args:[{name:"channel",positional:!0,required:!0,help:"channelId UUID or #name"},{name:"status",help:`Filter by status: ${r.join("|")}`},{name:"server",help:"Override active server"}],columns:["id","taskNumber","title","taskStatus","assigneeId"],func:async(n,s)=>{const i=String(s.channel??"").trim();if(!i)throw new o("channel required");const e=s.status?String(s.status).trim():"";if(e&&!r.includes(e))throw new o(`status "${e}" not in {${r.join("|")}}`);await n.goto(v);const d=`
|
|
2
|
+
${m({serverScoped:!0,serverIdOverride:s.server})}
|
|
3
|
+
${p(i)}
|
|
4
|
+
const status = ${JSON.stringify(e)};
|
|
5
|
+
const qs = status ? ('?status=' + encodeURIComponent(status)) : '';
|
|
6
|
+
const tres = await fetch('${w}/tasks/channel/' + encodeURIComponent(channelId) + qs, { credentials:'include', headers });
|
|
7
|
+
if (!tres.ok) return { kind: tres.status===401?'auth':'http', status: tres.status, where: '/tasks/channel/:id' };
|
|
8
|
+
const data = await tres.json();
|
|
9
|
+
// Server contract: { tasks: [...] }. Reject anything else as drift.
|
|
10
|
+
if (!data || !Array.isArray(data.tasks)) {
|
|
11
|
+
return { kind: 'http', status: 200, where: '/tasks/channel/:id (expected {tasks:[]}, got drift)' };
|
|
12
|
+
}
|
|
13
|
+
return { kind: 'ok', rows: data.tasks };
|
|
14
|
+
`,c=await n.evaluate(`(async () => { ${d} })()`),a=k(c);if(!Array.isArray(a))throw new h(`expected array of rows from server, got ${typeof a} (contract drift?)`);return a.map((t)=>({id:t.id??"",taskNumber:t.taskNumber??null,title:t.content??t.title??"",taskStatus:t.taskStatus??t.status??"",assigneeId:t.claimedById??t.assigneeId??null}))}});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import{cli as c,Strategy as l}from"@jackwener/opencli/registry";import{ArgumentError as d,CommandExecutionError as i}from"@jackwener/opencli/errors";import{authHeadersFragment as h}from"./in-page.js";import{dispatchEvaluateResult as m}from"./errors.js";import{SLOCK_SITE as f,SLOCK_DOMAIN as S,SLOCK_HOME_URL as p,SLOCK_API_BASE as w}from"./shared.js";import{assertMessageIdShape as I}from"./resolve.js";const o=["todo","in_progress","in_review","done","closed"];c({site:f,name:"task-status",access:"write",description:`Set a task's status (PATCH /tasks/:taskId/status, body {status}). One of ${o.join("|")}.`,domain:S,strategy:l.COOKIE,browser:!0,siteSession:"persistent",args:[{name:"taskId",positional:!0,required:!0,help:"Full task UUID (= message id; short ids rejected)"},{name:"status",positional:!0,required:!0,help:`One of: ${o.join("|")}`},{name:"server",help:"Override active server"}],columns:["taskId","taskStatus","assigneeId","taskNumber"],func:async(e,s)=>{let a;try{a=I(String(s.taskId??""))}catch(n){throw new d(n.message)}const t=String(s.status??"").trim();if(!o.includes(t))throw new d(`status "${t}" not in {${o.join("|")}} — pre-network reject (saves a 400 round-trip).`);await e.goto(p);const r=`
|
|
2
|
+
${h({serverScoped:!0,serverIdOverride:s.server})}
|
|
3
|
+
const res = await fetch('${w}/tasks/' + encodeURIComponent(${JSON.stringify(a)}) + '/status', {
|
|
4
|
+
method:'PATCH', credentials:'include', headers,
|
|
5
|
+
body: JSON.stringify({ status: ${JSON.stringify(t)} }),
|
|
6
|
+
});
|
|
7
|
+
if (res.status === 400) {
|
|
8
|
+
const j = await res.json().catch(() => ({}));
|
|
9
|
+
return { kind: 'http', status: 400, where: '/tasks/:taskId/status (bad request: ' + (j.error || j.message || 'invalid status transition') + ')' };
|
|
10
|
+
}
|
|
11
|
+
if (res.status === 403) return { kind: 'http', status: 403, where: '/tasks/:taskId/status (forbidden — terminal status (done/closed), not the assignee, or channel archived)' };
|
|
12
|
+
if (res.status === 404) return { kind: 'http', status: 404, where: '/tasks/:taskId/status (task not found)' };
|
|
13
|
+
// F6 — actionable hint for repeat-set 409 ("status already X").
|
|
14
|
+
if (res.status === 409) return { kind: 'http', status: 409, where: '/tasks/:taskId/status (conflict — task is already in status ' + ${JSON.stringify(t)} + '; no-op set rejected)' };
|
|
15
|
+
if (!res.ok) return { kind: res.status===401?'auth':'http', status: res.status, where:'/tasks/:taskId/status' };
|
|
16
|
+
const data = await res.json().catch(() => ({}));
|
|
17
|
+
const t = (data && data.task) ? data.task : data;
|
|
18
|
+
return { kind: 'ok', rows: [t] };
|
|
19
|
+
`,k=await e.evaluate(`(async () => { ${r} })()`);return m(k).map((n)=>{const u=g(n,a,t);return{taskId:u.taskId,taskStatus:u.taskStatus,assigneeId:n.claimedById??n.assigneeId??null,taskNumber:n.taskNumber??null}})}});function g(e,s,a){const t=e?.id;if(!t)throw new i(`Slock task-status succeeded without returning task id ${s}; refusing to report a status row.`);if(t!==s)throw new i(`Slock task-status returned task id ${t}, expected ${s}.`);const r=e.taskStatus??e.status;if(!r)throw new i(`Slock task-status returned task ${s} without taskStatus.`);if(r!==a)throw new i(`Slock task-status returned status ${r}, expected ${a}.`);return{taskId:t,taskStatus:r}}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import{cli as o,Strategy as u}from"@jackwener/opencli/registry";import{ArgumentError as d,CommandExecutionError as n}from"@jackwener/opencli/errors";import{authHeadersFragment as c}from"./in-page.js";import{dispatchEvaluateResult as l}from"./errors.js";import{SLOCK_SITE as m,SLOCK_DOMAIN as k,SLOCK_HOME_URL as h,SLOCK_API_BASE as p}from"./shared.js";import{assertMessageIdShape as f}from"./resolve.js";o({site:m,name:"task-unclaim",access:"write",description:"Release ownership of a chat task (PATCH /tasks/:id/unclaim).",domain:k,strategy:u.COOKIE,browser:!0,siteSession:"persistent",args:[{name:"taskId",positional:!0,required:!0,help:"Full task UUID (= message id; short ids rejected)"},{name:"server",help:"Override active server"}],columns:["taskId","taskStatus","assigneeId","taskNumber"],func:async(r,s)=>{let e;try{e=f(String(s.taskId??""))}catch(t){throw new d(t.message)}await r.goto(h);const a=`
|
|
2
|
+
${c({serverScoped:!0,serverIdOverride:s.server})}
|
|
3
|
+
const res = await fetch('${p}/tasks/' + encodeURIComponent(${JSON.stringify(e)}) + '/unclaim', { method:'PATCH', credentials:'include', headers });
|
|
4
|
+
if (res.status === 404) return { kind: 'http', status: 404, where: '/tasks/:id/unclaim (task not found)' };
|
|
5
|
+
if (res.status === 403) return { kind: 'http', status: 403, where: '/tasks/:id/unclaim (forbidden — not the assignee, terminal status, or channel archived)' };
|
|
6
|
+
// F6 — actionable hint for the most common reason this 409s (task already
|
|
7
|
+
// unclaimed, or terminal state). Bare "HTTP 409" was confusing.
|
|
8
|
+
if (res.status === 409) return { kind: 'http', status: 409, where: '/tasks/:id/unclaim (conflict — task is not claimed, or already in a terminal state (done/closed))' };
|
|
9
|
+
if (!res.ok) return { kind: res.status===401?'auth':'http', status: res.status, where:'/tasks/:id/unclaim' };
|
|
10
|
+
const data = await res.json().catch(() => ({}));
|
|
11
|
+
const t = (data && data.task) ? data.task : data;
|
|
12
|
+
return { kind: 'ok', rows: [t] };
|
|
13
|
+
`,i=await r.evaluate(`(async () => { ${a} })()`);return l(i).map((t)=>({taskId:w(t,e,"task-unclaim"),taskStatus:t.taskStatus??t.status??"",assigneeId:t.claimedById??t.assigneeId??null,taskNumber:t.taskNumber??null}))}});function w(r,s,e){const a=r?.id;if(!a)throw new n(`Slock ${e} succeeded without returning task id ${s}; refusing to report a task row.`);if(a!==s)throw new n(`Slock ${e} returned task id ${a}, expected ${s}.`);return a}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{makeThreadStateCommand as e}from"./thread-state.js";e({name:"thread-done",verb:"done",resultLabel:"done",description:"Mark a thread as done / hide it from the active list (POST /channels/threads/done)"});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{cli as W,Strategy as X}from"@jackwener/opencli/registry";import{ArgumentError as Y,CommandExecutionError as Z}from"@jackwener/opencli/errors";import{buildFetchSnippet as $}from"./in-page.js";import{dispatchEvaluateResult as b}from"./errors.js";import{SLOCK_SITE as f,SLOCK_DOMAIN as x,SLOCK_HOME_URL as D}from"./shared.js";import{assertMessageIdShape as F}from"./resolve.js";W({site:f,name:"thread-follow",access:"write",description:"Follow the thread on a parent message (POST /channels/threads/follow)",domain:x,strategy:X.COOKIE,browser:!0,siteSession:"persistent",args:[{name:"parentMessageId",positional:!0,required:!0,help:"Full parent messageId UUID (short ids rejected)"},{name:"server",help:"Override active server"}],columns:["parentMessageId","threadChannelId","result"],func:async(B,G)=>{let q;try{q=F(String(G.parentMessageId??""))}catch(V){throw new Y(V.message)}await B.goto(D);const P=$({method:"POST",path:"/channels/threads/follow",body:{parentMessageId:q},serverScoped:!0,serverIdOverride:G.server}),Q=await B.evaluate(`(async () => { ${P} })()`),z=b(Q),J=z?.threadChannelId??z?.channelId??z?.id;if(!J)throw new Z(`Slock thread-follow succeeded without returning a thread channel id for parent message ${q}.`);return[{parentMessageId:q,threadChannelId:J,result:"followed"}]}});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{cli as d,Strategy as l}from"@jackwener/opencli/registry";import{CommandExecutionError as i}from"@jackwener/opencli/errors";import{buildFetchSnippet as p}from"./in-page.js";import{dispatchEvaluateResult as u}from"./errors.js";import{SLOCK_SITE as h,SLOCK_DOMAIN as c,SLOCK_HOME_URL as m}from"./shared.js";d({site:h,name:"thread-list",access:"read",description:"List followed threads in the active server (GET /channels/threads/followed)",domain:c,strategy:l.COOKIE,browser:!0,siteSession:"persistent",args:[{name:"server",help:"Override active server"}],columns:["threadChannelId","parentMessageId","parentChannelName","unreadCount","replyCount","lastReplyAt"],func:async(a,n)=>{await a.goto(m);const s=p({method:"GET",path:"/channels/threads/followed",serverScoped:!0,serverIdOverride:n.server}),o=await a.evaluate(`(async () => { ${s} })()`),r=u(o),t=Array.isArray(r)?r:r.threads||[];if(!Array.isArray(t))throw new i(`expected threads array, got ${typeof t} (contract drift?)`);return t.map((e)=>({threadChannelId:e.threadChannelId??e.id??"",parentMessageId:e.parentMessageId??"",parentChannelName:e.parentChannelName??"",unreadCount:typeof e.unreadCount==="number"?e.unreadCount:0,replyCount:typeof e.replyCount==="number"?e.replyCount:null,lastReplyAt:e.lastReplyAt??null}))}});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{cli as W,Strategy as X}from"@jackwener/opencli/registry";import{ArgumentError as Y}from"@jackwener/opencli/errors";import{buildFetchSnippet as Z}from"./in-page.js";import{dispatchEvaluateResult as $}from"./errors.js";import{SLOCK_SITE as F,SLOCK_DOMAIN as H,SLOCK_HOME_URL as N}from"./shared.js";import{UUID_RE as T}from"./resolve.js";export function makeThreadStateCommand({name:B,verb:G,resultLabel:J,description:P}){W({site:F,name:B,access:"write",description:P,domain:H,strategy:X.COOKIE,browser:!0,siteSession:"persistent",args:[{name:"threadChannelId",positional:!0,required:!0,help:"Thread channel UUID (from thread-list / message-read)"},{name:"server",help:"Override active server"}],columns:["threadChannelId","result"],func:async(x,z)=>{const q=String(z.threadChannelId??"").trim();if(!T.test(q))throw new Y(`threadChannelId must be a full UUID (got "${q}"). Get it from thread-list or message-read's threadChannelId column.`);await x.goto(N);const Q=Z({method:"POST",path:`/channels/threads/${G}`,body:{threadChannelId:q},serverScoped:!0,serverIdOverride:z.server}),V=await x.evaluate(`(async () => { ${Q} })()`);$(V);return[{threadChannelId:q,result:J}]}})}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{makeThreadStateCommand as e}from"./thread-state.js";e({name:"thread-undone",verb:"undone",resultLabel:"undone",description:"Restore a done thread to the active list (POST /channels/threads/undone)"});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{makeThreadStateCommand as o}from"./thread-state.js";o({name:"thread-unfollow",verb:"unfollow",resultLabel:"unfollowed",description:"Stop following a thread (POST /channels/threads/unfollow)"});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import{cli as X,Strategy as Y}from"@jackwener/opencli/registry";import{CommandExecutionError as Z}from"@jackwener/opencli/errors";import{authHeadersFragment as $}from"./in-page.js";import{dispatchEvaluateResult as b}from"./errors.js";import{SLOCK_SITE as f,SLOCK_DOMAIN as q,SLOCK_HOME_URL as x,SLOCK_API_BASE as Q}from"./shared.js";X({site:f,name:"unread-summary",access:"read",description:"Global unread counts across every server you belong to.",domain:q,strategy:Y.COOKIE,browser:!0,siteSession:"persistent",args:[],columns:["serverId","slug","name","unreadCount"],func:async(J)=>{await J.goto(x);const V=`
|
|
2
|
+
${$({serverScoped:!1})}
|
|
3
|
+
const sres = await fetch('${Q}/servers/', { credentials:'include', headers });
|
|
4
|
+
if (sres.status === 401) return { kind: 'auth', detail: '/servers/ returned 401' };
|
|
5
|
+
if (!sres.ok) return { kind: 'http', status: sres.status, where:'/servers/' };
|
|
6
|
+
const servers = await sres.json();
|
|
7
|
+
const ures = await fetch('${Q}/servers/unread-summary', { credentials:'include', headers });
|
|
8
|
+
if (ures.status === 401) return { kind: 'auth', detail: '/servers/unread-summary returned 401' };
|
|
9
|
+
if (!ures.ok) return { kind: 'http', status: ures.status, where:'/servers/unread-summary' };
|
|
10
|
+
const summary = await ures.json();
|
|
11
|
+
const byId = {};
|
|
12
|
+
(Array.isArray(servers) ? servers : []).forEach((s) => { if (s && s.id) byId[s.id] = s; });
|
|
13
|
+
const rows = (Array.isArray(summary) ? summary : []).map((u) => {
|
|
14
|
+
const s = byId[u.serverId] || {};
|
|
15
|
+
return { serverId: u.serverId, slug: s.slug || '', name: s.name || '', unreadCount: u.unreadCount || 0 };
|
|
16
|
+
});
|
|
17
|
+
return { kind: 'ok', rows };
|
|
18
|
+
`,W=await J.evaluate(`(async () => { ${V} })()`),z=b(W);if(!Array.isArray(z))throw new Z(`expected array of summary rows, got ${typeof z} (contract drift?)`);return z}});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{registerSiteAuthCommands as e}from"../_shared/site-auth.js";import{SLOCK_SITE as o,SLOCK_DOMAIN as r,SLOCK_HOME_URL as m}from"./shared.js";import{verifySlockSession as s}from"./auth-verify.js";e({site:o,domain:r,loginUrl:m,verify:(i)=>s(i),columns:["id","name","email"]});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import{cli as O,Strategy as P}from"@jackwener/opencli/registry";import{ArgumentError as D,CommandExecutionError as Q}from"@jackwener/opencli/errors";function F(f){if(f&&!Array.isArray(f)&&typeof f==="object"&&"session"in f&&"data"in f)return f.data;return f}function G(f){const B=F(f);if(!Array.isArray(B))throw new Q("Unexpected SMZDM search extraction payload shape; expected an array of rows.");return B}function H(f){let B;if(f==null)B=20;else if(typeof f==="number")B=f;else if(typeof f==="string"&&/^[0-9]+$/.test(f))B=Number(f);else B=NaN;if(!Number.isFinite(B)||!Number.isInteger(B))throw new D(`--limit must be an integer between 1 and 100, got ${JSON.stringify(f)}`);if(B<1||B>100)throw new D(`--limit must be between 1 and 100, got ${B}`);return B}function I(f){return`
|
|
2
|
+
(() => {
|
|
3
|
+
const limit = ${f};
|
|
4
|
+
const items = document.querySelectorAll('li.feed-row-wide');
|
|
5
|
+
const results = [];
|
|
6
|
+
const normalizeCount = (text) => {
|
|
7
|
+
const raw = (text || '').replace(/,/g, '').trim();
|
|
8
|
+
const match = raw.match(/(\\d+(?:\\.\\d+)?)\\s*([万kK]?)/);
|
|
9
|
+
if (!match) return 0;
|
|
10
|
+
const base = Number(match[1]);
|
|
11
|
+
if (!Number.isFinite(base)) return 0;
|
|
12
|
+
const unit = match[2];
|
|
13
|
+
if (unit === '万') return Math.round(base * 10000);
|
|
14
|
+
if (unit === 'k' || unit === 'K') return Math.round(base * 1000);
|
|
15
|
+
return Math.round(base);
|
|
16
|
+
};
|
|
17
|
+
const intFrom = (el) => {
|
|
18
|
+
if (!el) return 0;
|
|
19
|
+
return normalizeCount(el.textContent || '');
|
|
20
|
+
};
|
|
21
|
+
const trustedSmzdmUrl = (raw) => {
|
|
22
|
+
const text = (raw || '').trim();
|
|
23
|
+
if (!text) return '';
|
|
24
|
+
let url;
|
|
25
|
+
try {
|
|
26
|
+
url = text.startsWith('/')
|
|
27
|
+
? new URL(text, 'https://www.smzdm.com')
|
|
28
|
+
: new URL(text, location.href);
|
|
29
|
+
} catch {
|
|
30
|
+
return '';
|
|
31
|
+
}
|
|
32
|
+
const hostname = url.hostname.toLowerCase();
|
|
33
|
+
if (url.protocol !== 'https:' || (hostname !== 'www.smzdm.com' && hostname !== 'post.smzdm.com')) {
|
|
34
|
+
return '';
|
|
35
|
+
}
|
|
36
|
+
return url.toString();
|
|
37
|
+
};
|
|
38
|
+
items.forEach((li) => {
|
|
39
|
+
if (results.length >= limit) return;
|
|
40
|
+
const titleEl = li.querySelector('h5.feed-block-title > a')
|
|
41
|
+
|| li.querySelector('h5 > a');
|
|
42
|
+
if (!titleEl) return;
|
|
43
|
+
const title = (titleEl.getAttribute('title') || titleEl.textContent || '').trim();
|
|
44
|
+
const url = trustedSmzdmUrl(titleEl.getAttribute('href') || titleEl.href || '');
|
|
45
|
+
if (!title || !url) return;
|
|
46
|
+
const priceEl = li.querySelector('.z-highlight');
|
|
47
|
+
const price = priceEl ? priceEl.textContent.trim() : '';
|
|
48
|
+
let mall = '';
|
|
49
|
+
const mallEl = li.querySelector('.z-feed-foot-r .feed-block-extras span')
|
|
50
|
+
|| li.querySelector('.z-feed-foot-r span');
|
|
51
|
+
if (mallEl) mall = mallEl.textContent.trim();
|
|
52
|
+
// Update time lives as the direct text node(s) of .feed-block-extras,
|
|
53
|
+
// alongside the nested mall <span> which we exclude here.
|
|
54
|
+
let updated_at = '';
|
|
55
|
+
const extrasEl = li.querySelector('.z-feed-foot-r .feed-block-extras');
|
|
56
|
+
if (extrasEl) {
|
|
57
|
+
updated_at = Array.from(extrasEl.childNodes)
|
|
58
|
+
.filter((node) => node.nodeType === 3)
|
|
59
|
+
.map((node) => (node.textContent || '').trim())
|
|
60
|
+
.filter(Boolean)
|
|
61
|
+
.join(' ');
|
|
62
|
+
}
|
|
63
|
+
const zhi_count = intFrom(li.querySelector('.price-btn-up .unvoted-wrap span'));
|
|
64
|
+
const buzhi_count = intFrom(li.querySelector('.price-btn-down .unvoted-wrap span'));
|
|
65
|
+
const favorite_count = intFrom(li.querySelector('.feed-btn-fav span'));
|
|
66
|
+
const comments = intFrom(li.querySelector('.feed-btn-comment'));
|
|
67
|
+
results.push({ rank: results.length + 1, title, price, mall, updated_at, zhi_count, buzhi_count, favorite_count, comments, url });
|
|
68
|
+
});
|
|
69
|
+
return results;
|
|
70
|
+
})()
|
|
71
|
+
`}export const smzdmSearchCommand=O({site:"smzdm",name:"search",access:"read",description:"什么值得买搜索好价",domain:"www.smzdm.com",strategy:P.COOKIE,args:[{name:"query",required:!0,positional:!0,help:"Search keyword"},{name:"limit",type:"int",default:20,help:"Number of results"}],columns:["rank","title","price","mall","updated_at","zhi_count","buzhi_count","favorite_count","comments","url"],func:async(f,B)=>{const K=encodeURIComponent(B.query),M=H(B.limit);await f.goto(`https://search.smzdm.com/?c=home&s=${K}&v=b`);return G(await f.evaluate(I(M)))}}),__test__={buildSmzdmSearchJs:I,parseLimit:H,requireSearchRows:G,unwrapEvaluateResult:F};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{CliError as $,CommandExecutionError as v}from"@jackwener/opencli/errors";import{cli as N,Strategy as b}from"@jackwener/opencli/registry";import{publishArticle as f,gotoWritePage as P}from"../_shared/article/publish.js";import{SOHU_MPBP_HEADERS_JS as R}from"./mpbp.js";function k(){const Q="0123456789abcdef";let K="";for(let z=0;z<32;z++)K+=Q[Math.floor(Math.random()*Q.length)];return K}export const sohuProfile={home:"https://mp.sohu.com/mpfe/v3/main/first/page?newsType=1",outputFormat:"html",preprocessConfig:{},checkAuth:async(Q)=>{try{const z=await(await fetch("https://mp.sohu.com/mpbp/bp/account/list?_="+Date.now(),{method:"GET",credentials:"include"})).json();if(z.code!==2000000||!z.data?.data?.length)return{isAuthenticated:!1};const L=[];for(const V of z.data.data)if(V.accounts)L.push(...V.accounts);if(!L.length)return{isAuthenticated:!1};const G=L[0],X=L.length>1?G.nickName+"(共"+L.length+"个子账号)":G.nickName;return{isAuthenticated:!0,userId:String(G.id),username:X,avatar:G.avatar||""}}catch(K){return{isAuthenticated:!1,error:String(K&&K.message||K)}}},image:{skip:["sohu.com"],uploadFn:async(Q,K)=>{const L=await(await fetch("https://mp.sohu.com/mpbp/bp/account/list?_="+Date.now(),{method:"GET",credentials:"include"})).json();if(L.code!==2000000||!L.data?.data?.length)throw Error("获取搜狐账号信息失败,请确认已登录搜狐号");const G=[];for(const H of L.data.data)if(H.accounts)G.push(...H.accounts);if(!G.length)throw Error("搜狐号子账号列表为空");const X=String(G[0].id),V=await fetch(Q,{credentials:"omit"});if(!V.ok)throw Error("图片下载失败("+V.status+"):"+Q);const Y=await V.blob(),M=new FormData;M.append("file",Y,"image.jpg");M.append("accountId",X);const W=await(await fetch("https://mp.sohu.com/commons/front/outerUpload/image/file?accountId="+X,{method:"POST",credentials:"include",body:M})).json();if(!W.url)throw Error("搜狐图片上传失败:"+(W.msg||JSON.stringify(W).slice(0,100)));return{url:W.url}}},publish:async(Q,K)=>{const z=Q.params||{},L=await fetch("https://mp.sohu.com/mpbp/bp/account/list?_="+Date.now(),{method:"GET",credentials:"include"}),G=await L.json();if(G.code!==2000000||!G.data?.data?.length)return{ok:!1,stage:"auth",status:L.status,message:"获取搜狐账号信息失败,请确认已登录搜狐号"};const X=[];for(const F of G.data.data)if(F.accounts)X.push(...F.accounts);if(!X.length)return{ok:!1,stage:"auth",status:0,message:"搜狐号子账号列表为空"};const V=Number(X[0].id),Y="0123456789abcdef";let M="";for(let F=0;F<32;F++)M+=Y[Math.floor(Math.random()*Y.length)];const B="100-"+Date.now()+"-"+M,W=Number(z.channelId);if(!Number.isFinite(W)||W<=0)return{ok:!1,stage:"params",status:0,message:"缺少合法 channelId(频道 id),请先用 `sohu channels` 取值"};const H=z.categoryId==null||z.categoryId===""?-1:Number(z.categoryId),_={title:Q.title,brief:typeof z.brief==="string"?z.brief:"",content:Q.content,channelId:W,categoryId:H,id:0,userColumnId:z.userColumnId==null||z.userColumnId==-1?0:Number(z.userColumnId),columnNewsIds:Array.isArray(z.columnNewsIds)?z.columnNewsIds:[],businessCode:0,declareOriginal:Boolean(z.declareOriginal),cover:typeof z.cover==="string"?z.cover:"",topicIds:Array.isArray(z.topicIds)?z.topicIds:[],isAd:0,userLabels:"[]",reprint:!1,customTags:typeof z.customTags==="string"?z.customTags:"",infoResource:0,sourceUrl:"",visibleToLoginedUsers:0,attrIds:Array.isArray(z.attrIds)?z.attrIds:[],accountId:V};if(Q.draftOnly){const F=Object.assign({},_,{auto:!0}),q=await fetch("https://mp.sohu.com/mpbp/bp/news/v4/news/draft/v2?accountId="+V,{method:"POST",credentials:"include",headers:{"Content-Type":"application/json","X-Requested-With":"XMLHttpRequest","dv-id":M,"sp-cm":B},body:JSON.stringify(F)}),x=await q.text();let D=null;try{D=JSON.parse(x)}catch(i){}if(!q.ok||!D||!D.success)return{ok:!1,stage:"draft",status:q.status,message:D&&D.msg||x.slice(0,300)};const A=String(D.data),E="https://mp.sohu.com/mpfe/v4/contentManagement/news/addarticle?spm=smmp.articlelist.0.0&contentStatus=2&id="+A;return{ok:!0,id:A,url:E,draft:!0}}const U=await fetch("https://mp.sohu.com/mpbp/bp/news/v4/news/publish/v2?accountId="+V,{method:"POST",credentials:"include",headers:{"Content-Type":"application/json","X-Requested-With":"XMLHttpRequest","dv-id":M,"sp-cm":B},body:JSON.stringify(_)}),S=await U.text();let Z=null;try{Z=JSON.parse(S)}catch(F){}if(!U.ok||!Z||Z.code!==2000000){let F=Z&&(Z.msg||Z.message)||"";if(!F){const q=[];if(H!==-1)q.push("--category");if(Array.isArray(z.topicIds)&&z.topicIds.length>0)q.push("--topics");if(_.cover)q.push("--cover");F="搜狐发布接口返回非 JSON 错误页(HTTP "+U.status+")。"+(q.length?"实测该 500 多由可选参数触发——去掉 "+q.join(" / ")+"、只保留必填 --channel 重试即可。":"稍后重试;若持续失败,用 `sohu stats` 确认是否已产生重复内容。")}return{ok:!1,stage:"publish",status:U.status,message:F}}if(Z.data!=null&&Object.prototype.toString.call(Z.data)==="[object Object]")return{ok:!1,stage:"origin_check",status:U.status,message:"声明原创触发了原创校验(需在搜狐后台完成原创确认):"+JSON.stringify(Z.data).slice(0,200)};const J=String(Z.data),T="https://mp.sohu.com/mpfe/v4/contentManagement/news/addarticle?spm=smmp.articlelist.0.0&contentStatus=1&id="+J;return{ok:!0,id:J,url:T,draft:!1}}},sohuAuthProfile={home:sohuProfile.home,checkAuth:sohuProfile.checkAuth};function y(Q){if(!Q.execute)throw new $("INVALID_INPUT","此命令需要 --execute 才会真正写入。注意:本报错仅表示缺少 --execute,并未校验其余参数,不能当 dry-run 预览用")}async function j(Q){const K=typeof Q.text==="string"?Q.text:void 0,z=typeof Q.file==="string"?Q.file:void 0;if(K&&z)throw new $("INVALID_INPUT","text 和 --file 只能二选一");let L=K??"";if(z){const{readFile:G,stat:X}=await import("node:fs/promises");let V;try{V=await X(z)}catch{throw new $("INVALID_INPUT","文件不存在:"+z)}if(!V.isFile())throw new $("INVALID_INPUT","路径不是可读文本文件:"+z);let Y;try{Y=await G(z)}catch{throw new $("INVALID_INPUT","文件读取失败:"+z)}try{L=new TextDecoder("utf-8",{fatal:!0}).decode(Y)}catch{throw new $("INVALID_INPUT","文件不是合法 UTF-8 编码:"+z)}}if(!L.trim())throw new $("INVALID_INPUT","正文不能为空");return L}function C(Q,K,z,L,G={}){return[{status:"success",outcome:L,message:Q,target_type:K,target:z,...G}]}async function O(Q,K,z){const L="(async () => {try {"+R+"const r = await fetch("+JSON.stringify(K)+', { method: "GET", credentials: "include", headers: HDRS });const t = await r.text();let j = null; try { j = JSON.parse(t); } catch (e) {}return { ok: r.ok, status: r.status, json: j, text: t.slice(0, 300) };} catch (e) { return { ok: false, status: 0, json: null, text: String((e && e.message) || e) }; }})()',G=await Q.evaluate(L);if(!G||!G.ok||!G.json)throw new $("INVALID_INPUT","搜狐"+z+"接口请求失败(HTTP "+(G?G.status:"?")+"):"+(G?G.text:""));if(G.json.success===!1||G.json.code!=null&&G.json.code!==2000000&&G.json.code!==2000)throw new $("INVALID_INPUT","搜狐"+z+"接口返回错误:"+(G.json.msg||G.json.message||"未登录或无权限"));return G.json}async function m(Q){const K=await O(Q,"https://mp.sohu.com/mpbp/bp/account/list?_="+Date.now(),"账号列表"),z=K.data&&K.data.data||[],L=[];for(const G of z)if(G.accounts)L.push(...G.accounts);if(!L.length)throw new $("INVALID_INPUT","搜狐号子账号列表为空,请确认已登录搜狐号");return String(L[0].id)}async function I(Q,K,z){const L=await O(Q,"https://mp.sohu.com/mpbp/bp/account/common/channels-data-api?status=1&accountId="+encodeURIComponent(K),"频道列举"),G=Array.isArray(L)?L:L.data||[],X=G.find((V)=>String(V.name)===String(z));if(!X)throw new $("INVALID_INPUT","未找到频道「"+z+"」,可选:"+(G.map((V)=>V.name).join(" / ")||"(空)")+"。用 `sohu channels` 查看完整列表。");return Number(X.id!=null?X.id:X.channelId)}async function h(Q,K,z,L){const G=await O(Q,"https://mp.sohu.com/mpbp/bp/account/common/channels/"+z+"/categories?accountId="+encodeURIComponent(K),"分类列举"),X=Array.isArray(G)?G:G.data||[],V=X.find((Y)=>String(Y.name)===String(L));if(!V)throw new $("INVALID_INPUT","频道(id="+z+")下未找到分类「"+L+"」,可选:"+(X.map((Y)=>Y.name).join(" / ")||"(该频道无分类)")+"。用 `sohu categories --channel <频道名>` 查看。");return Number(V.id)}async function w(Q,K,z){const L=await O(Q,"https://mp.sohu.com/mpbp/bp/account/column/v2/list?accountId="+encodeURIComponent(K)+"&page=1&size=100","专栏列举"),G=Array.isArray(L)?L:L.data&&(L.data.data||L.data)||L.data||[],X=Array.isArray(G)?G:[],V=X.find((Y)=>String(Y.name)===String(z));if(!V)throw new $("INVALID_INPUT","未找到专栏「"+z+"」,可选:"+(X.map((Y)=>Y.name).join(" / ")||"(你还没有任何专栏)")+"。用 `sohu columns` 查看。");return Number(V.id)}async function d(Q,K,z){const L=z.split(",").map((X)=>X.trim()).filter(Boolean);if(!L.length)return[];const G=[];for(const X of L){const V=await O(Q,"https://mp.sohu.com/mpbp/bp/news/v4/label/topic/search?accountId="+K+"&keyword="+encodeURIComponent(X),"话题搜索"),M=(Array.isArray(V)?V:V.data||[]).find((B)=>String(B.name)===String(X));if(!M)throw new $("INVALID_INPUT","未找到话题「"+X+"」,请用 `sohu topics --keyword "+X+"` 搜索确认确切名称。");G.push(M.id)}return G}N({site:"sohu",name:"article",access:"write",description:"发布文章到搜狐号(HTML 格式,外链图片自动转存到搜狐图床)。默认正式发布,加 --draft 仅存草稿。频道必填,合法值用 `sohu channels` 取。",domain:"mp.sohu.com",strategy:b.COOKIE,browser:!0,args:[{name:"title",positional:!0,required:!0,help:"文章标题"},{name:"text",positional:!0,help:"文章正文(默认 Markdown,传 --html 则视为 HTML)"},{name:"file",help:"正文文件路径(UTF-8,Markdown 或 HTML)"},{name:"html",type:"boolean",help:"将正文视为原始 HTML 而非 Markdown"},{name:"channel",help:"频道名(精确匹配,必填),合法值用 `sohu channels` 列举"},{name:"category",help:"分类名(精确匹配,依赖所选频道),合法值用 `sohu categories --channel <频道名>` 列举;不传=不限"},{name:"column",help:"专栏名(精确匹配),合法值用 `sohu columns` 列举;不传=不归属专栏"},{name:"topics",help:"话题名,逗号分隔(每个精确匹配),用 `sohu topics` 搜索取确切名"},{name:"cover",help:"封面图 URL(须为搜狐图床地址);可空"},{name:"brief",help:"文章摘要;可空"},{name:"declare-original",type:"boolean",help:"声明原创(会触发搜狐原创校验,发布将被拦到原创确认流程)"},{name:"draft",type:"boolean",help:"仅保存草稿,不正式发布"},{name:"execute",type:"boolean",help:"实际执行写入操作;不加此参数则拒绝写入(干跑保护)"}],columns:["status","outcome","message","target_type","target","created_target","created_url"],func:async(Q,K)=>{if(!Q)throw new v("搜狐号文章发布需要浏览器会话");y(K);const z=String(K.title??"").trim();if(!z)throw new $("INVALID_INPUT","文章标题不能为空");const L=await j(K),G=Boolean(K.draft),X=typeof K.channel==="string"?K.channel.trim():"";if(!X)throw new $("INVALID_INPUT","缺少 --channel(频道名)。请先运行 `sohu channels` 取合法频道名再传入,不提供默认值。");await P(Q,sohuProfile.home);const V=await m(Q),Y=await I(Q,V,X);let M=-1;const B=typeof K.category==="string"?K.category.trim():"";if(B)M=await h(Q,V,Y,B);let W=0;const H=typeof K.column==="string"?K.column.trim():"";if(H)W=await w(Q,V,H);let _=[];const U=typeof K.topics==="string"?K.topics.trim():"";if(U)_=await d(Q,V,U);const S={channelId:Y,categoryId:M,userColumnId:W,topicIds:_,cover:typeof K.cover==="string"?K.cover.trim():"",brief:typeof K.brief==="string"?K.brief:"",declareOriginal:Boolean(K["declare-original"])},Z=await f(Q,{title:z,body:L,format:K.html?"html":"markdown",draftOnly:G,profile:sohuProfile,publishParams:S}),J=Z.images.uploaded.length|0,T=Z.images.failed.length|0;let F=Z.draft?"已保存搜狐号草稿":"已正式发布到搜狐号";if(J||T)F+=`;图片:${J} 张已转存${T?`,${T} 张失败`:""}`;return C(F,"article","",Z.draft?"draft":"created",{created_target:(Z.draft?"draft:":"article:")+Z.id,created_url:Z.url})}});export const __test__={sohuProfile,requireExecute:y,buildResultRow:C,resolvePayload:j,generateDeviceId:k};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{cli as z,Strategy as A}from"@jackwener/opencli/registry";import{CommandExecutionError as B}from"@jackwener/opencli/errors";import{gotoWritePage as D}from"../_shared/article/publish.js";import{sohuProfile as F}from"./article.js";z({site:"sohu",name:"attributes",access:"read",description:"列出搜狐号文章属性候选(id + 名称),供发布时选择文章属性。",domain:"mp.sohu.com",strategy:A.COOKIE,browser:!0,columns:["attr_id","attr_name"],func:async(q)=>{if(!q)throw new B("搜狐号文章属性列举需要浏览器会话");await D(q,F.home);const v=await q.evaluate("(async () => {const r = await fetch('https://mp.sohu.com/mpbp/bp/news/v4/news/attribute', { method: 'GET', credentials: 'include' });const j = await r.json();"+"if (!j || j.success === false) throw new Error('文章属性列举失败:' + ((j && j.msg) || '未登录或无权限'));"+"const raw = (j && j.data) || [];const list = Array.isArray(raw) ? raw : (Array.isArray(raw.data) ? raw.data : []);return list.map(a => ({ attr_id: String(a.id), attr_name: a.name || a.attrName || '' }));})()");return Array.isArray(v)?v:[]}});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{cli as G,Strategy as K}from"@jackwener/opencli/registry";import{CliError as L,CommandExecutionError as Q}from"@jackwener/opencli/errors";import{gotoWritePage as T}from"../_shared/article/publish.js";import{sohuProfile as V}from"./article.js";import{SOHU_MPBP_HEADERS_JS as X}from"./mpbp.js";G({site:"sohu",name:"categories",access:"read",description:"列出某个搜狐号频道下的分类(id + 名称),供 `sohu article --category` 取合法分类名。须用 --channel 指定频道名。",domain:"mp.sohu.com",strategy:K.COOKIE,browser:!0,args:[{name:"channel",required:!0,help:"频道名(精确匹配),合法值用 `sohu channels` 列举"}],columns:["category_id","category_name"],func:async(q,F)=>{if(!q)throw new Q("搜狐号分类列举需要浏览器会话");const v=String(F.channel??"").trim();if(!v)throw new L("INVALID_INPUT","请用 --channel 指定频道名");await T(q,V.home);const z=await q.evaluate("(async () => {"+X+"const ar = await fetch('https://mp.sohu.com/mpbp/bp/account/list?_=' + Date.now(), { method: 'GET', credentials: 'include', headers: HDRS });const aj = await ar.json();"+"if (!aj || aj.code !== 2000000 || !(aj.data && aj.data.data && aj.data.data.length)) throw new Error('获取搜狐账号失败,请确认已登录搜狐号');"+"let accountId = '';for (const g of aj.data.data) { if (g.accounts && g.accounts.length) { accountId = String(g.accounts[0].id); break; } }"+"if (!accountId) throw new Error('搜狐号子账号列表为空');"+"const cr = await fetch('https://mp.sohu.com/mpbp/bp/account/common/channels-data-api?status=1&accountId=' + accountId, { method: 'GET', credentials: 'include', headers: HDRS });const cj = await cr.json();"+"if (!cj || cj.success === false) throw new Error('频道列举失败:' + ((cj && cj.msg) || '未登录或无权限'));"+"const channels = Array.isArray(cj) ? cj : ((cj && cj.data) || []);const ch = channels.find(c => String(c.name) === "+JSON.stringify(v)+");"+"if (!ch) throw new Error('未找到频道「"+v.replace(/"/g,"\\\"")+"」,可选:' + (channels.map(c => c.name).join(' / ') || '(空)'));"+"const channelId = ch.id != null ? ch.id : ch.channelId;const r = await fetch('https://mp.sohu.com/mpbp/bp/account/common/channels/' + channelId + '/categories?accountId=' + accountId, { method: 'GET', credentials: 'include', headers: HDRS });const j = await r.json();"+"if (!j || j.success === false) throw new Error('分类列举失败:' + ((j && j.msg) || '未登录或无权限'));"+"const list = Array.isArray(j) ? j : ((j && j.data) || []);return list.map(c => ({ category_id: String(c.id), category_name: c.name || '' }));})()");return Array.isArray(z)?z:[]}});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{cli as z,Strategy as F}from"@jackwener/opencli/registry";import{CommandExecutionError as G}from"@jackwener/opencli/errors";import{gotoWritePage as I}from"../_shared/article/publish.js";import{sohuProfile as K}from"./article.js";import{SOHU_MPBP_HEADERS_JS as L}from"./mpbp.js";z({site:"sohu",name:"channels",access:"read",description:"列出当前搜狐号可发布的频道(id + 名称),供 `sohu article --channel` 取合法频道名。",domain:"mp.sohu.com",strategy:F.COOKIE,browser:!0,columns:["channel_id","channel_name"],func:async(q)=>{if(!q)throw new G("搜狐号频道列举需要浏览器会话");await I(q,K.home);const v=await q.evaluate("(async () => {"+L+"const ar = await fetch('https://mp.sohu.com/mpbp/bp/account/list?_=' + Date.now(), { method: 'GET', credentials: 'include', headers: HDRS });const aj = await ar.json();"+"if (!aj || aj.code !== 2000000 || !(aj.data && aj.data.data && aj.data.data.length)) throw new Error('获取搜狐账号失败,请确认已登录搜狐号');"+"let accountId = '';for (const g of aj.data.data) { if (g.accounts && g.accounts.length) { accountId = String(g.accounts[0].id); break; } }"+"if (!accountId) throw new Error('搜狐号子账号列表为空');"+"const r = await fetch('https://mp.sohu.com/mpbp/bp/account/common/channels-data-api?status=1&accountId=' + accountId, { method: 'GET', credentials: 'include', headers: HDRS });const j = await r.json();"+"if (!j || j.success === false) throw new Error('频道列举失败:' + ((j && j.msg) || '未登录或无权限'));"+"const list = Array.isArray(j) ? j : ((j && j.data) || []);return list.map(c => ({ channel_id: String(c.id != null ? c.id : c.channelId), channel_name: c.name || '' }));})()");return Array.isArray(v)?v:[]}});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{cli as z,Strategy as F}from"@jackwener/opencli/registry";import{CommandExecutionError as G}from"@jackwener/opencli/errors";import{gotoWritePage as I}from"../_shared/article/publish.js";import{sohuProfile as K}from"./article.js";import{SOHU_MPBP_HEADERS_JS as L}from"./mpbp.js";z({site:"sohu",name:"columns",access:"read",description:"列出当前搜狐号的专栏(id + 名称),供 `sohu article --column` 取合法专栏名。",domain:"mp.sohu.com",strategy:F.COOKIE,browser:!0,columns:["column_id","column_name"],func:async(q)=>{if(!q)throw new G("搜狐号专栏列举需要浏览器会话");await I(q,K.home);const v=await q.evaluate("(async () => {"+L+"const ar = await fetch('https://mp.sohu.com/mpbp/bp/account/list?_=' + Date.now(), { method: 'GET', credentials: 'include', headers: HDRS });const aj = await ar.json();"+"if (!aj || aj.code !== 2000000 || !(aj.data && aj.data.data && aj.data.data.length)) throw new Error('获取搜狐账号失败,请确认已登录搜狐号');"+"let accountId = '';for (const g of aj.data.data) { if (g.accounts && g.accounts.length) { accountId = String(g.accounts[0].id); break; } }"+"if (!accountId) throw new Error('搜狐号子账号列表为空');"+"const r = await fetch('https://mp.sohu.com/mpbp/bp/account/column/v2/list?accountId=' + accountId + '&page=1&size=100', { method: 'GET', credentials: 'include', headers: HDRS });const j = await r.json();"+"if (!j || j.success === false) throw new Error('专栏列举失败:' + ((j && j.msg) || '未登录或无权限'));"+"const raw = Array.isArray(j) ? j : ((j && j.data) || []);const list = Array.isArray(raw) ? raw : (Array.isArray(raw.data) ? raw.data : []);return list.map(c => ({ column_id: String(c.id), column_name: c.name || '' }));})()");return Array.isArray(v)?v:[]}});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{registerArticleLogin as k}from"../_shared/article/login.js";import{sohuAuthProfile as b}from"./article.js";k({site:"sohu",domain:"mp.sohu.com",profile:{home:b.home,checkAuth:b.checkAuth},loginDescription:"打开搜狐号登录页并等待浏览器完成登录(供桌面客户端引导登录)。"});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const SOHU_MPBP_HEADERS_JS="let __dvId = '', __spCm = '';try { __dvId = localStorage.getItem('preview-dv-id') || ''; __spCm = localStorage.getItem('preview-sp-cm') || ''; } catch (e) {}if (!__dvId || !__spCm) { const __chars = '0123456789abcdef'; let __gen = ''; for (let __i = 0; __i < 32; __i++) __gen += __chars[Math.floor(Math.random() * 16)]; if (!__dvId) __dvId = __gen; if (!__spCm) __spCm = '100-' + Date.now() + '-' + __gen;}const HDRS = { 'X-Requested-With': 'XMLHttpRequest', 'dv-id': __dvId, 'sp-cm': __spCm };";
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import{cli as A,Strategy as C}from"@jackwener/opencli/registry";import{CommandExecutionError as L,EmptyResultError as G}from"@jackwener/opencli/errors";import{gotoWritePage as P}from"../_shared/article/publish.js";const T="https://mp.sohu.com/mpfe/v4/contentManagement/news/articlelist",_=10;function R(M){if(!M)return"";const F=new Date(M+28800000),J=(Q)=>String(Q).padStart(2,"0");return`${F.getUTCFullYear()}-${J(F.getUTCMonth()+1)}-${J(F.getUTCDate())} ${J(F.getUTCHours())}:${J(F.getUTCMinutes())}`}function W(M){const F=new Date(Date.now()+28800000-M*86400000),J=(Q)=>String(Q).padStart(2,"0");return`${F.getUTCFullYear()}-${J(F.getUTCMonth()+1)}-${J(F.getUTCDate())}`}A({site:"sohu",name:"stats",access:"read",description:"搜狐号文章数据(每篇阅读/评论/播放等全量运营指标;点赞/分享/投票仅覆盖最近30天已发布内容)",domain:"mp.sohu.com",strategy:C.COOKIE,browser:!0,args:[{name:"limit",type:"number",default:20,help:"返回条数"}],columns:["id","type","title","url","published_at","status","views","likes","comments","collects","shares","video_plays","votes","extra"],func:async(M,F)=>{if(!M)throw new L("搜狐号文章数据需要浏览器会话");const J=Number(F.limit)>0?Math.floor(Number(F.limit)):20;await P(M,T);const Q={limit:J,pageSize:_,startDate:W(30),endDate:W(0)},H=await M.evaluate(`(async () => {
|
|
2
|
+
const P = ${JSON.stringify(Q)};
|
|
3
|
+
|
|
4
|
+
// ── 请求头:dv-id / sp-cm 优先取页面自己存的值,逐字复刻 ──
|
|
5
|
+
let dvId = '', spCm = '';
|
|
6
|
+
try {
|
|
7
|
+
dvId = localStorage.getItem('preview-dv-id') || '';
|
|
8
|
+
spCm = localStorage.getItem('preview-sp-cm') || '';
|
|
9
|
+
} catch (e) {}
|
|
10
|
+
if (!dvId || !spCm) {
|
|
11
|
+
const chars = '0123456789abcdef';
|
|
12
|
+
let gen = '';
|
|
13
|
+
for (let i = 0; i < 32; i++) gen += chars[Math.floor(Math.random() * chars.length)];
|
|
14
|
+
if (!dvId) dvId = gen;
|
|
15
|
+
if (!spCm) spCm = '100-' + Date.now() + '-' + gen;
|
|
16
|
+
}
|
|
17
|
+
const HDRS = { 'X-Requested-With': 'XMLHttpRequest', 'dv-id': dvId, 'sp-cm': spCm };
|
|
18
|
+
|
|
19
|
+
const getJson = async (url) => {
|
|
20
|
+
const r = await fetch(url, { method: 'GET', credentials: 'include', headers: HDRS });
|
|
21
|
+
const t = await r.text();
|
|
22
|
+
let j = null;
|
|
23
|
+
try { j = JSON.parse(t); } catch (e) {}
|
|
24
|
+
if (!r.ok || !j || j.success === false || (j.code != null && j.code !== 2000000)) {
|
|
25
|
+
throw new Error('HTTP ' + r.status + ' ' + ((j && (j.msg || j.message)) || t.slice(0, 150)));
|
|
26
|
+
}
|
|
27
|
+
return j;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// ── accountId(与 article.js checkAuth 同一接口)──
|
|
31
|
+
let accountId = '';
|
|
32
|
+
try {
|
|
33
|
+
const auth = await getJson('https://mp.sohu.com/mpbp/bp/account/list?_=' + Date.now());
|
|
34
|
+
const accounts = [];
|
|
35
|
+
for (const g of (auth.data && auth.data.data) || []) {
|
|
36
|
+
if (g.accounts) accounts.push(...g.accounts);
|
|
37
|
+
}
|
|
38
|
+
if (!accounts.length) return { err: '搜狐号子账号列表为空,请确认已登录搜狐号' };
|
|
39
|
+
accountId = String(accounts[0].id);
|
|
40
|
+
} catch (e) {
|
|
41
|
+
return { err: '获取搜狐账号信息失败(可能未登录搜狐号):' + String((e && e.message) || e) };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// ── 内容列表:statusType=1(全部),按页面原样 psize=10 翻页 ──
|
|
45
|
+
const listUrl = (statusType, pno) =>
|
|
46
|
+
'https://mp.sohu.com/mpbp/bp/news/v4/users/news?psize=' + P.pageSize
|
|
47
|
+
+ '&newsType=0&statusType=' + statusType + '&columnId=&pno=' + pno
|
|
48
|
+
+ '&streamId=&accountId=' + accountId + '&_=' + Date.now();
|
|
49
|
+
const news = [];
|
|
50
|
+
let total = 0;
|
|
51
|
+
try {
|
|
52
|
+
for (let pno = 1; news.length < P.limit; pno++) {
|
|
53
|
+
const j = await getJson(listUrl(1, pno));
|
|
54
|
+
const rows = (j.data && j.data.news) || [];
|
|
55
|
+
total = (j.data && j.data.totalCount) || total;
|
|
56
|
+
news.push(...rows);
|
|
57
|
+
if (!rows.length || news.length >= total) break;
|
|
58
|
+
}
|
|
59
|
+
} catch (e) {
|
|
60
|
+
return { err: '搜狐号内容列表接口请求失败:' + String((e && e.message) || e) };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ── 已发布集合:statusType=2(「已发布」tab,同样为观测值)──
|
|
64
|
+
const publishedIds = [];
|
|
65
|
+
try {
|
|
66
|
+
for (let pno = 1; ; pno++) {
|
|
67
|
+
const j = await getJson(listUrl(2, pno));
|
|
68
|
+
const rows = (j.data && j.data.news) || [];
|
|
69
|
+
for (const r of rows) publishedIds.push(String(r.id));
|
|
70
|
+
const tc = (j.data && j.data.totalCount) || 0;
|
|
71
|
+
if (!rows.length || publishedIds.length >= tc || pno >= 20) break;
|
|
72
|
+
}
|
|
73
|
+
} catch (e) { /* 已发布集合仅用于 status 标注,失败不阻断(下方 status 回落为空) */ }
|
|
74
|
+
|
|
75
|
+
// ── 单篇统计(最近30天,实时):{data:{news:[...], totalCount}} ──
|
|
76
|
+
const statRows = [];
|
|
77
|
+
let statError = '';
|
|
78
|
+
try {
|
|
79
|
+
for (let pg = 1; pg <= 20; pg++) {
|
|
80
|
+
const j = await getJson(
|
|
81
|
+
'https://mp.sohu.com/mpbp/bp/news/v4/users/stat/single/list?page=' + pg
|
|
82
|
+
+ '&type=0&startDate=' + P.startDate + '&endDate=' + P.endDate
|
|
83
|
+
+ '&accountId=' + accountId,
|
|
84
|
+
);
|
|
85
|
+
const rows = (j.data && j.data.news) || [];
|
|
86
|
+
statRows.push(...rows);
|
|
87
|
+
const tc = (j.data && j.data.totalCount) || 0;
|
|
88
|
+
if (!rows.length || statRows.length >= tc) break;
|
|
89
|
+
}
|
|
90
|
+
} catch (e) {
|
|
91
|
+
statError = String((e && e.message) || e);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return { accountId, news: news.slice(0, P.limit), totalCount: total, publishedIds, statRows, statError };
|
|
95
|
+
})()`);if(!H||H.err)throw new L(H&&H.err||"搜狐号文章数据获取失败:页面未返回任何数据(请确认已登录 mp.sohu.com)");const V=Array.isArray(H.news)?H.news:[];if(!V.length)throw new G("sohu stats","该搜狐号名下没有任何内容(或列表接口返回为空)。请先在 mp.sohu.com 发布内容后再查数据。");const X=new Map,Y=new Map;for(const q of Array.isArray(H.statRows)?H.statRows:[]){if(q&&q.id!=null)X.set(String(q.id),q);if(q&&typeof q.title==="string"&&q.title)Y.set(q.title,q)}const U=(q,O)=>{if(!q)return"";for(const K of O)if(typeof q[K]==="number")return q[K];return""},Z=new Set(Array.isArray(H.publishedIds)?H.publishedIds:[]);return V.map((q)=>{const O=q.id!=null?String(q.id):"",K=X.get(O)||Y.get(q.title||"")||null,$=Z.has(O),z={};if(q.auditStatus!=null)z.audit_status=q.auditStatus;if(q.status!=null)z.status_raw=q.status;if(q.rejectReason)z.reject_reason=q.rejectReason;if(q.original!=null)z.original=q.original;if(q.star!=null)z.star=q.star;if(q.secureScore!=null)z.secure_score=q.secureScore;if(q.channelId!=null)z.channel_id=q.channelId;if(q.modifiedTime)z.modified_at=R(q.modifiedTime);if(q.brief)z.brief=String(q.brief).slice(0,80);if(K)z.stat=K;if(H.statError)z.stat_error="单篇统计接口失败:"+H.statError;return{id:O,type:q.type!=null?String(q.type):"",title:q.title||q.mobileTitle||"",url:O?"https://mp.sohu.com/mpfe/v4/contentManagement/news/addarticle?spm=smmp.articlelist.0.0&contentStatus="+($?1:2)+"&id="+O:"",published_at:R(q.postTime||q.createdTime),status:$?"已发布":"未发布",views:typeof q.pv==="number"?q.pv:"",likes:U(K,["digg","diggCount","like","likeCount","praise","zan"]),comments:typeof q.cmt==="number"?q.cmt:U(K,["cmt","comment","commentCount"]),collects:"",shares:U(K,["share","shareCount","forward","forwardCount"]),video_plays:typeof q.videoPlayPv==="number"?q.videoPlayPv:"",votes:U(K,["vote","voteCount"]),extra:Object.keys(z).length?JSON.stringify(z):""}})}});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{cli as G,Strategy as I}from"@jackwener/opencli/registry";import{CommandExecutionError as K}from"@jackwener/opencli/errors";import{gotoWritePage as L}from"../_shared/article/publish.js";import{sohuProfile as N}from"./article.js";import{SOHU_MPBP_HEADERS_JS as Q}from"./mpbp.js";G({site:"sohu",name:"topics",access:"read",description:"列举/搜索搜狐号话题(id + 名称 + 类型),供 `sohu article --topics` 取确切话题名。不传 --keyword 为推荐话题,传则按关键词搜索。",domain:"mp.sohu.com",strategy:I.COOKIE,browser:!0,args:[{name:"keyword",help:"搜索关键词;不传则返回推荐话题列表"}],columns:["topic_id","topic_name","topic_type"],func:async(q,v)=>{if(!q)throw new K("搜狐号话题列举需要浏览器会话");const F=typeof v.keyword==="string"?v.keyword.trim():"";await L(q,N.home);const z=await q.evaluate("(async () => {"+Q+"const ar = await fetch('https://mp.sohu.com/mpbp/bp/account/list?_=' + Date.now(), { method: 'GET', credentials: 'include', headers: HDRS });const aj = await ar.json();"+"if (!aj || aj.code !== 2000000 || !(aj.data && aj.data.data && aj.data.data.length)) throw new Error('获取搜狐账号失败,请确认已登录搜狐号');"+"let accountId = '';for (const g of aj.data.data) { if (g.accounts && g.accounts.length) { accountId = String(g.accounts[0].id); break; } }"+"if (!accountId) throw new Error('搜狐号子账号列表为空');"+"const kw = "+JSON.stringify(F)+";const url = kw ? 'https://mp.sohu.com/mpbp/bp/news/v4/label/topic/search?accountId=' + accountId + '&keyword=' + encodeURIComponent(kw) : 'https://mp.sohu.com/mpbp/bp/news/v4/label/topic/list?accountId=' + accountId;const r = await fetch(url, { method: 'GET', credentials: 'include', headers: HDRS });const j = await r.json();"+"if (!j || j.success === false) throw new Error('话题接口失败:' + ((j && j.msg) || '未登录或无权限'));"+"const list = Array.isArray(j) ? j : ((j && j.data) || []);return list.map(t => ({ topic_id: String(t.id), topic_name: t.name || '', topic_type: t.type != null ? String(t.type) : '' }));})()");return Array.isArray(z)?z:[]}});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{cli as q,Strategy as v}from"@jackwener/opencli/registry";import{checkLogin as x,cookieQuickCheck as z}from"../_shared/article/auth.js";import{sohuAuthProfile as B}from"./article.js";q({site:"sohu",name:"whoami",access:"read",description:"查看当前搜狐号登录账号信息(用户名、用户 ID)。",domain:"mp.sohu.com",strategy:v.COOKIE,browser:!0,columns:["logged_in","user_id","username"],authStatus:{quickCheck:z("https://mp.sohu.com",["pprdig"])},func:async(m)=>{const b=await x(m,B);return[{logged_in:b.isAuthenticated,user_id:b.userId||"",username:b.username||""}]}});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{cli as X,Strategy as Y}from"@jackwener/opencli/registry";import{CliError as Z}from"@jackwener/opencli/errors";import{readFileSync as q,writeFileSync as j,mkdirSync as R,existsSync as f}from"fs";import{createServer as h}from"http";import{homedir as P}from"os";import{join as x}from"path";import{exec as m}from"child_process";import{assertSpotifyCredentialsConfigured as I,getFirstSpotifyTrack as v,mapSpotifyTrackResults as p,parseDotEnv as u,resolveSpotifyCredentials as C}from"./utils.js";const K=x(P(),".opencli","spotify.env");function w(){if(!f(K))return{};return u(q(K,"utf-8"))}const T=w(),O=C(T),V=O.clientId,D=O.clientSecret,U="http://127.0.0.1:8888/callback",S=["user-read-playback-state","user-modify-playback-state","user-read-currently-playing","playlist-read-private"].join(" "),F=x(P(),".opencli","spotify-tokens.json");function y(){try{return JSON.parse(q(F,"utf-8"))}catch{return null}}function L(z){R(x(P(),".opencli"),{recursive:!0});j(F,JSON.stringify(z,null,2))}async function E(z){const G=await fetch("https://accounts.spotify.com/api/token",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Authorization:"Basic "+Buffer.from(`${V}:${D}`).toString("base64")},body:new URLSearchParams({grant_type:"refresh_token",refresh_token:z})});if(!G.ok){const J=await G.json().catch(()=>({}));throw new Z("REFRESH_FAILED",J?.error_description||`Token refresh failed (${G.status})`)}const H=await G.json(),M={access_token:H.access_token,refresh_token:H.refresh_token||z,expires_at:Date.now()+H.expires_in*1000};L(M);return M.access_token}async function g(){const z=y();if(!z)throw new Z("AUTH_REQUIRED","Not authenticated. Run: opencli spotify auth");if(!z.access_token||!z.refresh_token||!(z.expires_at>0))throw new Z("AUTH_CORRUPTED","Token file is corrupted. Run: opencli spotify auth");if(Date.now()>z.expires_at-60000)return E(z.refresh_token);return z.access_token}async function Q(z,G,H){const M=await g(),J=await fetch(`https://api.spotify.com/v1${G}`,{method:z,headers:{Authorization:`Bearer ${M}`,"Content-Type":"application/json"},body:H?JSON.stringify(H):void 0});if(J.status===204||J.status===202)return null;if(!J.ok){const W=await J.json().catch(()=>({}));throw new Z("API_ERROR",W?.error?.message||`Spotify API error ${J.status}`)}return J.json()}async function N(z){const G=await Q("GET",`/search?q=${encodeURIComponent(z)}&type=track&limit=1`),H=v(G);if(!H)throw new Z("EMPTY_RESULT",`No track found for: ${z}`);return H}function d(z){const G=process.platform==="win32"?`start "" "${z}"`:process.platform==="darwin"?`open "${z}"`:`xdg-open "${z}"`;m(G)}X({site:"spotify",name:"auth",access:"write",description:"Authenticate with Spotify (OAuth — run once)",strategy:Y.PUBLIC,browser:!1,args:[],columns:["status"],func:async()=>{I(O,K);return new Promise((z,G)=>{const H=h(async(J,W)=>{try{const $=new URL(J.url,"http://localhost:8888");if($.pathname!=="/callback"){W.end();return}const b=$.searchParams.get("code");if(!b){W.end("Missing code");return}const A=await fetch("https://accounts.spotify.com/api/token",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Authorization:"Basic "+Buffer.from(`${V}:${D}`).toString("base64")},body:new URLSearchParams({grant_type:"authorization_code",code:b,redirect_uri:U})});if(!A.ok){const _=await A.json().catch(()=>({}));H.close();G(new Z("AUTH_FAILED",_?.error_description||`Token exchange failed (${A.status})`));return}const B=await A.json();L({access_token:B.access_token,refresh_token:B.refresh_token,expires_at:Date.now()+B.expires_in*1000});W.writeHead(200,{"Content-Type":"text/html"});W.end("<h2>Spotify authenticated! You can close this tab.</h2>");H.close();z([{status:"Authenticated successfully"}])}catch($){H.close();G($)}});H.on("error",(J)=>{if(J.code==="EADDRINUSE")G(new Z("PORT_IN_USE","Port 8888 is already in use. Stop the other process and retry."));else G(J)});const M=setTimeout(()=>{H.close();G(new Z("AUTH_TIMEOUT","Authentication timed out after 5 minutes"))},300000);H.listen(8888,()=>{const J=`https://accounts.spotify.com/authorize?${new URLSearchParams({client_id:V,response_type:"code",redirect_uri:U,scope:S})}`;console.log("Opening browser for Spotify login...");console.log("If it does not open, visit:",J);d(J)});H.on("close",()=>clearTimeout(M))})}});X({site:"spotify",name:"status",access:"read",description:"Show current playback status",strategy:Y.PUBLIC,browser:!1,args:[],columns:["track","artist","album","status","progress"],func:async()=>{const z=await Q("GET","/me/player");if(!z||!z.item)return[{track:"Nothing playing",artist:"",album:"",status:"",progress:""}];const G=z.item;if(G.type!=="track")return[{track:G.name,artist:"",album:G.show?.name??"",status:z.is_playing?"playing":"paused",progress:""}];const H=(z.progress_ms??0)/1000|0,M=G.duration_ms/1000|0,J=(W)=>`${W/60|0}:${String(W%60).padStart(2,"0")}`;return[{track:G.name,artist:G.artists.map((W)=>W.name).join(", "),album:G.album.name,status:z.is_playing?"playing":"paused",progress:`${J(H)} / ${J(M)}`}]}});X({site:"spotify",name:"play",access:"write",description:"Resume playback or search and play a track/artist",strategy:Y.PUBLIC,browser:!1,args:[{name:"query",type:"str",default:"",positional:!0,help:"Track or artist to play (optional)"}],columns:["track","artist","status"],func:async(z)=>{if(z.query){const{uri:G,name:H,artist:M}=await N(z.query);await Q("PUT","/me/player/play",{uris:[G]});return[{track:H,artist:M,status:"playing"}]}await Q("PUT","/me/player/play");return[{track:"",artist:"",status:"resumed"}]}});X({site:"spotify",name:"pause",access:"write",description:"Pause playback",strategy:Y.PUBLIC,browser:!1,args:[],columns:["status"],func:async()=>{await Q("PUT","/me/player/pause");return[{status:"paused"}]}});X({site:"spotify",name:"next",access:"write",description:"Skip to next track",strategy:Y.PUBLIC,browser:!1,args:[],columns:["status"],func:async()=>{await Q("POST","/me/player/next");return[{status:"skipped to next"}]}});X({site:"spotify",name:"prev",access:"write",description:"Skip to previous track",strategy:Y.PUBLIC,browser:!1,args:[],columns:["status"],func:async()=>{await Q("POST","/me/player/previous");return[{status:"skipped to previous"}]}});X({site:"spotify",name:"volume",access:"write",description:"Set playback volume (0-100)",strategy:Y.PUBLIC,browser:!1,args:[{name:"level",type:"int",default:50,positional:!0,required:!0,help:"Volume 0–100"}],columns:["volume"],func:async(z)=>{const G=Math.round(z.level);if(G<0||G>100)throw new Z("INVALID_ARGS","Volume must be between 0 and 100");await Q("PUT",`/me/player/volume?volume_percent=${G}`);return[{volume:`${G}%`}]}});X({site:"spotify",name:"search",access:"read",description:"Search for tracks",strategy:Y.PUBLIC,browser:!1,args:[{name:"query",type:"str",required:!0,positional:!0,help:"Search query"},{name:"limit",type:"int",default:10,help:"Number of results (default: 10)"}],columns:["track","artist","album","uri"],func:async(z)=>{const G=Math.min(50,Math.max(1,Math.round(z.limit))),H=await Q("GET",`/search?q=${encodeURIComponent(z.query)}&type=track&limit=${G}`),M=p(H);if(!M.length)throw new Z("EMPTY_RESULT",`No results found for: ${z.query}`);return M}});X({site:"spotify",name:"queue",access:"write",description:"Add a track to the playback queue",strategy:Y.PUBLIC,browser:!1,args:[{name:"query",type:"str",required:!0,positional:!0,help:"Track to add to queue"}],columns:["track","artist","status"],func:async(z)=>{const{uri:G,name:H,artist:M}=await N(z.query);await Q("POST",`/me/player/queue?uri=${encodeURIComponent(G)}`);return[{track:H,artist:M,status:"added to queue"}]}});X({site:"spotify",name:"shuffle",access:"write",description:"Toggle shuffle on/off",strategy:Y.PUBLIC,browser:!1,args:[{name:"state",type:"str",default:"on",positional:!0,choices:["on","off"],help:"on or off"}],columns:["shuffle"],func:async(z)=>{await Q("PUT",`/me/player/shuffle?state=${z.state==="on"}`);return[{shuffle:z.state}]}});X({site:"spotify",name:"repeat",access:"write",description:"Set repeat mode (off / track / context)",strategy:Y.PUBLIC,browser:!1,args:[{name:"mode",type:"str",default:"context",positional:!0,choices:["off","track","context"],help:"off / track / context"}],columns:["repeat"],func:async(z)=>{await Q("PUT",`/me/player/repeat?state=${z.mode}`);return[{repeat:z.mode}]}});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import{CliError as n}from"@jackwener/opencli/errors";const o=[/^your_spotify_client_id_here$/i,/^your_spotify_client_secret_here$/i,/^your_.+_here$/i];export function parseDotEnv(r){return Object.fromEntries(r.split(/\r?\n/).map((t)=>t.trim()).filter((t)=>t&&!t.startsWith("#")&&t.includes("=")).map((t)=>{const e=t.indexOf("=");return[t.slice(0,e).trim(),t.slice(e+1).trim()]}))}export function resolveSpotifyCredentials(r,t=process.env){return{clientId:t.SPOTIFY_CLIENT_ID||r.SPOTIFY_CLIENT_ID||"",clientSecret:t.SPOTIFY_CLIENT_SECRET||r.SPOTIFY_CLIENT_SECRET||""}}export function isPlaceholderCredential(r){const t=r?.trim()||"";if(!t)return!1;return o.some((e)=>e.test(t))}export function hasConfiguredSpotifyCredentials(r){return Boolean(r.clientId.trim())&&Boolean(r.clientSecret.trim())&&!isPlaceholderCredential(r.clientId)&&!isPlaceholderCredential(r.clientSecret)}export function assertSpotifyCredentialsConfigured(r,t){if(hasConfiguredSpotifyCredentials(r))return;throw new n("CONFIG",`Missing Spotify credentials.
|
|
2
|
+
|
|
3
|
+
1. Go to https://developer.spotify.com/dashboard and create an app
|
|
4
|
+
2. Add http://127.0.0.1:8888/callback as a Redirect URI
|
|
5
|
+
3. Copy your Client ID and Client Secret
|
|
6
|
+
4. Open the file: ${t}
|
|
7
|
+
5. Fill in SPOTIFY_CLIENT_ID and SPOTIFY_CLIENT_SECRET, then save
|
|
8
|
+
6. Run: opencli spotify auth`)}export function mapSpotifyTrackResults(r){const t=r?.tracks?.items;if(!Array.isArray(t))return[];return t.map((e)=>({track:e?.name||"",artist:Array.isArray(e?.artists)?e.artists.map((i)=>i.name).join(", "):"",album:e?.album?.name||"",uri:e?.uri||""}))}export function getFirstSpotifyTrack(r){const t=mapSpotifyTrackResults(r)[0];if(!t)return null;return{uri:t.uri,name:t.track,artist:t.artist}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{cli as e,Strategy as t}from"@jackwener/opencli/registry";e({site:"stackoverflow",name:"bounties",access:"read",description:"Active bounties on Stack Overflow",domain:"stackoverflow.com",strategy:t.PUBLIC,browser:!1,args:[{name:"limit",type:"int",default:10,help:"Max number of results"}],columns:["rank","id","bounty","title","score","answers","views","is_answered","tags","author","creation_date","url"],pipeline:[{fetch:{url:"https://api.stackexchange.com/2.3/questions/featured?order=desc&sort=activity&site=stackoverflow&pagesize=${{ args.limit }}"}},{select:"items"},{map:{rank:"${{ index + 1 }}",id:"${{ item.question_id }}",bounty:"${{ item.bounty_amount }}",title:"${{ item.title }}",score:"${{ item.score }}",answers:"${{ item.answer_count }}",views:"${{ item.view_count }}",is_answered:"${{ item.is_answered }}",tags:"${{ item.tags | join(', ') }}",author:"${{ item.owner.display_name }}",creation_date:"${{ item.creation_date }}",url:"${{ item.link }}"}},{limit:"${{ args.limit }}"}]});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{cli as e,Strategy as t}from"@jackwener/opencli/registry";e({site:"stackoverflow",name:"hot",access:"read",description:"Hot Stack Overflow questions",domain:"stackoverflow.com",strategy:t.PUBLIC,browser:!1,args:[{name:"limit",type:"int",default:10,help:"Max number of results"}],columns:["rank","id","title","score","answers","views","is_answered","tags","author","creation_date","url"],pipeline:[{fetch:{url:"https://api.stackexchange.com/2.3/questions?order=desc&sort=hot&site=stackoverflow&pagesize=${{ args.limit }}"}},{select:"items"},{map:{rank:"${{ index + 1 }}",id:"${{ item.question_id }}",title:"${{ item.title }}",score:"${{ item.score }}",answers:"${{ item.answer_count }}",views:"${{ item.view_count }}",is_answered:"${{ item.is_answered }}",tags:"${{ item.tags | join(', ') }}",author:"${{ item.owner.display_name }}",creation_date:"${{ item.creation_date }}",url:"${{ item.link }}"}},{limit:"${{ args.limit }}"}]});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import{cli as h,Strategy as x}from"@jackwener/opencli/registry";import{ArgumentError as f,CommandExecutionError as G,EmptyResultError as B}from"@jackwener/opencli/errors";const O="https://api.stackexchange.com/2.3",R="stackoverflow",M=100;async function X(F,H){let V;try{V=await fetch(F)}catch(Y){const $=Y instanceof Error?Y.message:String(Y);throw new G(`Network failure fetching ${H}: ${$}`,"Check connectivity to api.stackexchange.com")}if(V.status===404)throw new B(H,`${H} not found`);if(!V.ok)throw new G(`Stack Exchange API HTTP ${V.status} for ${H}`,"Check the question id and quota (300/day per IP)");let K;try{K=await V.json()}catch(Y){const $=Y instanceof Error?Y.message:String(Y);throw new G(`Malformed JSON from Stack Exchange API for ${H}: ${$}`,"The API returned a non-JSON body — likely a transient outage")}if(K&&K.error_id)throw new G(`Stack Exchange API error ${K.error_id} (${K.error_name}) for ${H}: ${K.error_message||""}`,"Common causes: invalid filter, throttled, or quota exhausted");return K}function v(F){if(F===void 0||F===null||F==="")return NaN;const H=typeof F==="number"?F:Number(F);return Number.isFinite(H)&&Number.isInteger(H)?H:NaN}function A(F,H,V){const K=v(F);if(!Number.isInteger(K)||K<H)throw new f(`${V} must be an integer >= ${H}, got ${JSON.stringify(F)}`);return K}function C(F,H,V,K){const Y=v(F);if(!Number.isInteger(Y)||Y<H||Y>V)throw new f(`${K} must be an integer between ${H} and ${V}, got ${JSON.stringify(F)}`);return Y}function E(F,H){const V=F.accepted_answer_id;return H.slice().sort((K,Y)=>{const $=K.is_accepted||V&&K.answer_id===V,W=Y.is_accepted||V&&Y.answer_id===V;if($!==W)return $?-1:1;return(Y.score??0)-(K.score??0)})}async function u(F,H,V){const K=F.accepted_answer_id;if(!K||H.some((W)=>W.answer_id===K))return H;const $=((await X(`${O}/answers/${K}?site=${R}&filter=withbody`,`${V}/accepted-answer`)).items||[])[0];return $?H.concat($):H}async function w(F,H,V){const K=new Map;if(F.length===0)return K;const Y=F.map((Q)=>Q.answer_id).join(";"),$=Math.min(M,F.length*H),W=await X(`${O}/answers/${Y}/comments?site=${R}&filter=withbody&order=asc&sort=creation&pagesize=${$}`,`${V}/answer-comments`);for(const Q of W.items||[]){if(!Q.post_id)continue;if(!K.has(Q.post_id))K.set(Q.post_id,[]);K.get(Q.post_id).push(Q)}if(W.has_more){if(F.some((z)=>{return(K.get(z.answer_id)||[]).length<H}))throw new G(`Stack Exchange answer comments for ${V} exceed one API page`,"Lower --answers-limit or --comments-limit; refusing to return a partial answer-comment set.")}return K}const d={amp:"&",lt:"<",gt:">",quot:'"',apos:"'",nbsp:" ",hellip:"…",mdash:"—",ndash:"–",laquo:"«",raquo:"»",copy:"©",reg:"®",trade:"™",euro:"€",pound:"£",yen:"¥",rsquo:"’",lsquo:"‘",rdquo:"”",ldquo:"“"};function L(F){if(!F)return"";return String(F).replace(/&#x([0-9a-fA-F]+);/g,(H,V)=>{const K=parseInt(V,16);return Number.isFinite(K)?String.fromCodePoint(K):""}).replace(/&#(\d+);/g,(H,V)=>{const K=parseInt(V,10);return Number.isFinite(K)?String.fromCodePoint(K):""}).replace(/&([a-zA-Z]+);/g,(H,V)=>d[V]??H)}function Z(F){if(!F)return"";const H=String(F).replace(/<pre[^>]*><code[^>]*>([\s\S]*?)<\/code><\/pre>/gi,`
|
|
2
|
+
$1
|
|
3
|
+
`).replace(/<code[^>]*>(.*?)<\/code>/gi,"`$1`").replace(/<p[^>]*>/gi,`
|
|
4
|
+
|
|
5
|
+
`).replace(/<\/p>/gi,"").replace(/<br\s*\/?>/gi,`
|
|
6
|
+
`).replace(/<li[^>]*>/gi,`
|
|
7
|
+
- `).replace(/<\/li>/gi,"").replace(/<a[^>]*href="([^"]*)"[^>]*>(.*?)<\/a>/gi,"$2 ($1)").replace(/<[^>]+>/g,"");return L(H).replace(/\n{3,}/g,`
|
|
8
|
+
|
|
9
|
+
`).trim()}function J(F){return L(F?.display_name||"")||"[deleted]"}function D(F,H){if(!F||F.length<=H)return F||"";return F.slice(0,H)+" ... [truncated]"}function T(F,H){if(H===0)return F;const K=`${" ".repeat(H)}> `;return F.split(`
|
|
10
|
+
`).map((Y)=>K+Y).join(`
|
|
11
|
+
`)}h({site:"stackoverflow",name:"read",access:"read",description:"Read a Stack Overflow question with answers and comments",domain:"stackoverflow.com",strategy:x.PUBLIC,browser:!1,args:[{name:"id",required:!0,positional:!0,help:"Stack Overflow question id (numeric, e.g. 79935770)"},{name:"answers-limit",type:"int",default:10,help:"Max answers to include (1-100; accepted answer always included first)"},{name:"comments-limit",type:"int",default:5,help:"Max comments per question/answer (1-100)"},{name:"max-length",type:"int",default:4000,help:"Max characters per body / answer / comment (min 100)"}],columns:["type","author","score","accepted","text"],func:async(F)=>{const H=String(F.id||"").trim();if(!/^\d+$/.test(H))throw new f(`Invalid Stack Overflow question id: ${F.id}`,"Pass a numeric id like 79935770");const V=C(F["answers-limit"]??10,1,M,"stackoverflow read --answers-limit"),K=C(F["comments-limit"]??5,1,M,"stackoverflow read --comments-limit"),Y=A(F["max-length"]??4000,100,"stackoverflow read --max-length"),$=`stackoverflow/${H}`,W=`${O}/questions/${H}?site=${R}&filter=withbody`,z=((await X(W,$)).items||[])[0];if(!z)throw new B($,"Question not found");const[P,q]=await Promise.all([X(`${O}/questions/${H}/comments?site=${R}&filter=withbody&order=asc&sort=creation&pagesize=${K}`,`${$}/comments`),X(`${O}/questions/${H}/answers?site=${R}&filter=withbody&order=desc&sort=votes&pagesize=${V}`,`${$}/answers`)]),g=await u(z,q.items||[],$),y=E(z,g).slice(0,V),_=await w(y,K,$),k=[],p=Z(z.body||""),S=[z.title||"",p,z.link||""].filter(Boolean);k.push({type:"POST",author:J(z.owner),score:z.score??0,accepted:"",text:D(S.join(`
|
|
12
|
+
|
|
13
|
+
`),Y)});const I=(P.items||[]).slice(0,K);for(const U of I){const j=T(Z(U.body||""),1);k.push({type:"Q-COMMENT",author:J(U.owner),score:U.score??0,accepted:"",text:D(j,Y)})}for(const U of y){k.push({type:"ANSWER",author:J(U.owner),score:U.score??0,accepted:U.is_accepted?"true":"",text:D(Z(U.body||""),Y)});const j=(_.get(U.answer_id)||[]).slice(0,K);for(const N of j){const b=T(Z(N.body||""),1);k.push({type:"A-COMMENT",author:J(N.owner),score:N.score??0,accepted:"",text:D(b,Y)})}}return k}});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{cli as u,Strategy as m}from"@jackwener/opencli/registry";import{ArgumentError as a}from"@jackwener/opencli/errors";import{seFetch as w,normalizeLimit as f,epochToDate as n,ensureItems as p,decodeHtmlEntities as l}from"./utils.js";const r=["rank","activity","votes","creation"];u({site:"stackoverflow",name:"related",access:"read",description:"List Stack Overflow questions related to a given question id.",domain:"stackoverflow.com",strategy:m.PUBLIC,browser:!1,args:[{name:"id",positional:!0,required:!0,type:"string",help:"Stack Overflow question id (numeric, e.g. 79935770)."},{name:"sort",type:"string",default:"rank",help:`Sort key: ${r.join(", ")} (rank = SO relevance default).`},{name:"limit",type:"int",default:20,help:"Max related questions (1-100)."}],columns:["rank","id","title","score","answers","views","isAnswered","tags","author","createdAt","lastActivityAt","url"],func:async(t)=>{const i=String(t.id??"").trim();if(!/^\d+$/.test(i))throw new a(`stackoverflow related id must be a numeric question id, got ${JSON.stringify(t.id)}`);const s=String(t.sort??"rank").toLowerCase();if(!r.includes(s))throw new a(`stackoverflow related sort must be one of ${r.join(", ")}`);const o=f(t.limit,20,100,"limit"),c=await w(`/questions/${encodeURIComponent(i)}/related`,{searchParams:{order:"desc",sort:s,pagesize:o}});return p(c,`stackoverflow related ${i}`).slice(0,o).map((e,d)=>({rank:d+1,id:e.question_id,title:l(e.title||""),score:e.score??0,answers:e.answer_count??0,views:e.view_count??0,isAnswered:Boolean(e.is_answered),tags:Array.isArray(e.tags)?e.tags.join(", "):"",author:l(e.owner?.display_name||""),createdAt:n(e.creation_date),lastActivityAt:n(e.last_activity_date),url:e.link||(e.question_id?`https://stackoverflow.com/questions/${e.question_id}`:"")}))}});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{cli as e,Strategy as t}from"@jackwener/opencli/registry";e({site:"stackoverflow",name:"search",access:"read",description:"Search Stack Overflow questions",domain:"stackoverflow.com",strategy:t.PUBLIC,browser:!1,args:[{name:"query",type:"string",required:!0,positional:!0,help:"Search query"},{name:"limit",type:"int",default:10,help:"Max number of results"}],columns:["rank","id","title","score","answers","views","is_answered","tags","author","creation_date","url"],pipeline:[{fetch:{url:"https://api.stackexchange.com/2.3/search/advanced?order=desc&sort=relevance&q=${{ args.query }}&site=stackoverflow&pagesize=${{ args.limit }}"}},{select:"items"},{map:{rank:"${{ index + 1 }}",id:"${{ item.question_id }}",title:"${{ item.title }}",score:"${{ item.score }}",answers:"${{ item.answer_count }}",views:"${{ item.view_count }}",is_answered:"${{ item.is_answered }}",tags:"${{ item.tags | join(', ') }}",author:"${{ item.owner.display_name }}",creation_date:"${{ item.creation_date }}",url:"${{ item.link }}"}},{limit:"${{ args.limit }}"}]});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{cli as m,Strategy as g}from"@jackwener/opencli/registry";import{ArgumentError as u}from"@jackwener/opencli/errors";import{seFetch as d,normalizeLimit as w,requireString as v,epochToDate as r,ensureItems as p,decodeHtmlEntities as n}from"./utils.js";const i=["activity","votes","creation","hot","week","month"];m({site:"stackoverflow",name:"tag",access:"read",description:"List Stack Overflow questions tagged with a given tag (most active first).",domain:"stackoverflow.com",strategy:g.PUBLIC,browser:!1,args:[{name:"tag",positional:!0,required:!0,type:"string",help:"Tag slug (e.g. python, rust, typescript)."},{name:"sort",type:"string",default:"activity",help:`Sort key: ${i.join(", ")}`},{name:"limit",type:"int",default:20,help:"Max questions to return (max 100)."}],columns:["rank","id","title","score","answers","views","isAnswered","tags","author","createdAt","lastActivityAt","url"],func:async(e)=>{const s=v(e.tag,"tag").toLowerCase(),a=String(e.sort??"activity").toLowerCase();if(!i.includes(a))throw new u(`sort must be one of ${i.join(", ")}`);const o=w(e.limit,20,100,"limit"),c=await d("/questions",{searchParams:{tagged:s,order:"desc",sort:a,pagesize:o}});return p(c,`stackoverflow tag "${s}"`).slice(0,o).map((t,l)=>({rank:l+1,id:t.question_id,title:n(t.title||""),score:t.score??0,answers:t.answer_count??0,views:t.view_count??0,isAnswered:Boolean(t.is_answered),tags:Array.isArray(t.tags)?t.tags.join(", "):"",author:n(t.owner?.display_name||""),createdAt:r(t.creation_date),lastActivityAt:r(t.last_activity_date),url:t.link||(t.question_id?`https://stackoverflow.com/questions/${t.question_id}`:"")}))}});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{cli as e,Strategy as t}from"@jackwener/opencli/registry";e({site:"stackoverflow",name:"unanswered",access:"read",description:"Top voted unanswered questions on Stack Overflow",domain:"stackoverflow.com",strategy:t.PUBLIC,browser:!1,args:[{name:"limit",type:"int",default:10,help:"Max number of results"}],columns:["rank","id","title","score","answers","views","tags","author","creation_date","url"],pipeline:[{fetch:{url:"https://api.stackexchange.com/2.3/questions/unanswered?order=desc&sort=votes&site=stackoverflow&pagesize=${{ args.limit }}"}},{select:"items"},{map:{rank:"${{ index + 1 }}",id:"${{ item.question_id }}",title:"${{ item.title }}",score:"${{ item.score }}",answers:"${{ item.answer_count }}",views:"${{ item.view_count }}",tags:"${{ item.tags | join(', ') }}",author:"${{ item.owner.display_name }}",creation_date:"${{ item.creation_date }}",url:"${{ item.link }}"}},{limit:"${{ args.limit }}"}]});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{cli as n,Strategy as c}from"@jackwener/opencli/registry";import{seFetch as l,normalizeLimit as d,requireString as m,epochToDate as a,ensureItems as u,decodeHtmlEntities as r}from"./utils.js";n({site:"stackoverflow",name:"user",access:"read",description:"Find Stack Overflow users by display name (highest reputation first).",domain:"stackoverflow.com",strategy:c.PUBLIC,browser:!1,args:[{name:"name",positional:!0,required:!0,type:"string",help:"Display name (or substring) to search."},{name:"limit",type:"int",default:10,help:"Max users to return (max 100)."}],columns:["userId","displayName","reputation","goldBadges","silverBadges","bronzeBadges","location","createdAt","lastAccessAt","url"],func:async(s)=>{const i=m(s.name,"name"),t=d(s.limit,10,100,"limit"),o=await l("/users",{searchParams:{inname:i,order:"desc",sort:"reputation",pagesize:t}});return u(o,"stackoverflow user").slice(0,t).map((e)=>({userId:e.user_id,displayName:r(e.display_name||""),reputation:e.reputation??0,goldBadges:e.badge_counts?.gold??0,silverBadges:e.badge_counts?.silver??0,bronzeBadges:e.badge_counts?.bronze??0,location:r(e.location||""),createdAt:a(e.creation_date),lastAccessAt:a(e.last_access_date),url:e.link||(e.user_id?`https://stackoverflow.com/users/${e.user_id}`:"")}))}});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ArgumentError as W,CommandExecutionError as O,EmptyResultError as X}from"@jackwener/opencli/errors";export const SE_API="https://api.stackexchange.com/2.3",SE_SITE="stackoverflow";const Z="opencli-stackoverflow (+https://github.com/jackwener/opencli)";export function normalizeLimit(q,z,B,G="limit"){const F=Number(q??z);if(!Number.isInteger(F)||F<=0)throw new W(`${G} must be a positive integer`);if(F>B)throw new W(`${G} must be <= ${B}`);return F}export function requireString(q,z){const B=String(q??"").trim();if(!B)throw new W(`${z} cannot be empty`);return B}export async function seFetch(q,{searchParams:z}={}){const B=new URL(q.startsWith("http")?q:`${SE_API}${q.startsWith("/")?"":"/"}${q}`);if(z)for(const[F,Q]of Object.entries(z)){if(Q==null||Q==="")continue;B.searchParams.set(F,String(Q))}if(!B.searchParams.has("site"))B.searchParams.set("site",SE_SITE);let G;try{G=await fetch(B,{headers:{Accept:"application/json","Accept-Encoding":"gzip","User-Agent":Z}})}catch(F){throw new O(`stack exchange request failed: ${F?.message||F}`)}if(G.status===429)throw new O("stack exchange returned HTTP 429 (rate limited)","Wait a few seconds and retry, or lower --limit.");if(!G.ok){let F="";try{F=(await G.json())?.error_message||""}catch{}throw new O(`stack exchange HTTP ${G.status}: ${F||G.statusText}`)}let K;try{K=await G.json()}catch(F){throw new O(`stack exchange returned malformed JSON: ${F?.message||F}`)}if(K?.error_id)throw new O(`stack exchange API error: ${K.error_message||K.error_name}`,"Inspect the URL in a browser for the canonical error context.");return K}export function epochToDate(q){if(q==null||q==="")return"";const z=Number(q);if(!Number.isFinite(z)||z<=0)return"";return new Date(z*1000).toISOString().slice(0,10)}export function ensureItems(q,z){const B=Array.isArray(q?.items)?q.items:[];if(B.length===0)throw new X(z,`${z} returned no items.`);return B}const $={"&":"&","<":"<",">":">",""":'"',"'":"'","'":"'"," ":" "};export function decodeHtmlEntities(q){if(q==null)return"";return String(q).replace(/&#x([0-9a-fA-F]+);/g,(z,B)=>String.fromCodePoint(parseInt(B,16))).replace(/&#(\d+);/g,(z,B)=>String.fromCodePoint(parseInt(B,10))).replace(/&(amp|lt|gt|quot|#39|apos|nbsp);/g,(z)=>$[z]||z)}
|