publishport-opencli 1.0.20 → 1.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1041) hide show
  1. package/clis/12306/me.js +2 -2
  2. package/clis/12306/orders.js +3 -3
  3. package/clis/12306/passengers.js +3 -3
  4. package/clis/12306/price.js +1 -1
  5. package/clis/12306/stations.js +1 -1
  6. package/clis/12306/train.js +1 -1
  7. package/clis/12306/trains.js +1 -1
  8. package/clis/12306/utils.js +1 -1
  9. package/clis/1688/download.js +1 -1
  10. package/clis/1688/item.js +4 -4
  11. package/clis/1688/search.js +4 -4
  12. package/clis/1688/store.js +4 -4
  13. package/clis/1point3acres/forum.js +1 -1
  14. package/clis/1point3acres/forums.js +1 -1
  15. package/clis/1point3acres/notifications.js +1 -1
  16. package/clis/1point3acres/search.js +1 -1
  17. package/clis/1point3acres/thread.js +2 -2
  18. package/clis/1point3acres/user.js +1 -1
  19. package/clis/1point3acres/utils.js +2 -2
  20. package/clis/36kr/article.js +2 -2
  21. package/clis/36kr/hot.js +2 -2
  22. package/clis/36kr/news.js +1 -1
  23. package/clis/36kr/search.js +2 -2
  24. package/clis/51job/company.js +2 -2
  25. package/clis/51job/detail.js +2 -2
  26. package/clis/51job/hot.js +1 -1
  27. package/clis/51job/search.js +1 -1
  28. package/clis/51job/utils.js +7 -7
  29. package/clis/_atlassian/shared.js +9 -9
  30. package/clis/_shared/article/auth.js +4 -4
  31. package/clis/_shared/article/douban-md2draft.js +4 -4
  32. package/clis/_shared/article/format.js +1 -1
  33. package/clis/_shared/article/images.js +7 -7
  34. package/clis/_shared/article/login.js +1 -1
  35. package/clis/_shared/article/publish.js +11 -11
  36. package/clis/_shared/common.js +1 -1
  37. package/clis/_shared/content-guard.js +1 -1
  38. package/clis/_shared/desktop-commands.js +1 -1
  39. package/clis/_shared/file-inject.js +12 -12
  40. package/clis/_shared/self-hosted-sites.js +2 -2
  41. package/clis/_shared/site-auth.js +1 -1
  42. package/clis/_shared/token-auth.js +2 -2
  43. package/clis/_shared/video-publish.js +9 -9
  44. package/clis/amazon/offer.js +3 -3
  45. package/clis/amazon/product.js +5 -5
  46. package/clis/amazon/shared.js +6 -6
  47. package/clis/antigravity/_actions.js +13 -13
  48. package/clis/antigravity/audit-extras.js +10 -10
  49. package/clis/antigravity/delete.js +1 -1
  50. package/clis/antigravity/model.js +6 -6
  51. package/clis/antigravity/new.js +2 -2
  52. package/clis/antigravity/read.js +2 -2
  53. package/clis/antigravity/rename.js +1 -1
  54. package/clis/antigravity/send.js +3 -3
  55. package/clis/antigravity/serve.js +17 -17
  56. package/clis/antigravity/storage.js +6 -6
  57. package/clis/antigravity/watch.js +2 -2
  58. package/clis/apple-podcasts/episodes.js +1 -1
  59. package/clis/apple-podcasts/top.js +1 -1
  60. package/clis/apple-podcasts/utils.js +1 -1
  61. package/clis/archive/item.js +1 -1
  62. package/clis/archive/search.js +1 -1
  63. package/clis/archive/snapshots.js +1 -1
  64. package/clis/archive/wayback.js +1 -1
  65. package/clis/arxiv/author.js +1 -1
  66. package/clis/arxiv/utils.js +1 -1
  67. package/clis/autohome/brand.js +1 -1
  68. package/clis/autohome/score.js +1 -1
  69. package/clis/autohome/utils.js +1 -1
  70. package/clis/baijiahao/article.js +1 -1
  71. package/clis/baijiahao/lists.js +1 -1
  72. package/clis/baijiahao/login.js +1 -1
  73. package/clis/baijiahao/publish.js +9 -9
  74. package/clis/baijiahao/stats.js +1 -1
  75. package/clis/baijiahao/whoami.js +1 -1
  76. package/clis/band/bands.js +2 -2
  77. package/clis/band/mentions.js +2 -2
  78. package/clis/band/post.js +4 -4
  79. package/clis/band/posts.js +3 -3
  80. package/clis/barchart/flow.js +3 -3
  81. package/clis/barchart/greeks.js +2 -2
  82. package/clis/barchart/quote.js +3 -3
  83. package/clis/bbc/news.js +1 -1
  84. package/clis/bbc/topic.js +1 -1
  85. package/clis/bbc/utils.js +1 -1
  86. package/clis/bilibili/article.js +1 -1
  87. package/clis/bilibili/categories.js +1 -1
  88. package/clis/bilibili/coin.js +1 -1
  89. package/clis/bilibili/comment-del.js +1 -1
  90. package/clis/bilibili/comment-like.js +1 -1
  91. package/clis/bilibili/comment.js +1 -1
  92. package/clis/bilibili/comments.js +1 -1
  93. package/clis/bilibili/dm-list.js +1 -1
  94. package/clis/bilibili/dm-read.js +1 -1
  95. package/clis/bilibili/dm-send.js +1 -1
  96. package/clis/bilibili/download.js +2 -2
  97. package/clis/bilibili/drafts.js +1 -1
  98. package/clis/bilibili/dynamic-post.js +3 -3
  99. package/clis/bilibili/favorite-add.js +1 -1
  100. package/clis/bilibili/favorite.js +1 -1
  101. package/clis/bilibili/feed.js +2 -2
  102. package/clis/bilibili/follow.js +1 -1
  103. package/clis/bilibili/following.js +1 -1
  104. package/clis/bilibili/like.js +1 -1
  105. package/clis/bilibili/partitions.js +1 -1
  106. package/clis/bilibili/stats.js +1 -1
  107. package/clis/bilibili/subtitle.js +3 -3
  108. package/clis/bilibili/summary.js +1 -1
  109. package/clis/bilibili/topics.js +1 -1
  110. package/clis/bilibili/unfollow.js +1 -1
  111. package/clis/bilibili/upload.js +1 -1
  112. package/clis/bilibili/utils.js +10 -10
  113. package/clis/bilibili/video-drafts.js +1 -1
  114. package/clis/bilibili/video.js +1 -1
  115. package/clis/bloomberg/businessweek.js +4 -4
  116. package/clis/bloomberg/news.js +2 -2
  117. package/clis/bloomberg/utils.js +13 -13
  118. package/clis/bluesky/post.js +1 -1
  119. package/clis/bluesky/shared.js +11 -11
  120. package/clis/bluesky/whoami.js +1 -1
  121. package/clis/booking/search.js +2 -2
  122. package/clis/boss/accept.js +1 -1
  123. package/clis/boss/applied.js +1 -1
  124. package/clis/boss/auth.js +1 -1
  125. package/clis/boss/batchgreet.js +1 -1
  126. package/clis/boss/bossinfo.js +1 -1
  127. package/clis/boss/chatlist.js +1 -1
  128. package/clis/boss/chatmsg.js +1 -1
  129. package/clis/boss/cities.js +1 -1
  130. package/clis/boss/detail.js +1 -1
  131. package/clis/boss/exchange.js +1 -1
  132. package/clis/boss/greet.js +1 -1
  133. package/clis/boss/interviews.js +1 -1
  134. package/clis/boss/invite.js +1 -1
  135. package/clis/boss/joblist.js +1 -1
  136. package/clis/boss/mark.js +1 -1
  137. package/clis/boss/me.js +2 -2
  138. package/clis/boss/recommend.js +1 -1
  139. package/clis/boss/resumedelete.js +1 -1
  140. package/clis/boss/resumelist.js +1 -1
  141. package/clis/boss/resumeupload.js +11 -11
  142. package/clis/boss/search.js +1 -1
  143. package/clis/boss/send.js +1 -1
  144. package/clis/boss/sendresume.js +1 -1
  145. package/clis/boss/stats.js +1 -1
  146. package/clis/boss/unread.js +1 -1
  147. package/clis/boss/utils.js +13 -13
  148. package/clis/chaoxing/assignments.js +1 -1
  149. package/clis/chaoxing/exams.js +1 -1
  150. package/clis/chaoxing/utils.js +9 -9
  151. package/clis/chatgpt/ask.js +1 -1
  152. package/clis/chatgpt/auth.js +2 -2
  153. package/clis/chatgpt/detail.js +1 -1
  154. package/clis/chatgpt/image.js +1 -1
  155. package/clis/chatgpt/read.js +1 -1
  156. package/clis/chatgpt/send.js +1 -1
  157. package/clis/chatgpt/utils.js +59 -59
  158. package/clis/chatgpt-app/ask.js +1 -1
  159. package/clis/chatgpt-app/send.js +1 -1
  160. package/clis/chatwise/model.js +6 -6
  161. package/clis/chess/analyze.js +1 -1
  162. package/clis/chess/game.js +1 -1
  163. package/clis/chess/games.js +1 -1
  164. package/clis/chess/stats.js +1 -1
  165. package/clis/chess/utils.js +1 -1
  166. package/clis/claude/ask.js +2 -2
  167. package/clis/claude/detail.js +1 -1
  168. package/clis/claude/new.js +1 -1
  169. package/clis/claude/read.js +1 -1
  170. package/clis/claude/send.js +1 -1
  171. package/clis/claude/utils.js +23 -23
  172. package/clis/cnblogs/article.js +1 -1
  173. package/clis/cnblogs/login.js +1 -1
  174. package/clis/cnblogs/stats.js +7 -7
  175. package/clis/cnblogs/whoami.js +1 -1
  176. package/clis/codex/_actions.js +3 -3
  177. package/clis/codex/archive.js +1 -1
  178. package/clis/codex/ask.js +6 -6
  179. package/clis/codex/model.js +8 -8
  180. package/clis/codex/pin.js +1 -1
  181. package/clis/codex/rename.js +4 -4
  182. package/clis/codex/send.js +3 -3
  183. package/clis/codex/sidebar.js +1 -1
  184. package/clis/coingecko/categories.js +1 -1
  185. package/clis/coingecko/coin.js +1 -1
  186. package/clis/coingecko/derivatives.js +1 -1
  187. package/clis/coingecko/exchanges.js +1 -1
  188. package/clis/coingecko/global.js +1 -1
  189. package/clis/coingecko/trending.js +1 -1
  190. package/clis/confluence/search.js +1 -1
  191. package/clis/coupang/product.js +3 -3
  192. package/clis/coupang/utils.js +1 -1
  193. package/clis/crates/crate.js +1 -1
  194. package/clis/crates/search.js +1 -1
  195. package/clis/crates/utils.js +1 -1
  196. package/clis/csdn/article.js +13 -13
  197. package/clis/csdn/columns.js +1 -1
  198. package/clis/csdn/login.js +1 -1
  199. package/clis/csdn/stats.js +4 -4
  200. package/clis/csdn/whoami.js +1 -1
  201. package/clis/cto51/article.js +1 -1
  202. package/clis/cto51/whoami.js +1 -1
  203. package/clis/ctrip/flight.js +2 -2
  204. package/clis/ctrip/hotel-search.js +3 -3
  205. package/clis/ctrip/hotel-suggest.js +1 -1
  206. package/clis/ctrip/search.js +1 -1
  207. package/clis/ctrip/utils.js +6 -6
  208. package/clis/cursor/ask.js +5 -5
  209. package/clis/cursor/composer.js +2 -2
  210. package/clis/cursor/model.js +4 -4
  211. package/clis/cursor/send.js +2 -2
  212. package/clis/dblp/author.js +1 -1
  213. package/clis/dblp/paper.js +1 -1
  214. package/clis/dblp/search.js +1 -1
  215. package/clis/dblp/utils.js +1 -1
  216. package/clis/dblp/venue.js +1 -1
  217. package/clis/deepseek/ask.js +1 -1
  218. package/clis/deepseek/auth.js +2 -2
  219. package/clis/deepseek/detail.js +1 -1
  220. package/clis/deepseek/new.js +1 -1
  221. package/clis/deepseek/read.js +1 -1
  222. package/clis/deepseek/send.js +7 -7
  223. package/clis/deepseek/utils.js +25 -25
  224. package/clis/defillama/protocol.js +1 -1
  225. package/clis/defillama/protocols.js +1 -1
  226. package/clis/defillama/utils.js +1 -1
  227. package/clis/devto/auth.js +2 -2
  228. package/clis/devto/latest.js +1 -1
  229. package/clis/devto/publish.js +5 -5
  230. package/clis/devto/read.js +2 -2
  231. package/clis/devto/stats.js +3 -3
  232. package/clis/dianping/auth.js +2 -2
  233. package/clis/dianping/cityResolver.js +2 -2
  234. package/clis/dianping/search.js +1 -1
  235. package/clis/dianping/shop.js +1 -1
  236. package/clis/dianping/utils.js +1 -1
  237. package/clis/discord-app/delete.js +3 -3
  238. package/clis/discord-app/read.js +1 -1
  239. package/clis/discord-app/thread-read.js +1 -1
  240. package/clis/discord-web/auth.js +2 -2
  241. package/clis/discord-web/send.js +5 -5
  242. package/clis/dockerhub/image.js +1 -1
  243. package/clis/dockerhub/search.js +1 -1
  244. package/clis/dockerhub/utils.js +1 -1
  245. package/clis/dongchedi/koubei.js +1 -1
  246. package/clis/dongchedi/models.js +1 -1
  247. package/clis/dongchedi/score.js +1 -1
  248. package/clis/dongchedi/search.js +1 -1
  249. package/clis/dongchedi/series.js +1 -1
  250. package/clis/dongchedi/specs.js +1 -1
  251. package/clis/dongchedi/utils.js +1 -1
  252. package/clis/douban/article.js +3 -3
  253. package/clis/douban/auth.js +2 -2
  254. package/clis/douban/download.js +1 -1
  255. package/clis/douban/utils.js +23 -23
  256. package/clis/doubao/auth.js +3 -3
  257. package/clis/doubao/utils.js +39 -39
  258. package/clis/doubao-app/ask.js +1 -1
  259. package/clis/doubao-app/utils.js +4 -4
  260. package/clis/douyin/_shared/browser-fetch.js +7 -7
  261. package/clis/douyin/_shared/draft-cache.js +1 -1
  262. package/clis/douyin/_shared/imagex-upload.js +1 -1
  263. package/clis/douyin/_shared/sts2.js +1 -1
  264. package/clis/douyin/_shared/text-extra.js +1 -1
  265. package/clis/douyin/_shared/tos-upload.js +4 -4
  266. package/clis/douyin/_shared/transcode.js +1 -1
  267. package/clis/douyin/_shared/vod-upload.js +4 -4
  268. package/clis/douyin/draft.js +18 -18
  269. package/clis/douyin/drafts.js +1 -1
  270. package/clis/douyin/publish-image.js +12 -12
  271. package/clis/douyin/publish.js +9 -9
  272. package/clis/douyin/search.js +3 -3
  273. package/clis/douyin/videos.js +1 -1
  274. package/clis/eastmoney/_secid.js +1 -1
  275. package/clis/eastmoney/announcement.js +1 -1
  276. package/clis/eastmoney/article.js +1 -1
  277. package/clis/eastmoney/convertible.js +1 -1
  278. package/clis/eastmoney/etf.js +1 -1
  279. package/clis/eastmoney/holders.js +1 -1
  280. package/clis/eastmoney/index-board.js +1 -1
  281. package/clis/eastmoney/kline.js +1 -1
  282. package/clis/eastmoney/kuaixun.js +1 -1
  283. package/clis/eastmoney/longhu.js +1 -1
  284. package/clis/eastmoney/money-flow.js +1 -1
  285. package/clis/eastmoney/northbound.js +1 -1
  286. package/clis/eastmoney/quote.js +1 -1
  287. package/clis/eastmoney/rank.js +1 -1
  288. package/clis/eastmoney/sectors.js +1 -1
  289. package/clis/endoflife/product.js +1 -1
  290. package/clis/endoflife/utils.js +1 -1
  291. package/clis/facebook/comment.js +8 -8
  292. package/clis/facebook/feed.js +4 -4
  293. package/clis/facebook/like.js +5 -5
  294. package/clis/facebook/notifications.js +3 -3
  295. package/clis/facebook/post.js +11 -11
  296. package/clis/facebook/search.js +3 -3
  297. package/clis/flathub/app.js +1 -1
  298. package/clis/flathub/search.js +1 -1
  299. package/clis/flathub/utils.js +1 -1
  300. package/clis/flomo/memos.js +1 -1
  301. package/clis/gemini/deep-research-result.js +4 -4
  302. package/clis/gemini/deep-research.js +1 -1
  303. package/clis/gemini/detail.js +1 -1
  304. package/clis/gemini/history.js +1 -1
  305. package/clis/gemini/image.js +2 -2
  306. package/clis/gemini/status.js +1 -1
  307. package/clis/gemini/utils.js +43 -43
  308. package/clis/geogebra/hexagon.js +1 -1
  309. package/clis/geogebra/info.js +3 -3
  310. package/clis/geogebra/triangle.js +1 -1
  311. package/clis/geogebra/utils.js +11 -11
  312. package/clis/ghost/login.js +1 -1
  313. package/clis/ghost/shared.js +2 -2
  314. package/clis/gitee/auth.js +2 -2
  315. package/clis/github-trending/repos.js +1 -1
  316. package/clis/google/news.js +1 -1
  317. package/clis/google/search.js +2 -2
  318. package/clis/google/suggest.js +1 -1
  319. package/clis/google/trends.js +1 -1
  320. package/clis/google/utils.js +1 -1
  321. package/clis/goproxy/module.js +1 -1
  322. package/clis/goproxy/utils.js +1 -1
  323. package/clis/goproxy/versions.js +1 -1
  324. package/clis/gov-policy/recent.js +2 -2
  325. package/clis/gov-policy/search.js +2 -2
  326. package/clis/grok/ask.js +1 -1
  327. package/clis/grok/detail.js +1 -1
  328. package/clis/grok/image.js +8 -8
  329. package/clis/grok/pin.js +1 -1
  330. package/clis/grok/send.js +1 -1
  331. package/clis/grok/status.js +1 -1
  332. package/clis/grok/utils.js +21 -21
  333. package/clis/guazi/browse.js +1 -1
  334. package/clis/guazi/car.js +1 -1
  335. package/clis/guazi/utils.js +1 -1
  336. package/clis/hackernews/auth.js +2 -2
  337. package/clis/hackernews/comment.js +8 -8
  338. package/clis/hackernews/read.js +7 -7
  339. package/clis/hackernews/submit.js +7 -7
  340. package/clis/hashnode/auth.js +3 -3
  341. package/clis/hashnode/publish.js +14 -14
  342. package/clis/hf/auth.js +2 -2
  343. package/clis/hf/models.js +1 -1
  344. package/clis/hf/paper.js +1 -1
  345. package/clis/hf/spaces.js +1 -1
  346. package/clis/hf/top.js +1 -1
  347. package/clis/homebrew/cask.js +1 -1
  348. package/clis/homebrew/formula.js +1 -1
  349. package/clis/homebrew/popular.js +1 -1
  350. package/clis/homebrew/utils.js +1 -1
  351. package/clis/huodongxing/events.js +1 -1
  352. package/clis/hupu/detail.js +4 -4
  353. package/clis/hupu/hot.js +3 -3
  354. package/clis/hupu/reply.js +1 -1
  355. package/clis/hupu/search.js +1 -1
  356. package/clis/hupu/unlike.js +1 -1
  357. package/clis/hupu/utils.js +10 -10
  358. package/clis/imdb/person.js +2 -2
  359. package/clis/imdb/reviews.js +3 -3
  360. package/clis/imdb/search.js +2 -2
  361. package/clis/imdb/title.js +1 -1
  362. package/clis/imdb/top.js +1 -1
  363. package/clis/imdb/trending.js +1 -1
  364. package/clis/imdb/utils.js +13 -13
  365. package/clis/imooc/article.js +6 -6
  366. package/clis/imooc/login.js +1 -1
  367. package/clis/imooc/whoami.js +1 -1
  368. package/clis/indeed/job.js +2 -2
  369. package/clis/indeed/search.js +2 -2
  370. package/clis/indeed/utils.js +1 -1
  371. package/clis/infoq/article.js +2 -2
  372. package/clis/infoq/login.js +1 -1
  373. package/clis/infoq/whoami.js +1 -1
  374. package/clis/instagram/_shared/private-publish.js +4 -4
  375. package/clis/instagram/_shared/protocol-capture.js +9 -9
  376. package/clis/instagram/detail.js +3 -3
  377. package/clis/instagram/post.js +25 -25
  378. package/clis/instagram/reel.js +18 -18
  379. package/clis/instagram/story.js +4 -4
  380. package/clis/instagram/user.js +2 -2
  381. package/clis/jd/item.js +65 -65
  382. package/clis/jianshu/article.js +1 -1
  383. package/clis/jianshu/login.js +1 -1
  384. package/clis/jianshu/notebooks.js +1 -1
  385. package/clis/jianshu/whoami.js +1 -1
  386. package/clis/jianyu/search.js +6 -6
  387. package/clis/jianyu/shared/procurement-contract.js +1 -1
  388. package/clis/jike/api.js +6 -6
  389. package/clis/jike/auth.js +3 -3
  390. package/clis/jike/comment.js +1 -1
  391. package/clis/jike/create.js +6 -6
  392. package/clis/jike/feed.js +3 -3
  393. package/clis/jike/like.js +1 -1
  394. package/clis/jike/notifications.js +3 -3
  395. package/clis/jike/repost.js +13 -13
  396. package/clis/jike/search.js +3 -3
  397. package/clis/jimeng/auth.js +2 -2
  398. package/clis/jimeng/generate.js +10 -10
  399. package/clis/jira/shared.js +1 -1
  400. package/clis/juejin/article.js +4 -4
  401. package/clis/juejin/categories.js +1 -1
  402. package/clis/juejin/hot.js +1 -1
  403. package/clis/juejin/login.js +1 -1
  404. package/clis/juejin/recommend.js +1 -1
  405. package/clis/juejin/stats.js +3 -3
  406. package/clis/juejin/tags.js +1 -1
  407. package/clis/juejin/utils.js +1 -1
  408. package/clis/juejin/whoami.js +1 -1
  409. package/clis/ke/utils.js +4 -4
  410. package/clis/kimi/_utils.js +7 -7
  411. package/clis/kimi/audit-extras.js +14 -14
  412. package/clis/kimi/auth.js +3 -3
  413. package/clis/kimi/chat.js +15 -15
  414. package/clis/kimi/storage.js +5 -5
  415. package/clis/kimi/ui.js +13 -13
  416. package/clis/kimi/usage.js +3 -3
  417. package/clis/kuaishou/auth.js +1 -1
  418. package/clis/kuaishou/publish.js +6 -6
  419. package/clis/lesswrong/_helpers.js +5 -5
  420. package/clis/lesswrong/comments.js +5 -5
  421. package/clis/lichess/top.js +1 -1
  422. package/clis/lichess/user.js +1 -1
  423. package/clis/lichess/utils.js +1 -1
  424. package/clis/linkedin/comment.js +1 -1
  425. package/clis/linkedin/connect.js +11 -11
  426. package/clis/linkedin/create.js +5 -5
  427. package/clis/linkedin/follow.js +1 -1
  428. package/clis/linkedin/inbox.js +1 -1
  429. package/clis/linkedin/job-detail.js +3 -3
  430. package/clis/linkedin/like.js +1 -1
  431. package/clis/linkedin/notifications.js +1 -1
  432. package/clis/linkedin/people-search.js +1 -1
  433. package/clis/linkedin/post-comments.js +1 -1
  434. package/clis/linkedin/post-detail.js +1 -1
  435. package/clis/linkedin/profile-analytics.js +1 -1
  436. package/clis/linkedin/profile-api.js +13 -13
  437. package/clis/linkedin/profile-experience.js +1 -1
  438. package/clis/linkedin/profile-projects.js +1 -1
  439. package/clis/linkedin/profile-read.js +3 -3
  440. package/clis/linkedin/reply.js +1 -1
  441. package/clis/linkedin/repost.js +1 -1
  442. package/clis/linkedin/safe-send.js +8 -8
  443. package/clis/linkedin/salesnav-inbox.js +5 -5
  444. package/clis/linkedin/salesnav-message.js +3 -3
  445. package/clis/linkedin/salesnav-search.js +4 -4
  446. package/clis/linkedin/salesnav-thread.js +1 -1
  447. package/clis/linkedin/search-api.js +3 -3
  448. package/clis/linkedin/search.js +8 -8
  449. package/clis/linkedin/social-api.js +31 -31
  450. package/clis/linkedin/timeline.js +3 -3
  451. package/clis/linkedin-learning/search.js +2 -2
  452. package/clis/linkedin-learning/trending.js +2 -2
  453. package/clis/linux-do/feed.js +4 -4
  454. package/clis/linux-do/topic-content.js +8 -8
  455. package/clis/lobsters/domain.js +1 -1
  456. package/clis/lobsters/read.js +7 -7
  457. package/clis/maimai/auth.js +2 -2
  458. package/clis/maimai/search-talents.js +4 -4
  459. package/clis/manus/_utils.js +1 -1
  460. package/clis/mastodon/login.js +1 -1
  461. package/clis/mastodon/post.js +1 -1
  462. package/clis/mastodon/shared.js +12 -12
  463. package/clis/mastodon/whoami.js +1 -1
  464. package/clis/maven/artifact.js +1 -1
  465. package/clis/maven/search.js +1 -1
  466. package/clis/maven/utils.js +1 -1
  467. package/clis/mdn/search.js +1 -1
  468. package/clis/medium/article.js +5 -5
  469. package/clis/medium/login.js +1 -1
  470. package/clis/medium/stats.js +3 -3
  471. package/clis/medium/tag.js +1 -1
  472. package/clis/medium/whoami.js +1 -1
  473. package/clis/mubu/notes.js +1 -1
  474. package/clis/mubu/utils.js +15 -15
  475. package/clis/note/auth.js +2 -2
  476. package/clis/note/note-utils.js +2 -2
  477. package/clis/note/publish.js +8 -8
  478. package/clis/notebooklm/add-source.js +8 -8
  479. package/clis/notebooklm/create.js +1 -1
  480. package/clis/notebooklm/generate-slides.js +1 -1
  481. package/clis/notebooklm/notes-get.js +1 -1
  482. package/clis/notebooklm/rpc.js +8 -8
  483. package/clis/notebooklm/source-fulltext.js +1 -1
  484. package/clis/notebooklm/utils.js +10 -10
  485. package/clis/nowcoder/auth.js +2 -2
  486. package/clis/nowcoder/comment.js +1 -1
  487. package/clis/nowcoder/comments.js +1 -1
  488. package/clis/nowcoder/dm-list.js +1 -1
  489. package/clis/nowcoder/dm-read.js +1 -1
  490. package/clis/nowcoder/dm-send.js +1 -1
  491. package/clis/nowcoder/drafts.js +1 -1
  492. package/clis/nowcoder/inbox.js +1 -1
  493. package/clis/nowcoder/like.js +1 -1
  494. package/clis/nowcoder/my.js +1 -1
  495. package/clis/nowcoder/post.js +1 -1
  496. package/clis/nowcoder/utils.js +13 -13
  497. package/clis/npm/downloads.js +1 -1
  498. package/clis/npm/package.js +1 -1
  499. package/clis/npm/search.js +1 -1
  500. package/clis/npm/utils.js +1 -1
  501. package/clis/nuget/package.js +1 -1
  502. package/clis/nuget/search.js +1 -1
  503. package/clis/nuget/utils.js +1 -1
  504. package/clis/nvd/cve.js +1 -1
  505. package/clis/oeis/search.js +1 -1
  506. package/clis/oeis/sequence.js +1 -1
  507. package/clis/oeis/utils.js +1 -1
  508. package/clis/ones/common.js +6 -6
  509. package/clis/ones/enrich-tasks.js +1 -1
  510. package/clis/ones/my-tasks.js +1 -1
  511. package/clis/ones/resolve-labels.js +1 -1
  512. package/clis/ones/task-helpers.js +1 -1
  513. package/clis/ones/task.js +1 -1
  514. package/clis/ones/worklog.js +7 -7
  515. package/clis/openalex/search.js +1 -1
  516. package/clis/openalex/utils.js +1 -1
  517. package/clis/openalex/work.js +1 -1
  518. package/clis/openfda/drug-label.js +1 -1
  519. package/clis/openfda/food-recall.js +1 -1
  520. package/clis/openfda/utils.js +1 -1
  521. package/clis/openreview/author.js +1 -1
  522. package/clis/openreview/paper.js +1 -1
  523. package/clis/openreview/reviews.js +3 -3
  524. package/clis/openreview/search.js +1 -1
  525. package/clis/openreview/utils.js +1 -1
  526. package/clis/openreview/venue.js +1 -1
  527. package/clis/oschina/article.js +1 -1
  528. package/clis/oschina/catalogs.js +1 -1
  529. package/clis/oschina/login.js +1 -1
  530. package/clis/oschina/stats.js +6 -6
  531. package/clis/oschina/whoami.js +1 -1
  532. package/clis/osv/query.js +1 -1
  533. package/clis/osv/utils.js +1 -1
  534. package/clis/osv/vulnerability.js +1 -1
  535. package/clis/packagist/package.js +1 -1
  536. package/clis/packagist/search.js +1 -1
  537. package/clis/packagist/utils.js +1 -1
  538. package/clis/pinterest/api.js +1 -1
  539. package/clis/pinterest/auth.js +1 -1
  540. package/clis/pinterest/boards.js +1 -1
  541. package/clis/pinterest/client.js +6 -6
  542. package/clis/pinterest/publish.js +5 -5
  543. package/clis/pixiv/auth.js +2 -2
  544. package/clis/pixiv/download.js +1 -1
  545. package/clis/pixiv/illusts.js +1 -1
  546. package/clis/pixiv/search.js +1 -1
  547. package/clis/pixiv/utils.js +3 -3
  548. package/clis/powerchina/auth.js +2 -2
  549. package/clis/powerchina/search.js +1 -1
  550. package/clis/producthunt/browse.js +2 -2
  551. package/clis/producthunt/hot.js +2 -2
  552. package/clis/producthunt/posts.js +1 -1
  553. package/clis/producthunt/today.js +1 -1
  554. package/clis/producthunt/utils.js +1 -1
  555. package/clis/pypi/downloads.js +1 -1
  556. package/clis/pypi/package.js +1 -1
  557. package/clis/pypi/utils.js +1 -1
  558. package/clis/qiita/auth.js +1 -1
  559. package/clis/qiita/gql.js +6 -6
  560. package/clis/qiita/publish.js +4 -4
  561. package/clis/qiita/stats.js +4 -4
  562. package/clis/qoder/_utils.js +16 -16
  563. package/clis/qoder/composer.js +1 -1
  564. package/clis/qoder/quest.js +1 -1
  565. package/clis/qoder/ui.js +14 -14
  566. package/clis/quark/auth.js +2 -2
  567. package/clis/quark/utils.js +2 -2
  568. package/clis/quora/answer-comments.js +3 -3
  569. package/clis/quora/create-answer.js +4 -4
  570. package/clis/quora/create-question.js +3 -3
  571. package/clis/quora/shared.js +17 -17
  572. package/clis/quora/whoami.js +1 -1
  573. package/clis/qwen/ask.js +1 -1
  574. package/clis/qwen/auth.js +3 -3
  575. package/clis/qwen/detail.js +1 -1
  576. package/clis/qwen/image.js +5 -5
  577. package/clis/qwen/status.js +1 -1
  578. package/clis/qwen/utils.js +16 -16
  579. package/clis/reddit/home.js +3 -3
  580. package/clis/reddit/read.js +10 -10
  581. package/clis/reddit/reply.js +4 -4
  582. package/clis/reddit/submit.js +11 -11
  583. package/clis/reddit/subreddit-info.js +3 -3
  584. package/clis/reddit/subscribed.js +4 -4
  585. package/clis/reddit/whoami.js +2 -2
  586. package/clis/rednote/comments.js +1 -1
  587. package/clis/rednote/download.js +1 -1
  588. package/clis/rednote/feed.js +1 -1
  589. package/clis/rednote/note.js +1 -1
  590. package/clis/rednote/notifications.js +2 -2
  591. package/clis/rednote/search.js +2 -2
  592. package/clis/rest-countries/country.js +1 -1
  593. package/clis/rest-countries/region.js +1 -1
  594. package/clis/rest-countries/utils.js +1 -1
  595. package/clis/reuters/article-detail.js +1 -1
  596. package/clis/reuters/auth.js +3 -3
  597. package/clis/reuters/search.js +1 -1
  598. package/clis/reuters/utils.js +4 -4
  599. package/clis/rfc/rfc.js +1 -1
  600. package/clis/rfc/utils.js +1 -1
  601. package/clis/rubygems/gem.js +1 -1
  602. package/clis/rubygems/search.js +1 -1
  603. package/clis/rubygems/utils.js +1 -1
  604. package/clis/segmentfault/article.js +3 -3
  605. package/clis/segmentfault/channels.js +1 -1
  606. package/clis/segmentfault/login.js +1 -1
  607. package/clis/segmentfault/stats.js +4 -4
  608. package/clis/segmentfault/tags.js +1 -1
  609. package/clis/segmentfault/whoami.js +1 -1
  610. package/clis/semanticscholar/citations.js +1 -1
  611. package/clis/semanticscholar/paper.js +1 -1
  612. package/clis/semanticscholar/recommendations.js +1 -1
  613. package/clis/semanticscholar/search.js +1 -1
  614. package/clis/semanticscholar/utils.js +1 -1
  615. package/clis/sinafinance/news.js +1 -1
  616. package/clis/sinafinance/stock-rank.js +1 -1
  617. package/clis/sinafinance/stock.js +1 -1
  618. package/clis/slock/attachment-download.js +1 -1
  619. package/clis/slock/attachment-upload.js +7 -7
  620. package/clis/slock/attachment-url.js +1 -1
  621. package/clis/slock/auth-verify.js +1 -1
  622. package/clis/slock/bookmark-add.js +1 -1
  623. package/clis/slock/bookmark-remove.js +1 -1
  624. package/clis/slock/channel-action.js +1 -1
  625. package/clis/slock/channel-create.js +1 -1
  626. package/clis/slock/channel-files.js +1 -1
  627. package/clis/slock/channel-list.js +1 -1
  628. package/clis/slock/channel-mark.js +1 -1
  629. package/clis/slock/channel-members.js +1 -1
  630. package/clis/slock/channel-unarchive.js +1 -1
  631. package/clis/slock/dm-list.js +1 -1
  632. package/clis/slock/errors.js +1 -1
  633. package/clis/slock/in-page.js +28 -28
  634. package/clis/slock/inbox-done.js +5 -5
  635. package/clis/slock/inbox.js +1 -1
  636. package/clis/slock/message-read.js +22 -22
  637. package/clis/slock/message-search.js +10 -10
  638. package/clis/slock/message-send.js +25 -25
  639. package/clis/slock/reaction-add.js +1 -1
  640. package/clis/slock/reaction-remove.js +1 -1
  641. package/clis/slock/resolve.js +1 -1
  642. package/clis/slock/server-list.js +2 -2
  643. package/clis/slock/task-claim.js +4 -4
  644. package/clis/slock/task-convert.js +13 -13
  645. package/clis/slock/task-create.js +1 -1
  646. package/clis/slock/task-delete.js +5 -5
  647. package/clis/slock/task-get.js +5 -5
  648. package/clis/slock/task-list-server.js +4 -4
  649. package/clis/slock/task-list.js +5 -5
  650. package/clis/slock/task-status.js +3 -3
  651. package/clis/slock/task-unclaim.js +3 -3
  652. package/clis/slock/thread-follow.js +1 -1
  653. package/clis/slock/thread-state.js +1 -1
  654. package/clis/slock/unread-summary.js +5 -5
  655. package/clis/slock/whoami.js +1 -1
  656. package/clis/smzdm/search.js +3 -3
  657. package/clis/sohu/article.js +1 -1
  658. package/clis/sohu/attributes.js +1 -1
  659. package/clis/sohu/categories.js +1 -1
  660. package/clis/sohu/channels.js +1 -1
  661. package/clis/sohu/columns.js +1 -1
  662. package/clis/sohu/login.js +1 -1
  663. package/clis/sohu/stats.js +3 -3
  664. package/clis/sohu/topics.js +1 -1
  665. package/clis/sohu/whoami.js +1 -1
  666. package/clis/spotify/spotify.js +1 -1
  667. package/clis/stackoverflow/read.js +6 -6
  668. package/clis/stackoverflow/related.js +1 -1
  669. package/clis/stackoverflow/tag.js +1 -1
  670. package/clis/stackoverflow/user.js +1 -1
  671. package/clis/stackoverflow/utils.js +1 -1
  672. package/clis/steam/app.js +1 -1
  673. package/clis/steam/search.js +1 -1
  674. package/clis/steam/utils.js +1 -1
  675. package/clis/substack/auth.js +2 -2
  676. package/clis/substack/post-utils.js +2 -2
  677. package/clis/substack/publish.js +5 -5
  678. package/clis/suno/auth.js +2 -2
  679. package/clis/suno/download.js +5 -5
  680. package/clis/suno/generate.js +3 -3
  681. package/clis/suno/list.js +1 -1
  682. package/clis/suno/status.js +1 -1
  683. package/clis/suno/utils.js +29 -29
  684. package/clis/telegram/send.js +7 -7
  685. package/clis/telegram/shared.js +2 -2
  686. package/clis/telegram/whoami.js +1 -1
  687. package/clis/test-utils.js +1 -1
  688. package/clis/threads/post.js +23 -23
  689. package/clis/threads/shared.js +3 -3
  690. package/clis/threads/whoami.js +1 -1
  691. package/clis/tieba/hot.js +3 -3
  692. package/clis/tieba/posts.js +1 -1
  693. package/clis/tieba/read.js +2 -2
  694. package/clis/tieba/search.js +3 -3
  695. package/clis/tieba/utils.js +1 -1
  696. package/clis/tiktok/comment.js +2 -2
  697. package/clis/tiktok/creator-videos.js +3 -3
  698. package/clis/tiktok/explore.js +3 -3
  699. package/clis/tiktok/follow.js +8 -8
  700. package/clis/tiktok/following.js +4 -4
  701. package/clis/tiktok/friends.js +7 -7
  702. package/clis/tiktok/live.js +3 -3
  703. package/clis/tiktok/notifications.js +6 -6
  704. package/clis/tiktok/publish.js +17 -17
  705. package/clis/tiktok/unfollow.js +4 -4
  706. package/clis/tiktok/user.js +2 -2
  707. package/clis/tiktok/utils.js +1 -1
  708. package/clis/toutiao/article.js +1 -1
  709. package/clis/toutiao/articles.js +2 -2
  710. package/clis/toutiao/auth.js +2 -2
  711. package/clis/toutiao/hot.js +1 -1
  712. package/clis/toutiao/recommend.js +1 -1
  713. package/clis/toutiao/utils.js +2 -2
  714. package/clis/trae-solo/_actions.js +4 -4
  715. package/clis/trae-solo/_fs.js +5 -5
  716. package/clis/trae-solo/_state.js +2 -2
  717. package/clis/trae-solo/automation.js +4 -4
  718. package/clis/trae-solo/mode.js +4 -4
  719. package/clis/trae-solo/model.js +4 -4
  720. package/clis/trae-solo/renderer-storage.js +4 -4
  721. package/clis/trae-solo/settings.js +1 -1
  722. package/clis/trae-solo/skill-fs.js +1 -1
  723. package/clis/trae-solo/skill.js +12 -12
  724. package/clis/trae-solo/state-fs.js +2 -2
  725. package/clis/trae-solo/task-fs.js +5 -5
  726. package/clis/trae-solo/workspaces-fs.js +1 -1
  727. package/clis/tumblr/auth.js +2 -2
  728. package/clis/tumblr/publish.js +3 -3
  729. package/clis/tvmaze/search.js +1 -1
  730. package/clis/tvmaze/show.js +1 -1
  731. package/clis/tvmaze/utils.js +1 -1
  732. package/clis/twitter/accept.js +7 -7
  733. package/clis/twitter/article.js +7 -7
  734. package/clis/twitter/bookmark-folder.js +3 -3
  735. package/clis/twitter/bookmark-folders.js +3 -3
  736. package/clis/twitter/bookmarks.js +4 -4
  737. package/clis/twitter/delete.js +5 -5
  738. package/clis/twitter/device-follow.js +3 -3
  739. package/clis/twitter/dm-list.js +1 -1
  740. package/clis/twitter/dm-read.js +1 -1
  741. package/clis/twitter/dm-send.js +5 -5
  742. package/clis/twitter/dm-shared.js +3 -3
  743. package/clis/twitter/download.js +6 -6
  744. package/clis/twitter/followers.js +5 -5
  745. package/clis/twitter/following.js +2 -2
  746. package/clis/twitter/like.js +3 -3
  747. package/clis/twitter/likes.js +8 -8
  748. package/clis/twitter/list-add-core.js +9 -9
  749. package/clis/twitter/list-create.js +5 -5
  750. package/clis/twitter/list-remove-core.js +9 -9
  751. package/clis/twitter/list-tweets.js +7 -7
  752. package/clis/twitter/lists.js +6 -6
  753. package/clis/twitter/notifications.js +2 -2
  754. package/clis/twitter/post.js +24 -24
  755. package/clis/twitter/profile.js +7 -7
  756. package/clis/twitter/quote.js +7 -7
  757. package/clis/twitter/reply-dm.js +7 -7
  758. package/clis/twitter/reply.js +12 -12
  759. package/clis/twitter/retweet.js +3 -3
  760. package/clis/twitter/scheduled-delete.js +3 -3
  761. package/clis/twitter/scheduled-list.js +2 -2
  762. package/clis/twitter/scheduled-utils.js +3 -3
  763. package/clis/twitter/search.js +5 -5
  764. package/clis/twitter/shared.js +6 -6
  765. package/clis/twitter/thread.js +4 -4
  766. package/clis/twitter/timeline.js +3 -3
  767. package/clis/twitter/trending.js +2 -2
  768. package/clis/twitter/tweets.js +11 -11
  769. package/clis/twitter/unlike.js +3 -3
  770. package/clis/twitter/unretweet.js +3 -3
  771. package/clis/twitter/utils.js +6 -6
  772. package/clis/upwork/detail.js +2 -2
  773. package/clis/upwork/feed.js +2 -2
  774. package/clis/upwork/search.js +2 -2
  775. package/clis/upwork/utils.js +1 -1
  776. package/clis/v2ex/auth.js +2 -2
  777. package/clis/v2ex/daily.js +3 -3
  778. package/clis/v2ex/me.js +2 -2
  779. package/clis/v2ex/notifications.js +2 -2
  780. package/clis/vk/post.js +1 -1
  781. package/clis/vk/shared.js +2 -2
  782. package/clis/vk/whoami.js +1 -1
  783. package/clis/web/read.js +8 -8
  784. package/clis/wechat-channels/auth.js +2 -2
  785. package/clis/wechat-channels/publish.js +30 -30
  786. package/clis/weibo/article.js +1 -1
  787. package/clis/weibo/auth.js +3 -3
  788. package/clis/weibo/comments.js +1 -1
  789. package/clis/weibo/delete.js +2 -2
  790. package/clis/weibo/feed.js +3 -3
  791. package/clis/weibo/hot.js +1 -1
  792. package/clis/weibo/publish.js +10 -10
  793. package/clis/weibo/search.js +2 -2
  794. package/clis/weibo/user-posts.js +3 -3
  795. package/clis/weibo/user.js +2 -2
  796. package/clis/weibo/utils.js +3 -3
  797. package/clis/weixin/article.js +1 -1
  798. package/clis/weixin/create-draft.js +26 -26
  799. package/clis/weixin/download.js +2 -2
  800. package/clis/weixin/login.js +1 -1
  801. package/clis/weixin/search.js +2 -2
  802. package/clis/weixin/stats.js +3 -3
  803. package/clis/weixin/whoami.js +1 -1
  804. package/clis/weread/ai-outline.js +2 -2
  805. package/clis/weread/book-search.js +2 -2
  806. package/clis/weread/book.js +2 -2
  807. package/clis/weread/notebooks.js +1 -1
  808. package/clis/weread/search.js +1 -1
  809. package/clis/weread/shelf.js +1 -1
  810. package/clis/weread/utils.js +6 -6
  811. package/clis/weread-official/book.js +1 -1
  812. package/clis/weread-official/discover.js +1 -1
  813. package/clis/weread-official/list-apis.js +1 -1
  814. package/clis/weread-official/notes.js +1 -1
  815. package/clis/weread-official/readdata.js +1 -1
  816. package/clis/weread-official/review.js +1 -1
  817. package/clis/weread-official/search.js +1 -1
  818. package/clis/weread-official/shelf.js +1 -1
  819. package/clis/weread-official/utils.js +1 -1
  820. package/clis/wikidata/entity.js +1 -1
  821. package/clis/wikidata/search.js +1 -1
  822. package/clis/wikidata/utils.js +1 -1
  823. package/clis/wikipedia/page.js +1 -1
  824. package/clis/wikipedia/trending.js +1 -1
  825. package/clis/wikipedia/utils.js +1 -1
  826. package/clis/wordpress/login.js +1 -1
  827. package/clis/wordpress/publish.js +1 -1
  828. package/clis/wordpress/shared.js +3 -3
  829. package/clis/wordpress/whoami.js +1 -1
  830. package/clis/woshipm/article.js +1 -1
  831. package/clis/woshipm/login.js +1 -1
  832. package/clis/woshipm/stats.js +4 -4
  833. package/clis/woshipm/whoami.js +1 -1
  834. package/clis/wttr/current.js +1 -1
  835. package/clis/wttr/forecast.js +1 -1
  836. package/clis/wttr/utils.js +1 -1
  837. package/clis/xianyu/collect.js +1 -1
  838. package/clis/xianyu/inbox.js +1 -1
  839. package/clis/xianyu/item-stats.js +2 -2
  840. package/clis/xianyu/location.js +1 -1
  841. package/clis/xianyu/manage.js +1 -1
  842. package/clis/xianyu/messages.js +1 -1
  843. package/clis/xianyu/mtop.js +5 -5
  844. package/clis/xianyu/order.js +1 -1
  845. package/clis/xianyu/promote-stats.js +2 -2
  846. package/clis/xianyu/publish.js +17 -17
  847. package/clis/xianyu/rate.js +1 -1
  848. package/clis/xianyu/reply.js +1 -1
  849. package/clis/xianyu/search.js +8 -8
  850. package/clis/xianyu/seller-data.js +1 -1
  851. package/clis/xianyu/seller-list.js +1 -1
  852. package/clis/xianyu/user.js +1 -1
  853. package/clis/xiaoe/catalog.js +2 -2
  854. package/clis/xiaoe/content.js +2 -2
  855. package/clis/xiaoe/courses.js +2 -2
  856. package/clis/xiaohongshu/ask.js +6 -6
  857. package/clis/xiaohongshu/comments.js +6 -6
  858. package/clis/xiaohongshu/creator-note-detail.js +7 -7
  859. package/clis/xiaohongshu/creator-notes-summary.js +1 -1
  860. package/clis/xiaohongshu/creator-notes.js +13 -13
  861. package/clis/xiaohongshu/creator-profile.js +2 -2
  862. package/clis/xiaohongshu/creator-stats.js +2 -2
  863. package/clis/xiaohongshu/delete-note.js +7 -7
  864. package/clis/xiaohongshu/download.js +4 -4
  865. package/clis/xiaohongshu/feed.js +2 -2
  866. package/clis/xiaohongshu/follow.js +3 -3
  867. package/clis/xiaohongshu/human.js +3 -3
  868. package/clis/xiaohongshu/note-helpers.js +1 -1
  869. package/clis/xiaohongshu/note.js +2 -2
  870. package/clis/xiaohongshu/notifications.js +1 -1
  871. package/clis/xiaohongshu/publish-video.js +8 -8
  872. package/clis/xiaohongshu/publish.js +59 -59
  873. package/clis/xiaohongshu/search.js +8 -8
  874. package/clis/xiaohongshu/unfollow.js +4 -4
  875. package/clis/xiaohongshu/user-helpers.js +1 -1
  876. package/clis/xiaohongshu/user.js +2 -2
  877. package/clis/xiaoyuzhou/auth.js +3 -3
  878. package/clis/xiaoyuzhou/download.js +1 -1
  879. package/clis/xiaoyuzhou/utils.js +1 -1
  880. package/clis/xueqiu/article.js +4 -4
  881. package/clis/xueqiu/comments.js +4 -4
  882. package/clis/xueqiu/danjuan-utils.js +4 -4
  883. package/clis/xueqiu/earnings-date.js +1 -1
  884. package/clis/xueqiu/events.js +3 -3
  885. package/clis/xueqiu/hashtags.js +3 -3
  886. package/clis/xueqiu/stocks.js +3 -3
  887. package/clis/xueqiu/users.js +3 -3
  888. package/clis/xueqiu/utils.js +3 -3
  889. package/clis/yahoo-finance/quote.js +1 -1
  890. package/clis/yollomi/background.js +1 -1
  891. package/clis/yollomi/edit.js +1 -1
  892. package/clis/yollomi/face-swap.js +1 -1
  893. package/clis/yollomi/generate.js +1 -1
  894. package/clis/yollomi/object-remover.js +1 -1
  895. package/clis/yollomi/remove-bg.js +1 -1
  896. package/clis/yollomi/restore.js +1 -1
  897. package/clis/yollomi/try-on.js +1 -1
  898. package/clis/yollomi/upload.js +4 -4
  899. package/clis/yollomi/upscale.js +1 -1
  900. package/clis/yollomi/utils.js +4 -4
  901. package/clis/yollomi/video.js +1 -1
  902. package/clis/youtube/channel.js +4 -4
  903. package/clis/youtube/feed.js +2 -2
  904. package/clis/youtube/like.js +5 -5
  905. package/clis/youtube/playlist.js +7 -7
  906. package/clis/youtube/publish.js +11 -11
  907. package/clis/youtube/search.js +3 -3
  908. package/clis/youtube/subscribe.js +7 -7
  909. package/clis/youtube/subscriptions.js +1 -1
  910. package/clis/youtube/transcript-group.js +2 -2
  911. package/clis/youtube/transcript.js +13 -13
  912. package/clis/youtube/unlike.js +5 -5
  913. package/clis/youtube/unsubscribe.js +7 -7
  914. package/clis/youtube/utils.js +3 -3
  915. package/clis/youtube/video.js +4 -4
  916. package/clis/youtube/watch-later.js +2 -2
  917. package/clis/yuanbao/ask.js +18 -18
  918. package/clis/yuanbao/detail.js +1 -1
  919. package/clis/yuanbao/read.js +1 -1
  920. package/clis/yuanbao/shared.js +9 -9
  921. package/clis/yuanbao/status.js +1 -1
  922. package/clis/yuque/article.js +1 -1
  923. package/clis/yuque/whoami.js +1 -1
  924. package/clis/zhihu/answer-comments.js +2 -2
  925. package/clis/zhihu/answer-detail.js +3 -3
  926. package/clis/zhihu/answer.js +1 -1
  927. package/clis/zhihu/article-transform.js +1 -1
  928. package/clis/zhihu/article.js +1 -1
  929. package/clis/zhihu/auth.js +2 -2
  930. package/clis/zhihu/collection.js +3 -3
  931. package/clis/zhihu/collections.js +3 -3
  932. package/clis/zhihu/download.js +2 -2
  933. package/clis/zhihu/image-profile.js +6 -6
  934. package/clis/zhihu/paginate.js +3 -3
  935. package/clis/zhihu/pin.js +4 -4
  936. package/clis/zhihu/question.js +3 -3
  937. package/clis/zhihu/recommend.js +3 -3
  938. package/clis/zhihu/search.js +3 -3
  939. package/clis/zhihu/stats.js +3 -3
  940. package/clis/zhihu/user-arg.js +1 -1
  941. package/clis/zhihu/write-shared.js +7 -7
  942. package/clis/zlibrary/utils.js +6 -6
  943. package/clis/zsxq/auth.js +3 -3
  944. package/clis/zsxq/search.js +1 -1
  945. package/clis/zsxq/topic.js +1 -1
  946. package/clis/zsxq/utils.js +5 -5
  947. package/dist/src/adapter-source.js +1 -1
  948. package/dist/src/browser/analyze.js +1 -1
  949. package/dist/src/browser/article-extract.js +2 -2
  950. package/dist/src/browser/ax-snapshot.js +2 -2
  951. package/dist/src/browser/base-page.js +25 -25
  952. package/dist/src/browser/bridge.js +1 -1
  953. package/dist/src/browser/cdp.js +1 -1
  954. package/dist/src/browser/daemon-client.js +1 -1
  955. package/dist/src/browser/daemon-lifecycle.js +7 -7
  956. package/dist/src/browser/dom-helpers.js +35 -35
  957. package/dist/src/browser/dom-snapshot.js +19 -19
  958. package/dist/src/browser/errors.js +3 -3
  959. package/dist/src/browser/extract.js +5 -5
  960. package/dist/src/browser/find.js +13 -13
  961. package/dist/src/browser/fingerprint.js +2 -2
  962. package/dist/src/browser/html-tree.js +6 -6
  963. package/dist/src/browser/managed-chrome.js +1 -1
  964. package/dist/src/browser/network-cache.js +1 -1
  965. package/dist/src/browser/network-key.js +1 -1
  966. package/dist/src/browser/page.js +7 -7
  967. package/dist/src/browser/profile.js +2 -2
  968. package/dist/src/browser/proxy-test.js +8 -8
  969. package/dist/src/browser/shape-filter.js +1 -1
  970. package/dist/src/browser/shape.js +1 -1
  971. package/dist/src/browser/stealth.js +3 -3
  972. package/dist/src/browser/tabs.js +2 -2
  973. package/dist/src/browser/target-errors.js +1 -1
  974. package/dist/src/browser/target-resolver.js +23 -23
  975. package/dist/src/browser/trace.js +2 -2
  976. package/dist/src/browser/utils.js +1 -1
  977. package/dist/src/browser/verify-fixture.js +2 -2
  978. package/dist/src/browser-session-lock.js +1 -1
  979. package/dist/src/build-manifest.js +11 -11
  980. package/dist/src/capabilityRouting.js +1 -1
  981. package/dist/src/cli-argv-preprocess.js +1 -1
  982. package/dist/src/cli.js +32 -32
  983. package/dist/src/commanderAdapter.js +3 -3
  984. package/dist/src/commands/auth.js +3 -3
  985. package/dist/src/commands/daemon.js +1 -1
  986. package/dist/src/completion-fast.js +1 -1
  987. package/dist/src/completion.js +1 -1
  988. package/dist/src/constants.js +1 -1
  989. package/dist/src/convention-audit.js +2 -2
  990. package/dist/src/daemon-utils.js +1 -1
  991. package/dist/src/daemon.js +1 -1
  992. package/dist/src/discovery.js +2 -2
  993. package/dist/src/doctor.js +9 -9
  994. package/dist/src/download/article-download.js +15 -15
  995. package/dist/src/download/index.js +4 -4
  996. package/dist/src/download/media-download.js +1 -1
  997. package/dist/src/download/progress.js +3 -3
  998. package/dist/src/electron-apps.js +1 -1
  999. package/dist/src/errors.js +2 -2
  1000. package/dist/src/execution.js +2 -2
  1001. package/dist/src/external.js +1 -1
  1002. package/dist/src/help.js +8 -8
  1003. package/dist/src/hooks.js +1 -1
  1004. package/dist/src/interceptor.js +21 -21
  1005. package/dist/src/launcher.js +7 -7
  1006. package/dist/src/logger.js +8 -8
  1007. package/dist/src/main.js +7 -7
  1008. package/dist/src/observation/artifact.js +5 -5
  1009. package/dist/src/observation/retention.js +1 -1
  1010. package/dist/src/output.js +2 -2
  1011. package/dist/src/package-paths.js +1 -1
  1012. package/dist/src/pipeline/executor.js +1 -1
  1013. package/dist/src/pipeline/registry.js +1 -1
  1014. package/dist/src/pipeline/steps/browser.js +1 -1
  1015. package/dist/src/pipeline/steps/download.js +1 -1
  1016. package/dist/src/pipeline/steps/fetch.js +6 -6
  1017. package/dist/src/pipeline/steps/intercept.js +1 -1
  1018. package/dist/src/pipeline/steps/tap.js +17 -17
  1019. package/dist/src/pipeline/steps/transform.js +1 -1
  1020. package/dist/src/pipeline/template.js +1 -1
  1021. package/dist/src/plugin-manifest.js +1 -1
  1022. package/dist/src/plugin-scaffold.js +19 -19
  1023. package/dist/src/plugin.js +12 -12
  1024. package/dist/src/rate-limit.js +1 -1
  1025. package/dist/src/registry.js +1 -1
  1026. package/dist/src/runtime-detect.js +1 -1
  1027. package/dist/src/runtime.js +1 -1
  1028. package/dist/src/scripts/framework.js +1 -1
  1029. package/dist/src/scripts/interact.js +1 -1
  1030. package/dist/src/scripts/store.js +1 -1
  1031. package/dist/src/serialization.js +2 -2
  1032. package/dist/src/session-lease.js +1 -1
  1033. package/dist/src/snapshotFormatter.js +2 -2
  1034. package/dist/src/tui.js +12 -12
  1035. package/dist/src/user-runtime.js +1 -1
  1036. package/dist/src/utils.d.ts +12 -0
  1037. package/dist/src/utils.js +4 -4
  1038. package/dist/src/validate.js +2 -2
  1039. package/dist/src/verify.js +2 -2
  1040. package/dist/src/version.js +1 -1
  1041. package/package.json +1 -1
@@ -1,19 +1,19 @@
1
- import*as R from"node:fs";import*as J from"node:path";import{cli as h,Strategy as C}from"@jackwener/opencli/registry";import{AuthRequiredError as j,CommandExecutionError as q}from"@jackwener/opencli/errors";import{describeTwitterApiError as U,resolveTwitterOperationMetadata as w,unwrapBrowserResult as I}from"./shared.js";import{TWITTER_BEARER_TOKEN as L}from"./utils.js";import{assertLiteralContent as P}from"../_shared/content-guard.js";import{setInputFiles as b}from"../_shared/file-inject.js";const B=4,N=500,D=30000,f=250,m=1e4,v=500,y=15000,S="https://x.com/compose/post",M="https://x.com/home",A='input[type="file"][data-testid="fileInput"]',O=new Set([".jpg",".jpeg",".png",".gif",".webp"]),x={queryId:"5CdvsV_zjv4L64XFifAglw",features:{premium_content_api_read_enabled:!1,communities_web_enable_tweet_community_results_fetch:!0,c9s_tweet_anatomy_moderator_badge_enabled:!0,responsive_web_grok_analyze_button_fetch_trends_enabled:!1,responsive_web_grok_analyze_post_followups_enabled:!0,rweb_cashtags_composer_attachment_enabled:!0,responsive_web_jetfuel_frame:!0,responsive_web_grok_share_attachment_enabled:!0,responsive_web_grok_annotations_enabled:!0,responsive_web_edit_tweet_api_enabled:!0,rweb_conversational_replies_downvote_enabled:!1,graphql_is_translatable_rweb_tweet_is_translatable_enabled:!0,view_counts_everywhere_api_enabled:!0,longform_notetweets_consumption_enabled:!0,responsive_web_twitter_article_tweet_consumption_enabled:!0,content_disclosure_indicator_enabled:!0,content_disclosure_ai_generated_indicator_enabled:!0,responsive_web_grok_show_grok_translated_post:!0,responsive_web_grok_analysis_button_from_backend:!0,post_ctas_fetch_enabled:!0,longform_notetweets_rich_text_read_enabled:!0,longform_notetweets_inline_media_enabled:!1,profile_label_improvements_pcf_label_in_post_enabled:!0,responsive_web_profile_redirect_enabled:!1,rweb_tipjar_consumption_enabled:!1,verified_phone_label_enabled:!1,articles_preview_enabled:!0,rweb_cashtags_enabled:!0,responsive_web_grok_community_note_auto_translation_is_enabled:!0,responsive_web_graphql_skip_user_profile_image_extensions_enabled:!1,freedom_of_speech_not_reach_fetch_enabled:!0,standardized_nudges_misinfo:!0,tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled:!0,responsive_web_grok_image_annotation_enabled:!0,responsive_web_grok_imagine_annotation_enabled:!0,responsive_web_graphql_timeline_navigation_enabled:!0},fieldToggles:{}};function c(z){const Q=z.split(",").map((H)=>H.trim()).filter(Boolean);if(Q.length>B)throw new q(`Too many images: ${Q.length} (max ${B})`);return Q.map((H)=>{const Y=J.resolve(H),$=J.extname(Y).toLowerCase();if(!O.has($))throw new q(`Unsupported image format "${$}". Supported: jpg, png, gif, webp`);const Z=R.statSync(Y,{throwIfNoEntry:!1});if(!Z||!Z.isFile())throw new q(`Not a valid file: ${Y}`);return Y})}function T(z){const H=(z instanceof Error?z.message:String(z)).toLowerCase();return H.includes("unknown action")||H.includes("not supported")||H.includes("inserttext returned no inserted flag")}async function _(z){return z.evaluate(`(() => {
1
+ import*as S from"node:fs";import*as b from"node:path";import{cli as v,Strategy as k}from"@jackwener/opencli/registry";import{AuthRequiredError as w,CommandExecutionError as c}from"@jackwener/opencli/errors";import{describeTwitterApiError as C,resolveTwitterOperationMetadata as A,unwrapBrowserResult as O}from"./shared.js";import{TWITTER_BEARER_TOKEN as E}from"./utils.js";import{assertLiteralContent as I}from"../_shared/content-guard.js";import{setInputFiles as P}from"../_shared/file-inject.js";const p=4,g=500,_=30000,h=250,q=1e4,f=500,y=15000,N="https://x.com/compose/post",M="https://x.com/home",x='input[type="file"][data-testid="fileInput"]',R=new Set([".jpg",".jpeg",".png",".gif",".webp"]),U={queryId:"5CdvsV_zjv4L64XFifAglw",features:{premium_content_api_read_enabled:!1,communities_web_enable_tweet_community_results_fetch:!0,c9s_tweet_anatomy_moderator_badge_enabled:!0,responsive_web_grok_analyze_button_fetch_trends_enabled:!1,responsive_web_grok_analyze_post_followups_enabled:!0,rweb_cashtags_composer_attachment_enabled:!0,responsive_web_jetfuel_frame:!0,responsive_web_grok_share_attachment_enabled:!0,responsive_web_grok_annotations_enabled:!0,responsive_web_edit_tweet_api_enabled:!0,rweb_conversational_replies_downvote_enabled:!1,graphql_is_translatable_rweb_tweet_is_translatable_enabled:!0,view_counts_everywhere_api_enabled:!0,longform_notetweets_consumption_enabled:!0,responsive_web_twitter_article_tweet_consumption_enabled:!0,content_disclosure_indicator_enabled:!0,content_disclosure_ai_generated_indicator_enabled:!0,responsive_web_grok_show_grok_translated_post:!0,responsive_web_grok_analysis_button_from_backend:!0,post_ctas_fetch_enabled:!0,longform_notetweets_rich_text_read_enabled:!0,longform_notetweets_inline_media_enabled:!1,profile_label_improvements_pcf_label_in_post_enabled:!0,responsive_web_profile_redirect_enabled:!1,rweb_tipjar_consumption_enabled:!1,verified_phone_label_enabled:!1,articles_preview_enabled:!0,rweb_cashtags_enabled:!0,responsive_web_grok_community_note_auto_translation_is_enabled:!0,responsive_web_graphql_skip_user_profile_image_extensions_enabled:!1,freedom_of_speech_not_reach_fetch_enabled:!0,standardized_nudges_misinfo:!0,tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled:!0,responsive_web_grok_image_annotation_enabled:!0,responsive_web_grok_imagine_annotation_enabled:!0,responsive_web_graphql_timeline_navigation_enabled:!0},fieldToggles:{}};function J(e){const o=e.split(",").map((t)=>t.trim()).filter(Boolean);if(o.length>p)throw new c(`Too many images: ${o.length} (max ${p})`);return o.map((t)=>{const s=b.resolve(t),n=b.extname(s).toLowerCase();if(!R.has(n))throw new c(`Unsupported image format "${n}". Supported: jpg, png, gif, webp`);const r=S.statSync(s,{throwIfNoEntry:!1});if(!r||!r.isFile())throw new c(`Not a valid file: ${s}`);return s})}function L(e){const t=(e instanceof Error?e.message:String(e)).toLowerCase();return t.includes("unknown action")||t.includes("not supported")||t.includes("inserttext returned no inserted flag")}async function z(e){return e.evaluate(`(() => {
2
2
  const visible = (el) => !!el && (el.offsetParent !== null || el.getClientRects().length > 0);
3
3
  const boxes = Array.from(document.querySelectorAll('[data-testid="tweetTextarea_0"]'));
4
4
  const box = boxes.find(visible) || boxes[0];
5
5
  if (!box) return { ok: false, message: 'Could not find the tweet composer text area. Are you logged in?' };
6
6
  box.focus();
7
7
  return { ok: true };
8
- })()`)}async function d(z,Q){const H=Math.ceil(m/f);return z.evaluate(`(async () => {
9
- const expected = ${JSON.stringify(Q)};
8
+ })()`)}async function B(e,o){const t=Math.ceil(q/h);return e.evaluate(`(async () => {
9
+ const expected = ${JSON.stringify(o)};
10
10
  const normalize = s => String(s || '').replace(/ /g, ' ').replace(/s+/g, ' ').trim();
11
11
  const normalizedExpected = normalize(expected);
12
- for (let i = 0; i < ${JSON.stringify(H)}; i++) {
12
+ for (let i = 0; i < ${JSON.stringify(t)}; i++) {
13
13
  const box = document.querySelector('[data-testid="tweetTextarea_0"]');
14
14
  const actual = box ? (box.innerText || box.textContent || '') : '';
15
15
  if (box && normalize(actual).includes(normalizedExpected)) return { ok: true };
16
- await new Promise(r => setTimeout(r, ${JSON.stringify(f)}));
16
+ await new Promise(r => setTimeout(r, ${JSON.stringify(h)}));
17
17
  }
18
18
  const box = document.querySelector('[data-testid="tweetTextarea_0"]');
19
19
  return {
@@ -21,13 +21,13 @@ import*as R from"node:fs";import*as J from"node:path";import{cli as h,Strategy a
21
21
  message: 'Could not verify tweet text in the composer after typing.',
22
22
  actualText: box ? (box.innerText || box.textContent || '') : ''
23
23
  };
24
- })()`)}async function l(z,Q){const H=await _(z);if(!H?.ok)return H;const Y=[z.nativeType?.bind(z),z.insertText?.bind(z)].filter(Boolean);for(const $ of Y)try{await $(Q);const Z=await d(z,Q);if(Z?.ok)return Z}catch(Z){if(!T(Z))throw Z}return z.evaluate(`(async () => {
24
+ })()`)}async function j(e,o){const t=await z(e);if(!t?.ok)return t;const s=[e.nativeType?.bind(e),e.insertText?.bind(e)].filter(Boolean);for(const n of s)try{await n(o);const r=await B(e,o);if(r?.ok)return r}catch(r){if(!L(r))throw r}return e.evaluate(`(async () => {
25
25
  try {
26
26
  const visible = (el) => !!el && (el.offsetParent !== null || el.getClientRects().length > 0);
27
27
  const boxes = Array.from(document.querySelectorAll('[data-testid="tweetTextarea_0"]'));
28
28
  const box = boxes.find(visible) || boxes[0];
29
29
  if (!box) return { ok: false, message: 'Could not find the tweet composer text area. Are you logged in?' };
30
- const textToInsert = ${JSON.stringify(Q)};
30
+ const textToInsert = ${JSON.stringify(o)};
31
31
  const normalize = s => String(s || '').replace(/ /g, ' ').replace(/s+/g, ' ').trim();
32
32
  box.focus();
33
33
  if (!document.execCommand('insertText', false, textToInsert)) {
@@ -40,11 +40,11 @@ import*as R from"node:fs";import*as J from"node:path";import{cli as h,Strategy a
40
40
  if (normalize(actual).includes(normalize(textToInsert))) return { ok: true };
41
41
  return { ok: false, message: 'Could not verify tweet text in the composer after typing.', actualText: actual };
42
42
  } catch (e) { return { ok: false, message: String(e) }; }
43
- })()`)}async function n(z,Q){const H=Math.ceil(D/N);return z.evaluate(`(async () => {
44
- const expected = ${JSON.stringify(Q)};
43
+ })()`)}async function D(e,o){const t=Math.ceil(_/g);return e.evaluate(`(async () => {
44
+ const expected = ${JSON.stringify(o)};
45
45
  const visible = (el) => !!el && (el.offsetParent !== null || el.getClientRects().length > 0);
46
- for (let i = 0; i < ${JSON.stringify(H)}; i++) {
47
- await new Promise(r => setTimeout(r, ${JSON.stringify(N)}));
46
+ for (let i = 0; i < ${JSON.stringify(t)}; i++) {
47
+ await new Promise(r => setTimeout(r, ${JSON.stringify(g)}));
48
48
  const attachments = document.querySelector('[data-testid="attachments"]');
49
49
  const previewCount = Math.max(
50
50
  attachments ? attachments.querySelectorAll('[role="group"], img, video').length : 0,
@@ -58,8 +58,8 @@ import*as R from"node:fs";import*as J from"node:path";import{cli as h,Strategy a
58
58
  const buttonReady = !!button && !button.disabled && button.getAttribute('aria-disabled') !== 'true';
59
59
  if (previewCount >= expected && buttonReady) return { ok: true, previewCount };
60
60
  }
61
- return { ok: false, message: 'Image upload timed out (${D/1000}s).' };
62
- })()`)}async function E(z,Q){const H=Math.ceil(y/v),Y=await z.evaluate(`(async () => {
61
+ return { ok: false, message: 'Image upload timed out (${_/1000}s).' };
62
+ })()`)}async function F(e,o){const t=Math.ceil(y/f),s=await e.evaluate(`(async () => {
63
63
  try {
64
64
  const visible = (el) => !!el && (el.offsetParent !== null || el.getClientRects().length > 0);
65
65
  // For text-only posts the Tweet button only becomes enabled once
@@ -68,18 +68,18 @@ import*as R from"node:fs";import*as J from"node:path";import{cli as h,Strategy a
68
68
  // slow renders with "Tweet button is disabled or not found." Poll for
69
69
  // a visible, enabled button before clicking.
70
70
  let btn;
71
- for (let i = 0; i < ${JSON.stringify(H)}; i++) {
71
+ for (let i = 0; i < ${JSON.stringify(t)}; i++) {
72
72
  const buttons = Array.from(document.querySelectorAll('[data-testid="tweetButtonInline"], [data-testid="tweetButton"]'));
73
73
  btn = buttons.find((el) => visible(el) && !el.disabled && el.getAttribute('aria-disabled') !== 'true');
74
74
  if (btn) break;
75
- await new Promise(r => setTimeout(r, ${JSON.stringify(v)}));
75
+ await new Promise(r => setTimeout(r, ${JSON.stringify(f)}));
76
76
  }
77
77
  if (!btn) return { ok: false, message: 'Tweet button is disabled or not found.' };
78
78
  btn.click();
79
79
  return { ok: true };
80
80
  } catch (e) { return { ok: false, message: String(e) }; }
81
- })()`);if(!Y?.ok)return Y;const $=Math.ceil(y/v);return z.evaluate(`(async () => {
82
- const expected = ${JSON.stringify(Q)};
81
+ })()`);if(!s?.ok)return s;const n=Math.ceil(y/f);return e.evaluate(`(async () => {
82
+ const expected = ${JSON.stringify(o)};
83
83
  const normalize = s => String(s || '').replace(/ /g, ' ').replace(/s+/g, ' ').trim();
84
84
  const expectedText = normalize(expected);
85
85
  const visible = (el) => !!el && (el.offsetParent !== null || el.getClientRects().length > 0);
@@ -96,8 +96,8 @@ import*as R from"node:fs";import*as J from"node:path";import{cli as h,Strategy a
96
96
  }
97
97
  return {};
98
98
  };
99
- for (let i = 0; i < ${JSON.stringify($)}; i++) {
100
- await new Promise(r => setTimeout(r, ${JSON.stringify(v)}));
99
+ for (let i = 0; i < ${JSON.stringify(n)}; i++) {
100
+ await new Promise(r => setTimeout(r, ${JSON.stringify(f)}));
101
101
  const toasts = Array.from(document.querySelectorAll('[role="alert"], [data-testid="toast"]'))
102
102
  .filter((el) => visible(el));
103
103
  const successToast = toasts.find((el) => /sent|posted|your post was sent|your tweet was sent/i.test(el.textContent || ''));
@@ -117,15 +117,15 @@ import*as R from"node:fs";import*as J from"node:path";import{cli as h,Strategy a
117
117
  }
118
118
  }
119
119
  return { ok: false, message: 'Tweet submission did not complete before timeout.' };
120
- })()`)}function k(z){const Q=Array.isArray(z?.errors)?z.errors:[];if(Q.length===0)return"";return Q.map((H)=>H?.message||JSON.stringify(H)).filter(Boolean).join("; ").slice(0,300)}function g(z){const Q=z?.data?.create_tweet?.tweet_results?.result,H=Q?.tweet||Q;if(!H||typeof H!=="object")return null;const Y=String(H.rest_id||H.legacy?.id_str||"").trim();if(!/^\d+$/.test(Y))return null;const $=H.core?.user_results?.result,Z=String($?.core?.screen_name||$?.legacy?.screen_name||"").trim();return{id:Y,url:Z?`https://x.com/${Z}/status/${Y}`:`https://x.com/i/status/${Y}`}}async function u(z,Q){await z.goto(M,{waitUntil:"load",settleMs:1000});const Y=(await z.getCookies({url:"https://x.com"})).find((G)=>G.name==="ct0")?.value||null;if(!Y)throw new j("x.com","Not logged into x.com (no ct0 cookie)");const $=await w(z,"CreateTweet",x),Z={variables:{tweet_text:Q,dark_request:!1,media:{media_entities:[],possibly_sensitive:!1},semantic_annotation_ids:[]},features:$.features,queryId:$.queryId};if($.fieldToggles&&Object.keys($.fieldToggles).length>0)Z.fieldToggles=$.fieldToggles;const F=JSON.stringify({Authorization:`Bearer ${decodeURIComponent(L)}`,"X-Csrf-Token":Y,"X-Twitter-Auth-Type":"OAuth2Session","X-Twitter-Active-User":"yes","Content-Type":"application/json"}),V=`/i/api/graphql/${$.queryId}/CreateTweet`,K=JSON.stringify(Z),W=I(await z.evaluate(`async () => {
121
- const r = await fetch(${JSON.stringify(V)}, {
120
+ })()`)}function T(e){const o=Array.isArray(e?.errors)?e.errors:[];if(o.length===0)return"";return o.map((t)=>t?.message||JSON.stringify(t)).filter(Boolean).join("; ").slice(0,300)}function X(e){const o=e?.data?.create_tweet?.tweet_results?.result,t=o?.tweet||o;if(!t||typeof t!=="object")return null;const s=String(t.rest_id||t.legacy?.id_str||"").trim();if(!/^\d+$/.test(s))return null;const n=t.core?.user_results?.result,r=String(n?.core?.screen_name||n?.legacy?.screen_name||"").trim();return{id:s,url:r?`https://x.com/${r}/status/${s}`:`https://x.com/i/status/${s}`}}async function H(e,o){await e.goto(M,{waitUntil:"load",settleMs:1000});const s=(await e.getCookies({url:"https://x.com"})).find((d)=>d.name==="ct0")?.value||null;if(!s)throw new w("x.com","Not logged into x.com (no ct0 cookie)");const n=await A(e,"CreateTweet",U),r={variables:{tweet_text:o,dark_request:!1,media:{media_entities:[],possibly_sensitive:!1},semantic_annotation_ids:[]},features:n.features,queryId:n.queryId};if(n.fieldToggles&&Object.keys(n.fieldToggles).length>0)r.fieldToggles=n.fieldToggles;const u=JSON.stringify({Authorization:`Bearer ${decodeURIComponent(E)}`,"X-Csrf-Token":s,"X-Twitter-Auth-Type":"OAuth2Session","X-Twitter-Active-User":"yes","Content-Type":"application/json"}),i=`/i/api/graphql/${n.queryId}/CreateTweet`,a=JSON.stringify(r),l=O(await e.evaluate(`async () => {
121
+ const r = await fetch(${JSON.stringify(i)}, {
122
122
  method: 'POST',
123
- headers: ${F},
123
+ headers: ${u},
124
124
  credentials: 'include',
125
- body: ${JSON.stringify(K)},
125
+ body: ${JSON.stringify(a)},
126
126
  });
127
127
  const bodyText = await r.text();
128
128
  let bodyJson = null;
129
129
  try { bodyJson = JSON.parse(bodyText); } catch {}
130
130
  return { ok: r.ok, httpStatus: r.status, bodyJson, bodyText };
131
- }`));if(W?.httpStatus===401||W?.httpStatus===403)throw new j("x.com",`Twitter CreateTweet returned HTTP ${W.httpStatus}`);if(!W?.ok){const G=k(W?.bodyJson);return{ok:!1,message:U("CreateTweet",W?.httpStatus??0,G||void 0)}}const X=g(W.bodyJson);if(!X){const G=k(W.bodyJson);return{ok:!1,message:G?`CreateTweet failed: ${G}`:"CreateTweet returned no created tweet id."}}return{ok:!0,message:"Tweet posted successfully.",...X}}h({site:"twitter",name:"post",access:"write",description:"Post a new tweet/thread",domain:"x.com",strategy:C.UI,browser:!0,args:[{name:"text",fromFile:!0,type:"string",required:!0,positional:!0,help:"The text content of the tweet"},{name:"images",type:"string",required:!1,help:"Image paths, comma-separated, max 4 (jpg/png/gif/webp)"}],columns:["status","message","text","id","url"],func:async(z,Q)=>{if(!z)throw new q("Browser session required for twitter post");const H=Q.images?c(String(Q.images)):[],Y=String(Q.text??"");P(Y,{label:"推文内容"});try{await z.goto(S,{waitUntil:"load",settleMs:2500});await z.wait({selector:'[data-testid="tweetTextarea_0"]',timeout:15})}catch(V){if(H.length>0)throw V;const K=await u(z,Y);if(!K?.ok)throw new q(K?.message??"Tweet failed to post.");return[{status:"success",message:K?.message??"Tweet posted.",text:Y,...K?.id?{id:K.id}:{},...K?.url?{url:K.url}:{}}]}if(H.length>0){await z.wait({selector:A,timeout:20});await b(z,A,H);const V=await n(z,H.length);if(!V?.ok)throw new q(V?.message??`Image upload timed out (${D/1000}s).`)}const $=await l(z,Y);if(!$?.ok)throw new q($?.message??"Could not type tweet text.");await z.wait(1);let Z=null,F=null;try{Z=await E(z,Y)}catch(V){F=V}if(!Z?.ok){const{confirmTweetByReadback:V}=await import("./tweets.js"),K=await V(z,Y);if(K.found)return[{status:"success",message:"提交回执未确认(可能超时),但发后回查已在时间线确认发布成功,请勿重发。",text:Y,...K.id?{id:K.id}:{},...K.url?{url:K.url}:{},confirmed_by:"readback"}];const W=F?String(F&&F.message||F):Z?.message??"Tweet was not confirmed sent.",X=K.error?`发后回查失败(${K.error})——无法确认,重试前请先人工核对时间线`:`发后回查已检查最近 ${K.checked} 条推文,未发现该内容,可安全重试`;throw new q(`${W};${X}`)}return[{status:"success",message:Z?.message??"Tweet posted.",text:Y,...Z?.id?{id:Z.id}:{},...Z?.url?{url:Z.url}:{}}]}});
131
+ }`));if(l?.httpStatus===401||l?.httpStatus===403)throw new w("x.com",`Twitter CreateTweet returned HTTP ${l.httpStatus}`);if(!l?.ok){const d=T(l?.bodyJson);return{ok:!1,message:C("CreateTweet",l?.httpStatus??0,d||void 0)}}const m=X(l.bodyJson);if(!m){const d=T(l.bodyJson);return{ok:!1,message:d?`CreateTweet failed: ${d}`:"CreateTweet returned no created tweet id."}}return{ok:!0,message:"Tweet posted successfully.",...m}}v({site:"twitter",name:"post",access:"write",description:"Post a new tweet/thread",domain:"x.com",strategy:k.UI,browser:!0,args:[{name:"text",fromFile:!0,type:"string",required:!0,positional:!0,help:"The text content of the tweet"},{name:"images",type:"string",required:!1,help:"Image paths, comma-separated, max 4 (jpg/png/gif/webp)"}],columns:["status","message","text","id","url"],func:async(e,o)=>{if(!e)throw new c("Browser session required for twitter post");const t=o.images?J(String(o.images)):[],s=String(o.text??"");I(s,{label:"推文内容"});try{await e.goto(N,{waitUntil:"load",settleMs:2500});await e.wait({selector:'[data-testid="tweetTextarea_0"]',timeout:15})}catch(i){if(t.length>0)throw i;const a=await H(e,s);if(!a?.ok)throw new c(a?.message??"Tweet failed to post.");return[{status:"success",message:a?.message??"Tweet posted.",text:s,...a?.id?{id:a.id}:{},...a?.url?{url:a.url}:{}}]}if(t.length>0){await e.wait({selector:x,timeout:20});await P(e,x,t);const i=await D(e,t.length);if(!i?.ok)throw new c(i?.message??`Image upload timed out (${_/1000}s).`)}const n=await j(e,s);if(!n?.ok)throw new c(n?.message??"Could not type tweet text.");await e.wait(1);let r=null,u=null;try{r=await F(e,s)}catch(i){u=i}if(!r?.ok){const{confirmTweetByReadback:i}=await import("./tweets.js"),a=await i(e,s);if(a.found)return[{status:"success",message:"提交回执未确认(可能超时),但发后回查已在时间线确认发布成功,请勿重发。",text:s,...a.id?{id:a.id}:{},...a.url?{url:a.url}:{},confirmed_by:"readback"}];const l=u?String(u&&u.message||u):r?.message??"Tweet was not confirmed sent.",m=a.error?`发后回查失败(${a.error})——无法确认,重试前请先人工核对时间线`:`发后回查已检查最近 ${a.checked} 条推文,未发现该内容,可安全重试`;throw new c(`${l};${m}`)}return[{status:"success",message:r?.message??"Tweet posted.",text:s,...r?.id?{id:r.id}:{},...r?.url?{url:r.url}:{}}]}});
@@ -1,12 +1,12 @@
1
- import{ArgumentError as k,AuthRequiredError as z,CommandExecutionError as M,EmptyResultError as B}from"@jackwener/opencli/errors";import{cli as I,Strategy as q}from"@jackwener/opencli/registry";import{describeTwitterApiError as U,normalizeTwitterScreenName as Q,resolveTwitterQueryId as b,unwrapBrowserResult as Y}from"./shared.js";import{TWITTER_BEARER_TOKEN as x}from"./utils.js";const S="IGgvgiOx4QZndDHuD3x9TQ";function W(G){return G!=null&&typeof G==="object"&&!Array.isArray(G)}function H(G){return typeof G==="string"?G:""}export function mapTwitterProfileResult(G,J){if(!W(G))throw new M(`Twitter profile response for @${J} is malformed`);const K=W(G.legacy),Z=W(G.core);if(!K&&!Z)throw new M(`Twitter profile response for @${J} is missing profile fields`);const V=K?G.legacy:{},$=Z?G.core:{};if(!H($.screen_name)&&!H(V.screen_name)&&!H($.name)&&!H(V.name)&&!H($.created_at)&&!H(V.created_at))throw new M(`Twitter profile response for @${J} is missing profile identity fields`);const L=W(G.location)?G.location:{},X=V.entities?.url?.urls?.[0]?.expanded_url||"";return[{screen_name:H($.screen_name)||H(V.screen_name)||J,name:H($.name)||H(V.name),bio:H(V.description),location:H(L.location)||H(V.location),url:H(X),followers:V.followers_count||0,following:V.friends_count||0,tweets:V.statuses_count||0,likes:V.favourites_count||0,verified:Boolean(G.is_blue_verified||V.verified),created_at:H($.created_at)||H(V.created_at)}]}I({site:"twitter",name:"profile",access:"read",description:"Fetch a Twitter user profile — bio, stats, etc. (defaults to the logged-in user when no username is given)",domain:"x.com",strategy:q.COOKIE,browser:!0,args:[{name:"username",type:"string",positional:!0,help:"Twitter screen name (with or without @). Defaults to the logged-in user when omitted."}],columns:["screen_name","name","bio","location","url","followers","following","tweets","likes","verified","created_at"],func:async(G,J)=>{const K=String(J.username??"").trim();let Z=Q(K);if(K&&!Z)throw new k("twitter profile username must be a valid Twitter/X handle","Example: ppcli twitter profile @jack");if(!Z){await G.goto("https://x.com/home");await G.wait({selector:'[data-testid="primaryColumn"]'});const D=Y(await G.evaluate(`() => {
1
+ import{ArgumentError as m,AuthRequiredError as f,CommandExecutionError as c,EmptyResultError as w}from"@jackwener/opencli/errors";import{cli as h,Strategy as g}from"@jackwener/opencli/registry";import{describeTwitterApiError as b,normalizeTwitterScreenName as _,resolveTwitterQueryId as y,unwrapBrowserResult as p}from"./shared.js";import{TWITTER_BEARER_TOKEN as v}from"./utils.js";const T="IGgvgiOx4QZndDHuD3x9TQ";function u(e){return e!=null&&typeof e==="object"&&!Array.isArray(e)}function t(e){return typeof e==="string"?e:""}export function mapTwitterProfileResult(e,a){if(!u(e))throw new c(`Twitter profile response for @${a} is malformed`);const l=u(e.legacy),o=u(e.core);if(!l&&!o)throw new c(`Twitter profile response for @${a} is missing profile fields`);const r=l?e.legacy:{},n=o?e.core:{};if(!t(n.screen_name)&&!t(r.screen_name)&&!t(n.name)&&!t(r.name)&&!t(n.created_at)&&!t(r.created_at))throw new c(`Twitter profile response for @${a} is missing profile identity fields`);const d=u(e.location)?e.location:{},i=r.entities?.url?.urls?.[0]?.expanded_url||"";return[{screen_name:t(n.screen_name)||t(r.screen_name)||a,name:t(n.name)||t(r.name),bio:t(r.description),location:t(d.location)||t(r.location),url:t(i),followers:r.followers_count||0,following:r.friends_count||0,tweets:r.statuses_count||0,likes:r.favourites_count||0,verified:Boolean(e.is_blue_verified||r.verified),created_at:t(n.created_at)||t(r.created_at)}]}h({site:"twitter",name:"profile",access:"read",description:"Fetch a Twitter user profile — bio, stats, etc. (defaults to the logged-in user when no username is given)",domain:"x.com",strategy:g.COOKIE,browser:!0,args:[{name:"username",type:"string",positional:!0,help:"Twitter screen name (with or without @). Defaults to the logged-in user when omitted."}],columns:["screen_name","name","bio","location","url","followers","following","tweets","likes","verified","created_at"],func:async(e,a)=>{const l=String(a.username??"").trim();let o=_(l);if(l&&!o)throw new m("twitter profile username must be a valid Twitter/X handle","Example: ppcli twitter profile @jack");if(!o){await e.goto("https://x.com/home");await e.wait({selector:'[data-testid="primaryColumn"]'});const s=p(await e.evaluate(`() => {
2
2
  const link = document.querySelector('a[data-testid="AppTabBar_Profile_Link"]');
3
3
  return link ? link.getAttribute('href') : null;
4
- }`));if(!D||typeof D!=="string")throw new z("x.com","Could not detect logged-in user. Are you logged in?");Z=Q(D);if(!Z)throw new z("x.com","Could not detect logged-in user. Are you logged in?")}await G.goto(`https://x.com/${Z}`);await G.wait(3);const $=(await G.getCookies({url:"https://x.com"})).find((D)=>D.name==="ct0")?.value||null;if(!$)throw new z("x.com","Not logged into x.com (no ct0 cookie)");const L=await b(G,"UserByScreenName",S),X=Y(await G.evaluate(`
4
+ }`));if(!s||typeof s!=="string")throw new f("x.com","Could not detect logged-in user. Are you logged in?");o=_(s);if(!o)throw new f("x.com","Could not detect logged-in user. Are you logged in?")}await e.goto(`https://x.com/${o}`);await e.wait(3);const n=(await e.getCookies({url:"https://x.com"})).find((s)=>s.name==="ct0")?.value||null;if(!n)throw new f("x.com","Not logged into x.com (no ct0 cookie)");const d=await y(e,"UserByScreenName",T),i=p(await e.evaluate(`
5
5
  async () => {
6
- const screenName = ${JSON.stringify(Z)};
7
- const ct0 = ${JSON.stringify($)};
6
+ const screenName = ${JSON.stringify(o)};
7
+ const ct0 = ${JSON.stringify(n)};
8
8
 
9
- const bearer = ${JSON.stringify(x)};
9
+ const bearer = ${JSON.stringify(v)};
10
10
  const headers = {
11
11
  'Authorization': 'Bearer ' + decodeURIComponent(bearer),
12
12
  'X-Csrf-Token': ct0,
@@ -33,7 +33,7 @@ import{ArgumentError as k,AuthRequiredError as z,CommandExecutionError as M,Empt
33
33
  responsive_web_graphql_timeline_navigation_enabled: true,
34
34
  });
35
35
 
36
- const url = '/i/api/graphql/' + ${JSON.stringify(L)} + '/UserByScreenName?variables='
36
+ const url = '/i/api/graphql/' + ${JSON.stringify(d)} + '/UserByScreenName?variables='
37
37
  + encodeURIComponent(variables)
38
38
  + '&features=' + encodeURIComponent(features);
39
39
 
@@ -63,4 +63,4 @@ import{ArgumentError as k,AuthRequiredError as z,CommandExecutionError as M,Empt
63
63
  if (!result) return {ok: false, notFound: true, error: 'User @' + screenName + ' not found'};
64
64
  return {ok: true, result};
65
65
  }
66
- `));if(!W(X))throw new M("Twitter profile response payload is malformed");if(!X.ok){const D=typeof X.httpStatus==="number"?U("UserByScreenName",X.httpStatus,X.hint):X.error+(X.hint?` (${X.hint})`:"");if(X.auth)throw new z("x.com",D);if(X.notFound)throw new B("twitter profile",D);throw new M(D)}return mapTwitterProfileResult(X.result,Z)}});export const __test__={mapTwitterProfileResult};
66
+ `));if(!u(i))throw new c("Twitter profile response payload is malformed");if(!i.ok){const s=typeof i.httpStatus==="number"?b("UserByScreenName",i.httpStatus,i.hint):i.error+(i.hint?` (${i.hint})`:"");if(i.auth)throw new f("x.com",s);if(i.notFound)throw new w("twitter profile",s);throw new c(s)}return mapTwitterProfileResult(i.result,o)}});export const __test__={mapTwitterProfileResult};
@@ -1,6 +1,6 @@
1
- import*as Z from"node:fs";import{CommandExecutionError as J}from"@jackwener/opencli/errors";import{cli as $,Strategy as f}from"@jackwener/opencli/registry";import{parseTweetUrl as K,buildTwitterArticleScopeSource as V}from"./shared.js";import{COMPOSER_FILE_INPUT_SELECTOR as W,attachComposerImage as X,downloadRemoteImage as y,resolveImagePath as A}from"./utils.js";function N(q){const j=K(q);return`https://x.com/compose/post?url=${encodeURIComponent(j.url)}`}async function D(q,j){await q.goto(j.url,{waitUntil:"load",settleMs:2500});await q.wait({selector:'[data-testid="primaryColumn"]',timeout:15});const v=await q.evaluate(`(async () => {
1
+ import*as f from"node:fs";import{CommandExecutionError as n}from"@jackwener/opencli/errors";import{cli as w,Strategy as p}from"@jackwener/opencli/registry";import{parseTweetUrl as l,buildTwitterArticleScopeSource as u}from"./shared.js";import{COMPOSER_FILE_INPUT_SELECTOR as m,attachComposerImage as c,downloadRemoteImage as b,resolveImagePath as x}from"./utils.js";function h(t){const e=l(t);return`https://x.com/compose/post?url=${encodeURIComponent(e.url)}`}async function g(t,e){await t.goto(e.url,{waitUntil:"load",settleMs:2500});await t.wait({selector:'[data-testid="primaryColumn"]',timeout:15});const o=await t.evaluate(`(async () => {
2
2
  try {
3
- ${V(j.id)}
3
+ ${u(e.id)}
4
4
  const visible = (el) => !!el && (el.offsetParent !== null || el.getClientRects().length > 0);
5
5
  let retweetBtn = null;
6
6
  let targetArticle = null;
@@ -30,9 +30,9 @@ import*as Z from"node:fs";import{CommandExecutionError as J}from"@jackwener/open
30
30
  } catch (e) {
31
31
  return { ok: false, message: e.toString() };
32
32
  }
33
- })()`);if(!v?.ok)return v;await q.wait({selector:'[data-testid="tweetTextarea_0"]',timeout:15});return{ok:!0}}async function Y(q,j,v,{allowMenuFallback:z=!0}={}){return q.evaluate(`(async () => {
33
+ })()`);if(!o?.ok)return o;await t.wait({selector:'[data-testid="tweetTextarea_0"]',timeout:15});return{ok:!0}}async function d(t,e,o,{allowMenuFallback:r=!0}={}){return t.evaluate(`(async () => {
34
34
  try {
35
- ${V(v.id)}
35
+ ${u(o.id)}
36
36
  const visible = (el) => !!el && (el.offsetParent !== null || el.getClientRects().length > 0);
37
37
  const normalize = s => String(s || '').replace(/\\u00a0/g, ' ').replace(/\\s+/g, ' ').trim();
38
38
  const insertTextIntoBox = async (box, value) => {
@@ -57,7 +57,7 @@ import*as Z from"node:fs";import{CommandExecutionError as J}from"@jackwener/open
57
57
  return { ok: false, message: 'Could not find the quote composer text area. Are you logged in?' };
58
58
  }
59
59
 
60
- const textToInsert = ${JSON.stringify(j)};
60
+ const textToInsert = ${JSON.stringify(e)};
61
61
  if (!(await insertTextIntoBox(box, textToInsert))) {
62
62
  return { ok: false, message: 'Could not verify quote text in the composer after typing.' };
63
63
  }
@@ -78,7 +78,7 @@ import*as Z from"node:fs";import{CommandExecutionError as J}from"@jackwener/open
78
78
  cardAttempts++;
79
79
  }
80
80
  if (!hasQuoteCard) {
81
- const allowMenuFallback = ${JSON.stringify(z)};
81
+ const allowMenuFallback = ${JSON.stringify(r)};
82
82
  if (allowMenuFallback) {
83
83
  return { ok: false, retryWithMenuFallback: true, message: 'Quote target did not render in the dedicated composer; retrying through the repost menu.' };
84
84
  }
@@ -120,4 +120,4 @@ import*as Z from"node:fs";import{CommandExecutionError as J}from"@jackwener/open
120
120
  } catch (e) {
121
121
  return { ok: false, message: e.toString() };
122
122
  }
123
- })()`)}$({site:"twitter",name:"quote",access:"write",description:"Quote-tweet a specific tweet with your own text, optionally with a local or remote image",domain:"x.com",strategy:f.UI,browser:!0,args:[{name:"url",type:"string",required:!0,positional:!0,help:"The URL of the tweet to quote"},{name:"text",fromFile:!0,type:"string",required:!0,positional:!0,help:"The text content of your quote"},{name:"image",help:"Optional local image path to attach to the quote tweet"},{name:"image-url",help:"Optional remote image URL to download and attach to the quote tweet"}],columns:["status","message","text"],func:async(q,j)=>{if(!q)throw new J("Browser session required for twitter quote");if(j.image&&j["image-url"])throw new J("Use either --image or --image-url, not both.");const v=K(j.url);let z,H;try{if(j.image)z=A(j.image);else if(j["image-url"]){const G=await y(j["image-url"]);z=G.absPath;H=G.cleanupDir}await q.goto(`https://x.com/compose/post?url=${encodeURIComponent(v.url)}`,{waitUntil:"load",settleMs:2500});await q.wait({selector:'[data-testid="tweetTextarea_0"]',timeout:15});if(z){await q.wait({selector:W,timeout:20});await X(q,z)}let B=await Y(q,j.text,v);if(B.retryWithMenuFallback){const G=await D(q,v);if(!G?.ok)return[{status:"failed",message:G?.message??"Could not open quote composer from repost menu.",text:j.text}];if(z){await q.wait({selector:W,timeout:20});await X(q,z)}B=await Y(q,j.text,v,{allowMenuFallback:!1})}if(B.ok)await q.wait(3);return[{status:B.ok?"success":"failed",message:B.message,text:j.text,...j.image?{image:j.image}:{},...j["image-url"]?{"image-url":j["image-url"]}:{}}]}finally{if(H)Z.rmSync(H,{recursive:!0,force:!0})}}});export const __test__={buildQuoteComposerUrl:N};
123
+ })()`)}w({site:"twitter",name:"quote",access:"write",description:"Quote-tweet a specific tweet with your own text, optionally with a local or remote image",domain:"x.com",strategy:p.UI,browser:!0,args:[{name:"url",type:"string",required:!0,positional:!0,help:"The URL of the tweet to quote"},{name:"text",fromFile:!0,type:"string",required:!0,positional:!0,help:"The text content of your quote"},{name:"image",help:"Optional local image path to attach to the quote tweet"},{name:"image-url",help:"Optional remote image URL to download and attach to the quote tweet"}],columns:["status","message","text"],func:async(t,e)=>{if(!t)throw new n("Browser session required for twitter quote");if(e.image&&e["image-url"])throw new n("Use either --image or --image-url, not both.");const o=l(e.url);let r,s;try{if(e.image)r=x(e.image);else if(e["image-url"]){const i=await b(e["image-url"]);r=i.absPath;s=i.cleanupDir}await t.goto(`https://x.com/compose/post?url=${encodeURIComponent(o.url)}`,{waitUntil:"load",settleMs:2500});await t.wait({selector:'[data-testid="tweetTextarea_0"]',timeout:15});if(r){await t.wait({selector:m,timeout:20});await c(t,r)}let a=await d(t,e.text,o);if(a.retryWithMenuFallback){const i=await g(t,o);if(!i?.ok)return[{status:"failed",message:i?.message??"Could not open quote composer from repost menu.",text:e.text}];if(r){await t.wait({selector:m,timeout:20});await c(t,r)}a=await d(t,e.text,o,{allowMenuFallback:!1})}if(a.ok)await t.wait(3);return[{status:a.ok?"success":"failed",message:a.message,text:e.text,...e.image?{image:e.image}:{},...e["image-url"]?{"image-url":e["image-url"]}:{}}]}finally{if(s)f.rmSync(s,{recursive:!0,force:!0})}}});export const __test__={buildQuoteComposerUrl:h};
@@ -1,4 +1,4 @@
1
- import{CommandExecutionError as N}from"@jackwener/opencli/errors";import{cli as O,Strategy as P}from"@jackwener/opencli/registry";import{assertLiteralContent as Q}from"../_shared/content-guard.js";O({site:"twitter",name:"reply-dm",access:"write",description:"Send a message to recent DM conversations",domain:"x.com",strategy:P.UI,browser:!0,args:[{name:"text",fromFile:!0,type:"string",required:!0,positional:!0,help:'Message text to send (e.g. "我的微信 wxkabi")'},{name:"max",type:"int",required:!1,default:20,help:"Maximum number of conversations to reply to (default: 20)"},{name:"skip-replied",type:"boolean",required:!1,default:!0,help:"Skip conversations where you already sent the same text (default: true)"},{name:"timeout",type:"int",required:!1,default:600,help:"Max seconds for the overall command (default: 600 — batch op)"}],columns:["index","status","user","message"],func:async(b,A)=>{if(!b)throw new N("Browser session required for twitter reply-dm");const F=A.text;Q(F,{label:"私信内容"});const G=A.max??20,J=A["skip-replied"]!==!1,f=[];let B=0;await b.goto("https://x.com/messages");await b.wait({selector:'[data-testid="primaryColumn"]'});const K=G+10,D=await b.evaluate(`(async () => {
1
+ import{CommandExecutionError as f}from"@jackwener/opencli/errors";import{cli as p,Strategy as h}from"@jackwener/opencli/registry";import{assertLiteralContent as w}from"../_shared/content-guard.js";p({site:"twitter",name:"reply-dm",access:"write",description:"Send a message to recent DM conversations",domain:"x.com",strategy:h.UI,browser:!0,args:[{name:"text",fromFile:!0,type:"string",required:!0,positional:!0,help:'Message text to send (e.g. "我的微信 wxkabi")'},{name:"max",type:"int",required:!1,default:20,help:"Maximum number of conversations to reply to (default: 20)"},{name:"skip-replied",type:"boolean",required:!1,default:!0,help:"Skip conversations where you already sent the same text (default: true)"},{name:"timeout",type:"int",required:!1,default:600,help:"Max seconds for the overall command (default: 600 — batch op)"}],columns:["index","status","user","message"],func:async(e,r)=>{if(!e)throw new f("Browser session required for twitter reply-dm");const i=r.text;w(i,{label:"私信内容"});const c=r.max??20,l=r["skip-replied"]!==!1,t=[];let o=0;await e.goto("https://x.com/messages");await e.wait({selector:'[data-testid="primaryColumn"]'});const d=c+10,a=await e.evaluate(`(async () => {
2
2
  try {
3
3
  // Wait for initial items
4
4
  let attempts = 0;
@@ -10,7 +10,7 @@ import{CommandExecutionError as N}from"@jackwener/opencli/errors";import{cli as
10
10
  }
11
11
 
12
12
  // Scroll to load more conversations
13
- const needed = ${K};
13
+ const needed = ${d};
14
14
  const seenIds = new Set();
15
15
  let noNewCount = 0;
16
16
 
@@ -63,16 +63,16 @@ import{CommandExecutionError as N}from"@jackwener/opencli/errors";import{cli as
63
63
  } catch(e) {
64
64
  return { ok: false, error: String(e), conversations: [], total: 0 };
65
65
  }
66
- })()`);if(!D?.ok||!D.conversations?.length)return[{index:1,status:"info",user:"System",message:"No conversations found"}];const M=D.conversations;for(const q of M){if(B>=G)break;const H=q.convId?`https://x.com/messages/${q.convId}`:q.href;if(!H)continue;await b.goto(H);await b.wait(3);const z=await b.evaluate(`(async () => {
66
+ })()`);if(!a?.ok||!a.conversations?.length)return[{index:1,status:"info",user:"System",message:"No conversations found"}];const u=a.conversations;for(const s of u){if(o>=c)break;const m=s.convId?`https://x.com/messages/${s.convId}`:s.href;if(!m)continue;await e.goto(m);await e.wait(3);const n=await e.evaluate(`(async () => {
67
67
  try {
68
- const messageText = ${JSON.stringify(F)};
69
- const skipReplied = ${J};
68
+ const messageText = ${JSON.stringify(i)};
69
+ const skipReplied = ${l};
70
70
 
71
71
  // Get username from conversation
72
72
  const dmHeader = document.querySelector('[data-testid="DmActivityContainer"] [dir="ltr"] span') ||
73
73
  document.querySelector('[data-testid="conversation-header"]') ||
74
74
  document.querySelector('[data-testid="DmActivityContainer"] h2');
75
- const username = dmHeader ? dmHeader.innerText.trim().split('\\\\n')[0] : '${q.user}';
75
+ const username = dmHeader ? dmHeader.innerText.trim().split('\\\\n')[0] : '${s.user}';
76
76
 
77
77
  // Check if we already sent this message
78
78
  if (skipReplied) {
@@ -109,4 +109,4 @@ import{CommandExecutionError as N}from"@jackwener/opencli/errors";import{cli as
109
109
  } catch(e) {
110
110
  return { status: 'error', user: 'system', message: String(e) };
111
111
  }
112
- })()`);if(z?.status==="sent"){B++;f.push({index:B,status:"sent",user:z.user||q.user,message:z.message})}else if(z?.status==="skipped")f.push({index:f.length+1,status:"skipped",user:z.user||q.user,message:z.message});await b.wait(1)}if(f.length===0)f.push({index:0,status:"info",user:"System",message:"No conversations processed"});return f}});
112
+ })()`);if(n?.status==="sent"){o++;t.push({index:o,status:"sent",user:n.user||s.user,message:n.message})}else if(n?.status==="skipped")t.push({index:t.length+1,status:"skipped",user:n.user||s.user,message:n.message});await e.wait(1)}if(t.length===0)t.push({index:0,status:"info",user:"System",message:"No conversations processed"});return t}});
@@ -1,11 +1,11 @@
1
- import*as W from"node:fs";import*as D from"node:path";import{CommandExecutionError as J}from"@jackwener/opencli/errors";import{cli as f,Strategy as F}from"@jackwener/opencli/registry";import{parseTweetUrl as j}from"./shared.js";import{assertLiteralContent as b}from"../_shared/content-guard.js";import{COMPOSER_FILE_INPUT_SELECTOR as B,attachComposerImage as L,downloadRemoteImage as h,resolveImagePath as O}from"./utils.js";const Z='[data-testid="tweetTextarea_0"]',V=500,$=15000;function N(z){return`https://x.com/compose/post?in_reply_to=${j(z).id}`}function X(z){return(z instanceof Error?z.message:String(z)).includes("Promise was collected")}async function y(z,q){await z.goto(N(q),{waitUntil:"load",settleMs:2500});try{await z.wait({selector:Z,timeout:15});return{ok:!0}}catch{await z.goto(q,{waitUntil:"load",settleMs:2500});const A=await z.evaluate(`(() => {
1
+ import*as c from"node:fs";import*as b from"node:path";import{CommandExecutionError as i}from"@jackwener/opencli/errors";import{cli as x,Strategy as w}from"@jackwener/opencli/registry";import{parseTweetUrl as h}from"./shared.js";import{assertLiteralContent as g}from"../_shared/content-guard.js";import{COMPOSER_FILE_INPUT_SELECTOR as T,attachComposerImage as S,downloadRemoteImage as C,resolveImagePath as v}from"./utils.js";const m='[data-testid="tweetTextarea_0"]',a=500,d=15000;function y(t){return`https://x.com/compose/post?in_reply_to=${h(t).id}`}function u(t){return(t instanceof Error?t.message:String(t)).includes("Promise was collected")}async function R(t,e){await t.goto(y(e),{waitUntil:"load",settleMs:2500});try{await t.wait({selector:m,timeout:15});return{ok:!0}}catch{await t.goto(e,{waitUntil:"load",settleMs:2500});const o=await t.evaluate(`(() => {
2
2
  const visible = (el) => !!el && (el.offsetParent !== null || el.getClientRects().length > 0);
3
3
  const buttons = Array.from(document.querySelectorAll('[data-testid="reply"]'));
4
4
  const btn = buttons.find((el) => visible(el) && !el.disabled && el.getAttribute('aria-disabled') !== 'true');
5
5
  if (!btn) return { ok: false, message: 'Could not find the reply button on the target tweet.' };
6
6
  btn.click();
7
7
  return { ok: true };
8
- })()`);if(!A?.ok)return A;await z.wait({selector:Z,timeout:15});return{ok:!0}}}async function v(z,q){return z.evaluate(`(async () => {
8
+ })()`);if(!o?.ok)return o;await t.wait({selector:m,timeout:15});return{ok:!0}}}async function p(t,e){return t.evaluate(`(async () => {
9
9
  try {
10
10
  const visible = (el) => !!el && (el.offsetParent !== null || el.getClientRects().length > 0);
11
11
  const boxes = Array.from(document.querySelectorAll('[data-testid="tweetTextarea_0"]'));
@@ -15,7 +15,7 @@ import*as W from"node:fs";import*as D from"node:path";import{CommandExecutionErr
15
15
  }
16
16
 
17
17
  box.focus();
18
- const textToInsert = ${JSON.stringify(q)};
18
+ const textToInsert = ${JSON.stringify(e)};
19
19
  // execCommand('insertText') is more reliable with Twitter's Draft.js editor
20
20
  if (!document.execCommand('insertText', false, textToInsert)) {
21
21
  // Fallback to paste event if execCommand fails
@@ -38,10 +38,10 @@ import*as W from"node:fs";import*as D from"node:path";import{CommandExecutionErr
38
38
  } catch (e) {
39
39
  return { ok: false, message: e.toString() };
40
40
  }
41
- })()`)}async function R(z){const q=Math.ceil($/V);return z.evaluate(`(async () => {
41
+ })()`)}async function k(t){const e=Math.ceil(d/a);return t.evaluate(`(async () => {
42
42
  try {
43
43
  const visible = (el) => !!el && (el.offsetParent !== null || el.getClientRects().length > 0);
44
- for (let i = 0; i < ${JSON.stringify(q)}; i++) {
44
+ for (let i = 0; i < ${JSON.stringify(e)}; i++) {
45
45
  const buttons = Array.from(
46
46
  document.querySelectorAll('[data-testid="tweetButton"], [data-testid="tweetButtonInline"]')
47
47
  );
@@ -50,13 +50,13 @@ import*as W from"node:fs";import*as D from"node:path";import{CommandExecutionErr
50
50
  btn.click();
51
51
  return { ok: true };
52
52
  }
53
- await new Promise(r => setTimeout(r, ${JSON.stringify(V)}));
53
+ await new Promise(r => setTimeout(r, ${JSON.stringify(a)}));
54
54
  }
55
55
  return { ok: false, message: 'Reply button is disabled or not found.' };
56
56
  } catch (e) {
57
57
  return { ok: false, message: e.toString() };
58
58
  }
59
- })()`)}async function I(z){return z.evaluate(`(() => {
59
+ })()`)}async function P(t){return t.evaluate(`(() => {
60
60
  const visible = (el) => !!el && (el.offsetParent !== null || el.getClientRects().length > 0);
61
61
  const toasts = Array.from(document.querySelectorAll('[role="alert"], [data-testid="toast"]'))
62
62
  .filter((el) => visible(el));
@@ -68,13 +68,13 @@ import*as W from"node:fs";import*as D from"node:path";import{CommandExecutionErr
68
68
  message: 'Reply posted successfully.',
69
69
  url: link?.href || link?.getAttribute('href') || undefined
70
70
  };
71
- })()`)}async function M(z,q){const A=Math.ceil($/V);try{return await z.evaluate(`(async () => {
72
- const expected = ${JSON.stringify(q)};
71
+ })()`)}async function _(t,e){const o=Math.ceil(d/a);try{return await t.evaluate(`(async () => {
72
+ const expected = ${JSON.stringify(e)};
73
73
  const normalize = s => String(s || '').replace(/\\u00a0/g, ' ').replace(/\\s+/g, ' ').trim();
74
74
  const expectedText = normalize(expected);
75
75
  const visible = (el) => !!el && (el.offsetParent !== null || el.getClientRects().length > 0);
76
- for (let i = 0; i < ${JSON.stringify(A)}; i++) {
77
- await new Promise(r => setTimeout(r, ${JSON.stringify(V)}));
76
+ for (let i = 0; i < ${JSON.stringify(o)}; i++) {
77
+ await new Promise(r => setTimeout(r, ${JSON.stringify(a)}));
78
78
  const toasts = Array.from(document.querySelectorAll('[role="alert"], [data-testid="toast"]'))
79
79
  .filter((el) => visible(el));
80
80
  const successToast = toasts.find((el) => /sent|posted|your post was sent|your tweet was sent/i.test(el.textContent || ''));
@@ -94,4 +94,4 @@ import*as W from"node:fs";import*as D from"node:path";import{CommandExecutionErr
94
94
  if (!composerStillHasText) return { ok: true, message: 'Reply posted successfully.' };
95
95
  }
96
96
  return { ok: false, message: 'Reply submission did not complete before timeout.' };
97
- })()`)}catch(G){if(!X(G))throw G;await z.wait(2);const H=await I(z);if(H?.ok)return H;throw G}}async function U(z,q){let A=await v(z,q);if(!A?.ok&&/Could not verify/i.test(A?.message||"")){await z.wait(2);A=await v(z,q)}if(!A?.ok)return A;let G;try{G=await R(z)}catch(H){if(!X(H))throw H}if(G&&!G.ok)return G;return M(z,q)}f({site:"twitter",name:"reply",access:"write",description:"Reply to a specific tweet, optionally with a local or remote image",domain:"x.com",strategy:F.UI,browser:!0,args:[{name:"url",type:"string",required:!0,positional:!0,help:"The URL of the tweet to reply to"},{name:"text",type:"string",required:!1,positional:!0,help:"The text content of your reply (or use --file)"},{name:"file",help:"从本机文件读取回复正文(UTF-8),与位置参数 <text> 二选一"},{name:"image",help:"Optional local image path to attach to the reply"},{name:"image-url",help:"Optional remote image URL to download and attach to the reply"}],columns:["status","message","text","url"],func:async(z,q)=>{if(!z)throw new J("Browser session required for twitter reply");const A=q.file?String(q.file).trim():"";if(A){if(q.text)throw new J("回复正文位置参数和 --file 只能二选一,不能同时给");const K=D.resolve(A);if(!W.existsSync(K))throw new J(`--file 指向的文件不存在: ${K}`);q.text=W.readFileSync(K,"utf-8").trim();if(!q.text)throw new J(`--file 指向的文件内容为空: ${K}`)}else{if(!q.text)throw new J("缺少回复正文:给位置参数 <text> 或 --file 其一");b(q.text,{label:"回复内容"})}if(q.image&&q["image-url"])throw new J("Use either --image or --image-url, not both.");let G,H;try{if(q.image)G=O(q.image);else if(q["image-url"]){const Y=await h(q["image-url"]);G=Y.absPath;H=Y.cleanupDir}const K=await y(z,q.url);if(!K?.ok)throw new J(K?.message??"Could not open the reply composer.");if(G){await z.wait({selector:B,timeout:20});await L(z,G)}const Q=await U(z,q.text);if(!Q?.ok)throw new J(Q?.message??"Reply was not confirmed sent; verify via readback before retrying.");return[{status:"success",message:Q.message,text:q.text,...Q.url?{url:Q.url}:{},...q.image?{image:q.image}:{},...q["image-url"]?{"image-url":q["image-url"]}:{}}]}finally{if(H)W.rmSync(H,{recursive:!0,force:!0})}}});export const __test__={buildReplyComposerUrl:N,isPromiseCollectedError:X};
97
+ })()`)}catch(r){if(!u(r))throw r;await t.wait(2);const s=await P(t);if(s?.ok)return s;throw r}}async function A(t,e){let o=await p(t,e);if(!o?.ok&&/Could not verify/i.test(o?.message||"")){await t.wait(2);o=await p(t,e)}if(!o?.ok)return o;let r;try{r=await k(t)}catch(s){if(!u(s))throw s}if(r&&!r.ok)return r;return _(t,e)}x({site:"twitter",name:"reply",access:"write",description:"Reply to a specific tweet, optionally with a local or remote image",domain:"x.com",strategy:w.UI,browser:!0,args:[{name:"url",type:"string",required:!0,positional:!0,help:"The URL of the tweet to reply to"},{name:"text",type:"string",required:!1,positional:!0,help:"The text content of your reply (or use --file)"},{name:"file",help:"从本机文件读取回复正文(UTF-8),与位置参数 <text> 二选一"},{name:"image",help:"Optional local image path to attach to the reply"},{name:"image-url",help:"Optional remote image URL to download and attach to the reply"}],columns:["status","message","text","url"],func:async(t,e)=>{if(!t)throw new i("Browser session required for twitter reply");const o=e.file?String(e.file).trim():"";if(o){if(e.text)throw new i("回复正文位置参数和 --file 只能二选一,不能同时给");const n=b.resolve(o);if(!c.existsSync(n))throw new i(`--file 指向的文件不存在: ${n}`);e.text=c.readFileSync(n,"utf-8").trim();if(!e.text)throw new i(`--file 指向的文件内容为空: ${n}`)}else{if(!e.text)throw new i("缺少回复正文:给位置参数 <text> 或 --file 其一");g(e.text,{label:"回复内容"})}if(e.image&&e["image-url"])throw new i("Use either --image or --image-url, not both.");let r,s;try{if(e.image)r=v(e.image);else if(e["image-url"]){const f=await C(e["image-url"]);r=f.absPath;s=f.cleanupDir}const n=await R(t,e.url);if(!n?.ok)throw new i(n?.message??"Could not open the reply composer.");if(r){await t.wait({selector:T,timeout:20});await S(t,r)}const l=await A(t,e.text);if(!l?.ok)throw new i(l?.message??"Reply was not confirmed sent; verify via readback before retrying.");return[{status:"success",message:l.message,text:e.text,...l.url?{url:l.url}:{},...e.image?{image:e.image}:{},...e["image-url"]?{"image-url":e["image-url"]}:{}}]}finally{if(s)c.rmSync(s,{recursive:!0,force:!0})}}});export const __test__={buildReplyComposerUrl:y,isPromiseCollectedError:u};
@@ -1,6 +1,6 @@
1
- import{CommandExecutionError as F}from"@jackwener/opencli/errors";import{cli as G,Strategy as H}from"@jackwener/opencli/registry";import{parseTweetUrl as I,buildTwitterArticleScopeSource as J}from"./shared.js";G({site:"twitter",name:"retweet",access:"write",description:"Retweet a specific tweet",domain:"x.com",strategy:H.UI,browser:!0,args:[{name:"url",type:"string",required:!0,positional:!0,help:"The URL of the tweet to retweet"}],columns:["status","message"],func:async(v,D)=>{if(!v)throw new F("Browser session required for twitter retweet");const B=I(D.url);await v.goto(B.url);await v.wait({selector:'[data-testid="primaryColumn"]'});const z=await v.evaluate(`(async () => {
1
+ import{CommandExecutionError as n}from"@jackwener/opencli/errors";import{cli as o,Strategy as a}from"@jackwener/opencli/registry";import{parseTweetUrl as s,buildTwitterArticleScopeSource as c}from"./shared.js";o({site:"twitter",name:"retweet",access:"write",description:"Retweet a specific tweet",domain:"x.com",strategy:a.UI,browser:!0,args:[{name:"url",type:"string",required:!0,positional:!0,help:"The URL of the tweet to retweet"}],columns:["status","message"],func:async(e,i)=>{if(!e)throw new n("Browser session required for twitter retweet");const r=s(i.url);await e.goto(r.url);await e.wait({selector:'[data-testid="primaryColumn"]'});const t=await e.evaluate(`(async () => {
2
2
  try {
3
- ${J(B.id)}
3
+ ${c(r.id)}
4
4
  // Poll for the tweet to render. State probes scoped to the article
5
5
  // matching the requested status id — bare querySelector on a
6
6
  // conversation page would silently grab the first article (e.g.
@@ -59,4 +59,4 @@ import{CommandExecutionError as F}from"@jackwener/opencli/errors";import{cli as
59
59
  } catch (e) {
60
60
  return { ok: false, message: e.toString() };
61
61
  }
62
- })()`);if(z.ok)await v.wait(2);return[{status:z.ok?"success":"failed",message:z.message}]}});
62
+ })()`);if(t.ok)await e.wait(2);return[{status:t.ok?"success":"failed",message:t.message}]}});
@@ -1,6 +1,6 @@
1
- import{ArgumentError as J,CommandExecutionError as H}from"@jackwener/opencli/errors";import{cli as K,Strategy as L}from"@jackwener/opencli/registry";import{openScheduledQueue as N}from"./scheduled-utils.js";function I(q){const v=String(q??"").trim();if(!v)throw new J("Text fragment is required to delete a scheduled post");return v}export function buildScheduledDeleteScript(q){return`(async () => {
1
+ import{ArgumentError as l,CommandExecutionError as i}from"@jackwener/opencli/errors";import{cli as a,Strategy as d}from"@jackwener/opencli/registry";import{openScheduledQueue as c}from"./scheduled-utils.js";function s(e){const t=String(e??"").trim();if(!t)throw new l("Text fragment is required to delete a scheduled post");return t}export function buildScheduledDeleteScript(e){return`(async () => {
2
2
  try {
3
- const needle = ${JSON.stringify(q)}.toLowerCase();
3
+ const needle = ${JSON.stringify(e)}.toLowerCase();
4
4
  const visible = (el) => !!el && (el.offsetParent !== null || el.getClientRects().length > 0);
5
5
  const normalize = (s) => String(s || '').replace(/\\s+/g, ' ').trim();
6
6
  const findItems = () => Array.from(document.querySelectorAll('[data-testid="unsentTweet"]'));
@@ -57,4 +57,4 @@ import{ArgumentError as J,CommandExecutionError as H}from"@jackwener/opencli/err
57
57
  } catch (e) {
58
58
  return { ok: false, message: String(e) };
59
59
  }
60
- })()`}K({site:"twitter",name:"scheduled-delete",access:"write",description:"Delete a scheduled X post by matching a text fragment",domain:"x.com",strategy:L.UI,browser:!0,args:[{name:"match",type:"string",required:!0,positional:!0,help:"Text fragment that uniquely identifies the scheduled post"}],columns:["status","message","match"],func:async(q,v)=>{if(!q)throw new H("Browser session required for twitter scheduled-delete");const B=I(v.match),F=await N(q);if(F?.empty)return[{status:"failed",message:"No scheduled posts found to delete.",match:B}];if(!F?.ok)throw new H(F?.message??"Could not open scheduled posts queue");const G=await q.evaluate(buildScheduledDeleteScript(B));return[{status:G?.ok?"success":"failed",message:G?.message??"Scheduled post delete failed.",match:B}]}});export const __test__={buildScheduledDeleteScript,normalizeMatch:I};
60
+ })()`}a({site:"twitter",name:"scheduled-delete",access:"write",description:"Delete a scheduled X post by matching a text fragment",domain:"x.com",strategy:d.UI,browser:!0,args:[{name:"match",type:"string",required:!0,positional:!0,help:"Text fragment that uniquely identifies the scheduled post"}],columns:["status","message","match"],func:async(e,t)=>{if(!e)throw new i("Browser session required for twitter scheduled-delete");const o=s(t.match),r=await c(e);if(r?.empty)return[{status:"failed",message:"No scheduled posts found to delete.",match:o}];if(!r?.ok)throw new i(r?.message??"Could not open scheduled posts queue");const n=await e.evaluate(buildScheduledDeleteScript(o));return[{status:n?.ok?"success":"failed",message:n?.message??"Scheduled post delete failed.",match:o}]}});export const __test__={buildScheduledDeleteScript,normalizeMatch:s};
@@ -1,4 +1,4 @@
1
- import{CommandExecutionError as v}from"@jackwener/opencli/errors";import{cli as z,Strategy as A}from"@jackwener/opencli/registry";import{openScheduledQueue as B}from"./scheduled-utils.js";export function buildScheduledListScript(){return`(() => {
1
+ import{CommandExecutionError as r}from"@jackwener/opencli/errors";import{cli as s,Strategy as o}from"@jackwener/opencli/registry";import{openScheduledQueue as d}from"./scheduled-utils.js";export function buildScheduledListScript(){return`(() => {
2
2
  const items = Array.from(document.querySelectorAll('[data-testid="unsentTweet"]'));
3
3
  return items.map((item, index) => {
4
4
  const text = (item.querySelector('[data-testid="tweetText"]')?.textContent || '').replace(/\\s+/g, ' ').trim();
@@ -12,4 +12,4 @@ import{CommandExecutionError as v}from"@jackwener/opencli/errors";import{cli as
12
12
  text,
13
13
  };
14
14
  });
15
- })()`}z({site:"twitter",name:"scheduled-list",access:"read",description:"List X posts currently scheduled in the web composer",domain:"x.com",strategy:A.UI,browser:!0,args:[],columns:["index","scheduledFor","text"],func:async(f)=>{if(!f)throw new v("Browser session required for twitter scheduled-list");const q=await B(f);if(q?.empty)return[];if(!q?.ok)throw new v(q?.message??"Could not open scheduled posts queue");return f.evaluate(buildScheduledListScript())}});export const __test__={buildScheduledListScript};
15
+ })()`}s({site:"twitter",name:"scheduled-list",access:"read",description:"List X posts currently scheduled in the web composer",domain:"x.com",strategy:o.UI,browser:!0,args:[],columns:["index","scheduledFor","text"],func:async(e)=>{if(!e)throw new r("Browser session required for twitter scheduled-list");const t=await d(e);if(t?.empty)return[];if(!t?.ok)throw new r(t?.message??"Could not open scheduled posts queue");return e.evaluate(buildScheduledListScript())}});export const __test__={buildScheduledListScript};
@@ -1,4 +1,4 @@
1
- export const COMPOSE_URL="https://x.com/compose/post";export async function openScheduledQueue(b){await b.goto(COMPOSE_URL,{waitUntil:"load",settleMs:2500});try{await b.wait({selector:'[data-testid="unsentButton"]',timeout:15})}catch{}const f=await b.evaluate(`(async () => {
1
+ export const COMPOSE_URL="https://x.com/compose/post";export async function openScheduledQueue(t){await t.goto(COMPOSE_URL,{waitUntil:"load",settleMs:2500});try{await t.wait({selector:'[data-testid="unsentButton"]',timeout:15})}catch{}const e=await t.evaluate(`(async () => {
2
2
  const visible = (el) => !!el && (el.offsetParent !== null || el.getClientRects().length > 0);
3
3
  // 优先用 locale 无关的 testid 判存在,其次回退到文案(个别皮肤无 testid)。
4
4
  const drafts = document.querySelector('[data-testid="unsentButton"]')
@@ -7,7 +7,7 @@ export const COMPOSE_URL="https://x.com/compose/post";export async function open
7
7
  if (!drafts) return { ok: true, empty: true };
8
8
  drafts.click();
9
9
  return { ok: true };
10
- })()`);if(f?.empty)return{ok:!0,empty:!0};if(!f?.ok)return f;await b.wait(1);const h=await b.evaluate(`(async () => {
10
+ })()`);if(e?.empty)return{ok:!0,empty:!0};if(!e?.ok)return e;await t.wait(1);const r=await t.evaluate(`(async () => {
11
11
  const visible = (el) => !!el && (el.offsetParent !== null || el.getClientRects().length > 0);
12
12
  const scheduledTab = Array.from(document.querySelectorAll('a, [role="tab"]'))
13
13
  .find((el) => visible(el) && /^scheduled$/i.test((el.textContent || '').trim()));
@@ -15,4 +15,4 @@ export const COMPOSE_URL="https://x.com/compose/post";export async function open
15
15
  if (!scheduledTab) return { ok: true, empty: true };
16
16
  scheduledTab.click();
17
17
  return { ok: true };
18
- })()`);if(h?.empty)return{ok:!0,empty:!0};if(!h?.ok)return h;await b.wait(2);return{ok:!0}}
18
+ })()`);if(r?.empty)return{ok:!0,empty:!0};if(!r?.ok)return r;await t.wait(2);return{ok:!0}}
@@ -1,12 +1,12 @@
1
- import{ArgumentError as f,AuthRequiredError as C,CommandExecutionError as d}from"@jackwener/opencli/errors";import{cli as O,Strategy as _}from"@jackwener/opencli/registry";import{extractMedia as R,extractCard as k,extractQuotedTweet as c,normalizeTwitterGraphqlPayload as T,resolveTwitterOperationMetadata as p,describeTwitterApiError as E}from"./shared.js";import{TWITTER_BEARER_TOKEN as g,applyTopByEngagement as n}from"./utils.js";const q=Object.freeze(["media","images","videos","links","replies"]),x=Object.freeze(["replies","retweets","media","links"]),D=Object.freeze(["top","live","photos","videos"]),Q=Object.freeze({top:"top",live:"live",photos:"image",videos:"video"}),i=Object.freeze({top:"Top",live:"Latest",photos:"Photos",videos:"Videos"}),w=100,j={queryId:"Yw6L66Pw54NHKuq4Dp7b4Q",features:{rweb_video_screen_enabled:!0,rweb_cashtags_enabled:!0,profile_label_improvements_pcf_label_in_post_enabled:!0,responsive_web_profile_redirect_enabled:!0,rweb_tipjar_consumption_enabled:!0,verified_phone_label_enabled:!1,creator_subscriptions_tweet_preview_api_enabled:!0,responsive_web_graphql_timeline_navigation_enabled:!0,responsive_web_graphql_skip_user_profile_image_extensions_enabled:!1,premium_content_api_read_enabled:!1,communities_web_enable_tweet_community_results_fetch:!0,c9s_tweet_anatomy_moderator_badge_enabled:!0,responsive_web_grok_analyze_button_fetch_trends_enabled:!1,responsive_web_grok_analyze_post_followups_enabled:!0,rweb_cashtags_composer_attachment_enabled:!0,responsive_web_jetfuel_frame:!0,responsive_web_grok_share_attachment_enabled:!0,responsive_web_grok_annotations_enabled:!0,articles_preview_enabled:!0,responsive_web_edit_tweet_api_enabled:!0,graphql_is_translatable_rweb_tweet_is_translatable_enabled:!0,view_counts_everywhere_api_enabled:!0,longform_notetweets_consumption_enabled:!0,responsive_web_twitter_article_tweet_consumption_enabled:!0,content_disclosure_indicator_enabled:!0,content_disclosure_ai_generated_indicator_enabled:!0,responsive_web_grok_show_grok_translated_post:!1,responsive_web_grok_analysis_button_from_backend:!0,post_ctas_fetch_enabled:!1,freedom_of_speech_not_reach_fetch_enabled:!0,standardized_nudges_misinfo:!0,tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled:!0,longform_notetweets_rich_text_read_enabled:!0,longform_notetweets_inline_media_enabled:!0,responsive_web_grok_image_annotation_enabled:!0,responsive_web_grok_imagine_annotation_enabled:!0,responsive_web_grok_community_note_auto_translation_is_enabled:!1,responsive_web_enhance_cards_enabled:!1},fieldToggles:{withPayments:!0,withAuxiliaryUserLabels:!0,withArticleRichContentState:!0,withArticlePlainText:!0,withArticleSummaryText:!0,withArticleVoiceOver:!0,withGrokAnalyze:!0,withDisallowedReplyControls:!0}},L=/^[A-Za-z0-9_]{1,15}$/,M=Object.freeze({replies:"-filter:replies",retweets:"-filter:nativeretweets",media:"-filter:media",links:"-filter:links"});function H(J,V){const Y=[String(J??"").trim()];if(V.from){const $=String(V.from).trim().replace(/^@+/,"");if($&&!L.test($))throw new f(`Invalid --from username: ${JSON.stringify(V.from)}`,"Use a Twitter/X handle with 1-15 letters, numbers, or underscores; omit @ or pass @handle.");if($)Y.push(`from:${$}`)}if(V.has)Y.push(`filter:${V.has}`);if(V.exclude){const $=M[V.exclude];if($)Y.push($)}return Y.filter(Boolean).join(" ")}function l(J){if(J.product){const V=Q[J.product];if(V)return V}return J.filter==="live"?"live":"top"}function y(J){const V=J.product||(J.filter==="live"?"live":"top");return i[V]||"Top"}function o(J){if(typeof J==="string")return{queryId:J,features:j.features,fieldToggles:j.fieldToggles};return{queryId:J?.queryId||j.queryId,features:J?.features||j.features,fieldToggles:J?.fieldToggles||j.fieldToggles}}function N(J,V,Y,$,W){const B=o(J),Z={rawQuery:V,count:$,querySource:"typed_query",product:Y};if(W)Z.cursor=W;return[`/i/api/graphql/${B.queryId}/SearchTimeline`,{variables:Z,features:B.features,fieldToggles:B.fieldToggles}]}function u(J){if(!J)return null;if(J.__typename==="TweetWithVisibilityResults"&&J.tweet)return J.tweet;if(J.tweet)return J.tweet;return J}function s(J,V){const Y=u(J);if(!Y?.rest_id||V.has(Y.rest_id))return null;V.add(Y.rest_id);const $=Y.core?.user_results?.result,W=$?.legacy?.description||"";return{id:Y.rest_id,author:$?.core?.screen_name||$?.legacy?.screen_name||"",bio:W,text:Y.note_tweet?.note_tweet_results?.result?.text||Y.legacy?.full_text||"",created_at:Y.legacy?.created_at||"",likes:Y.legacy?.favorite_count||0,views:Y.views?.count||"0",url:`https://x.com/i/status/${Y.rest_id}`,...R(Y.legacy),card:k(Y),quoted_tweet:c(Y)}}function h(J,V){const Y=[];let $=null;const W=J?.data?.search_by_raw_query?.search_timeline?.timeline?.instructions||[],B=(Z)=>{if(!Z||typeof Z!=="object")return;if(Z.tweet_results?.result){const K=s(Z.tweet_results.result,V);if(K)Y.push(K)}if((Z.entryType==="TimelineTimelineCursor"||Z.__typename==="TimelineTimelineCursor")&&(Z.cursorType==="Bottom"||Z.cursorType==="ShowMore")&&Z.value)$=Z.value;if(Array.isArray(Z)){for(const K of Z)B(K);return}for(const K of Object.values(Z))if(K&&typeof K==="object")B(K)};B(W);return{rows:Y,nextCursor:$}}O({site:"twitter",name:"search",access:"read",description:"Search Twitter/X for tweets, with optional --from / --has / --exclude / --product filters mapped to X's search operators",domain:"x.com",strategy:_.COOKIE,browser:!0,args:[{name:"query",type:"string",required:!0,positional:!0,help:'Search query. Raw X operators (e.g. "exact phrase", #tag, OR, lang:en, since:YYYY-MM-DD, from:, since:) are passed through unchanged.'},{name:"filter",type:"string",default:"top",choices:["top","live"],help:"Legacy alias for --product. Kept for backwards compatibility; if --product is set it wins."},{name:"product",type:"string",choices:D,help:"Which X search tab to read: top (default), live (Latest), photos, videos. Maps to the f= URL param."},{name:"from",type:"string",help:"Restrict to tweets authored by <user>. Leading @ is stripped. Equivalent to appending `from:<user>` to the query."},{name:"has",type:"string",choices:q,help:"Restrict to tweets that have media|images|videos|links|replies. Maps to X's `filter:<has>` operator."},{name:"exclude",type:"string",choices:x,help:"Exclude tweets matching <type>: replies|retweets|media|links. Maps to X's `-filter:<x>` operator (retweets → -filter:nativeretweets)."},{name:"limit",type:"int",default:15,help:"Maximum number of tweets to return (default 15). Result count after server-side filtering."},{name:"top-by-engagement",type:"int",default:0,help:"When set to N>0, re-rank the results by weighted engagement (likes×1 + retweets×3 + replies×2 + bookmarks×5 + log10(views+1)×0.5) and return the top N. Default 0 keeps X's native ordering."}],columns:["id","author","bio","text","created_at","likes","views","url","has_media","media_urls","media_posters","card","quoted_tweet"],func:async(J,V)=>{const Y=H(V.query,V);if(!Y)throw new f("twitter search query is empty","Provide a non-empty <query>, or use at least one of --from / --has / --exclude.");if(!Number.isInteger(Number(V.limit))||Number(V.limit)<=0)throw new f("twitter search --limit must be a positive integer","Example: ppcli twitter search ppcli --limit 15");const W=(await J.getCookies({url:"https://x.com"})).find((z)=>z.name==="ct0")?.value||null;if(!W)throw new C("x.com","Not logged into x.com (no ct0 cookie)");await J.goto("https://x.com/home",{waitUntil:"load",settleMs:1000});const B=await p(J,"SearchTimeline",j),Z=JSON.stringify({Authorization:`Bearer ${decodeURIComponent(g)}`,"X-Csrf-Token":W,"X-Twitter-Auth-Type":"OAuth2Session","X-Twitter-Active-User":"yes","Content-Type":"application/json"}),K=y(V),G=[],U=new Set;let F=null;for(let z=0;z<w&&G.length<V.limit;z++){const m=Number(V.limit)-G.length+10,[I,S]=N(B,Y,K,m,F),A=JSON.stringify(S),X=T(await J.evaluate(`async () => {
1
+ import{ArgumentError as f,AuthRequiredError as I,CommandExecutionError as N}from"@jackwener/opencli/errors";import{cli as k,Strategy as U}from"@jackwener/opencli/registry";import{extractMedia as z,extractCard as j,extractQuotedTweet as M,normalizeTwitterGraphqlPayload as X,resolveTwitterOperationMetadata as D,describeTwitterApiError as L}from"./shared.js";import{TWITTER_BEARER_TOKEN as H,applyTopByEngagement as B}from"./utils.js";const m=Object.freeze(["media","images","videos","links","replies"]),h=Object.freeze(["replies","retweets","media","links"]),w=Object.freeze(["top","live","photos","videos"]),b=Object.freeze({top:"top",live:"live",photos:"image",videos:"video"}),G=Object.freeze({top:"Top",live:"Latest",photos:"Photos",videos:"Videos"}),J=100,l={queryId:"Yw6L66Pw54NHKuq4Dp7b4Q",features:{rweb_video_screen_enabled:!0,rweb_cashtags_enabled:!0,profile_label_improvements_pcf_label_in_post_enabled:!0,responsive_web_profile_redirect_enabled:!0,rweb_tipjar_consumption_enabled:!0,verified_phone_label_enabled:!1,creator_subscriptions_tweet_preview_api_enabled:!0,responsive_web_graphql_timeline_navigation_enabled:!0,responsive_web_graphql_skip_user_profile_image_extensions_enabled:!1,premium_content_api_read_enabled:!1,communities_web_enable_tweet_community_results_fetch:!0,c9s_tweet_anatomy_moderator_badge_enabled:!0,responsive_web_grok_analyze_button_fetch_trends_enabled:!1,responsive_web_grok_analyze_post_followups_enabled:!0,rweb_cashtags_composer_attachment_enabled:!0,responsive_web_jetfuel_frame:!0,responsive_web_grok_share_attachment_enabled:!0,responsive_web_grok_annotations_enabled:!0,articles_preview_enabled:!0,responsive_web_edit_tweet_api_enabled:!0,graphql_is_translatable_rweb_tweet_is_translatable_enabled:!0,view_counts_everywhere_api_enabled:!0,longform_notetweets_consumption_enabled:!0,responsive_web_twitter_article_tweet_consumption_enabled:!0,content_disclosure_indicator_enabled:!0,content_disclosure_ai_generated_indicator_enabled:!0,responsive_web_grok_show_grok_translated_post:!1,responsive_web_grok_analysis_button_from_backend:!0,post_ctas_fetch_enabled:!1,freedom_of_speech_not_reach_fetch_enabled:!0,standardized_nudges_misinfo:!0,tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled:!0,longform_notetweets_rich_text_read_enabled:!0,longform_notetweets_inline_media_enabled:!0,responsive_web_grok_image_annotation_enabled:!0,responsive_web_grok_imagine_annotation_enabled:!0,responsive_web_grok_community_note_auto_translation_is_enabled:!1,responsive_web_enhance_cards_enabled:!1},fieldToggles:{withPayments:!0,withAuxiliaryUserLabels:!0,withArticleRichContentState:!0,withArticlePlainText:!0,withArticleSummaryText:!0,withArticleVoiceOver:!0,withGrokAnalyze:!0,withDisallowedReplyControls:!0}},y=/^[A-Za-z0-9_]{1,15}$/,g=Object.freeze({replies:"-filter:replies",retweets:"-filter:nativeretweets",media:"-filter:media",links:"-filter:links"});function v(e,t){const r=[String(e??"").trim()];if(t.from){const o=String(t.from).trim().replace(/^@+/,"");if(o&&!y.test(o))throw new f(`Invalid --from username: ${JSON.stringify(t.from)}`,"Use a Twitter/X handle with 1-15 letters, numbers, or underscores; omit @ or pass @handle.");if(o)r.push(`from:${o}`)}if(t.has)r.push(`filter:${t.has}`);if(t.exclude){const o=g[t.exclude];if(o)r.push(o)}return r.filter(Boolean).join(" ")}function Q(e){if(e.product){const t=b[e.product];if(t)return t}return e.filter==="live"?"live":"top"}function T(e){const t=e.product||(e.filter==="live"?"live":"top");return G[t]||"Top"}function Y(e){if(typeof e==="string")return{queryId:e,features:l.features,fieldToggles:l.fieldToggles};return{queryId:e?.queryId||l.queryId,features:e?.features||l.features,fieldToggles:e?.fieldToggles||l.fieldToggles}}function O(e,t,r,o,n){const a=Y(e),i={rawQuery:t,count:o,querySource:"typed_query",product:r};if(n)i.cursor=n;return[`/i/api/graphql/${a.queryId}/SearchTimeline`,{variables:i,features:a.features,fieldToggles:a.fieldToggles}]}function K(e){if(!e)return null;if(e.__typename==="TweetWithVisibilityResults"&&e.tweet)return e.tweet;if(e.tweet)return e.tweet;return e}function W(e,t){const r=K(e);if(!r?.rest_id||t.has(r.rest_id))return null;t.add(r.rest_id);const o=r.core?.user_results?.result,n=o?.legacy?.description||"";return{id:r.rest_id,author:o?.core?.screen_name||o?.legacy?.screen_name||"",bio:n,text:r.note_tweet?.note_tweet_results?.result?.text||r.legacy?.full_text||"",created_at:r.legacy?.created_at||"",likes:r.legacy?.favorite_count||0,views:r.views?.count||"0",url:`https://x.com/i/status/${r.rest_id}`,...z(r.legacy),card:j(r),quoted_tweet:M(r)}}function x(e,t){const r=[];let o=null;const n=e?.data?.search_by_raw_query?.search_timeline?.timeline?.instructions||[],a=(i)=>{if(!i||typeof i!=="object")return;if(i.tweet_results?.result){const s=W(i.tweet_results.result,t);if(s)r.push(s)}if((i.entryType==="TimelineTimelineCursor"||i.__typename==="TimelineTimelineCursor")&&(i.cursorType==="Bottom"||i.cursorType==="ShowMore")&&i.value)o=i.value;if(Array.isArray(i)){for(const s of i)a(s);return}for(const s of Object.values(i))if(s&&typeof s==="object")a(s)};a(n);return{rows:r,nextCursor:o}}k({site:"twitter",name:"search",access:"read",description:"Search Twitter/X for tweets, with optional --from / --has / --exclude / --product filters mapped to X's search operators",domain:"x.com",strategy:U.COOKIE,browser:!0,args:[{name:"query",type:"string",required:!0,positional:!0,help:'Search query. Raw X operators (e.g. "exact phrase", #tag, OR, lang:en, since:YYYY-MM-DD, from:, since:) are passed through unchanged.'},{name:"filter",type:"string",default:"top",choices:["top","live"],help:"Legacy alias for --product. Kept for backwards compatibility; if --product is set it wins."},{name:"product",type:"string",choices:w,help:"Which X search tab to read: top (default), live (Latest), photos, videos. Maps to the f= URL param."},{name:"from",type:"string",help:"Restrict to tweets authored by <user>. Leading @ is stripped. Equivalent to appending `from:<user>` to the query."},{name:"has",type:"string",choices:m,help:"Restrict to tweets that have media|images|videos|links|replies. Maps to X's `filter:<has>` operator."},{name:"exclude",type:"string",choices:h,help:"Exclude tweets matching <type>: replies|retweets|media|links. Maps to X's `-filter:<x>` operator (retweets → -filter:nativeretweets)."},{name:"limit",type:"int",default:15,help:"Maximum number of tweets to return (default 15). Result count after server-side filtering."},{name:"top-by-engagement",type:"int",default:0,help:"When set to N>0, re-rank the results by weighted engagement (likes×1 + retweets×3 + replies×2 + bookmarks×5 + log10(views+1)×0.5) and return the top N. Default 0 keeps X's native ordering."}],columns:["id","author","bio","text","created_at","likes","views","url","has_media","media_urls","media_posters","card","quoted_tweet"],func:async(e,t)=>{const r=v(t.query,t);if(!r)throw new f("twitter search query is empty","Provide a non-empty <query>, or use at least one of --from / --has / --exclude.");if(!Number.isInteger(Number(t.limit))||Number(t.limit)<=0)throw new f("twitter search --limit must be a positive integer","Example: ppcli twitter search ppcli --limit 15");const n=(await e.getCookies({url:"https://x.com"})).find((c)=>c.name==="ct0")?.value||null;if(!n)throw new I("x.com","Not logged into x.com (no ct0 cookie)");await e.goto("https://x.com/home",{waitUntil:"load",settleMs:1000});const a=await D(e,"SearchTimeline",l),i=JSON.stringify({Authorization:`Bearer ${decodeURIComponent(H)}`,"X-Csrf-Token":n,"X-Twitter-Auth-Type":"OAuth2Session","X-Twitter-Active-User":"yes","Content-Type":"application/json"}),s=T(t),_=[],S=new Set;let u=null;for(let c=0;c<J&&_.length<t.limit;c++){const R=Number(t.limit)-_.length+10,[A,E]=O(a,r,s,R,u),C=JSON.stringify(E),d=X(await e.evaluate(`async () => {
2
2
  const options = {
3
3
  method: 'POST',
4
- headers: ${Z},
4
+ headers: ${i},
5
5
  credentials: 'include',
6
6
  };
7
- options['body'] = ${JSON.stringify(A)};
8
- const r = await fetch(${JSON.stringify(I)}, {
7
+ options['body'] = ${JSON.stringify(C)};
8
+ const r = await fetch(${JSON.stringify(A)}, {
9
9
  ...options,
10
10
  });
11
11
  return r.ok ? await r.json() : { error: r.status };
12
- }`));if(X?.error){if(G.length===0)throw new d(E("SearchTimeline",X.error));break}const{rows:v,nextCursor:b}=h(X,U);G.push(...v);if(!b||b===F)break;F=b}const P=G.slice(0,V.limit);return n(P,V["top-by-engagement"])}});export const __test__={buildSearchQuery:H,resolveSearchFParam:l,resolveSearchProduct:y,buildSearchTimelineRequest:N,parseSearchTimeline:h,HAS_CHOICES:q,EXCLUDE_CHOICES:x,PRODUCT_CHOICES:D,EXCLUDE_TO_OPERATOR:M,PRODUCT_TO_F_PARAM:Q,FROM_USER_PATTERN:L};
12
+ }`));if(d?.error){if(_.length===0)throw new N(L("SearchTimeline",d.error));break}const{rows:P,nextCursor:p}=x(d,S);_.push(...P);if(!p||p===u)break;u=p}const q=_.slice(0,t.limit);return B(q,t["top-by-engagement"])}});export const __test__={buildSearchQuery:v,resolveSearchFParam:Q,resolveSearchProduct:T,buildSearchTimelineRequest:O,parseSearchTimeline:x,HAS_CHOICES:m,EXCLUDE_CHOICES:h,PRODUCT_CHOICES:w,EXCLUDE_TO_OPERATOR:g,PRODUCT_TO_F_PARAM:b,FROM_USER_PATTERN:y};