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,19 +1,19 @@
1
- import B from"node:https";import{ArgumentError as G,AuthRequiredError as L,CommandExecutionError as W,EmptyResultError as _}from"@jackwener/opencli/errors";export function resolveBvid(z){const F=String(z).trim();if(/^BV[A-Za-z0-9]+$/i.test(F))return Promise.resolve(F);try{const Z=new URL(F);if(/(\.|^)bilibili\.com$/i.test(Z.hostname)){const V=Z.pathname.match(/\/(?:video|bangumi\/play)\/(BV[A-Za-z0-9]+)/i);if(V)return Promise.resolve(V[1])}}catch{}const Q=F.replace(/^https?:\/\//,"").replace(/^(www\.)?b23\.tv\//,"");if(!/^[A-Za-z0-9]+$/.test(Q))return Promise.reject(Error(`Cannot resolve BV ID from invalid b23.tv short code: ${F}`));const $="https://b23.tv/"+Q;return new Promise((Z,V)=>{const H=B.get($,(O)=>{const T=O.headers.location;if(T){const X=T.match(/\/video\/(BV[A-Za-z0-9]+)/);if(X){O.resume();Z(X[1]);return}}O.resume();V(Error(`Cannot resolve BV ID from short URL: ${F}`))});H.on("error",V);H.setTimeout(4000,()=>{H.destroy();V(Error(`Timeout resolving short URL: ${F}`))})})}export function parsePageArg(z){if(z==null||z==="")return null;if(typeof z==="number"){if(Number.isSafeInteger(z)&&z>=1)return z;throw new G(`--page must be a positive decimal integer, got: ${z}`)}if(typeof z!=="string"||!/^[1-9]\d*$/.test(z))throw new G(`--page must be a positive decimal integer, got: ${String(z)}`);const F=Number(z);if(!Number.isSafeInteger(F))throw new G(`--page is too large: ${z}`);return F}function M(z,F){if(typeof z==="number"&&Number.isSafeInteger(z)&&z>=1)return z;if(typeof z==="string"&&/^[1-9]\d*$/.test(z)){const Q=Number(z);if(Number.isSafeInteger(Q))return Q}throw new W(`Bilibili view API returned a malformed ${F}`)}export function selectVideoPart(z,F){const Q=Array.isArray(z?.pages)?z.pages:null;if(!Q||Q.length===0)throw new W("Bilibili view API did not return pages[] for --page selection");const $=[];for(const V of Q){if(!V||typeof V!=="object"||Array.isArray(V))throw new W("Bilibili view API returned a malformed pages[] entry");if(M(V.page,"page number")===F)$.push(V)}if($.length>1)throw new W(`Bilibili view API returned duplicate page entries for p=${F}`);const Z=$[0];if(!Z){const V=Q.length||z?.videos||1;throw new W(`分P 序号超出范围:p=${F}(该视频共 ${V} 集)`)}M(Z.cid,`cid for p=${F}`);return Z}const R=[46,47,18,2,53,8,23,32,15,50,10,31,58,3,45,35,27,43,5,49,33,9,42,19,29,28,14,39,12,38,41,13,37,48,7,16,24,55,40,61,26,17,0,1,60,51,30,4,22,25,54,21,56,59,6,63,57,62,11,36,20,34,44,52];export function stripHtml(z){return z.replace(/<[^>]+>/g,"").replace(/&[a-z]+;/gi," ").trim()}export function payloadData(z){return z?.data??z}async function S(z){return z.evaluate(`
1
+ import g from"node:https";import{ArgumentError as u,AuthRequiredError as d,CommandExecutionError as f,EmptyResultError as b}from"@jackwener/opencli/errors";export function resolveBvid(t){const e=String(t).trim();if(/^BV[A-Za-z0-9]+$/i.test(e))return Promise.resolve(e);try{const n=new URL(e);if(/(\.|^)bilibili\.com$/i.test(n.hostname)){const i=n.pathname.match(/\/(?:video|bangumi\/play)\/(BV[A-Za-z0-9]+)/i);if(i)return Promise.resolve(i[1])}}catch{}const r=e.replace(/^https?:\/\//,"").replace(/^(www\.)?b23\.tv\//,"");if(!/^[A-Za-z0-9]+$/.test(r))return Promise.reject(Error(`Cannot resolve BV ID from invalid b23.tv short code: ${e}`));const s="https://b23.tv/"+r;return new Promise((n,i)=>{const o=g.get(s,(a)=>{const c=a.headers.location;if(c){const m=c.match(/\/video\/(BV[A-Za-z0-9]+)/);if(m){a.resume();n(m[1]);return}}a.resume();i(Error(`Cannot resolve BV ID from short URL: ${e}`))});o.on("error",i);o.setTimeout(4000,()=>{o.destroy();i(Error(`Timeout resolving short URL: ${e}`))})})}export function parsePageArg(t){if(t==null||t==="")return null;if(typeof t==="number"){if(Number.isSafeInteger(t)&&t>=1)return t;throw new u(`--page must be a positive decimal integer, got: ${t}`)}if(typeof t!=="string"||!/^[1-9]\d*$/.test(t))throw new u(`--page must be a positive decimal integer, got: ${String(t)}`);const e=Number(t);if(!Number.isSafeInteger(e))throw new u(`--page is too large: ${t}`);return e}function w(t,e){if(typeof t==="number"&&Number.isSafeInteger(t)&&t>=1)return t;if(typeof t==="string"&&/^[1-9]\d*$/.test(t)){const r=Number(t);if(Number.isSafeInteger(r))return r}throw new f(`Bilibili view API returned a malformed ${e}`)}export function selectVideoPart(t,e){const r=Array.isArray(t?.pages)?t.pages:null;if(!r||r.length===0)throw new f("Bilibili view API did not return pages[] for --page selection");const s=[];for(const i of r){if(!i||typeof i!=="object"||Array.isArray(i))throw new f("Bilibili view API returned a malformed pages[] entry");if(w(i.page,"page number")===e)s.push(i)}if(s.length>1)throw new f(`Bilibili view API returned duplicate page entries for p=${e}`);const n=s[0];if(!n){const i=r.length||t?.videos||1;throw new f(`分P 序号超出范围:p=${e}(该视频共 ${i} 集)`)}w(n.cid,`cid for p=${e}`);return n}const h=[46,47,18,2,53,8,23,32,15,50,10,31,58,3,45,35,27,43,5,49,33,9,42,19,29,28,14,39,12,38,41,13,37,48,7,16,24,55,40,61,26,17,0,1,60,51,30,4,22,25,54,21,56,59,6,63,57,62,11,36,20,34,44,52];export function stripHtml(t){return t.replace(/<[^>]+>/g,"").replace(/&[a-z]+;/gi," ").trim()}export function payloadData(t){return t?.data??t}async function p(t){return t.evaluate(`
2
2
  async () => {
3
3
  const res = await fetch('https://api.bilibili.com/x/web-interface/nav', { credentials: 'include' });
4
4
  return await res.json();
5
5
  }
6
- `)}async function f(z){const Q=(await S(z))?.data?.wbi_img??{},$=Q.img_url??"",Z=Q.sub_url??"",V=$.split("/").pop()?.split(".")[0]??"",H=Z.split("/").pop()?.split(".")[0]??"";return{imgKey:V,subKey:H}}function J(z,F){const Q=z+F;return R.map(($)=>Q[$]||"").join("").slice(0,32)}async function P(z){const{createHash:F}=await import("node:crypto");return F("md5").update(z).digest("hex")}export async function wbiSign(z,F){const{imgKey:Q,subKey:$}=await f(z),Z=J(Q,$),V=Math.floor(Date.now()/1000),H={},O={...F,wts:String(V)};for(const Y of Object.keys(O).sort())H[Y]=String(O[Y]).replace(/[!'()*]/g,"");const T=new URLSearchParams(H).toString().replace(/\+/g,"%20"),X=await P(T+Z);H.w_rid=X;return H}export async function apiGet(z,F,Q={}){const $="https://api.bilibili.com";let Z=Q.params??{};if(Q.signed)Z=await wbiSign(z,Z);const V=new URLSearchParams(Object.fromEntries(Object.entries(Z).map(([O,T])=>[O,String(T)]))).toString().replace(/\+/g,"%20"),H=`${$}${F}?${V}`;return fetchJson(z,H)}export async function fetchJson(z,F){const Q=JSON.stringify(F);return z.evaluate(`
6
+ `)}async function y(t){const r=(await p(t))?.data?.wbi_img??{},s=r.img_url??"",n=r.sub_url??"",i=s.split("/").pop()?.split(".")[0]??"",o=n.split("/").pop()?.split(".")[0]??"";return{imgKey:i,subKey:o}}function S(t,e){const r=t+e;return h.map((s)=>r[s]||"").join("").slice(0,32)}async function x(t){const{createHash:e}=await import("node:crypto");return e("md5").update(t).digest("hex")}export async function wbiSign(t,e){const{imgKey:r,subKey:s}=await y(t),n=S(r,s),i=Math.floor(Date.now()/1000),o={},a={...e,wts:String(i)};for(const l of Object.keys(a).sort())o[l]=String(a[l]).replace(/[!'()*]/g,"");const c=new URLSearchParams(o).toString().replace(/\+/g,"%20"),m=await x(c+n);o.w_rid=m;return o}export async function apiGet(t,e,r={}){const s="https://api.bilibili.com";let n=r.params??{};if(r.signed)n=await wbiSign(t,n);const i=new URLSearchParams(Object.fromEntries(Object.entries(n).map(([a,c])=>[a,String(c)]))).toString().replace(/\+/g,"%20"),o=`${s}${e}?${i}`;return fetchJson(t,o)}export async function fetchJson(t,e){const r=JSON.stringify(e);return t.evaluate(`
7
7
  async () => {
8
- const res = await fetch(${Q}, { credentials: "include" });
8
+ const res = await fetch(${r}, { credentials: "include" });
9
9
  return await res.json();
10
10
  }
11
- `)}export function isAuthLikeBilibiliError(z,F){return z===-101||z===-111||z===-403||/csrf|登录|账号|权限|forbidden|permission|login/i.test(String(F??""))}export function requireOkPayload(z,F){if(!z||typeof z!=="object"||Array.isArray(z)||!Object.hasOwn(z,"code"))throw new W(`Bilibili ${F} API returned a malformed payload`);if(z.code!==0){const Q=z.message??"unknown error";if(isAuthLikeBilibiliError(z.code,Q))throw new L("bilibili.com",`Bilibili ${F} API requires login or permission: ${Q} (${z.code})`);throw new W(`Bilibili ${F} API failed: ${Q} (${z.code})`)}return z.data}export async function apiPost(z,F,Q={}){const $=Q.params??{},Z=Object.fromEntries(Object.entries($).map(([O,T])=>[O,String(T)])),V=JSON.stringify(Z),H=JSON.stringify(`https://api.bilibili.com${F}`);return z.evaluate(`
11
+ `)}export function isAuthLikeBilibiliError(t,e){return t===-101||t===-111||t===-403||/csrf|登录|账号|权限|forbidden|permission|login/i.test(String(e??""))}export function requireOkPayload(t,e){if(!t||typeof t!=="object"||Array.isArray(t)||!Object.hasOwn(t,"code"))throw new f(`Bilibili ${e} API returned a malformed payload`);if(t.code!==0){const r=t.message??"unknown error";if(isAuthLikeBilibiliError(t.code,r))throw new d("bilibili.com",`Bilibili ${e} API requires login or permission: ${r} (${t.code})`);throw new f(`Bilibili ${e} API failed: ${r} (${t.code})`)}return t.data}export async function apiPost(t,e,r={}){const s=r.params??{},n=Object.fromEntries(Object.entries(s).map(([a,c])=>[a,String(c)])),i=JSON.stringify(n),o=JSON.stringify(`https://api.bilibili.com${e}`);return t.evaluate(`
12
12
  async () => {
13
13
  const csrf = (document.cookie.match(/bili_jct=([^;]+)/) || [])[1] || "";
14
- const body = new URLSearchParams(${V});
14
+ const body = new URLSearchParams(${i});
15
15
  body.set("csrf", csrf);
16
- const res = await fetch(${H}, {
16
+ const res = await fetch(${o}, {
17
17
  method: "POST",
18
18
  credentials: "include",
19
19
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
@@ -28,13 +28,13 @@ import B from"node:https";import{ArgumentError as G,AuthRequiredError as L,Comma
28
28
  return { code: -1, message: "Non-JSON response (HTTP " + res.status + "): " + text.slice(0, 200) };
29
29
  }
30
30
  }
31
- `)}export async function apiPostAbs(z,F,Q={}){const $=Q.params??{},Z=Object.fromEntries(Object.entries($).map(([T,X])=>[T,String(X)])),V=JSON.stringify(Z);let H=F;if(Q.query&&Object.keys(Q.query).length>0){const T=new URLSearchParams(Object.fromEntries(Object.entries(Q.query).map(([X,Y])=>[X,String(Y)]))).toString().replace(/\+/g,"%20");H=`${F}?${T}`}const O=JSON.stringify(H);return z.evaluate(`
31
+ `)}export async function apiPostAbs(t,e,r={}){const s=r.params??{},n=Object.fromEntries(Object.entries(s).map(([c,m])=>[c,String(m)])),i=JSON.stringify(n);let o=e;if(r.query&&Object.keys(r.query).length>0){const c=new URLSearchParams(Object.fromEntries(Object.entries(r.query).map(([m,l])=>[m,String(l)]))).toString().replace(/\+/g,"%20");o=`${e}?${c}`}const a=JSON.stringify(o);return t.evaluate(`
32
32
  async () => {
33
33
  const csrf = (document.cookie.match(/bili_jct=([^;]+)/) || [])[1] || "";
34
- const body = new URLSearchParams(${V});
34
+ const body = new URLSearchParams(${i});
35
35
  body.set("csrf", csrf);
36
36
  body.set("csrf_token", csrf);
37
- const res = await fetch(${O}, {
37
+ const res = await fetch(${a}, {
38
38
  method: "POST",
39
39
  credentials: "include",
40
40
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
@@ -47,4 +47,4 @@ import B from"node:https";import{ArgumentError as G,AuthRequiredError as L,Comma
47
47
  return { code: -1, message: "Non-JSON response (HTTP " + res.status + "): " + text.slice(0, 200) };
48
48
  }
49
49
  }
50
- `)}export async function resolveVideoIds(z,F){let Q;try{Q=await resolveBvid(F)}catch(H){throw new G(`Cannot resolve Bilibili BV ID from input: ${String(F??"")}`,H instanceof Error?H.message:String(H))}const $=await apiGet(z,"/x/web-interface/view",{params:{bvid:Q}}),V=requireOkPayload($,"view")?.aid;if(!V)throw new W(`Cannot resolve aid for bvid: ${Q}`);return{bvid:Q,aid:Number(V)}}export async function getSelfUid(z){const Q=(await S(z))?.data?.mid;if(!Q)throw new L("bilibili.com");return String(Q)}export async function resolveUid(z,F){if(/^\d+$/.test(F))return F;const Q=await apiGet(z,"/x/web-interface/wbi/search/type",{params:{search_type:"bili_user",keyword:F},signed:!0});if(!Q||typeof Q!=="object"||Array.isArray(Q)||!Q.data||typeof Q.data!=="object"||Array.isArray(Q.data)||!Object.hasOwn(Q.data,"result"))throw new W(`Bilibili user search returned malformed result for ${F}`);const $=Q.data.result;if(!Array.isArray($))throw new W(`Bilibili user search returned malformed result for ${F}`);if($.length>0){const Z=String($[0]?.mid??"").trim();if(!Z)throw new W(`Bilibili user search returned malformed mid for ${F}`);return Z}throw new _(`bilibili user search: ${F}`,"User may not exist or username may have changed.")}
50
+ `)}export async function resolveVideoIds(t,e){let r;try{r=await resolveBvid(e)}catch(o){throw new u(`Cannot resolve Bilibili BV ID from input: ${String(e??"")}`,o instanceof Error?o.message:String(o))}const s=await apiGet(t,"/x/web-interface/view",{params:{bvid:r}}),i=requireOkPayload(s,"view")?.aid;if(!i)throw new f(`Cannot resolve aid for bvid: ${r}`);return{bvid:r,aid:Number(i)}}export async function getSelfUid(t){const r=(await p(t))?.data?.mid;if(!r)throw new d("bilibili.com");return String(r)}export async function resolveUid(t,e){if(/^\d+$/.test(e))return e;const r=await apiGet(t,"/x/web-interface/wbi/search/type",{params:{search_type:"bili_user",keyword:e},signed:!0});if(!r||typeof r!=="object"||Array.isArray(r)||!r.data||typeof r.data!=="object"||Array.isArray(r.data)||!Object.hasOwn(r.data,"result"))throw new f(`Bilibili user search returned malformed result for ${e}`);const s=r.data.result;if(!Array.isArray(s))throw new f(`Bilibili user search returned malformed result for ${e}`);if(s.length>0){const n=String(s[0]?.mid??"").trim();if(!n)throw new f(`Bilibili user search returned malformed mid for ${e}`);return n}throw new b(`bilibili user search: ${e}`,"User may not exist or username may have changed.")}
@@ -1 +1 @@
1
- import{cli as B,Strategy as D}from"@jackwener/opencli/registry";import{CommandExecutionError as A}from"@jackwener/opencli/errors";async function F(q){for(let v=0;v<6;v++){await q.goto("https://member.bilibili.com/platform/upload-manager/article?group=draft");await q.wait({time:1});let z="";try{z=String(await q.evaluate("location.href")||"")}catch{z=""}if(/^https?:\/\/member\.bilibili\.com\//.test(z))return}throw new A("无法进入 B站创作中心(可能未登录或被风控)。请先在客户端登录哔哩哔哩。")}B({site:"bilibili",name:"video-drafts",aliases:["upload-drafts"],access:"read",description:"列出 B站视频投稿草稿箱里的草稿(id + 标题 + 时长 + 修改时间),供确认 `bilibili upload --draft` 结果。(专栏草稿见 `bilibili drafts`)",domain:"member.bilibili.com",strategy:D.COOKIE,browser:!0,columns:["id","title","duration","mtime","cid"],func:async(q)=>{if(!q)throw new A("B站视频草稿列举需要浏览器会话");await F(q);const v=await q.evaluate("(async () => {const r = await fetch('https://member.bilibili.com/x/vupre/web/draft/list', { credentials: 'include' });const j = await r.json();if (!j || j.code !== 0) {"+" throw new Error('获取 B站视频草稿失败(可能未登录 B站):' + ((j && j.message) || ('code=' + (j && j.code))));"+'}const arr = Array.isArray(j.data) ? j.data : (j.data && Array.isArray(j.data.drafts) ? j.data.drafts : []);return arr.map(function (d) { return { id: d.id, title: d.title || "", duration: d.duration != null ? d.duration : "", mtime: d.mtime != null ? d.mtime : "", cid: d.cid != null ? d.cid : "", };});})()');if(!Array.isArray(v))throw new A("未取到视频草稿列表(接口返回异常)");return v}});
1
+ import{cli as e,Strategy as o}from"@jackwener/opencli/registry";import{CommandExecutionError as a}from"@jackwener/opencli/errors";async function d(t){for(let i=0;i<6;i++){await t.goto("https://member.bilibili.com/platform/upload-manager/article?group=draft");await t.wait({time:1});let r="";try{r=String(await t.evaluate("location.href")||"")}catch{r=""}if(/^https?:\/\/member\.bilibili\.com\//.test(r))return}throw new a("无法进入 B站创作中心(可能未登录或被风控)。请先在客户端登录哔哩哔哩。")}e({site:"bilibili",name:"video-drafts",aliases:["upload-drafts"],access:"read",description:"列出 B站视频投稿草稿箱里的草稿(id + 标题 + 时长 + 修改时间),供确认 `bilibili upload --draft` 结果。(专栏草稿见 `bilibili drafts`)",domain:"member.bilibili.com",strategy:o.COOKIE,browser:!0,columns:["id","title","duration","mtime","cid"],func:async(t)=>{if(!t)throw new a("B站视频草稿列举需要浏览器会话");await d(t);const i=await t.evaluate("(async () => {const r = await fetch('https://member.bilibili.com/x/vupre/web/draft/list', { credentials: 'include' });const j = await r.json();if (!j || j.code !== 0) {"+" throw new Error('获取 B站视频草稿失败(可能未登录 B站):' + ((j && j.message) || ('code=' + (j && j.code))));"+'}const arr = Array.isArray(j.data) ? j.data : (j.data && Array.isArray(j.data.drafts) ? j.data.drafts : []);return arr.map(function (d) { return { id: d.id, title: d.title || "", duration: d.duration != null ? d.duration : "", mtime: d.mtime != null ? d.mtime : "", cid: d.cid != null ? d.cid : "", };});})()');if(!Array.isArray(i))throw new a("未取到视频草稿列表(接口返回异常)");return i}});
@@ -1 +1 @@
1
- import{cli as C,Strategy as h}from"@jackwener/opencli/registry";import{CommandExecutionError as Q}from"@jackwener/opencli/errors";import{apiGet as O,resolveBvid as E,parsePageArg as P,selectVideoPart as m}from"./utils.js";function $(f,H){if(!f||typeof f!=="object"||Array.isArray(f))throw new Q(`${H} returned a malformed payload`);return f}function y(f){if(f&&typeof f==="object"&&typeof f.session==="string"&&Object.hasOwn(f,"data"))return f.data;return f}function K(f,H){if(f==null)return!1;if(typeof f==="boolean")return f;if(typeof f==="number")return f!==0;throw new Q(`${H} returned a malformed flag`)}function b(f,H){if(f==null)return"";if(typeof f==="string")return f;throw new Q(`${H} returned a malformed string`)}C({site:"bilibili",name:"video",access:"read",description:"Get Bilibili video metadata (title, author, duration, stats, etc.)",strategy:h.COOKIE,args:[{name:"bvid",required:!0,positional:!0,help:"BV ID, video URL, or b23.tv short link"},{name:"page",required:!1,help:"分P 选集序号(从 1 开始)。多 P 视频指定某一集,title/cid 返回该集;缺省取整集默认(P1)"}],columns:["field","value"],func:async(f,H)=>{if(!f)throw new Q("Browser session required for bilibili video");const L=P(H.page),G=String(H.bvid??"").trim(),R=G.match(/bilibili\.com\/(?:video|bangumi\/play)\/(BV[A-Za-z0-9]+)/i),V=R?R[1]:await E(G);await f.goto(`https://www.bilibili.com/video/${V}/`);const N=y(await O(f,"/x/web-interface/view",{params:{bvid:V}}));$(N,"Bilibili view API");if(N.code!==0)throw new Q(`Bilibili view API failed: ${N.message} (${N.code})`);const z=$(N.data,"Bilibili view API data"),I=z.stat||{},Z=z.owner||{},W=$(z.rights,"Bilibili view API data.rights"),S=K(W.pay,"Bilibili rights.pay"),T=K(W.ugc_pay,"Bilibili rights.ugc_pay"),q=K(W.arc_pay,"Bilibili rights.arc_pay"),D=K(z.is_upower_exclusive,"Bilibili is_upower_exclusive"),_=S?"vip":T||q?"ugc_pay":D?"upower":"",U=K(W.ugc_pay_preview,"Bilibili rights.ugc_pay_preview")||K(z.is_upower_preview,"Bilibili is_upower_preview"),j=b(z.redirect_url,"Bilibili redirect_url"),k=z.pubdate?new Date(z.pubdate*1000).toISOString().slice(0,16).replace("T"," "):"";let A=z.title??"",B="",M=z.duration||0;if(L!=null){const J=m(z,L);B=String(J.cid??"");A=(typeof J.part==="string"?J.part.trim():"")||`${z.title??""} P${L}`;if(Number.isFinite(Number(J.duration))&&Number(J.duration)>0)M=Number(J.duration)}const X=M||0,x=Math.floor(X/60),F=X%60,Y=[{field:"bvid",value:z.bvid??""},{field:"aid",value:String(z.aid??"")},{field:"title",value:A},{field:"author",value:Z.name?`${Z.name} (mid: ${Z.mid})`:""},{field:"category",value:z.tname_v2||z.tname||""},{field:"publish_time",value:k},{field:"duration",value:X?`${x}m${F}s (${X}s)`:""},{field:"view",value:String(I.view??"")},{field:"danmaku",value:String(I.danmaku??"")},{field:"reply",value:String(I.reply??"")},{field:"like",value:String(I.like??"")},{field:"coin",value:String(I.coin??"")},{field:"favorite",value:String(I.favorite??"")},{field:"share",value:String(I.share??"")},{field:"parts",value:String(z.videos??1)},{field:"thumbnail",value:z.pic??""},{field:"description",value:z.desc??""},{field:"requires_payment",value:String(!!_)},{field:"payment_type",value:_},{field:"pay_preview",value:String(U)},{field:"redirect_url",value:j}];if(L!=null){Y.push({field:"page",value:String(L)});Y.push({field:"cid",value:B});Y.push({field:"series_title",value:z.title??""})}return Y}});
1
+ import{cli as j,Strategy as k}from"@jackwener/opencli/registry";import{CommandExecutionError as s}from"@jackwener/opencli/errors";import{apiGet as D,resolveBvid as E,parsePageArg as N,selectVideoPart as T}from"./utils.js";function f(i,t){if(!i||typeof i!=="object"||Array.isArray(i))throw new s(`${t} returned a malformed payload`);return i}function U(i){if(i&&typeof i==="object"&&typeof i.session==="string"&&Object.hasOwn(i,"data"))return i.data;return i}function l(i,t){if(i==null)return!1;if(typeof i==="boolean")return i;if(typeof i==="number")return i!==0;throw new s(`${t} returned a malformed flag`)}function C(i,t){if(i==null)return"";if(typeof i==="string")return i;throw new s(`${t} returned a malformed string`)}j({site:"bilibili",name:"video",access:"read",description:"Get Bilibili video metadata (title, author, duration, stats, etc.)",strategy:k.COOKIE,args:[{name:"bvid",required:!0,positional:!0,help:"BV ID, video URL, or b23.tv short link"},{name:"page",required:!1,help:"分P 选集序号(从 1 开始)。多 P 视频指定某一集,title/cid 返回该集;缺省取整集默认(P1)"}],columns:["field","value"],func:async(i,t)=>{if(!i)throw new s("Browser session required for bilibili video");const n=N(t.page),g=String(t.bvid??"").trim(),m=g.match(/bilibili\.com\/(?:video|bangumi\/play)\/(BV[A-Za-z0-9]+)/i),v=m?m[1]:await E(g);await i.goto(`https://www.bilibili.com/video/${v}/`);const o=U(await D(i,"/x/web-interface/view",{params:{bvid:v}}));f(o,"Bilibili view API");if(o.code!==0)throw new s(`Bilibili view API failed: ${o.message} (${o.code})`);const e=f(o.data,"Bilibili view API data"),r=e.stat||{},p=e.owner||{},d=f(e.rights,"Bilibili view API data.rights"),_=l(d.pay,"Bilibili rights.pay"),S=l(d.ugc_pay,"Bilibili rights.ugc_pay"),B=l(d.arc_pay,"Bilibili rights.arc_pay"),P=l(e.is_upower_exclusive,"Bilibili is_upower_exclusive"),b=_?"vip":S||B?"ugc_pay":P?"upower":"",A=l(d.ugc_pay_preview,"Bilibili rights.ugc_pay_preview")||l(e.is_upower_preview,"Bilibili is_upower_preview"),O=C(e.redirect_url,"Bilibili redirect_url"),I=e.pubdate?new Date(e.pubdate*1000).toISOString().slice(0,16).replace("T"," "):"";let w=e.title??"",y="",h=e.duration||0;if(n!=null){const a=T(e,n);y=String(a.cid??"");w=(typeof a.part==="string"?a.part.trim():"")||`${e.title??""} P${n}`;if(Number.isFinite(Number(a.duration))&&Number(a.duration)>0)h=Number(a.duration)}const u=h||0,q=Math.floor(u/60),x=u%60,c=[{field:"bvid",value:e.bvid??""},{field:"aid",value:String(e.aid??"")},{field:"title",value:w},{field:"author",value:p.name?`${p.name} (mid: ${p.mid})`:""},{field:"category",value:e.tname_v2||e.tname||""},{field:"publish_time",value:I},{field:"duration",value:u?`${q}m${x}s (${u}s)`:""},{field:"view",value:String(r.view??"")},{field:"danmaku",value:String(r.danmaku??"")},{field:"reply",value:String(r.reply??"")},{field:"like",value:String(r.like??"")},{field:"coin",value:String(r.coin??"")},{field:"favorite",value:String(r.favorite??"")},{field:"share",value:String(r.share??"")},{field:"parts",value:String(e.videos??1)},{field:"thumbnail",value:e.pic??""},{field:"description",value:e.desc??""},{field:"requires_payment",value:String(!!b)},{field:"payment_type",value:b},{field:"pay_preview",value:String(A)},{field:"redirect_url",value:O}];if(n!=null){c.push({field:"page",value:String(n)});c.push({field:"cid",value:y});c.push({field:"series_title",value:e.title??""})}return c}});
@@ -1,6 +1,6 @@
1
- import{cli as Y,Strategy as Z}from"@jackwener/opencli/registry";import{ArgumentError as $,CliError as Q}from"@jackwener/opencli/errors";const A="https://www.bloomberg.com/businessweek";export function parseBusinessweekLimit(f){const j=f==null||f===""?1:Number(f);if(!Number.isInteger(j)||j<1||j>20)throw new $("bloomberg businessweek --limit must be an integer between 1 and 20","Example: ppcli bloomberg businessweek --limit 5");return j}export function normalizeBusinessweekStoryPath(f){const j=typeof f==="string"?f.trim():"";if(!j)return"";let q;try{q=new URL(j,"https://www.bloomberg.com")}catch{return""}if(q.protocol!=="https:"||q.hostname!=="www.bloomberg.com")return"";if(!/^\/(?:news|features)\//.test(q.pathname))return"";return`${q.pathname}${q.search}`}export function extractBusinessweekStoriesFromNextData(f){const j=f&&f.props&&f.props.pageProps&&f.props.pageProps.initialState&&f.props.pageProps.initialState.modulesById;if(!j||typeof j!=="object")return null;const q=new Set,J=[];for(const G of Object.values(j)){const K=G&&Array.isArray(G.items)?G.items:[];for(const b of K){const H=b&&typeof b.headline==="string"?b.headline.trim():"",M=normalizeBusinessweekStoryPath(b&&typeof b.url==="string"?b.url:"");if(!H||!M)continue;const V=M.split("?")[0];if(q.has(V))continue;q.add(V);const X=b.summary&&String(b.summary).trim()||(b.eyebrow&&b.eyebrow.text?String(b.eyebrow.text).trim():""),W=b.image&&(b.image.baseUrl||b.image.url)||b.lede&&(b.lede.baseUrl||b.lede.url)||"";J.push({title:H,summary:X,link:`https://www.bloomberg.com${M}`,mediaLinks:W?[W]:[]})}}return J}export const command=Y({site:"bloomberg",name:"businessweek",access:"read",description:"Bloomberg Businessweek top stories",domain:"www.bloomberg.com",strategy:Z.PUBLIC,browser:!0,args:[{name:"limit",type:"int",default:1,help:"Number of stories to return (max 20)"}],columns:["title","summary","link","mediaLinks"],func:async(f,j)=>{const q=parseBusinessweekLimit(j.limit);await f.goto(A);await f.wait({selector:"#__NEXT_DATA__",timeout:8});const J=normalizeBusinessweekStoryPath.toString(),G=extractBusinessweekStoriesFromNextData.toString(),K=async()=>f.evaluate(`(() => {
2
- ${J}
3
- ${G}
1
+ import{cli as p,Strategy as g}from"@jackwener/opencli/registry";import{ArgumentError as b,CliError as l}from"@jackwener/opencli/errors";const f="https://www.bloomberg.com/businessweek";export function parseBusinessweekLimit(t){const r=t==null||t===""?1:Number(t);if(!Number.isInteger(r)||r<1||r>20)throw new b("bloomberg businessweek --limit must be an integer between 1 and 20","Example: ppcli bloomberg businessweek --limit 5");return r}export function normalizeBusinessweekStoryPath(t){const r=typeof t==="string"?t.trim():"";if(!r)return"";let o;try{o=new URL(r,"https://www.bloomberg.com")}catch{return""}if(o.protocol!=="https:"||o.hostname!=="www.bloomberg.com")return"";if(!/^\/(?:news|features)\//.test(o.pathname))return"";return`${o.pathname}${o.search}`}export function extractBusinessweekStoriesFromNextData(t){const r=t&&t.props&&t.props.pageProps&&t.props.pageProps.initialState&&t.props.pageProps.initialState.modulesById;if(!r||typeof r!=="object")return null;const o=new Set,n=[];for(const s of Object.values(r)){const a=s&&Array.isArray(s.items)?s.items:[];for(const e of a){const i=e&&typeof e.headline==="string"?e.headline.trim():"",m=normalizeBusinessweekStoryPath(e&&typeof e.url==="string"?e.url:"");if(!i||!m)continue;const u=m.split("?")[0];if(o.has(u))continue;o.add(u);const w=e.summary&&String(e.summary).trim()||(e.eyebrow&&e.eyebrow.text?String(e.eyebrow.text).trim():""),c=e.image&&(e.image.baseUrl||e.image.url)||e.lede&&(e.lede.baseUrl||e.lede.url)||"";n.push({title:i,summary:w,link:`https://www.bloomberg.com${m}`,mediaLinks:c?[c]:[]})}}return n}export const command=p({site:"bloomberg",name:"businessweek",access:"read",description:"Bloomberg Businessweek top stories",domain:"www.bloomberg.com",strategy:g.PUBLIC,browser:!0,args:[{name:"limit",type:"int",default:1,help:"Number of stories to return (max 20)"}],columns:["title","summary","link","mediaLinks"],func:async(t,r)=>{const o=parseBusinessweekLimit(r.limit);await t.goto(f);await t.wait({selector:"#__NEXT_DATA__",timeout:8});const n=normalizeBusinessweekStoryPath.toString(),s=extractBusinessweekStoriesFromNextData.toString(),a=async()=>t.evaluate(`(() => {
2
+ ${n}
3
+ ${s}
4
4
  const el = document.getElementById('__NEXT_DATA__');
5
5
  if (!el) return { ok: false, error: 'NO_NEXT_DATA', title: document.title };
6
6
  let data;
@@ -9,4 +9,4 @@ import{cli as Y,Strategy as Z}from"@jackwener/opencli/registry";import{ArgumentE
9
9
  const stories = extractBusinessweekStoriesFromNextData(data);
10
10
  if (!stories) return { ok: false, error: 'NO_MODULES' };
11
11
  return { ok: true, stories };
12
- })()`);let b=await K();if(b&&b.ok===!1&&(b.error==="NO_NEXT_DATA"||b.error==="NO_MODULES")){await f.wait(4);b=await K()}if(!b||typeof b!=="object")throw new Q("PARSE_ERROR","Bloomberg Businessweek page returned malformed story data","Bloomberg may have changed the page structure.");if(b.ok===!1)throw new Q("PARSE_ERROR",`Bloomberg Businessweek page did not expose story data (${b.error})`,"Bloomberg may have changed the page structure.");const H=Array.isArray(b.stories)?b.stories:[];if(!H.length)throw new Q("NOT_FOUND","No Bloomberg Businessweek stories found","Bloomberg may have changed the page structure.");return H.slice(0,q)}}),__test__={command,parseBusinessweekLimit,normalizeBusinessweekStoryPath,extractBusinessweekStoriesFromNextData};
12
+ })()`);let e=await a();if(e&&e.ok===!1&&(e.error==="NO_NEXT_DATA"||e.error==="NO_MODULES")){await t.wait(4);e=await a()}if(!e||typeof e!=="object")throw new l("PARSE_ERROR","Bloomberg Businessweek page returned malformed story data","Bloomberg may have changed the page structure.");if(e.ok===!1)throw new l("PARSE_ERROR",`Bloomberg Businessweek page did not expose story data (${e.error})`,"Bloomberg may have changed the page structure.");const i=Array.isArray(e.stories)?e.stories:[];if(!i.length)throw new l("NOT_FOUND","No Bloomberg Businessweek stories found","Bloomberg may have changed the page structure.");return i.slice(0,o)}}),__test__={command,parseBusinessweekLimit,normalizeBusinessweekStoryPath,extractBusinessweekStoriesFromNextData};
@@ -1,4 +1,4 @@
1
- import{cli as I,Strategy as J}from"@jackwener/opencli/registry";import{CliError as A}from"@jackwener/opencli/errors";import{extractStoryMediaLinks as K,renderStoryBody as N,validateBloombergLink as O}from"./utils.js";I({site:"bloomberg",name:"news",access:"read",description:"Read a Bloomberg story/article page and return title, full content, and media links",domain:"www.bloomberg.com",strategy:J.COOKIE,browser:!0,args:[{name:"link",positional:!0,required:!0,help:"Bloomberg story/article URL or relative Bloomberg path"}],columns:["title","summary","link","mediaLinks","content"],func:async(z,H)=>{const D=O(H.link);await z.goto(D);await z.wait({selector:"article",timeout:5});const F=async()=>z.evaluate(`(() => {
1
+ import{cli as l,Strategy as c}from"@jackwener/opencli/registry";import{CliError as o}from"@jackwener/opencli/errors";import{extractStoryMediaLinks as d,renderStoryBody as m,validateBloombergLink as y}from"./utils.js";l({site:"bloomberg",name:"news",access:"read",description:"Read a Bloomberg story/article page and return title, full content, and media links",domain:"www.bloomberg.com",strategy:c.COOKIE,browser:!0,args:[{name:"link",positional:!0,required:!0,help:"Bloomberg story/article URL or relative Bloomberg path"}],columns:["title","summary","link","mediaLinks","content"],func:async(r,s)=>{const n=y(s.link);await r.goto(n);await r.wait({selector:"article",timeout:5});const a=async()=>r.evaluate(`(() => {
2
2
  const isRobot = /Are you a robot/i.test(document.title)
3
3
  || /unusual activity/i.test(document.body.innerText)
4
4
  || /click the box below to let us know you're not a robot/i.test(document.body.innerText);
@@ -54,4 +54,4 @@ import{cli as I,Strategy as J}from"@jackwener/opencli/registry";import{CliError
54
54
  videoAttachments: story.videoAttachments || {},
55
55
  }
56
56
  };
57
- })()`);let f=await F();if(f?.errorCode==="NO_NEXT_DATA"||f?.errorCode==="NO_STORY"){await z.wait(4);f=await F()}if(f?.errorCode==="ROBOT_PAGE")throw new A("FETCH_ERROR","Bloomberg served the bot-protection page instead of article content","Try again later or open the article in a regular Chrome session first, then rerun the command. This command uses your current Bloomberg access and does not bypass paywall or entitlement checks.");if(f?.errorCode)throw new A("PARSE_ERROR",`Bloomberg page did not expose article story data (${f.errorCode})`,"This command currently works on standard Bloomberg story/article pages that expose __NEXT_DATA__. Audio, video, newsletter, or other non-standard/blocked pages may not work. Access still depends on your current Bloomberg session.");const q=f?.story;if(!q)throw new A("PARSE_ERROR","Failed to extract Bloomberg story data","Bloomberg may have changed the page structure.");const G=N(q.body);if(!G)throw new A("PARSE_ERROR","Bloomberg article body was empty after parsing","Bloomberg may have changed the story-body format, the URL may not point to a standard article page, or the page may not be accessible in your current Bloomberg session.");return[{title:q.headline||"",summary:q.summary||"",link:q.url||D,mediaLinks:K(q),content:G}]}});
57
+ })()`);let e=await a();if(e?.errorCode==="NO_NEXT_DATA"||e?.errorCode==="NO_STORY"){await r.wait(4);e=await a()}if(e?.errorCode==="ROBOT_PAGE")throw new o("FETCH_ERROR","Bloomberg served the bot-protection page instead of article content","Try again later or open the article in a regular Chrome session first, then rerun the command. This command uses your current Bloomberg access and does not bypass paywall or entitlement checks.");if(e?.errorCode)throw new o("PARSE_ERROR",`Bloomberg page did not expose article story data (${e.errorCode})`,"This command currently works on standard Bloomberg story/article pages that expose __NEXT_DATA__. Audio, video, newsletter, or other non-standard/blocked pages may not work. Access still depends on your current Bloomberg session.");const t=e?.story;if(!t)throw new o("PARSE_ERROR","Failed to extract Bloomberg story data","Bloomberg may have changed the page structure.");const i=m(t.body);if(!i)throw new o("PARSE_ERROR","Bloomberg article body was empty after parsing","Bloomberg may have changed the story-body format, the URL may not point to a standard article page, or the page may not be accessible in your current Bloomberg session.");return[{title:t.headline||"",summary:t.summary||"",link:t.url||n,mediaLinks:d(t),content:i}]}});
@@ -1,17 +1,17 @@
1
- import{CliError as H}from"@jackwener/opencli/errors";export const BLOOMBERG_FEEDS={main:"https://feeds.bloomberg.com/news.rss",markets:"https://feeds.bloomberg.com/markets/news.rss",economics:"https://feeds.bloomberg.com/economics/news.rss",industries:"https://feeds.bloomberg.com/industries/news.rss",tech:"https://feeds.bloomberg.com/technology/news.rss",politics:"https://feeds.bloomberg.com/politics/news.rss",opinions:"https://feeds.bloomberg.com/bview/news.rss",green:"https://feeds.bloomberg.com/green/news.rss",crypto:"https://feeds.bloomberg.com/crypto/news.rss",pursuits:"https://feeds.bloomberg.com/pursuits/news.rss"};const L="Mozilla/5.0 (compatible; ppcli)";export async function fetchBloombergFeed(q,J=1){const K=BLOOMBERG_FEEDS[q];if(!K)throw new H("ARGUMENT",`Unknown Bloomberg feed: ${q}`);let P;for(let Q=0;Q<3;Q+=1){if(Q>0)await new Promise((A)=>setTimeout(A,400*Q));const V=await fetch(K,{headers:{"User-Agent":L}});if(!V.ok){P=new H("FETCH_ERROR",`Bloomberg RSS HTTP ${V.status}`,"Bloomberg may be temporarily unavailable; try again later.");continue}const Z=await V.text(),W=parseBloombergRss(Z);if(W.length){const A=Math.max(1,Math.min(Number(J)||1,20));return W.slice(0,A)}P=new H("NOT_FOUND","Bloomberg RSS feed returned no items","Bloomberg may have changed the feed format.")}throw P}export function parseBloombergRss(q){const J=[],K=/<item\b[^>]*>([\s\S]*?)<\/item>/gi;let P;while(P=K.exec(q)){const Q=P[1],V=G(Q,"title"),Z=G(Q,"description"),W=G(Q,"link")||G(Q,"guid"),A=M(Q);if(!V||!W)continue;J.push({title:V,summary:Z,link:W,mediaLinks:A})}return J}export function normalizeBloombergLink(q){const J=String(q||"").trim();if(!J)throw new H("ARGUMENT","A Bloomberg link is required");if(J.startsWith("/"))return`https://www.bloomberg.com${J}`;return J}export function validateBloombergLink(q){const J=normalizeBloombergLink(q);let K;try{K=new URL(J)}catch{throw new H("ARGUMENT",`Invalid Bloomberg link: ${q}`,"Pass a full https://www.bloomberg.com/... URL or a relative Bloomberg path.")}if(!/(?:\.|^)bloomberg\.com$/i.test(K.hostname))throw new H("ARGUMENT",`Expected a bloomberg.com link, got: ${K.hostname}`,"Pass a Bloomberg article URL from bloomberg.com.");return K.toString()}export function renderStoryBody(q){return(Array.isArray(q?.content)?q.content:[]).map((P)=>D(P,0)).map((P)=>j(P)).filter(Boolean).join(`
1
+ import{CliError as u}from"@jackwener/opencli/errors";export const BLOOMBERG_FEEDS={main:"https://feeds.bloomberg.com/news.rss",markets:"https://feeds.bloomberg.com/markets/news.rss",economics:"https://feeds.bloomberg.com/economics/news.rss",industries:"https://feeds.bloomberg.com/industries/news.rss",tech:"https://feeds.bloomberg.com/technology/news.rss",politics:"https://feeds.bloomberg.com/politics/news.rss",opinions:"https://feeds.bloomberg.com/bview/news.rss",green:"https://feeds.bloomberg.com/green/news.rss",crypto:"https://feeds.bloomberg.com/crypto/news.rss",pursuits:"https://feeds.bloomberg.com/pursuits/news.rss"};const A="Mozilla/5.0 (compatible; ppcli)";export async function fetchBloombergFeed(t,e=1){const n=BLOOMBERG_FEEDS[t];if(!n)throw new u("ARGUMENT",`Unknown Bloomberg feed: ${t}`);let r;for(let o=0;o<3;o+=1){if(o>0)await new Promise((f)=>setTimeout(f,400*o));const i=await fetch(n,{headers:{"User-Agent":A}});if(!i.ok){r=new u("FETCH_ERROR",`Bloomberg RSS HTTP ${i.status}`,"Bloomberg may be temporarily unavailable; try again later.");continue}const c=await i.text(),s=parseBloombergRss(c);if(s.length){const f=Math.max(1,Math.min(Number(e)||1,20));return s.slice(0,f)}r=new u("NOT_FOUND","Bloomberg RSS feed returned no items","Bloomberg may have changed the feed format.")}throw r}export function parseBloombergRss(t){const e=[],n=/<item\b[^>]*>([\s\S]*?)<\/item>/gi;let r;while(r=n.exec(t)){const o=r[1],i=h(o,"title"),c=h(o,"description"),s=h(o,"link")||h(o,"guid"),f=j(o);if(!i||!s)continue;e.push({title:i,summary:c,link:s,mediaLinks:f})}return e}export function normalizeBloombergLink(t){const e=String(t||"").trim();if(!e)throw new u("ARGUMENT","A Bloomberg link is required");if(e.startsWith("/"))return`https://www.bloomberg.com${e}`;return e}export function validateBloombergLink(t){const e=normalizeBloombergLink(t);let n;try{n=new URL(e)}catch{throw new u("ARGUMENT",`Invalid Bloomberg link: ${t}`,"Pass a full https://www.bloomberg.com/... URL or a relative Bloomberg path.")}if(!/(?:\.|^)bloomberg\.com$/i.test(n.hostname))throw new u("ARGUMENT",`Expected a bloomberg.com link, got: ${n.hostname}`,"Pass a Bloomberg article URL from bloomberg.com.");return n.toString()}export function renderStoryBody(t){return(Array.isArray(t?.content)?t.content:[]).map((r)=>g(r,0)).map((r)=>m(r)).filter(Boolean).join(`
2
2
 
3
3
  `).replace(/\n{3,}/g,`
4
4
 
5
- `).trim()}export function extractStoryMediaLinks(q){const J=new Set;$(q?.ledeImageUrl,J);$(q?.socialImageUrl,J);$(q?.lede,J);$(q?.imageAttachments,J);$(q?.videoAttachments,J);const K=Array.isArray(q?.body?.content)?q.body.content.filter((P)=>P?.type==="media"):[];$(K,J);return[...J]}function D(q,J){if(!q||typeof q!=="object")return"";switch(q.type){case"paragraph":return S(q.content||[]);case"heading":{const K=S(q.content||[]);if(!K)return"";const P=Number(q.data?.level??q.data?.weight??2);return`${P<=1?"# ":P===2?"## ":"### "}${K}`}case"blockquote":{const K=S(q.content||[]);if(!K)return"";return K.split(`
6
- `).map((P)=>P?`> ${P}`:">").join(`
7
- `)}case"list":return w(q,J);case"tabularData":return N(q);case"media":return g(q);case"inline-newsletter":case"newsletter":case"ad":return"";default:{if(Array.isArray(q.content)&&q.content.length>0){const K=S(q.content);if(K)return K;const P=q.content.map((Q)=>D(Q,J+1)).filter(Boolean);if(P.length)return P.join(`
8
- `)}return O(q)}}}function S(q){return q.map((J)=>X(J)).join("")}function X(q){if(q==null)return"";if(typeof q==="string")return Y(q);switch(q.type){case"text":return Y(q.value||"");case"linebreak":return`
9
- `;case"link":case"entity":case"strong":case"emphasis":case"italic":case"underline":case"span":if(Array.isArray(q.content)&&q.content.length>0)return S(q.content);return Y(q.value||"");default:if(Array.isArray(q.content)&&q.content.length>0)return S(q.content);if(typeof q.value==="string")return Y(q.value);return""}}function w(q,J){const K=Array.isArray(q.content)?q.content:[];if(!K.length)return"";const P=String(q.subType||q.data?.style||q.data?.listType||""),Q=/\bordered\b|\bnumber(?:ed)?\b/i.test(P);let V=1;return K.map((Z)=>{const W=Q?`${V++}. `:"- ";return f(Z,W,J)}).filter(Boolean).join(`
10
- `)}function f(q,J,K){const P=" ".repeat(K),Q=j(I(q,K+1));if(!Q)return"";const V=Q.split(`
11
- `),Z=`${P}${J}${V[0]}`;if(V.length===1)return Z;const W=`${P}${" ".repeat(J.length)}`,A=V.slice(1).map((R)=>`${W}${R}`).join(`
12
- `);return`${Z}
13
- ${A}`}function I(q,J){if(!q||typeof q!=="object")return"";if(q.type==="list-item"&&Array.isArray(q.content))return q.content.map((P)=>P?.type==="paragraph"?S(P.content||[]):D(P,J)).map((P)=>j(P)).filter(Boolean).join(`
14
- `);return D(q,J)}function N(q){const J=q?.data?.rows??q?.data?.table?.rows??q?.content;if(!Array.isArray(J)||!J.length)return O(q.data||q.content||q);return J.map((P)=>O(P)).map((P)=>j(P)).filter(Boolean).join(`
15
- `)}function g(q){return[q?.data?.chart?.caption,q?.data?.attachment?.caption,q?.data?.attachment?.title,q?.data?.attachment?.subtitle,q?.data?.video?.caption].map((P)=>j(_(String(P||"")))).find(Boolean)||""}function O(q){const J=[];F(q,J);return J.join(" ").replace(/\s+/g," ").trim()}function F(q,J){if(q==null)return;if(typeof q==="string"){const K=j(_(Y(q)));if(K)J.push(K);return}if(Array.isArray(q)){for(const K of q)F(K,J);return}if(typeof q==="object"){if(typeof q.value==="string"){const K=j(_(Y(q.value)));if(K)J.push(K);return}if(Array.isArray(q.content)){F(q.content,J);return}for(const K of Object.values(q))F(K,J)}}function G(q,J){const K=B(J),P=q.match(new RegExp(`<${K}(?:\\s[^>]*)?>([\\s\\S]*?)<\\/${K}>`,"i"));if(!P)return"";return j(_(Y(U(P[1]))))}function M(q){const J=new Set,K=/<(?:media:content|media:thumbnail|enclosure)\b[^>]*\burl="([^"]+)"[^>]*>/gi;let P;while(P=K.exec(q)){const Q=Y(P[1]||"").trim();if(Q)J.add(Q)}return[...J]}function $(q,J,K=new WeakSet){if(q==null)return;if(typeof q==="string"){const P=C(q);if(P)J.add(P);return}if(Array.isArray(q)){for(const P of q)$(P,J,K);return}if(typeof q==="object"){if(K.has(q))return;K.add(q);for(const P of["url","src","fallback","poster"]){const Q=q[P];if(typeof Q==="string"){const V=C(Q);if(V)J.add(V)}}for(const P of Object.values(q))$(P,J,K)}}function C(q){const J=Y(String(q||"")).trim();if(!/^https?:\/\//i.test(J))return null;if(!z(J))return null;return J}function z(q){return/(?:assets\.bwbx\.io|resource\.bloomberg\.com|media\.bloomberg\.com)/i.test(q)||/\.(?:jpg|jpeg|png|webp|gif|svg|mp4|m3u8)(?:[?#].*)?$/i.test(q)}function U(q){const J=q.match(/^<!\[CDATA\[([\s\S]*?)\]\]>$/);return J?J[1]:q}function _(q){return String(q||"").replace(/<[^>]+>/g," ")}function Y(q){return String(q||"").replace(/<!\[CDATA\[([\s\S]*?)\]\]>/g,"$1").replace(/&#(\d+);/g,(J,K)=>String.fromCodePoint(Number(K))).replace(/&#x([0-9a-f]+);/gi,(J,K)=>String.fromCodePoint(parseInt(K,16))).replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/&apos;/g,"'").replace(/&nbsp;/g," ")}function j(q){return String(q||"").replace(/\r/g,"").replace(/[ \t]+\n/g,`
5
+ `).trim()}export function extractStoryMediaLinks(t){const e=new Set;l(t?.ledeImageUrl,e);l(t?.socialImageUrl,e);l(t?.lede,e);l(t?.imageAttachments,e);l(t?.videoAttachments,e);const n=Array.isArray(t?.body?.content)?t.body.content.filter((r)=>r?.type==="media"):[];l(n,e);return[...e]}function g(t,e){if(!t||typeof t!=="object")return"";switch(t.type){case"paragraph":return p(t.content||[]);case"heading":{const n=p(t.content||[]);if(!n)return"";const r=Number(t.data?.level??t.data?.weight??2);return`${r<=1?"# ":r===2?"## ":"### "}${n}`}case"blockquote":{const n=p(t.content||[]);if(!n)return"";return n.split(`
6
+ `).map((r)=>r?`> ${r}`:">").join(`
7
+ `)}case"list":return S(t,e);case"tabularData":return E(t);case"media":return U(t);case"inline-newsletter":case"newsletter":case"ad":return"";default:{if(Array.isArray(t.content)&&t.content.length>0){const n=p(t.content);if(n)return n;const r=t.content.map((o)=>g(o,e+1)).filter(Boolean);if(r.length)return r.join(`
8
+ `)}return y(t)}}}function p(t){return t.map((e)=>B(e)).join("")}function B(t){if(t==null)return"";if(typeof t==="string")return a(t);switch(t.type){case"text":return a(t.value||"");case"linebreak":return`
9
+ `;case"link":case"entity":case"strong":case"emphasis":case"italic":case"underline":case"span":if(Array.isArray(t.content)&&t.content.length>0)return p(t.content);return a(t.value||"");default:if(Array.isArray(t.content)&&t.content.length>0)return p(t.content);if(typeof t.value==="string")return a(t.value);return""}}function S(t,e){const n=Array.isArray(t.content)?t.content:[];if(!n.length)return"";const r=String(t.subType||t.data?.style||t.data?.listType||""),o=/\bordered\b|\bnumber(?:ed)?\b/i.test(r);let i=1;return n.map((c)=>{const s=o?`${i++}. `:"- ";return T(c,s,e)}).filter(Boolean).join(`
10
+ `)}function T(t,e,n){const r=" ".repeat(n),o=m(R(t,n+1));if(!o)return"";const i=o.split(`
11
+ `),c=`${r}${e}${i[0]}`;if(i.length===1)return c;const s=`${r}${" ".repeat(e.length)}`,f=i.slice(1).map((x)=>`${s}${x}`).join(`
12
+ `);return`${c}
13
+ ${f}`}function R(t,e){if(!t||typeof t!=="object")return"";if(t.type==="list-item"&&Array.isArray(t.content))return t.content.map((r)=>r?.type==="paragraph"?p(r.content||[]):g(r,e)).map((r)=>m(r)).filter(Boolean).join(`
14
+ `);return g(t,e)}function E(t){const e=t?.data?.rows??t?.data?.table?.rows??t?.content;if(!Array.isArray(e)||!e.length)return y(t.data||t.content||t);return e.map((r)=>y(r)).map((r)=>m(r)).filter(Boolean).join(`
15
+ `)}function U(t){return[t?.data?.chart?.caption,t?.data?.attachment?.caption,t?.data?.attachment?.title,t?.data?.attachment?.subtitle,t?.data?.video?.caption].map((r)=>m(b(String(r||"")))).find(Boolean)||""}function y(t){const e=[];d(t,e);return e.join(" ").replace(/\s+/g," ").trim()}function d(t,e){if(t==null)return;if(typeof t==="string"){const n=m(b(a(t)));if(n)e.push(n);return}if(Array.isArray(t)){for(const n of t)d(n,e);return}if(typeof t==="object"){if(typeof t.value==="string"){const n=m(b(a(t.value)));if(n)e.push(n);return}if(Array.isArray(t.content)){d(t.content,e);return}for(const n of Object.values(t))d(n,e)}}function h(t,e){const n=N(e),r=t.match(new RegExp(`<${n}(?:\\s[^>]*)?>([\\s\\S]*?)<\\/${n}>`,"i"));if(!r)return"";return m(b(a(M(r[1]))))}function j(t){const e=new Set,n=/<(?:media:content|media:thumbnail|enclosure)\b[^>]*\burl="([^"]+)"[^>]*>/gi;let r;while(r=n.exec(t)){const o=a(r[1]||"").trim();if(o)e.add(o)}return[...e]}function l(t,e,n=new WeakSet){if(t==null)return;if(typeof t==="string"){const r=w(t);if(r)e.add(r);return}if(Array.isArray(t)){for(const r of t)l(r,e,n);return}if(typeof t==="object"){if(n.has(t))return;n.add(t);for(const r of["url","src","fallback","poster"]){const o=t[r];if(typeof o==="string"){const i=w(o);if(i)e.add(i)}}for(const r of Object.values(t))l(r,e,n)}}function w(t){const e=a(String(t||"")).trim();if(!/^https?:\/\//i.test(e))return null;if(!L(e))return null;return e}function L(t){return/(?:assets\.bwbx\.io|resource\.bloomberg\.com|media\.bloomberg\.com)/i.test(t)||/\.(?:jpg|jpeg|png|webp|gif|svg|mp4|m3u8)(?:[?#].*)?$/i.test(t)}function M(t){const e=t.match(/^<!\[CDATA\[([\s\S]*?)\]\]>$/);return e?e[1]:t}function b(t){return String(t||"").replace(/<[^>]+>/g," ")}function a(t){return String(t||"").replace(/<!\[CDATA\[([\s\S]*?)\]\]>/g,"$1").replace(/&#(\d+);/g,(e,n)=>String.fromCodePoint(Number(n))).replace(/&#x([0-9a-f]+);/gi,(e,n)=>String.fromCodePoint(parseInt(n,16))).replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/&apos;/g,"'").replace(/&nbsp;/g," ")}function m(t){return String(t||"").replace(/\r/g,"").replace(/[ \t]+\n/g,`
16
16
  `).replace(/\n[ \t]+/g,`
17
- `).replace(/[ \t]{2,}/g," ").trim()}function B(q){return q.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}
17
+ `).replace(/[ \t]{2,}/g," ").trim()}function N(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}
@@ -1 +1 @@
1
- import*as U from"node:fs";import*as y from"node:path";import{cli as f,Strategy as C}from"@jackwener/opencli/registry";import{AuthRequiredError as W,ArgumentError as N,CommandExecutionError as H}from"@jackwener/opencli/errors";import{assertLiteralContent as L}from"../_shared/content-guard.js";import{IMAGES_EMBED_TYPE as R,MAX_BLOB_BYTES as j,MAX_IMAGES as G,MAX_POST_GRAPHEMES as Y,POST_COLLECTION as X,POST_TYPE as O,graphemeLength as B,loadBskySession as I,postUriToWebUrl as T,uploadBlobWithRefresh as x,xrpcJsonWithRefresh as S}from"./shared.js";const b={".jpg":"image/jpeg",".jpeg":"image/jpeg",".png":"image/png",".gif":"image/gif",".webp":"image/webp"};function M(v,K){const Z=String(v).split(",").map((Q)=>Q.trim()).filter(Boolean);if(Z.length===0)return[];if(Z.length>G)throw new N(`图片过多:${Z.length} 张(Bluesky 单帖最多 ${G} 张)`);const D=K!=null&&String(K).length>0?String(K).split(",").map((Q)=>Q.trim()):[];return Z.map((Q,J)=>{const z=y.resolve(Q),$=y.extname(z).toLowerCase(),F=b[$];if(!F)throw new N(`不支持的图片格式 "${$}"。支持:jpg / png / gif / webp`);const V=U.statSync(z,{throwIfNoEntry:!1});if(!V||!V.isFile())throw new N(`不是有效文件:${z}`);if(V.size>j)throw new N(`图片超过 ${j} 字节上限(${z} 为 ${V.size} 字节)。请先本地压缩后再发。`);return{absPath:z,mime:F,alt:D[J]||""}})}async function P(v,K,Z){const D=[];for(const Q of Z){const J=U.readFileSync(Q.absPath).toString("base64"),z=await x(v,K,{base64:J,mime:Q.mime});if(z&&(z.httpStatus===401||z.httpStatus===403))throw new W("bsky.app",`uploadBlob 返回 HTTP ${z.httpStatus}`);const $=z&&z.bodyJson&&z.bodyJson.blob;if(!z||!z.ok||!$){const F=z&&z.bodyJson&&(z.bodyJson.message||z.bodyJson.error)||z?.error||`HTTP ${z?.httpStatus??0}`;throw new H(`图片上传失败(${Q.absPath}):${F}`)}D.push({alt:Q.alt,image:$})}return{$type:R,images:D}}f({site:"bluesky",name:"post",access:"write",description:"发布一条 Bluesky 帖子(支持文字 + 最多 4 张图)",domain:"bsky.app",strategy:C.UI,browser:!0,args:[{name:"text",fromFile:!0,type:"string",required:!0,positional:!0,help:"帖子正文(≤300 graphemes)"},{name:"images",type:"string",required:!1,help:"图片路径,逗号分隔,最多 4 张(jpg/png/gif/webp,每张≤1MB)"},{name:"alts",type:"string",required:!1,help:"图片 alt 文本,逗号分隔,与 images 一一对应(可选)"},{name:"langs",type:"string",required:!1,help:"语言标签,逗号分隔(如 zh,en);不传则不标注语言"}],columns:["status","message","text","uri","cid","url"],func:async(v,K)=>{if(!v)throw new H("Bluesky post 需要浏览器会话");const Z=String(K.text??"");L(Z,{label:"帖子正文"});if(Z.trim().length===0)throw new N("帖子正文不能为空");const D=B(Z);if(D>Y)throw new N(`帖子正文 ${D} graphemes,超过 Bluesky 上限 ${Y}`);const Q=K.images?M(String(K.images),K.alts):[],J=K.langs!=null&&String(K.langs).length>0?String(K.langs).split(",").map((q)=>q.trim()).filter(Boolean):[],z=await I(v),$={$type:O,text:Z,createdAt:new Date().toISOString()};if(J.length>0)$.langs=J;if(Q.length>0)$.embed=await P(v,z,Q);const F=await S(v,z,{path:"com.atproto.repo.createRecord",method:"POST",body:{repo:z.did,collection:X,record:$}});if(F&&(F.httpStatus===401||F.httpStatus===403))throw new W("bsky.app",`createRecord 返回 HTTP ${F.httpStatus}`);const V=F&&F.bodyJson;if(!F||!F.ok||!V||!V.uri){const q=V&&(V.message||V.error)||F?.error||`HTTP ${F?.httpStatus??0}`;throw new H(`发布失败:${q}`)}return[{status:"success",message:"帖子发布成功",text:Z,uri:String(V.uri),cid:String(V.cid||""),url:T(V.uri,z.handle)}]}});
1
+ import*as c from"node:fs";import*as u from"node:path";import{cli as y,Strategy as w}from"@jackwener/opencli/registry";import{AuthRequiredError as f,ArgumentError as m,CommandExecutionError as h}from"@jackwener/opencli/errors";import{assertLiteralContent as T}from"../_shared/content-guard.js";import{IMAGES_EMBED_TYPE as E,MAX_BLOB_BYTES as d,MAX_IMAGES as S,MAX_POST_GRAPHEMES as b,POST_COLLECTION as B,POST_TYPE as P,graphemeLength as _,loadBskySession as I,postUriToWebUrl as M,uploadBlobWithRefresh as x,xrpcJsonWithRefresh as O}from"./shared.js";const A={".jpg":"image/jpeg",".jpeg":"image/jpeg",".png":"image/png",".gif":"image/gif",".webp":"image/webp"};function J(a,s){const n=String(a).split(",").map((r)=>r.trim()).filter(Boolean);if(n.length===0)return[];if(n.length>S)throw new m(`图片过多:${n.length} 张(Bluesky 单帖最多 ${S} 张)`);const l=s!=null&&String(s).length>0?String(s).split(",").map((r)=>r.trim()):[];return n.map((r,p)=>{const t=u.resolve(r),i=u.extname(t).toLowerCase(),e=A[i];if(!e)throw new m(`不支持的图片格式 "${i}"。支持:jpg / png / gif / webp`);const o=c.statSync(t,{throwIfNoEntry:!1});if(!o||!o.isFile())throw new m(`不是有效文件:${t}`);if(o.size>d)throw new m(`图片超过 ${d} 字节上限(${t} 为 ${o.size} 字节)。请先本地压缩后再发。`);return{absPath:t,mime:e,alt:l[p]||""}})}async function j(a,s,n){const l=[];for(const r of n){const p=c.readFileSync(r.absPath).toString("base64"),t=await x(a,s,{base64:p,mime:r.mime});if(t&&(t.httpStatus===401||t.httpStatus===403))throw new f("bsky.app",`uploadBlob 返回 HTTP ${t.httpStatus}`);const i=t&&t.bodyJson&&t.bodyJson.blob;if(!t||!t.ok||!i){const e=t&&t.bodyJson&&(t.bodyJson.message||t.bodyJson.error)||t?.error||`HTTP ${t?.httpStatus??0}`;throw new h(`图片上传失败(${r.absPath}):${e}`)}l.push({alt:r.alt,image:i})}return{$type:E,images:l}}y({site:"bluesky",name:"post",access:"write",description:"发布一条 Bluesky 帖子(支持文字 + 最多 4 张图)",domain:"bsky.app",strategy:w.UI,browser:!0,args:[{name:"text",fromFile:!0,type:"string",required:!0,positional:!0,help:"帖子正文(≤300 graphemes)"},{name:"images",type:"string",required:!1,help:"图片路径,逗号分隔,最多 4 张(jpg/png/gif/webp,每张≤1MB)"},{name:"alts",type:"string",required:!1,help:"图片 alt 文本,逗号分隔,与 images 一一对应(可选)"},{name:"langs",type:"string",required:!1,help:"语言标签,逗号分隔(如 zh,en);不传则不标注语言"}],columns:["status","message","text","uri","cid","url"],func:async(a,s)=>{if(!a)throw new h("Bluesky post 需要浏览器会话");const n=String(s.text??"");T(n,{label:"帖子正文"});if(n.trim().length===0)throw new m("帖子正文不能为空");const l=_(n);if(l>b)throw new m(`帖子正文 ${l} graphemes,超过 Bluesky 上限 ${b}`);const r=s.images?J(String(s.images),s.alts):[],p=s.langs!=null&&String(s.langs).length>0?String(s.langs).split(",").map((g)=>g.trim()).filter(Boolean):[],t=await I(a),i={$type:P,text:n,createdAt:new Date().toISOString()};if(p.length>0)i.langs=p;if(r.length>0)i.embed=await j(a,t,r);const e=await O(a,t,{path:"com.atproto.repo.createRecord",method:"POST",body:{repo:t.did,collection:B,record:i}});if(e&&(e.httpStatus===401||e.httpStatus===403))throw new f("bsky.app",`createRecord 返回 HTTP ${e.httpStatus}`);const o=e&&e.bodyJson;if(!e||!e.ok||!o||!o.uri){const g=o&&(o.message||o.error)||e?.error||`HTTP ${e?.httpStatus??0}`;throw new h(`发布失败:${g}`)}return[{status:"success",message:"帖子发布成功",text:n,uri:String(o.uri),cid:String(o.cid||""),url:M(o.uri,t.handle)}]}});
@@ -1,4 +1,4 @@
1
- import{AuthRequiredError as W,CommandExecutionError as Z}from"@jackwener/opencli/errors";export const BSKY_APP_URL="https://bsky.app",DEFAULT_PDS_HOST="https://bsky.social",POST_COLLECTION="app.bsky.feed.post",POST_TYPE="app.bsky.feed.post",IMAGES_EMBED_TYPE="app.bsky.embed.images",MAX_IMAGES=4,MAX_BLOB_BYTES=1e6,MAX_POST_GRAPHEMES=300,READ_SESSION_JS=`(() => {
1
+ import{AuthRequiredError as c,CommandExecutionError as u}from"@jackwener/opencli/errors";export const BSKY_APP_URL="https://bsky.app",DEFAULT_PDS_HOST="https://bsky.social",POST_COLLECTION="app.bsky.feed.post",POST_TYPE="app.bsky.feed.post",IMAGES_EMBED_TYPE="app.bsky.embed.images",MAX_IMAGES=4,MAX_BLOB_BYTES=1e6,MAX_POST_GRAPHEMES=300,READ_SESSION_JS=`(() => {
2
2
  try {
3
3
  const raw = localStorage.getItem('BSKY_STORAGE');
4
4
  if (!raw) return { kind: 'auth', detail: 'BSKY_STORAGE 不在 localStorage 里(未登录 bsky.app)' };
@@ -23,12 +23,12 @@ import{AuthRequiredError as W,CommandExecutionError as Z}from"@jackwener/opencli
23
23
  } catch (e) {
24
24
  return { kind: 'exception', detail: String((e && e.message) || e) };
25
25
  }
26
- })()`;export async function loadBskySession(F){if(!F)throw new Z("Bluesky 命令需要浏览器会话");await F.goto(BSKY_APP_URL);let v="";for(let G=0;G<30;G++){v=await F.evaluate("() => location.href");if(typeof v==="string"&&v.includes("bsky.app"))break;await F.wait(0.5)}let z=await F.evaluate(READ_SESSION_JS);for(let G=0;G<20&&z&&z.kind==="auth";G++){await F.wait(0.5);z=await F.evaluate(READ_SESSION_JS)}if(!z||z.ok!==!0){if(z&&z.kind==="auth")throw new W("bsky.app",z.detail);throw new W("bsky.app",`读取 Bluesky 会话失败:${z?.detail||"未知"}(可能未登录)`)}return z}export const WHOAMI_PROBE_JS=READ_SESSION_JS;export async function xrpcJson(F,{url:v,method:z,token:G,body:M}){const V={Authorization:`Bearer ${G}`};let Q="";if(M!==void 0){V["Content-Type"]="application/json";Q=`body: ${JSON.stringify(JSON.stringify(M))},`}const X=`(async () => {
26
+ })()`;export async function loadBskySession(r){if(!r)throw new u("Bluesky 命令需要浏览器会话");await r.goto(BSKY_APP_URL);let t="";for(let n=0;n<30;n++){t=await r.evaluate("() => location.href");if(typeof t==="string"&&t.includes("bsky.app"))break;await r.wait(0.5)}let e=await r.evaluate(READ_SESSION_JS);for(let n=0;n<20&&e&&e.kind==="auth";n++){await r.wait(0.5);e=await r.evaluate(READ_SESSION_JS)}if(!e||e.ok!==!0){if(e&&e.kind==="auth")throw new c("bsky.app",e.detail);throw new c("bsky.app",`读取 Bluesky 会话失败:${e?.detail||"未知"}(可能未登录)`)}return e}export const WHOAMI_PROBE_JS=READ_SESSION_JS;export async function xrpcJson(r,{url:t,method:e,token:n,body:s}){const a={Authorization:`Bearer ${n}`};let o="";if(s!==void 0){a["Content-Type"]="application/json";o=`body: ${JSON.stringify(JSON.stringify(s))},`}const i=`(async () => {
27
27
  try {
28
- const r = await fetch(${JSON.stringify(v)}, {
29
- method: ${JSON.stringify(z)},
30
- headers: ${JSON.stringify(V)},
31
- ${Q}
28
+ const r = await fetch(${JSON.stringify(t)}, {
29
+ method: ${JSON.stringify(e)},
30
+ headers: ${JSON.stringify(a)},
31
+ ${o}
32
32
  });
33
33
  const text = await r.text();
34
34
  let json = null; try { json = JSON.parse(text); } catch (e) {}
@@ -36,15 +36,15 @@ import{AuthRequiredError as W,CommandExecutionError as Z}from"@jackwener/opencli
36
36
  } catch (e) {
37
37
  return { ok: false, httpStatus: 0, error: String((e && e.message) || e) };
38
38
  }
39
- })()`;return await F.evaluate(X)}export async function xrpcUploadBlob(F,{pdsHost:v,token:z,base64:G,mime:M}){const V=`${v}/xrpc/com.atproto.repo.uploadBlob`,Q=`(async () => {
39
+ })()`;return await r.evaluate(i)}export async function xrpcUploadBlob(r,{pdsHost:t,token:e,base64:n,mime:s}){const a=`${t}/xrpc/com.atproto.repo.uploadBlob`,o=`(async () => {
40
40
  try {
41
- const b64 = ${JSON.stringify(G)};
41
+ const b64 = ${JSON.stringify(n)};
42
42
  const bin = atob(b64);
43
43
  const bytes = new Uint8Array(bin.length);
44
44
  for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
45
- const r = await fetch(${JSON.stringify(V)}, {
45
+ const r = await fetch(${JSON.stringify(a)}, {
46
46
  method: 'POST',
47
- headers: { Authorization: 'Bearer ' + ${JSON.stringify(z)}, 'Content-Type': ${JSON.stringify(M)} },
47
+ headers: { Authorization: 'Bearer ' + ${JSON.stringify(e)}, 'Content-Type': ${JSON.stringify(s)} },
48
48
  body: bytes,
49
49
  });
50
50
  const text = await r.text();
@@ -53,4 +53,4 @@ import{AuthRequiredError as W,CommandExecutionError as Z}from"@jackwener/opencli
53
53
  } catch (e) {
54
54
  return { ok: false, httpStatus: 0, error: String((e && e.message) || e) };
55
55
  }
56
- })()`;return await F.evaluate(Q)}export function isExpiredToken(F){if(!F)return!1;const v=F.bodyJson&&F.bodyJson.error;if(v==="ExpiredToken"||v==="InvalidToken")return!0;return F.httpStatus===401}export async function refreshBskySession(F,v){const z=await xrpcJson(F,{url:`${v.pdsHost}/xrpc/com.atproto.server.refreshSession`,method:"POST",token:v.refreshJwt}),G=z&&z.bodyJson;if(!z||!z.ok||!G||!G.accessJwt)throw new W("bsky.app",`Bluesky 会话过期且刷新失败(HTTP ${z?.httpStatus??0}),需要重新登录`);v.accessJwt=String(G.accessJwt);if(G.refreshJwt)v.refreshJwt=String(G.refreshJwt);return v}export async function xrpcJsonWithRefresh(F,v,{path:z,method:G,body:M}){const V=`${v.pdsHost}/xrpc/${z}`;let Q=await xrpcJson(F,{url:V,method:G,token:v.accessJwt,body:M});if(isExpiredToken(Q)){await refreshBskySession(F,v);Q=await xrpcJson(F,{url:V,method:G,token:v.accessJwt,body:M})}return Q}export async function uploadBlobWithRefresh(F,v,{base64:z,mime:G}){let M=await xrpcUploadBlob(F,{pdsHost:v.pdsHost,token:v.accessJwt,base64:z,mime:G});if(isExpiredToken(M)){await refreshBskySession(F,v);M=await xrpcUploadBlob(F,{pdsHost:v.pdsHost,token:v.accessJwt,base64:z,mime:G})}return M}export function graphemeLength(F){const v=String(F??"");try{if(typeof Intl<"u"&&typeof Intl.Segmenter==="function"){const z=new Intl.Segmenter(void 0,{granularity:"grapheme"});let G=0;for(const M of z.segment(v))G++;return G}}catch(z){}return[...v].length}export function postUriToWebUrl(F,v){const z=String(F||"").split("/").pop();if(!z||!v)return"";return`https://bsky.app/profile/${v}/post/${z}`}
56
+ })()`;return await r.evaluate(o)}export function isExpiredToken(r){if(!r)return!1;const t=r.bodyJson&&r.bodyJson.error;if(t==="ExpiredToken"||t==="InvalidToken")return!0;return r.httpStatus===401}export async function refreshBskySession(r,t){const e=await xrpcJson(r,{url:`${t.pdsHost}/xrpc/com.atproto.server.refreshSession`,method:"POST",token:t.refreshJwt}),n=e&&e.bodyJson;if(!e||!e.ok||!n||!n.accessJwt)throw new c("bsky.app",`Bluesky 会话过期且刷新失败(HTTP ${e?.httpStatus??0}),需要重新登录`);t.accessJwt=String(n.accessJwt);if(n.refreshJwt)t.refreshJwt=String(n.refreshJwt);return t}export async function xrpcJsonWithRefresh(r,t,{path:e,method:n,body:s}){const a=`${t.pdsHost}/xrpc/${e}`;let o=await xrpcJson(r,{url:a,method:n,token:t.accessJwt,body:s});if(isExpiredToken(o)){await refreshBskySession(r,t);o=await xrpcJson(r,{url:a,method:n,token:t.accessJwt,body:s})}return o}export async function uploadBlobWithRefresh(r,t,{base64:e,mime:n}){let s=await xrpcUploadBlob(r,{pdsHost:t.pdsHost,token:t.accessJwt,base64:e,mime:n});if(isExpiredToken(s)){await refreshBskySession(r,t);s=await xrpcUploadBlob(r,{pdsHost:t.pdsHost,token:t.accessJwt,base64:e,mime:n})}return s}export function graphemeLength(r){const t=String(r??"");try{if(typeof Intl<"u"&&typeof Intl.Segmenter==="function"){const e=new Intl.Segmenter(void 0,{granularity:"grapheme"});let n=0;for(const s of e.segment(t))n++;return n}}catch(e){}return[...t].length}export function postUriToWebUrl(r,t){const e=String(r||"").split("/").pop();if(!e||!t)return"";return`https://bsky.app/profile/${t}/post/${e}`}
@@ -1 +1 @@
1
- import{cli as H,Strategy as M}from"@jackwener/opencli/registry";import{BSKY_APP_URL as Q,READ_SESSION_JS as F}from"./shared.js";async function G(q){const v=await q.evaluate(F);if(v&&v.ok===!0)return{logged_in:!0,did:v.did||"",handle:v.handle||""};return{logged_in:!1,did:"",handle:""}}H({site:"bluesky",name:"whoami",access:"read",description:"检测 Bluesky 当前登录状态,返回是否已登录及 did/handle。",domain:"bsky.app",strategy:M.UI,browser:!0,columns:["logged_in","did","handle"],authStatus:{quickCheckRequiresNavigation:!0,quickCheck:async(q)=>{await q.goto("https://bsky.app/robots.txt");const v=await q.evaluate(F);return{logged_in:!!(v&&v.ok===!0)}}},func:async(q)=>{await q.goto(Q);let v="";for(let z=0;z<30;z++){v=await q.evaluate("() => location.href");if(typeof v==="string"&&v.includes("bsky.app"))break;await q.wait(0.5)}let C=await G(q);for(let z=0;z<20&&!C.logged_in;z++){await q.wait(0.5);C=await G(q)}return[C]}});
1
+ import{cli as n,Strategy as l}from"@jackwener/opencli/registry";import{BSKY_APP_URL as d,READ_SESSION_JS as o}from"./shared.js";async function r(t){const a=await t.evaluate(o);if(a&&a.ok===!0)return{logged_in:!0,did:a.did||"",handle:a.handle||""};return{logged_in:!1,did:"",handle:""}}n({site:"bluesky",name:"whoami",access:"read",description:"检测 Bluesky 当前登录状态,返回是否已登录及 did/handle。",domain:"bsky.app",strategy:l.UI,browser:!0,columns:["logged_in","did","handle"],authStatus:{quickCheckRequiresNavigation:!0,quickCheck:async(t)=>{await t.goto("https://bsky.app/robots.txt");const a=await t.evaluate(o);return{logged_in:!!(a&&a.ok===!0)}}},func:async(t)=>{await t.goto(d);let a="";for(let e=0;e<30;e++){a=await t.evaluate("() => location.href");if(typeof a==="string"&&a.includes("bsky.app"))break;await t.wait(0.5)}let i=await r(t);for(let e=0;e<20&&!i.logged_in;e++){await t.wait(0.5);i=await r(t)}return[i]}});
@@ -1,4 +1,4 @@
1
- import{ArgumentError as Y,CommandExecutionError as j,EmptyResultError as p}from"@jackwener/opencli/errors";import{cli as y,Strategy as x}from"@jackwener/opencli/registry";const k=/^\d{4}-\d{2}-\d{2}$/;function _(F,q,H,J){const K=Number(F??q);if(!Number.isInteger(K)||K<=0)throw new Y(`${H} must be a positive integer`);if(typeof J==="number"&&K>J)throw new Y(`${H} must be <= ${J}`);return K}function S(F,q,H,J){const K=Number(F??q);if(!Number.isInteger(K)||K<0)throw new Y(`${H} must be a non-negative integer`);if(typeof J==="number"&&K>J)throw new Y(`${H} must be <= ${J}`);return K}function D(F,q){const H=String(F||"").trim();if(!H)throw new Y(`${q} is required (YYYY-MM-DD)`);if(!k.test(H))throw new Y(`${q} must be YYYY-MM-DD, got ${JSON.stringify(F)}`);const[J,Z,K]=H.split("-").map(Number),$=new Date(Date.UTC(J,Z-1,K));if(Number.isNaN($.getTime())||$.getUTCFullYear()!==J||$.getUTCMonth()!==Z-1||$.getUTCDate()!==K)throw new Y(`${q} is not a valid calendar date: ${H}`);return H}function N(F){if(F==null||F==="")return"";const q=String(F).trim().toUpperCase();if(!/^[A-Z]{3}$/.test(q))throw new Y(`currency must be a 3-letter ISO code (e.g. USD, JPY, CNY), got ${JSON.stringify(F)}`);return q}const R=new Set(["en-us","en-gb","zh-cn","zh-tw","ja","ko","de","fr","es","it","pt-br","pt-pt","ru","th","vi","tr","pl","nl","ar"]);function T(F){if(F==null||F==="")return"";const q=String(F).trim().toLowerCase();if(!R.has(q))throw new Y(`lang must be one of: ${[...R].join(", ")}`);return q}function z(F){const H=String(F||"").replace(/\u00a0/g," ").match(/\b([1-9][0-9,.\s]*)\s+(?:properties|property|stays|stay|hotels|hotel)\b/i);if(!H)return!1;const J=H[1].replace(/\D/g,"");return Boolean(J)&&Number(J)>0}function b({destination:F,checkin:q,checkout:H,adults:J,rooms:Z,children:K,offset:$,currency:W,lang:G}){const O=G?`searchresults.${G}.html`:"searchresults.html",Q=new URLSearchParams;Q.set("ss",F);Q.set("checkin",q);Q.set("checkout",H);Q.set("group_adults",String(J));Q.set("no_rooms",String(Z));Q.set("group_children",String(K));if($>0)Q.set("offset",String($));if(W)Q.set("selected_currency",W);return`https://www.booking.com/${O}?${Q.toString()}`}const C=`
1
+ import{ArgumentError as s,CommandExecutionError as m,EmptyResultError as q}from"@jackwener/opencli/errors";import{cli as M,Strategy as A}from"@jackwener/opencli/registry";const B=/^\d{4}-\d{2}-\d{2}$/;function g(r,t,o,n){const c=Number(r??t);if(!Number.isInteger(c)||c<=0)throw new s(`${o} must be a positive integer`);if(typeof n==="number"&&c>n)throw new s(`${o} must be <= ${n}`);return c}function y(r,t,o,n){const c=Number(r??t);if(!Number.isInteger(c)||c<0)throw new s(`${o} must be a non-negative integer`);if(typeof n==="number"&&c>n)throw new s(`${o} must be <= ${n}`);return c}function b(r,t){const o=String(r||"").trim();if(!o)throw new s(`${t} is required (YYYY-MM-DD)`);if(!B.test(o))throw new s(`${t} must be YYYY-MM-DD, got ${JSON.stringify(r)}`);const[n,l,c]=o.split("-").map(Number),u=new Date(Date.UTC(n,l-1,c));if(Number.isNaN(u.getTime())||u.getUTCFullYear()!==n||u.getUTCMonth()!==l-1||u.getUTCDate()!==c)throw new s(`${t} is not a valid calendar date: ${o}`);return o}function _(r){if(r==null||r==="")return"";const t=String(r).trim().toUpperCase();if(!/^[A-Z]{3}$/.test(t))throw new s(`currency must be a 3-letter ISO code (e.g. USD, JPY, CNY), got ${JSON.stringify(r)}`);return t}const N=new Set(["en-us","en-gb","zh-cn","zh-tw","ja","ko","de","fr","es","it","pt-br","pt-pt","ru","th","vi","tr","pl","nl","ar"]);function x(r){if(r==null||r==="")return"";const t=String(r).trim().toLowerCase();if(!N.has(t))throw new s(`lang must be one of: ${[...N].join(", ")}`);return t}function T(r){const o=String(r||"").replace(/\u00a0/g," ").match(/\b([1-9][0-9,.\s]*)\s+(?:properties|property|stays|stay|hotels|hotel)\b/i);if(!o)return!1;const n=o[1].replace(/\D/g,"");return Boolean(n)&&Number(n)>0}function D({destination:r,checkin:t,checkout:o,adults:n,rooms:l,children:c,offset:u,currency:h,lang:d}){const w=d?`searchresults.${d}.html`:"searchresults.html",a=new URLSearchParams;a.set("ss",r);a.set("checkin",t);a.set("checkout",o);a.set("group_adults",String(n));a.set("no_rooms",String(l));a.set("group_children",String(c));if(u>0)a.set("offset",String(u));if(h)a.set("selected_currency",h);return`https://www.booking.com/${w}?${a.toString()}`}const E=`
2
2
  (() => {
3
3
  const trim = (v) => (v == null ? '' : String(v).replace(/\\s+/g, ' ').trim());
4
4
  const cards = Array.from(document.querySelectorAll('[data-testid=property-card]'));
@@ -90,4 +90,4 @@ import{ArgumentError as Y,CommandExecutionError as j,EmptyResultError as p}from"
90
90
  const totalText = trim(totalEl && totalEl.textContent);
91
91
  return { ok: true, items, blocked: false, totalText };
92
92
  })()
93
- `;y({site:"booking",name:"search",description:"Search Booking.com hotels by destination and dates (server-rendered card scrape).",access:"read",example:"ppcli booking search Tokyo --checkin 2026-06-15 --checkout 2026-06-17 -f yaml",domain:"www.booking.com",strategy:x.PUBLIC,browser:!0,args:[{name:"destination",required:!0,positional:!0,help:"Destination keyword (city, district, or hotel name)"},{name:"checkin",required:!0,help:"Check-in date YYYY-MM-DD"},{name:"checkout",required:!0,help:"Check-out date YYYY-MM-DD"},{name:"adults",type:"int",default:2,help:"Number of adults (1-30)"},{name:"rooms",type:"int",default:1,help:"Number of rooms (1-30)"},{name:"children",type:"int",default:0,help:"Number of children (0-10)"},{name:"currency",required:!1,help:"Force result currency (e.g. USD, JPY, CNY)"},{name:"lang",required:!1,help:"Force result language (e.g. en-us, zh-cn, ja)"},{name:"limit",type:"int",default:25,help:"Max rows to return (1-100; Booking pages 25 per request)"},{name:"offset",type:"int",default:0,help:"Result offset for pagination (multiple of 25)"}],columns:["rank","name","country","slug","star_rating","review_score","review_count","price_amount","price_currency","distance","recommended_room","url"],func:async(F,q)=>{const H=String(q.destination||"").trim();if(!H)throw new Y("destination is required");const J=D(q.checkin,"checkin"),Z=D(q.checkout,"checkout");if(J>=Z)throw new Y(`checkout (${Z}) must be after checkin (${J})`);const K=_(q.adults,2,"adults",30),$=_(q.rooms,1,"rooms",30),W=S(q.children,0,"children",10),G=N(q.currency),O=T(q.lang),Q=_(q.limit,25,"limit",100),P=S(q.offset,0,"offset",1000),A=b({destination:H,checkin:J,checkout:Z,adults:K,rooms:$,children:W,offset:P,currency:G,lang:O});try{await F.goto(A)}catch(B){throw new j(`Failed to load Booking.com search page: ${B?.message||B}`)}try{await F.wait("selector","[data-testid=property-card]",{timeoutMs:20000})}catch(B){}let M;try{M=await F.evaluate(C)}catch(B){throw new j(`Failed to extract Booking.com cards: ${B?.message||B}`)}if(M&&typeof M==="object"&&M.data&&M.session)M=M.data;if(!M||typeof M!=="object")throw new j("Booking.com page returned no extractable data");if(M.blocked)throw new j("Booking.com served a verification / captcha page; retry later or change profile");if(M.ok!==!0)throw new j("Booking.com extractor returned an invalid status");if(!Array.isArray(M.items))throw new j("Booking.com extractor returned malformed items");const V=M.items;if(V.length===0){const B=String(M.totalText||"").trim();if(z(B))throw new j(`Booking.com page declared results but no property cards were parsed: ${B}`);throw new p(`booking search ${JSON.stringify(H)}`,B?`No hotels rendered (${B}). Try a broader destination, different dates, or check the URL in a browser.`:"No hotels rendered. Try a broader destination, different dates, or check the URL in a browser.")}return V.slice(0,Q).map((B,f)=>{if(!B||typeof B!=="object")throw new j("Booking.com extractor returned malformed hotel row");const I=String(B.name||"").trim(),X=String(B.country||"").trim(),U=String(B.slug||"").trim(),L=String(B.url||"").trim(),h=X&&U?`https://www.booking.com/hotel/${X}/${U}.html`:"";if(!I||!/^[a-z]{2}$/.test(X)||!U||L!==h)throw new j("Booking.com hotel row is missing stable name/url identity");return{rank:P+f+1,name:I,country:X,slug:U,star_rating:B.star_rating,review_score:B.review_score,review_count:B.review_count,price_amount:B.price_amount,price_currency:B.price_amount==null?"":G||B.price_currency||"",distance:B.distance,recommended_room:B.recommended_room,url:L}})}});export const __test__={normalizePositiveInt:_,normalizeNonNegativeInt:S,normalizeDate:D,normalizeCurrency:N,normalizeLang:T,hasPositiveResultCount:z,buildSearchUrl:b,EXTRACTOR:C};
93
+ `;M({site:"booking",name:"search",description:"Search Booking.com hotels by destination and dates (server-rendered card scrape).",access:"read",example:"ppcli booking search Tokyo --checkin 2026-06-15 --checkout 2026-06-17 -f yaml",domain:"www.booking.com",strategy:A.PUBLIC,browser:!0,args:[{name:"destination",required:!0,positional:!0,help:"Destination keyword (city, district, or hotel name)"},{name:"checkin",required:!0,help:"Check-in date YYYY-MM-DD"},{name:"checkout",required:!0,help:"Check-out date YYYY-MM-DD"},{name:"adults",type:"int",default:2,help:"Number of adults (1-30)"},{name:"rooms",type:"int",default:1,help:"Number of rooms (1-30)"},{name:"children",type:"int",default:0,help:"Number of children (0-10)"},{name:"currency",required:!1,help:"Force result currency (e.g. USD, JPY, CNY)"},{name:"lang",required:!1,help:"Force result language (e.g. en-us, zh-cn, ja)"},{name:"limit",type:"int",default:25,help:"Max rows to return (1-100; Booking pages 25 per request)"},{name:"offset",type:"int",default:0,help:"Result offset for pagination (multiple of 25)"}],columns:["rank","name","country","slug","star_rating","review_score","review_count","price_amount","price_currency","distance","recommended_room","url"],func:async(r,t)=>{const o=String(t.destination||"").trim();if(!o)throw new s("destination is required");const n=b(t.checkin,"checkin"),l=b(t.checkout,"checkout");if(n>=l)throw new s(`checkout (${l}) must be after checkin (${n})`);const c=g(t.adults,2,"adults",30),u=g(t.rooms,1,"rooms",30),h=y(t.children,0,"children",10),d=_(t.currency),w=x(t.lang),a=g(t.limit,25,"limit",100),S=y(t.offset,0,"offset",1000),Y=D({destination:o,checkin:n,checkout:l,adults:c,rooms:u,children:h,offset:S,currency:d,lang:w});try{await r.goto(Y)}catch(e){throw new m(`Failed to load Booking.com search page: ${e?.message||e}`)}try{await r.wait("selector","[data-testid=property-card]",{timeoutMs:20000})}catch(e){}let i;try{i=await r.evaluate(E)}catch(e){throw new m(`Failed to extract Booking.com cards: ${e?.message||e}`)}if(i&&typeof i==="object"&&i.data&&i.session)i=i.data;if(!i||typeof i!=="object")throw new m("Booking.com page returned no extractable data");if(i.blocked)throw new m("Booking.com served a verification / captcha page; retry later or change profile");if(i.ok!==!0)throw new m("Booking.com extractor returned an invalid status");if(!Array.isArray(i.items))throw new m("Booking.com extractor returned malformed items");const k=i.items;if(k.length===0){const e=String(i.totalText||"").trim();if(T(e))throw new m(`Booking.com page declared results but no property cards were parsed: ${e}`);throw new q(`booking search ${JSON.stringify(o)}`,e?`No hotels rendered (${e}). Try a broader destination, different dates, or check the URL in a browser.`:"No hotels rendered. Try a broader destination, different dates, or check the URL in a browser.")}return k.slice(0,a).map((e,U)=>{if(!e||typeof e!=="object")throw new m("Booking.com extractor returned malformed hotel row");const C=String(e.name||"").trim(),p=String(e.country||"").trim(),f=String(e.slug||"").trim(),v=String(e.url||"").trim(),R=p&&f?`https://www.booking.com/hotel/${p}/${f}.html`:"";if(!C||!/^[a-z]{2}$/.test(p)||!f||v!==R)throw new m("Booking.com hotel row is missing stable name/url identity");return{rank:S+U+1,name:C,country:p,slug:f,star_rating:e.star_rating,review_score:e.review_score,review_count:e.review_count,price_amount:e.price_amount,price_currency:e.price_amount==null?"":d||e.price_currency||"",distance:e.distance,recommended_room:e.recommended_room,url:v}})}});export const __test__={normalizePositiveInt:g,normalizeNonNegativeInt:y,normalizeDate:b,normalizeCurrency:_,normalizeLang:x,hasPositiveResultCount:T,buildSearchUrl:D,EXTRACTOR:E};
@@ -1 +1 @@
1
- import{cli as W,Strategy as X}from"@jackwener/opencli/registry";import{CommandExecutionError as O,EmptyResultError as Y}from"@jackwener/opencli/errors";import{requirePage as _,navigateToGeekChat as B,geekPost as H,fetchGeekBossData as S,fetchGeekLastMsgs as j,resolveGeekBossId as q,resolveGeekResumeId as f,verbose as K}from"./utils.js";const C=["是否同意","交换","附件简历","联系方式"];W({site:"boss",name:"accept",access:"write",description:"BOSS直聘同意/拒绝 Boss 发来的交换请求(求职端,手机/微信/简历)",domain:"www.zhipin.com",strategy:X.COOKIE,navigateBefore:!1,browser:!0,args:[{name:"uid",positional:!0,required:!0,help:"Boss 的 uid(数字 friendId 或 encryptFriendId,从 boss chatlist --side geek 拿)"},{name:"reject",type:"boolean",default:!1,help:"拒绝请求(默认同意)"},{name:"resume-id",default:"",help:"HR 索要简历时指定发哪份 encryptResumeId(从 boss resumelist 拿)"}],columns:["status","detail"],func:async(F,Z)=>{_(F);await B(F);const z=await q(F,Z.uid),L=await j(F,[z]);if(L.length===0)throw new Y("boss accept",`找不到与 uid=${z} 的消息记录`);const M=L[0].lastMsgInfo||{},Q=M.msgId,J=M.showText||"";if(!Q)throw new O("无法获取消息 ID(lastMsgInfo.msgId 缺失)");if(!C.some((T)=>J.includes(T)))throw new O(`最新消息不是交换请求,不处理:「${J.slice(0,40)}」`);const U=await S(F,z),V=U.name||U.bossName||z,$=U.securityId?{securityId:U.securityId}:{};if(Z.reject){K(`Rejecting exchange from boss ${z}...`);await H(F,"/wapi/zpchat/geek/rejectItemContact",{bossId:z,mid:Q,...$});return[{status:"✅ 已拒绝交换请求",detail:`已拒绝 ${V} 的请求:${J.slice(0,40)}`}]}if(J.includes("微信")){K(`Accepting wechat exchange from boss ${z}...`);await H(F,"/wapi/zpchat/geek/acceptItemWeiXinRequest",{bossId:z,mid:Q,...$});return[{status:"✅ 已同意交换微信",detail:`已同意 ${V} 的微信交换请求`}]}const N=J.includes("简历")||J.includes("附件"),A={bossId:z,mid:Q,...$};if(N)A.encryptResumeId=await f(F,Z["resume-id"]);K(`Accepting exchange from boss ${z}...`);await H(F,"/wapi/zpchat/geek/acceptItemContact",A);return[{status:"✅ 已同意交换请求",detail:N?`已向 ${V} 发送附件简历 ${A.encryptResumeId}`:`已同意 ${V} 的请求:${J.slice(0,40)}`}]}});
1
+ import{cli as I,Strategy as p}from"@jackwener/opencli/registry";import{CommandExecutionError as w,EmptyResultError as b}from"@jackwener/opencli/errors";import{requirePage as g,navigateToGeekChat as y,geekPost as d,fetchGeekBossData as R,fetchGeekLastMsgs as k,resolveGeekBossId as E,resolveGeekResumeId as x,verbose as u}from"./utils.js";const B=["是否同意","交换","附件简历","联系方式"];I({site:"boss",name:"accept",access:"write",description:"BOSS直聘同意/拒绝 Boss 发来的交换请求(求职端,手机/微信/简历)",domain:"www.zhipin.com",strategy:p.COOKIE,navigateBefore:!1,browser:!0,args:[{name:"uid",positional:!0,required:!0,help:"Boss 的 uid(数字 friendId 或 encryptFriendId,从 boss chatlist --side geek 拿)"},{name:"reject",type:"boolean",default:!1,help:"拒绝请求(默认同意)"},{name:"resume-id",default:"",help:"HR 索要简历时指定发哪份 encryptResumeId(从 boss resumelist 拿)"}],columns:["status","detail"],func:async(t,c)=>{g(t);await y(t);const e=await E(t,c.uid),m=await k(t,[e]);if(m.length===0)throw new b("boss accept",`找不到与 uid=${e} 的消息记录`);const l=m[0].lastMsgInfo||{},i=l.msgId,s=l.showText||"";if(!i)throw new w("无法获取消息 ID(lastMsgInfo.msgId 缺失)");if(!B.some((h)=>s.includes(h)))throw new w(`最新消息不是交换请求,不处理:「${s.slice(0,40)}」`);const o=await R(t,e),a=o.name||o.bossName||e,n=o.securityId?{securityId:o.securityId}:{};if(c.reject){u(`Rejecting exchange from boss ${e}...`);await d(t,"/wapi/zpchat/geek/rejectItemContact",{bossId:e,mid:i,...n});return[{status:"✅ 已拒绝交换请求",detail:`已拒绝 ${a} 的请求:${s.slice(0,40)}`}]}if(s.includes("微信")){u(`Accepting wechat exchange from boss ${e}...`);await d(t,"/wapi/zpchat/geek/acceptItemWeiXinRequest",{bossId:e,mid:i,...n});return[{status:"✅ 已同意交换微信",detail:`已同意 ${a} 的微信交换请求`}]}const f=s.includes("简历")||s.includes("附件"),r={bossId:e,mid:i,...n};if(f)r.encryptResumeId=await x(t,c["resume-id"]);u(`Accepting exchange from boss ${e}...`);await d(t,"/wapi/zpchat/geek/acceptItemContact",r);return[{status:"✅ 已同意交换请求",detail:f?`已向 ${a} 发送附件简历 ${r.encryptResumeId}`:`已同意 ${a} 的请求:${s.slice(0,40)}`}]}});
@@ -1 +1 @@
1
- import{cli as n,Strategy as m}from"@jackwener/opencli/registry";import{EmptyResultError as p}from"@jackwener/opencli/errors";import{requirePage as l,navigateToGeekJob as u,geekGet as d,verbose as c}from"./utils.js";n({site:"boss",name:"applied",access:"read",description:"BOSS直聘查看已投递的职位(求职端)",domain:"www.zhipin.com",strategy:m.COOKIE,navigateBefore:!1,browser:!0,args:[{name:"page",type:"int",default:1,help:"Page number"},{name:"limit",type:"int",default:30,help:"Number of results to return"}],columns:["job_name","company","salary","status","time","security_id"],func:async(a,r)=>{l(a);c("Fetching applied jobs...");await u(a);const s=(await d(a,"/wapi/zprelation/resume/geekDeliverList",{page:r.page||1})).cardList??[];if(s.length===0)throw new p("boss applied","暂无投递记录。");const i=r.limit||30;return s.slice(0,i).map((e)=>{const t=e.jobInfo??e,o=e.brandInfo??e;return{job_name:t.jobName||e.jobName||"",company:o.brandName||e.brandName||"",salary:t.salaryDesc||e.salaryDesc||"",status:e.deliverStatusDesc||e.statusDesc||"",time:e.updateTimeDesc||e.createTimeDesc||"",security_id:t.securityId||e.securityId||""}})}});
1
+ import{cli as n,Strategy as m}from"@jackwener/opencli/registry";import{EmptyResultError as p}from"@jackwener/opencli/errors";import{requirePage as l,navigateToGeekJob as u,geekGet as d,verbose as c}from"./utils.js";n({site:"boss",name:"applied",access:"read",description:"BOSS直聘查看已投递的职位(求职端)",domain:"www.zhipin.com",strategy:m.COOKIE,navigateBefore:!1,browser:!0,args:[{name:"page",type:"int",default:1,help:"Page number"},{name:"limit",type:"int",default:30,help:"Number of results to return"}],columns:["job_name","company","salary","status","time","security_id"],func:async(t,r)=>{l(t);c("Fetching applied jobs...");await u(t);const s=(await d(t,"/wapi/zprelation/resume/geekDeliverList",{page:r.page||1})).cardList??[];if(s.length===0)throw new p("boss applied","暂无投递记录。");const i=r.limit||30;return s.slice(0,i).map((e)=>{const a=e.jobInfo??e,o=e.brandInfo??e;return{job_name:a.jobName||e.jobName||"",company:o.brandName||e.brandName||"",salary:a.salaryDesc||e.salaryDesc||"",status:e.deliverStatusDesc||e.statusDesc||"",time:e.updateTimeDesc||e.createTimeDesc||"",security_id:a.securityId||e.securityId||""}})}});
package/clis/boss/auth.js CHANGED
@@ -1 +1 @@
1
- import{AuthRequiredError as J,CommandExecutionError as Z}from"@jackwener/opencli/errors";import{registerSiteAuthCommands as W}from"../_shared/site-auth.js";async function M(b){const D=await b.getCookies({url:"https://www.zhipin.com"}),F=new Set(D.filter((K)=>K.value).map((K)=>K.name));return F.has("wt2")||F.has("t")}const P=/login\.zhipin\.com|\/web\/user\/|\/login\.html/;function X(b){const D=(()=>{try{return new URL(b).pathname||""}catch{return String(b||"")}})();if(/^\/web\/geek\//.test(D))return"geek";if(/^\/web\/(boss|recruit)\//.test(D))return"recruiter";if(/^\/web\/chat\//.test(D))return"recruiter";return""}async function Q(b){const D=await b.evaluate("location.href");return typeof D==="string"?D:""}async function V(b){if(!await M(b))throw new J("zhipin.com","Boss wt2 / t cookies missing");await b.goto("https://www.zhipin.com/web/geek/job-recommend");await b.wait(3);const D=await Q(b);if(P.test(D))throw new J("zhipin.com","Boss redirected to login page");const F=X(D);if(!F)return{user_type:"unknown"};return{user_type:F}}W({site:"boss",domain:"zhipin.com",loginUrl:"https://login.zhipin.com/",columns:["user_type"],quickCheck:M,verify:V,poll:async(b)=>{if(!await M(b))throw new J("zhipin.com","Waiting for Boss wt2 / t cookies");const D=await Q(b);if(!D||P.test(D))throw new J("zhipin.com","Waiting for Boss to leave the login page");return V(b)}});
1
+ import{AuthRequiredError as o,CommandExecutionError as m}from"@jackwener/opencli/errors";import{registerSiteAuthCommands as u}from"../_shared/site-auth.js";async function r(t){const e=await t.getCookies({url:"https://www.zhipin.com"}),i=new Set(e.filter((n)=>n.value).map((n)=>n.name));return i.has("wt2")||i.has("t")}const s=/login\.zhipin\.com|\/web\/user\/|\/login\.html/;function w(t){const e=(()=>{try{return new URL(t).pathname||""}catch{return String(t||"")}})();if(/^\/web\/geek\//.test(e))return"geek";if(/^\/web\/(boss|recruit)\//.test(e))return"recruiter";if(/^\/web\/chat\//.test(e))return"recruiter";return""}async function c(t){const e=await t.evaluate("location.href");return typeof e==="string"?e:""}async function a(t){if(!await r(t))throw new o("zhipin.com","Boss wt2 / t cookies missing");await t.goto("https://www.zhipin.com/web/geek/job-recommend");await t.wait(3);const e=await c(t);if(s.test(e))throw new o("zhipin.com","Boss redirected to login page");const i=w(e);if(!i)return{user_type:"unknown"};return{user_type:i}}u({site:"boss",domain:"zhipin.com",loginUrl:"https://login.zhipin.com/",columns:["user_type"],quickCheck:r,verify:a,poll:async(t)=>{if(!await r(t))throw new o("zhipin.com","Waiting for Boss wt2 / t cookies");const e=await c(t);if(!e||s.test(e))throw new o("zhipin.com","Waiting for Boss to leave the login page");return a(t)}});
@@ -1 +1 @@
1
- import{cli as F,Strategy as P}from"@jackwener/opencli/registry";import{ArgumentError as U}from"@jackwener/opencli/errors";import{requirePage as C,navigateToChat as L,navigateToGeekJob as M,fetchRecommendList as T,clickCandidateInList as j,typeAndSendMessage as x,geekAddFriend as z,verbose as $}from"./utils.js";async function q(D,B){const V=String(B["security-ids"]||"").split(",").map((H)=>H.trim()).filter(Boolean);if(V.length===0)throw new U("求职端批量投递需要 --security-ids(逗号分隔的职位 securityId,先跑 boss search 拿 security_id 列)");const X=B.limit||5,Q=V.slice(0,X),Z=Math.round((B.delay??1.5)*1000);if(B["dry-run"])return Q.map((H,K)=>({name:`#${K+1}`,status:"\uD83D\uDCCB 预览",detail:`将投递 securityId=${H}(未实际发送)`}));$(`Batch applying to ${Q.length} jobs...`);await M(D);const O=[];for(let H=0;H<Q.length;H++){const K=Q[H];try{const W=await z(D,K,B.lid||"");O.push({name:W?.bossName||K.slice(0,12),status:"✅ 已投递",detail:W?.jobName?`${W.jobName}`:K})}catch(W){O.push({name:K.slice(0,12),status:"❌ 失败",detail:W.message?.substring(0,80)||"未知错误"})}if(H<Q.length-1)await D.wait({time:Z/1000})}return O}async function E(D,B){const V=B["job-id"]||"",X=B.limit||5,Q=B.text||"你好,请问您对这个职位感兴趣吗?",Z=B.delay??1.5;$(`Batch greeting up to ${X} candidates...`);await L(D,3);let O=await T(D);if(V)O=O.filter((K)=>K.encryptJobId===V);O=O.slice(0,X);if(O.length===0)return[{name:"-",status:"⚠️ 无候选人",detail:"当前没有待招呼的推荐候选人"}];if(B["dry-run"])return O.map((K)=>({name:K.name||"候选人",status:"\uD83D\uDCCB 预览",detail:`将发送:${Q}(未实际发送)`}));const H=[];for(const K of O){const W=K.uid,Y=K.name||"候选人";try{if(!await j(D,W)){H.push({name:Y,status:"❌ 跳过",detail:"在聊天列表中未找到"});continue}await D.wait({time:2});if(!await x(D,Q)){H.push({name:Y,status:"❌ 失败",detail:"找不到消息输入框"});continue}await D.wait({time:Z});H.push({name:Y,status:"✅ 已发送",detail:Q})}catch(_){H.push({name:Y,status:"❌ 失败",detail:_.message?.substring(0,80)||"未知错误"})}}return H}F({site:"boss",name:"batchgreet",access:"write",description:"BOSS直聘批量打招呼(求职端批量投递职位 / 招聘端批量招呼候选人)",domain:"www.zhipin.com",strategy:P.COOKIE,navigateBefore:!1,browser:!0,args:[{name:"side",default:"auto",choices:["auto","geek","boss"],help:"Identity side: auto (default), geek (job-seeker), boss (recruiter)"},{name:"security-ids",default:"",help:"[geek] 逗号分隔的职位 securityId(先跑 boss search 拿 security_id 列)"},{name:"lid",default:"",help:"[geek] Lid parameter from search results (optional)"},{name:"job-id",default:"",help:"[boss] Filter by encrypted job ID (greet all jobs if empty)"},{name:"text",fromFile:!0,default:"",help:"[boss] Custom greeting message (uses default if empty)"},{name:"limit",type:"int",default:5,help:"Max targets to greet"},{name:"delay",type:"number",default:1.5,help:"Seconds to wait between greetings (风控节流,别调太低)"},{name:"dry-run",type:"boolean",default:!1,help:"只预览将要打招呼的目标,不实际发送"}],columns:["name","status","detail"],func:async(D,B)=>{C(D);const V=B.side||"auto";if(V==="geek")return q(D,B);if(V==="boss")return E(D,B);return B["security-ids"]?q(D,B):E(D,B)}});
1
+ import{cli as h,Strategy as b}from"@jackwener/opencli/registry";import{ArgumentError as p}from"@jackwener/opencli/errors";import{requirePage as g,navigateToChat as I,navigateToGeekJob as j,fetchRecommendList as w,clickCandidateInList as S,typeAndSendMessage as A,geekAddFriend as B,verbose as m}from"./utils.js";async function f(t,e){const r=String(e["security-ids"]||"").split(",").map((i)=>i.trim()).filter(Boolean);if(r.length===0)throw new p("求职端批量投递需要 --security-ids(逗号分隔的职位 securityId,先跑 boss search 拿 security_id 列)");const c=e.limit||5,n=r.slice(0,c),u=Math.round((e.delay??1.5)*1000);if(e["dry-run"])return n.map((i,s)=>({name:`#${s+1}`,status:"\uD83D\uDCCB 预览",detail:`将投递 securityId=${i}(未实际发送)`}));m(`Batch applying to ${n.length} jobs...`);await j(t);const a=[];for(let i=0;i<n.length;i++){const s=n[i];try{const o=await B(t,s,e.lid||"");a.push({name:o?.bossName||s.slice(0,12),status:"✅ 已投递",detail:o?.jobName?`${o.jobName}`:s})}catch(o){a.push({name:s.slice(0,12),status:"❌ 失败",detail:o.message?.substring(0,80)||"未知错误"})}if(i<n.length-1)await t.wait({time:u/1000})}return a}async function y(t,e){const r=e["job-id"]||"",c=e.limit||5,n=e.text||"你好,请问您对这个职位感兴趣吗?",u=e.delay??1.5;m(`Batch greeting up to ${c} candidates...`);await I(t,3);let a=await w(t);if(r)a=a.filter((s)=>s.encryptJobId===r);a=a.slice(0,c);if(a.length===0)return[{name:"-",status:"⚠️ 无候选人",detail:"当前没有待招呼的推荐候选人"}];if(e["dry-run"])return a.map((s)=>({name:s.name||"候选人",status:"\uD83D\uDCCB 预览",detail:`将发送:${n}(未实际发送)`}));const i=[];for(const s of a){const o=s.uid,d=s.name||"候选人";try{if(!await S(t,o)){i.push({name:d,status:"❌ 跳过",detail:"在聊天列表中未找到"});continue}await t.wait({time:2});if(!await A(t,n)){i.push({name:d,status:"❌ 失败",detail:"找不到消息输入框"});continue}await t.wait({time:u});i.push({name:d,status:"✅ 已发送",detail:n})}catch(l){i.push({name:d,status:"❌ 失败",detail:l.message?.substring(0,80)||"未知错误"})}}return i}h({site:"boss",name:"batchgreet",access:"write",description:"BOSS直聘批量打招呼(求职端批量投递职位 / 招聘端批量招呼候选人)",domain:"www.zhipin.com",strategy:b.COOKIE,navigateBefore:!1,browser:!0,args:[{name:"side",default:"auto",choices:["auto","geek","boss"],help:"Identity side: auto (default), geek (job-seeker), boss (recruiter)"},{name:"security-ids",default:"",help:"[geek] 逗号分隔的职位 securityId(先跑 boss search 拿 security_id 列)"},{name:"lid",default:"",help:"[geek] Lid parameter from search results (optional)"},{name:"job-id",default:"",help:"[boss] Filter by encrypted job ID (greet all jobs if empty)"},{name:"text",fromFile:!0,default:"",help:"[boss] Custom greeting message (uses default if empty)"},{name:"limit",type:"int",default:5,help:"Max targets to greet"},{name:"delay",type:"number",default:1.5,help:"Seconds to wait between greetings (风控节流,别调太低)"},{name:"dry-run",type:"boolean",default:!1,help:"只预览将要打招呼的目标,不实际发送"}],columns:["name","status","detail"],func:async(t,e)=>{g(t);const r=e.side||"auto";if(r==="geek")return f(t,e);if(r==="boss")return y(t,e);return e["security-ids"]?f(t,e):y(t,e)}});
@@ -1 +1 @@
1
- import{cli as a,Strategy as i}from"@jackwener/opencli/registry";import{requirePage as c,navigateToGeekChat as r,fetchGeekBossData as d,resolveGeekBossId as m,verbose as b}from"./utils.js";a({site:"boss",name:"bossinfo",access:"read",description:"BOSS直聘查看与某个 Boss 的会话上下文(求职端)",domain:"www.zhipin.com",strategy:i.COOKIE,navigateBefore:!1,browser:!0,args:[{name:"uid",positional:!0,required:!0,help:"Boss 的 uid(数字 friendId 或 encryptFriendId,从 boss chatlist --side geek 拿)"}],columns:["name","company","job","security_id","encrypt_job_id","phone","wechat","exchange"],func:async(o,n)=>{c(o);await r(o);const t=await m(o,n.uid);b(`Fetching boss data for ${t}...`);const e=await d(o,t),s=e.exchange||{};return[{name:e.name||e.bossName||"",company:e.brandName||e.company||"",job:e.jobName||"",security_id:e.securityId||"",encrypt_job_id:e.encryptJobId||"",phone:s.phone||e.phone||"",wechat:s.weixin||s.wechat||e.weixin||"",exchange:Object.keys(s).length?JSON.stringify(s):""}]}});
1
+ import{cli as t,Strategy as i}from"@jackwener/opencli/registry";import{requirePage as r,navigateToGeekChat as c,fetchGeekBossData as d,resolveGeekBossId as h,verbose as m}from"./utils.js";t({site:"boss",name:"bossinfo",access:"read",description:"BOSS直聘查看与某个 Boss 的会话上下文(求职端)",domain:"www.zhipin.com",strategy:i.COOKIE,navigateBefore:!1,browser:!0,args:[{name:"uid",positional:!0,required:!0,help:"Boss 的 uid(数字 friendId 或 encryptFriendId,从 boss chatlist --side geek 拿)"}],columns:["name","company","job","security_id","encrypt_job_id","phone","wechat","exchange"],func:async(s,n)=>{r(s);await c(s);const a=await h(s,n.uid);m(`Fetching boss data for ${a}...`);const e=await d(s,a),o=e.exchange||{};return[{name:e.name||e.bossName||"",company:e.brandName||e.company||"",job:e.jobName||"",security_id:e.securityId||"",encrypt_job_id:e.encryptJobId||"",phone:o.phone||e.phone||"",wechat:o.weixin||o.wechat||e.weixin||"",exchange:Object.keys(o).length?JSON.stringify(o):""}]}});
@@ -1 +1 @@
1
- import{cli as _,Strategy as j}from"@jackwener/opencli/registry";import{CommandExecutionError as N,EmptyResultError as $}from"@jackwener/opencli/errors";import{requirePage as P,navigateToChat as q,navigateToGeekChat as x,fetchFriendList as A,fetchGeekFriendLabelList as F,fetchGeekFriendInfoList as S,readEncryptSystemId as M,assertOk as v,IDENTITY_MISMATCH_CODE as G,readPositiveInteger as H}from"./utils.js";function Y(z){if(!z)return"";return new Date(z).toLocaleString("zh-CN")}function B(z){return{name:z.name||"",company:"",job:z.jobName||"",title:"",last_msg:z.lastMessageInfo?.text||"",last_time:z.lastTime||"",uid:z.encryptUid||"",security_id:z.securityId||""}}async function D(z,U){const W=await M(z),X=await F(z,{encryptSystemId:W});if(X.length===0)return[];const Z=X.slice(0,U),V=Z.map((J)=>J.friendId).filter(Boolean),Q=await S(z,V),O=new Map(Q.map((J)=>[String(J.friendId??J.uid),J]));return Z.map((J)=>{const K=O.get(String(J.friendId))||{};return{name:K.name||J.name||"",company:K.brandName||J.brandName||"",job:K.jobName||J.jobName||"",title:K.bossTitle||J.bossTitle||"",last_msg:K.lastMessageInfo?.showText||K.lastMsg||J.lastMsg||"",last_time:K.lastTime||Y(K.lastMessageInfo?.msgTime)||Y(J.updateTime)||"",uid:K.encryptUid||J.encryptFriendId||String(K.uid??K.friendId??J.friendId??""),security_id:K.securityId||""}})}_({site:"boss",name:"chatlist",access:"read",description:"BOSS直聘查看聊天列表(招聘端/求职端)",domain:"www.zhipin.com",strategy:j.COOKIE,navigateBefore:!1,browser:!0,args:[{name:"page",type:"int",default:1,help:"Page number"},{name:"limit",type:"int",default:20,help:"Number of results"},{name:"job-id",default:"0",help:"Filter by job ID (0=all, boss side only)"},{name:"side",default:"auto",choices:["auto","boss","geek"],help:"Identity side: auto (default), boss (recruiter), or geek (job-seeker)"}],columns:["name","company","job","title","last_msg","last_time","uid","security_id"],func:async(z,U)=>{P(z);const W=H(U.limit,"chatlist --limit",20,100),X=H(U.page,"chatlist --page",1),Z=U.side||"auto";if(Z==="boss"){await q(z);const Q=await A(z,{pageNum:X,jobId:U["job-id"]||"0"});if(Q.length===0)throw new $("boss chatlist","No recruiter-side chat sessions were returned.");return Q.slice(0,W).map(B)}if(Z==="geek"){await x(z);const Q=await D(z,W);if(Q.length===0)throw new $("boss chatlist","No job-seeker-side chat sessions were returned.");return Q}await q(z);const V=await A(z,{pageNum:X,jobId:U["job-id"]||"0",allowNonZero:!0});if(Array.isArray(V)){if(V.length===0)throw new $("boss chatlist","No recruiter-side chat sessions were returned.");return V.slice(0,W).map(B)}if(V.code===G){await x(z);const Q=await D(z,W);if(Q.length===0)throw new $("boss chatlist","No job-seeker-side chat sessions were returned.");return Q}v(V);throw new N("Boss chatlist returned an unexpected response")}});
1
+ import{cli as p,Strategy as I}from"@jackwener/opencli/registry";import{CommandExecutionError as g,EmptyResultError as c}from"@jackwener/opencli/errors";import{requirePage as j,navigateToChat as l,navigateToGeekChat as m,fetchFriendList as u,fetchGeekFriendLabelList as N,fetchGeekFriendInfoList as T,readEncryptSystemId as _,assertOk as M,IDENTITY_MISMATCH_CODE as S,readPositiveInteger as b}from"./utils.js";function h(e){if(!e)return"";return new Date(e).toLocaleString("zh-CN")}function w(e){return{name:e.name||"",company:"",job:e.jobName||"",title:"",last_msg:e.lastMessageInfo?.text||"",last_time:e.lastTime||"",uid:e.encryptUid||"",security_id:e.securityId||""}}async function y(e,r){const a=await _(e),o=await N(e,{encryptSystemId:a});if(o.length===0)return[];const d=o.slice(0,r),n=d.map((t)=>t.friendId).filter(Boolean),i=await T(e,n),f=new Map(i.map((t)=>[String(t.friendId??t.uid),t]));return d.map((t)=>{const s=f.get(String(t.friendId))||{};return{name:s.name||t.name||"",company:s.brandName||t.brandName||"",job:s.jobName||t.jobName||"",title:s.bossTitle||t.bossTitle||"",last_msg:s.lastMessageInfo?.showText||s.lastMsg||t.lastMsg||"",last_time:s.lastTime||h(s.lastMessageInfo?.msgTime)||h(t.updateTime)||"",uid:s.encryptUid||t.encryptFriendId||String(s.uid??s.friendId??t.friendId??""),security_id:s.securityId||""}})}p({site:"boss",name:"chatlist",access:"read",description:"BOSS直聘查看聊天列表(招聘端/求职端)",domain:"www.zhipin.com",strategy:I.COOKIE,navigateBefore:!1,browser:!0,args:[{name:"page",type:"int",default:1,help:"Page number"},{name:"limit",type:"int",default:20,help:"Number of results"},{name:"job-id",default:"0",help:"Filter by job ID (0=all, boss side only)"},{name:"side",default:"auto",choices:["auto","boss","geek"],help:"Identity side: auto (default), boss (recruiter), or geek (job-seeker)"}],columns:["name","company","job","title","last_msg","last_time","uid","security_id"],func:async(e,r)=>{j(e);const a=b(r.limit,"chatlist --limit",20,100),o=b(r.page,"chatlist --page",1),d=r.side||"auto";if(d==="boss"){await l(e);const i=await u(e,{pageNum:o,jobId:r["job-id"]||"0"});if(i.length===0)throw new c("boss chatlist","No recruiter-side chat sessions were returned.");return i.slice(0,a).map(w)}if(d==="geek"){await m(e);const i=await y(e,a);if(i.length===0)throw new c("boss chatlist","No job-seeker-side chat sessions were returned.");return i}await l(e);const n=await u(e,{pageNum:o,jobId:r["job-id"]||"0",allowNonZero:!0});if(Array.isArray(n)){if(n.length===0)throw new c("boss chatlist","No recruiter-side chat sessions were returned.");return n.slice(0,a).map(w)}if(n.code===S){await m(e);const i=await y(e,a);if(i.length===0)throw new c("boss chatlist","No job-seeker-side chat sessions were returned.");return i}M(n);throw new g("Boss chatlist returned an unexpected response")}});