@jackwener/opencli 1.1.0 → 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 (354) 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 +25 -10
  8. package/README.zh-CN.md +26 -11
  9. package/SKILL.md +95 -31
  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 +431 -276
  15. package/dist/cli.d.ts +6 -0
  16. package/dist/cli.js +189 -162
  17. package/dist/clis/apple-podcasts/commands.test.d.ts +2 -0
  18. package/dist/clis/apple-podcasts/commands.test.js +76 -0
  19. package/dist/clis/apple-podcasts/search.js +2 -2
  20. package/dist/clis/apple-podcasts/top.js +9 -2
  21. package/dist/clis/arxiv/search.js +1 -1
  22. package/dist/clis/bilibili/dynamic.js +1 -1
  23. package/dist/clis/bilibili/favorite.js +1 -1
  24. package/dist/clis/bilibili/feed.js +1 -1
  25. package/dist/clis/bilibili/following.js +1 -1
  26. package/dist/clis/bilibili/history.js +1 -1
  27. package/dist/clis/bilibili/me.js +1 -1
  28. package/dist/clis/bilibili/ranking.js +1 -1
  29. package/dist/clis/bilibili/search.js +3 -3
  30. package/dist/clis/bilibili/subtitle.js +1 -1
  31. package/dist/clis/bilibili/user-videos.js +1 -1
  32. package/dist/{bilibili.d.ts → clis/bilibili/utils.d.ts} +1 -1
  33. package/dist/clis/bloomberg/businessweek.js +17 -0
  34. package/dist/clis/bloomberg/economics.js +17 -0
  35. package/dist/clis/bloomberg/feeds.d.ts +1 -0
  36. package/dist/clis/bloomberg/feeds.js +15 -0
  37. package/dist/clis/bloomberg/industries.d.ts +1 -0
  38. package/dist/clis/bloomberg/industries.js +17 -0
  39. package/dist/clis/bloomberg/main.d.ts +1 -0
  40. package/dist/clis/bloomberg/main.js +17 -0
  41. package/dist/clis/bloomberg/markets.d.ts +1 -0
  42. package/dist/clis/bloomberg/markets.js +17 -0
  43. package/dist/clis/bloomberg/news.d.ts +1 -0
  44. package/dist/clis/bloomberg/news.js +105 -0
  45. package/dist/clis/bloomberg/opinions.d.ts +1 -0
  46. package/dist/clis/bloomberg/opinions.js +17 -0
  47. package/dist/clis/bloomberg/politics.d.ts +1 -0
  48. package/dist/clis/bloomberg/politics.js +17 -0
  49. package/dist/clis/bloomberg/tech.d.ts +1 -0
  50. package/dist/clis/bloomberg/tech.js +17 -0
  51. package/dist/clis/bloomberg/utils.d.ts +34 -0
  52. package/dist/clis/bloomberg/utils.js +364 -0
  53. package/dist/clis/bloomberg/utils.test.d.ts +1 -0
  54. package/dist/clis/bloomberg/utils.test.js +129 -0
  55. package/dist/clis/boss/batchgreet.js +2 -2
  56. package/dist/clis/boss/chatlist.js +2 -2
  57. package/dist/clis/boss/detail.js +2 -2
  58. package/dist/clis/boss/greet.js +4 -4
  59. package/dist/clis/boss/search.js +1 -1
  60. package/dist/clis/boss/send.js +1 -1
  61. package/dist/clis/boss/stats.js +2 -2
  62. package/dist/clis/chaoxing/assignments.js +1 -1
  63. package/dist/clis/chaoxing/exams.js +1 -1
  64. package/dist/{chaoxing.d.ts → clis/chaoxing/utils.d.ts} +1 -1
  65. package/dist/{chaoxing.js → clis/chaoxing/utils.js} +0 -2
  66. package/dist/clis/chaoxing/utils.test.d.ts +1 -0
  67. package/dist/{chaoxing.test.js → clis/chaoxing/utils.test.js} +1 -1
  68. package/dist/clis/chatgpt/read.js +1 -1
  69. package/dist/clis/chatwise/export.js +1 -1
  70. package/dist/clis/chatwise/model.js +2 -2
  71. package/dist/clis/chatwise/screenshot.js +1 -1
  72. package/dist/clis/codex/export.js +1 -1
  73. package/dist/clis/codex/model.js +2 -2
  74. package/dist/clis/codex/screenshot.js +1 -1
  75. package/dist/clis/coupang/add-to-cart.js +3 -4
  76. package/dist/clis/coupang/search.js +2 -4
  77. package/dist/clis/coupang/utils.test.d.ts +1 -0
  78. package/dist/{coupang.test.js → clis/coupang/utils.test.js} +1 -1
  79. package/dist/clis/ctrip/search.js +1 -1
  80. package/dist/clis/cursor/export.js +1 -1
  81. package/dist/clis/cursor/model.js +2 -2
  82. package/dist/clis/cursor/screenshot.js +1 -1
  83. package/dist/clis/jike/comment.js +2 -3
  84. package/dist/clis/jike/create.js +1 -2
  85. package/dist/clis/jike/feed.js +0 -1
  86. package/dist/clis/jike/like.js +1 -2
  87. package/dist/clis/jike/notifications.js +0 -1
  88. package/dist/clis/jike/post.yaml +1 -0
  89. package/dist/clis/jike/repost.js +1 -2
  90. package/dist/clis/jike/search.js +2 -3
  91. package/dist/clis/jike/topic.yaml +1 -0
  92. package/dist/clis/jike/user.yaml +1 -0
  93. package/dist/clis/jimeng/history.yaml +0 -1
  94. package/dist/clis/linkedin/search.js +7 -7
  95. package/dist/clis/linux-do/category.yaml +1 -0
  96. package/dist/clis/linux-do/search.yaml +4 -3
  97. package/dist/clis/linux-do/topic.yaml +1 -0
  98. package/dist/clis/notion/export.js +1 -1
  99. package/dist/clis/reddit/comment.js +3 -4
  100. package/dist/clis/reddit/read.js +4 -5
  101. package/dist/clis/reddit/save.js +2 -3
  102. package/dist/clis/reddit/saved.js +0 -1
  103. package/dist/clis/reddit/search.yaml +1 -0
  104. package/dist/clis/reddit/subscribe.js +0 -1
  105. package/dist/clis/reddit/upvote.js +2 -3
  106. package/dist/clis/reddit/upvoted.js +0 -1
  107. package/dist/clis/reddit/user-comments.yaml +1 -0
  108. package/dist/clis/reddit/user-posts.yaml +1 -0
  109. package/dist/clis/reddit/user.yaml +1 -0
  110. package/dist/clis/reuters/search.js +1 -1
  111. package/dist/clis/smzdm/search.js +2 -3
  112. package/dist/clis/stackoverflow/search.yaml +1 -0
  113. package/dist/clis/steam/top-sellers.yaml +29 -0
  114. package/dist/clis/twitter/accept.js +2 -2
  115. package/dist/clis/twitter/article.js +2 -2
  116. package/dist/clis/twitter/block.d.ts +1 -0
  117. package/dist/clis/twitter/block.js +88 -0
  118. package/dist/clis/twitter/delete.js +1 -1
  119. package/dist/clis/twitter/hide-reply.d.ts +1 -0
  120. package/dist/clis/twitter/hide-reply.js +66 -0
  121. package/dist/clis/twitter/like.js +1 -1
  122. package/dist/clis/twitter/post.js +1 -1
  123. package/dist/clis/twitter/reply-dm.js +1 -1
  124. package/dist/clis/twitter/reply.js +2 -2
  125. package/dist/clis/twitter/search.js +1 -1
  126. package/dist/clis/twitter/thread.js +2 -2
  127. package/dist/clis/twitter/trending.d.ts +1 -0
  128. package/dist/clis/twitter/trending.js +91 -0
  129. package/dist/clis/twitter/unblock.d.ts +1 -0
  130. package/dist/clis/twitter/unblock.js +71 -0
  131. package/dist/clis/v2ex/topic.yaml +1 -0
  132. package/dist/clis/weibo/hot.js +0 -1
  133. package/dist/clis/weread/book.js +1 -1
  134. package/dist/clis/weread/highlights.js +1 -1
  135. package/dist/clis/weread/notes.js +1 -1
  136. package/dist/clis/weread/search.js +1 -1
  137. package/dist/clis/wikipedia/search.js +1 -1
  138. package/dist/clis/xiaohongshu/creator-note-detail.d.ts +15 -0
  139. package/dist/clis/xiaohongshu/creator-note-detail.js +69 -5
  140. package/dist/clis/xiaohongshu/creator-note-detail.test.js +80 -33
  141. package/dist/clis/xiaohongshu/creator-notes.js +35 -5
  142. package/dist/clis/xiaohongshu/creator-notes.test.js +35 -6
  143. package/dist/clis/xiaohongshu/creator-profile.js +0 -1
  144. package/dist/clis/xiaohongshu/creator-stats.js +0 -1
  145. package/dist/clis/xiaohongshu/download.js +2 -3
  146. package/dist/clis/xiaohongshu/feed.yaml +0 -1
  147. package/dist/clis/xiaohongshu/notifications.yaml +0 -1
  148. package/dist/clis/xiaohongshu/search.js +2 -2
  149. package/dist/clis/xiaohongshu/user.js +1 -2
  150. package/dist/clis/yahoo-finance/quote.js +0 -1
  151. package/dist/clis/youtube/search.js +1 -1
  152. package/dist/clis/youtube/transcript.js +1 -1
  153. package/dist/clis/youtube/video.js +1 -1
  154. package/dist/clis/zhihu/download.js +1 -2
  155. package/dist/clis/zhihu/question.js +1 -1
  156. package/dist/clis/zhihu/search.yaml +4 -3
  157. package/dist/commanderAdapter.d.ts +21 -0
  158. package/dist/commanderAdapter.js +111 -0
  159. package/dist/{engine.d.ts → discovery.d.ts} +0 -6
  160. package/dist/{engine.js → discovery.js} +1 -98
  161. package/dist/download/index.d.ts +2 -6
  162. package/dist/download/index.js +19 -46
  163. package/dist/engine.test.d.ts +1 -1
  164. package/dist/engine.test.js +8 -7
  165. package/dist/execution.d.ts +22 -0
  166. package/dist/execution.js +129 -0
  167. package/dist/explore.js +121 -107
  168. package/dist/external-clis.yaml +48 -0
  169. package/dist/external.d.ts +7 -2
  170. package/dist/external.js +11 -14
  171. package/dist/main.js +1 -1
  172. package/dist/pipeline/steps/browser.js +8 -2
  173. package/dist/registry.d.ts +2 -0
  174. package/dist/registry.js +2 -0
  175. package/dist/runtime.d.ts +5 -0
  176. package/dist/runtime.js +8 -0
  177. package/dist/serialization.d.ts +34 -0
  178. package/dist/serialization.js +63 -0
  179. package/dist/types.d.ts +4 -1
  180. package/docs/.vitepress/config.mts +14 -3
  181. package/docs/adapters/browser/arxiv.md +27 -0
  182. package/docs/adapters/browser/barchart.md +32 -0
  183. package/docs/adapters/browser/bloomberg.md +70 -0
  184. package/docs/adapters/browser/chaoxing.md +39 -0
  185. package/docs/adapters/browser/grok.md +35 -0
  186. package/docs/adapters/browser/hf.md +42 -0
  187. package/docs/adapters/browser/jike.md +45 -0
  188. package/docs/adapters/browser/jimeng.md +39 -0
  189. package/docs/adapters/browser/linux-do.md +45 -0
  190. package/docs/adapters/browser/sinafinance.md +35 -0
  191. package/docs/adapters/browser/stackoverflow.md +35 -0
  192. package/docs/adapters/browser/steam.md +26 -0
  193. package/docs/adapters/browser/twitter.md +3 -0
  194. package/docs/adapters/browser/weread.md +48 -0
  195. package/docs/adapters/browser/wikipedia.md +30 -0
  196. package/docs/adapters/browser/xiaohongshu.md +5 -1
  197. package/docs/adapters/desktop/chatgpt.md +3 -3
  198. package/docs/adapters/index.md +13 -0
  199. package/docs/advanced/download.md +4 -4
  200. package/docs/developer/architecture.md +17 -4
  201. package/package.json +1 -1
  202. package/scripts/check-doc-coverage.sh +69 -0
  203. package/scripts/copy-yaml.cjs +7 -0
  204. package/src/browser/cdp.ts +6 -1
  205. package/src/browser/page.ts +7 -1
  206. package/src/build-manifest.ts +25 -19
  207. package/src/cli.ts +218 -139
  208. package/src/clis/apple-podcasts/commands.test.ts +95 -0
  209. package/src/clis/apple-podcasts/search.ts +2 -2
  210. package/src/clis/apple-podcasts/top.ts +12 -2
  211. package/src/clis/arxiv/search.ts +1 -1
  212. package/src/clis/bilibili/dynamic.ts +1 -1
  213. package/src/clis/bilibili/favorite.ts +1 -1
  214. package/src/clis/bilibili/feed.ts +1 -1
  215. package/src/clis/bilibili/following.ts +1 -1
  216. package/src/clis/bilibili/history.ts +1 -1
  217. package/src/clis/bilibili/me.ts +1 -1
  218. package/src/clis/bilibili/ranking.ts +1 -1
  219. package/src/clis/bilibili/search.ts +3 -3
  220. package/src/clis/bilibili/subtitle.ts +1 -1
  221. package/src/clis/bilibili/user-videos.ts +1 -1
  222. package/src/{bilibili.ts → clis/bilibili/utils.ts} +1 -1
  223. package/src/clis/bloomberg/businessweek.ts +18 -0
  224. package/src/clis/bloomberg/economics.ts +18 -0
  225. package/src/clis/bloomberg/feeds.ts +16 -0
  226. package/src/clis/bloomberg/industries.ts +18 -0
  227. package/src/clis/bloomberg/main.ts +18 -0
  228. package/src/clis/bloomberg/markets.ts +18 -0
  229. package/src/clis/bloomberg/news.ts +136 -0
  230. package/src/clis/bloomberg/opinions.ts +18 -0
  231. package/src/clis/bloomberg/politics.ts +18 -0
  232. package/src/clis/bloomberg/tech.ts +18 -0
  233. package/src/clis/bloomberg/utils.test.ts +135 -0
  234. package/src/clis/bloomberg/utils.ts +429 -0
  235. package/src/clis/boss/batchgreet.ts +2 -2
  236. package/src/clis/boss/chatlist.ts +2 -2
  237. package/src/clis/boss/detail.ts +2 -2
  238. package/src/clis/boss/greet.ts +4 -4
  239. package/src/clis/boss/search.ts +1 -1
  240. package/src/clis/boss/send.ts +1 -1
  241. package/src/clis/boss/stats.ts +2 -2
  242. package/src/clis/chaoxing/assignments.ts +1 -1
  243. package/src/clis/chaoxing/exams.ts +1 -1
  244. package/src/{chaoxing.test.ts → clis/chaoxing/utils.test.ts} +1 -1
  245. package/src/{chaoxing.ts → clis/chaoxing/utils.ts} +1 -3
  246. package/src/clis/chatgpt/README.zh-CN.md +3 -3
  247. package/src/clis/chatgpt/read.ts +1 -1
  248. package/src/clis/chatwise/export.ts +1 -1
  249. package/src/clis/chatwise/model.ts +2 -2
  250. package/src/clis/chatwise/screenshot.ts +1 -1
  251. package/src/clis/codex/export.ts +1 -1
  252. package/src/clis/codex/model.ts +2 -2
  253. package/src/clis/codex/screenshot.ts +1 -1
  254. package/src/clis/coupang/add-to-cart.ts +3 -4
  255. package/src/clis/coupang/search.ts +2 -4
  256. package/src/{coupang.test.ts → clis/coupang/utils.test.ts} +1 -1
  257. package/src/clis/ctrip/search.ts +1 -1
  258. package/src/clis/cursor/export.ts +1 -1
  259. package/src/clis/cursor/model.ts +2 -2
  260. package/src/clis/cursor/screenshot.ts +1 -1
  261. package/src/clis/jike/comment.ts +2 -3
  262. package/src/clis/jike/create.ts +1 -2
  263. package/src/clis/jike/feed.ts +0 -1
  264. package/src/clis/jike/like.ts +1 -2
  265. package/src/clis/jike/notifications.ts +0 -1
  266. package/src/clis/jike/post.yaml +1 -0
  267. package/src/clis/jike/repost.ts +1 -2
  268. package/src/clis/jike/search.ts +2 -3
  269. package/src/clis/jike/topic.yaml +1 -0
  270. package/src/clis/jike/user.yaml +1 -0
  271. package/src/clis/jimeng/history.yaml +0 -1
  272. package/src/clis/linkedin/search.ts +7 -7
  273. package/src/clis/linux-do/category.yaml +1 -0
  274. package/src/clis/linux-do/search.yaml +4 -3
  275. package/src/clis/linux-do/topic.yaml +1 -0
  276. package/src/clis/notion/export.ts +1 -1
  277. package/src/clis/reddit/comment.ts +3 -4
  278. package/src/clis/reddit/read.ts +4 -5
  279. package/src/clis/reddit/save.ts +2 -3
  280. package/src/clis/reddit/saved.ts +0 -1
  281. package/src/clis/reddit/search.yaml +1 -0
  282. package/src/clis/reddit/subscribe.ts +0 -1
  283. package/src/clis/reddit/upvote.ts +2 -3
  284. package/src/clis/reddit/upvoted.ts +0 -1
  285. package/src/clis/reddit/user-comments.yaml +1 -0
  286. package/src/clis/reddit/user-posts.yaml +1 -0
  287. package/src/clis/reddit/user.yaml +1 -0
  288. package/src/clis/reuters/search.ts +1 -1
  289. package/src/clis/smzdm/search.ts +2 -3
  290. package/src/clis/stackoverflow/search.yaml +1 -0
  291. package/src/clis/steam/top-sellers.yaml +29 -0
  292. package/src/clis/twitter/accept.ts +2 -2
  293. package/src/clis/twitter/article.ts +2 -2
  294. package/src/clis/twitter/block.ts +92 -0
  295. package/src/clis/twitter/delete.ts +1 -1
  296. package/src/clis/twitter/hide-reply.ts +70 -0
  297. package/src/clis/twitter/like.ts +1 -1
  298. package/src/clis/twitter/post.ts +1 -1
  299. package/src/clis/twitter/reply-dm.ts +1 -1
  300. package/src/clis/twitter/reply.ts +2 -2
  301. package/src/clis/twitter/search.ts +1 -1
  302. package/src/clis/twitter/thread.ts +2 -2
  303. package/src/clis/twitter/trending.ts +113 -0
  304. package/src/clis/twitter/unblock.ts +75 -0
  305. package/src/clis/v2ex/topic.yaml +1 -0
  306. package/src/clis/weibo/hot.ts +0 -1
  307. package/src/clis/weread/book.ts +1 -1
  308. package/src/clis/weread/highlights.ts +1 -1
  309. package/src/clis/weread/notes.ts +1 -1
  310. package/src/clis/weread/search.ts +1 -1
  311. package/src/clis/wikipedia/search.ts +1 -1
  312. package/src/clis/xiaohongshu/creator-note-detail.test.ts +82 -33
  313. package/src/clis/xiaohongshu/creator-note-detail.ts +89 -5
  314. package/src/clis/xiaohongshu/creator-notes.test.ts +39 -6
  315. package/src/clis/xiaohongshu/creator-notes.ts +44 -5
  316. package/src/clis/xiaohongshu/creator-profile.ts +0 -1
  317. package/src/clis/xiaohongshu/creator-stats.ts +0 -1
  318. package/src/clis/xiaohongshu/download.ts +2 -3
  319. package/src/clis/xiaohongshu/feed.yaml +0 -1
  320. package/src/clis/xiaohongshu/notifications.yaml +0 -1
  321. package/src/clis/xiaohongshu/search.ts +2 -2
  322. package/src/clis/xiaohongshu/user.ts +1 -2
  323. package/src/clis/yahoo-finance/quote.ts +0 -1
  324. package/src/clis/youtube/search.ts +1 -1
  325. package/src/clis/youtube/transcript.ts +1 -1
  326. package/src/clis/youtube/video.ts +1 -1
  327. package/src/clis/zhihu/download.ts +1 -2
  328. package/src/clis/zhihu/question.ts +1 -1
  329. package/src/clis/zhihu/search.yaml +4 -3
  330. package/src/commanderAdapter.ts +113 -0
  331. package/src/{engine.ts → discovery.ts} +1 -108
  332. package/src/download/index.ts +21 -54
  333. package/src/engine.test.ts +8 -7
  334. package/src/execution.ts +138 -0
  335. package/src/explore.ts +135 -109
  336. package/src/external-clis.yaml +9 -0
  337. package/src/external.ts +15 -12
  338. package/src/main.ts +1 -1
  339. package/src/pipeline/steps/browser.ts +7 -2
  340. package/src/registry.ts +5 -0
  341. package/src/runtime.ts +9 -0
  342. package/src/serialization.ts +79 -0
  343. package/src/types.ts +1 -1
  344. package/tests/e2e/browser-public.test.ts +25 -0
  345. package/tests/e2e/public-commands.test.ts +55 -1
  346. package/dist/clis/twitter/trending.yaml +0 -46
  347. package/docs/public/CNAME +0 -1
  348. package/src/clis/twitter/trending.yaml +0 -46
  349. /package/dist/{bilibili.js → clis/bilibili/utils.js} +0 -0
  350. /package/dist/{chaoxing.test.d.ts → clis/bloomberg/businessweek.d.ts} +0 -0
  351. /package/dist/{coupang.test.d.ts → clis/bloomberg/economics.d.ts} +0 -0
  352. /package/dist/{coupang.d.ts → clis/coupang/utils.d.ts} +0 -0
  353. /package/dist/{coupang.js → clis/coupang/utils.js} +0 -0
  354. /package/src/{coupang.ts → clis/coupang/utils.ts} +0 -0
@@ -4,7 +4,7 @@ import { getVisibleChatMessages } from './ax.js';
4
4
  export const readCommand = cli({
5
5
  site: 'chatgpt',
6
6
  name: 'read',
7
- description: 'Copy the most recent ChatGPT Desktop App response to clipboard and read it',
7
+ description: 'Read the last visible message from the focused ChatGPT Desktop window',
8
8
  domain: 'localhost',
9
9
  strategy: Strategy.PUBLIC,
10
10
  browser: false,
@@ -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/chatwise-export.md)' },
11
+ { name: 'output', required: false, help: 'Output file (default: /tmp/chatwise-export.md)' },
12
12
  ],
13
13
  columns: ['Status', 'File', 'Messages'],
14
14
  func: async (page, kwargs) => {
@@ -7,11 +7,11 @@ export const modelCommand = cli({
7
7
  strategy: Strategy.UI,
8
8
  browser: true,
9
9
  args: [
10
- { name: 'model_name', required: false, positional: true, help: 'Model to switch to (e.g. gpt-4, claude-3)' },
10
+ { name: 'model-name', required: false, positional: true, help: 'Model to switch to (e.g. gpt-4, claude-3)' },
11
11
  ],
12
12
  columns: ['Status', 'Model'],
13
13
  func: async (page, kwargs) => {
14
- const desiredModel = kwargs.model_name;
14
+ const desiredModel = kwargs['model-name'];
15
15
  if (!desiredModel) {
16
16
  // Read current model
17
17
  const currentModel = await page.evaluate(`
@@ -8,7 +8,7 @@ export const screenshotCommand = cli({
8
8
  strategy: Strategy.UI,
9
9
  browser: true,
10
10
  args: [
11
- { name: 'output', required: false, positional: true, help: 'Output file path (default: /tmp/chatwise-snapshot)' },
11
+ { name: 'output', required: false, help: 'Output file path (default: /tmp/chatwise-snapshot)' },
12
12
  ],
13
13
  columns: ['Status', 'File'],
14
14
  func: async (page, kwargs) => {
@@ -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/codex-export.md)' },
11
+ { name: 'output', required: false, help: 'Output file (default: /tmp/codex-export.md)' },
12
12
  ],
13
13
  columns: ['Status', 'File', 'Messages'],
14
14
  func: async (page, kwargs) => {
@@ -7,11 +7,11 @@ export const modelCommand = cli({
7
7
  strategy: Strategy.UI,
8
8
  browser: true,
9
9
  args: [
10
- { name: 'model_name', required: false, positional: true, help: 'The ID of the model to switch to (e.g. gpt-4)' }
10
+ { name: 'model-name', required: false, positional: true, help: 'The ID of the model to switch to (e.g. gpt-4)' }
11
11
  ],
12
12
  columns: ['Status', 'Model'],
13
13
  func: async (page, kwargs) => {
14
- const desiredModel = kwargs.model_name;
14
+ const desiredModel = kwargs['model-name'];
15
15
  if (!desiredModel) {
16
16
  // Just read the current model. We traverse iframes/webviews if needed.
17
17
  const currentModel = await page.evaluate(`
@@ -8,7 +8,7 @@ export const screenshotCommand = cli({
8
8
  strategy: Strategy.UI,
9
9
  browser: true,
10
10
  args: [
11
- { name: 'output', required: false, positional: true, help: 'Output file path (default: /tmp/codex-snapshot.txt)' },
11
+ { name: 'output', required: false, help: 'Output file path (default: /tmp/codex-snapshot.txt)' },
12
12
  ],
13
13
  columns: ['Status', 'File'],
14
14
  func: async (page, kwargs) => {
@@ -1,5 +1,5 @@
1
1
  import { cli, Strategy } from '../../registry.js';
2
- import { canonicalizeProductUrl, normalizeProductId } from '../../coupang.js';
2
+ import { canonicalizeProductUrl, normalizeProductId } from './utils.js';
3
3
  function escapeJsString(value) {
4
4
  return JSON.stringify(value);
5
5
  }
@@ -99,12 +99,12 @@ cli({
99
99
  strategy: Strategy.COOKIE,
100
100
  browser: true,
101
101
  args: [
102
- { name: 'productId', required: false, help: 'Coupang product ID' },
102
+ { name: 'product-id', required: false, help: 'Coupang product ID' },
103
103
  { name: 'url', required: false, help: 'Canonical product URL' },
104
104
  ],
105
105
  columns: ['ok', 'product_id', 'url', 'message'],
106
106
  func: async (page, kwargs) => {
107
- const rawProductId = kwargs.productId ?? kwargs.product_id;
107
+ const rawProductId = kwargs['product-id'] ?? kwargs['product-id'];
108
108
  const productId = normalizeProductId(rawProductId);
109
109
  const targetUrl = canonicalizeProductUrl(kwargs.url, productId);
110
110
  if (!productId && !targetUrl) {
@@ -112,7 +112,6 @@ cli({
112
112
  }
113
113
  const finalUrl = targetUrl || canonicalizeProductUrl('', productId);
114
114
  await page.goto(finalUrl);
115
- await page.wait(3);
116
115
  const result = await page.evaluate(buildAddToCartEvaluate(productId));
117
116
  const loginHints = result?.loginHints ?? {};
118
117
  if (loginHints.hasLoginLink && !loginHints.hasMyCoupang) {
@@ -1,5 +1,5 @@
1
1
  import { cli, Strategy } from '../../registry.js';
2
- import { mergeSearchItems, normalizeSearchItem, sanitizeSearchItems } from '../../coupang.js';
2
+ import { mergeSearchItems, normalizeSearchItem, sanitizeSearchItems } from './utils.js';
3
3
  function escapeJsString(value) {
4
4
  return JSON.stringify(value);
5
5
  }
@@ -404,7 +404,7 @@ cli({
404
404
  strategy: Strategy.COOKIE,
405
405
  browser: true,
406
406
  args: [
407
- { name: 'query', required: true, help: 'Search keyword' },
407
+ { name: 'query', required: true, positional: true, help: 'Search keyword' },
408
408
  { name: 'page', type: 'int', default: 1, help: 'Search result page number' },
409
409
  { name: 'limit', type: 'int', default: 20, help: 'Max results (max 50)' },
410
410
  { name: 'filter', required: false, help: 'Optional search filter (currently supports: rocket)' },
@@ -420,7 +420,6 @@ cli({
420
420
  const initialPage = filter ? 1 : pageNumber;
421
421
  const url = `https://www.coupang.com/np/search?q=${encodeURIComponent(query)}&channel=user&page=${initialPage}`;
422
422
  await page.goto(url);
423
- await page.wait(3);
424
423
  if (filter) {
425
424
  const filterResult = await page.evaluate(buildApplyFilterEvaluate(filter));
426
425
  if (!filterResult?.ok) {
@@ -432,7 +431,6 @@ cli({
432
431
  const filteredUrl = new URL(locationInfo?.href || url);
433
432
  filteredUrl.searchParams.set('page', String(pageNumber));
434
433
  await page.goto(filteredUrl.toString());
435
- await page.wait(3);
436
434
  }
437
435
  }
438
436
  await page.autoScroll({ times: filter ? 3 : 2, delayMs: 1500 });
@@ -0,0 +1 @@
1
+ export {};
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from 'vitest';
2
- import { canonicalizeProductUrl, dedupeSearchItems, normalizeProductId, normalizeSearchItem, sanitizeSearchItems, } from './coupang.js';
2
+ import { canonicalizeProductUrl, dedupeSearchItems, normalizeProductId, normalizeSearchItem, sanitizeSearchItems, } from './utils.js';
3
3
  describe('normalizeProductId', () => {
4
4
  it('extracts product id from canonical path', () => {
5
5
  expect(normalizeProductId('https://www.coupang.com/vp/products/123456789')).toBe('123456789');
@@ -10,7 +10,7 @@ cli({
10
10
  domain: 'www.ctrip.com',
11
11
  strategy: Strategy.COOKIE,
12
12
  args: [
13
- { name: 'query', required: true, help: 'Search keyword (city or attraction)' },
13
+ { name: 'query', required: true, positional: true, help: 'Search keyword (city or attraction)' },
14
14
  { name: 'limit', type: 'int', default: 15, help: 'Number of results' },
15
15
  ],
16
16
  columns: ['rank', 'name', 'type', 'score', 'price', 'url'],
@@ -9,7 +9,7 @@ function makeExportCommand(site, readSelector) {
9
9
  strategy: Strategy.UI,
10
10
  browser: true,
11
11
  args: [
12
- { name: 'output', required: false, positional: true, help: `Output file (default: /tmp/${site}-export.md)` },
12
+ { name: 'output', required: false, help: `Output file (default: /tmp/${site}-export.md)` },
13
13
  ],
14
14
  columns: ['Status', 'File', 'Messages'],
15
15
  func: async (page, kwargs) => {
@@ -7,11 +7,11 @@ export const modelCommand = cli({
7
7
  strategy: Strategy.UI,
8
8
  browser: true,
9
9
  args: [
10
- { name: 'model_name', required: false, positional: true, help: 'The ID of the model to switch to (e.g. claude-3.5-sonnet)' }
10
+ { name: 'model-name', required: false, positional: true, help: 'The ID of the model to switch to (e.g. claude-3.5-sonnet)' }
11
11
  ],
12
12
  columns: ['Status', 'Model'],
13
13
  func: async (page, kwargs) => {
14
- const desiredModel = kwargs.model_name;
14
+ const desiredModel = kwargs['model-name'];
15
15
  if (!desiredModel) {
16
16
  // Just read the current model
17
17
  const currentModel = await page.evaluate(`
@@ -9,7 +9,7 @@ function makeScreenshotCommand(site) {
9
9
  strategy: Strategy.UI,
10
10
  browser: true,
11
11
  args: [
12
- { name: 'output', required: false, positional: true, help: `Output file path (default: /tmp/${site}-snapshot.txt)` },
12
+ { name: 'output', required: false, help: `Output file path (default: /tmp/${site}-snapshot.txt)` },
13
13
  ],
14
14
  columns: ['Status', 'File'],
15
15
  func: async (page, kwargs) => {
@@ -13,13 +13,12 @@ cli({
13
13
  strategy: Strategy.UI,
14
14
  browser: true,
15
15
  args: [
16
- { name: 'id', type: 'string', required: true, help: '帖子 ID' },
17
- { name: 'text', type: 'string', required: true, help: '评论内容' },
16
+ { name: 'id', type: 'string', required: true, positional: true, help: '帖子 ID' },
17
+ { name: 'text', type: 'string', required: true, positional: true, help: '评论内容' },
18
18
  ],
19
19
  columns: ['status', 'message'],
20
20
  func: async (page, kwargs) => {
21
21
  await page.goto(`https://web.okjike.com/originalPost/${kwargs.id}`);
22
- await page.wait(5);
23
22
  // 1. 找到评论输入框并填入文本
24
23
  const inputResult = await page.evaluate(`(async () => {
25
24
  try {
@@ -13,13 +13,12 @@ cli({
13
13
  strategy: Strategy.UI,
14
14
  browser: true,
15
15
  args: [
16
- { name: 'text', type: 'string', required: true, help: '动态正文内容' },
16
+ { name: 'text', type: 'string', required: true, positional: true, help: '动态正文内容' },
17
17
  ],
18
18
  columns: ['status', 'message'],
19
19
  func: async (page, kwargs) => {
20
20
  // 1. 导航到首页(有内联发帖框)
21
21
  await page.goto('https://web.okjike.com');
22
- await page.wait(5);
23
22
  // 2. 在发帖框中输入文本
24
23
  const textResult = await page.evaluate(`(async () => {
25
24
  try {
@@ -21,7 +21,6 @@ cli({
21
21
  const limit = kwargs.limit || 20;
22
22
  // 1. 导航到即刻首页,等待 SPA 重定向到 /following
23
23
  await page.goto('https://web.okjike.com');
24
- await page.wait(5);
25
24
  // 2. 通过 React fiber 提取帖子数据
26
25
  const extract = async () => {
27
26
  return (await page.evaluate(`(() => {
@@ -13,13 +13,12 @@ cli({
13
13
  strategy: Strategy.UI,
14
14
  browser: true,
15
15
  args: [
16
- { name: 'id', type: 'string', required: true, help: '帖子 ID' },
16
+ { name: 'id', type: 'string', required: true, positional: true, help: '帖子 ID' },
17
17
  ],
18
18
  columns: ['status', 'message'],
19
19
  func: async (page, kwargs) => {
20
20
  // 1. 导航到帖子详情页
21
21
  await page.goto(`https://web.okjike.com/originalPost/${kwargs.id}`);
22
- await page.wait(5);
23
22
  // 2. 找到点赞按钮并点击
24
23
  const result = await page.evaluate(`(async () => {
25
24
  try {
@@ -33,7 +33,6 @@ cli({
33
33
  const limit = kwargs.limit || 20;
34
34
  // 1. 直接导航到通知页
35
35
  await page.goto('https://web.okjike.com/notification');
36
- await page.wait(5);
37
36
  // 3. 优先用 React fiber 提取通知数据
38
37
  // 通知 fiber 数据结构与帖子不同,需查找含 type + user 字段的 props
39
38
  const fiberResults = (await page.evaluate(`(() => {
@@ -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)
@@ -14,13 +14,12 @@ cli({
14
14
  strategy: Strategy.UI,
15
15
  browser: true,
16
16
  args: [
17
- { name: 'id', type: 'string', required: true, help: '帖子 ID' },
17
+ { name: 'id', type: 'string', required: true, positional: true, help: '帖子 ID' },
18
18
  { name: 'text', type: 'string', required: false, help: '转发附言(可选)' },
19
19
  ],
20
20
  columns: ['status', 'message'],
21
21
  func: async (page, kwargs) => {
22
22
  await page.goto(`https://web.okjike.com/originalPost/${kwargs.id}`);
23
- await page.wait(5);
24
23
  // 1. 点击操作栏中的转发按钮(第三个子元素)
25
24
  const clickResult = await page.evaluate(`(async () => {
26
25
  try {
@@ -14,17 +14,16 @@ cli({
14
14
  strategy: Strategy.COOKIE,
15
15
  browser: true,
16
16
  args: [
17
- { name: 'keyword', type: 'string', required: true },
17
+ { name: 'query', type: 'string', required: true, positional: true },
18
18
  { name: 'limit', type: 'int', default: 20 },
19
19
  ],
20
20
  columns: ['author', 'content', 'likes', 'comments', 'time', 'url'],
21
21
  func: async (page, kwargs) => {
22
- const keyword = kwargs.keyword;
22
+ const keyword = kwargs.query;
23
23
  const limit = kwargs.limit || 20;
24
24
  // 1. 直接导航到搜索页
25
25
  const encodedKeyword = encodeURIComponent(keyword);
26
26
  await page.goto(`https://web.okjike.com/search?q=${encodedKeyword}`);
27
- await page.wait(5);
28
27
  // 2. 通过 React fiber 提取帖子数据
29
28
  const extract = async () => {
30
29
  return (await page.evaluate(`(() => {
@@ -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 }};
@@ -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'],
@@ -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