@jackwener/opencli 1.6.8 → 1.6.10

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 (572) hide show
  1. package/README.md +117 -59
  2. package/README.zh-CN.md +123 -79
  3. package/dist/clis/_shared/common.d.ts +3 -0
  4. package/dist/clis/_shared/common.js +22 -0
  5. package/dist/clis/bilibili/hot.d.ts +1 -0
  6. package/dist/clis/bilibili/hot.js +35 -0
  7. package/dist/clis/bluesky/feeds.d.ts +1 -0
  8. package/dist/clis/bluesky/feeds.js +27 -0
  9. package/dist/clis/bluesky/followers.d.ts +1 -0
  10. package/dist/clis/bluesky/followers.js +27 -0
  11. package/dist/clis/bluesky/following.d.ts +1 -0
  12. package/dist/clis/bluesky/following.js +27 -0
  13. package/dist/clis/bluesky/profile.d.ts +1 -0
  14. package/dist/clis/bluesky/profile.js +29 -0
  15. package/dist/clis/bluesky/search.d.ts +1 -0
  16. package/dist/clis/bluesky/search.js +28 -0
  17. package/dist/clis/bluesky/starter-packs.d.ts +1 -0
  18. package/dist/clis/bluesky/starter-packs.js +28 -0
  19. package/dist/clis/bluesky/thread.d.ts +1 -0
  20. package/dist/clis/bluesky/thread.js +30 -0
  21. package/dist/clis/bluesky/trending.d.ts +1 -0
  22. package/dist/clis/bluesky/trending.js +19 -0
  23. package/dist/clis/bluesky/user.d.ts +1 -0
  24. package/dist/clis/bluesky/user.js +33 -0
  25. package/dist/clis/cnki/search.d.ts +1 -0
  26. package/dist/clis/cnki/search.js +60 -0
  27. package/dist/clis/cnki/search.test.d.ts +1 -0
  28. package/dist/clis/cnki/search.test.js +18 -0
  29. package/dist/clis/devto/tag.d.ts +1 -0
  30. package/dist/clis/devto/tag.js +32 -0
  31. package/dist/clis/devto/top.d.ts +1 -0
  32. package/dist/clis/devto/top.js +26 -0
  33. package/dist/clis/devto/user.d.ts +1 -0
  34. package/dist/clis/devto/user.js +31 -0
  35. package/dist/clis/dictionary/examples.d.ts +1 -0
  36. package/dist/clis/dictionary/examples.js +27 -0
  37. package/dist/clis/dictionary/search.d.ts +1 -0
  38. package/dist/clis/dictionary/search.js +29 -0
  39. package/dist/clis/dictionary/synonyms.d.ts +1 -0
  40. package/dist/clis/dictionary/synonyms.js +27 -0
  41. package/dist/clis/douban/subject.d.ts +1 -0
  42. package/dist/clis/douban/subject.js +118 -0
  43. package/dist/clis/douban/top250.d.ts +1 -0
  44. package/dist/clis/douban/top250.js +67 -0
  45. package/dist/clis/facebook/add-friend.d.ts +1 -0
  46. package/dist/clis/facebook/add-friend.js +43 -0
  47. package/dist/clis/facebook/events.d.ts +1 -0
  48. package/dist/clis/facebook/events.js +40 -0
  49. package/dist/clis/facebook/feed.d.ts +1 -0
  50. package/dist/clis/facebook/feed.js +59 -0
  51. package/dist/clis/facebook/friends.d.ts +1 -0
  52. package/dist/clis/facebook/friends.js +38 -0
  53. package/dist/clis/facebook/groups.d.ts +1 -0
  54. package/dist/clis/facebook/groups.js +46 -0
  55. package/dist/clis/facebook/join-group.d.ts +1 -0
  56. package/dist/clis/facebook/join-group.js +44 -0
  57. package/dist/clis/facebook/memories.d.ts +1 -0
  58. package/dist/clis/facebook/memories.js +35 -0
  59. package/dist/clis/facebook/notifications.d.ts +1 -0
  60. package/dist/clis/facebook/notifications.js +36 -0
  61. package/dist/clis/facebook/profile.d.ts +1 -0
  62. package/dist/clis/facebook/profile.js +37 -0
  63. package/dist/clis/facebook/search.d.ts +1 -0
  64. package/dist/clis/facebook/search.js +38 -0
  65. package/dist/clis/facebook/search.test.d.ts +1 -1
  66. package/dist/clis/facebook/search.test.js +6 -9
  67. package/dist/clis/gitee/index.d.ts +3 -0
  68. package/dist/clis/gitee/index.js +3 -0
  69. package/dist/clis/gitee/search.d.ts +1 -0
  70. package/dist/clis/gitee/search.js +136 -0
  71. package/dist/clis/gitee/trending.d.ts +1 -0
  72. package/dist/clis/gitee/trending.js +567 -0
  73. package/dist/clis/gitee/user.d.ts +1 -0
  74. package/dist/clis/gitee/user.js +199 -0
  75. package/dist/clis/gitee/user.test.d.ts +1 -0
  76. package/dist/clis/gitee/user.test.js +63 -0
  77. package/dist/clis/hackernews/ask.d.ts +1 -0
  78. package/dist/clis/hackernews/ask.js +29 -0
  79. package/dist/clis/hackernews/best.d.ts +1 -0
  80. package/dist/clis/hackernews/best.js +29 -0
  81. package/dist/clis/hackernews/jobs.d.ts +1 -0
  82. package/dist/clis/hackernews/jobs.js +27 -0
  83. package/dist/clis/hackernews/new.d.ts +1 -0
  84. package/dist/clis/hackernews/new.js +29 -0
  85. package/dist/clis/hackernews/search.d.ts +1 -0
  86. package/dist/clis/hackernews/search.js +36 -0
  87. package/dist/clis/hackernews/show.d.ts +1 -0
  88. package/dist/clis/hackernews/show.js +29 -0
  89. package/dist/clis/hackernews/top.d.ts +1 -0
  90. package/dist/clis/hackernews/top.js +29 -0
  91. package/dist/clis/hackernews/user.d.ts +1 -0
  92. package/dist/clis/hackernews/user.js +22 -0
  93. package/dist/clis/hupu/hot.d.ts +1 -0
  94. package/dist/clis/hupu/hot.js +40 -0
  95. package/dist/clis/instagram/comment.d.ts +1 -0
  96. package/dist/clis/instagram/comment.js +47 -0
  97. package/dist/clis/instagram/explore.d.ts +1 -0
  98. package/dist/clis/instagram/explore.js +41 -0
  99. package/dist/clis/instagram/follow.d.ts +1 -0
  100. package/dist/clis/instagram/follow.js +43 -0
  101. package/dist/clis/instagram/followers.d.ts +1 -0
  102. package/dist/clis/instagram/followers.js +45 -0
  103. package/dist/clis/instagram/following.d.ts +1 -0
  104. package/dist/clis/instagram/following.js +45 -0
  105. package/dist/clis/instagram/like.d.ts +1 -0
  106. package/dist/clis/instagram/like.js +45 -0
  107. package/dist/clis/instagram/profile.d.ts +1 -0
  108. package/dist/clis/instagram/profile.js +39 -0
  109. package/dist/clis/instagram/save.d.ts +1 -0
  110. package/dist/clis/instagram/save.js +45 -0
  111. package/dist/clis/instagram/saved.d.ts +1 -0
  112. package/dist/clis/instagram/saved.js +38 -0
  113. package/dist/clis/instagram/search.d.ts +1 -0
  114. package/dist/clis/instagram/search.js +38 -0
  115. package/dist/clis/instagram/unfollow.d.ts +1 -0
  116. package/dist/clis/instagram/unfollow.js +40 -0
  117. package/dist/clis/instagram/unlike.d.ts +1 -0
  118. package/dist/clis/instagram/unlike.js +45 -0
  119. package/dist/clis/instagram/unsave.d.ts +1 -0
  120. package/dist/clis/instagram/unsave.js +45 -0
  121. package/dist/clis/instagram/user.d.ts +1 -0
  122. package/dist/clis/instagram/user.js +48 -0
  123. package/dist/clis/jd/add-cart.d.ts +1 -0
  124. package/dist/clis/jd/add-cart.js +71 -0
  125. package/dist/clis/jd/cart.d.ts +1 -0
  126. package/dist/clis/jd/cart.js +79 -0
  127. package/dist/clis/jd/commands.test.d.ts +5 -0
  128. package/dist/clis/jd/commands.test.js +64 -0
  129. package/dist/clis/jd/detail.d.ts +1 -0
  130. package/dist/clis/jd/detail.js +62 -0
  131. package/dist/clis/jd/reviews.d.ts +1 -0
  132. package/dist/clis/jd/reviews.js +54 -0
  133. package/dist/clis/jd/search.d.ts +1 -0
  134. package/dist/clis/jd/search.js +65 -0
  135. package/dist/clis/jianyu/search.d.ts +14 -0
  136. package/dist/clis/jianyu/search.js +135 -0
  137. package/dist/clis/jianyu/search.test.d.ts +1 -0
  138. package/dist/clis/jianyu/search.test.js +23 -0
  139. package/dist/clis/jike/post.d.ts +1 -0
  140. package/dist/clis/jike/post.js +61 -0
  141. package/dist/clis/jike/topic.d.ts +1 -0
  142. package/dist/clis/jike/topic.js +51 -0
  143. package/dist/clis/jike/user.d.ts +1 -0
  144. package/dist/clis/jike/user.js +50 -0
  145. package/dist/clis/jimeng/generate.d.ts +1 -0
  146. package/dist/clis/jimeng/generate.js +83 -0
  147. package/dist/clis/jimeng/history.d.ts +1 -0
  148. package/dist/clis/jimeng/history.js +47 -0
  149. package/dist/clis/jimeng/new.d.ts +1 -0
  150. package/dist/clis/jimeng/new.js +43 -0
  151. package/dist/clis/jimeng/workspaces.d.ts +1 -0
  152. package/dist/clis/jimeng/workspaces.js +41 -0
  153. package/dist/clis/linux-do/categories.d.ts +1 -0
  154. package/dist/clis/linux-do/categories.js +65 -0
  155. package/dist/clis/linux-do/search.d.ts +1 -0
  156. package/dist/clis/linux-do/search.js +41 -0
  157. package/dist/clis/linux-do/tags.d.ts +1 -0
  158. package/dist/clis/linux-do/tags.js +39 -0
  159. package/dist/clis/linux-do/topic-content.test.js +5 -5
  160. package/dist/clis/linux-do/topic.d.ts +1 -0
  161. package/dist/clis/linux-do/topic.js +56 -0
  162. package/dist/clis/linux-do/user-posts.d.ts +1 -0
  163. package/dist/clis/linux-do/user-posts.js +61 -0
  164. package/dist/clis/linux-do/user-topics.d.ts +1 -0
  165. package/dist/clis/linux-do/user-topics.js +48 -0
  166. package/dist/clis/lobsters/active.d.ts +1 -0
  167. package/dist/clis/lobsters/active.js +26 -0
  168. package/dist/clis/lobsters/hot.d.ts +1 -0
  169. package/dist/clis/lobsters/hot.js +26 -0
  170. package/dist/clis/lobsters/newest.d.ts +1 -0
  171. package/dist/clis/lobsters/newest.js +26 -0
  172. package/dist/clis/lobsters/tag.d.ts +1 -0
  173. package/dist/clis/lobsters/tag.js +32 -0
  174. package/dist/clis/pixiv/detail.d.ts +1 -0
  175. package/dist/clis/pixiv/detail.js +58 -0
  176. package/dist/clis/pixiv/ranking.d.ts +1 -0
  177. package/dist/clis/pixiv/ranking.js +59 -0
  178. package/dist/clis/pixiv/user.d.ts +1 -0
  179. package/dist/clis/pixiv/user.js +52 -0
  180. package/dist/clis/quark/ls.d.ts +1 -0
  181. package/dist/clis/quark/ls.js +63 -0
  182. package/dist/clis/quark/mkdir.d.ts +1 -0
  183. package/dist/clis/quark/mkdir.js +36 -0
  184. package/dist/clis/quark/mv.d.ts +1 -0
  185. package/dist/clis/quark/mv.js +53 -0
  186. package/dist/clis/quark/rename.d.ts +1 -0
  187. package/dist/clis/quark/rename.js +26 -0
  188. package/dist/clis/quark/rm.d.ts +1 -0
  189. package/dist/clis/quark/rm.js +24 -0
  190. package/dist/clis/quark/save.d.ts +1 -0
  191. package/dist/clis/quark/save.js +80 -0
  192. package/dist/clis/quark/share-tree.d.ts +1 -0
  193. package/dist/clis/quark/share-tree.js +45 -0
  194. package/dist/clis/quark/utils.d.ts +50 -0
  195. package/dist/clis/quark/utils.js +146 -0
  196. package/dist/clis/quark/utils.test.d.ts +1 -0
  197. package/dist/clis/quark/utils.test.js +58 -0
  198. package/dist/clis/reddit/frontpage.d.ts +1 -0
  199. package/dist/clis/reddit/frontpage.js +31 -0
  200. package/dist/clis/reddit/hot.d.ts +1 -0
  201. package/dist/clis/reddit/hot.js +45 -0
  202. package/dist/clis/reddit/popular.d.ts +1 -0
  203. package/dist/clis/reddit/popular.js +41 -0
  204. package/dist/clis/reddit/search.d.ts +1 -0
  205. package/dist/clis/reddit/search.js +65 -0
  206. package/dist/clis/reddit/subreddit.d.ts +1 -0
  207. package/dist/clis/reddit/subreddit.js +52 -0
  208. package/dist/clis/reddit/user-comments.d.ts +1 -0
  209. package/dist/clis/reddit/user-comments.js +44 -0
  210. package/dist/clis/reddit/user-posts.d.ts +1 -0
  211. package/dist/clis/reddit/user-posts.js +42 -0
  212. package/dist/clis/reddit/user.d.ts +1 -0
  213. package/dist/clis/reddit/user.js +37 -0
  214. package/dist/clis/stackoverflow/bounties.d.ts +1 -0
  215. package/dist/clis/stackoverflow/bounties.js +27 -0
  216. package/dist/clis/stackoverflow/hot.d.ts +1 -0
  217. package/dist/clis/stackoverflow/hot.js +24 -0
  218. package/dist/clis/stackoverflow/search.d.ts +1 -0
  219. package/dist/clis/stackoverflow/search.js +27 -0
  220. package/dist/clis/stackoverflow/unanswered.d.ts +1 -0
  221. package/dist/clis/stackoverflow/unanswered.js +26 -0
  222. package/dist/clis/steam/top-sellers.d.ts +1 -0
  223. package/dist/clis/steam/top-sellers.js +25 -0
  224. package/dist/clis/taobao/add-cart.d.ts +1 -0
  225. package/dist/clis/taobao/add-cart.js +149 -0
  226. package/dist/clis/taobao/cart.d.ts +1 -0
  227. package/dist/clis/taobao/cart.js +95 -0
  228. package/dist/clis/taobao/commands.test.d.ts +5 -0
  229. package/dist/clis/taobao/commands.test.js +64 -0
  230. package/dist/clis/taobao/detail.d.ts +1 -0
  231. package/dist/clis/taobao/detail.js +70 -0
  232. package/dist/clis/taobao/reviews.d.ts +1 -0
  233. package/dist/clis/taobao/reviews.js +76 -0
  234. package/dist/clis/taobao/search.d.ts +1 -0
  235. package/dist/clis/taobao/search.js +96 -0
  236. package/dist/clis/tiktok/comment.d.ts +1 -0
  237. package/dist/clis/tiktok/comment.js +57 -0
  238. package/dist/clis/tiktok/explore.d.ts +1 -0
  239. package/dist/clis/tiktok/explore.js +35 -0
  240. package/dist/clis/tiktok/follow.d.ts +1 -0
  241. package/dist/clis/tiktok/follow.js +39 -0
  242. package/dist/clis/tiktok/following.d.ts +1 -0
  243. package/dist/clis/tiktok/following.js +42 -0
  244. package/dist/clis/tiktok/friends.d.ts +1 -0
  245. package/dist/clis/tiktok/friends.js +43 -0
  246. package/dist/clis/tiktok/like.d.ts +1 -0
  247. package/dist/clis/tiktok/like.js +33 -0
  248. package/dist/clis/tiktok/live.d.ts +1 -0
  249. package/dist/clis/tiktok/live.js +47 -0
  250. package/dist/clis/tiktok/notifications.d.ts +1 -0
  251. package/dist/clis/tiktok/notifications.js +49 -0
  252. package/dist/clis/tiktok/profile.d.ts +1 -0
  253. package/dist/clis/tiktok/profile.js +54 -0
  254. package/dist/clis/tiktok/save.d.ts +1 -0
  255. package/dist/clis/tiktok/save.js +29 -0
  256. package/dist/clis/tiktok/search.d.ts +1 -0
  257. package/dist/clis/tiktok/search.js +39 -0
  258. package/dist/clis/tiktok/unfollow.d.ts +1 -0
  259. package/dist/clis/tiktok/unfollow.js +44 -0
  260. package/dist/clis/tiktok/unlike.d.ts +1 -0
  261. package/dist/clis/tiktok/unlike.js +33 -0
  262. package/dist/clis/tiktok/unsave.d.ts +1 -0
  263. package/dist/clis/tiktok/unsave.js +31 -0
  264. package/dist/clis/tiktok/user.d.ts +1 -0
  265. package/dist/clis/tiktok/user.js +41 -0
  266. package/dist/clis/twitter/reply.js +3 -8
  267. package/dist/clis/twitter/reply.test.js +5 -5
  268. package/dist/clis/v2ex/hot.d.ts +1 -0
  269. package/dist/clis/v2ex/hot.js +25 -0
  270. package/dist/clis/v2ex/latest.d.ts +1 -0
  271. package/dist/clis/v2ex/latest.js +25 -0
  272. package/dist/clis/v2ex/member.d.ts +1 -0
  273. package/dist/clis/v2ex/member.js +27 -0
  274. package/dist/clis/v2ex/node.d.ts +1 -0
  275. package/dist/clis/v2ex/node.js +38 -0
  276. package/dist/clis/v2ex/nodes.d.ts +1 -0
  277. package/dist/clis/v2ex/nodes.js +25 -0
  278. package/dist/clis/v2ex/replies.d.ts +1 -0
  279. package/dist/clis/v2ex/replies.js +26 -0
  280. package/dist/clis/v2ex/topic.d.ts +1 -0
  281. package/dist/clis/v2ex/topic.js +30 -0
  282. package/dist/clis/v2ex/user.d.ts +1 -0
  283. package/dist/clis/v2ex/user.js +33 -0
  284. package/dist/clis/xiaoe/catalog.d.ts +1 -0
  285. package/dist/clis/xiaoe/catalog.js +125 -0
  286. package/dist/clis/xiaoe/content.d.ts +1 -0
  287. package/dist/clis/xiaoe/content.js +39 -0
  288. package/dist/clis/xiaoe/courses.d.ts +1 -0
  289. package/dist/clis/xiaoe/courses.js +69 -0
  290. package/dist/clis/xiaoe/detail.d.ts +1 -0
  291. package/dist/clis/xiaoe/detail.js +35 -0
  292. package/dist/clis/xiaoe/play-url.d.ts +1 -0
  293. package/dist/clis/xiaoe/play-url.js +120 -0
  294. package/dist/clis/xiaohongshu/feed.d.ts +1 -0
  295. package/dist/clis/xiaohongshu/feed.js +32 -0
  296. package/dist/clis/xiaohongshu/note.js +8 -3
  297. package/dist/clis/xiaohongshu/note.test.js +11 -0
  298. package/dist/clis/xiaohongshu/notifications.d.ts +1 -0
  299. package/dist/clis/xiaohongshu/notifications.js +38 -0
  300. package/dist/clis/xueqiu/earnings-date.d.ts +1 -0
  301. package/dist/clis/xueqiu/earnings-date.js +61 -0
  302. package/dist/clis/xueqiu/feed.d.ts +1 -0
  303. package/dist/clis/xueqiu/feed.js +48 -0
  304. package/dist/clis/xueqiu/groups.d.ts +1 -0
  305. package/dist/clis/xueqiu/groups.js +25 -0
  306. package/dist/clis/xueqiu/hot-stock.d.ts +1 -0
  307. package/dist/clis/xueqiu/hot-stock.js +44 -0
  308. package/dist/clis/xueqiu/hot.d.ts +1 -0
  309. package/dist/clis/xueqiu/hot.js +44 -0
  310. package/dist/clis/xueqiu/kline.d.ts +1 -0
  311. package/dist/clis/xueqiu/kline.js +64 -0
  312. package/dist/clis/xueqiu/search.d.ts +1 -0
  313. package/dist/clis/xueqiu/search.js +49 -0
  314. package/dist/clis/xueqiu/stock.d.ts +1 -0
  315. package/dist/clis/xueqiu/stock.js +72 -0
  316. package/dist/clis/xueqiu/watchlist.d.ts +1 -0
  317. package/dist/clis/xueqiu/watchlist.js +45 -0
  318. package/dist/clis/zhihu/answer.d.ts +1 -0
  319. package/dist/clis/zhihu/answer.js +194 -0
  320. package/dist/clis/zhihu/answer.test.d.ts +1 -0
  321. package/dist/clis/zhihu/answer.test.js +81 -0
  322. package/dist/clis/zhihu/comment.d.ts +1 -0
  323. package/dist/clis/zhihu/comment.js +335 -0
  324. package/dist/clis/zhihu/comment.test.d.ts +1 -0
  325. package/dist/clis/zhihu/comment.test.js +54 -0
  326. package/dist/clis/zhihu/favorite.d.ts +1 -0
  327. package/dist/clis/zhihu/favorite.js +224 -0
  328. package/dist/clis/zhihu/favorite.test.d.ts +1 -0
  329. package/dist/clis/zhihu/favorite.test.js +196 -0
  330. package/dist/clis/zhihu/follow.d.ts +1 -0
  331. package/dist/clis/zhihu/follow.js +80 -0
  332. package/dist/clis/zhihu/follow.test.d.ts +1 -0
  333. package/dist/clis/zhihu/follow.test.js +45 -0
  334. package/dist/clis/zhihu/hot.d.ts +1 -0
  335. package/dist/clis/zhihu/hot.js +43 -0
  336. package/dist/clis/zhihu/like.d.ts +1 -0
  337. package/dist/clis/zhihu/like.js +91 -0
  338. package/dist/clis/zhihu/like.test.d.ts +1 -0
  339. package/dist/clis/zhihu/like.test.js +64 -0
  340. package/dist/clis/zhihu/search.d.ts +1 -0
  341. package/dist/clis/zhihu/search.js +52 -0
  342. package/dist/clis/zhihu/target.d.ts +24 -0
  343. package/dist/clis/zhihu/target.js +91 -0
  344. package/dist/clis/zhihu/target.test.d.ts +1 -0
  345. package/dist/clis/zhihu/target.test.js +77 -0
  346. package/dist/clis/zhihu/write-shared.d.ts +32 -0
  347. package/dist/clis/zhihu/write-shared.js +221 -0
  348. package/dist/clis/zhihu/write-shared.test.d.ts +1 -0
  349. package/dist/clis/zhihu/write-shared.test.js +175 -0
  350. package/dist/src/browser/bridge.d.ts +2 -0
  351. package/dist/src/browser/bridge.js +30 -24
  352. package/dist/src/browser/daemon-client.d.ts +30 -10
  353. package/dist/src/browser/daemon-client.js +42 -27
  354. package/dist/src/browser/daemon-client.test.js +32 -25
  355. package/dist/src/browser/dom-helpers.test.js +3 -2
  356. package/dist/src/browser/errors.d.ts +26 -1
  357. package/dist/src/browser/errors.js +40 -7
  358. package/dist/src/browser/errors.test.d.ts +1 -0
  359. package/dist/src/browser/errors.test.js +51 -0
  360. package/dist/src/browser/index.d.ts +2 -1
  361. package/dist/src/browser/index.js +1 -1
  362. package/dist/src/browser/page.d.ts +9 -8
  363. package/dist/src/browser/page.js +33 -31
  364. package/dist/src/browser.test.js +27 -8
  365. package/dist/src/build-manifest.d.ts +5 -11
  366. package/dist/src/build-manifest.js +6 -75
  367. package/dist/src/build-manifest.test.js +1 -39
  368. package/dist/src/cascade.js +3 -2
  369. package/dist/src/cli.d.ts +3 -3
  370. package/dist/src/cli.js +73 -65
  371. package/dist/src/cli.test.js +20 -15
  372. package/dist/src/clis/binance/asks.d.ts +1 -0
  373. package/dist/src/clis/binance/asks.js +20 -0
  374. package/dist/src/clis/binance/commands.test.d.ts +3 -0
  375. package/dist/src/clis/binance/commands.test.js +58 -0
  376. package/dist/src/clis/binance/depth.d.ts +1 -0
  377. package/dist/src/clis/binance/depth.js +20 -0
  378. package/dist/src/clis/binance/gainers.d.ts +1 -0
  379. package/dist/src/clis/binance/gainers.js +21 -0
  380. package/dist/src/clis/binance/klines.d.ts +1 -0
  381. package/dist/src/clis/binance/klines.js +20 -0
  382. package/dist/src/clis/binance/losers.d.ts +1 -0
  383. package/dist/src/clis/binance/losers.js +21 -0
  384. package/dist/src/clis/binance/pairs.d.ts +1 -0
  385. package/dist/src/clis/binance/pairs.js +20 -0
  386. package/dist/src/clis/binance/price.d.ts +1 -0
  387. package/dist/src/clis/binance/price.js +17 -0
  388. package/dist/src/clis/binance/prices.d.ts +1 -0
  389. package/dist/src/clis/binance/prices.js +18 -0
  390. package/dist/src/clis/binance/ticker.d.ts +1 -0
  391. package/dist/src/clis/binance/ticker.js +20 -0
  392. package/dist/src/clis/binance/top.d.ts +1 -0
  393. package/dist/src/clis/binance/top.js +20 -0
  394. package/dist/src/clis/binance/trades.d.ts +1 -0
  395. package/dist/src/clis/binance/trades.js +19 -0
  396. package/dist/src/commanderAdapter.js +19 -6
  397. package/dist/src/completion-fast.d.ts +25 -0
  398. package/dist/src/completion-fast.js +140 -0
  399. package/dist/src/completion.d.ts +1 -0
  400. package/dist/src/completion.js +1 -0
  401. package/dist/src/diagnostic.d.ts +1 -0
  402. package/dist/src/diagnostic.js +64 -2
  403. package/dist/src/diagnostic.test.js +93 -3
  404. package/dist/src/discovery.d.ts +3 -3
  405. package/dist/src/discovery.js +34 -97
  406. package/dist/src/doctor.d.ts +2 -0
  407. package/dist/src/doctor.js +59 -31
  408. package/dist/src/doctor.test.js +89 -16
  409. package/dist/src/download/index.d.ts +1 -1
  410. package/dist/src/engine.test.js +4 -19
  411. package/dist/src/execution.js +1 -13
  412. package/dist/src/explore.js +1 -1
  413. package/dist/src/generate-verified.d.ts +105 -0
  414. package/dist/src/generate-verified.js +696 -0
  415. package/dist/src/generate-verified.test.d.ts +1 -0
  416. package/dist/src/generate-verified.test.js +925 -0
  417. package/dist/src/generate.d.ts +11 -6
  418. package/dist/src/generate.js +4 -7
  419. package/dist/src/main.js +65 -12
  420. package/dist/src/pipeline/steps/download.d.ts +1 -17
  421. package/dist/src/pipeline/steps/download.js +20 -31
  422. package/dist/src/pipeline/steps/intercept.d.ts +1 -1
  423. package/dist/src/pipeline/steps/intercept.js +1 -1
  424. package/dist/src/pipeline/steps/tap.d.ts +1 -1
  425. package/dist/src/pipeline/steps/tap.js +1 -1
  426. package/dist/src/plugin-scaffold.d.ts +2 -2
  427. package/dist/src/plugin-scaffold.js +24 -21
  428. package/dist/src/plugin-scaffold.test.js +1 -1
  429. package/dist/src/plugin.d.ts +3 -2
  430. package/dist/src/plugin.js +29 -14
  431. package/dist/src/plugin.test.js +47 -32
  432. package/dist/src/record.js +26 -25
  433. package/dist/src/runtime-detect.js +3 -7
  434. package/dist/src/scripts/framework.d.ts +3 -0
  435. package/dist/src/scripts/framework.js +8 -4
  436. package/dist/src/scripts/store.d.ts +5 -1
  437. package/dist/src/scripts/store.js +5 -1
  438. package/dist/src/skill-generate.d.ts +30 -0
  439. package/dist/src/skill-generate.js +75 -0
  440. package/dist/src/skill-generate.test.d.ts +1 -0
  441. package/dist/src/skill-generate.test.js +173 -0
  442. package/dist/src/synthesize.d.ts +1 -1
  443. package/dist/src/synthesize.js +7 -8
  444. package/dist/src/types.d.ts +3 -1
  445. package/package.json +5 -5
  446. package/dist/clis/bilibili/hot.yaml +0 -38
  447. package/dist/clis/bluesky/feeds.yaml +0 -29
  448. package/dist/clis/bluesky/followers.yaml +0 -33
  449. package/dist/clis/bluesky/following.yaml +0 -33
  450. package/dist/clis/bluesky/profile.yaml +0 -27
  451. package/dist/clis/bluesky/search.yaml +0 -34
  452. package/dist/clis/bluesky/starter-packs.yaml +0 -34
  453. package/dist/clis/bluesky/thread.yaml +0 -32
  454. package/dist/clis/bluesky/trending.yaml +0 -27
  455. package/dist/clis/bluesky/user.yaml +0 -34
  456. package/dist/clis/devto/tag.yaml +0 -34
  457. package/dist/clis/devto/top.yaml +0 -29
  458. package/dist/clis/devto/user.yaml +0 -33
  459. package/dist/clis/dictionary/examples.yaml +0 -25
  460. package/dist/clis/dictionary/search.yaml +0 -27
  461. package/dist/clis/dictionary/synonyms.yaml +0 -25
  462. package/dist/clis/douban/subject.yaml +0 -107
  463. package/dist/clis/douban/top250.yaml +0 -70
  464. package/dist/clis/facebook/add-friend.yaml +0 -43
  465. package/dist/clis/facebook/events.yaml +0 -44
  466. package/dist/clis/facebook/feed.yaml +0 -63
  467. package/dist/clis/facebook/friends.yaml +0 -42
  468. package/dist/clis/facebook/groups.yaml +0 -50
  469. package/dist/clis/facebook/join-group.yaml +0 -44
  470. package/dist/clis/facebook/memories.yaml +0 -39
  471. package/dist/clis/facebook/notifications.yaml +0 -40
  472. package/dist/clis/facebook/profile.yaml +0 -37
  473. package/dist/clis/facebook/search.yaml +0 -47
  474. package/dist/clis/hackernews/ask.yaml +0 -38
  475. package/dist/clis/hackernews/best.yaml +0 -38
  476. package/dist/clis/hackernews/jobs.yaml +0 -36
  477. package/dist/clis/hackernews/new.yaml +0 -38
  478. package/dist/clis/hackernews/search.yaml +0 -44
  479. package/dist/clis/hackernews/show.yaml +0 -38
  480. package/dist/clis/hackernews/top.yaml +0 -38
  481. package/dist/clis/hackernews/user.yaml +0 -25
  482. package/dist/clis/hupu/hot.yaml +0 -43
  483. package/dist/clis/instagram/comment.yaml +0 -52
  484. package/dist/clis/instagram/explore.yaml +0 -43
  485. package/dist/clis/instagram/follow.yaml +0 -41
  486. package/dist/clis/instagram/followers.yaml +0 -51
  487. package/dist/clis/instagram/following.yaml +0 -51
  488. package/dist/clis/instagram/like.yaml +0 -46
  489. package/dist/clis/instagram/profile.yaml +0 -42
  490. package/dist/clis/instagram/save.yaml +0 -46
  491. package/dist/clis/instagram/saved.yaml +0 -40
  492. package/dist/clis/instagram/search.yaml +0 -44
  493. package/dist/clis/instagram/unfollow.yaml +0 -38
  494. package/dist/clis/instagram/unlike.yaml +0 -46
  495. package/dist/clis/instagram/unsave.yaml +0 -46
  496. package/dist/clis/instagram/user.yaml +0 -54
  497. package/dist/clis/jike/post.yaml +0 -59
  498. package/dist/clis/jike/topic.yaml +0 -53
  499. package/dist/clis/jike/user.yaml +0 -52
  500. package/dist/clis/jimeng/generate.yaml +0 -85
  501. package/dist/clis/jimeng/history.yaml +0 -46
  502. package/dist/clis/linux-do/categories.yaml +0 -70
  503. package/dist/clis/linux-do/search.yaml +0 -48
  504. package/dist/clis/linux-do/tags.yaml +0 -41
  505. package/dist/clis/linux-do/topic.yaml +0 -62
  506. package/dist/clis/linux-do/user-posts.yaml +0 -67
  507. package/dist/clis/linux-do/user-topics.yaml +0 -54
  508. package/dist/clis/lobsters/active.yaml +0 -29
  509. package/dist/clis/lobsters/hot.yaml +0 -29
  510. package/dist/clis/lobsters/newest.yaml +0 -29
  511. package/dist/clis/lobsters/tag.yaml +0 -34
  512. package/dist/clis/pixiv/detail.yaml +0 -49
  513. package/dist/clis/pixiv/ranking.yaml +0 -53
  514. package/dist/clis/pixiv/user.yaml +0 -46
  515. package/dist/clis/reddit/frontpage.yaml +0 -30
  516. package/dist/clis/reddit/hot.yaml +0 -47
  517. package/dist/clis/reddit/popular.yaml +0 -40
  518. package/dist/clis/reddit/search.yaml +0 -61
  519. package/dist/clis/reddit/subreddit.yaml +0 -50
  520. package/dist/clis/reddit/user-comments.yaml +0 -46
  521. package/dist/clis/reddit/user-posts.yaml +0 -44
  522. package/dist/clis/reddit/user.yaml +0 -40
  523. package/dist/clis/stackoverflow/bounties.yaml +0 -29
  524. package/dist/clis/stackoverflow/hot.yaml +0 -28
  525. package/dist/clis/stackoverflow/search.yaml +0 -33
  526. package/dist/clis/stackoverflow/unanswered.yaml +0 -28
  527. package/dist/clis/steam/top-sellers.yaml +0 -29
  528. package/dist/clis/tiktok/comment.yaml +0 -66
  529. package/dist/clis/tiktok/explore.yaml +0 -39
  530. package/dist/clis/tiktok/follow.yaml +0 -39
  531. package/dist/clis/tiktok/following.yaml +0 -46
  532. package/dist/clis/tiktok/friends.yaml +0 -47
  533. package/dist/clis/tiktok/like.yaml +0 -38
  534. package/dist/clis/tiktok/live.yaml +0 -51
  535. package/dist/clis/tiktok/notifications.yaml +0 -52
  536. package/dist/clis/tiktok/profile.yaml +0 -45
  537. package/dist/clis/tiktok/save.yaml +0 -34
  538. package/dist/clis/tiktok/search.yaml +0 -47
  539. package/dist/clis/tiktok/unfollow.yaml +0 -44
  540. package/dist/clis/tiktok/unlike.yaml +0 -38
  541. package/dist/clis/tiktok/unsave.yaml +0 -36
  542. package/dist/clis/tiktok/user.yaml +0 -44
  543. package/dist/clis/v2ex/hot.yaml +0 -28
  544. package/dist/clis/v2ex/latest.yaml +0 -28
  545. package/dist/clis/v2ex/member.yaml +0 -29
  546. package/dist/clis/v2ex/node.yaml +0 -34
  547. package/dist/clis/v2ex/nodes.yaml +0 -31
  548. package/dist/clis/v2ex/replies.yaml +0 -32
  549. package/dist/clis/v2ex/topic.yaml +0 -33
  550. package/dist/clis/v2ex/user.yaml +0 -34
  551. package/dist/clis/xiaoe/catalog.yaml +0 -129
  552. package/dist/clis/xiaoe/content.yaml +0 -43
  553. package/dist/clis/xiaoe/courses.yaml +0 -73
  554. package/dist/clis/xiaoe/detail.yaml +0 -39
  555. package/dist/clis/xiaoe/play-url.yaml +0 -124
  556. package/dist/clis/xiaohongshu/feed.yaml +0 -31
  557. package/dist/clis/xiaohongshu/notifications.yaml +0 -37
  558. package/dist/clis/xueqiu/earnings-date.yaml +0 -69
  559. package/dist/clis/xueqiu/feed.yaml +0 -53
  560. package/dist/clis/xueqiu/groups.yaml +0 -23
  561. package/dist/clis/xueqiu/hot-stock.yaml +0 -49
  562. package/dist/clis/xueqiu/hot.yaml +0 -46
  563. package/dist/clis/xueqiu/kline.yaml +0 -65
  564. package/dist/clis/xueqiu/search.yaml +0 -55
  565. package/dist/clis/xueqiu/stock.yaml +0 -69
  566. package/dist/clis/xueqiu/watchlist.yaml +0 -46
  567. package/dist/clis/zhihu/hot.yaml +0 -46
  568. package/dist/clis/zhihu/search.yaml +0 -59
  569. package/dist/src/browser/discover.d.ts +0 -15
  570. package/dist/src/browser/discover.js +0 -19
  571. package/dist/src/yaml-schema.d.ts +0 -29
  572. package/dist/src/yaml-schema.js +0 -22
package/dist/src/cli.js CHANGED
@@ -21,11 +21,11 @@ import { registerAllCommands } from './commanderAdapter.js';
21
21
  import { EXIT_CODES, getErrorMessage } from './errors.js';
22
22
  import { daemonStatus, daemonStop, daemonRestart } from './commands/daemon.js';
23
23
  const CLI_FILE = fileURLToPath(import.meta.url);
24
- /** Create a browser page for operate commands. Uses 'operate' workspace for session persistence. */
25
- async function getOperatePage() {
24
+ /** Create a browser page for browser commands. Uses a dedicated browser workspace for session persistence. */
25
+ async function getBrowserPage() {
26
26
  const { BrowserBridge } = await import('./browser/index.js');
27
27
  const bridge = new BrowserBridge();
28
- return bridge.connect({ timeout: 30, workspace: 'operate:default' });
28
+ return bridge.connect({ timeout: 30, workspace: 'browser:default' });
29
29
  }
30
30
  function applyVerbose(opts) {
31
31
  if (opts.verbose)
@@ -171,24 +171,30 @@ export function createProgram(BUILTIN_CLIS, USER_CLIS) {
171
171
  });
172
172
  program
173
173
  .command('generate')
174
- .description('One-shot: explore → synthesize → register')
174
+ .description('One-shot: explore → synthesize → verify → register')
175
175
  .argument('<url>')
176
176
  .option('--goal <text>')
177
177
  .option('--site <name>')
178
+ .option('--format <fmt>', 'Output format: table, json', 'table')
179
+ .option('--no-register', 'Verify the generated adapter without registering it')
178
180
  .option('-v, --verbose', 'Debug output')
179
181
  .action(async (url, opts) => {
180
182
  applyVerbose(opts);
181
- const { generateCliFromUrl, renderGenerateSummary } = await import('./generate.js');
183
+ const { generateVerifiedFromUrl, renderGenerateVerifiedSummary } = await import('./generate-verified.js');
182
184
  const workspace = `generate:${inferHost(url, opts.site)}`;
183
- const r = await generateCliFromUrl({
185
+ const r = await generateVerifiedFromUrl({
184
186
  url,
185
187
  BrowserFactory: getBrowserFactory(),
186
188
  goal: opts.goal,
187
189
  site: opts.site,
188
190
  workspace,
191
+ noRegister: opts.register === false,
189
192
  });
190
- console.log(renderGenerateSummary(r));
191
- process.exitCode = r.ok ? EXIT_CODES.SUCCESS : EXIT_CODES.GENERIC_ERROR;
193
+ if (opts.format === 'json')
194
+ console.log(JSON.stringify(r, null, 2));
195
+ else
196
+ console.log(renderGenerateVerifiedSummary(r));
197
+ process.exitCode = r.status === 'success' ? EXIT_CODES.SUCCESS : EXIT_CODES.GENERIC_ERROR;
192
198
  });
193
199
  // ── Built-in: record ─────────────────────────────────────────────────────
194
200
  program
@@ -235,22 +241,22 @@ export function createProgram(BUILTIN_CLIS, USER_CLIS) {
235
241
  }, { workspace });
236
242
  console.log(renderCascadeResult(result));
237
243
  });
238
- // ── Built-in: operate (browser control for Claude Code skill) ───────────────
244
+ // ── Built-in: browser (browser control for Claude Code skill) ───────────────
239
245
  //
240
246
  // Make websites accessible for AI agents.
241
- // All commands wrapped in operateAction() for consistent error handling.
242
- const operate = program
243
- .command('operate')
247
+ // All commands wrapped in browserAction() for consistent error handling.
248
+ const browser = program
249
+ .command('browser')
244
250
  .description('Browser control — navigate, click, type, extract, wait (no LLM needed)');
245
- /** Wrap operate actions with error handling and optional --json output */
246
- function operateAction(fn) {
251
+ /** Wrap browser actions with error handling and optional --json output */
252
+ function browserAction(fn) {
247
253
  return async (...args) => {
248
254
  try {
249
- const page = await getOperatePage();
255
+ const page = await getBrowserPage();
250
256
  await fn(page, ...args);
251
257
  }
252
258
  catch (err) {
253
- const msg = err instanceof Error ? err.message : String(err);
259
+ const msg = getErrorMessage(err);
254
260
  if (msg.includes('Extension not connected') || msg.includes('Daemon')) {
255
261
  console.error(`Browser not connected. Run 'opencli doctor' to diagnose.`);
256
262
  }
@@ -267,14 +273,14 @@ export function createProgram(BUILTIN_CLIS, USER_CLIS) {
267
273
  // ── Navigation ──
268
274
  /** Network interceptor JS — injected on every open/navigate to capture fetch/XHR */
269
275
  const NETWORK_INTERCEPTOR_JS = `(function(){if(window.__opencli_net)return;window.__opencli_net=[];var M=200,B=50000,F=window.fetch;window.fetch=async function(){var r=await F.apply(this,arguments);try{var ct=r.headers.get('content-type')||'';if(ct.includes('json')||ct.includes('text')){var c=r.clone(),t=await c.text();if(window.__opencli_net.length<M){var b=null;if(t.length<=B)try{b=JSON.parse(t)}catch(e){b=t}window.__opencli_net.push({url:r.url||(arguments[0]&&arguments[0].url)||String(arguments[0]),method:(arguments[1]&&arguments[1].method)||'GET',status:r.status,size:t.length,ct:ct,body:b})}}}catch(e){}return r};var X=XMLHttpRequest.prototype,O=X.open,S=X.send;X.open=function(m,u){this._om=m;this._ou=u;return O.apply(this,arguments)};X.send=function(){var x=this;x.addEventListener('load',function(){try{var ct=x.getResponseHeader('content-type')||'';if((ct.includes('json')||ct.includes('text'))&&window.__opencli_net.length<M){var t=x.responseText,b=null;if(t&&t.length<=B)try{b=JSON.parse(t)}catch(e){b=t}window.__opencli_net.push({url:x._ou,method:x._om||'GET',status:x.status,size:t?t.length:0,ct:ct,body:b})}}catch(e){}});return S.apply(this,arguments)}})()`;
270
- operate.command('open').argument('<url>').description('Open URL in automation window')
271
- .action(operateAction(async (page, url) => {
276
+ browser.command('open').argument('<url>').description('Open URL in automation window')
277
+ .action(browserAction(async (page, url) => {
272
278
  // Start session-level capture before navigation (catches initial requests)
273
- await page.startNetworkCapture?.();
279
+ const hasSessionCapture = await page.startNetworkCapture?.().then(() => true).catch(() => false);
274
280
  await page.goto(url);
275
281
  await page.wait(2);
276
- // Fallback: also inject JS interceptor for pages without session capture
277
- if (!page.startNetworkCapture) {
282
+ // Fallback: inject JS interceptor when session capture is unavailable
283
+ if (!hasSessionCapture) {
278
284
  try {
279
285
  await page.evaluate(NETWORK_INTERCEPTOR_JS);
280
286
  }
@@ -282,15 +288,15 @@ export function createProgram(BUILTIN_CLIS, USER_CLIS) {
282
288
  }
283
289
  console.log(`Navigated to: ${await page.getCurrentUrl?.() ?? url}`);
284
290
  }));
285
- operate.command('back').description('Go back in browser history')
286
- .action(operateAction(async (page) => {
291
+ browser.command('back').description('Go back in browser history')
292
+ .action(browserAction(async (page) => {
287
293
  await page.evaluate('history.back()');
288
294
  await page.wait(2);
289
295
  console.log('Navigated back');
290
296
  }));
291
- operate.command('scroll').argument('<direction>', 'up or down').option('--amount <pixels>', 'Pixels to scroll', '500')
297
+ browser.command('scroll').argument('<direction>', 'up or down').option('--amount <pixels>', 'Pixels to scroll', '500')
292
298
  .description('Scroll page')
293
- .action(operateAction(async (page, direction, opts) => {
299
+ .action(browserAction(async (page, direction, opts) => {
294
300
  if (direction !== 'up' && direction !== 'down') {
295
301
  console.error(`Invalid direction "${direction}". Use "up" or "down".`);
296
302
  process.exitCode = EXIT_CODES.USAGE_ERROR;
@@ -300,16 +306,16 @@ export function createProgram(BUILTIN_CLIS, USER_CLIS) {
300
306
  console.log(`Scrolled ${direction}`);
301
307
  }));
302
308
  // ── Inspect ──
303
- operate.command('state').description('Page state: URL, title, interactive elements with [N] indices')
304
- .action(operateAction(async (page) => {
309
+ browser.command('state').description('Page state: URL, title, interactive elements with [N] indices')
310
+ .action(browserAction(async (page) => {
305
311
  const snapshot = await page.snapshot({ viewportExpand: 2000 });
306
312
  const url = await page.getCurrentUrl?.() ?? '';
307
313
  console.log(`URL: ${url}\n`);
308
314
  console.log(typeof snapshot === 'string' ? snapshot : JSON.stringify(snapshot, null, 2));
309
315
  }));
310
- operate.command('screenshot').argument('[path]', 'Save to file (base64 if omitted)')
316
+ browser.command('screenshot').argument('[path]', 'Save to file (base64 if omitted)')
311
317
  .description('Take screenshot')
312
- .action(operateAction(async (page, path) => {
318
+ .action(browserAction(async (page, path) => {
313
319
  if (path) {
314
320
  await page.screenshot({ path });
315
321
  console.log(`Screenshot saved to: ${path}`);
@@ -319,45 +325,45 @@ export function createProgram(BUILTIN_CLIS, USER_CLIS) {
319
325
  }
320
326
  }));
321
327
  // ── Get commands (structured data extraction) ──
322
- const get = operate.command('get').description('Get page properties');
328
+ const get = browser.command('get').description('Get page properties');
323
329
  get.command('title').description('Page title')
324
- .action(operateAction(async (page) => {
330
+ .action(browserAction(async (page) => {
325
331
  console.log(await page.evaluate('document.title'));
326
332
  }));
327
333
  get.command('url').description('Current page URL')
328
- .action(operateAction(async (page) => {
334
+ .action(browserAction(async (page) => {
329
335
  console.log(await page.getCurrentUrl?.() ?? await page.evaluate('location.href'));
330
336
  }));
331
337
  get.command('text').argument('<index>', 'Element index').description('Element text content')
332
- .action(operateAction(async (page, index) => {
338
+ .action(browserAction(async (page, index) => {
333
339
  const text = await page.evaluate(`document.querySelector('[data-opencli-ref="${index}"]')?.textContent?.trim()`);
334
340
  console.log(text ?? '(empty)');
335
341
  }));
336
342
  get.command('value').argument('<index>', 'Element index').description('Input/textarea value')
337
- .action(operateAction(async (page, index) => {
343
+ .action(browserAction(async (page, index) => {
338
344
  const val = await page.evaluate(`document.querySelector('[data-opencli-ref="${index}"]')?.value`);
339
345
  console.log(val ?? '(empty)');
340
346
  }));
341
347
  get.command('html').option('--selector <css>', 'CSS selector scope').description('Page HTML (or scoped)')
342
- .action(operateAction(async (page, opts) => {
348
+ .action(browserAction(async (page, opts) => {
343
349
  const sel = opts.selector ? JSON.stringify(opts.selector) : 'null';
344
350
  const html = await page.evaluate(`(${sel} ? document.querySelector(${sel})?.outerHTML : document.documentElement.outerHTML)?.slice(0, 50000)`);
345
351
  console.log(html ?? '(empty)');
346
352
  }));
347
353
  get.command('attributes').argument('<index>', 'Element index').description('Element attributes')
348
- .action(operateAction(async (page, index) => {
354
+ .action(browserAction(async (page, index) => {
349
355
  const attrs = await page.evaluate(`JSON.stringify(Object.fromEntries([...document.querySelector('[data-opencli-ref="${index}"]')?.attributes].map(a=>[a.name,a.value])))`);
350
356
  console.log(attrs ?? '{}');
351
357
  }));
352
358
  // ── Interact ──
353
- operate.command('click').argument('<index>', 'Element index from state').description('Click element by index')
354
- .action(operateAction(async (page, index) => {
359
+ browser.command('click').argument('<index>', 'Element index from state').description('Click element by index')
360
+ .action(browserAction(async (page, index) => {
355
361
  await page.click(index);
356
362
  console.log(`Clicked element [${index}]`);
357
363
  }));
358
- operate.command('type').argument('<index>', 'Element index').argument('<text>', 'Text to type')
364
+ browser.command('type').argument('<index>', 'Element index').argument('<text>', 'Text to type')
359
365
  .description('Click element, then type text')
360
- .action(operateAction(async (page, index, text) => {
366
+ .action(browserAction(async (page, index, text) => {
361
367
  await page.click(index);
362
368
  await page.wait(0.3);
363
369
  await page.typeText(index, text);
@@ -380,9 +386,9 @@ export function createProgram(BUILTIN_CLIS, USER_CLIS) {
380
386
  console.log(`Typed "${text}" into element [${index}]`);
381
387
  }
382
388
  }));
383
- operate.command('select').argument('<index>', 'Element index of <select>').argument('<option>', 'Option text')
389
+ browser.command('select').argument('<index>', 'Element index of <select>').argument('<option>', 'Option text')
384
390
  .description('Select dropdown option')
385
- .action(operateAction(async (page, index, option) => {
391
+ .action(browserAction(async (page, index, option) => {
386
392
  const result = await page.evaluate(`
387
393
  (function() {
388
394
  var sel = document.querySelector('[data-opencli-ref="${index}"]');
@@ -404,19 +410,19 @@ export function createProgram(BUILTIN_CLIS, USER_CLIS) {
404
410
  console.log(`Selected "${result?.selected}" in element [${index}]`);
405
411
  }
406
412
  }));
407
- operate.command('keys').argument('<key>', 'Key to press (Enter, Escape, Tab, Control+a)')
413
+ browser.command('keys').argument('<key>', 'Key to press (Enter, Escape, Tab, Control+a)')
408
414
  .description('Press keyboard key')
409
- .action(operateAction(async (page, key) => {
415
+ .action(browserAction(async (page, key) => {
410
416
  await page.pressKey(key);
411
417
  console.log(`Pressed: ${key}`);
412
418
  }));
413
419
  // ── Wait commands ──
414
- operate.command('wait')
420
+ browser.command('wait')
415
421
  .argument('<type>', 'selector, text, or time')
416
422
  .argument('[value]', 'CSS selector, text string, or seconds')
417
423
  .option('--timeout <ms>', 'Timeout in milliseconds', '10000')
418
424
  .description('Wait for selector, text, or time (e.g. wait selector ".loaded", wait text "Success", wait time 3)')
419
- .action(operateAction(async (page, type, value, opts) => {
425
+ .action(browserAction(async (page, type, value, opts) => {
420
426
  const timeout = parseInt(opts.timeout, 10);
421
427
  if (type === 'time') {
422
428
  const seconds = parseFloat(value ?? '2');
@@ -447,8 +453,8 @@ export function createProgram(BUILTIN_CLIS, USER_CLIS) {
447
453
  }
448
454
  }));
449
455
  // ── Extract ──
450
- operate.command('eval').argument('<js>', 'JavaScript code').description('Execute JS in page context, return result')
451
- .action(operateAction(async (page, js) => {
456
+ browser.command('eval').argument('<js>', 'JavaScript code').description('Execute JS in page context, return result')
457
+ .action(browserAction(async (page, js) => {
452
458
  const result = await page.evaluate(js);
453
459
  if (typeof result === 'string')
454
460
  console.log(result);
@@ -456,11 +462,11 @@ export function createProgram(BUILTIN_CLIS, USER_CLIS) {
456
462
  console.log(JSON.stringify(result, null, 2));
457
463
  }));
458
464
  // ── Network (API discovery) ──
459
- operate.command('network')
465
+ browser.command('network')
460
466
  .option('--detail <index>', 'Show full response body of request at index')
461
467
  .option('--all', 'Show all requests including static resources')
462
468
  .description('Show captured network requests (auto-captured since last open)')
463
- .action(operateAction(async (page, opts) => {
469
+ .action(browserAction(async (page, opts) => {
464
470
  let items = [];
465
471
  if (page.readNetworkCapture) {
466
472
  const raw = await page.readNetworkCapture();
@@ -498,7 +504,7 @@ export function createProgram(BUILTIN_CLIS, USER_CLIS) {
498
504
  items = JSON.parse(requests);
499
505
  }
500
506
  catch {
501
- console.log('No network data captured. Run "operate open <url>" first.');
507
+ console.log('No network data captured. Run "browser open <url>" first.');
502
508
  return;
503
509
  }
504
510
  }
@@ -537,7 +543,7 @@ export function createProgram(BUILTIN_CLIS, USER_CLIS) {
537
543
  }
538
544
  }));
539
545
  // ── Init (adapter scaffolding) ──
540
- operate.command('init')
546
+ browser.command('init')
541
547
  .argument('<name>', 'Adapter name in site/command format (e.g. hn/top)')
542
548
  .description('Generate adapter scaffold in ~/.opencli/clis/')
543
549
  .action(async (name) => {
@@ -563,10 +569,10 @@ export function createProgram(BUILTIN_CLIS, USER_CLIS) {
563
569
  console.log(`Adapter already exists: ${filePath}`);
564
570
  return;
565
571
  }
566
- // Try to detect domain from last operate session
572
+ // Try to detect domain from the last browser session
567
573
  let domain = site;
568
574
  try {
569
- const page = await getOperatePage();
575
+ const page = await getBrowserPage();
570
576
  const url = await page.getCurrentUrl?.();
571
577
  if (url) {
572
578
  try {
@@ -600,7 +606,7 @@ cli({
600
606
  fs.mkdirSync(dir, { recursive: true });
601
607
  fs.writeFileSync(filePath, template, 'utf-8');
602
608
  console.log(`Created: ${filePath}`);
603
- console.log(`Edit the file to implement your adapter, then run: opencli operate verify ${name}`);
609
+ console.log(`Edit the file to implement your adapter, then run: opencli browser verify ${name}`);
604
610
  }
605
611
  catch (err) {
606
612
  console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
@@ -608,7 +614,7 @@ cli({
608
614
  }
609
615
  });
610
616
  // ── Verify (test adapter) ──
611
- operate.command('verify')
617
+ browser.command('verify')
612
618
  .argument('<name>', 'Adapter name in site/command format (e.g. hn/top)')
613
619
  .description('Execute an adapter and show results')
614
620
  .action(async (name) => {
@@ -630,7 +636,7 @@ cli({
630
636
  const filePath = path.join(os.homedir(), '.opencli', 'clis', site, `${command}.ts`);
631
637
  if (!fs.existsSync(filePath)) {
632
638
  console.error(`Adapter not found: ${filePath}`);
633
- console.error(`Run "opencli operate init ${name}" to create it.`);
639
+ console.error(`Run "opencli browser init ${name}" to create it.`);
634
640
  process.exitCode = EXIT_CODES.GENERIC_ERROR;
635
641
  return;
636
642
  }
@@ -641,7 +647,7 @@ cli({
641
647
  const hasLimitArg = /['"]limit['"]/.test(adapterSrc);
642
648
  const limitFlag = hasLimitArg ? ' --limit 3' : '';
643
649
  const limitArgs = hasLimitArg ? ['--limit', '3'] : [];
644
- const invocation = resolveOperateVerifyInvocation();
650
+ const invocation = resolveBrowserVerifyInvocation();
645
651
  try {
646
652
  const output = execFileSync(invocation.binary, [...invocation.args, site, command, ...limitArgs], {
647
653
  cwd: invocation.cwd,
@@ -657,10 +663,12 @@ cli({
657
663
  }
658
664
  catch (err) {
659
665
  console.log(` Executing: opencli ${site} ${command}${limitFlag}\n`);
660
- if (err.stdout)
661
- console.log(err.stdout);
662
- if (err.stderr)
663
- console.error(err.stderr.slice(0, 500));
666
+ // execFileSync attaches captured stdout/stderr on its thrown Error.
667
+ const execErr = err;
668
+ if (execErr.stdout)
669
+ console.log(String(execErr.stdout));
670
+ if (execErr.stderr)
671
+ console.error(String(execErr.stderr).slice(0, 500));
664
672
  console.log(`\n ✗ Adapter failed. Fix the code and try again.`);
665
673
  process.exitCode = EXIT_CODES.GENERIC_ERROR;
666
674
  }
@@ -671,8 +679,8 @@ cli({
671
679
  }
672
680
  });
673
681
  // ── Session ──
674
- operate.command('close').description('Close the automation window')
675
- .action(operateAction(async (page) => {
682
+ browser.command('close').description('Close the automation window')
683
+ .action(browserAction(async (page) => {
676
684
  await page.closeWindow?.();
677
685
  console.log('Automation window closed');
678
686
  }));
@@ -978,7 +986,7 @@ export function runCli(BUILTIN_CLIS, USER_CLIS) {
978
986
  createProgram(BUILTIN_CLIS, USER_CLIS).parse();
979
987
  }
980
988
  export { findPackageRoot };
981
- export function resolveOperateVerifyInvocation(opts = {}) {
989
+ export function resolveBrowserVerifyInvocation(opts = {}) {
982
990
  const platform = opts.platform ?? process.platform;
983
991
  const fileExists = opts.fileExists ?? fs.existsSync;
984
992
  const readFile = opts.readFile ?? ((filePath) => fs.readFileSync(filePath, 'utf-8'));
@@ -1,10 +1,10 @@
1
1
  import { beforeEach, describe, expect, it, vi } from 'vitest';
2
2
  import * as path from 'node:path';
3
- const { mockExploreUrl, mockRenderExploreSummary, mockGenerateCliFromUrl, mockRenderGenerateSummary, mockRecordSession, mockRenderRecordSummary, mockCascadeProbe, mockRenderCascadeResult, mockGetBrowserFactory, mockBrowserSession, } = vi.hoisted(() => ({
3
+ const { mockExploreUrl, mockRenderExploreSummary, mockGenerateVerifiedFromUrl, mockRenderGenerateVerifiedSummary, mockRecordSession, mockRenderRecordSummary, mockCascadeProbe, mockRenderCascadeResult, mockGetBrowserFactory, mockBrowserSession, } = vi.hoisted(() => ({
4
4
  mockExploreUrl: vi.fn(),
5
5
  mockRenderExploreSummary: vi.fn(),
6
- mockGenerateCliFromUrl: vi.fn(),
7
- mockRenderGenerateSummary: vi.fn(),
6
+ mockGenerateVerifiedFromUrl: vi.fn(),
7
+ mockRenderGenerateVerifiedSummary: vi.fn(),
8
8
  mockRecordSession: vi.fn(),
9
9
  mockRenderRecordSummary: vi.fn(),
10
10
  mockCascadeProbe: vi.fn(),
@@ -16,9 +16,9 @@ vi.mock('./explore.js', () => ({
16
16
  exploreUrl: mockExploreUrl,
17
17
  renderExploreSummary: mockRenderExploreSummary,
18
18
  }));
19
- vi.mock('./generate.js', () => ({
20
- generateCliFromUrl: mockGenerateCliFromUrl,
21
- renderGenerateSummary: mockRenderGenerateSummary,
19
+ vi.mock('./generate-verified.js', () => ({
20
+ generateVerifiedFromUrl: mockGenerateVerifiedFromUrl,
21
+ renderGenerateVerifiedSummary: mockRenderGenerateVerifiedSummary,
22
22
  }));
23
23
  vi.mock('./record.js', () => ({
24
24
  recordSession: mockRecordSession,
@@ -32,7 +32,7 @@ vi.mock('./runtime.js', () => ({
32
32
  getBrowserFactory: mockGetBrowserFactory,
33
33
  browserSession: mockBrowserSession,
34
34
  }));
35
- import { createProgram, findPackageRoot, resolveOperateVerifyInvocation } from './cli.js';
35
+ import { createProgram, findPackageRoot, resolveBrowserVerifyInvocation } from './cli.js';
36
36
  describe('built-in browser commands verbose wiring', () => {
37
37
  const consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
38
38
  beforeEach(() => {
@@ -40,8 +40,8 @@ describe('built-in browser commands verbose wiring', () => {
40
40
  process.exitCode = undefined;
41
41
  mockExploreUrl.mockReset().mockResolvedValue({ ok: true });
42
42
  mockRenderExploreSummary.mockReset().mockReturnValue('explore-summary');
43
- mockGenerateCliFromUrl.mockReset().mockResolvedValue({ ok: true });
44
- mockRenderGenerateSummary.mockReset().mockReturnValue('generate-summary');
43
+ mockGenerateVerifiedFromUrl.mockReset().mockResolvedValue({ status: 'success' });
44
+ mockRenderGenerateVerifiedSummary.mockReset().mockReturnValue('generate-summary');
45
45
  mockRecordSession.mockReset().mockResolvedValue({ candidateCount: 1 });
46
46
  mockRenderRecordSummary.mockReset().mockReturnValue('record-summary');
47
47
  mockCascadeProbe.mockReset().mockResolvedValue({ ok: true });
@@ -65,7 +65,12 @@ describe('built-in browser commands verbose wiring', () => {
65
65
  const program = createProgram('', '');
66
66
  await program.parseAsync(['node', 'opencli', 'generate', 'https://example.com', '-v']);
67
67
  expect(process.env.OPENCLI_VERBOSE).toBe('1');
68
- expect(mockGenerateCliFromUrl).toHaveBeenCalledWith(expect.objectContaining({ url: 'https://example.com', workspace: 'generate:example.com' }));
68
+ expect(mockGenerateVerifiedFromUrl).toHaveBeenCalledWith(expect.objectContaining({ url: 'https://example.com', workspace: 'generate:example.com', noRegister: false }));
69
+ });
70
+ it('passes --no-register through the real CLI command', async () => {
71
+ const program = createProgram('', '');
72
+ await program.parseAsync(['node', 'opencli', 'generate', 'https://example.com', '--no-register']);
73
+ expect(mockGenerateVerifiedFromUrl).toHaveBeenCalledWith(expect.objectContaining({ url: 'https://example.com', workspace: 'generate:example.com', noRegister: true }));
69
74
  });
70
75
  it('enables OPENCLI_VERBOSE for record via the real CLI command', async () => {
71
76
  const program = createProgram('', '');
@@ -87,13 +92,13 @@ describe('built-in browser commands verbose wiring', () => {
87
92
  });
88
93
  consoleLogSpy.mockClear();
89
94
  });
90
- describe('resolveOperateVerifyInvocation', () => {
95
+ describe('resolveBrowserVerifyInvocation', () => {
91
96
  it('prefers the built entry declared in package metadata', () => {
92
97
  const projectRoot = path.join('repo-root');
93
98
  const exists = new Set([
94
99
  path.join(projectRoot, 'dist', 'src', 'main.js'),
95
100
  ]);
96
- expect(resolveOperateVerifyInvocation({
101
+ expect(resolveBrowserVerifyInvocation({
97
102
  projectRoot,
98
103
  readFile: () => JSON.stringify({ bin: { opencli: 'dist/src/main.js' } }),
99
104
  fileExists: (candidate) => exists.has(candidate),
@@ -108,7 +113,7 @@ describe('resolveOperateVerifyInvocation', () => {
108
113
  const exists = new Set([
109
114
  path.join(projectRoot, 'dist', 'src', 'main.js'),
110
115
  ]);
111
- expect(resolveOperateVerifyInvocation({
116
+ expect(resolveBrowserVerifyInvocation({
112
117
  projectRoot,
113
118
  readFile: () => { throw new Error('no package json'); },
114
119
  fileExists: (candidate) => exists.has(candidate),
@@ -124,7 +129,7 @@ describe('resolveOperateVerifyInvocation', () => {
124
129
  path.join(projectRoot, 'src', 'main.ts'),
125
130
  path.join(projectRoot, 'node_modules', '.bin', 'tsx.cmd'),
126
131
  ]);
127
- expect(resolveOperateVerifyInvocation({
132
+ expect(resolveBrowserVerifyInvocation({
128
133
  projectRoot,
129
134
  platform: 'win32',
130
135
  fileExists: (candidate) => exists.has(candidate),
@@ -140,7 +145,7 @@ describe('resolveOperateVerifyInvocation', () => {
140
145
  const exists = new Set([
141
146
  path.join(projectRoot, 'src', 'main.ts'),
142
147
  ]);
143
- expect(resolveOperateVerifyInvocation({
148
+ expect(resolveBrowserVerifyInvocation({
144
149
  projectRoot,
145
150
  platform: 'linux',
146
151
  fileExists: (candidate) => exists.has(candidate),
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,20 @@
1
+ import { cli, Strategy } from '@jackwener/opencli/registry';
2
+ cli({
3
+ site: 'binance',
4
+ name: 'asks',
5
+ description: 'Order book ask prices for a trading pair',
6
+ domain: 'data-api.binance.vision',
7
+ strategy: Strategy.PUBLIC,
8
+ browser: false,
9
+ args: [
10
+ { name: 'symbol', type: 'str', required: true, positional: true, help: 'Trading pair symbol (e.g. BTCUSDT, ETHUSDT)' },
11
+ { name: 'limit', type: 'int', default: 10, help: 'Number of price levels (5, 10, 20, 50, 100)' },
12
+ ],
13
+ columns: ['rank', 'ask_price', 'ask_qty'],
14
+ pipeline: [
15
+ { fetch: { url: 'https://data-api.binance.vision/api/v3/depth?symbol=${{ args.symbol }}&limit=${{ args.limit }}' } },
16
+ { select: 'asks' },
17
+ { map: { rank: '${{ index + 1 }}', ask_price: '${{ item.0 }}', ask_qty: '${{ item.1 }}' } },
18
+ { limit: '${{ args.limit }}' },
19
+ ],
20
+ });
@@ -0,0 +1,3 @@
1
+ import './top.js';
2
+ import './gainers.js';
3
+ import './pairs.js';
@@ -0,0 +1,58 @@
1
+ import { getRegistry } from '@jackwener/opencli/registry';
2
+ import { afterEach, describe, expect, it, vi } from 'vitest';
3
+ import { executePipeline } from '../../pipeline/index.js';
4
+ // Import all binance adapters to register them
5
+ import './top.js';
6
+ import './gainers.js';
7
+ import './pairs.js';
8
+ function loadPipeline(name) {
9
+ const cmd = getRegistry().get(`binance/${name}`);
10
+ if (!cmd?.pipeline)
11
+ throw new Error(`Command binance/${name} not found or has no pipeline`);
12
+ return cmd.pipeline;
13
+ }
14
+ function mockJsonOnce(payload) {
15
+ vi.stubGlobal('fetch', vi.fn().mockResolvedValue({
16
+ ok: true,
17
+ status: 200,
18
+ statusText: 'OK',
19
+ json: vi.fn().mockResolvedValue(payload),
20
+ }));
21
+ }
22
+ afterEach(() => {
23
+ vi.unstubAllGlobals();
24
+ vi.restoreAllMocks();
25
+ });
26
+ describe('binance adapters', () => {
27
+ it('sorts top pairs by numeric quote volume', async () => {
28
+ mockJsonOnce([
29
+ { symbol: 'SMALL', lastPrice: '1', priceChangePercent: '1.2', highPrice: '1', lowPrice: '1', quoteVolume: '9.9' },
30
+ { symbol: 'LARGE', lastPrice: '2', priceChangePercent: '2.3', highPrice: '2', lowPrice: '2', quoteVolume: '100.0' },
31
+ { symbol: 'MID', lastPrice: '3', priceChangePercent: '3.4', highPrice: '3', lowPrice: '3', quoteVolume: '11.0' },
32
+ ]);
33
+ const result = await executePipeline(null, loadPipeline('top'), { args: { limit: 3 } });
34
+ expect(result.map((item) => item.symbol)).toEqual(['LARGE', 'MID', 'SMALL']);
35
+ expect(result.map((item) => item.rank)).toEqual([1, 2, 3]);
36
+ });
37
+ it('sorts gainers by numeric percent change', async () => {
38
+ mockJsonOnce([
39
+ { symbol: 'TEN', lastPrice: '1', priceChangePercent: '10.0', quoteVolume: '100' },
40
+ { symbol: 'NINE', lastPrice: '1', priceChangePercent: '9.5', quoteVolume: '100' },
41
+ { symbol: 'HUNDRED', lastPrice: '1', priceChangePercent: '100.0', quoteVolume: '100' },
42
+ ]);
43
+ const result = await executePipeline(null, loadPipeline('gainers'), { args: { limit: 3 } });
44
+ expect(result.map((item) => item.symbol)).toEqual(['HUNDRED', 'TEN', 'NINE']);
45
+ });
46
+ it('keeps only TRADING pairs', async () => {
47
+ mockJsonOnce({
48
+ symbols: [
49
+ { symbol: 'BTCUSDT', baseAsset: 'BTC', quoteAsset: 'USDT', status: 'TRADING' },
50
+ { symbol: 'OLDPAIR', baseAsset: 'OLD', quoteAsset: 'USDT', status: 'BREAK' },
51
+ ],
52
+ });
53
+ const result = await executePipeline(null, loadPipeline('pairs'), { args: { limit: 10 } });
54
+ expect(result).toEqual([
55
+ { symbol: 'BTCUSDT', base: 'BTC', quote: 'USDT', status: 'TRADING' },
56
+ ]);
57
+ });
58
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,20 @@
1
+ import { cli, Strategy } from '@jackwener/opencli/registry';
2
+ cli({
3
+ site: 'binance',
4
+ name: 'depth',
5
+ description: 'Order book bid prices for a trading pair',
6
+ domain: 'data-api.binance.vision',
7
+ strategy: Strategy.PUBLIC,
8
+ browser: false,
9
+ args: [
10
+ { name: 'symbol', type: 'str', required: true, positional: true, help: 'Trading pair symbol (e.g. BTCUSDT, ETHUSDT)' },
11
+ { name: 'limit', type: 'int', default: 10, help: 'Number of price levels (5, 10, 20, 50, 100)' },
12
+ ],
13
+ columns: ['rank', 'bid_price', 'bid_qty'],
14
+ pipeline: [
15
+ { fetch: { url: 'https://data-api.binance.vision/api/v3/depth?symbol=${{ args.symbol }}&limit=${{ args.limit }}' } },
16
+ { select: 'bids' },
17
+ { map: { rank: '${{ index + 1 }}', bid_price: '${{ item.0 }}', bid_qty: '${{ item.1 }}' } },
18
+ { limit: '${{ args.limit }}' },
19
+ ],
20
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,21 @@
1
+ import { cli, Strategy } from '@jackwener/opencli/registry';
2
+ cli({
3
+ site: 'binance',
4
+ name: 'gainers',
5
+ description: 'Top gaining trading pairs by 24h price change',
6
+ domain: 'data-api.binance.vision',
7
+ strategy: Strategy.PUBLIC,
8
+ browser: false,
9
+ args: [
10
+ { name: 'limit', type: 'int', default: 10, help: 'Number of trading pairs' },
11
+ ],
12
+ columns: ['rank', 'symbol', 'price', 'change_24h', 'volume'],
13
+ pipeline: [
14
+ { fetch: { url: 'https://data-api.binance.vision/api/v3/ticker/24hr' } },
15
+ { filter: 'item.priceChangePercent' },
16
+ { map: { symbol: '${{ item.symbol }}', price: '${{ item.lastPrice }}', change_24h: '${{ item.priceChangePercent }}', volume: '${{ item.quoteVolume }}', sort_change: '${{ Number(item.priceChangePercent) }}' } },
17
+ { sort: { by: 'sort_change', order: 'desc' } },
18
+ { map: { rank: '${{ index + 1 }}', symbol: '${{ item.symbol }}', price: '${{ item.lastPrice }}', change_24h: '${{ item.priceChangePercent }}', volume: '${{ item.quoteVolume }}' } },
19
+ { limit: '${{ args.limit }}' },
20
+ ],
21
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,20 @@
1
+ import { cli, Strategy } from '@jackwener/opencli/registry';
2
+ cli({
3
+ site: 'binance',
4
+ name: 'klines',
5
+ description: 'Candlestick/kline data for a trading pair',
6
+ domain: 'data-api.binance.vision',
7
+ strategy: Strategy.PUBLIC,
8
+ browser: false,
9
+ args: [
10
+ { name: 'symbol', type: 'str', required: true, positional: true, help: 'Trading pair symbol (e.g. BTCUSDT, ETHUSDT)' },
11
+ { name: 'interval', type: 'str', default: '1d', help: 'Kline interval (1m, 5m, 15m, 1h, 4h, 1d, 1w, 1M)' },
12
+ { name: 'limit', type: 'int', default: 10, help: 'Number of klines (max 1000)' },
13
+ ],
14
+ columns: ['open', 'high', 'low', 'close', 'volume'],
15
+ pipeline: [
16
+ { fetch: { url: 'https://data-api.binance.vision/api/v3/klines?symbol=${{ args.symbol }}&interval=${{ args.interval }}&limit=${{ args.limit }}' } },
17
+ { map: { open: '${{ item.1 }}', high: '${{ item.2 }}', low: '${{ item.3 }}', close: '${{ item.4 }}', volume: '${{ item.5 }}' } },
18
+ { limit: '${{ args.limit }}' },
19
+ ],
20
+ });
@@ -0,0 +1 @@
1
+ export {};