@jackwener/opencli 1.7.12 → 1.7.14

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 (419) hide show
  1. package/README.md +8 -7
  2. package/README.zh-CN.md +9 -8
  3. package/cli-manifest.json +12128 -6665
  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/quote.js +139 -0
  298. package/clis/twitter/quote.test.js +106 -0
  299. package/clis/twitter/reply-dm.js +1 -1
  300. package/clis/twitter/reply.test.js +1 -29
  301. package/clis/twitter/retweet.js +99 -0
  302. package/clis/twitter/retweet.test.js +69 -0
  303. package/clis/twitter/shared.js +38 -0
  304. package/clis/twitter/shared.test.js +28 -1
  305. package/clis/twitter/unlike.js +87 -0
  306. package/clis/twitter/unlike.test.js +72 -0
  307. package/clis/twitter/unretweet.js +99 -0
  308. package/clis/twitter/unretweet.test.js +69 -0
  309. package/clis/uisdc/news.js +105 -0
  310. package/clis/uisdc/news.test.js +66 -0
  311. package/clis/wanfang/search.js +0 -1
  312. package/clis/web/read.js +47 -17
  313. package/clis/web/read.test.js +101 -1
  314. package/clis/weixin/create-draft.js +1 -1
  315. package/clis/weixin/drafts.js +1 -1
  316. package/clis/weixin/drafts.test.js +5 -1
  317. package/clis/weixin/search.js +157 -0
  318. package/clis/weixin/search.test.js +227 -0
  319. package/clis/wikidata/entity.js +60 -0
  320. package/clis/wikidata/search.js +50 -0
  321. package/clis/wikidata/utils.js +117 -0
  322. package/clis/wikidata/wikidata.test.js +83 -0
  323. package/clis/wikipedia/page.js +95 -0
  324. package/clis/wttr/current.js +63 -0
  325. package/clis/wttr/forecast.js +71 -0
  326. package/clis/wttr/utils.js +50 -0
  327. package/clis/wttr/wttr.test.js +84 -0
  328. package/clis/xianyu/chat.js +16 -4
  329. package/clis/xianyu/chat.test.js +64 -0
  330. package/clis/xianyu/publish.js +485 -0
  331. package/clis/xianyu/publish.test.js +220 -0
  332. package/clis/xiaoe/catalog.js +105 -40
  333. package/clis/xiaoe/content.js +164 -29
  334. package/clis/xiaoe/courses.js +86 -29
  335. package/clis/xiaoe/xiaoe.test.js +486 -0
  336. package/clis/xiaohongshu/creator-notes-summary.js +1 -1
  337. package/clis/xiaohongshu/publish.js +16 -3
  338. package/clis/xiaohongshu/publish.test.js +46 -1
  339. package/clis/youtube/transcript.js +13 -19
  340. package/clis/youtube/transcript.test.js +17 -0
  341. package/clis/yuanbao/ask.js +17 -66
  342. package/clis/yuanbao/ask.test.js +5 -5
  343. package/clis/yuanbao/detail.js +65 -0
  344. package/clis/yuanbao/history.js +51 -0
  345. package/clis/yuanbao/new.js +1 -0
  346. package/clis/yuanbao/read.js +38 -0
  347. package/clis/yuanbao/send.js +57 -0
  348. package/clis/yuanbao/shared.js +297 -5
  349. package/clis/yuanbao/shared.test.js +80 -0
  350. package/clis/yuanbao/status.js +44 -0
  351. package/clis/zlibrary/commands.test.js +1 -11
  352. package/dist/src/browser/base-page.d.ts +9 -0
  353. package/dist/src/browser/base-page.js +44 -1
  354. package/dist/src/browser/base-page.test.js +66 -0
  355. package/dist/src/browser/bridge.js +47 -45
  356. package/dist/src/browser/cdp.d.ts +1 -0
  357. package/dist/src/browser/cdp.js +51 -9
  358. package/dist/src/browser/daemon-client.d.ts +4 -0
  359. package/dist/src/browser/errors.js +1 -1
  360. package/dist/src/browser/page.d.ts +1 -1
  361. package/dist/src/browser/page.js +3 -1
  362. package/dist/src/browser/page.test.js +29 -0
  363. package/dist/src/browser/target-errors.d.ts +2 -1
  364. package/dist/src/browser/target-errors.js +1 -0
  365. package/dist/src/browser/target-resolver.d.ts +25 -0
  366. package/dist/src/browser/target-resolver.js +43 -0
  367. package/dist/src/browser.test.js +18 -0
  368. package/dist/src/build-manifest.js +9 -4
  369. package/dist/src/build-manifest.test.js +2 -8
  370. package/dist/src/capabilityRouting.d.ts +16 -1
  371. package/dist/src/capabilityRouting.js +24 -1
  372. package/dist/src/capabilityRouting.test.js +19 -1
  373. package/dist/src/cli.js +76 -11
  374. package/dist/src/cli.test.js +241 -1
  375. package/dist/src/commanderAdapter.js +23 -9
  376. package/dist/src/commanderAdapter.test.js +0 -1
  377. package/dist/src/discovery.js +2 -5
  378. package/dist/src/errors.js +1 -1
  379. package/dist/src/execution.d.ts +1 -1
  380. package/dist/src/execution.js +111 -27
  381. package/dist/src/execution.test.js +326 -17
  382. package/dist/src/help.d.ts +27 -2
  383. package/dist/src/help.js +196 -23
  384. package/dist/src/help.test.d.ts +1 -0
  385. package/dist/src/help.test.js +54 -0
  386. package/dist/src/main.js +14 -1
  387. package/dist/src/manifest-types.d.ts +5 -3
  388. package/dist/src/pipeline/executor.js +1 -1
  389. package/dist/src/pipeline/executor.test.js +8 -0
  390. package/dist/src/pipeline/registry.d.ts +9 -0
  391. package/dist/src/pipeline/registry.js +13 -1
  392. package/dist/src/pipeline/steps/browser.d.ts +1 -0
  393. package/dist/src/pipeline/steps/browser.js +10 -0
  394. package/dist/src/pipeline/steps/download.test.js +1 -0
  395. package/dist/src/registry-api.d.ts +1 -1
  396. package/dist/src/registry.d.ts +12 -11
  397. package/dist/src/registry.js +16 -6
  398. package/dist/src/registry.test.js +2 -2
  399. package/dist/src/runtime.d.ts +2 -1
  400. package/dist/src/runtime.js +1 -1
  401. package/dist/src/serialization.d.ts +2 -2
  402. package/dist/src/serialization.js +4 -6
  403. package/dist/src/serialization.test.js +17 -0
  404. package/dist/src/types.d.ts +17 -0
  405. package/dist/src/validate.js +15 -11
  406. package/dist/src/validate.test.d.ts +9 -0
  407. package/dist/src/validate.test.js +90 -0
  408. package/package.json +1 -1
  409. package/scripts/fetch-adapters.js +1 -1
  410. package/scripts/typed-error-lint-baseline.json +5 -77
  411. package/clis/ctrip/search.test.js +0 -64
  412. package/clis/gov-policy/commands.test.js +0 -27
  413. package/clis/linux-do/category.js +0 -37
  414. package/clis/linux-do/hot.js +0 -26
  415. package/clis/linux-do/latest.js +0 -19
  416. package/clis/pixiv/test-utils.js +0 -23
  417. package/clis/toutiao/articles.test.js +0 -30
  418. package/dist/src/analysis.d.ts +0 -40
  419. package/dist/src/analysis.js +0 -172
@@ -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.14",
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')) {
@@ -135,14 +135,6 @@
135
135
  "text": "ps: Math.min(Number(limit), 50),",
136
136
  "occurrence": 0
137
137
  },
138
- {
139
- "rule": "silent-clamp",
140
- "command": "coupang/search",
141
- "file": "clis/coupang/search.js",
142
- "line": 417,
143
- "text": "const limit = Math.min(Math.max(Number(kwargs.limit || 20), 1), 50);",
144
- "occurrence": 0
145
- },
146
138
  {
147
139
  "rule": "silent-clamp",
148
140
  "command": "douyin/user-videos",
@@ -419,18 +411,10 @@
419
411
  "rule": "silent-clamp",
420
412
  "command": "linkedin/search",
421
413
  "file": "clis/linkedin/search.js",
422
- "line": 207,
414
+ "line": 249,
423
415
  "text": "const count = Math.min(MAX_BATCH, input.limit - allJobs.length);",
424
416
  "occurrence": 0
425
417
  },
426
- {
427
- "rule": "silent-clamp",
428
- "command": "linkedin/search",
429
- "file": "clis/linkedin/search.js",
430
- "line": 339,
431
- "text": "const limit = Math.max(1, Math.min(kwargs.limit ?? 10, 100));",
432
- "occurrence": 0
433
- },
434
418
  {
435
419
  "rule": "silent-clamp",
436
420
  "command": "linkedin/timeline",
@@ -503,14 +487,6 @@
503
487
  "text": "for (var i = 0; i < Math.min(t1TopLevel.length, limit); i++) {",
504
488
  "occurrence": 0
505
489
  },
506
- {
507
- "rule": "silent-clamp",
508
- "command": "reuters/search",
509
- "file": "clis/reuters/search.js",
510
- "line": 18,
511
- "text": "const count = Math.min(kwargs.limit || 10, 40);",
512
- "occurrence": 0
513
- },
514
490
  {
515
491
  "rule": "silent-clamp",
516
492
  "command": "sinablog/search",
@@ -983,14 +959,6 @@
983
959
  "text": "const jobName = f.jobName || 'unknown';",
984
960
  "occurrence": 0
985
961
  },
986
- {
987
- "rule": "silent-sentinel",
988
- "command": "coupang/add-to-cart",
989
- "file": "clis/coupang/add-to-cart.js",
990
- "line": 123,
991
- "text": "throw new Error(`Product mismatch: expected ${productId}, got ${actualProductId || 'unknown'}`);",
992
- "occurrence": 0
993
- },
994
962
  {
995
963
  "rule": "silent-sentinel",
996
964
  "command": "doubao-app/send",
@@ -1031,14 +999,6 @@
1031
999
  "text": "throw new CommandExecutionError(`点击草稿按钮失败: ${result?.reason || 'unknown'}`);",
1032
1000
  "occurrence": 0
1033
1001
  },
1034
- {
1035
- "rule": "silent-sentinel",
1036
- "command": "facebook/notifications",
1037
- "file": "clis/facebook/notifications.js",
1038
- "line": 31,
1039
- "text": "time: time || '-',",
1040
- "occurrence": 0
1041
- },
1042
1002
  {
1043
1003
  "rule": "silent-sentinel",
1044
1004
  "command": "gitee/search",
@@ -1223,22 +1183,6 @@
1223
1183
  "text": "title: c.data.title || '-',",
1224
1184
  "occurrence": 0
1225
1185
  },
1226
- {
1227
- "rule": "silent-sentinel",
1228
- "command": "tiktok/explore",
1229
- "file": "clis/tiktok/explore.js",
1230
- "line": 27,
1231
- "text": "views: a.textContent.trim() || '-',",
1232
- "occurrence": 0
1233
- },
1234
- {
1235
- "rule": "silent-sentinel",
1236
- "command": "tiktok/user",
1237
- "file": "clis/tiktok/user.js",
1238
- "line": 32,
1239
- "text": "views: a.textContent.trim() || '-',",
1240
- "occurrence": 0
1241
- },
1242
1186
  {
1243
1187
  "rule": "silent-sentinel",
1244
1188
  "command": "twitter/accept",
@@ -1271,22 +1215,6 @@
1271
1215
  "text": "const screenName = user?.legacy?.screen_name || user?.core?.screen_name || 'unknown';",
1272
1216
  "occurrence": 0
1273
1217
  },
1274
- {
1275
- "rule": "silent-sentinel",
1276
- "command": "twitter/followers",
1277
- "file": "clis/twitter/followers.js",
1278
- "line": 87,
1279
- "text": "name: core.name || legacy.name || 'unknown',",
1280
- "occurrence": 0
1281
- },
1282
- {
1283
- "rule": "silent-sentinel",
1284
- "command": "twitter/followers",
1285
- "file": "clis/twitter/followers.js",
1286
- "line": 86,
1287
- "text": "screen_name: core.screen_name || legacy.screen_name || 'unknown',",
1288
- "occurrence": 0
1289
- },
1290
1218
  {
1291
1219
  "rule": "silent-sentinel",
1292
1220
  "command": "twitter/following",
@@ -1411,7 +1339,7 @@
1411
1339
  "rule": "silent-sentinel",
1412
1340
  "command": "web/read",
1413
1341
  "file": "clis/web/read.js",
1414
- "line": 348,
1342
+ "line": 378,
1415
1343
  "text": "lines.push(` [frame ${frame.index}] ${frame.sameOrigin ? 'same-origin' : 'cross-origin'} ${frame.accessible ? 'accessible' : 'blocked'} text=${frame.textLength || 0} ${frame.src || '-'}`);",
1416
1344
  "occurrence": 0
1417
1345
  },
@@ -1419,7 +1347,7 @@
1419
1347
  "rule": "silent-sentinel",
1420
1348
  "command": "web/read",
1421
1349
  "file": "clis/web/read.js",
1422
- "line": 360,
1350
+ "line": 390,
1423
1351
  "text": "lines.push(` ${entry.method} ${entry.status || '-'} ${entry.contentType || '-'} ${entry.url}`);",
1424
1352
  "occurrence": 0
1425
1353
  },
@@ -1427,7 +1355,7 @@
1427
1355
  "rule": "silent-sentinel",
1428
1356
  "command": "web/read",
1429
1357
  "file": "clis/web/read.js",
1430
- "line": 354,
1358
+ "line": 384,
1431
1359
  "text": "lines.push(` ${item.scope}: ${selector} (${item.url || '-'})`);",
1432
1360
  "occurrence": 0
1433
1361
  },
@@ -1435,7 +1363,7 @@
1435
1363
  "rule": "silent-sentinel",
1436
1364
  "command": "web/read",
1437
1365
  "file": "clis/web/read.js",
1438
- "line": 345,
1366
+ "line": 375,
1439
1367
  "text": "lines.push(`url: ${diag.url || '-'}`);",
1440
1368
  "occurrence": 0
1441
1369
  },
@@ -1,64 +0,0 @@
1
- import { beforeEach, describe, expect, it, vi } from 'vitest';
2
- import { getRegistry } from '@jackwener/opencli/registry';
3
- import './search.js';
4
- describe('ctrip search', () => {
5
- const command = getRegistry().get('ctrip/search');
6
- beforeEach(() => {
7
- vi.unstubAllGlobals();
8
- });
9
- it('maps live endpoint results into ranked rows', async () => {
10
- vi.stubGlobal('fetch', vi.fn().mockResolvedValue(new Response(JSON.stringify({
11
- Response: {
12
- searchResults: [
13
- {
14
- displayName: '苏州, 江苏, 中国',
15
- displayType: '城市',
16
- commentScore: 0,
17
- price: '',
18
- },
19
- {
20
- word: '姑苏区',
21
- type: '行政区',
22
- cStar: 4.8,
23
- minPrice: 320,
24
- },
25
- ],
26
- },
27
- }), { status: 200 })));
28
- const result = await command.func({ query: '苏州', limit: 3 });
29
- expect(result).toEqual([
30
- {
31
- rank: 1,
32
- name: '苏州, 江苏, 中国',
33
- type: '城市',
34
- score: 0,
35
- price: '',
36
- url: '',
37
- },
38
- {
39
- rank: 2,
40
- name: '姑苏区',
41
- type: '行政区',
42
- score: 4.8,
43
- price: 320,
44
- url: '',
45
- },
46
- ]);
47
- });
48
- it('rejects empty queries', async () => {
49
- await expect(command.func({ query: ' ', limit: 3 })).rejects.toThrow('Search keyword cannot be empty');
50
- });
51
- it('surfaces fetch failures as CliError', async () => {
52
- vi.stubGlobal('fetch', vi.fn().mockResolvedValue(new Response('{}', { status: 503 })));
53
- await expect(command.func({ query: '苏州', limit: 3 })).rejects.toMatchObject({
54
- code: 'FETCH_ERROR',
55
- message: 'ctrip search failed with status 503',
56
- });
57
- });
58
- it('surfaces empty results as EmptyResultError', async () => {
59
- vi.stubGlobal('fetch', vi.fn().mockResolvedValue(new Response(JSON.stringify({
60
- Response: { searchResults: [] },
61
- }), { status: 200 })));
62
- await expect(command.func({ query: '苏州', limit: 3 })).rejects.toThrow('ctrip search returned no data');
63
- });
64
- });
@@ -1,27 +0,0 @@
1
- import { describe, expect, it, vi } from 'vitest';
2
- import { getRegistry } from '@jackwener/opencli/registry';
3
- import './search.js';
4
- import './recent.js';
5
-
6
- describe('gov-policy commands', () => {
7
- const search = getRegistry().get('gov-policy/search');
8
- const recent = getRegistry().get('gov-policy/recent');
9
-
10
- it('registers both commands as public browser commands', () => {
11
- expect(search).toBeDefined();
12
- expect(recent).toBeDefined();
13
- expect(search.browser).toBe(true);
14
- expect(recent.browser).toBe(true);
15
- expect(search.strategy).toBe('public');
16
- expect(recent.strategy).toBe('public');
17
- });
18
-
19
- it('rejects empty search queries before browser navigation', async () => {
20
- const page = { goto: vi.fn() };
21
- await expect(search.func(page, { query: ' ' })).rejects.toMatchObject({
22
- name: 'ArgumentError',
23
- code: 'ARGUMENT',
24
- });
25
- expect(page.goto).not.toHaveBeenCalled();
26
- });
27
- });
@@ -1,37 +0,0 @@
1
- import { cli, Strategy } from '@jackwener/opencli/registry';
2
- import { buildLinuxDoCompatFooter, executeLinuxDoFeed } from './feed.js';
3
- cli({
4
- site: 'linux-do',
5
- name: 'category',
6
- access: 'read',
7
- description: 'linux.do 分类内话题',
8
- domain: 'linux.do',
9
- strategy: Strategy.COOKIE,
10
- browser: true,
11
- columns: ['title', 'replies', 'created', 'likes', 'views', 'url'],
12
- deprecated: 'opencli linux-do category is kept for backward compatibility.',
13
- replacedBy: 'opencli linux-do feed --category <id-or-name>',
14
- args: [
15
- {
16
- name: 'slug',
17
- positional: true,
18
- type: 'str',
19
- required: true,
20
- help: 'Category slug (legacy compatibility argument)',
21
- },
22
- {
23
- name: 'id',
24
- positional: true,
25
- type: 'int',
26
- required: true,
27
- help: 'Category ID',
28
- },
29
- { name: 'limit', type: 'int', default: 20, help: 'Number of items (per_page)' },
30
- ],
31
- func: async (page, kwargs) => executeLinuxDoFeed(page, {
32
- limit: kwargs.limit,
33
- category: String(kwargs.id),
34
- view: 'latest',
35
- }),
36
- footerExtra: (kwargs) => buildLinuxDoCompatFooter(`opencli linux-do feed --category ${kwargs.id ?? '<id>'}`),
37
- });
@@ -1,26 +0,0 @@
1
- import { cli, Strategy } from '@jackwener/opencli/registry';
2
- import { buildLinuxDoCompatFooter, executeLinuxDoFeed } from './feed.js';
3
- cli({
4
- site: 'linux-do',
5
- name: 'hot',
6
- access: 'read',
7
- description: 'linux.do 热门话题',
8
- domain: 'linux.do',
9
- strategy: Strategy.COOKIE,
10
- browser: true,
11
- columns: ['title', 'replies', 'created', 'likes', 'views', 'url'],
12
- deprecated: 'opencli linux-do hot is kept for backward compatibility.',
13
- replacedBy: 'opencli linux-do feed --view top --period <period>',
14
- args: [
15
- { name: 'limit', type: 'int', default: 20, help: 'Number of items (per_page)' },
16
- {
17
- name: 'period',
18
- type: 'str',
19
- default: 'weekly',
20
- help: 'Time period',
21
- choices: ['all', 'daily', 'weekly', 'monthly', 'quarterly', 'yearly'],
22
- },
23
- ],
24
- func: async (page, kwargs) => executeLinuxDoFeed(page, { ...kwargs, view: 'top' }),
25
- footerExtra: () => buildLinuxDoCompatFooter('opencli linux-do feed --view top --period <period>'),
26
- });
@@ -1,19 +0,0 @@
1
- import { cli, Strategy } from '@jackwener/opencli/registry';
2
- import { buildLinuxDoCompatFooter, executeLinuxDoFeed } from './feed.js';
3
- cli({
4
- site: 'linux-do',
5
- name: 'latest',
6
- access: 'read',
7
- description: 'linux.do 最新话题',
8
- domain: 'linux.do',
9
- strategy: Strategy.COOKIE,
10
- browser: true,
11
- columns: ['title', 'replies', 'created', 'likes', 'views', 'url'],
12
- deprecated: 'opencli linux-do latest is kept for backward compatibility.',
13
- replacedBy: 'opencli linux-do feed --view latest',
14
- args: [
15
- { name: 'limit', type: 'int', default: 20, help: 'Number of items (per_page)' },
16
- ],
17
- func: async (page, kwargs) => executeLinuxDoFeed(page, { ...kwargs, view: 'latest' }),
18
- footerExtra: () => buildLinuxDoCompatFooter('opencli linux-do feed --view latest'),
19
- });
@@ -1,23 +0,0 @@
1
- import { vi } from 'vitest';
2
- /**
3
- * Create a minimal page mock with only the methods commonly used by Pixiv adapters.
4
- *
5
- * Since all TS adapters now go through `pixivFetch` which calls `page.evaluate`,
6
- * the evaluate results should match the raw Pixiv Ajax response format:
7
- * - Success: `{ body: ... }` (pixivFetch returns the `body` field)
8
- * - HTTP error: `{ __httpError: <status> }` (pixivFetch detects and throws)
9
- *
10
- * Additional methods can be overridden via the overrides parameter.
11
- */
12
- export function createPageMock(evaluateResults, overrides) {
13
- const evaluate = vi.fn();
14
- for (const result of evaluateResults) {
15
- evaluate.mockResolvedValueOnce(result);
16
- }
17
- return {
18
- goto: vi.fn().mockResolvedValue(undefined),
19
- evaluate,
20
- getCookies: vi.fn().mockResolvedValue([]),
21
- ...overrides,
22
- };
23
- }