@jackwener/opencli 1.7.11 → 1.7.13

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.
Files changed (1004) hide show
  1. package/README.md +8 -7
  2. package/README.zh-CN.md +11 -9
  3. package/cli-manifest.json +12952 -6208
  4. package/clis/1688/assets.js +1 -0
  5. package/clis/1688/download.js +1 -0
  6. package/clis/1688/item.js +1 -0
  7. package/clis/1688/search.js +2 -1
  8. package/clis/1688/store.js +1 -0
  9. package/clis/1point3acres/digest.js +35 -0
  10. package/clis/1point3acres/forum.js +51 -0
  11. package/clis/1point3acres/forums.js +44 -0
  12. package/clis/1point3acres/hot.js +35 -0
  13. package/clis/1point3acres/latest.js +35 -0
  14. package/clis/1point3acres/notifications.js +64 -0
  15. package/clis/1point3acres/search.js +71 -0
  16. package/clis/1point3acres/thread.js +117 -0
  17. package/clis/1point3acres/user.js +77 -0
  18. package/clis/1point3acres/utils.js +247 -0
  19. package/clis/36kr/article.js +1 -0
  20. package/clis/36kr/hot.js +1 -0
  21. package/clis/36kr/news.js +1 -0
  22. package/clis/36kr/search.js +1 -0
  23. package/clis/51job/company.js +1 -0
  24. package/clis/51job/detail.js +1 -0
  25. package/clis/51job/hot.js +1 -0
  26. package/clis/51job/search.js +1 -0
  27. package/clis/_shared/desktop-commands.js +4 -0
  28. package/clis/aibase/news.js +110 -0
  29. package/clis/aibase/news.test.js +59 -0
  30. package/clis/amazon/bestsellers.js +1 -0
  31. package/clis/amazon/discussion.js +1 -0
  32. package/clis/amazon/discussion.test.js +1 -28
  33. package/clis/amazon/movers-shakers.js +1 -0
  34. package/clis/amazon/new-releases.js +1 -0
  35. package/clis/amazon/offer.js +1 -0
  36. package/clis/amazon/product.js +1 -0
  37. package/clis/amazon/rankings.js +1 -0
  38. package/clis/amazon/search.js +1 -0
  39. package/clis/antigravity/dump.js +1 -0
  40. package/clis/antigravity/extract-code.js +1 -0
  41. package/clis/antigravity/model.js +1 -0
  42. package/clis/antigravity/new.js +1 -0
  43. package/clis/antigravity/read.js +1 -0
  44. package/clis/antigravity/send.js +1 -0
  45. package/clis/antigravity/status.js +1 -0
  46. package/clis/antigravity/watch.js +4 -2
  47. package/clis/apple-podcasts/episodes.js +1 -0
  48. package/clis/apple-podcasts/search.js +1 -0
  49. package/clis/apple-podcasts/top.js +1 -0
  50. package/clis/arxiv/arxiv.test.js +112 -0
  51. package/clis/arxiv/author.js +44 -0
  52. package/clis/arxiv/paper.js +4 -3
  53. package/clis/arxiv/recent.js +33 -0
  54. package/clis/arxiv/search.js +19 -7
  55. package/clis/arxiv/utils.js +68 -5
  56. package/clis/baidu-scholar/search.js +1 -1
  57. package/clis/band/bands.js +1 -0
  58. package/clis/band/mentions.js +1 -0
  59. package/clis/band/post.js +1 -0
  60. package/clis/band/posts.js +1 -0
  61. package/clis/barchart/flow.js +1 -0
  62. package/clis/barchart/greeks.js +1 -0
  63. package/clis/barchart/options.js +1 -0
  64. package/clis/barchart/quote.js +1 -0
  65. package/clis/bbc/news.js +1 -0
  66. package/clis/bbc/topic.js +57 -0
  67. package/clis/bbc/utils.js +79 -0
  68. package/clis/bilibili/comments.js +1 -0
  69. package/clis/bilibili/download.js +1 -0
  70. package/clis/bilibili/dynamic.js +1 -0
  71. package/clis/bilibili/favorite.js +1 -0
  72. package/clis/bilibili/feed.js +2 -0
  73. package/clis/bilibili/following.js +1 -0
  74. package/clis/bilibili/history.js +1 -0
  75. package/clis/bilibili/hot.js +6 -1
  76. package/clis/bilibili/hot.test.js +17 -0
  77. package/clis/bilibili/me.js +1 -1
  78. package/clis/bilibili/ranking.js +1 -0
  79. package/clis/bilibili/search.js +1 -1
  80. package/clis/bilibili/subtitle.js +1 -0
  81. package/clis/bilibili/user-videos.js +1 -0
  82. package/clis/bilibili/video.js +1 -0
  83. package/clis/binance/asks.js +1 -0
  84. package/clis/binance/depth.js +1 -0
  85. package/clis/binance/gainers.js +1 -0
  86. package/clis/binance/klines.js +1 -0
  87. package/clis/binance/losers.js +1 -0
  88. package/clis/binance/pairs.js +1 -0
  89. package/clis/binance/price.js +1 -0
  90. package/clis/binance/prices.js +1 -0
  91. package/clis/binance/ticker.js +1 -0
  92. package/clis/binance/top.js +1 -0
  93. package/clis/binance/trades.js +1 -0
  94. package/clis/bloomberg/businessweek.js +1 -0
  95. package/clis/bloomberg/economics.js +1 -0
  96. package/clis/bloomberg/feeds.js +1 -0
  97. package/clis/bloomberg/industries.js +1 -0
  98. package/clis/bloomberg/main.js +1 -0
  99. package/clis/bloomberg/markets.js +1 -0
  100. package/clis/bloomberg/news.js +1 -0
  101. package/clis/bloomberg/opinions.js +1 -0
  102. package/clis/bloomberg/politics.js +1 -0
  103. package/clis/bloomberg/tech.js +1 -0
  104. package/clis/bluesky/feeds.js +1 -0
  105. package/clis/bluesky/followers.js +1 -0
  106. package/clis/bluesky/following.js +1 -0
  107. package/clis/bluesky/profile.js +1 -0
  108. package/clis/bluesky/search.js +1 -0
  109. package/clis/bluesky/starter-packs.js +1 -0
  110. package/clis/bluesky/thread.js +1 -0
  111. package/clis/bluesky/trending.js +1 -0
  112. package/clis/bluesky/user.js +3 -1
  113. package/clis/boss/batchgreet.js +1 -0
  114. package/clis/boss/chatlist.js +1 -0
  115. package/clis/boss/chatmsg.js +1 -0
  116. package/clis/boss/detail.js +1 -0
  117. package/clis/boss/exchange.js +1 -0
  118. package/clis/boss/greet.js +1 -0
  119. package/clis/boss/invite.js +1 -0
  120. package/clis/boss/joblist.js +1 -0
  121. package/clis/boss/mark.js +1 -0
  122. package/clis/boss/recommend.js +1 -0
  123. package/clis/boss/resume.js +1 -0
  124. package/clis/boss/search.js +1 -0
  125. package/clis/boss/send.js +1 -0
  126. package/clis/boss/stats.js +1 -0
  127. package/clis/chaoxing/assignments.js +2 -1
  128. package/clis/chaoxing/exams.js +2 -1
  129. package/clis/chatgpt/ask.js +57 -0
  130. package/clis/chatgpt/commands.test.js +45 -0
  131. package/clis/chatgpt/detail.js +46 -0
  132. package/clis/chatgpt/history.js +39 -0
  133. package/clis/chatgpt/image.js +13 -11
  134. package/clis/chatgpt/image.test.js +23 -0
  135. package/clis/chatgpt/new.js +25 -0
  136. package/clis/chatgpt/read.js +43 -0
  137. package/clis/chatgpt/send.js +46 -0
  138. package/clis/chatgpt/status.js +29 -0
  139. package/clis/chatgpt/utils.js +294 -4
  140. package/clis/chatgpt/utils.test.js +13 -0
  141. package/clis/chatgpt-app/ask.js +7 -3
  142. package/clis/chatgpt-app/model.js +1 -0
  143. package/clis/chatgpt-app/new.js +1 -0
  144. package/clis/chatgpt-app/read.js +1 -0
  145. package/clis/chatgpt-app/send.js +1 -0
  146. package/clis/chatgpt-app/status.js +1 -0
  147. package/clis/chatwise/ask.js +17 -43
  148. package/clis/chatwise/composer.test.js +186 -0
  149. package/clis/chatwise/export.js +1 -0
  150. package/clis/chatwise/history.js +1 -0
  151. package/clis/chatwise/model.js +1 -0
  152. package/clis/chatwise/read.js +1 -0
  153. package/clis/chatwise/send.js +3 -24
  154. package/clis/chatwise/utils.js +143 -0
  155. package/clis/claude/ask.js +2 -1
  156. package/clis/claude/detail.js +2 -0
  157. package/clis/claude/history.js +2 -0
  158. package/clis/claude/new.js +2 -0
  159. package/clis/claude/read.js +2 -0
  160. package/clis/claude/send.js +2 -0
  161. package/clis/claude/status.js +2 -0
  162. package/clis/cnki/search.js +1 -0
  163. package/clis/codex/ask.js +16 -9
  164. package/clis/codex/export.js +1 -0
  165. package/clis/codex/extract-diff.js +1 -0
  166. package/clis/codex/history.js +17 -33
  167. package/clis/codex/model.js +1 -0
  168. package/clis/codex/projects.js +28 -0
  169. package/clis/codex/read.js +11 -4
  170. package/clis/codex/send.js +11 -3
  171. package/clis/codex/sidebar.js +356 -0
  172. package/clis/codex/sidebar.test.js +329 -0
  173. package/clis/coingecko/categories.js +75 -0
  174. package/clis/coingecko/coin.js +107 -0
  175. package/clis/coingecko/coingecko.test.js +109 -0
  176. package/clis/coingecko/derivatives.js +84 -0
  177. package/clis/coingecko/exchanges.js +74 -0
  178. package/clis/coingecko/global.js +71 -0
  179. package/clis/coingecko/top.js +64 -0
  180. package/clis/coingecko/trending.js +55 -0
  181. package/clis/coupang/add-to-cart.js +22 -13
  182. package/clis/coupang/coupang.test.js +159 -0
  183. package/clis/coupang/product.js +257 -0
  184. package/clis/coupang/search.js +39 -16
  185. package/clis/coupang/utils.js +55 -1
  186. package/clis/crates/crate.js +62 -0
  187. package/clis/crates/search.js +44 -0
  188. package/clis/crates/utils.js +72 -0
  189. package/clis/ctrip/ctrip.test.js +234 -0
  190. package/clis/ctrip/hotel-suggest.js +45 -0
  191. package/clis/ctrip/search.js +23 -68
  192. package/clis/ctrip/utils.js +175 -0
  193. package/clis/cursor/ask.js +7 -3
  194. package/clis/cursor/composer.js +1 -0
  195. package/clis/cursor/export.js +1 -0
  196. package/clis/cursor/extract-code.js +1 -0
  197. package/clis/cursor/history.js +1 -0
  198. package/clis/cursor/model.js +1 -0
  199. package/clis/cursor/read.js +1 -0
  200. package/clis/cursor/send.js +1 -0
  201. package/clis/dblp/author.js +133 -0
  202. package/clis/dblp/dblp.test.js +397 -0
  203. package/clis/dblp/paper.js +40 -0
  204. package/clis/dblp/search.js +45 -0
  205. package/clis/dblp/utils.js +290 -0
  206. package/clis/dblp/venue.js +64 -0
  207. package/clis/deepseek/ask.js +13 -7
  208. package/clis/deepseek/ask.test.js +13 -13
  209. package/clis/deepseek/detail.js +38 -0
  210. package/clis/deepseek/detail.test.js +81 -0
  211. package/clis/deepseek/history.js +2 -0
  212. package/clis/deepseek/new.js +2 -0
  213. package/clis/deepseek/read.js +2 -0
  214. package/clis/deepseek/send.js +140 -0
  215. package/clis/deepseek/send.test.js +107 -0
  216. package/clis/deepseek/status.js +2 -0
  217. package/clis/deepseek/utils.js +66 -0
  218. package/clis/deepseek/utils.test.js +107 -1
  219. package/clis/defillama/defillama.test.js +99 -0
  220. package/clis/defillama/protocol.js +84 -0
  221. package/clis/defillama/protocols.js +55 -0
  222. package/clis/defillama/utils.js +99 -0
  223. package/clis/devto/devto.test.js +236 -0
  224. package/clis/devto/latest.js +74 -0
  225. package/clis/devto/read.js +103 -0
  226. package/clis/devto/tag.js +5 -1
  227. package/clis/devto/top.js +5 -1
  228. package/clis/devto/user.js +5 -1
  229. package/clis/dianping/__fixtures__/search.html +168 -0
  230. package/clis/dianping/__fixtures__/shop.html +6 -0
  231. package/clis/dianping/dianping.test.js +424 -0
  232. package/clis/dianping/search.js +154 -0
  233. package/clis/dianping/shop.js +173 -0
  234. package/clis/dianping/utils.js +157 -0
  235. package/clis/dictionary/examples.js +1 -0
  236. package/clis/dictionary/search.js +1 -0
  237. package/clis/dictionary/synonyms.js +1 -0
  238. package/clis/discord-app/channels.js +1 -0
  239. package/clis/discord-app/delete.js +1 -0
  240. package/clis/discord-app/members.js +1 -0
  241. package/clis/discord-app/read.js +1 -0
  242. package/clis/discord-app/search.js +1 -0
  243. package/clis/discord-app/send.js +1 -0
  244. package/clis/discord-app/servers.js +1 -0
  245. package/clis/discord-app/status.js +1 -0
  246. package/clis/dockerhub/image.js +52 -0
  247. package/clis/dockerhub/search.js +47 -0
  248. package/clis/dockerhub/utils.js +100 -0
  249. package/clis/douban/book-hot.js +1 -0
  250. package/clis/douban/download.js +1 -0
  251. package/clis/douban/marks.js +1 -0
  252. package/clis/douban/movie-hot.js +2 -1
  253. package/clis/douban/movie-hot.test.js +14 -0
  254. package/clis/douban/photos.js +2 -1
  255. package/clis/douban/reviews.js +1 -0
  256. package/clis/douban/search.js +1 -0
  257. package/clis/douban/subject.js +1 -0
  258. package/clis/douban/top250.js +1 -0
  259. package/clis/douban/utils.js +11 -13
  260. package/clis/douban/utils.test.js +79 -0
  261. package/clis/doubao/ask.js +8 -3
  262. package/clis/doubao/detail.js +2 -0
  263. package/clis/doubao/history.js +2 -0
  264. package/clis/doubao/meeting-summary.js +2 -0
  265. package/clis/doubao/meeting-transcript.js +2 -0
  266. package/clis/doubao/new.js +2 -0
  267. package/clis/doubao/read.js +2 -0
  268. package/clis/doubao/send.js +2 -0
  269. package/clis/doubao/status.js +2 -0
  270. package/clis/doubao-app/ask.js +1 -0
  271. package/clis/doubao-app/dump.js +1 -0
  272. package/clis/doubao-app/new.js +1 -0
  273. package/clis/doubao-app/read.js +1 -0
  274. package/clis/doubao-app/screenshot.js +1 -0
  275. package/clis/doubao-app/send.js +1 -0
  276. package/clis/doubao-app/status.js +1 -0
  277. package/clis/douyin/activities.js +1 -0
  278. package/clis/douyin/collections.js +1 -0
  279. package/clis/douyin/delete.js +1 -0
  280. package/clis/douyin/draft.js +1 -0
  281. package/clis/douyin/draft.test.js +1 -30
  282. package/clis/douyin/drafts.js +1 -0
  283. package/clis/douyin/hashtag.js +1 -0
  284. package/clis/douyin/location.js +1 -0
  285. package/clis/douyin/profile.js +1 -0
  286. package/clis/douyin/publish.js +1 -0
  287. package/clis/douyin/stats.js +1 -0
  288. package/clis/douyin/update.js +1 -0
  289. package/clis/douyin/user-videos.js +1 -0
  290. package/clis/douyin/videos.js +1 -0
  291. package/clis/eastmoney/announcement.js +1 -0
  292. package/clis/eastmoney/convertible.js +1 -0
  293. package/clis/eastmoney/etf.js +1 -0
  294. package/clis/eastmoney/holders.js +1 -0
  295. package/clis/eastmoney/hot-rank.js +1 -0
  296. package/clis/eastmoney/index-board.js +1 -0
  297. package/clis/eastmoney/kline.js +1 -0
  298. package/clis/eastmoney/kuaixun.js +1 -0
  299. package/clis/eastmoney/longhu.js +1 -0
  300. package/clis/eastmoney/money-flow.js +1 -0
  301. package/clis/eastmoney/northbound.js +1 -0
  302. package/clis/eastmoney/quote.js +1 -0
  303. package/clis/eastmoney/rank.js +1 -0
  304. package/clis/eastmoney/sectors.js +1 -0
  305. package/clis/endoflife/endoflife.test.js +51 -0
  306. package/clis/endoflife/product.js +55 -0
  307. package/clis/endoflife/utils.js +89 -0
  308. package/clis/facebook/__fixtures__/notifications-page.html +13 -0
  309. package/clis/facebook/add-friend.js +1 -0
  310. package/clis/facebook/events.js +1 -0
  311. package/clis/facebook/feed.js +1 -0
  312. package/clis/facebook/friends.js +1 -0
  313. package/clis/facebook/groups.js +1 -0
  314. package/clis/facebook/join-group.js +1 -0
  315. package/clis/facebook/marketplace-inbox.js +1 -0
  316. package/clis/facebook/marketplace-listings.js +1 -0
  317. package/clis/facebook/memories.js +1 -0
  318. package/clis/facebook/notifications.js +327 -30
  319. package/clis/facebook/notifications.test.js +458 -0
  320. package/clis/facebook/profile.js +1 -0
  321. package/clis/facebook/search.js +1 -0
  322. package/clis/flathub/app.js +71 -0
  323. package/clis/flathub/flathub.test.js +90 -0
  324. package/clis/flathub/search.js +80 -0
  325. package/clis/flathub/utils.js +114 -0
  326. package/clis/gemini/ask.js +8 -3
  327. package/clis/gemini/ask.test.js +2 -2
  328. package/clis/gemini/deep-research-result.js +7 -2
  329. package/clis/gemini/deep-research-result.test.js +15 -14
  330. package/clis/gemini/deep-research.js +9 -4
  331. package/clis/gemini/deep-research.test.js +15 -18
  332. package/clis/gemini/image.js +8 -2
  333. package/clis/gemini/new.js +2 -0
  334. package/clis/gemini/utils.js +0 -4
  335. package/clis/gitee/search.js +1 -0
  336. package/clis/gitee/trending.js +1 -0
  337. package/clis/gitee/user.js +1 -0
  338. package/clis/google/news.js +1 -0
  339. package/clis/google/search.js +1 -0
  340. package/clis/google/suggest.js +1 -0
  341. package/clis/google/trends.js +1 -0
  342. package/clis/google-scholar/cite.js +1 -1
  343. package/clis/google-scholar/profile.js +1 -1
  344. package/clis/google-scholar/search.js +1 -1
  345. package/clis/goproxy/goproxy.test.js +103 -0
  346. package/clis/goproxy/module.js +47 -0
  347. package/clis/goproxy/utils.js +165 -0
  348. package/clis/goproxy/versions.js +59 -0
  349. package/clis/gov-law/recent.js +1 -1
  350. package/clis/gov-law/search.js +1 -1
  351. package/clis/gov-policy/__fixtures__/recent.html +16 -0
  352. package/clis/gov-policy/__fixtures__/search.html +41 -0
  353. package/clis/gov-policy/gov-policy.test.js +224 -0
  354. package/clis/gov-policy/recent.js +67 -24
  355. package/clis/gov-policy/search.js +66 -23
  356. package/clis/gov-policy/utils.js +54 -0
  357. package/clis/grok/ask.js +50 -265
  358. package/clis/grok/ask.test.js +21 -46
  359. package/clis/grok/detail.js +60 -0
  360. package/clis/grok/history.js +48 -0
  361. package/clis/grok/{image.ts → image.js} +57 -70
  362. package/clis/grok/image.test.ts +20 -0
  363. package/clis/grok/new.js +20 -0
  364. package/clis/grok/read.js +39 -0
  365. package/clis/grok/send.js +50 -0
  366. package/clis/grok/status.js +41 -0
  367. package/clis/grok/utils.js +326 -0
  368. package/clis/grok/utils.test.js +103 -0
  369. package/clis/hackernews/ask.js +3 -1
  370. package/clis/hackernews/best.js +3 -1
  371. package/clis/hackernews/hackernews.test.js +132 -0
  372. package/clis/hackernews/jobs.js +3 -1
  373. package/clis/hackernews/new.js +3 -1
  374. package/clis/hackernews/read.js +188 -0
  375. package/clis/hackernews/search.js +3 -1
  376. package/clis/hackernews/show.js +3 -1
  377. package/clis/hackernews/top.js +3 -1
  378. package/clis/hackernews/user.js +1 -0
  379. package/clis/hf/datasets.js +88 -0
  380. package/clis/hf/hf.test.js +16 -0
  381. package/clis/hf/models.js +91 -0
  382. package/clis/hf/paper.js +79 -0
  383. package/clis/hf/spaces.js +101 -0
  384. package/clis/hf/top.js +2 -0
  385. package/clis/homebrew/cask.js +39 -0
  386. package/clis/homebrew/formula.js +41 -0
  387. package/clis/homebrew/popular.js +54 -0
  388. package/clis/homebrew/utils.js +100 -0
  389. package/clis/hupu/__fixtures__/hot-home.html +64 -0
  390. package/clis/hupu/detail.js +1 -1
  391. package/clis/hupu/hot.js +157 -34
  392. package/clis/hupu/hot.test.js +224 -0
  393. package/clis/hupu/like.js +1 -0
  394. package/clis/hupu/mentions.js +2 -1
  395. package/clis/hupu/reply.js +1 -0
  396. package/clis/hupu/search.js +3 -2
  397. package/clis/hupu/unlike.js +1 -0
  398. package/clis/imdb/person.js +1 -0
  399. package/clis/imdb/reviews.js +1 -0
  400. package/clis/imdb/search.js +1 -0
  401. package/clis/imdb/title.js +1 -0
  402. package/clis/imdb/top.js +1 -0
  403. package/clis/imdb/trending.js +1 -0
  404. package/clis/indeed/indeed.test.js +375 -0
  405. package/clis/indeed/job.js +86 -0
  406. package/clis/indeed/search.js +110 -0
  407. package/clis/indeed/utils.js +152 -0
  408. package/clis/instagram/collection-create.js +1 -0
  409. package/clis/instagram/collection-delete.js +1 -0
  410. package/clis/instagram/comment.js +1 -0
  411. package/clis/instagram/download.js +1 -0
  412. package/clis/instagram/explore.js +1 -0
  413. package/clis/instagram/follow.js +1 -0
  414. package/clis/instagram/followers.js +1 -0
  415. package/clis/instagram/following.js +1 -0
  416. package/clis/instagram/like.js +1 -0
  417. package/clis/instagram/note.js +2 -1
  418. package/clis/instagram/note.test.js +1 -29
  419. package/clis/instagram/post.js +2 -1
  420. package/clis/instagram/post.test.js +1 -1
  421. package/clis/instagram/profile.js +1 -0
  422. package/clis/instagram/reel.js +2 -1
  423. package/clis/instagram/save.js +1 -0
  424. package/clis/instagram/saved.js +1 -0
  425. package/clis/instagram/search.js +1 -0
  426. package/clis/instagram/story.js +2 -1
  427. package/clis/instagram/story.test.js +1 -34
  428. package/clis/instagram/unfollow.js +1 -0
  429. package/clis/instagram/unlike.js +1 -0
  430. package/clis/instagram/unsave.js +1 -0
  431. package/clis/instagram/user.js +1 -0
  432. package/clis/jd/add-cart.js +1 -0
  433. package/clis/jd/cart.js +1 -0
  434. package/clis/jd/commands.test.js +1 -24
  435. package/clis/jd/detail.js +1 -0
  436. package/clis/jd/item.js +1 -0
  437. package/clis/jd/reviews.js +1 -0
  438. package/clis/jd/search.js +1 -0
  439. package/clis/jianyu/detail.js +1 -0
  440. package/clis/jianyu/search.js +1 -0
  441. package/clis/jike/comment.js +1 -0
  442. package/clis/jike/create.js +1 -0
  443. package/clis/jike/feed.js +3 -1
  444. package/clis/jike/like.js +1 -0
  445. package/clis/jike/notifications.js +1 -0
  446. package/clis/jike/post.js +1 -0
  447. package/clis/jike/repost.js +1 -0
  448. package/clis/jike/search.js +3 -1
  449. package/clis/jike/topic.js +1 -0
  450. package/clis/jike/user.js +3 -1
  451. package/clis/jimeng/generate.js +1 -0
  452. package/clis/jimeng/history.js +1 -0
  453. package/clis/jimeng/new.js +1 -0
  454. package/clis/jimeng/workspaces.js +1 -0
  455. package/clis/ke/chengjiao.js +1 -0
  456. package/clis/ke/ershoufang.js +1 -0
  457. package/clis/ke/xiaoqu.js +1 -0
  458. package/clis/ke/zufang.js +1 -0
  459. package/clis/lesswrong/comments.js +1 -0
  460. package/clis/lesswrong/curated.js +1 -0
  461. package/clis/lesswrong/frontpage.js +1 -0
  462. package/clis/lesswrong/new.js +1 -0
  463. package/clis/lesswrong/read.js +1 -0
  464. package/clis/lesswrong/sequences.js +1 -0
  465. package/clis/lesswrong/shortform.js +1 -0
  466. package/clis/lesswrong/tag.js +1 -0
  467. package/clis/lesswrong/tags.js +1 -0
  468. package/clis/lesswrong/top-month.js +1 -0
  469. package/clis/lesswrong/top-week.js +1 -0
  470. package/clis/lesswrong/top-year.js +1 -0
  471. package/clis/lesswrong/top.js +1 -0
  472. package/clis/lesswrong/user-posts.js +1 -0
  473. package/clis/lesswrong/user.js +1 -0
  474. package/clis/lichess/lichess.test.js +85 -0
  475. package/clis/lichess/top.js +46 -0
  476. package/clis/lichess/user.js +91 -0
  477. package/clis/lichess/utils.js +97 -0
  478. package/clis/linkedin/search.js +108 -10
  479. package/clis/linkedin/search.test.js +222 -0
  480. package/clis/linkedin/timeline.js +1 -0
  481. package/clis/linux-do/categories.js +1 -0
  482. package/clis/linux-do/feed.js +3 -5
  483. package/clis/linux-do/feed.test.js +35 -0
  484. package/clis/linux-do/search.js +1 -0
  485. package/clis/linux-do/tags.js +2 -1
  486. package/clis/linux-do/topic-content.js +1 -0
  487. package/clis/linux-do/topic.js +1 -0
  488. package/clis/linux-do/user-posts.js +1 -0
  489. package/clis/linux-do/user-topics.js +1 -0
  490. package/clis/lobsters/active.js +4 -1
  491. package/clis/lobsters/domain.js +92 -0
  492. package/clis/lobsters/hot.js +4 -1
  493. package/clis/lobsters/lobsters.test.js +169 -0
  494. package/clis/lobsters/newest.js +4 -1
  495. package/clis/lobsters/read.js +196 -0
  496. package/clis/lobsters/tag.js +4 -1
  497. package/clis/maimai/search-talents.js +1 -0
  498. package/clis/maven/artifact.js +49 -0
  499. package/clis/maven/search.js +51 -0
  500. package/clis/maven/utils.js +110 -0
  501. package/clis/mdn/search.js +97 -0
  502. package/clis/medium/feed.js +1 -0
  503. package/clis/medium/search.js +1 -0
  504. package/clis/medium/tag.js +135 -0
  505. package/clis/medium/user.js +1 -0
  506. package/clis/mubu/doc.js +1 -0
  507. package/clis/mubu/docs.js +1 -0
  508. package/clis/mubu/notes.js +1 -0
  509. package/clis/mubu/recent.js +1 -0
  510. package/clis/mubu/search.js +1 -0
  511. package/clis/notebooklm/current.js +1 -0
  512. package/clis/notebooklm/get.js +1 -0
  513. package/clis/notebooklm/history.js +1 -0
  514. package/clis/notebooklm/list.js +1 -0
  515. package/clis/notebooklm/note-list.js +1 -0
  516. package/clis/notebooklm/notes-get.js +1 -0
  517. package/clis/notebooklm/open.js +1 -0
  518. package/clis/notebooklm/source-fulltext.js +1 -0
  519. package/clis/notebooklm/source-get.js +1 -0
  520. package/clis/notebooklm/source-guide.js +1 -0
  521. package/clis/notebooklm/source-list.js +1 -0
  522. package/clis/notebooklm/status.js +1 -0
  523. package/clis/notebooklm/summary.js +1 -0
  524. package/clis/notion/export.js +1 -0
  525. package/clis/notion/favorites.js +1 -0
  526. package/clis/notion/new.js +1 -0
  527. package/clis/notion/read.js +1 -0
  528. package/clis/notion/search.js +1 -0
  529. package/clis/notion/sidebar.js +1 -0
  530. package/clis/notion/status.js +1 -0
  531. package/clis/notion/write.js +1 -0
  532. package/clis/nowcoder/companies.js +1 -0
  533. package/clis/nowcoder/creators.js +1 -0
  534. package/clis/nowcoder/detail.js +1 -0
  535. package/clis/nowcoder/experience.js +1 -0
  536. package/clis/nowcoder/hot.js +1 -0
  537. package/clis/nowcoder/jobs.js +1 -0
  538. package/clis/nowcoder/notifications.js +1 -0
  539. package/clis/nowcoder/papers.js +1 -0
  540. package/clis/nowcoder/practice.js +1 -0
  541. package/clis/nowcoder/recommend.js +1 -0
  542. package/clis/nowcoder/referral.js +1 -0
  543. package/clis/nowcoder/salary.js +1 -0
  544. package/clis/nowcoder/search.js +1 -0
  545. package/clis/nowcoder/suggest.js +1 -0
  546. package/clis/nowcoder/topics.js +1 -0
  547. package/clis/nowcoder/trending.js +1 -0
  548. package/clis/npm/downloads.js +59 -0
  549. package/clis/npm/package.js +70 -0
  550. package/clis/npm/search.js +49 -0
  551. package/clis/npm/utils.js +76 -0
  552. package/clis/nuget/nuget.test.js +111 -0
  553. package/clis/nuget/package.js +101 -0
  554. package/clis/nuget/search.js +69 -0
  555. package/clis/nuget/utils.js +87 -0
  556. package/clis/nvd/cve.js +121 -0
  557. package/clis/oeis/oeis.test.js +88 -0
  558. package/clis/oeis/search.js +63 -0
  559. package/clis/oeis/sequence.js +71 -0
  560. package/clis/oeis/utils.js +88 -0
  561. package/clis/ones/login.js +1 -0
  562. package/clis/ones/logout.js +1 -0
  563. package/clis/ones/me.js +1 -0
  564. package/clis/ones/my-tasks.js +1 -0
  565. package/clis/ones/task.js +1 -0
  566. package/clis/ones/tasks.js +1 -0
  567. package/clis/ones/token-info.js +1 -0
  568. package/clis/ones/worklog.js +1 -0
  569. package/clis/openalex/search.js +69 -0
  570. package/clis/openalex/utils.js +160 -0
  571. package/clis/openalex/work.js +65 -0
  572. package/clis/openfda/drug-label.js +74 -0
  573. package/clis/openfda/food-recall.js +65 -0
  574. package/clis/openfda/openfda.test.js +114 -0
  575. package/clis/openfda/utils.js +67 -0
  576. package/clis/openreview/openreview.test.js +345 -0
  577. package/clis/openreview/paper.js +43 -0
  578. package/clis/openreview/reviews.js +131 -0
  579. package/clis/openreview/search.js +46 -0
  580. package/clis/openreview/utils.js +158 -0
  581. package/clis/openreview/venue.js +63 -0
  582. package/clis/osv/osv.test.js +97 -0
  583. package/clis/osv/query.js +72 -0
  584. package/clis/osv/utils.js +169 -0
  585. package/clis/osv/vulnerability.js +54 -0
  586. package/clis/packagist/package.js +49 -0
  587. package/clis/packagist/search.js +43 -0
  588. package/clis/packagist/utils.js +113 -0
  589. package/clis/paperreview/feedback.js +2 -1
  590. package/clis/paperreview/review.js +2 -1
  591. package/clis/paperreview/submit.js +2 -1
  592. package/clis/pixiv/detail.js +1 -0
  593. package/clis/pixiv/download.js +1 -0
  594. package/clis/pixiv/download.test.js +1 -1
  595. package/clis/pixiv/illusts.js +2 -1
  596. package/clis/pixiv/illusts.test.js +1 -1
  597. package/clis/pixiv/ranking.js +2 -1
  598. package/clis/pixiv/search.js +2 -1
  599. package/clis/pixiv/search.test.js +1 -1
  600. package/clis/pixiv/user.js +2 -0
  601. package/clis/powerchina/search.js +1 -0
  602. package/clis/producthunt/browse.js +1 -0
  603. package/clis/producthunt/hot.js +1 -0
  604. package/clis/producthunt/posts.js +1 -0
  605. package/clis/producthunt/today.js +1 -0
  606. package/clis/pubmed/article.js +50 -0
  607. package/clis/pubmed/author.js +64 -0
  608. package/clis/pubmed/citations.js +36 -0
  609. package/clis/pubmed/pubmed.test.js +276 -0
  610. package/clis/pubmed/related.js +45 -0
  611. package/clis/pubmed/search.js +75 -0
  612. package/clis/pubmed/utils.js +309 -0
  613. package/clis/pypi/downloads.js +66 -0
  614. package/clis/pypi/package.js +79 -0
  615. package/clis/pypi/utils.js +55 -0
  616. package/clis/quark/ls.js +1 -0
  617. package/clis/quark/mkdir.js +1 -0
  618. package/clis/quark/mv.js +2 -1
  619. package/clis/quark/rename.js +1 -0
  620. package/clis/quark/rm.js +1 -0
  621. package/clis/quark/save.js +2 -1
  622. package/clis/quark/share-tree.js +1 -0
  623. package/clis/qwen/ask.js +85 -0
  624. package/clis/qwen/detail.js +62 -0
  625. package/clis/qwen/history.js +61 -0
  626. package/clis/qwen/image.js +179 -0
  627. package/clis/qwen/new.js +23 -0
  628. package/clis/qwen/read.js +41 -0
  629. package/clis/qwen/send.js +55 -0
  630. package/clis/qwen/status.js +37 -0
  631. package/clis/qwen/utils.js +409 -0
  632. package/clis/qwen/utils.test.js +45 -0
  633. package/clis/reddit/comment.js +1 -0
  634. package/clis/reddit/frontpage.js +1 -0
  635. package/clis/reddit/hot.js +6 -1
  636. package/clis/reddit/hot.test.js +18 -0
  637. package/clis/reddit/popular.js +1 -0
  638. package/clis/reddit/read.js +1 -0
  639. package/clis/reddit/save.js +1 -0
  640. package/clis/reddit/saved.js +1 -0
  641. package/clis/reddit/search.js +1 -0
  642. package/clis/reddit/subreddit.js +1 -0
  643. package/clis/reddit/subscribe.js +1 -0
  644. package/clis/reddit/upvote.js +1 -0
  645. package/clis/reddit/upvoted.js +1 -0
  646. package/clis/reddit/user-comments.js +1 -0
  647. package/clis/reddit/user-posts.js +1 -0
  648. package/clis/reddit/user.js +1 -0
  649. package/clis/rest-countries/country.js +65 -0
  650. package/clis/rest-countries/region.js +64 -0
  651. package/clis/rest-countries/rest-countries.test.js +83 -0
  652. package/clis/rest-countries/utils.js +126 -0
  653. package/clis/reuters/article-detail.js +53 -0
  654. package/clis/reuters/reuters.test.js +299 -0
  655. package/clis/reuters/search.js +46 -34
  656. package/clis/reuters/utils.js +159 -0
  657. package/clis/rfc/rfc.js +52 -0
  658. package/clis/rfc/rfc.test.js +74 -0
  659. package/clis/rfc/utils.js +72 -0
  660. package/clis/rubygems/gem.js +42 -0
  661. package/clis/rubygems/search.js +47 -0
  662. package/clis/rubygems/utils.js +86 -0
  663. package/clis/sinablog/article.js +1 -0
  664. package/clis/sinablog/hot.js +1 -0
  665. package/clis/sinablog/search.js +1 -0
  666. package/clis/sinablog/user.js +1 -0
  667. package/clis/sinafinance/news.js +1 -0
  668. package/clis/sinafinance/rolling-news.js +1 -0
  669. package/clis/sinafinance/stock-rank.js +1 -0
  670. package/clis/sinafinance/stock.js +1 -0
  671. package/clis/smzdm/search.js +1 -0
  672. package/clis/spotify/spotify.js +11 -0
  673. package/clis/stackoverflow/bounties.js +11 -3
  674. package/clis/stackoverflow/hot.js +10 -2
  675. package/clis/stackoverflow/read.js +314 -0
  676. package/clis/stackoverflow/related.js +66 -0
  677. package/clis/stackoverflow/search.js +10 -2
  678. package/clis/stackoverflow/stackoverflow.test.js +404 -0
  679. package/clis/stackoverflow/tag.js +60 -0
  680. package/clis/stackoverflow/unanswered.js +9 -2
  681. package/clis/stackoverflow/user.js +50 -0
  682. package/clis/stackoverflow/utils.js +118 -0
  683. package/clis/steam/app.js +67 -0
  684. package/clis/steam/search.js +58 -0
  685. package/clis/steam/steam.test.js +46 -0
  686. package/clis/steam/top-sellers.js +1 -0
  687. package/clis/steam/utils.js +107 -0
  688. package/clis/substack/feed.js +1 -0
  689. package/clis/substack/publication.js +1 -0
  690. package/clis/substack/search.js +1 -0
  691. package/clis/taobao/add-cart.js +1 -0
  692. package/clis/taobao/cart.js +1 -0
  693. package/clis/taobao/commands.test.js +1 -24
  694. package/clis/taobao/detail.js +1 -0
  695. package/clis/taobao/reviews.js +1 -0
  696. package/clis/taobao/search.js +1 -0
  697. package/clis/tdx/hot-rank.js +1 -0
  698. package/clis/test-utils.js +61 -0
  699. package/clis/ths/hot-rank.js +1 -0
  700. package/clis/tieba/hot.js +2 -2
  701. package/clis/tieba/posts.js +1 -0
  702. package/clis/tieba/read.js +1 -0
  703. package/clis/tieba/search.js +2 -1
  704. package/clis/tiktok/comment.js +128 -40
  705. package/clis/tiktok/creator-videos.js +270 -0
  706. package/clis/tiktok/creator-videos.test.js +113 -0
  707. package/clis/tiktok/explore.js +138 -29
  708. package/clis/tiktok/follow.js +116 -33
  709. package/clis/tiktok/following.js +157 -35
  710. package/clis/tiktok/friends.js +140 -37
  711. package/clis/tiktok/like.js +1 -0
  712. package/clis/tiktok/live.js +138 -41
  713. package/clis/tiktok/notifications.js +142 -38
  714. package/clis/tiktok/profile.js +1 -0
  715. package/clis/tiktok/refactor.test.js +389 -0
  716. package/clis/tiktok/save.js +1 -0
  717. package/clis/tiktok/search.js +1 -0
  718. package/clis/tiktok/unfollow.js +125 -38
  719. package/clis/tiktok/unlike.js +1 -0
  720. package/clis/tiktok/unsave.js +1 -0
  721. package/clis/tiktok/user.js +204 -29
  722. package/clis/tiktok/utils.js +505 -0
  723. package/clis/tiktok/write-refactor.test.js +370 -0
  724. package/clis/toutiao/articles.js +37 -62
  725. package/clis/toutiao/hot.js +63 -0
  726. package/clis/toutiao/toutiao.test.js +378 -0
  727. package/clis/toutiao/utils.js +161 -0
  728. package/clis/tvmaze/search.js +61 -0
  729. package/clis/tvmaze/show.js +60 -0
  730. package/clis/tvmaze/tvmaze.test.js +93 -0
  731. package/clis/tvmaze/utils.js +110 -0
  732. package/clis/twitter/accept.js +2 -1
  733. package/clis/twitter/article.js +1 -0
  734. package/clis/twitter/block.js +1 -0
  735. package/clis/twitter/bookmark.js +1 -0
  736. package/clis/twitter/bookmarks.js +2 -1
  737. package/clis/twitter/delete.js +1 -0
  738. package/clis/twitter/download.js +1 -0
  739. package/clis/twitter/follow.js +1 -0
  740. package/clis/twitter/followers.js +135 -69
  741. package/clis/twitter/following.js +1 -0
  742. package/clis/twitter/hide-reply.js +1 -0
  743. package/clis/twitter/like.js +1 -0
  744. package/clis/twitter/likes.js +2 -1
  745. package/clis/twitter/list-add.js +1 -0
  746. package/clis/twitter/list-remove.js +1 -0
  747. package/clis/twitter/list-tweets.js +1 -0
  748. package/clis/twitter/lists.js +1 -0
  749. package/clis/twitter/notifications.js +1 -0
  750. package/clis/twitter/post.js +1 -0
  751. package/clis/twitter/profile.js +1 -0
  752. package/clis/twitter/reply-dm.js +2 -1
  753. package/clis/twitter/reply.js +1 -0
  754. package/clis/twitter/reply.test.js +1 -29
  755. package/clis/twitter/search.js +1 -0
  756. package/clis/twitter/thread.js +1 -0
  757. package/clis/twitter/timeline.js +1 -0
  758. package/clis/twitter/trending.js +11 -12
  759. package/clis/twitter/trending.test.js +15 -0
  760. package/clis/twitter/tweets.js +2 -1
  761. package/clis/twitter/tweets.test.js +2 -2
  762. package/clis/twitter/unblock.js +1 -0
  763. package/clis/twitter/unbookmark.js +1 -0
  764. package/clis/twitter/unfollow.js +1 -0
  765. package/clis/uisdc/news.js +105 -0
  766. package/clis/uisdc/news.test.js +66 -0
  767. package/clis/uiverse/code.js +1 -0
  768. package/clis/uiverse/preview.js +1 -0
  769. package/clis/v2ex/daily.js +1 -0
  770. package/clis/v2ex/hot.js +1 -0
  771. package/clis/v2ex/latest.js +1 -0
  772. package/clis/v2ex/me.js +1 -0
  773. package/clis/v2ex/member.js +1 -0
  774. package/clis/v2ex/node.js +1 -0
  775. package/clis/v2ex/nodes.js +1 -0
  776. package/clis/v2ex/notifications.js +1 -0
  777. package/clis/v2ex/replies.js +1 -0
  778. package/clis/v2ex/topic.js +1 -0
  779. package/clis/v2ex/user.js +1 -0
  780. package/clis/wanfang/search.js +1 -1
  781. package/clis/web/read.js +48 -17
  782. package/clis/web/read.test.js +101 -1
  783. package/clis/weibo/comments.js +1 -0
  784. package/clis/weibo/favorites.js +1 -0
  785. package/clis/weibo/feed.js +3 -1
  786. package/clis/weibo/hot.js +1 -0
  787. package/clis/weibo/me.js +1 -0
  788. package/clis/weibo/post.js +1 -0
  789. package/clis/weibo/publish.js +1 -0
  790. package/clis/weibo/search.js +8 -2
  791. package/clis/weibo/user.js +1 -0
  792. package/clis/weixin/create-draft.js +2 -1
  793. package/clis/weixin/download.js +1 -0
  794. package/clis/weixin/drafts.js +2 -1
  795. package/clis/weixin/drafts.test.js +5 -1
  796. package/clis/weixin/search.js +157 -0
  797. package/clis/weixin/search.test.js +227 -0
  798. package/clis/weread/ai-outline.js +1 -0
  799. package/clis/weread/book.js +1 -0
  800. package/clis/weread/highlights.js +1 -0
  801. package/clis/weread/notebooks.js +1 -0
  802. package/clis/weread/notes.js +1 -0
  803. package/clis/weread/ranking.js +1 -0
  804. package/clis/weread/search.js +1 -0
  805. package/clis/weread/shelf.js +1 -0
  806. package/clis/wikidata/entity.js +60 -0
  807. package/clis/wikidata/search.js +50 -0
  808. package/clis/wikidata/utils.js +117 -0
  809. package/clis/wikidata/wikidata.test.js +83 -0
  810. package/clis/wikipedia/page.js +95 -0
  811. package/clis/wikipedia/random.js +1 -0
  812. package/clis/wikipedia/search.js +1 -0
  813. package/clis/wikipedia/summary.js +1 -0
  814. package/clis/wikipedia/trending.js +1 -0
  815. package/clis/wttr/current.js +63 -0
  816. package/clis/wttr/forecast.js +71 -0
  817. package/clis/wttr/utils.js +50 -0
  818. package/clis/wttr/wttr.test.js +84 -0
  819. package/clis/xianyu/chat.js +17 -4
  820. package/clis/xianyu/chat.test.js +64 -0
  821. package/clis/xianyu/item.js +1 -0
  822. package/clis/xianyu/publish.js +485 -0
  823. package/clis/xianyu/publish.test.js +220 -0
  824. package/clis/xianyu/search.js +1 -0
  825. package/clis/xiaoe/catalog.js +105 -39
  826. package/clis/xiaoe/content.js +165 -29
  827. package/clis/xiaoe/courses.js +86 -28
  828. package/clis/xiaoe/detail.js +1 -0
  829. package/clis/xiaoe/play-url.js +1 -0
  830. package/clis/xiaoe/xiaoe.test.js +486 -0
  831. package/clis/xiaohongshu/comments.js +1 -0
  832. package/clis/xiaohongshu/creator-note-detail.js +1 -0
  833. package/clis/xiaohongshu/creator-notes-summary.js +2 -1
  834. package/clis/xiaohongshu/creator-notes.js +1 -0
  835. package/clis/xiaohongshu/creator-profile.js +1 -0
  836. package/clis/xiaohongshu/creator-stats.js +1 -0
  837. package/clis/xiaohongshu/download.js +1 -0
  838. package/clis/xiaohongshu/feed.js +2 -1
  839. package/clis/xiaohongshu/note.js +1 -0
  840. package/clis/xiaohongshu/notifications.js +1 -0
  841. package/clis/xiaohongshu/publish.js +17 -3
  842. package/clis/xiaohongshu/publish.test.js +46 -1
  843. package/clis/xiaohongshu/search.js +1 -0
  844. package/clis/xiaohongshu/user.js +1 -0
  845. package/clis/xiaoyuzhou/download.js +1 -0
  846. package/clis/xiaoyuzhou/episode.js +1 -0
  847. package/clis/xiaoyuzhou/podcast-episodes.js +1 -0
  848. package/clis/xiaoyuzhou/podcast.js +1 -0
  849. package/clis/xiaoyuzhou/transcript.js +1 -0
  850. package/clis/xueqiu/comments.js +1 -0
  851. package/clis/xueqiu/earnings-date.js +1 -0
  852. package/clis/xueqiu/feed.js +1 -0
  853. package/clis/xueqiu/fund-holdings.js +1 -0
  854. package/clis/xueqiu/fund-snapshot.js +1 -0
  855. package/clis/xueqiu/groups.js +1 -0
  856. package/clis/xueqiu/hot-stock.js +1 -0
  857. package/clis/xueqiu/hot.js +1 -0
  858. package/clis/xueqiu/kline.js +1 -0
  859. package/clis/xueqiu/search.js +1 -0
  860. package/clis/xueqiu/stock.js +1 -0
  861. package/clis/xueqiu/watchlist.js +1 -0
  862. package/clis/yahoo-finance/quote.js +1 -0
  863. package/clis/yollomi/background.js +1 -0
  864. package/clis/yollomi/edit.js +1 -0
  865. package/clis/yollomi/face-swap.js +1 -0
  866. package/clis/yollomi/generate.js +1 -0
  867. package/clis/yollomi/models.js +1 -0
  868. package/clis/yollomi/object-remover.js +1 -0
  869. package/clis/yollomi/remove-bg.js +1 -0
  870. package/clis/yollomi/restore.js +1 -0
  871. package/clis/yollomi/try-on.js +1 -0
  872. package/clis/yollomi/upload.js +1 -0
  873. package/clis/yollomi/upscale.js +1 -0
  874. package/clis/yollomi/video.js +1 -0
  875. package/clis/youtube/channel.js +1 -0
  876. package/clis/youtube/comments.js +1 -0
  877. package/clis/youtube/feed.js +8 -7
  878. package/clis/youtube/feed.test.js +131 -0
  879. package/clis/youtube/history.js +1 -0
  880. package/clis/youtube/like.js +1 -0
  881. package/clis/youtube/playlist.js +1 -0
  882. package/clis/youtube/search.js +1 -0
  883. package/clis/youtube/subscribe.js +1 -0
  884. package/clis/youtube/subscriptions.js +1 -0
  885. package/clis/youtube/transcript.js +14 -19
  886. package/clis/youtube/transcript.test.js +17 -0
  887. package/clis/youtube/unlike.js +1 -0
  888. package/clis/youtube/unsubscribe.js +1 -0
  889. package/clis/youtube/video.js +1 -0
  890. package/clis/youtube/watch-later.js +1 -0
  891. package/clis/yuanbao/ask.js +18 -66
  892. package/clis/yuanbao/ask.test.js +5 -5
  893. package/clis/yuanbao/detail.js +65 -0
  894. package/clis/yuanbao/history.js +51 -0
  895. package/clis/yuanbao/new.js +2 -0
  896. package/clis/yuanbao/read.js +38 -0
  897. package/clis/yuanbao/send.js +57 -0
  898. package/clis/yuanbao/shared.js +297 -5
  899. package/clis/yuanbao/shared.test.js +80 -0
  900. package/clis/yuanbao/status.js +44 -0
  901. package/clis/zhihu/answer.js +1 -0
  902. package/clis/zhihu/collection.js +1 -0
  903. package/clis/zhihu/collections.js +1 -0
  904. package/clis/zhihu/comment.js +1 -0
  905. package/clis/zhihu/download.js +1 -0
  906. package/clis/zhihu/favorite.js +1 -0
  907. package/clis/zhihu/follow.js +1 -0
  908. package/clis/zhihu/hot.js +1 -0
  909. package/clis/zhihu/like.js +1 -0
  910. package/clis/zhihu/question.js +1 -0
  911. package/clis/zhihu/search.js +1 -0
  912. package/clis/zlibrary/commands.test.js +1 -11
  913. package/clis/zlibrary/info.js +1 -0
  914. package/clis/zlibrary/search.js +1 -0
  915. package/clis/zsxq/dynamics.js +1 -0
  916. package/clis/zsxq/groups.js +1 -0
  917. package/clis/zsxq/search.js +1 -0
  918. package/clis/zsxq/topic.js +1 -0
  919. package/clis/zsxq/topics.js +1 -0
  920. package/dist/src/adapter-source.test.js +1 -1
  921. package/dist/src/browser/analyze.test.js +2 -0
  922. package/dist/src/browser/base-page.d.ts +18 -0
  923. package/dist/src/browser/base-page.js +116 -4
  924. package/dist/src/browser/base-page.test.js +108 -0
  925. package/dist/src/browser/cdp.d.ts +1 -0
  926. package/dist/src/browser/cdp.js +57 -9
  927. package/dist/src/browser/cdp.test.js +3 -0
  928. package/dist/src/browser/daemon-client.d.ts +4 -0
  929. package/dist/src/browser/errors.js +1 -1
  930. package/dist/src/browser/page.d.ts +2 -1
  931. package/dist/src/browser/page.js +9 -1
  932. package/dist/src/browser/page.test.js +46 -0
  933. package/dist/src/browser/target-errors.d.ts +2 -1
  934. package/dist/src/browser/target-errors.js +1 -0
  935. package/dist/src/browser/target-resolver.d.ts +35 -3
  936. package/dist/src/browser/target-resolver.js +59 -10
  937. package/dist/src/browser/verify-fixture.d.ts +6 -1
  938. package/dist/src/browser/verify-fixture.js +87 -0
  939. package/dist/src/browser/verify-fixture.test.js +44 -1
  940. package/dist/src/build-manifest.js +12 -4
  941. package/dist/src/build-manifest.test.js +20 -20
  942. package/dist/src/capabilityRouting.d.ts +16 -1
  943. package/dist/src/capabilityRouting.js +24 -1
  944. package/dist/src/capabilityRouting.test.js +20 -2
  945. package/dist/src/cli.js +213 -12
  946. package/dist/src/cli.test.js +329 -0
  947. package/dist/src/commanderAdapter.d.ts +1 -1
  948. package/dist/src/commanderAdapter.js +17 -12
  949. package/dist/src/commanderAdapter.test.js +7 -7
  950. package/dist/src/convention-audit.d.ts +50 -0
  951. package/dist/src/convention-audit.js +546 -0
  952. package/dist/src/convention-audit.test.d.ts +1 -0
  953. package/dist/src/convention-audit.test.js +226 -0
  954. package/dist/src/discovery.js +4 -5
  955. package/dist/src/doctor.js +0 -1
  956. package/dist/src/doctor.test.js +1 -1
  957. package/dist/src/engine.test.js +10 -10
  958. package/dist/src/errors.js +1 -1
  959. package/dist/src/execution.d.ts +1 -1
  960. package/dist/src/execution.js +111 -27
  961. package/dist/src/execution.test.js +334 -25
  962. package/dist/src/help.d.ts +36 -0
  963. package/dist/src/help.js +171 -0
  964. package/dist/src/help.test.d.ts +1 -0
  965. package/dist/src/help.test.js +54 -0
  966. package/dist/src/main.js +27 -8
  967. package/dist/src/manifest-types.d.ts +7 -3
  968. package/dist/src/pipeline/executor.js +1 -1
  969. package/dist/src/pipeline/executor.test.js +8 -0
  970. package/dist/src/pipeline/registry.d.ts +9 -0
  971. package/dist/src/pipeline/registry.js +13 -1
  972. package/dist/src/pipeline/steps/browser.d.ts +1 -0
  973. package/dist/src/pipeline/steps/browser.js +10 -0
  974. package/dist/src/pipeline/steps/download.test.js +1 -0
  975. package/dist/src/plugin.test.js +26 -26
  976. package/dist/src/registry-api.d.ts +1 -1
  977. package/dist/src/registry.d.ts +17 -11
  978. package/dist/src/registry.js +24 -6
  979. package/dist/src/registry.test.js +29 -22
  980. package/dist/src/runtime.d.ts +2 -1
  981. package/dist/src/runtime.js +1 -1
  982. package/dist/src/serialization.d.ts +6 -2
  983. package/dist/src/serialization.js +31 -7
  984. package/dist/src/serialization.test.js +41 -2
  985. package/dist/src/types.d.ts +19 -0
  986. package/dist/src/validate.js +15 -11
  987. package/dist/src/validate.test.d.ts +9 -0
  988. package/dist/src/validate.test.js +90 -0
  989. package/package.json +4 -1
  990. package/scripts/check-listing-id-pairing.mjs +193 -0
  991. package/scripts/check-silent-column-drop.mjs +105 -0
  992. package/scripts/check-typed-error-lint.mjs +118 -0
  993. package/scripts/fetch-adapters.js +1 -1
  994. package/scripts/silent-column-drop-baseline.json +962 -0
  995. package/scripts/typed-error-lint-baseline.json +1514 -0
  996. package/clis/ctrip/search.test.js +0 -64
  997. package/clis/gov-policy/commands.test.js +0 -27
  998. package/clis/linux-do/category.js +0 -36
  999. package/clis/linux-do/hot.js +0 -25
  1000. package/clis/linux-do/latest.js +0 -18
  1001. package/clis/pixiv/test-utils.js +0 -23
  1002. package/clis/toutiao/articles.test.js +0 -30
  1003. package/dist/src/analysis.d.ts +0 -40
  1004. package/dist/src/analysis.js +0 -172
@@ -0,0 +1,93 @@
1
+ import { afterEach, describe, expect, it, vi } from 'vitest';
2
+ import { getRegistry } from '@jackwener/opencli/registry';
3
+ import { ArgumentError, CommandExecutionError, EmptyResultError } from '@jackwener/opencli/errors';
4
+ import './search.js';
5
+ import './show.js';
6
+
7
+ afterEach(() => {
8
+ vi.unstubAllGlobals();
9
+ vi.restoreAllMocks();
10
+ });
11
+
12
+ describe('tvmaze search adapter', () => {
13
+ const cmd = getRegistry().get('tvmaze/search');
14
+
15
+ it('rejects empty query and bad limit before fetching', async () => {
16
+ const fetchMock = vi.fn();
17
+ vi.stubGlobal('fetch', fetchMock);
18
+
19
+ await expect(cmd.func({ query: '', limit: 5 })).rejects.toThrow(ArgumentError);
20
+ await expect(cmd.func({ query: 'foo', limit: 0 })).rejects.toThrow(ArgumentError);
21
+ await expect(cmd.func({ query: 'foo', limit: 100 })).rejects.toThrow(ArgumentError);
22
+ expect(fetchMock).not.toHaveBeenCalled();
23
+ });
24
+
25
+ it('maps HTTP 429 to CommandExecutionError', async () => {
26
+ vi.stubGlobal('fetch', vi.fn().mockResolvedValue(new Response('rate limited', { status: 429 })));
27
+ await expect(cmd.func({ query: 'foo', limit: 5 })).rejects.toThrow(CommandExecutionError);
28
+ });
29
+
30
+ it('throws EmptyResultError when no shows match', async () => {
31
+ vi.stubGlobal('fetch', vi.fn().mockResolvedValue(new Response('[]', { status: 200 })));
32
+ await expect(cmd.func({ query: 'asdfghjkl', limit: 5 })).rejects.toThrow(EmptyResultError);
33
+ });
34
+
35
+ it('strips HTML from summary and ids round-trip into tvmaze show <id>', async () => {
36
+ const list = [{
37
+ score: 1.2,
38
+ show: {
39
+ id: 169, name: 'Breaking Bad', type: 'Scripted', language: 'English',
40
+ genres: ['Drama'], status: 'Ended', premiered: '2008-01-20', ended: '2019-10-11',
41
+ network: { name: 'AMC' }, rating: { average: 9.2 },
42
+ summary: '<p><b>Breaking Bad</b> is a show with &amp; entities &#39;here&#39;, &#x27;hex&#x27;, and &hellip;.</p>',
43
+ url: 'https://www.tvmaze.com/shows/169/breaking-bad',
44
+ },
45
+ }];
46
+ vi.stubGlobal('fetch', vi.fn().mockResolvedValue(new Response(JSON.stringify(list), { status: 200 })));
47
+
48
+ const rows = await cmd.func({ query: 'breaking bad', limit: 5 });
49
+ expect(rows[0]).toMatchObject({
50
+ rank: 1, id: 169, name: 'Breaking Bad', network: 'AMC', rating: 9.2, matchScore: 1.2,
51
+ });
52
+ expect(rows[0].summary).toBe("Breaking Bad is a show with & entities 'here', 'hex', and ….");
53
+ // id round-trip
54
+ expect(typeof rows[0].id).toBe('number');
55
+ });
56
+ });
57
+
58
+ describe('tvmaze show adapter', () => {
59
+ const cmd = getRegistry().get('tvmaze/show');
60
+
61
+ it('rejects non-positive id before fetching', async () => {
62
+ const fetchMock = vi.fn();
63
+ vi.stubGlobal('fetch', fetchMock);
64
+
65
+ await expect(cmd.func({ id: 0 })).rejects.toThrow(ArgumentError);
66
+ await expect(cmd.func({ id: -5 })).rejects.toThrow(ArgumentError);
67
+ await expect(cmd.func({ id: 'abc' })).rejects.toThrow(ArgumentError);
68
+ expect(fetchMock).not.toHaveBeenCalled();
69
+ });
70
+
71
+ it('maps HTTP 404 to EmptyResultError', async () => {
72
+ vi.stubGlobal('fetch', vi.fn().mockResolvedValue(new Response('not found', { status: 404 })));
73
+ await expect(cmd.func({ id: 99999999 })).rejects.toThrow(EmptyResultError);
74
+ });
75
+
76
+ it('returns full show detail with externals + schedule', async () => {
77
+ const show = {
78
+ id: 169, name: 'Breaking Bad', type: 'Scripted', language: 'English', genres: ['Drama'],
79
+ status: 'Ended', premiered: '2008-01-20', ended: '2019-10-11', runtime: 60, averageRuntime: 60,
80
+ network: { name: 'AMC', country: { name: 'United States' } }, schedule: { time: '22:00', days: ['Sunday'] },
81
+ rating: { average: 9.2 }, externals: { imdb: 'tt0903747', thetvdb: 81189 },
82
+ officialSite: 'http://www.amc.com/shows/breaking-bad',
83
+ summary: '<p>Plain.</p>', url: 'https://www.tvmaze.com/shows/169/breaking-bad',
84
+ };
85
+ vi.stubGlobal('fetch', vi.fn().mockResolvedValue(new Response(JSON.stringify(show), { status: 200 })));
86
+
87
+ const rows = await cmd.func({ id: 169 });
88
+ expect(rows[0]).toMatchObject({
89
+ id: 169, name: 'Breaking Bad', country: 'United States', schedule: 'Sunday 22:00',
90
+ imdb: 'tt0903747', thetvdb: 81189, rating: 9.2, summary: 'Plain.',
91
+ });
92
+ });
93
+ });
@@ -0,0 +1,110 @@
1
+ // Shared helpers for the TVmaze adapters.
2
+ //
3
+ // TVmaze publishes a free, unauthenticated REST API at https://api.tvmaze.com.
4
+ // Docs: https://www.tvmaze.com/api
5
+ import { ArgumentError, CommandExecutionError, EmptyResultError } from '@jackwener/opencli/errors';
6
+
7
+ export const TVMAZE_BASE = 'https://api.tvmaze.com';
8
+ const UA = 'opencli-tvmaze-adapter (+https://github.com/jackwener/opencli)';
9
+
10
+ export function requireString(value, label) {
11
+ const s = String(value ?? '').trim();
12
+ if (!s) throw new ArgumentError(`tvmaze ${label} cannot be empty`);
13
+ return s;
14
+ }
15
+
16
+ export function requireShowId(value) {
17
+ const raw = value;
18
+ const n = typeof raw === 'number' ? raw : Number(String(raw ?? '').trim());
19
+ if (!Number.isInteger(n) || n <= 0) {
20
+ throw new ArgumentError(
21
+ 'tvmaze show id is required and must be a positive integer',
22
+ 'TVmaze show ids appear in the URL: https://www.tvmaze.com/shows/<id>/<slug>.',
23
+ );
24
+ }
25
+ return n;
26
+ }
27
+
28
+ export function requireBoundedInt(value, defaultValue, maxValue, label = 'limit') {
29
+ const raw = value ?? defaultValue;
30
+ const n = typeof raw === 'number' ? raw : Number(raw);
31
+ if (!Number.isInteger(n) || n <= 0) {
32
+ throw new ArgumentError(`tvmaze ${label} must be a positive integer`);
33
+ }
34
+ if (n > maxValue) {
35
+ throw new ArgumentError(`tvmaze ${label} must be <= ${maxValue}`);
36
+ }
37
+ return n;
38
+ }
39
+
40
+ export async function tvmazeFetch(url, label) {
41
+ let resp;
42
+ try {
43
+ resp = await fetch(url, { headers: { 'user-agent': UA, accept: 'application/json' } });
44
+ }
45
+ catch (err) {
46
+ throw new CommandExecutionError(
47
+ `${label} request failed: ${err?.message ?? err}`,
48
+ 'Check that api.tvmaze.com is reachable from this network.',
49
+ );
50
+ }
51
+ if (resp.status === 404) {
52
+ throw new EmptyResultError(label, `TVmaze returned 404 for ${url}.`);
53
+ }
54
+ if (resp.status === 429) {
55
+ throw new CommandExecutionError(
56
+ `${label} returned HTTP 429 (rate limited)`,
57
+ 'TVmaze caps unauthenticated traffic at ~20 req/10s; wait a few seconds and retry.',
58
+ );
59
+ }
60
+ if (!resp.ok) {
61
+ throw new CommandExecutionError(`${label} returned HTTP ${resp.status}`);
62
+ }
63
+ let body;
64
+ try {
65
+ body = await resp.json();
66
+ }
67
+ catch (err) {
68
+ throw new CommandExecutionError(`${label} returned malformed JSON: ${err?.message ?? err}`);
69
+ }
70
+ return body;
71
+ }
72
+
73
+ const HTML_ENTITY_MAP = {
74
+ amp: '&',
75
+ lt: '<',
76
+ gt: '>',
77
+ quot: '"',
78
+ apos: "'",
79
+ nbsp: ' ',
80
+ rsquo: '’',
81
+ lsquo: '‘',
82
+ rdquo: '”',
83
+ ldquo: '“',
84
+ hellip: '…',
85
+ ndash: '–',
86
+ mdash: '—',
87
+ };
88
+
89
+ // TVmaze ships HTML in `summary` ("<p><b>...</b> ...</p>"). Strip tags + decode
90
+ // named and numeric entities so output is plain text.
91
+ export function stripHtml(html) {
92
+ if (html == null) return '';
93
+ let s = String(html);
94
+ s = s.replace(/<[^>]+>/g, '');
95
+ s = s
96
+ .replace(/&#x([0-9a-fA-F]+);/g, (_, hex) => {
97
+ const code = parseInt(hex, 16);
98
+ return Number.isFinite(code) ? String.fromCodePoint(code) : '';
99
+ })
100
+ .replace(/&#(\d+);/g, (_, dec) => {
101
+ const code = parseInt(dec, 10);
102
+ return Number.isFinite(code) ? String.fromCodePoint(code) : '';
103
+ })
104
+ .replace(/&([a-zA-Z]+);/g, (match, name) => HTML_ENTITY_MAP[name] ?? match);
105
+ return s.replace(/\s+/g, ' ').trim();
106
+ }
107
+
108
+ export function joinList(value) {
109
+ return Array.isArray(value) ? value.filter(Boolean).join(', ') : '';
110
+ }
@@ -3,14 +3,15 @@ import { cli, Strategy } from '@jackwener/opencli/registry';
3
3
  cli({
4
4
  site: 'twitter',
5
5
  name: 'accept',
6
+ access: 'write',
6
7
  description: 'Auto-accept DM requests containing specific keywords',
7
8
  domain: 'x.com',
8
9
  strategy: Strategy.UI,
9
10
  browser: true,
10
- timeoutSeconds: 600, // 10 min — batch operation iterating many conversations
11
11
  args: [
12
12
  { name: 'query', type: 'string', required: true, positional: true, help: 'Keywords to match (comma-separated for OR, e.g. "群,微信")' },
13
13
  { name: 'max', type: 'int', required: false, default: 20, help: 'Maximum number of requests to accept (default: 20)' },
14
+ { name: 'timeout', type: 'int', required: false, default: 600, help: 'Max seconds for the overall command (default: 600 — batch op)' },
14
15
  ],
15
16
  columns: ['index', 'status', 'user', 'message'],
16
17
  func: async (page, kwargs) => {
@@ -5,6 +5,7 @@ const TWEET_RESULT_BY_REST_ID_QUERY_ID = '7xflPyRiUxGVbJd4uWmbfg';
5
5
  cli({
6
6
  site: 'twitter',
7
7
  name: 'article',
8
+ access: 'read',
8
9
  description: 'Fetch a Twitter Article (long-form content) and export as Markdown',
9
10
  domain: 'x.com',
10
11
  strategy: Strategy.COOKIE,
@@ -3,6 +3,7 @@ import { cli, Strategy } from '@jackwener/opencli/registry';
3
3
  cli({
4
4
  site: 'twitter',
5
5
  name: 'block',
6
+ access: 'write',
6
7
  description: 'Block a Twitter user',
7
8
  domain: 'x.com',
8
9
  strategy: Strategy.UI,
@@ -3,6 +3,7 @@ import { cli, Strategy } from '@jackwener/opencli/registry';
3
3
  cli({
4
4
  site: 'twitter',
5
5
  name: 'bookmark',
6
+ access: 'write',
6
7
  description: 'Bookmark a tweet',
7
8
  domain: 'x.com',
8
9
  strategy: Strategy.UI,
@@ -100,6 +100,7 @@ function parseBookmarks(data, seen) {
100
100
  cli({
101
101
  site: 'twitter',
102
102
  name: 'bookmarks',
103
+ access: 'read',
103
104
  description: 'Fetch Twitter/X bookmarks',
104
105
  domain: 'x.com',
105
106
  strategy: Strategy.COOKIE,
@@ -107,7 +108,7 @@ cli({
107
108
  args: [
108
109
  { name: 'limit', type: 'int', default: 20 },
109
110
  ],
110
- columns: ['author', 'text', 'likes', 'retweets', 'bookmarks', 'url'],
111
+ columns: ['id', 'author', 'text', 'likes', 'retweets', 'bookmarks', 'created_at', 'url'],
111
112
  func: async (page, kwargs) => {
112
113
  const limit = kwargs.limit || 20;
113
114
  await page.goto('https://x.com');
@@ -70,6 +70,7 @@ function buildDeleteScript(tweetId) {
70
70
  cli({
71
71
  site: 'twitter',
72
72
  name: 'delete',
73
+ access: 'write',
73
74
  description: 'Delete a specific tweet by URL',
74
75
  domain: 'x.com',
75
76
  strategy: Strategy.UI, // Utilizes internal DOM flows for interaction
@@ -11,6 +11,7 @@ import { downloadMedia } from '@jackwener/opencli/download/media-download';
11
11
  cli({
12
12
  site: 'twitter',
13
13
  name: 'download',
14
+ access: 'read',
14
15
  description: '下载 Twitter/X 媒体(图片和视频)',
15
16
  domain: 'x.com',
16
17
  strategy: Strategy.COOKIE,
@@ -3,6 +3,7 @@ import { cli, Strategy } from '@jackwener/opencli/registry';
3
3
  cli({
4
4
  site: 'twitter',
5
5
  name: 'follow',
6
+ access: 'write',
6
7
  description: 'Follow a Twitter user',
7
8
  domain: 'x.com',
8
9
  strategy: Strategy.UI,
@@ -1,102 +1,168 @@
1
- import { AuthRequiredError, selectorError } from '@jackwener/opencli/errors';
1
+ import { ArgumentError, AuthRequiredError, selectorError, EmptyResultError } from '@jackwener/opencli/errors';
2
2
  import { cli, Strategy } from '@jackwener/opencli/registry';
3
+
4
+ /**
5
+ * Extract follower rows from Twitter/X follower-list SPA cells.
6
+ *
7
+ * Verified DOM shape on x.com followers list (confirmed live 2026-05-05):
8
+ * - `[data-testid="UserCell"]` per follower
9
+ * - `[data-testid="UserAvatar-Container-<handle>"]` — stable handle source
10
+ * - `[data-testid="<userId>-follow"]` — follow button (i18n-independent)
11
+ * - `[data-testid="userFollowIndicator"]` — "Follows you" badge when present
12
+ * - the bio (when present) is rendered into `cell.innerText` but has NO
13
+ * dedicated testid in the list view (`UserDescription` only appears on
14
+ * the standalone profile page, NOT inside follower-list cells).
15
+ *
16
+ * Strategy: subtract the i18n-variable button / badge texts from the lines of
17
+ * `cell.innerText`, treat the first remaining `@…` line as the handle, the
18
+ * first non-handle line as display name, and the rest as bio. We avoid
19
+ * locale-coupled string matching (`"Follow"` / `"关注"` / `"Folgen"`).
20
+ *
21
+ * Note: Twitter does NOT render follower COUNTS in the list view, so the
22
+ * `followers` column is omitted from the output schema. Use
23
+ * `opencli twitter profile <user>` to read a per-user follower count.
24
+ */
25
+ async function extractFollowersFromDOM(page) {
26
+ const script = `() => {
27
+ const cells = document.querySelectorAll('[data-testid="UserCell"]');
28
+ const out = [];
29
+ for (const cell of cells) {
30
+ // Collect i18n-variable UI strings to strip from the cell text.
31
+ const stripTexts = new Set();
32
+ const buttons = cell.querySelectorAll(
33
+ '[data-testid$="-follow"],[data-testid$="-unfollow"],[data-testid="userFollowIndicator"]'
34
+ );
35
+ for (const el of buttons) {
36
+ const t = (el.innerText || '').trim();
37
+ if (t) stripTexts.add(t);
38
+ }
39
+ const lines = (cell.innerText || '')
40
+ .split('\\n')
41
+ .map(s => s.trim())
42
+ .filter(Boolean)
43
+ .filter(l => !stripTexts.has(l));
44
+ // Pull the @handle line; fall back to UserAvatar-Container-<handle>.
45
+ let screen_name = '';
46
+ const remaining = [];
47
+ for (const l of lines) {
48
+ if (!screen_name && l.startsWith('@')) {
49
+ screen_name = l.slice(1).split(/\\s/)[0];
50
+ } else {
51
+ remaining.push(l);
52
+ }
53
+ }
54
+ if (!screen_name) {
55
+ const av = cell.querySelector('[data-testid^="UserAvatar-Container-"]');
56
+ const tid = av ? av.getAttribute('data-testid') || '' : '';
57
+ if (tid.startsWith('UserAvatar-Container-')) {
58
+ screen_name = tid.slice('UserAvatar-Container-'.length);
59
+ }
60
+ }
61
+ // First non-handle line is display name (may equal handle when the user hasn't set one).
62
+ const name = remaining[0] || screen_name;
63
+ // Lines past the display name form the bio.
64
+ const bio = remaining.slice(1).join(' ').replace(/\\s+/g, ' ').trim();
65
+ if (screen_name) {
66
+ out.push({ screen_name, name, bio });
67
+ }
68
+ }
69
+ return out;
70
+ }`;
71
+ return page.evaluate(script);
72
+ }
73
+
74
+ function normalizeScreenName(value) {
75
+ return String(value ?? '').trim().replace(/^\/+/, '').replace(/^@+/, '');
76
+ }
77
+
3
78
  cli({
4
79
  site: 'twitter',
5
80
  name: 'followers',
81
+ access: 'read',
6
82
  description: 'Get accounts following a Twitter/X user',
7
83
  domain: 'x.com',
8
- strategy: Strategy.INTERCEPT,
84
+ strategy: Strategy.UI,
9
85
  browser: true,
10
86
  args: [
11
87
  { name: 'user', positional: true, type: 'string', required: false },
12
88
  { name: 'limit', type: 'int', default: 50 },
13
89
  ],
14
- columns: ['screen_name', 'name', 'bio', 'followers'],
90
+ // `followers` (count) is NOT exposed: the SPA followers-list view does not
91
+ // render it. Use `twitter profile <user>` for per-user follower counts.
92
+ columns: ['screen_name', 'name', 'bio'],
15
93
  func: async (page, kwargs) => {
16
- let targetUser = kwargs.user;
17
- // If no user is specified, figure out the logged-in user's handle
94
+ const limit = kwargs.limit;
95
+ if (!Number.isInteger(limit) || limit <= 0) {
96
+ throw new ArgumentError('limit must be a positive integer');
97
+ }
98
+
99
+ let targetUser = normalizeScreenName(kwargs.user);
18
100
  if (!targetUser) {
19
101
  await page.goto('https://x.com/home');
20
102
  await page.wait({ selector: '[data-testid="primaryColumn"]' });
21
103
  const href = await page.evaluate(`() => {
22
- const link = document.querySelector('a[data-testid="AppTabBar_Profile_Link"]');
23
- return link ? link.getAttribute('href') : null;
24
- }`);
104
+ const link = document.querySelector('a[data-testid="AppTabBar_Profile_Link"]');
105
+ return link ? link.getAttribute('href') : null;
106
+ }`);
25
107
  if (!href) {
26
108
  throw new AuthRequiredError('x.com', 'Could not find logged-in user profile link. Are you logged in?');
27
109
  }
28
- targetUser = href.replace('/', '');
110
+ targetUser = normalizeScreenName(href);
29
111
  }
112
+ if (!targetUser) {
113
+ throw new ArgumentError('twitter followers user cannot be empty', 'Example: opencli twitter followers @elonmusk --limit 100');
114
+ }
115
+
30
116
  // 1. Navigate to profile page
31
117
  await page.goto(`https://x.com/${targetUser}`);
32
118
  await page.wait(3);
33
- // 2. Install interceptor BEFORE SPA navigation.
34
- // goto() resets JS context, but SPA click preserves it.
35
- await page.installInterceptor('Followers');
36
- // 3. Click the followers link via SPA navigation (preserves interceptor).
37
- // Twitter uses /verified_followers instead of /followers now.
119
+
120
+ // 2. Click the followers tab via SPA navigation (preserves session/state).
121
+ // Twitter sometimes only renders /verified_followers on profiles with
122
+ // badge filtering enabled; try the canonical link first, fall back.
38
123
  const safeUser = JSON.stringify(targetUser);
39
124
  const clicked = await page.evaluate(`() => {
40
- const target = ${safeUser};
41
- const selectors = [
42
- 'a[href="/' + target + '/verified_followers"]',
43
- 'a[href="/' + target + '/followers"]',
44
- ];
45
- for (const sel of selectors) {
46
- const link = document.querySelector(sel);
47
- if (link) { link.click(); return true; }
48
- }
49
- return false;
50
- }`);
125
+ const target = ${safeUser};
126
+ const selectors = [
127
+ 'a[href="/' + target + '/followers"]',
128
+ 'a[href="/' + target + '/verified_followers"]',
129
+ ];
130
+ for (const sel of selectors) {
131
+ const link = document.querySelector(sel);
132
+ if (link) { link.click(); return true; }
133
+ }
134
+ return false;
135
+ }`);
51
136
  if (!clicked) {
52
137
  throw selectorError('Twitter followers link', 'Twitter may have changed the layout.');
53
138
  }
54
- await page.waitForCapture(5);
55
- // 4. Scroll to trigger pagination API calls
56
- await page.autoScroll({ times: Math.ceil(kwargs.limit / 20), delayMs: 2000 });
57
- // 5. Retrieve intercepted data
58
- const requests = await page.getInterceptedRequests();
59
- const requestList = Array.isArray(requests) ? requests : [];
60
- if (requestList.length === 0) {
61
- return [];
62
- }
63
- let results = [];
64
- for (const req of requestList) {
65
- try {
66
- // GraphQL response: { data: { user: { result: { timeline: ... } } } }
67
- let instructions = req.data?.user?.result?.timeline?.timeline?.instructions;
68
- if (!instructions)
69
- continue;
70
- let addEntries = instructions.find((i) => i.type === 'TimelineAddEntries');
71
- if (!addEntries) {
72
- addEntries = instructions.find((i) => i.entries && Array.isArray(i.entries));
73
- }
74
- if (!addEntries)
75
- continue;
76
- for (const entry of addEntries.entries) {
77
- if (!entry.entryId.startsWith('user-'))
78
- continue;
79
- const item = entry.content?.itemContent?.user_results?.result;
80
- if (!item || item.__typename !== 'User')
81
- continue;
82
- const core = item.core || {};
83
- const legacy = item.legacy || {};
84
- results.push({
85
- screen_name: core.screen_name || legacy.screen_name || 'unknown',
86
- name: core.name || legacy.name || 'unknown',
87
- bio: legacy.description || item.profile_bio?.description || '',
88
- followers: legacy.followers_count || legacy.normal_followers_count || 0
89
- });
90
- }
139
+
140
+ // 3. Wait for follower cells to appear
141
+ await page.wait({ selector: '[data-testid="UserCell"]', timeout: 10000 });
142
+
143
+ // 4. Extract from DOM, scroll to load more, dedupe by screen_name
144
+ const allFollowers = [];
145
+ const seen = new Set();
146
+ let sameCount = 0;
147
+ while (allFollowers.length < limit && sameCount < 3) {
148
+ const followers = await extractFollowersFromDOM(page);
149
+ const newFollowers = followers.filter(f => !seen.has(f.screen_name));
150
+ for (const f of newFollowers) {
151
+ seen.add(f.screen_name);
152
+ allFollowers.push(f);
91
153
  }
92
- catch (e) {
93
- // ignore parsing errors for individual payloads
154
+ if (newFollowers.length === 0) {
155
+ sameCount++;
156
+ } else {
157
+ sameCount = 0;
94
158
  }
159
+ if (allFollowers.length >= limit) break;
160
+ await page.autoScroll({ times: 1, delayMs: 500 });
161
+ await page.wait(2);
162
+ }
163
+ if (allFollowers.length === 0) {
164
+ throw new EmptyResultError('twitter followers', `No followers found for @${targetUser}`);
95
165
  }
96
- // Deduplicate by screen_name
97
- const unique = new Map();
98
- results.forEach(r => unique.set(r.screen_name, r));
99
- const deduplicatedResults = Array.from(unique.values());
100
- return deduplicatedResults.slice(0, kwargs.limit);
166
+ return allFollowers.slice(0, limit);
101
167
  }
102
168
  });
@@ -134,6 +134,7 @@ function normalizeScreenName(value) {
134
134
  cli({
135
135
  site: 'twitter',
136
136
  name: 'following',
137
+ access: 'read',
137
138
  description: 'Get accounts a Twitter/X user is following',
138
139
  domain: 'x.com',
139
140
  strategy: Strategy.COOKIE,
@@ -3,6 +3,7 @@ import { cli, Strategy } from '@jackwener/opencli/registry';
3
3
  cli({
4
4
  site: 'twitter',
5
5
  name: 'hide-reply',
6
+ access: 'write',
6
7
  description: 'Hide a reply on your tweet (useful for hiding bot/spam replies)',
7
8
  domain: 'x.com',
8
9
  strategy: Strategy.UI,
@@ -3,6 +3,7 @@ import { cli, Strategy } from '@jackwener/opencli/registry';
3
3
  cli({
4
4
  site: 'twitter',
5
5
  name: 'like',
6
+ access: 'write',
6
7
  description: 'Like a specific tweet',
7
8
  domain: 'x.com',
8
9
  strategy: Strategy.UI, // Utilizes internal DOM flows for interaction
@@ -137,6 +137,7 @@ function parseLikes(data, seen) {
137
137
  cli({
138
138
  site: 'twitter',
139
139
  name: 'likes',
140
+ access: 'read',
140
141
  description: 'Fetch liked tweets of a Twitter user',
141
142
  domain: 'x.com',
142
143
  strategy: Strategy.COOKIE,
@@ -145,7 +146,7 @@ cli({
145
146
  { name: 'username', type: 'string', positional: true, help: 'Twitter screen name (without @). Defaults to logged-in user.' },
146
147
  { name: 'limit', type: 'int', default: 20 },
147
148
  ],
148
- columns: ['author', 'name', 'text', 'likes', 'url', 'has_media', 'media_urls'],
149
+ columns: ['id', 'author', 'name', 'text', 'likes', 'retweets', 'created_at', 'url', 'has_media', 'media_urls'],
149
150
  func: async (page, kwargs) => {
150
151
  const limit = kwargs.limit || 20;
151
152
  let username = (kwargs.username || '').replace(/^@/, '');
@@ -65,6 +65,7 @@ function buildUserByScreenNameUrl(queryId, screenName) {
65
65
  cli({
66
66
  site: 'twitter',
67
67
  name: 'list-add',
68
+ access: 'write',
68
69
  description: 'Add a user to a Twitter/X list you own (no-op if already a member)',
69
70
  domain: 'x.com',
70
71
  strategy: Strategy.UI,
@@ -74,6 +74,7 @@ export function interpretRemoveResponse(status, json) {
74
74
  cli({
75
75
  site: 'twitter',
76
76
  name: 'list-remove',
77
+ access: 'write',
77
78
  description: 'Remove a user from a Twitter/X list you own (toggles via UI; no-op if not currently a member)',
78
79
  domain: 'x.com',
79
80
  strategy: Strategy.UI,
@@ -107,6 +107,7 @@ export function parseListTimeline(data, seen) {
107
107
  cli({
108
108
  site: 'twitter',
109
109
  name: 'list-tweets',
110
+ access: 'read',
110
111
  description: 'Fetch tweets from a Twitter/X list timeline',
111
112
  domain: 'x.com',
112
113
  strategy: Strategy.COOKIE,
@@ -87,6 +87,7 @@ export function parseListsManagement(data, seen) {
87
87
  export const command = cli({
88
88
  site: 'twitter',
89
89
  name: 'lists',
90
+ access: 'read',
90
91
  description: 'Get Twitter/X lists for the logged-in user (owned + subscribed)',
91
92
  domain: 'x.com',
92
93
  strategy: Strategy.COOKIE,
@@ -3,6 +3,7 @@ import { cli, Strategy } from '@jackwener/opencli/registry';
3
3
  cli({
4
4
  site: 'twitter',
5
5
  name: 'notifications',
6
+ access: 'read',
6
7
  description: 'Get Twitter/X notifications',
7
8
  domain: 'x.com',
8
9
  strategy: Strategy.INTERCEPT,
@@ -185,6 +185,7 @@ async function submitTweet(page, text) {
185
185
  cli({
186
186
  site: 'twitter',
187
187
  name: 'post',
188
+ access: 'write',
188
189
  description: 'Post a new tweet/thread',
189
190
  domain: 'x.com',
190
191
  strategy: Strategy.UI,
@@ -5,6 +5,7 @@ const USER_BY_SCREEN_NAME_QUERY_ID = 'qRednkZG-rn1P6b48NINmQ';
5
5
  cli({
6
6
  site: 'twitter',
7
7
  name: 'profile',
8
+ access: 'read',
8
9
  description: 'Fetch a Twitter user profile (bio, stats, etc.)',
9
10
  domain: 'x.com',
10
11
  strategy: Strategy.COOKIE,