publishport-opencli 1.0.20 → 1.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1041) hide show
  1. package/clis/12306/me.js +2 -2
  2. package/clis/12306/orders.js +3 -3
  3. package/clis/12306/passengers.js +3 -3
  4. package/clis/12306/price.js +1 -1
  5. package/clis/12306/stations.js +1 -1
  6. package/clis/12306/train.js +1 -1
  7. package/clis/12306/trains.js +1 -1
  8. package/clis/12306/utils.js +1 -1
  9. package/clis/1688/download.js +1 -1
  10. package/clis/1688/item.js +4 -4
  11. package/clis/1688/search.js +4 -4
  12. package/clis/1688/store.js +4 -4
  13. package/clis/1point3acres/forum.js +1 -1
  14. package/clis/1point3acres/forums.js +1 -1
  15. package/clis/1point3acres/notifications.js +1 -1
  16. package/clis/1point3acres/search.js +1 -1
  17. package/clis/1point3acres/thread.js +2 -2
  18. package/clis/1point3acres/user.js +1 -1
  19. package/clis/1point3acres/utils.js +2 -2
  20. package/clis/36kr/article.js +2 -2
  21. package/clis/36kr/hot.js +2 -2
  22. package/clis/36kr/news.js +1 -1
  23. package/clis/36kr/search.js +2 -2
  24. package/clis/51job/company.js +2 -2
  25. package/clis/51job/detail.js +2 -2
  26. package/clis/51job/hot.js +1 -1
  27. package/clis/51job/search.js +1 -1
  28. package/clis/51job/utils.js +7 -7
  29. package/clis/_atlassian/shared.js +9 -9
  30. package/clis/_shared/article/auth.js +4 -4
  31. package/clis/_shared/article/douban-md2draft.js +4 -4
  32. package/clis/_shared/article/format.js +1 -1
  33. package/clis/_shared/article/images.js +7 -7
  34. package/clis/_shared/article/login.js +1 -1
  35. package/clis/_shared/article/publish.js +11 -11
  36. package/clis/_shared/common.js +1 -1
  37. package/clis/_shared/content-guard.js +1 -1
  38. package/clis/_shared/desktop-commands.js +1 -1
  39. package/clis/_shared/file-inject.js +12 -12
  40. package/clis/_shared/self-hosted-sites.js +2 -2
  41. package/clis/_shared/site-auth.js +1 -1
  42. package/clis/_shared/token-auth.js +2 -2
  43. package/clis/_shared/video-publish.js +9 -9
  44. package/clis/amazon/offer.js +3 -3
  45. package/clis/amazon/product.js +5 -5
  46. package/clis/amazon/shared.js +6 -6
  47. package/clis/antigravity/_actions.js +13 -13
  48. package/clis/antigravity/audit-extras.js +10 -10
  49. package/clis/antigravity/delete.js +1 -1
  50. package/clis/antigravity/model.js +6 -6
  51. package/clis/antigravity/new.js +2 -2
  52. package/clis/antigravity/read.js +2 -2
  53. package/clis/antigravity/rename.js +1 -1
  54. package/clis/antigravity/send.js +3 -3
  55. package/clis/antigravity/serve.js +17 -17
  56. package/clis/antigravity/storage.js +6 -6
  57. package/clis/antigravity/watch.js +2 -2
  58. package/clis/apple-podcasts/episodes.js +1 -1
  59. package/clis/apple-podcasts/top.js +1 -1
  60. package/clis/apple-podcasts/utils.js +1 -1
  61. package/clis/archive/item.js +1 -1
  62. package/clis/archive/search.js +1 -1
  63. package/clis/archive/snapshots.js +1 -1
  64. package/clis/archive/wayback.js +1 -1
  65. package/clis/arxiv/author.js +1 -1
  66. package/clis/arxiv/utils.js +1 -1
  67. package/clis/autohome/brand.js +1 -1
  68. package/clis/autohome/score.js +1 -1
  69. package/clis/autohome/utils.js +1 -1
  70. package/clis/baijiahao/article.js +1 -1
  71. package/clis/baijiahao/lists.js +1 -1
  72. package/clis/baijiahao/login.js +1 -1
  73. package/clis/baijiahao/publish.js +9 -9
  74. package/clis/baijiahao/stats.js +1 -1
  75. package/clis/baijiahao/whoami.js +1 -1
  76. package/clis/band/bands.js +2 -2
  77. package/clis/band/mentions.js +2 -2
  78. package/clis/band/post.js +4 -4
  79. package/clis/band/posts.js +3 -3
  80. package/clis/barchart/flow.js +3 -3
  81. package/clis/barchart/greeks.js +2 -2
  82. package/clis/barchart/quote.js +3 -3
  83. package/clis/bbc/news.js +1 -1
  84. package/clis/bbc/topic.js +1 -1
  85. package/clis/bbc/utils.js +1 -1
  86. package/clis/bilibili/article.js +1 -1
  87. package/clis/bilibili/categories.js +1 -1
  88. package/clis/bilibili/coin.js +1 -1
  89. package/clis/bilibili/comment-del.js +1 -1
  90. package/clis/bilibili/comment-like.js +1 -1
  91. package/clis/bilibili/comment.js +1 -1
  92. package/clis/bilibili/comments.js +1 -1
  93. package/clis/bilibili/dm-list.js +1 -1
  94. package/clis/bilibili/dm-read.js +1 -1
  95. package/clis/bilibili/dm-send.js +1 -1
  96. package/clis/bilibili/download.js +2 -2
  97. package/clis/bilibili/drafts.js +1 -1
  98. package/clis/bilibili/dynamic-post.js +3 -3
  99. package/clis/bilibili/favorite-add.js +1 -1
  100. package/clis/bilibili/favorite.js +1 -1
  101. package/clis/bilibili/feed.js +2 -2
  102. package/clis/bilibili/follow.js +1 -1
  103. package/clis/bilibili/following.js +1 -1
  104. package/clis/bilibili/like.js +1 -1
  105. package/clis/bilibili/partitions.js +1 -1
  106. package/clis/bilibili/stats.js +1 -1
  107. package/clis/bilibili/subtitle.js +3 -3
  108. package/clis/bilibili/summary.js +1 -1
  109. package/clis/bilibili/topics.js +1 -1
  110. package/clis/bilibili/unfollow.js +1 -1
  111. package/clis/bilibili/upload.js +1 -1
  112. package/clis/bilibili/utils.js +10 -10
  113. package/clis/bilibili/video-drafts.js +1 -1
  114. package/clis/bilibili/video.js +1 -1
  115. package/clis/bloomberg/businessweek.js +4 -4
  116. package/clis/bloomberg/news.js +2 -2
  117. package/clis/bloomberg/utils.js +13 -13
  118. package/clis/bluesky/post.js +1 -1
  119. package/clis/bluesky/shared.js +11 -11
  120. package/clis/bluesky/whoami.js +1 -1
  121. package/clis/booking/search.js +2 -2
  122. package/clis/boss/accept.js +1 -1
  123. package/clis/boss/applied.js +1 -1
  124. package/clis/boss/auth.js +1 -1
  125. package/clis/boss/batchgreet.js +1 -1
  126. package/clis/boss/bossinfo.js +1 -1
  127. package/clis/boss/chatlist.js +1 -1
  128. package/clis/boss/chatmsg.js +1 -1
  129. package/clis/boss/cities.js +1 -1
  130. package/clis/boss/detail.js +1 -1
  131. package/clis/boss/exchange.js +1 -1
  132. package/clis/boss/greet.js +1 -1
  133. package/clis/boss/interviews.js +1 -1
  134. package/clis/boss/invite.js +1 -1
  135. package/clis/boss/joblist.js +1 -1
  136. package/clis/boss/mark.js +1 -1
  137. package/clis/boss/me.js +2 -2
  138. package/clis/boss/recommend.js +1 -1
  139. package/clis/boss/resumedelete.js +1 -1
  140. package/clis/boss/resumelist.js +1 -1
  141. package/clis/boss/resumeupload.js +11 -11
  142. package/clis/boss/search.js +1 -1
  143. package/clis/boss/send.js +1 -1
  144. package/clis/boss/sendresume.js +1 -1
  145. package/clis/boss/stats.js +1 -1
  146. package/clis/boss/unread.js +1 -1
  147. package/clis/boss/utils.js +13 -13
  148. package/clis/chaoxing/assignments.js +1 -1
  149. package/clis/chaoxing/exams.js +1 -1
  150. package/clis/chaoxing/utils.js +9 -9
  151. package/clis/chatgpt/ask.js +1 -1
  152. package/clis/chatgpt/auth.js +2 -2
  153. package/clis/chatgpt/detail.js +1 -1
  154. package/clis/chatgpt/image.js +1 -1
  155. package/clis/chatgpt/read.js +1 -1
  156. package/clis/chatgpt/send.js +1 -1
  157. package/clis/chatgpt/utils.js +59 -59
  158. package/clis/chatgpt-app/ask.js +1 -1
  159. package/clis/chatgpt-app/send.js +1 -1
  160. package/clis/chatwise/model.js +6 -6
  161. package/clis/chess/analyze.js +1 -1
  162. package/clis/chess/game.js +1 -1
  163. package/clis/chess/games.js +1 -1
  164. package/clis/chess/stats.js +1 -1
  165. package/clis/chess/utils.js +1 -1
  166. package/clis/claude/ask.js +2 -2
  167. package/clis/claude/detail.js +1 -1
  168. package/clis/claude/new.js +1 -1
  169. package/clis/claude/read.js +1 -1
  170. package/clis/claude/send.js +1 -1
  171. package/clis/claude/utils.js +23 -23
  172. package/clis/cnblogs/article.js +1 -1
  173. package/clis/cnblogs/login.js +1 -1
  174. package/clis/cnblogs/stats.js +7 -7
  175. package/clis/cnblogs/whoami.js +1 -1
  176. package/clis/codex/_actions.js +3 -3
  177. package/clis/codex/archive.js +1 -1
  178. package/clis/codex/ask.js +6 -6
  179. package/clis/codex/model.js +8 -8
  180. package/clis/codex/pin.js +1 -1
  181. package/clis/codex/rename.js +4 -4
  182. package/clis/codex/send.js +3 -3
  183. package/clis/codex/sidebar.js +1 -1
  184. package/clis/coingecko/categories.js +1 -1
  185. package/clis/coingecko/coin.js +1 -1
  186. package/clis/coingecko/derivatives.js +1 -1
  187. package/clis/coingecko/exchanges.js +1 -1
  188. package/clis/coingecko/global.js +1 -1
  189. package/clis/coingecko/trending.js +1 -1
  190. package/clis/confluence/search.js +1 -1
  191. package/clis/coupang/product.js +3 -3
  192. package/clis/coupang/utils.js +1 -1
  193. package/clis/crates/crate.js +1 -1
  194. package/clis/crates/search.js +1 -1
  195. package/clis/crates/utils.js +1 -1
  196. package/clis/csdn/article.js +13 -13
  197. package/clis/csdn/columns.js +1 -1
  198. package/clis/csdn/login.js +1 -1
  199. package/clis/csdn/stats.js +4 -4
  200. package/clis/csdn/whoami.js +1 -1
  201. package/clis/cto51/article.js +1 -1
  202. package/clis/cto51/whoami.js +1 -1
  203. package/clis/ctrip/flight.js +2 -2
  204. package/clis/ctrip/hotel-search.js +3 -3
  205. package/clis/ctrip/hotel-suggest.js +1 -1
  206. package/clis/ctrip/search.js +1 -1
  207. package/clis/ctrip/utils.js +6 -6
  208. package/clis/cursor/ask.js +5 -5
  209. package/clis/cursor/composer.js +2 -2
  210. package/clis/cursor/model.js +4 -4
  211. package/clis/cursor/send.js +2 -2
  212. package/clis/dblp/author.js +1 -1
  213. package/clis/dblp/paper.js +1 -1
  214. package/clis/dblp/search.js +1 -1
  215. package/clis/dblp/utils.js +1 -1
  216. package/clis/dblp/venue.js +1 -1
  217. package/clis/deepseek/ask.js +1 -1
  218. package/clis/deepseek/auth.js +2 -2
  219. package/clis/deepseek/detail.js +1 -1
  220. package/clis/deepseek/new.js +1 -1
  221. package/clis/deepseek/read.js +1 -1
  222. package/clis/deepseek/send.js +7 -7
  223. package/clis/deepseek/utils.js +25 -25
  224. package/clis/defillama/protocol.js +1 -1
  225. package/clis/defillama/protocols.js +1 -1
  226. package/clis/defillama/utils.js +1 -1
  227. package/clis/devto/auth.js +2 -2
  228. package/clis/devto/latest.js +1 -1
  229. package/clis/devto/publish.js +5 -5
  230. package/clis/devto/read.js +2 -2
  231. package/clis/devto/stats.js +3 -3
  232. package/clis/dianping/auth.js +2 -2
  233. package/clis/dianping/cityResolver.js +2 -2
  234. package/clis/dianping/search.js +1 -1
  235. package/clis/dianping/shop.js +1 -1
  236. package/clis/dianping/utils.js +1 -1
  237. package/clis/discord-app/delete.js +3 -3
  238. package/clis/discord-app/read.js +1 -1
  239. package/clis/discord-app/thread-read.js +1 -1
  240. package/clis/discord-web/auth.js +2 -2
  241. package/clis/discord-web/send.js +5 -5
  242. package/clis/dockerhub/image.js +1 -1
  243. package/clis/dockerhub/search.js +1 -1
  244. package/clis/dockerhub/utils.js +1 -1
  245. package/clis/dongchedi/koubei.js +1 -1
  246. package/clis/dongchedi/models.js +1 -1
  247. package/clis/dongchedi/score.js +1 -1
  248. package/clis/dongchedi/search.js +1 -1
  249. package/clis/dongchedi/series.js +1 -1
  250. package/clis/dongchedi/specs.js +1 -1
  251. package/clis/dongchedi/utils.js +1 -1
  252. package/clis/douban/article.js +3 -3
  253. package/clis/douban/auth.js +2 -2
  254. package/clis/douban/download.js +1 -1
  255. package/clis/douban/utils.js +23 -23
  256. package/clis/doubao/auth.js +3 -3
  257. package/clis/doubao/utils.js +39 -39
  258. package/clis/doubao-app/ask.js +1 -1
  259. package/clis/doubao-app/utils.js +4 -4
  260. package/clis/douyin/_shared/browser-fetch.js +7 -7
  261. package/clis/douyin/_shared/draft-cache.js +1 -1
  262. package/clis/douyin/_shared/imagex-upload.js +1 -1
  263. package/clis/douyin/_shared/sts2.js +1 -1
  264. package/clis/douyin/_shared/text-extra.js +1 -1
  265. package/clis/douyin/_shared/tos-upload.js +4 -4
  266. package/clis/douyin/_shared/transcode.js +1 -1
  267. package/clis/douyin/_shared/vod-upload.js +4 -4
  268. package/clis/douyin/draft.js +18 -18
  269. package/clis/douyin/drafts.js +1 -1
  270. package/clis/douyin/publish-image.js +12 -12
  271. package/clis/douyin/publish.js +9 -9
  272. package/clis/douyin/search.js +3 -3
  273. package/clis/douyin/videos.js +1 -1
  274. package/clis/eastmoney/_secid.js +1 -1
  275. package/clis/eastmoney/announcement.js +1 -1
  276. package/clis/eastmoney/article.js +1 -1
  277. package/clis/eastmoney/convertible.js +1 -1
  278. package/clis/eastmoney/etf.js +1 -1
  279. package/clis/eastmoney/holders.js +1 -1
  280. package/clis/eastmoney/index-board.js +1 -1
  281. package/clis/eastmoney/kline.js +1 -1
  282. package/clis/eastmoney/kuaixun.js +1 -1
  283. package/clis/eastmoney/longhu.js +1 -1
  284. package/clis/eastmoney/money-flow.js +1 -1
  285. package/clis/eastmoney/northbound.js +1 -1
  286. package/clis/eastmoney/quote.js +1 -1
  287. package/clis/eastmoney/rank.js +1 -1
  288. package/clis/eastmoney/sectors.js +1 -1
  289. package/clis/endoflife/product.js +1 -1
  290. package/clis/endoflife/utils.js +1 -1
  291. package/clis/facebook/comment.js +8 -8
  292. package/clis/facebook/feed.js +4 -4
  293. package/clis/facebook/like.js +5 -5
  294. package/clis/facebook/notifications.js +3 -3
  295. package/clis/facebook/post.js +11 -11
  296. package/clis/facebook/search.js +3 -3
  297. package/clis/flathub/app.js +1 -1
  298. package/clis/flathub/search.js +1 -1
  299. package/clis/flathub/utils.js +1 -1
  300. package/clis/flomo/memos.js +1 -1
  301. package/clis/gemini/deep-research-result.js +4 -4
  302. package/clis/gemini/deep-research.js +1 -1
  303. package/clis/gemini/detail.js +1 -1
  304. package/clis/gemini/history.js +1 -1
  305. package/clis/gemini/image.js +2 -2
  306. package/clis/gemini/status.js +1 -1
  307. package/clis/gemini/utils.js +43 -43
  308. package/clis/geogebra/hexagon.js +1 -1
  309. package/clis/geogebra/info.js +3 -3
  310. package/clis/geogebra/triangle.js +1 -1
  311. package/clis/geogebra/utils.js +11 -11
  312. package/clis/ghost/login.js +1 -1
  313. package/clis/ghost/shared.js +2 -2
  314. package/clis/gitee/auth.js +2 -2
  315. package/clis/github-trending/repos.js +1 -1
  316. package/clis/google/news.js +1 -1
  317. package/clis/google/search.js +2 -2
  318. package/clis/google/suggest.js +1 -1
  319. package/clis/google/trends.js +1 -1
  320. package/clis/google/utils.js +1 -1
  321. package/clis/goproxy/module.js +1 -1
  322. package/clis/goproxy/utils.js +1 -1
  323. package/clis/goproxy/versions.js +1 -1
  324. package/clis/gov-policy/recent.js +2 -2
  325. package/clis/gov-policy/search.js +2 -2
  326. package/clis/grok/ask.js +1 -1
  327. package/clis/grok/detail.js +1 -1
  328. package/clis/grok/image.js +8 -8
  329. package/clis/grok/pin.js +1 -1
  330. package/clis/grok/send.js +1 -1
  331. package/clis/grok/status.js +1 -1
  332. package/clis/grok/utils.js +21 -21
  333. package/clis/guazi/browse.js +1 -1
  334. package/clis/guazi/car.js +1 -1
  335. package/clis/guazi/utils.js +1 -1
  336. package/clis/hackernews/auth.js +2 -2
  337. package/clis/hackernews/comment.js +8 -8
  338. package/clis/hackernews/read.js +7 -7
  339. package/clis/hackernews/submit.js +7 -7
  340. package/clis/hashnode/auth.js +3 -3
  341. package/clis/hashnode/publish.js +14 -14
  342. package/clis/hf/auth.js +2 -2
  343. package/clis/hf/models.js +1 -1
  344. package/clis/hf/paper.js +1 -1
  345. package/clis/hf/spaces.js +1 -1
  346. package/clis/hf/top.js +1 -1
  347. package/clis/homebrew/cask.js +1 -1
  348. package/clis/homebrew/formula.js +1 -1
  349. package/clis/homebrew/popular.js +1 -1
  350. package/clis/homebrew/utils.js +1 -1
  351. package/clis/huodongxing/events.js +1 -1
  352. package/clis/hupu/detail.js +4 -4
  353. package/clis/hupu/hot.js +3 -3
  354. package/clis/hupu/reply.js +1 -1
  355. package/clis/hupu/search.js +1 -1
  356. package/clis/hupu/unlike.js +1 -1
  357. package/clis/hupu/utils.js +10 -10
  358. package/clis/imdb/person.js +2 -2
  359. package/clis/imdb/reviews.js +3 -3
  360. package/clis/imdb/search.js +2 -2
  361. package/clis/imdb/title.js +1 -1
  362. package/clis/imdb/top.js +1 -1
  363. package/clis/imdb/trending.js +1 -1
  364. package/clis/imdb/utils.js +13 -13
  365. package/clis/imooc/article.js +6 -6
  366. package/clis/imooc/login.js +1 -1
  367. package/clis/imooc/whoami.js +1 -1
  368. package/clis/indeed/job.js +2 -2
  369. package/clis/indeed/search.js +2 -2
  370. package/clis/indeed/utils.js +1 -1
  371. package/clis/infoq/article.js +2 -2
  372. package/clis/infoq/login.js +1 -1
  373. package/clis/infoq/whoami.js +1 -1
  374. package/clis/instagram/_shared/private-publish.js +4 -4
  375. package/clis/instagram/_shared/protocol-capture.js +9 -9
  376. package/clis/instagram/detail.js +3 -3
  377. package/clis/instagram/post.js +25 -25
  378. package/clis/instagram/reel.js +18 -18
  379. package/clis/instagram/story.js +4 -4
  380. package/clis/instagram/user.js +2 -2
  381. package/clis/jd/item.js +65 -65
  382. package/clis/jianshu/article.js +1 -1
  383. package/clis/jianshu/login.js +1 -1
  384. package/clis/jianshu/notebooks.js +1 -1
  385. package/clis/jianshu/whoami.js +1 -1
  386. package/clis/jianyu/search.js +6 -6
  387. package/clis/jianyu/shared/procurement-contract.js +1 -1
  388. package/clis/jike/api.js +6 -6
  389. package/clis/jike/auth.js +3 -3
  390. package/clis/jike/comment.js +1 -1
  391. package/clis/jike/create.js +6 -6
  392. package/clis/jike/feed.js +3 -3
  393. package/clis/jike/like.js +1 -1
  394. package/clis/jike/notifications.js +3 -3
  395. package/clis/jike/repost.js +13 -13
  396. package/clis/jike/search.js +3 -3
  397. package/clis/jimeng/auth.js +2 -2
  398. package/clis/jimeng/generate.js +10 -10
  399. package/clis/jira/shared.js +1 -1
  400. package/clis/juejin/article.js +4 -4
  401. package/clis/juejin/categories.js +1 -1
  402. package/clis/juejin/hot.js +1 -1
  403. package/clis/juejin/login.js +1 -1
  404. package/clis/juejin/recommend.js +1 -1
  405. package/clis/juejin/stats.js +3 -3
  406. package/clis/juejin/tags.js +1 -1
  407. package/clis/juejin/utils.js +1 -1
  408. package/clis/juejin/whoami.js +1 -1
  409. package/clis/ke/utils.js +4 -4
  410. package/clis/kimi/_utils.js +7 -7
  411. package/clis/kimi/audit-extras.js +14 -14
  412. package/clis/kimi/auth.js +3 -3
  413. package/clis/kimi/chat.js +15 -15
  414. package/clis/kimi/storage.js +5 -5
  415. package/clis/kimi/ui.js +13 -13
  416. package/clis/kimi/usage.js +3 -3
  417. package/clis/kuaishou/auth.js +1 -1
  418. package/clis/kuaishou/publish.js +6 -6
  419. package/clis/lesswrong/_helpers.js +5 -5
  420. package/clis/lesswrong/comments.js +5 -5
  421. package/clis/lichess/top.js +1 -1
  422. package/clis/lichess/user.js +1 -1
  423. package/clis/lichess/utils.js +1 -1
  424. package/clis/linkedin/comment.js +1 -1
  425. package/clis/linkedin/connect.js +11 -11
  426. package/clis/linkedin/create.js +5 -5
  427. package/clis/linkedin/follow.js +1 -1
  428. package/clis/linkedin/inbox.js +1 -1
  429. package/clis/linkedin/job-detail.js +3 -3
  430. package/clis/linkedin/like.js +1 -1
  431. package/clis/linkedin/notifications.js +1 -1
  432. package/clis/linkedin/people-search.js +1 -1
  433. package/clis/linkedin/post-comments.js +1 -1
  434. package/clis/linkedin/post-detail.js +1 -1
  435. package/clis/linkedin/profile-analytics.js +1 -1
  436. package/clis/linkedin/profile-api.js +13 -13
  437. package/clis/linkedin/profile-experience.js +1 -1
  438. package/clis/linkedin/profile-projects.js +1 -1
  439. package/clis/linkedin/profile-read.js +3 -3
  440. package/clis/linkedin/reply.js +1 -1
  441. package/clis/linkedin/repost.js +1 -1
  442. package/clis/linkedin/safe-send.js +8 -8
  443. package/clis/linkedin/salesnav-inbox.js +5 -5
  444. package/clis/linkedin/salesnav-message.js +3 -3
  445. package/clis/linkedin/salesnav-search.js +4 -4
  446. package/clis/linkedin/salesnav-thread.js +1 -1
  447. package/clis/linkedin/search-api.js +3 -3
  448. package/clis/linkedin/search.js +8 -8
  449. package/clis/linkedin/social-api.js +31 -31
  450. package/clis/linkedin/timeline.js +3 -3
  451. package/clis/linkedin-learning/search.js +2 -2
  452. package/clis/linkedin-learning/trending.js +2 -2
  453. package/clis/linux-do/feed.js +4 -4
  454. package/clis/linux-do/topic-content.js +8 -8
  455. package/clis/lobsters/domain.js +1 -1
  456. package/clis/lobsters/read.js +7 -7
  457. package/clis/maimai/auth.js +2 -2
  458. package/clis/maimai/search-talents.js +4 -4
  459. package/clis/manus/_utils.js +1 -1
  460. package/clis/mastodon/login.js +1 -1
  461. package/clis/mastodon/post.js +1 -1
  462. package/clis/mastodon/shared.js +12 -12
  463. package/clis/mastodon/whoami.js +1 -1
  464. package/clis/maven/artifact.js +1 -1
  465. package/clis/maven/search.js +1 -1
  466. package/clis/maven/utils.js +1 -1
  467. package/clis/mdn/search.js +1 -1
  468. package/clis/medium/article.js +5 -5
  469. package/clis/medium/login.js +1 -1
  470. package/clis/medium/stats.js +3 -3
  471. package/clis/medium/tag.js +1 -1
  472. package/clis/medium/whoami.js +1 -1
  473. package/clis/mubu/notes.js +1 -1
  474. package/clis/mubu/utils.js +15 -15
  475. package/clis/note/auth.js +2 -2
  476. package/clis/note/note-utils.js +2 -2
  477. package/clis/note/publish.js +8 -8
  478. package/clis/notebooklm/add-source.js +8 -8
  479. package/clis/notebooklm/create.js +1 -1
  480. package/clis/notebooklm/generate-slides.js +1 -1
  481. package/clis/notebooklm/notes-get.js +1 -1
  482. package/clis/notebooklm/rpc.js +8 -8
  483. package/clis/notebooklm/source-fulltext.js +1 -1
  484. package/clis/notebooklm/utils.js +10 -10
  485. package/clis/nowcoder/auth.js +2 -2
  486. package/clis/nowcoder/comment.js +1 -1
  487. package/clis/nowcoder/comments.js +1 -1
  488. package/clis/nowcoder/dm-list.js +1 -1
  489. package/clis/nowcoder/dm-read.js +1 -1
  490. package/clis/nowcoder/dm-send.js +1 -1
  491. package/clis/nowcoder/drafts.js +1 -1
  492. package/clis/nowcoder/inbox.js +1 -1
  493. package/clis/nowcoder/like.js +1 -1
  494. package/clis/nowcoder/my.js +1 -1
  495. package/clis/nowcoder/post.js +1 -1
  496. package/clis/nowcoder/utils.js +13 -13
  497. package/clis/npm/downloads.js +1 -1
  498. package/clis/npm/package.js +1 -1
  499. package/clis/npm/search.js +1 -1
  500. package/clis/npm/utils.js +1 -1
  501. package/clis/nuget/package.js +1 -1
  502. package/clis/nuget/search.js +1 -1
  503. package/clis/nuget/utils.js +1 -1
  504. package/clis/nvd/cve.js +1 -1
  505. package/clis/oeis/search.js +1 -1
  506. package/clis/oeis/sequence.js +1 -1
  507. package/clis/oeis/utils.js +1 -1
  508. package/clis/ones/common.js +6 -6
  509. package/clis/ones/enrich-tasks.js +1 -1
  510. package/clis/ones/my-tasks.js +1 -1
  511. package/clis/ones/resolve-labels.js +1 -1
  512. package/clis/ones/task-helpers.js +1 -1
  513. package/clis/ones/task.js +1 -1
  514. package/clis/ones/worklog.js +7 -7
  515. package/clis/openalex/search.js +1 -1
  516. package/clis/openalex/utils.js +1 -1
  517. package/clis/openalex/work.js +1 -1
  518. package/clis/openfda/drug-label.js +1 -1
  519. package/clis/openfda/food-recall.js +1 -1
  520. package/clis/openfda/utils.js +1 -1
  521. package/clis/openreview/author.js +1 -1
  522. package/clis/openreview/paper.js +1 -1
  523. package/clis/openreview/reviews.js +3 -3
  524. package/clis/openreview/search.js +1 -1
  525. package/clis/openreview/utils.js +1 -1
  526. package/clis/openreview/venue.js +1 -1
  527. package/clis/oschina/article.js +1 -1
  528. package/clis/oschina/catalogs.js +1 -1
  529. package/clis/oschina/login.js +1 -1
  530. package/clis/oschina/stats.js +6 -6
  531. package/clis/oschina/whoami.js +1 -1
  532. package/clis/osv/query.js +1 -1
  533. package/clis/osv/utils.js +1 -1
  534. package/clis/osv/vulnerability.js +1 -1
  535. package/clis/packagist/package.js +1 -1
  536. package/clis/packagist/search.js +1 -1
  537. package/clis/packagist/utils.js +1 -1
  538. package/clis/pinterest/api.js +1 -1
  539. package/clis/pinterest/auth.js +1 -1
  540. package/clis/pinterest/boards.js +1 -1
  541. package/clis/pinterest/client.js +6 -6
  542. package/clis/pinterest/publish.js +5 -5
  543. package/clis/pixiv/auth.js +2 -2
  544. package/clis/pixiv/download.js +1 -1
  545. package/clis/pixiv/illusts.js +1 -1
  546. package/clis/pixiv/search.js +1 -1
  547. package/clis/pixiv/utils.js +3 -3
  548. package/clis/powerchina/auth.js +2 -2
  549. package/clis/powerchina/search.js +1 -1
  550. package/clis/producthunt/browse.js +2 -2
  551. package/clis/producthunt/hot.js +2 -2
  552. package/clis/producthunt/posts.js +1 -1
  553. package/clis/producthunt/today.js +1 -1
  554. package/clis/producthunt/utils.js +1 -1
  555. package/clis/pypi/downloads.js +1 -1
  556. package/clis/pypi/package.js +1 -1
  557. package/clis/pypi/utils.js +1 -1
  558. package/clis/qiita/auth.js +1 -1
  559. package/clis/qiita/gql.js +6 -6
  560. package/clis/qiita/publish.js +4 -4
  561. package/clis/qiita/stats.js +4 -4
  562. package/clis/qoder/_utils.js +16 -16
  563. package/clis/qoder/composer.js +1 -1
  564. package/clis/qoder/quest.js +1 -1
  565. package/clis/qoder/ui.js +14 -14
  566. package/clis/quark/auth.js +2 -2
  567. package/clis/quark/utils.js +2 -2
  568. package/clis/quora/answer-comments.js +3 -3
  569. package/clis/quora/create-answer.js +4 -4
  570. package/clis/quora/create-question.js +3 -3
  571. package/clis/quora/shared.js +17 -17
  572. package/clis/quora/whoami.js +1 -1
  573. package/clis/qwen/ask.js +1 -1
  574. package/clis/qwen/auth.js +3 -3
  575. package/clis/qwen/detail.js +1 -1
  576. package/clis/qwen/image.js +5 -5
  577. package/clis/qwen/status.js +1 -1
  578. package/clis/qwen/utils.js +16 -16
  579. package/clis/reddit/home.js +3 -3
  580. package/clis/reddit/read.js +10 -10
  581. package/clis/reddit/reply.js +4 -4
  582. package/clis/reddit/submit.js +11 -11
  583. package/clis/reddit/subreddit-info.js +3 -3
  584. package/clis/reddit/subscribed.js +4 -4
  585. package/clis/reddit/whoami.js +2 -2
  586. package/clis/rednote/comments.js +1 -1
  587. package/clis/rednote/download.js +1 -1
  588. package/clis/rednote/feed.js +1 -1
  589. package/clis/rednote/note.js +1 -1
  590. package/clis/rednote/notifications.js +2 -2
  591. package/clis/rednote/search.js +2 -2
  592. package/clis/rest-countries/country.js +1 -1
  593. package/clis/rest-countries/region.js +1 -1
  594. package/clis/rest-countries/utils.js +1 -1
  595. package/clis/reuters/article-detail.js +1 -1
  596. package/clis/reuters/auth.js +3 -3
  597. package/clis/reuters/search.js +1 -1
  598. package/clis/reuters/utils.js +4 -4
  599. package/clis/rfc/rfc.js +1 -1
  600. package/clis/rfc/utils.js +1 -1
  601. package/clis/rubygems/gem.js +1 -1
  602. package/clis/rubygems/search.js +1 -1
  603. package/clis/rubygems/utils.js +1 -1
  604. package/clis/segmentfault/article.js +3 -3
  605. package/clis/segmentfault/channels.js +1 -1
  606. package/clis/segmentfault/login.js +1 -1
  607. package/clis/segmentfault/stats.js +4 -4
  608. package/clis/segmentfault/tags.js +1 -1
  609. package/clis/segmentfault/whoami.js +1 -1
  610. package/clis/semanticscholar/citations.js +1 -1
  611. package/clis/semanticscholar/paper.js +1 -1
  612. package/clis/semanticscholar/recommendations.js +1 -1
  613. package/clis/semanticscholar/search.js +1 -1
  614. package/clis/semanticscholar/utils.js +1 -1
  615. package/clis/sinafinance/news.js +1 -1
  616. package/clis/sinafinance/stock-rank.js +1 -1
  617. package/clis/sinafinance/stock.js +1 -1
  618. package/clis/slock/attachment-download.js +1 -1
  619. package/clis/slock/attachment-upload.js +7 -7
  620. package/clis/slock/attachment-url.js +1 -1
  621. package/clis/slock/auth-verify.js +1 -1
  622. package/clis/slock/bookmark-add.js +1 -1
  623. package/clis/slock/bookmark-remove.js +1 -1
  624. package/clis/slock/channel-action.js +1 -1
  625. package/clis/slock/channel-create.js +1 -1
  626. package/clis/slock/channel-files.js +1 -1
  627. package/clis/slock/channel-list.js +1 -1
  628. package/clis/slock/channel-mark.js +1 -1
  629. package/clis/slock/channel-members.js +1 -1
  630. package/clis/slock/channel-unarchive.js +1 -1
  631. package/clis/slock/dm-list.js +1 -1
  632. package/clis/slock/errors.js +1 -1
  633. package/clis/slock/in-page.js +28 -28
  634. package/clis/slock/inbox-done.js +5 -5
  635. package/clis/slock/inbox.js +1 -1
  636. package/clis/slock/message-read.js +22 -22
  637. package/clis/slock/message-search.js +10 -10
  638. package/clis/slock/message-send.js +25 -25
  639. package/clis/slock/reaction-add.js +1 -1
  640. package/clis/slock/reaction-remove.js +1 -1
  641. package/clis/slock/resolve.js +1 -1
  642. package/clis/slock/server-list.js +2 -2
  643. package/clis/slock/task-claim.js +4 -4
  644. package/clis/slock/task-convert.js +13 -13
  645. package/clis/slock/task-create.js +1 -1
  646. package/clis/slock/task-delete.js +5 -5
  647. package/clis/slock/task-get.js +5 -5
  648. package/clis/slock/task-list-server.js +4 -4
  649. package/clis/slock/task-list.js +5 -5
  650. package/clis/slock/task-status.js +3 -3
  651. package/clis/slock/task-unclaim.js +3 -3
  652. package/clis/slock/thread-follow.js +1 -1
  653. package/clis/slock/thread-state.js +1 -1
  654. package/clis/slock/unread-summary.js +5 -5
  655. package/clis/slock/whoami.js +1 -1
  656. package/clis/smzdm/search.js +3 -3
  657. package/clis/sohu/article.js +1 -1
  658. package/clis/sohu/attributes.js +1 -1
  659. package/clis/sohu/categories.js +1 -1
  660. package/clis/sohu/channels.js +1 -1
  661. package/clis/sohu/columns.js +1 -1
  662. package/clis/sohu/login.js +1 -1
  663. package/clis/sohu/stats.js +3 -3
  664. package/clis/sohu/topics.js +1 -1
  665. package/clis/sohu/whoami.js +1 -1
  666. package/clis/spotify/spotify.js +1 -1
  667. package/clis/stackoverflow/read.js +6 -6
  668. package/clis/stackoverflow/related.js +1 -1
  669. package/clis/stackoverflow/tag.js +1 -1
  670. package/clis/stackoverflow/user.js +1 -1
  671. package/clis/stackoverflow/utils.js +1 -1
  672. package/clis/steam/app.js +1 -1
  673. package/clis/steam/search.js +1 -1
  674. package/clis/steam/utils.js +1 -1
  675. package/clis/substack/auth.js +2 -2
  676. package/clis/substack/post-utils.js +2 -2
  677. package/clis/substack/publish.js +5 -5
  678. package/clis/suno/auth.js +2 -2
  679. package/clis/suno/download.js +5 -5
  680. package/clis/suno/generate.js +3 -3
  681. package/clis/suno/list.js +1 -1
  682. package/clis/suno/status.js +1 -1
  683. package/clis/suno/utils.js +29 -29
  684. package/clis/telegram/send.js +7 -7
  685. package/clis/telegram/shared.js +2 -2
  686. package/clis/telegram/whoami.js +1 -1
  687. package/clis/test-utils.js +1 -1
  688. package/clis/threads/post.js +23 -23
  689. package/clis/threads/shared.js +3 -3
  690. package/clis/threads/whoami.js +1 -1
  691. package/clis/tieba/hot.js +3 -3
  692. package/clis/tieba/posts.js +1 -1
  693. package/clis/tieba/read.js +2 -2
  694. package/clis/tieba/search.js +3 -3
  695. package/clis/tieba/utils.js +1 -1
  696. package/clis/tiktok/comment.js +2 -2
  697. package/clis/tiktok/creator-videos.js +3 -3
  698. package/clis/tiktok/explore.js +3 -3
  699. package/clis/tiktok/follow.js +8 -8
  700. package/clis/tiktok/following.js +4 -4
  701. package/clis/tiktok/friends.js +7 -7
  702. package/clis/tiktok/live.js +3 -3
  703. package/clis/tiktok/notifications.js +6 -6
  704. package/clis/tiktok/publish.js +17 -17
  705. package/clis/tiktok/unfollow.js +4 -4
  706. package/clis/tiktok/user.js +2 -2
  707. package/clis/tiktok/utils.js +1 -1
  708. package/clis/toutiao/article.js +1 -1
  709. package/clis/toutiao/articles.js +2 -2
  710. package/clis/toutiao/auth.js +2 -2
  711. package/clis/toutiao/hot.js +1 -1
  712. package/clis/toutiao/recommend.js +1 -1
  713. package/clis/toutiao/utils.js +2 -2
  714. package/clis/trae-solo/_actions.js +4 -4
  715. package/clis/trae-solo/_fs.js +5 -5
  716. package/clis/trae-solo/_state.js +2 -2
  717. package/clis/trae-solo/automation.js +4 -4
  718. package/clis/trae-solo/mode.js +4 -4
  719. package/clis/trae-solo/model.js +4 -4
  720. package/clis/trae-solo/renderer-storage.js +4 -4
  721. package/clis/trae-solo/settings.js +1 -1
  722. package/clis/trae-solo/skill-fs.js +1 -1
  723. package/clis/trae-solo/skill.js +12 -12
  724. package/clis/trae-solo/state-fs.js +2 -2
  725. package/clis/trae-solo/task-fs.js +5 -5
  726. package/clis/trae-solo/workspaces-fs.js +1 -1
  727. package/clis/tumblr/auth.js +2 -2
  728. package/clis/tumblr/publish.js +3 -3
  729. package/clis/tvmaze/search.js +1 -1
  730. package/clis/tvmaze/show.js +1 -1
  731. package/clis/tvmaze/utils.js +1 -1
  732. package/clis/twitter/accept.js +7 -7
  733. package/clis/twitter/article.js +7 -7
  734. package/clis/twitter/bookmark-folder.js +3 -3
  735. package/clis/twitter/bookmark-folders.js +3 -3
  736. package/clis/twitter/bookmarks.js +4 -4
  737. package/clis/twitter/delete.js +5 -5
  738. package/clis/twitter/device-follow.js +3 -3
  739. package/clis/twitter/dm-list.js +1 -1
  740. package/clis/twitter/dm-read.js +1 -1
  741. package/clis/twitter/dm-send.js +5 -5
  742. package/clis/twitter/dm-shared.js +3 -3
  743. package/clis/twitter/download.js +6 -6
  744. package/clis/twitter/followers.js +5 -5
  745. package/clis/twitter/following.js +2 -2
  746. package/clis/twitter/like.js +3 -3
  747. package/clis/twitter/likes.js +8 -8
  748. package/clis/twitter/list-add-core.js +9 -9
  749. package/clis/twitter/list-create.js +5 -5
  750. package/clis/twitter/list-remove-core.js +9 -9
  751. package/clis/twitter/list-tweets.js +7 -7
  752. package/clis/twitter/lists.js +6 -6
  753. package/clis/twitter/notifications.js +2 -2
  754. package/clis/twitter/post.js +24 -24
  755. package/clis/twitter/profile.js +7 -7
  756. package/clis/twitter/quote.js +7 -7
  757. package/clis/twitter/reply-dm.js +7 -7
  758. package/clis/twitter/reply.js +12 -12
  759. package/clis/twitter/retweet.js +3 -3
  760. package/clis/twitter/scheduled-delete.js +3 -3
  761. package/clis/twitter/scheduled-list.js +2 -2
  762. package/clis/twitter/scheduled-utils.js +3 -3
  763. package/clis/twitter/search.js +5 -5
  764. package/clis/twitter/shared.js +6 -6
  765. package/clis/twitter/thread.js +4 -4
  766. package/clis/twitter/timeline.js +3 -3
  767. package/clis/twitter/trending.js +2 -2
  768. package/clis/twitter/tweets.js +11 -11
  769. package/clis/twitter/unlike.js +3 -3
  770. package/clis/twitter/unretweet.js +3 -3
  771. package/clis/twitter/utils.js +6 -6
  772. package/clis/upwork/detail.js +2 -2
  773. package/clis/upwork/feed.js +2 -2
  774. package/clis/upwork/search.js +2 -2
  775. package/clis/upwork/utils.js +1 -1
  776. package/clis/v2ex/auth.js +2 -2
  777. package/clis/v2ex/daily.js +3 -3
  778. package/clis/v2ex/me.js +2 -2
  779. package/clis/v2ex/notifications.js +2 -2
  780. package/clis/vk/post.js +1 -1
  781. package/clis/vk/shared.js +2 -2
  782. package/clis/vk/whoami.js +1 -1
  783. package/clis/web/read.js +8 -8
  784. package/clis/wechat-channels/auth.js +2 -2
  785. package/clis/wechat-channels/publish.js +30 -30
  786. package/clis/weibo/article.js +1 -1
  787. package/clis/weibo/auth.js +3 -3
  788. package/clis/weibo/comments.js +1 -1
  789. package/clis/weibo/delete.js +2 -2
  790. package/clis/weibo/feed.js +3 -3
  791. package/clis/weibo/hot.js +1 -1
  792. package/clis/weibo/publish.js +10 -10
  793. package/clis/weibo/search.js +2 -2
  794. package/clis/weibo/user-posts.js +3 -3
  795. package/clis/weibo/user.js +2 -2
  796. package/clis/weibo/utils.js +3 -3
  797. package/clis/weixin/article.js +1 -1
  798. package/clis/weixin/create-draft.js +26 -26
  799. package/clis/weixin/download.js +2 -2
  800. package/clis/weixin/login.js +1 -1
  801. package/clis/weixin/search.js +2 -2
  802. package/clis/weixin/stats.js +3 -3
  803. package/clis/weixin/whoami.js +1 -1
  804. package/clis/weread/ai-outline.js +2 -2
  805. package/clis/weread/book-search.js +2 -2
  806. package/clis/weread/book.js +2 -2
  807. package/clis/weread/notebooks.js +1 -1
  808. package/clis/weread/search.js +1 -1
  809. package/clis/weread/shelf.js +1 -1
  810. package/clis/weread/utils.js +6 -6
  811. package/clis/weread-official/book.js +1 -1
  812. package/clis/weread-official/discover.js +1 -1
  813. package/clis/weread-official/list-apis.js +1 -1
  814. package/clis/weread-official/notes.js +1 -1
  815. package/clis/weread-official/readdata.js +1 -1
  816. package/clis/weread-official/review.js +1 -1
  817. package/clis/weread-official/search.js +1 -1
  818. package/clis/weread-official/shelf.js +1 -1
  819. package/clis/weread-official/utils.js +1 -1
  820. package/clis/wikidata/entity.js +1 -1
  821. package/clis/wikidata/search.js +1 -1
  822. package/clis/wikidata/utils.js +1 -1
  823. package/clis/wikipedia/page.js +1 -1
  824. package/clis/wikipedia/trending.js +1 -1
  825. package/clis/wikipedia/utils.js +1 -1
  826. package/clis/wordpress/login.js +1 -1
  827. package/clis/wordpress/publish.js +1 -1
  828. package/clis/wordpress/shared.js +3 -3
  829. package/clis/wordpress/whoami.js +1 -1
  830. package/clis/woshipm/article.js +1 -1
  831. package/clis/woshipm/login.js +1 -1
  832. package/clis/woshipm/stats.js +4 -4
  833. package/clis/woshipm/whoami.js +1 -1
  834. package/clis/wttr/current.js +1 -1
  835. package/clis/wttr/forecast.js +1 -1
  836. package/clis/wttr/utils.js +1 -1
  837. package/clis/xianyu/collect.js +1 -1
  838. package/clis/xianyu/inbox.js +1 -1
  839. package/clis/xianyu/item-stats.js +2 -2
  840. package/clis/xianyu/location.js +1 -1
  841. package/clis/xianyu/manage.js +1 -1
  842. package/clis/xianyu/messages.js +1 -1
  843. package/clis/xianyu/mtop.js +5 -5
  844. package/clis/xianyu/order.js +1 -1
  845. package/clis/xianyu/promote-stats.js +2 -2
  846. package/clis/xianyu/publish.js +17 -17
  847. package/clis/xianyu/rate.js +1 -1
  848. package/clis/xianyu/reply.js +1 -1
  849. package/clis/xianyu/search.js +8 -8
  850. package/clis/xianyu/seller-data.js +1 -1
  851. package/clis/xianyu/seller-list.js +1 -1
  852. package/clis/xianyu/user.js +1 -1
  853. package/clis/xiaoe/catalog.js +2 -2
  854. package/clis/xiaoe/content.js +2 -2
  855. package/clis/xiaoe/courses.js +2 -2
  856. package/clis/xiaohongshu/ask.js +6 -6
  857. package/clis/xiaohongshu/comments.js +6 -6
  858. package/clis/xiaohongshu/creator-note-detail.js +7 -7
  859. package/clis/xiaohongshu/creator-notes-summary.js +1 -1
  860. package/clis/xiaohongshu/creator-notes.js +13 -13
  861. package/clis/xiaohongshu/creator-profile.js +2 -2
  862. package/clis/xiaohongshu/creator-stats.js +2 -2
  863. package/clis/xiaohongshu/delete-note.js +7 -7
  864. package/clis/xiaohongshu/download.js +4 -4
  865. package/clis/xiaohongshu/feed.js +2 -2
  866. package/clis/xiaohongshu/follow.js +3 -3
  867. package/clis/xiaohongshu/human.js +3 -3
  868. package/clis/xiaohongshu/note-helpers.js +1 -1
  869. package/clis/xiaohongshu/note.js +2 -2
  870. package/clis/xiaohongshu/notifications.js +1 -1
  871. package/clis/xiaohongshu/publish-video.js +8 -8
  872. package/clis/xiaohongshu/publish.js +59 -59
  873. package/clis/xiaohongshu/search.js +8 -8
  874. package/clis/xiaohongshu/unfollow.js +4 -4
  875. package/clis/xiaohongshu/user-helpers.js +1 -1
  876. package/clis/xiaohongshu/user.js +2 -2
  877. package/clis/xiaoyuzhou/auth.js +3 -3
  878. package/clis/xiaoyuzhou/download.js +1 -1
  879. package/clis/xiaoyuzhou/utils.js +1 -1
  880. package/clis/xueqiu/article.js +4 -4
  881. package/clis/xueqiu/comments.js +4 -4
  882. package/clis/xueqiu/danjuan-utils.js +4 -4
  883. package/clis/xueqiu/earnings-date.js +1 -1
  884. package/clis/xueqiu/events.js +3 -3
  885. package/clis/xueqiu/hashtags.js +3 -3
  886. package/clis/xueqiu/stocks.js +3 -3
  887. package/clis/xueqiu/users.js +3 -3
  888. package/clis/xueqiu/utils.js +3 -3
  889. package/clis/yahoo-finance/quote.js +1 -1
  890. package/clis/yollomi/background.js +1 -1
  891. package/clis/yollomi/edit.js +1 -1
  892. package/clis/yollomi/face-swap.js +1 -1
  893. package/clis/yollomi/generate.js +1 -1
  894. package/clis/yollomi/object-remover.js +1 -1
  895. package/clis/yollomi/remove-bg.js +1 -1
  896. package/clis/yollomi/restore.js +1 -1
  897. package/clis/yollomi/try-on.js +1 -1
  898. package/clis/yollomi/upload.js +4 -4
  899. package/clis/yollomi/upscale.js +1 -1
  900. package/clis/yollomi/utils.js +4 -4
  901. package/clis/yollomi/video.js +1 -1
  902. package/clis/youtube/channel.js +4 -4
  903. package/clis/youtube/feed.js +2 -2
  904. package/clis/youtube/like.js +5 -5
  905. package/clis/youtube/playlist.js +7 -7
  906. package/clis/youtube/publish.js +11 -11
  907. package/clis/youtube/search.js +3 -3
  908. package/clis/youtube/subscribe.js +7 -7
  909. package/clis/youtube/subscriptions.js +1 -1
  910. package/clis/youtube/transcript-group.js +2 -2
  911. package/clis/youtube/transcript.js +13 -13
  912. package/clis/youtube/unlike.js +5 -5
  913. package/clis/youtube/unsubscribe.js +7 -7
  914. package/clis/youtube/utils.js +3 -3
  915. package/clis/youtube/video.js +4 -4
  916. package/clis/youtube/watch-later.js +2 -2
  917. package/clis/yuanbao/ask.js +18 -18
  918. package/clis/yuanbao/detail.js +1 -1
  919. package/clis/yuanbao/read.js +1 -1
  920. package/clis/yuanbao/shared.js +9 -9
  921. package/clis/yuanbao/status.js +1 -1
  922. package/clis/yuque/article.js +1 -1
  923. package/clis/yuque/whoami.js +1 -1
  924. package/clis/zhihu/answer-comments.js +2 -2
  925. package/clis/zhihu/answer-detail.js +3 -3
  926. package/clis/zhihu/answer.js +1 -1
  927. package/clis/zhihu/article-transform.js +1 -1
  928. package/clis/zhihu/article.js +1 -1
  929. package/clis/zhihu/auth.js +2 -2
  930. package/clis/zhihu/collection.js +3 -3
  931. package/clis/zhihu/collections.js +3 -3
  932. package/clis/zhihu/download.js +2 -2
  933. package/clis/zhihu/image-profile.js +6 -6
  934. package/clis/zhihu/paginate.js +3 -3
  935. package/clis/zhihu/pin.js +4 -4
  936. package/clis/zhihu/question.js +3 -3
  937. package/clis/zhihu/recommend.js +3 -3
  938. package/clis/zhihu/search.js +3 -3
  939. package/clis/zhihu/stats.js +3 -3
  940. package/clis/zhihu/user-arg.js +1 -1
  941. package/clis/zhihu/write-shared.js +7 -7
  942. package/clis/zlibrary/utils.js +6 -6
  943. package/clis/zsxq/auth.js +3 -3
  944. package/clis/zsxq/search.js +1 -1
  945. package/clis/zsxq/topic.js +1 -1
  946. package/clis/zsxq/utils.js +5 -5
  947. package/dist/src/adapter-source.js +1 -1
  948. package/dist/src/browser/analyze.js +1 -1
  949. package/dist/src/browser/article-extract.js +2 -2
  950. package/dist/src/browser/ax-snapshot.js +2 -2
  951. package/dist/src/browser/base-page.js +25 -25
  952. package/dist/src/browser/bridge.js +1 -1
  953. package/dist/src/browser/cdp.js +1 -1
  954. package/dist/src/browser/daemon-client.js +1 -1
  955. package/dist/src/browser/daemon-lifecycle.js +7 -7
  956. package/dist/src/browser/dom-helpers.js +35 -35
  957. package/dist/src/browser/dom-snapshot.js +19 -19
  958. package/dist/src/browser/errors.js +3 -3
  959. package/dist/src/browser/extract.js +5 -5
  960. package/dist/src/browser/find.js +13 -13
  961. package/dist/src/browser/fingerprint.js +2 -2
  962. package/dist/src/browser/html-tree.js +6 -6
  963. package/dist/src/browser/managed-chrome.js +1 -1
  964. package/dist/src/browser/network-cache.js +1 -1
  965. package/dist/src/browser/network-key.js +1 -1
  966. package/dist/src/browser/page.js +7 -7
  967. package/dist/src/browser/profile.js +2 -2
  968. package/dist/src/browser/proxy-test.js +8 -8
  969. package/dist/src/browser/shape-filter.js +1 -1
  970. package/dist/src/browser/shape.js +1 -1
  971. package/dist/src/browser/stealth.js +3 -3
  972. package/dist/src/browser/tabs.js +2 -2
  973. package/dist/src/browser/target-errors.js +1 -1
  974. package/dist/src/browser/target-resolver.js +23 -23
  975. package/dist/src/browser/trace.js +2 -2
  976. package/dist/src/browser/utils.js +1 -1
  977. package/dist/src/browser/verify-fixture.js +2 -2
  978. package/dist/src/browser-session-lock.js +1 -1
  979. package/dist/src/build-manifest.js +11 -11
  980. package/dist/src/capabilityRouting.js +1 -1
  981. package/dist/src/cli-argv-preprocess.js +1 -1
  982. package/dist/src/cli.js +32 -32
  983. package/dist/src/commanderAdapter.js +3 -3
  984. package/dist/src/commands/auth.js +3 -3
  985. package/dist/src/commands/daemon.js +1 -1
  986. package/dist/src/completion-fast.js +1 -1
  987. package/dist/src/completion.js +1 -1
  988. package/dist/src/constants.js +1 -1
  989. package/dist/src/convention-audit.js +2 -2
  990. package/dist/src/daemon-utils.js +1 -1
  991. package/dist/src/daemon.js +1 -1
  992. package/dist/src/discovery.js +2 -2
  993. package/dist/src/doctor.js +9 -9
  994. package/dist/src/download/article-download.js +15 -15
  995. package/dist/src/download/index.js +4 -4
  996. package/dist/src/download/media-download.js +1 -1
  997. package/dist/src/download/progress.js +3 -3
  998. package/dist/src/electron-apps.js +1 -1
  999. package/dist/src/errors.js +2 -2
  1000. package/dist/src/execution.js +2 -2
  1001. package/dist/src/external.js +1 -1
  1002. package/dist/src/help.js +8 -8
  1003. package/dist/src/hooks.js +1 -1
  1004. package/dist/src/interceptor.js +21 -21
  1005. package/dist/src/launcher.js +7 -7
  1006. package/dist/src/logger.js +8 -8
  1007. package/dist/src/main.js +7 -7
  1008. package/dist/src/observation/artifact.js +5 -5
  1009. package/dist/src/observation/retention.js +1 -1
  1010. package/dist/src/output.js +2 -2
  1011. package/dist/src/package-paths.js +1 -1
  1012. package/dist/src/pipeline/executor.js +1 -1
  1013. package/dist/src/pipeline/registry.js +1 -1
  1014. package/dist/src/pipeline/steps/browser.js +1 -1
  1015. package/dist/src/pipeline/steps/download.js +1 -1
  1016. package/dist/src/pipeline/steps/fetch.js +6 -6
  1017. package/dist/src/pipeline/steps/intercept.js +1 -1
  1018. package/dist/src/pipeline/steps/tap.js +17 -17
  1019. package/dist/src/pipeline/steps/transform.js +1 -1
  1020. package/dist/src/pipeline/template.js +1 -1
  1021. package/dist/src/plugin-manifest.js +1 -1
  1022. package/dist/src/plugin-scaffold.js +19 -19
  1023. package/dist/src/plugin.js +12 -12
  1024. package/dist/src/rate-limit.js +1 -1
  1025. package/dist/src/registry.js +1 -1
  1026. package/dist/src/runtime-detect.js +1 -1
  1027. package/dist/src/runtime.js +1 -1
  1028. package/dist/src/scripts/framework.js +1 -1
  1029. package/dist/src/scripts/interact.js +1 -1
  1030. package/dist/src/scripts/store.js +1 -1
  1031. package/dist/src/serialization.js +2 -2
  1032. package/dist/src/session-lease.js +1 -1
  1033. package/dist/src/snapshotFormatter.js +2 -2
  1034. package/dist/src/tui.js +12 -12
  1035. package/dist/src/user-runtime.js +1 -1
  1036. package/dist/src/utils.d.ts +12 -0
  1037. package/dist/src/utils.js +4 -4
  1038. package/dist/src/validate.js +2 -2
  1039. package/dist/src/verify.js +2 -2
  1040. package/dist/src/version.js +1 -1
  1041. package/package.json +1 -1
package/clis/hupu/hot.js CHANGED
@@ -1,4 +1,4 @@
1
- import{cli as P,Strategy as X}from"@jackwener/opencli/registry";import{ArgumentError as x,CommandExecutionError as b,EmptyResultError as A}from"@jackwener/opencli/errors";export const HUPU_HOST="https://bbs.hupu.com",HOT_LIMIT_DEFAULT=20,HOT_LIMIT_MAX=100;export function normalizeHotLimit(q){if(q===void 0||q===null||q==="")return HOT_LIMIT_DEFAULT;const B=typeof q==="number"?q:Number(q);if(!Number.isFinite(B)||!Number.isInteger(B)||B<1||B>HOT_LIMIT_MAX)throw new x(`--limit must be a positive integer in [1, ${HOT_LIMIT_MAX}], got ${JSON.stringify(q)}`);return B}export function parseHupuCount(q){if(q===void 0||q===null)return null;const B=String(q).trim();if(!B)return null;const G=B.match(/^([0-9]+(?:\.[0-9]+)?)\s*(万)?/);if(!G)return null;const v=parseFloat(G[1]);if(!Number.isFinite(v))return null;return Math.round(G[2]==="万"?v*1e4:v)}export function extractHupuHotRowsFromDoc(q,B,G){const v=[],J=q.querySelectorAll(".t-info");for(let K=0;K<J.length&&v.length<B;K+=1){const N=J[K],Q=N.querySelector("a[href]");if(!Q)continue;const V=(Q.getAttribute("href")||"").match(/^\/(\d{9})\.html$/);if(!V)continue;const W=V[1],Y=Q.querySelector(".t-title"),Z=Y?(Y.textContent||"").trim():"";if(!Z)continue;const R=(Q.getAttribute("class")||"").split(/\s+/).filter(Boolean).includes("hot"),$=N.querySelector(".t-lights"),z=N.querySelector(".t-replies"),y=G($?$.textContent:null),D=G(z?z.textContent:null),j=N.parentElement,k=j?j.querySelector(".t-label a"):null,F=k?(k.textContent||"").trim():"";v.push({rank:v.length+1,tid:W,title:Z,lights:y,replies:D,forum:F,is_hot:R,url:`${HUPU_HOST}/${W}.html`})}return v}export function buildHotScript(q){return`
1
+ import{cli as x,Strategy as H}from"@jackwener/opencli/registry";import{ArgumentError as _,CommandExecutionError as E,EmptyResultError as w}from"@jackwener/opencli/errors";export const HUPU_HOST="https://bbs.hupu.com",HOT_LIMIT_DEFAULT=20,HOT_LIMIT_MAX=100;export function normalizeHotLimit(t){if(t===void 0||t===null||t==="")return HOT_LIMIT_DEFAULT;const n=typeof t==="number"?t:Number(t);if(!Number.isFinite(n)||!Number.isInteger(n)||n<1||n>HOT_LIMIT_MAX)throw new _(`--limit must be a positive integer in [1, ${HOT_LIMIT_MAX}], got ${JSON.stringify(t)}`);return n}export function parseHupuCount(t){if(t===void 0||t===null)return null;const n=String(t).trim();if(!n)return null;const o=n.match(/^([0-9]+(?:\.[0-9]+)?)\s*(万)?/);if(!o)return null;const e=parseFloat(o[1]);if(!Number.isFinite(e))return null;return Math.round(o[2]==="万"?e*1e4:e)}export function extractHupuHotRowsFromDoc(t,n,o){const e=[],r=t.querySelectorAll(".t-info");for(let i=0;i<r.length&&e.length<n;i+=1){const s=r[i],u=s.querySelector("a[href]");if(!u)continue;const l=(u.getAttribute("href")||"").match(/^\/(\d{9})\.html$/);if(!l)continue;const c=l[1],a=u.querySelector(".t-title"),m=a?(a.textContent||"").trim():"";if(!m)continue;const d=(u.getAttribute("class")||"").split(/\s+/).filter(Boolean).includes("hot"),h=s.querySelector(".t-lights"),f=s.querySelector(".t-replies"),b=o(h?h.textContent:null),y=o(f?f.textContent:null),p=s.parentElement,g=p?p.querySelector(".t-label a"):null,S=g?(g.textContent||"").trim():"";e.push({rank:e.length+1,tid:c,title:m,lights:b,replies:y,forum:S,is_hot:d,url:`${HUPU_HOST}/${c}.html`})}return e}export function buildHotScript(t){return`
2
2
  (async () => {
3
3
  const HUPU_HOST = ${JSON.stringify(HUPU_HOST)};
4
4
  ${parseHupuCount.toString()}
@@ -9,6 +9,6 @@ import{cli as P,Strategy as X}from"@jackwener/opencli/registry";import{ArgumentE
9
9
  while (document.querySelectorAll('.t-info').length === 0 && Date.now() - start < 5000) {
10
10
  await new Promise(r => setTimeout(r, 100));
11
11
  }
12
- return extractHupuHotRowsFromDoc(document, ${JSON.stringify(q)}, parseHupuCount);
12
+ return extractHupuHotRowsFromDoc(document, ${JSON.stringify(t)}, parseHupuCount);
13
13
  })()
14
- `}async function C(q,B){const G=normalizeHotLimit(B.limit);await q.goto(`${HUPU_HOST}/`,{waitUntil:"load",settleMs:1000});let v;try{v=await q.evaluate(buildHotScript(G))}catch(J){const K=J instanceof Error?J.message:String(J);throw new b(`Failed to read hupu hot threads: ${K}`,"bbs.hupu.com may be unreachable or its markup may have changed")}if(!Array.isArray(v)||v.length===0)throw new A("hupu/hot","No threads found on bbs.hupu.com — page structure may have changed");return v}export const hotCommand=P({site:"hupu",name:"hot",access:"read",description:"虎扑首页热门帖子(含 lights / replies / forum / is_hot 列)",domain:"bbs.hupu.com",strategy:X.PUBLIC,browser:!0,args:[{name:"limit",type:"int",default:HOT_LIMIT_DEFAULT,help:`Number of threads (1-${HOT_LIMIT_MAX})`}],columns:["rank","tid","title","lights","replies","forum","is_hot","url"],func:C}),__test__={buildHotScript};
14
+ `}async function A(t,n){const o=normalizeHotLimit(n.limit);await t.goto(`${HUPU_HOST}/`,{waitUntil:"load",settleMs:1000});let e;try{e=await t.evaluate(buildHotScript(o))}catch(r){const i=r instanceof Error?r.message:String(r);throw new E(`Failed to read hupu hot threads: ${i}`,"bbs.hupu.com may be unreachable or its markup may have changed")}if(!Array.isArray(e)||e.length===0)throw new w("hupu/hot","No threads found on bbs.hupu.com — page structure may have changed");return e}export const hotCommand=x({site:"hupu",name:"hot",access:"read",description:"虎扑首页热门帖子(含 lights / replies / forum / is_hot 列)",domain:"bbs.hupu.com",strategy:H.PUBLIC,browser:!0,args:[{name:"limit",type:"int",default:HOT_LIMIT_DEFAULT,help:`Number of threads (1-${HOT_LIMIT_MAX})`}],columns:["rank","tid","title","lights","replies","forum","is_hot","url"],func:A}),__test__={buildHotScript};
@@ -1 +1 @@
1
- import{CliError as N}from"@jackwener/opencli/errors";import{cli as O,Strategy as P}from"@jackwener/opencli/registry";import{postHupuJson as Q}from"./utils.js";O({site:"hupu",name:"reply",access:"write",description:"回复虎扑帖子 (需要登录)",domain:"bbs.hupu.com",strategy:P.COOKIE,navigateBefore:!1,args:[{name:"tid",required:!0,positional:!0,help:"帖子ID(9位数字)"},{name:"topic_id",required:!0,help:"板块ID,即接口中的 topicId(如 502 篮球资讯)"},{name:"text",required:!0,positional:!0,help:"回复内容"},{name:"quote_id",help:"被引用回复的 pid;填写后会以“回复某条热门回复”的方式发言"}],columns:["status","message"],func:async(z,A)=>{const{tid:h,topic_id:B,text:F,quote_id:m}=A,G="https://bbs.hupu.com/pcmapi/pc/bbs/v1/createReply",K=`<p>${F}</p>`,v={topicId:B,content:K,shumeiId:"",deviceid:"",tid:h};if(m)v.quoteId=m;try{const f=await Q(z,h,G,v,"Reply to Hupu thread","reply");if(f.code===1)return[{status:"✅ 回复成功",message:f.msg||f.message||""}];else throw Error(`接口错误 code=${f.code}: ${f.msg||f.message}`)}catch(f){if(f instanceof N)throw f;const L=f instanceof Error?f.message:String(f);throw Error(`回复失败: ${L}`)}}});
1
+ import{CliError as m}from"@jackwener/opencli/errors";import{cli as d,Strategy as l}from"@jackwener/opencli/registry";import{postHupuJson as h}from"./utils.js";d({site:"hupu",name:"reply",access:"write",description:"回复虎扑帖子 (需要登录)",domain:"bbs.hupu.com",strategy:l.COOKIE,navigateBefore:!1,args:[{name:"tid",required:!0,positional:!0,help:"帖子ID(9位数字)"},{name:"topic_id",required:!0,help:"板块ID,即接口中的 topicId(如 502 篮球资讯)"},{name:"text",required:!0,positional:!0,help:"回复内容"},{name:"quote_id",help:"被引用回复的 pid;填写后会以“回复某条热门回复”的方式发言"}],columns:["status","message"],func:async(s,i)=>{const{tid:t,topic_id:a,text:c,quote_id:r}=i,p="https://bbs.hupu.com/pcmapi/pc/bbs/v1/createReply",n=`<p>${c}</p>`,o={topicId:a,content:n,shumeiId:"",deviceid:"",tid:t};if(r)o.quoteId=r;try{const e=await h(s,t,p,o,"Reply to Hupu thread","reply");if(e.code===1)return[{status:"✅ 回复成功",message:e.msg||e.message||""}];else throw Error(`接口错误 code=${e.code}: ${e.msg||e.message}`)}catch(e){if(e instanceof m)throw e;const u=e instanceof Error?e.message:String(e);throw Error(`回复失败: ${u}`)}}});
@@ -1 +1 @@
1
- import{cli as K,Strategy as O}from"@jackwener/opencli/registry";import{decodeHtmlEntities as P,getHupuSearchUrl as Q,readHupuSearchData as R,stripHtml as V}from"./utils.js";K({site:"hupu",name:"search",access:"read",description:"搜索虎扑帖子 (使用官方API)",domain:"bbs.hupu.com",strategy:O.PUBLIC,browser:!0,args:[{name:"query",required:!0,positional:!0,help:"搜索关键词"},{name:"page",type:"int",default:1,help:"结果页码"},{name:"limit",type:"int",default:20,help:"返回结果数量"},{name:"forum",help:"板块ID过滤 (可选)"},{name:"sort",default:"general",help:"排序方式: general/createtime/replytime/light/reply"}],columns:["rank","tid","title","author","replies","lights","forum","url"],func:async(v,z)=>{const{query:A,page:B=1,limit:C=20,forum:F,sort:G="general"}=z,I=Q(A,B,F,G);return((await R(v,I,"Search Hupu threads")).searchRes?.data||[]).slice(0,Number(C)).map((b,J)=>({rank:J+1,tid:String(b.id||""),title:P(V(b.title)),author:b.username||"未知用户",replies:b.replies||"0",lights:b.lights||"0",forum:b.forum_name||"未知板块",url:`https://bbs.hupu.com/${b.id}.html`}))}});
1
+ import{cli as o,Strategy as c}from"@jackwener/opencli/registry";import{decodeHtmlEntities as m,getHupuSearchUrl as h,readHupuSearchData as d,stripHtml as g}from"./utils.js";o({site:"hupu",name:"search",access:"read",description:"搜索虎扑帖子 (使用官方API)",domain:"bbs.hupu.com",strategy:c.PUBLIC,browser:!0,args:[{name:"query",required:!0,positional:!0,help:"搜索关键词"},{name:"page",type:"int",default:1,help:"结果页码"},{name:"limit",type:"int",default:20,help:"返回结果数量"},{name:"forum",help:"板块ID过滤 (可选)"},{name:"sort",default:"general",help:"排序方式: general/createtime/replytime/light/reply"}],columns:["rank","tid","title","author","replies","lights","forum","url"],func:async(r,t)=>{const{query:a,page:s=1,limit:l=20,forum:u,sort:i="general"}=t,p=h(a,s,u,i);return((await d(r,p,"Search Hupu threads")).searchRes?.data||[]).slice(0,Number(l)).map((e,n)=>({rank:n+1,tid:String(e.id||""),title:m(g(e.title)),author:e.username||"未知用户",replies:e.replies||"0",lights:e.lights||"0",forum:e.forum_name||"未知板块",url:`https://bbs.hupu.com/${e.id}.html`}))}});
@@ -1 +1 @@
1
- import{CliError as F}from"@jackwener/opencli/errors";import{cli as G,Strategy as I}from"@jackwener/opencli/registry";import{postHupuJson as K}from"./utils.js";G({site:"hupu",name:"unlike",access:"write",description:"取消点赞虎扑回复 (需要登录)",domain:"bbs.hupu.com",strategy:I.COOKIE,navigateBefore:!1,args:[{name:"tid",required:!0,positional:!0,help:"帖子ID(9位数字)"},{name:"pid",required:!0,positional:!0,help:"回复ID"},{name:"fid",required:!0,help:"板块ID(如278汽车区)"}],columns:["status","message"],func:async(q,v)=>{const{tid:m,pid:x,fid:z}=v,A="https://bbs.hupu.com/pcmapi/pc/bbs/v1/reply/cancelLight",B={tid:m,pid:x,puid:"",fid:z,shumei_id:"",deviceid:""};try{const h=await K(q,m,A,B,"Unlike Hupu reply");if(h.code===1)return[{status:"✅ 取消点赞成功",message:""}];else if(h.code===0&&h.msg==="你还没有点亮过这个回帖")return[{status:"⚠️ 你还没点赞过",message:h.msg||""}];else if(h.code===0)return[{status:"⚠️ 操作未执行",message:h.msg||h.message||""}];else throw Error(`接口错误 code=${h.code}: ${h.msg||h.message}`)}catch(h){if(h instanceof F)throw h;const D=h instanceof Error?h.message:String(h);throw Error(`取消点赞失败: ${D}`)}}});
1
+ import{CliError as c}from"@jackwener/opencli/errors";import{cli as m,Strategy as p}from"@jackwener/opencli/registry";import{postHupuJson as d}from"./utils.js";m({site:"hupu",name:"unlike",access:"write",description:"取消点赞虎扑回复 (需要登录)",domain:"bbs.hupu.com",strategy:p.COOKIE,navigateBefore:!1,args:[{name:"tid",required:!0,positional:!0,help:"帖子ID(9位数字)"},{name:"pid",required:!0,positional:!0,help:"回复ID"},{name:"fid",required:!0,help:"板块ID(如278汽车区)"}],columns:["status","message"],func:async(r,t)=>{const{tid:s,pid:i,fid:o}=t,a="https://bbs.hupu.com/pcmapi/pc/bbs/v1/reply/cancelLight",u={tid:s,pid:i,puid:"",fid:o,shumei_id:"",deviceid:""};try{const e=await d(r,s,a,u,"Unlike Hupu reply");if(e.code===1)return[{status:"✅ 取消点赞成功",message:""}];else if(e.code===0&&e.msg==="你还没有点亮过这个回帖")return[{status:"⚠️ 你还没点赞过",message:e.msg||""}];else if(e.code===0)return[{status:"⚠️ 操作未执行",message:e.msg||e.message||""}];else throw Error(`接口错误 code=${e.code}: ${e.msg||e.message}`)}catch(e){if(e instanceof c)throw e;const n=e instanceof Error?e.message:String(e);throw Error(`取消点赞失败: ${n}`)}}});
@@ -1,9 +1,9 @@
1
- import{AuthRequiredError as X,CommandExecutionError as M}from"@jackwener/opencli/errors";export function stripHtml(z){if(!z)return"";return z.replace(/\\u003c/g,"<").replace(/\\u003e/g,">").replace(/\\n/g,`
2
- `).replace(/\\r/g,"").replace(/<[^>]+>/g,"").trim()}export function decodeHtmlEntities(z){if(!z)return"";return z.replace(/&nbsp;/g," ").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&amp;/g,"&").replace(/&quot;/g,'"').replace(/&#x27;/g,"'")}export function getHupuThreadUrl(z){return`https://bbs.hupu.com/${encodeURIComponent(String(z))}-1.html`}export function getHupuSearchUrl(z,I,K,F){const D=new URLSearchParams;D.append("q",String(z));D.append("page",String(I));if(K)D.append("topicId",String(K));if(F)D.append("sortby",String(F));return`https://bbs.hupu.com/search?${D.toString()}`}export async function readHupuNextData(z,I,K,F={}){await z.goto(I);const D=await z.evaluate(`
1
+ import{AuthRequiredError as u,CommandExecutionError as s}from"@jackwener/opencli/errors";export function stripHtml(e){if(!e)return"";return e.replace(/\\u003c/g,"<").replace(/\\u003e/g,">").replace(/\\n/g,`
2
+ `).replace(/\\r/g,"").replace(/<[^>]+>/g,"").trim()}export function decodeHtmlEntities(e){if(!e)return"";return e.replace(/&nbsp;/g," ").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&amp;/g,"&").replace(/&quot;/g,'"').replace(/&#x27;/g,"'")}export function getHupuThreadUrl(e){return`https://bbs.hupu.com/${encodeURIComponent(String(e))}-1.html`}export function getHupuSearchUrl(e,a,o,r){const t=new URLSearchParams;t.append("q",String(e));t.append("page",String(a));if(o)t.append("topicId",String(o));if(r)t.append("sortby",String(r));return`https://bbs.hupu.com/search?${t.toString()}`}export async function readHupuNextData(e,a,o,r={}){await e.goto(a);const t=await e.evaluate(`
3
3
  (async () => {
4
4
  const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
5
- const expectedTid = ${JSON.stringify(F.expectedTid||"")};
6
- const timeoutMs = ${JSON.stringify(F.timeoutMs??5000)};
5
+ const expectedTid = ${JSON.stringify(r.expectedTid||"")};
6
+ const timeoutMs = ${JSON.stringify(r.timeoutMs??5000)};
7
7
  let lastSeenTid = '';
8
8
  let lastSeenHref = '';
9
9
 
@@ -55,7 +55,7 @@ import{AuthRequiredError as X,CommandExecutionError as M}from"@jackwener/opencli
55
55
  };
56
56
  }
57
57
  })()
58
- `);if(!D||typeof D!=="object"||!D.ok)throw new M(`${K} failed: ${D?.error||"invalid browser response"}`);return D.data}export async function readHupuSearchData(z,I,K){await z.goto(I);const F=await z.evaluate(`
58
+ `);if(!t||typeof t!=="object"||!t.ok)throw new s(`${o} failed: ${t?.error||"invalid browser response"}`);return t.data}export async function readHupuSearchData(e,a,o){await e.goto(a);const r=await e.evaluate(`
59
59
  (async () => {
60
60
  const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
61
61
  const waitFor = async (predicate, timeoutMs = 5000) => {
@@ -145,11 +145,11 @@ import{AuthRequiredError as X,CommandExecutionError as M}from"@jackwener/opencli
145
145
  };
146
146
  }
147
147
  })()
148
- `);if(!F||typeof F!=="object"||!F.ok)throw new M(`${K} failed: ${F?.error||"invalid browser response"}`);return F.data}function Y(z,I,K){return`
148
+ `);if(!r||typeof r!=="object"||!r.ok)throw new s(`${o} failed: ${r?.error||"invalid browser response"}`);return r.data}function l(e,a,o){return`
149
149
  (async () => {
150
- const url = ${JSON.stringify(z)};
151
- const payload = ${JSON.stringify(I)};
152
- const mode = ${JSON.stringify(K)};
150
+ const url = ${JSON.stringify(e)};
151
+ const payload = ${JSON.stringify(a)};
152
+ const mode = ${JSON.stringify(o)};
153
153
  const getCookie = (name) => document.cookie
154
154
  .split('; ')
155
155
  .find((item) => item.startsWith(name + '='))
@@ -240,4 +240,4 @@ import{AuthRequiredError as X,CommandExecutionError as M}from"@jackwener/opencli
240
240
  };
241
241
  }
242
242
  })()
243
- `}export async function postHupuJson(z,I,K,F,D,Q="default"){const V=getHupuThreadUrl(I);await z.goto(V);const G=await z.evaluate(Y(K,F,Q));if(!G||typeof G!=="object")throw new M(`${D} failed: invalid browser response`);if(G.status===401||G.status===403)throw new X("bbs.hupu.com",`${D} failed: please log in to Hupu first`);if(G.error)throw new M(`${D} failed: ${G.error}`);if(!G.ok){const W=G.data?.msg||G.data?.message||`HTTP ${G.status??"unknown"}`;throw new M(`${D} failed: ${W}`)}return G.data??{}}
243
+ `}export async function postHupuJson(e,a,o,r,t,i="default"){const c=getHupuThreadUrl(a);await e.goto(c);const n=await e.evaluate(l(o,r,i));if(!n||typeof n!=="object")throw new s(`${t} failed: invalid browser response`);if(n.status===401||n.status===403)throw new u("bbs.hupu.com",`${t} failed: please log in to Hupu first`);if(n.error)throw new s(`${t} failed: ${n.error}`);if(!n.ok){const d=n.data?.msg||n.data?.message||`HTTP ${n.status??"unknown"}`;throw new s(`${t} failed: ${d}`)}return n.data??{}}
@@ -1,4 +1,4 @@
1
- import{CommandExecutionError as K}from"@jackwener/opencli/errors";import{cli as Y,Strategy as Z}from"@jackwener/opencli/registry";import{forceEnglishUrl as _,getCurrentImdbId as $,isChallengePage as q,normalizeImdbId as z,waitForImdbPath as F}from"./utils.js";Y({site:"imdb",name:"person",access:"read",description:"Get actor or director info",domain:"www.imdb.com",strategy:Z.PUBLIC,browser:!0,args:[{name:"id",positional:!0,required:!0,help:"IMDb person ID (nm0634240) or URL"},{name:"limit",type:"int",default:10,help:"Max filmography entries"}],columns:["field","value"],func:async(H,Q)=>{const B=z(String(Q.id),"nm"),V=Math.max(1,Math.min(Number(Q.limit)||10,30)),W=_(`https://www.imdb.com/name/${B}/`);await H.goto(W);const X=await F(H,`^/name/${B}/`);if(await q(H))throw new K("IMDb blocked this request","Try again with a normal browser session or extension mode");if(!X)throw new K(`Person page did not finish loading: ${B}`,"Retry the command; if it persists, IMDb may have changed their navigation flow");const M=await $(H,"nm");if(M&&M!==B)throw new K(`IMDb redirected to a different person: ${M}`,"Retry the command; if it persists, the person page may have changed");const J=await H.evaluate(`
1
+ import{CommandExecutionError as n}from"@jackwener/opencli/errors";import{cli as g,Strategy as h}from"@jackwener/opencli/registry";import{forceEnglishUrl as f,getCurrentImdbId as y,isChallengePage as b,normalizeImdbId as v,waitForImdbPath as w}from"./utils.js";g({site:"imdb",name:"person",access:"read",description:"Get actor or director info",domain:"www.imdb.com",strategy:h.PUBLIC,browser:!0,args:[{name:"id",positional:!0,required:!0,help:"IMDb person ID (nm0634240) or URL"},{name:"limit",type:"int",default:10,help:"Max filmography entries"}],columns:["field","value"],func:async(a,s)=>{const t=v(String(s.id),"nm"),p=Math.max(1,Math.min(Number(s.limit)||10,30)),c=f(`https://www.imdb.com/name/${t}/`);await a.goto(c);const u=await w(a,`^/name/${t}/`);if(await b(a))throw new n("IMDb blocked this request","Try again with a normal browser session or extension mode");if(!u)throw new n(`Person page did not finish loading: ${t}`,"Retry the command; if it persists, IMDb may have changed their navigation flow");const l=await y(a,"nm");if(l&&l!==t)throw new n(`IMDb redirected to a different person: ${l}`,"Retry the command; if it persists, the person page may have changed");const i=await a.evaluate(`
2
2
  (function() {
3
3
  var result = {
4
4
  nameId: '',
@@ -137,4 +137,4 @@ import{CommandExecutionError as K}from"@jackwener/opencli/errors";import{cli as
137
137
 
138
138
  return result;
139
139
  })()
140
- `);if(!J||typeof J!=="object"||!("name"in J)||!J.name)throw new K(`Person not found: ${B}`,"Check the person ID and try again");const D=J;if(D.nameId&&D.nameId!==B)throw new K(`IMDb returned a different person payload: ${D.nameId}`,"Retry the command; if it persists, the person parser may need updating");const T=Array.isArray(D.filmography)?D.filmography:[];D.url=`https://www.imdb.com/name/${B}/`;const N=Object.entries(D).filter(([A,G])=>A!=="filmography"&&A!=="nameId"&&G!==""&&G!=null).map(([A,G])=>({field:A,value:String(G)}));if(T.length>0){N.push({field:"filmography",value:""});for(const A of T.slice(0,V)){const G=[A.year?`(${A.year})`:"",A.role?`[${A.role}]`:""].filter(Boolean).join(" ");N.push({field:String(A.title||""),value:G})}}return N}});
140
+ `);if(!i||typeof i!=="object"||!("name"in i)||!i.name)throw new n(`Person not found: ${t}`,"Check the person ID and try again");const r=i;if(r.nameId&&r.nameId!==t)throw new n(`IMDb returned a different person payload: ${r.nameId}`,"Retry the command; if it persists, the person parser may need updating");const m=Array.isArray(r.filmography)?r.filmography:[];r.url=`https://www.imdb.com/name/${t}/`;const d=Object.entries(r).filter(([e,o])=>e!=="filmography"&&e!=="nameId"&&o!==""&&o!=null).map(([e,o])=>({field:e,value:String(o)}));if(m.length>0){d.push({field:"filmography",value:""});for(const e of m.slice(0,p)){const o=[e.year?`(${e.year})`:"",e.role?`[${e.role}]`:""].filter(Boolean).join(" ");d.push({field:String(e.title||""),value:o})}}return d}});
@@ -1,6 +1,6 @@
1
- import{CommandExecutionError as H}from"@jackwener/opencli/errors";import{cli as V,Strategy as W}from"@jackwener/opencli/registry";import{forceEnglishUrl as X,getCurrentImdbId as Y,isChallengePage as Z,normalizeImdbId as _,waitForImdbPath as $,waitForImdbReviewsReady as z}from"./utils.js";V({site:"imdb",name:"reviews",access:"read",description:"Get user reviews for a movie or TV show",domain:"www.imdb.com",strategy:W.PUBLIC,browser:!0,args:[{name:"id",positional:!0,required:!0,help:"IMDb title ID (tt1375666) or URL"},{name:"limit",type:"int",default:10,help:"Number of reviews"}],columns:["rank","title","rating","author","date","text"],func:async(q,J)=>{const B=_(String(J.id),"tt"),L=Math.max(1,Math.min(Number(J.limit)||10,25)),N=X(`https://www.imdb.com/title/${B}/reviews/`);await q.goto(N);const O=await $(q,`^/title/${B}/reviews/?$`),Q=await z(q,15000);if(await Z(q))throw new H("IMDb blocked this request","Try again with a normal browser session or extension mode");if(!O||!Q)throw new H("IMDb reviews did not finish loading","Retry the command; if it persists, the review page structure may have changed");const G=await Y(q,"tt");if(G&&G!==B)throw new H(`IMDb redirected to a different title: ${G}`,"Retry the command; if it persists, the review page may have changed");const K=await q.evaluate(`
1
+ import{CommandExecutionError as a}from"@jackwener/opencli/errors";import{cli as u,Strategy as w}from"@jackwener/opencli/registry";import{forceEnglishUrl as v,getCurrentImdbId as h,isChallengePage as f,normalizeImdbId as g,waitForImdbPath as p,waitForImdbReviewsReady as x}from"./utils.js";u({site:"imdb",name:"reviews",access:"read",description:"Get user reviews for a movie or TV show",domain:"www.imdb.com",strategy:w.PUBLIC,browser:!0,args:[{name:"id",positional:!0,required:!0,help:"IMDb title ID (tt1375666) or URL"},{name:"limit",type:"int",default:10,help:"Number of reviews"}],columns:["rank","title","rating","author","date","text"],func:async(t,n)=>{const r=g(String(n.id),"tt"),s=Math.max(1,Math.min(Number(n.limit)||10,25)),l=v(`https://www.imdb.com/title/${r}/reviews/`);await t.goto(l);const d=await p(t,`^/title/${r}/reviews/?$`),m=await x(t,15000);if(await f(t))throw new a("IMDb blocked this request","Try again with a normal browser session or extension mode");if(!d||!m)throw new a("IMDb reviews did not finish loading","Retry the command; if it persists, the review page structure may have changed");const i=await h(t,"tt");if(i&&i!==r)throw new a(`IMDb redirected to a different title: ${i}`,"Retry the command; if it persists, the review page may have changed");const o=await t.evaluate(`
2
2
  (function() {
3
- var limit = ${L};
3
+ var limit = ${s};
4
4
  var items = [];
5
5
  var containers = document.querySelectorAll('article.user-review-item, [data-testid="review-card-parent"], .imdb-user-review, [data-testid="review-card"], .review-container');
6
6
 
@@ -37,4 +37,4 @@ import{CommandExecutionError as H}from"@jackwener/opencli/errors";import{cli as
37
37
 
38
38
  return items;
39
39
  })()
40
- `);if(!Array.isArray(K))return[];return K.map((A,T)=>({rank:T+1,title:A.title||"",rating:A.rating||"",author:A.author||"",date:A.date||"",text:A.text||""}))}});
40
+ `);if(!Array.isArray(o))return[];return o.map((e,c)=>({rank:c+1,title:e.title||"",rating:e.rating||"",author:e.author||"",date:e.date||"",text:e.text||""}))}});
@@ -1,4 +1,4 @@
1
- import{ArgumentError as Q,CommandExecutionError as J}from"@jackwener/opencli/errors";import{cli as V,Strategy as W}from"@jackwener/opencli/registry";import{forceEnglishUrl as X,isChallengePage as Y,normalizeImdbTitleType as Z,waitForImdbPath as _,waitForImdbSearchReady as $}from"./utils.js";V({site:"imdb",name:"search",access:"read",description:"Search IMDb for movies, TV shows, and people",domain:"www.imdb.com",strategy:W.PUBLIC,browser:!0,args:[{name:"query",positional:!0,required:!0,help:"Search query"},{name:"limit",type:"int",default:20,help:"Number of results"}],columns:["rank","id","title","year","type","url"],func:async(v,D)=>{const G=String(D.query||"").trim();if(!G)throw new Q("Search query cannot be empty");const K=Math.max(1,Math.min(Number(D.limit)||20,50)),L=X(`https://www.imdb.com/find/?q=${encodeURIComponent(G)}&ref_=nv_sr_sm`);await v.goto(L);const M=await _(v,"^/find/?$"),N=await $(v,15000);if(await Y(v))throw new J("IMDb blocked this request","Try again with a normal browser session or extension mode");if(!M||!N)throw new J("IMDb search results did not finish loading","Retry the command; if it persists, the search page structure may have changed");const H=await v.evaluate(`
1
+ import{ArgumentError as p,CommandExecutionError as n}from"@jackwener/opencli/errors";import{cli as y,Strategy as f}from"@jackwener/opencli/registry";import{forceEnglishUrl as d,isChallengePage as h,normalizeImdbTitleType as I,waitForImdbPath as c,waitForImdbSearchReady as g}from"./utils.js";y({site:"imdb",name:"search",access:"read",description:"Search IMDb for movies, TV shows, and people",domain:"www.imdb.com",strategy:f.PUBLIC,browser:!0,args:[{name:"query",positional:!0,required:!0,help:"Search query"},{name:"limit",type:"int",default:20,help:"Number of results"}],columns:["rank","id","title","year","type","url"],func:async(e,r)=>{const a=String(r.query||"").trim();if(!a)throw new p("Search query cannot be empty");const s=Math.max(1,Math.min(Number(r.limit)||20,50)),l=d(`https://www.imdb.com/find/?q=${encodeURIComponent(a)}&ref_=nv_sr_sm`);await e.goto(l);const m=await c(e,"^/find/?$"),o=await g(e,15000);if(await h(e))throw new n("IMDb blocked this request","Try again with a normal browser session or extension mode");if(!m||!o)throw new n("IMDb search results did not finish loading","Retry the command; if it persists, the search page structure may have changed");const i=await e.evaluate(`
2
2
  (function() {
3
3
  var results = [];
4
4
 
@@ -110,4 +110,4 @@ import{ArgumentError as Q,CommandExecutionError as J}from"@jackwener/opencli/err
110
110
 
111
111
  return results;
112
112
  })()
113
- `);if(!Array.isArray(H))return[];return H.slice(0,K).map((B,O)=>({rank:O+1,id:B.id||"",title:B.title||"",year:B.year||"",type:Z(B.type),url:B.url||""}))}});
113
+ `);if(!Array.isArray(i))return[];return i.slice(0,s).map((t,u)=>({rank:u+1,id:t.id||"",title:t.title||"",year:t.year||"",type:I(t.type),url:t.url||""}))}});
@@ -1 +1 @@
1
- import{CommandExecutionError as M}from"@jackwener/opencli/errors";import{cli as U,Strategy as V}from"@jackwener/opencli/registry";import{extractJsonLd as k,forceEnglishUrl as D,formatDuration as F,getCurrentImdbId as b,isChallengePage as j,normalizeImdbId as h,waitForImdbPath as w}from"./utils.js";U({site:"imdb",name:"title",access:"read",description:"Get movie or TV show details",domain:"www.imdb.com",strategy:V.PUBLIC,browser:!0,args:[{name:"id",positional:!0,required:!0,help:"IMDb title ID (tt1375666) or URL"}],columns:["field","value"],func:async(G,X)=>{const B=h(String(X.id),"tt"),Z=D(`https://www.imdb.com/title/${B}/`);await G.goto(Z);const _=await w(G,`^/title/${B}/`);if(await j(G))throw new M("IMDb blocked this request","Try again with a normal browser session or extension mode");if(!_)throw new M(`Title page did not finish loading: ${B}`,"Retry the command; if it persists, IMDb may have changed their navigation flow");const N=await b(G,"tt");if(N&&N!==B)throw new M(`IMDb redirected to a different title: ${N}`,"Retry the command; if it persists, the title page may have changed");const W=await k(G,["Movie","TVSeries","TVEpisode","TVMiniseries","TVMovie","TVSpecial","VideoGame","ShortFilm"]);if(!W)throw new M(`Title not found: ${B}`,"Check the title ID and try again");const q=W,O=String(q["@type"]||""),K=O==="TVSeries"||O==="TVMiniseries",Q=(A)=>{if(!A)return"";return(Array.isArray(A)?A:[A]).slice(0,5).map((L)=>L.name||"").filter(Boolean).join(", ")},$=(()=>{if(K&&typeof q.startDate==="string"){const A=q.startDate.split("-")[0]||"",H=typeof q.endDate==="string"?q.endDate.split("-")[0]||"":"";return H?`${A}-${H}`:`${A}-`}if(typeof q.datePublished==="string")return q.datePublished.split("-")[0]||"";return""})(),z=K?"creator":"director",J=K?Q(q.creator):Q(q.director),R={title:String(q.name||""),type:O,year:$,rating:q.aggregateRating?.ratingValue!=null?String(q.aggregateRating.ratingValue):"",votes:q.aggregateRating?.ratingCount!=null?String(q.aggregateRating.ratingCount):"",genre:Array.isArray(q.genre)?q.genre.join(", "):String(q.genre||""),[z]:J,cast:Q(q.actor),duration:F(String(q.duration||"")),contentRating:String(q.contentRating||""),plot:String(q.description||""),url:`https://www.imdb.com/title/${B}/`};if(K){if(q.numberOfSeasons!=null)R.seasons=String(q.numberOfSeasons);if(q.numberOfEpisodes!=null)R.episodes=String(q.numberOfEpisodes)}return Object.entries(R).filter(([,A])=>A!=="").map(([A,H])=>({field:A,value:H}))}});
1
+ import{CommandExecutionError as a}from"@jackwener/opencli/errors";import{cli as y,Strategy as S}from"@jackwener/opencli/registry";import{extractJsonLd as T,forceEnglishUrl as I,formatDuration as V,getCurrentImdbId as D,isChallengePage as v,normalizeImdbId as R,waitForImdbPath as M}from"./utils.js";y({site:"imdb",name:"title",access:"read",description:"Get movie or TV show details",domain:"www.imdb.com",strategy:S.PUBLIC,browser:!0,args:[{name:"id",positional:!0,required:!0,help:"IMDb title ID (tt1375666) or URL"}],columns:["field","value"],func:async(r,m)=>{const i=R(String(m.id),"tt"),u=I(`https://www.imdb.com/title/${i}/`);await r.goto(u);const f=await M(r,`^/title/${i}/`);if(await v(r))throw new a("IMDb blocked this request","Try again with a normal browser session or extension mode");if(!f)throw new a(`Title page did not finish loading: ${i}`,"Retry the command; if it persists, IMDb may have changed their navigation flow");const s=await D(r,"tt");if(s&&s!==i)throw new a(`IMDb redirected to a different title: ${s}`,"Retry the command; if it persists, the title page may have changed");const c=await T(r,["Movie","TVSeries","TVEpisode","TVMiniseries","TVMovie","TVSpecial","VideoGame","ShortFilm"]);if(!c)throw new a(`Title not found: ${i}`,"Check the title ID and try again");const t=c,l=String(t["@type"]||""),o=l==="TVSeries"||l==="TVMiniseries",d=(e)=>{if(!e)return"";return(Array.isArray(e)?e:[e]).slice(0,5).map((b)=>b.name||"").filter(Boolean).join(", ")},p=(()=>{if(o&&typeof t.startDate==="string"){const e=t.startDate.split("-")[0]||"",n=typeof t.endDate==="string"?t.endDate.split("-")[0]||"":"";return n?`${e}-${n}`:`${e}-`}if(typeof t.datePublished==="string")return t.datePublished.split("-")[0]||"";return""})(),w=o?"creator":"director",h=o?d(t.creator):d(t.director),g={title:String(t.name||""),type:l,year:p,rating:t.aggregateRating?.ratingValue!=null?String(t.aggregateRating.ratingValue):"",votes:t.aggregateRating?.ratingCount!=null?String(t.aggregateRating.ratingCount):"",genre:Array.isArray(t.genre)?t.genre.join(", "):String(t.genre||""),[w]:h,cast:d(t.actor),duration:V(String(t.duration||"")),contentRating:String(t.contentRating||""),plot:String(t.description||""),url:`https://www.imdb.com/title/${i}/`};if(o){if(t.numberOfSeasons!=null)g.seasons=String(t.numberOfSeasons);if(t.numberOfEpisodes!=null)g.episodes=String(t.numberOfEpisodes)}return Object.entries(g).filter(([,e])=>e!=="").map(([e,n])=>({field:e,value:n}))}});
package/clis/imdb/top.js CHANGED
@@ -1 +1 @@
1
- import{CommandExecutionError as K}from"@jackwener/opencli/errors";import{cli as X,Strategy as Y}from"@jackwener/opencli/registry";import{extractJsonLd as Z,forceEnglishUrl as _,isChallengePage as $}from"./utils.js";X({site:"imdb",name:"top",access:"read",description:"IMDb Top 250 Movies",domain:"www.imdb.com",strategy:Y.PUBLIC,browser:!0,args:[{name:"limit",type:"int",default:20,help:"Number of results"}],columns:["rank","title","rating","votes","genre","url"],func:async(B,O)=>{const Q=_("https://www.imdb.com/chart/top/");await B.goto(Q);await B.wait(2);if(await $(B))throw new K("IMDb blocked this request","Try again with a normal browser session or extension mode");const G=await Z(B,"ItemList");if(!G||!Array.isArray(G.itemListElement))throw new K("Could not find chart data on page","IMDb may have changed their page structure");const T=Math.max(1,Math.min(Number(O.limit)||20,250));return G.itemListElement.slice(0,T).map((H,V)=>{const q=H.item||{},F=q.aggregateRating||{},W=Array.isArray(q.genre)?q.genre.join(", "):String(q.genre||"");let A=q.url||"";if(A&&!/^https?:\/\//.test(A))A="https://www.imdb.com"+A;return{rank:H.position||V+1,title:String(q.name||""),rating:F.ratingValue!=null?String(F.ratingValue):"",votes:F.ratingCount!=null?String(F.ratingCount):"",genre:W,url:A}})}});
1
+ import{CommandExecutionError as o}from"@jackwener/opencli/errors";import{cli as u,Strategy as w}from"@jackwener/opencli/registry";import{extractJsonLd as d,forceEnglishUrl as h,isChallengePage as p}from"./utils.js";u({site:"imdb",name:"top",access:"read",description:"IMDb Top 250 Movies",domain:"www.imdb.com",strategy:w.PUBLIC,browser:!0,args:[{name:"limit",type:"int",default:20,help:"Number of results"}],columns:["rank","title","rating","votes","genre","url"],func:async(r,s)=>{const m=h("https://www.imdb.com/chart/top/");await r.goto(m);await r.wait(2);if(await p(r))throw new o("IMDb blocked this request","Try again with a normal browser session or extension mode");const n=await d(r,"ItemList");if(!n||!Array.isArray(n.itemListElement))throw new o("Could not find chart data on page","IMDb may have changed their page structure");const l=Math.max(1,Math.min(Number(s.limit)||20,250));return n.itemListElement.slice(0,l).map((a,g)=>{const t=a.item||{},i=t.aggregateRating||{},c=Array.isArray(t.genre)?t.genre.join(", "):String(t.genre||"");let e=t.url||"";if(e&&!/^https?:\/\//.test(e))e="https://www.imdb.com"+e;return{rank:a.position||g+1,title:String(t.name||""),rating:i.ratingValue!=null?String(i.ratingValue):"",votes:i.ratingCount!=null?String(i.ratingCount):"",genre:c,url:e}})}});
@@ -1 +1 @@
1
- import{CommandExecutionError as K}from"@jackwener/opencli/errors";import{cli as X,Strategy as Y}from"@jackwener/opencli/registry";import{extractJsonLd as Z,forceEnglishUrl as _,isChallengePage as $}from"./utils.js";X({site:"imdb",name:"trending",access:"read",description:"IMDb Most Popular Movies",domain:"www.imdb.com",strategy:Y.PUBLIC,browser:!0,args:[{name:"limit",type:"int",default:20,help:"Number of results"}],columns:["rank","title","rating","genre","url"],func:async(B,O)=>{const Q=_("https://www.imdb.com/chart/moviemeter/");await B.goto(Q);await B.wait(2);if(await $(B))throw new K("IMDb blocked this request","Try again with a normal browser session or extension mode");const F=await Z(B,"ItemList");if(!F||!Array.isArray(F.itemListElement))throw new K("Could not find chart data on page","IMDb may have changed their page structure");const T=Math.max(1,Math.min(Number(O.limit)||20,100));return F.itemListElement.slice(0,T).map((G,V)=>{const q=G.item||{},H=q.aggregateRating||{},W=Array.isArray(q.genre)?q.genre.join(", "):String(q.genre||"");let A=q.url||"";if(A&&!/^https?:\/\//.test(A))A="https://www.imdb.com"+A;return{rank:G.position||V+1,title:String(q.name||""),rating:H.ratingValue!=null?String(H.ratingValue):"",genre:W,url:A}})}});
1
+ import{CommandExecutionError as o}from"@jackwener/opencli/errors";import{cli as u,Strategy as w}from"@jackwener/opencli/registry";import{extractJsonLd as d,forceEnglishUrl as h,isChallengePage as b}from"./utils.js";u({site:"imdb",name:"trending",access:"read",description:"IMDb Most Popular Movies",domain:"www.imdb.com",strategy:w.PUBLIC,browser:!0,args:[{name:"limit",type:"int",default:20,help:"Number of results"}],columns:["rank","title","rating","genre","url"],func:async(r,s)=>{const m=h("https://www.imdb.com/chart/moviemeter/");await r.goto(m);await r.wait(2);if(await b(r))throw new o("IMDb blocked this request","Try again with a normal browser session or extension mode");const i=await d(r,"ItemList");if(!i||!Array.isArray(i.itemListElement))throw new o("Could not find chart data on page","IMDb may have changed their page structure");const l=Math.max(1,Math.min(Number(s.limit)||20,100));return i.itemListElement.slice(0,l).map((n,c)=>{const t=n.item||{},a=t.aggregateRating||{},g=Array.isArray(t.genre)?t.genre.join(", "):String(t.genre||"");let e=t.url||"";if(e&&!/^https?:\/\//.test(e))e="https://www.imdb.com"+e;return{rank:n.position||c+1,title:String(t.name||""),rating:a.ratingValue!=null?String(a.ratingValue):"",genre:g,url:e}})}});
@@ -1,7 +1,7 @@
1
- import{ArgumentError as H}from"@jackwener/opencli/errors";export function normalizeImdbId(z,q){const B=z.trim();if(new RegExp(`^${q}\\d{7,8}$`).test(B))return B;const G=new RegExp(`/(?:[a-z]{2}/)?(?:title|name)/(${q}\\d{7,8})(?:[/?#]|$)`,"i"),F=B.match(G);if(F)return F[1];throw new H(`Invalid IMDb ID: "${z}"`,`Expected ${q==="tt"?"title":"name"} ID like ${q==="tt"?"tt1375666":"nm0634240"} or an IMDb URL`)}export function formatDuration(z){if(!z)return"";const q=z.match(/^PT(?:(\d+)H)?(?:(\d+)M)?$/);if(!q)return"";const B=[];if(q[1])B.push(`${q[1]}h`);if(q[2])B.push(`${q[2]}m`);return B.join(" ")}export function forceEnglishUrl(z){const q=new URL(z);q.searchParams.set("language","en-US");return q.toString()}export function normalizeImdbTitleType(z){const q=(()=>{if(typeof z==="string")return z;if(!z||typeof z!=="object")return"";const C=z;return typeof C.text==="string"&&C.text.trim()?C.text:typeof C.id==="string"?C.id:""})().trim();if(!q)return"";return{movie:"Movie",short:"Short",video:"Video",tvEpisode:"TV Episode",tvMiniSeries:"TV Mini Series",tvMovie:"TV Movie",tvSeries:"TV Series",tvShort:"TV Short",tvSpecial:"TV Special",videoGame:"Video Game"}[q]??q}export async function extractJsonLd(z,q){const B=q?Array.isArray(q)?q:[q]:[];return z.evaluate(`
1
+ import{ArgumentError as i}from"@jackwener/opencli/errors";export function normalizeImdbId(e,t){const r=e.trim();if(new RegExp(`^${t}\\d{7,8}$`).test(r))return r;const o=new RegExp(`/(?:[a-z]{2}/)?(?:title|name)/(${t}\\d{7,8})(?:[/?#]|$)`,"i"),n=r.match(o);if(n)return n[1];throw new i(`Invalid IMDb ID: "${e}"`,`Expected ${t==="tt"?"title":"name"} ID like ${t==="tt"?"tt1375666":"nm0634240"} or an IMDb URL`)}export function formatDuration(e){if(!e)return"";const t=e.match(/^PT(?:(\d+)H)?(?:(\d+)M)?$/);if(!t)return"";const r=[];if(t[1])r.push(`${t[1]}h`);if(t[2])r.push(`${t[2]}m`);return r.join(" ")}export function forceEnglishUrl(e){const t=new URL(e);t.searchParams.set("language","en-US");return t.toString()}export function normalizeImdbTitleType(e){const t=(()=>{if(typeof e==="string")return e;if(!e||typeof e!=="object")return"";const a=e;return typeof a.text==="string"&&a.text.trim()?a.text:typeof a.id==="string"?a.id:""})().trim();if(!t)return"";return{movie:"Movie",short:"Short",video:"Video",tvEpisode:"TV Episode",tvMiniSeries:"TV Mini Series",tvMovie:"TV Movie",tvSeries:"TV Series",tvShort:"TV Short",tvSpecial:"TV Special",videoGame:"Video Game"}[t]??t}export async function extractJsonLd(e,t){const r=t?Array.isArray(t)?t:[t]:[];return e.evaluate(`
2
2
  (function() {
3
3
  var scripts = document.querySelectorAll('script[type="application/ld+json"]');
4
- var wantedTypes = ${JSON.stringify(B)};
4
+ var wantedTypes = ${JSON.stringify(r)};
5
5
 
6
6
  function matchesType(data) {
7
7
  if (wantedTypes.length === 0) {
@@ -61,10 +61,10 @@ import{ArgumentError as H}from"@jackwener/opencli/errors";export function normal
61
61
 
62
62
  return null;
63
63
  })()
64
- `)}export async function waitForImdbPath(z,q,B=15000){const C=await z.evaluate(`
64
+ `)}export async function waitForImdbPath(e,t,r=15000){const a=await e.evaluate(`
65
65
  (async function() {
66
- var deadline = Date.now() + ${B};
67
- var pattern = new RegExp(${JSON.stringify(q)}, 'i');
66
+ var deadline = Date.now() + ${r};
67
+ var pattern = new RegExp(${JSON.stringify(t)}, 'i');
68
68
  while (Date.now() < deadline) {
69
69
  if (pattern.test(window.location.pathname)) {
70
70
  return true;
@@ -73,9 +73,9 @@ import{ArgumentError as H}from"@jackwener/opencli/errors";export function normal
73
73
  }
74
74
  return pattern.test(window.location.pathname);
75
75
  })()
76
- `);return Boolean(C)}export async function waitForImdbSearchReady(z,q=15000){const B=await z.evaluate(`
76
+ `);return Boolean(a)}export async function waitForImdbSearchReady(e,t=15000){const r=await e.evaluate(`
77
77
  (async function() {
78
- var deadline = Date.now() + ${q};
78
+ var deadline = Date.now() + ${t};
79
79
 
80
80
  function hasSearchResults() {
81
81
  var nextDataEl = document.getElementById('__NEXT_DATA__');
@@ -110,9 +110,9 @@ import{ArgumentError as H}from"@jackwener/opencli/errors";export function normal
110
110
 
111
111
  return hasSearchResults();
112
112
  })()
113
- `);return Boolean(B)}export async function waitForImdbReviewsReady(z,q=15000){const B=await z.evaluate(`
113
+ `);return Boolean(r)}export async function waitForImdbReviewsReady(e,t=15000){const r=await e.evaluate(`
114
114
  (async function() {
115
- var deadline = Date.now() + ${q};
115
+ var deadline = Date.now() + ${t};
116
116
 
117
117
  function hasReviewContent() {
118
118
  if (document.querySelector('article.user-review-item, [data-testid="review-card-parent"], [data-testid="tturv-total-reviews"]')) {
@@ -131,9 +131,9 @@ import{ArgumentError as H}from"@jackwener/opencli/errors";export function normal
131
131
 
132
132
  return hasReviewContent();
133
133
  })()
134
- `);return Boolean(B)}export async function getCurrentImdbId(z,q){const B=await z.evaluate(`
134
+ `);return Boolean(r)}export async function getCurrentImdbId(e,t){const r=await e.evaluate(`
135
135
  (function() {
136
- var pattern = new RegExp('(${q}\\\\d{7,8})', 'i');
136
+ var pattern = new RegExp('(${t}\\\\d{7,8})', 'i');
137
137
  var candidates = [
138
138
  window.location.pathname || '',
139
139
  document.querySelector('link[rel="canonical"]')?.getAttribute('href') || '',
@@ -148,7 +148,7 @@ import{ArgumentError as H}from"@jackwener/opencli/errors";export function normal
148
148
  }
149
149
  return '';
150
150
  })()
151
- `);return typeof B==="string"?B:""}export async function isChallengePage(z){const q=await z.evaluate(`
151
+ `);return typeof r==="string"?r:""}export async function isChallengePage(e){const t=await e.evaluate(`
152
152
  (function() {
153
153
  var title = document.title || '';
154
154
  var body = document.body ? (document.body.textContent || '') : '';
@@ -159,4 +159,4 @@ import{ArgumentError as H}from"@jackwener/opencli/errors";export function normal
159
159
  body.includes('verify that you are human') ||
160
160
  body.includes('not a robot');
161
161
  })()
162
- `);return Boolean(q)}
162
+ `);return Boolean(t)}
@@ -1,6 +1,6 @@
1
- import{CliError as z,CommandExecutionError as T}from"@jackwener/opencli/errors";import{cli as U,Strategy as N}from"@jackwener/opencli/registry";import{publishArticle as P,gotoWritePage as h}from"../_shared/article/publish.js";import{normalizeContent as I}from"../_shared/article/format.js";import{inlineLocalImages as R,isLocalImagePath as x,localImageToDataUri as C}from"../_shared/article/images.js";import{readFile as b,stat as E}from"node:fs/promises";export const imoocProfile={home:"https://www.imooc.com/article",outputFormat:"markdown",checkAuth:async(Q)=>{let G=await(await fetch("https://www.imooc.com/u/card",{credentials:"include"})).text();G=G.replace(/^jsonpcallback\(/,"").replace(/\}\)$/,"}");let V;try{V=JSON.parse(G)}catch(Y){return{isAuthenticated:!1,error:"JSONP 解析失败:"+String(Y&&Y.message||Y)}}if(!V||V.result!==0)return{isAuthenticated:!1,error:V&&V.msg||"未登录"};return{isAuthenticated:!0,userId:String(V.data.uid),username:V.data.nickname,avatar:V.data.img}},image:{uploadFn:async(Q,X)=>{const G=await fetch(Q,{credentials:"omit"});if(!G.ok)throw Error("图片下载失败:HTTP "+G.status);const V=await G.blob(),Y=Date.now()+".jpg",Z=new File([V],Y,{type:V.type||"image/jpeg"}),$=new FormData;$.append("photo",Z,Y);$.append("type",Z.type);$.append("id","WU_FILE_0");$.append("name",Y);$.append("lastModifiedDate",new Date().toString());$.append("size",String(Z.size));const H=await(await fetch("https://www.imooc.com/article/ajaxuploadimg",{method:"POST",credentials:"include",body:$})).json();if(!H||H.result!==0)throw Error(H&&H.msg||"图片上传失败");let K=H.data.imgpath;if(K&&K.indexOf("//")===0)K="https:"+K;return{url:K}},skip:["img.imooc.com","imooc.com"]},publish:async(Q,X)=>{const G=await fetch("https://www.imooc.com/article/savedraft",{method:"POST",credentials:"include",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({editor:"0",draft_id:"0",title:Q.title,content:Q.content})});if(!G.ok){const Z=await G.text();return{ok:!1,stage:"savedraft",status:G.status,message:Z.slice(0,300)}}const V=await G.json();if(!V||!V.data){const Z=JSON.stringify(V).slice(0,300);return{ok:!1,stage:"savedraft",status:G.status,message:"保存草稿失败:"+Z}}const Y=String(V.data);return{ok:!0,id:Y,url:"https://www.imooc.com/article/draft/id/"+Y,draft:!0}}};function k(Q){if(!Q.execute)throw new z("INVALID_INPUT","此命令需要 --execute 才会真正写入。注意:本报错仅表示缺少 --execute,并未校验其余参数,不能当 dry-run 预览用")}async function f(Q){const X=typeof Q.text==="string"?Q.text:void 0,G=typeof Q.file==="string"?Q.file:void 0;if(X&&G)throw new z("INVALID_INPUT","<text> 和 --file 不能同时使用");let V=X??"";if(G){let Y;try{Y=await E(G)}catch{throw new z("INVALID_INPUT","文件不存在:"+G)}if(!Y.isFile())throw new z("INVALID_INPUT","路径必须是可读文本文件:"+G);let Z;try{Z=await b(G)}catch{throw new z("INVALID_INPUT","文件读取失败:"+G)}try{V=new TextDecoder("utf-8",{fatal:!0}).decode(Z)}catch{throw new z("INVALID_INPUT","文件不是有效 UTF-8:"+G)}}if(!V.trim())throw new z("INVALID_INPUT","正文不能为空");return V}function _(Q,X,G,V,Y={}){return[{status:"success",outcome:V,message:Q,target_type:X,target:G,...Y}]}const w="https://www.imooc.com/article/publish",d="https?://www\\.imooc\\.com/article/(\\d+)",n=imoocProfile.image.uploadFn.toString();function c(Q,X){return`(async () => {
2
- const I = `+JSON.stringify(Q)+`;
3
- const __upload = (`+X+`);
1
+ import{CliError as s,CommandExecutionError as g}from"@jackwener/opencli/errors";import{cli as P,Strategy as L}from"@jackwener/opencli/registry";import{publishArticle as N,gotoWritePage as A}from"../_shared/article/publish.js";import{normalizeContent as T}from"../_shared/article/format.js";import{inlineLocalImages as U,isLocalImagePath as C,localImageToDataUri as D}from"../_shared/article/images.js";import{readFile as E,stat as F}from"node:fs/promises";export const imoocProfile={home:"https://www.imooc.com/article",outputFormat:"markdown",checkAuth:async(t)=>{let e=await(await fetch("https://www.imooc.com/u/card",{credentials:"include"})).text();e=e.replace(/^jsonpcallback\(/,"").replace(/\}\)$/,"}");let n;try{n=JSON.parse(e)}catch(o){return{isAuthenticated:!1,error:"JSONP 解析失败:"+String(o&&o.message||o)}}if(!n||n.result!==0)return{isAuthenticated:!1,error:n&&n.msg||"未登录"};return{isAuthenticated:!0,userId:String(n.data.uid),username:n.data.nickname,avatar:n.data.img}},image:{uploadFn:async(t,r)=>{const e=await fetch(t,{credentials:"omit"});if(!e.ok)throw Error("图片下载失败:HTTP "+e.status);const n=await e.blob(),o=Date.now()+".jpg",a=new File([n],o,{type:n.type||"image/jpeg"}),i=new FormData;i.append("photo",a,o);i.append("type",a.type);i.append("id","WU_FILE_0");i.append("name",o);i.append("lastModifiedDate",new Date().toString());i.append("size",String(a.size));const u=await(await fetch("https://www.imooc.com/article/ajaxuploadimg",{method:"POST",credentials:"include",body:i})).json();if(!u||u.result!==0)throw Error(u&&u.msg||"图片上传失败");let d=u.data.imgpath;if(d&&d.indexOf("//")===0)d="https:"+d;return{url:d}},skip:["img.imooc.com","imooc.com"]},publish:async(t,r)=>{const e=await fetch("https://www.imooc.com/article/savedraft",{method:"POST",credentials:"include",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({editor:"0",draft_id:"0",title:t.title,content:t.content})});if(!e.ok){const a=await e.text();return{ok:!1,stage:"savedraft",status:e.status,message:a.slice(0,300)}}const n=await e.json();if(!n||!n.data){const a=JSON.stringify(n).slice(0,300);return{ok:!1,stage:"savedraft",status:e.status,message:"保存草稿失败:"+a}}const o=String(n.data);return{ok:!0,id:o,url:"https://www.imooc.com/article/draft/id/"+o,draft:!0}}};function j(t){if(!t.execute)throw new s("INVALID_INPUT","此命令需要 --execute 才会真正写入。注意:本报错仅表示缺少 --execute,并未校验其余参数,不能当 dry-run 预览用")}async function O(t){const r=typeof t.text==="string"?t.text:void 0,e=typeof t.file==="string"?t.file:void 0;if(r&&e)throw new s("INVALID_INPUT","<text> 和 --file 不能同时使用");let n=r??"";if(e){let o;try{o=await F(e)}catch{throw new s("INVALID_INPUT","文件不存在:"+e)}if(!o.isFile())throw new s("INVALID_INPUT","路径必须是可读文本文件:"+e);let a;try{a=await E(e)}catch{throw new s("INVALID_INPUT","文件读取失败:"+e)}try{n=new TextDecoder("utf-8",{fatal:!0}).decode(a)}catch{throw new s("INVALID_INPUT","文件不是有效 UTF-8:"+e)}}if(!n.trim())throw new s("INVALID_INPUT","正文不能为空");return n}function x(t,r,e,n,o={}){return[{status:"success",outcome:n,message:t,target_type:r,target:e,...o}]}const R="https://www.imooc.com/article/publish",V="https?://www\\.imooc\\.com/article/(\\d+)",q=imoocProfile.image.uploadFn.toString();function M(t,r){return`(async () => {
2
+ const I = `+JSON.stringify(t)+`;
3
+ const __upload = (`+r+`);
4
4
  const PP = {};
5
5
  const sleep = (ms) => new Promise(r => setTimeout(r, ms));
6
6
  var mk = document.querySelector('.js-change-editor[data-type="0"]');
@@ -23,8 +23,8 @@ window.app.setEditorContent(md);
23
23
  await sleep(400);
24
24
  var plen = (window.parsinCtx && window.parsinCtx.text) ? window.parsinCtx.text.length : 0;
25
25
  return { ok: true, uploaded: uploaded, failed: failed, cover: cover, parsinLen: plen };
26
- })()`}function p(Q){return`(async () => {
27
- const I = `+JSON.stringify(Q)+`;
26
+ })()`}function J(t){return`(async () => {
27
+ const I = `+JSON.stringify(t)+`;
28
28
  const sleep = (ms) => new Promise(r => setTimeout(r, ms));
29
29
  var pub = document.querySelector(".js-article-publish");
30
30
  `+`if (!pub) return { ok: false, message: "找不到「发表」按钮" };
@@ -56,4 +56,4 @@ var chosenCount = document.querySelectorAll(".js-chosen-tags .tag-item").length;
56
56
  document.getElementById("save_article").click();
57
57
  await sleep(400);
58
58
  return { ok: true, chosen: chosen, notFound: notFound, column: col.textContent.trim() };
59
- })()`}async function m(Q,X){const{title:G,body:V,format:Y,column:Z,tags:$,original:B,cover:H}=X,K=I(V,{format:Y}),F=await R(K.markdown);let W=F.content;const A=F.missing||[];let J="";if(H){const M=H.trim();if(/["<>\s]/.test(M))throw new T("封面图路径/URL 含非法字符(引号/尖括号/空白):"+M.slice(0,120));if(x(M))try{J=(await C(M)).dataUri}catch(O){throw new T("封面图读取失败:"+M+"("+String(O&&O.message||O)+")")}else J=M}await h(Q,w,imoocProfile.originRe);const q=await Q.evaluate(c({title:G,md:W,cover:J,skip:imoocProfile.image.skip||[]},n));if(!q||q.ok===!1)throw new T("["+(q?.stage||"setup")+"] "+(q?.message||"内容准备失败"));if(!q.parsinLen||q.parsinLen<200)throw new T("正文进入编辑器后不足 200 字(慕课发表要求正文≥200字),当前约 "+(q.parsinLen||0)+" 字。");const j=await Q.evaluate(p({column:String(Z),tags:$,original:B,cover:q.cover}));if(!j||j.ok===!1)throw new T(j?.message||"填写发表信息失败");const v=new RegExp(d);let L="";for(let M=0;M<75;M++){await Q.wait({time:2});let O="";try{O=await Q.getCurrentUrl()}catch{}const y=O&&O.match(v);if(y){L=y[1];break}}const D=q.uploaded||[],S=(q.failed||[]).concat(A);if(!L)throw new T("内容与发表信息已全部填好并进入发表流程,但未检测到发表成功跳转"+"(约 150 秒内未完成点选文字验证码)。请在弹出的慕课浏览器窗口按提示点选文字完成验证,"+"页面会自动跳到文章页即代表发表成功;或稍后重试本命令。");return{id:L,url:"https://www.imooc.com/article/"+L,images:{uploaded:D,failed:S},column:j.column,tags:j.chosen||[],notFoundTags:j.notFound||[]}}U({site:"imooc",name:"article",access:"write",description:"发布慕课手记文章(Markdown)。默认走「发表」(半自动:AI 填全部内容/栏目/标签/封面,"+"最后的点选文字验证码需用户在弹出的浏览器窗口点一下);加 --draft 则只存草稿(无验证码)。外链图自动转存到慕课图床。",domain:"www.imooc.com",strategy:N.COOKIE,browser:!0,args:[{name:"title",positional:!0,required:!0,help:"文章标题(≤80字)"},{name:"text",positional:!0,help:"文章正文(Markdown,默认;发表要求正文≥200字)"},{name:"file",help:"正文文件路径(UTF-8,Markdown)"},{name:"column",help:"栏目(发表必填):名称或 data-columnid,如「后端开发」/120、「前端开发」/119、「人工智能」/117"},{name:"tags",help:"标签(发表必填,逗号分隔,至少 1 个):名称或 data-tag,如 MySQL,Java 或 11,3"},{name:"cover",help:"封面图 URL 或本机路径(发表可选,缺省用慕课随机封面)"},{name:"original",help:"文章类型(发表可选,默认「原创」):原创 / 首发 / 转载"},{name:"html",type:"boolean",help:"将正文视为原始 HTML 而非 Markdown"},{name:"draft",type:"boolean",help:"只存草稿(不发表,无需验证码)"},{name:"execute",type:"boolean",help:"真正执行写入,不加此标志时拒绝写操作"}],columns:["status","outcome","message","target_type","target","created_target","created_url"],func:async(Q,X)=>{if(!Q)throw new T("慕课手记发布需要浏览器会话");k(X);const G=String(X.title??"").trim();if(!G)throw new z("INVALID_INPUT","文章标题不能为空");if(G.length>80)throw new z("INVALID_INPUT","标题不能超过 80 字,当前 "+G.length+" 字");const V=await f(X);if(X.draft){const W=await P(Q,{title:G,body:V,format:X.html?"html":"markdown",draftOnly:!0,profile:imoocProfile}),A=W.images.uploaded.length|0,J=W.images.failed.length|0;let q="已保存慕课手记草稿";if(A||J)q+=`・图片:${A} 张已转存${J?`,${J} 张失败`:""}`;return _(q,"article","","draft",{created_target:"article:"+W.id,created_url:W.url})}const Y=String(X.column??"").trim();if(!Y)throw new z("INVALID_INPUT","发表必填 --column(栏目)。可选:前端开发/后端开发/人工智能/对话ChatGPT/移动开发/云计算大数据/产品设计/工具资源/职场生活/经验分享/其它。"+"只想存草稿加 --draft。");const Z=String(X.tags??"").split(",").map((W)=>W.trim()).filter(Boolean);if(Z.length===0)throw new z("INVALID_INPUT","发表必填 --tags(标签,逗号分隔,至少 1 个),如 --tags MySQL,Java。只想存草稿加 --draft。");const $=String(X.original??"原创").trim()||"原创";if(!["原创","首发","转载","其他"].includes($))throw new z("INVALID_INPUT","--original 只能是 原创 / 首发 / 转载,当前:"+$);const B=await m(Q,{title:G,body:V,format:X.html?"html":"markdown",column:Y,tags:Z,original:$,cover:typeof X.cover==="string"?X.cover:""}),H=B.images.uploaded.length|0,K=B.images.failed.length|0;let F=`已发表慕课手记・栏目「${B.column}」・标签 ${B.tags.join("/")}`;if(H||K)F+=`・图片:${H} 张已转存${K?`,${K} 张失败`:""}`;if(B.notFoundTags.length)F+=`・未匹配标签:${B.notFoundTags.join(",")}`;return _(F,"article","","published",{created_target:"article:"+B.id,created_url:B.url})}});
59
+ })()`}async function B(t,r){const{title:e,body:n,format:o,column:a,tags:i,original:c,cover:u}=r,d=T(n,{format:o}),h=await U(d.markdown);let p=h.content;const I=h.missing||[];let f="";if(u){const m=u.trim();if(/["<>\s]/.test(m))throw new g("封面图路径/URL 含非法字符(引号/尖括号/空白):"+m.slice(0,120));if(C(m))try{f=(await D(m)).dataUri}catch(w){throw new g("封面图读取失败:"+m+"("+String(w&&w.message||w)+")")}else f=m}await A(t,R,imoocProfile.originRe);const l=await t.evaluate(M({title:e,md:p,cover:f,skip:imoocProfile.image.skip||[]},q));if(!l||l.ok===!1)throw new g("["+(l?.stage||"setup")+"] "+(l?.message||"内容准备失败"));if(!l.parsinLen||l.parsinLen<200)throw new g("正文进入编辑器后不足 200 字(慕课发表要求正文≥200字),当前约 "+(l.parsinLen||0)+" 字。");const y=await t.evaluate(J({column:String(a),tags:i,original:c,cover:l.cover}));if(!y||y.ok===!1)throw new g(y?.message||"填写发表信息失败");const b=new RegExp(V);let v="";for(let m=0;m<75;m++){await t.wait({time:2});let w="";try{w=await t.getCurrentUrl()}catch{}const S=w&&w.match(b);if(S){v=S[1];break}}const k=l.uploaded||[],_=(l.failed||[]).concat(I);if(!v)throw new g("内容与发表信息已全部填好并进入发表流程,但未检测到发表成功跳转"+"(约 150 秒内未完成点选文字验证码)。请在弹出的慕课浏览器窗口按提示点选文字完成验证,"+"页面会自动跳到文章页即代表发表成功;或稍后重试本命令。");return{id:v,url:"https://www.imooc.com/article/"+v,images:{uploaded:k,failed:_},column:y.column,tags:y.chosen||[],notFoundTags:y.notFound||[]}}P({site:"imooc",name:"article",access:"write",description:"发布慕课手记文章(Markdown)。默认走「发表」(半自动:AI 填全部内容/栏目/标签/封面,"+"最后的点选文字验证码需用户在弹出的浏览器窗口点一下);加 --draft 则只存草稿(无验证码)。外链图自动转存到慕课图床。",domain:"www.imooc.com",strategy:L.COOKIE,browser:!0,args:[{name:"title",positional:!0,required:!0,help:"文章标题(≤80字)"},{name:"text",positional:!0,help:"文章正文(Markdown,默认;发表要求正文≥200字)"},{name:"file",help:"正文文件路径(UTF-8,Markdown)"},{name:"column",help:"栏目(发表必填):名称或 data-columnid,如「后端开发」/120、「前端开发」/119、「人工智能」/117"},{name:"tags",help:"标签(发表必填,逗号分隔,至少 1 个):名称或 data-tag,如 MySQL,Java 或 11,3"},{name:"cover",help:"封面图 URL 或本机路径(发表可选,缺省用慕课随机封面)"},{name:"original",help:"文章类型(发表可选,默认「原创」):原创 / 首发 / 转载"},{name:"html",type:"boolean",help:"将正文视为原始 HTML 而非 Markdown"},{name:"draft",type:"boolean",help:"只存草稿(不发表,无需验证码)"},{name:"execute",type:"boolean",help:"真正执行写入,不加此标志时拒绝写操作"}],columns:["status","outcome","message","target_type","target","created_target","created_url"],func:async(t,r)=>{if(!t)throw new g("慕课手记发布需要浏览器会话");j(r);const e=String(r.title??"").trim();if(!e)throw new s("INVALID_INPUT","文章标题不能为空");if(e.length>80)throw new s("INVALID_INPUT","标题不能超过 80 字,当前 "+e.length+" 字");const n=await O(r);if(r.draft){const p=await N(t,{title:e,body:n,format:r.html?"html":"markdown",draftOnly:!0,profile:imoocProfile}),I=p.images.uploaded.length|0,f=p.images.failed.length|0;let l="已保存慕课手记草稿";if(I||f)l+=`・图片:${I} 张已转存${f?`,${f} 张失败`:""}`;return x(l,"article","","draft",{created_target:"article:"+p.id,created_url:p.url})}const o=String(r.column??"").trim();if(!o)throw new s("INVALID_INPUT","发表必填 --column(栏目)。可选:前端开发/后端开发/人工智能/对话ChatGPT/移动开发/云计算大数据/产品设计/工具资源/职场生活/经验分享/其它。"+"只想存草稿加 --draft。");const a=String(r.tags??"").split(",").map((p)=>p.trim()).filter(Boolean);if(a.length===0)throw new s("INVALID_INPUT","发表必填 --tags(标签,逗号分隔,至少 1 个),如 --tags MySQL,Java。只想存草稿加 --draft。");const i=String(r.original??"原创").trim()||"原创";if(!["原创","首发","转载","其他"].includes(i))throw new s("INVALID_INPUT","--original 只能是 原创 / 首发 / 转载,当前:"+i);const c=await B(t,{title:e,body:n,format:r.html?"html":"markdown",column:o,tags:a,original:i,cover:typeof r.cover==="string"?r.cover:""}),u=c.images.uploaded.length|0,d=c.images.failed.length|0;let h=`已发表慕课手记・栏目「${c.column}」・标签 ${c.tags.join("/")}`;if(u||d)h+=`・图片:${u} 张已转存${d?`,${d} 张失败`:""}`;if(c.notFoundTags.length)h+=`・未匹配标签:${c.notFoundTags.join(",")}`;return x(h,"article","","published",{created_target:"article:"+c.id,created_url:c.url})}});
@@ -1 +1 @@
1
- import{registerArticleLogin as k}from"../_shared/article/login.js";import{imoocProfile as b}from"./article.js";k({site:"imooc",domain:"imooc.com",profile:{home:b.home,checkAuth:b.checkAuth},loginDescription:"打开慕课网登录页并等待浏览器完成登录(供桌面客户端引导登录)。"});
1
+ import{registerArticleLogin as i}from"../_shared/article/login.js";import{imoocProfile as o}from"./article.js";i({site:"imooc",domain:"imooc.com",profile:{home:o.home,checkAuth:o.checkAuth},loginDescription:"打开慕课网登录页并等待浏览器完成登录(供桌面客户端引导登录)。"});
@@ -1 +1 @@
1
- import{cli as x,Strategy as z}from"@jackwener/opencli/registry";import{checkLogin as A,cookieQuickCheck as B}from"../_shared/article/auth.js";import{imoocProfile as q}from"./article.js";const D={home:q.home,checkAuth:q.checkAuth};x({site:"imooc",name:"whoami",access:"read",description:"查询当前在 Chrome 里登录的慕课网账号。",domain:"www.imooc.com",strategy:z.COOKIE,browser:!0,columns:["logged_in","user_id","username"],authStatus:{quickCheck:B("https://www.imooc.com",["apsid"])},func:async(v)=>{const b=await A(v,D);return[{logged_in:b.isAuthenticated,user_id:b.userId||"",username:b.username||""}]}});
1
+ import{cli as i,Strategy as r}from"@jackwener/opencli/registry";import{checkLogin as t,cookieQuickCheck as m}from"../_shared/article/auth.js";import{imoocProfile as o}from"./article.js";const s={home:o.home,checkAuth:o.checkAuth};i({site:"imooc",name:"whoami",access:"read",description:"查询当前在 Chrome 里登录的慕课网账号。",domain:"www.imooc.com",strategy:r.COOKIE,browser:!0,columns:["logged_in","user_id","username"],authStatus:{quickCheck:m("https://www.imooc.com",["apsid"])},func:async(c)=>{const e=await t(c,s);return[{logged_in:e.isAuthenticated,user_id:e.userId||"",username:e.username||""}]}});
@@ -1,4 +1,4 @@
1
- import{cli as d,Strategy as c}from"@jackwener/opencli/registry";import{EmptyResultError as s,CommandExecutionError as a}from"@jackwener/opencli/errors";import{JOB_COLUMNS as l,requireJobKey as m,buildJobUrl as y}from"./utils.js";d({site:"indeed",name:"job",aliases:["detail","view"],access:"read",description:"Read the full Indeed job posting by jk (job key)",domain:"www.indeed.com",strategy:c.COOKIE,browser:!0,navigateBefore:!1,args:[{name:"id",positional:!0,required:!0,help:'Job key (16-char hex from `indeed search`, e.g. "dccc07ac5a6a3683")'}],columns:l,func:async(t,i)=>{const o=m(i.id),r=y(o);await t.goto(r);await t.wait(4);let e;try{e=await t.evaluate(`(async () => {
1
+ import{cli as d,Strategy as c}from"@jackwener/opencli/registry";import{EmptyResultError as l,CommandExecutionError as r}from"@jackwener/opencli/errors";import{JOB_COLUMNS as s,requireJobKey as m,buildJobUrl as y}from"./utils.js";d({site:"indeed",name:"job",aliases:["detail","view"],access:"read",description:"Read the full Indeed job posting by jk (job key)",domain:"www.indeed.com",strategy:c.COOKIE,browser:!0,navigateBefore:!1,args:[{name:"id",positional:!0,required:!0,help:'Job key (16-char hex from `indeed search`, e.g. "dccc07ac5a6a3683")'}],columns:s,func:async(t,i)=>{const o=m(i.id),a=y(o);await t.goto(a);await t.wait(4);let e;try{e=await t.evaluate(`(async () => {
2
2
  let ready = !!document.querySelector('#jobDescriptionText, h1, [data-testid="error-page"]');
3
3
  for (let i = 0; i < 30; i++) {
4
4
  if (ready) break;
@@ -17,4 +17,4 @@ import{cli as d,Strategy as c}from"@jackwener/opencli/registry";import{EmptyResu
17
17
  .join(', ');
18
18
  const description = document.querySelector('#jobDescriptionText')?.innerText?.trim() ?? '';
19
19
  return { ready, challenge, notFound, title, company, location, salary, jobType, description };
20
- })()`)}catch(n){throw new a(`Failed to scrape Indeed job detail DOM: ${n?.message??n}`,"The page may not have fully loaded; try again.")}if(e?.challenge)throw new a("Indeed served a Cloudflare challenge page","Open https://www.indeed.com in the connected browser and clear the challenge, then retry.");if(!e?.ready)throw new a("Indeed job page did not expose detail or error markers within 15s","Indeed may still be loading or the DOM shape may have changed; retry after opening Indeed in the connected browser.");if(e?.notFound||!e?.title&&!e?.description)throw new s("indeed job",`No Indeed job posting found for jk "${o}"`);return[{id:o,title:e.title.replace(/\s+/g," ").trim(),company:e.company.replace(/\s+/g," ").trim(),location:e.location.replace(/\s+/g," ").trim(),salary:e.salary.replace(/\s+/g," ").trim(),job_type:e.jobType.replace(/\s+/g," ").trim(),description:e.description,url:r}]}});
20
+ })()`)}catch(n){throw new r(`Failed to scrape Indeed job detail DOM: ${n?.message??n}`,"The page may not have fully loaded; try again.")}if(e?.challenge)throw new r("Indeed served a Cloudflare challenge page","Open https://www.indeed.com in the connected browser and clear the challenge, then retry.");if(!e?.ready)throw new r("Indeed job page did not expose detail or error markers within 15s","Indeed may still be loading or the DOM shape may have changed; retry after opening Indeed in the connected browser.");if(e?.notFound||!e?.title&&!e?.description)throw new l("indeed job",`No Indeed job posting found for jk "${o}"`);return[{id:o,title:e.title.replace(/\s+/g," ").trim(),company:e.company.replace(/\s+/g," ").trim(),location:e.location.replace(/\s+/g," ").trim(),salary:e.salary.replace(/\s+/g," ").trim(),job_type:e.jobType.replace(/\s+/g," ").trim(),description:e.description,url:a}]}});
@@ -1,4 +1,4 @@
1
- import{cli as y,Strategy as p}from"@jackwener/opencli/registry";import{EmptyResultError as b,CommandExecutionError as o}from"@jackwener/opencli/errors";import{SEARCH_COLUMNS as f,requireQuery as g,requireBoundedInt as w,requireNonNegativeInt as S,requireFromage as q,requireSort as j,buildSearchUrl as C,searchCardToRow as k}from"./utils.js";y({site:"indeed",name:"search",access:"read",description:"Indeed keyword job search (rendered DOM via browser session, US site)",domain:"www.indeed.com",strategy:p.COOKIE,browser:!0,navigateBefore:!1,args:[{name:"query",positional:!0,required:!0,help:"Job keyword (title / skill / company)"},{name:"location",type:"string",default:"",help:'Location filter (e.g. "remote", "New York, NY", "San Francisco")'},{name:"fromage",type:"string",default:"",help:"Recency filter, days back: 1 / 3 / 7 / 14"},{name:"sort",type:"string",default:"relevance",help:"Sort order: relevance | date"},{name:"start",type:"int",default:0,help:"Pagination offset (multiple of 10, 0-based)"},{name:"limit",type:"int",default:15,help:"Max rows to return (1-25, capped at one page)"}],columns:f,func:async(r,e)=>{const s=g(e.query),n=String(e.location??"").trim(),l=q(e.fromage),d=j(e.sort),i=S(e.start,0,"start"),u=w(e.limit,15,25,"limit"),m=C({query:s,location:n,fromage:l,sort:d,start:i});await r.goto(m);await r.wait(4);let t;try{t=await r.evaluate(`(async () => {
1
+ import{cli as h,Strategy as p}from"@jackwener/opencli/registry";import{EmptyResultError as b,CommandExecutionError as n}from"@jackwener/opencli/errors";import{SEARCH_COLUMNS as f,requireQuery as g,requireBoundedInt as w,requireNonNegativeInt as S,requireFromage as q,requireSort as j,buildSearchUrl as C,searchCardToRow as k}from"./utils.js";h({site:"indeed",name:"search",access:"read",description:"Indeed keyword job search (rendered DOM via browser session, US site)",domain:"www.indeed.com",strategy:p.COOKIE,browser:!0,navigateBefore:!1,args:[{name:"query",positional:!0,required:!0,help:"Job keyword (title / skill / company)"},{name:"location",type:"string",default:"",help:'Location filter (e.g. "remote", "New York, NY", "San Francisco")'},{name:"fromage",type:"string",default:"",help:"Recency filter, days back: 1 / 3 / 7 / 14"},{name:"sort",type:"string",default:"relevance",help:"Sort order: relevance | date"},{name:"start",type:"int",default:0,help:"Pagination offset (multiple of 10, 0-based)"},{name:"limit",type:"int",default:15,help:"Max rows to return (1-25, capped at one page)"}],columns:f,func:async(r,e)=>{const s=g(e.query),o=String(e.location??"").trim(),l=q(e.fromage),d=j(e.sort),i=S(e.start,0,"start"),u=w(e.limit,15,25,"limit"),m=C({query:s,location:o,fromage:l,sort:d,start:i});await r.goto(m);await r.wait(4);let t;try{t=await r.evaluate(`(async () => {
2
2
  const hasResults = () => !!document.querySelector('.job_seen_beacon');
3
3
  const hasEmptyState = () => {
4
4
  const text = document.body?.innerText || '';
@@ -34,4 +34,4 @@ import{cli as y,Strategy as p}from"@jackwener/opencli/registry";import{EmptyResu
34
34
  const blockedHeadline = document.title || '';
35
35
  const challenge = blockedHeadline.includes('Just a moment') || !!document.querySelector('[id^="cf-"]');
36
36
  return { cards: out, challenge, ready };
37
- })()`)}catch(a){throw new o(`Failed to scrape Indeed search DOM: ${a?.message??a}`,"The page may not have fully loaded; try again.")}if(t?.challenge)throw new o("Indeed served a Cloudflare challenge page","Open https://www.indeed.com in the connected browser and clear the challenge, then retry.");if(!t?.ready)throw new o("Indeed search page did not expose result or empty-state markers within 15s","Indeed may still be loading or the DOM shape may have changed; retry after opening Indeed in the connected browser.");const c=Array.isArray(t?.cards)?t.cards:[];if(c.length===0)throw new b("indeed search",`No Indeed jobs matched "${s}"${n?` in ${n}`:""}`);return c.slice(0,u).map((a,h)=>k(a,i+h+1))}});
37
+ })()`)}catch(a){throw new n(`Failed to scrape Indeed search DOM: ${a?.message??a}`,"The page may not have fully loaded; try again.")}if(t?.challenge)throw new n("Indeed served a Cloudflare challenge page","Open https://www.indeed.com in the connected browser and clear the challenge, then retry.");if(!t?.ready)throw new n("Indeed search page did not expose result or empty-state markers within 15s","Indeed may still be loading or the DOM shape may have changed; retry after opening Indeed in the connected browser.");const c=Array.isArray(t?.cards)?t.cards:[];if(c.length===0)throw new b("indeed search",`No Indeed jobs matched "${s}"${o?` in ${o}`:""}`);return c.slice(0,u).map((a,y)=>k(a,i+y+1))}});
@@ -1 +1 @@
1
- import{ArgumentError as $}from"@jackwener/opencli/errors";export const INDEED_ORIGIN="https://www.indeed.com";const z=/^[a-f0-9]{16}$/,F=new Set(["1","3","7","14"]),H=new Set(["relevance","date"]);export function coerceInt(B){if(B===void 0||B===null||B==="")return NaN;const Q=typeof B==="number"?B:Number(B);return Number.isFinite(Q)&&Number.isInteger(Q)?Q:NaN}export function requireBoundedInt(B,Q,W,Y){const Z=coerceInt(B??Q);if(!Number.isInteger(Z)||Z<=0)throw new $(`indeed ${Y} must be a positive integer`);if(Z>W)throw new $(`indeed ${Y} must be <= ${W}`);return Z}export function requireNonNegativeInt(B,Q,W){const X=coerceInt(B??Q);if(!Number.isInteger(X)||X<0)throw new $(`indeed ${W} must be a non-negative integer`);return X}export function requireJobKey(B){const Q=String(B??"").trim().toLowerCase();if(!Q)throw new $("indeed job id is required");if(!z.test(Q))throw new $(`indeed job id "${B}" is not a valid jk (expected 16-char lowercase hex)`);return Q}export function requireQuery(B,Q="query"){const W=String(B??"").trim();if(!W)throw new $(`indeed ${Q} cannot be empty`);return W}export function requireFromage(B){if(B===void 0||B===null||B==="")return"";const Q=String(B).trim();if(!F.has(Q))throw new $(`indeed fromage must be one of 1/3/7/14 (days), got "${B}"`);return Q}export function requireSort(B,Q="relevance"){const W=String(B??Q).trim().toLowerCase();if(!H.has(W))throw new $(`indeed sort must be "relevance" or "date", got "${B}"`);return W}export function buildSearchUrl({query:B,location:Q,fromage:W,sort:Y,start:X}){const Z=new URLSearchParams;Z.set("q",B);if(Q)Z.set("l",Q);if(W)Z.set("fromage",W);if(Y&&Y!=="relevance")Z.set("sort",Y);if(X&&X>0)Z.set("start",String(X));return`${INDEED_ORIGIN}/jobs?${Z.toString()}`}export function buildJobUrl(B){return`${INDEED_ORIGIN}/viewjob?jk=${B}`}export function dedupeTags(B,Q){const W=[];for(const Y of B){const X=String(Y||"").trim();if(!X)continue;if(Q&&X===Q)continue;if(W.includes(X))continue;W.push(X)}return W.join(" · ")}export function searchCardToRow(B,Q){const W=String(B?.jk??"").trim(),Y=String(B?.salary??"").trim(),X=Array.isArray(B?.tags)?B.tags:[];return{rank:Q,id:W,title:String(B?.title??"").replace(/\s+/g," ").trim(),company:String(B?.company??"").replace(/\s+/g," ").trim(),location:String(B?.location??"").replace(/\s+/g," ").trim(),salary:Y,tags:dedupeTags(X,Y),url:W?buildJobUrl(W):""}}export const SEARCH_COLUMNS=["rank","id","title","company","location","salary","tags","url"],JOB_COLUMNS=["id","title","company","location","salary","job_type","description","url"];
1
+ import{ArgumentError as s}from"@jackwener/opencli/errors";export const INDEED_ORIGIN="https://www.indeed.com";const c=/^[a-f0-9]{16}$/,u=new Set(["1","3","7","14"]),a=new Set(["relevance","date"]);export function coerceInt(e){if(e===void 0||e===null||e==="")return NaN;const t=typeof e==="number"?e:Number(e);return Number.isFinite(t)&&Number.isInteger(t)?t:NaN}export function requireBoundedInt(e,t,n,i){const o=coerceInt(e??t);if(!Number.isInteger(o)||o<=0)throw new s(`indeed ${i} must be a positive integer`);if(o>n)throw new s(`indeed ${i} must be <= ${n}`);return o}export function requireNonNegativeInt(e,t,n){const r=coerceInt(e??t);if(!Number.isInteger(r)||r<0)throw new s(`indeed ${n} must be a non-negative integer`);return r}export function requireJobKey(e){const t=String(e??"").trim().toLowerCase();if(!t)throw new s("indeed job id is required");if(!c.test(t))throw new s(`indeed job id "${e}" is not a valid jk (expected 16-char lowercase hex)`);return t}export function requireQuery(e,t="query"){const n=String(e??"").trim();if(!n)throw new s(`indeed ${t} cannot be empty`);return n}export function requireFromage(e){if(e===void 0||e===null||e==="")return"";const t=String(e).trim();if(!u.has(t))throw new s(`indeed fromage must be one of 1/3/7/14 (days), got "${e}"`);return t}export function requireSort(e,t="relevance"){const n=String(e??t).trim().toLowerCase();if(!a.has(n))throw new s(`indeed sort must be "relevance" or "date", got "${e}"`);return n}export function buildSearchUrl({query:e,location:t,fromage:n,sort:i,start:r}){const o=new URLSearchParams;o.set("q",e);if(t)o.set("l",t);if(n)o.set("fromage",n);if(i&&i!=="relevance")o.set("sort",i);if(r&&r>0)o.set("start",String(r));return`${INDEED_ORIGIN}/jobs?${o.toString()}`}export function buildJobUrl(e){return`${INDEED_ORIGIN}/viewjob?jk=${e}`}export function dedupeTags(e,t){const n=[];for(const i of e){const r=String(i||"").trim();if(!r)continue;if(t&&r===t)continue;if(n.includes(r))continue;n.push(r)}return n.join(" · ")}export function searchCardToRow(e,t){const n=String(e?.jk??"").trim(),i=String(e?.salary??"").trim(),r=Array.isArray(e?.tags)?e.tags:[];return{rank:t,id:n,title:String(e?.title??"").replace(/\s+/g," ").trim(),company:String(e?.company??"").replace(/\s+/g," ").trim(),location:String(e?.location??"").replace(/\s+/g," ").trim(),salary:i,tags:dedupeTags(r,i),url:n?buildJobUrl(n):""}}export const SEARCH_COLUMNS=["rank","id","title","company","location","salary","tags","url"],JOB_COLUMNS=["id","title","company","location","salary","job_type","description","url"];