publishport-opencli 1.0.20 → 1.0.21

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 (1041) hide show
  1. package/clis/12306/me.js +2 -2
  2. package/clis/12306/orders.js +3 -3
  3. package/clis/12306/passengers.js +3 -3
  4. package/clis/12306/price.js +1 -1
  5. package/clis/12306/stations.js +1 -1
  6. package/clis/12306/train.js +1 -1
  7. package/clis/12306/trains.js +1 -1
  8. package/clis/12306/utils.js +1 -1
  9. package/clis/1688/download.js +1 -1
  10. package/clis/1688/item.js +4 -4
  11. package/clis/1688/search.js +4 -4
  12. package/clis/1688/store.js +4 -4
  13. package/clis/1point3acres/forum.js +1 -1
  14. package/clis/1point3acres/forums.js +1 -1
  15. package/clis/1point3acres/notifications.js +1 -1
  16. package/clis/1point3acres/search.js +1 -1
  17. package/clis/1point3acres/thread.js +2 -2
  18. package/clis/1point3acres/user.js +1 -1
  19. package/clis/1point3acres/utils.js +2 -2
  20. package/clis/36kr/article.js +2 -2
  21. package/clis/36kr/hot.js +2 -2
  22. package/clis/36kr/news.js +1 -1
  23. package/clis/36kr/search.js +2 -2
  24. package/clis/51job/company.js +2 -2
  25. package/clis/51job/detail.js +2 -2
  26. package/clis/51job/hot.js +1 -1
  27. package/clis/51job/search.js +1 -1
  28. package/clis/51job/utils.js +7 -7
  29. package/clis/_atlassian/shared.js +9 -9
  30. package/clis/_shared/article/auth.js +4 -4
  31. package/clis/_shared/article/douban-md2draft.js +4 -4
  32. package/clis/_shared/article/format.js +1 -1
  33. package/clis/_shared/article/images.js +7 -7
  34. package/clis/_shared/article/login.js +1 -1
  35. package/clis/_shared/article/publish.js +11 -11
  36. package/clis/_shared/common.js +1 -1
  37. package/clis/_shared/content-guard.js +1 -1
  38. package/clis/_shared/desktop-commands.js +1 -1
  39. package/clis/_shared/file-inject.js +12 -12
  40. package/clis/_shared/self-hosted-sites.js +2 -2
  41. package/clis/_shared/site-auth.js +1 -1
  42. package/clis/_shared/token-auth.js +2 -2
  43. package/clis/_shared/video-publish.js +9 -9
  44. package/clis/amazon/offer.js +3 -3
  45. package/clis/amazon/product.js +5 -5
  46. package/clis/amazon/shared.js +6 -6
  47. package/clis/antigravity/_actions.js +13 -13
  48. package/clis/antigravity/audit-extras.js +10 -10
  49. package/clis/antigravity/delete.js +1 -1
  50. package/clis/antigravity/model.js +6 -6
  51. package/clis/antigravity/new.js +2 -2
  52. package/clis/antigravity/read.js +2 -2
  53. package/clis/antigravity/rename.js +1 -1
  54. package/clis/antigravity/send.js +3 -3
  55. package/clis/antigravity/serve.js +17 -17
  56. package/clis/antigravity/storage.js +6 -6
  57. package/clis/antigravity/watch.js +2 -2
  58. package/clis/apple-podcasts/episodes.js +1 -1
  59. package/clis/apple-podcasts/top.js +1 -1
  60. package/clis/apple-podcasts/utils.js +1 -1
  61. package/clis/archive/item.js +1 -1
  62. package/clis/archive/search.js +1 -1
  63. package/clis/archive/snapshots.js +1 -1
  64. package/clis/archive/wayback.js +1 -1
  65. package/clis/arxiv/author.js +1 -1
  66. package/clis/arxiv/utils.js +1 -1
  67. package/clis/autohome/brand.js +1 -1
  68. package/clis/autohome/score.js +1 -1
  69. package/clis/autohome/utils.js +1 -1
  70. package/clis/baijiahao/article.js +1 -1
  71. package/clis/baijiahao/lists.js +1 -1
  72. package/clis/baijiahao/login.js +1 -1
  73. package/clis/baijiahao/publish.js +9 -9
  74. package/clis/baijiahao/stats.js +1 -1
  75. package/clis/baijiahao/whoami.js +1 -1
  76. package/clis/band/bands.js +2 -2
  77. package/clis/band/mentions.js +2 -2
  78. package/clis/band/post.js +4 -4
  79. package/clis/band/posts.js +3 -3
  80. package/clis/barchart/flow.js +3 -3
  81. package/clis/barchart/greeks.js +2 -2
  82. package/clis/barchart/quote.js +3 -3
  83. package/clis/bbc/news.js +1 -1
  84. package/clis/bbc/topic.js +1 -1
  85. package/clis/bbc/utils.js +1 -1
  86. package/clis/bilibili/article.js +1 -1
  87. package/clis/bilibili/categories.js +1 -1
  88. package/clis/bilibili/coin.js +1 -1
  89. package/clis/bilibili/comment-del.js +1 -1
  90. package/clis/bilibili/comment-like.js +1 -1
  91. package/clis/bilibili/comment.js +1 -1
  92. package/clis/bilibili/comments.js +1 -1
  93. package/clis/bilibili/dm-list.js +1 -1
  94. package/clis/bilibili/dm-read.js +1 -1
  95. package/clis/bilibili/dm-send.js +1 -1
  96. package/clis/bilibili/download.js +2 -2
  97. package/clis/bilibili/drafts.js +1 -1
  98. package/clis/bilibili/dynamic-post.js +3 -3
  99. package/clis/bilibili/favorite-add.js +1 -1
  100. package/clis/bilibili/favorite.js +1 -1
  101. package/clis/bilibili/feed.js +2 -2
  102. package/clis/bilibili/follow.js +1 -1
  103. package/clis/bilibili/following.js +1 -1
  104. package/clis/bilibili/like.js +1 -1
  105. package/clis/bilibili/partitions.js +1 -1
  106. package/clis/bilibili/stats.js +1 -1
  107. package/clis/bilibili/subtitle.js +3 -3
  108. package/clis/bilibili/summary.js +1 -1
  109. package/clis/bilibili/topics.js +1 -1
  110. package/clis/bilibili/unfollow.js +1 -1
  111. package/clis/bilibili/upload.js +1 -1
  112. package/clis/bilibili/utils.js +10 -10
  113. package/clis/bilibili/video-drafts.js +1 -1
  114. package/clis/bilibili/video.js +1 -1
  115. package/clis/bloomberg/businessweek.js +4 -4
  116. package/clis/bloomberg/news.js +2 -2
  117. package/clis/bloomberg/utils.js +13 -13
  118. package/clis/bluesky/post.js +1 -1
  119. package/clis/bluesky/shared.js +11 -11
  120. package/clis/bluesky/whoami.js +1 -1
  121. package/clis/booking/search.js +2 -2
  122. package/clis/boss/accept.js +1 -1
  123. package/clis/boss/applied.js +1 -1
  124. package/clis/boss/auth.js +1 -1
  125. package/clis/boss/batchgreet.js +1 -1
  126. package/clis/boss/bossinfo.js +1 -1
  127. package/clis/boss/chatlist.js +1 -1
  128. package/clis/boss/chatmsg.js +1 -1
  129. package/clis/boss/cities.js +1 -1
  130. package/clis/boss/detail.js +1 -1
  131. package/clis/boss/exchange.js +1 -1
  132. package/clis/boss/greet.js +1 -1
  133. package/clis/boss/interviews.js +1 -1
  134. package/clis/boss/invite.js +1 -1
  135. package/clis/boss/joblist.js +1 -1
  136. package/clis/boss/mark.js +1 -1
  137. package/clis/boss/me.js +2 -2
  138. package/clis/boss/recommend.js +1 -1
  139. package/clis/boss/resumedelete.js +1 -1
  140. package/clis/boss/resumelist.js +1 -1
  141. package/clis/boss/resumeupload.js +11 -11
  142. package/clis/boss/search.js +1 -1
  143. package/clis/boss/send.js +1 -1
  144. package/clis/boss/sendresume.js +1 -1
  145. package/clis/boss/stats.js +1 -1
  146. package/clis/boss/unread.js +1 -1
  147. package/clis/boss/utils.js +13 -13
  148. package/clis/chaoxing/assignments.js +1 -1
  149. package/clis/chaoxing/exams.js +1 -1
  150. package/clis/chaoxing/utils.js +9 -9
  151. package/clis/chatgpt/ask.js +1 -1
  152. package/clis/chatgpt/auth.js +2 -2
  153. package/clis/chatgpt/detail.js +1 -1
  154. package/clis/chatgpt/image.js +1 -1
  155. package/clis/chatgpt/read.js +1 -1
  156. package/clis/chatgpt/send.js +1 -1
  157. package/clis/chatgpt/utils.js +59 -59
  158. package/clis/chatgpt-app/ask.js +1 -1
  159. package/clis/chatgpt-app/send.js +1 -1
  160. package/clis/chatwise/model.js +6 -6
  161. package/clis/chess/analyze.js +1 -1
  162. package/clis/chess/game.js +1 -1
  163. package/clis/chess/games.js +1 -1
  164. package/clis/chess/stats.js +1 -1
  165. package/clis/chess/utils.js +1 -1
  166. package/clis/claude/ask.js +2 -2
  167. package/clis/claude/detail.js +1 -1
  168. package/clis/claude/new.js +1 -1
  169. package/clis/claude/read.js +1 -1
  170. package/clis/claude/send.js +1 -1
  171. package/clis/claude/utils.js +23 -23
  172. package/clis/cnblogs/article.js +1 -1
  173. package/clis/cnblogs/login.js +1 -1
  174. package/clis/cnblogs/stats.js +7 -7
  175. package/clis/cnblogs/whoami.js +1 -1
  176. package/clis/codex/_actions.js +3 -3
  177. package/clis/codex/archive.js +1 -1
  178. package/clis/codex/ask.js +6 -6
  179. package/clis/codex/model.js +8 -8
  180. package/clis/codex/pin.js +1 -1
  181. package/clis/codex/rename.js +4 -4
  182. package/clis/codex/send.js +3 -3
  183. package/clis/codex/sidebar.js +1 -1
  184. package/clis/coingecko/categories.js +1 -1
  185. package/clis/coingecko/coin.js +1 -1
  186. package/clis/coingecko/derivatives.js +1 -1
  187. package/clis/coingecko/exchanges.js +1 -1
  188. package/clis/coingecko/global.js +1 -1
  189. package/clis/coingecko/trending.js +1 -1
  190. package/clis/confluence/search.js +1 -1
  191. package/clis/coupang/product.js +3 -3
  192. package/clis/coupang/utils.js +1 -1
  193. package/clis/crates/crate.js +1 -1
  194. package/clis/crates/search.js +1 -1
  195. package/clis/crates/utils.js +1 -1
  196. package/clis/csdn/article.js +13 -13
  197. package/clis/csdn/columns.js +1 -1
  198. package/clis/csdn/login.js +1 -1
  199. package/clis/csdn/stats.js +4 -4
  200. package/clis/csdn/whoami.js +1 -1
  201. package/clis/cto51/article.js +1 -1
  202. package/clis/cto51/whoami.js +1 -1
  203. package/clis/ctrip/flight.js +2 -2
  204. package/clis/ctrip/hotel-search.js +3 -3
  205. package/clis/ctrip/hotel-suggest.js +1 -1
  206. package/clis/ctrip/search.js +1 -1
  207. package/clis/ctrip/utils.js +6 -6
  208. package/clis/cursor/ask.js +5 -5
  209. package/clis/cursor/composer.js +2 -2
  210. package/clis/cursor/model.js +4 -4
  211. package/clis/cursor/send.js +2 -2
  212. package/clis/dblp/author.js +1 -1
  213. package/clis/dblp/paper.js +1 -1
  214. package/clis/dblp/search.js +1 -1
  215. package/clis/dblp/utils.js +1 -1
  216. package/clis/dblp/venue.js +1 -1
  217. package/clis/deepseek/ask.js +1 -1
  218. package/clis/deepseek/auth.js +2 -2
  219. package/clis/deepseek/detail.js +1 -1
  220. package/clis/deepseek/new.js +1 -1
  221. package/clis/deepseek/read.js +1 -1
  222. package/clis/deepseek/send.js +7 -7
  223. package/clis/deepseek/utils.js +25 -25
  224. package/clis/defillama/protocol.js +1 -1
  225. package/clis/defillama/protocols.js +1 -1
  226. package/clis/defillama/utils.js +1 -1
  227. package/clis/devto/auth.js +2 -2
  228. package/clis/devto/latest.js +1 -1
  229. package/clis/devto/publish.js +5 -5
  230. package/clis/devto/read.js +2 -2
  231. package/clis/devto/stats.js +3 -3
  232. package/clis/dianping/auth.js +2 -2
  233. package/clis/dianping/cityResolver.js +2 -2
  234. package/clis/dianping/search.js +1 -1
  235. package/clis/dianping/shop.js +1 -1
  236. package/clis/dianping/utils.js +1 -1
  237. package/clis/discord-app/delete.js +3 -3
  238. package/clis/discord-app/read.js +1 -1
  239. package/clis/discord-app/thread-read.js +1 -1
  240. package/clis/discord-web/auth.js +2 -2
  241. package/clis/discord-web/send.js +5 -5
  242. package/clis/dockerhub/image.js +1 -1
  243. package/clis/dockerhub/search.js +1 -1
  244. package/clis/dockerhub/utils.js +1 -1
  245. package/clis/dongchedi/koubei.js +1 -1
  246. package/clis/dongchedi/models.js +1 -1
  247. package/clis/dongchedi/score.js +1 -1
  248. package/clis/dongchedi/search.js +1 -1
  249. package/clis/dongchedi/series.js +1 -1
  250. package/clis/dongchedi/specs.js +1 -1
  251. package/clis/dongchedi/utils.js +1 -1
  252. package/clis/douban/article.js +3 -3
  253. package/clis/douban/auth.js +2 -2
  254. package/clis/douban/download.js +1 -1
  255. package/clis/douban/utils.js +23 -23
  256. package/clis/doubao/auth.js +3 -3
  257. package/clis/doubao/utils.js +39 -39
  258. package/clis/doubao-app/ask.js +1 -1
  259. package/clis/doubao-app/utils.js +4 -4
  260. package/clis/douyin/_shared/browser-fetch.js +7 -7
  261. package/clis/douyin/_shared/draft-cache.js +1 -1
  262. package/clis/douyin/_shared/imagex-upload.js +1 -1
  263. package/clis/douyin/_shared/sts2.js +1 -1
  264. package/clis/douyin/_shared/text-extra.js +1 -1
  265. package/clis/douyin/_shared/tos-upload.js +4 -4
  266. package/clis/douyin/_shared/transcode.js +1 -1
  267. package/clis/douyin/_shared/vod-upload.js +4 -4
  268. package/clis/douyin/draft.js +18 -18
  269. package/clis/douyin/drafts.js +1 -1
  270. package/clis/douyin/publish-image.js +12 -12
  271. package/clis/douyin/publish.js +9 -9
  272. package/clis/douyin/search.js +3 -3
  273. package/clis/douyin/videos.js +1 -1
  274. package/clis/eastmoney/_secid.js +1 -1
  275. package/clis/eastmoney/announcement.js +1 -1
  276. package/clis/eastmoney/article.js +1 -1
  277. package/clis/eastmoney/convertible.js +1 -1
  278. package/clis/eastmoney/etf.js +1 -1
  279. package/clis/eastmoney/holders.js +1 -1
  280. package/clis/eastmoney/index-board.js +1 -1
  281. package/clis/eastmoney/kline.js +1 -1
  282. package/clis/eastmoney/kuaixun.js +1 -1
  283. package/clis/eastmoney/longhu.js +1 -1
  284. package/clis/eastmoney/money-flow.js +1 -1
  285. package/clis/eastmoney/northbound.js +1 -1
  286. package/clis/eastmoney/quote.js +1 -1
  287. package/clis/eastmoney/rank.js +1 -1
  288. package/clis/eastmoney/sectors.js +1 -1
  289. package/clis/endoflife/product.js +1 -1
  290. package/clis/endoflife/utils.js +1 -1
  291. package/clis/facebook/comment.js +8 -8
  292. package/clis/facebook/feed.js +4 -4
  293. package/clis/facebook/like.js +5 -5
  294. package/clis/facebook/notifications.js +3 -3
  295. package/clis/facebook/post.js +11 -11
  296. package/clis/facebook/search.js +3 -3
  297. package/clis/flathub/app.js +1 -1
  298. package/clis/flathub/search.js +1 -1
  299. package/clis/flathub/utils.js +1 -1
  300. package/clis/flomo/memos.js +1 -1
  301. package/clis/gemini/deep-research-result.js +4 -4
  302. package/clis/gemini/deep-research.js +1 -1
  303. package/clis/gemini/detail.js +1 -1
  304. package/clis/gemini/history.js +1 -1
  305. package/clis/gemini/image.js +2 -2
  306. package/clis/gemini/status.js +1 -1
  307. package/clis/gemini/utils.js +43 -43
  308. package/clis/geogebra/hexagon.js +1 -1
  309. package/clis/geogebra/info.js +3 -3
  310. package/clis/geogebra/triangle.js +1 -1
  311. package/clis/geogebra/utils.js +11 -11
  312. package/clis/ghost/login.js +1 -1
  313. package/clis/ghost/shared.js +2 -2
  314. package/clis/gitee/auth.js +2 -2
  315. package/clis/github-trending/repos.js +1 -1
  316. package/clis/google/news.js +1 -1
  317. package/clis/google/search.js +2 -2
  318. package/clis/google/suggest.js +1 -1
  319. package/clis/google/trends.js +1 -1
  320. package/clis/google/utils.js +1 -1
  321. package/clis/goproxy/module.js +1 -1
  322. package/clis/goproxy/utils.js +1 -1
  323. package/clis/goproxy/versions.js +1 -1
  324. package/clis/gov-policy/recent.js +2 -2
  325. package/clis/gov-policy/search.js +2 -2
  326. package/clis/grok/ask.js +1 -1
  327. package/clis/grok/detail.js +1 -1
  328. package/clis/grok/image.js +8 -8
  329. package/clis/grok/pin.js +1 -1
  330. package/clis/grok/send.js +1 -1
  331. package/clis/grok/status.js +1 -1
  332. package/clis/grok/utils.js +21 -21
  333. package/clis/guazi/browse.js +1 -1
  334. package/clis/guazi/car.js +1 -1
  335. package/clis/guazi/utils.js +1 -1
  336. package/clis/hackernews/auth.js +2 -2
  337. package/clis/hackernews/comment.js +8 -8
  338. package/clis/hackernews/read.js +7 -7
  339. package/clis/hackernews/submit.js +7 -7
  340. package/clis/hashnode/auth.js +3 -3
  341. package/clis/hashnode/publish.js +14 -14
  342. package/clis/hf/auth.js +2 -2
  343. package/clis/hf/models.js +1 -1
  344. package/clis/hf/paper.js +1 -1
  345. package/clis/hf/spaces.js +1 -1
  346. package/clis/hf/top.js +1 -1
  347. package/clis/homebrew/cask.js +1 -1
  348. package/clis/homebrew/formula.js +1 -1
  349. package/clis/homebrew/popular.js +1 -1
  350. package/clis/homebrew/utils.js +1 -1
  351. package/clis/huodongxing/events.js +1 -1
  352. package/clis/hupu/detail.js +4 -4
  353. package/clis/hupu/hot.js +3 -3
  354. package/clis/hupu/reply.js +1 -1
  355. package/clis/hupu/search.js +1 -1
  356. package/clis/hupu/unlike.js +1 -1
  357. package/clis/hupu/utils.js +10 -10
  358. package/clis/imdb/person.js +2 -2
  359. package/clis/imdb/reviews.js +3 -3
  360. package/clis/imdb/search.js +2 -2
  361. package/clis/imdb/title.js +1 -1
  362. package/clis/imdb/top.js +1 -1
  363. package/clis/imdb/trending.js +1 -1
  364. package/clis/imdb/utils.js +13 -13
  365. package/clis/imooc/article.js +6 -6
  366. package/clis/imooc/login.js +1 -1
  367. package/clis/imooc/whoami.js +1 -1
  368. package/clis/indeed/job.js +2 -2
  369. package/clis/indeed/search.js +2 -2
  370. package/clis/indeed/utils.js +1 -1
  371. package/clis/infoq/article.js +2 -2
  372. package/clis/infoq/login.js +1 -1
  373. package/clis/infoq/whoami.js +1 -1
  374. package/clis/instagram/_shared/private-publish.js +4 -4
  375. package/clis/instagram/_shared/protocol-capture.js +9 -9
  376. package/clis/instagram/detail.js +3 -3
  377. package/clis/instagram/post.js +25 -25
  378. package/clis/instagram/reel.js +18 -18
  379. package/clis/instagram/story.js +4 -4
  380. package/clis/instagram/user.js +2 -2
  381. package/clis/jd/item.js +65 -65
  382. package/clis/jianshu/article.js +1 -1
  383. package/clis/jianshu/login.js +1 -1
  384. package/clis/jianshu/notebooks.js +1 -1
  385. package/clis/jianshu/whoami.js +1 -1
  386. package/clis/jianyu/search.js +6 -6
  387. package/clis/jianyu/shared/procurement-contract.js +1 -1
  388. package/clis/jike/api.js +6 -6
  389. package/clis/jike/auth.js +3 -3
  390. package/clis/jike/comment.js +1 -1
  391. package/clis/jike/create.js +6 -6
  392. package/clis/jike/feed.js +3 -3
  393. package/clis/jike/like.js +1 -1
  394. package/clis/jike/notifications.js +3 -3
  395. package/clis/jike/repost.js +13 -13
  396. package/clis/jike/search.js +3 -3
  397. package/clis/jimeng/auth.js +2 -2
  398. package/clis/jimeng/generate.js +10 -10
  399. package/clis/jira/shared.js +1 -1
  400. package/clis/juejin/article.js +4 -4
  401. package/clis/juejin/categories.js +1 -1
  402. package/clis/juejin/hot.js +1 -1
  403. package/clis/juejin/login.js +1 -1
  404. package/clis/juejin/recommend.js +1 -1
  405. package/clis/juejin/stats.js +3 -3
  406. package/clis/juejin/tags.js +1 -1
  407. package/clis/juejin/utils.js +1 -1
  408. package/clis/juejin/whoami.js +1 -1
  409. package/clis/ke/utils.js +4 -4
  410. package/clis/kimi/_utils.js +7 -7
  411. package/clis/kimi/audit-extras.js +14 -14
  412. package/clis/kimi/auth.js +3 -3
  413. package/clis/kimi/chat.js +15 -15
  414. package/clis/kimi/storage.js +5 -5
  415. package/clis/kimi/ui.js +13 -13
  416. package/clis/kimi/usage.js +3 -3
  417. package/clis/kuaishou/auth.js +1 -1
  418. package/clis/kuaishou/publish.js +6 -6
  419. package/clis/lesswrong/_helpers.js +5 -5
  420. package/clis/lesswrong/comments.js +5 -5
  421. package/clis/lichess/top.js +1 -1
  422. package/clis/lichess/user.js +1 -1
  423. package/clis/lichess/utils.js +1 -1
  424. package/clis/linkedin/comment.js +1 -1
  425. package/clis/linkedin/connect.js +11 -11
  426. package/clis/linkedin/create.js +5 -5
  427. package/clis/linkedin/follow.js +1 -1
  428. package/clis/linkedin/inbox.js +1 -1
  429. package/clis/linkedin/job-detail.js +3 -3
  430. package/clis/linkedin/like.js +1 -1
  431. package/clis/linkedin/notifications.js +1 -1
  432. package/clis/linkedin/people-search.js +1 -1
  433. package/clis/linkedin/post-comments.js +1 -1
  434. package/clis/linkedin/post-detail.js +1 -1
  435. package/clis/linkedin/profile-analytics.js +1 -1
  436. package/clis/linkedin/profile-api.js +13 -13
  437. package/clis/linkedin/profile-experience.js +1 -1
  438. package/clis/linkedin/profile-projects.js +1 -1
  439. package/clis/linkedin/profile-read.js +3 -3
  440. package/clis/linkedin/reply.js +1 -1
  441. package/clis/linkedin/repost.js +1 -1
  442. package/clis/linkedin/safe-send.js +8 -8
  443. package/clis/linkedin/salesnav-inbox.js +5 -5
  444. package/clis/linkedin/salesnav-message.js +3 -3
  445. package/clis/linkedin/salesnav-search.js +4 -4
  446. package/clis/linkedin/salesnav-thread.js +1 -1
  447. package/clis/linkedin/search-api.js +3 -3
  448. package/clis/linkedin/search.js +8 -8
  449. package/clis/linkedin/social-api.js +31 -31
  450. package/clis/linkedin/timeline.js +3 -3
  451. package/clis/linkedin-learning/search.js +2 -2
  452. package/clis/linkedin-learning/trending.js +2 -2
  453. package/clis/linux-do/feed.js +4 -4
  454. package/clis/linux-do/topic-content.js +8 -8
  455. package/clis/lobsters/domain.js +1 -1
  456. package/clis/lobsters/read.js +7 -7
  457. package/clis/maimai/auth.js +2 -2
  458. package/clis/maimai/search-talents.js +4 -4
  459. package/clis/manus/_utils.js +1 -1
  460. package/clis/mastodon/login.js +1 -1
  461. package/clis/mastodon/post.js +1 -1
  462. package/clis/mastodon/shared.js +12 -12
  463. package/clis/mastodon/whoami.js +1 -1
  464. package/clis/maven/artifact.js +1 -1
  465. package/clis/maven/search.js +1 -1
  466. package/clis/maven/utils.js +1 -1
  467. package/clis/mdn/search.js +1 -1
  468. package/clis/medium/article.js +5 -5
  469. package/clis/medium/login.js +1 -1
  470. package/clis/medium/stats.js +3 -3
  471. package/clis/medium/tag.js +1 -1
  472. package/clis/medium/whoami.js +1 -1
  473. package/clis/mubu/notes.js +1 -1
  474. package/clis/mubu/utils.js +15 -15
  475. package/clis/note/auth.js +2 -2
  476. package/clis/note/note-utils.js +2 -2
  477. package/clis/note/publish.js +8 -8
  478. package/clis/notebooklm/add-source.js +8 -8
  479. package/clis/notebooklm/create.js +1 -1
  480. package/clis/notebooklm/generate-slides.js +1 -1
  481. package/clis/notebooklm/notes-get.js +1 -1
  482. package/clis/notebooklm/rpc.js +8 -8
  483. package/clis/notebooklm/source-fulltext.js +1 -1
  484. package/clis/notebooklm/utils.js +10 -10
  485. package/clis/nowcoder/auth.js +2 -2
  486. package/clis/nowcoder/comment.js +1 -1
  487. package/clis/nowcoder/comments.js +1 -1
  488. package/clis/nowcoder/dm-list.js +1 -1
  489. package/clis/nowcoder/dm-read.js +1 -1
  490. package/clis/nowcoder/dm-send.js +1 -1
  491. package/clis/nowcoder/drafts.js +1 -1
  492. package/clis/nowcoder/inbox.js +1 -1
  493. package/clis/nowcoder/like.js +1 -1
  494. package/clis/nowcoder/my.js +1 -1
  495. package/clis/nowcoder/post.js +1 -1
  496. package/clis/nowcoder/utils.js +13 -13
  497. package/clis/npm/downloads.js +1 -1
  498. package/clis/npm/package.js +1 -1
  499. package/clis/npm/search.js +1 -1
  500. package/clis/npm/utils.js +1 -1
  501. package/clis/nuget/package.js +1 -1
  502. package/clis/nuget/search.js +1 -1
  503. package/clis/nuget/utils.js +1 -1
  504. package/clis/nvd/cve.js +1 -1
  505. package/clis/oeis/search.js +1 -1
  506. package/clis/oeis/sequence.js +1 -1
  507. package/clis/oeis/utils.js +1 -1
  508. package/clis/ones/common.js +6 -6
  509. package/clis/ones/enrich-tasks.js +1 -1
  510. package/clis/ones/my-tasks.js +1 -1
  511. package/clis/ones/resolve-labels.js +1 -1
  512. package/clis/ones/task-helpers.js +1 -1
  513. package/clis/ones/task.js +1 -1
  514. package/clis/ones/worklog.js +7 -7
  515. package/clis/openalex/search.js +1 -1
  516. package/clis/openalex/utils.js +1 -1
  517. package/clis/openalex/work.js +1 -1
  518. package/clis/openfda/drug-label.js +1 -1
  519. package/clis/openfda/food-recall.js +1 -1
  520. package/clis/openfda/utils.js +1 -1
  521. package/clis/openreview/author.js +1 -1
  522. package/clis/openreview/paper.js +1 -1
  523. package/clis/openreview/reviews.js +3 -3
  524. package/clis/openreview/search.js +1 -1
  525. package/clis/openreview/utils.js +1 -1
  526. package/clis/openreview/venue.js +1 -1
  527. package/clis/oschina/article.js +1 -1
  528. package/clis/oschina/catalogs.js +1 -1
  529. package/clis/oschina/login.js +1 -1
  530. package/clis/oschina/stats.js +6 -6
  531. package/clis/oschina/whoami.js +1 -1
  532. package/clis/osv/query.js +1 -1
  533. package/clis/osv/utils.js +1 -1
  534. package/clis/osv/vulnerability.js +1 -1
  535. package/clis/packagist/package.js +1 -1
  536. package/clis/packagist/search.js +1 -1
  537. package/clis/packagist/utils.js +1 -1
  538. package/clis/pinterest/api.js +1 -1
  539. package/clis/pinterest/auth.js +1 -1
  540. package/clis/pinterest/boards.js +1 -1
  541. package/clis/pinterest/client.js +6 -6
  542. package/clis/pinterest/publish.js +5 -5
  543. package/clis/pixiv/auth.js +2 -2
  544. package/clis/pixiv/download.js +1 -1
  545. package/clis/pixiv/illusts.js +1 -1
  546. package/clis/pixiv/search.js +1 -1
  547. package/clis/pixiv/utils.js +3 -3
  548. package/clis/powerchina/auth.js +2 -2
  549. package/clis/powerchina/search.js +1 -1
  550. package/clis/producthunt/browse.js +2 -2
  551. package/clis/producthunt/hot.js +2 -2
  552. package/clis/producthunt/posts.js +1 -1
  553. package/clis/producthunt/today.js +1 -1
  554. package/clis/producthunt/utils.js +1 -1
  555. package/clis/pypi/downloads.js +1 -1
  556. package/clis/pypi/package.js +1 -1
  557. package/clis/pypi/utils.js +1 -1
  558. package/clis/qiita/auth.js +1 -1
  559. package/clis/qiita/gql.js +6 -6
  560. package/clis/qiita/publish.js +4 -4
  561. package/clis/qiita/stats.js +4 -4
  562. package/clis/qoder/_utils.js +16 -16
  563. package/clis/qoder/composer.js +1 -1
  564. package/clis/qoder/quest.js +1 -1
  565. package/clis/qoder/ui.js +14 -14
  566. package/clis/quark/auth.js +2 -2
  567. package/clis/quark/utils.js +2 -2
  568. package/clis/quora/answer-comments.js +3 -3
  569. package/clis/quora/create-answer.js +4 -4
  570. package/clis/quora/create-question.js +3 -3
  571. package/clis/quora/shared.js +17 -17
  572. package/clis/quora/whoami.js +1 -1
  573. package/clis/qwen/ask.js +1 -1
  574. package/clis/qwen/auth.js +3 -3
  575. package/clis/qwen/detail.js +1 -1
  576. package/clis/qwen/image.js +5 -5
  577. package/clis/qwen/status.js +1 -1
  578. package/clis/qwen/utils.js +16 -16
  579. package/clis/reddit/home.js +3 -3
  580. package/clis/reddit/read.js +10 -10
  581. package/clis/reddit/reply.js +4 -4
  582. package/clis/reddit/submit.js +11 -11
  583. package/clis/reddit/subreddit-info.js +3 -3
  584. package/clis/reddit/subscribed.js +4 -4
  585. package/clis/reddit/whoami.js +2 -2
  586. package/clis/rednote/comments.js +1 -1
  587. package/clis/rednote/download.js +1 -1
  588. package/clis/rednote/feed.js +1 -1
  589. package/clis/rednote/note.js +1 -1
  590. package/clis/rednote/notifications.js +2 -2
  591. package/clis/rednote/search.js +2 -2
  592. package/clis/rest-countries/country.js +1 -1
  593. package/clis/rest-countries/region.js +1 -1
  594. package/clis/rest-countries/utils.js +1 -1
  595. package/clis/reuters/article-detail.js +1 -1
  596. package/clis/reuters/auth.js +3 -3
  597. package/clis/reuters/search.js +1 -1
  598. package/clis/reuters/utils.js +4 -4
  599. package/clis/rfc/rfc.js +1 -1
  600. package/clis/rfc/utils.js +1 -1
  601. package/clis/rubygems/gem.js +1 -1
  602. package/clis/rubygems/search.js +1 -1
  603. package/clis/rubygems/utils.js +1 -1
  604. package/clis/segmentfault/article.js +3 -3
  605. package/clis/segmentfault/channels.js +1 -1
  606. package/clis/segmentfault/login.js +1 -1
  607. package/clis/segmentfault/stats.js +4 -4
  608. package/clis/segmentfault/tags.js +1 -1
  609. package/clis/segmentfault/whoami.js +1 -1
  610. package/clis/semanticscholar/citations.js +1 -1
  611. package/clis/semanticscholar/paper.js +1 -1
  612. package/clis/semanticscholar/recommendations.js +1 -1
  613. package/clis/semanticscholar/search.js +1 -1
  614. package/clis/semanticscholar/utils.js +1 -1
  615. package/clis/sinafinance/news.js +1 -1
  616. package/clis/sinafinance/stock-rank.js +1 -1
  617. package/clis/sinafinance/stock.js +1 -1
  618. package/clis/slock/attachment-download.js +1 -1
  619. package/clis/slock/attachment-upload.js +7 -7
  620. package/clis/slock/attachment-url.js +1 -1
  621. package/clis/slock/auth-verify.js +1 -1
  622. package/clis/slock/bookmark-add.js +1 -1
  623. package/clis/slock/bookmark-remove.js +1 -1
  624. package/clis/slock/channel-action.js +1 -1
  625. package/clis/slock/channel-create.js +1 -1
  626. package/clis/slock/channel-files.js +1 -1
  627. package/clis/slock/channel-list.js +1 -1
  628. package/clis/slock/channel-mark.js +1 -1
  629. package/clis/slock/channel-members.js +1 -1
  630. package/clis/slock/channel-unarchive.js +1 -1
  631. package/clis/slock/dm-list.js +1 -1
  632. package/clis/slock/errors.js +1 -1
  633. package/clis/slock/in-page.js +28 -28
  634. package/clis/slock/inbox-done.js +5 -5
  635. package/clis/slock/inbox.js +1 -1
  636. package/clis/slock/message-read.js +22 -22
  637. package/clis/slock/message-search.js +10 -10
  638. package/clis/slock/message-send.js +25 -25
  639. package/clis/slock/reaction-add.js +1 -1
  640. package/clis/slock/reaction-remove.js +1 -1
  641. package/clis/slock/resolve.js +1 -1
  642. package/clis/slock/server-list.js +2 -2
  643. package/clis/slock/task-claim.js +4 -4
  644. package/clis/slock/task-convert.js +13 -13
  645. package/clis/slock/task-create.js +1 -1
  646. package/clis/slock/task-delete.js +5 -5
  647. package/clis/slock/task-get.js +5 -5
  648. package/clis/slock/task-list-server.js +4 -4
  649. package/clis/slock/task-list.js +5 -5
  650. package/clis/slock/task-status.js +3 -3
  651. package/clis/slock/task-unclaim.js +3 -3
  652. package/clis/slock/thread-follow.js +1 -1
  653. package/clis/slock/thread-state.js +1 -1
  654. package/clis/slock/unread-summary.js +5 -5
  655. package/clis/slock/whoami.js +1 -1
  656. package/clis/smzdm/search.js +3 -3
  657. package/clis/sohu/article.js +1 -1
  658. package/clis/sohu/attributes.js +1 -1
  659. package/clis/sohu/categories.js +1 -1
  660. package/clis/sohu/channels.js +1 -1
  661. package/clis/sohu/columns.js +1 -1
  662. package/clis/sohu/login.js +1 -1
  663. package/clis/sohu/stats.js +3 -3
  664. package/clis/sohu/topics.js +1 -1
  665. package/clis/sohu/whoami.js +1 -1
  666. package/clis/spotify/spotify.js +1 -1
  667. package/clis/stackoverflow/read.js +6 -6
  668. package/clis/stackoverflow/related.js +1 -1
  669. package/clis/stackoverflow/tag.js +1 -1
  670. package/clis/stackoverflow/user.js +1 -1
  671. package/clis/stackoverflow/utils.js +1 -1
  672. package/clis/steam/app.js +1 -1
  673. package/clis/steam/search.js +1 -1
  674. package/clis/steam/utils.js +1 -1
  675. package/clis/substack/auth.js +2 -2
  676. package/clis/substack/post-utils.js +2 -2
  677. package/clis/substack/publish.js +5 -5
  678. package/clis/suno/auth.js +2 -2
  679. package/clis/suno/download.js +5 -5
  680. package/clis/suno/generate.js +3 -3
  681. package/clis/suno/list.js +1 -1
  682. package/clis/suno/status.js +1 -1
  683. package/clis/suno/utils.js +29 -29
  684. package/clis/telegram/send.js +7 -7
  685. package/clis/telegram/shared.js +2 -2
  686. package/clis/telegram/whoami.js +1 -1
  687. package/clis/test-utils.js +1 -1
  688. package/clis/threads/post.js +23 -23
  689. package/clis/threads/shared.js +3 -3
  690. package/clis/threads/whoami.js +1 -1
  691. package/clis/tieba/hot.js +3 -3
  692. package/clis/tieba/posts.js +1 -1
  693. package/clis/tieba/read.js +2 -2
  694. package/clis/tieba/search.js +3 -3
  695. package/clis/tieba/utils.js +1 -1
  696. package/clis/tiktok/comment.js +2 -2
  697. package/clis/tiktok/creator-videos.js +3 -3
  698. package/clis/tiktok/explore.js +3 -3
  699. package/clis/tiktok/follow.js +8 -8
  700. package/clis/tiktok/following.js +4 -4
  701. package/clis/tiktok/friends.js +7 -7
  702. package/clis/tiktok/live.js +3 -3
  703. package/clis/tiktok/notifications.js +6 -6
  704. package/clis/tiktok/publish.js +17 -17
  705. package/clis/tiktok/unfollow.js +4 -4
  706. package/clis/tiktok/user.js +2 -2
  707. package/clis/tiktok/utils.js +1 -1
  708. package/clis/toutiao/article.js +1 -1
  709. package/clis/toutiao/articles.js +2 -2
  710. package/clis/toutiao/auth.js +2 -2
  711. package/clis/toutiao/hot.js +1 -1
  712. package/clis/toutiao/recommend.js +1 -1
  713. package/clis/toutiao/utils.js +2 -2
  714. package/clis/trae-solo/_actions.js +4 -4
  715. package/clis/trae-solo/_fs.js +5 -5
  716. package/clis/trae-solo/_state.js +2 -2
  717. package/clis/trae-solo/automation.js +4 -4
  718. package/clis/trae-solo/mode.js +4 -4
  719. package/clis/trae-solo/model.js +4 -4
  720. package/clis/trae-solo/renderer-storage.js +4 -4
  721. package/clis/trae-solo/settings.js +1 -1
  722. package/clis/trae-solo/skill-fs.js +1 -1
  723. package/clis/trae-solo/skill.js +12 -12
  724. package/clis/trae-solo/state-fs.js +2 -2
  725. package/clis/trae-solo/task-fs.js +5 -5
  726. package/clis/trae-solo/workspaces-fs.js +1 -1
  727. package/clis/tumblr/auth.js +2 -2
  728. package/clis/tumblr/publish.js +3 -3
  729. package/clis/tvmaze/search.js +1 -1
  730. package/clis/tvmaze/show.js +1 -1
  731. package/clis/tvmaze/utils.js +1 -1
  732. package/clis/twitter/accept.js +7 -7
  733. package/clis/twitter/article.js +7 -7
  734. package/clis/twitter/bookmark-folder.js +3 -3
  735. package/clis/twitter/bookmark-folders.js +3 -3
  736. package/clis/twitter/bookmarks.js +4 -4
  737. package/clis/twitter/delete.js +5 -5
  738. package/clis/twitter/device-follow.js +3 -3
  739. package/clis/twitter/dm-list.js +1 -1
  740. package/clis/twitter/dm-read.js +1 -1
  741. package/clis/twitter/dm-send.js +5 -5
  742. package/clis/twitter/dm-shared.js +3 -3
  743. package/clis/twitter/download.js +6 -6
  744. package/clis/twitter/followers.js +5 -5
  745. package/clis/twitter/following.js +2 -2
  746. package/clis/twitter/like.js +3 -3
  747. package/clis/twitter/likes.js +8 -8
  748. package/clis/twitter/list-add-core.js +9 -9
  749. package/clis/twitter/list-create.js +5 -5
  750. package/clis/twitter/list-remove-core.js +9 -9
  751. package/clis/twitter/list-tweets.js +7 -7
  752. package/clis/twitter/lists.js +6 -6
  753. package/clis/twitter/notifications.js +2 -2
  754. package/clis/twitter/post.js +24 -24
  755. package/clis/twitter/profile.js +7 -7
  756. package/clis/twitter/quote.js +7 -7
  757. package/clis/twitter/reply-dm.js +7 -7
  758. package/clis/twitter/reply.js +12 -12
  759. package/clis/twitter/retweet.js +3 -3
  760. package/clis/twitter/scheduled-delete.js +3 -3
  761. package/clis/twitter/scheduled-list.js +2 -2
  762. package/clis/twitter/scheduled-utils.js +3 -3
  763. package/clis/twitter/search.js +5 -5
  764. package/clis/twitter/shared.js +6 -6
  765. package/clis/twitter/thread.js +4 -4
  766. package/clis/twitter/timeline.js +3 -3
  767. package/clis/twitter/trending.js +2 -2
  768. package/clis/twitter/tweets.js +11 -11
  769. package/clis/twitter/unlike.js +3 -3
  770. package/clis/twitter/unretweet.js +3 -3
  771. package/clis/twitter/utils.js +6 -6
  772. package/clis/upwork/detail.js +2 -2
  773. package/clis/upwork/feed.js +2 -2
  774. package/clis/upwork/search.js +2 -2
  775. package/clis/upwork/utils.js +1 -1
  776. package/clis/v2ex/auth.js +2 -2
  777. package/clis/v2ex/daily.js +3 -3
  778. package/clis/v2ex/me.js +2 -2
  779. package/clis/v2ex/notifications.js +2 -2
  780. package/clis/vk/post.js +1 -1
  781. package/clis/vk/shared.js +2 -2
  782. package/clis/vk/whoami.js +1 -1
  783. package/clis/web/read.js +8 -8
  784. package/clis/wechat-channels/auth.js +2 -2
  785. package/clis/wechat-channels/publish.js +30 -30
  786. package/clis/weibo/article.js +1 -1
  787. package/clis/weibo/auth.js +3 -3
  788. package/clis/weibo/comments.js +1 -1
  789. package/clis/weibo/delete.js +2 -2
  790. package/clis/weibo/feed.js +3 -3
  791. package/clis/weibo/hot.js +1 -1
  792. package/clis/weibo/publish.js +10 -10
  793. package/clis/weibo/search.js +2 -2
  794. package/clis/weibo/user-posts.js +3 -3
  795. package/clis/weibo/user.js +2 -2
  796. package/clis/weibo/utils.js +3 -3
  797. package/clis/weixin/article.js +1 -1
  798. package/clis/weixin/create-draft.js +26 -26
  799. package/clis/weixin/download.js +2 -2
  800. package/clis/weixin/login.js +1 -1
  801. package/clis/weixin/search.js +2 -2
  802. package/clis/weixin/stats.js +3 -3
  803. package/clis/weixin/whoami.js +1 -1
  804. package/clis/weread/ai-outline.js +2 -2
  805. package/clis/weread/book-search.js +2 -2
  806. package/clis/weread/book.js +2 -2
  807. package/clis/weread/notebooks.js +1 -1
  808. package/clis/weread/search.js +1 -1
  809. package/clis/weread/shelf.js +1 -1
  810. package/clis/weread/utils.js +6 -6
  811. package/clis/weread-official/book.js +1 -1
  812. package/clis/weread-official/discover.js +1 -1
  813. package/clis/weread-official/list-apis.js +1 -1
  814. package/clis/weread-official/notes.js +1 -1
  815. package/clis/weread-official/readdata.js +1 -1
  816. package/clis/weread-official/review.js +1 -1
  817. package/clis/weread-official/search.js +1 -1
  818. package/clis/weread-official/shelf.js +1 -1
  819. package/clis/weread-official/utils.js +1 -1
  820. package/clis/wikidata/entity.js +1 -1
  821. package/clis/wikidata/search.js +1 -1
  822. package/clis/wikidata/utils.js +1 -1
  823. package/clis/wikipedia/page.js +1 -1
  824. package/clis/wikipedia/trending.js +1 -1
  825. package/clis/wikipedia/utils.js +1 -1
  826. package/clis/wordpress/login.js +1 -1
  827. package/clis/wordpress/publish.js +1 -1
  828. package/clis/wordpress/shared.js +3 -3
  829. package/clis/wordpress/whoami.js +1 -1
  830. package/clis/woshipm/article.js +1 -1
  831. package/clis/woshipm/login.js +1 -1
  832. package/clis/woshipm/stats.js +4 -4
  833. package/clis/woshipm/whoami.js +1 -1
  834. package/clis/wttr/current.js +1 -1
  835. package/clis/wttr/forecast.js +1 -1
  836. package/clis/wttr/utils.js +1 -1
  837. package/clis/xianyu/collect.js +1 -1
  838. package/clis/xianyu/inbox.js +1 -1
  839. package/clis/xianyu/item-stats.js +2 -2
  840. package/clis/xianyu/location.js +1 -1
  841. package/clis/xianyu/manage.js +1 -1
  842. package/clis/xianyu/messages.js +1 -1
  843. package/clis/xianyu/mtop.js +5 -5
  844. package/clis/xianyu/order.js +1 -1
  845. package/clis/xianyu/promote-stats.js +2 -2
  846. package/clis/xianyu/publish.js +17 -17
  847. package/clis/xianyu/rate.js +1 -1
  848. package/clis/xianyu/reply.js +1 -1
  849. package/clis/xianyu/search.js +8 -8
  850. package/clis/xianyu/seller-data.js +1 -1
  851. package/clis/xianyu/seller-list.js +1 -1
  852. package/clis/xianyu/user.js +1 -1
  853. package/clis/xiaoe/catalog.js +2 -2
  854. package/clis/xiaoe/content.js +2 -2
  855. package/clis/xiaoe/courses.js +2 -2
  856. package/clis/xiaohongshu/ask.js +6 -6
  857. package/clis/xiaohongshu/comments.js +6 -6
  858. package/clis/xiaohongshu/creator-note-detail.js +7 -7
  859. package/clis/xiaohongshu/creator-notes-summary.js +1 -1
  860. package/clis/xiaohongshu/creator-notes.js +13 -13
  861. package/clis/xiaohongshu/creator-profile.js +2 -2
  862. package/clis/xiaohongshu/creator-stats.js +2 -2
  863. package/clis/xiaohongshu/delete-note.js +7 -7
  864. package/clis/xiaohongshu/download.js +4 -4
  865. package/clis/xiaohongshu/feed.js +2 -2
  866. package/clis/xiaohongshu/follow.js +3 -3
  867. package/clis/xiaohongshu/human.js +3 -3
  868. package/clis/xiaohongshu/note-helpers.js +1 -1
  869. package/clis/xiaohongshu/note.js +2 -2
  870. package/clis/xiaohongshu/notifications.js +1 -1
  871. package/clis/xiaohongshu/publish-video.js +8 -8
  872. package/clis/xiaohongshu/publish.js +59 -59
  873. package/clis/xiaohongshu/search.js +8 -8
  874. package/clis/xiaohongshu/unfollow.js +4 -4
  875. package/clis/xiaohongshu/user-helpers.js +1 -1
  876. package/clis/xiaohongshu/user.js +2 -2
  877. package/clis/xiaoyuzhou/auth.js +3 -3
  878. package/clis/xiaoyuzhou/download.js +1 -1
  879. package/clis/xiaoyuzhou/utils.js +1 -1
  880. package/clis/xueqiu/article.js +4 -4
  881. package/clis/xueqiu/comments.js +4 -4
  882. package/clis/xueqiu/danjuan-utils.js +4 -4
  883. package/clis/xueqiu/earnings-date.js +1 -1
  884. package/clis/xueqiu/events.js +3 -3
  885. package/clis/xueqiu/hashtags.js +3 -3
  886. package/clis/xueqiu/stocks.js +3 -3
  887. package/clis/xueqiu/users.js +3 -3
  888. package/clis/xueqiu/utils.js +3 -3
  889. package/clis/yahoo-finance/quote.js +1 -1
  890. package/clis/yollomi/background.js +1 -1
  891. package/clis/yollomi/edit.js +1 -1
  892. package/clis/yollomi/face-swap.js +1 -1
  893. package/clis/yollomi/generate.js +1 -1
  894. package/clis/yollomi/object-remover.js +1 -1
  895. package/clis/yollomi/remove-bg.js +1 -1
  896. package/clis/yollomi/restore.js +1 -1
  897. package/clis/yollomi/try-on.js +1 -1
  898. package/clis/yollomi/upload.js +4 -4
  899. package/clis/yollomi/upscale.js +1 -1
  900. package/clis/yollomi/utils.js +4 -4
  901. package/clis/yollomi/video.js +1 -1
  902. package/clis/youtube/channel.js +4 -4
  903. package/clis/youtube/feed.js +2 -2
  904. package/clis/youtube/like.js +5 -5
  905. package/clis/youtube/playlist.js +7 -7
  906. package/clis/youtube/publish.js +11 -11
  907. package/clis/youtube/search.js +3 -3
  908. package/clis/youtube/subscribe.js +7 -7
  909. package/clis/youtube/subscriptions.js +1 -1
  910. package/clis/youtube/transcript-group.js +2 -2
  911. package/clis/youtube/transcript.js +13 -13
  912. package/clis/youtube/unlike.js +5 -5
  913. package/clis/youtube/unsubscribe.js +7 -7
  914. package/clis/youtube/utils.js +3 -3
  915. package/clis/youtube/video.js +4 -4
  916. package/clis/youtube/watch-later.js +2 -2
  917. package/clis/yuanbao/ask.js +18 -18
  918. package/clis/yuanbao/detail.js +1 -1
  919. package/clis/yuanbao/read.js +1 -1
  920. package/clis/yuanbao/shared.js +9 -9
  921. package/clis/yuanbao/status.js +1 -1
  922. package/clis/yuque/article.js +1 -1
  923. package/clis/yuque/whoami.js +1 -1
  924. package/clis/zhihu/answer-comments.js +2 -2
  925. package/clis/zhihu/answer-detail.js +3 -3
  926. package/clis/zhihu/answer.js +1 -1
  927. package/clis/zhihu/article-transform.js +1 -1
  928. package/clis/zhihu/article.js +1 -1
  929. package/clis/zhihu/auth.js +2 -2
  930. package/clis/zhihu/collection.js +3 -3
  931. package/clis/zhihu/collections.js +3 -3
  932. package/clis/zhihu/download.js +2 -2
  933. package/clis/zhihu/image-profile.js +6 -6
  934. package/clis/zhihu/paginate.js +3 -3
  935. package/clis/zhihu/pin.js +4 -4
  936. package/clis/zhihu/question.js +3 -3
  937. package/clis/zhihu/recommend.js +3 -3
  938. package/clis/zhihu/search.js +3 -3
  939. package/clis/zhihu/stats.js +3 -3
  940. package/clis/zhihu/user-arg.js +1 -1
  941. package/clis/zhihu/write-shared.js +7 -7
  942. package/clis/zlibrary/utils.js +6 -6
  943. package/clis/zsxq/auth.js +3 -3
  944. package/clis/zsxq/search.js +1 -1
  945. package/clis/zsxq/topic.js +1 -1
  946. package/clis/zsxq/utils.js +5 -5
  947. package/dist/src/adapter-source.js +1 -1
  948. package/dist/src/browser/analyze.js +1 -1
  949. package/dist/src/browser/article-extract.js +2 -2
  950. package/dist/src/browser/ax-snapshot.js +2 -2
  951. package/dist/src/browser/base-page.js +25 -25
  952. package/dist/src/browser/bridge.js +1 -1
  953. package/dist/src/browser/cdp.js +1 -1
  954. package/dist/src/browser/daemon-client.js +1 -1
  955. package/dist/src/browser/daemon-lifecycle.js +7 -7
  956. package/dist/src/browser/dom-helpers.js +35 -35
  957. package/dist/src/browser/dom-snapshot.js +19 -19
  958. package/dist/src/browser/errors.js +3 -3
  959. package/dist/src/browser/extract.js +5 -5
  960. package/dist/src/browser/find.js +13 -13
  961. package/dist/src/browser/fingerprint.js +2 -2
  962. package/dist/src/browser/html-tree.js +6 -6
  963. package/dist/src/browser/managed-chrome.js +1 -1
  964. package/dist/src/browser/network-cache.js +1 -1
  965. package/dist/src/browser/network-key.js +1 -1
  966. package/dist/src/browser/page.js +7 -7
  967. package/dist/src/browser/profile.js +2 -2
  968. package/dist/src/browser/proxy-test.js +8 -8
  969. package/dist/src/browser/shape-filter.js +1 -1
  970. package/dist/src/browser/shape.js +1 -1
  971. package/dist/src/browser/stealth.js +3 -3
  972. package/dist/src/browser/tabs.js +2 -2
  973. package/dist/src/browser/target-errors.js +1 -1
  974. package/dist/src/browser/target-resolver.js +23 -23
  975. package/dist/src/browser/trace.js +2 -2
  976. package/dist/src/browser/utils.js +1 -1
  977. package/dist/src/browser/verify-fixture.js +2 -2
  978. package/dist/src/browser-session-lock.js +1 -1
  979. package/dist/src/build-manifest.js +11 -11
  980. package/dist/src/capabilityRouting.js +1 -1
  981. package/dist/src/cli-argv-preprocess.js +1 -1
  982. package/dist/src/cli.js +32 -32
  983. package/dist/src/commanderAdapter.js +3 -3
  984. package/dist/src/commands/auth.js +3 -3
  985. package/dist/src/commands/daemon.js +1 -1
  986. package/dist/src/completion-fast.js +1 -1
  987. package/dist/src/completion.js +1 -1
  988. package/dist/src/constants.js +1 -1
  989. package/dist/src/convention-audit.js +2 -2
  990. package/dist/src/daemon-utils.js +1 -1
  991. package/dist/src/daemon.js +1 -1
  992. package/dist/src/discovery.js +2 -2
  993. package/dist/src/doctor.js +9 -9
  994. package/dist/src/download/article-download.js +15 -15
  995. package/dist/src/download/index.js +4 -4
  996. package/dist/src/download/media-download.js +1 -1
  997. package/dist/src/download/progress.js +3 -3
  998. package/dist/src/electron-apps.js +1 -1
  999. package/dist/src/errors.js +2 -2
  1000. package/dist/src/execution.js +2 -2
  1001. package/dist/src/external.js +1 -1
  1002. package/dist/src/help.js +8 -8
  1003. package/dist/src/hooks.js +1 -1
  1004. package/dist/src/interceptor.js +21 -21
  1005. package/dist/src/launcher.js +7 -7
  1006. package/dist/src/logger.js +8 -8
  1007. package/dist/src/main.js +7 -7
  1008. package/dist/src/observation/artifact.js +5 -5
  1009. package/dist/src/observation/retention.js +1 -1
  1010. package/dist/src/output.js +2 -2
  1011. package/dist/src/package-paths.js +1 -1
  1012. package/dist/src/pipeline/executor.js +1 -1
  1013. package/dist/src/pipeline/registry.js +1 -1
  1014. package/dist/src/pipeline/steps/browser.js +1 -1
  1015. package/dist/src/pipeline/steps/download.js +1 -1
  1016. package/dist/src/pipeline/steps/fetch.js +6 -6
  1017. package/dist/src/pipeline/steps/intercept.js +1 -1
  1018. package/dist/src/pipeline/steps/tap.js +17 -17
  1019. package/dist/src/pipeline/steps/transform.js +1 -1
  1020. package/dist/src/pipeline/template.js +1 -1
  1021. package/dist/src/plugin-manifest.js +1 -1
  1022. package/dist/src/plugin-scaffold.js +19 -19
  1023. package/dist/src/plugin.js +12 -12
  1024. package/dist/src/rate-limit.js +1 -1
  1025. package/dist/src/registry.js +1 -1
  1026. package/dist/src/runtime-detect.js +1 -1
  1027. package/dist/src/runtime.js +1 -1
  1028. package/dist/src/scripts/framework.js +1 -1
  1029. package/dist/src/scripts/interact.js +1 -1
  1030. package/dist/src/scripts/store.js +1 -1
  1031. package/dist/src/serialization.js +2 -2
  1032. package/dist/src/session-lease.js +1 -1
  1033. package/dist/src/snapshotFormatter.js +2 -2
  1034. package/dist/src/tui.js +12 -12
  1035. package/dist/src/user-runtime.js +1 -1
  1036. package/dist/src/utils.d.ts +12 -0
  1037. package/dist/src/utils.js +4 -4
  1038. package/dist/src/validate.js +2 -2
  1039. package/dist/src/verify.js +2 -2
  1040. package/dist/src/version.js +1 -1
  1041. package/package.json +1 -1
package/clis/qwen/ask.js CHANGED
@@ -1 +1 @@
1
- import{cli as Q,Strategy as j}from"@jackwener/opencli/registry";import{ArgumentError as $,CommandExecutionError as f,TimeoutError as L}from"@jackwener/opencli/errors";import{QIANWEN_DOMAIN as R,QIANWEN_URL as A,authRequired as D,bubbleHtmlToMarkdown as y,dismissLoginModal as G,ensureOnQianwen as z,getMessageBubbles as N,hasLoginGate as C,normalizeBooleanFlag as X,sendMessage as I,setFeatureToggle as H,startNewChat as T,waitForAnswer as M}from"./utils.js";Q({site:"qwen",name:"ask",access:"write",description:"Send a prompt to Qianwen and return the assistant reply",domain:R,strategy:j.COOKIE,browser:!0,siteSession:"persistent",navigateBefore:!1,defaultFormat:"plain",args:[{name:"prompt",fromFile:!0,required:!0,positional:!0,help:"Prompt to send to Qianwen"},{name:"timeout",type:"int",default:120,help:"Max seconds to wait for the response"},{name:"new",type:"boolean",default:!1,help:"Start a new chat before sending"},{name:"think",type:"boolean",default:!1,help:"Enable 深度思考 (DeepThink)"},{name:"research",type:"boolean",default:!1,help:"Enable 深度研究 (DeepResearch)"},{name:"markdown",type:"boolean",default:!1,help:"Emit assistant reply as markdown"}],columns:["Role","Text"],func:async(J,v)=>{const P=String(v.prompt||"").trim();if(!P)throw new $("prompt is required");const K=Number(v.timeout??120);if(!Number.isInteger(K)||K<=0)throw new $("timeout must be a positive integer");const U=X(v.new,!1),W=X(v.think,!1),_=X(v.research,!1),q=X(v.markdown,!1);await z(J);await G(J);if(U){await T(J);await G(J)}if(W)await H(J,"think",!0);if(_)await H(J,"research",!0);const x=await S(J),Z=await I(J,P);if(!Z?.ok){if(await C(J))throw D();throw new f(Z?.reason||"Failed to send Qianwen prompt")}const Y=await M(J,P,K,x);if(Y.status==="auth_required")throw D();if(Y.status==="timeout")throw new L("qianwen ask",K,"No Qianwen reply observed before timeout. Retry with --timeout increased.");const V=Y.assistant;if(!V)throw new f("No assistant reply found in Qianwen chat.");const O=q&&V.html?y(V.html)||V.text:V.text;return[{Role:"User",Text:P},{Role:"Assistant",Text:O}]}});async function S(J){const v=await N(J),P=v.length?v[v.length-1].id:"";let K="";for(let U=v.length-1;U>=0;U-=1)if(v[U].role==="Assistant"){K=v[U].id;break}return{lastBubbleId:P,lastAssistantId:K}}export const __test__={getBaselineChatAnchor:S};
1
+ import{cli as E,Strategy as N}from"@jackwener/opencli/registry";import{ArgumentError as u,CommandExecutionError as m,TimeoutError as k}from"@jackwener/opencli/errors";import{QIANWEN_DOMAIN as x,QIANWEN_URL as S,authRequired as w,bubbleHtmlToMarkdown as Q,dismissLoginModal as h,ensureOnQianwen as R,getMessageBubbles as T,hasLoginGate as g,normalizeBooleanFlag as r,sendMessage as F,setFeatureToggle as f,startNewChat as I,waitForAnswer as M}from"./utils.js";E({site:"qwen",name:"ask",access:"write",description:"Send a prompt to Qianwen and return the assistant reply",domain:x,strategy:N.COOKIE,browser:!0,siteSession:"persistent",navigateBefore:!1,defaultFormat:"plain",args:[{name:"prompt",fromFile:!0,required:!0,positional:!0,help:"Prompt to send to Qianwen"},{name:"timeout",type:"int",default:120,help:"Max seconds to wait for the response"},{name:"new",type:"boolean",default:!1,help:"Start a new chat before sending"},{name:"think",type:"boolean",default:!1,help:"Enable 深度思考 (DeepThink)"},{name:"research",type:"boolean",default:!1,help:"Enable 深度研究 (DeepResearch)"},{name:"markdown",type:"boolean",default:!1,help:"Emit assistant reply as markdown"}],columns:["Role","Text"],func:async(t,e)=>{const a=String(e.prompt||"").trim();if(!a)throw new u("prompt is required");const n=Number(e.timeout??120);if(!Number.isInteger(n)||n<=0)throw new u("timeout must be a positive integer");const s=r(e.new,!1),c=r(e.think,!1),p=r(e.research,!1),b=r(e.markdown,!1);await R(t);await h(t);if(s){await I(t);await h(t)}if(c)await f(t,"think",!0);if(p)await f(t,"research",!0);const y=await d(t),l=await F(t,a);if(!l?.ok){if(await g(t))throw w();throw new m(l?.reason||"Failed to send Qianwen prompt")}const i=await M(t,a,n,y);if(i.status==="auth_required")throw w();if(i.status==="timeout")throw new k("qianwen ask",n,"No Qianwen reply observed before timeout. Retry with --timeout increased.");const o=i.assistant;if(!o)throw new m("No assistant reply found in Qianwen chat.");const A=b&&o.html?Q(o.html)||o.text:o.text;return[{Role:"User",Text:a},{Role:"Assistant",Text:A}]}});async function d(t){const e=await T(t),a=e.length?e[e.length-1].id:"";let n="";for(let s=e.length-1;s>=0;s-=1)if(e[s].role==="Assistant"){n=e[s].id;break}return{lastBubbleId:a,lastAssistantId:n}}export const __test__={getBaselineChatAnchor:d};
package/clis/qwen/auth.js CHANGED
@@ -1,6 +1,6 @@
1
- import{AuthRequiredError as D,CommandExecutionError as F}from"@jackwener/opencli/errors";import{registerSiteAuthCommands as L}from"../_shared/site-auth.js";async function G(z){return(await z.getCookies({url:"https://chat.qwen.ai"})).some((B)=>B.name==="token"&&B.value)}async function H(z){const B=(await z.getCookies({url:"https://chat.qwen.ai"})).find((K)=>K.name==="token")?.value||"";if(!B)throw new D("qwen.ai","Qwen token cookie missing");await z.goto("https://chat.qwen.ai/");await z.wait(2);const b=await z.evaluate(`(async () => {
1
+ import{AuthRequiredError as n,CommandExecutionError as a}from"@jackwener/opencli/errors";import{registerSiteAuthCommands as w}from"../_shared/site-auth.js";async function o(e){return(await e.getCookies({url:"https://chat.qwen.ai"})).some((i)=>i.name==="token"&&i.value)}async function r(e){const i=(await e.getCookies({url:"https://chat.qwen.ai"})).find((u)=>u.name==="token")?.value||"";if(!i)throw new n("qwen.ai","Qwen token cookie missing");await e.goto("https://chat.qwen.ai/");await e.wait(2);const t=await e.evaluate(`(async () => {
2
2
  try {
3
- const token = ${JSON.stringify(B)};
3
+ const token = ${JSON.stringify(i)};
4
4
  const res = await fetch('/api/v1/auths/', { credentials: 'include', headers: { 'Authorization': 'Bearer ' + token, 'Accept': 'application/json' } });
5
5
  if (res.status === 401 || res.status === 403) {
6
6
  return { kind: 'auth', detail: 'Qwen /api/v1/auths/ HTTP ' + res.status };
@@ -14,4 +14,4 @@ import{AuthRequiredError as D,CommandExecutionError as F}from"@jackwener/opencli
14
14
  } catch (e) {
15
15
  return { kind: 'exception', detail: String(e && e.message || e) };
16
16
  }
17
- })()`);if(b?.kind==="auth")throw new D("qwen.ai",b.detail);if(b?.kind==="http")throw new F(`HTTP ${b.httpStatus} from /api/v1/auths/`);if(b?.kind==="exception")throw new F(`Qwen whoami failed: ${b.detail}`);if(!b?.ok)throw new F(`Unexpected Qwen probe: ${JSON.stringify(b)}`);return{user_id:b.user_id,name:b.name}}L({site:"qwen",domain:"qwen.ai",loginUrl:"https://chat.qwen.ai/auth?action=login",columns:["user_id","name"],quickCheck:G,verify:H,poll:async(z)=>{if(!await G(z))throw new D("qwen.ai","Waiting for Qwen token cookie");return H(z)}});
17
+ })()`);if(t?.kind==="auth")throw new n("qwen.ai",t.detail);if(t?.kind==="http")throw new a(`HTTP ${t.httpStatus} from /api/v1/auths/`);if(t?.kind==="exception")throw new a(`Qwen whoami failed: ${t.detail}`);if(!t?.ok)throw new a(`Unexpected Qwen probe: ${JSON.stringify(t)}`);return{user_id:t.user_id,name:t.name}}w({site:"qwen",domain:"qwen.ai",loginUrl:"https://chat.qwen.ai/auth?action=login",columns:["user_id","name"],quickCheck:o,verify:r,poll:async(e)=>{if(!await o(e))throw new n("qwen.ai","Waiting for Qwen token cookie");return r(e)}});
@@ -1 +1 @@
1
- import{cli as Z,Strategy as $}from"@jackwener/opencli/registry";import{EmptyResultError as f}from"@jackwener/opencli/errors";import{QIANWEN_DOMAIN as z,bubbleHtmlToMarkdown as C,dismissLoginModal as F,getMessageBubbles as H,normalizeBooleanFlag as V,parseQianwenSessionId as W}from"./utils.js";Z({site:"qwen",name:"detail",access:"read",description:"Open a Qianwen conversation by ID and read its messages",domain:z,strategy:$.COOKIE,browser:!0,navigateBefore:!1,siteSession:"persistent",args:[{name:"id",positional:!0,required:!0,help:"Session ID (32-char hex) or full https://www.qianwen.com/chat/<id> URL"},{name:"markdown",type:"boolean",default:!1,help:"Emit assistant replies as markdown"}],columns:["Role","Text"],func:async(v,G)=>{const J=W(G.id),K=V(G.markdown,!1);await v.goto(`https://www.qianwen.com/chat/${J}`);await v.wait(2);await F(v);let x=[];const U=20000,X=1,Y=Date.now();while(Date.now()-Y<U){x=await H(v);if(x.length>0)break;await v.wait(X)}if(!x.length)throw new f("qwen detail",`No visible messages found for conversation ${J}. Verify the ID is correct and that the session belongs to the current device's b-user-id (or that you are logged in for cross-device sync).`);return x.map((q)=>({Role:q.role,Text:K&&q.role==="Assistant"&&q.html?C(q.html)||q.text:q.text}))}});
1
+ import{cli as w,Strategy as d}from"@jackwener/opencli/registry";import{EmptyResultError as c}from"@jackwener/opencli/errors";import{QIANWEN_DOMAIN as m,bubbleHtmlToMarkdown as h,dismissLoginModal as u,getMessageBubbles as f,normalizeBooleanFlag as p,parseQianwenSessionId as g}from"./utils.js";w({site:"qwen",name:"detail",access:"read",description:"Open a Qianwen conversation by ID and read its messages",domain:m,strategy:d.COOKIE,browser:!0,navigateBefore:!1,siteSession:"persistent",args:[{name:"id",positional:!0,required:!0,help:"Session ID (32-char hex) or full https://www.qianwen.com/chat/<id> URL"},{name:"markdown",type:"boolean",default:!1,help:"Emit assistant replies as markdown"}],columns:["Role","Text"],func:async(t,a)=>{const o=g(a.id),n=p(a.markdown,!1);await t.goto(`https://www.qianwen.com/chat/${o}`);await t.wait(2);await u(t);let s=[];const i=20000,r=1,l=Date.now();while(Date.now()-l<i){s=await f(t);if(s.length>0)break;await t.wait(r)}if(!s.length)throw new c("qwen detail",`No visible messages found for conversation ${o}. Verify the ID is correct and that the session belongs to the current device's b-user-id (or that you are logged in for cross-device sync).`);return s.map((e)=>({Role:e.role,Text:n&&e.role==="Assistant"&&e.html?h(e.html)||e.text:e.text}))}});
@@ -1,5 +1,5 @@
1
- import*as S from"node:os";import*as F from"node:path";import{cli as P,Strategy as U}from"@jackwener/opencli/registry";import{saveBase64ToFile as b}from"@jackwener/opencli/utils";import{ArgumentError as j,CommandExecutionError as B,EmptyResultError as E,TimeoutError as f}from"@jackwener/opencli/errors";import{QIANWEN_DOMAIN as A,authRequired as L,dismissLoginModal as N,ensureOnQianwen as I,getMessageBubbles as k,hasLoginGate as T,normalizeBooleanFlag as x,sendMessage as h,setFeatureToggle as c,startNewChat as w}from"./utils.js";function d(H){const J=S.homedir();return H.startsWith(J)?`~${H.slice(J.length)}`:H}function m(H){if(!H)return".jpg";if(H.includes("png"))return".png";if(H.includes("webp"))return".webp";if(H.includes("gif"))return".gif";return".jpg"}async function y(H,J){return await H.evaluate(`(() => {
2
- const scope = ${JSON.stringify(J||"")};
1
+ import*as p from"node:os";import*as E from"node:path";import{cli as x,Strategy as O}from"@jackwener/opencli/registry";import{saveBase64ToFile as D}from"@jackwener/opencli/utils";import{ArgumentError as y,CommandExecutionError as S,EmptyResultError as M,TimeoutError as Q}from"@jackwener/opencli/errors";import{QIANWEN_DOMAIN as B,authRequired as k,dismissLoginModal as q,ensureOnQianwen as C,getMessageBubbles as L,hasLoginGate as v,normalizeBooleanFlag as A,sendMessage as _,setFeatureToggle as T,startNewChat as U}from"./utils.js";function j(t){const e=p.homedir();return t.startsWith(e)?`~${t.slice(e.length)}`:t}function R(t){if(!t)return".jpg";if(t.includes("png"))return".png";if(t.includes("webp"))return".webp";if(t.includes("gif"))return".gif";return".jpg"}async function F(t,e){return await t.evaluate(`(() => {
2
+ const scope = ${JSON.stringify(e||"")};
3
3
  const bubbles = Array.from(document.querySelectorAll('[data-msgid$="-answer"]'));
4
4
  const target = scope
5
5
  ? bubbles.find((b) => b.getAttribute('data-msgid') === scope)
@@ -12,9 +12,9 @@ import*as S from"node:os";import*as F from"node:path";import{cli as P,Strategy a
12
12
  && !/\\.(svg)$/i.test(src)
13
13
  && !src.includes('alicdn.com/imgextra'));
14
14
  return Array.from(new Set(imgs));
15
- })()`)}async function n(H,J,v){const _=Date.now();let X=[];while(Date.now()-_<v*1000){await H.wait(2);if(await T(H))return{status:"auth_required",urls:[]};const V=await y(H,J);if(V.length&&V.length===X.length&&V.every((K,$)=>K===X[$]))return{status:"ok",urls:V};if(V.length){await H.wait(2);const K=await y(H,J);if(K.length===V.length&&K.every(($,W)=>$===V[W]))return{status:"ok",urls:K};X=K;continue}X=V}return X.length?{status:"partial",urls:X}:{status:"timeout",urls:[]}}async function u(H,J){return await H.evaluate(`(async () => {
15
+ })()`)}async function W(t,e,u){const c=Date.now();let n=[];while(Date.now()-c<u*1000){await t.wait(2);if(await v(t))return{status:"auth_required",urls:[]};const a=await F(t,e);if(a.length&&a.length===n.length&&a.every((r,o)=>r===n[o]))return{status:"ok",urls:a};if(a.length){await t.wait(2);const r=await F(t,e);if(r.length===a.length&&r.every((o,l)=>o===a[l]))return{status:"ok",urls:r};n=r;continue}n=a}return n.length?{status:"partial",urls:n}:{status:"timeout",urls:[]}}async function G(t,e){return await t.evaluate(`(async () => {
16
16
  try {
17
- const res = await fetch(${JSON.stringify(J)}, { credentials: 'include' });
17
+ const res = await fetch(${JSON.stringify(e)}, { credentials: 'include' });
18
18
  if (!res.ok) return { ok: false, status: res.status };
19
19
  const mime = res.headers.get('content-type') || '';
20
20
  const buf = await res.arrayBuffer();
@@ -28,4 +28,4 @@ import*as S from"node:os";import*as F from"node:path";import{cli as P,Strategy a
28
28
  } catch (error) {
29
29
  return { ok: false, status: 0, error: String(error?.message || error) };
30
30
  }
31
- })()`)}P({site:"qwen",name:"image",access:"write",description:"Generate images with Qianwen (AI生图) and save them locally",domain:A,strategy:U.COOKIE,browser:!0,siteSession:"persistent",navigateBefore:!1,defaultFormat:"plain",args:[{name:"prompt",fromFile:!0,required:!0,positional:!0,help:"Image prompt to send"},{name:"op",default:"~/Pictures/qianwen",help:"Output directory"},{name:"new",type:"boolean",default:!0,help:"Start a new chat before generating (default: true)"},{name:"sd",type:"boolean",default:!1,help:"Skip download; only show the Qianwen link"},{name:"timeout",type:"int",default:180,help:"Max seconds to wait for the image response"}],columns:["Status","File","Link"],func:async(H,J)=>{const v=String(J.prompt||"").trim();if(!v)throw new j("prompt is required");const _=String(J.op||"~/Pictures/qianwen").replace(/^~\//,`${S.homedir()}/`),X=x(J.new,!0),V=x(J.sd,!1),K=Number(J.timeout??180);if(!Number.isInteger(K)||K<=0)throw new j("timeout must be a positive integer");await I(H);await N(H);if(X){await w(H);await N(H)}await c(H,"image",!0);await H.wait(0.5);const $=await h(H,v);if(!$?.ok){if(await T(H))throw L();throw new B($?.reason||"Failed to send Qianwen image prompt")}let W="";for(let Y=0;Y<5;Y+=1){await H.wait(1);const Z=[...await k(H)].reverse().find((Q)=>Q.role==="Assistant");if(Z){W=Z.id;break}}const q=await n(H,W,K),C=await H.evaluate("window.location.href").catch(()=>"https://www.qianwen.com/");if(q.status==="auth_required")throw L();if(q.status==="timeout")throw new f("qianwen image",K,"No generated images observed before timeout.");const z=q.urls;if(V)return[{Status:"\uD83C\uDFA8 generated",File:null,Link:C}];const M=Date.now(),O=[];for(let Y=0;Y<z.length;Y+=1){const D=z[Y],Z=await u(H,D);if(!Z?.ok)throw new B(`Failed to fetch generated Qianwen image ${Y+1}: status=${Z?.status||"?"}`);const Q=z.length>1?`_${Y+1}`:"",R=m(Z.mime),G=F.join(_,`qianwen_${M}${Q}${R}`);await b(Z.base64,G);O.push({Status:"✅ saved",File:d(G),Link:C})}if(!O.length)throw new E("qwen image","No generated images were available to download.");return O}});
31
+ })()`)}x({site:"qwen",name:"image",access:"write",description:"Generate images with Qianwen (AI生图) and save them locally",domain:B,strategy:O.COOKIE,browser:!0,siteSession:"persistent",navigateBefore:!1,defaultFormat:"plain",args:[{name:"prompt",fromFile:!0,required:!0,positional:!0,help:"Image prompt to send"},{name:"op",default:"~/Pictures/qianwen",help:"Output directory"},{name:"new",type:"boolean",default:!0,help:"Start a new chat before generating (default: true)"},{name:"sd",type:"boolean",default:!1,help:"Skip download; only show the Qianwen link"},{name:"timeout",type:"int",default:180,help:"Max seconds to wait for the image response"}],columns:["Status","File","Link"],func:async(t,e)=>{const u=String(e.prompt||"").trim();if(!u)throw new y("prompt is required");const c=String(e.op||"~/Pictures/qianwen").replace(/^~\//,`${p.homedir()}/`),n=A(e.new,!0),a=A(e.sd,!1),r=Number(e.timeout??180);if(!Number.isInteger(r)||r<=0)throw new y("timeout must be a positive integer");await C(t);await q(t);if(n){await U(t);await q(t)}await T(t,"image",!0);await t.wait(0.5);const o=await _(t,u);if(!o?.ok){if(await v(t))throw k();throw new S(o?.reason||"Failed to send Qianwen image prompt")}let l="";for(let s=0;s<5;s+=1){await t.wait(1);const i=[...await L(t)].reverse().find((d)=>d.role==="Assistant");if(i){l=i.id;break}}const m=await W(t,l,r),h=await t.evaluate("window.location.href").catch(()=>"https://www.qianwen.com/");if(m.status==="auth_required")throw k();if(m.status==="timeout")throw new Q("qianwen image",r,"No generated images observed before timeout.");const w=m.urls;if(a)return[{Status:"\uD83C\uDFA8 generated",File:null,Link:h}];const N=Date.now(),f=[];for(let s=0;s<w.length;s+=1){const g=w[s],i=await G(t,g);if(!i?.ok)throw new S(`Failed to fetch generated Qianwen image ${s+1}: status=${i?.status||"?"}`);const d=w.length>1?`_${s+1}`:"",I=R(i.mime),b=E.join(c,`qianwen_${N}${d}${I}`);await D(i.base64,b);f.push({Status:"✅ saved",File:j(b),Link:h})}if(!f.length)throw new M("qwen image","No generated images were available to download.");return f}});
@@ -1 +1 @@
1
- import{cli as z,Strategy as B}from"@jackwener/opencli/registry";import{QIANWEN_DOMAIN as F,ensureOnQianwen as G,isLoggedIn as H,getCurrentSessionId as J,getModelLabel as K}from"./utils.js";z({site:"qwen",name:"status",access:"read",description:"Check Qianwen page availability, login state, current session and model",domain:F,strategy:B.COOKIE,browser:!0,siteSession:"persistent",navigateBefore:!1,args:[],columns:["Status","Login","Model","SessionId","Url"],func:async(f)=>{await G(f);await f.wait(2);const[x,h,q,v]=await Promise.all([H(f),J(f),K(f),f.evaluate("window.location.href").catch(()=>"")]);return[{Status:"Connected",Login:x?"Yes":"No (guest mode)",Model:q?q:null,SessionId:h?h:null,Url:typeof v==="string"?v:""}]}});
1
+ import{cli as i,Strategy as a}from"@jackwener/opencli/registry";import{QIANWEN_DOMAIN as r,ensureOnQianwen as l,isLoggedIn as d,getCurrentSessionId as u,getModelLabel as c}from"./utils.js";i({site:"qwen",name:"status",access:"read",description:"Check Qianwen page availability, login state, current session and model",domain:r,strategy:a.COOKIE,browser:!0,siteSession:"persistent",navigateBefore:!1,args:[],columns:["Status","Login","Model","SessionId","Url"],func:async(e)=>{await l(e);await e.wait(2);const[o,s,t,n]=await Promise.all([d(e),u(e),c(e),e.evaluate("window.location.href").catch(()=>"")]);return[{Status:"Connected",Login:o?"Yes":"No (guest mode)",Model:t?t:null,SessionId:s?s:null,Url:typeof n==="string"?n:""}]}});
@@ -1,4 +1,4 @@
1
- import{htmlToMarkdown as O}from"@jackwener/opencli/utils";import{ArgumentError as k,AuthRequiredError as R,CommandExecutionError as C,TimeoutError as N}from"@jackwener/opencli/errors";export const QIANWEN_DOMAIN="www.qianwen.com",QIANWEN_URL="https://www.qianwen.com/",QIANWEN_API_DOMAIN="chat2-api.qianwen.com",IS_VISIBLE_JS=`
1
+ import{htmlToMarkdown as b}from"@jackwener/opencli/utils";import{ArgumentError as f,AuthRequiredError as g,CommandExecutionError as A,TimeoutError as L}from"@jackwener/opencli/errors";export const QIANWEN_DOMAIN="www.qianwen.com",QIANWEN_URL="https://www.qianwen.com/",QIANWEN_API_DOMAIN="chat2-api.qianwen.com",IS_VISIBLE_JS=`
2
2
  const isVisible = (node) => {
3
3
  if (!(node instanceof Element)) return false;
4
4
  const style = window.getComputedStyle(node);
@@ -6,7 +6,7 @@ import{htmlToMarkdown as O}from"@jackwener/opencli/utils";import{ArgumentError a
6
6
  const rect = node.getBoundingClientRect();
7
7
  return rect.width > 0 && rect.height > 0;
8
8
  };
9
- `;const J=2,M=6000,w=2;export function authRequired(H){return new R(QIANWEN_DOMAIN,H||"请在浏览器里用千问 APP 扫码登录 qianwen.com 后再重试。")}export function normalizeBooleanFlag(H,X=!1){if(typeof H==="boolean")return H;if(H==null||H==="")return X;const K=String(H).trim().toLowerCase();return K==="true"||K==="1"||K==="yes"||K==="on"}export async function isOnQianwen(H){const X=await H.evaluate("window.location.href").catch(()=>"");return typeof X==="string"&&X.includes("qianwen.com")}export async function ensureOnQianwen(H){if(await isOnQianwen(H))return;await H.goto(QIANWEN_URL);await H.wait(2)}export async function dismissLoginModal(H){return await H.evaluate(`(() => {
9
+ `;const h=2,x=6000,S=2;export function authRequired(t){return new g(QIANWEN_DOMAIN,t||"请在浏览器里用千问 APP 扫码登录 qianwen.com 后再重试。")}export function normalizeBooleanFlag(t,n=!1){if(typeof t==="boolean")return t;if(t==null||t==="")return n;const e=String(t).trim().toLowerCase();return e==="true"||e==="1"||e==="yes"||e==="on"}export async function isOnQianwen(t){const n=await t.evaluate("window.location.href").catch(()=>"");return typeof n==="string"&&n.includes("qianwen.com")}export async function ensureOnQianwen(t){if(await isOnQianwen(t))return;await t.goto(QIANWEN_URL);await t.wait(2)}export async function dismissLoginModal(t){return await t.evaluate(`(() => {
10
10
  ${IS_VISIBLE_JS}
11
11
  const modal = document.querySelector('[role=alert-biz-modal]');
12
12
  if (!modal || !isVisible(modal)) return { dismissed: false };
@@ -27,7 +27,7 @@ import{htmlToMarkdown as O}from"@jackwener/opencli/utils";import{ArgumentError a
27
27
  // Last resort: synth ESC key on document
28
28
  document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', code: 'Escape', bubbles: true }));
29
29
  return { dismissed: true, method: 'escape' };
30
- })()`)}export async function hasLoginGate(H){const X=await H.evaluate(`(() => {
30
+ })()`)}export async function hasLoginGate(t){const n=await t.evaluate(`(() => {
31
31
  ${IS_VISIBLE_JS}
32
32
  const modal = document.querySelector('[role=alert-biz-modal]');
33
33
  if (modal && isVisible(modal)) {
@@ -36,7 +36,7 @@ import{htmlToMarkdown as O}from"@jackwener/opencli/utils";import{ArgumentError a
36
36
  if (src.includes('passport.qianwen.com') || src.includes('login')) return true;
37
37
  }
38
38
  return false;
39
- })()`);return Boolean(X)}export async function isLoggedIn(H){const X=await H.evaluate(`(() => {
39
+ })()`);return Boolean(n)}export async function isLoggedIn(t){const n=await t.evaluate(`(() => {
40
40
  ${IS_VISIBLE_JS}
41
41
  const loginBtn = Array.from(document.querySelectorAll('button'))
42
42
  .find((node) => (node.textContent || '').trim() === '登录' && isVisible(node));
@@ -45,14 +45,14 @@ import{htmlToMarkdown as O}from"@jackwener/opencli/utils";import{ArgumentError a
45
45
  .find((node) => (node.textContent || '').includes('登录可同步历史对话'));
46
46
  if (hint && isVisible(hint)) return false;
47
47
  return true;
48
- })()`);return Boolean(X)}export async function getCurrentSessionId(H){const X=await H.evaluate("window.location.href").catch(()=>"");if(typeof X!=="string")return"";const K=X.match(/\/chat\/([A-Za-z0-9_-]+)/);return K?K[1]:""}const V=/^[a-f0-9]{32}$/i;export function parseQianwenSessionId(H){const X=String(H??"").trim();if(!X)throw new k("id","must be a non-empty session ID or qianwen.com chat URL");const K=X.match(/qianwen\.com\/chat\/([a-f0-9]{32})(?:[/?#]|$)/i),Z=K?K[1]:X;if(!V.test(Z))throw new k("id",`not a valid Qianwen session ID (got "${H}"); expected a 32-char hex ID like "abcd1234ef567890abcd1234ef567890" or a full https://www.qianwen.com/chat/<id> URL`);return Z.toLowerCase()}export async function getModelLabel(H){const X=await H.evaluate(`(() => {
48
+ })()`);return Boolean(n)}export async function getCurrentSessionId(t){const n=await t.evaluate("window.location.href").catch(()=>"");if(typeof n!=="string")return"";const e=n.match(/\/chat\/([A-Za-z0-9_-]+)/);return e?e[1]:""}const E=/^[a-f0-9]{32}$/i;export function parseQianwenSessionId(t){const n=String(t??"").trim();if(!n)throw new f("id","must be a non-empty session ID or qianwen.com chat URL");const e=n.match(/qianwen\.com\/chat\/([a-f0-9]{32})(?:[/?#]|$)/i),o=e?e[1]:n;if(!E.test(o))throw new f("id",`not a valid Qianwen session ID (got "${t}"); expected a 32-char hex ID like "abcd1234ef567890abcd1234ef567890" or a full https://www.qianwen.com/chat/<id> URL`);return o.toLowerCase()}export async function getModelLabel(t){const n=await t.evaluate(`(() => {
49
49
  ${IS_VISIBLE_JS}
50
50
  const trigger = Array.from(document.querySelectorAll('[aria-haspopup=dialog]'))
51
51
  .find((node) => isVisible(node) && (node.innerText || '').includes('Qwen'));
52
52
  if (!trigger) return '';
53
53
  const label = (trigger.innerText || '').split('\\n')[0].trim();
54
54
  return label;
55
- })()`);return typeof X==="string"?X:""}export async function startNewChat(H){if((await H.evaluate(`(() => {
55
+ })()`);return typeof n==="string"?n:""}export async function startNewChat(t){if((await t.evaluate(`(() => {
56
56
  ${IS_VISIBLE_JS}
57
57
  const button = Array.from(document.querySelectorAll('button'))
58
58
  .find((node) => isVisible(node) && (node.innerText || '').trim() === '新建对话');
@@ -61,12 +61,12 @@ import{htmlToMarkdown as O}from"@jackwener/opencli/utils";import{ArgumentError a
61
61
  return { ok: true, method: 'button' };
62
62
  }
63
63
  return { ok: false };
64
- })()`))?.ok){await H.wait(1.5);return!0}await H.goto(QIANWEN_URL);await H.wait(2);return!0}export async function getComposer(H){return await H.evaluate(`(() => {
64
+ })()`))?.ok){await t.wait(1.5);return!0}await t.goto(QIANWEN_URL);await t.wait(2);return!0}export async function getComposer(t){return await t.evaluate(`(() => {
65
65
  ${IS_VISIBLE_JS}
66
66
  const editor = Array.from(document.querySelectorAll('[role=textbox][contenteditable=true]'))
67
67
  .find((node) => isVisible(node));
68
68
  return { found: !!editor, text: editor?.textContent || '' };
69
- })()`)}export async function sendMessage(H,X){return await H.evaluate(`(async () => {
69
+ })()`)}export async function sendMessage(t,n){return await t.evaluate(`(async () => {
70
70
  ${IS_VISIBLE_JS}
71
71
  const waitFor = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
72
72
 
@@ -89,7 +89,7 @@ import{htmlToMarkdown as O}from"@jackwener/opencli/utils";import{ArgumentError a
89
89
  // Slate editor accepts content via beforeinput InputEvent
90
90
  editor.dispatchEvent(new InputEvent('beforeinput', {
91
91
  inputType: 'insertText',
92
- data: ${JSON.stringify(X)},
92
+ data: ${JSON.stringify(n)},
93
93
  bubbles: true,
94
94
  cancelable: true,
95
95
  }));
@@ -105,7 +105,7 @@ import{htmlToMarkdown as O}from"@jackwener/opencli/utils";import{ArgumentError a
105
105
  editor.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', code: 'Enter', keyCode: 13, bubbles: true }));
106
106
  editor.dispatchEvent(new KeyboardEvent('keyup', { key: 'Enter', code: 'Enter', keyCode: 13, bubbles: true }));
107
107
  return { ok: true, action: 'enter-fallback' };
108
- })()`)}export async function getMessageBubbles(H){const X=await H.evaluate(`(() => {
108
+ })()`)}export async function getMessageBubbles(t){const n=await t.evaluate(`(() => {
109
109
  ${IS_VISIBLE_JS}
110
110
  const wraps = Array.from(document.querySelectorAll('[data-chat-question-wrap], [data-chat-answers-wrap]'))
111
111
  .filter((node) => node instanceof HTMLElement && isVisible(node));
@@ -140,20 +140,20 @@ import{htmlToMarkdown as O}from"@jackwener/opencli/utils";import{ArgumentError a
140
140
  out.push({ id, role, text: (text || '').replace(/\\s+/g, ' ').trim(), html });
141
141
  }
142
142
  return out;
143
- })()`);if(!Array.isArray(X))return[];return X.map((K)=>({id:String(K?.id||""),role:K?.role==="Assistant"?"Assistant":"User",text:String(K?.text||"").trim(),html:String(K?.html||"")})).filter((K)=>K.id&&K.text)}export function bubbleHtmlToMarkdown(H){try{return O(H).trim()}catch{return(H||"").replace(/<[^>]+>/g," ").replace(/\s+/g," ").trim()}}function D(H){return(H||"").replace(/\u00a0/g," ").replace(/复制\s*$/g,"").replace(/重新生成\s*$/g,"").trim()}function P(H){return D(H).replace(/\s+/g," ").trim()}function f(H){if(typeof H==="string")return{lastBubbleId:"",lastAssistantId:H};return{lastBubbleId:String(H?.lastBubbleId||""),lastAssistantId:String(H?.lastAssistantId||"")}}function T(H,X,K){const Z=P(X);let q=-1;const j=Boolean(K.lastBubbleId||K.lastAssistantId);let F=!1;if(K.lastBubbleId){const $=H.findIndex((G)=>G.id===K.lastBubbleId);if($>=0){q=$;F=!0}}if(K.lastAssistantId){const $=H.findIndex((G)=>G.id===K.lastAssistantId);if($>=0){q=Math.max(q,$);F=!0}}if(j&&!F)return null;let Y=-1;for(let $=q+1;$<H.length;$+=1)if(H[$].role==="User"&&P(H[$].text)===Z)Y=$;if(Y<0)return null;for(let $=Y+1;$<H.length;$+=1)if(H[$].role==="Assistant")return H[$];return null}export async function waitForAnswer(H,X,K,Z){const q=f(Z),j=Date.now();let F="",Y=0,$="",G=null;while(Date.now()-j<K*1000){await H.wait(J);if(await hasLoginGate(H))return{status:"auth_required"};const Q=await getMessageBubbles(H),y=T(Q,X,q);if(!y)continue;if(q.lastAssistantId&&y.id===q.lastAssistantId)continue;const U=D(y.text);if(!U||U===X)continue;$=U;G=y;const W=Date.now()-j>=M;if(U===F){Y+=1;if(W&&Y>=w)return{status:"ok",assistant:y}}else{F=U;Y=0}}if($)return{status:"partial",assistant:G};return{status:"timeout"}}const v={think:"深度思考",research:"深度研究",task:"任务助理",image:"AI生图",ppt:"PPT创作"};export async function setFeatureToggle(H,X,K){const Z=v[X];if(!Z)return!1;const q=await H.evaluate(`(async () => {
143
+ })()`);if(!Array.isArray(n))return[];return n.map((e)=>({id:String(e?.id||""),role:e?.role==="Assistant"?"Assistant":"User",text:String(e?.text||"").trim(),html:String(e?.html||"")})).filter((e)=>e.id&&e.text)}export function bubbleHtmlToMarkdown(t){try{return b(t).trim()}catch{return(t||"").replace(/<[^>]+>/g," ").replace(/\s+/g," ").trim()}}function m(t){return(t||"").replace(/\u00a0/g," ").replace(/复制\s*$/g,"").replace(/重新生成\s*$/g,"").trim()}function p(t){return m(t).replace(/\s+/g," ").trim()}function I(t){if(typeof t==="string")return{lastBubbleId:"",lastAssistantId:t};return{lastBubbleId:String(t?.lastBubbleId||""),lastAssistantId:String(t?.lastAssistantId||"")}}function q(t,n,e){const o=p(n);let a=-1;const c=Boolean(e.lastBubbleId||e.lastAssistantId);let i=!1;if(e.lastBubbleId){const s=t.findIndex((l)=>l.id===e.lastBubbleId);if(s>=0){a=s;i=!0}}if(e.lastAssistantId){const s=t.findIndex((l)=>l.id===e.lastAssistantId);if(s>=0){a=Math.max(a,s);i=!0}}if(c&&!i)return null;let r=-1;for(let s=a+1;s<t.length;s+=1)if(t[s].role==="User"&&p(t[s].text)===o)r=s;if(r<0)return null;for(let s=r+1;s<t.length;s+=1)if(t[s].role==="Assistant")return t[s];return null}export async function waitForAnswer(t,n,e,o){const a=I(o),c=Date.now();let i="",r=0,s="",l=null;while(Date.now()-c<e*1000){await t.wait(h);if(await hasLoginGate(t))return{status:"auth_required"};const w=await getMessageBubbles(t),d=q(w,n,a);if(!d)continue;if(a.lastAssistantId&&d.id===a.lastAssistantId)continue;const u=m(d.text);if(!u||u===n)continue;s=u;l=d;const y=Date.now()-c>=x;if(u===i){r+=1;if(y&&r>=S)return{status:"ok",assistant:d}}else{i=u;r=0}}if(s)return{status:"partial",assistant:l};return{status:"timeout"}}const k={think:"深度思考",research:"深度研究",task:"任务助理",image:"AI生图",ppt:"PPT创作"};export async function setFeatureToggle(t,n,e){const o=k[n];if(!o)return!1;const a=await t.evaluate(`(async () => {
144
144
  ${IS_VISIBLE_JS}
145
145
  const waitFor = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
146
- const label = ${JSON.stringify(Z)};
146
+ const label = ${JSON.stringify(o)};
147
147
  const button = Array.from(document.querySelectorAll('button[aria-label]'))
148
148
  .find((node) => isVisible(node) && node.getAttribute('aria-label') === label);
149
149
  if (!(button instanceof HTMLElement)) return { found: false };
150
150
  const selected = button.getAttribute('aria-pressed') === 'true'
151
151
  || /active|selected|bg-primary/.test(button.className || '');
152
- if (selected === ${Boolean(K)}) return { found: true, changed: false, selected };
152
+ if (selected === ${Boolean(e)}) return { found: true, changed: false, selected };
153
153
  button.click();
154
154
  await waitFor(300);
155
155
  return { found: true, changed: true };
156
- })()`);return Boolean(q?.found)}export async function getSessionListFromApi(H,X=30){const K=Number(X??30);if(!Number.isInteger(K)||K<=0||K>100)throw new C("Qianwen history page_size must be an integer between 1 and 100");const Z=await H.evaluate(`(async () => {
156
+ })()`);return Boolean(a?.found)}export async function getSessionListFromApi(t,n=30){const e=Number(n??30);if(!Number.isInteger(e)||e<=0||e>100)throw new A("Qianwen history page_size must be an integer between 1 and 100");const o=await t.evaluate(`(async () => {
157
157
  try {
158
158
  const utdid = (document.cookie.match(/(?:^|;\\s*)b-user-id=([^;]+)/)?.[1])
159
159
  || (document.cookie.match(/(?:^|;\\s*)utdid=([^;]+)/)?.[1])
@@ -173,7 +173,7 @@ import{htmlToMarkdown as O}from"@jackwener/opencli/utils";import{ArgumentError a
173
173
  method: 'POST',
174
174
  credentials: 'include',
175
175
  headers: { 'Content-Type': 'application/json' },
176
- body: JSON.stringify({ page_num: 1, page_size: ${K}, page_no: 1 }),
176
+ body: JSON.stringify({ page_num: 1, page_size: ${e}, page_no: 1 }),
177
177
  });
178
178
  const text = await res.text();
179
179
  let body = null;
@@ -182,4 +182,4 @@ import{htmlToMarkdown as O}from"@jackwener/opencli/utils";import{ArgumentError a
182
182
  } catch (error) {
183
183
  return { ok: false, status: 0, error: String(error?.message || error) };
184
184
  }
185
- })()`);if(!Z||!Z.ok)return{ok:!1,status:Z?.status||0,error:Z?.error||"",sessions:[]};const q=Z.body?.data||Z.body?.result||{},F=(Array.isArray(q?.list)?q.list:Array.isArray(q?.items)?q.items:Array.isArray(q?.page_list)?q.page_list:Array.isArray(Z.body?.list)?Z.body.list:[]).map((Y)=>({id:String(Y?.session_id||Y?.sessionId||Y?.id||""),title:String(Y?.title||Y?.name||Y?.summary||"").trim(),updated_at:Number(Y?.updated_at||Y?.last_req_timestamp||Y?.updatedAt||Y?.gmt_modified||Y?.update_time||0)})).filter((Y)=>Y.id);return{ok:!0,status:Z.status,sessions:F}}
185
+ })()`);if(!o||!o.ok)return{ok:!1,status:o?.status||0,error:o?.error||"",sessions:[]};const a=o.body?.data||o.body?.result||{},i=(Array.isArray(a?.list)?a.list:Array.isArray(a?.items)?a.items:Array.isArray(a?.page_list)?a.page_list:Array.isArray(o.body?.list)?o.body.list:[]).map((r)=>({id:String(r?.session_id||r?.sessionId||r?.id||""),title:String(r?.title||r?.name||r?.summary||"").trim(),updated_at:Number(r?.updated_at||r?.last_req_timestamp||r?.updatedAt||r?.gmt_modified||r?.update_time||0)})).filter((r)=>r.id);return{ok:!0,status:o.status,sessions:i}}
@@ -1,4 +1,4 @@
1
- import{ArgumentError as V,AuthRequiredError as W,CommandExecutionError as N,EmptyResultError as Y}from"@jackwener/opencli/errors";import{cli as Z,Strategy as $}from"@jackwener/opencli/registry";const Q=100;export function parseRedditHomeLimit(b){if(b===void 0||b===null||b==="")return 25;const B=Number(b);if(!Number.isFinite(B)||!Number.isInteger(B)||B<1||B>Q)throw new V(`limit must be an integer in [1, ${Q}].`,`Got: ${b}`);return B}export function decodeRedditHtml(b){if(typeof b!=="string"||!b)return"";return b.replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#x27;/gi,"'").replace(/&#39;/g,"'")}export function extractRedditMedia(b){const B=[],G=b?.gallery_data?.items,z=b?.media_metadata;if(Array.isArray(G)&&z&&typeof z==="object")for(const J of G){const F=z[J?.media_id]?.s?.u;if(typeof F==="string"&&F)B.push(decodeRedditHtml(F))}return{post_hint:typeof b?.post_hint==="string"?b.post_hint:"",url_overridden_by_dest:decodeRedditHtml(b?.url_overridden_by_dest||""),preview_image_url:decodeRedditHtml(b?.preview?.images?.[0]?.source?.url||""),gallery_urls:B}}Z({site:"reddit",name:"home",access:"read",description:"Reddit personalized home feed (Best, requires login)",domain:"reddit.com",strategy:$.COOKIE,browser:!0,args:[{name:"limit",type:"int",default:25,help:`Number of posts (1–${Q})`}],columns:["rank","title","subreddit","score","comments","postId","author","url","post_hint","url_overridden_by_dest","preview_image_url","gallery_urls"],func:async(b,B)=>{const G=parseRedditHomeLimit(B.limit);await b.goto("https://www.reddit.com");const z=await b.evaluate(`(async () => {
1
+ import{ArgumentError as l,AuthRequiredError as m,CommandExecutionError as a,EmptyResultError as c}from"@jackwener/opencli/errors";import{cli as p,Strategy as h}from"@jackwener/opencli/registry";const u=100;export function parseRedditHomeLimit(e){if(e===void 0||e===null||e==="")return 25;const i=Number(e);if(!Number.isFinite(i)||!Number.isInteger(i)||i<1||i>u)throw new l(`limit must be an integer in [1, ${u}].`,`Got: ${e}`);return i}export function decodeRedditHtml(e){if(typeof e!=="string"||!e)return"";return e.replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#x27;/gi,"'").replace(/&#39;/g,"'")}export function extractRedditMedia(e){const i=[],s=e?.gallery_data?.items,r=e?.media_metadata;if(Array.isArray(s)&&r&&typeof r==="object")for(const o of s){const n=r[o?.media_id]?.s?.u;if(typeof n==="string"&&n)i.push(decodeRedditHtml(n))}return{post_hint:typeof e?.post_hint==="string"?e.post_hint:"",url_overridden_by_dest:decodeRedditHtml(e?.url_overridden_by_dest||""),preview_image_url:decodeRedditHtml(e?.preview?.images?.[0]?.source?.url||""),gallery_urls:i}}p({site:"reddit",name:"home",access:"read",description:"Reddit personalized home feed (Best, requires login)",domain:"reddit.com",strategy:h.COOKIE,browser:!0,args:[{name:"limit",type:"int",default:25,help:`Number of posts (1–${u})`}],columns:["rank","title","subreddit","score","comments","postId","author","url","post_hint","url_overridden_by_dest","preview_image_url","gallery_urls"],func:async(e,i)=>{const s=parseRedditHomeLimit(i.limit);await e.goto("https://www.reddit.com");const r=await e.evaluate(`(async () => {
2
2
  try {
3
3
  const meRes = await fetch('/api/me.json', { credentials: 'include' });
4
4
  if (meRes.status === 401 || meRes.status === 403) {
@@ -12,7 +12,7 @@ import{ArgumentError as V,AuthRequiredError as W,CommandExecutionError as N,Empt
12
12
  return { kind: 'auth', detail: 'Not logged in to reddit.com (no identity in /api/me.json)' };
13
13
  }
14
14
 
15
- const limit = ${JSON.stringify(G)};
15
+ const limit = ${JSON.stringify(s)};
16
16
  const res = await fetch('/best.json?limit=' + limit + '&raw_json=1', { credentials: 'include' });
17
17
  if (res.status === 401 || res.status === 403) {
18
18
  return { kind: 'auth', detail: 'Reddit /best.json returned HTTP ' + res.status };
@@ -29,4 +29,4 @@ import{ArgumentError as V,AuthRequiredError as W,CommandExecutionError as N,Empt
29
29
  } catch (e) {
30
30
  return { kind: 'exception', detail: String(e && e.message || e) };
31
31
  }
32
- })()`);if(z?.kind==="auth")throw new W("reddit.com",z.detail);if(z?.kind==="http")throw new N(`HTTP ${z.httpStatus} from ${z.where}`);if(z?.kind==="exception")throw new N(`home failed: ${z.detail}`);if(z?.kind!=="ok")throw new N(`Unexpected result from reddit home: ${JSON.stringify(z)}`);const J=[],F=z.entries.slice(0,G);for(let K=0;K<F.length;K++){const f=F[K]?.data;if(!f||!f.id)continue;J.push({rank:K+1,title:typeof f.title==="string"?f.title:null,subreddit:typeof f.subreddit_name_prefixed==="string"?f.subreddit_name_prefixed:null,score:typeof f.score==="number"?f.score:null,comments:typeof f.num_comments==="number"?f.num_comments:null,postId:f.id,author:typeof f.author==="string"?f.author:null,url:f.permalink?"https://www.reddit.com"+f.permalink:null,...extractRedditMedia(f)})}if(J.length===0){if(F.length>0)throw new N("Reddit home feed entries were missing required post id anchors");throw new Y("Reddit returned no posts in the personalized home feed.")}return J}});
32
+ })()`);if(r?.kind==="auth")throw new m("reddit.com",r.detail);if(r?.kind==="http")throw new a(`HTTP ${r.httpStatus} from ${r.where}`);if(r?.kind==="exception")throw new a(`home failed: ${r.detail}`);if(r?.kind!=="ok")throw new a(`Unexpected result from reddit home: ${JSON.stringify(r)}`);const o=[],n=r.entries.slice(0,s);for(let d=0;d<n.length;d++){const t=n[d]?.data;if(!t||!t.id)continue;o.push({rank:d+1,title:typeof t.title==="string"?t.title:null,subreddit:typeof t.subreddit_name_prefixed==="string"?t.subreddit_name_prefixed:null,score:typeof t.score==="number"?t.score:null,comments:typeof t.num_comments==="number"?t.num_comments:null,postId:t.id,author:typeof t.author==="string"?t.author:null,url:t.permalink?"https://www.reddit.com"+t.permalink:null,...extractRedditMedia(t)})}if(o.length===0){if(n.length>0)throw new a("Reddit home feed entries were missing required post id anchors");throw new c("Reddit returned no posts in the personalized home feed.")}return o}});
@@ -1,4 +1,4 @@
1
- import{cli as v,Strategy as B}from"@jackwener/opencli/registry";import{ArgumentError as K,AuthRequiredError as z,CommandExecutionError as W,EmptyResultError as h}from"@jackwener/opencli/errors";const f=1,j=5,F=2,C=/^[a-z0-9]+$/i;function q(H){const b=String(H||"").trim();if(!C.test(b))throw new K("Post ID must be a Reddit post id, t3_ fullname, or reddit.com post URL.","Use a bare post id like 1abc123, a fullname like t3_1abc123, or a full Reddit post URL.");return b.toLowerCase()}export function normalizeRedditPostId(H){const b=String(H||"").trim();if(!b)throw new K("Post ID is required.","Use a bare post id like 1abc123, a fullname like t3_1abc123, or a full Reddit post URL.");const Y=b.match(/^t3_([a-z0-9]+)$/i);if(Y)return q(Y[1]);if(/^https?:\/\//i.test(b)){let V;try{V=new URL(b)}catch{throw new K(`Invalid Reddit post URL: ${b}`)}const Z=V.hostname.toLowerCase();if(V.protocol!=="https:"||Z!=="reddit.com"&&!Z.endsWith(".reddit.com"))throw new K("Post URL must be an https reddit.com URL.","Use a URL like https://www.reddit.com/r/sub/comments/1abc123/title_slug/");const J=V.pathname.split("/").filter(Boolean),$=J.indexOf("comments"),Q=$+1;if($<0||J.length<=Q)throw new K("Post URL must include the target post id.","Use a URL like https://www.reddit.com/r/sub/comments/1abc123/title_slug/");if(J.length>Q+3)throw new K("Post URL must end at the post slug or comment permalink id.","Remove extra path segments after the post slug or comment id.");if(J.length===Q+3)q(J[Q+2]);return q(J[Q])}if(b.includes("/")||b.startsWith("t1_"))throw new K("Post ID must be a Reddit post id, t3_ fullname, or reddit.com post URL.","Use a bare post id like 1abc123, a fullname like t3_1abc123, or a full Reddit post URL.");return q(b)}export function parseExpandRounds(H){if(H===void 0||H===null||H==="")return F;const b=Number(H);if(!Number.isFinite(b)||!Number.isInteger(b)||b<f||b>j)throw new K(`expand-rounds must be an integer in [${f}, ${j}].`,`Got: ${H}`);return b}v({site:"reddit",name:"read",access:"read",description:"Read a Reddit post and its comments",domain:"reddit.com",strategy:B.COOKIE,browser:!0,args:[{name:"post-id",required:!0,positional:!0,help:"Post ID (e.g. 1abc123) or full URL"},{name:"sort",default:"best",help:"Comment sort: best, top, new, controversial, old, qa"},{name:"limit",type:"int",default:25,help:"Number of top-level comments"},{name:"depth",type:"int",default:2,help:"Max reply depth (1=no replies, 2=one level of replies, etc.)"},{name:"replies",type:"int",default:5,help:"Max replies shown per comment at each level (sorted by score)"},{name:"max-length",type:"int",default:2000,help:"Max characters per comment body (min 100)"},{name:"expand-more",type:"bool",default:!1,help:'Follow Reddit "more comments" stubs by calling /api/morechildren.json'},{name:"expand-rounds",type:"int",default:F,help:`Max expansion passes when --expand-more is on (${f}–${j}; each round can fan out new "more" stubs)`}],columns:["type","author","score","text","post_hint","url_overridden_by_dest","preview_image_url","gallery_urls"],func:async(H,b)=>{const Y=b.sort??"best",V=Math.max(1,b.limit??25),Z=Math.max(1,b.depth??2),J=Math.max(1,b.replies??5),$=Math.max(100,b["max-length"]??2000),Q=Boolean(b["expand-more"]),y=parseExpandRounds(b["expand-rounds"]),L=normalizeRedditPostId(b["post-id"]),G=await H.evaluate(`
1
+ import{cli as v,Strategy as y}from"@jackwener/opencli/registry";import{ArgumentError as n,AuthRequiredError as _,CommandExecutionError as o,EmptyResultError as b}from"@jackwener/opencli/errors";const h=1,m=5,u=2,w=/^[a-z0-9]+$/i;function c(r){const e=String(r||"").trim();if(!w.test(e))throw new n("Post ID must be a Reddit post id, t3_ fullname, or reddit.com post URL.","Use a bare post id like 1abc123, a fullname like t3_1abc123, or a full Reddit post URL.");return e.toLowerCase()}export function normalizeRedditPostId(r){const e=String(r||"").trim();if(!e)throw new n("Post ID is required.","Use a bare post id like 1abc123, a fullname like t3_1abc123, or a full Reddit post URL.");const s=e.match(/^t3_([a-z0-9]+)$/i);if(s)return c(s[1]);if(/^https?:\/\//i.test(e)){let d;try{d=new URL(e)}catch{throw new n(`Invalid Reddit post URL: ${e}`)}const l=d.hostname.toLowerCase();if(d.protocol!=="https:"||l!=="reddit.com"&&!l.endsWith(".reddit.com"))throw new n("Post URL must be an https reddit.com URL.","Use a URL like https://www.reddit.com/r/sub/comments/1abc123/title_slug/");const a=d.pathname.split("/").filter(Boolean),p=a.indexOf("comments"),i=p+1;if(p<0||a.length<=i)throw new n("Post URL must include the target post id.","Use a URL like https://www.reddit.com/r/sub/comments/1abc123/title_slug/");if(a.length>i+3)throw new n("Post URL must end at the post slug or comment permalink id.","Remove extra path segments after the post slug or comment id.");if(a.length===i+3)c(a[i+2]);return c(a[i])}if(e.includes("/")||e.startsWith("t1_"))throw new n("Post ID must be a Reddit post id, t3_ fullname, or reddit.com post URL.","Use a bare post id like 1abc123, a fullname like t3_1abc123, or a full Reddit post URL.");return c(e)}export function parseExpandRounds(r){if(r===void 0||r===null||r==="")return u;const e=Number(r);if(!Number.isFinite(e)||!Number.isInteger(e)||e<h||e>m)throw new n(`expand-rounds must be an integer in [${h}, ${m}].`,`Got: ${r}`);return e}v({site:"reddit",name:"read",access:"read",description:"Read a Reddit post and its comments",domain:"reddit.com",strategy:y.COOKIE,browser:!0,args:[{name:"post-id",required:!0,positional:!0,help:"Post ID (e.g. 1abc123) or full URL"},{name:"sort",default:"best",help:"Comment sort: best, top, new, controversial, old, qa"},{name:"limit",type:"int",default:25,help:"Number of top-level comments"},{name:"depth",type:"int",default:2,help:"Max reply depth (1=no replies, 2=one level of replies, etc.)"},{name:"replies",type:"int",default:5,help:"Max replies shown per comment at each level (sorted by score)"},{name:"max-length",type:"int",default:2000,help:"Max characters per comment body (min 100)"},{name:"expand-more",type:"bool",default:!1,help:'Follow Reddit "more comments" stubs by calling /api/morechildren.json'},{name:"expand-rounds",type:"int",default:u,help:`Max expansion passes when --expand-more is on (${h}–${m}; each round can fan out new "more" stubs)`}],columns:["type","author","score","text","post_hint","url_overridden_by_dest","preview_image_url","gallery_urls"],func:async(r,e)=>{const s=e.sort??"best",d=Math.max(1,e.limit??25),l=Math.max(1,e.depth??2),a=Math.max(1,e.replies??5),p=Math.max(100,e["max-length"]??2000),i=Boolean(e["expand-more"]),f=parseExpandRounds(e["expand-rounds"]),g=normalizeRedditPostId(e["post-id"]),t=await r.evaluate(`
2
2
  (async function() {
3
3
  function decodeHtml(s) {
4
4
  if (typeof s !== 'string' || !s) return '';
@@ -34,16 +34,16 @@ import{cli as v,Strategy as B}from"@jackwener/opencli/registry";import{ArgumentE
34
34
  gallery_urls: gallery_urls,
35
35
  };
36
36
  }
37
- var postId = ${JSON.stringify(L)};
37
+ var postId = ${JSON.stringify(g)};
38
38
  var linkFullname = 't3_' + postId;
39
39
 
40
- var sort = ${JSON.stringify(Y)};
41
- var limit = ${V};
42
- var maxDepth = ${Z};
43
- var maxReplies = ${J};
44
- var maxLength = ${$};
45
- var expandMore = ${JSON.stringify(Q)};
46
- var expandRounds = ${y};
40
+ var sort = ${JSON.stringify(s)};
41
+ var limit = ${d};
42
+ var maxDepth = ${l};
43
+ var maxReplies = ${a};
44
+ var maxLength = ${p};
45
+ var expandMore = ${JSON.stringify(i)};
46
+ var expandRounds = ${f};
47
47
 
48
48
  // ---------------------------------------------------------------
49
49
  // Step 1: fetch the post + initial comment tree
@@ -395,4 +395,4 @@ import{cli as v,Strategy as B}from"@jackwener/opencli/registry";import{ArgumentE
395
395
 
396
396
  return { kind: 'ok', rows: rows, expandMeta: expandMeta };
397
397
  })()
398
- `);if(!G||typeof G!=="object")throw new W("Reddit /comments fetch returned no result envelope.");if(G.kind==="inaccessible")throw new h(G.detail);if(G.kind==="auth")throw new z("reddit.com",G.detail);if(G.kind==="http")throw new W(`HTTP ${G.httpStatus} from ${G.where}`);if(G.kind==="malformed")throw new W(G.detail);if(G.kind==="parser-drift")throw new W(G.detail);if(G.kind==="expand-failed")throw new W(G.detail);if(G.kind!=="ok"||!Array.isArray(G.rows))throw new W(`Unexpected result from reddit read: ${JSON.stringify(G)}`);return G.rows}});
398
+ `);if(!t||typeof t!=="object")throw new o("Reddit /comments fetch returned no result envelope.");if(t.kind==="inaccessible")throw new b(t.detail);if(t.kind==="auth")throw new _("reddit.com",t.detail);if(t.kind==="http")throw new o(`HTTP ${t.httpStatus} from ${t.where}`);if(t.kind==="malformed")throw new o(t.detail);if(t.kind==="parser-drift")throw new o(t.detail);if(t.kind==="expand-failed")throw new o(t.detail);if(t.kind!=="ok"||!Array.isArray(t.rows))throw new o(`Unexpected result from reddit read: ${JSON.stringify(t)}`);return t.rows}});
@@ -1,7 +1,7 @@
1
- import{ArgumentError as J,AuthRequiredError as Y,CommandExecutionError as L}from"@jackwener/opencli/errors";import{cli as Z,Strategy as $}from"@jackwener/opencli/registry";const F=/^[a-z0-9]+$/i;function W(H){const b=String(H||"").trim();if(!F.test(b))throw new J("Comment ID must be a Reddit comment id, t1_ fullname, or reddit.com comment URL.","Use a bare comment id like okf3s7u, a fullname like t1_okf3s7u, or a full Reddit comment URL.");return b.toLowerCase()}export function normalizeRedditCommentFullname(H){const b=String(H||"").trim();if(!b)throw new J("Comment ID is required.","Use a bare comment id like okf3s7u, a fullname like t1_okf3s7u, or a full Reddit comment URL.");const Q=b.match(/^t1_([a-z0-9]+)$/i);if(Q)return`t1_${W(Q[1])}`;if(/^https?:\/\//i.test(b)){let K;try{K=new URL(b)}catch{throw new J(`Invalid Reddit comment URL: ${b}`)}const G=K.hostname.toLowerCase();if(K.protocol!=="https:"||G!=="reddit.com"&&!G.endsWith(".reddit.com"))throw new J("Comment URL must be an https reddit.com URL.","Use a URL like https://www.reddit.com/r/sub/comments/post/title/okf3s7u/");const U=K.pathname.split("/").filter(Boolean),X=U.indexOf("comments"),V=X+3;if(X<0||U.length<=V)throw new J("Comment URL must include the target comment id.","Use a URL like https://www.reddit.com/r/sub/comments/post/title/okf3s7u/");if(U.length!==V+1)throw new J("Comment URL must end at the target comment id.","Remove extra path segments after the comment id.");return`t1_${W(U[V])}`}if(b.includes("/")||b.startsWith("t3_"))throw new J("Comment ID must be a Reddit comment id, t1_ fullname, or reddit.com comment URL.","Use a bare comment id like okf3s7u, a fullname like t1_okf3s7u, or a full Reddit comment URL.");return`t1_${W(b)}`}export function requireReplyText(H){const b=String(H||"");if(!b.trim())throw new J("Reply text is required.","Pass non-empty text to post as the Reddit reply.");return b}Z({site:"reddit",name:"reply",access:"write",description:"Reply to a Reddit comment",domain:"reddit.com",strategy:$.COOKIE,browser:!0,args:[{name:"comment-id",type:"string",required:!0,positional:!0,help:"Comment ID (e.g. okf3s7u) or fullname (t1_xxx)"},{name:"text",fromFile:!0,type:"string",required:!0,positional:!0,help:"Reply text"}],columns:["status","message"],func:async(H,b)=>{const Q=normalizeRedditCommentFullname(b["comment-id"]),K=requireReplyText(b.text);await H.goto("https://www.reddit.com");const G=await H.evaluate(`(async () => {
1
+ import{ArgumentError as o,AuthRequiredError as u,CommandExecutionError as i}from"@jackwener/opencli/errors";import{cli as l,Strategy as h}from"@jackwener/opencli/registry";const p=/^[a-z0-9]+$/i;function m(n){const t=String(n||"").trim();if(!p.test(t))throw new o("Comment ID must be a Reddit comment id, t1_ fullname, or reddit.com comment URL.","Use a bare comment id like okf3s7u, a fullname like t1_okf3s7u, or a full Reddit comment URL.");return t.toLowerCase()}export function normalizeRedditCommentFullname(n){const t=String(n||"").trim();if(!t)throw new o("Comment ID is required.","Use a bare comment id like okf3s7u, a fullname like t1_okf3s7u, or a full Reddit comment URL.");const s=t.match(/^t1_([a-z0-9]+)$/i);if(s)return`t1_${m(s[1])}`;if(/^https?:\/\//i.test(t)){let r;try{r=new URL(t)}catch{throw new o(`Invalid Reddit comment URL: ${t}`)}const e=r.hostname.toLowerCase();if(r.protocol!=="https:"||e!=="reddit.com"&&!e.endsWith(".reddit.com"))throw new o("Comment URL must be an https reddit.com URL.","Use a URL like https://www.reddit.com/r/sub/comments/post/title/okf3s7u/");const a=r.pathname.split("/").filter(Boolean),c=a.indexOf("comments"),d=c+3;if(c<0||a.length<=d)throw new o("Comment URL must include the target comment id.","Use a URL like https://www.reddit.com/r/sub/comments/post/title/okf3s7u/");if(a.length!==d+1)throw new o("Comment URL must end at the target comment id.","Remove extra path segments after the comment id.");return`t1_${m(a[d])}`}if(t.includes("/")||t.startsWith("t3_"))throw new o("Comment ID must be a Reddit comment id, t1_ fullname, or reddit.com comment URL.","Use a bare comment id like okf3s7u, a fullname like t1_okf3s7u, or a full Reddit comment URL.");return`t1_${m(t)}`}export function requireReplyText(n){const t=String(n||"");if(!t.trim())throw new o("Reply text is required.","Pass non-empty text to post as the Reddit reply.");return t}l({site:"reddit",name:"reply",access:"write",description:"Reply to a Reddit comment",domain:"reddit.com",strategy:h.COOKIE,browser:!0,args:[{name:"comment-id",type:"string",required:!0,positional:!0,help:"Comment ID (e.g. okf3s7u) or fullname (t1_xxx)"},{name:"text",fromFile:!0,type:"string",required:!0,positional:!0,help:"Reply text"}],columns:["status","message"],func:async(n,t)=>{const s=normalizeRedditCommentFullname(t["comment-id"]),r=requireReplyText(t.text);await n.goto("https://www.reddit.com");const e=await n.evaluate(`(async () => {
2
2
  try {
3
- const fullname = ${JSON.stringify(Q)};
4
- const text = ${JSON.stringify(K)};
3
+ const fullname = ${JSON.stringify(s)};
4
+ const text = ${JSON.stringify(r)};
5
5
 
6
6
  // Probe identity + modhash. /api/me.json returns data.name only when
7
7
  // logged in — empty modhash alone is not a strong enough auth signal
@@ -53,4 +53,4 @@ import{ArgumentError as J,AuthRequiredError as Y,CommandExecutionError as L}from
53
53
  } catch (e) {
54
54
  return { kind: 'exception', detail: String(e && e.message || e) };
55
55
  }
56
- })()`);if(G?.kind==="auth")throw new Y("reddit.com",G.detail);if(G?.kind==="http")throw new L(`HTTP ${G.httpStatus} from ${G.where}`);if(G?.kind==="reddit-error")throw new L(`Reddit rejected reply: ${G.detail}`);if(G?.kind==="postcondition")throw new L(G.detail);if(G?.kind==="exception")throw new L(`Reply failed: ${G.detail}`);if(G?.kind!=="ok")throw new L(`Unexpected result from reddit reply: ${JSON.stringify(G)}`);return[{status:"success",message:G.detail}]}});
56
+ })()`);if(e?.kind==="auth")throw new u("reddit.com",e.detail);if(e?.kind==="http")throw new i(`HTTP ${e.httpStatus} from ${e.where}`);if(e?.kind==="reddit-error")throw new i(`Reddit rejected reply: ${e.detail}`);if(e?.kind==="postcondition")throw new i(e.detail);if(e?.kind==="exception")throw new i(`Reply failed: ${e.detail}`);if(e?.kind!=="ok")throw new i(`Unexpected result from reddit reply: ${JSON.stringify(e)}`);return[{status:"success",message:e.detail}]}});
@@ -1,4 +1,4 @@
1
- import{ArgumentError as H,AuthRequiredError as V,CommandExecutionError as P}from"@jackwener/opencli/errors";import{cli as W,Strategy as X}from"@jackwener/opencli/registry";const Y=/^[A-Za-z0-9][A-Za-z0-9_]{1,20}$/;export function normalizeSubreddit(M){let F=String(M||"").trim();if(!F)throw new H("Subreddit is required.",'Pass a subreddit like "test" or "r/test".');if(/^https?:\/\//i.test(F)){let N;try{N=new URL(F)}catch{throw new H(`Invalid subreddit URL: ${F}`)}const J=N.pathname.split("/").filter(Boolean),K=J.indexOf("r");if(K<0||J.length<=K+1)throw new H("Subreddit URL must contain /r/<name>.");F=J[K+1]}F=F.replace(/^\/?r\//i,"").replace(/^\/+/,"");if(!Y.test(F))throw new H(`Invalid subreddit name: ${JSON.stringify(F)}`,'Use the bare name, e.g. "test" (2–21 chars, letters/digits/underscore).');return F}W({site:"reddit",name:"submit",access:"write",description:"Submit a new post to a subreddit. Text post by default (--text); pass --url for a link post. Note: many subreddits gate submissions behind karma/age requirements or flair — a rejection is surfaced verbatim.",domain:"reddit.com",strategy:X.COOKIE,browser:!0,args:[{name:"subreddit",type:"string",required:!0,positional:!0,help:'Target subreddit, e.g. "test" or "r/test"'},{name:"title",type:"string",required:!0,positional:!0,help:"Post title (max 300 chars)"},{name:"text",fromFile:!0,type:"string",help:"Body text (markdown) for a self/text post"},{name:"url",type:"string",help:"External URL for a link post (mutually exclusive with --text)"},{name:"flair-id",type:"string",help:"Flair template id, if the subreddit requires one"},{name:"flair-text",type:"string",help:"Flair text to accompany --flair-id"},{name:"nsfw",type:"bool",default:!1,help:"Mark the post as NSFW"},{name:"spoiler",type:"bool",default:!1,help:"Mark the post as a spoiler"},{name:"sendreplies",type:"bool",default:!0,help:"Receive inbox replies for this post (default: true)"}],columns:["status","url","id","message"],func:async(M,F)=>{if(!M)throw new P("Browser session required");const N=normalizeSubreddit(F.subreddit),J=String(F.title??"").trim();if(!J)throw new H("Title is required.");if(J.length>300)throw new H("Title must be at most 300 characters.");const K=typeof F.text==="string"?F.text:"",O=typeof F.url==="string"?F.url.trim():"";if(O&&K)throw new H("Pass either --text (self post) or --url (link post), not both.");const Q=O?"link":"self";if(Q==="link")try{new URL(O)}catch{throw new H(`Invalid --url: ${O}`)}await M.goto("https://www.reddit.com");const G=await M.evaluate(`(async () => {
1
+ import{ArgumentError as r,AuthRequiredError as u,CommandExecutionError as d}from"@jackwener/opencli/errors";import{cli as p,Strategy as m}from"@jackwener/opencli/registry";const f=/^[A-Za-z0-9][A-Za-z0-9_]{1,20}$/;export function normalizeSubreddit(n){let t=String(n||"").trim();if(!t)throw new r("Subreddit is required.",'Pass a subreddit like "test" or "r/test".');if(/^https?:\/\//i.test(t)){let a;try{a=new URL(t)}catch{throw new r(`Invalid subreddit URL: ${t}`)}const i=a.pathname.split("/").filter(Boolean),s=i.indexOf("r");if(s<0||i.length<=s+1)throw new r("Subreddit URL must contain /r/<name>.");t=i[s+1]}t=t.replace(/^\/?r\//i,"").replace(/^\/+/,"");if(!f.test(t))throw new r(`Invalid subreddit name: ${JSON.stringify(t)}`,'Use the bare name, e.g. "test" (2–21 chars, letters/digits/underscore).');return t}p({site:"reddit",name:"submit",access:"write",description:"Submit a new post to a subreddit. Text post by default (--text); pass --url for a link post. Note: many subreddits gate submissions behind karma/age requirements or flair — a rejection is surfaced verbatim.",domain:"reddit.com",strategy:m.COOKIE,browser:!0,args:[{name:"subreddit",type:"string",required:!0,positional:!0,help:'Target subreddit, e.g. "test" or "r/test"'},{name:"title",type:"string",required:!0,positional:!0,help:"Post title (max 300 chars)"},{name:"text",fromFile:!0,type:"string",help:"Body text (markdown) for a self/text post"},{name:"url",type:"string",help:"External URL for a link post (mutually exclusive with --text)"},{name:"flair-id",type:"string",help:"Flair template id, if the subreddit requires one"},{name:"flair-text",type:"string",help:"Flair text to accompany --flair-id"},{name:"nsfw",type:"bool",default:!1,help:"Mark the post as NSFW"},{name:"spoiler",type:"bool",default:!1,help:"Mark the post as a spoiler"},{name:"sendreplies",type:"bool",default:!0,help:"Receive inbox replies for this post (default: true)"}],columns:["status","url","id","message"],func:async(n,t)=>{if(!n)throw new d("Browser session required");const a=normalizeSubreddit(t.subreddit),i=String(t.title??"").trim();if(!i)throw new r("Title is required.");if(i.length>300)throw new r("Title must be at most 300 characters.");const s=typeof t.text==="string"?t.text:"",o=typeof t.url==="string"?t.url.trim():"";if(o&&s)throw new r("Pass either --text (self post) or --url (link post), not both.");const l=o?"link":"self";if(l==="link")try{new URL(o)}catch{throw new r(`Invalid --url: ${o}`)}await n.goto("https://www.reddit.com");const e=await n.evaluate(`(async () => {
2
2
  try {
3
3
  const meRes = await fetch('/api/me.json', { credentials: 'include' });
4
4
  if (meRes.status === 401 || meRes.status === 403) {
@@ -9,17 +9,17 @@ import{ArgumentError as H,AuthRequiredError as V,CommandExecutionError as P}from
9
9
  if (!modhash) return { kind: 'auth', detail: 'No modhash — anonymous or expired session' };
10
10
 
11
11
  const p = new URLSearchParams();
12
- p.set('sr', ${JSON.stringify(N)});
13
- p.set('title', ${JSON.stringify(J)});
14
- p.set('kind', ${JSON.stringify(Q)});
15
- ${Q==="link"?`p.set('url', ${JSON.stringify(O)}); p.set('resubmit', 'true');`:`p.set('text', ${JSON.stringify(K)});`}
12
+ p.set('sr', ${JSON.stringify(a)});
13
+ p.set('title', ${JSON.stringify(i)});
14
+ p.set('kind', ${JSON.stringify(l)});
15
+ ${l==="link"?`p.set('url', ${JSON.stringify(o)}); p.set('resubmit', 'true');`:`p.set('text', ${JSON.stringify(s)});`}
16
16
  p.set('api_type', 'json');
17
17
  p.set('validate_on_submit', 'true');
18
- p.set('sendreplies', ${F.sendreplies===!1?"'false'":"'true'"});
19
- ${F.nsfw?"p.set('nsfw', 'true');":""}
20
- ${F.spoiler?"p.set('spoiler', 'true');":""}
21
- ${F["flair-id"]?`p.set('flair_id', ${JSON.stringify(String(F["flair-id"]))});`:""}
22
- ${F["flair-text"]?`p.set('flair_text', ${JSON.stringify(String(F["flair-text"]))});`:""}
18
+ p.set('sendreplies', ${t.sendreplies===!1?"'false'":"'true'"});
19
+ ${t.nsfw?"p.set('nsfw', 'true');":""}
20
+ ${t.spoiler?"p.set('spoiler', 'true');":""}
21
+ ${t["flair-id"]?`p.set('flair_id', ${JSON.stringify(String(t["flair-id"]))});`:""}
22
+ ${t["flair-text"]?`p.set('flair_text', ${JSON.stringify(String(t["flair-text"]))});`:""}
23
23
  p.set('uh', modhash);
24
24
 
25
25
  const res = await fetch('/api/submit', {
@@ -39,4 +39,4 @@ import{ArgumentError as H,AuthRequiredError as V,CommandExecutionError as P}from
39
39
  } catch (e) {
40
40
  return { kind: 'exception', detail: String((e && e.message) || e) };
41
41
  }
42
- })()`);if(G?.kind==="auth")throw new V("reddit.com",G.detail);if(G?.kind==="http")throw new P(`HTTP ${G.httpStatus} from /api/submit`);if(G?.kind==="exception")throw new P(`Reddit submit failed: ${G.detail}`);if(G?.kind==="reject")return[{status:"failed",url:"",id:"",message:G.detail}];if(!G?.ok)throw new P(`Unexpected Reddit submit result: ${JSON.stringify(G)}`);return[{status:"success",url:G.url,id:G.id,message:"Post submitted to r/"+N}]}});
42
+ })()`);if(e?.kind==="auth")throw new u("reddit.com",e.detail);if(e?.kind==="http")throw new d(`HTTP ${e.httpStatus} from /api/submit`);if(e?.kind==="exception")throw new d(`Reddit submit failed: ${e.detail}`);if(e?.kind==="reject")return[{status:"failed",url:"",id:"",message:e.detail}];if(!e?.ok)throw new d(`Unexpected Reddit submit result: ${JSON.stringify(e)}`);return[{status:"success",url:e.url,id:e.id,message:"Post submitted to r/"+a}]}});
@@ -1,6 +1,6 @@
1
- import{ArgumentError as K,CommandExecutionError as G,EmptyResultError as Q}from"@jackwener/opencli/errors";import{cli as V,Strategy as W}from"@jackwener/opencli/registry";const X=/^[A-Za-z][A-Za-z0-9_]{2,20}$/;export function parseSubredditName(F){let z=String(F||"").trim();if(!z)throw new K("Subreddit name is required.","Pass a subreddit name like `python` (or `r/python`).");if(z.startsWith("/r/"))z=z.slice(3);else if(z.startsWith("r/"))z=z.slice(2);if(!X.test(z))throw new K("Invalid subreddit name.","Subreddit names are 3–21 characters, start with a letter, and contain only letters, digits, and underscores.");return z}V({site:"reddit",name:"subreddit-info",access:"read",description:"Show metadata for a Reddit subreddit (subscribers, description, created date, NSFW)",domain:"reddit.com",strategy:W.COOKIE,browser:!0,args:[{name:"name",type:"string",required:!0,positional:!0,help:"Subreddit name (no `r/` prefix needed)"}],columns:["field","value"],func:async(F,z)=>{const L=parseSubredditName(z.name);await F.goto("https://www.reddit.com");const q=await F.evaluate(`(async () => {
1
+ import{ArgumentError as d,CommandExecutionError as n,EmptyResultError as c}from"@jackwener/opencli/errors";import{cli as f,Strategy as b}from"@jackwener/opencli/registry";const m=/^[A-Za-z][A-Za-z0-9_]{2,20}$/;export function parseSubredditName(i){let r=String(i||"").trim();if(!r)throw new d("Subreddit name is required.","Pass a subreddit name like `python` (or `r/python`).");if(r.startsWith("/r/"))r=r.slice(3);else if(r.startsWith("r/"))r=r.slice(2);if(!m.test(r))throw new d("Invalid subreddit name.","Subreddit names are 3–21 characters, start with a letter, and contain only letters, digits, and underscores.");return r}f({site:"reddit",name:"subreddit-info",access:"read",description:"Show metadata for a Reddit subreddit (subscribers, description, created date, NSFW)",domain:"reddit.com",strategy:b.COOKIE,browser:!0,args:[{name:"name",type:"string",required:!0,positional:!0,help:"Subreddit name (no `r/` prefix needed)"}],columns:["field","value"],func:async(i,r)=>{const o=parseSubredditName(r.name);await i.goto("https://www.reddit.com");const t=await i.evaluate(`(async () => {
2
2
  try {
3
- const sub = ${JSON.stringify(L)};
3
+ const sub = ${JSON.stringify(o)};
4
4
  const res = await fetch('/r/' + encodeURIComponent(sub) + '/about.json?raw_json=1', { credentials: 'include' });
5
5
  if (res.status === 401 || res.status === 403 || res.status === 404) {
6
6
  return { kind: 'missing', detail: 'Subreddit r/' + sub + ' was not found or is not accessible (HTTP ' + res.status + ').' };
@@ -26,4 +26,4 @@ import{ArgumentError as K,CommandExecutionError as G,EmptyResultError as Q}from"
26
26
  } catch (e) {
27
27
  return { kind: 'exception', detail: String(e && e.message || e) };
28
28
  }
29
- })()`);if(q?.kind==="missing")throw new Q(q.detail);if(q?.kind==="http")throw new G(`HTTP ${q.httpStatus} from ${q.where}`);if(q?.kind==="malformed")throw new G(q.detail);if(q?.kind==="exception")throw new G(`subreddit-info failed: ${q.detail}`);if(q?.kind!=="ok")throw new G(`Unexpected result from reddit subreddit-info: ${JSON.stringify(q)}`);const h=q.info,O=h.created_utc?new Date(h.created_utc*1000).toISOString().split("T")[0]:null,H=typeof h.subscribers==="number"?h.subscribers:null,J=typeof h.active_user_count==="number"?h.active_user_count:typeof h.accounts_active==="number"?h.accounts_active:null,P=typeof h.public_description==="string"?h.public_description.trim():"";return[{field:"Name",value:h.display_name_prefixed||"r/"+h.display_name},{field:"Title",value:typeof h.title==="string"?h.title:null},{field:"Subscribers",value:H!=null?String(H):null},{field:"Active Now",value:J!=null?String(J):null},{field:"NSFW",value:h.over18?"Yes":"No"},{field:"Type",value:typeof h.subreddit_type==="string"?h.subreddit_type:null},{field:"Description",value:P||null},{field:"Created",value:O},{field:"URL",value:h.url?"https://www.reddit.com"+h.url:null}]}});
29
+ })()`);if(t?.kind==="missing")throw new c(t.detail);if(t?.kind==="http")throw new n(`HTTP ${t.httpStatus} from ${t.where}`);if(t?.kind==="malformed")throw new n(t.detail);if(t?.kind==="exception")throw new n(`subreddit-info failed: ${t.detail}`);if(t?.kind!=="ok")throw new n(`Unexpected result from reddit subreddit-info: ${JSON.stringify(t)}`);const e=t.info,u=e.created_utc?new Date(e.created_utc*1000).toISOString().split("T")[0]:null,s=typeof e.subscribers==="number"?e.subscribers:null,a=typeof e.active_user_count==="number"?e.active_user_count:typeof e.accounts_active==="number"?e.accounts_active:null,l=typeof e.public_description==="string"?e.public_description.trim():"";return[{field:"Name",value:e.display_name_prefixed||"r/"+e.display_name},{field:"Title",value:typeof e.title==="string"?e.title:null},{field:"Subscribers",value:s!=null?String(s):null},{field:"Active Now",value:a!=null?String(a):null},{field:"NSFW",value:e.over18?"Yes":"No"},{field:"Type",value:typeof e.subreddit_type==="string"?e.subreddit_type:null},{field:"Description",value:l||null},{field:"Created",value:u},{field:"URL",value:e.url?"https://www.reddit.com"+e.url:null}]}});
@@ -1,5 +1,5 @@
1
- import{ArgumentError as $,AuthRequiredError as q,CommandExecutionError as P,EmptyResultError as J}from"@jackwener/opencli/errors";import{cli as v,Strategy as O}from"@jackwener/opencli/registry";import{BROWSER_JSON_SNIFF_FN as f,throwIfLoginWall as j}from"@jackwener/opencli/utils";export const REDDIT_SUBSCRIBED_MAX_LIMIT=1000;export function parseRedditSubscribedLimit(G){if(G===void 0||G===null||G==="")return 100;const K=Number(G);if(!Number.isFinite(K)||!Number.isInteger(K)||K<1||K>REDDIT_SUBSCRIBED_MAX_LIMIT)throw new $(`limit must be an integer in [1, ${REDDIT_SUBSCRIBED_MAX_LIMIT}].`,`Got: ${G}`);return K}export function unwrapEvaluateResult(G){if(G&&typeof G==="object"&&!Array.isArray(G)&&"session"in G&&"data"in G)return G.data;return G}function F(G,K){const z=G?.data;if(!z||typeof z!=="object")throw new P(`Reddit subscriptions row ${K+1} was missing data.`);const H=typeof z.name==="string"?z.name:"",Q=H.startsWith("t5_")?H:G?.kind==="t5"&&typeof z.id==="string"&&z.id?`t5_${z.id}`:"",V=typeof z.display_name==="string"&&z.display_name?z.display_name:"",Y=typeof z.display_name_prefixed==="string"&&z.display_name_prefixed?z.display_name_prefixed:V?`r/${V}`:"",Z=typeof z.url==="string"&&z.url.startsWith("/r/")?z.url:"";if(!Q||!V||!Y||!Z)throw new P(`Reddit subscriptions row ${K+1} was missing subreddit identity.`);return{id:Q,subreddit:Y,title:typeof z.title==="string"?z.title:"",subscribers:typeof z.subscribers==="number"?z.subscribers:null,description:typeof z.public_description==="string"?z.public_description.slice(0,200):"",url:"https://www.reddit.com"+Z}}v({site:"reddit",name:"subscribed",description:"List subreddits you are subscribed to",access:"read",domain:"reddit.com",strategy:O.COOKIE,browser:!0,args:[{name:"limit",type:"int",default:100,help:`Max subreddits to return (1-${REDDIT_SUBSCRIBED_MAX_LIMIT}, auto-paginates)`}],columns:["id","subreddit","title","subscribers","description","url"],func:async(G,K)=>{const z=parseRedditSubscribedLimit(K.limit);if(!G)throw new P("Browser session required");await G.goto("https://www.reddit.com");const H=unwrapEvaluateResult(await G.evaluate(`(async () => {
2
- ${f}
1
+ import{ArgumentError as u,AuthRequiredError as l,CommandExecutionError as n,EmptyResultError as c}from"@jackwener/opencli/errors";import{cli as m,Strategy as f}from"@jackwener/opencli/registry";import{BROWSER_JSON_SNIFF_FN as p,throwIfLoginWall as g}from"@jackwener/opencli/utils";export const REDDIT_SUBSCRIBED_MAX_LIMIT=1000;export function parseRedditSubscribedLimit(t){if(t===void 0||t===null||t==="")return 100;const i=Number(t);if(!Number.isFinite(i)||!Number.isInteger(i)||i<1||i>REDDIT_SUBSCRIBED_MAX_LIMIT)throw new u(`limit must be an integer in [1, ${REDDIT_SUBSCRIBED_MAX_LIMIT}].`,`Got: ${t}`);return i}export function unwrapEvaluateResult(t){if(t&&typeof t==="object"&&!Array.isArray(t)&&"session"in t&&"data"in t)return t.data;return t}function h(t,i){const e=t?.data;if(!e||typeof e!=="object")throw new n(`Reddit subscriptions row ${i+1} was missing data.`);const r=typeof e.name==="string"?e.name:"",s=r.startsWith("t5_")?r:t?.kind==="t5"&&typeof e.id==="string"&&e.id?`t5_${e.id}`:"",d=typeof e.display_name==="string"&&e.display_name?e.display_name:"",o=typeof e.display_name_prefixed==="string"&&e.display_name_prefixed?e.display_name_prefixed:d?`r/${d}`:"",a=typeof e.url==="string"&&e.url.startsWith("/r/")?e.url:"";if(!s||!d||!o||!a)throw new n(`Reddit subscriptions row ${i+1} was missing subreddit identity.`);return{id:s,subreddit:o,title:typeof e.title==="string"?e.title:"",subscribers:typeof e.subscribers==="number"?e.subscribers:null,description:typeof e.public_description==="string"?e.public_description.slice(0,200):"",url:"https://www.reddit.com"+a}}m({site:"reddit",name:"subscribed",description:"List subreddits you are subscribed to",access:"read",domain:"reddit.com",strategy:f.COOKIE,browser:!0,args:[{name:"limit",type:"int",default:100,help:`Max subreddits to return (1-${REDDIT_SUBSCRIBED_MAX_LIMIT}, auto-paginates)`}],columns:["id","subreddit","title","subscribers","description","url"],func:async(t,i)=>{const e=parseRedditSubscribedLimit(i.limit);if(!t)throw new n("Browser session required");await t.goto("https://www.reddit.com");const r=unwrapEvaluateResult(await t.evaluate(`(async () => {
2
+ ${p}
3
3
  try {
4
4
  // fetchJsonOrLoginWall sniffs HTML responses (login wall / WAF / rate-limit
5
5
  // page) and returns a structured { __loginWall, status, url, ... } sentinel
@@ -17,7 +17,7 @@ import{ArgumentError as $,AuthRequiredError as q,CommandExecutionError as P,Empt
17
17
  const username = me?.data?.name || me?.name;
18
18
  if (!username) return { kind: 'auth', detail: 'Not logged in to reddit.com (no identity in /api/me.json)' };
19
19
 
20
- const target = ${JSON.stringify(z)};
20
+ const target = ${JSON.stringify(e)};
21
21
  const PAGE_SIZE = 100;
22
22
  const out = [];
23
23
  let after = null;
@@ -65,4 +65,4 @@ import{ArgumentError as $,AuthRequiredError as q,CommandExecutionError as P,Empt
65
65
  } catch (e) {
66
66
  return { kind: 'exception', detail: String(e && e.message || e) };
67
67
  }
68
- })()`));if(H?.kind==="login-wall")j(H.sentinel,{url:H.where});if(H?.kind==="auth")throw new q("reddit.com",H.detail);if(H?.kind==="http")throw new P(`HTTP ${H.httpStatus} from ${H.where}`);if(H?.kind==="malformed")throw new P(H.detail);if(H?.kind==="exception")throw new P(`subscribed failed: ${H.detail}`);if(H?.kind!=="ok"||!Array.isArray(H.entries))throw new P(`Unexpected result from reddit subscribed: ${JSON.stringify(H)}`);const Q=H.entries.slice(0,z).map((V,Y)=>F(V,Y));if(Q.length===0)throw new J("Reddit returned no subscribed subreddits for the logged-in account.");return Q}});
68
+ })()`));if(r?.kind==="login-wall")g(r.sentinel,{url:r.where});if(r?.kind==="auth")throw new l("reddit.com",r.detail);if(r?.kind==="http")throw new n(`HTTP ${r.httpStatus} from ${r.where}`);if(r?.kind==="malformed")throw new n(r.detail);if(r?.kind==="exception")throw new n(`subscribed failed: ${r.detail}`);if(r?.kind!=="ok"||!Array.isArray(r.entries))throw new n(`Unexpected result from reddit subscribed: ${JSON.stringify(r)}`);const s=r.entries.slice(0,e).map((d,o)=>h(d,o));if(s.length===0)throw new c("Reddit returned no subscribed subreddits for the logged-in account.");return s}});
@@ -1,4 +1,4 @@
1
- import{AuthRequiredError as L,CommandExecutionError as F}from"@jackwener/opencli/errors";import{cli as M,Strategy as N}from"@jackwener/opencli/registry";import{cookieQuickCheck as O}from"../_shared/article/auth.js";M({site:"reddit",name:"whoami",access:"read",description:"Show the currently logged-in Reddit user",domain:"reddit.com",strategy:N.COOKIE,browser:!0,args:[],columns:["field","value"],authStatus:{quickCheck:O("https://www.reddit.com",["reddit_session"])},func:async(G)=>{await G.goto("https://www.reddit.com");const z=await G.evaluate(`(async () => {
1
+ import{AuthRequiredError as u,CommandExecutionError as a}from"@jackwener/opencli/errors";import{cli as s,Strategy as m}from"@jackwener/opencli/registry";import{cookieQuickCheck as c}from"../_shared/article/auth.js";s({site:"reddit",name:"whoami",access:"read",description:"Show the currently logged-in Reddit user",domain:"reddit.com",strategy:m.COOKIE,browser:!0,args:[],columns:["field","value"],authStatus:{quickCheck:c("https://www.reddit.com",["reddit_session"])},func:async(r)=>{await r.goto("https://www.reddit.com");const t=await r.evaluate(`(async () => {
2
2
  try {
3
3
  const res = await fetch('/api/me.json?raw_json=1', { credentials: 'include' });
4
4
  if (res.status === 401 || res.status === 403) {
@@ -16,4 +16,4 @@ import{AuthRequiredError as L,CommandExecutionError as F}from"@jackwener/opencli
16
16
  } catch (e) {
17
17
  return { kind: 'exception', detail: String(e && e.message || e) };
18
18
  }
19
- })()`);if(z?.kind==="auth")throw new L("reddit.com",z.detail);if(z?.kind==="http")throw new F(`HTTP ${z.httpStatus} from ${z.where}`);if(z?.kind==="exception")throw new F(`whoami failed: ${z.detail}`);if(z?.kind!=="ok")throw new F(`Unexpected result from reddit whoami: ${JSON.stringify(z)}`);const f=z.identity,J=f.created_utc?new Date(f.created_utc*1000).toISOString().split("T")[0]:null,B=typeof f.link_karma==="number"?f.link_karma:null,D=typeof f.comment_karma==="number"?f.comment_karma:null,H=typeof f.total_karma==="number"?f.total_karma:B!=null&&D!=null?B+D:null,I=typeof f.inbox_count==="number"?f.inbox_count:null;return[{field:"Username",value:"u/"+f.name},{field:"ID",value:f.id?"t2_"+f.id:null},{field:"Post Karma",value:B!=null?String(B):null},{field:"Comment Karma",value:D!=null?String(D):null},{field:"Total Karma",value:H!=null?String(H):null},{field:"Account Created",value:J},{field:"Gold",value:f.is_gold?"Yes":"No"},{field:"Mod",value:f.is_mod?"Yes":"No"},{field:"Verified Email",value:f.has_verified_email?"Yes":"No"},{field:"Has Mail",value:f.has_mail?"Yes":"No"},{field:"Inbox Count",value:I!=null?String(I):null}]}});
19
+ })()`);if(t?.kind==="auth")throw new u("reddit.com",t.detail);if(t?.kind==="http")throw new a(`HTTP ${t.httpStatus} from ${t.where}`);if(t?.kind==="exception")throw new a(`whoami failed: ${t.detail}`);if(t?.kind!=="ok")throw new a(`Unexpected result from reddit whoami: ${JSON.stringify(t)}`);const e=t.identity,d=e.created_utc?new Date(e.created_utc*1000).toISOString().split("T")[0]:null,i=typeof e.link_karma==="number"?e.link_karma:null,n=typeof e.comment_karma==="number"?e.comment_karma:null,o=typeof e.total_karma==="number"?e.total_karma:i!=null&&n!=null?i+n:null,l=typeof e.inbox_count==="number"?e.inbox_count:null;return[{field:"Username",value:"u/"+e.name},{field:"ID",value:e.id?"t2_"+e.id:null},{field:"Post Karma",value:i!=null?String(i):null},{field:"Comment Karma",value:n!=null?String(n):null},{field:"Total Karma",value:o!=null?String(o):null},{field:"Account Created",value:d},{field:"Gold",value:e.is_gold?"Yes":"No"},{field:"Mod",value:e.is_mod?"Yes":"No"},{field:"Verified Email",value:e.has_verified_email?"Yes":"No"},{field:"Has Mail",value:e.has_mail?"Yes":"No"},{field:"Inbox Count",value:l!=null?String(l):null}]}});
@@ -1 +1 @@
1
- import{cli as p,Strategy as f}from"@jackwener/opencli/registry";import{ArgumentError as u,AuthRequiredError as h,CommandExecutionError as w,EmptyResultError as y}from"@jackwener/opencli/errors";import{buildCommentsExtractJs as g,normalizeCommentRows as b}from"../xiaohongshu/comments.js";import{buildNoteUrl as R,parseNoteId as x}from"../xiaohongshu/note-helpers.js";const _="Pass a full rednote.com note URL with xsec_token from search results or user/profile context.";function k(o){const e=Number(o??20);if(!Number.isFinite(e)||!Number.isInteger(e))throw new u(`--limit must be an integer between 1 and 50, got ${JSON.stringify(o)}`);if(e<1||e>50)throw new u(`--limit must be between 1 and 50, got ${e}`);return e}p({site:"rednote",name:"comments",access:"read",description:"Read comments from a rednote note (supports nested replies)",domain:"www.rednote.com",strategy:f.COOKIE,navigateBefore:!1,args:[{name:"note-id",required:!0,positional:!0,help:"Full rednote note URL with xsec_token"},{name:"limit",type:"int",default:20,help:"Number of top-level comments (max 50)"},{name:"with-replies",type:"boolean",default:!1,help:"Include nested replies (楼中楼)"}],columns:["rank","author","text","likes","time","is_reply","reply_to","images"],func:async(o,e)=>{const i=k(e.limit),m=Boolean(e["with-replies"]),s=String(e["note-id"]),d=x(s);await o.goto(R(s,{commandName:"rednote comments",cookieRoot:"rednote.com",signedUrlHint:_}));await o.wait({time:2+Math.random()*3});const r=await o.evaluate(g(m,i));if(!r||typeof r!=="object")throw new y("rednote/comments","Unexpected evaluate response");if(r.securityBlock)throw new w("Rednote security block: the note detail page was blocked by risk control.",/^https?:\/\//.test(s)?"The page may be temporarily restricted. Try again later or from a different session.":"Try using a full URL from search results (with xsec_token) instead of a bare note ID.");if(r.loginWall)throw new h("www.rednote.com","Note comments require login");const a=b(r.results,"rednote/comments"),l=(t,n)=>({rank:n+1,author:t.author,text:t.text,likes:t.likes,time:t.time,is_reply:t.is_reply,reply_to:t.reply_to,images:t.images??[]});if(m){const t=[];let n=0;for(const c of a){if(!c.is_reply)n++;if(n>i)break;t.push(c)}return t.map(l)}return a.slice(0,i).map(l)}});
1
+ import{cli as p,Strategy as f}from"@jackwener/opencli/registry";import{ArgumentError as d,AuthRequiredError as w,CommandExecutionError as h,EmptyResultError as y}from"@jackwener/opencli/errors";import{buildCommentsExtractJs as b,normalizeCommentRows as g}from"../xiaohongshu/comments.js";import{buildNoteUrl as R,parseNoteId as _}from"../xiaohongshu/note-helpers.js";const k="Pass a full rednote.com note URL with xsec_token from search results or user/profile context.";function N(o){const e=Number(o??20);if(!Number.isFinite(e)||!Number.isInteger(e))throw new d(`--limit must be an integer between 1 and 50, got ${JSON.stringify(o)}`);if(e<1||e>50)throw new d(`--limit must be between 1 and 50, got ${e}`);return e}p({site:"rednote",name:"comments",access:"read",description:"Read comments from a rednote note (supports nested replies)",domain:"www.rednote.com",strategy:f.COOKIE,navigateBefore:!1,args:[{name:"note-id",required:!0,positional:!0,help:"Full rednote note URL with xsec_token"},{name:"limit",type:"int",default:20,help:"Number of top-level comments (max 50)"},{name:"with-replies",type:"boolean",default:!1,help:"Include nested replies (楼中楼)"}],columns:["rank","author","text","likes","time","is_reply","reply_to","images"],func:async(o,e)=>{const i=N(e.limit),a=Boolean(e["with-replies"]),s=String(e["note-id"]),u=_(s);await o.goto(R(s,{commandName:"rednote comments",cookieRoot:"rednote.com",signedUrlHint:k}));await o.wait({time:2+Math.random()*3});const r=await o.evaluate(b(a,i));if(!r||typeof r!=="object")throw new y("rednote/comments","Unexpected evaluate response");if(r.securityBlock)throw new h("Rednote security block: the note detail page was blocked by risk control.",/^https?:\/\//.test(s)?"The page may be temporarily restricted. Try again later or from a different session.":"Try using a full URL from search results (with xsec_token) instead of a bare note ID.");if(r.loginWall)throw new w("www.rednote.com","Note comments require login");const m=g(r.results,"rednote/comments"),l=(t,n)=>({rank:n+1,author:t.author,text:t.text,likes:t.likes,time:t.time,is_reply:t.is_reply,reply_to:t.reply_to,images:t.images??[]});if(a){const t=[];let n=0;for(const c of m){if(!c.is_reply)n++;if(n>i)break;t.push(c)}return t.map(l)}return m.slice(0,i).map(l)}});