@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
@@ -9,11 +9,11 @@ export const modelCommand = cli({
9
9
  strategy: Strategy.UI,
10
10
  browser: true,
11
11
  args: [
12
- { name: 'model_name', required: false, positional: true, help: 'The ID of the model to switch to (e.g. claude-3.5-sonnet)' }
12
+ { name: 'model-name', required: false, positional: true, help: 'The ID of the model to switch to (e.g. claude-3.5-sonnet)' }
13
13
  ],
14
14
  columns: ['Status', 'Model'],
15
15
  func: async (page: IPage, kwargs: any) => {
16
- const desiredModel = kwargs.model_name as string | undefined;
16
+ const desiredModel = kwargs['model-name'] as string | undefined;
17
17
 
18
18
  if (!desiredModel) {
19
19
  // Just read the current model
@@ -11,7 +11,7 @@ function makeScreenshotCommand(site: string) {
11
11
  strategy: Strategy.UI,
12
12
  browser: true,
13
13
  args: [
14
- { name: 'output', required: false, positional: true, help: `Output file path (default: /tmp/${site}-snapshot.txt)` },
14
+ { name: 'output', required: false, help: `Output file path (default: /tmp/${site}-snapshot.txt)` },
15
15
  ],
16
16
  columns: ['Status', 'File'],
17
17
  func: async (page: IPage, kwargs: any) => {
@@ -15,13 +15,12 @@ cli({
15
15
  strategy: Strategy.UI,
16
16
  browser: true,
17
17
  args: [
18
- { name: 'id', type: 'string', required: true, help: '帖子 ID' },
19
- { name: 'text', type: 'string', required: true, help: '评论内容' },
18
+ { name: 'id', type: 'string', required: true, positional: true, help: '帖子 ID' },
19
+ { name: 'text', type: 'string', required: true, positional: true, help: '评论内容' },
20
20
  ],
21
21
  columns: ['status', 'message'],
22
22
  func: async (page, kwargs) => {
23
23
  await page.goto(`https://web.okjike.com/originalPost/${kwargs.id}`);
24
- await page.wait(5);
25
24
 
26
25
  // 1. 找到评论输入框并填入文本
27
26
  const inputResult = await page.evaluate(`(async () => {
@@ -15,13 +15,12 @@ cli({
15
15
  strategy: Strategy.UI,
16
16
  browser: true,
17
17
  args: [
18
- { name: 'text', type: 'string', required: true, help: '动态正文内容' },
18
+ { name: 'text', type: 'string', required: true, positional: true, help: '动态正文内容' },
19
19
  ],
20
20
  columns: ['status', 'message'],
21
21
  func: async (page, kwargs) => {
22
22
  // 1. 导航到首页(有内联发帖框)
23
23
  await page.goto('https://web.okjike.com');
24
- await page.wait(5);
25
24
 
26
25
  // 2. 在发帖框中输入文本
27
26
  const textResult = await page.evaluate(`(async () => {
@@ -24,7 +24,6 @@ cli({
24
24
 
25
25
  // 1. 导航到即刻首页,等待 SPA 重定向到 /following
26
26
  await page.goto('https://web.okjike.com');
27
- await page.wait(5);
28
27
 
29
28
  // 2. 通过 React fiber 提取帖子数据
30
29
  const extract = async (): Promise<JikePost[]> => {
@@ -15,13 +15,12 @@ cli({
15
15
  strategy: Strategy.UI,
16
16
  browser: true,
17
17
  args: [
18
- { name: 'id', type: 'string', required: true, help: '帖子 ID' },
18
+ { name: 'id', type: 'string', required: true, positional: true, help: '帖子 ID' },
19
19
  ],
20
20
  columns: ['status', 'message'],
21
21
  func: async (page, kwargs) => {
22
22
  // 1. 导航到帖子详情页
23
23
  await page.goto(`https://web.okjike.com/originalPost/${kwargs.id}`);
24
- await page.wait(5);
25
24
 
26
25
  // 2. 找到点赞按钮并点击
27
26
  const result = await page.evaluate(`(async () => {
@@ -44,7 +44,6 @@ cli({
44
44
 
45
45
  // 1. 直接导航到通知页
46
46
  await page.goto('https://web.okjike.com/notification');
47
- await page.wait(5);
48
47
 
49
48
  // 3. 优先用 React fiber 提取通知数据
50
49
  // 通知 fiber 数据结构与帖子不同,需查找含 type + user 字段的 props
@@ -6,6 +6,7 @@ browser: true
6
6
 
7
7
  args:
8
8
  id:
9
+ positional: true
9
10
  type: string
10
11
  required: true
11
12
  description: Post ID (from post URL)
@@ -16,13 +16,12 @@ cli({
16
16
  strategy: Strategy.UI,
17
17
  browser: true,
18
18
  args: [
19
- { name: 'id', type: 'string', required: true, help: '帖子 ID' },
19
+ { name: 'id', type: 'string', required: true, positional: true, help: '帖子 ID' },
20
20
  { name: 'text', type: 'string', required: false, help: '转发附言(可选)' },
21
21
  ],
22
22
  columns: ['status', 'message'],
23
23
  func: async (page, kwargs) => {
24
24
  await page.goto(`https://web.okjike.com/originalPost/${kwargs.id}`);
25
- await page.wait(5);
26
25
 
27
26
  // 1. 点击操作栏中的转发按钮(第三个子元素)
28
27
  const clickResult = await page.evaluate(`(async () => {
@@ -16,18 +16,17 @@ cli({
16
16
  strategy: Strategy.COOKIE,
17
17
  browser: true,
18
18
  args: [
19
- { name: 'keyword', type: 'string', required: true },
19
+ { name: 'query', type: 'string', required: true, positional: true },
20
20
  { name: 'limit', type: 'int', default: 20 },
21
21
  ],
22
22
  columns: ['author', 'content', 'likes', 'comments', 'time', 'url'],
23
23
  func: async (page, kwargs) => {
24
- const keyword = kwargs.keyword as string;
24
+ const keyword = kwargs.query as string;
25
25
  const limit = (kwargs.limit as number) || 20;
26
26
 
27
27
  // 1. 直接导航到搜索页
28
28
  const encodedKeyword = encodeURIComponent(keyword);
29
29
  await page.goto(`https://web.okjike.com/search?q=${encodedKeyword}`);
30
- await page.wait(5);
31
30
 
32
31
  // 2. 通过 React fiber 提取帖子数据
33
32
  const extract = async (): Promise<JikePost[]> => {
@@ -6,6 +6,7 @@ browser: true
6
6
 
7
7
  args:
8
8
  id:
9
+ positional: true
9
10
  type: string
10
11
  required: true
11
12
  description: Topic ID (from topic URL, e.g. 553870e8e4b0cafb0a1bef68)
@@ -6,6 +6,7 @@ browser: true
6
6
 
7
7
  args:
8
8
  username:
9
+ positional: true
9
10
  type: string
10
11
  required: true
11
12
  description: Username from profile URL (e.g. wenhao1996)
@@ -14,7 +14,6 @@ columns: [prompt, model, status, image_url, created_at]
14
14
 
15
15
  pipeline:
16
16
  - navigate: https://jimeng.jianying.com/ai-tool/generate?type=image&workspace=0
17
- - wait: 3
18
17
  - evaluate: |
19
18
  (async () => {
20
19
  const limit = ${{ args.limit }};
@@ -368,15 +368,15 @@ cli({
368
368
  strategy: Strategy.HEADER,
369
369
  browser: true,
370
370
  args: [
371
- { name: 'query', type: 'string', required: true, help: 'Job search keywords' },
371
+ { name: 'query', type: 'string', required: true, positional: true, help: 'Job search keywords' },
372
372
  { name: 'location', type: 'string', required: false, help: 'Location text such as San Francisco Bay Area' },
373
373
  { name: 'limit', type: 'int', default: 10, help: 'Number of jobs to return (max 100)' },
374
374
  { name: 'start', type: 'int', default: 0, help: 'Result offset for pagination' },
375
375
  { name: 'details', type: 'bool', default: false, help: 'Include full job description and apply URL (slower)' },
376
376
  { name: 'company', type: 'string', required: false, help: 'Comma-separated company names or LinkedIn company IDs' },
377
- { name: 'experience_level', type: 'string', required: false, help: 'Comma-separated: internship, entry, associate, mid-senior, director, executive' },
378
- { name: 'job_type', type: 'string', required: false, help: 'Comma-separated: full-time, part-time, contract, temporary, volunteer, internship, other' },
379
- { name: 'date_posted', type: 'string', required: false, help: 'One of: any, month, week, 24h' },
377
+ { name: 'experience-level', type: 'string', required: false, help: 'Comma-separated: internship, entry, associate, mid-senior, director, executive' },
378
+ { name: 'job-type', type: 'string', required: false, help: 'Comma-separated: full-time, part-time, contract, temporary, volunteer, internship, other' },
379
+ { name: 'date-posted', type: 'string', required: false, help: 'One of: any, month, week, 24h' },
380
380
  { name: 'remote', type: 'string', required: false, help: 'Comma-separated: on-site, hybrid, remote' },
381
381
  ],
382
382
  columns: ['rank', 'title', 'company', 'location', 'listed', 'salary', 'url'],
@@ -402,9 +402,9 @@ cli({
402
402
  limit,
403
403
  start,
404
404
  companyIds,
405
- experienceLevels: mapFilterValues(kwargs.experience_level, EXPERIENCE_LEVELS, 'experience_level'),
406
- jobTypes: mapFilterValues(kwargs.job_type, JOB_TYPES, 'job_type'),
407
- datePostedValues: mapFilterValues(kwargs.date_posted, DATE_POSTED, 'date_posted'),
405
+ experienceLevels: mapFilterValues(kwargs['experience-level'], EXPERIENCE_LEVELS, 'experience_level'),
406
+ jobTypes: mapFilterValues(kwargs['job-type'], JOB_TYPES, 'job_type'),
407
+ datePostedValues: mapFilterValues(kwargs['date-posted'], DATE_POSTED, 'date_posted'),
408
408
  remoteTypes: mapFilterValues(kwargs.remote, REMOTE_TYPES, 'remote'),
409
409
  };
410
410
 
@@ -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
@@ -10,7 +10,7 @@ export const exportCommand = cli({
10
10
  strategy: Strategy.UI,
11
11
  browser: true,
12
12
  args: [
13
- { name: 'output', required: false, positional: true, help: 'Output file (default: /tmp/notion-export.md)' },
13
+ { name: 'output', required: false, help: 'Output file (default: /tmp/notion-export.md)' },
14
14
  ],
15
15
  columns: ['Status', 'File'],
16
16
  func: async (page: IPage, kwargs: any) => {
@@ -8,19 +8,18 @@ cli({
8
8
  strategy: Strategy.COOKIE,
9
9
  browser: true,
10
10
  args: [
11
- { name: 'post_id', type: 'string', required: true, help: 'Post ID (e.g. 1abc123) or fullname (t3_xxx)' },
12
- { name: 'text', type: 'string', required: true, help: 'Comment text' },
11
+ { name: 'post-id', type: 'string', required: true, help: 'Post ID (e.g. 1abc123) or fullname (t3_xxx)' },
12
+ { name: 'text', type: 'string', required: true, positional: true, help: 'Comment text' },
13
13
  ],
14
14
  columns: ['status', 'message'],
15
15
  func: async (page, kwargs) => {
16
16
  if (!page) throw new Error('Requires browser');
17
17
 
18
18
  await page.goto('https://www.reddit.com');
19
- await page.wait(3);
20
19
 
21
20
  const result = await page.evaluate(`(async () => {
22
21
  try {
23
- let postId = ${JSON.stringify(kwargs.post_id)};
22
+ let postId = ${JSON.stringify(kwargs['post-id'])};
24
23
  const urlMatch = postId.match(/comments\\/([a-z0-9]+)/);
25
24
  if (urlMatch) postId = urlMatch[1];
26
25
  const fullname = postId.startsWith('t3_') || postId.startsWith('t1_')
@@ -15,12 +15,12 @@ cli({
15
15
  domain: 'reddit.com',
16
16
  strategy: Strategy.COOKIE,
17
17
  args: [
18
- { name: 'post_id', required: true, help: 'Post ID (e.g. 1abc123) or full URL' },
18
+ { name: 'post-id', required: true, help: 'Post ID (e.g. 1abc123) or full URL' },
19
19
  { name: 'sort', default: 'best', help: 'Comment sort: best, top, new, controversial, old, qa' },
20
20
  { name: 'limit', type: 'int', default: 25, help: 'Number of top-level comments' },
21
21
  { name: 'depth', type: 'int', default: 2, help: 'Max reply depth (1=no replies, 2=one level of replies, etc.)' },
22
22
  { name: 'replies', type: 'int', default: 5, help: 'Max replies shown per comment at each level (sorted by score)' },
23
- { name: 'max_length', type: 'int', default: 2000, help: 'Max characters per comment body (min 100)' },
23
+ { name: 'max-length', type: 'int', default: 2000, help: 'Max characters per comment body (min 100)' },
24
24
  ],
25
25
  columns: ['type', 'author', 'score', 'text'],
26
26
  func: async (page, kwargs) => {
@@ -28,14 +28,13 @@ cli({
28
28
  const limit = Math.max(1, kwargs.limit ?? 25);
29
29
  const maxDepth = Math.max(1, kwargs.depth ?? 2);
30
30
  const maxReplies = Math.max(1, kwargs.replies ?? 5);
31
- const maxLength = Math.max(100, kwargs.max_length ?? 2000);
31
+ const maxLength = Math.max(100, kwargs['max-length'] ?? 2000);
32
32
 
33
33
  await page.goto('https://www.reddit.com');
34
- await page.wait(2);
35
34
 
36
35
  const data = await page.evaluate(`
37
36
  (async function() {
38
- var postId = ${JSON.stringify(kwargs.post_id)};
37
+ var postId = ${JSON.stringify(kwargs['post-id'])};
39
38
  var urlMatch = postId.match(/comments\\/([a-z0-9]+)/);
40
39
  if (urlMatch) postId = urlMatch[1];
41
40
 
@@ -8,7 +8,7 @@ cli({
8
8
  strategy: Strategy.COOKIE,
9
9
  browser: true,
10
10
  args: [
11
- { name: 'post_id', type: 'string', required: true, help: 'Post ID (e.g. 1abc123) or fullname (t3_xxx)' },
11
+ { name: 'post-id', type: 'string', required: true, help: 'Post ID (e.g. 1abc123) or fullname (t3_xxx)' },
12
12
  { name: 'undo', type: 'boolean', default: false, help: 'Unsave instead of save' },
13
13
  ],
14
14
  columns: ['status', 'message'],
@@ -16,11 +16,10 @@ cli({
16
16
  if (!page) throw new Error('Requires browser');
17
17
 
18
18
  await page.goto('https://www.reddit.com');
19
- await page.wait(3);
20
19
 
21
20
  const result = await page.evaluate(`(async () => {
22
21
  try {
23
- let postId = ${JSON.stringify(kwargs.post_id)};
22
+ let postId = ${JSON.stringify(kwargs['post-id'])};
24
23
  const urlMatch = postId.match(/comments\\/([a-z0-9]+)/);
25
24
  if (urlMatch) postId = urlMatch[1];
26
25
  const fullname = postId.startsWith('t3_') || postId.startsWith('t1_')
@@ -15,7 +15,6 @@ cli({
15
15
  if (!page) throw new Error('Requires browser');
16
16
 
17
17
  await page.goto('https://www.reddit.com');
18
- await page.wait(3);
19
18
 
20
19
  const result = await page.evaluate(`(async () => {
21
20
  try {
@@ -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:
@@ -16,7 +16,6 @@ cli({
16
16
  if (!page) throw new Error('Requires browser');
17
17
 
18
18
  await page.goto('https://www.reddit.com');
19
- await page.wait(3);
20
19
 
21
20
  const result = await page.evaluate(`(async () => {
22
21
  try {
@@ -8,7 +8,7 @@ cli({
8
8
  strategy: Strategy.COOKIE,
9
9
  browser: true,
10
10
  args: [
11
- { name: 'post_id', type: 'string', required: true, help: 'Post ID (e.g. 1abc123) or fullname (t3_xxx)' },
11
+ { name: 'post-id', type: 'string', required: true, help: 'Post ID (e.g. 1abc123) or fullname (t3_xxx)' },
12
12
  { name: 'direction', type: 'string', default: 'up', help: 'Vote direction: up, down, none' },
13
13
  ],
14
14
  columns: ['status', 'message'],
@@ -16,11 +16,10 @@ cli({
16
16
  if (!page) throw new Error('Requires browser');
17
17
 
18
18
  await page.goto('https://www.reddit.com');
19
- await page.wait(3);
20
19
 
21
20
  const result = await page.evaluate(`(async () => {
22
21
  try {
23
- let postId = ${JSON.stringify(kwargs.post_id)};
22
+ let postId = ${JSON.stringify(kwargs['post-id'])};
24
23
  // Extract ID from URL if needed
25
24
  const urlMatch = postId.match(/comments\\/([a-z0-9]+)/);
26
25
  if (urlMatch) postId = urlMatch[1];
@@ -15,7 +15,6 @@ cli({
15
15
  if (!page) throw new Error('Requires browser');
16
16
 
17
17
  await page.goto('https://www.reddit.com');
18
- await page.wait(3);
19
18
 
20
19
  const result = await page.evaluate(`(async () => {
21
20
  try {
@@ -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
 
@@ -11,7 +11,7 @@ cli({
11
11
  domain: 'www.reuters.com',
12
12
  strategy: Strategy.COOKIE,
13
13
  args: [
14
- { name: 'query', required: true, help: 'Search query' },
14
+ { name: 'query', required: true, positional: true, help: 'Search query' },
15
15
  { name: 'limit', type: 'int', default: 10, help: 'Number of results (max 40)' },
16
16
  ],
17
17
  columns: ['rank', 'title', 'date', 'section', 'url'],
@@ -0,0 +1,76 @@
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
+
8
+ import { cli, Strategy } from '../../registry.js';
9
+ import { CliError } from '../../errors.js';
10
+
11
+ // User-facing type (0-9) → Sina API tag ID
12
+ const TYPE_MAP = [
13
+ 0, // 0: 全部
14
+ 10, // 1: A股
15
+ 1, // 2: 宏观
16
+ 3, // 3: 公司
17
+ 4, // 4: 数据
18
+ 5, // 5: 市场
19
+ 102, // 6: 国际
20
+ 6, // 7: 观点
21
+ 6, // 8: 央行
22
+ 8, // 9: 其它
23
+ ] as const;
24
+
25
+ interface SinaNewsItem {
26
+ id?: string;
27
+ create_time?: string;
28
+ rich_text?: string;
29
+ view_num?: number;
30
+ }
31
+
32
+ function stripHtml(html: string): string {
33
+ return html.replace(/<[^>]+>/g, '').trim();
34
+ }
35
+
36
+ cli({
37
+ site: 'sinafinance',
38
+ name: 'news',
39
+ description: '新浪财经 7x24 小时实时快讯',
40
+ domain: 'app.cj.sina.com.cn',
41
+ strategy: Strategy.PUBLIC,
42
+ browser: false,
43
+ args: [
44
+ { name: 'limit', type: 'int', default: 20, help: 'Max results (max 50)' },
45
+ { name: 'type', type: 'int', default: 0, help: 'News type: 0=全部 1=A股 2=宏观 3=公司 4=数据 5=市场 6=国际 7=观点 8=央行 9=其它' },
46
+ ],
47
+ columns: ['id', 'time', 'content', 'views'],
48
+ func: async (_page, args) => {
49
+ const limit = Math.max(1, Math.min(Number(args.limit), 50));
50
+ const apiTag = TYPE_MAP[args.type as number] ?? 0;
51
+
52
+ const params = new URLSearchParams({
53
+ page: '1',
54
+ size: String(limit),
55
+ tag: String(apiTag),
56
+ });
57
+
58
+ const res = await fetch(`https://app.cj.sina.com.cn/api/news/pc?${params}`);
59
+ if (!res.ok) {
60
+ throw new CliError('FETCH_ERROR', `Sina Finance API HTTP ${res.status}`, 'Check your network connection');
61
+ }
62
+ const json = await res.json() as { result?: { data?: { feed?: { list?: SinaNewsItem[] } } } };
63
+ const list = json?.result?.data?.feed?.list ?? [];
64
+
65
+ if (!list.length) {
66
+ throw new CliError('NOT_FOUND', 'No news found', 'Try a different type or increase limit');
67
+ }
68
+
69
+ return list.map((item) => ({
70
+ id: item.id ?? '',
71
+ time: item.create_time ?? '',
72
+ content: stripHtml(item.rich_text ?? ''),
73
+ views: item.view_num ?? 0,
74
+ }));
75
+ },
76
+ });
@@ -14,17 +14,16 @@ cli({
14
14
  domain: 'www.smzdm.com',
15
15
  strategy: Strategy.COOKIE,
16
16
  args: [
17
- { name: 'keyword', required: true, help: 'Search keyword' },
17
+ { name: 'query', required: true, positional: true, help: 'Search keyword' },
18
18
  { name: 'limit', type: 'int', default: 20, help: 'Number of results' },
19
19
  ],
20
20
  columns: ['rank', 'title', 'price', 'mall', 'comments', 'url'],
21
21
  func: async (page, kwargs) => {
22
- const q = encodeURIComponent(kwargs.keyword);
22
+ const q = encodeURIComponent(kwargs.query);
23
23
  const limit = kwargs.limit || 20;
24
24
 
25
25
  // Navigate directly to search results page
26
26
  await page.goto(`https://search.smzdm.com/?c=home&s=${q}&v=b`);
27
- await page.wait(2);
28
27
 
29
28
  const data = await page.evaluate(`
30
29
  (() => {
@@ -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]
@@ -10,14 +10,14 @@ cli({
10
10
  browser: true,
11
11
  timeoutSeconds: 600, // 10 min — batch operation iterating many conversations
12
12
  args: [
13
- { name: 'keyword', type: 'string', required: true, help: 'Keywords to match (comma-separated for OR, e.g. "群,微信")' },
13
+ { name: 'query', type: 'string', required: true, positional: true, help: 'Keywords to match (comma-separated for OR, e.g. "群,微信")' },
14
14
  { name: 'max', type: 'int', required: false, default: 20, help: 'Maximum number of requests to accept (default: 20)' },
15
15
  ],
16
16
  columns: ['index', 'status', 'user', 'message'],
17
17
  func: async (page: IPage | null, kwargs: any) => {
18
18
  if (!page) throw new Error('Requires browser');
19
19
 
20
- const keywords: string[] = kwargs.keyword.split(',').map((k: string) => k.trim()).filter(Boolean);
20
+ const keywords: string[] = kwargs.query.split(',').map((k: string) => k.trim()).filter(Boolean);
21
21
  const maxAccepts: number = kwargs.max ?? 20;
22
22
  const results: Array<{ index: number; status: string; user: string; message: string }> = [];
23
23
  let acceptCount = 0;
@@ -8,12 +8,12 @@ cli({
8
8
  strategy: Strategy.COOKIE,
9
9
  browser: true,
10
10
  args: [
11
- { name: 'tweet_id', type: 'string', positional: true, required: true, help: 'Tweet ID or URL containing the article' },
11
+ { name: 'tweet-id', type: 'string', positional: true, required: true, help: 'Tweet ID or URL containing the article' },
12
12
  ],
13
13
  columns: ['title', 'author', 'content', 'url'],
14
14
  func: async (page, kwargs) => {
15
15
  // Extract tweet ID from URL if needed
16
- let tweetId = kwargs.tweet_id;
16
+ let tweetId = kwargs['tweet-id'];
17
17
  const urlMatch = tweetId.match(/\/(?:status|article)\/(\d+)/);
18
18
  if (urlMatch) tweetId = urlMatch[1];
19
19