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
@@ -1 +1 @@
1
- import{ArgumentError,AuthRequiredError as Q,CommandExecutionError,EmptyResultError}from"@jackwener/opencli/errors";export const GUAZI_M_BASE="https://m.guazi.com";const V="Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5 Mobile/15E148 Safari/604.1";export const BROWSE_COLUMNS=["rank","clue_id","title","price","down_payment","mileage","year","city","url"],CAR_COLUMNS=["field","value"],CITY_CODE={beijing:"bj","北京":"bj",shanghai:"sh","上海":"sh",guangzhou:"gz","广州":"gz",shenzhen:"sz","深圳":"sz",hangzhou:"hz","杭州":"hz",chengdu:"cd","成都":"cd",chongqing:"cq","重庆":"cq",nanjing:"nj","南京":"nj",wuhan:"wh","武汉":"wh",tianjin:"tj","天津":"tj",xian:"xa","西安":"xa",suzhou:"su","苏州":"su",zhengzhou:"zz","郑州":"zz",changsha:"cs","长沙":"cs",qingdao:"qd","青岛":"qd",shenyang:"sy","沈阳":"sy",dalian:"dl","大连":"dl",jinan:"jn","济南":"jn",hefei:"hf","合肥":"hf",foshan:"fs","佛山":"fs"};export function resolveCityCode(F){if(F==null||F==="")return"bj";const K=String(F).trim().toLowerCase();if(CITY_CODE[K])return CITY_CODE[K];if(CITY_CODE[String(F).trim()])return CITY_CODE[String(F).trim()];if(/^[a-z]{2,3}$/.test(K))return K;const L=Object.keys(CITY_CODE).filter((N)=>/^[a-z]+$/.test(N)).join(", ");throw new ArgumentError("city",`unknown city '${F}'. pass a Guazi city code or one of: ${L}`)}export function normalizeClueId(F){const K=String(F||"").trim();if(!K)throw new ArgumentError("clue_id must be a non-empty value");const L=K.match(/car-detail\/c(\d+)/)||K.match(/^c?(\d+)$/);if(!L)throw new ArgumentError(`'${F}' does not look like a guazi clue id (a number, or a /car-detail/c<id>.html URL)`);return L[1]}export function requireLimit(F,K,L){const N=F==null||F===""?K:F,P=typeof N==="number"?N:Number(String(N).trim());if(!Number.isInteger(P)||P<1||P>L)throw new ArgumentError(`limit must be an integer between 1 and ${L}`);return P}export function clean(F){return String(F==null?"":F).replace(/\s+/g," ").trim()}export function requireText(F,K){const L=clean(F);if(!L)throw new CommandExecutionError(`${K} did not include a stable text value.`);return L}export function requireStableId(F,K){const L=String(F??"").trim();if(!/^\d+$/.test(L))throw new CommandExecutionError(`${K} did not include a stable numeric id.`);return L}export async function guaziFetch(F,K){let L;try{L=await fetch(`${GUAZI_M_BASE}${F}`,{headers:{"User-Agent":V,Referer:`${GUAZI_M_BASE}/`,"Accept-Language":"zh-CN,zh;q=0.9"}})}catch(P){throw new CommandExecutionError(`guazi ${K} network error: ${P?.message||P}`)}if(!L.ok)throw new CommandExecutionError(`guazi ${K} HTTP ${L.status}`);const N=await L.text();if(/瑞数|reese84|captcha|滑动验证|verify\.guazi|安全验证/i.test(N)&&!/car-detail\/c\d+/.test(N))throw new Q("guazi.com",`guazi ${K} hit an anti-bot challenge — Guazi may have started gating the mobile site.`);return N}export{ArgumentError,CommandExecutionError,EmptyResultError};
1
+ import{ArgumentError,AuthRequiredError as o,CommandExecutionError,EmptyResultError}from"@jackwener/opencli/errors";export const GUAZI_M_BASE="https://m.guazi.com";const a="Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5 Mobile/15E148 Safari/604.1";export const BROWSE_COLUMNS=["rank","clue_id","title","price","down_payment","mileage","year","city","url"],CAR_COLUMNS=["field","value"],CITY_CODE={beijing:"bj","北京":"bj",shanghai:"sh","上海":"sh",guangzhou:"gz","广州":"gz",shenzhen:"sz","深圳":"sz",hangzhou:"hz","杭州":"hz",chengdu:"cd","成都":"cd",chongqing:"cq","重庆":"cq",nanjing:"nj","南京":"nj",wuhan:"wh","武汉":"wh",tianjin:"tj","天津":"tj",xian:"xa","西安":"xa",suzhou:"su","苏州":"su",zhengzhou:"zz","郑州":"zz",changsha:"cs","长沙":"cs",qingdao:"qd","青岛":"qd",shenyang:"sy","沈阳":"sy",dalian:"dl","大连":"dl",jinan:"jn","济南":"jn",hefei:"hf","合肥":"hf",foshan:"fs","佛山":"fs"};export function resolveCityCode(e){if(e==null||e==="")return"bj";const t=String(e).trim().toLowerCase();if(CITY_CODE[t])return CITY_CODE[t];if(CITY_CODE[String(e).trim()])return CITY_CODE[String(e).trim()];if(/^[a-z]{2,3}$/.test(t))return t;const n=Object.keys(CITY_CODE).filter((r)=>/^[a-z]+$/.test(r)).join(", ");throw new ArgumentError("city",`unknown city '${e}'. pass a Guazi city code or one of: ${n}`)}export function normalizeClueId(e){const t=String(e||"").trim();if(!t)throw new ArgumentError("clue_id must be a non-empty value");const n=t.match(/car-detail\/c(\d+)/)||t.match(/^c?(\d+)$/);if(!n)throw new ArgumentError(`'${e}' does not look like a guazi clue id (a number, or a /car-detail/c<id>.html URL)`);return n[1]}export function requireLimit(e,t,n){const r=e==null||e===""?t:e,i=typeof r==="number"?r:Number(String(r).trim());if(!Number.isInteger(i)||i<1||i>n)throw new ArgumentError(`limit must be an integer between 1 and ${n}`);return i}export function clean(e){return String(e==null?"":e).replace(/\s+/g," ").trim()}export function requireText(e,t){const n=clean(e);if(!n)throw new CommandExecutionError(`${t} did not include a stable text value.`);return n}export function requireStableId(e,t){const n=String(e??"").trim();if(!/^\d+$/.test(n))throw new CommandExecutionError(`${t} did not include a stable numeric id.`);return n}export async function guaziFetch(e,t){let n;try{n=await fetch(`${GUAZI_M_BASE}${e}`,{headers:{"User-Agent":a,Referer:`${GUAZI_M_BASE}/`,"Accept-Language":"zh-CN,zh;q=0.9"}})}catch(i){throw new CommandExecutionError(`guazi ${t} network error: ${i?.message||i}`)}if(!n.ok)throw new CommandExecutionError(`guazi ${t} HTTP ${n.status}`);const r=await n.text();if(/瑞数|reese84|captcha|滑动验证|verify\.guazi|安全验证/i.test(r)&&!/car-detail\/c\d+/.test(r))throw new o("guazi.com",`guazi ${t} hit an anti-bot challenge — Guazi may have started gating the mobile site.`);return r}export{ArgumentError,CommandExecutionError,EmptyResultError};
@@ -1,4 +1,4 @@
1
- import{AuthRequiredError as n,CommandExecutionError as c}from"@jackwener/opencli/errors";import{registerSiteAuthCommands as i}from"../_shared/site-auth.js";const t="https://news.ycombinator.com";async function r(e){return(await e.getCookies({url:t})).some((a)=>a.name==="user"&&a.value)}async function s(e){if(!await r(e))throw new n("news.ycombinator.com","Hacker News `user` cookie missing — not signed in");await e.goto(`${t}/news`);await e.wait(1);const o=await e.evaluate(`(() => {
1
+ import{AuthRequiredError as n,CommandExecutionError as m}from"@jackwener/opencli/errors";import{registerSiteAuthCommands as i}from"../_shared/site-auth.js";const r="https://news.ycombinator.com";async function t(e){return(await e.getCookies({url:r})).some((a)=>a.name==="user"&&a.value)}async function s(e){if(!await t(e))throw new n("news.ycombinator.com","Hacker News `user` cookie missing — not signed in");await e.goto(`${r}/news`);await e.wait(1);const o=await e.evaluate(`(() => {
2
2
  // The top-right nav shows "<username> (karma) | logout" only when signed in.
3
3
  const userLink = document.querySelector('span.pagetop a[href^="user?id="]');
4
4
  const logout = document.querySelector('a[href^="logout"]');
@@ -6,4 +6,4 @@ import{AuthRequiredError as n,CommandExecutionError as c}from"@jackwener/opencli
6
6
  const username = (userLink.textContent || '').trim();
7
7
  const karmaMatch = (document.querySelector('span.pagetop')?.textContent || '').match(/\\((\\d+)\\)/);
8
8
  return { username, karma: karmaMatch ? karmaMatch[1] : '' };
9
- })()`);if(o?.anon||!o?.username)throw new n("news.ycombinator.com","Hacker News shows no signed-in user — cookie stale");return{username:o.username,karma:o.karma||""}}i({site:"hackernews",domain:"news.ycombinator.com",loginUrl:`${t}/login`,columns:["username","karma"],quickCheck:r,verify:s,poll:async(e)=>{if(!await r(e))throw new n("news.ycombinator.com","Waiting for Hacker News `user` cookie");return s(e)}});
9
+ })()`);if(o?.anon||!o?.username)throw new n("news.ycombinator.com","Hacker News shows no signed-in user — cookie stale");return{username:o.username,karma:o.karma||""}}i({site:"hackernews",domain:"news.ycombinator.com",loginUrl:`${r}/login`,columns:["username","karma"],quickCheck:t,verify:s,poll:async(e)=>{if(!await t(e))throw new n("news.ycombinator.com","Waiting for Hacker News `user` cookie");return s(e)}});
@@ -1,22 +1,22 @@
1
- import{ArgumentError as Q,AuthRequiredError as T,CommandExecutionError as L}from"@jackwener/opencli/errors";import{cli as U,Strategy as V}from"@jackwener/opencli/registry";const M="https://news.ycombinator.com";export function normalizeItemId(F){const J=String(F||"").trim();if(!J)throw new Q("Item id is required.","Pass an HN item id (story or comment), e.g. 48811591.");if(/^\d+$/.test(J))return J;const B=J.match(/[?&]id=(\d+)/);if(B)return B[1];throw new Q(`Invalid HN item reference: ${JSON.stringify(J)}`,"Pass a numeric id or an item?id=… URL.")}U({site:"hackernews",name:"comment",access:"write",description:"Post a comment on a Hacker News item. Pass the parent id (a story to comment on it, or a comment to reply). Contribute a substantive, on-topic comment — HN flags low-effort or off-topic replies.",domain:"news.ycombinator.com",strategy:V.COOKIE,browser:!0,args:[{name:"parent",type:"string",required:!0,positional:!0,help:"Parent item id (story or comment) to reply to"},{name:"text",fromFile:!0,type:"string",required:!0,positional:!0,help:"Comment text (HN markup: blank line = paragraph)"}],columns:["status","id","url","parent","message"],func:async(F,J)=>{if(!F)throw new L("Browser session required");const B=normalizeItemId(J.parent),P=String(J.text??"");if(!P.trim())throw new Q("Comment text cannot be empty.");await F.goto(`${M}/item?id=${B}`);await F.wait(1);const D=await F.evaluate(`(async () => {
1
+ import{ArgumentError as m,AuthRequiredError as c,CommandExecutionError as i}from"@jackwener/opencli/errors";import{cli as u,Strategy as d}from"@jackwener/opencli/registry";const s="https://news.ycombinator.com";export function normalizeItemId(r){const o=String(r||"").trim();if(!o)throw new m("Item id is required.","Pass an HN item id (story or comment), e.g. 48811591.");if(/^\d+$/.test(o))return o;const t=o.match(/[?&]id=(\d+)/);if(t)return t[1];throw new m(`Invalid HN item reference: ${JSON.stringify(o)}`,"Pass a numeric id or an item?id=… URL.")}u({site:"hackernews",name:"comment",access:"write",description:"Post a comment on a Hacker News item. Pass the parent id (a story to comment on it, or a comment to reply). Contribute a substantive, on-topic comment — HN flags low-effort or off-topic replies.",domain:"news.ycombinator.com",strategy:d.COOKIE,browser:!0,args:[{name:"parent",type:"string",required:!0,positional:!0,help:"Parent item id (story or comment) to reply to"},{name:"text",fromFile:!0,type:"string",required:!0,positional:!0,help:"Comment text (HN markup: blank line = paragraph)"}],columns:["status","id","url","parent","message"],func:async(r,o)=>{if(!r)throw new i("Browser session required");const t=normalizeItemId(o.parent),a=String(o.text??"");if(!a.trim())throw new m("Comment text cannot be empty.");await r.goto(`${s}/item?id=${t}`);await r.wait(1);const e=await r.evaluate(`(async () => {
2
2
  try {
3
3
  if (/\\/login/.test(location.pathname)) return { kind: 'auth', detail: 'redirected to /login' };
4
4
  // The reply form posts to "comment" (relative). Match it by the hidden
5
5
  // fields it carries rather than the action attribute, which HN writes
6
6
  // relative ("comment") so /comment suffix selectors miss it.
7
7
  const forms = [...document.querySelectorAll('form')].filter(f => f.querySelector('input[name="hmac"]') && f.querySelector('input[name="parent"]'));
8
- const form = forms.find(f => (f.querySelector('input[name="parent"]')?.value) === ${JSON.stringify(B)}) || forms[0];
8
+ const form = forms.find(f => (f.querySelector('input[name="parent"]')?.value) === ${JSON.stringify(t)}) || forms[0];
9
9
  if (!form) return { kind: 'notfound', detail: 'No comment form on this item — it may be closed, deleted, or you are signed out.' };
10
10
  const hmac = form.querySelector('input[name="hmac"]')?.value;
11
- const goto = form.querySelector('input[name="goto"]')?.value || ('item?id=' + ${JSON.stringify(B)});
12
- const parentVal = form.querySelector('input[name="parent"]')?.value || ${JSON.stringify(B)};
11
+ const goto = form.querySelector('input[name="goto"]')?.value || ('item?id=' + ${JSON.stringify(t)});
12
+ const parentVal = form.querySelector('input[name="parent"]')?.value || ${JSON.stringify(t)};
13
13
  if (!hmac) return { kind: 'auth', detail: 'comment hmac token missing — likely signed out' };
14
14
 
15
15
  const p = new URLSearchParams();
16
16
  p.set('parent', parentVal);
17
17
  p.set('goto', goto);
18
18
  p.set('hmac', hmac);
19
- p.set('text', ${JSON.stringify(P)});
19
+ p.set('text', ${JSON.stringify(a)});
20
20
 
21
21
  const res = await fetch('/comment', {
22
22
  method: 'POST',
@@ -40,12 +40,12 @@ import{ArgumentError as Q,AuthRequiredError as T,CommandExecutionError as L}from
40
40
  } catch (e) {
41
41
  return { kind: 'exception', detail: String((e && e.message) || e) };
42
42
  }
43
- })()`);if(D?.kind==="auth")throw new T("news.ycombinator.com",D.detail);if(D?.kind==="notfound")throw new L(D.detail);if(D?.kind==="exception")throw new L(`HN comment failed: ${D.detail}`);if(D?.kind==="reject")return[{status:"failed",id:"",url:"",parent:B,message:D.detail}];if(!D?.ok)throw new L(`Unexpected HN comment result: ${JSON.stringify(D)}`);await F.goto(`${M}/item?id=${B}`);await F.wait(1);const K=(await F.evaluate(`(() => {
43
+ })()`);if(e?.kind==="auth")throw new c("news.ycombinator.com",e.detail);if(e?.kind==="notfound")throw new i(e.detail);if(e?.kind==="exception")throw new i(`HN comment failed: ${e.detail}`);if(e?.kind==="reject")return[{status:"failed",id:"",url:"",parent:t,message:e.detail}];if(!e?.ok)throw new i(`Unexpected HN comment result: ${JSON.stringify(e)}`);await r.goto(`${s}/item?id=${t}`);await r.wait(1);const n=(await r.evaluate(`(() => {
44
44
  try {
45
45
  let username = '';
46
46
  const navLink = document.querySelector('span.pagetop a[href^="user?id="]');
47
47
  if (navLink) username = (navLink.getAttribute('href') || '').replace('user?id=', '');
48
- const want = ${JSON.stringify(P)}.replace(/\\s+/g, ' ').trim();
48
+ const want = ${JSON.stringify(a)}.replace(/\\s+/g, ' ').trim();
49
49
  const rows = [...document.querySelectorAll('tr.athing.comtr')];
50
50
  // Newest first: our fresh comment is usually near the top of its thread.
51
51
  for (const row of rows) {
@@ -58,4 +58,4 @@ import{ArgumentError as Q,AuthRequiredError as T,CommandExecutionError as L}from
58
58
  }
59
59
  return null;
60
60
  } catch { return null; }
61
- })()`))?.id||"";return[{status:"success",id:K,url:K?`${M}/item?id=${K}`:`${M}/item?id=${B}`,parent:B,message:K?"Comment posted":"Comment posted (id not confirmed on reload)"}]}});
61
+ })()`))?.id||"";return[{status:"success",id:n,url:n?`${s}/item?id=${n}`:`${s}/item?id=${t}`,parent:t,message:n?"Comment posted":"Comment posted (id not confirmed on reload)"}]}});
@@ -1,11 +1,11 @@
1
- import{cli as P,Strategy as w}from"@jackwener/opencli/registry";import{ArgumentError as F,CommandExecutionError as E,EmptyResultError as T}from"@jackwener/opencli/errors";const I="https://hacker-news.firebaseio.com/v0/item";async function K(z){const G=await fetch(`${I}/${z}.json`);if(!G.ok)throw new E(`HN API HTTP ${G.status} for item ${z}`,"Check the item ID");return G.json()}function M(z,G){if(!Number.isInteger(z)||z<=0)throw new F(`${G} must be a positive integer`);return z}function x(z,G,V){if(!Number.isInteger(z)||z<G)throw new F(`${V} must be an integer >= ${G}`);return z}function B(z){if(!z)return"";return String(z).replace(/<p>/gi,`
1
+ import{cli as S,Strategy as H}from"@jackwener/opencli/registry";import{ArgumentError as f,CommandExecutionError as v,EmptyResultError as R}from"@jackwener/opencli/errors";const j="https://hacker-news.firebaseio.com/v0/item";async function y(e){const t=await fetch(`${j}/${e}.json`);if(!t.ok)throw new v(`HN API HTTP ${t.status} for item ${e}`,"Check the item ID");return t.json()}function g(e,t){if(!Number.isInteger(e)||e<=0)throw new f(`${t} must be a positive integer`);return e}function q(e,t,s){if(!Number.isInteger(e)||e<t)throw new f(`${s} must be an integer >= ${t}`);return e}function L(e){if(!e)return"";return String(e).replace(/<p>/gi,`
2
2
 
3
3
  `).replace(/<\/p>/gi,"").replace(/<br\s*\/?>/gi,`
4
4
  `).replace(/<i>(.*?)<\/i>/gi,"$1").replace(/<a[^>]*href="([^"]*)"[^>]*>(.*?)<\/a>/gi,"$2 ($1)").replace(/<pre><code>([\s\S]*?)<\/code><\/pre>/gi,`
5
5
  $1
6
- `).replace(/<[^>]+>/g,"").replace(/&#x27;/g,"'").replace(/&quot;/g,'"').replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&amp;/g,"&").replace(/&nbsp;/g," ").replace(/&#x2F;/g,"/").trim()}function v(z,G){if(G===0)return z;const Y=`${" ".repeat(G)}> `;return z.split(`
7
- `).map((Z)=>Y+Z).join(`
8
- `)}function b(z){return" ".repeat(z+1)}P({site:"hackernews",name:"read",access:"read",description:"Read a Hacker News story and its comment tree",domain:"news.ycombinator.com",strategy:w.PUBLIC,browser:!1,args:[{name:"id",required:!0,positional:!0,help:"HN item ID (e.g. 39847301)"},{name:"limit",type:"int",default:25,help:"Max 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"},{name:"max-length",type:"int",default:2000,help:"Max characters per comment body (min 100)"}],columns:["type","author","score","text"],func:async(z)=>{const G=String(z.id||"").trim();if(!/^\d+$/.test(G))throw new F(`Invalid HN item id: ${z.id}`,"Pass a numeric id like 39847301");const V=M(z.limit??25,"hackernews read --limit"),Y=M(z.depth??2,"hackernews read --depth"),Z=M(z.replies??5,"hackernews read --replies"),W=x(z["max-length"]??2000,100,"hackernews read --max-length"),O=await K(G);if(!O||O.deleted||O.dead)throw new T(`hackernews/${G}`,"Story not found, deleted, or dead");const U=[],$=B(O.text||""),N=$.length>W?$.slice(0,W)+`
9
- ... [truncated]`:$,D=[O.title||""];if(N)D.push(`
10
- `+N);if(O.url)D.push(`
11
- `+O.url);U.push({type:"POST",author:O.by||"[deleted]",score:O.score??0,text:D.join("").trim()});const S=Array.isArray(O.kids)?O.kids:[],_=S.slice(0,V),k=await Promise.all(_.map((J)=>K(J).catch(()=>null)));async function C(J,Q){if(!J||J.deleted||J.dead||J.type!=="comment")return;const H=B(J.text||""),L=H.length>W?H.slice(0,W)+"...":H;U.push({type:Q===0?"L0":`L${Q}`,author:J.by||"[deleted]",score:"",text:v(L,Q)});const X=Array.isArray(J.kids)?J.kids:[];if(Q+1>=Y){if(X.length>0)U.push({type:`L${Q+1}`,author:"",score:"",text:`${b(Q)}[+${X.length} more replies]`});return}const A=X.slice(0,Z),R=await Promise.all(A.map((j)=>K(j).catch(()=>null)));for(const j of R)await C(j,Q+1);const f=X.length-A.length;if(f>0)U.push({type:`L${Q+1}`,author:"",score:"",text:`${b(Q)}[+${f} more replies]`})}for(const J of k)await C(J,0);const q=Math.max(0,S.length-_.length);if(q>0)U.push({type:"",author:"",score:"",text:`[+${q} more top-level comments]`});return U}});
6
+ `).replace(/<[^>]+>/g,"").replace(/&#x27;/g,"'").replace(/&quot;/g,'"').replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&amp;/g,"&").replace(/&nbsp;/g," ").replace(/&#x2F;/g,"/").trim()}function B(e,t){if(t===0)return e;const l=`${" ".repeat(t)}> `;return e.split(`
7
+ `).map((p)=>l+p).join(`
8
+ `)}function A(e){return" ".repeat(e+1)}S({site:"hackernews",name:"read",access:"read",description:"Read a Hacker News story and its comment tree",domain:"news.ycombinator.com",strategy:H.PUBLIC,browser:!1,args:[{name:"id",required:!0,positional:!0,help:"HN item ID (e.g. 39847301)"},{name:"limit",type:"int",default:25,help:"Max 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"},{name:"max-length",type:"int",default:2000,help:"Max characters per comment body (min 100)"}],columns:["type","author","score","text"],func:async(e)=>{const t=String(e.id||"").trim();if(!/^\d+$/.test(t))throw new f(`Invalid HN item id: ${e.id}`,"Pass a numeric id like 39847301");const s=g(e.limit??25,"hackernews read --limit"),l=g(e.depth??2,"hackernews read --depth"),p=g(e.replies??5,"hackernews read --replies"),a=q(e["max-length"]??2000,100,"hackernews read --max-length"),n=await y(t);if(!n||n.deleted||n.dead)throw new R(`hackernews/${t}`,"Story not found, deleted, or dead");const o=[],m=L(n.text||""),w=m.length>a?m.slice(0,a)+`
9
+ ... [truncated]`:m,u=[n.title||""];if(w)u.push(`
10
+ `+w);if(n.url)u.push(`
11
+ `+n.url);o.push({type:"POST",author:n.by||"[deleted]",score:n.score??0,text:u.join("").trim()});const x=Array.isArray(n.kids)?n.kids:[],k=x.slice(0,s),E=await Promise.all(k.map((r)=>y(r).catch(()=>null)));async function b(r,i){if(!r||r.deleted||r.dead||r.type!=="comment")return;const h=L(r.text||""),M=h.length>a?h.slice(0,a)+"...":h;o.push({type:i===0?"L0":`L${i}`,author:r.by||"[deleted]",score:"",text:B(M,i)});const c=Array.isArray(r.kids)?r.kids:[];if(i+1>=l){if(c.length>0)o.push({type:`L${i+1}`,author:"",score:"",text:`${A(i)}[+${c.length} more replies]`});return}const P=c.slice(0,p),N=await Promise.all(P.map((d)=>y(d).catch(()=>null)));for(const d of N)await b(d,i+1);const T=c.length-P.length;if(T>0)o.push({type:`L${i+1}`,author:"",score:"",text:`${A(i)}[+${T} more replies]`})}for(const r of E)await b(r,0);const I=Math.max(0,x.length-k.length);if(I>0)o.push({type:"",author:"",score:"",text:`[+${I} more top-level comments]`});return o}});
@@ -1,4 +1,4 @@
1
- import{ArgumentError as F,AuthRequiredError as Q,CommandExecutionError as L}from"@jackwener/opencli/errors";import{cli as T,Strategy as V}from"@jackwener/opencli/registry";const M="https://news.ycombinator.com";T({site:"hackernews",name:"submit",access:"write",description:"Submit a story to Hacker News. Link post by default (--url), or an Ask/text post with --text. HN gates submissions on account age/karma and dedupes URLs — rejections are surfaced verbatim. Post genuinely worthwhile content; low-effort submissions hurt the account.",domain:"news.ycombinator.com",strategy:V.COOKIE,browser:!0,args:[{name:"title",type:"string",required:!0,positional:!0,help:"Story title (max 80 chars)"},{name:"url",type:"string",help:"External URL for a link post (mutually exclusive with --text)"},{name:"text",fromFile:!0,type:"string",help:"Body text for an Ask HN / text post (mutually exclusive with --url)"}],columns:["status","id","url","title","message"],func:async(v,D)=>{if(!v)throw new L("Browser session required");const z=String(D.title??"").trim();if(!z)throw new F("Title is required.");if(z.length>80)throw new F("HN titles must be at most 80 characters.");const B=typeof D.url==="string"?D.url.trim():"",K=typeof D.text==="string"?D.text:"";if(B&&K)throw new F("Pass either --url (link post) or --text (text post), not both.");if(!B&&!K)throw new F("A story needs either --url or --text.","Give a link to submit, or --text for an Ask HN post.");if(B)try{new URL(B)}catch{throw new F(`Invalid --url: ${B}`)}await v.goto(`${M}/submit`);await v.wait(1);const f=await v.evaluate(`(async () => {
1
+ import{ArgumentError as s,AuthRequiredError as d,CommandExecutionError as u}from"@jackwener/opencli/errors";import{cli as m,Strategy as f}from"@jackwener/opencli/registry";const c="https://news.ycombinator.com";m({site:"hackernews",name:"submit",access:"write",description:"Submit a story to Hacker News. Link post by default (--url), or an Ask/text post with --text. HN gates submissions on account age/karma and dedupes URLs — rejections are surfaced verbatim. Post genuinely worthwhile content; low-effort submissions hurt the account.",domain:"news.ycombinator.com",strategy:f.COOKIE,browser:!0,args:[{name:"title",type:"string",required:!0,positional:!0,help:"Story title (max 80 chars)"},{name:"url",type:"string",help:"External URL for a link post (mutually exclusive with --text)"},{name:"text",fromFile:!0,type:"string",help:"Body text for an Ask HN / text post (mutually exclusive with --url)"}],columns:["status","id","url","title","message"],func:async(e,n)=>{if(!e)throw new u("Browser session required");const r=String(n.title??"").trim();if(!r)throw new s("Title is required.");if(r.length>80)throw new s("HN titles must be at most 80 characters.");const i=typeof n.url==="string"?n.url.trim():"",a=typeof n.text==="string"?n.text:"";if(i&&a)throw new s("Pass either --url (link post) or --text (text post), not both.");if(!i&&!a)throw new s("A story needs either --url or --text.","Give a link to submit, or --text for an Ask HN post.");if(i)try{new URL(i)}catch{throw new s(`Invalid --url: ${i}`)}await e.goto(`${c}/submit`);await e.wait(1);const t=await e.evaluate(`(async () => {
2
2
  try {
3
3
  // The submit form only renders for a signed-in user; if HN bounced us
4
4
  // to /login the form (and its fnid) will be absent.
@@ -12,9 +12,9 @@ import{ArgumentError as F,AuthRequiredError as Q,CommandExecutionError as L}from
12
12
  const p = new URLSearchParams();
13
13
  p.set('fnid', fnid);
14
14
  p.set('fnop', 'submit-page');
15
- p.set('title', ${JSON.stringify(z)});
16
- p.set('url', ${JSON.stringify(B)});
17
- p.set('text', ${JSON.stringify(K)});
15
+ p.set('title', ${JSON.stringify(r)});
16
+ p.set('url', ${JSON.stringify(i)});
17
+ p.set('text', ${JSON.stringify(a)});
18
18
 
19
19
  const res = await fetch('/r', {
20
20
  method: 'POST',
@@ -39,7 +39,7 @@ import{ArgumentError as F,AuthRequiredError as Q,CommandExecutionError as L}from
39
39
  } catch (e) {
40
40
  return { kind: 'exception', detail: String((e && e.message) || e) };
41
41
  }
42
- })()`);if(f?.kind==="auth")throw new Q("news.ycombinator.com",f.detail);if(f?.kind==="exception")throw new L(`HN submit failed: ${f.detail}`);if(f?.kind==="reject")return[{status:"failed",id:"",url:"",title:z,message:f.detail}];if(!f?.ok)throw new L(`Unexpected HN submit result: ${JSON.stringify(f)}`);await v.wait(1);const J=(await v.evaluate(`(async () => {
42
+ })()`);if(t?.kind==="auth")throw new d("news.ycombinator.com",t.detail);if(t?.kind==="exception")throw new u(`HN submit failed: ${t.detail}`);if(t?.kind==="reject")return[{status:"failed",id:"",url:"",title:r,message:t.detail}];if(!t?.ok)throw new u(`Unexpected HN submit result: ${JSON.stringify(t)}`);await e.wait(1);const o=(await e.evaluate(`(async () => {
43
43
  try {
44
44
  const uc = document.cookie.match(/(?:^|; )user=([^;]+)/);
45
45
  // Cookie value is "<username>&<hash>"; the nav link is more reliable.
@@ -52,7 +52,7 @@ import{ArgumentError as F,AuthRequiredError as Q,CommandExecutionError as L}from
52
52
  const html = await res.text();
53
53
  const doc = new DOMParser().parseFromString(html, 'text/html');
54
54
  const rows = [...doc.querySelectorAll('tr.athing')];
55
- const want = ${JSON.stringify(z)}.replace(/\\s+/g, ' ').trim();
55
+ const want = ${JSON.stringify(r)}.replace(/\\s+/g, ' ').trim();
56
56
  for (const row of rows.slice(0, 5)) {
57
57
  const link = row.querySelector('.titleline a, a.storylink, .title a');
58
58
  const t = (link?.textContent || '').replace(/\\s+/g, ' ').trim();
@@ -62,4 +62,4 @@ import{ArgumentError as F,AuthRequiredError as Q,CommandExecutionError as L}from
62
62
  }
63
63
  return { id: rows[0]?.id || '', href: '' };
64
64
  } catch { return null; }
65
- })()`))?.id||"",P=J?`${M}/item?id=${J}`:"";return[{status:"success",id:J,url:P,title:z,message:J?"Story submitted":"Story submitted (item id not confirmed; check /newest)"}]}});
65
+ })()`))?.id||"",l=o?`${c}/item?id=${o}`:"";return[{status:"success",id:o,url:l,title:r,message:o?"Story submitted":"Story submitted (item id not confirmed; check /newest)"}]}});
@@ -1,6 +1,6 @@
1
- import{AuthRequiredError as z}from"@jackwener/opencli/errors";import{registerSiteAuthCommands as G}from"../_shared/site-auth.js";const B="https://hashnode.com",J="https://hashnode.com/api/auth/session";function K(v){return v==="hashnode-session"||/(authjs|next-auth)\.session-token$/.test(v)}async function D(v){return(await v.getCookies({url:B})).some((y)=>K(y.name)&&y.value)}async function F(v){await v.goto(B);const x=await v.evaluate(`(async () => {
1
+ import{AuthRequiredError as o}from"@jackwener/opencli/errors";import{registerSiteAuthCommands as i}from"../_shared/site-auth.js";const a="https://hashnode.com",u="https://hashnode.com/api/auth/session";function h(e){return e==="hashnode-session"||/(authjs|next-auth)\.session-token$/.test(e)}async function t(e){return(await e.getCookies({url:a})).some((n)=>h(n.name)&&n.value)}async function r(e){await e.goto(a);const s=await e.evaluate(`(async () => {
2
2
  try {
3
- var r = await fetch(${JSON.stringify(J)}, { credentials: 'include', headers: { Accept: 'application/json' } });
3
+ var r = await fetch(${JSON.stringify(u)}, { credentials: 'include', headers: { Accept: 'application/json' } });
4
4
  if (r.status === 401 || r.status === 403) return { ok: false, reason: 'HTTP ' + r.status };
5
5
  var text = await r.text();
6
6
  var j = null; try { j = JSON.parse(text); } catch (e) { return { ok: false, reason: 'non-JSON session' }; }
@@ -8,4 +8,4 @@ import{AuthRequiredError as z}from"@jackwener/opencli/errors";import{registerSit
8
8
  if (!u || !u.username) return { ok: false, reason: 'anonymous' };
9
9
  return { ok: true, id: String(u.id || ''), username: String(u.username || ''), name: String(u.name || ''), email: String(u.email || '') };
10
10
  } catch (e) { return { ok: false, reason: String(e && e.message || e) }; }
11
- })()`);if(!x||!x.ok)throw new z("hashnode.com",`Not logged in (${x?x.reason:"no probe"})`);return{user_id:x.id,username:x.username,name:x.name}}G({site:"hashnode",domain:"hashnode.com",loginUrl:"https://hashnode.com/onboard",columns:["user_id","username","name"],loginDescription:"打开 Hashnode 登录页并等待浏览器完成登录(供桌面客户端引导登录)。",quickCheck:D,verify:F,poll:async(v)=>{if(!await D(v))throw new z("hashnode.com","Waiting for hashnode.com session cookie");return F(v)}});
11
+ })()`);if(!s||!s.ok)throw new o("hashnode.com",`Not logged in (${s?s.reason:"no probe"})`);return{user_id:s.id,username:s.username,name:s.name}}i({site:"hashnode",domain:"hashnode.com",loginUrl:"https://hashnode.com/onboard",columns:["user_id","username","name"],loginDescription:"打开 Hashnode 登录页并等待浏览器完成登录(供桌面客户端引导登录)。",quickCheck:t,verify:r,poll:async(e)=>{if(!await t(e))throw new o("hashnode.com","Waiting for hashnode.com session cookie");return r(e)}});
@@ -1,4 +1,4 @@
1
- import*as M from"node:fs";import{cli as I,Strategy as S}from"@jackwener/opencli/registry";import{ArgumentError as _,AuthRequiredError as b,CommandExecutionError as V}from"@jackwener/opencli/errors";import{assertLiteralContent as O}from"../_shared/content-guard.js";const j="https://hashnode.com";export function resolveBody(z){if(z["body-file"]){const D=String(z["body-file"]);if(!M.statSync(D,{throwIfNoEntry:!1})?.isFile())throw new _(`--body-file not found: ${D}`);return M.readFileSync(D,"utf8")}if(z.body!==void 0&&z.body!==null){O(String(z.body),{fileFlag:"--body-file"});return String(z.body)}return}export function resolveTags(z){if(z===void 0||z===null||z==="")return[];return[...new Set(String(z).split(",").map((D)=>D.trim()).filter(Boolean))]}const h=`(async () => {
1
+ import*as k from"node:fs";import{cli as O,Strategy as E}from"@jackwener/opencli/registry";import{ArgumentError as g,AuthRequiredError as q,CommandExecutionError as a}from"@jackwener/opencli/errors";import{assertLiteralContent as T}from"../_shared/content-guard.js";const v="https://hashnode.com";export function resolveBody(e){if(e["body-file"]){const t=String(e["body-file"]);if(!k.statSync(t,{throwIfNoEntry:!1})?.isFile())throw new g(`--body-file not found: ${t}`);return k.readFileSync(t,"utf8")}if(e.body!==void 0&&e.body!==null){T(String(e.body),{fileFlag:"--body-file"});return String(e.body)}return}export function resolveTags(e){if(e===void 0||e===null||e==="")return[];return[...new Set(String(e).split(",").map((t)=>t.trim()).filter(Boolean))]}const P=`(async () => {
2
2
  if (location.href.indexOf('hashnode.com') < 0) return { drift: true };
3
3
  try {
4
4
  var r = await fetch('/api/auth/session', { credentials: 'include', headers: { Accept: 'application/json' } });
@@ -6,7 +6,7 @@ import*as M from"node:fs";import{cli as I,Strategy as S}from"@jackwener/opencli/
6
6
  var u = j && j.user;
7
7
  return u && u.username ? { ok: true, username: String(u.username) } : { ok: false };
8
8
  } catch (e) { return { drift: true, err: String(e && e.message || e) }; }
9
- })()`;async function W(z,D,{tries:Y=8,label:Z="eval",anchor:$=j}={}){let q;for(let B=0;B<Y;B+=1){let F;try{F=await z.evaluate(D)}catch(G){F={drift:!0,err:String(G&&G.message||G)}}q=F;if(F&&F.drift){await z.goto($);await z.wait(2);continue}return F}throw new V(`Hashnode ${Z}: browser tab kept drifting (last: ${JSON.stringify(q)})`)}I({site:"hashnode",name:"publish",access:"write",description:"Publish a Hashnode post via the web editor (or save a draft with --draft). Markdown body + tags/cover/canonical.",domain:"hashnode.com",strategy:S.COOKIE,browser:!0,defaultWindowMode:"foreground",siteSession:"persistent",args:[{name:"title",type:"string",required:!0,help:"Post title"},{name:"body",type:"string",required:!1,help:"Post body in Markdown (or use --body-file)"},{name:"body-file",type:"string",required:!1,help:"Path to a Markdown file for the body"},{name:"tags",type:"string",required:!1,help:"Comma-separated tag names"},{name:"cover-image",type:"string",required:!1,help:"Cover image URL"},{name:"canonical-url",type:"string",required:!1,help:"Canonical / original article URL"},{name:"draft",type:"boolean",required:!1,default:!1,help:"Save as draft instead of publishing"}],columns:["status","draft_id","url"],func:async(z,D)=>{if(!z)throw new V("Browser session required for hashnode publish");const Y=String(D.title??"").trim();if(!Y)throw new _("hashnode publish: --title is required");const Z=resolveBody(D);if(Z===void 0)throw new _("--body or --body-file is required");const $=resolveTags(D.tags),q=D["canonical-url"]?String(D["canonical-url"]):"",B=D["cover-image"]?String(D["cover-image"]):"";await z.goto(j);const F=await W(z,h,{label:"auth"});if(!F||!F.ok)throw new b("hashnode.com","Not logged in. Run `ppcli hashnode login`.");const G=await W(z,`(async () => {
9
+ })()`;async function l(e,t,{tries:d=8,label:u="eval",anchor:c=v}={}){let f;for(let y=0;y<d;y+=1){let r;try{r=await e.evaluate(t)}catch(i){r={drift:!0,err:String(i&&i.message||i)}}f=r;if(r&&r.drift){await e.goto(c);await e.wait(2);continue}return r}throw new a(`Hashnode ${u}: browser tab kept drifting (last: ${JSON.stringify(f)})`)}O({site:"hashnode",name:"publish",access:"write",description:"Publish a Hashnode post via the web editor (or save a draft with --draft). Markdown body + tags/cover/canonical.",domain:"hashnode.com",strategy:E.COOKIE,browser:!0,defaultWindowMode:"foreground",siteSession:"persistent",args:[{name:"title",type:"string",required:!0,help:"Post title"},{name:"body",type:"string",required:!1,help:"Post body in Markdown (or use --body-file)"},{name:"body-file",type:"string",required:!1,help:"Path to a Markdown file for the body"},{name:"tags",type:"string",required:!1,help:"Comma-separated tag names"},{name:"cover-image",type:"string",required:!1,help:"Cover image URL"},{name:"canonical-url",type:"string",required:!1,help:"Canonical / original article URL"},{name:"draft",type:"boolean",required:!1,default:!1,help:"Save as draft instead of publishing"}],columns:["status","draft_id","url"],func:async(e,t)=>{if(!e)throw new a("Browser session required for hashnode publish");const d=String(t.title??"").trim();if(!d)throw new g("hashnode publish: --title is required");const u=resolveBody(t);if(u===void 0)throw new g("--body or --body-file is required");const c=resolveTags(t.tags),f=t["canonical-url"]?String(t["canonical-url"]):"",y=t["cover-image"]?String(t["cover-image"]):"";await e.goto(v);const r=await l(e,P,{label:"auth"});if(!r||!r.ok)throw new q("hashnode.com","Not logged in. Run `ppcli hashnode login`.");const i=await l(e,`(async () => {
10
10
  if (location.href.indexOf('hashnode.com') < 0) return { drift: true };
11
11
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
12
12
  const w = [...document.querySelectorAll('a,button')].find((e) => (e.innerText || '').trim() === 'Write');
@@ -16,7 +16,7 @@ import*as M from"node:fs";import{cli as I,Strategy as S}from"@jackwener/opencli/
16
16
  while (t < 18000) { await sleep(500); t += 500; if (location.href.indexOf('/draft/') >= 0) break; }
17
17
  const m = location.href.match(/\\/draft\\/([a-z0-9]+)/i);
18
18
  return m ? { ok: true, draftId: m[1], href: location.href } : { ok: false, reason: 'editor did not open (no /draft/ url) — does the account have a publication?' };
19
- })()`,{label:"new-draft"});if(!G||!G.ok)throw new V(`Hashnode could not open the editor: ${G?G.reason:"unknown"}`);const L=G.draftId,Q=`${j}/draft/${L}`;await z.goto(Q);const J=await W(z,`(async () => {
19
+ })()`,{label:"new-draft"});if(!i||!i.ok)throw new a(`Hashnode could not open the editor: ${i?i.reason:"unknown"}`);const w=i.draftId,n=`${v}/draft/${w}`;await e.goto(n);const h=await l(e,`(async () => {
20
20
  if (location.href.indexOf('/draft/') < 0) return { drift: true };
21
21
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
22
22
  let t = 0, title, body;
@@ -27,16 +27,16 @@ import*as M from"node:fs";import{cli as I,Strategy as S}from"@jackwener/opencli/
27
27
  if (!title || !body) return { ok: false, reason: 'editor fields not found' };
28
28
  const setter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, 'value').set;
29
29
  title.focus();
30
- setter.call(title, ${JSON.stringify(Y)});
30
+ setter.call(title, ${JSON.stringify(d)});
31
31
  title.dispatchEvent(new Event('input', { bubbles: true }));
32
32
  title.dispatchEvent(new Event('change', { bubbles: true }));
33
33
  await sleep(500);
34
34
  body.focus();
35
35
  document.execCommand('selectAll', false, null);
36
- document.execCommand('insertText', false, ${JSON.stringify(Z)});
36
+ document.execCommand('insertText', false, ${JSON.stringify(u)});
37
37
  await sleep(1500);
38
38
  return { ok: true, titleVal: title.value, bodyLen: (body.innerText || '').length };
39
- })()`,{label:"fill",anchor:Q});if(!J||!J.ok)throw new V(`Hashnode fill failed: ${J?J.reason:"unknown"}`);if(D.draft)return[{status:"draft",draft_id:L,url:Q}];const A=JSON.stringify($),H=q;await z.goto(Q);const N=await W(z,`(async () => {
39
+ })()`,{label:"fill",anchor:n});if(!h||!h.ok)throw new a(`Hashnode fill failed: ${h?h.reason:"unknown"}`);if(t.draft)return[{status:"draft",draft_id:w,url:n}];const x=JSON.stringify(c),S=f;await e.goto(n);const b=await l(e,`(async () => {
40
40
  if (location.href.indexOf('/draft/') < 0) return { drift: true };
41
41
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
42
42
  let t = 0, tops;
@@ -47,7 +47,7 @@ import*as M from"node:fs";import{cli as I,Strategy as S}from"@jackwener/opencli/
47
47
  tops.forEach((b) => b.removeAttribute('data-pp'));
48
48
  tops[0].setAttribute('data-pp', 'top-publish');
49
49
  return { ok: true };
50
- })()`,{label:"publish-ready",anchor:Q});if(!N||!N.ok)throw new V(`Hashnode publish not ready: ${N?N.reason:"unknown"}`);await z.click('[data-pp="top-publish"]');await z.wait(3);const X=await W(z,`(async () => {
50
+ })()`,{label:"publish-ready",anchor:n});if(!b||!b.ok)throw new a(`Hashnode publish not ready: ${b?b.reason:"unknown"}`);await e.click('[data-pp="top-publish"]');await e.wait(3);const s=await l(e,`(async () => {
51
51
  if (location.href.indexOf('hashnode.com') < 0) return { drift: true };
52
52
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
53
53
  let d = 0, dlg;
@@ -61,13 +61,13 @@ import*as M from"node:fs";import{cli as I,Strategy as S}from"@jackwener/opencli/
61
61
  var pub = [...dlg.querySelectorAll('button')].find((b) => (b.innerText || '').trim() === 'Publish');
62
62
  if (pub) pub.setAttribute('data-pp', 'dlg-publish');
63
63
  return { ok: !!pub, hasDiscovery: !!disc };
64
- })()`,{label:"dialog-ready",anchor:Q});if(!X||!X.ok)throw new V(`Hashnode publish dialog failed: ${X?X.reason:"unknown"}`);if($.length&&X.hasDiscovery)try{await z.click('[data-pp="discovery-tab"]');await z.wait(2);await W(z,`(async () => {
64
+ })()`,{label:"dialog-ready",anchor:n});if(!s||!s.ok)throw new a(`Hashnode publish dialog failed: ${s?s.reason:"unknown"}`);if(c.length&&s.hasDiscovery)try{await e.click('[data-pp="discovery-tab"]');await e.wait(2);await l(e,`(async () => {
65
65
  if (location.href.indexOf('hashnode.com') < 0) return { drift: true };
66
66
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
67
67
  var ti = document.querySelector('input#editor-tags');
68
68
  if (!ti) return { ok: false };
69
69
  var setter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
70
- var tags = ${A};
70
+ var tags = ${x};
71
71
  for (var i = 0; i < tags.length; i++) {
72
72
  ti.focus(); setter.call(ti, tags[i]); ti.dispatchEvent(new Event('input', { bubbles: true }));
73
73
  await sleep(500);
@@ -75,18 +75,18 @@ import*as M from"node:fs";import{cli as I,Strategy as S}from"@jackwener/opencli/
75
75
  await sleep(500);
76
76
  }
77
77
  return { ok: true };
78
- })()`,{label:"tags",anchor:Q})}catch(T){}if(H)try{await W(z,`(async () => {
78
+ })()`,{label:"tags",anchor:n})}catch(m){}if(S)try{await l(e,`(async () => {
79
79
  if (location.href.indexOf('hashnode.com') < 0) return { drift: true };
80
80
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
81
81
  var toggle = [...document.querySelectorAll('label,button')].find((e) => /add a canonical url/i.test(e.innerText || ''));
82
82
  if (toggle && !document.querySelector('input[placeholder="https://example.com/original-article"]')) { toggle.setAttribute('data-pp','canon-toggle'); }
83
83
  return { ok: true };
84
- })()`,{label:"canon-prep",anchor:Q});await z.click('[data-pp="canon-toggle"]').catch(()=>{});await z.wait(1);await z.evaluate(`(() => {
84
+ })()`,{label:"canon-prep",anchor:n});await e.click('[data-pp="canon-toggle"]').catch(()=>{});await e.wait(1);await e.evaluate(`(() => {
85
85
  var ci = document.querySelector('input[placeholder="https://example.com/original-article"]');
86
- if (ci) { var s = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,'value').set; ci.focus(); s.call(ci, ${JSON.stringify(H)}); ci.dispatchEvent(new Event('input',{bubbles:true})); ci.dispatchEvent(new Event('blur',{bubbles:true})); }
86
+ if (ci) { var s = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,'value').set; ci.focus(); s.call(ci, ${JSON.stringify(S)}); ci.dispatchEvent(new Event('input',{bubbles:true})); ci.dispatchEvent(new Event('blur',{bubbles:true})); }
87
87
  return true;
88
- })()`)}catch(T){}await z.evaluate(`(() => {
88
+ })()`)}catch(m){}await e.evaluate(`(() => {
89
89
  var dlg = document.querySelector('[role="dialog"][data-state="open"]') || document.querySelector('[role="dialog"]');
90
90
  if (dlg) { var pub = [...dlg.querySelectorAll('button')].find((b) => (b.innerText||'').trim()==='Publish'); if (pub) pub.setAttribute('data-pp','dlg-publish'); }
91
91
  return true;
92
- })()`);await z.click('[data-pp="dlg-publish"]');let P="";for(let T=0;T<30;T+=1){await z.wait(1);const K=await z.evaluate("(() => location.href)()").catch(()=>"");if(typeof K==="string"&&K.indexOf("/draft/")<0&&K.indexOf("hashnode.com")<0){P=K;break}if(typeof K==="string"&&K.indexOf("/draft/")<0&&K.indexOf("/edit/")<0&&K.indexOf("hashnode.com")>=0){P=K;break}}if(!P)throw new V("Hashnode publish did not navigate to a live article URL (still on /draft or /edit). The post may have been saved but not published.");return[{status:"published",draft_id:L,url:P}]}});
92
+ })()`);await e.click('[data-pp="dlg-publish"]');let p="";for(let m=0;m<30;m+=1){await e.wait(1);const o=await e.evaluate("(() => location.href)()").catch(()=>"");if(typeof o==="string"&&o.indexOf("/draft/")<0&&o.indexOf("hashnode.com")<0){p=o;break}if(typeof o==="string"&&o.indexOf("/draft/")<0&&o.indexOf("/edit/")<0&&o.indexOf("hashnode.com")>=0){p=o;break}}if(!p)throw new a("Hashnode publish did not navigate to a live article URL (still on /draft or /edit). The post may have been saved but not published.");return[{status:"published",draft_id:w,url:p}]}});
package/clis/hf/auth.js CHANGED
@@ -1,4 +1,4 @@
1
- import{AuthRequiredError as G,CommandExecutionError as F}from"@jackwener/opencli/errors";import{registerSiteAuthCommands as K}from"../_shared/site-auth.js";const J=`(async () => {
1
+ import{AuthRequiredError as a,CommandExecutionError as n}from"@jackwener/opencli/errors";import{registerSiteAuthCommands as r}from"../_shared/site-auth.js";const i=`(async () => {
2
2
  try {
3
3
  const r = await fetch('/api/whoami-v2', { credentials: 'include', headers: { Accept: 'application/json' } });
4
4
  if (r.status === 401 || r.status === 403) return { kind: 'auth', detail: 'HF /api/whoami-v2 HTTP ' + r.status };
@@ -9,4 +9,4 @@ import{AuthRequiredError as G,CommandExecutionError as F}from"@jackwener/opencli
9
9
  } catch (e) {
10
10
  return { kind: 'exception', detail: String(e && e.message || e) };
11
11
  }
12
- })()`;async function L(D){await D.goto("https://huggingface.co/");await D.wait(1);const z=await D.evaluate(J);if(z?.kind==="auth")throw new G("huggingface.co",z.detail);if(z?.kind==="http")throw new F(`HTTP ${z.httpStatus} from HF /api/whoami-v2`);if(z?.kind==="exception")throw new F(`HF whoami failed: ${z.detail}`);if(!z?.ok)throw new F(`Unexpected HF probe: ${JSON.stringify(z)}`);return{username:z.username,fullname:z.fullname,type:z.type}}K({site:"hf",domain:"huggingface.co",loginUrl:"https://huggingface.co/login",columns:["username","fullname","type"],verify:L,poll:async(D)=>{const z=await D.evaluate(J);if(!z?.ok)throw new G("huggingface.co","Waiting for Hugging Face login");return{username:z.username,fullname:z.fullname,type:z.type}}});
12
+ })()`;async function o(e){await e.goto("https://huggingface.co/");await e.wait(1);const t=await e.evaluate(i);if(t?.kind==="auth")throw new a("huggingface.co",t.detail);if(t?.kind==="http")throw new n(`HTTP ${t.httpStatus} from HF /api/whoami-v2`);if(t?.kind==="exception")throw new n(`HF whoami failed: ${t.detail}`);if(!t?.ok)throw new n(`Unexpected HF probe: ${JSON.stringify(t)}`);return{username:t.username,fullname:t.fullname,type:t.type}}r({site:"hf",domain:"huggingface.co",loginUrl:"https://huggingface.co/login",columns:["username","fullname","type"],verify:o,poll:async(e)=>{const t=await e.evaluate(i);if(!t?.ok)throw new a("huggingface.co","Waiting for Hugging Face login");return{username:t.username,fullname:t.fullname,type:t.type}}});
package/clis/hf/models.js CHANGED
@@ -1 +1 @@
1
- import{cli as y,Strategy as S}from"@jackwener/opencli/registry";import{ArgumentError as n,CommandExecutionError as l,EmptyResultError as k}from"@jackwener/opencli/errors";const d=["downloads","likes","trending","created_at","last_modified"],b={lastmodified:"last_modified",createdat:"created_at"};y({site:"hf",name:"models",access:"read",description:"Top Hugging Face models (downloads / likes / trending / freshness).",domain:"huggingface.co",strategy:S.PUBLIC,browser:!1,args:[{name:"sort",type:"string",default:"downloads",help:`Sort key: ${d.join(", ")}`},{name:"search",type:"string",required:!1,help:'Optional name/owner substring filter (e.g. "llama", "mistralai/")'},{name:"pipeline",type:"string",required:!1,help:"Filter by pipeline tag (e.g. text-generation, image-classification)"},{name:"limit",type:"int",default:20,help:"Max models (max 100; one API page)."}],columns:["rank","id","author","pipelineTag","downloads","likes","tags","lastModified","url"],func:async(s)=>{const c=String(s.sort??"downloads").toLowerCase(),m=b[c]??c;if(!d.includes(m))throw new n(`hf models sort must be one of ${d.join(", ")}`);const i=Number(s.limit??20);if(!Number.isInteger(i)||i<=0)throw new n("hf models limit must be a positive integer");if(i>100)throw new n("hf models limit must be <= 100");const t=new URL("https://huggingface.co/api/models");t.searchParams.set("sort",m);t.searchParams.set("direction","-1");t.searchParams.set("limit",String(i));t.searchParams.set("full","true");if(s.search)t.searchParams.set("search",String(s.search));if(s.pipeline)t.searchParams.set("pipeline_tag",String(s.pipeline));let r;try{r=await fetch(t,{headers:{Accept:"application/json","User-Agent":"ppcli/1.0 (+https://github.com/jackwener/OpenCLI)"}})}catch(e){throw new l(`hf models request failed: ${e?.message||e}`)}if(!r.ok)throw new l(`hf models failed: HTTP ${r.status}`);let o;try{o=await r.json()}catch(e){throw new l(`hf models returned malformed JSON: ${e?.message||e}`)}const g=Array.isArray(o)?o:[];if(g.length===0)throw new k("hf models","No matching models on huggingface.co.");return g.slice(0,i).map((e,p)=>{const a=e.id||e.modelId||"",h=a.indexOf("/"),f=h>0?a.slice(0,h):"",u=Array.isArray(e.tags)?e.tags.filter((w)=>!w.startsWith("license:")).slice(0,10).join(", "):"";return{rank:p+1,id:a,author:f,pipelineTag:e.pipeline_tag||e.pipelineTag||"",downloads:e.downloads??0,likes:e.likes??0,tags:u,lastModified:e.lastModified?String(e.lastModified).slice(0,10):"",url:a?`https://huggingface.co/${a}`:""}})}});
1
+ import{cli as y,Strategy as S}from"@jackwener/opencli/registry";import{ArgumentError as n,CommandExecutionError as l,EmptyResultError as k}from"@jackwener/opencli/errors";const d=["downloads","likes","trending","created_at","last_modified"],A={lastmodified:"last_modified",createdat:"created_at"};y({site:"hf",name:"models",access:"read",description:"Top Hugging Face models (downloads / likes / trending / freshness).",domain:"huggingface.co",strategy:S.PUBLIC,browser:!1,args:[{name:"sort",type:"string",default:"downloads",help:`Sort key: ${d.join(", ")}`},{name:"search",type:"string",required:!1,help:'Optional name/owner substring filter (e.g. "llama", "mistralai/")'},{name:"pipeline",type:"string",required:!1,help:"Filter by pipeline tag (e.g. text-generation, image-classification)"},{name:"limit",type:"int",default:20,help:"Max models (max 100; one API page)."}],columns:["rank","id","author","pipelineTag","downloads","likes","tags","lastModified","url"],func:async(i)=>{const c=String(i.sort??"downloads").toLowerCase(),m=A[c]??c;if(!d.includes(m))throw new n(`hf models sort must be one of ${d.join(", ")}`);const s=Number(i.limit??20);if(!Number.isInteger(s)||s<=0)throw new n("hf models limit must be a positive integer");if(s>100)throw new n("hf models limit must be <= 100");const t=new URL("https://huggingface.co/api/models");t.searchParams.set("sort",m);t.searchParams.set("direction","-1");t.searchParams.set("limit",String(s));t.searchParams.set("full","true");if(i.search)t.searchParams.set("search",String(i.search));if(i.pipeline)t.searchParams.set("pipeline_tag",String(i.pipeline));let r;try{r=await fetch(t,{headers:{Accept:"application/json","User-Agent":"ppcli/1.0 (+https://github.com/jackwener/OpenCLI)"}})}catch(e){throw new l(`hf models request failed: ${e?.message||e}`)}if(!r.ok)throw new l(`hf models failed: HTTP ${r.status}`);let o;try{o=await r.json()}catch(e){throw new l(`hf models returned malformed JSON: ${e?.message||e}`)}const g=Array.isArray(o)?o:[];if(g.length===0)throw new k("hf models","No matching models on huggingface.co.");return g.slice(0,s).map((e,p)=>{const a=e.id||e.modelId||"",h=a.indexOf("/"),f=h>0?a.slice(0,h):"",u=Array.isArray(e.tags)?e.tags.filter((w)=>!w.startsWith("license:")).slice(0,10).join(", "):"";return{rank:p+1,id:a,author:f,pipelineTag:e.pipeline_tag||e.pipelineTag||"",downloads:e.downloads??0,likes:e.likes??0,tags:u,lastModified:e.lastModified?String(e.lastModified).slice(0,10):"",url:a?`https://huggingface.co/${a}`:""}})}});
package/clis/hf/paper.js CHANGED
@@ -1 +1 @@
1
- import{cli as c,Strategy as h}from"@jackwener/opencli/registry";import{ArgumentError as n,CommandExecutionError as i,EmptyResultError as p}from"@jackwener/opencli/errors";const m=/^\d{4}\.\d{4,5}(?:v\d+)?$/;c({site:"hf",name:"paper",access:"read",description:"Hugging Face paper detail by arXiv id (full title / summary / authors / AI keywords)",domain:"huggingface.co",strategy:h.PUBLIC,browser:!1,args:[{name:"id",positional:!0,required:!0,help:'arXiv id (e.g. "1706.03762") — same value HF uses to mirror the paper'}],columns:["id","title","authors","publishedAt","upvotes","aiKeywords","summary","aiSummary","url"],func:async(o)=>{const a=String(o.id??"").trim();if(!a)throw new n("hf paper id cannot be empty","Example: ppcli hf paper 1706.03762");if(!m.test(a))throw new n(`hf paper id "${o.id}" is not a valid arXiv id`,"Expected the modern arXiv form `YYMM.NNNNN` (optionally with a version suffix like `v3`).");const s=process.env.HF_ENDPOINT?.replace(/\/+$/,"")||"https://huggingface.co",u=`${s}/api/papers/${encodeURIComponent(a)}`;let t;try{t=await fetch(u,{headers:{accept:"application/json"}})}catch(r){throw new i(`hf paper request failed: ${r?.message??r}`)}if(t.status===404)throw new p("hf paper",`Hugging Face has no paper page for "${a}".`);if(t.status===429)throw new i("hf paper returned HTTP 429 (rate limited)","Hugging Face throttles unauthenticated traffic; wait a few seconds and retry.");if(!t.ok)throw new i(`hf paper returned HTTP ${t.status}`);let e;try{e=await t.json()}catch(r){throw new i(`hf paper returned malformed JSON: ${r?.message??r}`)}if(!e||typeof e!=="object"||!e.id)throw new p("hf paper",`Hugging Face returned no paper data for "${a}".`);const d=Array.isArray(e.authors)?e.authors.map((r)=>typeof r==="object"&&r?r.name||r.fullname||"":String(r)).filter(Boolean):[],l=Array.isArray(e.ai_keywords)?e.ai_keywords.join(", "):"";return[{id:String(e.id),title:String(e.title??""),authors:d.join(", "),publishedAt:String(e.publishedAt??"").slice(0,10),upvotes:e.upvotes!=null?Number(e.upvotes):null,aiKeywords:l,summary:String(e.summary??""),aiSummary:String(e.ai_summary??""),url:`${s}/papers/${e.id}`}]}});
1
+ import{cli as m,Strategy as c}from"@jackwener/opencli/registry";import{ArgumentError as n,CommandExecutionError as i,EmptyResultError as p}from"@jackwener/opencli/errors";const h=/^\d{4}\.\d{4,5}(?:v\d+)?$/;m({site:"hf",name:"paper",access:"read",description:"Hugging Face paper detail by arXiv id (full title / summary / authors / AI keywords)",domain:"huggingface.co",strategy:c.PUBLIC,browser:!1,args:[{name:"id",positional:!0,required:!0,help:'arXiv id (e.g. "1706.03762") — same value HF uses to mirror the paper'}],columns:["id","title","authors","publishedAt","upvotes","aiKeywords","summary","aiSummary","url"],func:async(o)=>{const a=String(o.id??"").trim();if(!a)throw new n("hf paper id cannot be empty","Example: ppcli hf paper 1706.03762");if(!h.test(a))throw new n(`hf paper id "${o.id}" is not a valid arXiv id`,"Expected the modern arXiv form `YYMM.NNNNN` (optionally with a version suffix like `v3`).");const s=process.env.HF_ENDPOINT?.replace(/\/+$/,"")||"https://huggingface.co",u=`${s}/api/papers/${encodeURIComponent(a)}`;let t;try{t=await fetch(u,{headers:{accept:"application/json"}})}catch(r){throw new i(`hf paper request failed: ${r?.message??r}`)}if(t.status===404)throw new p("hf paper",`Hugging Face has no paper page for "${a}".`);if(t.status===429)throw new i("hf paper returned HTTP 429 (rate limited)","Hugging Face throttles unauthenticated traffic; wait a few seconds and retry.");if(!t.ok)throw new i(`hf paper returned HTTP ${t.status}`);let e;try{e=await t.json()}catch(r){throw new i(`hf paper returned malformed JSON: ${r?.message??r}`)}if(!e||typeof e!=="object"||!e.id)throw new p("hf paper",`Hugging Face returned no paper data for "${a}".`);const d=Array.isArray(e.authors)?e.authors.map((r)=>typeof r==="object"&&r?r.name||r.fullname||"":String(r)).filter(Boolean):[],l=Array.isArray(e.ai_keywords)?e.ai_keywords.join(", "):"";return[{id:String(e.id),title:String(e.title??""),authors:d.join(", "),publishedAt:String(e.publishedAt??"").slice(0,10),upvotes:e.upvotes!=null?Number(e.upvotes):null,aiKeywords:l,summary:String(e.summary??""),aiSummary:String(e.ai_summary??""),url:`${s}/papers/${e.id}`}]}});
package/clis/hf/spaces.js CHANGED
@@ -1 +1 @@
1
- import{cli as S,Strategy as y}from"@jackwener/opencli/registry";import{ArgumentError as o,CommandExecutionError as n,EmptyResultError as b}from"@jackwener/opencli/errors";const d=["likes","created_at","last_modified"],P={lastmodified:"last_modified",createdat:"created_at"};S({site:"hf",name:"spaces",access:"read",description:"Top Hugging Face Spaces (likes / created_at / last_modified).",domain:"huggingface.co",strategy:y.PUBLIC,browser:!1,args:[{name:"sort",type:"string",default:"likes",help:`Sort key: ${d.join(", ")}`},{name:"search",type:"string",required:!1,help:'Optional name/owner substring filter (e.g. "stability", "openai/")'},{name:"sdk",type:"string",required:!1,help:"Filter by Space SDK: gradio / streamlit / docker / static"},{name:"limit",type:"int",default:20,help:"Max spaces (max 100; one API page)."}],columns:["rank","id","author","sdk","likes","tags","lastModified","url"],func:async(s)=>{const h=String(s.sort??"likes").toLowerCase(),f=P[h]??h;if(!d.includes(f))throw new o(`hf spaces sort must be one of ${d.join(", ")}`);const a=Number(s.limit??20);if(!Number.isInteger(a)||a<=0)throw new o("hf spaces limit must be a positive integer");if(a>100)throw new o("hf spaces limit must be <= 100");const c=s.sdk==null?"":String(s.sdk).trim().toLowerCase();if(!new Set(["","gradio","streamlit","docker","static"]).has(c))throw new o("hf spaces sdk must be one of gradio / streamlit / docker / static");const t=new URL("https://huggingface.co/api/spaces");t.searchParams.set("sort",f);t.searchParams.set("direction","-1");t.searchParams.set("limit",String(a));t.searchParams.set("full","true");if(s.search)t.searchParams.set("search",String(s.search));if(c)t.searchParams.set("sdk",c);let r;try{r=await fetch(t,{headers:{Accept:"application/json","User-Agent":"ppcli/1.0 (+https://github.com/jackwener/OpenCLI)"}})}catch(e){throw new n(`hf spaces request failed: ${e?.message??e}`)}if(r.status===429)throw new n("hf spaces returned HTTP 429 (rate limited)","Hugging Face throttles unauthenticated traffic; wait a few seconds and retry.");if(!r.ok)throw new n(`hf spaces failed: HTTP ${r.status}`);let l;try{l=await r.json()}catch(e){throw new n(`hf spaces returned malformed JSON: ${e?.message??e}`)}const m=Array.isArray(l)?l:[];if(!m.length)throw new b("hf spaces","No matching spaces on huggingface.co.");return m.slice(0,a).map((e,p)=>{const i=String(e.id??e._id??""),g=i.indexOf("/"),u=String(e.author??(g>0?i.slice(0,g):"")),w=Array.isArray(e.tags)?e.tags.filter((k)=>!String(k).startsWith("license:")).slice(0,10).join(", "):"";return{rank:p+1,id:i,author:u,sdk:String(e.sdk??""),likes:e.likes!=null?Number(e.likes):null,tags:w,lastModified:String(e.lastModified??"").slice(0,10),url:i?`https://huggingface.co/spaces/${i}`:""}})}});
1
+ import{cli as S,Strategy as y}from"@jackwener/opencli/registry";import{ArgumentError as n,CommandExecutionError as o,EmptyResultError as b}from"@jackwener/opencli/errors";const d=["likes","created_at","last_modified"],P={lastmodified:"last_modified",createdat:"created_at"};S({site:"hf",name:"spaces",access:"read",description:"Top Hugging Face Spaces (likes / created_at / last_modified).",domain:"huggingface.co",strategy:y.PUBLIC,browser:!1,args:[{name:"sort",type:"string",default:"likes",help:`Sort key: ${d.join(", ")}`},{name:"search",type:"string",required:!1,help:'Optional name/owner substring filter (e.g. "stability", "openai/")'},{name:"sdk",type:"string",required:!1,help:"Filter by Space SDK: gradio / streamlit / docker / static"},{name:"limit",type:"int",default:20,help:"Max spaces (max 100; one API page)."}],columns:["rank","id","author","sdk","likes","tags","lastModified","url"],func:async(s)=>{const h=String(s.sort??"likes").toLowerCase(),m=P[h]??h;if(!d.includes(m))throw new n(`hf spaces sort must be one of ${d.join(", ")}`);const a=Number(s.limit??20);if(!Number.isInteger(a)||a<=0)throw new n("hf spaces limit must be a positive integer");if(a>100)throw new n("hf spaces limit must be <= 100");const c=s.sdk==null?"":String(s.sdk).trim().toLowerCase();if(!new Set(["","gradio","streamlit","docker","static"]).has(c))throw new n("hf spaces sdk must be one of gradio / streamlit / docker / static");const t=new URL("https://huggingface.co/api/spaces");t.searchParams.set("sort",m);t.searchParams.set("direction","-1");t.searchParams.set("limit",String(a));t.searchParams.set("full","true");if(s.search)t.searchParams.set("search",String(s.search));if(c)t.searchParams.set("sdk",c);let r;try{r=await fetch(t,{headers:{Accept:"application/json","User-Agent":"ppcli/1.0 (+https://github.com/jackwener/OpenCLI)"}})}catch(e){throw new o(`hf spaces request failed: ${e?.message??e}`)}if(r.status===429)throw new o("hf spaces returned HTTP 429 (rate limited)","Hugging Face throttles unauthenticated traffic; wait a few seconds and retry.");if(!r.ok)throw new o(`hf spaces failed: HTTP ${r.status}`);let l;try{l=await r.json()}catch(e){throw new o(`hf spaces returned malformed JSON: ${e?.message??e}`)}const f=Array.isArray(l)?l:[];if(!f.length)throw new b("hf spaces","No matching spaces on huggingface.co.");return f.slice(0,a).map((e,p)=>{const i=String(e.id??e._id??""),g=i.indexOf("/"),u=String(e.author??(g>0?i.slice(0,g):"")),w=Array.isArray(e.tags)?e.tags.filter((k)=>!String(k).startsWith("license:")).slice(0,10).join(", "):"";return{rank:p+1,id:i,author:u,sdk:String(e.sdk??""),likes:e.likes!=null?Number(e.likes):null,tags:w,lastModified:String(e.lastModified??"").slice(0,10),url:i?`https://huggingface.co/spaces/${i}`:""}})}});
package/clis/hf/top.js CHANGED
@@ -1 +1 @@
1
- import{cli as A,Strategy as _}from"@jackwener/opencli/registry";import{CliError as l}from"@jackwener/opencli/errors";function R(t,e=60){return t.length>e?t.slice(0,e-3)+"...":t}function w(t,e=3){const a=t.map((n)=>n.name);if(a.length<=e)return a.join(", ");return a.slice(0,e).join(", ")+" et al."}const c=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function F(){const t=new Date;return`${c[t.getUTCMonth()]} ${t.getUTCFullYear()}`}function I(){const t=new Date,e=t.getUTCDay(),a=e===6?0:6-e,n=new Date(t);n.setUTCDate(t.getUTCDate()+a);const d=new Date(n);d.setUTCDate(n.getUTCDate()-6);const r=c[d.getUTCMonth()],u=c[n.getUTCMonth()],m=d.getUTCDate(),h=n.getUTCDate();return r===u?`${r} ${m}-${h}`:`${r} ${m}-${u} ${h}`}A({site:"hf",name:"top",access:"read",description:"Top upvoted Hugging Face papers",domain:"huggingface.co",strategy:_.PUBLIC,browser:!1,args:[{name:"limit",type:"int",default:20,help:"Number of papers"},{name:"all",type:"bool",default:!1,help:"Return all papers (ignore limit)"},{name:"date",type:"str",required:!1,help:"Date (YYYY-MM-DD), defaults to most recent"},{name:"period",type:"str",default:"daily",choices:["daily","weekly","monthly"],help:"Time period: daily, weekly, or monthly"}],columns:["rank","id","title","upvotes","authors"],footerExtra:(t)=>{if(t._footerDate)return t._footerDate;if(t.period==="monthly")return F();if(t.period==="weekly")return I();return t.date??new Date().toISOString().slice(0,10)},func:async(t)=>{const e=String(t.period??"daily"),a=Boolean(t.all),n=process.env.HF_ENDPOINT?.replace(/\/+$/,"")||"https://huggingface.co";if(e==="weekly"||e==="monthly"){if(t.date)throw new l("INVALID_ARG",`--date is not supported for ${e} period`,`Omit --date when using --period ${e}`);const s=`${n}/api/papers?period=${e}`,i=await fetch(s);if(!i.ok)throw new l("FETCH_ERROR",`HF API error: ${i.status} ${i.statusText}`,"Check HF_ENDPOINT or try again later");const D=await i.json();if(!Array.isArray(D))throw new l("FETCH_ERROR","Unexpected HF API response","Check endpoint");const $=D,f=$.map((o)=>o.publishedAt).filter(Boolean).sort();if(f.length>0)if(e==="monthly"){const o=new Date(f[0]);t._footerDate=`${c[o.getUTCMonth()]} ${o.getUTCFullYear()}`}else{const o=new Date(f[0]),p=new Date(f[f.length-1]),y=c[o.getUTCMonth()],g=c[p.getUTCMonth()],C=o.getUTCDate(),U=p.getUTCDate();t._footerDate=y===g?`${y} ${C}-${U}`:`${y} ${C}-${g} ${U}`}const T=[...$].sort((o,p)=>(p.upvotes??0)-(o.upvotes??0));return(a?T:T.slice(0,Number(t.limit))).map((o,p)=>({rank:p+1,id:o.id??"",title:R(o.title??""),upvotes:o.upvotes??0,authors:w(o.authors??[])}))}if(t.date&&!/^\d{4}-\d{2}-\d{2}$/.test(String(t.date)))throw new l("INVALID_ARG",`Invalid date format: ${t.date}`,"Use YYYY-MM-DD");const d=t.date?`${n}/api/daily_papers?date=${t.date}`:`${n}/api/daily_papers`,r=await fetch(d);if(!r.ok)throw new l("FETCH_ERROR",`HF API error: ${r.status} ${r.statusText}`,"Check HF_ENDPOINT or try again later");const u=await r.json();if(!Array.isArray(u))throw new l("FETCH_ERROR","Unexpected HF API response","Check date format or endpoint");const h=[...u].sort((s,i)=>(i.paper?.upvotes??0)-(s.paper?.upvotes??0));return(a?h:h.slice(0,Number(t.limit))).map((s,i)=>({rank:i+1,id:s.paper?.id??"",title:R(s.title??""),upvotes:s.paper?.upvotes??0,authors:w(s.paper?.authors??[])}))}});
1
+ import{cli as _,Strategy as F}from"@jackwener/opencli/registry";import{CliError as l}from"@jackwener/opencli/errors";function w(t,e=60){return t.length>e?t.slice(0,e-3)+"...":t}function A(t,e=3){const a=t.map((n)=>n.name);if(a.length<=e)return a.join(", ");return a.slice(0,e).join(", ")+" et al."}const c=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function I(){const t=new Date;return`${c[t.getUTCMonth()]} ${t.getUTCFullYear()}`}function M(){const t=new Date,e=t.getUTCDay(),a=e===6?0:6-e,n=new Date(t);n.setUTCDate(t.getUTCDate()+a);const d=new Date(n);d.setUTCDate(n.getUTCDate()-6);const r=c[d.getUTCMonth()],u=c[n.getUTCMonth()],m=d.getUTCDate(),h=n.getUTCDate();return r===u?`${r} ${m}-${h}`:`${r} ${m}-${u} ${h}`}_({site:"hf",name:"top",access:"read",description:"Top upvoted Hugging Face papers",domain:"huggingface.co",strategy:F.PUBLIC,browser:!1,args:[{name:"limit",type:"int",default:20,help:"Number of papers"},{name:"all",type:"bool",default:!1,help:"Return all papers (ignore limit)"},{name:"date",type:"str",required:!1,help:"Date (YYYY-MM-DD), defaults to most recent"},{name:"period",type:"str",default:"daily",choices:["daily","weekly","monthly"],help:"Time period: daily, weekly, or monthly"}],columns:["rank","id","title","upvotes","authors"],footerExtra:(t)=>{if(t._footerDate)return t._footerDate;if(t.period==="monthly")return I();if(t.period==="weekly")return M();return t.date??new Date().toISOString().slice(0,10)},func:async(t)=>{const e=String(t.period??"daily"),a=Boolean(t.all),n=process.env.HF_ENDPOINT?.replace(/\/+$/,"")||"https://huggingface.co";if(e==="weekly"||e==="monthly"){if(t.date)throw new l("INVALID_ARG",`--date is not supported for ${e} period`,`Omit --date when using --period ${e}`);const s=`${n}/api/papers?period=${e}`,i=await fetch(s);if(!i.ok)throw new l("FETCH_ERROR",`HF API error: ${i.status} ${i.statusText}`,"Check HF_ENDPOINT or try again later");const D=await i.json();if(!Array.isArray(D))throw new l("FETCH_ERROR","Unexpected HF API response","Check endpoint");const T=D,f=T.map((o)=>o.publishedAt).filter(Boolean).sort();if(f.length>0)if(e==="monthly"){const o=new Date(f[0]);t._footerDate=`${c[o.getUTCMonth()]} ${o.getUTCFullYear()}`}else{const o=new Date(f[0]),p=new Date(f[f.length-1]),y=c[o.getUTCMonth()],C=c[p.getUTCMonth()],U=o.getUTCDate(),R=p.getUTCDate();t._footerDate=y===C?`${y} ${U}-${R}`:`${y} ${U}-${C} ${R}`}const g=[...T].sort((o,p)=>(p.upvotes??0)-(o.upvotes??0));return(a?g:g.slice(0,Number(t.limit))).map((o,p)=>({rank:p+1,id:o.id??"",title:w(o.title??""),upvotes:o.upvotes??0,authors:A(o.authors??[])}))}if(t.date&&!/^\d{4}-\d{2}-\d{2}$/.test(String(t.date)))throw new l("INVALID_ARG",`Invalid date format: ${t.date}`,"Use YYYY-MM-DD");const d=t.date?`${n}/api/daily_papers?date=${t.date}`:`${n}/api/daily_papers`,r=await fetch(d);if(!r.ok)throw new l("FETCH_ERROR",`HF API error: ${r.status} ${r.statusText}`,"Check HF_ENDPOINT or try again later");const u=await r.json();if(!Array.isArray(u))throw new l("FETCH_ERROR","Unexpected HF API response","Check date format or endpoint");const h=[...u].sort((s,i)=>(i.paper?.upvotes??0)-(s.paper?.upvotes??0));return(a?h:h.slice(0,Number(t.limit))).map((s,i)=>({rank:i+1,id:s.paper?.id??"",title:w(s.title??""),upvotes:s.paper?.upvotes??0,authors:A(s.paper?.authors??[])}))}});
@@ -1 +1 @@
1
- import{cli as n,Strategy as s}from"@jackwener/opencli/registry";import{BREW_BASE as i,brewFetch as d,requireToken as m}from"./utils.js";n({site:"homebrew",name:"cask",access:"read",description:"Fetch a Homebrew cask's metadata (version, homepage, deprecation, download URL)",domain:"formulae.brew.sh",strategy:s.PUBLIC,browser:!1,args:[{name:"token",positional:!0,required:!0,help:'Cask token (e.g. "firefox", "visual-studio-code", "google-chrome")'}],columns:["cask","tap","name","version","description","homepage","deprecated","disabled","download","url"],func:async(a)=>{const o=m(a.token,"token"),r=`${i}/cask/${encodeURIComponent(o)}.json`,e=await d(r,"homebrew cask"),t=Array.isArray(e?.name)?e.name.filter(Boolean).join(", "):String(e?.name??"").trim();return[{cask:String(e?.token??o).trim(),tap:String(e?.tap??"").trim(),name:t,version:String(e?.version??"").trim(),description:String(e?.desc??"").trim(),homepage:String(e?.homepage??"").trim(),deprecated:Boolean(e?.deprecated),disabled:Boolean(e?.disabled),download:String(e?.url??"").trim(),url:`https://formulae.brew.sh/cask/${encodeURIComponent(o)}`}]}});
1
+ import{cli as n,Strategy as i}from"@jackwener/opencli/registry";import{BREW_BASE as s,brewFetch as d,requireToken as m}from"./utils.js";n({site:"homebrew",name:"cask",access:"read",description:"Fetch a Homebrew cask's metadata (version, homepage, deprecation, download URL)",domain:"formulae.brew.sh",strategy:i.PUBLIC,browser:!1,args:[{name:"token",positional:!0,required:!0,help:'Cask token (e.g. "firefox", "visual-studio-code", "google-chrome")'}],columns:["cask","tap","name","version","description","homepage","deprecated","disabled","download","url"],func:async(r)=>{const o=m(r.token,"token"),t=`${s}/cask/${encodeURIComponent(o)}.json`,e=await d(t,"homebrew cask"),a=Array.isArray(e?.name)?e.name.filter(Boolean).join(", "):String(e?.name??"").trim();return[{cask:String(e?.token??o).trim(),tap:String(e?.tap??"").trim(),name:a,version:String(e?.version??"").trim(),description:String(e?.desc??"").trim(),homepage:String(e?.homepage??"").trim(),deprecated:Boolean(e?.deprecated),disabled:Boolean(e?.disabled),download:String(e?.url??"").trim(),url:`https://formulae.brew.sh/cask/${encodeURIComponent(o)}`}]}});
@@ -1 +1 @@
1
- import{cli as s,Strategy as i}from"@jackwener/opencli/registry";import{BREW_BASE as m,brewFetch as l,requireToken as c}from"./utils.js";s({site:"homebrew",name:"formula",access:"read",description:"Fetch a Homebrew formula's metadata (version, license, deps, deprecation, source)",domain:"formulae.brew.sh",strategy:i.PUBLIC,browser:!1,args:[{name:"name",positional:!0,required:!0,help:'Formula name (e.g. "wget", "gcc@13", "imagemagick")'}],columns:["formula","tap","version","license","description","homepage","dependencies","deprecated","disabled","source","url"],func:async(a)=>{const r=c(a.name,"formula"),o=`${m}/formula/${encodeURIComponent(r)}.json`,e=await l(o,"homebrew formula"),n=Array.isArray(e?.dependencies)?e.dependencies.filter(Boolean):[],t=String(e?.urls?.stable?.url??"").trim();return[{formula:String(e?.name??r).trim(),tap:String(e?.tap??"").trim(),version:String(e?.versions?.stable??"").trim(),license:String(e?.license??"").trim(),description:String(e?.desc??"").trim(),homepage:String(e?.homepage??"").trim(),dependencies:n.join(", "),deprecated:Boolean(e?.deprecated),disabled:Boolean(e?.disabled),source:t,url:`https://formulae.brew.sh/formula/${encodeURIComponent(r)}`}]}});
1
+ import{cli as i,Strategy as s}from"@jackwener/opencli/registry";import{BREW_BASE as m,brewFetch as c,requireToken as l}from"./utils.js";i({site:"homebrew",name:"formula",access:"read",description:"Fetch a Homebrew formula's metadata (version, license, deps, deprecation, source)",domain:"formulae.brew.sh",strategy:s.PUBLIC,browser:!1,args:[{name:"name",positional:!0,required:!0,help:'Formula name (e.g. "wget", "gcc@13", "imagemagick")'}],columns:["formula","tap","version","license","description","homepage","dependencies","deprecated","disabled","source","url"],func:async(o)=>{const r=l(o.name,"formula"),n=`${m}/formula/${encodeURIComponent(r)}.json`,e=await c(n,"homebrew formula"),a=Array.isArray(e?.dependencies)?e.dependencies.filter(Boolean):[],t=String(e?.urls?.stable?.url??"").trim();return[{formula:String(e?.name??r).trim(),tap:String(e?.tap??"").trim(),version:String(e?.versions?.stable??"").trim(),license:String(e?.license??"").trim(),description:String(e?.desc??"").trim(),homepage:String(e?.homepage??"").trim(),dependencies:a.join(", "),deprecated:Boolean(e?.deprecated),disabled:Boolean(e?.disabled),source:t,url:`https://formulae.brew.sh/formula/${encodeURIComponent(r)}`}]}});
@@ -1 +1 @@
1
- import{cli as w,Strategy as h}from"@jackwener/opencli/registry";import{EmptyResultError as b}from"@jackwener/opencli/errors";import{BREW_BASE as y,brewFetch as f,parseInstallCount as k,requireBoundedInt as g,requireOneOf as l}from"./utils.js";const i=["formula","cask"],m=["30d","90d","365d"];w({site:"homebrew",name:"popular",access:"read",description:"List most-installed Homebrew formulae or casks (Homebrew's analytics ranking)",domain:"formulae.brew.sh",strategy:h.PUBLIC,browser:!1,args:[{name:"type",default:"formula",help:`Package type (${i.join(" / ")})`},{name:"window",default:"30d",help:`Time window (${m.join(" / ")})`},{name:"limit",type:"int",default:30,help:"Max rows (1-500)"}],columns:["rank","token","type","installs","percent","window","url"],func:async(n)=>{const t=l(n.type,i,"type"),s=l(n.window,m,"window"),c=g(n.limit,30,500),u=`${y}/analytics/${t==="cask"?"cask-install":"install"}/${s}.json`,o=await f(u,"homebrew popular"),r=Array.isArray(o?.items)?o.items:[];if(!r.length)throw new b("homebrew popular",`Homebrew analytics returned no items for ${t}/${s}.`);return r.slice(0,c).map((e,p)=>{const a=String(t==="cask"?e.cask:e.formula??"").trim(),d=t==="cask"?"cask":"formula";return{rank:e.number!=null?Number(e.number):p+1,token:a,type:t,installs:k(e.count),percent:e.percent!=null?Number(e.percent):null,window:s,url:a?`https://formulae.brew.sh/${d}/${encodeURIComponent(a)}`:""}})}});
1
+ import{cli as w,Strategy as f}from"@jackwener/opencli/registry";import{EmptyResultError as y}from"@jackwener/opencli/errors";import{BREW_BASE as b,brewFetch as h,parseInstallCount as k,requireBoundedInt as g,requireOneOf as l}from"./utils.js";const i=["formula","cask"],m=["30d","90d","365d"];w({site:"homebrew",name:"popular",access:"read",description:"List most-installed Homebrew formulae or casks (Homebrew's analytics ranking)",domain:"formulae.brew.sh",strategy:f.PUBLIC,browser:!1,args:[{name:"type",default:"formula",help:`Package type (${i.join(" / ")})`},{name:"window",default:"30d",help:`Time window (${m.join(" / ")})`},{name:"limit",type:"int",default:30,help:"Max rows (1-500)"}],columns:["rank","token","type","installs","percent","window","url"],func:async(n)=>{const t=l(n.type,i,"type"),r=l(n.window,m,"window"),c=g(n.limit,30,500),u=`${b}/analytics/${t==="cask"?"cask-install":"install"}/${r}.json`,o=await h(u,"homebrew popular"),s=Array.isArray(o?.items)?o.items:[];if(!s.length)throw new y("homebrew popular",`Homebrew analytics returned no items for ${t}/${r}.`);return s.slice(0,c).map((e,p)=>{const a=String(t==="cask"?e.cask:e.formula??"").trim(),d=t==="cask"?"cask":"formula";return{rank:e.number!=null?Number(e.number):p+1,token:a,type:t,installs:k(e.count),percent:e.percent!=null?Number(e.percent):null,window:r,url:a?`https://formulae.brew.sh/${d}/${encodeURIComponent(a)}`:""}})}});
@@ -1 +1 @@
1
- import{ArgumentError as G,CommandExecutionError as J,EmptyResultError as L}from"@jackwener/opencli/errors";export const BREW_BASE="https://formulae.brew.sh/api";const M="opencli-homebrew-adapter (+https://github.com/jackwener/OpenCLI)",P=/^[A-Za-z0-9][A-Za-z0-9._+@-]*$/;export function requireString(B,z){const q=String(B??"").trim();if(!q)throw new G(`homebrew ${z} cannot be empty`);return q}export function requireBoundedInt(B,z,q,D="limit"){const F=B??z,I=typeof F==="number"?F:Number(F);if(!Number.isInteger(I)||I<=0)throw new G(`homebrew ${D} must be a positive integer`);if(I>q)throw new G(`homebrew ${D} must be <= ${q}`);return I}export function requireToken(B,z){const q=String(B??"").trim();if(!q)throw new G(`homebrew ${z} is required (e.g. "wget", "gcc@13", "firefox")`);if(q.length>100||!P.test(q))throw new G(`homebrew ${z} "${B}" is not a valid token`,'Use letters / digits / "_-.+@", starting with a letter or digit (max 100 chars).');return q}export function requireOneOf(B,z,q){const D=String(B??"").trim().toLowerCase();if(!D)throw new G(`homebrew ${q} is required`);if(!z.includes(D))throw new G(`homebrew ${q} "${B}" is not supported`,`Allowed: ${z.join(", ")}.`);return D}export async function brewFetch(B,z){let q;try{q=await fetch(B,{headers:{"user-agent":M,accept:"application/json"}})}catch(F){throw new J(`${z} request failed: ${F?.message??F}`,"Check that formulae.brew.sh is reachable from this network.")}if(q.status===404)throw new L(z,`Homebrew API returned 404 for ${B}.`);if(q.status===429)throw new J(`${z} returned HTTP 429 (rate limited)`,"Homebrew throttles bursts; wait a few seconds and retry.");if(!q.ok)throw new J(`${z} returned HTTP ${q.status}`);let D;try{D=await q.json()}catch(F){throw new J(`${z} returned malformed JSON: ${F?.message??F}`)}return D}export function parseInstallCount(B){if(B==null)return null;const z=String(B).replace(/,/g,"").trim();if(!z)return null;const q=Number(z);return Number.isFinite(q)?q:null}
1
+ import{ArgumentError as i,CommandExecutionError as w,EmptyResultError as u}from"@jackwener/opencli/errors";export const BREW_BASE="https://formulae.brew.sh/api";const c="opencli-homebrew-adapter (+https://github.com/jackwener/OpenCLI)",h=/^[A-Za-z0-9][A-Za-z0-9._+@-]*$/;export function requireString(t,r){const e=String(t??"").trim();if(!e)throw new i(`homebrew ${r} cannot be empty`);return e}export function requireBoundedInt(t,r,e,n="limit"){const o=t??r,s=typeof o==="number"?o:Number(o);if(!Number.isInteger(s)||s<=0)throw new i(`homebrew ${n} must be a positive integer`);if(s>e)throw new i(`homebrew ${n} must be <= ${e}`);return s}export function requireToken(t,r){const e=String(t??"").trim();if(!e)throw new i(`homebrew ${r} is required (e.g. "wget", "gcc@13", "firefox")`);if(e.length>100||!h.test(e))throw new i(`homebrew ${r} "${t}" is not a valid token`,'Use letters / digits / "_-.+@", starting with a letter or digit (max 100 chars).');return e}export function requireOneOf(t,r,e){const n=String(t??"").trim().toLowerCase();if(!n)throw new i(`homebrew ${e} is required`);if(!r.includes(n))throw new i(`homebrew ${e} "${t}" is not supported`,`Allowed: ${r.join(", ")}.`);return n}export async function brewFetch(t,r){let e;try{e=await fetch(t,{headers:{"user-agent":c,accept:"application/json"}})}catch(o){throw new w(`${r} request failed: ${o?.message??o}`,"Check that formulae.brew.sh is reachable from this network.")}if(e.status===404)throw new u(r,`Homebrew API returned 404 for ${t}.`);if(e.status===429)throw new w(`${r} returned HTTP 429 (rate limited)`,"Homebrew throttles bursts; wait a few seconds and retry.");if(!e.ok)throw new w(`${r} returned HTTP ${e.status}`);let n;try{n=await e.json()}catch(o){throw new w(`${r} returned malformed JSON: ${o?.message??o}`)}return n}export function parseInstallCount(t){if(t==null)return null;const r=String(t).replace(/,/g,"").trim();if(!r)return null;const e=Number(r);return Number.isFinite(e)?e:null}
@@ -1 +1 @@
1
- import{cli as Y,Strategy as v}from"@jackwener/opencli/registry";import{ArgumentError as _,CommandExecutionError as L,EmptyResultError as f}from"@jackwener/opencli/errors";const h="https://www.huodongxing.com/events",b=50;export const EVENTS_COLUMNS=["rank","id","title","time","eventType","city","location","organizer","url"];function X(K){return String(K??"").replace(/\s+/g," ").trim()}export function requireLimit(K){const G=K??20,J=typeof G==="number"?G:Number(String(G).trim());if(!Number.isInteger(J)||J<=0)throw new _("huodongxing limit must be a positive integer");if(J>b)throw new _(`huodongxing limit must be <= ${b}`);return J}function P(K,G,J){const W=X(J);if(W)K.set(G,W)}function M(K,G,J){return Math.floor(Date.UTC(K,G-1,J)/86400000)}function C(K){const G=X(K).match(/^(\d{4})-(\d{2})-(\d{2})$/);if(!G)return null;const J=Number(G[1]),W=Number(G[2]),F=Number(G[3]),$=new Date(Date.UTC(J,W-1,F));if($.getUTCFullYear()!==J||$.getUTCMonth()!==W-1||$.getUTCDate()!==F)return null;return M(J,W,F)}function D(K,G){const J=X(K);if(!J)return"";if(C(J)==null)throw new _(`huodongxing ${G} must be a valid YYYY-MM-DD date`);return J}function A(K={}){const G=D(K.date,"date"),J=D(K.dateTo,"dateTo");if(G&&J&&C(G)>C(J))throw new _("huodongxing date must be <= dateTo");return{date:G,dateTo:J}}function w(K){if(K&&!Array.isArray(K)&&typeof K==="object"&&"session"in K&&"data"in K)return K.data;return K}function T(K){return M(K.getFullYear(),K.getMonth()+1,K.getDate())}function q(K,G){const J=X(K).match(/(\d{1,2})\/(\d{1,2})/);if(!J)return null;return{month:Number(J[1]),day:Number(J[2]),ordinal:M(G,Number(J[1]),Number(J[2]))}}function E(K,G={}){const J=X(K);if(!J)return null;const W=C(G.date),F=C(G.dateTo)??W,$=G.referenceDate instanceof Date?G.referenceDate:new Date,B=T($);if(/今天/.test(J))return{start:B,end:B};if(/明天/.test(J))return{start:B+1,end:B+1};if(/后天/.test(J))return{start:B+2,end:B+2};const z=G.year??(X(G.date).match(/^(\d{4})-/)?.[1]?Number(X(G.date).slice(0,4)):$.getFullYear()),Z=Array.from(J.matchAll(/(\d{1,2}\/\d{1,2})/g)).map((Q)=>Q[1]);if(Z.length===0)return null;const V=q(Z[0],z);if(!V)return null;if(Z.length===1)return{start:V.ordinal,end:V.ordinal};const N=q(Z[1],z)?.month<V.month?z+1:z,U=q(Z[1],N);if(!U)return{start:V.ordinal,end:V.ordinal};if(W!=null&&U.ordinal<W&&V.month>=10){const Q=q(Z[0],z+1),j=q(Z[1],z+1)?.month<Q.month?z+2:z+1,H=q(Z[1],j);if(Q&&H)return{start:Q.ordinal,end:H.ordinal}}return{start:V.ordinal,end:U.ordinal}}export function filterRowsByDateRange(K,G={}){A(G);const J=C(G.date),W=C(G.dateTo)??J;if(J==null&&W==null)return K;const F=J??W,$=W??J;return K.filter((z)=>{const Z=E(z.time,G);if(!Z)return!0;return Z.start<=$&&Z.end>=F}).map((z,Z)=>({...z,rank:Z+1}))}export function buildEventsUrl(K={}){const G=A(K),J=new URLSearchParams;J.set("orderby","o");J.set("d","ts");P(J,"date",G.date);P(J,"dateTo",G.dateTo);P(J,"tag",K.tag);P(J,"city",K.city);const W=X(K.eventType);if(W){if(W!=="1"&&W!=="2")throw new _("huodongxing eventType must be 1 (offline) or 2 (online)");J.set("eventType",W)}P(J,"qs",K.qs);return`${h}?${J.toString()}`}export function extractEventRowsPayload(K=20){const G=50,J=K??20,W=typeof J==="number"?J:Number(String(J).trim());if(!Number.isInteger(W)||W<=0||W>G)return{ok:!1,code:"INVALID_LIMIT",message:`huodongxing limit must be a positive integer <= ${G}`};const F=(Q)=>String(Q??"").replace(/\s+/g," ").trim(),$=(Q,j)=>F(Q.querySelector(j)?.textContent??""),B=(Q)=>{const j=String(Q??"").match(/\/event\/(\d+)/);return j?j[1]:""},z=(Q)=>`https://www.huodongxing.com/event/${Q}`,Z=(Q,j)=>{if(Q.querySelector(".item-live-icon"))return"online";if(Q.querySelector(".item-dress-icon"))return"offline";if(/线上|在线|直播/.test(j))return"online";return""},V=Array.from(document.querySelectorAll(".search-tab-content-item-mesh")),N=[],U=new Set;for(const Q of V){if(N.length>=W)break;const j=Q.querySelector('a.item-title[href*="/event/"], a[href*="/event/"]'),H=B(j?.getAttribute("href")??"");if(!H||U.has(H))continue;const O=F($(Q,"a.item-title span")||$(Q,"a.item-title")||Q.querySelector("img.item-logo")?.getAttribute("alt")||"");if(!O)continue;const S=$(Q,".item-dress p"),I=$(Q,".item-dress-pp"),k=F($(Q,".item-bottom-left .user-name")||Q.querySelector(".item-bottom-left img[title]")?.getAttribute("title")||Q.querySelector(".item-bottom-left img[alt]")?.getAttribute("alt")||"");U.add(H);N.push({rank:N.length+1,id:H,title:O,time:S,eventType:Z(Q,I),city:I,location:I,organizer:k,url:z(H)})}if(N.length===0){const Q=F(document.body?.textContent??"");if(/操作过于频繁|too\s+frequent|rate\s*limit/i.test(Q))return{ok:!1,code:"RATE_LIMIT",message:"huodongxing events was rate limited by www.huodongxing.com",hint:"Wait a few minutes and retry from a real browser session."};if(V.length>0)return{ok:!1,code:"MALFORMED_RESULT",message:"huodongxing events cards were found but no stable event rows could be extracted",hint:"Huodongxing card markup changed: expected event links with /event/<id> and non-empty titles."};return{ok:!1,code:"EMPTY_RESULT",message:"huodongxing events returned no data",hint:"No Huodongxing event cards were found. The page may be empty or the DOM structure may have changed."}}return{ok:!0,rows:N}}function R(K){const G=w(K);if(G?.ok===!0&&Array.isArray(G.rows))return G.rows;if(G?.ok===!0)throw new L("huodongxing events returned malformed extraction rows","Expected browser extraction payload rows to be an array.");if(G?.code==="RATE_LIMIT")throw new L(G.message||"huodongxing events was rate limited by www.huodongxing.com",G.hint||"Wait a few minutes and retry from a real browser session.");if(G?.code==="INVALID_LIMIT")throw new _(G.message||"huodongxing limit must be a positive integer <= 50");if(G?.code==="EMPTY_RESULT")throw new f("huodongxing events",G.hint||"No Huodongxing event cards were found. The page may be empty.");throw new L(G?.message||"huodongxing events returned malformed extraction data",G?.hint||"Huodongxing extraction did not return the expected structured payload.")}export function extractEventRows(K=20){return R(extractEventRowsPayload(K))}Y({site:"huodongxing",name:"events",access:"read",description:"活动行活动搜索(按标签、城市、日期、线上/线下、名称过滤)",domain:"www.huodongxing.com",strategy:v.PUBLIC,browser:!0,args:[{name:"tag",type:"string",default:"",help:"活动标签,例如 AI"},{name:"city",type:"string",default:"全部",help:"城市名,例如 北京 / 上海 / 全部"},{name:"date",type:"string",default:"",help:"开始日期,格式 YYYY-MM-DD"},{name:"dateTo",type:"string",default:"",help:"结束日期,格式 YYYY-MM-DD"},{name:"eventType",type:"int",default:void 0,help:"活动类型:1 线下,2 线上"},{name:"qs",type:"string",default:"",help:"按活动名称关键词过滤"},{name:"limit",type:"int",default:20,help:"返回条数(1-50)"}],columns:EVENTS_COLUMNS,func:async(K,G)=>{const J=requireLimit(G.limit),W=buildEventsUrl(G);await K.goto(W);await K.wait(2);const F=await K.evaluate(`(${extractEventRowsPayload.toString()})(${J})`);return filterRowsByDateRange(R(F),G)}});
1
+ import{cli as L,Strategy as N}from"@jackwener/opencli/registry";import{ArgumentError as y,CommandExecutionError as T,EmptyResultError as R}from"@jackwener/opencli/errors";const k="https://www.huodongxing.com/events",S=50;export const EVENTS_COLUMNS=["rank","id","title","time","eventType","city","location","organizer","url"];function f(n){return String(n??"").replace(/\s+/g," ").trim()}export function requireLimit(n){const e=n??20,t=typeof e==="number"?e:Number(String(e).trim());if(!Number.isInteger(t)||t<=0)throw new y("huodongxing limit must be a positive integer");if(t>S)throw new y(`huodongxing limit must be <= ${S}`);return t}function p(n,e,t){const o=f(t);if(o)n.set(e,o)}function v(n,e,t){return Math.floor(Date.UTC(n,e-1,t)/86400000)}function h(n){const e=f(n).match(/^(\d{4})-(\d{2})-(\d{2})$/);if(!e)return null;const t=Number(e[1]),o=Number(e[2]),u=Number(e[3]),a=new Date(Date.UTC(t,o-1,u));if(a.getUTCFullYear()!==t||a.getUTCMonth()!==o-1||a.getUTCDate()!==u)return null;return v(t,o,u)}function D(n,e){const t=f(n);if(!t)return"";if(h(t)==null)throw new y(`huodongxing ${e} must be a valid YYYY-MM-DD date`);return t}function A(n={}){const e=D(n.date,"date"),t=D(n.dateTo,"dateTo");if(e&&t&&h(e)>h(t))throw new y("huodongxing date must be <= dateTo");return{date:e,dateTo:t}}function q(n){if(n&&!Array.isArray(n)&&typeof n==="object"&&"session"in n&&"data"in n)return n.data;return n}function U(n){return v(n.getFullYear(),n.getMonth()+1,n.getDate())}function x(n,e){const t=f(n).match(/(\d{1,2})\/(\d{1,2})/);if(!t)return null;return{month:Number(t[1]),day:Number(t[2]),ordinal:v(e,Number(t[1]),Number(t[2]))}}function C(n,e={}){const t=f(n);if(!t)return null;const o=h(e.date),u=h(e.dateTo)??o,a=e.referenceDate instanceof Date?e.referenceDate:new Date,l=U(a);if(/今天/.test(t))return{start:l,end:l};if(/明天/.test(t))return{start:l+1,end:l+1};if(/后天/.test(t))return{start:l+2,end:l+2};const s=e.year??(f(e.date).match(/^(\d{4})-/)?.[1]?Number(f(e.date).slice(0,4)):a.getFullYear()),i=Array.from(t.matchAll(/(\d{1,2}\/\d{1,2})/g)).map((r)=>r[1]);if(i.length===0)return null;const c=x(i[0],s);if(!c)return null;if(i.length===1)return{start:c.ordinal,end:c.ordinal};const g=x(i[1],s)?.month<c.month?s+1:s,w=x(i[1],g);if(!w)return{start:c.ordinal,end:c.ordinal};if(o!=null&&w.ordinal<o&&c.month>=10){const r=x(i[0],s+1),d=x(i[1],s+1)?.month<r.month?s+2:s+1,m=x(i[1],d);if(r&&m)return{start:r.ordinal,end:m.ordinal}}return{start:c.ordinal,end:w.ordinal}}export function filterRowsByDateRange(n,e={}){A(e);const t=h(e.date),o=h(e.dateTo)??t;if(t==null&&o==null)return n;const u=t??o,a=o??t;return n.filter((s)=>{const i=C(s.time,e);if(!i)return!0;return i.start<=a&&i.end>=u}).map((s,i)=>({...s,rank:i+1}))}export function buildEventsUrl(n={}){const e=A(n),t=new URLSearchParams;t.set("orderby","o");t.set("d","ts");p(t,"date",e.date);p(t,"dateTo",e.dateTo);p(t,"tag",n.tag);p(t,"city",n.city);const o=f(n.eventType);if(o){if(o!=="1"&&o!=="2")throw new y("huodongxing eventType must be 1 (offline) or 2 (online)");t.set("eventType",o)}p(t,"qs",n.qs);return`${k}?${t.toString()}`}export function extractEventRowsPayload(n=20){const e=50,t=n??20,o=typeof t==="number"?t:Number(String(t).trim());if(!Number.isInteger(o)||o<=0||o>e)return{ok:!1,code:"INVALID_LIMIT",message:`huodongxing limit must be a positive integer <= ${e}`};const u=(r)=>String(r??"").replace(/\s+/g," ").trim(),a=(r,d)=>u(r.querySelector(d)?.textContent??""),l=(r)=>{const d=String(r??"").match(/\/event\/(\d+)/);return d?d[1]:""},s=(r)=>`https://www.huodongxing.com/event/${r}`,i=(r,d)=>{if(r.querySelector(".item-live-icon"))return"online";if(r.querySelector(".item-dress-icon"))return"offline";if(/线上|在线|直播/.test(d))return"online";return""},c=Array.from(document.querySelectorAll(".search-tab-content-item-mesh")),g=[],w=new Set;for(const r of c){if(g.length>=o)break;const d=r.querySelector('a.item-title[href*="/event/"], a[href*="/event/"]'),m=l(d?.getAttribute("href")??"");if(!m||w.has(m))continue;const E=u(a(r,"a.item-title span")||a(r,"a.item-title")||r.querySelector("img.item-logo")?.getAttribute("alt")||"");if(!E)continue;const Y=a(r,".item-dress p"),b=a(r,".item-dress-pp"),I=u(a(r,".item-bottom-left .user-name")||r.querySelector(".item-bottom-left img[title]")?.getAttribute("title")||r.querySelector(".item-bottom-left img[alt]")?.getAttribute("alt")||"");w.add(m);g.push({rank:g.length+1,id:m,title:E,time:Y,eventType:i(r,b),city:b,location:b,organizer:I,url:s(m)})}if(g.length===0){const r=u(document.body?.textContent??"");if(/操作过于频繁|too\s+frequent|rate\s*limit/i.test(r))return{ok:!1,code:"RATE_LIMIT",message:"huodongxing events was rate limited by www.huodongxing.com",hint:"Wait a few minutes and retry from a real browser session."};if(c.length>0)return{ok:!1,code:"MALFORMED_RESULT",message:"huodongxing events cards were found but no stable event rows could be extracted",hint:"Huodongxing card markup changed: expected event links with /event/<id> and non-empty titles."};return{ok:!1,code:"EMPTY_RESULT",message:"huodongxing events returned no data",hint:"No Huodongxing event cards were found. The page may be empty or the DOM structure may have changed."}}return{ok:!0,rows:g}}function M(n){const e=q(n);if(e?.ok===!0&&Array.isArray(e.rows))return e.rows;if(e?.ok===!0)throw new T("huodongxing events returned malformed extraction rows","Expected browser extraction payload rows to be an array.");if(e?.code==="RATE_LIMIT")throw new T(e.message||"huodongxing events was rate limited by www.huodongxing.com",e.hint||"Wait a few minutes and retry from a real browser session.");if(e?.code==="INVALID_LIMIT")throw new y(e.message||"huodongxing limit must be a positive integer <= 50");if(e?.code==="EMPTY_RESULT")throw new R("huodongxing events",e.hint||"No Huodongxing event cards were found. The page may be empty.");throw new T(e?.message||"huodongxing events returned malformed extraction data",e?.hint||"Huodongxing extraction did not return the expected structured payload.")}export function extractEventRows(n=20){return M(extractEventRowsPayload(n))}L({site:"huodongxing",name:"events",access:"read",description:"活动行活动搜索(按标签、城市、日期、线上/线下、名称过滤)",domain:"www.huodongxing.com",strategy:N.PUBLIC,browser:!0,args:[{name:"tag",type:"string",default:"",help:"活动标签,例如 AI"},{name:"city",type:"string",default:"全部",help:"城市名,例如 北京 / 上海 / 全部"},{name:"date",type:"string",default:"",help:"开始日期,格式 YYYY-MM-DD"},{name:"dateTo",type:"string",default:"",help:"结束日期,格式 YYYY-MM-DD"},{name:"eventType",type:"int",default:void 0,help:"活动类型:1 线下,2 线上"},{name:"qs",type:"string",default:"",help:"按活动名称关键词过滤"},{name:"limit",type:"int",default:20,help:"返回条数(1-50)"}],columns:EVENTS_COLUMNS,func:async(n,e)=>{const t=requireLimit(e.limit),o=buildEventsUrl(e);await n.goto(o);await n.wait(2);const u=await n.evaluate(`(${extractEventRowsPayload.toString()})(${t})`);return filterRowsByDateRange(M(u),e)}});
@@ -1,7 +1,7 @@
1
- import{cli as D,Strategy as L}from"@jackwener/opencli/registry";import{getHupuThreadUrl as S,readHupuNextData as U,stripHtml as M}from"./utils.js";D({site:"hupu",name:"detail",access:"read",description:"获取虎扑帖子详情 (使用Next.js JSON数据)",domain:"bbs.hupu.com",strategy:L.PUBLIC,browser:!0,args:[{name:"tid",required:!0,positional:!0,help:"帖子ID(9位数字)"},{name:"replies",type:"boolean",default:!1,help:"是否包含热门回复"}],columns:["title","author","content","replies","lights","url"],func:async(O,Q)=>{const{tid:A,replies:V=!1}=Q,W=S(A).replace(/-1\.html$/,".html"),B=await U(O,W,"Read Hupu thread detail",{expectedTid:String(A)}),q=B.props.pageProps.detail_error_info;if(q&&q.code!==200)throw Error(`帖子访问失败: ${q.message} (code: ${q.code})`);const b=B.props.pageProps.detail?.thread;if(!b)throw Error("帖子不存在或已被删除");const X=b.author?.puname||"未知作者",E=M(b.content),F=E.length>300?E.substring(0,300)+"...":E,G={title:b.title,author:X,content:F,replies:b.replies||0,lights:b.lights||0,url:`https://bbs.hupu.com/${A}.html`};if(V){const J=(B.props.pageProps.detail?.lights||[]).slice(0,3);if(J.length>0){let K=`
1
+ import{cli as N,Strategy as P}from"@jackwener/opencli/registry";import{getHupuThreadUrl as x,readHupuNextData as H,stripHtml as c}from"./utils.js";N({site:"hupu",name:"detail",access:"read",description:"获取虎扑帖子详情 (使用Next.js JSON数据)",domain:"bbs.hupu.com",strategy:P.PUBLIC,browser:!0,args:[{name:"tid",required:!0,positional:!0,help:"帖子ID(9位数字)"},{name:"replies",type:"boolean",default:!1,help:"是否包含热门回复"}],columns:["title","author","content","replies","lights","url"],func:async(u,h)=>{const{tid:o,replies:d=!1}=h,m=x(o).replace(/-1\.html$/,".html"),n=await H(u,m,"Read Hupu thread detail",{expectedTid:String(o)}),e=n.props.pageProps.detail_error_info;if(e&&e.code!==200)throw Error(`帖子访问失败: ${e.message} (code: ${e.code})`);const t=n.props.pageProps.detail?.thread;if(!t)throw Error("帖子不存在或已被删除");const g=t.author?.puname||"未知作者",s=c(t.content),a=s.length>300?s.substring(0,300)+"...":s,i={title:t.title,author:g,content:a,replies:t.replies||0,lights:t.lights||0,url:`https://bbs.hupu.com/${o}.html`};if(d){const l=(n.props.pageProps.detail?.lights||[]).slice(0,3);if(l.length>0){let p=`
2
2
 
3
3
  【热门回复】
4
- `;J.forEach((z,Y)=>{const Z=z.author?.puname||"未知用户",_=M(z.content).substring(0,100),$=z.allLightCount||0,C=z.created_at_format||"未知时间";K+=`${Y+1}. ${Z} (亮${$} ${C}):
5
- ${_}
4
+ `;l.forEach((r,f)=>{const b=r.author?.puname||"未知用户",w=c(r.content).substring(0,100),y=r.allLightCount||0,L=r.created_at_format||"未知时间";p+=`${f+1}. ${b} (亮${y} ${L}):
5
+ ${w}
6
6
 
7
- `});G.content=F+K}}return[G]}});
7
+ `});i.content=a+p}}return[i]}});