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,4 +1,4 @@
1
- import{cli as P,Strategy as j}from"@jackwener/opencli/registry";import{ArgumentError as Z,AuthRequiredError as N,CommandExecutionError as $}from"@jackwener/opencli/errors";const U=`
1
+ import{cli as h,Strategy as f}from"@jackwener/opencli/registry";import{ArgumentError as l,AuthRequiredError as d,CommandExecutionError as c}from"@jackwener/opencli/errors";const m=`
2
2
  new Promise((resolve) => {
3
3
  const findNoteCard = () => document.querySelector(
4
4
  'section.note-item, section:has(a[href*="/search_result/"]), section:has(a[href*="/explore/"])'
@@ -22,7 +22,7 @@ import{cli as P,Strategy as j}from"@jackwener/opencli/registry";import{ArgumentE
22
22
  observer.observe(document.body, { childList: true, subtree: true });
23
23
  setTimeout(() => { observer.disconnect(); resolve('timeout'); }, 5000);
24
24
  })
25
- `,W=`
25
+ `,p=`
26
26
  new Promise((resolve) => {
27
27
  const isSearchRoute = () => /\\/search_result(?:_ai)?/.test(location.pathname);
28
28
  const isSecurityBlock = () => {
@@ -48,7 +48,7 @@ import{cli as P,Strategy as j}from"@jackwener/opencli/registry";import{ArgumentE
48
48
  resolve('timeout');
49
49
  }, 8000);
50
50
  })
51
- `;export function noteIdToDate(z){const B=z.match(/\/(?:search_result|explore|note)\/([0-9a-f]{24})(?=[?#/]|$)/i);if(!B)return"";const G=B[1].substring(0,8),Q=parseInt(G,16);if(!Q||Q<1e9||Q>4000000000)return"";return new Date((Q+28800)*1000).toISOString().slice(0,10)}export function stripXhsAuthorDateSuffix(z){const B=(z||"").replace(/\s+/g," ").trim();return B.replace(/\s*(?:\d{1,2}天前|\d+小时前|\d+分钟前|\d+秒前|刚刚|昨天|前天|\d+周前|\d+个月前|\d{1,2}-\d{1,2}|\d{4}-\d{1,2}-\d{1,2})$/u,"").trim()||B}export function unwrapEvaluateResult(z){if(z&&!Array.isArray(z)&&typeof z==="object"&&"session"in z&&"data"in z)return z.data;return z}function L(z,B){const G=unwrapEvaluateResult(z);if(!Array.isArray(G))throw new $(`Unexpected Xiaohongshu search ${B} payload shape; expected an array of rows.`);return G}function X(z){const B=unwrapEvaluateResult(z);if(B==="search_route")return;if(B==="security_block")throw new $("Xiaohongshu search hit a security restriction page instead of search results.");throw new $("Xiaohongshu search did not reach a search results route after submitting the query.")}async function D(z,B){await z.goto("https://www.xiaohongshu.com/");await z.wait?.(1);await z.click("#search-input-in-feeds");await z.typeText("#search-input-in-feeds",B);await z.pressKey("Enter")}export function parseLimit(z){const B=Number(z??20);if(!Number.isFinite(B)||!Number.isInteger(B))throw new Z(`--limit must be an integer between 1 and 100, got ${JSON.stringify(z)}`);if(B<1||B>100)throw new Z(`--limit must be between 1 and 100, got ${B}`);return B}export function buildScrollUntilJs(z,B=15){if(!Number.isSafeInteger(z)||z<1)throw new Z(`targetCount must be a positive integer, got ${JSON.stringify(z)}`);if(!Number.isSafeInteger(B)||B<1)throw new Z(`maxScrolls must be a positive integer, got ${JSON.stringify(B)}`);return`
51
+ `;export function noteIdToDate(e){const t=e.match(/\/(?:search_result|explore|note)\/([0-9a-f]{24})(?=[?#/]|$)/i);if(!t)return"";const r=t[1].substring(0,8),s=parseInt(r,16);if(!s||s<1e9||s>4000000000)return"";return new Date((s+28800)*1000).toISOString().slice(0,10)}export function stripXhsAuthorDateSuffix(e){const t=(e||"").replace(/\s+/g," ").trim();return t.replace(/\s*(?:\d{1,2}天前|\d+小时前|\d+分钟前|\d+秒前|刚刚|昨天|前天|\d+周前|\d+个月前|\d{1,2}-\d{1,2}|\d{4}-\d{1,2}-\d{1,2})$/u,"").trim()||t}export function unwrapEvaluateResult(e){if(e&&!Array.isArray(e)&&typeof e==="object"&&"session"in e&&"data"in e)return e.data;return e}function u(e,t){const r=unwrapEvaluateResult(e);if(!Array.isArray(r))throw new c(`Unexpected Xiaohongshu search ${t} payload shape; expected an array of rows.`);return r}function w(e){const t=unwrapEvaluateResult(e);if(t==="search_route")return;if(t==="security_block")throw new c("Xiaohongshu search hit a security restriction page instead of search results.");throw new c("Xiaohongshu search did not reach a search results route after submitting the query.")}async function y(e,t){await e.goto("https://www.xiaohongshu.com/");await e.wait?.(1);await e.click("#search-input-in-feeds");await e.typeText("#search-input-in-feeds",t);await e.pressKey("Enter")}export function parseLimit(e){const t=Number(e??20);if(!Number.isFinite(t)||!Number.isInteger(t))throw new l(`--limit must be an integer between 1 and 100, got ${JSON.stringify(e)}`);if(t<1||t>100)throw new l(`--limit must be between 1 and 100, got ${t}`);return t}export function buildScrollUntilJs(e,t=15){if(!Number.isSafeInteger(e)||e<1)throw new l(`targetCount must be a positive integer, got ${JSON.stringify(e)}`);if(!Number.isSafeInteger(t)||t<1)throw new l(`maxScrolls must be a positive integer, got ${JSON.stringify(t)}`);return`
52
52
  (async () => {
53
53
  const isVisibleNote = (el) => {
54
54
  if (el.classList.contains('query-note-item')) return false;
@@ -80,8 +80,8 @@ import{cli as P,Strategy as j}from"@jackwener/opencli/registry";import{ArgumentE
80
80
 
81
81
  let lastCount = countItems();
82
82
  let plateauRounds = 0;
83
- for (let i = 0; i < ${B}; i++) {
84
- if (countItems() >= ${z}) break;
83
+ for (let i = 0; i < ${t}; i++) {
84
+ if (countItems() >= ${e}) break;
85
85
  const lastHeight = document.body.scrollHeight;
86
86
  window.scrollTo(0, lastHeight);
87
87
  await new Promise((resolve) => {
@@ -107,12 +107,12 @@ import{cli as P,Strategy as j}from"@jackwener/opencli/registry";import{ArgumentE
107
107
  }
108
108
  return countItems();
109
109
  })()
110
- `}export function buildSearchExtractJs(z){return`
110
+ `}export function buildSearchExtractJs(e){return`
111
111
  (() => {
112
112
  const normalizeUrl = (href) => {
113
113
  if (!href) return '';
114
114
  if (href.startsWith('http://') || href.startsWith('https://')) return href;
115
- if (href.startsWith('/')) return 'https://${z}' + href;
115
+ if (href.startsWith('/')) return 'https://${e}' + href;
116
116
  return '';
117
117
  };
118
118
 
@@ -191,4 +191,4 @@ import{cli as P,Strategy as j}from"@jackwener/opencli/registry";import{ArgumentE
191
191
 
192
192
  return results;
193
193
  })()
194
- `}export const command=P({site:"xiaohongshu",name:"search",access:"read",description:"搜索小红书笔记",domain:"www.xiaohongshu.com",strategy:j.COOKIE,navigateBefore:!1,args:[{name:"query",required:!0,positional:!0,help:"Search keyword"},{name:"limit",type:"int",default:20,help:"Number of results"}],columns:["rank","title","author","likes","published_at","url"],func:async(z,B)=>{const G=parseLimit(B.limit);await D(z,B.query);X(await z.evaluate(W));if(unwrapEvaluateResult(await z.evaluate(U))==="login_wall")throw new N("www.xiaohongshu.com","Xiaohongshu search results are blocked behind a login wall");const V=[...L(await z.evaluate(buildSearchExtractJs("www.xiaohongshu.com")),"initial extraction")];if(V.length<G){await z.evaluate(buildScrollUntilJs(G));const M=L(await z.evaluate(buildSearchExtractJs("www.xiaohongshu.com")),"post-scroll extraction"),Y=new Set(V.map((K)=>K.url).filter(Boolean));for(const K of M){if(K?.url&&Y.has(K.url))continue;if(K?.url)Y.add(K.url);V.push(K);if(V.length>=G)break}}return V.filter((M)=>M.title).slice(0,G).map((M,Y)=>({rank:Y+1,...M,published_at:noteIdToDate(M.url)}))}}),__test__={stripXhsAuthorDateSuffix};
194
+ `}export const command=h({site:"xiaohongshu",name:"search",access:"read",description:"搜索小红书笔记",domain:"www.xiaohongshu.com",strategy:f.COOKIE,navigateBefore:!1,args:[{name:"query",required:!0,positional:!0,help:"Search keyword"},{name:"limit",type:"int",default:20,help:"Number of results"}],columns:["rank","title","author","likes","published_at","url"],func:async(e,t)=>{const r=parseLimit(t.limit);await y(e,t.query);w(await e.evaluate(p));if(unwrapEvaluateResult(await e.evaluate(m))==="login_wall")throw new d("www.xiaohongshu.com","Xiaohongshu search results are blocked behind a login wall");const i=[...u(await e.evaluate(buildSearchExtractJs("www.xiaohongshu.com")),"initial extraction")];if(i.length<r){await e.evaluate(buildScrollUntilJs(r));const o=u(await e.evaluate(buildSearchExtractJs("www.xiaohongshu.com")),"post-scroll extraction"),a=new Set(i.map((n)=>n.url).filter(Boolean));for(const n of o){if(n?.url&&a.has(n.url))continue;if(n?.url)a.add(n.url);i.push(n);if(i.length>=r)break}}return i.filter((o)=>o.title).slice(0,r).map((o,a)=>({rank:a+1,...o,published_at:noteIdToDate(o.url)}))}}),__test__={stripXhsAuthorDateSuffix};
@@ -1,4 +1,4 @@
1
- import{cli as L,Strategy as F}from"@jackwener/opencli/registry";import{ArgumentError as Z,AuthRequiredError as M,CliError as U,CommandExecutionError as K}from"@jackwener/opencli/errors";import{normalizeXhsUserId as b}from"./user-helpers.js";const v=2500,H=1500,T=5000,A=/^[a-zA-Z0-9]{8,32}$/;function P(B){const J=String(B||"").toLowerCase();return J==="xiaohongshu.com"||J.endsWith(".xiaohongshu.com")}function z(B){if(B&&typeof B==="object"&&"session"in B&&"data"in B)return B.data;return B}function V(B,J){const G=z(B);if(!G||typeof G!=="object"||Array.isArray(G)||typeof G.ok!=="boolean")throw new K(`xiaohongshu/unfollow: malformed ${J} payload`);return G}function j(B){const J=String(B??"").trim();if(/^https?:\/\//i.test(J)){let N;try{N=new URL(J)}catch{throw new Z("xiaohongshu/unfollow: invalid profile URL")}if(N.protocol!=="https:"||!P(N.hostname))throw new Z("xiaohongshu/unfollow: profile URL must be an exact https://*.xiaohongshu.com URL");const W=N.pathname.match(/^\/user\/profile\/([a-zA-Z0-9]{8,32})\/?$/);if(!W)throw new Z("xiaohongshu/unfollow: profile URL must be /user/profile/<userId>");return W[1]}const G=b(B);if(!G||!A.test(G))throw new Z("xiaohongshu/unfollow: user-id must be a Xiaohongshu user ID (e.g. 5d8f88dc0000000001005d3a) or full profile URL");return G}function q(){return`
1
+ import{cli as S,Strategy as L}from"@jackwener/opencli/registry";import{ArgumentError as u,AuthRequiredError as g,CliError as E,CommandExecutionError as n}from"@jackwener/opencli/errors";import{normalizeXhsUserId as _}from"./user-helpers.js";const x=2500,O=1500,T=5000,A=/^[a-zA-Z0-9]{8,32}$/;function h(o){const e=String(o||"").toLowerCase();return e==="xiaohongshu.com"||e.endsWith(".xiaohongshu.com")}function a(o){if(o&&typeof o==="object"&&"session"in o&&"data"in o)return o.data;return o}function w(o,e){const t=a(o);if(!t||typeof t!=="object"||Array.isArray(t)||typeof t.ok!=="boolean")throw new n(`xiaohongshu/unfollow: malformed ${e} payload`);return t}function d(o){const e=String(o??"").trim();if(/^https?:\/\//i.test(e)){let r;try{r=new URL(e)}catch{throw new u("xiaohongshu/unfollow: invalid profile URL")}if(r.protocol!=="https:"||!h(r.hostname))throw new u("xiaohongshu/unfollow: profile URL must be an exact https://*.xiaohongshu.com URL");const s=r.pathname.match(/^\/user\/profile\/([a-zA-Z0-9]{8,32})\/?$/);if(!s)throw new u("xiaohongshu/unfollow: profile URL must be /user/profile/<userId>");return s[1]}const t=_(o);if(!t||!A.test(t))throw new u("xiaohongshu/unfollow: user-id must be a Xiaohongshu user ID (e.g. 5d8f88dc0000000001005d3a) or full profile URL");return t}function m(){return`
2
2
  (() => {
3
3
  const FOLLOW_LABELS = ['关注', '+ 关注', '+关注'];
4
4
  const FOLLOWING_LABELS = ['已关注', '已互关', '互相关注'];
@@ -46,7 +46,7 @@ import{cli as L,Strategy as F}from"@jackwener/opencli/registry";import{ArgumentE
46
46
  btn.click();
47
47
  return { ok: true, state: 'unfollow-clicked' };
48
48
  })()
49
- `}function O(){return`
49
+ `}function p(){return`
50
50
  (() => {
51
51
  const isVisible = (el) => !!el && el.offsetParent !== null;
52
52
  const footer = Array.from(document.querySelectorAll('.d-modal-footer')).find(isVisible);
@@ -62,7 +62,7 @@ import{cli as L,Strategy as F}from"@jackwener/opencli/registry";import{ArgumentE
62
62
  confirmBtn.click();
63
63
  return { ok: true };
64
64
  })()
65
- `}function X(){return`
65
+ `}function b(){return`
66
66
  (async () => {
67
67
  const FOLLOW_LABELS = ['关注', '+ 关注', '+关注'];
68
68
  const STATE_FLIP_TIMEOUT_MS = ${T};
@@ -95,4 +95,4 @@ import{cli as L,Strategy as F}from"@jackwener/opencli/registry";import{ArgumentE
95
95
  }
96
96
  return { ok: false, reason: 'Unfollow click did not flip button back to 关注 within ' + (STATE_FLIP_TIMEOUT_MS / 1000) + 's' };
97
97
  })()
98
- `}L({site:"xiaohongshu",name:"unfollow",access:"write",description:"取消关注小红书用户 (profile UI automation)",domain:"www.xiaohongshu.com",strategy:F.COOKIE,navigateBefore:!1,browser:!0,args:[{name:"user-id",required:!0,positional:!0,help:"User ID (e.g. 5d8f88dc0000000001005d3a) or profile URL"}],columns:["status","user_id","url"],func:async(B,J)=>{if(!B)throw new K("Browser session required for xiaohongshu unfollow");try{const G=j(J["user-id"]),N=`https://www.xiaohongshu.com/user/profile/${G}`;await B.goto(N);await B.wait({time:v/1000});const W=z(await B.evaluate("() => location.href"));if(typeof W!=="string")throw new K("xiaohongshu/unfollow: malformed current-url payload");const Q=new URL(W);if(Q.protocol!=="https:"||!P(Q.hostname))throw new K(`xiaohongshu/unfollow: expected Xiaohongshu profile host, got ${Q.hostname}`);if(/\/login(?:[/?#]|$)/i.test(Q.pathname))throw new M("www.xiaohongshu.com");if(Q.pathname.match(/^\/user\/profile\/([a-zA-Z0-9]{8,32})\/?$/)?.[1]!==G)throw new K(`xiaohongshu/unfollow: expected profile ${G}, got ${Q.pathname}`);const $=V(await B.evaluate(q()),"click-unfollow");if(!$.ok)throw new K(`xiaohongshu/unfollow failed: ${$.reason??"unknown reason"}`);if($.state==="not-following")return[{status:"not-following",user_id:G,url:N}];await B.wait({time:H/1000});const D=V(await B.evaluate(O()),"confirm-modal");if(!D.ok)throw new K(`xiaohongshu/unfollow: confirmation modal step failed (${D.kind??"no kind reported"})`);const Y=z(await B.evaluate(X()));if(!Y||typeof Y!=="object"||Y.ok!==!0)throw new K(`xiaohongshu/unfollow: ${Y?.reason??"state verification failed"}`);return[{status:"unfollowed",user_id:G,url:N}]}catch(G){if(G instanceof U)throw G;throw new K(`xiaohongshu/unfollow failed: ${G?.message??String(G)}`)}}});export const __test__={assertUserId:j,buildClickUnfollowScript:q,buildConfirmModalScript:O,buildVerifyFollowFlippedScript:X};
98
+ `}S({site:"xiaohongshu",name:"unfollow",access:"write",description:"取消关注小红书用户 (profile UI automation)",domain:"www.xiaohongshu.com",strategy:L.COOKIE,navigateBefore:!1,browser:!0,args:[{name:"user-id",required:!0,positional:!0,help:"User ID (e.g. 5d8f88dc0000000001005d3a) or profile URL"}],columns:["status","user_id","url"],func:async(o,e)=>{if(!o)throw new n("Browser session required for xiaohongshu unfollow");try{const t=d(e["user-id"]),r=`https://www.xiaohongshu.com/user/profile/${t}`;await o.goto(r);await o.wait({time:x/1000});const s=a(await o.evaluate("() => location.href"));if(typeof s!=="string")throw new n("xiaohongshu/unfollow: malformed current-url payload");const i=new URL(s);if(i.protocol!=="https:"||!h(i.hostname))throw new n(`xiaohongshu/unfollow: expected Xiaohongshu profile host, got ${i.hostname}`);if(/\/login(?:[/?#]|$)/i.test(i.pathname))throw new g("www.xiaohongshu.com");if(i.pathname.match(/^\/user\/profile\/([a-zA-Z0-9]{8,32})\/?$/)?.[1]!==t)throw new n(`xiaohongshu/unfollow: expected profile ${t}, got ${i.pathname}`);const f=w(await o.evaluate(m()),"click-unfollow");if(!f.ok)throw new n(`xiaohongshu/unfollow failed: ${f.reason??"unknown reason"}`);if(f.state==="not-following")return[{status:"not-following",user_id:t,url:r}];await o.wait({time:O/1000});const c=w(await o.evaluate(p()),"confirm-modal");if(!c.ok)throw new n(`xiaohongshu/unfollow: confirmation modal step failed (${c.kind??"no kind reported"})`);const l=a(await o.evaluate(b()));if(!l||typeof l!=="object"||l.ok!==!0)throw new n(`xiaohongshu/unfollow: ${l?.reason??"state verification failed"}`);return[{status:"unfollowed",user_id:t,url:r}]}catch(t){if(t instanceof E)throw t;throw new n(`xiaohongshu/unfollow failed: ${t?.message??String(t)}`)}}});export const __test__={assertUserId:d,buildClickUnfollowScript:m,buildConfirmModalScript:p,buildVerifyFollowFlippedScript:b};
@@ -1 +1 @@
1
- function B(q){return typeof q==="string"?q.trim():q==null?"":String(q).trim()}export function normalizeXhsUserId(q){const z=B(q).replace(/[?#].*$/,""),E=z.match(/\/user\/profile\/([a-zA-Z0-9]+)/);if(E?.[1])return E[1];return z.replace(/\/+$/,"").split("/").pop()??z}export function flattenXhsNoteGroups(q){if(!Array.isArray(q))return[];const D=[];for(const z of q){if(!z)continue;if(Array.isArray(z)){for(const E of z)if(E)D.push(E);continue}D.push(z)}return D}export function buildXhsNoteUrl(q,D,z,E="www.xiaohongshu.com"){const F=B(q),J=B(D);if(!F||!J)return"";const A=new URL(`https://${E}/user/profile/${F}/${J}`),j=B(z);if(j){A.searchParams.set("xsec_token",j);A.searchParams.set("xsec_source","pc_user")}return A.toString()}export function extractXhsUserNotes(q,D,z="www.xiaohongshu.com"){const E=flattenXhsNoteGroups(q.noteGroups),F=[],J=new Set;for(const A of E){const j=A?.noteCard??A?.note_card??A;if(!j||typeof j!=="object")continue;const K=B(j.noteId??j.note_id??A?.noteId??A?.note_id??A?.id);if(!K||J.has(K))continue;J.add(K);const M=B(j.user?.userId??j.user?.user_id??D),O=B(A?.xsecToken??A?.xsec_token??j.xsecToken??j.xsec_token),V=B(j.interactInfo?.likedCount??j.interact_info?.liked_count??0)||"0",W=B(j.cover?.urlDefault??j.cover?.urlPre??j.cover?.url??"");F.push({id:K,title:B(j.displayTitle??j.display_title??j.title),type:B(j.type),likes:V,cover:W,url:buildXhsNoteUrl(M||D,K,O,z)})}return F}
1
+ function r(e){return typeof e==="string"?e.trim():e==null?"":String(e).trim()}export function normalizeXhsUserId(e){const o=r(e).replace(/[?#].*$/,""),c=o.match(/\/user\/profile\/([a-zA-Z0-9]+)/);if(c?.[1])return c[1];return o.replace(/\/+$/,"").split("/").pop()??o}export function flattenXhsNoteGroups(e){if(!Array.isArray(e))return[];const s=[];for(const o of e){if(!o)continue;if(Array.isArray(o)){for(const c of o)if(c)s.push(c);continue}s.push(o)}return s}export function buildXhsNoteUrl(e,s,o,c="www.xiaohongshu.com"){const i=r(e),u=r(s);if(!i||!u)return"";const n=new URL(`https://${c}/user/profile/${i}/${u}`),t=r(o);if(t){n.searchParams.set("xsec_token",t);n.searchParams.set("xsec_source","pc_user")}return n.toString()}export function extractXhsUserNotes(e,s,o="www.xiaohongshu.com"){const c=flattenXhsNoteGroups(e.noteGroups),i=[],u=new Set;for(const n of c){const t=n?.noteCard??n?.note_card??n;if(!t||typeof t!=="object")continue;const a=r(t.noteId??t.note_id??n?.noteId??n?.note_id??n?.id);if(!a||u.has(a))continue;u.add(a);const f=r(t.user?.userId??t.user?.user_id??s),d=r(n?.xsecToken??n?.xsec_token??t.xsecToken??t.xsec_token),l=r(t.interactInfo?.likedCount??t.interact_info?.liked_count??0)||"0",p=r(t.cover?.urlDefault??t.cover?.urlPre??t.cover?.url??"");i.push({id:a,title:r(t.displayTitle??t.display_title??t.title),type:r(t.type),likes:l,cover:p,url:buildXhsNoteUrl(f||s,a,d,o)})}return i}
@@ -1,4 +1,4 @@
1
- import{cli as Y,Strategy as b}from"@jackwener/opencli/registry";import{AuthRequiredError as v,CommandExecutionError as $,EmptyResultError as F}from"@jackwener/opencli/errors";import{extractXhsUserNotes as M,normalizeXhsUserId as H}from"./user-helpers.js";export const USER_SNAPSHOT_JS=`
1
+ import{cli as c,Strategy as d}from"@jackwener/opencli/registry";import{AuthRequiredError as p,CommandExecutionError as i,EmptyResultError as w}from"@jackwener/opencli/errors";import{extractXhsUserNotes as f,normalizeXhsUserId as m}from"./user-helpers.js";export const USER_SNAPSHOT_JS=`
2
2
  (() => {
3
3
  const safeClone = (value) => {
4
4
  try {
@@ -27,4 +27,4 @@ import{cli as Y,Strategy as b}from"@jackwener/opencli/registry";import{AuthRequi
27
27
  loginWall: Boolean(onLoginPage || loggedInVal === false),
28
28
  };
29
29
  })()
30
- `;async function f(B){return await B.evaluate(USER_SNAPSHOT_JS)}export function assertReadableUserSnapshot(B){if(!B||typeof B!=="object"||Array.isArray(B))throw new $("Malformed Xiaohongshu user snapshot");if(B.storePresent!==!0)throw new $("Malformed Xiaohongshu user snapshot: user store was not found");if(B.notesPresent!==!0||!Array.isArray(B.noteGroups))throw new $("Malformed Xiaohongshu user snapshot: notes array was not found")}export function countFlatNotes(B){const Q=B?.noteGroups;if(!Array.isArray(Q))return 0;let K=0;for(const D of Q)K+=Array.isArray(D)?D.length:D?1:0;return K}export function isLoginWallSnapshot(B){return Boolean(B&&typeof B==="object"&&B.loginWall===!0)}function O(){throw new v("xiaohongshu.com","Xiaohongshu profile requires login (page redirected to /login or session expired); re-login to xiaohongshu.com and retry.")}export async function readUserSnapshotHydrated(B,Q=8,K=2){let D=await f(B);for(let G=0;G<Q&&!isLoginWallSnapshot(D)&&countFlatNotes(D)===0;G+=1){await B.wait({time:K});D=await f(B)}return D}export const command=Y({site:"xiaohongshu",name:"user",access:"read",description:"Get public notes from a Xiaohongshu user profile",domain:"www.xiaohongshu.com",strategy:b.COOKIE,browser:!0,navigateBefore:!1,args:[{name:"id",type:"string",required:!0,positional:!0,help:"User id or profile URL"},{name:"limit",type:"int",default:15,help:"Number of notes to return"}],columns:["id","title","type","likes","url"],func:async(B,Q)=>{const K=H(String(Q.id)),D=Math.max(1,Number(Q.limit??15));await B.goto(`https://www.xiaohongshu.com/user/profile/${K}`);let G=await readUserSnapshotHydrated(B);if(isLoginWallSnapshot(G))O();assertReadableUserSnapshot(G);let V=M(G??{},K),z=V.length;for(let J=0;V.length<D&&J<4;J+=1){await B.autoScroll({times:1,delayMs:1500});await B.wait(1);G=await f(B);if(isLoginWallSnapshot(G))O();assertReadableUserSnapshot(G);const Z=M(G??{},K);if(Z.length<=z)break;V=Z;z=Z.length}if(V.length===0)throw new F("xiaohongshu user","该用户没有公开笔记(可能销号 / 私密 / 全部删除)。");return V.slice(0,D)}});
30
+ `;async function u(e){return await e.evaluate(USER_SNAPSHOT_JS)}export function assertReadableUserSnapshot(e){if(!e||typeof e!=="object"||Array.isArray(e))throw new i("Malformed Xiaohongshu user snapshot");if(e.storePresent!==!0)throw new i("Malformed Xiaohongshu user snapshot: user store was not found");if(e.notesPresent!==!0||!Array.isArray(e.noteGroups))throw new i("Malformed Xiaohongshu user snapshot: notes array was not found")}export function countFlatNotes(e){const a=e?.noteGroups;if(!Array.isArray(a))return 0;let o=0;for(const t of a)o+=Array.isArray(t)?t.length:t?1:0;return o}export function isLoginWallSnapshot(e){return Boolean(e&&typeof e==="object"&&e.loginWall===!0)}function g(){throw new p("xiaohongshu.com","Xiaohongshu profile requires login (page redirected to /login or session expired); re-login to xiaohongshu.com and retry.")}export async function readUserSnapshotHydrated(e,a=8,o=2){let t=await u(e);for(let r=0;r<a&&!isLoginWallSnapshot(t)&&countFlatNotes(t)===0;r+=1){await e.wait({time:o});t=await u(e)}return t}export const command=c({site:"xiaohongshu",name:"user",access:"read",description:"Get public notes from a Xiaohongshu user profile",domain:"www.xiaohongshu.com",strategy:d.COOKIE,browser:!0,navigateBefore:!1,args:[{name:"id",type:"string",required:!0,positional:!0,help:"User id or profile URL"},{name:"limit",type:"int",default:15,help:"Number of notes to return"}],columns:["id","title","type","likes","url"],func:async(e,a)=>{const o=m(String(a.id)),t=Math.max(1,Number(a.limit??15));await e.goto(`https://www.xiaohongshu.com/user/profile/${o}`);let r=await readUserSnapshotHydrated(e);if(isLoginWallSnapshot(r))g();assertReadableUserSnapshot(r);let n=f(r??{},o),l=n.length;for(let h=0;n.length<t&&h<4;h+=1){await e.autoScroll({times:1,delayMs:1500});await e.wait(1);r=await u(e);if(isLoginWallSnapshot(r))g();assertReadableUserSnapshot(r);const s=f(r??{},o);if(s.length<=l)break;n=s;l=s.length}if(n.length===0)throw new w("xiaohongshu user","该用户没有公开笔记(可能销号 / 私密 / 全部删除)。");return n.slice(0,t)}});
@@ -1,3 +1,3 @@
1
- import*as Q from"node:fs";import*as z from"node:os";import*as W from"node:path";import{CliError as L,CommandExecutionError as M,ConfigError as S,EXIT_CODES as X,getErrorMessage as N}from"@jackwener/opencli/errors";export const XIAOYUZHOU_API_BASE_URL="https://api.xiaoyuzhoufm.com",XIAOYUZHOU_TOKEN_TTL_MS=1200000,XIAOYUZHOU_REFRESH_SKEW_MS=60000,XIAOYUZHOU_DEFAULT_DEVICE_ID="81ADBFD6-6921-482B-9AB9-A29E7CC7BB55",XIAOYUZHOU_DEFAULT_DEVICE_PROPERTIES="",XIAOYUZHOU_DEFAULT_USER_AGENT="Xiaoyuzhou/2.98.0 (build:2908; iOS 26.2.1)";function Y(){return Date.now()}export function getXiaoyuzhouCredentialFile(){return W.join(z.homedir(),".ppcli","xiaoyuzhou.json")}function V(j){return new L("AUTH_REQUIRED",j,`Update ${getXiaoyuzhouCredentialFile()} with fresh Xiaoyuzhou credentials before retrying.`,X.NOPERM)}function Z(j){const D=Number(j);return Number.isFinite(D)?D:0}export function normalizeXiaoyuzhouCredentials(j={}){const D=Z(j.last_updated_ts??j.lastUpdatedTs);let F=Z(j.expires_at??j.expiresAt);if(F>0&&F<10000000000)F*=1000;if(!F&&D>0)F=D*1000+XIAOYUZHOU_TOKEN_TTL_MS;return{access_token:String(j.access_token??j.accessToken??"").trim(),refresh_token:String(j.refresh_token??j.refreshToken??"").trim(),expires_at:F,device_id:String(j.device_id??j.deviceId??XIAOYUZHOU_DEFAULT_DEVICE_ID).trim()||XIAOYUZHOU_DEFAULT_DEVICE_ID,device_properties:String(j.device_properties??j.deviceProperties??XIAOYUZHOU_DEFAULT_DEVICE_PROPERTIES)}}export function loadXiaoyuzhouCredentials(){const j=getXiaoyuzhouCredentialFile();if(Q.existsSync(j))try{const D=JSON.parse(Q.readFileSync(j,"utf-8")),F=normalizeXiaoyuzhouCredentials(D);if(!F.access_token||!F.refresh_token)throw new S(`Xiaoyuzhou credential file is missing access_token or refresh_token: ${j}`,"Recreate the file with valid credentials.");return F}catch(D){if(D instanceof S)throw D;throw new S(`Failed to parse Xiaoyuzhou credential file: ${j}`,`Ensure ${j} contains valid JSON. (${N(D)})`)}throw new S(`Missing Xiaoyuzhou credentials. Expected ${j}`,`Create ${j} with access_token and refresh_token.`)}export function saveXiaoyuzhouCredentials(j){const D=getXiaoyuzhouCredentialFile();Q.mkdirSync(W.dirname(D),{recursive:!0});Q.writeFileSync(D,`${JSON.stringify({access_token:j.access_token,refresh_token:j.refresh_token,expires_at:j.expires_at,device_id:j.device_id,device_properties:j.device_properties},null,2)}
2
- `,"utf-8")}export function shouldRefreshXiaoyuzhouCredentials(j,D=Y()){return Number.isFinite(j.expires_at)&&j.expires_at>0&&D>=j.expires_at-XIAOYUZHOU_REFRESH_SKEW_MS}export function buildXiaoyuzhouHeaders(j,D={}){const{contentType:F="application/json",includeLocalTime:H=!1,includeRefreshToken:G=!1}=D,J={"Content-Type":F,Host:"api.xiaoyuzhoufm.com","User-Agent":XIAOYUZHOU_DEFAULT_USER_AGENT,Market:"AppStore","App-BuildNo":"2908",OS:"ios",Manufacturer:"Apple",BundleID:"app.podcast.cosmos",Connection:"keep-alive","abtest-info":'{"old_user_discovery_feed":"enable"}',"Accept-Language":"en-HK;q=1.0, zh-Hans-HK;q=0.9",Model:"iPhone18,1","app-permissions":"100000",Accept:"*/*","App-Version":"2.98.0",WifiConnected:"true","OS-Version":"26.2.1","x-custom-xiaoyuzhou-app-dev":"","x-jike-device-id":j.device_id||XIAOYUZHOU_DEFAULT_DEVICE_ID,"x-jike-device-properties":j.device_properties??XIAOYUZHOU_DEFAULT_DEVICE_PROPERTIES};if(j.access_token)J["x-jike-access-token"]=j.access_token;if(G&&j.refresh_token)J["x-jike-refresh-token"]=j.refresh_token;if(H){J["Local-Time"]=new Date().toISOString();J.Timezone=Intl.DateTimeFormat().resolvedOptions().timeZone||"UTC"}return J}export async function refreshXiaoyuzhouCredentials(j,D=fetch){if(!j.refresh_token)throw V("Xiaoyuzhou refresh token is missing");let F;try{F=await D(`${XIAOYUZHOU_API_BASE_URL}/app_auth_tokens.refresh`,{method:"POST",headers:buildXiaoyuzhouHeaders(j,{contentType:"application/x-www-form-urlencoded; charset=utf-8",includeLocalTime:!0,includeRefreshToken:!0}),signal:AbortSignal.timeout(20000)})}catch(K){throw new M(`Failed to refresh Xiaoyuzhou credentials: ${N(K)}`)}const H=await F.text();if(!F.ok)throw V(`Xiaoyuzhou token refresh failed with HTTP ${F.status}${H?`: ${H}`:""}`);let G;try{G=JSON.parse(H)}catch(K){throw new M(`Xiaoyuzhou refresh returned invalid JSON: ${N(K)}`)}if(!G?.success)throw V("Xiaoyuzhou refresh API returned success=false");const J=normalizeXiaoyuzhouCredentials({...j,access_token:G["x-jike-access-token"]||"",refresh_token:G["x-jike-refresh-token"]||"",expires_at:Y()+XIAOYUZHOU_TOKEN_TTL_MS});if(!J.access_token||!J.refresh_token)throw V("Xiaoyuzhou refresh API returned empty access_token or refresh_token");saveXiaoyuzhouCredentials(J);return J}function B(j,D){const F=new URL(j,XIAOYUZHOU_API_BASE_URL);if(D){for(const[H,G]of Object.entries(D))if(G!==void 0&&G!==null&&G!=="")F.searchParams.set(H,String(G))}return F.toString()}async function _(j,D,F,H){const{method:G="GET",query:J,body:K}=D;let O;try{O=await H(B(j,J),{method:G,headers:buildXiaoyuzhouHeaders(F,{contentType:"application/json",includeLocalTime:!0}),body:K===void 0?void 0:JSON.stringify(K),signal:AbortSignal.timeout(20000)})}catch($){throw new M(`Failed to reach Xiaoyuzhou API: ${N($)}`)}return O}export async function requestXiaoyuzhouJson(j,D={},F=fetch){let H=D.credentials??loadXiaoyuzhouCredentials();if(shouldRefreshXiaoyuzhouCredentials(H))H=await refreshXiaoyuzhouCredentials(H,F);let G=await _(j,D,H,F);if(G.status===401){H=await refreshXiaoyuzhouCredentials(H,F);G=await _(j,D,H,F)}const J=await G.text();if(!G.ok)throw new M(`Xiaoyuzhou API request failed with HTTP ${G.status}${J?`: ${J}`:""}`);let K;try{K=JSON.parse(J)}catch(O){throw new M(`Xiaoyuzhou API returned invalid JSON: ${N(O)}`)}if(K?.success===!1)throw new M(K?.message||K?.msg||"Xiaoyuzhou API returned success=false");return{credentials:H,raw:K,data:K?.data}}export async function fetchXiaoyuzhouTranscriptBody(j,D=fetch){let F;try{F=await D(j,{method:"GET",headers:{"User-Agent":XIAOYUZHOU_DEFAULT_USER_AGENT,Accept:"*/*",Market:"AppStore"},signal:AbortSignal.timeout(20000)})}catch(G){throw new M(`Failed to fetch Xiaoyuzhou transcript content: ${N(G)}`)}const H=await F.text();if(!F.ok)throw new M(`Xiaoyuzhou transcript download failed with HTTP ${F.status}${H?`: ${H}`:""}`);return H}export function extractTranscriptText(j){let D;try{D=JSON.parse(j)}catch{return{text:"",segmentCount:0}}let F=[];if(Array.isArray(D))F=D;else if(D&&typeof D==="object"){for(const G of["segments","data","transcript","items"])if(Array.isArray(D[G])){F=D[G];break}if(F.length===0){const G=typeof D.text==="string"?D.text.trim():"";if(G)return{text:G,segmentCount:1}}}const H=[];for(const G of F){if(!G||typeof G!=="object"||typeof G.text!=="string")continue;const J=G.text.trim();if(J)H.push(J)}return{text:H.join(`
3
- `),segmentCount:H.length}}
1
+ import*as f from"node:fs";import*as m from"node:os";import*as d from"node:path";import{CliError as k,CommandExecutionError as a,ConfigError as h,EXIT_CODES as w,getErrorMessage as c}from"@jackwener/opencli/errors";export const XIAOYUZHOU_API_BASE_URL="https://api.xiaoyuzhoufm.com",XIAOYUZHOU_TOKEN_TTL_MS=1200000,XIAOYUZHOU_REFRESH_SKEW_MS=60000,XIAOYUZHOU_DEFAULT_DEVICE_ID="81ADBFD6-6921-482B-9AB9-A29E7CC7BB55",XIAOYUZHOU_DEFAULT_DEVICE_PROPERTIES="",XIAOYUZHOU_DEFAULT_USER_AGENT="Xiaoyuzhou/2.98.0 (build:2908; iOS 26.2.1)";function l(){return Date.now()}export function getXiaoyuzhouCredentialFile(){return d.join(m.homedir(),".ppcli","xiaoyuzhou.json")}function p(e){return new k("AUTH_REQUIRED",e,`Update ${getXiaoyuzhouCredentialFile()} with fresh Xiaoyuzhou credentials before retrying.`,w.NOPERM)}function _(e){const t=Number(e);return Number.isFinite(t)?t:0}export function normalizeXiaoyuzhouCredentials(e={}){const t=_(e.last_updated_ts??e.lastUpdatedTs);let r=_(e.expires_at??e.expiresAt);if(r>0&&r<10000000000)r*=1000;if(!r&&t>0)r=t*1000+XIAOYUZHOU_TOKEN_TTL_MS;return{access_token:String(e.access_token??e.accessToken??"").trim(),refresh_token:String(e.refresh_token??e.refreshToken??"").trim(),expires_at:r,device_id:String(e.device_id??e.deviceId??XIAOYUZHOU_DEFAULT_DEVICE_ID).trim()||XIAOYUZHOU_DEFAULT_DEVICE_ID,device_properties:String(e.device_properties??e.deviceProperties??XIAOYUZHOU_DEFAULT_DEVICE_PROPERTIES)}}export function loadXiaoyuzhouCredentials(){const e=getXiaoyuzhouCredentialFile();if(f.existsSync(e))try{const t=JSON.parse(f.readFileSync(e,"utf-8")),r=normalizeXiaoyuzhouCredentials(t);if(!r.access_token||!r.refresh_token)throw new h(`Xiaoyuzhou credential file is missing access_token or refresh_token: ${e}`,"Recreate the file with valid credentials.");return r}catch(t){if(t instanceof h)throw t;throw new h(`Failed to parse Xiaoyuzhou credential file: ${e}`,`Ensure ${e} contains valid JSON. (${c(t)})`)}throw new h(`Missing Xiaoyuzhou credentials. Expected ${e}`,`Create ${e} with access_token and refresh_token.`)}export function saveXiaoyuzhouCredentials(e){const t=getXiaoyuzhouCredentialFile();f.mkdirSync(d.dirname(t),{recursive:!0});f.writeFileSync(t,`${JSON.stringify({access_token:e.access_token,refresh_token:e.refresh_token,expires_at:e.expires_at,device_id:e.device_id,device_properties:e.device_properties},null,2)}
2
+ `,"utf-8")}export function shouldRefreshXiaoyuzhouCredentials(e,t=l()){return Number.isFinite(e.expires_at)&&e.expires_at>0&&t>=e.expires_at-XIAOYUZHOU_REFRESH_SKEW_MS}export function buildXiaoyuzhouHeaders(e,t={}){const{contentType:r="application/json",includeLocalTime:i=!1,includeRefreshToken:o=!1}=t,n={"Content-Type":r,Host:"api.xiaoyuzhoufm.com","User-Agent":XIAOYUZHOU_DEFAULT_USER_AGENT,Market:"AppStore","App-BuildNo":"2908",OS:"ios",Manufacturer:"Apple",BundleID:"app.podcast.cosmos",Connection:"keep-alive","abtest-info":'{"old_user_discovery_feed":"enable"}',"Accept-Language":"en-HK;q=1.0, zh-Hans-HK;q=0.9",Model:"iPhone18,1","app-permissions":"100000",Accept:"*/*","App-Version":"2.98.0",WifiConnected:"true","OS-Version":"26.2.1","x-custom-xiaoyuzhou-app-dev":"","x-jike-device-id":e.device_id||XIAOYUZHOU_DEFAULT_DEVICE_ID,"x-jike-device-properties":e.device_properties??XIAOYUZHOU_DEFAULT_DEVICE_PROPERTIES};if(e.access_token)n["x-jike-access-token"]=e.access_token;if(o&&e.refresh_token)n["x-jike-refresh-token"]=e.refresh_token;if(i){n["Local-Time"]=new Date().toISOString();n.Timezone=Intl.DateTimeFormat().resolvedOptions().timeZone||"UTC"}return n}export async function refreshXiaoyuzhouCredentials(e,t=fetch){if(!e.refresh_token)throw p("Xiaoyuzhou refresh token is missing");let r;try{r=await t(`${XIAOYUZHOU_API_BASE_URL}/app_auth_tokens.refresh`,{method:"POST",headers:buildXiaoyuzhouHeaders(e,{contentType:"application/x-www-form-urlencoded; charset=utf-8",includeLocalTime:!0,includeRefreshToken:!0}),signal:AbortSignal.timeout(20000)})}catch(s){throw new a(`Failed to refresh Xiaoyuzhou credentials: ${c(s)}`)}const i=await r.text();if(!r.ok)throw p(`Xiaoyuzhou token refresh failed with HTTP ${r.status}${i?`: ${i}`:""}`);let o;try{o=JSON.parse(i)}catch(s){throw new a(`Xiaoyuzhou refresh returned invalid JSON: ${c(s)}`)}if(!o?.success)throw p("Xiaoyuzhou refresh API returned success=false");const n=normalizeXiaoyuzhouCredentials({...e,access_token:o["x-jike-access-token"]||"",refresh_token:o["x-jike-refresh-token"]||"",expires_at:l()+XIAOYUZHOU_TOKEN_TTL_MS});if(!n.access_token||!n.refresh_token)throw p("Xiaoyuzhou refresh API returned empty access_token or refresh_token");saveXiaoyuzhouCredentials(n);return n}function A(e,t){const r=new URL(e,XIAOYUZHOU_API_BASE_URL);if(t){for(const[i,o]of Object.entries(t))if(o!==void 0&&o!==null&&o!=="")r.searchParams.set(i,String(o))}return r.toString()}async function y(e,t,r,i){const{method:o="GET",query:n,body:s}=t;let u;try{u=await i(A(e,n),{method:o,headers:buildXiaoyuzhouHeaders(r,{contentType:"application/json",includeLocalTime:!0}),body:s===void 0?void 0:JSON.stringify(s),signal:AbortSignal.timeout(20000)})}catch(x){throw new a(`Failed to reach Xiaoyuzhou API: ${c(x)}`)}return u}export async function requestXiaoyuzhouJson(e,t={},r=fetch){let i=t.credentials??loadXiaoyuzhouCredentials();if(shouldRefreshXiaoyuzhouCredentials(i))i=await refreshXiaoyuzhouCredentials(i,r);let o=await y(e,t,i,r);if(o.status===401){i=await refreshXiaoyuzhouCredentials(i,r);o=await y(e,t,i,r)}const n=await o.text();if(!o.ok)throw new a(`Xiaoyuzhou API request failed with HTTP ${o.status}${n?`: ${n}`:""}`);let s;try{s=JSON.parse(n)}catch(u){throw new a(`Xiaoyuzhou API returned invalid JSON: ${c(u)}`)}if(s?.success===!1)throw new a(s?.message||s?.msg||"Xiaoyuzhou API returned success=false");return{credentials:i,raw:s,data:s?.data}}export async function fetchXiaoyuzhouTranscriptBody(e,t=fetch){let r;try{r=await t(e,{method:"GET",headers:{"User-Agent":XIAOYUZHOU_DEFAULT_USER_AGENT,Accept:"*/*",Market:"AppStore"},signal:AbortSignal.timeout(20000)})}catch(o){throw new a(`Failed to fetch Xiaoyuzhou transcript content: ${c(o)}`)}const i=await r.text();if(!r.ok)throw new a(`Xiaoyuzhou transcript download failed with HTTP ${r.status}${i?`: ${i}`:""}`);return i}export function extractTranscriptText(e){let t;try{t=JSON.parse(e)}catch{return{text:"",segmentCount:0}}let r=[];if(Array.isArray(t))r=t;else if(t&&typeof t==="object"){for(const o of["segments","data","transcript","items"])if(Array.isArray(t[o])){r=t[o];break}if(r.length===0){const o=typeof t.text==="string"?t.text.trim():"";if(o)return{text:o,segmentCount:1}}}const i=[];for(const o of r){if(!o||typeof o!=="object"||typeof o.text!=="string")continue;const n=o.text.trim();if(n)i.push(n)}return{text:i.join(`
3
+ `),segmentCount:i.length}}
@@ -1 +1 @@
1
- import*as T from"node:fs";import*as H from"node:path";import{cli as V,Strategy as W}from"@jackwener/opencli/registry";import{CliError as M}from"@jackwener/opencli/errors";import{httpDownload as Y,sanitizeFilename as Z}from"@jackwener/opencli/download";import{formatBytes as _}from"@jackwener/opencli/download/progress";import{loadXiaoyuzhouCredentials as $,requestXiaoyuzhouJson as k}from"./auth.js";V({site:"xiaoyuzhou",name:"download",access:"read",description:"Download Xiaoyuzhou episode audio",domain:"www.xiaoyuzhoufm.com",strategy:W.LOCAL,browser:!1,args:[{name:"id",positional:!0,required:!0,help:"Episode ID (eid from podcast-episodes output)"},{name:"output",default:"./xiaoyuzhou-downloads",help:"Output directory"}],columns:["title","podcast","status","size","file"],func:async(v)=>{const N=$(),A=(await k("/v1/episode/get",{query:{eid:v.id},credentials:N})).data;if(!A)throw new M("NOT_FOUND","Episode not found","Please check the ID");const G=A.media?.source?.url;if(!G)throw new M("PARSE_ERROR","Audio URL not found in episode payload","Episode payload does not expose media.source.url");const O=String(v.output||"./xiaoyuzhou-downloads"),Q=H.extname(new URL(G).pathname)||".mp3",I=String(A.title||"episode"),R=`${v.id}_${Z(I,80)||"episode"}${Q}`,K=H.join(O,String(v.id));T.mkdirSync(K,{recursive:!0});const L=H.join(K,R),b=await Y(G,L,{timeout:60000});return[{title:I,podcast:A.podcast?.title||"",status:b.success?"success":"failed",size:b.success?_(b.size):b.error||"unknown error",file:b.success?L:"-"}]}});
1
+ import*as m from"node:fs";import*as i from"node:path";import{cli as f,Strategy as h}from"@jackwener/opencli/registry";import{CliError as n}from"@jackwener/opencli/errors";import{httpDownload as w,sanitizeFilename as y}from"@jackwener/opencli/download";import{formatBytes as z}from"@jackwener/opencli/download/progress";import{loadXiaoyuzhouCredentials as x,requestXiaoyuzhouJson as D}from"./auth.js";f({site:"xiaoyuzhou",name:"download",access:"read",description:"Download Xiaoyuzhou episode audio",domain:"www.xiaoyuzhoufm.com",strategy:h.LOCAL,browser:!1,args:[{name:"id",positional:!0,required:!0,help:"Episode ID (eid from podcast-episodes output)"},{name:"output",default:"./xiaoyuzhou-downloads",help:"Output directory"}],columns:["title","podcast","status","size","file"],func:async(e)=>{const d=x(),t=(await D("/v1/episode/get",{query:{eid:e.id},credentials:d})).data;if(!t)throw new n("NOT_FOUND","Episode not found","Please check the ID");const s=t.media?.source?.url;if(!s)throw new n("PARSE_ERROR","Audio URL not found in episode payload","Episode payload does not expose media.source.url");const p=String(e.output||"./xiaoyuzhou-downloads"),c=i.extname(new URL(s).pathname)||".mp3",r=String(t.title||"episode"),l=`${e.id}_${y(r,80)||"episode"}${c}`,a=i.join(p,String(e.id));m.mkdirSync(a,{recursive:!0});const u=i.join(a,l),o=await w(s,u,{timeout:60000});return[{title:r,podcast:t.podcast?.title||"",status:o.success?"success":"failed",size:o.success?z(o.size):o.error||"unknown error",file:o.success?u:"-"}]}});
@@ -1 +1 @@
1
- export function formatDuration(b){if(!Number.isFinite(b)||b<0)return"-";b=Math.round(b);const h=Math.floor(b/60),j=b%60;return`${h}:${String(j).padStart(2,"0")}`}export function formatDate(b){if(!b)return"-";return b.slice(0,10)}
1
+ export function formatDuration(t){if(!Number.isFinite(t)||t<0)return"-";t=Math.round(t);const r=Math.floor(t/60),i=t%60;return`${r}:${String(i).padStart(2,"0")}`}export function formatDate(t){if(!t)return"-";return t.slice(0,10)}
@@ -1,4 +1,4 @@
1
- import{CliError as Y,CommandExecutionError as E}from"@jackwener/opencli/errors";import{cli as b,Strategy as m}from"@jackwener/opencli/registry";import{readFile as R,stat as k}from"node:fs/promises";import{publishArticle as v}from"../_shared/article/publish.js";export const xueqiuProfile={home:"https://mp.xueqiu.com/writeV2",outputFormat:"markdown",image:{spec:{url:"https://mp.xueqiu.com/xq/photo/upload.json",method:"POST",bodyType:"binary-multipart",fileField:"file",fileName:"image.jpg",responsePath:"url"},skip:["xueqiu.com","imedao.com"],uploadFn:async(J,D)=>{const z=await fetch(J,{credentials:"omit"});if(!z.ok)throw Error("图片下载失败: "+J);const U=await z.blob(),K=new FormData;K.append("file",U,"image.jpg");const H=await fetch("https://mp.xueqiu.com/xq/photo/upload.json",{method:"POST",credentials:"include",body:K}),B=await H.text();let Q=null;try{Q=JSON.parse(B)}catch(Z){}if(!H.ok||!Q||!Q.url||!Q.filename)throw Error("图片上传失败: "+B.slice(0,200));return{url:(Q.url.startsWith("//")?"https:"+Q.url:Q.url)+"/"+Q.filename}}},checkAuth:async(J)=>{try{const U=(await(await fetch("https://mp.xueqiu.com/writeV2",{method:"GET",credentials:"include"})).text()).match(/window\.UOM_CURRENTUSER\s*=\s*(\{[\s\S]*?\})\s*<\/script>/);if(!U)return{isAuthenticated:!1};let K=null;try{K=JSON.parse(U[1])}catch(Q){}const H=K&&K.currentUser;if(!H||!H.id)return{isAuthenticated:!1};const B=H.photo_domain&&H.profile_image_url?"https:"+H.photo_domain+(H.profile_image_url.split(",")[0]||""):"";return{isAuthenticated:!0,userId:String(H.id),username:H.screen_name||"",avatar:B}}catch(D){return{isAuthenticated:!1,error:String(D&&D.message||D)}}},publish:async(J,D)=>{const z=J.params||{};let U=J.content;const K=U.split(`
2
- `),H=[];let B=0;while(B<K.length){const G=K[B];if(G.startsWith("```")){let L="";B++;while(B<K.length&&!K[B].startsWith("```")){L+=(L?`
3
- `:"")+K[B];B++}H.push("<pre><code>"+L.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")+"</code></pre>");B++;continue}const V=G.match(/^#{1,6}\s+(.*)/);if(V){H.push("<h4>"+V[1]+"</h4>");B++;continue}const X=G.match(/^!\[([^\]]*)\]\(([^)]+)\)/);if(X){H.push('<img src="'+X[2]+'" alt="'+X[1]+'" class="ke_img">');B++;continue}if(/^[-*_]{3,}\s*$/.test(G)){B++;continue}if(!G.trim()){H.push("");B++;continue}let f=G.replace(/\*\*([^*]+)\*\*/g,"<b>$1</b>").replace(/\*([^*]+)\*/g,"<i>$1</i>").replace(/`([^`]+)`/g,"<code>$1</code>");H.push("<p>"+f+"</p>");B++}U=H.filter((G,V,X)=>{return!(G===""&&V>0&&X[V-1]==="")}).join(`
4
- `).trim();const Q=typeof z.coverPic==="string"?z.coverPic.trim():"";if(Q&&!/(imedao\.com|xueqiu\.com)/.test(Q))return{ok:!1,stage:"cover",message:"封面图必须是雪球图床地址(含 imedao.com / xueqiu.com);外链需先上传。当前:"+Q.slice(0,120)};const $=new URLSearchParams({text:U,title:J.title,cover_pic:Q,flags:"false",original_event:"",status_id:"",legal_user_visible:"false",is_private:"false"}),Z=await fetch("https://mp.xueqiu.com/xq/statuses/draft/save.json",{method:"POST",credentials:"include",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:$}),y=await Z.text();let F=null;try{F=JSON.parse(y)}catch(G){}if(!Z.ok||!F||!F.id)return{ok:!1,stage:"save",status:Z.status,message:F&&F.error_description||y.slice(0,300)};const M=String(F.id);if(J.draftOnly)return{ok:!0,id:M,url:"https://mp.xueqiu.com/write/draft/"+M,draft:!0};let _=typeof z.originalEventId==="string"?z.originalEventId.trim():"",j="",q=!0;if(_)try{const V=await(await fetch("/xq/statuses/original/original_event.json?id="+encodeURIComponent(_),{credentials:"include"})).json(),X=V&&V.originalEvent;if(!X||X.id==null)return{ok:!1,stage:"original_event",message:"原创活动事件不存在:"+_+"(用 `xueqiu events` 列举热门事件)"};if(X.disabled)return{ok:!1,stage:"original_event",message:"原创活动事件已停用,不可参与:"+_};j=String(X.tag||"")}catch(G){return{ok:!1,stage:"original_event",message:"校验原创活动事件失败:"+String(G&&G.message||G)}}else q=!1;let S="";try{const V=await(await fetch("/xq/provider/session/token.json?api_path="+encodeURIComponent("/statuses/update.json"),{credentials:"include"})).json();S=V&&V.session_token?String(V.session_token):""}catch(G){return{ok:!1,stage:"csrf",message:"获取发布 CSRF token 失败:"+String(G&&G.message||G)}}if(!S)return{ok:!1,stage:"csrf",message:"未取得发布 CSRF token(session_token 为空)"};const T=z.showCoverPic===!1?"false":"true",h=z.original===!0?"true":"false",x=z.allowReward===!0?"true":"false",P=new URLSearchParams({title:J.title,status:U,draft_id:M,session_token:S,cover_pic:Q,show_cover_pic:T,original:h,industry_category_name:"",original_event_id:q?_:"",original_event_tag:q?j:"",original_event_active:q?"true":"false",legal_user_visible:"false",is_private:"false",legal_user_state:"open",allow_reward:x}),A=await fetch("https://mp.xueqiu.com/xq/statuses/update.json",{method:"POST",credentials:"include",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:P}),C=await A.text();let W=null;try{W=JSON.parse(C)}catch(G){}if(!A.ok||!W||!W.id)return{ok:!1,stage:"publish",status:A.status,message:W&&(W.error_description||W.error_code)||C.slice(0,300)};const N=String(W.id);let O="";if(W.user_id!=null)O=String(W.user_id);else if(W.user&&W.user.id!=null)O=String(W.user.id);if(!O)try{const G=(document.documentElement.outerHTML||"").match(/UOM_CURRENTUSER\s*=\s*(\{[\s\S]*?\})\s*<\/script>/);if(G){const V=JSON.parse(G[1]).currentUser;if(V&&V.id!=null)O=String(V.id)}}catch(G){}const I=O?"https://xueqiu.com/"+O+"/"+N:"https://xueqiu.com/"+N;return{ok:!0,id:N,url:I,draft:!1}}};function w(J){if(!J.execute)throw new Y("INVALID_INPUT","此命令需要 --execute 参数才能实际写入,防止误操作。注意:本报错仅表示缺少 --execute,并未校验其余参数,不能当 dry-run 预览用")}async function c(J){const D=typeof J.text==="string"?J.text:void 0,z=typeof J.file==="string"?J.file:void 0;if(D&&z)throw new Y("INVALID_INPUT","不能同时使用 <text> 和 --file,请选一种");let U=D??"";if(z){let K;try{K=await k(z)}catch{throw new Y("INVALID_INPUT","文件不存在: "+z)}if(!K.isFile())throw new Y("INVALID_INPUT","路径必须是可读文本文件: "+z);let H;try{H=await R(z)}catch{throw new Y("INVALID_INPUT","文件读取失败: "+z)}try{U=new TextDecoder("utf-8",{fatal:!0}).decode(H)}catch{throw new Y("INVALID_INPUT","文件不是合法 UTF-8 文本: "+z)}}if(!U.trim())throw new Y("INVALID_INPUT","正文不能为空");return U}function d(J,D,z,U,K={}){return[{status:"success",outcome:U,message:J,target_type:D,target:z,...K}]}b({site:"xueqiu",name:"article",access:"write",description:"发布雪球文章(长文)。默认正式发布,加 --draft 仅存草稿。正文默认 Markdown,图片自动转存到雪球图床。",domain:"mp.xueqiu.com",strategy:m.COOKIE,browser:!0,args:[{name:"title",positional:!0,required:!0,help:"文章标题"},{name:"text",positional:!0,help:"正文(默认 Markdown;传 --html 则视为原始 HTML)"},{name:"file",help:"正文文件路径(UTF-8,默认 Markdown)"},{name:"html",type:"boolean",help:"把正文视为原始 HTML 而非 Markdown"},{name:"cover-image",help:"封面图地址(必须是雪球图床 imedao.com/xueqiu.com 的 url;外链请先上传)。可空=无封面"},{name:"no-cover",type:"boolean",help:"有封面图时不在文章头部展示封面(show_cover_pic=false)"},{name:"original",type:"boolean",help:"声明原创(需账号有原创权限,否则发布会被拒)。默认非原创"},{name:"original-event-id",help:"参与的原创活动/事件 id(精确校验,找不到/已停用报错);合法值用 `xueqiu events` 列举。可空=不参与"},{name:"allow-reward",type:"boolean",help:"允许打赏。默认不允许"},{name:"draft",type:"boolean",help:"仅保存为草稿,不正式发布"},{name:"execute",type:"boolean",help:"实际执行写入;不加此参数命令拒绝写操作"}],columns:["status","outcome","message","target_type","target","created_target","created_url"],func:async(J,D)=>{if(!J)throw new E("雪球文章发布需要浏览器会话(browser session)");w(D);const z=String(D.title??"").trim();if(!z)throw new Y("INVALID_INPUT","文章标题不能为空");const U=await c(D),K=Boolean(D.draft),H={coverPic:typeof D["cover-image"]==="string"?D["cover-image"].trim():"",showCoverPic:!D["no-cover"],original:Boolean(D.original),originalEventId:typeof D["original-event-id"]==="string"?D["original-event-id"].trim():"",allowReward:Boolean(D["allow-reward"])},B=await v(J,{title:z,body:U,format:D.html?"html":"markdown",draftOnly:K,profile:xueqiuProfile,publishParams:H}),Q=B.images.uploaded.length|0,$=B.images.failed.length|0;let Z=B.draft?"已保存雪球文章草稿(需在写作页手动发布)":"已正式发布雪球文章";if(Q||$)Z+=`;图片: ${Q} 张已转存${$?`,${$} 张失败`:""}`;return d(Z,"article","",B.draft?"draft":"created",{created_target:"article:"+B.id,created_url:B.url})}});
1
+ import{CliError as m,CommandExecutionError as A}from"@jackwener/opencli/errors";import{cli as O,Strategy as j}from"@jackwener/opencli/registry";import{readFile as C,stat as L}from"node:fs/promises";import{publishArticle as D}from"../_shared/article/publish.js";export const xueqiuProfile={home:"https://mp.xueqiu.com/writeV2",outputFormat:"markdown",image:{spec:{url:"https://mp.xueqiu.com/xq/photo/upload.json",method:"POST",bodyType:"binary-multipart",fileField:"file",fileName:"image.jpg",responsePath:"url"},skip:["xueqiu.com","imedao.com"],uploadFn:async(o,i)=>{const e=await fetch(o,{credentials:"omit"});if(!e.ok)throw Error("图片下载失败: "+o);const l=await e.blob(),s=new FormData;s.append("file",l,"image.jpg");const a=await fetch("https://mp.xueqiu.com/xq/photo/upload.json",{method:"POST",credentials:"include",body:s}),t=await a.text();let n=null;try{n=JSON.parse(t)}catch(p){}if(!a.ok||!n||!n.url||!n.filename)throw Error("图片上传失败: "+t.slice(0,200));return{url:(n.url.startsWith("//")?"https:"+n.url:n.url)+"/"+n.filename}}},checkAuth:async(o)=>{try{const l=(await(await fetch("https://mp.xueqiu.com/writeV2",{method:"GET",credentials:"include"})).text()).match(/window\.UOM_CURRENTUSER\s*=\s*(\{[\s\S]*?\})\s*<\/script>/);if(!l)return{isAuthenticated:!1};let s=null;try{s=JSON.parse(l[1])}catch(n){}const a=s&&s.currentUser;if(!a||!a.id)return{isAuthenticated:!1};const t=a.photo_domain&&a.profile_image_url?"https:"+a.photo_domain+(a.profile_image_url.split(",")[0]||""):"";return{isAuthenticated:!0,userId:String(a.id),username:a.screen_name||"",avatar:t}}catch(i){return{isAuthenticated:!1,error:String(i&&i.message||i)}}},publish:async(o,i)=>{const e=o.params||{};let l=o.content;const s=l.split(`
2
+ `),a=[];let t=0;while(t<s.length){const r=s[t];if(r.startsWith("```")){let P="";t++;while(t<s.length&&!s[t].startsWith("```")){P+=(P?`
3
+ `:"")+s[t];t++}a.push("<pre><code>"+P.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")+"</code></pre>");t++;continue}const c=r.match(/^#{1,6}\s+(.*)/);if(c){a.push("<h4>"+c[1]+"</h4>");t++;continue}const d=r.match(/^!\[([^\]]*)\]\(([^)]+)\)/);if(d){a.push('<img src="'+d[2]+'" alt="'+d[1]+'" class="ke_img">');t++;continue}if(/^[-*_]{3,}\s*$/.test(r)){t++;continue}if(!r.trim()){a.push("");t++;continue}let k=r.replace(/\*\*([^*]+)\*\*/g,"<b>$1</b>").replace(/\*([^*]+)\*/g,"<i>$1</i>").replace(/`([^`]+)`/g,"<code>$1</code>");a.push("<p>"+k+"</p>");t++}l=a.filter((r,c,d)=>{return!(r===""&&c>0&&d[c-1]==="")}).join(`
4
+ `).trim();const n=typeof e.coverPic==="string"?e.coverPic.trim():"";if(n&&!/(imedao\.com|xueqiu\.com)/.test(n))return{ok:!1,stage:"cover",message:"封面图必须是雪球图床地址(含 imedao.com / xueqiu.com);外链需先上传。当前:"+n.slice(0,120)};const f=new URLSearchParams({text:l,title:o.title,cover_pic:n,flags:"false",original_event:"",status_id:"",legal_user_visible:"false",is_private:"false"}),p=await fetch("https://mp.xueqiu.com/xq/statuses/draft/save.json",{method:"POST",credentials:"include",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:f}),S=await p.text();let h=null;try{h=JSON.parse(S)}catch(r){}if(!p.ok||!h||!h.id)return{ok:!1,stage:"save",status:p.status,message:h&&h.error_description||S.slice(0,300)};const v=String(h.id);if(o.draftOnly)return{ok:!0,id:v,url:"https://mp.xueqiu.com/write/draft/"+v,draft:!0};let w=typeof e.originalEventId==="string"?e.originalEventId.trim():"",I="",_=!0;if(w)try{const c=await(await fetch("/xq/statuses/original/original_event.json?id="+encodeURIComponent(w),{credentials:"include"})).json(),d=c&&c.originalEvent;if(!d||d.id==null)return{ok:!1,stage:"original_event",message:"原创活动事件不存在:"+w+"(用 `xueqiu events` 列举热门事件)"};if(d.disabled)return{ok:!1,stage:"original_event",message:"原创活动事件已停用,不可参与:"+w};I=String(d.tag||"")}catch(r){return{ok:!1,stage:"original_event",message:"校验原创活动事件失败:"+String(r&&r.message||r)}}else _=!1;let y="";try{const c=await(await fetch("/xq/provider/session/token.json?api_path="+encodeURIComponent("/statuses/update.json"),{credentials:"include"})).json();y=c&&c.session_token?String(c.session_token):""}catch(r){return{ok:!1,stage:"csrf",message:"获取发布 CSRF token 失败:"+String(r&&r.message||r)}}if(!y)return{ok:!1,stage:"csrf",message:"未取得发布 CSRF token(session_token 为空)"};const q=e.showCoverPic===!1?"false":"true",N=e.original===!0?"true":"false",R=e.allowReward===!0?"true":"false",U=new URLSearchParams({title:o.title,status:l,draft_id:v,session_token:y,cover_pic:n,show_cover_pic:q,original:N,industry_category_name:"",original_event_id:_?w:"",original_event_tag:_?I:"",original_event_active:_?"true":"false",legal_user_visible:"false",is_private:"false",legal_user_state:"open",allow_reward:R}),x=await fetch("https://mp.xueqiu.com/xq/statuses/update.json",{method:"POST",credentials:"include",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:U}),T=await x.text();let u=null;try{u=JSON.parse(T)}catch(r){}if(!x.ok||!u||!u.id)return{ok:!1,stage:"publish",status:x.status,message:u&&(u.error_description||u.error_code)||T.slice(0,300)};const b=String(u.id);let g="";if(u.user_id!=null)g=String(u.user_id);else if(u.user&&u.user.id!=null)g=String(u.user.id);if(!g)try{const r=(document.documentElement.outerHTML||"").match(/UOM_CURRENTUSER\s*=\s*(\{[\s\S]*?\})\s*<\/script>/);if(r){const c=JSON.parse(r[1]).currentUser;if(c&&c.id!=null)g=String(c.id)}}catch(r){}const E=g?"https://xueqiu.com/"+g+"/"+b:"https://xueqiu.com/"+b;return{ok:!0,id:b,url:E,draft:!1}}};function F(o){if(!o.execute)throw new m("INVALID_INPUT","此命令需要 --execute 参数才能实际写入,防止误操作。注意:本报错仅表示缺少 --execute,并未校验其余参数,不能当 dry-run 预览用")}async function M(o){const i=typeof o.text==="string"?o.text:void 0,e=typeof o.file==="string"?o.file:void 0;if(i&&e)throw new m("INVALID_INPUT","不能同时使用 <text> 和 --file,请选一种");let l=i??"";if(e){let s;try{s=await L(e)}catch{throw new m("INVALID_INPUT","文件不存在: "+e)}if(!s.isFile())throw new m("INVALID_INPUT","路径必须是可读文本文件: "+e);let a;try{a=await C(e)}catch{throw new m("INVALID_INPUT","文件读取失败: "+e)}try{l=new TextDecoder("utf-8",{fatal:!0}).decode(a)}catch{throw new m("INVALID_INPUT","文件不是合法 UTF-8 文本: "+e)}}if(!l.trim())throw new m("INVALID_INPUT","正文不能为空");return l}function V(o,i,e,l,s={}){return[{status:"success",outcome:l,message:o,target_type:i,target:e,...s}]}O({site:"xueqiu",name:"article",access:"write",description:"发布雪球文章(长文)。默认正式发布,加 --draft 仅存草稿。正文默认 Markdown,图片自动转存到雪球图床。",domain:"mp.xueqiu.com",strategy:j.COOKIE,browser:!0,args:[{name:"title",positional:!0,required:!0,help:"文章标题"},{name:"text",positional:!0,help:"正文(默认 Markdown;传 --html 则视为原始 HTML)"},{name:"file",help:"正文文件路径(UTF-8,默认 Markdown)"},{name:"html",type:"boolean",help:"把正文视为原始 HTML 而非 Markdown"},{name:"cover-image",help:"封面图地址(必须是雪球图床 imedao.com/xueqiu.com 的 url;外链请先上传)。可空=无封面"},{name:"no-cover",type:"boolean",help:"有封面图时不在文章头部展示封面(show_cover_pic=false)"},{name:"original",type:"boolean",help:"声明原创(需账号有原创权限,否则发布会被拒)。默认非原创"},{name:"original-event-id",help:"参与的原创活动/事件 id(精确校验,找不到/已停用报错);合法值用 `xueqiu events` 列举。可空=不参与"},{name:"allow-reward",type:"boolean",help:"允许打赏。默认不允许"},{name:"draft",type:"boolean",help:"仅保存为草稿,不正式发布"},{name:"execute",type:"boolean",help:"实际执行写入;不加此参数命令拒绝写操作"}],columns:["status","outcome","message","target_type","target","created_target","created_url"],func:async(o,i)=>{if(!o)throw new A("雪球文章发布需要浏览器会话(browser session)");F(i);const e=String(i.title??"").trim();if(!e)throw new m("INVALID_INPUT","文章标题不能为空");const l=await M(i),s=Boolean(i.draft),a={coverPic:typeof i["cover-image"]==="string"?i["cover-image"].trim():"",showCoverPic:!i["no-cover"],original:Boolean(i.original),originalEventId:typeof i["original-event-id"]==="string"?i["original-event-id"].trim():"",allowReward:Boolean(i["allow-reward"])},t=await D(o,{title:e,body:l,format:i.html?"html":"markdown",draftOnly:s,profile:xueqiuProfile,publishParams:a}),n=t.images.uploaded.length|0,f=t.images.failed.length|0;let p=t.draft?"已保存雪球文章草稿(需在写作页手动发布)":"已正式发布雪球文章";if(n||f)p+=`;图片: ${n} 张已转存${f?`,${f} 张失败`:""}`;return V(p,"article","",t.draft?"draft":"created",{created_target:"article:"+t.id,created_url:t.url})}});
@@ -1,13 +1,13 @@
1
- import{cli as L,Strategy as P}from"@jackwener/opencli/registry";import{ArgumentError as Q,AuthRequiredError as z,CommandExecutionError as M,EmptyResultError as T}from"@jackwener/opencli/errors";import{log as U}from"@jackwener/opencli/logger";import{isRecord as K}from"@jackwener/opencli/utils";const f=/^(?:[A-Z]{2}\d{5,6}|\d{4,6}|[A-Z]{1,5}(?:[.-][A-Z]{1,2})?)$/,x={auth:"auth failure","anti-bot":"anti-bot challenge",argument:"invalid symbol",empty:"no more discussion data",incompatible:"unexpected response shape",unknown:"unknown request failure"};function _(G){if(Array.isArray(G.list))return G.list;if(K(G.data)&&Array.isArray(G.data.list))return G.data.list;return null}function S(G,J){const V=`${J} ${G.textSnippet}`.toLowerCase();return G.contentType.includes("text/html")&&(/captcha|challenge|aliyun_waf|risk/i.test(V)||/_WAF_|_waf_|renderData|aliyun_waf/i.test(G.textSnippet))}function O(G){const J=Number(G??0);return Number.isFinite(J)?J:0}function F(G){if(typeof G==="string")return G.trim();if(typeof G==="number"&&Number.isFinite(G))return String(G);return""}function B(G,J,V,Z){return`xueqiu comments pagination stopped after request ${G}, collected ${J}/${V} items, reason: ${Z}`}function q(G,J){if(G==="auth"||G==="anti-bot")throw new z("xueqiu.com","Stock discussions require login or challenge clearance");if(G==="argument")throw new Q(`xueqiu comments received an invalid symbol: ${J}`);if(G==="empty")throw new T(`xueqiu/comments ${J}`,`No discussion data found for ${J}`);throw new M(`Unexpected response while loading xueqiu comments for ${J}`,"Run the command again with --verbose to inspect the raw site response.")}export function getCommentItems(G){if(!K(G))return[];return(_(G)??[]).filter((V)=>!!V&&typeof V==="object")}export function classifyXueqiuCommentsResponse(G){const J=K(G.json)?G.json:null,V=J?_(J):null,Z=[J?.error,J?.errors,J?.code,J?.message,J?.msg].filter(Boolean).join(" ").toLowerCase(),W=`${Z} ${G.textSnippet}`.toLowerCase();if(S(G,Z))return{kind:"anti-bot"};if(G.status===401||G.status===403)return{kind:"auth"};if(/login required|unauthorized|unauthorised|forbidden|not logged in|need login/.test(W))return{kind:"auth"};if(/invalid symbol|invalid code|bad symbol/.test(Z))return{kind:"argument"};if(/no data|no result|not found|no matching/.test(Z))return{kind:"empty"};if(V&&V.length===0)return{kind:"empty"};if(G.contentType.includes("application/json")&&J&&V===null)return{kind:"incompatible"};return{kind:"unknown"}}export function mergeUniqueCommentRows(G,J){const V=[...G],Z=new Set(G.map((W)=>W.id));for(const W of J){if(Z.has(W.id))continue;Z.add(W.id);V.push(W)}return V}export function normalizeCommentItem(G){const J=String(G.description??"").replace(/<[^>]+>/g," ").replace(/&nbsp;/g," ").replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/\s+/g," ").trim(),V=F(G.id),Z=F(G.user?.id),W=G.created_at?new Date(G.created_at):null,X=W&&!Number.isNaN(W.getTime())?W.toISOString():null;return{id:V,author:String(G.user?.screen_name??""),text:J,likes:O(G.fav_count),replies:O(G.reply_count),retweets:O(G.retweet_count),created_at:X,url:Z&&V?`https://xueqiu.com/${Z}/${V}`:null}}export function toCommentOutputRow(G){const{id:J,...V}=G;return V}export function describeFailureKind(G){return x[G]}export async function fetchCommentsPage(G,J,V,Z){const W=new URL("https://xueqiu.com/query/v1/symbol/search/status");W.searchParams.set("symbol",J);W.searchParams.set("count",String(Z));W.searchParams.set("page",String(V));W.searchParams.set("sort","time");return G.evaluate(`
1
+ import{cli as x,Strategy as b}from"@jackwener/opencli/registry";import{ArgumentError as a,AuthRequiredError as q,CommandExecutionError as g,EmptyResultError as S}from"@jackwener/opencli/errors";import{log as h}from"@jackwener/opencli/logger";import{isRecord as m}from"@jackwener/opencli/utils";const k=/^(?:[A-Z]{2}\d{5,6}|\d{4,6}|[A-Z]{1,5}(?:[.-][A-Z]{1,2})?)$/,R={auth:"auth failure","anti-bot":"anti-bot challenge",argument:"invalid symbol",empty:"no more discussion data",incompatible:"unexpected response shape",unknown:"unknown request failure"};function w(e){if(Array.isArray(e.list))return e.list;if(m(e.data)&&Array.isArray(e.data.list))return e.data.list;return null}function _(e,t){const n=`${t} ${e.textSnippet}`.toLowerCase();return e.contentType.includes("text/html")&&(/captcha|challenge|aliyun_waf|risk/i.test(n)||/_WAF_|_waf_|renderData|aliyun_waf/i.test(e.textSnippet))}function d(e){const t=Number(e??0);return Number.isFinite(t)?t:0}function y(e){if(typeof e==="string")return e.trim();if(typeof e==="number"&&Number.isFinite(e))return String(e);return""}function l(e,t,n,i){return`xueqiu comments pagination stopped after request ${e}, collected ${t}/${n} items, reason: ${i}`}function A(e,t){if(e==="auth"||e==="anti-bot")throw new q("xueqiu.com","Stock discussions require login or challenge clearance");if(e==="argument")throw new a(`xueqiu comments received an invalid symbol: ${t}`);if(e==="empty")throw new S(`xueqiu/comments ${t}`,`No discussion data found for ${t}`);throw new g(`Unexpected response while loading xueqiu comments for ${t}`,"Run the command again with --verbose to inspect the raw site response.")}export function getCommentItems(e){if(!m(e))return[];return(w(e)??[]).filter((n)=>!!n&&typeof n==="object")}export function classifyXueqiuCommentsResponse(e){const t=m(e.json)?e.json:null,n=t?w(t):null,i=[t?.error,t?.errors,t?.code,t?.message,t?.msg].filter(Boolean).join(" ").toLowerCase(),r=`${i} ${e.textSnippet}`.toLowerCase();if(_(e,i))return{kind:"anti-bot"};if(e.status===401||e.status===403)return{kind:"auth"};if(/login required|unauthorized|unauthorised|forbidden|not logged in|need login/.test(r))return{kind:"auth"};if(/invalid symbol|invalid code|bad symbol/.test(i))return{kind:"argument"};if(/no data|no result|not found|no matching/.test(i))return{kind:"empty"};if(n&&n.length===0)return{kind:"empty"};if(e.contentType.includes("application/json")&&t&&n===null)return{kind:"incompatible"};return{kind:"unknown"}}export function mergeUniqueCommentRows(e,t){const n=[...e],i=new Set(e.map((r)=>r.id));for(const r of t){if(i.has(r.id))continue;i.add(r.id);n.push(r)}return n}export function normalizeCommentItem(e){const t=String(e.description??"").replace(/<[^>]+>/g," ").replace(/&nbsp;/g," ").replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/\s+/g," ").trim(),n=y(e.id),i=y(e.user?.id),r=e.created_at?new Date(e.created_at):null,u=r&&!Number.isNaN(r.getTime())?r.toISOString():null;return{id:n,author:String(e.user?.screen_name??""),text:t,likes:d(e.fav_count),replies:d(e.reply_count),retweets:d(e.retweet_count),created_at:u,url:i&&n?`https://xueqiu.com/${i}/${n}`:null}}export function toCommentOutputRow(e){const{id:t,...n}=e;return n}export function describeFailureKind(e){return R[e]}export async function fetchCommentsPage(e,t,n,i){const r=new URL("https://xueqiu.com/query/v1/symbol/search/status");r.searchParams.set("symbol",t);r.searchParams.set("count",String(i));r.searchParams.set("page",String(n));r.searchParams.set("sort","time");return e.evaluate(`
2
2
  (async () => {
3
3
  try {
4
- const response = await fetch(${JSON.stringify(W.toString())}, {
4
+ const response = await fetch(${JSON.stringify(r.toString())}, {
5
5
  credentials: 'include',
6
6
  headers: {
7
7
  'accept': 'application/json, text/plain, */*',
8
8
  'x-requested-with': 'XMLHttpRequest',
9
9
  },
10
- referrer: ${JSON.stringify(`https://xueqiu.com/S/${J}`)},
10
+ referrer: ${JSON.stringify(`https://xueqiu.com/S/${t}`)},
11
11
  referrerPolicy: 'strict-origin-when-cross-origin',
12
12
  });
13
13
  const contentType = response.headers.get('content-type') || '';
@@ -35,4 +35,4 @@ import{cli as L,Strategy as P}from"@jackwener/opencli/registry";import{ArgumentE
35
35
  };
36
36
  }
37
37
  })()
38
- `)}export async function collectCommentRows(G){const J=G.warn??U.warn;let V=[];const Z=new Set;for(let W=1;W<=G.maxRequests;W+=1){const X=await G.fetchPage(W,G.pageSize),$=classifyXueqiuCommentsResponse(X);if(W===1&&$.kind!=="unknown")q($.kind,G.symbol);else if($.kind==="empty")break;else if($.kind!=="unknown"){J(B(W,V.length,G.limit,describeFailureKind($.kind)));break}const Y=getCommentItems(X.json),h=Y.map((H)=>normalizeCommentItem(H)).filter((H)=>H.id);if(h.length===0){if(W===1)throw new M(`Unexpected response while loading xueqiu comments for ${G.symbol}`,"Run the command again with --verbose to inspect the raw site response.");if($.kind==="unknown")J(B(W,V.length,G.limit,describeFailureKind($.kind)));break}let D=!1;for(const H of h){if(Z.has(H.id))continue;Z.add(H.id);V.push(H);D=!0}if(V.length>=G.limit)return V.slice(0,G.limit);if(Y.length<G.pageSize)break;if(!D){J(B(W,V.length,G.limit,"pagination did not advance"));break}if(W===G.maxRequests)J(B(W,V.length,G.limit,"reached safety cap"))}return V.slice(0,G.limit)}L({site:"xueqiu",name:"comments",access:"read",description:"获取单只股票的讨论动态",domain:"xueqiu.com",strategy:P.COOKIE,browser:!0,navigateBefore:!1,args:[{name:"symbol",positional:!0,required:!0,help:"Stock symbol, e.g. SH600519, AAPL, or 00700"},{name:"limit",type:"int",default:20,help:"Number of discussion posts to return"}],columns:["author","text","likes","replies","retweets","created_at","url"],func:async(G,J)=>{const V=normalizeSymbolInput(J.symbol),Z=Number(J.limit);if(!Number.isInteger(Z)||Z<=0)throw new Q("xueqiu comments requires --limit to be a positive integer");if(Z>100)throw new Q("xueqiu comments supports --limit up to 100");const W=Math.min(Z,20);await G.goto("https://xueqiu.com");return(await collectCommentRows({symbol:V,limit:Z,pageSize:W,maxRequests:5,fetchPage:($,Y)=>fetchCommentsPage(G,V,$,Y),warn:U.warn})).map(($)=>toCommentOutputRow($))}});export function normalizeSymbolInput(G){const J=String(G??"").trim().toUpperCase();if(!J)throw new Q("xueqiu comments requires a symbol");if(/^HTTPS?:\/\//.test(J))throw new Q("xueqiu comments only accepts a symbol, not a URL");if(!f.test(J))throw new Q(`xueqiu comments received an invalid symbol: ${J}`);return J}
38
+ `)}export async function collectCommentRows(e){const t=e.warn??h.warn;let n=[];const i=new Set;for(let r=1;r<=e.maxRequests;r+=1){const u=await e.fetchPage(r,e.pageSize),o=classifyXueqiuCommentsResponse(u);if(r===1&&o.kind!=="unknown")A(o.kind,e.symbol);else if(o.kind==="empty")break;else if(o.kind!=="unknown"){t(l(r,n.length,e.limit,describeFailureKind(o.kind)));break}const c=getCommentItems(u.json),p=c.map((s)=>normalizeCommentItem(s)).filter((s)=>s.id);if(p.length===0){if(r===1)throw new g(`Unexpected response while loading xueqiu comments for ${e.symbol}`,"Run the command again with --verbose to inspect the raw site response.");if(o.kind==="unknown")t(l(r,n.length,e.limit,describeFailureKind(o.kind)));break}let f=!1;for(const s of p){if(i.has(s.id))continue;i.add(s.id);n.push(s);f=!0}if(n.length>=e.limit)return n.slice(0,e.limit);if(c.length<e.pageSize)break;if(!f){t(l(r,n.length,e.limit,"pagination did not advance"));break}if(r===e.maxRequests)t(l(r,n.length,e.limit,"reached safety cap"))}return n.slice(0,e.limit)}x({site:"xueqiu",name:"comments",access:"read",description:"获取单只股票的讨论动态",domain:"xueqiu.com",strategy:b.COOKIE,browser:!0,navigateBefore:!1,args:[{name:"symbol",positional:!0,required:!0,help:"Stock symbol, e.g. SH600519, AAPL, or 00700"},{name:"limit",type:"int",default:20,help:"Number of discussion posts to return"}],columns:["author","text","likes","replies","retweets","created_at","url"],func:async(e,t)=>{const n=normalizeSymbolInput(t.symbol),i=Number(t.limit);if(!Number.isInteger(i)||i<=0)throw new a("xueqiu comments requires --limit to be a positive integer");if(i>100)throw new a("xueqiu comments supports --limit up to 100");const r=Math.min(i,20);await e.goto("https://xueqiu.com");return(await collectCommentRows({symbol:n,limit:i,pageSize:r,maxRequests:5,fetchPage:(o,c)=>fetchCommentsPage(e,n,o,c),warn:h.warn})).map((o)=>toCommentOutputRow(o))}});export function normalizeSymbolInput(e){const t=String(e??"").trim().toUpperCase();if(!t)throw new a("xueqiu comments requires a symbol");if(/^HTTPS?:\/\//.test(t))throw new a("xueqiu comments only accepts a symbol, not a URL");if(!k.test(t))throw new a(`xueqiu comments received an invalid symbol: ${t}`);return t}
@@ -1,4 +1,4 @@
1
- export const DANJUAN_DOMAIN="danjuanfunds.com",DANJUAN_ASSET_PAGE=`https://${DANJUAN_DOMAIN}/my-money`;const C=`https://${DANJUAN_DOMAIN}/djapi/fundx/profit/assets/gain?gains=%5B%22private%22%5D`,H=`https://${DANJUAN_DOMAIN}/djapi/fundx/profit/assets/summary?invest_account_id=`;export async function fetchDanjuanAll(z){const k=await z.evaluate(`
1
+ export const DANJUAN_DOMAIN="danjuanfunds.com",DANJUAN_ASSET_PAGE=`https://${DANJUAN_DOMAIN}/my-money`;const c=`https://${DANJUAN_DOMAIN}/djapi/fundx/profit/assets/gain?gains=%5B%22private%22%5D`,r=`https://${DANJUAN_DOMAIN}/djapi/fundx/profit/assets/summary?invest_account_id=`;export async function fetchDanjuanAll(n){const a=await n.evaluate(`
2
2
  (async () => {
3
3
  const f = async (u) => {
4
4
  const r = await fetch(u, { credentials: 'include' });
@@ -7,7 +7,7 @@ export const DANJUAN_DOMAIN="danjuanfunds.com",DANJUAN_ASSET_PAGE=`https://${DAN
7
7
  };
8
8
  const n = (v) => { const x = Number(v); return Number.isFinite(x) ? x : null; };
9
9
 
10
- const gain = await f(${JSON.stringify(C)});
10
+ const gain = await f(${JSON.stringify(c)});
11
11
  if (gain._err) return { _httpError: gain._err };
12
12
 
13
13
  const root = gain.data || {};
@@ -30,7 +30,7 @@ export const DANJUAN_DOMAIN="danjuanfunds.com",DANJUAN_ASSET_PAGE=`https://${DAN
30
30
  }
31
31
 
32
32
  const details = await Promise.all(
33
- accounts.map(a => f(${JSON.stringify(H)} + encodeURIComponent(a.accountId)))
33
+ accounts.map(a => f(${JSON.stringify(r)} + encodeURIComponent(a.accountId)))
34
34
  );
35
35
 
36
36
  const holdings = [];
@@ -81,4 +81,4 @@ export const DANJUAN_DOMAIN="danjuanfunds.com",DANJUAN_ASSET_PAGE=`https://${DAN
81
81
  detailErrors,
82
82
  };
83
83
  })()
84
- `);if(k?._httpError)throw Error(`HTTP ${k._httpError} — Hint: not logged in to ${DANJUAN_DOMAIN}?`);if(k?._emptyAccounts)throw Error(`No fund accounts found — Hint: not logged in to ${DANJUAN_DOMAIN}?`);if(Array.isArray(k?.detailErrors)&&k.detailErrors.length>0){const B=k.detailErrors.map((q)=>{return`${q.accountName&&q.accountId?`${q.accountName} (${q.accountId})`:q.accountName||q.accountId||"unknown account"}: ${q.error}`}).join(", ");throw Error(`Failed to fetch Danjuan account details: ${B}`)}return k}
84
+ `);if(a?._httpError)throw Error(`HTTP ${a._httpError} — Hint: not logged in to ${DANJUAN_DOMAIN}?`);if(a?._emptyAccounts)throw Error(`No fund accounts found — Hint: not logged in to ${DANJUAN_DOMAIN}?`);if(Array.isArray(a?.detailErrors)&&a.detailErrors.length>0){const o=a.detailErrors.map((t)=>{return`${t.accountName&&t.accountId?`${t.accountName} (${t.accountId})`:t.accountName||t.accountId||"unknown account"}: ${t.error}`}).join(", ");throw Error(`Failed to fetch Danjuan account details: ${o}`)}return a}
@@ -1 +1 @@
1
- import{cli as N}from"@jackwener/opencli/registry";import{EmptyResultError as O}from"@jackwener/opencli/errors";import{fetchXueqiuJson as P,formatChinaDate as Q}from"./utils.js";N({site:"xueqiu",name:"earnings-date",access:"read",description:"获取股票预计财报发布日期(公司大事)",domain:"xueqiu.com",browser:!0,args:[{name:"symbol",required:!0,positional:!0,help:"股票代码,如 SH600519、SZ000858、00700"},{name:"next",type:"bool",default:!1,help:"仅返回最近一次未发布的财报日期"},{name:"limit",type:"int",default:10,help:"返回数量,默认 10"}],columns:["date","report","status"],func:async(G,A)=>{await G.goto("https://xueqiu.com");const H=String(A.symbol).toUpperCase(),L=`https://stock.xueqiu.com/v5/stock/screener/event/list.json?symbol=${encodeURIComponent(H)}&page=1&size=100`,I=await P(G,L);if(!I.data?.items)throw new O("xueqiu/earnings-date","请确认股票代码是否正确: "+H);const M=Date.now();let B=I.data.items.filter((x)=>x.subtype===2).map((x)=>{const v=x.timestamp,z=v?Q(v):null,K=v&&v>M;return{date:z,report:x.message,status:K?"⏳ 未发布":"✅ 已发布",_ts:v,_future:K}});if(A.next){const x=B.filter((v)=>v._future).sort((v,z)=>v._ts-z._ts);B=x.length?[x[0]]:[]}return B.slice(0,A.limit).map(({date:x,report:v,status:z})=>({date:x,report:v,status:z}))}});
1
+ import{cli as c}from"@jackwener/opencli/registry";import{EmptyResultError as p}from"@jackwener/opencli/errors";import{fetchXueqiuJson as f,formatChinaDate as d}from"./utils.js";c({site:"xueqiu",name:"earnings-date",access:"read",description:"获取股票预计财报发布日期(公司大事)",domain:"xueqiu.com",browser:!0,args:[{name:"symbol",required:!0,positional:!0,help:"股票代码,如 SH600519、SZ000858、00700"},{name:"next",type:"bool",default:!1,help:"仅返回最近一次未发布的财报日期"},{name:"limit",type:"int",default:10,help:"返回数量,默认 10"}],columns:["date","report","status"],func:async(n,o)=>{await n.goto("https://xueqiu.com");const i=String(o.symbol).toUpperCase(),m=`https://stock.xueqiu.com/v5/stock/screener/event/list.json?symbol=${encodeURIComponent(i)}&page=1&size=100`,a=await f(n,m);if(!a.data?.items)throw new p("xueqiu/earnings-date","请确认股票代码是否正确: "+i);const l=Date.now();let r=a.data.items.filter((e)=>e.subtype===2).map((e)=>{const t=e.timestamp,s=t?d(t):null,u=t&&t>l;return{date:s,report:e.message,status:u?"⏳ 未发布":"✅ 已发布",_ts:t,_future:u}});if(o.next){const e=r.filter((t)=>t._future).sort((t,s)=>t._ts-s._ts);r=e.length?[e[0]]:[]}return r.slice(0,o.limit).map(({date:e,report:t,status:s})=>({date:e,report:t,status:s}))}});
@@ -1,5 +1,5 @@
1
- import{cli as F,Strategy as G}from"@jackwener/opencli/registry";import{CliError as H,CommandExecutionError as I}from"@jackwener/opencli/errors";import{gotoWritePage as J}from"../_shared/article/publish.js";import{xueqiuProfile as K}from"./article.js";F({site:"xueqiu",name:"events",access:"read",description:"列举雪球热门原创活动/事件,或用 --id 校验某事件是否可参与。供 `xueqiu article --original-event-id` 取合法值。",domain:"mp.xueqiu.com",strategy:G.COOKIE,browser:!0,args:[{name:"id",help:"校验某个事件 id 是否可用(返回 tag/disabled);不传则列举热门事件"}],columns:["id","tag","disabled"],func:async(z,A)=>{if(!z)throw new I("雪球事件查询需要浏览器会话");await J(z,K.home);const B=typeof A.id==="string"?A.id.trim():"",D=`(async () => {
2
- const id = `+JSON.stringify(B)+`;
1
+ import{cli as a,Strategy as o}from"@jackwener/opencli/registry";import{CliError as s,CommandExecutionError as d}from"@jackwener/opencli/errors";import{gotoWritePage as l}from"../_shared/article/publish.js";import{xueqiuProfile as c}from"./article.js";a({site:"xueqiu",name:"events",access:"read",description:"列举雪球热门原创活动/事件,或用 --id 校验某事件是否可参与。供 `xueqiu article --original-event-id` 取合法值。",domain:"mp.xueqiu.com",strategy:o.COOKIE,browser:!0,args:[{name:"id",help:"校验某个事件 id 是否可用(返回 tag/disabled);不传则列举热门事件"}],columns:["id","tag","disabled"],func:async(e,i)=>{if(!e)throw new d("雪球事件查询需要浏览器会话");await l(e,c.home);const r=typeof i.id==="string"?i.id.trim():"",n=`(async () => {
2
+ const id = `+JSON.stringify(r)+`;
3
3
  if (id) {
4
4
  const r = await fetch("/xq/statuses/original/original_event.json?id=" + encodeURIComponent(id), { credentials: "include" });
5
5
  const t = await r.text();
@@ -14,4 +14,4 @@ import{cli as F,Strategy as G}from"@jackwener/opencli/registry";import{CliError
14
14
  let j = null; try { j = JSON.parse(t); } catch (e) {}
15
15
  `+` if (!r.ok || j == null) return { __err: "热门事件列举失败(HTTP " + r.status + "):" + t.slice(0, 200) };
16
16
  `+` return ((j && j.data) || []).map(e => ({ id: String(e.id != null ? e.id : ""), tag: String(e.title || ""), disabled: "false" }));
17
- })()`,v=await z.evaluate(D);if(v&&v.__err)throw new H("FETCH_ERROR",v.__err);return Array.isArray(v)?v:[]}});
17
+ })()`,t=await e.evaluate(n);if(t&&t.__err)throw new s("FETCH_ERROR",t.__err);return Array.isArray(t)?t:[]}});
@@ -1,5 +1,5 @@
1
- import{cli as F,Strategy as G}from"@jackwener/opencli/registry";import{CliError as H,CommandExecutionError as I}from"@jackwener/opencli/errors";import{gotoWritePage as J}from"../_shared/article/publish.js";import{xueqiuProfile as K}from"./article.js";F({site:"xueqiu",name:"hashtags",access:"read",description:"搜索/列举雪球话题(#话题#)。带 <keyword> 时按关键词搜索;不带则列出热门 + 我最近用过的话题。供在正文里嵌入话题 mention 取合法值。",domain:"mp.xueqiu.com",strategy:G.COOKIE,browser:!0,args:[{name:"keyword",positional:!0,help:"话题关键词(不含 #);留空则返回热门 + 历史话题"}],columns:["source","id","name"],func:async(z,A)=>{if(!z)throw new I("雪球话题搜索需要浏览器会话");await J(z,K.home);const B=typeof A.keyword==="string"?A.keyword.trim():"",D=`(async () => {
2
- const kw = `+JSON.stringify(B)+`;
1
+ import{cli as i,Strategy as a}from"@jackwener/opencli/registry";import{CliError as s,CommandExecutionError as c}from"@jackwener/opencli/errors";import{gotoWritePage as u}from"../_shared/article/publish.js";import{xueqiuProfile as l}from"./article.js";i({site:"xueqiu",name:"hashtags",access:"read",description:"搜索/列举雪球话题(#话题#)。带 <keyword> 时按关键词搜索;不带则列出热门 + 我最近用过的话题。供在正文里嵌入话题 mention 取合法值。",domain:"mp.xueqiu.com",strategy:a.COOKIE,browser:!0,args:[{name:"keyword",positional:!0,help:"话题关键词(不含 #);留空则返回热门 + 历史话题"}],columns:["source","id","name"],func:async(e,n)=>{if(!e)throw new c("雪球话题搜索需要浏览器会话");await u(e,l.home);const r=typeof n.keyword==="string"?n.keyword.trim():"",o=`(async () => {
2
+ const kw = `+JSON.stringify(r)+`;
3
3
  const out = [];
4
4
  if (kw) {
5
5
  const r = await fetch("/statuses/tags/search.json?q=" + encodeURIComponent(kw) + "&count=5", { credentials: "include" });
@@ -23,4 +23,4 @@ import{cli as F,Strategy as G}from"@jackwener/opencli/registry";import{CliError
23
23
  if (rj && rj.items) for (const e of rj.items) out.push({ source: "recent", id: String(e.id != null ? e.id : ""), name: String(e.tag || "") });
24
24
  } catch (e) {}
25
25
  return out;
26
- })()`,v=await z.evaluate(D);if(v&&v.__err)throw new H("FETCH_ERROR",v.__err);return Array.isArray(v)?v:[]}});
26
+ })()`,t=await e.evaluate(o);if(t&&t.__err)throw new s("FETCH_ERROR",t.__err);return Array.isArray(t)?t:[]}});
@@ -1,5 +1,5 @@
1
- import{cli as G,Strategy as H}from"@jackwener/opencli/registry";import{CliError as B,CommandExecutionError as I}from"@jackwener/opencli/errors";import{gotoWritePage as J}from"../_shared/article/publish.js";import{xueqiuProfile as K}from"./article.js";G({site:"xueqiu",name:"stocks",access:"read",description:"搜索雪球个股($股票$),返回代码 + 名称,供在正文里嵌入股票 mention 取合法值。",domain:"mp.xueqiu.com",strategy:H.COOKIE,browser:!0,args:[{name:"keyword",positional:!0,required:!0,help:"股票关键词(名称/代码片段,不含 $)"}],columns:["symbol","name","exchange"],func:async(z,D)=>{if(!z)throw new I("雪球个股搜索需要浏览器会话");const A=String(D.keyword??"").trim();if(!A)throw new B("INVALID_INPUT","股票关键词不能为空");await J(z,K.home);const F=`(async () => {
2
- const kw = `+JSON.stringify(A)+`;
1
+ import{cli as a,Strategy as s}from"@jackwener/opencli/registry";import{CliError as n,CommandExecutionError as c}from"@jackwener/opencli/errors";import{gotoWritePage as m}from"../_shared/article/publish.js";import{xueqiuProfile as u}from"./article.js";a({site:"xueqiu",name:"stocks",access:"read",description:"搜索雪球个股($股票$),返回代码 + 名称,供在正文里嵌入股票 mention 取合法值。",domain:"mp.xueqiu.com",strategy:s.COOKIE,browser:!0,args:[{name:"keyword",positional:!0,required:!0,help:"股票关键词(名称/代码片段,不含 $)"}],columns:["symbol","name","exchange"],func:async(r,o)=>{if(!r)throw new c("雪球个股搜索需要浏览器会话");const t=String(o.keyword??"").trim();if(!t)throw new n("INVALID_INPUT","股票关键词不能为空");await m(r,u.home);const i=`(async () => {
2
+ const kw = `+JSON.stringify(t)+`;
3
3
  const r = await fetch("/xq/query/v1/search/stock.json?size=5&code=" + encodeURIComponent(kw), { credentials: "include" });
4
4
  const t = await r.text();
5
5
  let j = null; try { j = JSON.parse(t); } catch (e) {}
@@ -10,4 +10,4 @@ import{cli as G,Strategy as H}from"@jackwener/opencli/registry";import{CliError
10
10
  name: String(e.name || e.stock_name || ""),
11
11
  exchange: String(e.exchange || e.market || ""),
12
12
  }));
13
- })()`,v=await z.evaluate(F);if(v&&v.__err)throw new B("FETCH_ERROR",v.__err);return Array.isArray(v)?v:[]}});
13
+ })()`,e=await r.evaluate(i);if(e&&e.__err)throw new n("FETCH_ERROR",e.__err);return Array.isArray(e)?e:[]}});
@@ -1,5 +1,5 @@
1
- import{cli as G,Strategy as H}from"@jackwener/opencli/registry";import{CliError as B,CommandExecutionError as I}from"@jackwener/opencli/errors";import{gotoWritePage as J}from"../_shared/article/publish.js";import{xueqiuProfile as K}from"./article.js";G({site:"xueqiu",name:"users",access:"read",description:"搜索雪球用户(@某人),返回用户 id + 昵称,供在正文里 @用户取合法值。",domain:"mp.xueqiu.com",strategy:H.COOKIE,browser:!0,args:[{name:"keyword",positional:!0,required:!0,help:"用户昵称关键词(不含 @)"}],columns:["user_id","name"],func:async(z,D)=>{if(!z)throw new I("雪球用户搜索需要浏览器会话");const A=String(D.keyword??"").trim();if(!A)throw new B("INVALID_INPUT","用户关键词不能为空");await J(z,K.home);const F=`(async () => {
2
- const kw = `+JSON.stringify(A)+`;
1
+ import{cli as s,Strategy as a}from"@jackwener/opencli/registry";import{CliError as n,CommandExecutionError as u}from"@jackwener/opencli/errors";import{gotoWritePage as c}from"../_shared/article/publish.js";import{xueqiuProfile as m}from"./article.js";s({site:"xueqiu",name:"users",access:"read",description:"搜索雪球用户(@某人),返回用户 id + 昵称,供在正文里 @用户取合法值。",domain:"mp.xueqiu.com",strategy:a.COOKIE,browser:!0,args:[{name:"keyword",positional:!0,required:!0,help:"用户昵称关键词(不含 @)"}],columns:["user_id","name"],func:async(e,i)=>{if(!e)throw new u("雪球用户搜索需要浏览器会话");const t=String(i.keyword??"").trim();if(!t)throw new n("INVALID_INPUT","用户关键词不能为空");await c(e,m.home);const o=`(async () => {
2
+ const kw = `+JSON.stringify(t)+`;
3
3
  const r = await fetch("/xq/query/v1/old/search/user.json?q=" + encodeURIComponent(kw) + "&count=5", { credentials: "include" });
4
4
  const t = await r.text();
5
5
  let j = null; try { j = JSON.parse(t); } catch (e) {}
@@ -9,4 +9,4 @@ import{cli as G,Strategy as H}from"@jackwener/opencli/registry";import{CliError
9
9
  user_id: String(e.id != null ? e.id : (e.user_id != null ? e.user_id : "")),
10
10
  name: String(e.screen_name || e.name || ""),
11
11
  }));
12
- })()`,v=await z.evaluate(F);if(v&&v.__err)throw new B("FETCH_ERROR",v.__err);return Array.isArray(v)?v:[]}});
12
+ })()`,r=await e.evaluate(o);if(r&&r.__err)throw new n("FETCH_ERROR",r.__err);return Array.isArray(r)?r:[]}});
@@ -1,9 +1,9 @@
1
- import{AuthRequiredError as U,CommandExecutionError as Q}from"@jackwener/opencli/errors";const V=new Intl.DateTimeFormat("en-US",{timeZone:"Asia/Shanghai",year:"numeric",month:"2-digit",day:"2-digit"});export function formatChinaDate(G){if(G==null)return null;const B=Object.fromEntries(V.formatToParts(new Date(G)).filter((z)=>z.type!=="literal").map((z)=>[z.type,z.value]));return`${B.year}-${B.month}-${B.day}`}export async function fetchXueqiuJson(G,B){const z=await G.evaluate(`(async () => {
2
- const res = await fetch(${JSON.stringify(B)}, { credentials: 'include' });
1
+ import{AuthRequiredError as o,CommandExecutionError as i}from"@jackwener/opencli/errors";const s=new Intl.DateTimeFormat("en-US",{timeZone:"Asia/Shanghai",year:"numeric",month:"2-digit",day:"2-digit"});export function formatChinaDate(e){if(e==null)return null;const t=Object.fromEntries(s.formatToParts(new Date(e)).filter((r)=>r.type!=="literal").map((r)=>[r.type,r.value]));return`${t.year}-${t.month}-${t.day}`}export async function fetchXueqiuJson(e,t){const r=await e.evaluate(`(async () => {
2
+ const res = await fetch(${JSON.stringify(t)}, { credentials: 'include' });
3
3
  if (!res.ok) return { __xqErr: res.status };
4
4
  try {
5
5
  return await res.json();
6
6
  } catch {
7
7
  return { __xqErr: 'parse' };
8
8
  }
9
- })()`),L=z;if(L?.__xqErr!==void 0){const K=L.__xqErr;if(K===401||K===403)throw new U("xueqiu.com","未登录或登录已过期");if(K==="parse")throw new Q("响应不是有效 JSON","可能触发了风控,请检查登录状态或稍后重试");throw new Q(`HTTP ${K}`,"请检查网络连接或登录状态")}return z}
9
+ })()`),a=r;if(a?.__xqErr!==void 0){const n=a.__xqErr;if(n===401||n===403)throw new o("xueqiu.com","未登录或登录已过期");if(n==="parse")throw new i("响应不是有效 JSON","可能触发了风控,请检查登录状态或稍后重试");throw new i(`HTTP ${n}`,"请检查网络连接或登录状态")}return r}
@@ -1,4 +1,4 @@
1
- import{cli as r,Strategy as c}from"@jackwener/opencli/registry";import{CommandExecutionError as o}from"@jackwener/opencli/errors";r({site:"yahoo-finance",name:"quote",access:"read",description:"Yahoo Finance 股票行情",domain:"finance.yahoo.com",strategy:c.COOKIE,args:[{name:"symbol",required:!0,positional:!0,help:"Stock ticker (e.g. AAPL, MSFT, TSLA)"}],columns:["symbol","name","price","change","changePercent","open","high","low","volume","marketCap"],func:async(n,a)=>{const t=a.symbol.toUpperCase().trim();await n.goto(`https://finance.yahoo.com/quote/${encodeURIComponent(t)}/`);const e=await n.evaluate(`
1
+ import{cli as a,Strategy as c}from"@jackwener/opencli/registry";import{CommandExecutionError as o}from"@jackwener/opencli/errors";a({site:"yahoo-finance",name:"quote",access:"read",description:"Yahoo Finance 股票行情",domain:"finance.yahoo.com",strategy:c.COOKIE,args:[{name:"symbol",required:!0,positional:!0,help:"Stock ticker (e.g. AAPL, MSFT, TSLA)"}],columns:["symbol","name","price","change","changePercent","open","high","low","volume","marketCap"],func:async(n,r)=>{const t=r.symbol.toUpperCase().trim();await n.goto(`https://finance.yahoo.com/quote/${encodeURIComponent(t)}/`);const e=await n.evaluate(`
2
2
  (async () => {
3
3
  const sym = ${JSON.stringify(t)};
4
4
 
@@ -1 +1 @@
1
- import*as s from"node:path";import{cli as m,Strategy as p}from"@jackwener/opencli/registry";import{CliError as d}from"@jackwener/opencli/errors";import{log as c}from"@jackwener/opencli/logger";import{YOLLOMI_DOMAIN as f,yollomiPost as g,downloadOutput as y,fmtBytes as O}from"./utils.js";m({site:"yollomi",name:"background",access:"write",description:"Generate AI background for a product/object image (5 credits)",domain:f,strategy:p.COOKIE,args:[{name:"image",positional:!0,required:!0,help:'Image URL (upload via "ppcli yollomi upload" first)'},{name:"prompt",fromFile:!0,default:"",help:"Background description (optional)"},{name:"output",default:"./yollomi-output",help:"Output directory"},{name:"no-download",type:"boolean",default:!1,help:"Only show URL"}],columns:["status","file","size","url"],func:async(a,e)=>{const{image:i,prompt:r}=e;c.status("Generating background...");const o=await g(a,"/api/ai/ai-background-generator",{images:[i],prompt:r||void 0,aspect_ratio:"1:1"}),t=o.image||o.images?.[0];if(!t)throw new d("EMPTY_RESPONSE","No result","Try a different image");if(e["no-download"])return[{status:"generated",file:"-",size:"-",url:t}];try{const n=`yollomi_bg_${Date.now()}.png`,{path:l,size:u}=await y(t,e.output,n);return[{status:"saved",file:s.relative(".",l),size:O(u),url:t}]}catch{return[{status:"download-failed",file:"-",size:"-",url:t}]}}});
1
+ import*as u from"node:path";import{cli as m,Strategy as p}from"@jackwener/opencli/registry";import{CliError as d}from"@jackwener/opencli/errors";import{log as c}from"@jackwener/opencli/logger";import{YOLLOMI_DOMAIN as f,yollomiPost as g,downloadOutput as y,fmtBytes as h}from"./utils.js";m({site:"yollomi",name:"background",access:"write",description:"Generate AI background for a product/object image (5 credits)",domain:f,strategy:p.COOKIE,args:[{name:"image",positional:!0,required:!0,help:'Image URL (upload via "ppcli yollomi upload" first)'},{name:"prompt",fromFile:!0,default:"",help:"Background description (optional)"},{name:"output",default:"./yollomi-output",help:"Output directory"},{name:"no-download",type:"boolean",default:!1,help:"Only show URL"}],columns:["status","file","size","url"],func:async(a,e)=>{const{image:i,prompt:r}=e;c.status("Generating background...");const o=await g(a,"/api/ai/ai-background-generator",{images:[i],prompt:r||void 0,aspect_ratio:"1:1"}),t=o.image||o.images?.[0];if(!t)throw new d("EMPTY_RESPONSE","No result","Try a different image");if(e["no-download"])return[{status:"generated",file:"-",size:"-",url:t}];try{const n=`yollomi_bg_${Date.now()}.png`,{path:l,size:s}=await y(t,e.output,n);return[{status:"saved",file:u.relative(".",l),size:h(s),url:t}]}catch{return[{status:"download-failed",file:"-",size:"-",url:t}]}}});
@@ -1 +1 @@
1
- import*as f from"node:path";import{cli as w,Strategy as h}from"@jackwener/opencli/registry";import{CliError as y}from"@jackwener/opencli/errors";import{log as l}from"@jackwener/opencli/logger";import{YOLLOMI_DOMAIN as q,yollomiPost as O,downloadOutput as E,fmtBytes as I}from"./utils.js";w({site:"yollomi",name:"edit",access:"write",description:"Edit images with AI text prompts (Qwen image edit)",domain:q,strategy:h.COOKIE,args:[{name:"image",positional:!0,required:!0,help:'Input image URL (upload via "ppcli yollomi upload" first)'},{name:"prompt",fromFile:!0,positional:!0,required:!0,help:'Editing instruction (e.g. "Make it look vintage")'},{name:"model",default:"qwen-image-edit",choices:["qwen-image-edit","qwen-image-edit-plus"],help:"Edit model"},{name:"output",default:"./yollomi-output",help:"Output directory"},{name:"no-download",type:"boolean",default:!1,help:"Only show URL"}],columns:["status","file","size","credits","url"],func:async(d,e)=>{const{image:s,prompt:r,model:a}=e;let n;if(a==="qwen-image-edit-plus")n={prompt:r,images:[s]};else n={image:s,prompt:r,go_fast:!0,output_format:"png"};const p=a==="qwen-image-edit-plus"?"/api/ai/qwen-image-edit-plus":"/api/ai/qwen-image-edit";l.status(`Editing with ${a}...`);const i=await O(d,p,n),m=i.images||(i.image?[i.image]:[]);if(!m.length)throw new y("EMPTY_RESPONSE","No result","Try a different prompt");const t=i.remainingCredits,o=m[0];if(e["no-download"])return[{status:"edited",file:"-",size:"-",credits:t??"-",url:o}];try{const u=`yollomi_edit_${Date.now()}.png`,{path:g,size:c}=await E(o,e.output,u);if(t!==void 0)l.status(`Credits remaining: ${t}`);return[{status:"saved",file:f.relative(".",g),size:I(c),credits:t??"-",url:o}]}catch{return[{status:"download-failed",file:"-",size:"-",credits:t??"-",url:o}]}}});
1
+ import*as g from"node:path";import{cli as w,Strategy as h}from"@jackwener/opencli/registry";import{CliError as y}from"@jackwener/opencli/errors";import{log as m}from"@jackwener/opencli/logger";import{YOLLOMI_DOMAIN as q,yollomiPost as E,downloadOutput as O,fmtBytes as I}from"./utils.js";w({site:"yollomi",name:"edit",access:"write",description:"Edit images with AI text prompts (Qwen image edit)",domain:q,strategy:h.COOKIE,args:[{name:"image",positional:!0,required:!0,help:'Input image URL (upload via "ppcli yollomi upload" first)'},{name:"prompt",fromFile:!0,positional:!0,required:!0,help:'Editing instruction (e.g. "Make it look vintage")'},{name:"model",default:"qwen-image-edit",choices:["qwen-image-edit","qwen-image-edit-plus"],help:"Edit model"},{name:"output",default:"./yollomi-output",help:"Output directory"},{name:"no-download",type:"boolean",default:!1,help:"Only show URL"}],columns:["status","file","size","credits","url"],func:async(d,e)=>{const{image:s,prompt:r,model:a}=e;let n;if(a==="qwen-image-edit-plus")n={prompt:r,images:[s]};else n={image:s,prompt:r,go_fast:!0,output_format:"png"};const p=a==="qwen-image-edit-plus"?"/api/ai/qwen-image-edit-plus":"/api/ai/qwen-image-edit";m.status(`Editing with ${a}...`);const i=await E(d,p,n),l=i.images||(i.image?[i.image]:[]);if(!l.length)throw new y("EMPTY_RESPONSE","No result","Try a different prompt");const t=i.remainingCredits,o=l[0];if(e["no-download"])return[{status:"edited",file:"-",size:"-",credits:t??"-",url:o}];try{const u=`yollomi_edit_${Date.now()}.png`,{path:c,size:f}=await O(o,e.output,u);if(t!==void 0)m.status(`Credits remaining: ${t}`);return[{status:"saved",file:g.relative(".",c),size:I(f),credits:t??"-",url:o}]}catch{return[{status:"download-failed",file:"-",size:"-",credits:t??"-",url:o}]}}});