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 +1 @@
1
- import{cli as o,Strategy as u}from"@jackwener/opencli/registry";import{EmptyResultError as l}from"@jackwener/opencli/errors";import{TVMAZE_BASE as d,joinList as g,requireShowId as c,stripHtml as h,tvmazeFetch as w}from"./utils.js";o({site:"tvmaze",name:"show",access:"read",description:"Single TVmaze TV show detail by id (network, schedule, rating, IMDB/TheTVDB cross-refs)",domain:"tvmaze.com",strategy:u.PUBLIC,browser:!1,args:[{name:"id",positional:!0,type:"int",required:!0,help:"TVmaze show id (positive integer)"}],columns:["id","name","type","language","genres","status","premiered","ended","runtime","averageRuntime","network","country","schedule","rating","imdb","thetvdb","officialSite","summary","url"],func:async(i)=>{const t=c(i.id),e=await w(`${d}/shows/${t}`,`tvmaze show ${t}`);if(!e||e.id==null)throw new l("tvmaze show",`TVmaze returned no show for id ${t}.`);const a=e.network?.name??e.webChannel?.name??"",s=e.network?.country?.name??e.webChannel?.country?.name??"",r=Array.isArray(e.schedule?.days)?e.schedule.days.join(", "):"",n=String(e.schedule?.time??"").trim(),m=r||n?`${r}${r&&n?" ":""}${n}`.trim():"";return[{id:Number(e.id),name:String(e.name??"").trim(),type:String(e.type??"").trim(),language:String(e.language??"").trim(),genres:g(e.genres),status:String(e.status??"").trim(),premiered:typeof e.premiered==="string"?e.premiered:null,ended:typeof e.ended==="string"?e.ended:null,runtime:e.runtime==null?null:Number(e.runtime),averageRuntime:e.averageRuntime==null?null:Number(e.averageRuntime),network:String(a).trim(),country:String(s).trim(),schedule:m,rating:e.rating?.average==null?null:Number(e.rating.average),imdb:String(e.externals?.imdb??"").trim(),thetvdb:e.externals?.thetvdb==null?null:Number(e.externals.thetvdb),officialSite:String(e.officialSite??"").trim(),summary:h(e.summary),url:String(e.url??"").trim()}]}});
1
+ import{cli as u,Strategy as o}from"@jackwener/opencli/registry";import{EmptyResultError as l}from"@jackwener/opencli/errors";import{TVMAZE_BASE as d,joinList as g,requireShowId as c,stripHtml as h,tvmazeFetch as y}from"./utils.js";u({site:"tvmaze",name:"show",access:"read",description:"Single TVmaze TV show detail by id (network, schedule, rating, IMDB/TheTVDB cross-refs)",domain:"tvmaze.com",strategy:o.PUBLIC,browser:!1,args:[{name:"id",positional:!0,type:"int",required:!0,help:"TVmaze show id (positive integer)"}],columns:["id","name","type","language","genres","status","premiered","ended","runtime","averageRuntime","network","country","schedule","rating","imdb","thetvdb","officialSite","summary","url"],func:async(i)=>{const t=c(i.id),e=await y(`${d}/shows/${t}`,`tvmaze show ${t}`);if(!e||e.id==null)throw new l("tvmaze show",`TVmaze returned no show for id ${t}.`);const a=e.network?.name??e.webChannel?.name??"",m=e.network?.country?.name??e.webChannel?.country?.name??"",r=Array.isArray(e.schedule?.days)?e.schedule.days.join(", "):"",n=String(e.schedule?.time??"").trim(),s=r||n?`${r}${r&&n?" ":""}${n}`.trim():"";return[{id:Number(e.id),name:String(e.name??"").trim(),type:String(e.type??"").trim(),language:String(e.language??"").trim(),genres:g(e.genres),status:String(e.status??"").trim(),premiered:typeof e.premiered==="string"?e.premiered:null,ended:typeof e.ended==="string"?e.ended:null,runtime:e.runtime==null?null:Number(e.runtime),averageRuntime:e.averageRuntime==null?null:Number(e.averageRuntime),network:String(a).trim(),country:String(m).trim(),schedule:s,rating:e.rating?.average==null?null:Number(e.rating.average),imdb:String(e.externals?.imdb??"").trim(),thetvdb:e.externals?.thetvdb==null?null:Number(e.externals.thetvdb),officialSite:String(e.officialSite??"").trim(),summary:h(e.summary),url:String(e.url??"").trim()}]}});
@@ -1 +1 @@
1
- import{ArgumentError as J,CommandExecutionError as K,EmptyResultError as O}from"@jackwener/opencli/errors";export const TVMAZE_BASE="https://api.tvmaze.com";const Q="opencli-tvmaze-adapter (+https://github.com/jackwener/OpenCLI)";export function requireString(D,z){const q=String(D??"").trim();if(!q)throw new J(`tvmaze ${z} cannot be empty`);return q}export function requireShowId(D){const z=D,q=typeof z==="number"?z:Number(String(z??"").trim());if(!Number.isInteger(q)||q<=0)throw new J("tvmaze show id is required and must be a positive integer","TVmaze show ids appear in the URL: https://www.tvmaze.com/shows/<id>/<slug>.");return q}export function requireBoundedInt(D,z,q,F="limit"){const B=D??z,G=typeof B==="number"?B:Number(B);if(!Number.isInteger(G)||G<=0)throw new J(`tvmaze ${F} must be a positive integer`);if(G>q)throw new J(`tvmaze ${F} must be <= ${q}`);return G}export async function tvmazeFetch(D,z){let q;try{q=await fetch(D,{headers:{"user-agent":Q,accept:"application/json"}})}catch(B){throw new K(`${z} request failed: ${B?.message??B}`,"Check that api.tvmaze.com is reachable from this network.")}if(q.status===404)throw new O(z,`TVmaze returned 404 for ${D}.`);if(q.status===429)throw new K(`${z} returned HTTP 429 (rate limited)`,"TVmaze caps unauthenticated traffic at ~20 req/10s; wait a few seconds and retry.");if(!q.ok)throw new K(`${z} returned HTTP ${q.status}`);let F;try{F=await q.json()}catch(B){throw new K(`${z} returned malformed JSON: ${B?.message??B}`)}return F}const S={amp:"&",lt:"<",gt:">",quot:'"',apos:"'",nbsp:" ",rsquo:"’",lsquo:"‘",rdquo:"”",ldquo:"“",hellip:"…",ndash:"–",mdash:"—"};export function stripHtml(D){if(D==null)return"";let z=String(D);z=z.replace(/<[^>]+>/g,"");z=z.replace(/&#x([0-9a-fA-F]+);/g,(q,F)=>{const B=parseInt(F,16);return Number.isFinite(B)?String.fromCodePoint(B):""}).replace(/&#(\d+);/g,(q,F)=>{const B=parseInt(F,10);return Number.isFinite(B)?String.fromCodePoint(B):""}).replace(/&([a-zA-Z]+);/g,(q,F)=>S[F]??q);return z.replace(/\s+/g," ").trim()}export function joinList(D){return Array.isArray(D)?D.filter(Boolean).join(", "):""}
1
+ import{ArgumentError as s,CommandExecutionError as a,EmptyResultError as u}from"@jackwener/opencli/errors";export const TVMAZE_BASE="https://api.tvmaze.com";const c="opencli-tvmaze-adapter (+https://github.com/jackwener/OpenCLI)";export function requireString(n,e){const t=String(n??"").trim();if(!t)throw new s(`tvmaze ${e} cannot be empty`);return t}export function requireShowId(n){const e=n,t=typeof e==="number"?e:Number(String(e??"").trim());if(!Number.isInteger(t)||t<=0)throw new s("tvmaze show id is required and must be a positive integer","TVmaze show ids appear in the URL: https://www.tvmaze.com/shows/<id>/<slug>.");return t}export function requireBoundedInt(n,e,t,o="limit"){const r=n??e,i=typeof r==="number"?r:Number(r);if(!Number.isInteger(i)||i<=0)throw new s(`tvmaze ${o} must be a positive integer`);if(i>t)throw new s(`tvmaze ${o} must be <= ${t}`);return i}export async function tvmazeFetch(n,e){let t;try{t=await fetch(n,{headers:{"user-agent":c,accept:"application/json"}})}catch(r){throw new a(`${e} request failed: ${r?.message??r}`,"Check that api.tvmaze.com is reachable from this network.")}if(t.status===404)throw new u(e,`TVmaze returned 404 for ${n}.`);if(t.status===429)throw new a(`${e} returned HTTP 429 (rate limited)`,"TVmaze caps unauthenticated traffic at ~20 req/10s; wait a few seconds and retry.");if(!t.ok)throw new a(`${e} returned HTTP ${t.status}`);let o;try{o=await t.json()}catch(r){throw new a(`${e} returned malformed JSON: ${r?.message??r}`)}return o}const m={amp:"&",lt:"<",gt:">",quot:'"',apos:"'",nbsp:" ",rsquo:"’",lsquo:"‘",rdquo:"”",ldquo:"“",hellip:"…",ndash:"–",mdash:"—"};export function stripHtml(n){if(n==null)return"";let e=String(n);e=e.replace(/<[^>]+>/g,"");e=e.replace(/&#x([0-9a-fA-F]+);/g,(t,o)=>{const r=parseInt(o,16);return Number.isFinite(r)?String.fromCodePoint(r):""}).replace(/&#(\d+);/g,(t,o)=>{const r=parseInt(o,10);return Number.isFinite(r)?String.fromCodePoint(r):""}).replace(/&([a-zA-Z]+);/g,(t,o)=>m[o]??t);return e.replace(/\s+/g," ").trim()}export function joinList(n){return Array.isArray(n)?n.filter(Boolean).join(", "):""}
@@ -1,4 +1,4 @@
1
- import{CommandExecutionError as V}from"@jackwener/opencli/errors";import{cli as W,Strategy as X}from"@jackwener/opencli/registry";W({site:"twitter",name:"accept",access:"write",description:"Auto-accept DM requests containing specific keywords",domain:"x.com",strategy:X.UI,browser:!0,args:[{name:"query",type:"string",required:!0,positional:!0,help:'Keywords to match (comma-separated for OR, e.g. "群,微信")'},{name:"max",type:"int",required:!1,default:20,help:"Maximum number of requests to accept (default: 20)"},{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(z,N)=>{if(!z)throw new V("Browser session required for twitter accept");const L=N.query.split(",").map((G)=>G.trim()).filter(Boolean),D=N.max??20,B=[];let F=0;const O=new Set;for(let G=0;G<D+50;G++){if(F>=D)break;await z.goto("https://x.com/messages/requests");await z.wait(4);const M=await z.evaluate(`(async () => {
1
+ import{CommandExecutionError as h}from"@jackwener/opencli/errors";import{cli as w,Strategy as y}from"@jackwener/opencli/registry";w({site:"twitter",name:"accept",access:"write",description:"Auto-accept DM requests containing specific keywords",domain:"x.com",strategy:y.UI,browser:!0,args:[{name:"query",type:"string",required:!0,positional:!0,help:'Keywords to match (comma-separated for OR, e.g. "群,微信")'},{name:"max",type:"int",required:!1,default:20,help:"Maximum number of requests to accept (default: 20)"},{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,u)=>{if(!e)throw new h("Browser session required for twitter accept");const a=u.query.split(",").map((r)=>r.trim()).filter(Boolean),n=u.max??20,t=[];let o=0;const l=new Set;for(let r=0;r<n+50;r++){if(o>=n)break;await e.goto("https://x.com/messages/requests");await e.wait(4);const i=await e.evaluate(`(async () => {
2
2
  try {
3
3
  // Wait for initial items
4
4
  let attempts = 0;
@@ -16,7 +16,7 @@ import{CommandExecutionError as V}from"@jackwener/opencli/errors";import{cli as
16
16
  const convs = Array.from(document.querySelectorAll('[data-testid="conversation"]'));
17
17
  const prevSize = seenCount.size;
18
18
  convs.forEach((_, i) => seenCount.add(i));
19
- if (convs.length >= ${D+10}) break;
19
+ if (convs.length >= ${n+10}) break;
20
20
 
21
21
  // Scroll last item into view
22
22
  if (convs.length > 0) {
@@ -47,10 +47,10 @@ import{CommandExecutionError as V}from"@jackwener/opencli/errors";import{cli as
47
47
  } catch(e) {
48
48
  return { ok: false, error: String(e), count: 0, items: [] };
49
49
  }
50
- })()`);if(!M?.ok||M.count===0){if(B.length===0)B.push({index:1,status:"info",user:"System",message:"No message requests found"});break}let P=!1;for(const H of M.items){if(F>=D)break;const Q=H.href||`conv-${H.idx}`;if(O.has(Q))continue;O.add(Q);if(!L.some((U)=>H.text.includes(U)))continue;if(!(await z.evaluate(`(async () => {
50
+ })()`);if(!i?.ok||i.count===0){if(t.length===0)t.push({index:1,status:"info",user:"System",message:"No message requests found"});break}let m=!1;for(const s of i.items){if(o>=n)break;const d=s.href||`conv-${s.idx}`;if(l.has(d))continue;l.add(d);if(!a.some((f)=>s.text.includes(f)))continue;if(!(await e.evaluate(`(async () => {
51
51
  try {
52
52
  const convs = Array.from(document.querySelectorAll('[data-testid="conversation"]'));
53
- const conv = convs[${H.idx}];
53
+ const conv = convs[${s.idx}];
54
54
  if (!conv) return { ok: false, error: 'Conversation element not found' };
55
55
  conv.click();
56
56
  await new Promise(r => setTimeout(r, 2000));
@@ -58,9 +58,9 @@ import{CommandExecutionError as V}from"@jackwener/opencli/errors";import{cli as
58
58
  } catch(e) {
59
59
  return { ok: false, error: String(e) };
60
60
  }
61
- })()`))?.ok)continue;await z.wait(2);const J=await z.evaluate(`(async () => {
61
+ })()`))?.ok)continue;await e.wait(2);const c=await e.evaluate(`(async () => {
62
62
  try {
63
- const keywords = ${JSON.stringify(L)};
63
+ const keywords = ${JSON.stringify(a)};
64
64
 
65
65
  // Get username from conversation header
66
66
  const heading = document.querySelector('[data-testid="conversation-header"]') ||
@@ -113,4 +113,4 @@ import{CommandExecutionError as V}from"@jackwener/opencli/errors";import{cli as
113
113
  } catch(e) {
114
114
  return { status: 'error', user: 'system', message: String(e) };
115
115
  }
116
- })()`);if(J?.status==="accepted"){F++;P=!0;B.push({index:F,status:"accepted",user:J.user||"Unknown",message:J.message||"Accepted"});await z.wait(2);break}else if(J?.status==="no_button")continue}if(!P)break}if(B.length===0)B.push({index:0,status:"info",user:"System",message:`No requests matched keywords "${L.join(", ")}"`});return B}});
116
+ })()`);if(c?.status==="accepted"){o++;m=!0;t.push({index:o,status:"accepted",user:c.user||"Unknown",message:c.message||"Accepted"});await e.wait(2);break}else if(c?.status==="no_button")continue}if(!m)break}if(t.length===0)t.push({index:0,status:"info",user:"System",message:`No requests matched keywords "${a.join(", ")}"`});return t}});
@@ -1,4 +1,4 @@
1
- import{AuthRequiredError as Z,CommandExecutionError as H}from"@jackwener/opencli/errors";import{cli as N,Strategy as P}from"@jackwener/opencli/registry";import{resolveTwitterQueryId as b,describeTwitterApiError as k,unwrapBrowserResult as $}from"./shared.js";import{TWITTER_BEARER_TOKEN as B}from"./utils.js";const D="7xflPyRiUxGVbJd4uWmbfg";function M(f){return Boolean(f&&typeof f==="object"&&!Array.isArray(f))}N({site:"twitter",name:"article",access:"read",description:"Fetch a Twitter Article (long-form content) and export as Markdown",domain:"x.com",strategy:P.COOKIE,browser:!0,args:[{name:"tweet-id",type:"string",positional:!0,required:!0,help:"Tweet ID or URL containing the article"}],columns:["title","author","content","url"],func:async(f,j)=>{let F=j["tweet-id"];const K=/\/article\/\d+/.test(F),V=F.match(/\/(?:status|article)\/(\d+)/);if(V)F=V[1];if(K){await f.goto(`https://x.com/i/article/${F}`);await f.wait(3);const G=await f.evaluate(`
1
+ import{AuthRequiredError as l,CommandExecutionError as s}from"@jackwener/opencli/errors";import{cli as f,Strategy as p}from"@jackwener/opencli/registry";import{resolveTwitterQueryId as m,describeTwitterApiError as y,unwrapBrowserResult as c}from"./shared.js";import{TWITTER_BEARER_TOKEN as h}from"./utils.js";const T="7xflPyRiUxGVbJd4uWmbfg";function b(e){return Boolean(e&&typeof e==="object"&&!Array.isArray(e))}f({site:"twitter",name:"article",access:"read",description:"Fetch a Twitter Article (long-form content) and export as Markdown",domain:"x.com",strategy:p.COOKIE,browser:!0,args:[{name:"tweet-id",type:"string",positional:!0,required:!0,help:"Tweet ID or URL containing the article"}],columns:["title","author","content","url"],func:async(e,u)=>{let r=u["tweet-id"];const d=/\/article\/\d+/.test(r),i=r.match(/\/(?:status|article)\/(\d+)/);if(i)r=i[1];if(d){await e.goto(`https://x.com/i/article/${r}`);await e.wait(3);const o=await e.evaluate(`
2
2
  (function() {
3
3
  var links = document.querySelectorAll('a[href*="/status/"]');
4
4
  for (var i = 0; i < links.length; i++) {
@@ -12,12 +12,12 @@ import{AuthRequiredError as Z,CommandExecutionError as H}from"@jackwener/opencli
12
12
  }
13
13
  return null;
14
14
  })()
15
- `),J=$(G);if(!J||typeof J!=="string")throw new H(`Could not resolve article ${F} to a tweet ID. The article page may not contain a linked tweet.`);F=J}await f.goto(`https://x.com/i/status/${F}`);await f.wait(3);const X=(await f.getCookies({url:"https://x.com"})).find((G)=>G.name==="ct0")?.value||null;if(!X)throw new Z("x.com","Not logged into x.com (no ct0 cookie)");const L=await b(f,"TweetResultByRestId",D),z=$(await f.evaluate(`
15
+ `),n=c(o);if(!n||typeof n!=="string")throw new s(`Could not resolve article ${r} to a tweet ID. The article page may not contain a linked tweet.`);r=n}await e.goto(`https://x.com/i/status/${r}`);await e.wait(3);const a=(await e.getCookies({url:"https://x.com"})).find((o)=>o.name==="ct0")?.value||null;if(!a)throw new l("x.com","Not logged into x.com (no ct0 cookie)");const w=await m(e,"TweetResultByRestId",T),t=c(await e.evaluate(`
16
16
  async () => {
17
- const tweetId = ${JSON.stringify(F)};
18
- const ct0 = ${JSON.stringify(X)};
17
+ const tweetId = ${JSON.stringify(r)};
18
+ const ct0 = ${JSON.stringify(a)};
19
19
 
20
- const bearer = ${JSON.stringify(B)};
20
+ const bearer = ${JSON.stringify(h)};
21
21
  const headers = {
22
22
  'Authorization': 'Bearer ' + decodeURIComponent(bearer),
23
23
  'X-Csrf-Token': ct0,
@@ -45,7 +45,7 @@ import{AuthRequiredError as Z,CommandExecutionError as H}from"@jackwener/opencli
45
45
  withArticlePlainText: true,
46
46
  });
47
47
 
48
- const url = '/i/api/graphql/' + ${JSON.stringify(L)} + '/TweetResultByRestId?variables='
48
+ const url = '/i/api/graphql/' + ${JSON.stringify(w)} + '/TweetResultByRestId?variables='
49
49
  + encodeURIComponent(variables)
50
50
  + '&features=' + encodeURIComponent(features)
51
51
  + '&fieldToggles=' + encodeURIComponent(fieldToggles);
@@ -154,4 +154,4 @@ import{AuthRequiredError as Z,CommandExecutionError as H}from"@jackwener/opencli
154
154
  url: 'https://x.com/' + screenName + '/status/' + tweetId,
155
155
  }];
156
156
  }
157
- `));if(!Array.isArray(z)&&!M(z))throw new H("Twitter article response payload is malformed");if(z?.httpStatus){const G=k("TweetResultByRestId",z.httpStatus);if(z.httpStatus===401||z.httpStatus===403)throw new Z("x.com",G);throw new H(G)}if(z?.error)throw new H(z.error+(z.hint?` (${z.hint})`:""));if(!Array.isArray(z))throw new H("Twitter article response payload is malformed");return z}});
157
+ `));if(!Array.isArray(t)&&!b(t))throw new s("Twitter article response payload is malformed");if(t?.httpStatus){const o=y("TweetResultByRestId",t.httpStatus);if(t.httpStatus===401||t.httpStatus===403)throw new l("x.com",o);throw new s(o)}if(t?.error)throw new s(t.error+(t.hint?` (${t.hint})`:""));if(!Array.isArray(t))throw new s("Twitter article response payload is malformed");return t}});
@@ -1,4 +1,4 @@
1
- import{cli as U,Strategy as P}from"@jackwener/opencli/registry";import{ArgumentError as S,AuthRequiredError as f,CommandExecutionError as O}from"@jackwener/opencli/errors";import{TWITTER_BEARER_TOKEN as C,applyTopByEngagement as F}from"./utils.js";import{extractMedia as N,resolveTwitterQueryId as _,describeTwitterApiError as R}from"./shared.js";const j="BookmarkFolderTimeline",x="13H7EUATwethsj_jZ6QQAQ",q=/^[A-Za-z0-9_-]+$/,k=100,p={rweb_video_screen_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,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,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,tweet_awards_web_tipping_enabled:!1,content_disclosure_indicator_enabled:!0,content_disclosure_ai_generated_indicator_enabled:!0,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:!1,responsive_web_enhance_cards_enabled:!1};function L(J,V,z,H){const $={bookmark_collection_id:String(V),count:z,includePromotedContent:!1};if(H)$.cursor=H;return`/i/api/graphql/${J}/${j}?variables=${encodeURIComponent(JSON.stringify($))}&features=${encodeURIComponent(JSON.stringify(p))}`}export function extractFolderTweet(J,V){if(!J)return null;const z=J.tweet||J,H=z.legacy||{};if(!z.rest_id||V.has(z.rest_id))return null;V.add(z.rest_id);const $=z.core?.user_results?.result,W=$?.legacy?.screen_name||$?.core?.screen_name||"",Y=z.note_tweet?.note_tweet_results?.result?.text;return{id:z.rest_id,author:W,text:Y||H.full_text||"",likes:H.favorite_count||0,retweets:H.retweet_count||0,bookmarks:H.bookmark_count||0,created_at:H.created_at||"",url:W?`https://x.com/${W}/status/${z.rest_id}`:`https://x.com/i/status/${z.rest_id}`,...N(H)}}export function parseBookmarkFolderTimeline(J,V){const z=[];let H=null;const $=J?.data?.bookmark_collection_timeline?.timeline?.instructions||J?.data?.bookmark_timeline_v2?.timeline?.instructions||J?.data?.bookmark_timeline?.timeline?.instructions||[];for(const W of $)for(const Y of W.entries||[]){const Z=Y.content;if(Z?.entryType==="TimelineTimelineCursor"||Z?.__typename==="TimelineTimelineCursor"){if(Z.cursorType==="Bottom"||Z.cursorType==="ShowMore")H=Z.value;continue}if(Y.entryId?.startsWith("cursor-bottom-")||Y.entryId?.startsWith("cursor-showMore-")){H=Z?.value||Z?.itemContent?.value||H;continue}const X=extractFolderTweet(Z?.itemContent?.tweet_results?.result,V);if(X){z.push(X);continue}for(const Q of Z?.items||[]){const G=extractFolderTweet(Q.item?.itemContent?.tweet_results?.result,V);if(G)z.push(G)}}return{tweets:z,nextCursor:H}}U({site:"twitter",name:"bookmark-folder",access:"read",description:"Read the tweets inside a single Twitter/X bookmark folder. Get the folder id from `ppcli twitter bookmark-folders`.",domain:"x.com",strategy:P.COOKIE,browser:!0,args:[{name:"folder-id",positional:!0,type:"string",required:!0,help:"Folder id from `ppcli twitter bookmark-folders`."},{name:"limit",type:"int",default:20,help:"Maximum number of bookmarks to return (default 20)."},{name:"top-by-engagement",type:"int",default:0,help:"When set to N>0, re-rank the folder by weighted engagement (likes×1 + retweets×3 + replies×2 + bookmarks×5 + log10(views+1)×0.5) and return the top N. Default 0 keeps the API's native (saved-time) ordering."}],columns:["id","author","text","likes","retweets","bookmarks","created_at","url","has_media","media_urls","media_posters"],func:async(J,V)=>{const z=String(V["folder-id"]||"").trim();if(!z||!q.test(z))throw new S(`Invalid folder-id: ${JSON.stringify(V["folder-id"])}. Expected a safe folder ID from \`ppcli twitter bookmark-folders\`.`);const H=Number(V.limit??20);if(!Number.isInteger(H)||H<1)throw new S(`Invalid --limit: ${JSON.stringify(V.limit)}. Expected a positive integer.`);const W=(await J.getCookies({url:"https://x.com"})).find((K)=>K.name==="ct0")?.value||null;if(!W)throw new f("x.com","Not logged into x.com (no ct0 cookie)");const Y=await _(J,j,x),Z=JSON.stringify({Authorization:`Bearer ${decodeURIComponent(C)}`,"X-Csrf-Token":W,"X-Twitter-Auth-Type":"OAuth2Session","X-Twitter-Active-User":"yes"}),X=[],Q=new Set;let G=null;for(let K=0;K<k&&X.length<H;K++){const h=Math.min(100,H-X.length+10),B=L(Y,z,h,G),b=await J.evaluate(`async () => {
2
- const r = await fetch(${JSON.stringify(B)}, { headers: ${Z}, credentials: 'include' });
1
+ import{cli as v,Strategy as T}from"@jackwener/opencli/registry";import{ArgumentError as f,AuthRequiredError as x,CommandExecutionError as A}from"@jackwener/opencli/errors";import{TWITTER_BEARER_TOKEN as E,applyTopByEngagement as I}from"./utils.js";import{extractMedia as N,resolveTwitterQueryId as C,describeTwitterApiError as O}from"./shared.js";const p="BookmarkFolderTimeline",S="13H7EUATwethsj_jZ6QQAQ",b=/^[A-Za-z0-9_-]+$/,R=100,F={rweb_video_screen_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,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,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,tweet_awards_web_tipping_enabled:!1,content_disclosure_indicator_enabled:!0,content_disclosure_ai_generated_indicator_enabled:!0,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:!1,responsive_web_enhance_cards_enabled:!1};function w(r,o,e,t){const i={bookmark_collection_id:String(o),count:e,includePromotedContent:!1};if(t)i.cursor=t;return`/i/api/graphql/${r}/${p}?variables=${encodeURIComponent(JSON.stringify(i))}&features=${encodeURIComponent(JSON.stringify(F))}`}export function extractFolderTweet(r,o){if(!r)return null;const e=r.tweet||r,t=e.legacy||{};if(!e.rest_id||o.has(e.rest_id))return null;o.add(e.rest_id);const i=e.core?.user_results?.result,s=i?.legacy?.screen_name||i?.core?.screen_name||"",l=e.note_tweet?.note_tweet_results?.result?.text;return{id:e.rest_id,author:s,text:l||t.full_text||"",likes:t.favorite_count||0,retweets:t.retweet_count||0,bookmarks:t.bookmark_count||0,created_at:t.created_at||"",url:s?`https://x.com/${s}/status/${e.rest_id}`:`https://x.com/i/status/${e.rest_id}`,...N(t)}}export function parseBookmarkFolderTimeline(r,o){const e=[];let t=null;const i=r?.data?.bookmark_collection_timeline?.timeline?.instructions||r?.data?.bookmark_timeline_v2?.timeline?.instructions||r?.data?.bookmark_timeline?.timeline?.instructions||[];for(const s of i)for(const l of s.entries||[]){const n=l.content;if(n?.entryType==="TimelineTimelineCursor"||n?.__typename==="TimelineTimelineCursor"){if(n.cursorType==="Bottom"||n.cursorType==="ShowMore")t=n.value;continue}if(l.entryId?.startsWith("cursor-bottom-")||l.entryId?.startsWith("cursor-showMore-")){t=n?.value||n?.itemContent?.value||t;continue}const a=extractFolderTweet(n?.itemContent?.tweet_results?.result,o);if(a){e.push(a);continue}for(const d of n?.items||[]){const _=extractFolderTweet(d.item?.itemContent?.tweet_results?.result,o);if(_)e.push(_)}}return{tweets:e,nextCursor:t}}v({site:"twitter",name:"bookmark-folder",access:"read",description:"Read the tweets inside a single Twitter/X bookmark folder. Get the folder id from `ppcli twitter bookmark-folders`.",domain:"x.com",strategy:T.COOKIE,browser:!0,args:[{name:"folder-id",positional:!0,type:"string",required:!0,help:"Folder id from `ppcli twitter bookmark-folders`."},{name:"limit",type:"int",default:20,help:"Maximum number of bookmarks to return (default 20)."},{name:"top-by-engagement",type:"int",default:0,help:"When set to N>0, re-rank the folder by weighted engagement (likes×1 + retweets×3 + replies×2 + bookmarks×5 + log10(views+1)×0.5) and return the top N. Default 0 keeps the API's native (saved-time) ordering."}],columns:["id","author","text","likes","retweets","bookmarks","created_at","url","has_media","media_urls","media_posters"],func:async(r,o)=>{const e=String(o["folder-id"]||"").trim();if(!e||!b.test(e))throw new f(`Invalid folder-id: ${JSON.stringify(o["folder-id"])}. Expected a safe folder ID from \`ppcli twitter bookmark-folders\`.`);const t=Number(o.limit??20);if(!Number.isInteger(t)||t<1)throw new f(`Invalid --limit: ${JSON.stringify(o.limit)}. Expected a positive integer.`);const s=(await r.getCookies({url:"https://x.com"})).find((c)=>c.name==="ct0")?.value||null;if(!s)throw new x("x.com","Not logged into x.com (no ct0 cookie)");const l=await C(r,p,S),n=JSON.stringify({Authorization:`Bearer ${decodeURIComponent(E)}`,"X-Csrf-Token":s,"X-Twitter-Auth-Type":"OAuth2Session","X-Twitter-Active-User":"yes"}),a=[],d=new Set;let _=null;for(let c=0;c<R&&a.length<t;c++){const g=Math.min(100,t-a.length+10),k=w(l,e,g,_),u=await r.evaluate(`async () => {
2
+ const r = await fetch(${JSON.stringify(k)}, { headers: ${n}, credentials: 'include' });
3
3
  return r.ok ? await r.json() : { error: r.status };
4
- }`);if(b?.error){if(X.length===0)throw new O(R("BookmarkFolderTimeline",b.error,`folder=${z}`));break}const{tweets:D,nextCursor:v}=parseBookmarkFolderTimeline(b,Q);X.push(...D);if(!v||v===G)break;G=v}const M=X.slice(0,H);return F(M,V["top-by-engagement"])}});export const __test__={parseBookmarkFolderTimeline,extractFolderTweet,buildFolderTimelineUrl:L,FOLDER_ID_PATTERN:q};
4
+ }`);if(u?.error){if(a.length===0)throw new A(O("BookmarkFolderTimeline",u.error,`folder=${e}`));break}const{tweets:y,nextCursor:m}=parseBookmarkFolderTimeline(u,d);a.push(...y);if(!m||m===_)break;_=m}const h=a.slice(0,t);return I(h,o["top-by-engagement"])}});export const __test__={parseBookmarkFolderTimeline,extractFolderTweet,buildFolderTimelineUrl:w,FOLDER_ID_PATTERN:b};
@@ -1,4 +1,4 @@
1
- import{cli as K,Strategy as L}from"@jackwener/opencli/registry";import{AuthRequiredError as M,CommandExecutionError as P}from"@jackwener/opencli/errors";import{TWITTER_BEARER_TOKEN as Q}from"./utils.js";import{resolveTwitterQueryId as S,describeTwitterApiError as C}from"./shared.js";const D="bookmarkFoldersSlice",j="i78YDd0Tza-dWKw5H2Y7WA",B={rweb_tipjar_consumption_enabled:!1,responsive_web_graphql_exclude_directive_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};function W(G){const J=JSON.stringify({});return`/i/api/graphql/${G}/${D}?variables=${encodeURIComponent(J)}&features=${encodeURIComponent(JSON.stringify(B))}`}export function parseBookmarkFolders(G,J){const V=[],Z=G?.data?.viewer?.bookmark_collections_slice||G?.data?.viewer_v2?.user_results?.result?.bookmark_collections_slice||G?.data?.bookmark_collections_slice||null,$=Z?.items||Z?.timeline?.timeline?.instructions?.flatMap?.((H)=>H.entries||[])||[];for(const H of $){const z=H?.bookmarkCollection||H?.content?.bookmarkCollection||H?.content?.itemContent?.bookmark_collection||H,X=z?.id_str||z?.id||z?.rest_id||"";if(!X||J.has(X))continue;J.add(X);const x=z?.name||z?.collection_name||"",Y=Number(z?.bookmarks_count??z?.items_count??z?.count??0)||0,v=z?.created_at||z?.timestamp_ms||"";V.push({id:String(X),name:String(x),items:Y,created_at:String(v)})}return V}K({site:"twitter",name:"bookmark-folders",access:"read",description:"List your Twitter/X bookmark folders (the user-created collections under Bookmarks). Returns folder id, name, item count, and created_at.",domain:"x.com",strategy:L.COOKIE,browser:!0,args:[],columns:["id","name","items","created_at"],func:async(G)=>{const V=(await G.getCookies({url:"https://x.com"})).find((x)=>x.name==="ct0")?.value||null;if(!V)throw new M("x.com","Not logged into x.com (no ct0 cookie)");const Z=await S(G,D,j),$=JSON.stringify({Authorization:`Bearer ${decodeURIComponent(Q)}`,"X-Csrf-Token":V,"X-Twitter-Auth-Type":"OAuth2Session","X-Twitter-Active-User":"yes"}),H=W(Z),z=await G.evaluate(`async () => {
2
- const r = await fetch(${JSON.stringify(H)}, { headers: ${$}, credentials: 'include' });
1
+ import{cli as u,Strategy as k}from"@jackwener/opencli/registry";import{AuthRequiredError as f,CommandExecutionError as p}from"@jackwener/opencli/errors";import{TWITTER_BEARER_TOKEN as b}from"./utils.js";import{resolveTwitterQueryId as w,describeTwitterApiError as h}from"./shared.js";const l="bookmarkFoldersSlice",g="i78YDd0Tza-dWKw5H2Y7WA",v={rweb_tipjar_consumption_enabled:!1,responsive_web_graphql_exclude_directive_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};function m(t){const r=JSON.stringify({});return`/i/api/graphql/${t}/${l}?variables=${encodeURIComponent(r)}&features=${encodeURIComponent(JSON.stringify(v))}`}export function parseBookmarkFolders(t,r){const n=[],s=t?.data?.viewer?.bookmark_collections_slice||t?.data?.viewer_v2?.user_results?.result?.bookmark_collections_slice||t?.data?.bookmark_collections_slice||null,a=s?.items||s?.timeline?.timeline?.instructions?.flatMap?.((o)=>o.entries||[])||[];for(const o of a){const e=o?.bookmarkCollection||o?.content?.bookmarkCollection||o?.content?.itemContent?.bookmark_collection||o,i=e?.id_str||e?.id||e?.rest_id||"";if(!i||r.has(i))continue;r.add(i);const c=e?.name||e?.collection_name||"",d=Number(e?.bookmarks_count??e?.items_count??e?.count??0)||0,_=e?.created_at||e?.timestamp_ms||"";n.push({id:String(i),name:String(c),items:d,created_at:String(_)})}return n}u({site:"twitter",name:"bookmark-folders",access:"read",description:"List your Twitter/X bookmark folders (the user-created collections under Bookmarks). Returns folder id, name, item count, and created_at.",domain:"x.com",strategy:k.COOKIE,browser:!0,args:[],columns:["id","name","items","created_at"],func:async(t)=>{const n=(await t.getCookies({url:"https://x.com"})).find((c)=>c.name==="ct0")?.value||null;if(!n)throw new f("x.com","Not logged into x.com (no ct0 cookie)");const s=await w(t,l,g),a=JSON.stringify({Authorization:`Bearer ${decodeURIComponent(b)}`,"X-Csrf-Token":n,"X-Twitter-Auth-Type":"OAuth2Session","X-Twitter-Active-User":"yes"}),o=m(s),e=await t.evaluate(`async () => {
2
+ const r = await fetch(${JSON.stringify(o)}, { headers: ${a}, credentials: 'include' });
3
3
  return r.ok ? await r.json() : { error: r.status };
4
- }`);if(z?.error)throw new P(C("bookmarkFoldersSlice",z.error,"account may not have folder access"));return parseBookmarkFolders(z,new Set)}});export const __test__={parseBookmarkFolders,buildUrl:W};
4
+ }`);if(e?.error)throw new p(h("bookmarkFoldersSlice",e.error,"account may not have folder access"));return parseBookmarkFolders(e,new Set)}});export const __test__={parseBookmarkFolders,buildUrl:m};
@@ -1,4 +1,4 @@
1
- import{cli as Y,Strategy as j}from"@jackwener/opencli/registry";import{AuthRequiredError as h,CommandExecutionError as M}from"@jackwener/opencli/errors";import{extractMedia as N,describeTwitterApiError as S}from"./shared.js";import{TWITTER_BEARER_TOKEN as U,applyTopByEngagement as I}from"./utils.js";const G="Fy0QMy4q_aZCpkO0PnyLYw",K=100,O={rweb_video_screen_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,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,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,tweet_awards_web_tipping_enabled:!1,content_disclosure_indicator_enabled:!0,content_disclosure_ai_generated_indicator_enabled:!0,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:!1,responsive_web_enhance_cards_enabled:!1};function C(J,V){const z={count:J,includePromotedContent:!1};if(V)z.cursor=V;return`/i/api/graphql/${G}/Bookmarks?variables=${encodeURIComponent(JSON.stringify(z))}&features=${encodeURIComponent(JSON.stringify(O))}`}export function extractBookmarkTweet(J,V){if(!J)return null;const z=J.tweet||J,L=z.legacy||{};if(!z.rest_id||V.has(z.rest_id))return null;V.add(z.rest_id);const Z=z.core?.user_results?.result,f=Z?.legacy?.screen_name||Z?.core?.screen_name||"unknown",$=Z?.legacy?.name||Z?.core?.name||"",H=z.note_tweet?.note_tweet_results?.result?.text;return{id:z.rest_id,author:f,name:$,text:H||L.full_text||"",likes:L.favorite_count||0,retweets:L.retweet_count||0,bookmarks:L.bookmark_count||0,created_at:L.created_at||"",url:`https://x.com/${f}/status/${z.rest_id}`,...N(L)}}export function parseBookmarks(J,V){const z=[];let L=null;const Z=J?.data?.bookmark_timeline_v2?.timeline?.instructions||J?.data?.bookmark_timeline?.timeline?.instructions||[];for(const f of Z)for(const $ of f.entries||[]){const H=$.content;if(H?.entryType==="TimelineTimelineCursor"||H?.__typename==="TimelineTimelineCursor"){if(H.cursorType==="Bottom"||H.cursorType==="ShowMore")L=H.value;continue}if($.entryId?.startsWith("cursor-bottom-")||$.entryId?.startsWith("cursor-showMore-")){L=H?.value||H?.itemContent?.value||L;continue}const W=extractBookmarkTweet(H?.itemContent?.tweet_results?.result,V);if(W){z.push(W);continue}for(const F of H?.items||[]){const X=extractBookmarkTweet(F.item?.itemContent?.tweet_results?.result,V);if(X)z.push(X)}}return{tweets:z,nextCursor:L}}Y({site:"twitter",name:"bookmarks",access:"read",description:"Fetch your Twitter/X bookmarks (the logged-in user's saved tweets, newest first)",domain:"x.com",strategy:j.COOKIE,browser:!0,args:[{name:"limit",type:"int",default:20,help:"Maximum number of bookmarks to return (default 20)."},{name:"top-by-engagement",type:"int",default:0,help:"When set to N>0, re-rank the bookmarks by weighted engagement (likes×1 + retweets×3 + replies×2 + bookmarks×5 + log10(views+1)×0.5) and return the top N. Default 0 keeps the API's native (saved-time) ordering."}],columns:["id","author","text","likes","retweets","bookmarks","created_at","url","has_media","media_urls","media_posters"],func:async(J,V)=>{const z=V.limit||20,Z=(await J.getCookies({url:"https://x.com"})).find((b)=>b.name==="ct0")?.value||null;if(!Z)throw new h("x.com","Not logged into x.com (no ct0 cookie)");const f=await J.evaluate(`async () => {
1
+ import{cli as h,Strategy as y}from"@jackwener/opencli/registry";import{AuthRequiredError as k,CommandExecutionError as g}from"@jackwener/opencli/errors";import{extractMedia as v,describeTwitterApiError as x}from"./shared.js";import{TWITTER_BEARER_TOKEN as T,applyTopByEngagement as C}from"./utils.js";const p="Fy0QMy4q_aZCpkO0PnyLYw",A=100,E={rweb_video_screen_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,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,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,tweet_awards_web_tipping_enabled:!1,content_disclosure_indicator_enabled:!0,content_disclosure_ai_generated_indicator_enabled:!0,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:!1,responsive_web_enhance_cards_enabled:!1};function I(r,o){const e={count:r,includePromotedContent:!1};if(o)e.cursor=o;return`/i/api/graphql/${p}/Bookmarks?variables=${encodeURIComponent(JSON.stringify(e))}&features=${encodeURIComponent(JSON.stringify(E))}`}export function extractBookmarkTweet(r,o){if(!r)return null;const e=r.tweet||r,n=e.legacy||{};if(!e.rest_id||o.has(e.rest_id))return null;o.add(e.rest_id);const s=e.core?.user_results?.result,a=s?.legacy?.screen_name||s?.core?.screen_name||"unknown",i=s?.legacy?.name||s?.core?.name||"",t=e.note_tweet?.note_tweet_results?.result?.text;return{id:e.rest_id,author:a,name:i,text:t||n.full_text||"",likes:n.favorite_count||0,retweets:n.retweet_count||0,bookmarks:n.bookmark_count||0,created_at:n.created_at||"",url:`https://x.com/${a}/status/${e.rest_id}`,...v(n)}}export function parseBookmarks(r,o){const e=[];let n=null;const s=r?.data?.bookmark_timeline_v2?.timeline?.instructions||r?.data?.bookmark_timeline?.timeline?.instructions||[];for(const a of s)for(const i of a.entries||[]){const t=i.content;if(t?.entryType==="TimelineTimelineCursor"||t?.__typename==="TimelineTimelineCursor"){if(t.cursorType==="Bottom"||t.cursorType==="ShowMore")n=t.value;continue}if(i.entryId?.startsWith("cursor-bottom-")||i.entryId?.startsWith("cursor-showMore-")){n=t?.value||t?.itemContent?.value||n;continue}const _=extractBookmarkTweet(t?.itemContent?.tweet_results?.result,o);if(_){e.push(_);continue}for(const c of t?.items||[]){const l=extractBookmarkTweet(c.item?.itemContent?.tweet_results?.result,o);if(l)e.push(l)}}return{tweets:e,nextCursor:n}}h({site:"twitter",name:"bookmarks",access:"read",description:"Fetch your Twitter/X bookmarks (the logged-in user's saved tweets, newest first)",domain:"x.com",strategy:y.COOKIE,browser:!0,args:[{name:"limit",type:"int",default:20,help:"Maximum number of bookmarks to return (default 20)."},{name:"top-by-engagement",type:"int",default:0,help:"When set to N>0, re-rank the bookmarks by weighted engagement (likes×1 + retweets×3 + replies×2 + bookmarks×5 + log10(views+1)×0.5) and return the top N. Default 0 keeps the API's native (saved-time) ordering."}],columns:["id","author","text","likes","retweets","bookmarks","created_at","url","has_media","media_urls","media_posters"],func:async(r,o)=>{const e=o.limit||20,s=(await r.getCookies({url:"https://x.com"})).find((u)=>u.name==="ct0")?.value||null;if(!s)throw new k("x.com","Not logged into x.com (no ct0 cookie)");const a=await r.evaluate(`async () => {
2
2
  try {
3
3
  const ghResp = await fetch('https://raw.githubusercontent.com/fa0311/twitter-openapi/refs/heads/main/src/config/placeholder.json');
4
4
  if (ghResp.ok) {
@@ -21,7 +21,7 @@ import{cli as Y,Strategy as j}from"@jackwener/opencli/registry";import{AuthRequi
21
21
  }
22
22
  } catch {}
23
23
  return null;
24
- }`)||G,$=JSON.stringify({Authorization:`Bearer ${decodeURIComponent(U)}`,"X-Csrf-Token":Z,"X-Twitter-Auth-Type":"OAuth2Session","X-Twitter-Active-User":"yes"}),H=[],W=new Set;let F=null;for(let b=0;b<K&&H.length<z;b++){const P=Math.min(100,z-H.length+10),D=C(P,F).replace(G,f),q=await J.evaluate(`async () => {
25
- const r = await fetch("${D}", { headers: ${$}, credentials: 'include' });
24
+ }`)||p,i=JSON.stringify({Authorization:`Bearer ${decodeURIComponent(T)}`,"X-Csrf-Token":s,"X-Twitter-Auth-Type":"OAuth2Session","X-Twitter-Active-User":"yes"}),t=[],_=new Set;let c=null;for(let u=0;u<A&&t.length<e;u++){const f=Math.min(100,e-t.length+10),w=I(f,c).replace(p,a),m=await r.evaluate(`async () => {
25
+ const r = await fetch("${w}", { headers: ${i}, credentials: 'include' });
26
26
  return r.ok ? await r.json() : { error: r.status };
27
- }`);if(q?.error){if(H.length===0)throw new M(S("Bookmarks",q.error));break}const{tweets:Q,nextCursor:v}=parseBookmarks(q,W);H.push(...Q);if(!v||v===F)break;F=v}const X=H.slice(0,z);return I(X,V["top-by-engagement"])}});export const __test__={parseBookmarks,extractBookmarkTweet};
27
+ }`);if(m?.error){if(t.length===0)throw new g(x("Bookmarks",m.error));break}const{tweets:b,nextCursor:d}=parseBookmarks(m,_);t.push(...b);if(!d||d===c)break;c=d}const l=t.slice(0,e);return C(l,o["top-by-engagement"])}});export const __test__={parseBookmarks,extractBookmarkTweet};
@@ -1,7 +1,7 @@
1
- import{cli as Y,Strategy as Z}from"@jackwener/opencli/registry";import{CommandExecutionError as _}from"@jackwener/opencli/errors";import{parseTweetUrl as $,buildTwitterArticleScopeSource as q}from"./shared.js";function O(z){return`(() => {
1
+ import{cli as y,Strategy as g}from"@jackwener/opencli/registry";import{CommandExecutionError as h}from"@jackwener/opencli/errors";import{parseTweetUrl as b,buildTwitterArticleScopeSource as A}from"./shared.js";function a(t){return`(() => {
2
2
  try {
3
3
  const visible = (el) => !!el && (el.offsetParent !== null || el.getClientRects().length > 0);
4
- ${q(z)}
4
+ ${A(t)}
5
5
  const targetArticle = findTargetArticle();
6
6
  if (!targetArticle) return { article: false, found: false };
7
7
  let moreMenu = Array.from(targetArticle.querySelectorAll('[data-testid="caret"]')).find(visible);
@@ -13,7 +13,7 @@ import{cli as Y,Strategy as Z}from"@jackwener/opencli/registry";import{CommandEx
13
13
  moreMenu.click();
14
14
  return { article: true, found: true };
15
15
  } catch (e) { return { article: false, found: false }; }
16
- })()`}function P(){return`(() => {
16
+ })()`}function c(){return`(() => {
17
17
  try {
18
18
  const items = Array.from(document.querySelectorAll('[role="menuitem"]'));
19
19
  const deleteBtn = items.find((item) => {
@@ -26,11 +26,11 @@ import{cli as Y,Strategy as Z}from"@jackwener/opencli/registry";import{CommandEx
26
26
  deleteBtn.click();
27
27
  return { found: true };
28
28
  } catch (e) { return { found: false }; }
29
- })()`}function Q(){return`(() => {
29
+ })()`}function d(){return`(() => {
30
30
  try {
31
31
  const confirmBtn = document.querySelector('[data-testid="confirmationSheetConfirm"]');
32
32
  if (!confirmBtn) return { found: false };
33
33
  confirmBtn.click();
34
34
  return { found: true };
35
35
  } catch (e) { return { found: false }; }
36
- })()`}Y({site:"twitter",name:"delete",access:"write",description:"Delete a specific tweet by URL",domain:"x.com",strategy:Z.UI,browser:!0,args:[{name:"url",type:"string",required:!0,positional:!0,help:"The URL of the tweet to delete"}],columns:["status","message"],func:async(z,R)=>{if(!z)throw new _("Browser session required for twitter delete");const J=$(R.url);await z.goto(J.url);await z.wait({selector:'[data-testid="primaryColumn"]'});const H=async(v,V,X=12)=>{let G;for(let N=0;N<X;N++){G=await z.evaluate(v);if(V(G))return G;await z.wait(0.5)}return G},B=await H(O(J.id),(v)=>!!(v&&v.found));if(!B||!B.found){if(B&&B.article===!1)return[{status:"failed",message:"Could not find the tweet card matching the requested URL."}];return[{status:"failed",message:'Could not find the "More" context menu on the matched tweet. Are you sure you are logged in and looking at a valid tweet?'}]}const K=await H(P(),(v)=>!!(v&&v.found));if(!K||!K.found)return[{status:"failed",message:"The matched tweet menu did not contain Delete. This tweet may not belong to you."}];const L=await H(Q(),(v)=>!!(v&&v.found));if(!L||!L.found)return[{status:"failed",message:"Delete confirmation dialog did not appear."}];await z.wait(2);return[{status:"success",message:"Tweet successfully deleted."}]}});export const __test__={buildFindAndClickMoreScript:O,buildClickDeleteScript:P,buildClickConfirmScript:Q};
36
+ })()`}y({site:"twitter",name:"delete",access:"write",description:"Delete a specific tweet by URL",domain:"x.com",strategy:g.UI,browser:!0,args:[{name:"url",type:"string",required:!0,positional:!0,help:"The URL of the tweet to delete"}],columns:["status","message"],func:async(t,f)=>{if(!t)throw new h("Browser session required for twitter delete");const o=b(f.url);await t.goto(o.url);await t.wait({selector:'[data-testid="primaryColumn"]'});const i=async(e,m,w=12)=>{let n;for(let s=0;s<w;s++){n=await t.evaluate(e);if(m(n))return n;await t.wait(0.5)}return n},r=await i(a(o.id),(e)=>!!(e&&e.found));if(!r||!r.found){if(r&&r.article===!1)return[{status:"failed",message:"Could not find the tweet card matching the requested URL."}];return[{status:"failed",message:'Could not find the "More" context menu on the matched tweet. Are you sure you are logged in and looking at a valid tweet?'}]}const l=await i(c(),(e)=>!!(e&&e.found));if(!l||!l.found)return[{status:"failed",message:"The matched tweet menu did not contain Delete. This tweet may not belong to you."}];const u=await i(d(),(e)=>!!(e&&e.found));if(!u||!u.found)return[{status:"failed",message:"Delete confirmation dialog did not appear."}];await t.wait(2);return[{status:"success",message:"Tweet successfully deleted."}]}});export const __test__={buildFindAndClickMoreScript:a,buildClickDeleteScript:c,buildClickConfirmScript:d};
@@ -1,6 +1,6 @@
1
- import{ArgumentError as D,AuthRequiredError as f,CommandExecutionError as P,EmptyResultError as F}from"@jackwener/opencli/errors";import{cli as k,Strategy as C}from"@jackwener/opencli/registry";import{TWITTER_BEARER_TOKEN as M,applyTopByEngagement as x}from"./utils.js";import{describeTwitterApiError as L}from"./shared.js";const _="/i/api/2/notifications/device_follow.json",V=200;function q(z){if(z===void 0||z===null||z==="")return 20;const G=Number(z);if(!Number.isInteger(G)||G<1||G>V)throw new D(`--limit must be an integer between 1 and ${V}`);return G}function B(z){const G=new URLSearchParams({include_profile_interstitial_type:"1",include_blocking:"1",include_blocked_by:"1",include_followed_by:"1",include_want_retweets:"1",include_mute_edge:"1",include_can_dm:"1",include_can_media_tag:"1",include_ext_has_nft_avatar:"1",include_ext_is_blue_verified:"1",include_ext_verified_type:"1",skip_status:"1",cards_platform:"Web-12",include_cards:"1",include_ext_alt_text:"true",include_quote_count:"true",include_reply_count:"1",tweet_mode:"extended",include_ext_views:"true",count:String(z)});return`${_}?${G.toString()}`}function W(z){if(!z||!Array.isArray(z.instructions))return null;const G=[];for(const Y of z.instructions){const J=Y?.addEntries?.entries;if(Array.isArray(J))G.push(...J)}return G}function N(z,G,Y){const J=z?.content?.item?.content?.tweet?.id;if(!J)return null;const Z=G?.[J];if(!Z)return null;const $=Y?.[Z.user_id_str]||null;if(typeof $?.screen_name!=="string"||!$.screen_name)return null;return{tweetId:J,tweet:Z,user:$}}function O({tweetId:z,tweet:G,user:Y}){const J=Y.screen_name;return{id:z,author:J,text:G?.full_text||G?.text||"",likes:G?.favorite_count??0,retweets:G?.retweet_count??0,replies:G?.reply_count??0,views:null,created_at:G?.created_at||"",url:`https://x.com/${J}/status/${z}`}}function U(z,G){if(!z?.globalObjects||typeof z.globalObjects!=="object")return null;const Y=z?.globalObjects?.tweets||{},J=z?.globalObjects?.users||{};if(typeof Y!=="object"||typeof J!=="object")return null;const Z=W(z?.timeline);if(!Z)return null;const $=[];let S=0,Q=0;for(const H of Z){if(!Boolean(H?.content?.item?.content?.tweet?.id)){Q++;continue}const K=N(H,Y,J);if(!K){S++;continue}if(G.has(K.tweetId))continue;G.add(K.tweetId);$.push(O(K))}return{rows:$,entryCount:Z.length,unmatchedTweetEntries:S,malformedEntries:Q}}k({site:"twitter",name:"device-follow",access:"read",description:'Read the /i/timeline device-follow notification stream (tweets aggregated under a bell-icon "new posts from @userA and N others" notification)',domain:"x.com",strategy:C.COOKIE,browser:!0,args:[{name:"limit",type:"int",default:20,help:`Maximum number of tweets to return (1-${V}, default 20)`},{name:"top-by-engagement",type:"int",default:0,help:"When set to N>0, re-rank by weighted engagement and return the top N. Default 0 keeps upstream ordering."}],columns:["id","author","text","likes","retweets","replies","views","created_at","url"],func:async(z,G)=>{const Y=q(G.limit),Z=(await z.getCookies({url:"https://x.com"})).find((b)=>b.name==="ct0")?.value||null;if(!Z)throw new f("x.com","Not logged into x.com (no ct0 cookie)");const $=B(Y),S=JSON.stringify({Authorization:`Bearer ${decodeURIComponent(M)}`,"X-Csrf-Token":Z,"X-Twitter-Auth-Type":"OAuth2Session","X-Twitter-Active-User":"yes"}),Q=await z.evaluate(`async () => {
1
+ import{ArgumentError as T,AuthRequiredError as w,CommandExecutionError as u,EmptyResultError as E}from"@jackwener/opencli/errors";import{cli as x,Strategy as v}from"@jackwener/opencli/registry";import{TWITTER_BEARER_TOKEN as j,applyTopByEngagement as A}from"./utils.js";import{describeTwitterApiError as k}from"./shared.js";const O="/i/api/2/notifications/device_follow.json",d=200;function f(e){if(e===void 0||e===null||e==="")return 20;const t=Number(e);if(!Number.isInteger(t)||t<1||t>d)throw new T(`--limit must be an integer between 1 and ${d}`);return t}function m(e){const t=new URLSearchParams({include_profile_interstitial_type:"1",include_blocking:"1",include_blocked_by:"1",include_followed_by:"1",include_want_retweets:"1",include_mute_edge:"1",include_can_dm:"1",include_can_media_tag:"1",include_ext_has_nft_avatar:"1",include_ext_is_blue_verified:"1",include_ext_verified_type:"1",skip_status:"1",cards_platform:"Web-12",include_cards:"1",include_ext_alt_text:"true",include_quote_count:"true",include_reply_count:"1",tweet_mode:"extended",include_ext_views:"true",count:String(e)});return`${O}?${t.toString()}`}function _(e){if(!e||!Array.isArray(e.instructions))return null;const t=[];for(const o of e.instructions){const r=o?.addEntries?.entries;if(Array.isArray(r))t.push(...r)}return t}function p(e,t,o){const r=e?.content?.item?.content?.tweet?.id;if(!r)return null;const i=t?.[r];if(!i)return null;const s=o?.[i.user_id_str]||null;if(typeof s?.screen_name!=="string"||!s.screen_name)return null;return{tweetId:r,tweet:i,user:s}}function h({tweetId:e,tweet:t,user:o}){const r=o.screen_name;return{id:e,author:r,text:t?.full_text||t?.text||"",likes:t?.favorite_count??0,retweets:t?.retweet_count??0,replies:t?.reply_count??0,views:null,created_at:t?.created_at||"",url:`https://x.com/${r}/status/${e}`}}function g(e,t){if(!e?.globalObjects||typeof e.globalObjects!=="object")return null;const o=e?.globalObjects?.tweets||{},r=e?.globalObjects?.users||{};if(typeof o!=="object"||typeof r!=="object")return null;const i=_(e?.timeline);if(!i)return null;const s=[];let a=0,n=0;for(const c of i){if(!Boolean(c?.content?.item?.content?.tweet?.id)){n++;continue}const l=p(c,o,r);if(!l){a++;continue}if(t.has(l.tweetId))continue;t.add(l.tweetId);s.push(h(l))}return{rows:s,entryCount:i.length,unmatchedTweetEntries:a,malformedEntries:n}}x({site:"twitter",name:"device-follow",access:"read",description:'Read the /i/timeline device-follow notification stream (tweets aggregated under a bell-icon "new posts from @userA and N others" notification)',domain:"x.com",strategy:v.COOKIE,browser:!0,args:[{name:"limit",type:"int",default:20,help:`Maximum number of tweets to return (1-${d}, default 20)`},{name:"top-by-engagement",type:"int",default:0,help:"When set to N>0, re-rank by weighted engagement and return the top N. Default 0 keeps upstream ordering."}],columns:["id","author","text","likes","retweets","replies","views","created_at","url"],func:async(e,t)=>{const o=f(t.limit),i=(await e.getCookies({url:"https://x.com"})).find((y)=>y.name==="ct0")?.value||null;if(!i)throw new w("x.com","Not logged into x.com (no ct0 cookie)");const s=m(o),a=JSON.stringify({Authorization:`Bearer ${decodeURIComponent(j)}`,"X-Csrf-Token":i,"X-Twitter-Auth-Type":"OAuth2Session","X-Twitter-Active-User":"yes"}),n=await e.evaluate(`async () => {
2
2
  try {
3
- const r = await fetch("${$}", { method: "GET", headers: ${S}, credentials: 'include' });
3
+ const r = await fetch("${s}", { method: "GET", headers: ${a}, credentials: 'include' });
4
4
  if (!r.ok) return { error: r.status };
5
5
  try {
6
6
  return await r.json();
@@ -10,4 +10,4 @@ import{ArgumentError as D,AuthRequiredError as f,CommandExecutionError as P,Empt
10
10
  } catch (e) {
11
11
  return { errorKind: 'exception', detail: String(e && e.message || e) };
12
12
  }
13
- }`);if(Q?.errorKind==="non_json")throw new P(`Twitter device-follow returned non-JSON response: ${Q.detail||"unknown parse error"}`);if(Q?.errorKind==="exception")throw new P(`Twitter device-follow fetch failed: ${Q.detail||"unknown error"}`);if(Q?.error){if(Q.error===401||Q.error===403)throw new f("x.com",`Twitter device-follow returned HTTP ${Q.error}`);throw new P(L("device_follow",Q.error))}const H=U(Q,new Set);if(!H)throw new P("Twitter device-follow response was missing the expected timeline/globalObjects shape.");if(H.malformedEntries>0||H.unmatchedTweetEntries>0)throw new P("Twitter device-follow entries could not be joined to tweet/user objects.");if(H.rows.length===0)throw new F("twitter device-follow","No device-follow notification tweets found.");const K=H.rows.slice(0,Y);return x(K,G["top-by-engagement"])}});export const __test__={buildDeviceFollowUrl:B,extractEntries:W,joinEntryToTweet:N,shapeRow:O,parseDeviceFollow:U,parseLimit:q};
13
+ }`);if(n?.errorKind==="non_json")throw new u(`Twitter device-follow returned non-JSON response: ${n.detail||"unknown parse error"}`);if(n?.errorKind==="exception")throw new u(`Twitter device-follow fetch failed: ${n.detail||"unknown error"}`);if(n?.error){if(n.error===401||n.error===403)throw new w("x.com",`Twitter device-follow returned HTTP ${n.error}`);throw new u(k("device_follow",n.error))}const c=g(n,new Set);if(!c)throw new u("Twitter device-follow response was missing the expected timeline/globalObjects shape.");if(c.malformedEntries>0||c.unmatchedTweetEntries>0)throw new u("Twitter device-follow entries could not be joined to tweet/user objects.");if(c.rows.length===0)throw new E("twitter device-follow","No device-follow notification tweets found.");const l=c.rows.slice(0,o);return A(l,t["top-by-engagement"])}});export const __test__={buildDeviceFollowUrl:m,extractEntries:_,joinEntryToTweet:p,shapeRow:h,parseDeviceFollow:g,parseLimit:f};
@@ -1 +1 @@
1
- import{cli as S,Strategy as T}from"@jackwener/opencli/registry";import{CommandExecutionError as G}from"@jackwener/opencli/errors";import{DM_REQUEST_QUERY as b,buildQuery as j,getDmAuth as B,dmApiFetch as M,shapeDmMessages as Q}from"./dm-shared.js";S({site:"twitter",name:"dm-list",access:"read",description:"List recent DM conversations (id, participants, last message, unread state)",domain:"x.com",strategy:T.COOKIE,browser:!0,args:[{name:"limit",type:"int",required:!1,default:20,help:"Maximum number of conversations to return (default 20)"}],columns:["conversation_id","type","participants","last_message","last_time","trusted","muted"],func:async(V,P)=>{const Y=Number(P.limit??20),{ownId:W,headers:x}=await B(V),A="https://x.com/i/api/1.1/dm/inbox_initial_state.json?"+j(b),J=await M(V,A,x);if(J?.error)throw new G(`inbox_initial_state failed: HTTP ${J.error} ${J.body||""}`);const H=J?.inbox_initial_state;if(!H||typeof H!=="object")throw new G("inbox_initial_state missing in response");const X=H.users||{},I=H.conversations||{},K=new Map;for(const q of Q(H.entries,X)){if(!q.conversation_id)continue;const f=K.get(q.conversation_id);if(!f||(q.time||"")>(f.time||""))K.set(q.conversation_id,q)}const Z=Object.entries(I).map(([q,f])=>{const $=(f.participants||[]).map((z)=>String(z.user_id)).filter((z)=>z!==W),N=($.length?$:[W]).map((z)=>{const F=X[z];return F?.screen_name?`@${F.screen_name}`:z}),L=K.get(q)||null;return{conversation_id:q,type:f.type||null,participants:N.join(","),last_message:L?L.text.slice(0,120):null,last_time:L?.time||(f.sort_timestamp?new Date(Number(f.sort_timestamp)).toISOString():null),trusted:f.trusted!==!1,muted:Boolean(f.muted)}});Z.sort((q,f)=>(f.last_time||"").localeCompare(q.last_time||""));return Z.slice(0,Y)}});
1
+ import{cli as y,Strategy as h}from"@jackwener/opencli/registry";import{CommandExecutionError as d}from"@jackwener/opencli/errors";import{DM_REQUEST_QUERY as x,buildQuery as E,getDmAuth as D,dmApiFetch as M,shapeDmMessages as S}from"./dm-shared.js";y({site:"twitter",name:"dm-list",access:"read",description:"List recent DM conversations (id, participants, last message, unread state)",domain:"x.com",strategy:h.COOKIE,browser:!0,args:[{name:"limit",type:"int",required:!1,default:20,help:"Maximum number of conversations to return (default 20)"}],columns:["conversation_id","type","participants","last_message","last_time","trusted","muted"],func:async(a,_)=>{const f=Number(_.limit??20),{ownId:m,headers:g}=await D(a),b="https://x.com/i/api/1.1/dm/inbox_initial_state.json?"+E(x),n=await M(a,b,g);if(n?.error)throw new d(`inbox_initial_state failed: HTTP ${n.error} ${n.body||""}`);const i=n?.inbox_initial_state;if(!i||typeof i!=="object")throw new d("inbox_initial_state missing in response");const c=i.users||{},w=i.conversations||{},o=new Map;for(const e of S(i.entries,c)){if(!e.conversation_id)continue;const t=o.get(e.conversation_id);if(!t||(e.time||"")>(t.time||""))o.set(e.conversation_id,e)}const l=Object.entries(w).map(([e,t])=>{const u=(t.participants||[]).map((s)=>String(s.user_id)).filter((s)=>s!==m),v=(u.length?u:[m]).map((s)=>{const p=c[s];return p?.screen_name?`@${p.screen_name}`:s}),r=o.get(e)||null;return{conversation_id:e,type:t.type||null,participants:v.join(","),last_message:r?r.text.slice(0,120):null,last_time:r?.time||(t.sort_timestamp?new Date(Number(t.sort_timestamp)).toISOString():null),trusted:t.trusted!==!1,muted:Boolean(t.muted)}});l.sort((e,t)=>(t.last_time||"").localeCompare(e.last_time||""));return l.slice(0,f)}});
@@ -1 +1 @@
1
- import{cli as P,Strategy as X}from"@jackwener/opencli/registry";import{CommandExecutionError as Z}from"@jackwener/opencli/errors";import{DM_REQUEST_QUERY as Y,buildQuery as b,getDmAuth as C,dmApiFetch as R,resolveTwitterUserId as T,shapeDmMessages as j}from"./dm-shared.js";const y=50;P({site:"twitter",name:"dm-read",access:"read",description:"Read message history of one DM conversation (by conversation id from dm-list, or @screen_name / numeric user id for the 1-on-1 conversation)",domain:"x.com",strategy:X.COOKIE,browser:!0,args:[{name:"conversation",type:"string",required:!0,positional:!0,help:"Conversation id like 123-456 (from `dm-list`), or @screen_name / numeric user id of the peer"},{name:"limit",type:"int",required:!1,default:50,help:"Maximum number of messages to return, newest first (default 50)"}],columns:["id","sender","text","time","media_url"],func:async(K,O)=>{const V=Number(O.limit??50),{ownId:$,headers:W}=await C(K),L=String(O.conversation??"").trim();let z;if(/^\d+-\d+$/.test(L))z=L;else z=`${await T(K,L,W)}-${$}`;const B=[];let H=null;for(let f=0;f<y&&B.length<V;f++){const F=`https://x.com/i/api/1.1/dm/conversation/${z}.json?`+b(Y,{context:"FETCH_DM_CONVERSATION_HISTORY",include_conversation_info:"true",...H?{max_id:H}:{}}),J=await R(K,F,W);if(J?.error){if(B.length===0)throw new Z(`dm/conversation failed for ${z}: HTTP ${J.error} ${J.body||""}`);break}const q=J?.conversation_timeline;if(!q)throw new Z("conversation_timeline missing in response");const G=j(q.entries,q.users);for(const N of G){if(!N.conversation_id)N.conversation_id=z;B.push(N)}if(q.status==="AT_END"||!q.min_entry_id||q.min_entry_id===H)break;H=q.min_entry_id}return B.slice(0,V).map((f)=>({id:f.id,sender:f.sender,text:f.text,time:f.time,media_url:f.media_url}))}});
1
+ import{cli as h,Strategy as v}from"@jackwener/opencli/registry";import{CommandExecutionError as u}from"@jackwener/opencli/errors";import{DM_REQUEST_QUERY as w,buildQuery as y,getDmAuth as g,dmApiFetch as x,resolveTwitterUserId as E,shapeDmMessages as b}from"./dm-shared.js";const I=50;h({site:"twitter",name:"dm-read",access:"read",description:"Read message history of one DM conversation (by conversation id from dm-list, or @screen_name / numeric user id for the 1-on-1 conversation)",domain:"x.com",strategy:v.COOKIE,browser:!0,args:[{name:"conversation",type:"string",required:!0,positional:!0,help:"Conversation id like 123-456 (from `dm-list`), or @screen_name / numeric user id of the peer"},{name:"limit",type:"int",required:!1,default:50,help:"Maximum number of messages to return, newest first (default 50)"}],columns:["id","sender","text","time","media_url"],func:async(s,d)=>{const c=Number(d.limit??50),{ownId:f,headers:l}=await g(s),a=String(d.conversation??"").trim();let i;if(/^\d+-\d+$/.test(a))i=a;else i=`${await E(s,a,l)}-${f}`;const r=[];let n=null;for(let e=0;e<I&&r.length<c;e++){const _=`https://x.com/i/api/1.1/dm/conversation/${i}.json?`+y(w,{context:"FETCH_DM_CONVERSATION_HISTORY",include_conversation_info:"true",...n?{max_id:n}:{}}),o=await x(s,_,l);if(o?.error){if(r.length===0)throw new u(`dm/conversation failed for ${i}: HTTP ${o.error} ${o.body||""}`);break}const t=o?.conversation_timeline;if(!t)throw new u("conversation_timeline missing in response");const p=b(t.entries,t.users);for(const m of p){if(!m.conversation_id)m.conversation_id=i;r.push(m)}if(t.status==="AT_END"||!t.min_entry_id||t.min_entry_id===n)break;n=t.min_entry_id}return r.slice(0,c).map((e)=>({id:e.id,sender:e.sender,text:e.text,time:e.time,media_url:e.media_url}))}});
@@ -1,13 +1,13 @@
1
- import{cli as $,Strategy as q}from"@jackwener/opencli/registry";import{ArgumentError as L,CommandExecutionError as W}from"@jackwener/opencli/errors";import{DM_SEND_QUERY as N,buildQuery as P,getDmAuth as R,resolveTwitterUserId as T,shapeDmMessages as Y}from"./dm-shared.js";import{assertLiteralContent as A}from"../_shared/content-guard.js";$({site:"twitter",name:"dm-send",access:"write",description:"Send a direct message to one user (by @screen_name, numeric user id, or conversation id from dm-list)",domain:"x.com",strategy:q.COOKIE,browser:!0,args:[{name:"user",type:"string",required:!0,positional:!0,help:"Recipient: @screen_name, numeric user id, or a conversation id like 123-456 from `dm-list`"},{name:"text",fromFile:!0,type:"string",required:!0,positional:!0,help:"Message text to send"},{name:"reply-to",type:"string",required:!1,help:"Message id to reply to (from `dm-read`)"}],columns:["id","conversation_id","text","time","status"],func:async(G,B)=>{const H=String(B.text??"").trim();A(H,{label:"私信内容"});if(!H)throw new L("Message text must not be empty");const{ownId:X,headers:K}=await R(G),J=String(B.user??"").trim();let F;if(/^\d+-\d+$/.test(J))F=J;else F=`${await T(G,J,K)}-${X}`;const O={cards_platform:"Web-12",conversation_id:F,dm_users:!1,include_cards:1,include_quote_count:!0,recipient_ids:!1,text:H,audio_only_media_attachment:!1};if(B["reply-to"])O.reply_to_dm_id=String(B["reply-to"]).trim();const Z="https://x.com/i/api/1.1/dm/new2.json?"+P(N),f=await G.evaluate(`async () => {
2
- const body = ${JSON.stringify(O)};
1
+ import{cli as y,Strategy as p}from"@jackwener/opencli/registry";import{ArgumentError as f,CommandExecutionError as m}from"@jackwener/opencli/errors";import{DM_SEND_QUERY as _,buildQuery as g,getDmAuth as b,resolveTwitterUserId as h,shapeDmMessages as w}from"./dm-shared.js";import{assertLiteralContent as x}from"../_shared/content-guard.js";y({site:"twitter",name:"dm-send",access:"write",description:"Send a direct message to one user (by @screen_name, numeric user id, or conversation id from dm-list)",domain:"x.com",strategy:p.COOKIE,browser:!0,args:[{name:"user",type:"string",required:!0,positional:!0,help:"Recipient: @screen_name, numeric user id, or a conversation id like 123-456 from `dm-list`"},{name:"text",fromFile:!0,type:"string",required:!0,positional:!0,help:"Message text to send"},{name:"reply-to",type:"string",required:!1,help:"Message id to reply to (from `dm-read`)"}],columns:["id","conversation_id","text","time","status"],func:async(i,r)=>{const n=String(r.text??"").trim();x(n,{label:"私信内容"});if(!n)throw new f("Message text must not be empty");const{ownId:u,headers:a}=await b(i),o=String(r.user??"").trim();let s;if(/^\d+-\d+$/.test(o))s=o;else s=`${await h(i,o,a)}-${u}`;const d={cards_platform:"Web-12",conversation_id:s,dm_users:!1,include_cards:1,include_quote_count:!0,recipient_ids:!1,text:n,audio_only_media_attachment:!1};if(r["reply-to"])d.reply_to_dm_id=String(r["reply-to"]).trim();const l="https://x.com/i/api/1.1/dm/new2.json?"+g(_),e=await i.evaluate(`async () => {
2
+ const body = ${JSON.stringify(d)};
3
3
  body.request_id = crypto.randomUUID();
4
- const r = await fetch(${JSON.stringify(Z)}, {
4
+ const r = await fetch(${JSON.stringify(l)}, {
5
5
  method: 'POST',
6
- headers: Object.assign(${JSON.stringify(K)}, { 'Content-Type': 'application/json' }),
6
+ headers: Object.assign(${JSON.stringify(a)}, { 'Content-Type': 'application/json' }),
7
7
  credentials: 'include',
8
8
  body: JSON.stringify(body),
9
9
  });
10
10
  const text = await r.text();
11
11
  if (!r.ok) return { error: r.status, body: text.slice(0, 300) };
12
12
  try { return JSON.parse(text); } catch { return { error: 'bad-json', body: text.slice(0, 300) }; }
13
- }`);if(f?.error)throw new W(`dm/new2.json failed: HTTP ${f.error} ${f.body||""}`);const V=Y(f.entries,f.users);if(!V.length)throw new W(`DM send returned no message entry (response keys: ${Object.keys(f||{}).join(",")})`);return V.map((z)=>({id:z.id,conversation_id:z.conversation_id||F,text:z.text,time:z.time,status:"sent"}))}});
13
+ }`);if(e?.error)throw new m(`dm/new2.json failed: HTTP ${e.error} ${e.body||""}`);const c=w(e.entries,e.users);if(!c.length)throw new m(`DM send returned no message entry (response keys: ${Object.keys(e||{}).join(",")})`);return c.map((t)=>({id:t.id,conversation_id:t.conversation_id||s,text:t.text,time:t.time,status:"sent"}))}});
@@ -1,6 +1,6 @@
1
- import{AuthRequiredError as W,CommandExecutionError as b}from"@jackwener/opencli/errors";import{TWITTER_BEARER_TOKEN as f}from"./utils.js";import{resolveTwitterOperationMetadata as q}from"./shared.js";export const DM_REQUEST_QUERY={nsfw_filtering_enabled:"false",filter_low_quality:"true",include_quality:"all",include_profile_interstitial_type:"1",include_blocking:"1",include_blocked_by:"1",include_followed_by:"1",include_want_retweets:"1",include_mute_edge:"1",include_can_dm:"1",include_can_media_tag:"1",include_ext_is_blue_verified:"1",include_ext_verified_type:"1",include_ext_profile_image_shape:"1",skip_status:"1",dm_secret_conversations_enabled:"false",krs_registration_enabled:"false",cards_platform:"Web-12",include_cards:"1",include_ext_alt_text:"true",include_ext_limited_action_results:"true",include_quote_count:"true",include_reply_count:"1",tweet_mode:"extended",include_ext_views:"true",dm_users:"true",include_groups:"true",include_inbox_timelines:"true",include_ext_media_color:"true",supports_reactions:"true",supports_edit:"true",include_ext_edit_control:"true",include_ext_business_affiliations_label:"true",include_ext_parody_commentary_fan_label:"true",ext:"mediaColor,altText,businessAffiliationsLabel,mediaStats,highlightedLabel,parodyCommentaryFanLabel,voiceInfo,birdwatchPivot,superFollowMetadata,unmentionInfo,editControl,article"},DM_SEND_QUERY={ext:"mediaColor,altText,mediaStats,highlightedLabel,voiceInfo,birdwatchPivot,superFollowMetadata,unmentionInfo,editControl,article",include_ext_alt_text:"true",include_ext_limited_action_results:"true",include_reply_count:"1",tweet_mode:"extended",include_ext_views:"true",include_groups:"true",include_inbox_timelines:"true",include_ext_media_color:"true",supports_reactions:"true",supports_edit:"true"};export function buildQuery(J,H={}){const G={...J,...H};return Object.entries(G).filter(([,D])=>D!==null&&D!==void 0).map(([D,z])=>`${encodeURIComponent(D)}=${encodeURIComponent(String(z))}`).join("&")}export async function getDmAuth(J){const H=await J.getCookies({url:"https://x.com"}),G=H.find((P)=>P.name==="ct0")?.value||null;if(!G)throw new W("x.com","Not logged into x.com (no ct0 cookie)");const D=H.find((P)=>P.name==="twid")?.value||"",z=decodeURIComponent(D).replace(/^u=/,"").trim();if(!/^\d+$/.test(z))throw new W("x.com","Cannot resolve own user id from twid cookie");const V={Authorization:`Bearer ${decodeURIComponent(f)}`,"X-Csrf-Token":G,"X-Twitter-Auth-Type":"OAuth2Session","X-Twitter-Active-User":"yes"};return{ct0:G,ownId:z,headers:V}}export async function dmApiFetch(J,H,G,D=null){const z=D?`, { method: ${JSON.stringify(D.method||"GET")}, headers: Object.assign(${JSON.stringify(G)}, ${JSON.stringify(D.extraHeaders||{})}), credentials: 'include', body: ${JSON.stringify(D.body??null)} }`:`, { headers: ${JSON.stringify(G)}, credentials: 'include' }`;return J.evaluate(`async () => {
2
- const r = await fetch(${JSON.stringify(H)}${z});
1
+ import{AuthRequiredError as c,CommandExecutionError as d}from"@jackwener/opencli/errors";import{TWITTER_BEARER_TOKEN as f}from"./utils.js";import{resolveTwitterOperationMetadata as m}from"./shared.js";export const DM_REQUEST_QUERY={nsfw_filtering_enabled:"false",filter_low_quality:"true",include_quality:"all",include_profile_interstitial_type:"1",include_blocking:"1",include_blocked_by:"1",include_followed_by:"1",include_want_retweets:"1",include_mute_edge:"1",include_can_dm:"1",include_can_media_tag:"1",include_ext_is_blue_verified:"1",include_ext_verified_type:"1",include_ext_profile_image_shape:"1",skip_status:"1",dm_secret_conversations_enabled:"false",krs_registration_enabled:"false",cards_platform:"Web-12",include_cards:"1",include_ext_alt_text:"true",include_ext_limited_action_results:"true",include_quote_count:"true",include_reply_count:"1",tweet_mode:"extended",include_ext_views:"true",dm_users:"true",include_groups:"true",include_inbox_timelines:"true",include_ext_media_color:"true",supports_reactions:"true",supports_edit:"true",include_ext_edit_control:"true",include_ext_business_affiliations_label:"true",include_ext_parody_commentary_fan_label:"true",ext:"mediaColor,altText,businessAffiliationsLabel,mediaStats,highlightedLabel,parodyCommentaryFanLabel,voiceInfo,birdwatchPivot,superFollowMetadata,unmentionInfo,editControl,article"},DM_SEND_QUERY={ext:"mediaColor,altText,mediaStats,highlightedLabel,voiceInfo,birdwatchPivot,superFollowMetadata,unmentionInfo,editControl,article",include_ext_alt_text:"true",include_ext_limited_action_results:"true",include_reply_count:"1",tweet_mode:"extended",include_ext_views:"true",include_groups:"true",include_inbox_timelines:"true",include_ext_media_color:"true",supports_reactions:"true",supports_edit:"true"};export function buildQuery(r,n={}){const i={...r,...n};return Object.entries(i).filter(([,t])=>t!==null&&t!==void 0).map(([t,e])=>`${encodeURIComponent(t)}=${encodeURIComponent(String(e))}`).join("&")}export async function getDmAuth(r){const n=await r.getCookies({url:"https://x.com"}),i=n.find((o)=>o.name==="ct0")?.value||null;if(!i)throw new c("x.com","Not logged into x.com (no ct0 cookie)");const t=n.find((o)=>o.name==="twid")?.value||"",e=decodeURIComponent(t).replace(/^u=/,"").trim();if(!/^\d+$/.test(e))throw new c("x.com","Cannot resolve own user id from twid cookie");const s={Authorization:`Bearer ${decodeURIComponent(f)}`,"X-Csrf-Token":i,"X-Twitter-Auth-Type":"OAuth2Session","X-Twitter-Active-User":"yes"};return{ct0:i,ownId:e,headers:s}}export async function dmApiFetch(r,n,i,t=null){const e=t?`, { method: ${JSON.stringify(t.method||"GET")}, headers: Object.assign(${JSON.stringify(i)}, ${JSON.stringify(t.extraHeaders||{})}), credentials: 'include', body: ${JSON.stringify(t.body??null)} }`:`, { headers: ${JSON.stringify(i)}, credentials: 'include' }`;return r.evaluate(`async () => {
2
+ const r = await fetch(${JSON.stringify(n)}${e});
3
3
  const text = await r.text();
4
4
  if (!r.ok) return { error: r.status, body: text.slice(0, 300) };
5
5
  try { return JSON.parse(text); } catch { return { error: 'bad-json', body: text.slice(0, 300) }; }
6
- }`)}const Q={queryId:"IGgvgiOx4QZndDHuD3x9TQ",features:{hidden_profile_subscriptions_enabled:!0,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,subscriptions_verification_info_is_identity_verified_enabled:!0,subscriptions_verification_info_verified_since_enabled:!0,highlights_tweets_tab_ui_enabled:!0,responsive_web_twitter_article_notes_tab_enabled:!0,subscriptions_feature_can_gift_premium:!0,creator_subscriptions_tweet_preview_api_enabled:!0,responsive_web_graphql_skip_user_profile_image_extensions_enabled:!1,responsive_web_graphql_timeline_navigation_enabled:!0},fieldToggles:{withPayments:!1,withAuxiliaryUserLabels:!0}};export async function resolveTwitterUserId(J,H,G){const D=String(H||"").trim().replace(/^@/,"");if(/^\d+$/.test(D))return D;if(!/^[A-Za-z0-9_]{1,15}$/.test(D))throw new b(`Invalid user: ${JSON.stringify(H)}. Expected @screen_name or numeric user id.`);const z=await q(J,"UserByScreenName",Q.queryId),V=Object.keys(z.features||{}).length?z.features:Q.features,P=Object.keys(z.fieldToggles||{}).length?z.fieldToggles:Q.fieldToggles,X=`https://x.com/i/api/graphql/${z.queryId}/UserByScreenName?`+buildQuery({variables:JSON.stringify({screen_name:D}),features:JSON.stringify(V),fieldToggles:JSON.stringify(P)}),Z=await dmApiFetch(J,X,G);if(Z?.error)throw new b(`UserByScreenName failed for @${D}: HTTP ${Z.error} ${Z.body||""}`);const $=Z?.data?.user?.result?.rest_id;if(typeof $!=="string"||!$)throw new b(`User @${D} not found or unavailable`);return $}export function shapeDmMessages(J,H){const G=[];for(const D of J||[]){const z=D?.message?.message_data;if(!z?.id)continue;const V=H?.[z.sender_id],P=z.attachment?.photo?.media_url_https||z.attachment?.video?.video_info?.variants?.find((X)=>X?.content_type==="video/mp4")?.url||z.attachment?.animated_gif?.video_info?.variants?.find((X)=>X?.content_type==="video/mp4")?.url||null;G.push({id:z.id,conversation_id:D.message.conversation_id||null,sender_id:z.sender_id||null,sender:V?.screen_name?`@${V.screen_name}`:z.sender_id||null,text:z.text||"",time:z.time?new Date(Number(z.time)).toISOString():null,media_url:P})}return G}
6
+ }`)}const u={queryId:"IGgvgiOx4QZndDHuD3x9TQ",features:{hidden_profile_subscriptions_enabled:!0,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,subscriptions_verification_info_is_identity_verified_enabled:!0,subscriptions_verification_info_verified_since_enabled:!0,highlights_tweets_tab_ui_enabled:!0,responsive_web_twitter_article_notes_tab_enabled:!0,subscriptions_feature_can_gift_premium:!0,creator_subscriptions_tweet_preview_api_enabled:!0,responsive_web_graphql_skip_user_profile_image_extensions_enabled:!1,responsive_web_graphql_timeline_navigation_enabled:!0},fieldToggles:{withPayments:!1,withAuxiliaryUserLabels:!0}};export async function resolveTwitterUserId(r,n,i){const t=String(n||"").trim().replace(/^@/,"");if(/^\d+$/.test(t))return t;if(!/^[A-Za-z0-9_]{1,15}$/.test(t))throw new d(`Invalid user: ${JSON.stringify(n)}. Expected @screen_name or numeric user id.`);const e=await m(r,"UserByScreenName",u.queryId),s=Object.keys(e.features||{}).length?e.features:u.features,o=Object.keys(e.fieldToggles||{}).length?e.fieldToggles:u.fieldToggles,a=`https://x.com/i/api/graphql/${e.queryId}/UserByScreenName?`+buildQuery({variables:JSON.stringify({screen_name:t}),features:JSON.stringify(s),fieldToggles:JSON.stringify(o)}),_=await dmApiFetch(r,a,i);if(_?.error)throw new d(`UserByScreenName failed for @${t}: HTTP ${_.error} ${_.body||""}`);const l=_?.data?.user?.result?.rest_id;if(typeof l!=="string"||!l)throw new d(`User @${t} not found or unavailable`);return l}export function shapeDmMessages(r,n){const i=[];for(const t of r||[]){const e=t?.message?.message_data;if(!e?.id)continue;const s=n?.[e.sender_id],o=e.attachment?.photo?.media_url_https||e.attachment?.video?.video_info?.variants?.find((a)=>a?.content_type==="video/mp4")?.url||e.attachment?.animated_gif?.video_info?.variants?.find((a)=>a?.content_type==="video/mp4")?.url||null;i.push({id:e.id,conversation_id:t.message.conversation_id||null,sender_id:e.sender_id||null,sender:s?.screen_name?`@${s.screen_name}`:e.sender_id||null,text:e.text||"",time:e.time?new Date(Number(e.time)).toISOString():null,media_url:o})}return i}
@@ -1,21 +1,21 @@
1
- import{cli as o,Strategy as r}from"@jackwener/opencli/registry";import{ArgumentError as D,AuthRequiredError as h,CliError as t,CommandExecutionError as X,EmptyResultError as T}from"@jackwener/opencli/errors";import{formatCookieHeader as C}from"@jackwener/opencli/download";import{downloadMedia as a}from"@jackwener/opencli/download/media-download";import{resolveTwitterOperationMetadata as R,normalizeTwitterGraphqlPayload as _,unwrapBrowserResult as y,normalizeTwitterScreenName as e,extractMedia as jj,parseTweetUrl as Fj}from"./shared.js";import{TWITTER_BEARER_TOKEN as Gj}from"./utils.js";const I="9EovraBTXJYGSEQXZqlLmQ",k="IGgvgiOx4QZndDHuD3x9TQ",E=100,O={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,rweb_conversational_replies_downvote_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},f={withPayments:!0,withAuxiliaryUserLabels:!0,withArticleRichContentState:!0,withArticlePlainText:!0,withArticleSummaryText:!0,withArticleVoiceOver:!0,withGrokAnalyze:!0,withDisallowedReplyControls:!0},S={hidden_profile_subscriptions_enabled:!0,profile_label_improvements_pcf_label_in_post_enabled:!0,responsive_web_profile_redirect_enabled:!0,rweb_tipjar_consumption_enabled:!0,responsive_web_graphql_exclude_directive_enabled:!0,verified_phone_label_enabled:!1,subscriptions_verification_info_is_identity_verified_enabled:!0,subscriptions_verification_info_verified_since_enabled:!0,highlights_tweets_tab_ui_enabled:!0,responsive_web_twitter_article_notes_tab_enabled:!0,subscriptions_feature_can_gift_premium:!0,creator_subscriptions_tweet_preview_api_enabled:!0,responsive_web_graphql_skip_user_profile_image_extensions_enabled:!1,responsive_web_graphql_timeline_navigation_enabled:!0},N={withPayments:!0,withAuxiliaryUserLabels:!0},Hj={queryId:I,features:O,fieldToggles:f},Jj={queryId:k,features:S,fieldToggles:N};function U(j){const F=Number(j??10);if(!Number.isInteger(F)||F<1||F>1000)throw new D("--limit must be an integer between 1 and 1000");return F}function x(j,F){const G=j-F;if(G<=0)return 0;const H=G+10;if(H>100)return 100;return H}async function w(j,F){return(await a(j,F)).map((H,K)=>{const V=j[K]||{};return{index:H.index,tweet_id:V.tweet_id||"",url:V.url||"",type:H.type,status:H.status,size:H.size}})}function Kj(j){if(typeof j==="string")return{queryId:j,features:O,fieldToggles:f};return{queryId:j?.queryId||I,features:j?.features||O,fieldToggles:j?.fieldToggles||f}}function Vj(j){if(typeof j==="string")return{queryId:j,features:S,fieldToggles:N};return{queryId:j?.queryId||k,features:j?.features||S,fieldToggles:j?.fieldToggles||N}}function c(j,F,G){const H=G.fieldToggles||{},K=[`variables=${encodeURIComponent(JSON.stringify(F))}`,`features=${encodeURIComponent(JSON.stringify(G.features||{}))}`];if(Object.keys(H).length>0)K.push(`fieldToggles=${encodeURIComponent(JSON.stringify(H))}`);return`${j}?${K.join("&")}`}function v(j,F,G,H){const K=Kj(j),V={userId:F,count:G,includePromotedContent:!1,withClientEventToken:!1,withBirdwatchNotes:!1,withVoice:!0};if(H)V.cursor=H;return c(`/i/api/graphql/${K.queryId}/UserMedia`,V,K)}function d(j,F){const G=Vj(j),H={screen_name:F,withSafetyModeUserFields:!0};return c(`/i/api/graphql/${G.queryId}/UserByScreenName`,H,G)}function g(j){if(!j)return"unknown";if(/video\.twimg\.com|\.mp4(\?|$)|\.m3u8(\?|$)/.test(j))return"video";return"image"}function p(j,F){if(!j||typeof j!=="object"||Array.isArray(j))throw new X(`Twitter ${F} returned malformed payload`);return j}function Wj(j,F,G){if(F===401||F===403)throw new h("x.com",`Twitter ${j} requires an authenticated x.com session`);if(F===404)throw new T(`twitter download ${j}`,G||"Twitter returned not found");const H=F?`HTTP ${F}`:"fetch failed";throw new X(`Twitter ${j} fetch failed: ${H}${G?` - ${G}`:""}`)}function m(j,F){const G=p(y(j),F);if(G.ok===!0)return G.payload;if(G.ok===!1)Wj(F,Number(G.status)||0,typeof G.error==="string"?G.error:"");throw new X(`Twitter ${F} returned malformed fetch result`)}function Xj(j){const F=p(j,"UserMedia");if(Array.isArray(F.errors)&&F.errors.length>0)throw new X(`Twitter UserMedia returned GraphQL errors: ${JSON.stringify(F.errors).slice(0,200)}`);const G=F.data?.user?.result;if(!G||typeof G!=="object")throw new X("Twitter UserMedia returned malformed user result");const H=G.timeline_v2?.timeline?.instructions||G.timeline?.timeline?.instructions;if(!Array.isArray(H))throw new X("Twitter UserMedia returned malformed timeline instructions");return F}function n(j,F){const G=[];let H=null;const K=Xj(j).data.user.result,Z=[K.timeline_v2?.timeline?.instructions,K.timeline?.timeline?.instructions].filter(Array.isArray).flat(),Q=(J)=>{if(!J||typeof J!=="object")return;if(J.type==="TimelinePinEntry")return;if(J.tweet_results?.result){const W=J.tweet_results.result,b=W.__typename==="TweetWithVisibilityResults"&&W.tweet?W.tweet:W.tweet||W,$=typeof b.rest_id==="string"||typeof b.rest_id==="number"?String(b.rest_id):"";if(!$)throw new X("Twitter UserMedia returned a tweet without rest_id");if(!F.has($)){F.add($);const{media_urls:B}=jj(b.legacy||{});for(const P of B)G.push({tweet_id:$,url:P,type:g(P)})}}if((J.entryType==="TimelineTimelineCursor"||J.__typename==="TimelineTimelineCursor")&&(J.cursorType==="Bottom"||J.cursorType==="ShowMore")&&J.value)H=J.value;if(Array.isArray(J)){for(const W of J)Q(W);return}for(const W of Object.values(J))if(W&&typeof W==="object")Q(W)};Q(Z);return{items:G,nextCursor:H}}o({site:"twitter",name:"download",access:"read",description:"Download Twitter/X media (images and videos). Provide either <username> to fetch every media item from their profile via the GraphQL UserMedia endpoint with cursor pagination, or --tweet-url to download a single tweet.",domain:"x.com",strategy:r.COOKIE,browser:!0,args:[{name:"username",positional:!0,help:"Twitter username (with or without @) to scan their profile media. Either <username> or --tweet-url is required."},{name:"tweet-url",help:"Single tweet URL to download. Use this OR <username>, not both required at once."},{name:"limit",type:"int",default:10,help:"Maximum number of media items to download when scanning a profile (default 10). Ignored when --tweet-url is used."},{name:"output",default:"./twitter-downloads",help:"Output directory (default ./twitter-downloads). A per-source subdir is created inside."}],columns:["index","tweet_id","url","type","status","size"],func:async(j,F)=>{try{const G=String(F.username??"").trim(),H=String(F["tweet-url"]??"").trim(),K=F.output;if(!G&&!H)throw new D("twitter download requires either <username> or --tweet-url");if(G&&H)throw new D("Use either <username> or --tweet-url, not both");if(H)return $j(j,H,K);const V=U(F.limit),Z=e(G);if(!Z)throw new D("twitter download username must be a valid Twitter/X handle","Example: ppcli twitter download @jack --limit 20");return Zj(j,Z,V,K)}catch(G){if(G instanceof t)throw G;throw new X(`twitter download failed: ${G?.message??String(G)}`)}}});async function Zj(j,F,G,H){await j.goto(`https://x.com/${F}`);await j.wait({selector:'[data-testid="primaryColumn"]'});const K=await j.getCookies({url:"https://x.com"}),V=K.find((Y)=>Y.name==="ct0")?.value||null;if(!V)throw new h("x.com","Not logged into x.com (no ct0 cookie)");const Z=await R(j,"UserMedia",Hj),Q=await R(j,"UserByScreenName",Jj),J=JSON.stringify({Authorization:`Bearer ${decodeURIComponent(Gj)}`,"X-Csrf-Token":V,"X-Twitter-Auth-Type":"OAuth2Session","X-Twitter-Active-User":"yes"}),W=d(Q,F),b=m(await j.evaluate(`async () => {
1
+ import{cli as V,Strategy as K}from"@jackwener/opencli/registry";import{ArgumentError as b,AuthRequiredError as k,CliError as W,CommandExecutionError as l,EmptyResultError as y}from"@jackwener/opencli/errors";import{formatCookieHeader as q}from"@jackwener/opencli/download";import{downloadMedia as Z}from"@jackwener/opencli/download/media-download";import{resolveTwitterOperationMetadata as M,normalizeTwitterGraphqlPayload as I,unwrapBrowserResult as R,normalizeTwitterScreenName as ee,extractMedia as te,parseTweetUrl as re}from"./shared.js";import{TWITTER_BEARER_TOKEN as ie}from"./utils.js";const x="9EovraBTXJYGSEQXZqlLmQ",N="IGgvgiOx4QZndDHuD3x9TQ",C=100,T={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,rweb_conversational_replies_downvote_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},E={withPayments:!0,withAuxiliaryUserLabels:!0,withArticleRichContentState:!0,withArticlePlainText:!0,withArticleSummaryText:!0,withArticleVoiceOver:!0,withGrokAnalyze:!0,withDisallowedReplyControls:!0},v={hidden_profile_subscriptions_enabled:!0,profile_label_improvements_pcf_label_in_post_enabled:!0,responsive_web_profile_redirect_enabled:!0,rweb_tipjar_consumption_enabled:!0,responsive_web_graphql_exclude_directive_enabled:!0,verified_phone_label_enabled:!1,subscriptions_verification_info_is_identity_verified_enabled:!0,subscriptions_verification_info_verified_since_enabled:!0,highlights_tweets_tab_ui_enabled:!0,responsive_web_twitter_article_notes_tab_enabled:!0,subscriptions_feature_can_gift_premium:!0,creator_subscriptions_tweet_preview_api_enabled:!0,responsive_web_graphql_skip_user_profile_image_extensions_enabled:!1,responsive_web_graphql_timeline_navigation_enabled:!0},S={withPayments:!0,withAuxiliaryUserLabels:!0},ne={queryId:x,features:T,fieldToggles:E},oe={queryId:N,features:v,fieldToggles:S};function O(e){const t=Number(e??10);if(!Number.isInteger(t)||t<1||t>1000)throw new b("--limit must be an integer between 1 and 1000");return t}function P(e,t){const r=e-t;if(r<=0)return 0;const i=r+10;if(i>100)return 100;return i}async function B(e,t){return(await Z(e,t)).map((i,o)=>{const s=e[o]||{};return{index:i.index,tweet_id:s.tweet_id||"",url:s.url||"",type:i.type,status:i.status,size:i.size}})}function se(e){if(typeof e==="string")return{queryId:e,features:T,fieldToggles:E};return{queryId:e?.queryId||x,features:e?.features||T,fieldToggles:e?.fieldToggles||E}}function ae(e){if(typeof e==="string")return{queryId:e,features:v,fieldToggles:S};return{queryId:e?.queryId||N,features:e?.features||v,fieldToggles:e?.fieldToggles||S}}function L(e,t,r){const i=r.fieldToggles||{},o=[`variables=${encodeURIComponent(JSON.stringify(t))}`,`features=${encodeURIComponent(JSON.stringify(r.features||{}))}`];if(Object.keys(i).length>0)o.push(`fieldToggles=${encodeURIComponent(JSON.stringify(i))}`);return`${e}?${o.join("&")}`}function z(e,t,r,i){const o=se(e),s={userId:t,count:r,includePromotedContent:!1,withClientEventToken:!1,withBirdwatchNotes:!1,withVoice:!0};if(i)s.cursor=i;return L(`/i/api/graphql/${o.queryId}/UserMedia`,s,o)}function G(e,t){const r=ae(e),i={screen_name:t,withSafetyModeUserFields:!0};return L(`/i/api/graphql/${r.queryId}/UserByScreenName`,i,r)}function j(e){if(!e)return"unknown";if(/video\.twimg\.com|\.mp4(\?|$)|\.m3u8(\?|$)/.test(e))return"video";return"image"}function D(e,t){if(!e||typeof e!=="object"||Array.isArray(e))throw new l(`Twitter ${t} returned malformed payload`);return e}function le(e,t,r){if(t===401||t===403)throw new k("x.com",`Twitter ${e} requires an authenticated x.com session`);if(t===404)throw new y(`twitter download ${e}`,r||"Twitter returned not found");const i=t?`HTTP ${t}`:"fetch failed";throw new l(`Twitter ${e} fetch failed: ${i}${r?` - ${r}`:""}`)}function Q(e,t){const r=D(R(e),t);if(r.ok===!0)return r.payload;if(r.ok===!1)le(t,Number(r.status)||0,typeof r.error==="string"?r.error:"");throw new l(`Twitter ${t} returned malformed fetch result`)}function ue(e){const t=D(e,"UserMedia");if(Array.isArray(t.errors)&&t.errors.length>0)throw new l(`Twitter UserMedia returned GraphQL errors: ${JSON.stringify(t.errors).slice(0,200)}`);const r=t.data?.user?.result;if(!r||typeof r!=="object")throw new l("Twitter UserMedia returned malformed user result");const i=r.timeline_v2?.timeline?.instructions||r.timeline?.timeline?.instructions;if(!Array.isArray(i))throw new l("Twitter UserMedia returned malformed timeline instructions");return t}function F(e,t){const r=[];let i=null;const o=ue(e).data.user.result,u=[o.timeline_v2?.timeline?.instructions,o.timeline?.timeline?.instructions].filter(Array.isArray).flat(),d=(n)=>{if(!n||typeof n!=="object")return;if(n.type==="TimelinePinEntry")return;if(n.tweet_results?.result){const a=n.tweet_results.result,c=a.__typename==="TweetWithVisibilityResults"&&a.tweet?a.tweet:a.tweet||a,_=typeof c.rest_id==="string"||typeof c.rest_id==="number"?String(c.rest_id):"";if(!_)throw new l("Twitter UserMedia returned a tweet without rest_id");if(!t.has(_)){t.add(_);const{media_urls:f}=te(c.legacy||{});for(const m of f)r.push({tweet_id:_,url:m,type:j(m)})}}if((n.entryType==="TimelineTimelineCursor"||n.__typename==="TimelineTimelineCursor")&&(n.cursorType==="Bottom"||n.cursorType==="ShowMore")&&n.value)i=n.value;if(Array.isArray(n)){for(const a of n)d(a);return}for(const a of Object.values(n))if(a&&typeof a==="object")d(a)};d(u);return{items:r,nextCursor:i}}V({site:"twitter",name:"download",access:"read",description:"Download Twitter/X media (images and videos). Provide either <username> to fetch every media item from their profile via the GraphQL UserMedia endpoint with cursor pagination, or --tweet-url to download a single tweet.",domain:"x.com",strategy:K.COOKIE,browser:!0,args:[{name:"username",positional:!0,help:"Twitter username (with or without @) to scan their profile media. Either <username> or --tweet-url is required."},{name:"tweet-url",help:"Single tweet URL to download. Use this OR <username>, not both required at once."},{name:"limit",type:"int",default:10,help:"Maximum number of media items to download when scanning a profile (default 10). Ignored when --tweet-url is used."},{name:"output",default:"./twitter-downloads",help:"Output directory (default ./twitter-downloads). A per-source subdir is created inside."}],columns:["index","tweet_id","url","type","status","size"],func:async(e,t)=>{try{const r=String(t.username??"").trim(),i=String(t["tweet-url"]??"").trim(),o=t.output;if(!r&&!i)throw new b("twitter download requires either <username> or --tweet-url");if(r&&i)throw new b("Use either <username> or --tweet-url, not both");if(i)return de(e,i,o);const s=O(t.limit),u=ee(r);if(!u)throw new b("twitter download username must be a valid Twitter/X handle","Example: ppcli twitter download @jack --limit 20");return _e(e,u,s,o)}catch(r){if(r instanceof W)throw r;throw new l(`twitter download failed: ${r?.message??String(r)}`)}}});async function _e(e,t,r,i){await e.goto(`https://x.com/${t}`);await e.wait({selector:'[data-testid="primaryColumn"]'});const o=await e.getCookies({url:"https://x.com"}),s=o.find((p)=>p.name==="ct0")?.value||null;if(!s)throw new k("x.com","Not logged into x.com (no ct0 cookie)");const u=await M(e,"UserMedia",ne),d=await M(e,"UserByScreenName",oe),n=JSON.stringify({Authorization:`Bearer ${decodeURIComponent(ie)}`,"X-Csrf-Token":s,"X-Twitter-Auth-Type":"OAuth2Session","X-Twitter-Active-User":"yes"}),a=G(d,t),c=Q(await e.evaluate(`async () => {
2
2
  try {
3
- const resp = await fetch("${W}", { headers: ${J}, credentials: 'include' });
3
+ const resp = await fetch("${a}", { headers: ${n}, credentials: 'include' });
4
4
  if (!resp.ok) return { ok: false, status: resp.status };
5
5
  const payload = await resp.json();
6
6
  return { ok: true, payload };
7
7
  } catch (err) {
8
8
  return { ok: false, error: err?.message ?? String(err) };
9
9
  }
10
- }`)),$=_(b);if(Array.isArray($?.errors)&&$.errors.length>0)throw new X(`Twitter UserByScreenName returned GraphQL errors: ${JSON.stringify($.errors).slice(0,200)}`);const B=$?.data?.user?.result?.rest_id;if(!B)throw new T(`twitter download @${F}`,`Could not resolve @${F}`);const P=new Set,q=[];let L=null,z=!1;for(let Y=0;Y<E&&q.length<G;Y++){const M=x(G,q.length);if(M===0)break;const l=v(Z,B,M,L),u=_(m(await j.evaluate(`async () => {
10
+ }`)),_=I(c);if(Array.isArray(_?.errors)&&_.errors.length>0)throw new l(`Twitter UserByScreenName returned GraphQL errors: ${JSON.stringify(_.errors).slice(0,200)}`);const f=_?.data?.user?.result?.rest_id;if(!f)throw new y(`twitter download @${t}`,`Could not resolve @${t}`);const m=new Set,w=[];let g=null,A=!1;for(let p=0;p<C&&w.length<r;p++){const U=P(r,w.length);if(U===0)break;const J=z(u,f,U,g),Y=I(Q(await e.evaluate(`async () => {
11
11
  try {
12
- const r = await fetch("${l}", { headers: ${J}, credentials: 'include' });
12
+ const r = await fetch("${J}", { headers: ${n}, credentials: 'include' });
13
13
  if (!r.ok) return { ok: false, status: r.status };
14
14
  return { ok: true, payload: await r.json() };
15
15
  } catch (err) {
16
16
  return { ok: false, error: err?.message ?? String(err) };
17
17
  }
18
- }`))),{items:s,nextCursor:A}=n(u,P);q.push(...s);z=Boolean(A);if(!A)break;if(A===L)throw new X("Twitter UserMedia pagination returned the same cursor twice");L=A}if(q.length===0)throw new T(`@${F} has no media`,"Account may be private, suspended, or have no media posts");if(q.length<G&&z)throw new X(`Twitter UserMedia pagination reached the ${E}-page safety cap before collecting ${G} media items`);const i=q.slice(0,G);return w(i,{output:H,subdir:F,cookies:C(K),browserCookies:K,filenamePrefix:F,ytdlpExtraArgs:["--merge-output-format","mp4"]})}async function $j(j,F,G){const H=Fj(F);await j.goto(H.url);await j.wait(3);const K=y(await j.evaluate(`
18
+ }`))),{items:H,nextCursor:h}=F(Y,m);w.push(...H);A=Boolean(h);if(!h)break;if(h===g)throw new l("Twitter UserMedia pagination returned the same cursor twice");g=h}if(w.length===0)throw new y(`@${t} has no media`,"Account may be private, suspended, or have no media posts");if(w.length<r&&A)throw new l(`Twitter UserMedia pagination reached the ${C}-page safety cap before collecting ${r} media items`);const X=w.slice(0,r);return B(X,{output:i,subdir:t,cookies:q(o),browserCookies:o,filenamePrefix:t,ytdlpExtraArgs:["--merge-output-format","mp4"]})}async function de(e,t,r){const i=re(t);await e.goto(i.url);await e.wait(3);const o=R(await e.evaluate(`
19
19
  (() => {
20
20
  const out = [];
21
21
  document.querySelectorAll('img[src*="pbs.twimg.com/media"]').forEach(img => {
@@ -35,4 +35,4 @@ import{cli as o,Strategy as r}from"@jackwener/opencli/registry";import{ArgumentE
35
35
  });
36
36
  return out;
37
37
  })()
38
- `));if(!Array.isArray(K))throw new X("Twitter tweet media extraction returned malformed payload");if(K.length===0)throw new T(`twitter download ${H.id}`,"No media found in the tweet");const V=await j.getCookies({domain:"x.com"}),Z=new Set,Q=K.filter((J)=>{if(Z.has(J.url))return!1;Z.add(J.url);return!0}).map((J)=>{return{...J,tweet_id:H.id}});return w(Q,{output:G,subdir:"tweets",cookies:C(V),browserCookies:V,filenamePrefix:"tweet",ytdlpExtraArgs:["--merge-output-format","mp4"]})}export const __test__={buildUserMediaUrl:v,buildUserByScreenNameUrl:d,parseUserMedia:n,classifyMediaUrl:g,requireLimit:U,nextUserMediaFetchCount:x};
38
+ `));if(!Array.isArray(o))throw new l("Twitter tweet media extraction returned malformed payload");if(o.length===0)throw new y(`twitter download ${i.id}`,"No media found in the tweet");const s=await e.getCookies({domain:"x.com"}),u=new Set,d=o.filter((n)=>{if(u.has(n.url))return!1;u.add(n.url);return!0}).map((n)=>{return{...n,tweet_id:i.id}});return B(d,{output:r,subdir:"tweets",cookies:q(s),browserCookies:s,filenamePrefix:"tweet",ytdlpExtraArgs:["--merge-output-format","mp4"]})}export const __test__={buildUserMediaUrl:z,buildUserByScreenNameUrl:G,parseUserMedia:F,classifyMediaUrl:j,requireLimit:O,nextUserMediaFetchCount:P};