@jackwener/opencli 1.7.12 → 1.7.13

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 (407) hide show
  1. package/README.md +8 -7
  2. package/README.zh-CN.md +9 -8
  3. package/cli-manifest.json +12194 -6843
  4. package/clis/1point3acres/digest.js +35 -0
  5. package/clis/1point3acres/forum.js +51 -0
  6. package/clis/1point3acres/forums.js +44 -0
  7. package/clis/1point3acres/hot.js +35 -0
  8. package/clis/1point3acres/latest.js +35 -0
  9. package/clis/1point3acres/notifications.js +64 -0
  10. package/clis/1point3acres/search.js +71 -0
  11. package/clis/1point3acres/thread.js +117 -0
  12. package/clis/1point3acres/user.js +77 -0
  13. package/clis/1point3acres/utils.js +247 -0
  14. package/clis/_shared/desktop-commands.js +4 -0
  15. package/clis/aibase/news.js +110 -0
  16. package/clis/aibase/news.test.js +59 -0
  17. package/clis/amazon/discussion.test.js +1 -28
  18. package/clis/antigravity/watch.js +3 -2
  19. package/clis/arxiv/author.js +44 -0
  20. package/clis/baidu-scholar/search.js +0 -1
  21. package/clis/bbc/topic.js +57 -0
  22. package/clis/bbc/utils.js +79 -0
  23. package/clis/chaoxing/assignments.js +1 -1
  24. package/clis/chaoxing/exams.js +1 -1
  25. package/clis/chatgpt/ask.js +57 -0
  26. package/clis/chatgpt/commands.test.js +45 -0
  27. package/clis/chatgpt/detail.js +46 -0
  28. package/clis/chatgpt/history.js +39 -0
  29. package/clis/chatgpt/image.js +12 -11
  30. package/clis/chatgpt/image.test.js +23 -0
  31. package/clis/chatgpt/new.js +25 -0
  32. package/clis/chatgpt/read.js +43 -0
  33. package/clis/chatgpt/send.js +46 -0
  34. package/clis/chatgpt/status.js +29 -0
  35. package/clis/chatgpt/utils.js +294 -4
  36. package/clis/chatgpt/utils.test.js +13 -0
  37. package/clis/chatgpt-app/ask.js +6 -3
  38. package/clis/chatwise/ask.js +16 -43
  39. package/clis/chatwise/composer.test.js +186 -0
  40. package/clis/chatwise/send.js +2 -24
  41. package/clis/chatwise/utils.js +143 -0
  42. package/clis/claude/ask.js +1 -1
  43. package/clis/claude/detail.js +1 -0
  44. package/clis/claude/history.js +1 -0
  45. package/clis/claude/new.js +1 -0
  46. package/clis/claude/read.js +1 -0
  47. package/clis/claude/send.js +1 -0
  48. package/clis/claude/status.js +1 -0
  49. package/clis/codex/ask.js +15 -9
  50. package/clis/codex/history.js +16 -33
  51. package/clis/codex/projects.js +28 -0
  52. package/clis/codex/read.js +10 -4
  53. package/clis/codex/send.js +10 -3
  54. package/clis/codex/sidebar.js +356 -0
  55. package/clis/codex/sidebar.test.js +329 -0
  56. package/clis/coingecko/categories.js +75 -0
  57. package/clis/coingecko/coin.js +107 -0
  58. package/clis/coingecko/coingecko.test.js +109 -0
  59. package/clis/coingecko/derivatives.js +84 -0
  60. package/clis/coingecko/exchanges.js +74 -0
  61. package/clis/coingecko/global.js +71 -0
  62. package/clis/coingecko/top.js +64 -0
  63. package/clis/coingecko/trending.js +55 -0
  64. package/clis/coupang/add-to-cart.js +21 -13
  65. package/clis/coupang/coupang.test.js +159 -0
  66. package/clis/coupang/product.js +257 -0
  67. package/clis/coupang/search.js +38 -16
  68. package/clis/coupang/utils.js +55 -1
  69. package/clis/crates/crate.js +62 -0
  70. package/clis/crates/search.js +44 -0
  71. package/clis/crates/utils.js +72 -0
  72. package/clis/ctrip/ctrip.test.js +234 -0
  73. package/clis/ctrip/hotel-suggest.js +45 -0
  74. package/clis/ctrip/search.js +22 -68
  75. package/clis/ctrip/utils.js +175 -0
  76. package/clis/cursor/ask.js +6 -3
  77. package/clis/dblp/author.js +133 -0
  78. package/clis/dblp/venue.js +64 -0
  79. package/clis/deepseek/ask.js +12 -7
  80. package/clis/deepseek/ask.test.js +13 -13
  81. package/clis/deepseek/detail.js +38 -0
  82. package/clis/deepseek/detail.test.js +81 -0
  83. package/clis/deepseek/history.js +1 -0
  84. package/clis/deepseek/new.js +1 -0
  85. package/clis/deepseek/read.js +1 -0
  86. package/clis/deepseek/send.js +140 -0
  87. package/clis/deepseek/send.test.js +107 -0
  88. package/clis/deepseek/status.js +1 -0
  89. package/clis/deepseek/utils.js +66 -0
  90. package/clis/deepseek/utils.test.js +107 -1
  91. package/clis/defillama/defillama.test.js +99 -0
  92. package/clis/defillama/protocol.js +84 -0
  93. package/clis/defillama/protocols.js +55 -0
  94. package/clis/defillama/utils.js +99 -0
  95. package/clis/devto/latest.js +74 -0
  96. package/clis/dockerhub/image.js +52 -0
  97. package/clis/dockerhub/search.js +47 -0
  98. package/clis/dockerhub/utils.js +100 -0
  99. package/clis/doubao/ask.js +7 -3
  100. package/clis/doubao/detail.js +1 -0
  101. package/clis/doubao/history.js +1 -0
  102. package/clis/doubao/meeting-summary.js +1 -0
  103. package/clis/doubao/meeting-transcript.js +1 -0
  104. package/clis/doubao/new.js +1 -0
  105. package/clis/doubao/read.js +1 -0
  106. package/clis/doubao/send.js +1 -0
  107. package/clis/doubao/status.js +1 -0
  108. package/clis/douyin/draft.test.js +1 -30
  109. package/clis/endoflife/endoflife.test.js +51 -0
  110. package/clis/endoflife/product.js +55 -0
  111. package/clis/endoflife/utils.js +89 -0
  112. package/clis/facebook/__fixtures__/notifications-page.html +13 -0
  113. package/clis/facebook/notifications.js +326 -30
  114. package/clis/facebook/notifications.test.js +458 -0
  115. package/clis/flathub/app.js +71 -0
  116. package/clis/flathub/flathub.test.js +90 -0
  117. package/clis/flathub/search.js +80 -0
  118. package/clis/flathub/utils.js +114 -0
  119. package/clis/gemini/ask.js +7 -3
  120. package/clis/gemini/ask.test.js +2 -2
  121. package/clis/gemini/deep-research-result.js +6 -2
  122. package/clis/gemini/deep-research-result.test.js +15 -14
  123. package/clis/gemini/deep-research.js +8 -4
  124. package/clis/gemini/deep-research.test.js +15 -18
  125. package/clis/gemini/image.js +7 -2
  126. package/clis/gemini/new.js +1 -0
  127. package/clis/gemini/utils.js +0 -4
  128. package/clis/google-scholar/cite.js +0 -1
  129. package/clis/google-scholar/profile.js +0 -1
  130. package/clis/google-scholar/search.js +0 -1
  131. package/clis/goproxy/goproxy.test.js +103 -0
  132. package/clis/goproxy/module.js +47 -0
  133. package/clis/goproxy/utils.js +165 -0
  134. package/clis/goproxy/versions.js +59 -0
  135. package/clis/gov-law/recent.js +0 -1
  136. package/clis/gov-law/search.js +0 -1
  137. package/clis/gov-policy/__fixtures__/recent.html +16 -0
  138. package/clis/gov-policy/__fixtures__/search.html +41 -0
  139. package/clis/gov-policy/gov-policy.test.js +224 -0
  140. package/clis/gov-policy/recent.js +66 -24
  141. package/clis/gov-policy/search.js +65 -23
  142. package/clis/gov-policy/utils.js +54 -0
  143. package/clis/grok/ask.js +49 -265
  144. package/clis/grok/ask.test.js +21 -46
  145. package/clis/grok/detail.js +60 -0
  146. package/clis/grok/history.js +48 -0
  147. package/clis/grok/{image.ts → image.js} +56 -70
  148. package/clis/grok/image.test.ts +20 -0
  149. package/clis/grok/new.js +20 -0
  150. package/clis/grok/read.js +39 -0
  151. package/clis/grok/send.js +50 -0
  152. package/clis/grok/status.js +41 -0
  153. package/clis/grok/utils.js +326 -0
  154. package/clis/grok/utils.test.js +103 -0
  155. package/clis/hf/datasets.js +88 -0
  156. package/clis/hf/hf.test.js +16 -0
  157. package/clis/hf/models.js +91 -0
  158. package/clis/hf/paper.js +79 -0
  159. package/clis/hf/spaces.js +101 -0
  160. package/clis/hf/top.js +1 -0
  161. package/clis/homebrew/cask.js +39 -0
  162. package/clis/homebrew/formula.js +41 -0
  163. package/clis/homebrew/popular.js +54 -0
  164. package/clis/homebrew/utils.js +100 -0
  165. package/clis/hupu/__fixtures__/hot-home.html +64 -0
  166. package/clis/hupu/detail.js +0 -1
  167. package/clis/hupu/hot.js +156 -35
  168. package/clis/hupu/hot.test.js +224 -0
  169. package/clis/hupu/search.js +0 -1
  170. package/clis/instagram/note.js +1 -1
  171. package/clis/instagram/note.test.js +1 -29
  172. package/clis/instagram/post.js +1 -1
  173. package/clis/instagram/post.test.js +1 -1
  174. package/clis/instagram/reel.js +1 -1
  175. package/clis/instagram/story.js +1 -1
  176. package/clis/instagram/story.test.js +1 -34
  177. package/clis/jd/commands.test.js +1 -24
  178. package/clis/lichess/lichess.test.js +85 -0
  179. package/clis/lichess/top.js +46 -0
  180. package/clis/lichess/user.js +91 -0
  181. package/clis/lichess/utils.js +97 -0
  182. package/clis/linkedin/search.js +107 -10
  183. package/clis/linkedin/search.test.js +222 -0
  184. package/clis/linux-do/feed.js +2 -5
  185. package/clis/linux-do/feed.test.js +35 -0
  186. package/clis/lobsters/domain.js +92 -0
  187. package/clis/maven/artifact.js +49 -0
  188. package/clis/maven/search.js +51 -0
  189. package/clis/maven/utils.js +110 -0
  190. package/clis/mdn/search.js +97 -0
  191. package/clis/medium/tag.js +135 -0
  192. package/clis/npm/downloads.js +59 -0
  193. package/clis/npm/package.js +70 -0
  194. package/clis/npm/search.js +49 -0
  195. package/clis/npm/utils.js +76 -0
  196. package/clis/nuget/nuget.test.js +111 -0
  197. package/clis/nuget/package.js +101 -0
  198. package/clis/nuget/search.js +69 -0
  199. package/clis/nuget/utils.js +87 -0
  200. package/clis/nvd/cve.js +121 -0
  201. package/clis/oeis/oeis.test.js +88 -0
  202. package/clis/oeis/search.js +63 -0
  203. package/clis/oeis/sequence.js +71 -0
  204. package/clis/oeis/utils.js +88 -0
  205. package/clis/openalex/search.js +69 -0
  206. package/clis/openalex/utils.js +160 -0
  207. package/clis/openalex/work.js +65 -0
  208. package/clis/openfda/drug-label.js +74 -0
  209. package/clis/openfda/food-recall.js +65 -0
  210. package/clis/openfda/openfda.test.js +114 -0
  211. package/clis/openfda/utils.js +67 -0
  212. package/clis/osv/osv.test.js +97 -0
  213. package/clis/osv/query.js +72 -0
  214. package/clis/osv/utils.js +169 -0
  215. package/clis/osv/vulnerability.js +54 -0
  216. package/clis/packagist/package.js +49 -0
  217. package/clis/packagist/search.js +43 -0
  218. package/clis/packagist/utils.js +113 -0
  219. package/clis/paperreview/feedback.js +1 -1
  220. package/clis/paperreview/review.js +1 -1
  221. package/clis/paperreview/submit.js +1 -1
  222. package/clis/pixiv/download.test.js +1 -1
  223. package/clis/pixiv/illusts.test.js +1 -1
  224. package/clis/pixiv/search.test.js +1 -1
  225. package/clis/pubmed/article.js +50 -0
  226. package/clis/pubmed/author.js +64 -0
  227. package/clis/pubmed/citations.js +36 -0
  228. package/clis/pubmed/pubmed.test.js +276 -0
  229. package/clis/pubmed/related.js +45 -0
  230. package/clis/pubmed/search.js +75 -0
  231. package/clis/pubmed/utils.js +309 -0
  232. package/clis/pypi/downloads.js +66 -0
  233. package/clis/pypi/package.js +79 -0
  234. package/clis/pypi/utils.js +55 -0
  235. package/clis/quark/mv.js +1 -1
  236. package/clis/quark/save.js +1 -1
  237. package/clis/qwen/ask.js +85 -0
  238. package/clis/qwen/detail.js +62 -0
  239. package/clis/qwen/history.js +61 -0
  240. package/clis/qwen/image.js +179 -0
  241. package/clis/qwen/new.js +23 -0
  242. package/clis/qwen/read.js +41 -0
  243. package/clis/qwen/send.js +55 -0
  244. package/clis/qwen/status.js +37 -0
  245. package/clis/qwen/utils.js +409 -0
  246. package/clis/qwen/utils.test.js +45 -0
  247. package/clis/rest-countries/country.js +65 -0
  248. package/clis/rest-countries/region.js +64 -0
  249. package/clis/rest-countries/rest-countries.test.js +83 -0
  250. package/clis/rest-countries/utils.js +126 -0
  251. package/clis/reuters/article-detail.js +53 -0
  252. package/clis/reuters/reuters.test.js +299 -0
  253. package/clis/reuters/search.js +45 -34
  254. package/clis/reuters/utils.js +159 -0
  255. package/clis/rfc/rfc.js +52 -0
  256. package/clis/rfc/rfc.test.js +74 -0
  257. package/clis/rfc/utils.js +72 -0
  258. package/clis/rubygems/gem.js +42 -0
  259. package/clis/rubygems/search.js +47 -0
  260. package/clis/rubygems/utils.js +86 -0
  261. package/clis/stackoverflow/related.js +66 -0
  262. package/clis/stackoverflow/stackoverflow.test.js +58 -0
  263. package/clis/stackoverflow/tag.js +60 -0
  264. package/clis/stackoverflow/user.js +50 -0
  265. package/clis/stackoverflow/utils.js +118 -0
  266. package/clis/steam/app.js +67 -0
  267. package/clis/steam/search.js +58 -0
  268. package/clis/steam/steam.test.js +46 -0
  269. package/clis/steam/utils.js +107 -0
  270. package/clis/taobao/commands.test.js +1 -24
  271. package/clis/test-utils.js +61 -0
  272. package/clis/tieba/hot.js +0 -1
  273. package/clis/tiktok/comment.js +128 -41
  274. package/clis/tiktok/creator-videos.js +270 -0
  275. package/clis/tiktok/creator-videos.test.js +113 -0
  276. package/clis/tiktok/explore.js +137 -29
  277. package/clis/tiktok/follow.js +115 -33
  278. package/clis/tiktok/following.js +157 -36
  279. package/clis/tiktok/friends.js +139 -37
  280. package/clis/tiktok/live.js +137 -41
  281. package/clis/tiktok/notifications.js +141 -38
  282. package/clis/tiktok/refactor.test.js +389 -0
  283. package/clis/tiktok/unfollow.js +124 -38
  284. package/clis/tiktok/user.js +203 -29
  285. package/clis/tiktok/utils.js +505 -0
  286. package/clis/tiktok/write-refactor.test.js +370 -0
  287. package/clis/toutiao/articles.js +36 -62
  288. package/clis/toutiao/hot.js +63 -0
  289. package/clis/toutiao/toutiao.test.js +378 -0
  290. package/clis/toutiao/utils.js +161 -0
  291. package/clis/tvmaze/search.js +61 -0
  292. package/clis/tvmaze/show.js +60 -0
  293. package/clis/tvmaze/tvmaze.test.js +93 -0
  294. package/clis/tvmaze/utils.js +110 -0
  295. package/clis/twitter/accept.js +1 -1
  296. package/clis/twitter/followers.js +134 -69
  297. package/clis/twitter/reply-dm.js +1 -1
  298. package/clis/twitter/reply.test.js +1 -29
  299. package/clis/uisdc/news.js +105 -0
  300. package/clis/uisdc/news.test.js +66 -0
  301. package/clis/wanfang/search.js +0 -1
  302. package/clis/web/read.js +47 -17
  303. package/clis/web/read.test.js +101 -1
  304. package/clis/weixin/create-draft.js +1 -1
  305. package/clis/weixin/drafts.js +1 -1
  306. package/clis/weixin/drafts.test.js +5 -1
  307. package/clis/weixin/search.js +157 -0
  308. package/clis/weixin/search.test.js +227 -0
  309. package/clis/wikidata/entity.js +60 -0
  310. package/clis/wikidata/search.js +50 -0
  311. package/clis/wikidata/utils.js +117 -0
  312. package/clis/wikidata/wikidata.test.js +83 -0
  313. package/clis/wikipedia/page.js +95 -0
  314. package/clis/wttr/current.js +63 -0
  315. package/clis/wttr/forecast.js +71 -0
  316. package/clis/wttr/utils.js +50 -0
  317. package/clis/wttr/wttr.test.js +84 -0
  318. package/clis/xianyu/chat.js +16 -4
  319. package/clis/xianyu/chat.test.js +64 -0
  320. package/clis/xianyu/publish.js +485 -0
  321. package/clis/xianyu/publish.test.js +220 -0
  322. package/clis/xiaoe/catalog.js +105 -40
  323. package/clis/xiaoe/content.js +164 -29
  324. package/clis/xiaoe/courses.js +86 -29
  325. package/clis/xiaoe/xiaoe.test.js +486 -0
  326. package/clis/xiaohongshu/creator-notes-summary.js +1 -1
  327. package/clis/xiaohongshu/publish.js +16 -3
  328. package/clis/xiaohongshu/publish.test.js +46 -1
  329. package/clis/youtube/transcript.js +13 -19
  330. package/clis/youtube/transcript.test.js +17 -0
  331. package/clis/yuanbao/ask.js +17 -66
  332. package/clis/yuanbao/ask.test.js +5 -5
  333. package/clis/yuanbao/detail.js +65 -0
  334. package/clis/yuanbao/history.js +51 -0
  335. package/clis/yuanbao/new.js +1 -0
  336. package/clis/yuanbao/read.js +38 -0
  337. package/clis/yuanbao/send.js +57 -0
  338. package/clis/yuanbao/shared.js +297 -5
  339. package/clis/yuanbao/shared.test.js +80 -0
  340. package/clis/yuanbao/status.js +44 -0
  341. package/clis/zlibrary/commands.test.js +1 -11
  342. package/dist/src/browser/base-page.d.ts +9 -0
  343. package/dist/src/browser/base-page.js +44 -1
  344. package/dist/src/browser/base-page.test.js +66 -0
  345. package/dist/src/browser/cdp.d.ts +1 -0
  346. package/dist/src/browser/cdp.js +51 -9
  347. package/dist/src/browser/daemon-client.d.ts +4 -0
  348. package/dist/src/browser/errors.js +1 -1
  349. package/dist/src/browser/page.d.ts +1 -1
  350. package/dist/src/browser/page.js +3 -1
  351. package/dist/src/browser/page.test.js +29 -0
  352. package/dist/src/browser/target-errors.d.ts +2 -1
  353. package/dist/src/browser/target-errors.js +1 -0
  354. package/dist/src/browser/target-resolver.d.ts +25 -0
  355. package/dist/src/browser/target-resolver.js +43 -0
  356. package/dist/src/build-manifest.js +9 -4
  357. package/dist/src/build-manifest.test.js +2 -8
  358. package/dist/src/capabilityRouting.d.ts +16 -1
  359. package/dist/src/capabilityRouting.js +24 -1
  360. package/dist/src/capabilityRouting.test.js +19 -1
  361. package/dist/src/cli.js +76 -11
  362. package/dist/src/cli.test.js +150 -0
  363. package/dist/src/commanderAdapter.js +0 -5
  364. package/dist/src/commanderAdapter.test.js +0 -1
  365. package/dist/src/discovery.js +2 -5
  366. package/dist/src/errors.js +1 -1
  367. package/dist/src/execution.d.ts +1 -1
  368. package/dist/src/execution.js +111 -27
  369. package/dist/src/execution.test.js +326 -17
  370. package/dist/src/help.d.ts +23 -2
  371. package/dist/src/help.js +41 -19
  372. package/dist/src/help.test.d.ts +1 -0
  373. package/dist/src/help.test.js +54 -0
  374. package/dist/src/main.js +14 -1
  375. package/dist/src/manifest-types.d.ts +5 -3
  376. package/dist/src/pipeline/executor.js +1 -1
  377. package/dist/src/pipeline/executor.test.js +8 -0
  378. package/dist/src/pipeline/registry.d.ts +9 -0
  379. package/dist/src/pipeline/registry.js +13 -1
  380. package/dist/src/pipeline/steps/browser.d.ts +1 -0
  381. package/dist/src/pipeline/steps/browser.js +10 -0
  382. package/dist/src/pipeline/steps/download.test.js +1 -0
  383. package/dist/src/registry-api.d.ts +1 -1
  384. package/dist/src/registry.d.ts +12 -11
  385. package/dist/src/registry.js +16 -6
  386. package/dist/src/registry.test.js +2 -2
  387. package/dist/src/runtime.d.ts +2 -1
  388. package/dist/src/runtime.js +1 -1
  389. package/dist/src/serialization.d.ts +2 -2
  390. package/dist/src/serialization.js +4 -6
  391. package/dist/src/serialization.test.js +17 -0
  392. package/dist/src/types.d.ts +17 -0
  393. package/dist/src/validate.js +15 -11
  394. package/dist/src/validate.test.d.ts +9 -0
  395. package/dist/src/validate.test.js +90 -0
  396. package/package.json +1 -1
  397. package/scripts/fetch-adapters.js +1 -1
  398. package/scripts/typed-error-lint-baseline.json +5 -77
  399. package/clis/ctrip/search.test.js +0 -64
  400. package/clis/gov-policy/commands.test.js +0 -27
  401. package/clis/linux-do/category.js +0 -37
  402. package/clis/linux-do/hot.js +0 -26
  403. package/clis/linux-do/latest.js +0 -19
  404. package/clis/pixiv/test-utils.js +0 -23
  405. package/clis/toutiao/articles.test.js +0 -30
  406. package/dist/src/analysis.d.ts +0 -40
  407. package/dist/src/analysis.js +0 -172
@@ -3,7 +3,7 @@
3
3
  * Allows core and third-party plugins to register custom YAML operations.
4
4
  */
5
5
  // Import core steps
6
- import { stepNavigate, stepClick, stepType, stepWait, stepPress, stepSnapshot, stepEvaluate } from './steps/browser.js';
6
+ import { stepNavigate, stepClick, stepType, stepFill, stepWait, stepPress, stepSnapshot, stepEvaluate } from './steps/browser.js';
7
7
  import { stepFetch } from './steps/fetch.js';
8
8
  import { stepSelect, stepMap, stepFilter, stepSort, stepLimit } from './steps/transform.js';
9
9
  import { stepIntercept } from './steps/intercept.js';
@@ -16,6 +16,17 @@ const _stepRegistry = new Map();
16
16
  export function getStep(name) {
17
17
  return _stepRegistry.get(name);
18
18
  }
19
+ /**
20
+ * List all currently registered step names. Used by `validate.ts` to allowlist
21
+ * step names without maintaining a parallel hand-coded list.
22
+ *
23
+ * Note: this depends on registerStep() side effects below already having run.
24
+ * Importing this module triggers all core registrations at the bottom of the
25
+ * file, so the returned array reflects every core + plugin step at call time.
26
+ */
27
+ export function getRegisteredStepNames() {
28
+ return [..._stepRegistry.keys()];
29
+ }
19
30
  /**
20
31
  * Register a new custom step handler for the YAML pipeline.
21
32
  */
@@ -32,6 +43,7 @@ registerStep('evaluate', stepEvaluate);
32
43
  registerStep('snapshot', stepSnapshot);
33
44
  registerStep('click', stepClick);
34
45
  registerStep('type', stepType);
46
+ registerStep('fill', stepFill);
35
47
  registerStep('wait', stepWait);
36
48
  registerStep('press', stepPress);
37
49
  registerStep('map', stepMap);
@@ -6,6 +6,7 @@ import type { IPage } from '../../types.js';
6
6
  export declare function stepNavigate(page: IPage | null, params: unknown, data: unknown, args: Record<string, unknown>): Promise<unknown>;
7
7
  export declare function stepClick(page: IPage | null, params: unknown, data: unknown, args: Record<string, unknown>): Promise<unknown>;
8
8
  export declare function stepType(page: IPage | null, params: unknown, data: unknown, args: Record<string, unknown>): Promise<unknown>;
9
+ export declare function stepFill(page: IPage | null, params: unknown, data: unknown, args: Record<string, unknown>): Promise<unknown>;
9
10
  export declare function stepWait(page: IPage | null, params: unknown, data: unknown, args: Record<string, unknown>): Promise<unknown>;
10
11
  export declare function stepPress(page: IPage | null, params: unknown, data: unknown, args: Record<string, unknown>): Promise<unknown>;
11
12
  export declare function stepSnapshot(page: IPage | null, params: unknown, _data: unknown, _args: Record<string, unknown>): Promise<unknown>;
@@ -29,6 +29,16 @@ export async function stepType(page, params, data, args) {
29
29
  }
30
30
  return data;
31
31
  }
32
+ export async function stepFill(page, params, data, args) {
33
+ if (isRecord(params)) {
34
+ const ref = String(render(params.ref ?? '', { args, data })).replace(/^@/, '');
35
+ const text = String(render(params.text ?? '', { args, data }));
36
+ await page.fillText(ref, text);
37
+ if (params.submit)
38
+ await page.pressKey('Enter');
39
+ }
40
+ return data;
41
+ }
32
42
  export async function stepWait(page, params, data, args) {
33
43
  if (typeof params === 'number')
34
44
  await page.wait(params);
@@ -25,6 +25,7 @@ function createMockPage(getCookies) {
25
25
  snapshot: vi.fn().mockResolvedValue(''),
26
26
  click: vi.fn(),
27
27
  typeText: vi.fn(),
28
+ fillText: vi.fn(),
28
29
  pressKey: vi.fn(),
29
30
  scrollTo: vi.fn(),
30
31
  getFormState: vi.fn().mockResolvedValue({}),
@@ -7,7 +7,7 @@
7
7
  * plugins are dynamically imported during discoverPlugins().
8
8
  */
9
9
  export { cli, Strategy, getRegistry, fullName, registerCommand } from './registry.js';
10
- export type { CliCommand, Arg, CliOptions, CommandArgs } from './registry.js';
10
+ export type { CliCommand, Arg, CliOptions, CommandArgs, BrowserSessionOptions, BrowserSessionReuse } from './registry.js';
11
11
  export type { IPage } from './types.js';
12
12
  export { onStartup, onBeforeExecute, onAfterExecute } from './hooks.js';
13
13
  export type { HookFn, HookContext, HookName } from './hooks.js';
@@ -6,7 +6,6 @@ export declare enum Strategy {
6
6
  PUBLIC = "public",
7
7
  LOCAL = "local",
8
8
  COOKIE = "cookie",
9
- HEADER = "header",
10
9
  INTERCEPT = "intercept",
11
10
  UI = "ui"
12
11
  }
@@ -20,14 +19,20 @@ export interface Arg {
20
19
  help?: string;
21
20
  choices?: string[];
22
21
  }
23
- export interface RequiredEnv {
24
- name: string;
25
- help?: string;
26
- }
27
22
  export type CommandArgs = Record<string, any>;
28
23
  export type BrowserCommandFunc = (page: IPage, kwargs: CommandArgs, debug?: boolean) => Promise<unknown>;
29
24
  export type NonBrowserCommandFunc = (kwargs: CommandArgs, debug?: boolean) => Promise<unknown>;
30
25
  export type CommandAccess = 'read' | 'write';
26
+ export type BrowserSessionReuse = 'none' | 'site';
27
+ export interface BrowserSessionOptions {
28
+ /**
29
+ * Control whether browser-backed adapter commands reuse a stable tab lease.
30
+ *
31
+ * - `none`: one-shot workspace per command execution (default)
32
+ * - `site`: all commands for this site share `site:<site>` until idle expiry
33
+ */
34
+ reuse?: BrowserSessionReuse;
35
+ }
31
36
  interface BaseCliCommand {
32
37
  site: string;
33
38
  name: string;
@@ -41,16 +46,10 @@ interface BaseCliCommand {
41
46
  args: Arg[];
42
47
  columns?: string[];
43
48
  pipeline?: Record<string, unknown>[];
44
- timeoutSeconds?: number;
45
49
  /** Origin of this command: 'yaml', 'ts', or plugin name. */
46
50
  source?: string;
47
51
  footerExtra?: (kwargs: CommandArgs) => string | undefined;
48
- requiredEnv?: RequiredEnv[];
49
52
  validateArgs?: (kwargs: CommandArgs) => void;
50
- /** Deprecation note shown in help / execution warnings. */
51
- deprecated?: boolean | string;
52
- /** Preferred replacement command, if any. */
53
- replacedBy?: string;
54
53
  /**
55
54
  * Control pre-navigation and browser-session requirement.
56
55
  *
@@ -67,6 +66,8 @@ interface BaseCliCommand {
67
66
  * Adapter authors can set this explicitly to override the strategy-based default.
68
67
  */
69
68
  navigateBefore?: boolean | string;
69
+ /** Browser session lifecycle defaults for adapter commands. */
70
+ browserSession?: BrowserSessionOptions;
70
71
  /** Override the default CLI output format when the user does not pass -f/--format. */
71
72
  defaultFormat?: 'table' | 'plain' | 'json' | 'yaml' | 'yml' | 'md' | 'markdown' | 'csv';
72
73
  }
@@ -6,7 +6,6 @@ export var Strategy;
6
6
  Strategy["PUBLIC"] = "public";
7
7
  Strategy["LOCAL"] = "local";
8
8
  Strategy["COOKIE"] = "cookie";
9
- Strategy["HEADER"] = "header";
10
9
  Strategy["INTERCEPT"] = "intercept";
11
10
  Strategy["UI"] = "ui";
12
11
  })(Strategy || (Strategy = {}));
@@ -18,6 +17,7 @@ export function cli(opts) {
18
17
  aliases: opts.aliases,
19
18
  description: opts.description ?? '',
20
19
  access: opts.access,
20
+ example: opts.example,
21
21
  domain: opts.domain,
22
22
  strategy: opts.strategy,
23
23
  browser: opts.browser,
@@ -25,12 +25,9 @@ export function cli(opts) {
25
25
  columns: opts.columns,
26
26
  func: opts.func,
27
27
  pipeline: opts.pipeline,
28
- timeoutSeconds: opts.timeoutSeconds,
29
28
  footerExtra: opts.footerExtra,
30
- requiredEnv: opts.requiredEnv,
31
- deprecated: opts.deprecated,
32
- replacedBy: opts.replacedBy,
33
29
  navigateBefore: opts.navigateBefore,
30
+ browserSession: opts.browserSession,
34
31
  defaultFormat: opts.defaultFormat,
35
32
  };
36
33
  registerCommand(cmd);
@@ -60,11 +57,12 @@ export function strategyLabel(cmd) {
60
57
  */
61
58
  function normalizeCommand(cmd) {
62
59
  assertCommandAccess(cmd);
60
+ assertBrowserSessionOptions(cmd);
63
61
  const strategy = cmd.strategy ?? (cmd.browser === false ? Strategy.PUBLIC : Strategy.COOKIE);
64
62
  const browser = cmd.browser ?? (strategy !== Strategy.PUBLIC && strategy !== Strategy.LOCAL);
65
63
  let navigateBefore = cmd.navigateBefore;
66
64
  if (navigateBefore === undefined) {
67
- if ((strategy === Strategy.COOKIE || strategy === Strategy.HEADER) && cmd.domain) {
65
+ if (strategy === Strategy.COOKIE && cmd.domain) {
68
66
  navigateBefore = `https://${cmd.domain}`;
69
67
  }
70
68
  else if (strategy !== Strategy.PUBLIC && strategy !== Strategy.LOCAL) {
@@ -84,6 +82,18 @@ function assertCommandAccess(cmd) {
84
82
  const key = `${cmd.site}/${cmd.name}`;
85
83
  throw new Error(`Command ${key} must declare access: 'read' | 'write'`);
86
84
  }
85
+ function assertBrowserSessionOptions(cmd) {
86
+ if (cmd.browserSession === undefined)
87
+ return;
88
+ const key = `${cmd.site}/${cmd.name}`;
89
+ if (cmd.browserSession === null || typeof cmd.browserSession !== 'object' || Array.isArray(cmd.browserSession)) {
90
+ throw new Error(`Command ${key} browserSession must be an object`);
91
+ }
92
+ const reuse = cmd.browserSession.reuse;
93
+ if (reuse !== undefined && reuse !== 'none' && reuse !== 'site') {
94
+ throw new Error(`Command ${key} browserSession.reuse must be one of: none, site`);
95
+ }
96
+ }
87
97
  export function registerCommand(cmd) {
88
98
  const normalized = normalizeCommand(cmd);
89
99
  const canonicalKey = fullName(normalized);
@@ -121,12 +121,12 @@ describe('registerCommand', () => {
121
121
  name: 'direct-reg', access: 'read',
122
122
  description: 'directly registered',
123
123
  args: [],
124
- strategy: Strategy.HEADER,
124
+ strategy: Strategy.COOKIE,
125
125
  browser: true,
126
126
  };
127
127
  registerCommand(cmd);
128
128
  const reg = getRegistry();
129
- expect(reg.get('test-registry/direct-reg')?.strategy).toBe(Strategy.HEADER);
129
+ expect(reg.get('test-registry/direct-reg')?.strategy).toBe(Strategy.COOKIE);
130
130
  });
131
131
  });
132
132
  describe('normalizeCommand (via registerCommand)', () => {
@@ -6,7 +6,6 @@ import type { IPage } from './types.js';
6
6
  export declare function getBrowserFactory(site?: string): new () => IBrowserFactory;
7
7
  export declare const DEFAULT_BROWSER_CONNECT_TIMEOUT: number;
8
8
  export declare const DEFAULT_BROWSER_COMMAND_TIMEOUT: number;
9
- export declare const DEFAULT_BROWSER_EXPLORE_TIMEOUT: number;
10
9
  /**
11
10
  * Timeout with seconds unit. Used for high-level command timeouts.
12
11
  */
@@ -28,6 +27,7 @@ export interface IBrowserFactory {
28
27
  workspace?: string;
29
28
  cdpEndpoint?: string;
30
29
  contextId?: string;
30
+ idleTimeout?: number;
31
31
  }): Promise<IPage>;
32
32
  close(): Promise<void>;
33
33
  }
@@ -35,4 +35,5 @@ export declare function browserSession<T>(BrowserFactory: new () => IBrowserFact
35
35
  workspace?: string;
36
36
  cdpEndpoint?: string;
37
37
  contextId?: string;
38
+ idleTimeout?: number;
38
39
  }): Promise<T>;
@@ -24,7 +24,6 @@ function parseEnvTimeout(envVar, fallback) {
24
24
  }
25
25
  export const DEFAULT_BROWSER_CONNECT_TIMEOUT = parseEnvTimeout('OPENCLI_BROWSER_CONNECT_TIMEOUT', 30);
26
26
  export const DEFAULT_BROWSER_COMMAND_TIMEOUT = parseEnvTimeout('OPENCLI_BROWSER_COMMAND_TIMEOUT', 60);
27
- export const DEFAULT_BROWSER_EXPLORE_TIMEOUT = parseEnvTimeout('OPENCLI_BROWSER_EXPLORE_TIMEOUT', 120);
28
27
  /**
29
28
  * Timeout with seconds unit. Used for high-level command timeouts.
30
29
  */
@@ -54,6 +53,7 @@ export async function browserSession(BrowserFactory, fn, opts = {}) {
54
53
  workspace: opts.workspace,
55
54
  cdpEndpoint: opts.cdpEndpoint,
56
55
  contextId: opts.contextId,
56
+ idleTimeout: opts.idleTimeout,
57
57
  });
58
58
  return await fn(page);
59
59
  }
@@ -31,8 +31,8 @@ export declare function serializeCommand(cmd: CliCommand): {
31
31
  columns: string[];
32
32
  domain: string | null;
33
33
  example: string;
34
- deprecated: string | boolean | null;
35
- replacedBy: string | null;
34
+ defaultFormat: "table" | "plain" | "json" | "yaml" | "yml" | "md" | "markdown" | "csv" | null;
35
+ browserSession: import("./registry.js").BrowserSessionOptions | null;
36
36
  };
37
37
  /** Human-readable arg summary: `<required> [optional]` style. */
38
38
  export declare function formatArgSummary(args: Arg[]): string;
@@ -33,8 +33,8 @@ export function serializeCommand(cmd) {
33
33
  columns: cmd.columns ?? [],
34
34
  domain: cmd.domain ?? null,
35
35
  example: formatCommandExample(cmd),
36
- deprecated: cmd.deprecated ?? null,
37
- replacedBy: cmd.replacedBy ?? null,
36
+ defaultFormat: cmd.defaultFormat ?? null,
37
+ browserSession: cmd.browserSession ?? null,
38
38
  };
39
39
  }
40
40
  // ── Formatting ──────────────────────────────────────────────────────────────
@@ -90,10 +90,8 @@ export function formatRegistryHelpText(cmd) {
90
90
  meta.push(`Browser: ${cmd.browser ? 'yes' : 'no'}`);
91
91
  if (cmd.domain)
92
92
  meta.push(`Domain: ${cmd.domain}`);
93
- if (cmd.deprecated)
94
- meta.push(`Deprecated: ${typeof cmd.deprecated === 'string' ? cmd.deprecated : 'yes'}`);
95
- if (cmd.replacedBy)
96
- meta.push(`Use instead: ${cmd.replacedBy}`);
93
+ if (cmd.defaultFormat)
94
+ meta.push(`Default format: ${cmd.defaultFormat}`);
97
95
  if (cmd.aliases?.length)
98
96
  meta.push(`Aliases: ${cmd.aliases.join(', ')}`);
99
97
  lines.push(meta.join(' | '));
@@ -58,4 +58,21 @@ describe('formatRegistryHelpText', () => {
58
58
  expect(formatRegistryHelpText(cmd)).toContain('Example: opencli bilibili hot -f yaml');
59
59
  expect(formatRegistryHelpText(cmd)).not.toContain('Strategy:');
60
60
  });
61
+ it('surfaces command default output format in structured serialization and help text', () => {
62
+ const cmd = {
63
+ site: 'gemini',
64
+ name: 'ask',
65
+ access: 'read',
66
+ description: 'Ask Gemini',
67
+ strategy: Strategy.COOKIE,
68
+ browser: true,
69
+ args: [],
70
+ defaultFormat: 'plain',
71
+ };
72
+ expect(serializeCommand(cmd)).toMatchObject({
73
+ command: 'gemini/ask',
74
+ defaultFormat: 'plain',
75
+ });
76
+ expect(formatRegistryHelpText(cmd)).toContain('Default format: plain');
77
+ });
61
78
  });
@@ -31,6 +31,10 @@ export interface ScreenshotOptions {
31
31
  format?: 'png' | 'jpeg';
32
32
  quality?: number;
33
33
  fullPage?: boolean;
34
+ /** Override viewport width in CSS pixels for the screenshot only (cleared after). */
35
+ width?: number;
36
+ /** Override viewport height in CSS pixels for the screenshot only (ignored when fullPage). */
37
+ height?: number;
34
38
  path?: string;
35
39
  }
36
40
  export interface FetchJsonOptions {
@@ -87,6 +91,19 @@ export interface IPage {
87
91
  matches_n: number;
88
92
  match_level: 'exact' | 'stable' | 'reidentified';
89
93
  }>;
94
+ fillText(ref: string, text: string, opts?: {
95
+ nth?: number;
96
+ firstOnMulti?: boolean;
97
+ }): Promise<{
98
+ filled: boolean;
99
+ verified: boolean;
100
+ expected: string;
101
+ actual: string;
102
+ length: number;
103
+ matches_n: number;
104
+ match_level: 'exact' | 'stable' | 'reidentified';
105
+ mode?: 'input' | 'textarea' | 'contenteditable';
106
+ }>;
90
107
  pressKey(key: string): Promise<void>;
91
108
  scrollTo(ref: string, opts?: {
92
109
  nth?: number;
@@ -1,12 +1,15 @@
1
1
  /** Validate CLI definitions from the registry (JS-first). */
2
2
  import { getRegistry, fullName } from './registry.js';
3
- /** All recognized pipeline step names */
4
- const KNOWN_STEP_NAMES = new Set([
5
- 'navigate', 'click', 'type', 'wait', 'press', 'snapshot',
6
- 'fetch', 'evaluate',
7
- 'select', 'map', 'filter', 'sort', 'limit',
8
- 'intercept', 'tap', 'download',
9
- ]);
3
+ import { getRegisteredStepNames } from './pipeline/registry.js';
4
+ /**
5
+ * Pipeline step names — derived from the live pipeline registry on each
6
+ * validate call so a new step registered in src/pipeline/registry.ts (or by
7
+ * a plugin at runtime) is automatically allowlisted here (no parallel
8
+ * hand-maintained list, no stale-snapshot drift).
9
+ */
10
+ function getKnownStepNames() {
11
+ return new Set(getRegisteredStepNames());
12
+ }
10
13
  /**
11
14
  * Validate registered CLI commands from the in-memory registry.
12
15
  *
@@ -66,18 +69,19 @@ function validateCommand(cmd) {
66
69
  const warnings = [];
67
70
  if (!cmd.description)
68
71
  warnings.push('Missing description');
69
- // Browser commands should specify a domain for cookie/header context
72
+ // Browser commands should specify a domain for authenticated browser context
70
73
  if (cmd.browser && !cmd.domain) {
71
- warnings.push('Browser command without "domain" — cookie/header context may not work');
74
+ warnings.push('Browser command without "domain" — authenticated browser context may not work');
72
75
  }
73
76
  // Pipeline validation: check step names for typos
74
77
  if (Array.isArray(cmd.pipeline)) {
78
+ const knownStepNames = getKnownStepNames();
75
79
  for (let i = 0; i < cmd.pipeline.length; i++) {
76
80
  const step = cmd.pipeline[i];
77
81
  if (step && typeof step === 'object') {
78
82
  for (const key of Object.keys(step)) {
79
- if (!KNOWN_STEP_NAMES.has(key)) {
80
- warnings.push(`Pipeline step ${i}: unknown step name "${key}" (did you mean one of: ${[...KNOWN_STEP_NAMES].join(', ')}?)`);
83
+ if (!knownStepNames.has(key)) {
84
+ warnings.push(`Pipeline step ${i}: unknown step name "${key}" (did you mean one of: ${[...knownStepNames].join(', ')}?)`);
81
85
  }
82
86
  }
83
87
  }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Tests for src/validate.ts.
3
+ *
4
+ * Focus: regression guards for the "single source of truth" link between
5
+ * pipeline step registry (src/pipeline/registry.ts) and validate.ts step
6
+ * allowlist. A new step registered via `registerStep()` must automatically
7
+ * be allowlisted by `opencli validate` — no parallel hand-maintained list.
8
+ */
9
+ export {};
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Tests for src/validate.ts.
3
+ *
4
+ * Focus: regression guards for the "single source of truth" link between
5
+ * pipeline step registry (src/pipeline/registry.ts) and validate.ts step
6
+ * allowlist. A new step registered via `registerStep()` must automatically
7
+ * be allowlisted by `opencli validate` — no parallel hand-maintained list.
8
+ */
9
+ import { describe, it, expect } from 'vitest';
10
+ import { getRegisteredStepNames, registerStep } from './pipeline/registry.js';
11
+ import { cli, getRegistry, Strategy } from './registry.js';
12
+ import { validateClisWithTarget } from './validate.js';
13
+ describe('validate.ts pipeline step allowlist', () => {
14
+ it('uses every step name registered in pipeline/registry.ts', () => {
15
+ const registered = getRegisteredStepNames();
16
+ expect(registered).toContain('navigate');
17
+ expect(registered).toContain('click');
18
+ expect(registered).toContain('type');
19
+ expect(registered).toContain('fill');
20
+ expect(registered).toContain('fetch');
21
+ expect(registered.length).toBeGreaterThanOrEqual(15);
22
+ });
23
+ it('does not warn for any step name currently registered in the pipeline registry', () => {
24
+ // Snapshot the registry before mutating it for the test.
25
+ const reg = getRegistry();
26
+ const original = reg.get('validate-allowlist-test/all-steps');
27
+ if (original)
28
+ reg.delete('validate-allowlist-test/all-steps');
29
+ const allRegisteredSteps = getRegisteredStepNames();
30
+ cli({
31
+ site: 'validate-allowlist-test',
32
+ name: 'all-steps',
33
+ access: 'read',
34
+ browser: false,
35
+ strategy: Strategy.PUBLIC,
36
+ args: [],
37
+ pipeline: allRegisteredSteps.map(stepName => ({ [stepName]: {} })),
38
+ func: async () => [],
39
+ });
40
+ try {
41
+ const report = validateClisWithTarget([], 'validate-allowlist-test/all-steps');
42
+ const r = report.results[0];
43
+ const unknownStepWarning = r.warnings.find(w => w.startsWith('Pipeline step '));
44
+ expect(unknownStepWarning).toBeUndefined();
45
+ }
46
+ finally {
47
+ reg.delete('validate-allowlist-test/all-steps');
48
+ if (original)
49
+ reg.set('validate-allowlist-test/all-steps', original);
50
+ }
51
+ });
52
+ it('newly registered step automatically appears in validator allowlist', () => {
53
+ const customStep = '__test_custom_step__';
54
+ expect(getRegisteredStepNames()).not.toContain(customStep);
55
+ registerStep(customStep, async (_p, _params, data) => data);
56
+ try {
57
+ expect(getRegisteredStepNames()).toContain(customStep);
58
+ const reg = getRegistry();
59
+ const original = reg.get('validate-dynamic-test/uses-custom');
60
+ if (original)
61
+ reg.delete('validate-dynamic-test/uses-custom');
62
+ cli({
63
+ site: 'validate-dynamic-test',
64
+ name: 'uses-custom',
65
+ access: 'read',
66
+ browser: false,
67
+ strategy: Strategy.PUBLIC,
68
+ args: [],
69
+ pipeline: [{ [customStep]: {} }],
70
+ func: async () => [],
71
+ });
72
+ try {
73
+ const report = validateClisWithTarget([], 'validate-dynamic-test/uses-custom');
74
+ const r = report.results[0];
75
+ const unknownStepWarning = r.warnings.find(w => w.includes(customStep));
76
+ expect(unknownStepWarning).toBeUndefined();
77
+ }
78
+ finally {
79
+ reg.delete('validate-dynamic-test/uses-custom');
80
+ if (original)
81
+ reg.set('validate-dynamic-test/uses-custom', original);
82
+ }
83
+ }
84
+ finally {
85
+ // Best-effort cleanup of the test step. There is no `unregisterStep` —
86
+ // leaving it registered is harmless because the test step name is
87
+ // namespaced and never used outside this file.
88
+ }
89
+ });
90
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jackwener/opencli",
3
- "version": "1.7.12",
3
+ "version": "1.7.13",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -188,7 +188,7 @@ export function fetchAdapters() {
188
188
 
189
189
  // 3b. Clean up stale .yaml/.yml adapter files left by older versions (pre-1.7.0)
190
190
  // Older versions shipped adapters as YAML; current versions use .js only.
191
- // These cause "Ignoring YAML adapter" warnings on every run (issue #953).
191
+ // These are no longer discoverable and can shadow the current .js adapter layout.
192
192
  let yamlCleaned = 0;
193
193
  for (const relPath of walkFiles(USER_CLIS_DIR)) {
194
194
  if (relPath.endsWith('.yaml') || relPath.endsWith('.yml')) {