@jackwener/opencli 1.0.6 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (400) hide show
  1. package/.agents/skills/cross-project-adapter-migration/SKILL.md +2 -2
  2. package/.github/pull_request_template.md +7 -0
  3. package/.github/workflows/doc-check.yml +36 -0
  4. package/.github/workflows/docs.yml +7 -42
  5. package/CHANGELOG.md +23 -0
  6. package/CLI-EXPLORER.md +9 -8
  7. package/README.md +51 -10
  8. package/README.zh-CN.md +29 -11
  9. package/SKILL.md +102 -33
  10. package/dist/browser/cdp.js +6 -1
  11. package/dist/browser/page.d.ts +4 -1
  12. package/dist/browser/page.js +7 -1
  13. package/dist/build-manifest.js +23 -16
  14. package/dist/cli-manifest.json +951 -296
  15. package/dist/cli.d.ts +6 -0
  16. package/dist/cli.js +225 -148
  17. package/dist/clis/antigravity/serve.js +296 -47
  18. package/dist/clis/apple-podcasts/commands.test.d.ts +2 -0
  19. package/dist/clis/apple-podcasts/commands.test.js +76 -0
  20. package/dist/clis/apple-podcasts/search.js +2 -2
  21. package/dist/clis/apple-podcasts/top.js +9 -2
  22. package/dist/clis/arxiv/paper.js +21 -0
  23. package/dist/clis/arxiv/search.js +24 -0
  24. package/dist/clis/arxiv/utils.d.ts +18 -0
  25. package/dist/clis/arxiv/utils.js +49 -0
  26. package/dist/clis/bilibili/dynamic.js +1 -1
  27. package/dist/clis/bilibili/favorite.js +1 -1
  28. package/dist/clis/bilibili/feed.js +1 -1
  29. package/dist/clis/bilibili/following.js +1 -1
  30. package/dist/clis/bilibili/history.js +1 -1
  31. package/dist/clis/bilibili/me.js +1 -1
  32. package/dist/clis/bilibili/ranking.js +1 -1
  33. package/dist/clis/bilibili/search.js +3 -3
  34. package/dist/clis/bilibili/subtitle.js +1 -1
  35. package/dist/clis/bilibili/user-videos.js +1 -1
  36. package/dist/{bilibili.d.ts → clis/bilibili/utils.d.ts} +1 -1
  37. package/dist/clis/bloomberg/businessweek.d.ts +1 -0
  38. package/dist/clis/bloomberg/businessweek.js +17 -0
  39. package/dist/clis/bloomberg/economics.d.ts +1 -0
  40. package/dist/clis/bloomberg/economics.js +17 -0
  41. package/dist/clis/bloomberg/feeds.d.ts +1 -0
  42. package/dist/clis/bloomberg/feeds.js +15 -0
  43. package/dist/clis/bloomberg/industries.d.ts +1 -0
  44. package/dist/clis/bloomberg/industries.js +17 -0
  45. package/dist/clis/bloomberg/main.d.ts +1 -0
  46. package/dist/clis/bloomberg/main.js +17 -0
  47. package/dist/clis/bloomberg/markets.d.ts +1 -0
  48. package/dist/clis/bloomberg/markets.js +17 -0
  49. package/dist/clis/bloomberg/news.d.ts +1 -0
  50. package/dist/clis/bloomberg/news.js +105 -0
  51. package/dist/clis/bloomberg/opinions.d.ts +1 -0
  52. package/dist/clis/bloomberg/opinions.js +17 -0
  53. package/dist/clis/bloomberg/politics.d.ts +1 -0
  54. package/dist/clis/bloomberg/politics.js +17 -0
  55. package/dist/clis/bloomberg/tech.d.ts +1 -0
  56. package/dist/clis/bloomberg/tech.js +17 -0
  57. package/dist/clis/bloomberg/utils.d.ts +34 -0
  58. package/dist/clis/bloomberg/utils.js +364 -0
  59. package/dist/clis/bloomberg/utils.test.d.ts +1 -0
  60. package/dist/clis/bloomberg/utils.test.js +129 -0
  61. package/dist/clis/boss/batchgreet.d.ts +1 -0
  62. package/dist/clis/boss/batchgreet.js +147 -0
  63. package/dist/clis/boss/chatlist.js +2 -2
  64. package/dist/clis/boss/detail.js +2 -2
  65. package/dist/clis/boss/exchange.d.ts +1 -0
  66. package/dist/clis/boss/exchange.js +111 -0
  67. package/dist/clis/boss/greet.d.ts +1 -0
  68. package/dist/clis/boss/greet.js +175 -0
  69. package/dist/clis/boss/invite.d.ts +1 -0
  70. package/dist/clis/boss/invite.js +158 -0
  71. package/dist/clis/boss/joblist.d.ts +1 -0
  72. package/dist/clis/boss/joblist.js +55 -0
  73. package/dist/clis/boss/mark.d.ts +1 -0
  74. package/dist/clis/boss/mark.js +141 -0
  75. package/dist/clis/boss/recommend.d.ts +1 -0
  76. package/dist/clis/boss/recommend.js +83 -0
  77. package/dist/clis/boss/search.js +1 -1
  78. package/dist/clis/boss/send.js +1 -1
  79. package/dist/clis/boss/stats.d.ts +1 -0
  80. package/dist/clis/boss/stats.js +116 -0
  81. package/dist/clis/chaoxing/assignments.js +1 -1
  82. package/dist/clis/chaoxing/exams.js +1 -1
  83. package/dist/{chaoxing.d.ts → clis/chaoxing/utils.d.ts} +1 -1
  84. package/dist/{chaoxing.js → clis/chaoxing/utils.js} +0 -2
  85. package/dist/clis/chaoxing/utils.test.d.ts +1 -0
  86. package/dist/{chaoxing.test.js → clis/chaoxing/utils.test.js} +1 -1
  87. package/dist/clis/chatgpt/read.js +1 -1
  88. package/dist/clis/chatwise/export.js +1 -1
  89. package/dist/clis/chatwise/model.js +2 -2
  90. package/dist/clis/chatwise/screenshot.js +1 -1
  91. package/dist/clis/codex/export.js +1 -1
  92. package/dist/clis/codex/model.js +2 -2
  93. package/dist/clis/codex/screenshot.js +1 -1
  94. package/dist/clis/coupang/add-to-cart.js +3 -4
  95. package/dist/clis/coupang/search.js +2 -4
  96. package/dist/clis/coupang/utils.test.d.ts +1 -0
  97. package/dist/{coupang.test.js → clis/coupang/utils.test.js} +1 -1
  98. package/dist/clis/ctrip/search.js +1 -1
  99. package/dist/clis/cursor/export.js +1 -1
  100. package/dist/clis/cursor/model.js +2 -2
  101. package/dist/clis/cursor/screenshot.js +1 -1
  102. package/dist/clis/jike/comment.js +2 -3
  103. package/dist/clis/jike/create.js +1 -2
  104. package/dist/clis/jike/feed.js +0 -1
  105. package/dist/clis/jike/like.js +1 -2
  106. package/dist/clis/jike/notifications.js +0 -1
  107. package/dist/clis/jike/post.yaml +1 -0
  108. package/dist/clis/jike/repost.js +1 -2
  109. package/dist/clis/jike/search.js +2 -3
  110. package/dist/clis/jike/topic.yaml +1 -0
  111. package/dist/clis/jike/user.yaml +1 -0
  112. package/dist/clis/jimeng/history.yaml +0 -1
  113. package/dist/clis/linkedin/search.js +7 -7
  114. package/dist/clis/linux-do/category.yaml +1 -0
  115. package/dist/clis/linux-do/search.yaml +4 -3
  116. package/dist/clis/linux-do/topic.yaml +1 -0
  117. package/dist/clis/notion/export.js +1 -1
  118. package/dist/clis/reddit/comment.js +3 -4
  119. package/dist/clis/reddit/read.js +4 -5
  120. package/dist/clis/reddit/save.js +2 -3
  121. package/dist/clis/reddit/saved.js +0 -1
  122. package/dist/clis/reddit/search.yaml +1 -0
  123. package/dist/clis/reddit/subscribe.js +0 -1
  124. package/dist/clis/reddit/upvote.js +2 -3
  125. package/dist/clis/reddit/upvoted.js +0 -1
  126. package/dist/clis/reddit/user-comments.yaml +1 -0
  127. package/dist/clis/reddit/user-posts.yaml +1 -0
  128. package/dist/clis/reddit/user.yaml +1 -0
  129. package/dist/clis/reuters/search.js +1 -1
  130. package/dist/clis/sinafinance/news.d.ts +7 -0
  131. package/dist/clis/sinafinance/news.js +61 -0
  132. package/dist/clis/smzdm/search.js +2 -3
  133. package/dist/clis/stackoverflow/search.yaml +1 -0
  134. package/dist/clis/steam/top-sellers.yaml +29 -0
  135. package/dist/clis/twitter/accept.js +2 -2
  136. package/dist/clis/twitter/article.js +2 -2
  137. package/dist/clis/twitter/block.d.ts +1 -0
  138. package/dist/clis/twitter/block.js +88 -0
  139. package/dist/clis/twitter/delete.js +1 -1
  140. package/dist/clis/twitter/hide-reply.d.ts +1 -0
  141. package/dist/clis/twitter/hide-reply.js +66 -0
  142. package/dist/clis/twitter/like.js +1 -1
  143. package/dist/clis/twitter/post.js +1 -1
  144. package/dist/clis/twitter/reply-dm.js +1 -1
  145. package/dist/clis/twitter/reply.js +2 -2
  146. package/dist/clis/twitter/search.js +1 -1
  147. package/dist/clis/twitter/thread.js +2 -2
  148. package/dist/clis/twitter/trending.d.ts +1 -0
  149. package/dist/clis/twitter/trending.js +91 -0
  150. package/dist/clis/twitter/unblock.d.ts +1 -0
  151. package/dist/clis/twitter/unblock.js +71 -0
  152. package/dist/clis/v2ex/topic.yaml +1 -0
  153. package/dist/clis/weibo/hot.js +0 -1
  154. package/dist/clis/weread/book.js +1 -1
  155. package/dist/clis/weread/highlights.js +1 -1
  156. package/dist/clis/weread/notes.js +1 -1
  157. package/dist/clis/weread/search.js +1 -1
  158. package/dist/clis/wikipedia/search.d.ts +1 -0
  159. package/dist/clis/wikipedia/search.js +30 -0
  160. package/dist/clis/wikipedia/summary.d.ts +1 -0
  161. package/dist/clis/wikipedia/summary.js +28 -0
  162. package/dist/clis/wikipedia/utils.d.ts +8 -0
  163. package/dist/clis/wikipedia/utils.js +18 -0
  164. package/dist/clis/xiaohongshu/creator-note-detail.d.ts +79 -5
  165. package/dist/clis/xiaohongshu/creator-note-detail.js +323 -70
  166. package/dist/clis/xiaohongshu/creator-note-detail.test.d.ts +1 -0
  167. package/dist/clis/xiaohongshu/creator-note-detail.test.js +258 -0
  168. package/dist/clis/xiaohongshu/creator-notes-summary.d.ts +28 -0
  169. package/dist/clis/xiaohongshu/creator-notes-summary.js +92 -0
  170. package/dist/clis/xiaohongshu/creator-notes-summary.test.d.ts +1 -0
  171. package/dist/clis/xiaohongshu/creator-notes-summary.test.js +49 -0
  172. package/dist/clis/xiaohongshu/creator-notes.d.ts +18 -5
  173. package/dist/clis/xiaohongshu/creator-notes.js +189 -71
  174. package/dist/clis/xiaohongshu/creator-notes.test.d.ts +1 -0
  175. package/dist/clis/xiaohongshu/creator-notes.test.js +191 -0
  176. package/dist/clis/xiaohongshu/creator-profile.js +0 -1
  177. package/dist/clis/xiaohongshu/creator-stats.js +0 -1
  178. package/dist/clis/xiaohongshu/download.js +2 -3
  179. package/dist/clis/xiaohongshu/feed.yaml +0 -1
  180. package/dist/clis/xiaohongshu/notifications.yaml +0 -1
  181. package/dist/clis/xiaohongshu/search.js +2 -2
  182. package/dist/clis/xiaohongshu/user.js +1 -2
  183. package/dist/clis/yahoo-finance/quote.js +0 -1
  184. package/dist/clis/youtube/search.js +1 -1
  185. package/dist/clis/youtube/transcript.js +1 -1
  186. package/dist/clis/youtube/video.js +1 -1
  187. package/dist/clis/zhihu/download.js +1 -2
  188. package/dist/clis/zhihu/question.js +1 -1
  189. package/dist/clis/zhihu/search.yaml +4 -3
  190. package/dist/commanderAdapter.d.ts +21 -0
  191. package/dist/commanderAdapter.js +111 -0
  192. package/dist/{engine.d.ts → discovery.d.ts} +0 -6
  193. package/dist/{engine.js → discovery.js} +1 -98
  194. package/dist/download/index.d.ts +2 -6
  195. package/dist/download/index.js +19 -46
  196. package/dist/engine.test.d.ts +1 -1
  197. package/dist/engine.test.js +8 -7
  198. package/dist/execution.d.ts +22 -0
  199. package/dist/execution.js +129 -0
  200. package/dist/explore.js +121 -107
  201. package/dist/external-clis.yaml +48 -0
  202. package/dist/external.d.ts +25 -0
  203. package/dist/external.js +156 -0
  204. package/dist/main.js +1 -1
  205. package/dist/pipeline/steps/browser.js +8 -2
  206. package/dist/registry.d.ts +2 -0
  207. package/dist/registry.js +2 -0
  208. package/dist/runtime.d.ts +5 -0
  209. package/dist/runtime.js +8 -0
  210. package/dist/serialization.d.ts +34 -0
  211. package/dist/serialization.js +63 -0
  212. package/dist/types.d.ts +4 -1
  213. package/docs/.vitepress/config.mts +14 -3
  214. package/docs/adapters/browser/arxiv.md +27 -0
  215. package/docs/adapters/browser/barchart.md +32 -0
  216. package/docs/adapters/browser/bloomberg.md +70 -0
  217. package/docs/adapters/browser/chaoxing.md +39 -0
  218. package/docs/adapters/browser/grok.md +35 -0
  219. package/docs/adapters/browser/hf.md +42 -0
  220. package/docs/adapters/browser/jike.md +45 -0
  221. package/docs/adapters/browser/jimeng.md +39 -0
  222. package/docs/adapters/browser/linux-do.md +45 -0
  223. package/docs/adapters/browser/sinafinance.md +35 -0
  224. package/docs/adapters/browser/stackoverflow.md +35 -0
  225. package/docs/adapters/browser/steam.md +26 -0
  226. package/docs/adapters/browser/twitter.md +3 -0
  227. package/docs/adapters/browser/weread.md +48 -0
  228. package/docs/adapters/browser/wikipedia.md +30 -0
  229. package/docs/adapters/browser/xiaohongshu.md +5 -1
  230. package/docs/adapters/desktop/chatgpt.md +3 -3
  231. package/docs/adapters/index.md +13 -0
  232. package/docs/advanced/download.md +4 -4
  233. package/docs/developer/architecture.md +17 -4
  234. package/package.json +1 -1
  235. package/scripts/check-doc-coverage.sh +69 -0
  236. package/scripts/copy-yaml.cjs +7 -0
  237. package/src/browser/cdp.ts +9 -4
  238. package/src/browser/page.ts +7 -1
  239. package/src/build-manifest.ts +25 -19
  240. package/src/cli.ts +253 -119
  241. package/src/clis/antigravity/serve.ts +323 -50
  242. package/src/clis/apple-podcasts/commands.test.ts +95 -0
  243. package/src/clis/apple-podcasts/search.ts +2 -2
  244. package/src/clis/apple-podcasts/top.ts +12 -2
  245. package/src/clis/arxiv/paper.ts +21 -0
  246. package/src/clis/arxiv/search.ts +24 -0
  247. package/src/clis/arxiv/utils.ts +63 -0
  248. package/src/clis/bilibili/dynamic.ts +1 -1
  249. package/src/clis/bilibili/favorite.ts +1 -1
  250. package/src/clis/bilibili/feed.ts +1 -1
  251. package/src/clis/bilibili/following.ts +1 -1
  252. package/src/clis/bilibili/history.ts +1 -1
  253. package/src/clis/bilibili/me.ts +1 -1
  254. package/src/clis/bilibili/ranking.ts +1 -1
  255. package/src/clis/bilibili/search.ts +3 -3
  256. package/src/clis/bilibili/subtitle.ts +1 -1
  257. package/src/clis/bilibili/user-videos.ts +1 -1
  258. package/src/{bilibili.ts → clis/bilibili/utils.ts} +1 -1
  259. package/src/clis/bloomberg/businessweek.ts +18 -0
  260. package/src/clis/bloomberg/economics.ts +18 -0
  261. package/src/clis/bloomberg/feeds.ts +16 -0
  262. package/src/clis/bloomberg/industries.ts +18 -0
  263. package/src/clis/bloomberg/main.ts +18 -0
  264. package/src/clis/bloomberg/markets.ts +18 -0
  265. package/src/clis/bloomberg/news.ts +136 -0
  266. package/src/clis/bloomberg/opinions.ts +18 -0
  267. package/src/clis/bloomberg/politics.ts +18 -0
  268. package/src/clis/bloomberg/tech.ts +18 -0
  269. package/src/clis/bloomberg/utils.test.ts +135 -0
  270. package/src/clis/bloomberg/utils.ts +429 -0
  271. package/src/clis/boss/batchgreet.ts +167 -0
  272. package/src/clis/boss/chatlist.ts +2 -2
  273. package/src/clis/boss/detail.ts +2 -2
  274. package/src/clis/boss/exchange.ts +126 -0
  275. package/src/clis/boss/greet.ts +198 -0
  276. package/src/clis/boss/invite.ts +177 -0
  277. package/src/clis/boss/joblist.ts +63 -0
  278. package/src/clis/boss/mark.ts +155 -0
  279. package/src/clis/boss/recommend.ts +94 -0
  280. package/src/clis/boss/search.ts +1 -1
  281. package/src/clis/boss/send.ts +1 -1
  282. package/src/clis/boss/stats.ts +130 -0
  283. package/src/clis/chaoxing/assignments.ts +1 -1
  284. package/src/clis/chaoxing/exams.ts +1 -1
  285. package/src/{chaoxing.test.ts → clis/chaoxing/utils.test.ts} +1 -1
  286. package/src/{chaoxing.ts → clis/chaoxing/utils.ts} +1 -3
  287. package/src/clis/chatgpt/README.zh-CN.md +3 -3
  288. package/src/clis/chatgpt/read.ts +1 -1
  289. package/src/clis/chatwise/export.ts +1 -1
  290. package/src/clis/chatwise/model.ts +2 -2
  291. package/src/clis/chatwise/screenshot.ts +1 -1
  292. package/src/clis/codex/export.ts +1 -1
  293. package/src/clis/codex/model.ts +2 -2
  294. package/src/clis/codex/screenshot.ts +1 -1
  295. package/src/clis/coupang/add-to-cart.ts +3 -4
  296. package/src/clis/coupang/search.ts +2 -4
  297. package/src/{coupang.test.ts → clis/coupang/utils.test.ts} +1 -1
  298. package/src/clis/ctrip/search.ts +1 -1
  299. package/src/clis/cursor/export.ts +1 -1
  300. package/src/clis/cursor/model.ts +2 -2
  301. package/src/clis/cursor/screenshot.ts +1 -1
  302. package/src/clis/jike/comment.ts +2 -3
  303. package/src/clis/jike/create.ts +1 -2
  304. package/src/clis/jike/feed.ts +0 -1
  305. package/src/clis/jike/like.ts +1 -2
  306. package/src/clis/jike/notifications.ts +0 -1
  307. package/src/clis/jike/post.yaml +1 -0
  308. package/src/clis/jike/repost.ts +1 -2
  309. package/src/clis/jike/search.ts +2 -3
  310. package/src/clis/jike/topic.yaml +1 -0
  311. package/src/clis/jike/user.yaml +1 -0
  312. package/src/clis/jimeng/history.yaml +0 -1
  313. package/src/clis/linkedin/search.ts +7 -7
  314. package/src/clis/linux-do/category.yaml +1 -0
  315. package/src/clis/linux-do/search.yaml +4 -3
  316. package/src/clis/linux-do/topic.yaml +1 -0
  317. package/src/clis/notion/export.ts +1 -1
  318. package/src/clis/reddit/comment.ts +3 -4
  319. package/src/clis/reddit/read.ts +4 -5
  320. package/src/clis/reddit/save.ts +2 -3
  321. package/src/clis/reddit/saved.ts +0 -1
  322. package/src/clis/reddit/search.yaml +1 -0
  323. package/src/clis/reddit/subscribe.ts +0 -1
  324. package/src/clis/reddit/upvote.ts +2 -3
  325. package/src/clis/reddit/upvoted.ts +0 -1
  326. package/src/clis/reddit/user-comments.yaml +1 -0
  327. package/src/clis/reddit/user-posts.yaml +1 -0
  328. package/src/clis/reddit/user.yaml +1 -0
  329. package/src/clis/reuters/search.ts +1 -1
  330. package/src/clis/sinafinance/news.ts +76 -0
  331. package/src/clis/smzdm/search.ts +2 -3
  332. package/src/clis/stackoverflow/search.yaml +1 -0
  333. package/src/clis/steam/top-sellers.yaml +29 -0
  334. package/src/clis/twitter/accept.ts +2 -2
  335. package/src/clis/twitter/article.ts +2 -2
  336. package/src/clis/twitter/block.ts +92 -0
  337. package/src/clis/twitter/delete.ts +1 -1
  338. package/src/clis/twitter/hide-reply.ts +70 -0
  339. package/src/clis/twitter/like.ts +1 -1
  340. package/src/clis/twitter/post.ts +1 -1
  341. package/src/clis/twitter/reply-dm.ts +1 -1
  342. package/src/clis/twitter/reply.ts +2 -2
  343. package/src/clis/twitter/search.ts +1 -1
  344. package/src/clis/twitter/thread.ts +2 -2
  345. package/src/clis/twitter/trending.ts +113 -0
  346. package/src/clis/twitter/unblock.ts +75 -0
  347. package/src/clis/v2ex/topic.yaml +1 -0
  348. package/src/clis/weibo/hot.ts +0 -1
  349. package/src/clis/weread/book.ts +1 -1
  350. package/src/clis/weread/highlights.ts +1 -1
  351. package/src/clis/weread/notes.ts +1 -1
  352. package/src/clis/weread/search.ts +1 -1
  353. package/src/clis/wikipedia/search.ts +32 -0
  354. package/src/clis/wikipedia/summary.ts +28 -0
  355. package/src/clis/wikipedia/utils.ts +20 -0
  356. package/src/clis/xiaohongshu/creator-note-detail.test.ts +272 -0
  357. package/src/clis/xiaohongshu/creator-note-detail.ts +425 -73
  358. package/src/clis/xiaohongshu/creator-notes-summary.test.ts +54 -0
  359. package/src/clis/xiaohongshu/creator-notes-summary.ts +120 -0
  360. package/src/clis/xiaohongshu/creator-notes.test.ts +211 -0
  361. package/src/clis/xiaohongshu/creator-notes.ts +254 -75
  362. package/src/clis/xiaohongshu/creator-profile.ts +0 -1
  363. package/src/clis/xiaohongshu/creator-stats.ts +0 -1
  364. package/src/clis/xiaohongshu/download.ts +2 -3
  365. package/src/clis/xiaohongshu/feed.yaml +0 -1
  366. package/src/clis/xiaohongshu/notifications.yaml +0 -1
  367. package/src/clis/xiaohongshu/search.ts +2 -2
  368. package/src/clis/xiaohongshu/user.ts +1 -2
  369. package/src/clis/yahoo-finance/quote.ts +0 -1
  370. package/src/clis/youtube/search.ts +1 -1
  371. package/src/clis/youtube/transcript.ts +1 -1
  372. package/src/clis/youtube/video.ts +1 -1
  373. package/src/clis/zhihu/download.ts +1 -2
  374. package/src/clis/zhihu/question.ts +1 -1
  375. package/src/clis/zhihu/search.yaml +4 -3
  376. package/src/commanderAdapter.ts +113 -0
  377. package/src/daemon.ts +3 -3
  378. package/src/{engine.ts → discovery.ts} +1 -108
  379. package/src/download/index.ts +21 -54
  380. package/src/engine.test.ts +8 -7
  381. package/src/execution.ts +138 -0
  382. package/src/explore.ts +135 -109
  383. package/src/external-clis.yaml +48 -0
  384. package/src/external.ts +185 -0
  385. package/src/main.ts +1 -1
  386. package/src/pipeline/steps/browser.ts +7 -2
  387. package/src/registry.ts +5 -0
  388. package/src/runtime.ts +9 -0
  389. package/src/serialization.ts +79 -0
  390. package/src/types.ts +1 -1
  391. package/tests/e2e/browser-public.test.ts +25 -0
  392. package/tests/e2e/public-commands.test.ts +55 -1
  393. package/dist/clis/twitter/trending.yaml +0 -46
  394. package/src/clis/twitter/trending.yaml +0 -46
  395. /package/dist/{chaoxing.test.d.ts → clis/arxiv/paper.d.ts} +0 -0
  396. /package/dist/{coupang.test.d.ts → clis/arxiv/search.d.ts} +0 -0
  397. /package/dist/{bilibili.js → clis/bilibili/utils.js} +0 -0
  398. /package/dist/{coupang.d.ts → clis/coupang/utils.d.ts} +0 -0
  399. /package/dist/{coupang.js → clis/coupang/utils.js} +0 -0
  400. /package/src/{coupang.ts → clis/coupang/utils.ts} +0 -0
@@ -321,15 +321,15 @@ cli({
321
321
  strategy: Strategy.HEADER,
322
322
  browser: true,
323
323
  args: [
324
- { name: 'query', type: 'string', required: true, help: 'Job search keywords' },
324
+ { name: 'query', type: 'string', required: true, positional: true, help: 'Job search keywords' },
325
325
  { name: 'location', type: 'string', required: false, help: 'Location text such as San Francisco Bay Area' },
326
326
  { name: 'limit', type: 'int', default: 10, help: 'Number of jobs to return (max 100)' },
327
327
  { name: 'start', type: 'int', default: 0, help: 'Result offset for pagination' },
328
328
  { name: 'details', type: 'bool', default: false, help: 'Include full job description and apply URL (slower)' },
329
329
  { name: 'company', type: 'string', required: false, help: 'Comma-separated company names or LinkedIn company IDs' },
330
- { name: 'experience_level', type: 'string', required: false, help: 'Comma-separated: internship, entry, associate, mid-senior, director, executive' },
331
- { name: 'job_type', type: 'string', required: false, help: 'Comma-separated: full-time, part-time, contract, temporary, volunteer, internship, other' },
332
- { name: 'date_posted', type: 'string', required: false, help: 'One of: any, month, week, 24h' },
330
+ { name: 'experience-level', type: 'string', required: false, help: 'Comma-separated: internship, entry, associate, mid-senior, director, executive' },
331
+ { name: 'job-type', type: 'string', required: false, help: 'Comma-separated: full-time, part-time, contract, temporary, volunteer, internship, other' },
332
+ { name: 'date-posted', type: 'string', required: false, help: 'One of: any, month, week, 24h' },
333
333
  { name: 'remote', type: 'string', required: false, help: 'Comma-separated: on-site, hybrid, remote' },
334
334
  ],
335
335
  columns: ['rank', 'title', 'company', 'location', 'listed', 'salary', 'url'],
@@ -353,9 +353,9 @@ cli({
353
353
  limit,
354
354
  start,
355
355
  companyIds,
356
- experienceLevels: mapFilterValues(kwargs.experience_level, EXPERIENCE_LEVELS, 'experience_level'),
357
- jobTypes: mapFilterValues(kwargs.job_type, JOB_TYPES, 'job_type'),
358
- datePostedValues: mapFilterValues(kwargs.date_posted, DATE_POSTED, 'date_posted'),
356
+ experienceLevels: mapFilterValues(kwargs['experience-level'], EXPERIENCE_LEVELS, 'experience_level'),
357
+ jobTypes: mapFilterValues(kwargs['job-type'], JOB_TYPES, 'job_type'),
358
+ datePostedValues: mapFilterValues(kwargs['date-posted'], DATE_POSTED, 'date_posted'),
359
359
  remoteTypes: mapFilterValues(kwargs.remote, REMOTE_TYPES, 'remote'),
360
360
  };
361
361
  const data = await fetchJobCards(page, input);
@@ -10,6 +10,7 @@ args:
10
10
  required: true
11
11
  description: Category slug (use 'categories' command to find)
12
12
  id:
13
+ positional: true
13
14
  type: int
14
15
  required: true
15
16
  description: Category ID (use 'categories' command to find)
@@ -5,10 +5,11 @@ domain: linux.do
5
5
  browser: true
6
6
 
7
7
  args:
8
- keyword:
8
+ query:
9
+ positional: true
9
10
  type: str
10
11
  required: true
11
- description: Search keyword
12
+ description: Search query
12
13
  limit:
13
14
  type: int
14
15
  default: 20
@@ -19,7 +20,7 @@ pipeline:
19
20
 
20
21
  - evaluate: |
21
22
  (async () => {
22
- const keyword = ${{ args.keyword | json }};
23
+ const keyword = ${{ args.query | json }};
23
24
  const res = await fetch('/search.json?q=' + encodeURIComponent(keyword), { credentials: 'include' });
24
25
  if (!res.ok) throw new Error('HTTP ' + res.status + ' - 请先登录 linux.do');
25
26
  let data;
@@ -6,6 +6,7 @@ browser: true
6
6
 
7
7
  args:
8
8
  id:
9
+ positional: true
9
10
  type: int
10
11
  required: true
11
12
  description: Topic ID
@@ -8,7 +8,7 @@ export const exportCommand = cli({
8
8
  strategy: Strategy.UI,
9
9
  browser: true,
10
10
  args: [
11
- { name: 'output', required: false, positional: true, help: 'Output file (default: /tmp/notion-export.md)' },
11
+ { name: 'output', required: false, help: 'Output file (default: /tmp/notion-export.md)' },
12
12
  ],
13
13
  columns: ['Status', 'File'],
14
14
  func: async (page, kwargs) => {
@@ -7,18 +7,17 @@ cli({
7
7
  strategy: Strategy.COOKIE,
8
8
  browser: true,
9
9
  args: [
10
- { name: 'post_id', type: 'string', required: true, help: 'Post ID (e.g. 1abc123) or fullname (t3_xxx)' },
11
- { name: 'text', type: 'string', required: true, help: 'Comment text' },
10
+ { name: 'post-id', type: 'string', required: true, help: 'Post ID (e.g. 1abc123) or fullname (t3_xxx)' },
11
+ { name: 'text', type: 'string', required: true, positional: true, help: 'Comment text' },
12
12
  ],
13
13
  columns: ['status', 'message'],
14
14
  func: async (page, kwargs) => {
15
15
  if (!page)
16
16
  throw new Error('Requires browser');
17
17
  await page.goto('https://www.reddit.com');
18
- await page.wait(3);
19
18
  const result = await page.evaluate(`(async () => {
20
19
  try {
21
- let postId = ${JSON.stringify(kwargs.post_id)};
20
+ let postId = ${JSON.stringify(kwargs['post-id'])};
22
21
  const urlMatch = postId.match(/comments\\/([a-z0-9]+)/);
23
22
  if (urlMatch) postId = urlMatch[1];
24
23
  const fullname = postId.startsWith('t3_') || postId.startsWith('t1_')
@@ -14,12 +14,12 @@ cli({
14
14
  domain: 'reddit.com',
15
15
  strategy: Strategy.COOKIE,
16
16
  args: [
17
- { name: 'post_id', required: true, help: 'Post ID (e.g. 1abc123) or full URL' },
17
+ { name: 'post-id', required: true, help: 'Post ID (e.g. 1abc123) or full URL' },
18
18
  { name: 'sort', default: 'best', help: 'Comment sort: best, top, new, controversial, old, qa' },
19
19
  { name: 'limit', type: 'int', default: 25, help: 'Number of top-level comments' },
20
20
  { name: 'depth', type: 'int', default: 2, help: 'Max reply depth (1=no replies, 2=one level of replies, etc.)' },
21
21
  { name: 'replies', type: 'int', default: 5, help: 'Max replies shown per comment at each level (sorted by score)' },
22
- { name: 'max_length', type: 'int', default: 2000, help: 'Max characters per comment body (min 100)' },
22
+ { name: 'max-length', type: 'int', default: 2000, help: 'Max characters per comment body (min 100)' },
23
23
  ],
24
24
  columns: ['type', 'author', 'score', 'text'],
25
25
  func: async (page, kwargs) => {
@@ -27,12 +27,11 @@ cli({
27
27
  const limit = Math.max(1, kwargs.limit ?? 25);
28
28
  const maxDepth = Math.max(1, kwargs.depth ?? 2);
29
29
  const maxReplies = Math.max(1, kwargs.replies ?? 5);
30
- const maxLength = Math.max(100, kwargs.max_length ?? 2000);
30
+ const maxLength = Math.max(100, kwargs['max-length'] ?? 2000);
31
31
  await page.goto('https://www.reddit.com');
32
- await page.wait(2);
33
32
  const data = await page.evaluate(`
34
33
  (async function() {
35
- var postId = ${JSON.stringify(kwargs.post_id)};
34
+ var postId = ${JSON.stringify(kwargs['post-id'])};
36
35
  var urlMatch = postId.match(/comments\\/([a-z0-9]+)/);
37
36
  if (urlMatch) postId = urlMatch[1];
38
37
 
@@ -7,7 +7,7 @@ cli({
7
7
  strategy: Strategy.COOKIE,
8
8
  browser: true,
9
9
  args: [
10
- { name: 'post_id', type: 'string', required: true, help: 'Post ID (e.g. 1abc123) or fullname (t3_xxx)' },
10
+ { name: 'post-id', type: 'string', required: true, help: 'Post ID (e.g. 1abc123) or fullname (t3_xxx)' },
11
11
  { name: 'undo', type: 'boolean', default: false, help: 'Unsave instead of save' },
12
12
  ],
13
13
  columns: ['status', 'message'],
@@ -15,10 +15,9 @@ cli({
15
15
  if (!page)
16
16
  throw new Error('Requires browser');
17
17
  await page.goto('https://www.reddit.com');
18
- await page.wait(3);
19
18
  const result = await page.evaluate(`(async () => {
20
19
  try {
21
- let postId = ${JSON.stringify(kwargs.post_id)};
20
+ let postId = ${JSON.stringify(kwargs['post-id'])};
22
21
  const urlMatch = postId.match(/comments\\/([a-z0-9]+)/);
23
22
  if (urlMatch) postId = urlMatch[1];
24
23
  const fullname = postId.startsWith('t3_') || postId.startsWith('t1_')
@@ -14,7 +14,6 @@ cli({
14
14
  if (!page)
15
15
  throw new Error('Requires browser');
16
16
  await page.goto('https://www.reddit.com');
17
- await page.wait(3);
18
17
  const result = await page.evaluate(`(async () => {
19
18
  try {
20
19
  // Get current username
@@ -7,6 +7,7 @@ browser: true
7
7
 
8
8
  args:
9
9
  query:
10
+ positional: true
10
11
  type: string
11
12
  required: true
12
13
  subreddit:
@@ -15,7 +15,6 @@ cli({
15
15
  if (!page)
16
16
  throw new Error('Requires browser');
17
17
  await page.goto('https://www.reddit.com');
18
- await page.wait(3);
19
18
  const result = await page.evaluate(`(async () => {
20
19
  try {
21
20
  let sub = ${JSON.stringify(kwargs.subreddit)};
@@ -7,7 +7,7 @@ cli({
7
7
  strategy: Strategy.COOKIE,
8
8
  browser: true,
9
9
  args: [
10
- { name: 'post_id', type: 'string', required: true, help: 'Post ID (e.g. 1abc123) or fullname (t3_xxx)' },
10
+ { name: 'post-id', type: 'string', required: true, help: 'Post ID (e.g. 1abc123) or fullname (t3_xxx)' },
11
11
  { name: 'direction', type: 'string', default: 'up', help: 'Vote direction: up, down, none' },
12
12
  ],
13
13
  columns: ['status', 'message'],
@@ -15,10 +15,9 @@ cli({
15
15
  if (!page)
16
16
  throw new Error('Requires browser');
17
17
  await page.goto('https://www.reddit.com');
18
- await page.wait(3);
19
18
  const result = await page.evaluate(`(async () => {
20
19
  try {
21
- let postId = ${JSON.stringify(kwargs.post_id)};
20
+ let postId = ${JSON.stringify(kwargs['post-id'])};
22
21
  // Extract ID from URL if needed
23
22
  const urlMatch = postId.match(/comments\\/([a-z0-9]+)/);
24
23
  if (urlMatch) postId = urlMatch[1];
@@ -14,7 +14,6 @@ cli({
14
14
  if (!page)
15
15
  throw new Error('Requires browser');
16
16
  await page.goto('https://www.reddit.com');
17
- await page.wait(3);
18
17
  const result = await page.evaluate(`(async () => {
19
18
  try {
20
19
  // Get current username
@@ -7,6 +7,7 @@ browser: true
7
7
 
8
8
  args:
9
9
  username:
10
+ positional: true
10
11
  type: string
11
12
  required: true
12
13
  limit:
@@ -7,6 +7,7 @@ browser: true
7
7
 
8
8
  args:
9
9
  username:
10
+ positional: true
10
11
  type: string
11
12
  required: true
12
13
  limit:
@@ -7,6 +7,7 @@ browser: true
7
7
 
8
8
  args:
9
9
  username:
10
+ positional: true
10
11
  type: string
11
12
  required: true
12
13
 
@@ -10,7 +10,7 @@ cli({
10
10
  domain: 'www.reuters.com',
11
11
  strategy: Strategy.COOKIE,
12
12
  args: [
13
- { name: 'query', required: true, help: 'Search query' },
13
+ { name: 'query', required: true, positional: true, help: 'Search query' },
14
14
  { name: 'limit', type: 'int', default: 10, help: 'Number of results (max 40)' },
15
15
  ],
16
16
  columns: ['rank', 'title', 'date', 'section', 'url'],
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Sina Finance 7x24 live news feed.
3
+ *
4
+ * Uses the public CJ API — no key or browser required.
5
+ * https://app.cj.sina.com.cn/api/news/pc
6
+ */
7
+ export {};
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Sina Finance 7x24 live news feed.
3
+ *
4
+ * Uses the public CJ API — no key or browser required.
5
+ * https://app.cj.sina.com.cn/api/news/pc
6
+ */
7
+ import { cli, Strategy } from '../../registry.js';
8
+ import { CliError } from '../../errors.js';
9
+ // User-facing type (0-9) → Sina API tag ID
10
+ const TYPE_MAP = [
11
+ 0, // 0: 全部
12
+ 10, // 1: A股
13
+ 1, // 2: 宏观
14
+ 3, // 3: 公司
15
+ 4, // 4: 数据
16
+ 5, // 5: 市场
17
+ 102, // 6: 国际
18
+ 6, // 7: 观点
19
+ 6, // 8: 央行
20
+ 8, // 9: 其它
21
+ ];
22
+ function stripHtml(html) {
23
+ return html.replace(/<[^>]+>/g, '').trim();
24
+ }
25
+ cli({
26
+ site: 'sinafinance',
27
+ name: 'news',
28
+ description: '新浪财经 7x24 小时实时快讯',
29
+ domain: 'app.cj.sina.com.cn',
30
+ strategy: Strategy.PUBLIC,
31
+ browser: false,
32
+ args: [
33
+ { name: 'limit', type: 'int', default: 20, help: 'Max results (max 50)' },
34
+ { name: 'type', type: 'int', default: 0, help: 'News type: 0=全部 1=A股 2=宏观 3=公司 4=数据 5=市场 6=国际 7=观点 8=央行 9=其它' },
35
+ ],
36
+ columns: ['id', 'time', 'content', 'views'],
37
+ func: async (_page, args) => {
38
+ const limit = Math.max(1, Math.min(Number(args.limit), 50));
39
+ const apiTag = TYPE_MAP[args.type] ?? 0;
40
+ const params = new URLSearchParams({
41
+ page: '1',
42
+ size: String(limit),
43
+ tag: String(apiTag),
44
+ });
45
+ const res = await fetch(`https://app.cj.sina.com.cn/api/news/pc?${params}`);
46
+ if (!res.ok) {
47
+ throw new CliError('FETCH_ERROR', `Sina Finance API HTTP ${res.status}`, 'Check your network connection');
48
+ }
49
+ const json = await res.json();
50
+ const list = json?.result?.data?.feed?.list ?? [];
51
+ if (!list.length) {
52
+ throw new CliError('NOT_FOUND', 'No news found', 'Try a different type or increase limit');
53
+ }
54
+ return list.map((item) => ({
55
+ id: item.id ?? '',
56
+ time: item.create_time ?? '',
57
+ content: stripHtml(item.rich_text ?? ''),
58
+ views: item.view_num ?? 0,
59
+ }));
60
+ },
61
+ });
@@ -13,16 +13,15 @@ cli({
13
13
  domain: 'www.smzdm.com',
14
14
  strategy: Strategy.COOKIE,
15
15
  args: [
16
- { name: 'keyword', required: true, help: 'Search keyword' },
16
+ { name: 'query', required: true, positional: true, help: 'Search keyword' },
17
17
  { name: 'limit', type: 'int', default: 20, help: 'Number of results' },
18
18
  ],
19
19
  columns: ['rank', 'title', 'price', 'mall', 'comments', 'url'],
20
20
  func: async (page, kwargs) => {
21
- const q = encodeURIComponent(kwargs.keyword);
21
+ const q = encodeURIComponent(kwargs.query);
22
22
  const limit = kwargs.limit || 20;
23
23
  // Navigate directly to search results page
24
24
  await page.goto(`https://search.smzdm.com/?c=home&s=${q}&v=b`);
25
- await page.wait(2);
26
25
  const data = await page.evaluate(`
27
26
  (() => {
28
27
  const limit = ${limit};
@@ -7,6 +7,7 @@ browser: false
7
7
 
8
8
  args:
9
9
  query:
10
+ positional: true
10
11
  type: string
11
12
  required: true
12
13
  description: Search query
@@ -0,0 +1,29 @@
1
+ site: steam
2
+ name: top-sellers
3
+ description: Steam top selling games
4
+ domain: store.steampowered.com
5
+ strategy: public
6
+ browser: false
7
+
8
+ args:
9
+ limit:
10
+ type: int
11
+ default: 10
12
+ description: Number of games
13
+
14
+ pipeline:
15
+ - fetch:
16
+ url: https://store.steampowered.com/api/featuredcategories/
17
+
18
+ - select: top_sellers.items
19
+
20
+ - map:
21
+ rank: ${{ index + 1 }}
22
+ name: ${{ item.name }}
23
+ price: ${{ item.final_price }}
24
+ discount: ${{ item.discount_percent }}
25
+ url: https://store.steampowered.com/app/${{ item.id }}
26
+
27
+ - limit: ${{ args.limit }}
28
+
29
+ columns: [rank, name, price, discount, url]
@@ -8,14 +8,14 @@ cli({
8
8
  browser: true,
9
9
  timeoutSeconds: 600, // 10 min — batch operation iterating many conversations
10
10
  args: [
11
- { name: 'keyword', type: 'string', required: true, help: 'Keywords to match (comma-separated for OR, e.g. "群,微信")' },
11
+ { name: 'query', type: 'string', required: true, positional: true, help: 'Keywords to match (comma-separated for OR, e.g. "群,微信")' },
12
12
  { name: 'max', type: 'int', required: false, default: 20, help: 'Maximum number of requests to accept (default: 20)' },
13
13
  ],
14
14
  columns: ['index', 'status', 'user', 'message'],
15
15
  func: async (page, kwargs) => {
16
16
  if (!page)
17
17
  throw new Error('Requires browser');
18
- const keywords = kwargs.keyword.split(',').map((k) => k.trim()).filter(Boolean);
18
+ const keywords = kwargs.query.split(',').map((k) => k.trim()).filter(Boolean);
19
19
  const maxAccepts = kwargs.max ?? 20;
20
20
  const results = [];
21
21
  let acceptCount = 0;
@@ -7,12 +7,12 @@ cli({
7
7
  strategy: Strategy.COOKIE,
8
8
  browser: true,
9
9
  args: [
10
- { name: 'tweet_id', type: 'string', positional: true, required: true, help: 'Tweet ID or URL containing the article' },
10
+ { name: 'tweet-id', type: 'string', positional: true, required: true, help: 'Tweet ID or URL containing the article' },
11
11
  ],
12
12
  columns: ['title', 'author', 'content', 'url'],
13
13
  func: async (page, kwargs) => {
14
14
  // Extract tweet ID from URL if needed
15
- let tweetId = kwargs.tweet_id;
15
+ let tweetId = kwargs['tweet-id'];
16
16
  const urlMatch = tweetId.match(/\/(?:status|article)\/(\d+)/);
17
17
  if (urlMatch)
18
18
  tweetId = urlMatch[1];
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,88 @@
1
+ import { cli, Strategy } from '../../registry.js';
2
+ cli({
3
+ site: 'twitter',
4
+ name: 'block',
5
+ description: 'Block a Twitter user',
6
+ domain: 'x.com',
7
+ strategy: Strategy.UI,
8
+ browser: true,
9
+ args: [
10
+ { name: 'username', type: 'string', positional: true, required: true, help: 'Twitter screen name (without @)' },
11
+ ],
12
+ columns: ['status', 'message'],
13
+ func: async (page, kwargs) => {
14
+ if (!page)
15
+ throw new Error('Requires browser');
16
+ const username = kwargs.username.replace(/^@/, '');
17
+ await page.goto(`https://x.com/${username}`);
18
+ await page.wait(5);
19
+ const result = await page.evaluate(`(async () => {
20
+ try {
21
+ let attempts = 0;
22
+
23
+ // Check if already blocked (profile shows "Blocked" / unblock button)
24
+ while (attempts < 20) {
25
+ const blockedIndicator = document.querySelector('[data-testid$="-unblock"]');
26
+ if (blockedIndicator) {
27
+ return { ok: true, message: 'Already blocking @${username}.' };
28
+ }
29
+
30
+ const moreBtn = document.querySelector('[data-testid="userActions"]');
31
+ if (moreBtn) break;
32
+
33
+ await new Promise(r => setTimeout(r, 500));
34
+ attempts++;
35
+ }
36
+
37
+ const moreBtn = document.querySelector('[data-testid="userActions"]');
38
+ if (!moreBtn) {
39
+ return { ok: false, message: 'Could not find user actions menu. Are you logged in?' };
40
+ }
41
+
42
+ // Open the more actions menu
43
+ moreBtn.click();
44
+ await new Promise(r => setTimeout(r, 1000));
45
+
46
+ // Find the Block menu item
47
+ const menuItems = document.querySelectorAll('[role="menuitem"]');
48
+ let blockItem = null;
49
+ for (const item of menuItems) {
50
+ if (item.textContent && item.textContent.includes('Block')) {
51
+ blockItem = item;
52
+ break;
53
+ }
54
+ }
55
+
56
+ if (!blockItem) {
57
+ return { ok: false, message: 'Could not find Block option in menu.' };
58
+ }
59
+
60
+ blockItem.click();
61
+ await new Promise(r => setTimeout(r, 1000));
62
+
63
+ // Confirm the block in the dialog
64
+ const confirmBtn = document.querySelector('[data-testid="confirmationSheetConfirm"]');
65
+ if (confirmBtn) {
66
+ confirmBtn.click();
67
+ await new Promise(r => setTimeout(r, 1500));
68
+ }
69
+
70
+ // Verify
71
+ const verify = document.querySelector('[data-testid$="-unblock"]');
72
+ if (verify) {
73
+ return { ok: true, message: 'Successfully blocked @${username}.' };
74
+ } else {
75
+ return { ok: false, message: 'Block action initiated but UI did not update.' };
76
+ }
77
+ } catch (e) {
78
+ return { ok: false, message: e.toString() };
79
+ }
80
+ })()`);
81
+ if (result.ok)
82
+ await page.wait(2);
83
+ return [{
84
+ status: result.ok ? 'success' : 'failed',
85
+ message: result.message
86
+ }];
87
+ }
88
+ });
@@ -7,7 +7,7 @@ cli({
7
7
  strategy: Strategy.UI, // Utilizes internal DOM flows for interaction
8
8
  browser: true,
9
9
  args: [
10
- { name: 'url', type: 'string', required: true, help: 'The URL of the tweet to delete' },
10
+ { name: 'url', type: 'string', required: true, positional: true, help: 'The URL of the tweet to delete' },
11
11
  ],
12
12
  columns: ['status', 'message'],
13
13
  func: async (page, kwargs) => {
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,66 @@
1
+ import { cli, Strategy } from '../../registry.js';
2
+ cli({
3
+ site: 'twitter',
4
+ name: 'hide-reply',
5
+ description: 'Hide a reply on your tweet (useful for hiding bot/spam replies)',
6
+ domain: 'x.com',
7
+ strategy: Strategy.UI,
8
+ browser: true,
9
+ args: [
10
+ { name: 'url', type: 'string', required: true, positional: true, help: 'The URL of the reply tweet to hide' },
11
+ ],
12
+ columns: ['status', 'message'],
13
+ func: async (page, kwargs) => {
14
+ if (!page)
15
+ throw new Error('Requires browser');
16
+ await page.goto(kwargs.url);
17
+ await page.wait(5);
18
+ const result = await page.evaluate(`(async () => {
19
+ try {
20
+ let attempts = 0;
21
+ let moreMenu = null;
22
+
23
+ while (attempts < 20) {
24
+ moreMenu = document.querySelector('[aria-label="More"]');
25
+ if (moreMenu) break;
26
+ await new Promise(r => setTimeout(r, 500));
27
+ attempts++;
28
+ }
29
+
30
+ if (!moreMenu) {
31
+ return { ok: false, message: 'Could not find the "More" menu on this tweet. Are you logged in?' };
32
+ }
33
+
34
+ moreMenu.click();
35
+ await new Promise(r => setTimeout(r, 1000));
36
+
37
+ // Look for the "Hide reply" menu item
38
+ const items = document.querySelectorAll('[role="menuitem"]');
39
+ let hideItem = null;
40
+ for (const item of items) {
41
+ if (item.textContent && item.textContent.includes('Hide reply')) {
42
+ hideItem = item;
43
+ break;
44
+ }
45
+ }
46
+
47
+ if (!hideItem) {
48
+ return { ok: false, message: 'Could not find "Hide reply" option. This may not be a reply on your tweet.' };
49
+ }
50
+
51
+ hideItem.click();
52
+ await new Promise(r => setTimeout(r, 1500));
53
+
54
+ return { ok: true, message: 'Reply successfully hidden.' };
55
+ } catch (e) {
56
+ return { ok: false, message: e.toString() };
57
+ }
58
+ })()`);
59
+ if (result.ok)
60
+ await page.wait(2);
61
+ return [{
62
+ status: result.ok ? 'success' : 'failed',
63
+ message: result.message
64
+ }];
65
+ }
66
+ });
@@ -7,7 +7,7 @@ cli({
7
7
  strategy: Strategy.UI, // Utilizes internal DOM flows for interaction
8
8
  browser: true,
9
9
  args: [
10
- { name: 'url', type: 'string', required: true, help: 'The URL of the tweet to like' },
10
+ { name: 'url', type: 'string', required: true, positional: true, help: 'The URL of the tweet to like' },
11
11
  ],
12
12
  columns: ['status', 'message'],
13
13
  func: async (page, kwargs) => {
@@ -7,7 +7,7 @@ cli({
7
7
  strategy: Strategy.UI,
8
8
  browser: true,
9
9
  args: [
10
- { name: 'text', type: 'string', required: true, help: 'The text content of the tweet' },
10
+ { name: 'text', type: 'string', required: true, positional: true, help: 'The text content of the tweet' },
11
11
  ],
12
12
  columns: ['status', 'message', 'text'],
13
13
  func: async (page, kwargs) => {
@@ -8,7 +8,7 @@ cli({
8
8
  browser: true,
9
9
  timeoutSeconds: 600, // 10 min — batch operation
10
10
  args: [
11
- { name: 'text', type: 'string', required: true, help: 'Message text to send (e.g. "我的微信 wxkabi")' },
11
+ { name: 'text', type: 'string', required: true, positional: true, help: 'Message text to send (e.g. "我的微信 wxkabi")' },
12
12
  { name: 'max', type: 'int', required: false, default: 20, help: 'Maximum number of conversations to reply to (default: 20)' },
13
13
  { name: 'skip-replied', type: 'boolean', required: false, default: true, help: 'Skip conversations where you already sent the same text (default: true)' },
14
14
  ],
@@ -7,8 +7,8 @@ cli({
7
7
  strategy: Strategy.UI, // Uses the UI directly to input and click post
8
8
  browser: true,
9
9
  args: [
10
- { name: 'url', type: 'string', required: true, help: 'The URL of the tweet to reply to' },
11
- { name: 'text', type: 'string', required: true, help: 'The text content of your reply' },
10
+ { name: 'url', type: 'string', required: true, positional: true, help: 'The URL of the tweet to reply to' },
11
+ { name: 'text', type: 'string', required: true, positional: true, help: 'The text content of your reply' },
12
12
  ],
13
13
  columns: ['status', 'message', 'text'],
14
14
  func: async (page, kwargs) => {
@@ -7,7 +7,7 @@ cli({
7
7
  strategy: Strategy.INTERCEPT, // Use intercept strategy
8
8
  browser: true,
9
9
  args: [
10
- { name: 'query', type: 'string', required: true },
10
+ { name: 'query', type: 'string', required: true, positional: true },
11
11
  { name: 'limit', type: 'int', default: 15 },
12
12
  ],
13
13
  columns: ['id', 'author', 'text', 'likes', 'views', 'url'],