@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
@@ -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
- }
@@ -1,30 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { __test__ } from './articles.js';
3
-
4
- describe('toutiao articles parser', () => {
5
- const articleText = [
6
- '短标题',
7
- '04-20 20:30',
8
- '已发布',
9
- '展现 8 阅读 0 点赞 0 评论 0',
10
- ].join('\n');
11
- const parsedArticle = {
12
- title: '短标题',
13
- date: '04-20 20:30',
14
- status: '已发布',
15
- '展现': '8',
16
- '阅读': '0',
17
- '点赞': '0',
18
- '评论': '0',
19
- };
20
-
21
- it('keeps short chinese titles instead of silently dropping the row', () => {
22
- expect(__test__.parseToutiaoArticlesText(articleText)).toEqual([parsedArticle]);
23
- });
24
-
25
- it('keeps parsing when serialized into the browser evaluate context', () => {
26
- const parse = Function(`return (${__test__.parseToutiaoArticlesText.toString()})`)();
27
-
28
- expect(parse(articleText)).toEqual([parsedArticle]);
29
- });
30
- });
@@ -1,40 +0,0 @@
1
- /**
2
- * Shared API analysis helpers used by both explore.ts and record.ts.
3
- *
4
- * Extracts common logic for:
5
- * - URL pattern normalization
6
- * - Array path discovery in JSON responses
7
- * - Field role detection
8
- * - Auth indicator inference
9
- * - Capability name inference
10
- * - Strategy inference
11
- */
12
- /** Normalize a full URL into a pattern (replace IDs, strip volatile params). */
13
- export declare function urlToPattern(url: string): string;
14
- export interface ArrayDiscovery {
15
- path: string;
16
- items: unknown[];
17
- }
18
- /** Find the best (largest) array of objects in a JSON response body. */
19
- export declare function findArrayPath(obj: unknown, depth?: number): ArrayDiscovery | null;
20
- /** Flatten nested object keys up to maxDepth. */
21
- export declare function flattenFields(obj: unknown, prefix: string, maxDepth: number): string[];
22
- /** Detect semantic field roles (title, url, author, etc.) from sample fields. */
23
- export declare function detectFieldRoles(sampleFields: string[]): Record<string, string>;
24
- /** Infer a CLI capability name from a URL. */
25
- export declare function inferCapabilityName(url: string, goal?: string): string;
26
- /** Infer auth strategy from detected indicators. */
27
- export declare function inferStrategy(authIndicators: string[]): string;
28
- /** Detect auth indicators from HTTP headers. */
29
- export declare function detectAuthFromHeaders(headers?: Record<string, string>): string[];
30
- /** Detect auth indicators from URL and response body (heuristic). */
31
- export declare function detectAuthFromContent(url: string, body: unknown): string[];
32
- /** Check whether a URL looks like tracking/telemetry noise rather than a business API. */
33
- export declare function isNoiseUrl(url: string): boolean;
34
- /** Extract non-volatile query params and classify them. */
35
- export declare function classifyQueryParams(url: string): {
36
- params: string[];
37
- hasSearch: boolean;
38
- hasPagination: boolean;
39
- hasLimit: boolean;
40
- };
@@ -1,172 +0,0 @@
1
- /**
2
- * Shared API analysis helpers used by both explore.ts and record.ts.
3
- *
4
- * Extracts common logic for:
5
- * - URL pattern normalization
6
- * - Array path discovery in JSON responses
7
- * - Field role detection
8
- * - Auth indicator inference
9
- * - Capability name inference
10
- * - Strategy inference
11
- */
12
- import { VOLATILE_PARAMS, SEARCH_PARAMS, PAGINATION_PARAMS, LIMIT_PARAMS, FIELD_ROLES, } from './constants.js';
13
- // ── URL pattern normalization ───────────────────────────────────────────────
14
- /** Normalize a full URL into a pattern (replace IDs, strip volatile params). */
15
- export function urlToPattern(url) {
16
- try {
17
- const p = new URL(url);
18
- const pathNorm = p.pathname
19
- .replace(/\/\d+/g, '/{id}')
20
- .replace(/\/[0-9a-fA-F]{8,}/g, '/{hex}')
21
- .replace(/\/BV[a-zA-Z0-9]{10}/g, '/{bvid}');
22
- const params = [];
23
- p.searchParams.forEach((_v, k) => { if (!VOLATILE_PARAMS.has(k))
24
- params.push(k); });
25
- return `${p.host}${pathNorm}${params.length ? '?' + params.sort().map(k => `${k}={}`).join('&') : ''}`;
26
- }
27
- catch {
28
- return url;
29
- }
30
- }
31
- /** Find the best (largest) array of objects in a JSON response body. */
32
- export function findArrayPath(obj, depth = 0) {
33
- if (depth > 5 || !obj || typeof obj !== 'object')
34
- return null;
35
- if (Array.isArray(obj)) {
36
- if (obj.length >= 2 && obj.some(i => i && typeof i === 'object' && !Array.isArray(i))) {
37
- return { path: '', items: obj };
38
- }
39
- return null;
40
- }
41
- let best = null;
42
- for (const [key, val] of Object.entries(obj)) {
43
- const found = findArrayPath(val, depth + 1);
44
- if (found) {
45
- const fullPath = found.path ? `${key}.${found.path}` : key;
46
- const candidate = { path: fullPath, items: found.items };
47
- if (!best || candidate.items.length > best.items.length)
48
- best = candidate;
49
- }
50
- }
51
- return best;
52
- }
53
- // ── Field flattening & role detection ───────────────────────────────────────
54
- /** Flatten nested object keys up to maxDepth. */
55
- export function flattenFields(obj, prefix, maxDepth) {
56
- if (maxDepth <= 0 || !obj || typeof obj !== 'object')
57
- return [];
58
- const names = [];
59
- const record = obj;
60
- for (const key of Object.keys(record)) {
61
- const full = prefix ? `${prefix}.${key}` : key;
62
- names.push(full);
63
- const val = record[key];
64
- if (val && typeof val === 'object' && !Array.isArray(val))
65
- names.push(...flattenFields(val, full, maxDepth - 1));
66
- }
67
- return names;
68
- }
69
- /** Detect semantic field roles (title, url, author, etc.) from sample fields. */
70
- export function detectFieldRoles(sampleFields) {
71
- const detectedFields = {};
72
- for (const [role, aliases] of Object.entries(FIELD_ROLES)) {
73
- for (const f of sampleFields) {
74
- if (aliases.includes(f.split('.').pop()?.toLowerCase() ?? '')) {
75
- detectedFields[role] = f;
76
- break;
77
- }
78
- }
79
- }
80
- return detectedFields;
81
- }
82
- // ── Capability name inference ───────────────────────────────────────────────
83
- /** Infer a CLI capability name from a URL. */
84
- export function inferCapabilityName(url, goal) {
85
- if (goal)
86
- return goal;
87
- const u = url.toLowerCase();
88
- if (u.includes('hot') || u.includes('popular') || u.includes('ranking') || u.includes('trending'))
89
- return 'hot';
90
- if (u.includes('search'))
91
- return 'search';
92
- if (u.includes('feed') || u.includes('timeline') || u.includes('dynamic'))
93
- return 'feed';
94
- if (u.includes('comment') || u.includes('reply'))
95
- return 'comments';
96
- if (u.includes('history'))
97
- return 'history';
98
- if (u.includes('profile') || u.includes('userinfo') || u.includes('/me'))
99
- return 'me';
100
- if (u.includes('favorite') || u.includes('collect') || u.includes('bookmark'))
101
- return 'favorite';
102
- try {
103
- const segs = new URL(url).pathname
104
- .split('/')
105
- .filter(s => s && !s.match(/^\d+$/) && !s.match(/^[0-9a-f]{8,}$/i) && !s.match(/^v\d+$/));
106
- if (segs.length)
107
- return segs[segs.length - 1].replace(/[^a-z0-9]/gi, '_').toLowerCase();
108
- }
109
- catch { }
110
- return 'data';
111
- }
112
- // ── Strategy inference ──────────────────────────────────────────────────────
113
- /** Infer auth strategy from detected indicators. */
114
- export function inferStrategy(authIndicators) {
115
- if (authIndicators.includes('signature'))
116
- return 'intercept';
117
- if (authIndicators.includes('bearer') || authIndicators.includes('csrf'))
118
- return 'header';
119
- return 'cookie';
120
- }
121
- // ── Auth indicator detection ────────────────────────────────────────────────
122
- /** Detect auth indicators from HTTP headers. */
123
- export function detectAuthFromHeaders(headers) {
124
- if (!headers)
125
- return [];
126
- const indicators = [];
127
- const keys = Object.keys(headers).map(k => k.toLowerCase());
128
- if (keys.some(k => k === 'authorization'))
129
- indicators.push('bearer');
130
- if (keys.some(k => k.startsWith('x-csrf') || k.startsWith('x-xsrf')))
131
- indicators.push('csrf');
132
- if (keys.some(k => k.startsWith('x-s') || k === 'x-t' || k === 'x-s-common'))
133
- indicators.push('signature');
134
- return indicators;
135
- }
136
- /** Detect auth indicators from URL and response body (heuristic). */
137
- export function detectAuthFromContent(url, body) {
138
- const indicators = [];
139
- if (body && typeof body === 'object') {
140
- const keys = Object.keys(body).map(k => k.toLowerCase());
141
- if (keys.some(k => k.includes('sign') || k === 'w_rid' || k.includes('token'))) {
142
- indicators.push('signature');
143
- }
144
- }
145
- if (url.includes('/wbi/') || url.includes('w_rid='))
146
- indicators.push('signature');
147
- if (url.includes('bearer') || url.includes('access_token'))
148
- indicators.push('bearer');
149
- return indicators;
150
- }
151
- // ── Noise filtering ─────────────────────────────────────────────────────────
152
- const NOISE_URL_PATTERN = /\/(track|log|analytics|beacon|pixel|ping|heartbeat|keep.?alive)\b/i;
153
- /** Check whether a URL looks like tracking/telemetry noise rather than a business API. */
154
- export function isNoiseUrl(url) {
155
- return NOISE_URL_PATTERN.test(url);
156
- }
157
- // ── Query param classification ──────────────────────────────────────────────
158
- /** Extract non-volatile query params and classify them. */
159
- export function classifyQueryParams(url) {
160
- const params = [];
161
- try {
162
- new URL(url).searchParams.forEach((_v, k) => { if (!VOLATILE_PARAMS.has(k))
163
- params.push(k); });
164
- }
165
- catch { }
166
- return {
167
- params,
168
- hasSearch: params.some(p => SEARCH_PARAMS.has(p)),
169
- hasPagination: params.some(p => PAGINATION_PARAMS.has(p)),
170
- hasLimit: params.some(p => LIMIT_PARAMS.has(p)),
171
- };
172
- }