publishport-opencli 1.8.4-pp.1

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 (2171) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +300 -0
  3. package/README.zh-CN.md +341 -0
  4. package/cli-manifest.json +44212 -0
  5. package/clis/12306/auth.js +59 -0
  6. package/clis/12306/me.js +73 -0
  7. package/clis/12306/orders.js +96 -0
  8. package/clis/12306/passengers.js +90 -0
  9. package/clis/12306/price.js +166 -0
  10. package/clis/12306/stations.js +66 -0
  11. package/clis/12306/train.js +91 -0
  12. package/clis/12306/trains.js +166 -0
  13. package/clis/12306/utils.js +272 -0
  14. package/clis/12306/utils.test.js +424 -0
  15. package/clis/1688/assets.js +205 -0
  16. package/clis/1688/assets.test.js +39 -0
  17. package/clis/1688/auth.js +46 -0
  18. package/clis/1688/download.js +77 -0
  19. package/clis/1688/download.test.js +31 -0
  20. package/clis/1688/item.js +188 -0
  21. package/clis/1688/item.test.js +67 -0
  22. package/clis/1688/search.js +310 -0
  23. package/clis/1688/search.test.js +75 -0
  24. package/clis/1688/shared.js +557 -0
  25. package/clis/1688/shared.test.js +57 -0
  26. package/clis/1688/store.js +227 -0
  27. package/clis/1688/store.test.js +62 -0
  28. package/clis/1point3acres/auth.js +52 -0
  29. package/clis/1point3acres/digest.js +35 -0
  30. package/clis/1point3acres/forum.js +51 -0
  31. package/clis/1point3acres/forums.js +44 -0
  32. package/clis/1point3acres/hot.js +35 -0
  33. package/clis/1point3acres/latest.js +35 -0
  34. package/clis/1point3acres/notifications.js +64 -0
  35. package/clis/1point3acres/search.js +71 -0
  36. package/clis/1point3acres/thread.js +117 -0
  37. package/clis/1point3acres/user.js +77 -0
  38. package/clis/1point3acres/utils.js +247 -0
  39. package/clis/36kr/article.js +66 -0
  40. package/clis/36kr/article.test.js +46 -0
  41. package/clis/36kr/hot.js +87 -0
  42. package/clis/36kr/hot.test.js +15 -0
  43. package/clis/36kr/news.js +52 -0
  44. package/clis/36kr/news.test.js +85 -0
  45. package/clis/36kr/search.js +79 -0
  46. package/clis/51job/company.js +126 -0
  47. package/clis/51job/detail.js +109 -0
  48. package/clis/51job/hot.js +56 -0
  49. package/clis/51job/search.js +80 -0
  50. package/clis/51job/utils.js +302 -0
  51. package/clis/51job/utils.test.js +69 -0
  52. package/clis/_atlassian/shared.js +577 -0
  53. package/clis/_atlassian/shared.test.js +170 -0
  54. package/clis/_shared/common.js +32 -0
  55. package/clis/_shared/desktop-commands.js +112 -0
  56. package/clis/_shared/search-adapter.js +70 -0
  57. package/clis/_shared/site-auth.js +118 -0
  58. package/clis/_shared/site-auth.test.js +98 -0
  59. package/clis/aibase/news.js +110 -0
  60. package/clis/aibase/news.test.js +59 -0
  61. package/clis/amazon/auth.js +53 -0
  62. package/clis/amazon/bestsellers.js +8 -0
  63. package/clis/amazon/bestsellers.test.js +29 -0
  64. package/clis/amazon/discussion.js +123 -0
  65. package/clis/amazon/discussion.test.js +124 -0
  66. package/clis/amazon/movers-shakers.js +8 -0
  67. package/clis/amazon/new-releases.js +8 -0
  68. package/clis/amazon/offer.js +141 -0
  69. package/clis/amazon/offer.test.js +29 -0
  70. package/clis/amazon/product.js +93 -0
  71. package/clis/amazon/product.test.js +24 -0
  72. package/clis/amazon/rankings.js +227 -0
  73. package/clis/amazon/rankings.test.js +41 -0
  74. package/clis/amazon/search.js +88 -0
  75. package/clis/amazon/search.test.js +22 -0
  76. package/clis/amazon/shared.js +365 -0
  77. package/clis/amazon/shared.test.js +44 -0
  78. package/clis/antigravity/SKILL.md +38 -0
  79. package/clis/antigravity/_actions.js +318 -0
  80. package/clis/antigravity/antigravity.test.js +172 -0
  81. package/clis/antigravity/audit-extras.js +341 -0
  82. package/clis/antigravity/delete.js +60 -0
  83. package/clis/antigravity/dump.js +29 -0
  84. package/clis/antigravity/extract-code.js +33 -0
  85. package/clis/antigravity/history.js +26 -0
  86. package/clis/antigravity/mark-read.js +52 -0
  87. package/clis/antigravity/model.js +161 -0
  88. package/clis/antigravity/new.js +26 -0
  89. package/clis/antigravity/read.js +35 -0
  90. package/clis/antigravity/rename.js +33 -0
  91. package/clis/antigravity/send.js +36 -0
  92. package/clis/antigravity/serve.js +558 -0
  93. package/clis/antigravity/status.js +19 -0
  94. package/clis/antigravity/storage.js +366 -0
  95. package/clis/antigravity/watch.js +43 -0
  96. package/clis/apple-podcasts/commands.test.js +119 -0
  97. package/clis/apple-podcasts/episodes.js +29 -0
  98. package/clis/apple-podcasts/search.js +31 -0
  99. package/clis/apple-podcasts/top.js +45 -0
  100. package/clis/apple-podcasts/utils.js +30 -0
  101. package/clis/apple-podcasts/utils.test.js +57 -0
  102. package/clis/archive/archive.test.js +262 -0
  103. package/clis/archive/item.js +92 -0
  104. package/clis/archive/search.js +115 -0
  105. package/clis/archive/snapshots.js +129 -0
  106. package/clis/archive/wayback.js +83 -0
  107. package/clis/arxiv/arxiv.test.js +112 -0
  108. package/clis/arxiv/author.js +44 -0
  109. package/clis/arxiv/paper.js +22 -0
  110. package/clis/arxiv/recent.js +33 -0
  111. package/clis/arxiv/search.js +36 -0
  112. package/clis/arxiv/utils.js +112 -0
  113. package/clis/autohome/__fixtures__/catalog.html +11 -0
  114. package/clis/autohome/__fixtures__/koubei.json +116 -0
  115. package/clis/autohome/autohome.test.js +115 -0
  116. package/clis/autohome/brand.js +108 -0
  117. package/clis/autohome/score.js +103 -0
  118. package/clis/autohome/utils.js +157 -0
  119. package/clis/baidu-scholar/search.js +87 -0
  120. package/clis/baidu-scholar/search.test.js +23 -0
  121. package/clis/band/auth.js +62 -0
  122. package/clis/band/bands.js +73 -0
  123. package/clis/band/mentions.js +128 -0
  124. package/clis/band/post.js +176 -0
  125. package/clis/band/posts.js +95 -0
  126. package/clis/barchart/flow.js +116 -0
  127. package/clis/barchart/greeks.js +208 -0
  128. package/clis/barchart/greeks.test.js +138 -0
  129. package/clis/barchart/options.js +107 -0
  130. package/clis/barchart/quote.js +135 -0
  131. package/clis/bbc/news.js +42 -0
  132. package/clis/bbc/topic.js +57 -0
  133. package/clis/bbc/utils.js +79 -0
  134. package/clis/bilibili/auth.js +36 -0
  135. package/clis/bilibili/comment.js +107 -0
  136. package/clis/bilibili/comment.test.js +153 -0
  137. package/clis/bilibili/comments.js +136 -0
  138. package/clis/bilibili/comments.test.js +142 -0
  139. package/clis/bilibili/download.js +178 -0
  140. package/clis/bilibili/download.test.js +173 -0
  141. package/clis/bilibili/dynamic.js +34 -0
  142. package/clis/bilibili/dynamic.test.js +68 -0
  143. package/clis/bilibili/favorite.js +47 -0
  144. package/clis/bilibili/feed.js +220 -0
  145. package/clis/bilibili/follow.js +140 -0
  146. package/clis/bilibili/follow.test.js +203 -0
  147. package/clis/bilibili/following.js +44 -0
  148. package/clis/bilibili/history.js +45 -0
  149. package/clis/bilibili/hot.js +40 -0
  150. package/clis/bilibili/hot.test.js +17 -0
  151. package/clis/bilibili/me.js +13 -0
  152. package/clis/bilibili/ranking.js +25 -0
  153. package/clis/bilibili/search.js +24 -0
  154. package/clis/bilibili/subtitle.js +141 -0
  155. package/clis/bilibili/subtitle.test.js +240 -0
  156. package/clis/bilibili/summary.js +167 -0
  157. package/clis/bilibili/summary.test.js +210 -0
  158. package/clis/bilibili/unfollow.js +121 -0
  159. package/clis/bilibili/user-videos.js +39 -0
  160. package/clis/bilibili/utils.js +273 -0
  161. package/clis/bilibili/utils.test.js +97 -0
  162. package/clis/bilibili/video.js +155 -0
  163. package/clis/bilibili/video.test.js +308 -0
  164. package/clis/binance/asks.js +22 -0
  165. package/clis/binance/commands.test.js +70 -0
  166. package/clis/binance/depth.js +21 -0
  167. package/clis/binance/gainers.js +23 -0
  168. package/clis/binance/klines.js +22 -0
  169. package/clis/binance/losers.js +23 -0
  170. package/clis/binance/pairs.js +22 -0
  171. package/clis/binance/price.js +19 -0
  172. package/clis/binance/prices.js +20 -0
  173. package/clis/binance/ticker.js +22 -0
  174. package/clis/binance/top.js +22 -0
  175. package/clis/binance/trades.js +21 -0
  176. package/clis/bloomberg/businessweek.js +125 -0
  177. package/clis/bloomberg/businessweek.test.js +149 -0
  178. package/clis/bloomberg/crypto.js +18 -0
  179. package/clis/bloomberg/economics.js +18 -0
  180. package/clis/bloomberg/feeds.js +16 -0
  181. package/clis/bloomberg/green.js +18 -0
  182. package/clis/bloomberg/industries.js +18 -0
  183. package/clis/bloomberg/main.js +18 -0
  184. package/clis/bloomberg/markets.js +18 -0
  185. package/clis/bloomberg/news.js +106 -0
  186. package/clis/bloomberg/opinions.js +18 -0
  187. package/clis/bloomberg/politics.js +18 -0
  188. package/clis/bloomberg/pursuits.js +18 -0
  189. package/clis/bloomberg/tech.js +18 -0
  190. package/clis/bloomberg/utils.js +380 -0
  191. package/clis/bloomberg/utils.test.js +129 -0
  192. package/clis/bluesky/feeds.js +28 -0
  193. package/clis/bluesky/followers.js +28 -0
  194. package/clis/bluesky/following.js +28 -0
  195. package/clis/bluesky/profile.js +30 -0
  196. package/clis/bluesky/search.js +29 -0
  197. package/clis/bluesky/starter-packs.js +29 -0
  198. package/clis/bluesky/thread.js +31 -0
  199. package/clis/bluesky/trending.js +20 -0
  200. package/clis/bluesky/user.js +35 -0
  201. package/clis/booking/booking.test.js +356 -0
  202. package/clis/booking/search.js +351 -0
  203. package/clis/boss/auth.js +47 -0
  204. package/clis/boss/batchgreet.js +61 -0
  205. package/clis/boss/chatlist.js +116 -0
  206. package/clis/boss/chatlist.test.js +211 -0
  207. package/clis/boss/chatmsg.js +117 -0
  208. package/clis/boss/chatmsg.test.js +230 -0
  209. package/clis/boss/detail.js +63 -0
  210. package/clis/boss/exchange.js +46 -0
  211. package/clis/boss/greet.js +49 -0
  212. package/clis/boss/invite.js +64 -0
  213. package/clis/boss/joblist.js +31 -0
  214. package/clis/boss/mark.js +70 -0
  215. package/clis/boss/recommend.js +45 -0
  216. package/clis/boss/resume.js +150 -0
  217. package/clis/boss/search.js +197 -0
  218. package/clis/boss/search.test.js +78 -0
  219. package/clis/boss/send.js +44 -0
  220. package/clis/boss/stats.js +66 -0
  221. package/clis/boss/utils.js +468 -0
  222. package/clis/boss/utils.test.js +34 -0
  223. package/clis/brave/search.js +80 -0
  224. package/clis/brave/search.test.js +76 -0
  225. package/clis/chaoxing/assignments.js +76 -0
  226. package/clis/chaoxing/auth.js +54 -0
  227. package/clis/chaoxing/exams.js +75 -0
  228. package/clis/chaoxing/utils.js +223 -0
  229. package/clis/chaoxing/utils.test.js +45 -0
  230. package/clis/chatgpt/ask.js +129 -0
  231. package/clis/chatgpt/auth.js +52 -0
  232. package/clis/chatgpt/commands.test.js +204 -0
  233. package/clis/chatgpt/detail.js +63 -0
  234. package/clis/chatgpt/envelope.test.js +108 -0
  235. package/clis/chatgpt/history.js +39 -0
  236. package/clis/chatgpt/image.js +167 -0
  237. package/clis/chatgpt/image.test.js +207 -0
  238. package/clis/chatgpt/model.js +31 -0
  239. package/clis/chatgpt/model.test.js +36 -0
  240. package/clis/chatgpt/new.js +32 -0
  241. package/clis/chatgpt/project-file-add.js +74 -0
  242. package/clis/chatgpt/project-list.js +37 -0
  243. package/clis/chatgpt/read.js +44 -0
  244. package/clis/chatgpt/send.js +68 -0
  245. package/clis/chatgpt/status.js +29 -0
  246. package/clis/chatgpt/utils.js +2226 -0
  247. package/clis/chatgpt/utils.test.js +1453 -0
  248. package/clis/chatgpt-app/ask.js +87 -0
  249. package/clis/chatgpt-app/ax.js +603 -0
  250. package/clis/chatgpt-app/ax.test.js +95 -0
  251. package/clis/chatgpt-app/commands.test.js +45 -0
  252. package/clis/chatgpt-app/model.js +25 -0
  253. package/clis/chatgpt-app/new.js +61 -0
  254. package/clis/chatgpt-app/read.js +32 -0
  255. package/clis/chatgpt-app/send.js +37 -0
  256. package/clis/chatgpt-app/status.js +26 -0
  257. package/clis/chatwise/ask.js +54 -0
  258. package/clis/chatwise/composer.test.js +186 -0
  259. package/clis/chatwise/export.js +47 -0
  260. package/clis/chatwise/history.js +61 -0
  261. package/clis/chatwise/model.js +85 -0
  262. package/clis/chatwise/new.js +2 -0
  263. package/clis/chatwise/read.js +40 -0
  264. package/clis/chatwise/screenshot.js +2 -0
  265. package/clis/chatwise/send.js +28 -0
  266. package/clis/chatwise/status.js +2 -0
  267. package/clis/chatwise/utils.js +143 -0
  268. package/clis/chess/analyze.js +35 -0
  269. package/clis/chess/analyze.test.js +79 -0
  270. package/clis/chess/game.js +114 -0
  271. package/clis/chess/game.test.js +178 -0
  272. package/clis/chess/games.js +67 -0
  273. package/clis/chess/games.test.js +164 -0
  274. package/clis/chess/stats.js +32 -0
  275. package/clis/chess/stats.test.js +79 -0
  276. package/clis/chess/utils.js +170 -0
  277. package/clis/chess/utils.test.js +230 -0
  278. package/clis/claude/ask.js +144 -0
  279. package/clis/claude/ask.test.js +338 -0
  280. package/clis/claude/auth.js +55 -0
  281. package/clis/claude/commands.test.js +118 -0
  282. package/clis/claude/detail.js +38 -0
  283. package/clis/claude/history.js +33 -0
  284. package/clis/claude/new.js +29 -0
  285. package/clis/claude/read.js +27 -0
  286. package/clis/claude/send.js +48 -0
  287. package/clis/claude/status.js +26 -0
  288. package/clis/claude/utils.js +463 -0
  289. package/clis/claude/utils.test.js +148 -0
  290. package/clis/cnki/search.js +61 -0
  291. package/clis/cnki/search.test.js +18 -0
  292. package/clis/codex/_actions.js +270 -0
  293. package/clis/codex/archive.js +37 -0
  294. package/clis/codex/ask.js +78 -0
  295. package/clis/codex/dump.js +2 -0
  296. package/clis/codex/export.js +38 -0
  297. package/clis/codex/extract-diff.js +45 -0
  298. package/clis/codex/history.js +27 -0
  299. package/clis/codex/model.js +264 -0
  300. package/clis/codex/new.js +2 -0
  301. package/clis/codex/pin.js +30 -0
  302. package/clis/codex/projects.js +28 -0
  303. package/clis/codex/read.js +41 -0
  304. package/clis/codex/rename.js +86 -0
  305. package/clis/codex/screenshot.js +2 -0
  306. package/clis/codex/send.js +51 -0
  307. package/clis/codex/sidebar.js +356 -0
  308. package/clis/codex/sidebar.test.js +388 -0
  309. package/clis/codex/status.js +2 -0
  310. package/clis/coingecko/categories.js +75 -0
  311. package/clis/coingecko/coin.js +107 -0
  312. package/clis/coingecko/coingecko.test.js +109 -0
  313. package/clis/coingecko/derivatives.js +84 -0
  314. package/clis/coingecko/exchanges.js +74 -0
  315. package/clis/coingecko/global.js +71 -0
  316. package/clis/coingecko/top.js +64 -0
  317. package/clis/coingecko/trending.js +55 -0
  318. package/clis/confluence/commands.test.js +195 -0
  319. package/clis/confluence/create.js +39 -0
  320. package/clis/confluence/page.js +23 -0
  321. package/clis/confluence/search.js +34 -0
  322. package/clis/confluence/shared.js +173 -0
  323. package/clis/confluence/update.js +38 -0
  324. package/clis/coupang/add-to-cart.js +149 -0
  325. package/clis/coupang/auth.js +48 -0
  326. package/clis/coupang/coupang.test.js +159 -0
  327. package/clis/coupang/product.js +257 -0
  328. package/clis/coupang/search.js +474 -0
  329. package/clis/coupang/utils.js +316 -0
  330. package/clis/coupang/utils.test.js +62 -0
  331. package/clis/crates/crate.js +62 -0
  332. package/clis/crates/search.js +44 -0
  333. package/clis/crates/utils.js +72 -0
  334. package/clis/ctrip/auth.js +50 -0
  335. package/clis/ctrip/ctrip.test.js +719 -0
  336. package/clis/ctrip/flight.js +136 -0
  337. package/clis/ctrip/hotel-search.js +132 -0
  338. package/clis/ctrip/hotel-suggest.js +45 -0
  339. package/clis/ctrip/search.js +41 -0
  340. package/clis/ctrip/utils.js +473 -0
  341. package/clis/cursor/ask.js +74 -0
  342. package/clis/cursor/composer.js +43 -0
  343. package/clis/cursor/dump.js +2 -0
  344. package/clis/cursor/export.js +52 -0
  345. package/clis/cursor/extract-code.js +36 -0
  346. package/clis/cursor/history.js +44 -0
  347. package/clis/cursor/model.js +54 -0
  348. package/clis/cursor/new.js +2 -0
  349. package/clis/cursor/read.js +45 -0
  350. package/clis/cursor/screenshot.js +2 -0
  351. package/clis/cursor/send.js +41 -0
  352. package/clis/cursor/status.js +2 -0
  353. package/clis/dblp/author.js +133 -0
  354. package/clis/dblp/dblp.test.js +397 -0
  355. package/clis/dblp/paper.js +40 -0
  356. package/clis/dblp/search.js +45 -0
  357. package/clis/dblp/utils.js +290 -0
  358. package/clis/dblp/venue.js +64 -0
  359. package/clis/deepseek/ask.js +158 -0
  360. package/clis/deepseek/ask.test.js +399 -0
  361. package/clis/deepseek/auth.js +54 -0
  362. package/clis/deepseek/detail.js +46 -0
  363. package/clis/deepseek/detail.test.js +81 -0
  364. package/clis/deepseek/history.js +27 -0
  365. package/clis/deepseek/new.js +33 -0
  366. package/clis/deepseek/read.js +25 -0
  367. package/clis/deepseek/send.js +140 -0
  368. package/clis/deepseek/send.test.js +107 -0
  369. package/clis/deepseek/status.js +26 -0
  370. package/clis/deepseek/utils.js +487 -0
  371. package/clis/deepseek/utils.test.js +370 -0
  372. package/clis/defillama/defillama.test.js +99 -0
  373. package/clis/defillama/protocol.js +84 -0
  374. package/clis/defillama/protocols.js +55 -0
  375. package/clis/defillama/utils.js +99 -0
  376. package/clis/devto/devto.test.js +236 -0
  377. package/clis/devto/latest.js +74 -0
  378. package/clis/devto/read.js +103 -0
  379. package/clis/devto/tag.js +36 -0
  380. package/clis/devto/top.js +30 -0
  381. package/clis/devto/user.js +35 -0
  382. package/clis/dianping/__fixtures__/search.html +168 -0
  383. package/clis/dianping/__fixtures__/shop.html +6 -0
  384. package/clis/dianping/auth.js +49 -0
  385. package/clis/dianping/cityResolver.js +185 -0
  386. package/clis/dianping/dianping.test.js +578 -0
  387. package/clis/dianping/search.js +157 -0
  388. package/clis/dianping/shop.js +173 -0
  389. package/clis/dianping/utils.js +157 -0
  390. package/clis/dictionary/examples.js +28 -0
  391. package/clis/dictionary/search.js +30 -0
  392. package/clis/dictionary/synonyms.js +28 -0
  393. package/clis/discord-app/channels.js +26 -0
  394. package/clis/discord-app/commands.test.js +395 -0
  395. package/clis/discord-app/delete.js +115 -0
  396. package/clis/discord-app/goto.js +38 -0
  397. package/clis/discord-app/members.js +39 -0
  398. package/clis/discord-app/read.js +42 -0
  399. package/clis/discord-app/search.js +67 -0
  400. package/clis/discord-app/send.js +28 -0
  401. package/clis/discord-app/servers.js +26 -0
  402. package/clis/discord-app/status.js +17 -0
  403. package/clis/discord-app/thread-read.js +45 -0
  404. package/clis/discord-app/threads.js +37 -0
  405. package/clis/discord-app/utils.js +610 -0
  406. package/clis/dockerhub/image.js +52 -0
  407. package/clis/dockerhub/search.js +47 -0
  408. package/clis/dockerhub/utils.js +100 -0
  409. package/clis/dongchedi/__fixtures__/search.json +60 -0
  410. package/clis/dongchedi/__fixtures__/series-detail.json +911 -0
  411. package/clis/dongchedi/__fixtures__/series-score.json +1396 -0
  412. package/clis/dongchedi/dongchedi.test.js +191 -0
  413. package/clis/dongchedi/koubei.js +85 -0
  414. package/clis/dongchedi/models.js +91 -0
  415. package/clis/dongchedi/score.js +83 -0
  416. package/clis/dongchedi/search.js +83 -0
  417. package/clis/dongchedi/series.js +87 -0
  418. package/clis/dongchedi/specs.js +115 -0
  419. package/clis/dongchedi/utils.js +180 -0
  420. package/clis/douban/auth.js +50 -0
  421. package/clis/douban/book-hot.js +15 -0
  422. package/clis/douban/download.js +68 -0
  423. package/clis/douban/download.test.js +170 -0
  424. package/clis/douban/marks.js +116 -0
  425. package/clis/douban/movie-hot.js +15 -0
  426. package/clis/douban/movie-hot.test.js +14 -0
  427. package/clis/douban/photos.js +35 -0
  428. package/clis/douban/reviews.js +107 -0
  429. package/clis/douban/search.js +18 -0
  430. package/clis/douban/search.test.js +11 -0
  431. package/clis/douban/subject.js +46 -0
  432. package/clis/douban/subject.test.js +11 -0
  433. package/clis/douban/top250.js +68 -0
  434. package/clis/douban/utils.js +657 -0
  435. package/clis/douban/utils.test.js +488 -0
  436. package/clis/doubao/ask.js +40 -0
  437. package/clis/doubao/auth.js +66 -0
  438. package/clis/doubao/detail.js +35 -0
  439. package/clis/doubao/detail.test.js +42 -0
  440. package/clis/doubao/history.js +30 -0
  441. package/clis/doubao/history.test.js +37 -0
  442. package/clis/doubao/meeting-summary.js +41 -0
  443. package/clis/doubao/meeting-transcript.js +38 -0
  444. package/clis/doubao/new.js +22 -0
  445. package/clis/doubao/read.js +21 -0
  446. package/clis/doubao/send.js +24 -0
  447. package/clis/doubao/status.js +26 -0
  448. package/clis/doubao/utils.js +1156 -0
  449. package/clis/doubao/utils.test.js +396 -0
  450. package/clis/doubao-app/ask.js +54 -0
  451. package/clis/doubao-app/dump.js +25 -0
  452. package/clis/doubao-app/new.js +21 -0
  453. package/clis/doubao-app/read.js +19 -0
  454. package/clis/doubao-app/screenshot.js +19 -0
  455. package/clis/doubao-app/send.js +28 -0
  456. package/clis/doubao-app/status.js +17 -0
  457. package/clis/doubao-app/utils.js +110 -0
  458. package/clis/douyin/_shared/browser-fetch.js +66 -0
  459. package/clis/douyin/_shared/browser-fetch.test.js +64 -0
  460. package/clis/douyin/_shared/creation-id.js +5 -0
  461. package/clis/douyin/_shared/creation-id.test.js +22 -0
  462. package/clis/douyin/_shared/evaluate-result.js +16 -0
  463. package/clis/douyin/_shared/imagex-upload.js +53 -0
  464. package/clis/douyin/_shared/imagex-upload.test.js +87 -0
  465. package/clis/douyin/_shared/public-api.js +29 -0
  466. package/clis/douyin/_shared/sts2.js +21 -0
  467. package/clis/douyin/_shared/sts2.test.js +27 -0
  468. package/clis/douyin/_shared/text-extra.js +15 -0
  469. package/clis/douyin/_shared/text-extra.test.js +37 -0
  470. package/clis/douyin/_shared/timing.js +22 -0
  471. package/clis/douyin/_shared/timing.test.js +28 -0
  472. package/clis/douyin/_shared/tos-upload-short-read.test.js +83 -0
  473. package/clis/douyin/_shared/tos-upload.js +331 -0
  474. package/clis/douyin/_shared/tos-upload.test.js +229 -0
  475. package/clis/douyin/_shared/transcode.js +45 -0
  476. package/clis/douyin/_shared/transcode.test.js +91 -0
  477. package/clis/douyin/_shared/types.js +1 -0
  478. package/clis/douyin/_shared/vod-upload.js +212 -0
  479. package/clis/douyin/_shared/vod-upload.test.js +38 -0
  480. package/clis/douyin/activities.js +23 -0
  481. package/clis/douyin/activities.test.js +55 -0
  482. package/clis/douyin/auth.js +39 -0
  483. package/clis/douyin/collections.js +23 -0
  484. package/clis/douyin/collections.test.js +45 -0
  485. package/clis/douyin/delete.js +152 -0
  486. package/clis/douyin/delete.test.js +100 -0
  487. package/clis/douyin/draft.js +355 -0
  488. package/clis/douyin/draft.test.js +335 -0
  489. package/clis/douyin/drafts.js +24 -0
  490. package/clis/douyin/drafts.test.js +11 -0
  491. package/clis/douyin/hashtag.js +114 -0
  492. package/clis/douyin/hashtag.test.js +171 -0
  493. package/clis/douyin/location.js +25 -0
  494. package/clis/douyin/location.test.js +23 -0
  495. package/clis/douyin/profile.js +29 -0
  496. package/clis/douyin/profile.test.js +46 -0
  497. package/clis/douyin/publish-upload-id.test.js +206 -0
  498. package/clis/douyin/publish.js +341 -0
  499. package/clis/douyin/publish.test.js +38 -0
  500. package/clis/douyin/search.js +308 -0
  501. package/clis/douyin/search.test.js +307 -0
  502. package/clis/douyin/stats.js +28 -0
  503. package/clis/douyin/stats.test.js +22 -0
  504. package/clis/douyin/update.js +32 -0
  505. package/clis/douyin/update.test.js +11 -0
  506. package/clis/douyin/user-videos.js +82 -0
  507. package/clis/douyin/user-videos.test.js +151 -0
  508. package/clis/douyin/videos.js +52 -0
  509. package/clis/douyin/videos.test.js +54 -0
  510. package/clis/duckduckgo/search.js +131 -0
  511. package/clis/duckduckgo/search.test.js +128 -0
  512. package/clis/duckduckgo/suggest.js +45 -0
  513. package/clis/duckduckgo/suggest.test.js +66 -0
  514. package/clis/eastmoney/_secid.js +78 -0
  515. package/clis/eastmoney/announcement.js +53 -0
  516. package/clis/eastmoney/convertible.js +74 -0
  517. package/clis/eastmoney/etf.js +66 -0
  518. package/clis/eastmoney/holders.js +79 -0
  519. package/clis/eastmoney/hot-rank.js +51 -0
  520. package/clis/eastmoney/hot-rank.test.js +59 -0
  521. package/clis/eastmoney/index-board.js +97 -0
  522. package/clis/eastmoney/kline.js +88 -0
  523. package/clis/eastmoney/kuaixun.js +55 -0
  524. package/clis/eastmoney/longhu.js +68 -0
  525. package/clis/eastmoney/money-flow.js +79 -0
  526. package/clis/eastmoney/northbound.js +58 -0
  527. package/clis/eastmoney/quote.js +108 -0
  528. package/clis/eastmoney/rank.js +95 -0
  529. package/clis/eastmoney/sectors.js +77 -0
  530. package/clis/endoflife/endoflife.test.js +51 -0
  531. package/clis/endoflife/product.js +55 -0
  532. package/clis/endoflife/utils.js +89 -0
  533. package/clis/facebook/__fixtures__/notifications-page.html +13 -0
  534. package/clis/facebook/add-friend.js +44 -0
  535. package/clis/facebook/auth.js +43 -0
  536. package/clis/facebook/events.js +41 -0
  537. package/clis/facebook/feed.js +305 -0
  538. package/clis/facebook/feed.test.js +169 -0
  539. package/clis/facebook/friends.js +39 -0
  540. package/clis/facebook/groups.js +47 -0
  541. package/clis/facebook/join-group.js +45 -0
  542. package/clis/facebook/marketplace-inbox.js +84 -0
  543. package/clis/facebook/marketplace-listings.js +84 -0
  544. package/clis/facebook/marketplace.test.js +91 -0
  545. package/clis/facebook/memories.js +36 -0
  546. package/clis/facebook/notifications.js +333 -0
  547. package/clis/facebook/notifications.test.js +458 -0
  548. package/clis/facebook/profile.js +38 -0
  549. package/clis/facebook/search.js +39 -0
  550. package/clis/facebook/search.test.js +55 -0
  551. package/clis/flathub/app.js +71 -0
  552. package/clis/flathub/flathub.test.js +90 -0
  553. package/clis/flathub/search.js +80 -0
  554. package/clis/flathub/utils.js +114 -0
  555. package/clis/flomo/auth.js +55 -0
  556. package/clis/flomo/memos.js +228 -0
  557. package/clis/flomo/memos.test.js +144 -0
  558. package/clis/gemini/ask.js +51 -0
  559. package/clis/gemini/ask.test.js +100 -0
  560. package/clis/gemini/auth.js +48 -0
  561. package/clis/gemini/commands.test.js +212 -0
  562. package/clis/gemini/deep-research-result.js +96 -0
  563. package/clis/gemini/deep-research-result.test.js +155 -0
  564. package/clis/gemini/deep-research.js +103 -0
  565. package/clis/gemini/deep-research.test.js +181 -0
  566. package/clis/gemini/detail.js +82 -0
  567. package/clis/gemini/history.js +70 -0
  568. package/clis/gemini/image.js +111 -0
  569. package/clis/gemini/new.js +22 -0
  570. package/clis/gemini/read.js +36 -0
  571. package/clis/gemini/reply-state.test.js +671 -0
  572. package/clis/gemini/status.js +32 -0
  573. package/clis/gemini/utils.js +2056 -0
  574. package/clis/gemini/utils.test.js +392 -0
  575. package/clis/geogebra/add-circle.js +46 -0
  576. package/clis/geogebra/add-line.js +35 -0
  577. package/clis/geogebra/add-point.js +27 -0
  578. package/clis/geogebra/add-polygon.js +25 -0
  579. package/clis/geogebra/eval.js +35 -0
  580. package/clis/geogebra/geogebra.test.js +175 -0
  581. package/clis/geogebra/hexagon.js +62 -0
  582. package/clis/geogebra/info.js +72 -0
  583. package/clis/geogebra/list.js +35 -0
  584. package/clis/geogebra/triangle.js +60 -0
  585. package/clis/geogebra/utils.js +271 -0
  586. package/clis/gitee/auth.js +41 -0
  587. package/clis/gitee/index.js +3 -0
  588. package/clis/gitee/search.js +137 -0
  589. package/clis/gitee/search.test.js +65 -0
  590. package/clis/gitee/trending.js +568 -0
  591. package/clis/gitee/user.js +200 -0
  592. package/clis/gitee/user.test.js +63 -0
  593. package/clis/github/auth.js +44 -0
  594. package/clis/github-trending/repos.js +168 -0
  595. package/clis/github-trending/repos.test.js +149 -0
  596. package/clis/google/news.js +59 -0
  597. package/clis/google/search.js +138 -0
  598. package/clis/google/suggest.js +35 -0
  599. package/clis/google/trends.js +39 -0
  600. package/clis/google/utils.js +23 -0
  601. package/clis/google/utils.test.js +75 -0
  602. package/clis/google-scholar/cite.js +74 -0
  603. package/clis/google-scholar/cite.test.js +47 -0
  604. package/clis/google-scholar/profile.js +92 -0
  605. package/clis/google-scholar/profile.test.js +49 -0
  606. package/clis/google-scholar/search.js +73 -0
  607. package/clis/google-scholar/search.test.js +71 -0
  608. package/clis/goproxy/goproxy.test.js +103 -0
  609. package/clis/goproxy/module.js +47 -0
  610. package/clis/goproxy/utils.js +165 -0
  611. package/clis/goproxy/versions.js +59 -0
  612. package/clis/gov-law/commands.test.js +39 -0
  613. package/clis/gov-law/recent.js +22 -0
  614. package/clis/gov-law/search.js +41 -0
  615. package/clis/gov-law/shared.js +51 -0
  616. package/clis/gov-policy/__fixtures__/recent.html +16 -0
  617. package/clis/gov-policy/__fixtures__/search.html +41 -0
  618. package/clis/gov-policy/gov-policy.test.js +224 -0
  619. package/clis/gov-policy/recent.js +90 -0
  620. package/clis/gov-policy/search.js +91 -0
  621. package/clis/gov-policy/utils.js +54 -0
  622. package/clis/grok/ask.js +77 -0
  623. package/clis/grok/ask.test.js +29 -0
  624. package/clis/grok/auth.js +52 -0
  625. package/clis/grok/delete.js +54 -0
  626. package/clis/grok/detail.js +60 -0
  627. package/clis/grok/export-all.js +409 -0
  628. package/clis/grok/export-utils.js +94 -0
  629. package/clis/grok/export.js +189 -0
  630. package/clis/grok/export.test.js +210 -0
  631. package/clis/grok/history.js +48 -0
  632. package/clis/grok/image.js +343 -0
  633. package/clis/grok/image.test.ts +127 -0
  634. package/clis/grok/new.js +20 -0
  635. package/clis/grok/pin.js +68 -0
  636. package/clis/grok/read.js +39 -0
  637. package/clis/grok/send.js +50 -0
  638. package/clis/grok/status.js +41 -0
  639. package/clis/grok/utils.js +640 -0
  640. package/clis/grok/utils.test.js +141 -0
  641. package/clis/guazi/__fixtures__/detail.html +7 -0
  642. package/clis/guazi/__fixtures__/list.html +5 -0
  643. package/clis/guazi/browse.js +95 -0
  644. package/clis/guazi/car.js +110 -0
  645. package/clis/guazi/guazi.test.js +126 -0
  646. package/clis/guazi/utils.js +133 -0
  647. package/clis/hackernews/ask.js +31 -0
  648. package/clis/hackernews/best.js +31 -0
  649. package/clis/hackernews/hackernews.test.js +132 -0
  650. package/clis/hackernews/jobs.js +29 -0
  651. package/clis/hackernews/new.js +31 -0
  652. package/clis/hackernews/read.js +188 -0
  653. package/clis/hackernews/search.js +38 -0
  654. package/clis/hackernews/show.js +31 -0
  655. package/clis/hackernews/top.js +31 -0
  656. package/clis/hackernews/user.js +23 -0
  657. package/clis/hf/auth.js +41 -0
  658. package/clis/hf/datasets.js +88 -0
  659. package/clis/hf/hf.test.js +16 -0
  660. package/clis/hf/models.js +91 -0
  661. package/clis/hf/paper.js +79 -0
  662. package/clis/hf/spaces.js +101 -0
  663. package/clis/hf/top.js +121 -0
  664. package/clis/homebrew/cask.js +39 -0
  665. package/clis/homebrew/formula.js +41 -0
  666. package/clis/homebrew/popular.js +54 -0
  667. package/clis/homebrew/utils.js +100 -0
  668. package/clis/huodongxing/events.js +322 -0
  669. package/clis/huodongxing/events.test.js +296 -0
  670. package/clis/hupu/__fixtures__/hot-home.html +64 -0
  671. package/clis/hupu/auth.js +47 -0
  672. package/clis/hupu/detail.js +72 -0
  673. package/clis/hupu/hot.js +163 -0
  674. package/clis/hupu/hot.test.js +224 -0
  675. package/clis/hupu/like.js +76 -0
  676. package/clis/hupu/mentions.js +160 -0
  677. package/clis/hupu/reply.js +72 -0
  678. package/clis/hupu/search.js +60 -0
  679. package/clis/hupu/unlike.js +76 -0
  680. package/clis/hupu/utils.js +319 -0
  681. package/clis/imdb/person.js +204 -0
  682. package/clis/imdb/reviews.js +89 -0
  683. package/clis/imdb/search.js +162 -0
  684. package/clis/imdb/title.js +94 -0
  685. package/clis/imdb/top.js +54 -0
  686. package/clis/imdb/trending.js +53 -0
  687. package/clis/imdb/utils.js +285 -0
  688. package/clis/imdb/utils.test.js +88 -0
  689. package/clis/indeed/indeed.test.js +375 -0
  690. package/clis/indeed/job.js +86 -0
  691. package/clis/indeed/search.js +110 -0
  692. package/clis/indeed/utils.js +152 -0
  693. package/clis/instagram/_shared/private-publish.js +1030 -0
  694. package/clis/instagram/_shared/private-publish.test.js +705 -0
  695. package/clis/instagram/_shared/protocol-capture.js +282 -0
  696. package/clis/instagram/_shared/protocol-capture.test.js +114 -0
  697. package/clis/instagram/_shared/runtime-info.js +81 -0
  698. package/clis/instagram/auth.js +57 -0
  699. package/clis/instagram/collection-create.js +58 -0
  700. package/clis/instagram/collection-delete.js +92 -0
  701. package/clis/instagram/comment.js +48 -0
  702. package/clis/instagram/download.js +226 -0
  703. package/clis/instagram/download.test.js +118 -0
  704. package/clis/instagram/explore.js +42 -0
  705. package/clis/instagram/follow.js +44 -0
  706. package/clis/instagram/followers.js +46 -0
  707. package/clis/instagram/following.js +90 -0
  708. package/clis/instagram/instagram.test.js +381 -0
  709. package/clis/instagram/like.js +46 -0
  710. package/clis/instagram/note.js +223 -0
  711. package/clis/instagram/note.test.js +53 -0
  712. package/clis/instagram/post.js +1497 -0
  713. package/clis/instagram/post.test.js +1647 -0
  714. package/clis/instagram/profile.js +40 -0
  715. package/clis/instagram/reel.js +827 -0
  716. package/clis/instagram/reel.test.js +167 -0
  717. package/clis/instagram/save.js +46 -0
  718. package/clis/instagram/saved.js +53 -0
  719. package/clis/instagram/search.js +39 -0
  720. package/clis/instagram/story.js +116 -0
  721. package/clis/instagram/story.test.js +134 -0
  722. package/clis/instagram/unfollow.js +41 -0
  723. package/clis/instagram/unlike.js +46 -0
  724. package/clis/instagram/unsave.js +46 -0
  725. package/clis/instagram/user.js +49 -0
  726. package/clis/jd/add-cart.js +72 -0
  727. package/clis/jd/auth.js +46 -0
  728. package/clis/jd/cart.js +80 -0
  729. package/clis/jd/commands.test.js +41 -0
  730. package/clis/jd/detail.js +63 -0
  731. package/clis/jd/item.js +730 -0
  732. package/clis/jd/item.test.js +354 -0
  733. package/clis/jd/item.test.ts +517 -0
  734. package/clis/jd/reviews.js +55 -0
  735. package/clis/jd/search.js +66 -0
  736. package/clis/jianyu/auth.js +62 -0
  737. package/clis/jianyu/detail.js +21 -0
  738. package/clis/jianyu/search.js +634 -0
  739. package/clis/jianyu/search.test.js +153 -0
  740. package/clis/jianyu/shared/china-bid-search.js +165 -0
  741. package/clis/jianyu/shared/procurement-contract.js +324 -0
  742. package/clis/jianyu/shared/procurement-contract.test.js +72 -0
  743. package/clis/jianyu/shared/procurement-detail.js +107 -0
  744. package/clis/jianyu/shared/procurement-detail.test.js +84 -0
  745. package/clis/jike/auth.js +48 -0
  746. package/clis/jike/comment.js +107 -0
  747. package/clis/jike/create.js +106 -0
  748. package/clis/jike/feed.js +68 -0
  749. package/clis/jike/like.js +61 -0
  750. package/clis/jike/notifications.js +169 -0
  751. package/clis/jike/post.js +72 -0
  752. package/clis/jike/read.test.js +86 -0
  753. package/clis/jike/repost.js +103 -0
  754. package/clis/jike/search.js +68 -0
  755. package/clis/jike/topic.js +65 -0
  756. package/clis/jike/user.js +65 -0
  757. package/clis/jike/utils.js +25 -0
  758. package/clis/jimeng/auth.js +46 -0
  759. package/clis/jimeng/generate.js +84 -0
  760. package/clis/jimeng/history.js +48 -0
  761. package/clis/jimeng/new.js +44 -0
  762. package/clis/jimeng/workspaces.js +42 -0
  763. package/clis/jira/attachments.js +28 -0
  764. package/clis/jira/commands.test.js +287 -0
  765. package/clis/jira/comments.js +28 -0
  766. package/clis/jira/issue.js +28 -0
  767. package/clis/jira/links.js +28 -0
  768. package/clis/jira/search.js +47 -0
  769. package/clis/jira/shared.js +256 -0
  770. package/clis/juejin/hot.js +37 -0
  771. package/clis/juejin/juejin.test.js +241 -0
  772. package/clis/juejin/recommend.js +61 -0
  773. package/clis/juejin/utils.js +199 -0
  774. package/clis/ke/auth.js +46 -0
  775. package/clis/ke/chengjiao.js +78 -0
  776. package/clis/ke/ershoufang.js +101 -0
  777. package/clis/ke/utils.js +104 -0
  778. package/clis/ke/xiaoqu.js +78 -0
  779. package/clis/ke/zufang.js +95 -0
  780. package/clis/kimi/_utils.js +110 -0
  781. package/clis/kimi/audit-extras.js +268 -0
  782. package/clis/kimi/auth.js +57 -0
  783. package/clis/kimi/chat.js +470 -0
  784. package/clis/kimi/kimi.test.js +187 -0
  785. package/clis/kimi/storage.js +169 -0
  786. package/clis/kimi/ui.js +314 -0
  787. package/clis/kimi/usage.js +144 -0
  788. package/clis/lesswrong/_helpers.js +75 -0
  789. package/clis/lesswrong/comments.js +65 -0
  790. package/clis/lesswrong/curated.js +31 -0
  791. package/clis/lesswrong/frontpage.js +31 -0
  792. package/clis/lesswrong/frontpage.test.js +37 -0
  793. package/clis/lesswrong/new.js +31 -0
  794. package/clis/lesswrong/read.js +46 -0
  795. package/clis/lesswrong/sequences.js +28 -0
  796. package/clis/lesswrong/shortform.js +31 -0
  797. package/clis/lesswrong/tag.js +46 -0
  798. package/clis/lesswrong/tags.js +28 -0
  799. package/clis/lesswrong/top-month.js +31 -0
  800. package/clis/lesswrong/top-week.js +31 -0
  801. package/clis/lesswrong/top-year.js +31 -0
  802. package/clis/lesswrong/top.js +31 -0
  803. package/clis/lesswrong/user-posts.js +42 -0
  804. package/clis/lesswrong/user.js +45 -0
  805. package/clis/lichess/lichess.test.js +85 -0
  806. package/clis/lichess/top.js +46 -0
  807. package/clis/lichess/user.js +91 -0
  808. package/clis/lichess/utils.js +97 -0
  809. package/clis/linkedin/auth.js +62 -0
  810. package/clis/linkedin/connect.js +524 -0
  811. package/clis/linkedin/connect.test.js +328 -0
  812. package/clis/linkedin/inbox.js +234 -0
  813. package/clis/linkedin/inbox.test.js +152 -0
  814. package/clis/linkedin/job-detail.js +167 -0
  815. package/clis/linkedin/job-detail.test.js +38 -0
  816. package/clis/linkedin/jobs-preferences.js +113 -0
  817. package/clis/linkedin/jobs-preferences.test.js +43 -0
  818. package/clis/linkedin/people-search.js +262 -0
  819. package/clis/linkedin/people-search.test.js +216 -0
  820. package/clis/linkedin/post-analytics.js +74 -0
  821. package/clis/linkedin/post-analytics.test.js +40 -0
  822. package/clis/linkedin/posts-core.js +241 -0
  823. package/clis/linkedin/posts.js +22 -0
  824. package/clis/linkedin/posts.test.js +40 -0
  825. package/clis/linkedin/profile-analytics.js +104 -0
  826. package/clis/linkedin/profile-analytics.test.js +67 -0
  827. package/clis/linkedin/profile-experience.js +671 -0
  828. package/clis/linkedin/profile-experience.test.js +152 -0
  829. package/clis/linkedin/profile-projects.js +311 -0
  830. package/clis/linkedin/profile-projects.test.js +111 -0
  831. package/clis/linkedin/profile-read.js +148 -0
  832. package/clis/linkedin/profile-read.test.js +77 -0
  833. package/clis/linkedin/safe-send.js +357 -0
  834. package/clis/linkedin/safe-send.test.js +204 -0
  835. package/clis/linkedin/salesnav-inbox.js +210 -0
  836. package/clis/linkedin/salesnav-inbox.test.js +113 -0
  837. package/clis/linkedin/salesnav-message.js +360 -0
  838. package/clis/linkedin/salesnav-message.test.js +172 -0
  839. package/clis/linkedin/salesnav-search.js +186 -0
  840. package/clis/linkedin/salesnav-search.test.js +76 -0
  841. package/clis/linkedin/salesnav-thread.js +212 -0
  842. package/clis/linkedin/salesnav-thread.test.js +79 -0
  843. package/clis/linkedin/search.js +462 -0
  844. package/clis/linkedin/search.test.js +222 -0
  845. package/clis/linkedin/sent-invitations.js +92 -0
  846. package/clis/linkedin/sent-invitations.test.js +62 -0
  847. package/clis/linkedin/services-read.js +213 -0
  848. package/clis/linkedin/services-read.test.js +105 -0
  849. package/clis/linkedin/shared.js +124 -0
  850. package/clis/linkedin/thread-snapshot.js +214 -0
  851. package/clis/linkedin/thread-snapshot.test.js +89 -0
  852. package/clis/linkedin/timeline.js +511 -0
  853. package/clis/linkedin/timeline.test.js +81 -0
  854. package/clis/linkedin-learning/auth.js +62 -0
  855. package/clis/linkedin-learning/course.js +138 -0
  856. package/clis/linkedin-learning/course.test.js +114 -0
  857. package/clis/linkedin-learning/search.js +155 -0
  858. package/clis/linkedin-learning/search.test.js +144 -0
  859. package/clis/linkedin-learning/trending.js +133 -0
  860. package/clis/linkedin-learning/trending.test.js +123 -0
  861. package/clis/linux-do/auth.js +55 -0
  862. package/clis/linux-do/categories.js +50 -0
  863. package/clis/linux-do/feed.js +395 -0
  864. package/clis/linux-do/feed.test.js +153 -0
  865. package/clis/linux-do/search.js +29 -0
  866. package/clis/linux-do/tags.js +28 -0
  867. package/clis/linux-do/topic-content.js +155 -0
  868. package/clis/linux-do/topic-content.test.js +59 -0
  869. package/clis/linux-do/topic.js +53 -0
  870. package/clis/linux-do/user-posts.js +57 -0
  871. package/clis/linux-do/user-topics.js +37 -0
  872. package/clis/lobsters/active.js +29 -0
  873. package/clis/lobsters/domain.js +92 -0
  874. package/clis/lobsters/hot.js +29 -0
  875. package/clis/lobsters/lobsters.test.js +169 -0
  876. package/clis/lobsters/newest.js +29 -0
  877. package/clis/lobsters/read.js +196 -0
  878. package/clis/lobsters/tag.js +35 -0
  879. package/clis/maimai/auth.js +47 -0
  880. package/clis/maimai/search-talents.js +192 -0
  881. package/clis/maimai/search-talents.test.js +29 -0
  882. package/clis/manus/_utils.js +133 -0
  883. package/clis/manus/auth.js +54 -0
  884. package/clis/manus/connectors.js +40 -0
  885. package/clis/manus/credits.js +39 -0
  886. package/clis/manus/list.js +66 -0
  887. package/clis/manus/manus.test.js +382 -0
  888. package/clis/manus/read.js +63 -0
  889. package/clis/manus/skills.js +61 -0
  890. package/clis/manus/status.js +43 -0
  891. package/clis/maven/artifact.js +49 -0
  892. package/clis/maven/search.js +51 -0
  893. package/clis/maven/utils.js +110 -0
  894. package/clis/mdn/search.js +97 -0
  895. package/clis/medium/feed.js +16 -0
  896. package/clis/medium/search.js +16 -0
  897. package/clis/medium/tag.js +135 -0
  898. package/clis/medium/user.js +16 -0
  899. package/clis/medium/utils.js +79 -0
  900. package/clis/mubu/doc.js +41 -0
  901. package/clis/mubu/docs.js +44 -0
  902. package/clis/mubu/notes.js +245 -0
  903. package/clis/mubu/recent.js +28 -0
  904. package/clis/mubu/search.js +63 -0
  905. package/clis/mubu/utils.js +304 -0
  906. package/clis/notebooklm/add-source.js +269 -0
  907. package/clis/notebooklm/add-source.test.js +97 -0
  908. package/clis/notebooklm/auth.js +55 -0
  909. package/clis/notebooklm/compat.test.js +16 -0
  910. package/clis/notebooklm/create.js +76 -0
  911. package/clis/notebooklm/create.test.js +58 -0
  912. package/clis/notebooklm/current.js +28 -0
  913. package/clis/notebooklm/generate-audio.js +91 -0
  914. package/clis/notebooklm/generate-audio.test.js +63 -0
  915. package/clis/notebooklm/generate-slides.js +106 -0
  916. package/clis/notebooklm/generate-slides.test.js +75 -0
  917. package/clis/notebooklm/get.js +37 -0
  918. package/clis/notebooklm/history.js +25 -0
  919. package/clis/notebooklm/history.test.js +58 -0
  920. package/clis/notebooklm/list.js +36 -0
  921. package/clis/notebooklm/note-list.js +28 -0
  922. package/clis/notebooklm/note-list.test.js +56 -0
  923. package/clis/notebooklm/notes-get.js +47 -0
  924. package/clis/notebooklm/notes-get.test.js +72 -0
  925. package/clis/notebooklm/open.js +42 -0
  926. package/clis/notebooklm/open.test.js +63 -0
  927. package/clis/notebooklm/rpc.js +203 -0
  928. package/clis/notebooklm/rpc.test.js +131 -0
  929. package/clis/notebooklm/shared.js +3 -0
  930. package/clis/notebooklm/source-fulltext.js +44 -0
  931. package/clis/notebooklm/source-fulltext.test.js +106 -0
  932. package/clis/notebooklm/source-get.js +40 -0
  933. package/clis/notebooklm/source-get.test.js +84 -0
  934. package/clis/notebooklm/source-guide.js +44 -0
  935. package/clis/notebooklm/source-guide.test.js +104 -0
  936. package/clis/notebooklm/source-list.js +30 -0
  937. package/clis/notebooklm/status.js +31 -0
  938. package/clis/notebooklm/summary.js +30 -0
  939. package/clis/notebooklm/summary.test.js +78 -0
  940. package/clis/notebooklm/utils.js +814 -0
  941. package/clis/notebooklm/utils.test.js +449 -0
  942. package/clis/notebooklm/write-note.js +103 -0
  943. package/clis/notebooklm/write-note.test.js +70 -0
  944. package/clis/nowcoder/auth.js +65 -0
  945. package/clis/nowcoder/companies.js +24 -0
  946. package/clis/nowcoder/creators.js +28 -0
  947. package/clis/nowcoder/detail.js +62 -0
  948. package/clis/nowcoder/experience.js +37 -0
  949. package/clis/nowcoder/hot.js +25 -0
  950. package/clis/nowcoder/jobs.js +22 -0
  951. package/clis/nowcoder/notifications.js +30 -0
  952. package/clis/nowcoder/papers.js +41 -0
  953. package/clis/nowcoder/practice.js +38 -0
  954. package/clis/nowcoder/recommend.js +31 -0
  955. package/clis/nowcoder/referral.js +40 -0
  956. package/clis/nowcoder/salary.js +41 -0
  957. package/clis/nowcoder/search.js +50 -0
  958. package/clis/nowcoder/suggest.js +34 -0
  959. package/clis/nowcoder/topics.js +28 -0
  960. package/clis/nowcoder/trending.js +26 -0
  961. package/clis/npm/downloads.js +59 -0
  962. package/clis/npm/package.js +70 -0
  963. package/clis/npm/search.js +49 -0
  964. package/clis/npm/utils.js +76 -0
  965. package/clis/nuget/nuget.test.js +111 -0
  966. package/clis/nuget/package.js +101 -0
  967. package/clis/nuget/search.js +69 -0
  968. package/clis/nuget/utils.js +87 -0
  969. package/clis/nvd/cve.js +121 -0
  970. package/clis/oeis/oeis.test.js +88 -0
  971. package/clis/oeis/search.js +63 -0
  972. package/clis/oeis/sequence.js +71 -0
  973. package/clis/oeis/utils.js +88 -0
  974. package/clis/ones/common.js +144 -0
  975. package/clis/ones/enrich-tasks.js +37 -0
  976. package/clis/ones/login.js +81 -0
  977. package/clis/ones/logout.js +18 -0
  978. package/clis/ones/me.js +31 -0
  979. package/clis/ones/my-tasks.js +121 -0
  980. package/clis/ones/resolve-labels.js +64 -0
  981. package/clis/ones/task-helpers.js +212 -0
  982. package/clis/ones/task-helpers.test.js +12 -0
  983. package/clis/ones/task.js +67 -0
  984. package/clis/ones/tasks.js +80 -0
  985. package/clis/ones/token-info.js +43 -0
  986. package/clis/ones/worklog.js +268 -0
  987. package/clis/ones/worklog.test.js +20 -0
  988. package/clis/openalex/search.js +69 -0
  989. package/clis/openalex/utils.js +160 -0
  990. package/clis/openalex/work.js +65 -0
  991. package/clis/openfda/drug-label.js +74 -0
  992. package/clis/openfda/food-recall.js +65 -0
  993. package/clis/openfda/openfda.test.js +114 -0
  994. package/clis/openfda/utils.js +67 -0
  995. package/clis/openreview/author.js +58 -0
  996. package/clis/openreview/openreview.test.js +427 -0
  997. package/clis/openreview/paper.js +43 -0
  998. package/clis/openreview/reviews.js +131 -0
  999. package/clis/openreview/search.js +46 -0
  1000. package/clis/openreview/utils.js +172 -0
  1001. package/clis/openreview/venue.js +63 -0
  1002. package/clis/osv/osv.test.js +97 -0
  1003. package/clis/osv/query.js +72 -0
  1004. package/clis/osv/utils.js +169 -0
  1005. package/clis/osv/vulnerability.js +54 -0
  1006. package/clis/packagist/package.js +49 -0
  1007. package/clis/packagist/search.js +43 -0
  1008. package/clis/packagist/utils.js +113 -0
  1009. package/clis/paperreview/commands.test.js +243 -0
  1010. package/clis/paperreview/feedback.js +53 -0
  1011. package/clis/paperreview/review.js +38 -0
  1012. package/clis/paperreview/submit.js +86 -0
  1013. package/clis/paperreview/utils.js +197 -0
  1014. package/clis/paperreview/utils.test.js +49 -0
  1015. package/clis/pixiv/auth.js +64 -0
  1016. package/clis/pixiv/detail.js +66 -0
  1017. package/clis/pixiv/detail.test.js +93 -0
  1018. package/clis/pixiv/download.js +82 -0
  1019. package/clis/pixiv/download.test.js +97 -0
  1020. package/clis/pixiv/illusts.js +66 -0
  1021. package/clis/pixiv/illusts.test.js +99 -0
  1022. package/clis/pixiv/ranking.js +60 -0
  1023. package/clis/pixiv/search.js +44 -0
  1024. package/clis/pixiv/search.test.js +83 -0
  1025. package/clis/pixiv/user.js +59 -0
  1026. package/clis/pixiv/user.test.js +100 -0
  1027. package/clis/pixiv/utils.js +98 -0
  1028. package/clis/powerchina/auth.js +52 -0
  1029. package/clis/powerchina/search.js +251 -0
  1030. package/clis/powerchina/search.test.js +93 -0
  1031. package/clis/producthunt/browse.js +100 -0
  1032. package/clis/producthunt/hot.js +111 -0
  1033. package/clis/producthunt/posts.js +29 -0
  1034. package/clis/producthunt/today.js +36 -0
  1035. package/clis/producthunt/utils.js +99 -0
  1036. package/clis/producthunt/utils.test.js +64 -0
  1037. package/clis/pubmed/article.js +55 -0
  1038. package/clis/pubmed/author.js +64 -0
  1039. package/clis/pubmed/citations.js +36 -0
  1040. package/clis/pubmed/clinical-trial.js +59 -0
  1041. package/clis/pubmed/journal.js +59 -0
  1042. package/clis/pubmed/mesh.js +47 -0
  1043. package/clis/pubmed/pubmed.test.js +464 -0
  1044. package/clis/pubmed/related.js +45 -0
  1045. package/clis/pubmed/review.js +58 -0
  1046. package/clis/pubmed/search.js +75 -0
  1047. package/clis/pubmed/utils.js +325 -0
  1048. package/clis/pypi/downloads.js +66 -0
  1049. package/clis/pypi/package.js +79 -0
  1050. package/clis/pypi/utils.js +55 -0
  1051. package/clis/qoder/_utils.js +191 -0
  1052. package/clis/qoder/composer.js +45 -0
  1053. package/clis/qoder/history.js +49 -0
  1054. package/clis/qoder/qoder.test.js +125 -0
  1055. package/clis/qoder/quest.js +147 -0
  1056. package/clis/qoder/read.js +29 -0
  1057. package/clis/qoder/status.js +21 -0
  1058. package/clis/qoder/ui.js +332 -0
  1059. package/clis/quark/auth.js +47 -0
  1060. package/clis/quark/ls.js +64 -0
  1061. package/clis/quark/mkdir.js +37 -0
  1062. package/clis/quark/mv.js +54 -0
  1063. package/clis/quark/rename.js +27 -0
  1064. package/clis/quark/rm.js +25 -0
  1065. package/clis/quark/save.js +81 -0
  1066. package/clis/quark/share-tree.js +46 -0
  1067. package/clis/quark/utils.js +146 -0
  1068. package/clis/quark/utils.test.js +58 -0
  1069. package/clis/qwen/ask.js +104 -0
  1070. package/clis/qwen/ask.test.js +36 -0
  1071. package/clis/qwen/auth.js +56 -0
  1072. package/clis/qwen/detail.js +62 -0
  1073. package/clis/qwen/history.js +61 -0
  1074. package/clis/qwen/image.js +179 -0
  1075. package/clis/qwen/new.js +23 -0
  1076. package/clis/qwen/read.js +41 -0
  1077. package/clis/qwen/send.js +55 -0
  1078. package/clis/qwen/status.js +37 -0
  1079. package/clis/qwen/utils.js +461 -0
  1080. package/clis/qwen/utils.test.js +128 -0
  1081. package/clis/reddit/auth.js +52 -0
  1082. package/clis/reddit/comment.js +58 -0
  1083. package/clis/reddit/extract-media.test.js +149 -0
  1084. package/clis/reddit/frontpage.js +70 -0
  1085. package/clis/reddit/frontpage.test.js +34 -0
  1086. package/clis/reddit/home.js +146 -0
  1087. package/clis/reddit/home.test.js +170 -0
  1088. package/clis/reddit/hot.js +81 -0
  1089. package/clis/reddit/hot.test.js +32 -0
  1090. package/clis/reddit/popular.js +79 -0
  1091. package/clis/reddit/popular.test.js +26 -0
  1092. package/clis/reddit/read.js +588 -0
  1093. package/clis/reddit/read.test.js +402 -0
  1094. package/clis/reddit/reply.js +182 -0
  1095. package/clis/reddit/reply.test.js +89 -0
  1096. package/clis/reddit/save.js +52 -0
  1097. package/clis/reddit/saved.js +50 -0
  1098. package/clis/reddit/search.js +102 -0
  1099. package/clis/reddit/search.test.js +26 -0
  1100. package/clis/reddit/subreddit-info.js +116 -0
  1101. package/clis/reddit/subreddit-info.test.js +163 -0
  1102. package/clis/reddit/subreddit.js +97 -0
  1103. package/clis/reddit/subreddit.test.js +31 -0
  1104. package/clis/reddit/subscribe.js +51 -0
  1105. package/clis/reddit/subscribed.js +165 -0
  1106. package/clis/reddit/subscribed.test.js +168 -0
  1107. package/clis/reddit/upvote.js +65 -0
  1108. package/clis/reddit/upvoted.js +50 -0
  1109. package/clis/reddit/user-comments.js +45 -0
  1110. package/clis/reddit/user-posts.js +43 -0
  1111. package/clis/reddit/user.js +38 -0
  1112. package/clis/reddit/whoami.js +83 -0
  1113. package/clis/reddit/whoami.test.js +105 -0
  1114. package/clis/rednote/auth.js +52 -0
  1115. package/clis/rednote/comments.js +85 -0
  1116. package/clis/rednote/download.js +59 -0
  1117. package/clis/rednote/feed.js +27 -0
  1118. package/clis/rednote/navigation.test.js +26 -0
  1119. package/clis/rednote/note.js +68 -0
  1120. package/clis/rednote/notifications.js +139 -0
  1121. package/clis/rednote/rednote.test.js +240 -0
  1122. package/clis/rednote/search.js +107 -0
  1123. package/clis/rednote/user.js +55 -0
  1124. package/clis/rest-countries/country.js +65 -0
  1125. package/clis/rest-countries/region.js +64 -0
  1126. package/clis/rest-countries/rest-countries.test.js +83 -0
  1127. package/clis/rest-countries/utils.js +126 -0
  1128. package/clis/reuters/article-detail.js +53 -0
  1129. package/clis/reuters/auth.js +67 -0
  1130. package/clis/reuters/reuters.test.js +299 -0
  1131. package/clis/reuters/search.js +63 -0
  1132. package/clis/reuters/utils.js +159 -0
  1133. package/clis/rfc/rfc.js +52 -0
  1134. package/clis/rfc/rfc.test.js +74 -0
  1135. package/clis/rfc/utils.js +72 -0
  1136. package/clis/rubygems/gem.js +42 -0
  1137. package/clis/rubygems/search.js +47 -0
  1138. package/clis/rubygems/utils.js +86 -0
  1139. package/clis/semanticscholar/citations.js +61 -0
  1140. package/clis/semanticscholar/paper.js +52 -0
  1141. package/clis/semanticscholar/recommendations.js +47 -0
  1142. package/clis/semanticscholar/search.js +48 -0
  1143. package/clis/semanticscholar/semanticscholar.test.js +279 -0
  1144. package/clis/semanticscholar/utils.js +196 -0
  1145. package/clis/sinablog/article.js +15 -0
  1146. package/clis/sinablog/hot.js +15 -0
  1147. package/clis/sinablog/search.js +52 -0
  1148. package/clis/sinablog/user.js +16 -0
  1149. package/clis/sinablog/utils.js +186 -0
  1150. package/clis/sinafinance/news.js +62 -0
  1151. package/clis/sinafinance/rolling-news.js +41 -0
  1152. package/clis/sinafinance/stock-rank.js +66 -0
  1153. package/clis/sinafinance/stock.js +121 -0
  1154. package/clis/sinafinance/stock.test.js +59 -0
  1155. package/clis/slock/api-base-canary.test.js +62 -0
  1156. package/clis/slock/attachment-download.js +72 -0
  1157. package/clis/slock/attachment-download.test.js +102 -0
  1158. package/clis/slock/attachment-upload.js +112 -0
  1159. package/clis/slock/attachment-upload.test.js +131 -0
  1160. package/clis/slock/attachment-url.js +53 -0
  1161. package/clis/slock/attachment-url.test.js +41 -0
  1162. package/clis/slock/auth-verify.js +19 -0
  1163. package/clis/slock/bookmark-add.js +43 -0
  1164. package/clis/slock/bookmark-add.test.js +38 -0
  1165. package/clis/slock/bookmark-list.js +50 -0
  1166. package/clis/slock/bookmark-list.test.js +47 -0
  1167. package/clis/slock/bookmark-remove.js +42 -0
  1168. package/clis/slock/bookmark-remove.test.js +24 -0
  1169. package/clis/slock/channel-action.js +63 -0
  1170. package/clis/slock/channel-action.test.js +65 -0
  1171. package/clis/slock/channel-archive.js +9 -0
  1172. package/clis/slock/channel-create.js +48 -0
  1173. package/clis/slock/channel-create.test.js +40 -0
  1174. package/clis/slock/channel-files.js +51 -0
  1175. package/clis/slock/channel-files.test.js +32 -0
  1176. package/clis/slock/channel-info.js +42 -0
  1177. package/clis/slock/channel-info.test.js +25 -0
  1178. package/clis/slock/channel-join.js +9 -0
  1179. package/clis/slock/channel-leave.js +9 -0
  1180. package/clis/slock/channel-list.js +40 -0
  1181. package/clis/slock/channel-list.test.js +37 -0
  1182. package/clis/slock/channel-mark.js +71 -0
  1183. package/clis/slock/channel-mark.test.js +49 -0
  1184. package/clis/slock/channel-members.js +64 -0
  1185. package/clis/slock/channel-members.test.js +44 -0
  1186. package/clis/slock/channel-unarchive.js +11 -0
  1187. package/clis/slock/cross-command.test.js +21 -0
  1188. package/clis/slock/dm-list.js +41 -0
  1189. package/clis/slock/dm-list.test.js +26 -0
  1190. package/clis/slock/error-detail-canary.test.js +144 -0
  1191. package/clis/slock/errors.js +30 -0
  1192. package/clis/slock/errors.test.js +29 -0
  1193. package/clis/slock/in-page.js +213 -0
  1194. package/clis/slock/in-page.test.js +362 -0
  1195. package/clis/slock/inbox-done.js +40 -0
  1196. package/clis/slock/inbox-done.test.js +21 -0
  1197. package/clis/slock/inbox-read-all.js +32 -0
  1198. package/clis/slock/inbox-read-all.test.js +20 -0
  1199. package/clis/slock/inbox.js +74 -0
  1200. package/clis/slock/inbox.test.js +46 -0
  1201. package/clis/slock/login.js +3 -0
  1202. package/clis/slock/message-read.js +168 -0
  1203. package/clis/slock/message-read.test.js +83 -0
  1204. package/clis/slock/message-search.js +72 -0
  1205. package/clis/slock/message-search.test.js +61 -0
  1206. package/clis/slock/message-send.js +149 -0
  1207. package/clis/slock/message-send.test.js +127 -0
  1208. package/clis/slock/reaction-add.js +42 -0
  1209. package/clis/slock/reaction-add.test.js +36 -0
  1210. package/clis/slock/reaction-remove.js +42 -0
  1211. package/clis/slock/reaction-remove.test.js +29 -0
  1212. package/clis/slock/resolve.js +74 -0
  1213. package/clis/slock/resolve.test.js +102 -0
  1214. package/clis/slock/server-list.js +38 -0
  1215. package/clis/slock/server-list.test.js +24 -0
  1216. package/clis/slock/server-override-canary.test.js +87 -0
  1217. package/clis/slock/server-use.js +53 -0
  1218. package/clis/slock/server-use.test.js +48 -0
  1219. package/clis/slock/shared.js +14 -0
  1220. package/clis/slock/short-id-canary.test.js +86 -0
  1221. package/clis/slock/site-session-canary.test.js +49 -0
  1222. package/clis/slock/task-claim.js +72 -0
  1223. package/clis/slock/task-claim.test.js +81 -0
  1224. package/clis/slock/task-convert.js +106 -0
  1225. package/clis/slock/task-convert.test.js +82 -0
  1226. package/clis/slock/task-create.js +82 -0
  1227. package/clis/slock/task-create.test.js +65 -0
  1228. package/clis/slock/task-delete.js +55 -0
  1229. package/clis/slock/task-delete.test.js +52 -0
  1230. package/clis/slock/task-get.js +59 -0
  1231. package/clis/slock/task-get.test.js +45 -0
  1232. package/clis/slock/task-list-server.js +63 -0
  1233. package/clis/slock/task-list-server.test.js +48 -0
  1234. package/clis/slock/task-list.js +70 -0
  1235. package/clis/slock/task-list.test.js +59 -0
  1236. package/clis/slock/task-status.js +93 -0
  1237. package/clis/slock/task-status.test.js +76 -0
  1238. package/clis/slock/task-unclaim.js +66 -0
  1239. package/clis/slock/task-unclaim.test.js +49 -0
  1240. package/clis/slock/thread-done.js +9 -0
  1241. package/clis/slock/thread-follow.js +46 -0
  1242. package/clis/slock/thread-follow.test.js +34 -0
  1243. package/clis/slock/thread-list.js +44 -0
  1244. package/clis/slock/thread-list.test.js +24 -0
  1245. package/clis/slock/thread-state.js +45 -0
  1246. package/clis/slock/thread-state.test.js +38 -0
  1247. package/clis/slock/thread-undone.js +9 -0
  1248. package/clis/slock/thread-unfollow.js +9 -0
  1249. package/clis/slock/unread-summary.js +49 -0
  1250. package/clis/slock/unread-summary.test.js +31 -0
  1251. package/clis/slock/whoami.js +12 -0
  1252. package/clis/slock/whoami.test.js +23 -0
  1253. package/clis/smzdm/search.js +149 -0
  1254. package/clis/smzdm/search.test.js +114 -0
  1255. package/clis/spotify/spotify.js +327 -0
  1256. package/clis/spotify/utils.js +66 -0
  1257. package/clis/spotify/utils.test.js +67 -0
  1258. package/clis/stackoverflow/bounties.js +35 -0
  1259. package/clis/stackoverflow/hot.js +32 -0
  1260. package/clis/stackoverflow/read.js +314 -0
  1261. package/clis/stackoverflow/related.js +66 -0
  1262. package/clis/stackoverflow/search.js +35 -0
  1263. package/clis/stackoverflow/stackoverflow.test.js +404 -0
  1264. package/clis/stackoverflow/tag.js +60 -0
  1265. package/clis/stackoverflow/unanswered.js +33 -0
  1266. package/clis/stackoverflow/user.js +50 -0
  1267. package/clis/stackoverflow/utils.js +118 -0
  1268. package/clis/steam/app.js +67 -0
  1269. package/clis/steam/search.js +58 -0
  1270. package/clis/steam/steam.test.js +46 -0
  1271. package/clis/steam/top-sellers.js +26 -0
  1272. package/clis/steam/utils.js +107 -0
  1273. package/clis/substack/feed.js +16 -0
  1274. package/clis/substack/publication.js +16 -0
  1275. package/clis/substack/search.js +79 -0
  1276. package/clis/substack/utils.js +136 -0
  1277. package/clis/substack/utils.test.js +44 -0
  1278. package/clis/suno/auth.js +63 -0
  1279. package/clis/suno/commands.test.js +188 -0
  1280. package/clis/suno/download.js +140 -0
  1281. package/clis/suno/download.test.js +151 -0
  1282. package/clis/suno/generate.js +231 -0
  1283. package/clis/suno/generate.test.js +252 -0
  1284. package/clis/suno/list.js +79 -0
  1285. package/clis/suno/status.js +63 -0
  1286. package/clis/suno/utils.js +549 -0
  1287. package/clis/suno/utils.test.js +329 -0
  1288. package/clis/taobao/add-cart.js +150 -0
  1289. package/clis/taobao/auth.js +58 -0
  1290. package/clis/taobao/cart.js +96 -0
  1291. package/clis/taobao/commands.test.js +41 -0
  1292. package/clis/taobao/detail.js +71 -0
  1293. package/clis/taobao/reviews.js +77 -0
  1294. package/clis/taobao/search.js +97 -0
  1295. package/clis/tdx/hot-rank.js +48 -0
  1296. package/clis/tdx/hot-rank.test.js +59 -0
  1297. package/clis/test-utils.js +61 -0
  1298. package/clis/ths/hot-rank.js +50 -0
  1299. package/clis/ths/hot-rank.test.js +64 -0
  1300. package/clis/tieba/commands.test.js +79 -0
  1301. package/clis/tieba/hot.js +48 -0
  1302. package/clis/tieba/posts.js +86 -0
  1303. package/clis/tieba/read.js +141 -0
  1304. package/clis/tieba/search.js +109 -0
  1305. package/clis/tieba/utils.js +240 -0
  1306. package/clis/tieba/utils.test.js +290 -0
  1307. package/clis/tiktok/auth.js +65 -0
  1308. package/clis/tiktok/comment.js +145 -0
  1309. package/clis/tiktok/creator-videos.js +270 -0
  1310. package/clis/tiktok/creator-videos.test.js +113 -0
  1311. package/clis/tiktok/explore.js +144 -0
  1312. package/clis/tiktok/follow.js +122 -0
  1313. package/clis/tiktok/following.js +164 -0
  1314. package/clis/tiktok/friends.js +146 -0
  1315. package/clis/tiktok/like.js +34 -0
  1316. package/clis/tiktok/live.js +144 -0
  1317. package/clis/tiktok/notifications.js +153 -0
  1318. package/clis/tiktok/profile.js +55 -0
  1319. package/clis/tiktok/refactor.test.js +389 -0
  1320. package/clis/tiktok/save.js +30 -0
  1321. package/clis/tiktok/search.js +40 -0
  1322. package/clis/tiktok/unfollow.js +131 -0
  1323. package/clis/tiktok/unlike.js +34 -0
  1324. package/clis/tiktok/unsave.js +32 -0
  1325. package/clis/tiktok/user.js +216 -0
  1326. package/clis/tiktok/utils.js +505 -0
  1327. package/clis/tiktok/write-refactor.test.js +370 -0
  1328. package/clis/toutiao/articles.js +55 -0
  1329. package/clis/toutiao/auth.js +70 -0
  1330. package/clis/toutiao/hot.js +63 -0
  1331. package/clis/toutiao/toutiao.test.js +378 -0
  1332. package/clis/toutiao/utils.js +161 -0
  1333. package/clis/trae-cn/activity.js +22 -0
  1334. package/clis/trae-cn/approve.js +52 -0
  1335. package/clis/trae-cn/ask.js +99 -0
  1336. package/clis/trae-cn/dump.js +5 -0
  1337. package/clis/trae-cn/export.js +40 -0
  1338. package/clis/trae-cn/model.js +22 -0
  1339. package/clis/trae-cn/new.js +63 -0
  1340. package/clis/trae-cn/read.js +23 -0
  1341. package/clis/trae-cn/screenshot.js +5 -0
  1342. package/clis/trae-cn/select-model.js +25 -0
  1343. package/clis/trae-cn/send.js +23 -0
  1344. package/clis/trae-cn/setup.js +75 -0
  1345. package/clis/trae-cn/status.js +27 -0
  1346. package/clis/trae-cn/targets.js +96 -0
  1347. package/clis/trae-cn/trae-cn.test.js +412 -0
  1348. package/clis/trae-cn/utils.js +750 -0
  1349. package/clis/trae-cn/watch.js +119 -0
  1350. package/clis/trae-solo/_actions.js +60 -0
  1351. package/clis/trae-solo/_fs.js +118 -0
  1352. package/clis/trae-solo/_state.js +111 -0
  1353. package/clis/trae-solo/automation.js +97 -0
  1354. package/clis/trae-solo/history.js +54 -0
  1355. package/clis/trae-solo/mode.js +81 -0
  1356. package/clis/trae-solo/model.js +134 -0
  1357. package/clis/trae-solo/renderer-storage.js +170 -0
  1358. package/clis/trae-solo/settings.js +54 -0
  1359. package/clis/trae-solo/skill-fs.js +123 -0
  1360. package/clis/trae-solo/skill.js +220 -0
  1361. package/clis/trae-solo/state-fs.js +156 -0
  1362. package/clis/trae-solo/status.js +2 -0
  1363. package/clis/trae-solo/task-fs.js +181 -0
  1364. package/clis/trae-solo/trae-solo.test.js +67 -0
  1365. package/clis/trae-solo/user-rules.js +29 -0
  1366. package/clis/trae-solo/workspaces-fs.js +113 -0
  1367. package/clis/tvmaze/search.js +61 -0
  1368. package/clis/tvmaze/show.js +60 -0
  1369. package/clis/tvmaze/tvmaze.test.js +93 -0
  1370. package/clis/tvmaze/utils.js +110 -0
  1371. package/clis/twitter/accept.js +204 -0
  1372. package/clis/twitter/article.js +170 -0
  1373. package/clis/twitter/auth.js +41 -0
  1374. package/clis/twitter/block.js +90 -0
  1375. package/clis/twitter/bookmark-folder.js +190 -0
  1376. package/clis/twitter/bookmark-folder.test.js +396 -0
  1377. package/clis/twitter/bookmark-folders.js +114 -0
  1378. package/clis/twitter/bookmark-folders.test.js +152 -0
  1379. package/clis/twitter/bookmark.js +74 -0
  1380. package/clis/twitter/bookmark.test.js +74 -0
  1381. package/clis/twitter/bookmarks.js +181 -0
  1382. package/clis/twitter/bookmarks.test.js +206 -0
  1383. package/clis/twitter/delete.js +85 -0
  1384. package/clis/twitter/delete.test.js +85 -0
  1385. package/clis/twitter/device-follow.js +194 -0
  1386. package/clis/twitter/device-follow.test.js +287 -0
  1387. package/clis/twitter/download.js +481 -0
  1388. package/clis/twitter/download.test.js +457 -0
  1389. package/clis/twitter/follow-batch.js +162 -0
  1390. package/clis/twitter/follow-batch.test.js +137 -0
  1391. package/clis/twitter/follow.js +67 -0
  1392. package/clis/twitter/followers.js +193 -0
  1393. package/clis/twitter/followers.test.js +62 -0
  1394. package/clis/twitter/following.js +274 -0
  1395. package/clis/twitter/following.test.js +359 -0
  1396. package/clis/twitter/hide-reply.js +87 -0
  1397. package/clis/twitter/hide-reply.test.js +76 -0
  1398. package/clis/twitter/like.js +80 -0
  1399. package/clis/twitter/like.test.js +73 -0
  1400. package/clis/twitter/likes.js +241 -0
  1401. package/clis/twitter/likes.test.js +220 -0
  1402. package/clis/twitter/list-add-batch.js +32 -0
  1403. package/clis/twitter/list-add-core.js +245 -0
  1404. package/clis/twitter/list-add.js +20 -0
  1405. package/clis/twitter/list-add.test.js +133 -0
  1406. package/clis/twitter/list-batch-utils.js +95 -0
  1407. package/clis/twitter/list-batch.test.js +113 -0
  1408. package/clis/twitter/list-create.js +155 -0
  1409. package/clis/twitter/list-create.test.js +169 -0
  1410. package/clis/twitter/list-delete.js +158 -0
  1411. package/clis/twitter/list-delete.test.js +102 -0
  1412. package/clis/twitter/list-remove-batch.js +32 -0
  1413. package/clis/twitter/list-remove-core.js +291 -0
  1414. package/clis/twitter/list-remove.js +20 -0
  1415. package/clis/twitter/list-remove.test.js +147 -0
  1416. package/clis/twitter/list-tweets.js +199 -0
  1417. package/clis/twitter/list-tweets.test.js +198 -0
  1418. package/clis/twitter/lists.js +178 -0
  1419. package/clis/twitter/lists.test.js +253 -0
  1420. package/clis/twitter/notifications.js +128 -0
  1421. package/clis/twitter/post.js +316 -0
  1422. package/clis/twitter/post.test.js +275 -0
  1423. package/clis/twitter/profile.js +174 -0
  1424. package/clis/twitter/profile.test.js +150 -0
  1425. package/clis/twitter/quote.js +172 -0
  1426. package/clis/twitter/quote.test.js +194 -0
  1427. package/clis/twitter/reply-dm.js +183 -0
  1428. package/clis/twitter/reply.js +248 -0
  1429. package/clis/twitter/reply.test.js +237 -0
  1430. package/clis/twitter/retweet.js +94 -0
  1431. package/clis/twitter/retweet.test.js +73 -0
  1432. package/clis/twitter/search.js +346 -0
  1433. package/clis/twitter/search.test.js +400 -0
  1434. package/clis/twitter/shared.js +564 -0
  1435. package/clis/twitter/shared.test.js +1012 -0
  1436. package/clis/twitter/thread.js +164 -0
  1437. package/clis/twitter/thread.test.js +58 -0
  1438. package/clis/twitter/timeline.js +211 -0
  1439. package/clis/twitter/timeline.test.js +104 -0
  1440. package/clis/twitter/trending.js +58 -0
  1441. package/clis/twitter/trending.test.js +15 -0
  1442. package/clis/twitter/tweets.js +314 -0
  1443. package/clis/twitter/tweets.test.js +362 -0
  1444. package/clis/twitter/unblock.js +73 -0
  1445. package/clis/twitter/unbookmark.js +71 -0
  1446. package/clis/twitter/unbookmark.test.js +73 -0
  1447. package/clis/twitter/unfollow.js +73 -0
  1448. package/clis/twitter/unlike.js +80 -0
  1449. package/clis/twitter/unlike.test.js +75 -0
  1450. package/clis/twitter/unretweet.js +94 -0
  1451. package/clis/twitter/unretweet.test.js +73 -0
  1452. package/clis/twitter/utils.js +323 -0
  1453. package/clis/twitter/utils.test.js +169 -0
  1454. package/clis/uisdc/news.js +105 -0
  1455. package/clis/uisdc/news.test.js +66 -0
  1456. package/clis/uiverse/_shared.js +427 -0
  1457. package/clis/uiverse/_shared.test.js +62 -0
  1458. package/clis/uiverse/code.js +49 -0
  1459. package/clis/uiverse/navigation.test.js +12 -0
  1460. package/clis/uiverse/preview.js +73 -0
  1461. package/clis/upwork/auth.js +53 -0
  1462. package/clis/upwork/detail.js +132 -0
  1463. package/clis/upwork/feed.js +109 -0
  1464. package/clis/upwork/search.js +115 -0
  1465. package/clis/upwork/upwork.test.js +566 -0
  1466. package/clis/upwork/utils.js +323 -0
  1467. package/clis/v2ex/auth.js +44 -0
  1468. package/clis/v2ex/daily.js +99 -0
  1469. package/clis/v2ex/hot.js +26 -0
  1470. package/clis/v2ex/latest.js +26 -0
  1471. package/clis/v2ex/me.js +100 -0
  1472. package/clis/v2ex/member.js +28 -0
  1473. package/clis/v2ex/node.js +39 -0
  1474. package/clis/v2ex/nodes.js +26 -0
  1475. package/clis/v2ex/notifications.js +72 -0
  1476. package/clis/v2ex/replies.js +27 -0
  1477. package/clis/v2ex/topic.js +31 -0
  1478. package/clis/v2ex/user.js +34 -0
  1479. package/clis/wanfang/search.js +66 -0
  1480. package/clis/wanfang/search.test.js +23 -0
  1481. package/clis/web/read.js +491 -0
  1482. package/clis/web/read.test.js +392 -0
  1483. package/clis/wechat-channels/auth.js +62 -0
  1484. package/clis/wechat-channels/publish.js +732 -0
  1485. package/clis/wechat-channels/publish.test.js +144 -0
  1486. package/clis/weibo/auth.js +53 -0
  1487. package/clis/weibo/comments.js +53 -0
  1488. package/clis/weibo/delete.js +172 -0
  1489. package/clis/weibo/delete.test.js +94 -0
  1490. package/clis/weibo/envelope.test.js +85 -0
  1491. package/clis/weibo/favorites.js +170 -0
  1492. package/clis/weibo/favorites.test.js +114 -0
  1493. package/clis/weibo/feed.js +69 -0
  1494. package/clis/weibo/hot.js +39 -0
  1495. package/clis/weibo/me.js +75 -0
  1496. package/clis/weibo/post.js +75 -0
  1497. package/clis/weibo/publish.js +306 -0
  1498. package/clis/weibo/publish.test.js +192 -0
  1499. package/clis/weibo/search.js +80 -0
  1500. package/clis/weibo/user-posts.js +234 -0
  1501. package/clis/weibo/user-posts.test.js +92 -0
  1502. package/clis/weibo/user.js +63 -0
  1503. package/clis/weibo/utils.js +59 -0
  1504. package/clis/weibo/utils.test.js +36 -0
  1505. package/clis/weixin/create-draft.js +226 -0
  1506. package/clis/weixin/download.js +371 -0
  1507. package/clis/weixin/download.test.js +106 -0
  1508. package/clis/weixin/drafts.js +66 -0
  1509. package/clis/weixin/drafts.test.js +69 -0
  1510. package/clis/weixin/search.js +157 -0
  1511. package/clis/weixin/search.test.js +227 -0
  1512. package/clis/weread/ai-outline.js +171 -0
  1513. package/clis/weread/ai-outline.test.js +83 -0
  1514. package/clis/weread/auth.js +59 -0
  1515. package/clis/weread/book-search.js +438 -0
  1516. package/clis/weread/book-search.test.js +242 -0
  1517. package/clis/weread/book.js +233 -0
  1518. package/clis/weread/commands.test.js +398 -0
  1519. package/clis/weread/highlights.js +24 -0
  1520. package/clis/weread/notebooks.js +22 -0
  1521. package/clis/weread/notes.js +30 -0
  1522. package/clis/weread/private-api-regression.test.js +369 -0
  1523. package/clis/weread/ranking.js +29 -0
  1524. package/clis/weread/search-regression.test.js +494 -0
  1525. package/clis/weread/search.js +186 -0
  1526. package/clis/weread/shelf.js +66 -0
  1527. package/clis/weread/utils.js +321 -0
  1528. package/clis/weread/utils.test.js +128 -0
  1529. package/clis/weread-official/book.js +135 -0
  1530. package/clis/weread-official/commands.test.js +385 -0
  1531. package/clis/weread-official/discover.js +107 -0
  1532. package/clis/weread-official/list-apis.js +95 -0
  1533. package/clis/weread-official/notes.js +171 -0
  1534. package/clis/weread-official/readdata.js +158 -0
  1535. package/clis/weread-official/review.js +93 -0
  1536. package/clis/weread-official/search.js +106 -0
  1537. package/clis/weread-official/shelf.js +97 -0
  1538. package/clis/weread-official/utils.js +293 -0
  1539. package/clis/weread-official/utils.test.js +242 -0
  1540. package/clis/wikidata/entity.js +60 -0
  1541. package/clis/wikidata/search.js +50 -0
  1542. package/clis/wikidata/utils.js +117 -0
  1543. package/clis/wikidata/wikidata.test.js +83 -0
  1544. package/clis/wikipedia/page.js +95 -0
  1545. package/clis/wikipedia/random.js +20 -0
  1546. package/clis/wikipedia/search.js +31 -0
  1547. package/clis/wikipedia/summary.js +24 -0
  1548. package/clis/wikipedia/trending.js +40 -0
  1549. package/clis/wikipedia/trending.test.js +57 -0
  1550. package/clis/wikipedia/utils.js +31 -0
  1551. package/clis/wttr/current.js +63 -0
  1552. package/clis/wttr/forecast.js +71 -0
  1553. package/clis/wttr/utils.js +50 -0
  1554. package/clis/wttr/wttr.test.js +84 -0
  1555. package/clis/xianyu/auth.js +68 -0
  1556. package/clis/xianyu/chat.js +74 -0
  1557. package/clis/xianyu/chat.test.js +84 -0
  1558. package/clis/xianyu/im.js +322 -0
  1559. package/clis/xianyu/im.test.js +253 -0
  1560. package/clis/xianyu/inbox.js +96 -0
  1561. package/clis/xianyu/item.js +153 -0
  1562. package/clis/xianyu/item.test.js +56 -0
  1563. package/clis/xianyu/messages.js +91 -0
  1564. package/clis/xianyu/publish.js +485 -0
  1565. package/clis/xianyu/publish.test.js +220 -0
  1566. package/clis/xianyu/reply.js +82 -0
  1567. package/clis/xianyu/search.js +135 -0
  1568. package/clis/xianyu/search.test.js +17 -0
  1569. package/clis/xianyu/utils.js +8 -0
  1570. package/clis/xiaoe/auth.js +55 -0
  1571. package/clis/xiaoe/catalog.js +227 -0
  1572. package/clis/xiaoe/content.js +175 -0
  1573. package/clis/xiaoe/courses.js +127 -0
  1574. package/clis/xiaoe/detail.js +36 -0
  1575. package/clis/xiaoe/play-url.js +121 -0
  1576. package/clis/xiaoe/xiaoe.test.js +486 -0
  1577. package/clis/xiaohongshu/ask.js +426 -0
  1578. package/clis/xiaohongshu/ask.test.js +271 -0
  1579. package/clis/xiaohongshu/auth.js +53 -0
  1580. package/clis/xiaohongshu/collection-helpers.js +283 -0
  1581. package/clis/xiaohongshu/collection-helpers.test.js +125 -0
  1582. package/clis/xiaohongshu/comments.js +228 -0
  1583. package/clis/xiaohongshu/comments.test.js +320 -0
  1584. package/clis/xiaohongshu/creator-note-detail.js +482 -0
  1585. package/clis/xiaohongshu/creator-note-detail.test.js +451 -0
  1586. package/clis/xiaohongshu/creator-notes-summary.js +98 -0
  1587. package/clis/xiaohongshu/creator-notes-summary.test.js +94 -0
  1588. package/clis/xiaohongshu/creator-notes.js +479 -0
  1589. package/clis/xiaohongshu/creator-notes.test.js +281 -0
  1590. package/clis/xiaohongshu/creator-profile.js +55 -0
  1591. package/clis/xiaohongshu/creator-stats.js +76 -0
  1592. package/clis/xiaohongshu/creator-stats.test.js +24 -0
  1593. package/clis/xiaohongshu/delete-note.js +260 -0
  1594. package/clis/xiaohongshu/delete-note.test.js +172 -0
  1595. package/clis/xiaohongshu/download.js +249 -0
  1596. package/clis/xiaohongshu/download.test.js +339 -0
  1597. package/clis/xiaohongshu/draft-clear.js +91 -0
  1598. package/clis/xiaohongshu/draft-delete.js +103 -0
  1599. package/clis/xiaohongshu/draft-open.js +43 -0
  1600. package/clis/xiaohongshu/draft-utils.js +142 -0
  1601. package/clis/xiaohongshu/drafts.js +28 -0
  1602. package/clis/xiaohongshu/drafts.test.js +172 -0
  1603. package/clis/xiaohongshu/feed.js +163 -0
  1604. package/clis/xiaohongshu/feed.test.js +126 -0
  1605. package/clis/xiaohongshu/follow.js +226 -0
  1606. package/clis/xiaohongshu/follow.test.js +211 -0
  1607. package/clis/xiaohongshu/liked.js +29 -0
  1608. package/clis/xiaohongshu/liked.test.js +82 -0
  1609. package/clis/xiaohongshu/navigation.test.js +38 -0
  1610. package/clis/xiaohongshu/note-helpers.js +69 -0
  1611. package/clis/xiaohongshu/note.js +104 -0
  1612. package/clis/xiaohongshu/note.test.js +249 -0
  1613. package/clis/xiaohongshu/notifications.js +46 -0
  1614. package/clis/xiaohongshu/publish.js +1423 -0
  1615. package/clis/xiaohongshu/publish.test.js +1141 -0
  1616. package/clis/xiaohongshu/saved.js +29 -0
  1617. package/clis/xiaohongshu/saved.test.js +143 -0
  1618. package/clis/xiaohongshu/search.js +330 -0
  1619. package/clis/xiaohongshu/search.test.js +325 -0
  1620. package/clis/xiaohongshu/unfollow.js +285 -0
  1621. package/clis/xiaohongshu/user-helpers.js +78 -0
  1622. package/clis/xiaohongshu/user-helpers.test.js +160 -0
  1623. package/clis/xiaohongshu/user.js +140 -0
  1624. package/clis/xiaohongshu/user.test.js +141 -0
  1625. package/clis/xiaoyuzhou/auth.js +303 -0
  1626. package/clis/xiaoyuzhou/auth.test.js +124 -0
  1627. package/clis/xiaoyuzhou/download.js +54 -0
  1628. package/clis/xiaoyuzhou/download.test.js +135 -0
  1629. package/clis/xiaoyuzhou/episode.js +34 -0
  1630. package/clis/xiaoyuzhou/podcast-episodes.js +41 -0
  1631. package/clis/xiaoyuzhou/podcast-episodes.test.js +78 -0
  1632. package/clis/xiaoyuzhou/podcast.js +33 -0
  1633. package/clis/xiaoyuzhou/transcript.js +77 -0
  1634. package/clis/xiaoyuzhou/transcript.test.js +195 -0
  1635. package/clis/xiaoyuzhou/utils.js +15 -0
  1636. package/clis/xiaoyuzhou/utils.test.js +39 -0
  1637. package/clis/xueqiu/auth.js +63 -0
  1638. package/clis/xueqiu/comments.js +355 -0
  1639. package/clis/xueqiu/comments.test.js +696 -0
  1640. package/clis/xueqiu/danjuan-utils.js +126 -0
  1641. package/clis/xueqiu/danjuan-utils.test.js +41 -0
  1642. package/clis/xueqiu/earnings-date.js +45 -0
  1643. package/clis/xueqiu/feed.js +39 -0
  1644. package/clis/xueqiu/fund-holdings.js +29 -0
  1645. package/clis/xueqiu/fund-snapshot.js +26 -0
  1646. package/clis/xueqiu/groups.js +23 -0
  1647. package/clis/xueqiu/hot-stock.js +32 -0
  1648. package/clis/xueqiu/hot.js +37 -0
  1649. package/clis/xueqiu/kline.js +44 -0
  1650. package/clis/xueqiu/search.js +37 -0
  1651. package/clis/xueqiu/stock.js +65 -0
  1652. package/clis/xueqiu/utils.js +48 -0
  1653. package/clis/xueqiu/utils.test.js +26 -0
  1654. package/clis/xueqiu/watchlist.js +37 -0
  1655. package/clis/yahoo/search.js +92 -0
  1656. package/clis/yahoo/search.test.js +94 -0
  1657. package/clis/yahoo-finance/quote.js +74 -0
  1658. package/clis/yollomi/background.js +46 -0
  1659. package/clis/yollomi/edit.js +57 -0
  1660. package/clis/yollomi/face-swap.js +44 -0
  1661. package/clis/yollomi/generate.js +101 -0
  1662. package/clis/yollomi/models.js +34 -0
  1663. package/clis/yollomi/object-remover.js +43 -0
  1664. package/clis/yollomi/remove-bg.js +39 -0
  1665. package/clis/yollomi/restore.js +39 -0
  1666. package/clis/yollomi/try-on.js +47 -0
  1667. package/clis/yollomi/upload.js +72 -0
  1668. package/clis/yollomi/upscale.js +54 -0
  1669. package/clis/yollomi/utils.js +180 -0
  1670. package/clis/yollomi/video.js +57 -0
  1671. package/clis/youdao/note.js +258 -0
  1672. package/clis/youdao/note.test.js +99 -0
  1673. package/clis/youtube/auth.js +54 -0
  1674. package/clis/youtube/channel.js +227 -0
  1675. package/clis/youtube/channel.test.js +283 -0
  1676. package/clis/youtube/comments.js +96 -0
  1677. package/clis/youtube/feed.js +121 -0
  1678. package/clis/youtube/feed.test.js +131 -0
  1679. package/clis/youtube/history.js +119 -0
  1680. package/clis/youtube/like.js +67 -0
  1681. package/clis/youtube/playlist.js +98 -0
  1682. package/clis/youtube/search.js +100 -0
  1683. package/clis/youtube/subscribe.js +76 -0
  1684. package/clis/youtube/subscriptions.js +58 -0
  1685. package/clis/youtube/transcript-group.js +226 -0
  1686. package/clis/youtube/transcript-group.test.js +99 -0
  1687. package/clis/youtube/transcript.js +656 -0
  1688. package/clis/youtube/transcript.test.js +296 -0
  1689. package/clis/youtube/unlike.js +67 -0
  1690. package/clis/youtube/unsubscribe.js +76 -0
  1691. package/clis/youtube/utils.js +220 -0
  1692. package/clis/youtube/utils.test.js +84 -0
  1693. package/clis/youtube/video.js +152 -0
  1694. package/clis/youtube/video.test.js +111 -0
  1695. package/clis/youtube/watch-later.js +77 -0
  1696. package/clis/yuanbao/ask.js +362 -0
  1697. package/clis/yuanbao/ask.test.js +124 -0
  1698. package/clis/yuanbao/auth.js +59 -0
  1699. package/clis/yuanbao/detail.js +65 -0
  1700. package/clis/yuanbao/history.js +51 -0
  1701. package/clis/yuanbao/new.js +72 -0
  1702. package/clis/yuanbao/new.test.js +30 -0
  1703. package/clis/yuanbao/read.js +38 -0
  1704. package/clis/yuanbao/send.js +57 -0
  1705. package/clis/yuanbao/shared.js +341 -0
  1706. package/clis/yuanbao/shared.test.js +80 -0
  1707. package/clis/yuanbao/status.js +44 -0
  1708. package/clis/zhihu/answer-comments.js +280 -0
  1709. package/clis/zhihu/answer-comments.test.js +287 -0
  1710. package/clis/zhihu/answer-detail.js +216 -0
  1711. package/clis/zhihu/answer-detail.test.js +338 -0
  1712. package/clis/zhihu/answer.js +54 -0
  1713. package/clis/zhihu/answer.test.js +54 -0
  1714. package/clis/zhihu/auth.js +59 -0
  1715. package/clis/zhihu/collection.js +199 -0
  1716. package/clis/zhihu/collection.test.js +337 -0
  1717. package/clis/zhihu/collections.js +128 -0
  1718. package/clis/zhihu/collections.test.js +182 -0
  1719. package/clis/zhihu/comment.js +55 -0
  1720. package/clis/zhihu/comment.test.js +50 -0
  1721. package/clis/zhihu/download.js +80 -0
  1722. package/clis/zhihu/download.test.js +12 -0
  1723. package/clis/zhihu/favorite.js +87 -0
  1724. package/clis/zhihu/favorite.test.js +59 -0
  1725. package/clis/zhihu/follow.js +50 -0
  1726. package/clis/zhihu/follow.test.js +42 -0
  1727. package/clis/zhihu/followers.js +40 -0
  1728. package/clis/zhihu/followers.test.js +42 -0
  1729. package/clis/zhihu/following.js +40 -0
  1730. package/clis/zhihu/following.test.js +44 -0
  1731. package/clis/zhihu/hot.js +44 -0
  1732. package/clis/zhihu/like.js +47 -0
  1733. package/clis/zhihu/like.test.js +41 -0
  1734. package/clis/zhihu/paginate.js +128 -0
  1735. package/clis/zhihu/pins.js +41 -0
  1736. package/clis/zhihu/pins.test.js +44 -0
  1737. package/clis/zhihu/question.js +113 -0
  1738. package/clis/zhihu/question.test.js +251 -0
  1739. package/clis/zhihu/recommend.js +103 -0
  1740. package/clis/zhihu/recommend.test.js +143 -0
  1741. package/clis/zhihu/search.js +206 -0
  1742. package/clis/zhihu/search.test.js +198 -0
  1743. package/clis/zhihu/target.js +91 -0
  1744. package/clis/zhihu/target.test.js +77 -0
  1745. package/clis/zhihu/text.js +29 -0
  1746. package/clis/zhihu/text.test.js +24 -0
  1747. package/clis/zhihu/user-answers.js +41 -0
  1748. package/clis/zhihu/user-answers.test.js +69 -0
  1749. package/clis/zhihu/user-arg.js +34 -0
  1750. package/clis/zhihu/user-articles.js +40 -0
  1751. package/clis/zhihu/user-articles.test.js +44 -0
  1752. package/clis/zhihu/user.js +59 -0
  1753. package/clis/zhihu/user.test.js +73 -0
  1754. package/clis/zhihu/write-shared.js +228 -0
  1755. package/clis/zhihu/write-shared.test.js +176 -0
  1756. package/clis/zlibrary/commands.test.js +65 -0
  1757. package/clis/zlibrary/info.js +48 -0
  1758. package/clis/zlibrary/search.js +47 -0
  1759. package/clis/zlibrary/utils.js +136 -0
  1760. package/clis/zsxq/auth.js +68 -0
  1761. package/clis/zsxq/dynamics.js +48 -0
  1762. package/clis/zsxq/groups.js +33 -0
  1763. package/clis/zsxq/search.js +44 -0
  1764. package/clis/zsxq/search.test.js +24 -0
  1765. package/clis/zsxq/topic.js +50 -0
  1766. package/clis/zsxq/topic.test.js +30 -0
  1767. package/clis/zsxq/topics.js +26 -0
  1768. package/clis/zsxq/topics.test.js +24 -0
  1769. package/clis/zsxq/utils.js +233 -0
  1770. package/clis/zsxq/utils.test.js +31 -0
  1771. package/dist/src/adapter-shadow.d.ts +11 -0
  1772. package/dist/src/adapter-shadow.js +72 -0
  1773. package/dist/src/adapter-shadow.test.d.ts +1 -0
  1774. package/dist/src/adapter-shadow.test.js +49 -0
  1775. package/dist/src/adapter-source.d.ts +11 -0
  1776. package/dist/src/adapter-source.js +24 -0
  1777. package/dist/src/adapter-source.test.d.ts +1 -0
  1778. package/dist/src/adapter-source.test.js +29 -0
  1779. package/dist/src/browser/analyze.d.ts +118 -0
  1780. package/dist/src/browser/analyze.js +405 -0
  1781. package/dist/src/browser/analyze.test.d.ts +1 -0
  1782. package/dist/src/browser/analyze.test.js +209 -0
  1783. package/dist/src/browser/article-extract.d.ts +57 -0
  1784. package/dist/src/browser/article-extract.e2e.test.d.ts +1 -0
  1785. package/dist/src/browser/article-extract.e2e.test.js +105 -0
  1786. package/dist/src/browser/article-extract.js +169 -0
  1787. package/dist/src/browser/article-extract.test.d.ts +1 -0
  1788. package/dist/src/browser/article-extract.test.js +94 -0
  1789. package/dist/src/browser/ax-snapshot.d.ts +37 -0
  1790. package/dist/src/browser/ax-snapshot.js +217 -0
  1791. package/dist/src/browser/ax-snapshot.test.d.ts +1 -0
  1792. package/dist/src/browser/ax-snapshot.test.js +91 -0
  1793. package/dist/src/browser/base-page.d.ts +151 -0
  1794. package/dist/src/browser/base-page.js +1060 -0
  1795. package/dist/src/browser/base-page.test.d.ts +1 -0
  1796. package/dist/src/browser/base-page.test.js +803 -0
  1797. package/dist/src/browser/bridge.d.ts +28 -0
  1798. package/dist/src/browser/bridge.js +172 -0
  1799. package/dist/src/browser/cdp-click-fixture.test.d.ts +1 -0
  1800. package/dist/src/browser/cdp-click-fixture.test.js +87 -0
  1801. package/dist/src/browser/cdp.d.ts +46 -0
  1802. package/dist/src/browser/cdp.js +536 -0
  1803. package/dist/src/browser/cdp.test.d.ts +1 -0
  1804. package/dist/src/browser/cdp.test.js +79 -0
  1805. package/dist/src/browser/compound.d.ts +59 -0
  1806. package/dist/src/browser/compound.js +112 -0
  1807. package/dist/src/browser/compound.test.d.ts +1 -0
  1808. package/dist/src/browser/compound.test.js +175 -0
  1809. package/dist/src/browser/daemon-client.d.ts +133 -0
  1810. package/dist/src/browser/daemon-client.js +154 -0
  1811. package/dist/src/browser/daemon-client.test.d.ts +1 -0
  1812. package/dist/src/browser/daemon-client.test.js +199 -0
  1813. package/dist/src/browser/daemon-lifecycle.d.ts +23 -0
  1814. package/dist/src/browser/daemon-lifecycle.js +67 -0
  1815. package/dist/src/browser/daemon-version.d.ts +4 -0
  1816. package/dist/src/browser/daemon-version.js +12 -0
  1817. package/dist/src/browser/dom-helpers.d.ts +41 -0
  1818. package/dist/src/browser/dom-helpers.js +239 -0
  1819. package/dist/src/browser/dom-helpers.test.d.ts +1 -0
  1820. package/dist/src/browser/dom-helpers.test.js +106 -0
  1821. package/dist/src/browser/dom-snapshot.d.ts +93 -0
  1822. package/dist/src/browser/dom-snapshot.js +894 -0
  1823. package/dist/src/browser/dom-snapshot.test.d.ts +11 -0
  1824. package/dist/src/browser/dom-snapshot.test.js +313 -0
  1825. package/dist/src/browser/errors.d.ts +38 -0
  1826. package/dist/src/browser/errors.js +78 -0
  1827. package/dist/src/browser/errors.test.d.ts +1 -0
  1828. package/dist/src/browser/errors.test.js +60 -0
  1829. package/dist/src/browser/extract.d.ts +69 -0
  1830. package/dist/src/browser/extract.js +132 -0
  1831. package/dist/src/browser/extract.test.d.ts +1 -0
  1832. package/dist/src/browser/extract.test.js +129 -0
  1833. package/dist/src/browser/find.d.ts +84 -0
  1834. package/dist/src/browser/find.js +398 -0
  1835. package/dist/src/browser/find.test.d.ts +1 -0
  1836. package/dist/src/browser/find.test.js +180 -0
  1837. package/dist/src/browser/html-tree.d.ts +75 -0
  1838. package/dist/src/browser/html-tree.js +112 -0
  1839. package/dist/src/browser/html-tree.test.d.ts +1 -0
  1840. package/dist/src/browser/html-tree.test.js +181 -0
  1841. package/dist/src/browser/index.d.ts +14 -0
  1842. package/dist/src/browser/index.js +12 -0
  1843. package/dist/src/browser/network-cache.d.ts +49 -0
  1844. package/dist/src/browser/network-cache.js +78 -0
  1845. package/dist/src/browser/network-cache.test.d.ts +1 -0
  1846. package/dist/src/browser/network-cache.test.js +75 -0
  1847. package/dist/src/browser/network-key.d.ts +22 -0
  1848. package/dist/src/browser/network-key.js +66 -0
  1849. package/dist/src/browser/network-key.test.d.ts +1 -0
  1850. package/dist/src/browser/network-key.test.js +49 -0
  1851. package/dist/src/browser/page.d.ts +83 -0
  1852. package/dist/src/browser/page.js +453 -0
  1853. package/dist/src/browser/page.test.d.ts +1 -0
  1854. package/dist/src/browser/page.test.js +406 -0
  1855. package/dist/src/browser/profile.d.ts +14 -0
  1856. package/dist/src/browser/profile.js +85 -0
  1857. package/dist/src/browser/shape-filter.d.ts +52 -0
  1858. package/dist/src/browser/shape-filter.js +101 -0
  1859. package/dist/src/browser/shape-filter.test.d.ts +1 -0
  1860. package/dist/src/browser/shape-filter.test.js +101 -0
  1861. package/dist/src/browser/shape.d.ts +23 -0
  1862. package/dist/src/browser/shape.js +95 -0
  1863. package/dist/src/browser/shape.test.d.ts +1 -0
  1864. package/dist/src/browser/shape.test.js +82 -0
  1865. package/dist/src/browser/stealth.d.ts +11 -0
  1866. package/dist/src/browser/stealth.js +359 -0
  1867. package/dist/src/browser/stealth.test.d.ts +1 -0
  1868. package/dist/src/browser/stealth.test.js +134 -0
  1869. package/dist/src/browser/tabs.d.ts +13 -0
  1870. package/dist/src/browser/tabs.js +70 -0
  1871. package/dist/src/browser/target-errors.d.ts +39 -0
  1872. package/dist/src/browser/target-errors.js +45 -0
  1873. package/dist/src/browser/target-errors.test.d.ts +1 -0
  1874. package/dist/src/browser/target-errors.test.js +94 -0
  1875. package/dist/src/browser/target-resolver.d.ts +158 -0
  1876. package/dist/src/browser/target-resolver.js +570 -0
  1877. package/dist/src/browser/target-resolver.test.d.ts +1 -0
  1878. package/dist/src/browser/target-resolver.test.js +118 -0
  1879. package/dist/src/browser/utils.d.ts +20 -0
  1880. package/dist/src/browser/utils.js +64 -0
  1881. package/dist/src/browser/utils.test.d.ts +1 -0
  1882. package/dist/src/browser/utils.test.js +29 -0
  1883. package/dist/src/browser/verify-fixture.d.ts +65 -0
  1884. package/dist/src/browser/verify-fixture.js +318 -0
  1885. package/dist/src/browser/verify-fixture.test.d.ts +1 -0
  1886. package/dist/src/browser/verify-fixture.test.js +219 -0
  1887. package/dist/src/browser/visual-refs.d.ts +11 -0
  1888. package/dist/src/browser/visual-refs.js +108 -0
  1889. package/dist/src/browser.test.d.ts +1 -0
  1890. package/dist/src/browser.test.js +287 -0
  1891. package/dist/src/build-manifest.d.ts +103 -0
  1892. package/dist/src/build-manifest.js +363 -0
  1893. package/dist/src/build-manifest.test.d.ts +1 -0
  1894. package/dist/src/build-manifest.test.js +341 -0
  1895. package/dist/src/capabilityRouting.d.ts +19 -0
  1896. package/dist/src/capabilityRouting.js +56 -0
  1897. package/dist/src/capabilityRouting.test.d.ts +1 -0
  1898. package/dist/src/capabilityRouting.test.js +63 -0
  1899. package/dist/src/cli-argv-preprocess.d.ts +63 -0
  1900. package/dist/src/cli-argv-preprocess.js +303 -0
  1901. package/dist/src/cli-argv-preprocess.test.d.ts +1 -0
  1902. package/dist/src/cli-argv-preprocess.test.js +304 -0
  1903. package/dist/src/cli.d.ts +79 -0
  1904. package/dist/src/cli.js +3357 -0
  1905. package/dist/src/cli.test.d.ts +1 -0
  1906. package/dist/src/cli.test.js +3003 -0
  1907. package/dist/src/commanderAdapter.d.ts +21 -0
  1908. package/dist/src/commanderAdapter.js +208 -0
  1909. package/dist/src/commanderAdapter.test.d.ts +1 -0
  1910. package/dist/src/commanderAdapter.test.js +352 -0
  1911. package/dist/src/commands/auth.d.ts +40 -0
  1912. package/dist/src/commands/auth.js +434 -0
  1913. package/dist/src/commands/auth.test.d.ts +1 -0
  1914. package/dist/src/commands/auth.test.js +252 -0
  1915. package/dist/src/commands/daemon.d.ts +9 -0
  1916. package/dist/src/commands/daemon.js +98 -0
  1917. package/dist/src/commands/daemon.test.d.ts +1 -0
  1918. package/dist/src/commands/daemon.test.js +283 -0
  1919. package/dist/src/completion-fast.d.ts +22 -0
  1920. package/dist/src/completion-fast.js +88 -0
  1921. package/dist/src/completion-shared.d.ts +13 -0
  1922. package/dist/src/completion-shared.js +60 -0
  1923. package/dist/src/completion.d.ts +21 -0
  1924. package/dist/src/completion.js +68 -0
  1925. package/dist/src/completion.test.d.ts +1 -0
  1926. package/dist/src/completion.test.js +24 -0
  1927. package/dist/src/constants.d.ts +15 -0
  1928. package/dist/src/constants.js +32 -0
  1929. package/dist/src/convention-audit.d.ts +50 -0
  1930. package/dist/src/convention-audit.js +553 -0
  1931. package/dist/src/convention-audit.test.d.ts +1 -0
  1932. package/dist/src/convention-audit.test.js +247 -0
  1933. package/dist/src/daemon-utils.d.ts +18 -0
  1934. package/dist/src/daemon-utils.js +37 -0
  1935. package/dist/src/daemon.d.ts +22 -0
  1936. package/dist/src/daemon.js +437 -0
  1937. package/dist/src/daemon.test.d.ts +1 -0
  1938. package/dist/src/daemon.test.js +60 -0
  1939. package/dist/src/discovery.d.ts +43 -0
  1940. package/dist/src/discovery.js +266 -0
  1941. package/dist/src/doctor.d.ts +39 -0
  1942. package/dist/src/doctor.js +230 -0
  1943. package/dist/src/doctor.test.d.ts +1 -0
  1944. package/dist/src/doctor.test.js +263 -0
  1945. package/dist/src/download/article-download.d.ts +72 -0
  1946. package/dist/src/download/article-download.js +305 -0
  1947. package/dist/src/download/article-download.test.d.ts +1 -0
  1948. package/dist/src/download/article-download.test.js +235 -0
  1949. package/dist/src/download/index.d.ts +71 -0
  1950. package/dist/src/download/index.js +363 -0
  1951. package/dist/src/download/index.test.d.ts +1 -0
  1952. package/dist/src/download/index.test.js +174 -0
  1953. package/dist/src/download/media-download.d.ts +49 -0
  1954. package/dist/src/download/media-download.js +127 -0
  1955. package/dist/src/download/media-download.test.d.ts +1 -0
  1956. package/dist/src/download/media-download.test.js +112 -0
  1957. package/dist/src/download/progress.d.ts +36 -0
  1958. package/dist/src/download/progress.js +120 -0
  1959. package/dist/src/download/progress.test.d.ts +1 -0
  1960. package/dist/src/download/progress.test.js +36 -0
  1961. package/dist/src/electron-apps.d.ts +31 -0
  1962. package/dist/src/electron-apps.js +91 -0
  1963. package/dist/src/electron-apps.test.d.ts +1 -0
  1964. package/dist/src/electron-apps.test.js +76 -0
  1965. package/dist/src/engine.test.d.ts +1 -0
  1966. package/dist/src/engine.test.js +312 -0
  1967. package/dist/src/errors.d.ts +114 -0
  1968. package/dist/src/errors.js +174 -0
  1969. package/dist/src/errors.test.d.ts +1 -0
  1970. package/dist/src/errors.test.js +109 -0
  1971. package/dist/src/execution.d.ts +24 -0
  1972. package/dist/src/execution.js +509 -0
  1973. package/dist/src/execution.test.d.ts +1 -0
  1974. package/dist/src/execution.test.js +645 -0
  1975. package/dist/src/extension-manifest-regression.test.d.ts +1 -0
  1976. package/dist/src/extension-manifest-regression.test.js +12 -0
  1977. package/dist/src/external-clis.yaml +109 -0
  1978. package/dist/src/external.d.ts +49 -0
  1979. package/dist/src/external.js +211 -0
  1980. package/dist/src/external.test.d.ts +1 -0
  1981. package/dist/src/external.test.js +110 -0
  1982. package/dist/src/help.d.ts +88 -0
  1983. package/dist/src/help.js +555 -0
  1984. package/dist/src/help.test.d.ts +1 -0
  1985. package/dist/src/help.test.js +58 -0
  1986. package/dist/src/hooks.d.ts +46 -0
  1987. package/dist/src/hooks.js +58 -0
  1988. package/dist/src/hooks.test.d.ts +4 -0
  1989. package/dist/src/hooks.test.js +92 -0
  1990. package/dist/src/interceptor.d.ts +44 -0
  1991. package/dist/src/interceptor.js +183 -0
  1992. package/dist/src/interceptor.test.d.ts +4 -0
  1993. package/dist/src/interceptor.test.js +81 -0
  1994. package/dist/src/launcher.d.ts +41 -0
  1995. package/dist/src/launcher.js +226 -0
  1996. package/dist/src/launcher.test.d.ts +1 -0
  1997. package/dist/src/launcher.test.js +153 -0
  1998. package/dist/src/logger.d.ts +26 -0
  1999. package/dist/src/logger.js +49 -0
  2000. package/dist/src/main.d.ts +5 -0
  2001. package/dist/src/main.js +171 -0
  2002. package/dist/src/manifest-types.d.ts +43 -0
  2003. package/dist/src/manifest-types.js +9 -0
  2004. package/dist/src/node-network.d.ts +10 -0
  2005. package/dist/src/node-network.js +174 -0
  2006. package/dist/src/node-network.test.d.ts +1 -0
  2007. package/dist/src/node-network.test.js +55 -0
  2008. package/dist/src/observation/artifact.d.ts +16 -0
  2009. package/dist/src/observation/artifact.js +260 -0
  2010. package/dist/src/observation/artifact.test.d.ts +1 -0
  2011. package/dist/src/observation/artifact.test.js +121 -0
  2012. package/dist/src/observation/events.d.ts +89 -0
  2013. package/dist/src/observation/events.js +1 -0
  2014. package/dist/src/observation/index.d.ts +7 -0
  2015. package/dist/src/observation/index.js +7 -0
  2016. package/dist/src/observation/manager.d.ts +9 -0
  2017. package/dist/src/observation/manager.js +27 -0
  2018. package/dist/src/observation/manager.test.d.ts +1 -0
  2019. package/dist/src/observation/manager.test.js +13 -0
  2020. package/dist/src/observation/redaction.d.ts +11 -0
  2021. package/dist/src/observation/redaction.js +81 -0
  2022. package/dist/src/observation/redaction.test.d.ts +1 -0
  2023. package/dist/src/observation/redaction.test.js +32 -0
  2024. package/dist/src/observation/retention.d.ts +32 -0
  2025. package/dist/src/observation/retention.js +160 -0
  2026. package/dist/src/observation/retention.test.d.ts +1 -0
  2027. package/dist/src/observation/retention.test.js +118 -0
  2028. package/dist/src/observation/ring-buffer.d.ts +22 -0
  2029. package/dist/src/observation/ring-buffer.js +45 -0
  2030. package/dist/src/observation/ring-buffer.test.d.ts +1 -0
  2031. package/dist/src/observation/ring-buffer.test.js +22 -0
  2032. package/dist/src/observation/session.d.ts +25 -0
  2033. package/dist/src/observation/session.js +50 -0
  2034. package/dist/src/output.d.ts +14 -0
  2035. package/dist/src/output.js +152 -0
  2036. package/dist/src/output.test.d.ts +1 -0
  2037. package/dist/src/output.test.js +53 -0
  2038. package/dist/src/package-exports.test.d.ts +1 -0
  2039. package/dist/src/package-exports.test.js +112 -0
  2040. package/dist/src/package-paths.d.ts +8 -0
  2041. package/dist/src/package-paths.js +41 -0
  2042. package/dist/src/pipeline/executor.d.ts +11 -0
  2043. package/dist/src/pipeline/executor.js +93 -0
  2044. package/dist/src/pipeline/executor.test.d.ts +4 -0
  2045. package/dist/src/pipeline/executor.test.js +182 -0
  2046. package/dist/src/pipeline/index.d.ts +5 -0
  2047. package/dist/src/pipeline/index.js +5 -0
  2048. package/dist/src/pipeline/registry.d.ts +28 -0
  2049. package/dist/src/pipeline/registry.js +55 -0
  2050. package/dist/src/pipeline/steps/browser.d.ts +13 -0
  2051. package/dist/src/pipeline/steps/browser.js +86 -0
  2052. package/dist/src/pipeline/steps/download.d.ts +18 -0
  2053. package/dist/src/pipeline/steps/download.js +252 -0
  2054. package/dist/src/pipeline/steps/download.test.d.ts +1 -0
  2055. package/dist/src/pipeline/steps/download.test.js +102 -0
  2056. package/dist/src/pipeline/steps/fetch.d.ts +5 -0
  2057. package/dist/src/pipeline/steps/fetch.js +122 -0
  2058. package/dist/src/pipeline/steps/fetch.test.d.ts +1 -0
  2059. package/dist/src/pipeline/steps/fetch.test.js +117 -0
  2060. package/dist/src/pipeline/steps/intercept.d.ts +5 -0
  2061. package/dist/src/pipeline/steps/intercept.js +50 -0
  2062. package/dist/src/pipeline/steps/tap.d.ts +12 -0
  2063. package/dist/src/pipeline/steps/tap.js +93 -0
  2064. package/dist/src/pipeline/steps/transform.d.ts +9 -0
  2065. package/dist/src/pipeline/steps/transform.js +70 -0
  2066. package/dist/src/pipeline/template.d.ts +17 -0
  2067. package/dist/src/pipeline/template.js +338 -0
  2068. package/dist/src/pipeline/template.test.d.ts +4 -0
  2069. package/dist/src/pipeline/template.test.js +175 -0
  2070. package/dist/src/pipeline/transform.test.d.ts +4 -0
  2071. package/dist/src/pipeline/transform.test.js +133 -0
  2072. package/dist/src/plugin-manifest.d.ts +70 -0
  2073. package/dist/src/plugin-manifest.js +160 -0
  2074. package/dist/src/plugin-manifest.test.d.ts +4 -0
  2075. package/dist/src/plugin-manifest.test.js +179 -0
  2076. package/dist/src/plugin-scaffold.d.ts +28 -0
  2077. package/dist/src/plugin-scaffold.js +143 -0
  2078. package/dist/src/plugin-scaffold.test.d.ts +4 -0
  2079. package/dist/src/plugin-scaffold.test.js +83 -0
  2080. package/dist/src/plugin.d.ts +145 -0
  2081. package/dist/src/plugin.js +1245 -0
  2082. package/dist/src/plugin.test.d.ts +4 -0
  2083. package/dist/src/plugin.test.js +1324 -0
  2084. package/dist/src/registry-api.d.ts +13 -0
  2085. package/dist/src/registry-api.js +10 -0
  2086. package/dist/src/registry.d.ts +123 -0
  2087. package/dist/src/registry.js +125 -0
  2088. package/dist/src/registry.test.d.ts +4 -0
  2089. package/dist/src/registry.test.js +209 -0
  2090. package/dist/src/runtime-detect.d.ts +31 -0
  2091. package/dist/src/runtime-detect.js +47 -0
  2092. package/dist/src/runtime-detect.test.d.ts +1 -0
  2093. package/dist/src/runtime-detect.test.js +39 -0
  2094. package/dist/src/runtime.d.ts +47 -0
  2095. package/dist/src/runtime.js +66 -0
  2096. package/dist/src/scripts/framework.d.ts +7 -0
  2097. package/dist/src/scripts/framework.js +25 -0
  2098. package/dist/src/scripts/interact.d.ts +4 -0
  2099. package/dist/src/scripts/interact.js +20 -0
  2100. package/dist/src/scripts/store.d.ts +13 -0
  2101. package/dist/src/scripts/store.js +48 -0
  2102. package/dist/src/serialization.d.ts +42 -0
  2103. package/dist/src/serialization.js +102 -0
  2104. package/dist/src/serialization.test.d.ts +1 -0
  2105. package/dist/src/serialization.test.js +78 -0
  2106. package/dist/src/skills.d.ts +14 -0
  2107. package/dist/src/skills.js +127 -0
  2108. package/dist/src/skills.test.d.ts +1 -0
  2109. package/dist/src/skills.test.js +71 -0
  2110. package/dist/src/snapshotFormatter.d.ts +11 -0
  2111. package/dist/src/snapshotFormatter.js +338 -0
  2112. package/dist/src/snapshotFormatter.test.d.ts +7 -0
  2113. package/dist/src/snapshotFormatter.test.js +521 -0
  2114. package/dist/src/tui.d.ts +28 -0
  2115. package/dist/src/tui.js +179 -0
  2116. package/dist/src/tui.test.d.ts +1 -0
  2117. package/dist/src/tui.test.js +19 -0
  2118. package/dist/src/types.d.ts +236 -0
  2119. package/dist/src/types.js +7 -0
  2120. package/dist/src/update-check.d.ts +66 -0
  2121. package/dist/src/update-check.js +202 -0
  2122. package/dist/src/update-check.test.d.ts +1 -0
  2123. package/dist/src/update-check.test.js +116 -0
  2124. package/dist/src/utils.d.ts +57 -0
  2125. package/dist/src/utils.js +152 -0
  2126. package/dist/src/utils.test.d.ts +1 -0
  2127. package/dist/src/utils.test.js +155 -0
  2128. package/dist/src/validate.d.ts +21 -0
  2129. package/dist/src/validate.js +129 -0
  2130. package/dist/src/validate.test.d.ts +9 -0
  2131. package/dist/src/validate.test.js +90 -0
  2132. package/dist/src/verify.d.ts +26 -0
  2133. package/dist/src/verify.js +67 -0
  2134. package/dist/src/version.d.ts +4 -0
  2135. package/dist/src/version.js +22 -0
  2136. package/dist/src/weixin-download.test.d.ts +1 -0
  2137. package/dist/src/weixin-download.test.js +45 -0
  2138. package/package.json +109 -0
  2139. package/scripts/check-doc-coverage.sh +81 -0
  2140. package/scripts/check-listing-id-pairing.mjs +193 -0
  2141. package/scripts/check-silent-column-drop.mjs +105 -0
  2142. package/scripts/check-typed-error-lint.mjs +118 -0
  2143. package/scripts/clean-dist.cjs +13 -0
  2144. package/scripts/copy-yaml.cjs +12 -0
  2145. package/scripts/fetch-adapters.js +293 -0
  2146. package/scripts/postinstall.js +174 -0
  2147. package/scripts/silent-column-drop-baseline.json +910 -0
  2148. package/scripts/typed-error-lint-baseline.json +1162 -0
  2149. package/skills/opencli-adapter-author/SKILL.md +256 -0
  2150. package/skills/opencli-adapter-author/references/adapter-template.md +471 -0
  2151. package/skills/opencli-adapter-author/references/api-discovery.md +295 -0
  2152. package/skills/opencli-adapter-author/references/coverage-matrix.md +81 -0
  2153. package/skills/opencli-adapter-author/references/field-conventions.md +172 -0
  2154. package/skills/opencli-adapter-author/references/field-decode-playbook.md +181 -0
  2155. package/skills/opencli-adapter-author/references/jsdom-fixture-pattern.md +196 -0
  2156. package/skills/opencli-adapter-author/references/output-design.md +149 -0
  2157. package/skills/opencli-adapter-author/references/site-memory/bilibili.md +70 -0
  2158. package/skills/opencli-adapter-author/references/site-memory/eastmoney.md +70 -0
  2159. package/skills/opencli-adapter-author/references/site-memory/tonghuashun.md +51 -0
  2160. package/skills/opencli-adapter-author/references/site-memory/xueqiu.md +58 -0
  2161. package/skills/opencli-adapter-author/references/site-memory.md +231 -0
  2162. package/skills/opencli-adapter-author/references/site-recon.md +134 -0
  2163. package/skills/opencli-adapter-author/references/strategy-selection.md +169 -0
  2164. package/skills/opencli-adapter-author/references/success-rate-pitfalls.md +162 -0
  2165. package/skills/opencli-adapter-author/references/typed-errors.md +234 -0
  2166. package/skills/opencli-autofix/SKILL.md +297 -0
  2167. package/skills/opencli-browser/SKILL.md +444 -0
  2168. package/skills/opencli-browser-sitemap/SKILL.md +96 -0
  2169. package/skills/opencli-sitemap-author/SKILL.md +161 -0
  2170. package/skills/opencli-sitemap-author/references/sitemap-schema.md +660 -0
  2171. package/skills/opencli-usage/SKILL.md +169 -0
@@ -0,0 +1,1423 @@
1
+ /**
2
+ * Xiaohongshu 图文笔记 publisher — creator center UI automation.
3
+ *
4
+ * Flow:
5
+ * 1. Navigate to creator publish page
6
+ * 2. Upload images via CDP DOM.setFileInputFiles (with base64 fallback)
7
+ * 3. Fill title and body text
8
+ * 4. Add topic hashtags
9
+ * 5. Publish (or save as draft)
10
+ *
11
+ * Requires: logged into creator.xiaohongshu.com in Chrome.
12
+ *
13
+ * Usage:
14
+ * opencli xiaohongshu publish --title "标题" "正文内容" \
15
+ * --images /path/a.jpg,/path/b.jpg \
16
+ * --topics 生活,旅行
17
+ */
18
+ import * as fs from 'node:fs';
19
+ import * as path from 'node:path';
20
+ import { CommandExecutionError, ArgumentError } from '@jackwener/opencli/errors';
21
+ import { cli, Strategy } from '@jackwener/opencli/registry';
22
+ const PUBLISH_URL = 'https://creator.xiaohongshu.com/publish/publish?from=menu_left&target=image';
23
+ const MAX_IMAGES = 9;
24
+ const MAX_TITLE_LEN = 20;
25
+ const UPLOAD_SETTLE_MS = 3000;
26
+ const CARD_TEXT_DELIM = '|||';
27
+ const DEFAULT_CARD_STYLE = '基础';
28
+ // Example styles for help text only — the real options are read live from the
29
+ // (virtualized, content-dependent) 预览图片 strip at runtime, so this list is NOT
30
+ // used to validate input; an unavailable requested style fails before submit.
31
+ // 文字配图 --card-style catalog: each style name → the content it suits.
32
+ // Styles are read live from the page at runtime (see selectCardStyle); this list
33
+ // only powers --help, and an unmatched requested style is a typed failure.
34
+ const CARD_STYLE_GUIDE = [
35
+ ['基础', '默认兜底,万能'],
36
+ ['边框', '金句/要点卡'],
37
+ ['备忘', '提醒/随手记'],
38
+ ['清新', '日常/清单贴士'],
39
+ ['涂写', '随笔/碎碎念'],
40
+ ['便签', '笔记/提醒'],
41
+ ['光影', '情绪/文艺'],
42
+ ['涂鸦', '趣味/童话'],
43
+ ['简约', '干货/观点'],
44
+ ['手写', '日记/情感'],
45
+ ['插图', '生活方式/轻松话题'],
46
+ ['美漫', '活力/趣味/故事感'],
47
+ ['弥散', '弥散光氛围'],
48
+ ['柔和', '柔和/温柔金句'],
49
+ ['印刷', '印刷海报/排版'],
50
+ ['科技', '科技/产品'],
51
+ ['贺卡', '节日祝福'],
52
+ ['札记', '艺术/水彩氛围'],
53
+ ['书摘', '书摘/引用'],
54
+ ['手帐', '手帐拼贴'],
55
+ ['几何', '醒目/有力主张'],
56
+ ];
57
+ const CARD_STYLES = CARD_STYLE_GUIDE.map(([name]) => name);
58
+ const TEXT_IMAGE_ENTRY_LABEL = '文字配图';
59
+ const ADD_CARD_LABEL = '再写一张';
60
+ const GENERATE_LABEL = '生成图片';
61
+ const PREVIEW_NEXT_LABEL = '下一步';
62
+ /** tiptap/ProseMirror card editor inside the 写文字 swiper. */
63
+ const CARD_EDITOR_SELECTOR = '.tiptap.ProseMirror';
64
+ /**
65
+ * XHS creator center wraps the publish/save button in an `<xhs-publish-btn>`
66
+ * web component backed by a CLOSED shadow root. Host-level `.click()` does
67
+ * not dispatch into the internal handler. Invoke these instance methods on
68
+ * the host element to trigger publish / save-draft directly (#1606).
69
+ */
70
+ const PUBLISH_METHOD_NAMES = ['_onPublish', 'onPublish', '_onSubmit', '_handlePublish'];
71
+ const DRAFT_METHOD_NAMES = ['_onSave', '_onSaveDraft', '_onDraft'];
72
+ /** Selectors for the title field, ordered by priority across current UI variants. */
73
+ const TITLE_SELECTORS = [
74
+ // Some creator-center variants expose the title as contenteditable,
75
+ // others use a normal <input> with the same placeholder. Visible
76
+ // user-facing variants always carry a Chinese placeholder; class-based
77
+ // variants also match a pair of 4 px wide hidden scaffolding inputs
78
+ // (same `class*="title"`, empty placeholder, no v-model commit on save)
79
+ // so placeholder-based selectors take precedence to avoid filling those.
80
+ '[contenteditable="true"][placeholder*="标题"]',
81
+ '[contenteditable="true"][placeholder*="赞"]',
82
+ 'input[placeholder*="标题"]',
83
+ 'input[placeholder*="title" i]',
84
+ '[contenteditable="true"][class*="title"]',
85
+ 'input[maxlength="20"]',
86
+ 'input[class*="title"]',
87
+ '.title-input input',
88
+ '.note-title input',
89
+ 'input[maxlength]',
90
+ ];
91
+ /** Selectors for the note body / content editor, ordered by priority. */
92
+ const BODY_SELECTORS = [
93
+ '[contenteditable="true"][class*="content"]',
94
+ '[contenteditable="true"][class*="editor"]',
95
+ '[contenteditable="true"][placeholder*="描述"]',
96
+ '[contenteditable="true"][placeholder*="正文"]',
97
+ '[contenteditable="true"][placeholder*="内容"]',
98
+ '.note-content [contenteditable="true"]',
99
+ '.editor-content [contenteditable="true"]',
100
+ // Broad fallback — last resort; filter out any title contenteditable
101
+ '[contenteditable="true"]:not([placeholder*="标题"]):not([placeholder*="赞"]):not([placeholder*="title" i])',
102
+ ];
103
+ const SUPPORTED_EXTENSIONS = {
104
+ '.jpg': 'image/jpeg',
105
+ '.jpeg': 'image/jpeg',
106
+ '.png': 'image/png',
107
+ '.gif': 'image/gif',
108
+ '.webp': 'image/webp',
109
+ };
110
+ function unwrapBrowserResult(value) {
111
+ if (
112
+ value
113
+ && typeof value === 'object'
114
+ && typeof value.session === 'string'
115
+ && Object.prototype.hasOwnProperty.call(value, 'data')
116
+ ) {
117
+ return value.data;
118
+ }
119
+ return value;
120
+ }
121
+ /**
122
+ * Validate image paths: check existence and extension.
123
+ * Returns resolved absolute paths.
124
+ */
125
+ function validateImagePaths(filePaths) {
126
+ return filePaths.map((filePath) => {
127
+ const absPath = path.resolve(filePath);
128
+ if (!fs.existsSync(absPath))
129
+ throw new ArgumentError(`Image file not found: ${absPath}`);
130
+ const ext = path.extname(absPath).toLowerCase();
131
+ if (!SUPPORTED_EXTENSIONS[ext]) {
132
+ throw new ArgumentError(`Unsupported image format "${ext}". Supported: jpg, png, gif, webp`);
133
+ }
134
+ return absPath;
135
+ });
136
+ }
137
+ /** CSS selector for image-accepting file inputs. */
138
+ const IMAGE_INPUT_SELECTOR = 'input[type="file"][accept*="image"],'
139
+ + 'input[type="file"][accept*=".jpg"],'
140
+ + 'input[type="file"][accept*=".jpeg"],'
141
+ + 'input[type="file"][accept*=".png"],'
142
+ + 'input[type="file"][accept*=".gif"],'
143
+ + 'input[type="file"][accept*=".webp"]';
144
+ /**
145
+ * Upload images via CDP DOM.setFileInputFiles — Chrome reads files directly
146
+ * from the local filesystem, avoiding base64 payload size limits.
147
+ *
148
+ * Falls back to the legacy base64 DataTransfer approach if the extension
149
+ * does not support set-file-input (e.g. older extension version).
150
+ */
151
+ async function uploadImages(page, absPaths) {
152
+ // ── Primary: CDP DOM.setFileInputFiles ──────────────────────────────
153
+ if (page.setFileInput) {
154
+ try {
155
+ // Find image-accepting file input on the page
156
+ const selector = await page.evaluate(`
157
+ (() => {
158
+ const sels = ${JSON.stringify(IMAGE_INPUT_SELECTOR)};
159
+ const el = document.querySelector(sels);
160
+ return el ? sels : null;
161
+ })()
162
+ `);
163
+ if (!selector) {
164
+ return { ok: false, count: 0, error: 'No file input found on page' };
165
+ }
166
+ await page.setFileInput(absPaths, selector);
167
+ return { ok: true, count: absPaths.length };
168
+ }
169
+ catch (err) {
170
+ // If set-file-input action is not supported by extension, fall through to legacy
171
+ const msg = err instanceof Error ? err.message : String(err);
172
+ if (msg.includes('Unknown action') || msg.includes('not supported') || msg.includes('Not allowed')) {
173
+ // Extension too old — fall through to legacy base64 method
174
+ }
175
+ else {
176
+ return { ok: false, count: 0, error: msg };
177
+ }
178
+ }
179
+ }
180
+ // ── Fallback: legacy base64 DataTransfer injection ─────────────────
181
+ const images = absPaths.map((absPath) => {
182
+ const base64 = fs.readFileSync(absPath).toString('base64');
183
+ const ext = path.extname(absPath).toLowerCase();
184
+ return { name: path.basename(absPath), mimeType: SUPPORTED_EXTENSIONS[ext], base64 };
185
+ });
186
+ // Warn if total payload is large — this may fail with older extensions
187
+ const totalBytes = images.reduce((sum, img) => sum + img.base64.length, 0);
188
+ if (totalBytes > 500_000) {
189
+ console.warn(`[warn] Total image payload is ${(totalBytes / 1024 / 1024).toFixed(1)}MB (base64). ` +
190
+ 'This may fail with the browser bridge. Update the extension to v1.6+ for CDP-based upload, ' +
191
+ 'or compress images before publishing.');
192
+ }
193
+ const payload = JSON.stringify(images);
194
+ return page.evaluate(`
195
+ (async () => {
196
+ const images = ${payload};
197
+
198
+ const inputs = Array.from(document.querySelectorAll('input[type="file"]'));
199
+ const input = inputs.find(el => {
200
+ const accept = el.getAttribute('accept') || '';
201
+ return (
202
+ accept.includes('image') ||
203
+ accept.includes('.jpg') ||
204
+ accept.includes('.jpeg') ||
205
+ accept.includes('.png') ||
206
+ accept.includes('.gif') ||
207
+ accept.includes('.webp')
208
+ );
209
+ });
210
+
211
+ if (!input) return { ok: false, count: 0, error: 'No image file input found on page' };
212
+
213
+ const dt = new DataTransfer();
214
+ for (const img of images) {
215
+ try {
216
+ const binary = atob(img.base64);
217
+ const bytes = new Uint8Array(binary.length);
218
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
219
+ const blob = new Blob([bytes], { type: img.mimeType });
220
+ dt.items.add(new File([blob], img.name, { type: img.mimeType }));
221
+ } catch (e) {
222
+ return { ok: false, count: 0, error: 'Failed to create File: ' + e.message };
223
+ }
224
+ }
225
+
226
+ Object.defineProperty(input, 'files', { value: dt.files, writable: false });
227
+ input.dispatchEvent(new Event('change', { bubbles: true }));
228
+ input.dispatchEvent(new Event('input', { bubbles: true }));
229
+
230
+ return { ok: true, count: dt.files.length };
231
+ })()
232
+ `);
233
+ }
234
+ /**
235
+ * Wait until all upload progress indicators have disappeared (up to maxWaitMs).
236
+ */
237
+ async function waitForUploads(page, maxWaitMs = 30_000) {
238
+ const pollMs = 2_000;
239
+ const maxAttempts = Math.ceil(maxWaitMs / pollMs);
240
+ for (let i = 0; i < maxAttempts; i++) {
241
+ const uploading = await page.evaluate(`
242
+ () => !!document.querySelector(
243
+ '[class*="upload"][class*="progress"], [class*="uploading"], [class*="loading"][class*="image"]'
244
+ )
245
+ `);
246
+ if (!uploading)
247
+ return;
248
+ await page.wait({ time: pollMs / 1_000 });
249
+ }
250
+ }
251
+ /**
252
+ * Fill a visible text input or contenteditable with the given text.
253
+ * Tries multiple selectors in priority order.
254
+ * Returns { ok, sel }.
255
+ */
256
+ async function fillField(page, selectors, text, fieldName) {
257
+ const located = await page.evaluate(`
258
+ (function(selectors) {
259
+ const __opencli_xhs_fill_phase = "locate";
260
+ for (const sel of selectors) {
261
+ const candidates = document.querySelectorAll(sel);
262
+ for (const el of candidates) {
263
+ if (!el || el.offsetParent === null) continue;
264
+ const kind = el.isContentEditable
265
+ ? 'contenteditable'
266
+ : (el.tagName === 'TEXTAREA' ? 'textarea' : 'input');
267
+ return { ok: true, sel, kind };
268
+ }
269
+ }
270
+ return { ok: false };
271
+ })(${JSON.stringify(selectors)})
272
+ `);
273
+ if (!located.ok) {
274
+ await page.screenshot({ path: `/tmp/xhs_publish_${fieldName}_debug.png` });
275
+ throw new Error(`Could not find ${fieldName} input. Debug screenshot: /tmp/xhs_publish_${fieldName}_debug.png`);
276
+ }
277
+ const applyInPage = () => page.evaluate(`
278
+ ((selector, expectedText) => {
279
+ const __opencli_xhs_fill_phase = "apply";
280
+ const normalize = (value) => (value || '').replace(/\\s+/g, ' ').trim();
281
+ const fireBeforeInput = (el, value) => {
282
+ try {
283
+ el.dispatchEvent(new InputEvent('beforeinput', {
284
+ bubbles: true,
285
+ data: value,
286
+ inputType: 'insertText',
287
+ }));
288
+ } catch {
289
+ el.dispatchEvent(new Event('beforeinput', { bubbles: true }));
290
+ }
291
+ };
292
+ const fireInput = (el, value) => {
293
+ try {
294
+ el.dispatchEvent(new InputEvent('input', {
295
+ bubbles: true,
296
+ data: value,
297
+ inputType: 'insertText',
298
+ }));
299
+ } catch {
300
+ el.dispatchEvent(new Event('input', { bubbles: true }));
301
+ }
302
+ };
303
+ const el = Array.from(document.querySelectorAll(selector)).find(node => node && node.offsetParent !== null);
304
+ if (!el) return { ok: false, actual: '' };
305
+ el.focus();
306
+ fireBeforeInput(el, expectedText);
307
+ if (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA') {
308
+ const proto = el.tagName === 'TEXTAREA'
309
+ ? HTMLTextAreaElement.prototype
310
+ : HTMLInputElement.prototype;
311
+ const nativeSetter = Object.getOwnPropertyDescriptor(proto, 'value')?.set;
312
+ if (nativeSetter) nativeSetter.call(el, expectedText);
313
+ else el.value = expectedText;
314
+ fireInput(el, expectedText);
315
+ el.dispatchEvent(new Event('change', { bubbles: true }));
316
+ el.blur();
317
+ return { ok: el.value === expectedText, actual: el.value || '' };
318
+ }
319
+ el.textContent = '';
320
+ const selection = window.getSelection();
321
+ const range = document.createRange();
322
+ range.selectNodeContents(el);
323
+ range.collapse(false);
324
+ selection?.removeAllRanges();
325
+ selection?.addRange(range);
326
+ const inserted = document.execCommand('insertText', false, expectedText);
327
+ if (!inserted) el.textContent = expectedText;
328
+ fireInput(el, expectedText);
329
+ el.dispatchEvent(new Event('change', { bubbles: true }));
330
+ el.blur();
331
+ const actual = normalize(el.innerText || el.textContent || '');
332
+ return { ok: actual === normalize(expectedText), actual };
333
+ })(${JSON.stringify(located.sel)}, ${JSON.stringify(text)})
334
+ `);
335
+ let result;
336
+ if (located.kind === 'contenteditable' && page.insertText) {
337
+ const prepared = await page.evaluate(`
338
+ ((selector, nextText) => {
339
+ const __opencli_xhs_fill_phase = "prepare";
340
+ const fireBeforeInput = (el, value) => {
341
+ try {
342
+ el.dispatchEvent(new InputEvent('beforeinput', {
343
+ bubbles: true,
344
+ data: value,
345
+ inputType: 'insertText',
346
+ }));
347
+ } catch {
348
+ el.dispatchEvent(new Event('beforeinput', { bubbles: true }));
349
+ }
350
+ };
351
+ const el = Array.from(document.querySelectorAll(selector)).find(node => node && node.offsetParent !== null);
352
+ if (!el) return { ok: false };
353
+ el.focus();
354
+ el.textContent = '';
355
+ const selection = window.getSelection();
356
+ const range = document.createRange();
357
+ range.selectNodeContents(el);
358
+ range.collapse(false);
359
+ selection?.removeAllRanges();
360
+ selection?.addRange(range);
361
+ fireBeforeInput(el, nextText);
362
+ return { ok: true };
363
+ })(${JSON.stringify(located.sel)}, ${JSON.stringify(text)})
364
+ `);
365
+ if (!prepared?.ok) {
366
+ await page.screenshot({ path: `/tmp/xhs_publish_${fieldName}_debug.png` });
367
+ throw new Error(`Could not prepare ${fieldName} input. Debug screenshot: /tmp/xhs_publish_${fieldName}_debug.png`);
368
+ }
369
+ try {
370
+ await page.insertText(text);
371
+ result = await page.evaluate(`
372
+ ((selector, expectedText) => {
373
+ const __opencli_xhs_fill_phase = "verify";
374
+ const normalize = (value) => (value || '').replace(/\\s+/g, ' ').trim();
375
+ const fireInput = (el, value) => {
376
+ try {
377
+ el.dispatchEvent(new InputEvent('input', {
378
+ bubbles: true,
379
+ data: value,
380
+ inputType: 'insertText',
381
+ }));
382
+ } catch {
383
+ el.dispatchEvent(new Event('input', { bubbles: true }));
384
+ }
385
+ };
386
+ const el = Array.from(document.querySelectorAll(selector)).find(node => node && node.offsetParent !== null);
387
+ if (!el) return { ok: false, actual: '' };
388
+ fireInput(el, expectedText);
389
+ el.dispatchEvent(new Event('change', { bubbles: true }));
390
+ el.blur();
391
+ const actual = normalize(el.innerText || el.textContent || '');
392
+ return { ok: actual === normalize(expectedText), actual };
393
+ })(${JSON.stringify(located.sel)}, ${JSON.stringify(text)})
394
+ `);
395
+ }
396
+ catch {
397
+ result = await applyInPage();
398
+ }
399
+ }
400
+ else {
401
+ result = await applyInPage();
402
+ }
403
+ if (!result?.ok) {
404
+ await page.screenshot({ path: `/tmp/xhs_publish_${fieldName}_debug.png` });
405
+ const actual = typeof result?.actual === 'string' ? result.actual : '';
406
+ throw new Error(`Failed to set ${fieldName}. Expected "${text}", got "${actual}". Debug screenshot: /tmp/xhs_publish_${fieldName}_debug.png`);
407
+ }
408
+ }
409
+ /**
410
+ * Add topic hashtags by driving the editor's native inline "#" flow.
411
+ *
412
+ * Modern XHS creator-center editors turn a "#keyword" typed into the note body
413
+ * into a linked topic entity only after the author picks an item from the
414
+ * suggestion dropdown that appears while typing. There is no standalone
415
+ * "添加话题" search input anymore, so we type directly into the body editor.
416
+ *
417
+ * For each topic we:
418
+ * 1. focus the body contenteditable and move the caret to the end,
419
+ * 2. type " #<topic>" using native CDP insertion (falls back to execCommand)
420
+ * so XHS fires its inline suggestion dropdown,
421
+ * 3. wait for the dropdown, then click the suggestion whose text best matches
422
+ * the topic (falling back to the first suggestion, then to Enter),
423
+ * 4. confirm a topic chip/link was produced before moving on.
424
+ *
425
+ * A requested topic is a write-side postcondition: if XHS does not create a
426
+ * real topic entity, fail before publishing instead of silently emitting a note
427
+ * with bare "#text".
428
+ */
429
+ async function focusBodyEnd(page, bodySelectors) {
430
+ return unwrapBrowserResult(await page.evaluate(`
431
+ (selectors => {
432
+ const el = selectors
433
+ .map(sel => Array.from(document.querySelectorAll(sel)))
434
+ .flat()
435
+ .find(node => node && node.offsetParent !== null && node.isContentEditable);
436
+ if (!el) return false;
437
+ el.focus();
438
+ const selection = window.getSelection();
439
+ const range = document.createRange();
440
+ range.selectNodeContents(el);
441
+ range.collapse(false);
442
+ selection?.removeAllRanges();
443
+ selection?.addRange(range);
444
+ return true;
445
+ })(${JSON.stringify(bodySelectors)})
446
+ `));
447
+ }
448
+ function topicSuggestionScript(topic, { click = false } = {}) {
449
+ // Returns the best matching suggestion's screen coordinates (center) so the
450
+ // caller can issue a real click.
451
+ return `
452
+ (topicName => {
453
+ const norm = (value) => (value || '').replace(/^#/, '').replace(/\\s+/g, '').trim();
454
+ const want = norm(topicName);
455
+ const SUGGESTION_SELECTORS = [
456
+ '[class*="topic-item"]',
457
+ '[class*="hashtag-item"]',
458
+ '[class*="suggest-item"]',
459
+ '[class*="suggestion"] li',
460
+ '[class*="mention"] li',
461
+ '[class*="dropdown"] li',
462
+ '[id*="topic"] li',
463
+ '[class*="topic"] li',
464
+ ];
465
+ const seen = new Set();
466
+ const items = [];
467
+ for (const sel of SUGGESTION_SELECTORS) {
468
+ for (const node of document.querySelectorAll(sel)) {
469
+ if (!node || seen.has(node)) continue;
470
+ if (node.offsetParent === null) continue;
471
+ const rect = node.getBoundingClientRect();
472
+ if (rect.width <= 0 || rect.height <= 0) continue;
473
+ seen.add(node);
474
+ items.push(node);
475
+ }
476
+ }
477
+ if (!items.length) return { ok: false, count: 0 };
478
+ let target = items.find(node => norm(node.innerText || node.textContent) === want);
479
+ if (!target) target = items.find(node => norm(node.innerText || node.textContent).includes(want));
480
+ if (!target) target = items[0];
481
+ const rect = target.getBoundingClientRect();
482
+ ${click ? "try { target.click(); } catch (e) { return { ok: false, count: items.length, message: String(e) }; }" : ''}
483
+ return {
484
+ ok: true,
485
+ count: items.length,
486
+ x: Math.round(rect.left + rect.width / 2),
487
+ y: Math.round(rect.top + rect.height / 2),
488
+ text: (target.innerText || target.textContent || '').trim().slice(0, 40),
489
+ };
490
+ })(${JSON.stringify(topic)})
491
+ `;
492
+ }
493
+ function topicEntityCountScript(topic, bodySelectors) {
494
+ return `
495
+ ((topicName, selectors) => {
496
+ const norm = (value) => (value || '').replace(/^#/, '').replace(/\\s+/g, '').trim();
497
+ const want = norm(topicName);
498
+ const editor = selectors
499
+ .map(sel => Array.from(document.querySelectorAll(sel)))
500
+ .flat()
501
+ .find(node => node && node.offsetParent !== null && node.isContentEditable);
502
+ if (!editor || !want) return 0;
503
+ const hasTopicSignal = (node) => {
504
+ const tag = (node.tagName || '').toLowerCase();
505
+ const role = (node.getAttribute && node.getAttribute('role')) || '';
506
+ const cls = String(node.className || '');
507
+ const id = String(node.id || '');
508
+ const href = (node.getAttribute && node.getAttribute('href')) || '';
509
+ const dataKeys = node.dataset ? Object.keys(node.dataset).join(' ') : '';
510
+ const haystack = [tag, role, cls, id, href, dataKeys].join(' ');
511
+ return tag === 'a'
512
+ || /link/i.test(role)
513
+ || /topic|hashtag|hash-tag|tag|mention|keyword/i.test(haystack)
514
+ || node.isContentEditable === false;
515
+ };
516
+ let count = 0;
517
+ for (const node of Array.from(editor.querySelectorAll('*'))) {
518
+ if (!node || node.offsetParent === null) continue;
519
+ if (!hasTopicSignal(node)) continue;
520
+ const text = norm(node.innerText || node.textContent || '');
521
+ if (text === want || text === '#' + want) count += 1;
522
+ }
523
+ return count;
524
+ })(${JSON.stringify(topic)}, ${JSON.stringify(bodySelectors)})
525
+ `;
526
+ }
527
+ function topicMarkerCountScript(topic, bodySelectors) {
528
+ return `
529
+ ((topicName, selectors) => {
530
+ const __opencli_xhs_topic_marker_count = true;
531
+ const marker = '#' + topicName + '[话题]';
532
+ const editor = selectors
533
+ .map(sel => Array.from(document.querySelectorAll(sel)))
534
+ .flat()
535
+ .find(node => node && node.offsetParent !== null && node.isContentEditable);
536
+ if (!editor || !marker) return 0;
537
+ const text = editor.innerText || editor.textContent || '';
538
+ let count = 0;
539
+ let index = text.indexOf(marker);
540
+ while (index !== -1) {
541
+ count += 1;
542
+ index = text.indexOf(marker, index + marker.length);
543
+ }
544
+ return count;
545
+ })(${JSON.stringify(topic)}, ${JSON.stringify(bodySelectors)})
546
+ `;
547
+ }
548
+ async function typeTopicQuery(page, topic) {
549
+ // Type "#<topic>" so XHS recognizes it as a topic query and pops the inline
550
+ // suggestion dropdown. The caller separates topics with Enter beforehand so
551
+ // each query starts on its own line and matches cleanly.
552
+ const query = `#${topic}`;
553
+ if (typeof page.insertText === 'function') {
554
+ try {
555
+ await page.insertText(query);
556
+ return true;
557
+ }
558
+ catch {
559
+ // fall through to execCommand path
560
+ }
561
+ }
562
+ return unwrapBrowserResult(await page.evaluate(`
563
+ (text => {
564
+ const ok = document.execCommand('insertText', false, text);
565
+ const active = document.activeElement;
566
+ if (active) active.dispatchEvent(new Event('input', { bubbles: true }));
567
+ return ok;
568
+ })(${JSON.stringify(query)})
569
+ `));
570
+ }
571
+ async function addTopics(page, bodySelectors, topics) {
572
+ const added = [];
573
+ for (const topic of topics) {
574
+ const focused = await focusBodyEnd(page, bodySelectors);
575
+ if (!focused) {
576
+ throw new CommandExecutionError(`Could not attach topic "${topic}": body editor not found`);
577
+ }
578
+ const beforeMarkerCount = Number(unwrapBrowserResult(await page.evaluate(topicMarkerCountScript(topic, bodySelectors)))) || 0;
579
+ // Separate this topic from the preceding text so the dropdown is clean.
580
+ if (typeof page.pressKey === 'function') {
581
+ try {
582
+ await page.pressKey('Enter');
583
+ }
584
+ catch { /* non-fatal */ }
585
+ }
586
+ // Type the inline "#<topic>" query so XHS pops the inline suggestion
587
+ // dropdown. We must use `page.insertText` (CDP) rather than the legacy
588
+ // `execCommand` path, otherwise XHS's editor doesn't fire its keyup
589
+ // listener and no dropdown appears.
590
+ if (typeof page.insertText !== 'function') {
591
+ throw new CommandExecutionError(`Could not attach topic "${topic}": page.insertText is unavailable`);
592
+ }
593
+ try {
594
+ await page.insertText(`#${topic}`);
595
+ }
596
+ catch {
597
+ throw new CommandExecutionError(`Could not attach topic "${topic}": failed to type inline topic query`);
598
+ }
599
+ await page.wait({ time: 1.2 }); // Let the suggestion dropdown render.
600
+ // The suggestion dropdown lives inside the editor's closed shadow root,
601
+ // so light-DOM queries cannot enumerate its items. XHS auto-highlights
602
+ // the first matching suggestion as soon as the query is typed, so
603
+ // pressing Enter accepts it directly. `page.nativeClick` would also
604
+ // work but is not always wired up in the browser-bridge wrapper.
605
+ if (typeof page.pressKey !== 'function') {
606
+ throw new CommandExecutionError(`Could not attach topic "${topic}": page.pressKey is unavailable`);
607
+ }
608
+ try {
609
+ await page.pressKey('Enter');
610
+ }
611
+ catch (err) {
612
+ throw new CommandExecutionError(`Could not attach topic "${topic}": failed to accept suggestion (${err && err.message || err})`);
613
+ }
614
+ await page.wait({ time: 0.8 });
615
+ // Verify the topic chip actually rendered. The chip itself lives in a
616
+ // closed shadow root so we cannot count `<a>` elements, but XHS exposes
617
+ // a stable "#<topic>[话题]" marker in the body editor's innerText once
618
+ // the suggestion is accepted. Require the scoped marker count to
619
+ // increase so an existing marker elsewhere cannot satisfy the write
620
+ // postcondition.
621
+ const afterMarkerCount = Number(unwrapBrowserResult(await page.evaluate(topicMarkerCountScript(topic, bodySelectors)))) || 0;
622
+ if (afterMarkerCount <= beforeMarkerCount) {
623
+ throw new CommandExecutionError(`Could not attach topic "${topic}": no real topic entity appeared after selection`);
624
+ }
625
+ added.push(topic);
626
+ await page.wait({ time: 0.4 });
627
+ }
628
+ return added;
629
+ }
630
+ async function selectImageTextTab(page) {
631
+ const result = await page.evaluate(`
632
+ () => {
633
+ const isVisible = (el) => {
634
+ if (!el || el.offsetParent === null) return false;
635
+ const rect = el.getBoundingClientRect();
636
+ return rect.width > 0 && rect.height > 0;
637
+ };
638
+
639
+ const normalize = (value) => (value || '').replace(/\\s+/g, ' ').trim();
640
+ const selector = 'button, [role="tab"], [role="button"], a, label, div, span, li';
641
+ const nodes = Array.from(document.querySelectorAll(selector));
642
+ const targets = ['上传图文', '图文', '图片'];
643
+
644
+ for (const target of targets) {
645
+ for (const node of nodes) {
646
+ if (!isVisible(node)) continue;
647
+ const text = normalize(node.innerText || node.textContent || '');
648
+ if (!text || text.includes('视频')) continue;
649
+ if (text === target) {
650
+ const clickable = node.closest('button, [role="tab"], [role="button"], a, label') || node;
651
+ clickable.click();
652
+ return { ok: true, target, text };
653
+ }
654
+ }
655
+ }
656
+
657
+ for (const target of targets) {
658
+ for (const node of nodes) {
659
+ if (!isVisible(node)) continue;
660
+ const text = normalize(node.innerText || node.textContent || '');
661
+ if (!text || text.includes('视频')) continue;
662
+ if (text.startsWith(target) || text.includes(target)) {
663
+ const clickable = node.closest('button, [role="tab"], [role="button"], a, label') || node;
664
+ clickable.click();
665
+ return { ok: true, target, text };
666
+ }
667
+ }
668
+ }
669
+
670
+ const visibleTexts = [];
671
+ for (const node of nodes) {
672
+ if (!isVisible(node)) continue;
673
+ const text = normalize(node.innerText || node.textContent || '');
674
+ if (!text || text.length > 20) continue;
675
+ visibleTexts.push(text);
676
+ if (visibleTexts.length >= 20) break;
677
+ }
678
+ return { ok: false, visibleTexts };
679
+ }
680
+ `);
681
+ if (result?.ok) {
682
+ await page.wait({ time: 1 });
683
+ }
684
+ return result;
685
+ }
686
+ /**
687
+ * Click the first visible element whose trimmed text equals `label`.
688
+ * Marker constant `__opencli_xhs_click_label` lets the test mock branch on it.
689
+ */
690
+ async function clickByText(page, label, maxWaitMs = 7_000) {
691
+ const pollMs = 500;
692
+ const maxAttempts = Math.max(1, Math.ceil(maxWaitMs / pollMs));
693
+ let result = { ok: false };
694
+ // Retry until the control appears: 生成图片 → 下一步 advances through async
695
+ // render/generation steps, so the target may not exist on the first probe.
696
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
697
+ result = unwrapBrowserResult(await page.evaluate(`
698
+ ((cfg) => {
699
+ const __opencli_xhs_click_label = { wantLabel: ${JSON.stringify(label)} };
700
+ const wantLabel = ${JSON.stringify(label)};
701
+ const isVisible = (el) => {
702
+ if (!el || el.offsetParent === null) return false;
703
+ const r = el.getBoundingClientRect();
704
+ return r.width > 0 && r.height > 0;
705
+ };
706
+ const norm = (v) => (v || '').replace(/\\s+/g, ' ').trim();
707
+ const clickable = (el) => el.closest('button, [role="button"], a, label') || el;
708
+ const enabled = (el) =>
709
+ !(el.getAttribute && el.getAttribute('aria-disabled') === 'true')
710
+ && !el.disabled
711
+ && !(el.className && String(el.className).split(/\\s+/).includes('disabled'));
712
+ // Exact-text matches, innermost first. The real click handler usually lives on
713
+ // an inner control (.edit-text-button 生成图片, .add-text-item-button-text 再写一张);
714
+ // an outer wrapper that merely *contains* the label is a no-op, so prefer the
715
+ // deepest matching node and let the event bubble up to the handler.
716
+ const nodes = Array.from(document.querySelectorAll('button, [role="button"], div, span, a, label, li'));
717
+ const exact = nodes.filter((n) => isVisible(n) && norm(n.innerText || n.textContent) === wantLabel);
718
+ const innermost = exact.filter((n) => !exact.some((o) => o !== n && n.contains(o)));
719
+ const contains = nodes.filter((n) => {
720
+ if (!isVisible(n)) return false;
721
+ const t = norm(n.innerText || n.textContent);
722
+ return t && t.length <= wantLabel.length + 4 && t.includes(wantLabel);
723
+ });
724
+ for (const node of [...(innermost.length ? innermost : exact), ...contains]) {
725
+ const c = clickable(node);
726
+ if (!enabled(c)) continue;
727
+ c.click();
728
+ return { ok: true, text: norm(node.innerText || node.textContent) || wantLabel };
729
+ }
730
+ return { ok: false };
731
+ })()
732
+ `));
733
+ if (result?.ok)
734
+ return result;
735
+ await page.wait({ time: pollMs / 1_000 });
736
+ }
737
+ return result;
738
+ }
739
+ /**
740
+ * Focus the currently-active 写文字 card editor (tiptap/ProseMirror) and move the
741
+ * caret to the end so insertText appends into it.
742
+ */
743
+ async function focusActiveCard(page) {
744
+ const result = await page.evaluate(`
745
+ (() => {
746
+ const __opencli_xhs_focus_card = true;
747
+ const sel = ${JSON.stringify(CARD_EDITOR_SELECTOR)};
748
+ const editors = Array.from(document.querySelectorAll(sel)).filter((el) => el.offsetParent !== null);
749
+ // Prefer the editor inside the active swiper slide if present.
750
+ const active = editors.find((el) => el.closest('.swiper-slide-active')) || editors[editors.length - 1];
751
+ if (!active) return { ok: false };
752
+ active.focus();
753
+ const selection = window.getSelection();
754
+ const range = document.createRange();
755
+ range.selectNodeContents(active);
756
+ range.collapse(false);
757
+ selection?.removeAllRanges();
758
+ selection?.addRange(range);
759
+ return { ok: true };
760
+ })()
761
+ `);
762
+ return unwrapBrowserResult(result);
763
+ }
764
+ /** Confirm the active card editor holds non-empty text (guards against empty cards). */
765
+ async function activeCardText(page) {
766
+ const result = await page.evaluate(`
767
+ (() => {
768
+ const __opencli_xhs_card_text = true;
769
+ const sel = ${JSON.stringify(CARD_EDITOR_SELECTOR)};
770
+ const editors = Array.from(document.querySelectorAll(sel)).filter((el) => el.offsetParent !== null);
771
+ const active = editors.find((el) => el.closest('.swiper-slide-active')) || editors[editors.length - 1];
772
+ const text = active ? (active.innerText || active.textContent || '').trim() : '';
773
+ return { ok: !!text, text };
774
+ })()
775
+ `);
776
+ return unwrapBrowserResult(result);
777
+ }
778
+ /**
779
+ * Count visible card editors and report whether the active one is still empty.
780
+ * Used to wait out the swiper render lag after clicking 再写一张.
781
+ */
782
+ async function cardEditorState(page) {
783
+ const result = await page.evaluate(`
784
+ (() => {
785
+ const __opencli_xhs_card_count = true;
786
+ const sel = ${JSON.stringify(CARD_EDITOR_SELECTOR)};
787
+ const editors = Array.from(document.querySelectorAll(sel)).filter((el) => el.offsetParent !== null);
788
+ const active = editors.find((el) => el.closest('.swiper-slide-active')) || editors[editors.length - 1];
789
+ const activeText = active ? (active.innerText || active.textContent || '').trim() : '';
790
+ return { ok: true, count: editors.length, activeEmpty: !activeText };
791
+ })()
792
+ `);
793
+ return unwrapBrowserResult(result);
794
+ }
795
+ /** Poll until at least one card editor has rendered (after entering 文字配图). */
796
+ async function waitForFirstCard(page, maxWaitMs = 8_000) {
797
+ const pollMs = 300;
798
+ const maxAttempts = Math.ceil(maxWaitMs / pollMs);
799
+ for (let i = 0; i < maxAttempts; i++) {
800
+ const state = await cardEditorState(page);
801
+ if (state?.count >= 1)
802
+ return true;
803
+ await page.wait({ time: pollMs / 1_000 });
804
+ }
805
+ return false;
806
+ }
807
+ /**
808
+ * After clicking 再写一张, the new card editor renders asynchronously and only
809
+ * then becomes the active swiper slide. Wait for the fresh empty card to be
810
+ * active before typing — otherwise the text lands in the previous card and the
811
+ * cards get merged.
812
+ */
813
+ async function waitForNewCard(page, expectedCount, maxWaitMs = 6_000) {
814
+ const pollMs = 300;
815
+ const maxAttempts = Math.ceil(maxWaitMs / pollMs);
816
+ for (let i = 0; i < maxAttempts; i++) {
817
+ const state = await cardEditorState(page);
818
+ if (state?.count >= expectedCount && state?.activeEmpty)
819
+ return true;
820
+ await page.wait({ time: pollMs / 1_000 });
821
+ }
822
+ return false;
823
+ }
824
+ /**
825
+ * Click 再写一张 and wait for the new card to render. Retries the click because
826
+ * 再写一张 only adds a card once the current card's text has registered in the
827
+ * editor model — a click fired too early no-ops. Re-clicking is safe: once the
828
+ * fresh empty card is active, 再写一张 no-ops, so this never over-adds.
829
+ */
830
+ async function addCard(page, expectedCount, maxAttempts = 4) {
831
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
832
+ const clicked = await clickByText(page, ADD_CARD_LABEL);
833
+ if (!clicked?.ok)
834
+ return false;
835
+ if (await waitForNewCard(page, expectedCount, 2_500))
836
+ return true;
837
+ }
838
+ return false;
839
+ }
840
+ /** True once the 预览图片 step has rendered (its 下一步 button is present). */
841
+ async function previewStepReady(page) {
842
+ const result = await page.evaluate(`
843
+ (() => {
844
+ const __opencli_xhs_preview_ready = true;
845
+ const ready = Array.from(document.querySelectorAll('button'))
846
+ .some((b) => b.offsetParent !== null && (b.innerText || '').replace(/\\s+/g, '') === '下一步');
847
+ return { ok: ready };
848
+ })()
849
+ `);
850
+ return unwrapBrowserResult(result);
851
+ }
852
+ /**
853
+ * Click 生成图片 and wait for the 预览图片 step. Retries the click because 生成图片
854
+ * no-ops until the card text has registered in the editor model (same timing quirk as
855
+ * 再写一张). Re-clicking is safe: once the preview step is showing, 生成图片 is gone.
856
+ */
857
+ async function clickGenerate(page, maxAttempts = 6) {
858
+ const pollMs = 400;
859
+ const polls = Math.ceil(3_000 / pollMs);
860
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
861
+ const clicked = await clickByText(page, GENERATE_LABEL);
862
+ if (!clicked?.ok && attempt === 0)
863
+ return false; // 生成图片 not on the page at all
864
+ for (let i = 0; i < polls; i++) {
865
+ if ((await previewStepReady(page))?.ok)
866
+ return true;
867
+ await page.wait({ time: pollMs / 1_000 });
868
+ }
869
+ }
870
+ return false;
871
+ }
872
+ /**
873
+ * Type one card's text into the active card editor, then verify it stuck.
874
+ *
875
+ * tiptap/ProseMirror swallows a "\n" embedded in a single insertText call, so a
876
+ * multi-line card would collapse onto one line. Split the text on "\n" and press
877
+ * Enter between segments to produce real line breaks (same Enter mechanism
878
+ * addTopics relies on). An empty segment (consecutive "\n") yields a blank line.
879
+ *
880
+ * Single-quoted shell args (the most natural way to pass `--card-text`) deliver a
881
+ * literal backslash + "n", not a real LF, so we normalize those to real newlines
882
+ * first — both `$'a\nb'` and `'a\nb'` then break lines identically.
883
+ */
884
+ async function fillCard(page, text, index) {
885
+ text = String(text).replace(/\\n/g, '\n');
886
+ const focused = await focusActiveCard(page);
887
+ if (!focused?.ok)
888
+ throw new CommandExecutionError(`文字配图: could not focus card editor #${index + 1}`);
889
+ if (typeof page.insertText === 'function') {
890
+ const lines = text.split('\n');
891
+ for (let i = 0; i < lines.length; i++) {
892
+ if (i > 0 && typeof page.pressKey === 'function')
893
+ await page.pressKey('Enter');
894
+ if (lines[i])
895
+ await page.insertText(lines[i]);
896
+ }
897
+ }
898
+ else {
899
+ await page.evaluate(`(t => document.execCommand('insertText', false, t))(${JSON.stringify(text)})`);
900
+ }
901
+ await page.wait({ time: 0.4 });
902
+ const state = await activeCardText(page);
903
+ if (!state?.ok)
904
+ throw new CommandExecutionError(`文字配图: card editor #${index + 1} is empty after typing`);
905
+ }
906
+ /**
907
+ * On the 预览图片 step, optionally pick a style. The style picker is a
908
+ * scrollable strip whose options are loaded lazily, so we scroll it to the end
909
+ * to surface every option, then read the real on-page labels (no hard-coded
910
+ * whitelist — XHS adds/removes styles over time). The strip is located by
911
+ * anchoring on a known seed label (e.g. 基础) rather than a volatile class name.
912
+ *
913
+ * If the caller requested a style, it is a write-side postcondition: either
914
+ * that style is available and clicked, or publishing fails before submit.
915
+ */
916
+ async function selectCardStyle(page, styleName) {
917
+ if (!styleName || styleName === DEFAULT_CARD_STYLE)
918
+ return DEFAULT_CARD_STYLE; // default 基础 is preselected — nothing to do.
919
+ // The style strip (".cover-list-container") is VIRTUALIZED: only the items
920
+ // near the viewport are in the DOM, so a single read sees ~10 of ~20 options
921
+ // and an option scrolled out of view cannot be clicked. Step-scroll the strip
922
+ // (".cover-list-container-wrapper"), accumulating every label seen; stop as
923
+ // soon as the requested style appears and scroll it into view so the
924
+ // subsequent click lands. XHS also shows a content-dependent subset, so the
925
+ // real options vary per note — hence no static whitelist.
926
+ const available = unwrapBrowserResult(await page.evaluate(`
927
+ (async () => {
928
+ const __opencli_xhs_card_styles = true;
929
+ const want = ${JSON.stringify(styleName)};
930
+ const norm = (el) => ((el && (el.innerText || el.textContent)) || '').trim();
931
+ const names = () => Array.from(document.querySelectorAll('.cover-list-container .cover-name'));
932
+ const seen = [];
933
+ const readAll = () => { for (const el of names()) { const t = norm(el); if (t && !seen.includes(t)) seen.push(t); } };
934
+ const target = () => names().find((el) => norm(el) === want);
935
+ const reveal = (el) => { el.scrollIntoView({ block: 'center' }); };
936
+ readAll();
937
+ let hit = target();
938
+ if (hit) { reveal(hit); return { ok: true, styles: seen, found: true }; }
939
+ const scroller = document.querySelector('.cover-list-container-wrapper')
940
+ || document.querySelector('.cover-list-container');
941
+ if (scroller) {
942
+ const ch = scroller.clientHeight || 200;
943
+ const sh = scroller.scrollHeight;
944
+ for (let y = 0; y <= sh + ch; y += Math.max(60, Math.floor(ch / 2))) {
945
+ scroller.scrollTop = y;
946
+ await new Promise((r) => setTimeout(r, 180));
947
+ readAll();
948
+ hit = target();
949
+ if (hit) { reveal(hit); await new Promise((r) => setTimeout(r, 150)); return { ok: true, styles: seen, found: true }; }
950
+ }
951
+ scroller.scrollTop = 0;
952
+ }
953
+ return { ok: seen.length > 0, styles: seen, found: false };
954
+ })()
955
+ `));
956
+ if (!available?.found) {
957
+ throw new CommandExecutionError(`文字配图: requested style "${styleName}" is not available for this content `
958
+ + `(options: ${(available?.styles || []).join(' / ') || 'none'}). `
959
+ + `Choose an available style or omit --card-style to use ${DEFAULT_CARD_STYLE}.`);
960
+ }
961
+ const clicked = await clickByText(page, styleName);
962
+ if (!clicked?.ok) {
963
+ throw new CommandExecutionError(`文字配图: could not click requested style "${styleName}".`);
964
+ }
965
+ await page.wait({ time: 0.6 });
966
+ return styleName;
967
+ }
968
+ /**
969
+ * Count visible media in the current editor/composer. Text-image generation must
970
+ * produce real image cards before we fill title/body or submit; otherwise a
971
+ * no-op 生成图片 / 下一步 sequence can publish the wrong draft surface.
972
+ */
973
+ async function currentComposerMediaCount(page) {
974
+ const result = await page.evaluate(`
975
+ (() => {
976
+ const __opencli_xhs_composer_media_count = true;
977
+ const visibleBox = (el) => {
978
+ if (!el || el.offsetParent === null) return false;
979
+ const r = el.getBoundingClientRect();
980
+ return r.width > 0 && r.height > 0;
981
+ };
982
+ const visibleMedia = (el) => {
983
+ if (!visibleBox(el)) return false;
984
+ const r = el.getBoundingClientRect();
985
+ return r.width >= 48 && r.height >= 48;
986
+ };
987
+ const titleSelectors = ${JSON.stringify(TITLE_SELECTORS)};
988
+ const titleEl = titleSelectors
989
+ .map((sel) => Array.from(document.querySelectorAll(sel)))
990
+ .flat()
991
+ .find((el) => visibleBox(el));
992
+ const root = titleEl?.closest('form, [class*="publish"], [class*="editor"], [class*="note"]') || document.body;
993
+ const seen = new Set();
994
+ let count = 0;
995
+ for (const el of Array.from(root.querySelectorAll('img, video, canvas, [style*="background-image"]'))) {
996
+ if (!visibleMedia(el)) continue;
997
+ const rect = el.getBoundingClientRect();
998
+ const src = el.currentSrc || el.src || el.getAttribute('src') || el.style?.backgroundImage || '';
999
+ const key = src || String(Math.round(rect.left)) + ':' + String(Math.round(rect.top));
1000
+ if (seen.has(key)) continue;
1001
+ seen.add(key);
1002
+ count += 1;
1003
+ }
1004
+ return { ok: true, count };
1005
+ })()
1006
+ `);
1007
+ return unwrapBrowserResult(result);
1008
+ }
1009
+ async function assertComposerMediaCount(page, expectedCount, label) {
1010
+ const state = await currentComposerMediaCount(page);
1011
+ if (!state || typeof state.count !== 'number') {
1012
+ throw new CommandExecutionError(`${label}: could not verify current composer media count`);
1013
+ }
1014
+ if (state.count < expectedCount) {
1015
+ await page.screenshot({ path: '/tmp/xhs_publish_media_debug.png' });
1016
+ throw new CommandExecutionError(`${label}: expected at least ${expectedCount} visible media item(s), got ${state.count}. ` +
1017
+ 'Debug screenshot: /tmp/xhs_publish_media_debug.png');
1018
+ }
1019
+ }
1020
+ /**
1021
+ * Drive the full 文字配图 sub-flow: entry → type cards → 生成图片 → pick style → 下一步.
1022
+ * Leaves the page on the standard editor (caller then runs waitForEditForm).
1023
+ */
1024
+ async function runTextImageFlow(page, cards, cardStyle) {
1025
+ const entry = await clickByText(page, TEXT_IMAGE_ENTRY_LABEL);
1026
+ if (!entry?.ok) {
1027
+ await page.screenshot({ path: '/tmp/xhs_publish_textimage_debug.png' });
1028
+ throw new CommandExecutionError(`文字配图: could not click "${TEXT_IMAGE_ENTRY_LABEL}" entry. ` +
1029
+ 'Debug: /tmp/xhs_publish_textimage_debug.png');
1030
+ }
1031
+ if (!(await waitForFirstCard(page))) {
1032
+ await page.screenshot({ path: '/tmp/xhs_publish_textimage_debug.png' });
1033
+ throw new CommandExecutionError(`文字配图: 写文字 card editor did not appear after clicking "${TEXT_IMAGE_ENTRY_LABEL}". ` +
1034
+ 'Debug: /tmp/xhs_publish_textimage_debug.png');
1035
+ }
1036
+ for (let i = 0; i < cards.length; i++) {
1037
+ if (i > 0) {
1038
+ const added = await addCard(page, i + 1);
1039
+ if (!added) {
1040
+ await page.screenshot({ path: '/tmp/xhs_publish_addcard_debug.png' });
1041
+ throw new CommandExecutionError(`文字配图: new card editor #${i + 1} did not render after "${ADD_CARD_LABEL}". ` +
1042
+ 'Debug: /tmp/xhs_publish_addcard_debug.png');
1043
+ }
1044
+ }
1045
+ await fillCard(page, cards[i], i);
1046
+ }
1047
+ const generated = await clickGenerate(page);
1048
+ if (!generated) {
1049
+ await page.screenshot({ path: '/tmp/xhs_publish_generate_debug.png' });
1050
+ throw new CommandExecutionError(`文字配图: "${GENERATE_LABEL}" did not advance to the 预览图片 step. ` +
1051
+ 'Debug: /tmp/xhs_publish_generate_debug.png');
1052
+ }
1053
+ const appliedStyle = await selectCardStyle(page, cardStyle);
1054
+ const next = await clickByText(page, PREVIEW_NEXT_LABEL);
1055
+ if (!next?.ok) {
1056
+ await page.screenshot({ path: '/tmp/xhs_publish_next_debug.png' });
1057
+ throw new CommandExecutionError(`文字配图: could not click "${PREVIEW_NEXT_LABEL}". ` +
1058
+ 'Debug: /tmp/xhs_publish_next_debug.png');
1059
+ }
1060
+ await page.wait({ time: 2 }); // editor render
1061
+ return appliedStyle;
1062
+ }
1063
+ async function inspectPublishSurfaceState(page) {
1064
+ return page.evaluate(`
1065
+ () => {
1066
+ const text = (document.body?.innerText || '').replace(/\s+/g, ' ').trim();
1067
+ const hasTitleInput = !!Array.from(document.querySelectorAll('input, textarea')).find((el) => {
1068
+ if (!el || el.offsetParent === null) return false;
1069
+ const placeholder = (el.getAttribute('placeholder') || '').trim();
1070
+ const cls = el.className ? String(el.className) : '';
1071
+ const maxLength = Number(el.getAttribute('maxlength') || 0);
1072
+ return (
1073
+ placeholder.includes('标题') ||
1074
+ /title/i.test(placeholder) ||
1075
+ /title/i.test(cls) ||
1076
+ maxLength === 20
1077
+ );
1078
+ });
1079
+ const hasImageInput = !!Array.from(document.querySelectorAll('input[type="file"]')).find((el) => {
1080
+ const accept = el.getAttribute('accept') || '';
1081
+ return (
1082
+ accept.includes('image') ||
1083
+ accept.includes('.jpg') ||
1084
+ accept.includes('.jpeg') ||
1085
+ accept.includes('.png') ||
1086
+ accept.includes('.gif') ||
1087
+ accept.includes('.webp')
1088
+ );
1089
+ });
1090
+ const hasVideoSurface = text.includes('拖拽视频到此处点击上传') || text.includes('上传视频');
1091
+ const state = hasTitleInput ? 'editor_ready' : hasImageInput || !hasVideoSurface ? 'image_surface' : 'video_surface';
1092
+ return { state, hasTitleInput, hasImageInput, hasVideoSurface };
1093
+ }
1094
+ `);
1095
+ }
1096
+ async function waitForPublishSurfaceState(page, maxWaitMs = 5_000) {
1097
+ const pollMs = 500;
1098
+ const maxAttempts = Math.max(1, Math.ceil(maxWaitMs / pollMs));
1099
+ let surface = await inspectPublishSurfaceState(page);
1100
+ for (let i = 0; i < maxAttempts; i++) {
1101
+ if (surface.state !== 'video_surface') {
1102
+ return surface;
1103
+ }
1104
+ if (i < maxAttempts - 1) {
1105
+ await page.wait({ time: pollMs / 1_000 });
1106
+ surface = await inspectPublishSurfaceState(page);
1107
+ }
1108
+ }
1109
+ return surface;
1110
+ }
1111
+ /**
1112
+ * Poll until the title/content editing form appears on the page.
1113
+ * The new creator center UI only renders the editor after images are uploaded.
1114
+ */
1115
+ async function waitForEditForm(page, maxWaitMs = 10_000) {
1116
+ const pollMs = 1_000;
1117
+ const maxAttempts = Math.ceil(maxWaitMs / pollMs);
1118
+ for (let i = 0; i < maxAttempts; i++) {
1119
+ const found = await page.evaluate(`
1120
+ (() => {
1121
+ const sels = ${JSON.stringify(TITLE_SELECTORS)};
1122
+ for (const sel of sels) {
1123
+ const el = document.querySelector(sel);
1124
+ if (el && el.offsetParent !== null) return true;
1125
+ }
1126
+ return false;
1127
+ })()`);
1128
+ if (found)
1129
+ return true;
1130
+ if (i < maxAttempts - 1)
1131
+ await page.wait({ time: pollMs / 1_000 });
1132
+ }
1133
+ return false;
1134
+ }
1135
+ cli({
1136
+ site: 'xiaohongshu',
1137
+ name: 'publish',
1138
+ access: 'write',
1139
+ description: '小红书发布图文笔记 (creator center UI automation)',
1140
+ domain: 'creator.xiaohongshu.com',
1141
+ strategy: Strategy.COOKIE,
1142
+ browser: true,
1143
+ navigateBefore: false,
1144
+ args: [
1145
+ { name: 'content', required: true, positional: true, help: '笔记正文' },
1146
+ { name: 'title', required: true, help: '笔记标题 (最多20字)' },
1147
+ { name: 'images', required: false, help: '图片路径,逗号分隔,最多9张 (jpg/png/gif/webp)' },
1148
+ { name: 'card-text', required: false, help: `文字配图卡片文字,多张卡片用 ${CARD_TEXT_DELIM} 分隔,卡内换行用 \\n` },
1149
+ { name: 'card-style', required: false, help: `文字配图卡片样式,运行时按页面实际选项匹配;找不到会失败。省略时使用${DEFAULT_CARD_STYLE}。可选: ${CARD_STYLE_GUIDE.map(([n, s]) => `${n}(${s})`).join(' ')}` },
1150
+ { name: 'topics', required: false, help: '话题标签,逗号分隔,不含 # 号' },
1151
+ { name: 'draft', type: 'bool', default: false, help: '保存为草稿,不直接发布' },
1152
+ ],
1153
+ columns: ['status', 'detail'],
1154
+ func: async (page, kwargs) => {
1155
+ if (!page)
1156
+ throw new Error('Browser page required');
1157
+ const title = String(kwargs.title ?? '').trim();
1158
+ const content = String(kwargs.content ?? '').trim();
1159
+ const imagePaths = kwargs.images
1160
+ ? String(kwargs.images).split(',').map((s) => s.trim()).filter(Boolean)
1161
+ : [];
1162
+ const topics = kwargs.topics
1163
+ ? String(kwargs.topics).split(',').map((s) => s.trim()).filter(Boolean)
1164
+ : [];
1165
+ const isDraft = Boolean(kwargs.draft);
1166
+ const cardText = kwargs['card-text'] ? String(kwargs['card-text']) : '';
1167
+ const cards = cardText
1168
+ ? cardText.split(CARD_TEXT_DELIM).map((s) => s.trim()).filter(Boolean)
1169
+ : [];
1170
+ const cardStyle = kwargs['card-style'] ? String(kwargs['card-style']).trim() : '';
1171
+ const isTextImage = cards.length > 0;
1172
+ // ── Validate inputs ────────────────────────────────────────────────────────
1173
+ if (!title)
1174
+ throw new ArgumentError('--title is required');
1175
+ if (title.length > MAX_TITLE_LEN)
1176
+ throw new ArgumentError(`Title is ${title.length} chars — must be ≤ ${MAX_TITLE_LEN}`);
1177
+ if (!content)
1178
+ throw new ArgumentError('Positional argument <content> is required');
1179
+ if (!isTextImage && imagePaths.length === 0)
1180
+ throw new ArgumentError('Provide --card-text (text-image mode) or --images (upload mode); neither was given.');
1181
+ if (imagePaths.length > MAX_IMAGES)
1182
+ throw new ArgumentError(`Too many images: ${imagePaths.length} (max ${MAX_IMAGES})`);
1183
+ // The editor-page image input (text-image append) rejects gif.
1184
+ if (isTextImage && imagePaths.some((p) => path.extname(p).toLowerCase() === '.gif'))
1185
+ throw new ArgumentError('文字配图模式追加的图片不支持 .gif(编辑器图片入口只接受 jpg/jpeg/png/webp)');
1186
+ // Validate image paths before navigating (fast-fail on bad paths / unsupported formats)
1187
+ const absImagePaths = validateImagePaths(imagePaths);
1188
+ // ── Step 1: Navigate to publish page ──────────────────────────────────────
1189
+ await page.goto(PUBLISH_URL);
1190
+ await page.wait({ time: 3 });
1191
+ // Verify we landed on the creator site (not redirected to login)
1192
+ const pageUrl = await page.evaluate('() => location.href');
1193
+ if (!pageUrl.includes('creator.xiaohongshu.com')) {
1194
+ throw new Error('Redirected away from creator center — session may have expired. ' +
1195
+ 'Re-capture browser login via: opencli xiaohongshu creator-profile');
1196
+ }
1197
+ // ── Step 2: Select 图文 (image+text) note type if tabs are present ─────────
1198
+ const tabResult = await selectImageTextTab(page);
1199
+ const surface = await waitForPublishSurfaceState(page, tabResult?.ok ? 5_000 : 2_000);
1200
+ if (surface.state === 'video_surface') {
1201
+ await page.screenshot({ path: '/tmp/xhs_publish_tab_debug.png' });
1202
+ const detail = tabResult?.ok
1203
+ ? `clicked "${tabResult.text}"`
1204
+ : `visible candidates: ${(tabResult?.visibleTexts || []).join(' | ') || 'none'}`;
1205
+ throw new Error('Still on the video publish page after trying to select 图文. ' +
1206
+ `Details: ${detail}. Debug screenshot: /tmp/xhs_publish_tab_debug.png`);
1207
+ }
1208
+ // ── Step 3: Acquire images — text-image generation and/or upload ──────────
1209
+ let appliedCardStyle = cardStyle;
1210
+ if (isTextImage) {
1211
+ // Drive 文字配图: type cards → 生成图片 → pick style → 下一步 → standard editor.
1212
+ appliedCardStyle = await runTextImageFlow(page, cards, cardStyle);
1213
+ }
1214
+ else {
1215
+ const upload = await uploadImages(page, absImagePaths);
1216
+ if (!upload.ok) {
1217
+ await page.screenshot({ path: '/tmp/xhs_publish_upload_debug.png' });
1218
+ throw new CommandExecutionError(`Image injection failed: ${upload.error ?? 'unknown'}. ` +
1219
+ 'Debug screenshot: /tmp/xhs_publish_upload_debug.png');
1220
+ }
1221
+ await page.wait({ time: UPLOAD_SETTLE_MS / 1_000 });
1222
+ await waitForUploads(page);
1223
+ }
1224
+ // ── Step 3b: Wait for editor form to render ───────────────────────────────
1225
+ const formReady = await waitForEditForm(page);
1226
+ if (!formReady) {
1227
+ await page.screenshot({ path: '/tmp/xhs_publish_form_debug.png' });
1228
+ throw new CommandExecutionError('Editing form did not appear after image acquisition. The page layout may have changed. ' +
1229
+ 'Debug screenshot: /tmp/xhs_publish_form_debug.png');
1230
+ }
1231
+ if (isTextImage) {
1232
+ await assertComposerMediaCount(page, cards.length, '文字配图 generated images');
1233
+ }
1234
+ // ── Step 3c: In text-image mode, optionally append uploaded images ────────
1235
+ if (isTextImage && absImagePaths.length > 0) {
1236
+ const upload = await uploadImages(page, absImagePaths);
1237
+ if (!upload.ok) {
1238
+ await page.screenshot({ path: '/tmp/xhs_publish_append_debug.png' });
1239
+ throw new CommandExecutionError(`Appending images failed: ${upload.error ?? 'unknown'}. ` +
1240
+ 'Debug screenshot: /tmp/xhs_publish_append_debug.png');
1241
+ }
1242
+ await page.wait({ time: UPLOAD_SETTLE_MS / 1_000 });
1243
+ await waitForUploads(page);
1244
+ await assertComposerMediaCount(page, cards.length + absImagePaths.length, '文字配图 appended images');
1245
+ }
1246
+ // ── Step 4: Fill title ─────────────────────────────────────────────────────
1247
+ await fillField(page, TITLE_SELECTORS, title, 'title');
1248
+ await page.wait({ time: 0.5 });
1249
+ // ── Step 5: Fill content / body ────────────────────────────────────────────
1250
+ await fillField(page, BODY_SELECTORS, content, 'content');
1251
+ await page.wait({ time: 0.5 });
1252
+ // ── Step 6: Add topic hashtags ─────────────────────────────────────────────
1253
+ // XHS converts a "#keyword" typed into the body editor into a real topic
1254
+ // entity only when the user picks an item from the inline suggestion
1255
+ // dropdown that pops up while typing. The previous implementation looked
1256
+ // for a standalone "添加话题" button + dedicated search <input>, which the
1257
+ // current creator-center editor no longer exposes — it left bare "#"
1258
+ // characters in the body with no linked topics. We now drive the native
1259
+ // inline flow: focus the body editor, type "#keyword" (firing the
1260
+ // dropdown), then select the matching suggestion.
1261
+ let addedTopics = [];
1262
+ if (topics.length) {
1263
+ addedTopics = await addTopics(page, BODY_SELECTORS, topics);
1264
+ }
1265
+ // ── Step 7: Publish or save draft ─────────────────────────────────────────
1266
+ const actionLabels = isDraft ? ['暂存离开', '存草稿'] : ['发布', '发布笔记'];
1267
+ const invokeResult = await page.evaluate(`
1268
+ (cfg => {
1269
+ const { isDraftMode, publishNames, draftNames, labels } = cfg;
1270
+ const isVisible = (el) => {
1271
+ if (!el || el.offsetParent === null) return false;
1272
+ const rect = el.getBoundingClientRect();
1273
+ return rect.width > 0 && rect.height > 0;
1274
+ };
1275
+ // Path 1: web component method invoke on <xhs-publish-btn>.
1276
+ const hosts = Array.from(document.querySelectorAll('xhs-publish-btn')).filter(isVisible);
1277
+ const wanted = isDraftMode ? draftNames : publishNames;
1278
+ // Try every host + every candidate; do NOT bail on the first throw
1279
+ // (multiple hosts can exist, and a later name may succeed).
1280
+ let lastMethodError = null;
1281
+ for (const host of hosts) {
1282
+ for (const name of wanted) {
1283
+ if (typeof host[name] !== 'function') continue;
1284
+ try {
1285
+ host[name]();
1286
+ return { ok: true, via: 'method', name };
1287
+ } catch (err) {
1288
+ lastMethodError = String(err && err.message || err);
1289
+ }
1290
+ }
1291
+ }
1292
+ // Path 2: legacy <button>/[role=button] text-match click fallback.
1293
+ const buttons = document.querySelectorAll('button, [role="button"]');
1294
+ for (const btn of buttons) {
1295
+ const text = (btn.innerText || btn.textContent || '').trim();
1296
+ if (
1297
+ labels.some(l => text === l || text.includes(l)) &&
1298
+ isVisible(btn) &&
1299
+ !btn.disabled
1300
+ ) {
1301
+ btn.click();
1302
+ return { ok: true, via: 'click', text };
1303
+ }
1304
+ }
1305
+ return { ok: false, via: 'none', hosts: hosts.length, lastMethodError };
1306
+ })(${JSON.stringify({
1307
+ isDraftMode: isDraft,
1308
+ publishNames: PUBLISH_METHOD_NAMES,
1309
+ draftNames: DRAFT_METHOD_NAMES,
1310
+ labels: actionLabels,
1311
+ })})
1312
+ `);
1313
+ if (!invokeResult?.ok) {
1314
+ // ── Draft fallback: try leave-and-save flow ──────────────────────────
1315
+ if (isDraft) {
1316
+ const leaveTriggered = await page.evaluate(`
1317
+ (() => {
1318
+ const labels = ['返回', '关闭', '取消', '离开'];
1319
+ const buttons = document.querySelectorAll('button, [role="button"], div, span');
1320
+ for (const btn of buttons) {
1321
+ const text = (btn.innerText || btn.textContent || '').trim();
1322
+ if (labels.some(l => text === l || text.includes(l)) && btn.offsetParent !== null) {
1323
+ btn.click();
1324
+ return true;
1325
+ }
1326
+ }
1327
+ return false;
1328
+ })()
1329
+ `);
1330
+ if (leaveTriggered) {
1331
+ await page.wait({ time: 1 });
1332
+ const saveLabels = ['暂存离开', '存草稿', '保存草稿'];
1333
+ const saved = await page.evaluate(`
1334
+ (labels => {
1335
+ const buttons = document.querySelectorAll('button, [role="button"]');
1336
+ for (const btn of buttons) {
1337
+ const text = (btn.innerText || btn.textContent || '').trim();
1338
+ if (
1339
+ labels.some(l => text === l || text.includes(l)) &&
1340
+ btn.offsetParent !== null &&
1341
+ !btn.disabled
1342
+ ) {
1343
+ btn.click();
1344
+ return true;
1345
+ }
1346
+ }
1347
+ return false;
1348
+ })(${JSON.stringify(saveLabels)})
1349
+ `);
1350
+ if (saved) {
1351
+ invokeResult.ok = true;
1352
+ invokeResult.via = 'leave-save-fallback';
1353
+ }
1354
+ }
1355
+ // Check if auto-saved
1356
+ if (!invokeResult?.ok) {
1357
+ await page.wait({ time: 2 });
1358
+ const autoSaved = await page.evaluate(`
1359
+ () => {
1360
+ const markers = ['草稿箱(', '保存于', '编辑于'];
1361
+ for (const el of document.querySelectorAll('*')) {
1362
+ const text = (el.innerText || el.textContent || '').trim();
1363
+ if (text && markers.some(marker => text.includes(marker))) return true;
1364
+ }
1365
+ return false;
1366
+ }
1367
+ `);
1368
+ if (autoSaved) {
1369
+ invokeResult.ok = true;
1370
+ invokeResult.via = 'auto-save';
1371
+ }
1372
+ }
1373
+ }
1374
+ }
1375
+ if (!invokeResult?.ok) {
1376
+ await page.screenshot({ path: '/tmp/xhs_publish_submit_debug.png' });
1377
+ const viaClause = invokeResult?.via ? ` (via=${invokeResult.via})` : '';
1378
+ const errorClause = invokeResult?.error ? `, error=${invokeResult.error}` : '';
1379
+ const lastMethodClause = invokeResult?.lastMethodError ? `, lastMethodError=${invokeResult.lastMethodError}` : '';
1380
+ throw new Error(`Could not trigger "${actionLabels[0]}" action${viaClause}${errorClause}${lastMethodClause}. ` +
1381
+ 'Debug screenshot: /tmp/xhs_publish_submit_debug.png');
1382
+ }
1383
+ // ── Step 8: Verify success ─────────────────────────────────────────────────
1384
+ await page.wait({ time: 4 });
1385
+ const finalUrl = await page.evaluate('() => location.href');
1386
+ const successMarkers = isDraft
1387
+ ? ['草稿已保存', '暂存成功', '保存成功', '保存于', '图文笔记(']
1388
+ : ['发布成功', '上传成功'];
1389
+ const successMsg = await page.evaluate(`
1390
+ (markers => {
1391
+ for (const el of document.querySelectorAll('*')) {
1392
+ if (el.tagName === 'STYLE' || el.tagName === 'SCRIPT') continue;
1393
+ const text = (el.innerText || '').trim();
1394
+ if (text.length > 200) continue;
1395
+ if (el.children.length === 0 && markers.some(marker => text.includes(marker))) return text;
1396
+ }
1397
+ return '';
1398
+ })(${JSON.stringify(successMarkers)})
1399
+ `);
1400
+ const navigatedAway = !finalUrl.includes('/publish/publish');
1401
+ const isSuccess = successMsg.length > 0 || navigatedAway;
1402
+ const verb = isDraft ? '暂存成功' : '发布成功';
1403
+ if (!isSuccess) {
1404
+ throw new CommandExecutionError(`${verb} could not be verified: no success marker or post-submit navigation was observed. ` +
1405
+ (finalUrl ? `Current URL: ${finalUrl}` : 'Current URL was empty.'));
1406
+ }
1407
+ return [
1408
+ {
1409
+ status: `✅ ${verb}`,
1410
+ detail: [
1411
+ `"${title}"`,
1412
+ isTextImage
1413
+ ? `${cards.length}张文字配图${absImagePaths.length ? ` + ${absImagePaths.length}张图片` : ''}${appliedCardStyle && appliedCardStyle !== DEFAULT_CARD_STYLE ? ` (${appliedCardStyle})` : ''}`
1414
+ : `${absImagePaths.length}张图片`,
1415
+ addedTopics.length ? `话题: ${addedTopics.join(' ')}` : '',
1416
+ successMsg || finalUrl || '',
1417
+ ]
1418
+ .filter(Boolean)
1419
+ .join(' · '),
1420
+ },
1421
+ ];
1422
+ },
1423
+ });