@jackwener/opencli 1.1.0 → 1.2.0

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 (769) hide show
  1. package/.agents/skills/cross-project-adapter-migration/SKILL.md +2 -2
  2. package/.github/pull_request_template.md +7 -0
  3. package/.github/workflows/doc-check.yml +36 -0
  4. package/.github/workflows/docs.yml +7 -42
  5. package/CHANGELOG.md +23 -0
  6. package/CLI-EXPLORER.md +9 -8
  7. package/CONTRIBUTING.md +39 -1
  8. package/README.md +33 -19
  9. package/README.zh-CN.md +64 -27
  10. package/SKILL.md +102 -33
  11. package/dist/browser/cdp.d.ts +4 -4
  12. package/dist/browser/cdp.js +45 -17
  13. package/dist/browser/daemon-client.d.ts +2 -1
  14. package/dist/browser/dom-helpers.js +38 -7
  15. package/dist/browser/dom-snapshot.d.ts +86 -0
  16. package/dist/browser/dom-snapshot.js +729 -0
  17. package/dist/browser/dom-snapshot.test.d.ts +11 -0
  18. package/dist/browser/dom-snapshot.test.js +212 -0
  19. package/dist/browser/index.d.ts +2 -0
  20. package/dist/browser/index.js +1 -0
  21. package/dist/browser/page.d.ts +18 -25
  22. package/dist/browser/page.js +44 -5
  23. package/dist/build-manifest.d.ts +11 -4
  24. package/dist/build-manifest.js +79 -34
  25. package/dist/build-manifest.test.js +58 -2
  26. package/dist/cli-manifest.json +4273 -1771
  27. package/dist/cli.d.ts +6 -0
  28. package/dist/cli.js +255 -162
  29. package/dist/clis/apple-podcasts/commands.test.d.ts +2 -0
  30. package/dist/clis/apple-podcasts/commands.test.js +76 -0
  31. package/dist/clis/apple-podcasts/search.js +2 -2
  32. package/dist/clis/apple-podcasts/top.js +9 -2
  33. package/dist/clis/arxiv/search.js +1 -1
  34. package/dist/clis/barchart/greeks.js +1 -1
  35. package/dist/clis/barchart/options.js +1 -1
  36. package/dist/clis/barchart/quote.js +1 -1
  37. package/dist/clis/bilibili/download.js +1 -1
  38. package/dist/clis/bilibili/dynamic.js +1 -1
  39. package/dist/clis/bilibili/favorite.js +1 -1
  40. package/dist/clis/bilibili/feed.js +1 -1
  41. package/dist/clis/bilibili/following.js +2 -2
  42. package/dist/clis/bilibili/history.js +1 -1
  43. package/dist/clis/bilibili/me.js +1 -1
  44. package/dist/clis/bilibili/ranking.js +1 -1
  45. package/dist/clis/bilibili/search.js +3 -3
  46. package/dist/clis/bilibili/subtitle.js +2 -2
  47. package/dist/clis/bilibili/user-videos.js +2 -2
  48. package/dist/{bilibili.d.ts → clis/bilibili/utils.d.ts} +1 -1
  49. package/dist/clis/bloomberg/businessweek.js +17 -0
  50. package/dist/clis/bloomberg/economics.js +17 -0
  51. package/dist/clis/bloomberg/feeds.d.ts +1 -0
  52. package/dist/clis/bloomberg/feeds.js +15 -0
  53. package/dist/clis/bloomberg/industries.d.ts +1 -0
  54. package/dist/clis/bloomberg/industries.js +17 -0
  55. package/dist/clis/bloomberg/main.d.ts +1 -0
  56. package/dist/clis/bloomberg/main.js +17 -0
  57. package/dist/clis/bloomberg/markets.d.ts +1 -0
  58. package/dist/clis/bloomberg/markets.js +17 -0
  59. package/dist/clis/bloomberg/news.d.ts +1 -0
  60. package/dist/clis/bloomberg/news.js +105 -0
  61. package/dist/clis/bloomberg/opinions.d.ts +1 -0
  62. package/dist/clis/bloomberg/opinions.js +17 -0
  63. package/dist/clis/bloomberg/politics.d.ts +1 -0
  64. package/dist/clis/bloomberg/politics.js +17 -0
  65. package/dist/clis/bloomberg/tech.d.ts +1 -0
  66. package/dist/clis/bloomberg/tech.js +17 -0
  67. package/dist/clis/bloomberg/utils.d.ts +34 -0
  68. package/dist/clis/bloomberg/utils.js +364 -0
  69. package/dist/clis/bloomberg/utils.test.d.ts +1 -0
  70. package/dist/clis/bloomberg/utils.test.js +129 -0
  71. package/dist/clis/boss/batchgreet.js +12 -99
  72. package/dist/clis/boss/chatlist.js +9 -26
  73. package/dist/clis/boss/chatmsg.js +11 -42
  74. package/dist/clis/boss/common.d.ts +92 -0
  75. package/dist/clis/boss/common.js +223 -0
  76. package/dist/clis/boss/detail.js +8 -50
  77. package/dist/clis/boss/exchange.js +13 -79
  78. package/dist/clis/boss/greet.js +20 -147
  79. package/dist/clis/boss/invite.js +26 -121
  80. package/dist/clis/boss/joblist.js +6 -31
  81. package/dist/clis/boss/mark.js +12 -85
  82. package/dist/clis/boss/recommend.js +10 -49
  83. package/dist/clis/boss/resume.js +18 -118
  84. package/dist/clis/boss/search.js +13 -61
  85. package/dist/clis/boss/send.js +18 -152
  86. package/dist/clis/boss/stats.js +20 -71
  87. package/dist/clis/chaoxing/assignments.js +1 -1
  88. package/dist/clis/chaoxing/exams.js +1 -1
  89. package/dist/{chaoxing.d.ts → clis/chaoxing/utils.d.ts} +1 -1
  90. package/dist/{chaoxing.js → clis/chaoxing/utils.js} +0 -2
  91. package/dist/clis/chaoxing/utils.test.d.ts +1 -0
  92. package/dist/{chaoxing.test.js → clis/chaoxing/utils.test.js} +1 -1
  93. package/dist/clis/chatgpt/read.js +1 -1
  94. package/dist/clis/chatwise/export.js +1 -1
  95. package/dist/clis/chatwise/model.js +2 -2
  96. package/dist/clis/chatwise/screenshot.js +1 -1
  97. package/dist/clis/codex/export.js +1 -1
  98. package/dist/clis/codex/model.js +2 -2
  99. package/dist/clis/codex/screenshot.js +1 -1
  100. package/dist/clis/coupang/add-to-cart.js +3 -4
  101. package/dist/clis/coupang/search.js +2 -4
  102. package/dist/clis/coupang/utils.test.d.ts +1 -0
  103. package/dist/{coupang.test.js → clis/coupang/utils.test.js} +1 -1
  104. package/dist/clis/ctrip/search.js +1 -1
  105. package/dist/clis/cursor/export.js +1 -1
  106. package/dist/clis/cursor/model.js +2 -2
  107. package/dist/clis/cursor/screenshot.js +1 -1
  108. package/dist/clis/devto/tag.yaml +34 -0
  109. package/dist/clis/devto/top.yaml +29 -0
  110. package/dist/clis/devto/user.yaml +33 -0
  111. package/dist/clis/douban/book-hot.d.ts +1 -0
  112. package/dist/clis/douban/book-hot.js +14 -0
  113. package/dist/clis/douban/marks.d.ts +1 -0
  114. package/dist/clis/douban/marks.js +115 -0
  115. package/dist/clis/douban/movie-hot.d.ts +1 -0
  116. package/dist/clis/douban/movie-hot.js +14 -0
  117. package/dist/clis/douban/reviews.d.ts +1 -0
  118. package/dist/clis/douban/reviews.js +106 -0
  119. package/dist/clis/douban/search.d.ts +1 -0
  120. package/dist/clis/douban/search.js +16 -0
  121. package/dist/clis/douban/shared.d.ts +4 -0
  122. package/dist/clis/douban/shared.js +155 -0
  123. package/dist/clis/douban/subject.yaml +76 -0
  124. package/dist/clis/douban/top250.yaml +70 -0
  125. package/dist/clis/douban/utils.d.ts +35 -0
  126. package/dist/clis/douban/utils.js +48 -0
  127. package/dist/clis/facebook/add-friend.yaml +43 -0
  128. package/dist/clis/facebook/events.yaml +44 -0
  129. package/dist/clis/facebook/feed.yaml +63 -0
  130. package/dist/clis/facebook/friends.yaml +42 -0
  131. package/dist/clis/facebook/groups.yaml +50 -0
  132. package/dist/clis/facebook/join-group.yaml +44 -0
  133. package/dist/clis/facebook/memories.yaml +39 -0
  134. package/dist/clis/facebook/notifications.yaml +40 -0
  135. package/dist/clis/facebook/profile.yaml +37 -0
  136. package/dist/clis/facebook/search.yaml +46 -0
  137. package/dist/clis/google/news.d.ts +5 -0
  138. package/dist/clis/google/news.js +58 -0
  139. package/dist/clis/google/search.d.ts +10 -0
  140. package/dist/clis/google/search.js +127 -0
  141. package/dist/clis/google/suggest.d.ts +5 -0
  142. package/dist/clis/google/suggest.js +34 -0
  143. package/dist/clis/google/trends.d.ts +5 -0
  144. package/dist/clis/google/trends.js +38 -0
  145. package/dist/clis/google/utils.d.ts +9 -0
  146. package/dist/clis/google/utils.js +23 -0
  147. package/dist/clis/google/utils.test.d.ts +1 -0
  148. package/dist/clis/google/utils.test.js +75 -0
  149. package/dist/clis/grok/ask.d.ts +14 -0
  150. package/dist/clis/grok/ask.js +257 -65
  151. package/dist/clis/grok/ask.test.d.ts +1 -0
  152. package/dist/clis/grok/ask.test.js +36 -0
  153. package/dist/clis/instagram/comment.yaml +52 -0
  154. package/dist/clis/instagram/explore.yaml +43 -0
  155. package/dist/clis/instagram/follow.yaml +41 -0
  156. package/dist/clis/instagram/followers.yaml +51 -0
  157. package/dist/clis/instagram/following.yaml +51 -0
  158. package/dist/clis/instagram/like.yaml +46 -0
  159. package/dist/clis/instagram/profile.yaml +42 -0
  160. package/dist/clis/instagram/save.yaml +46 -0
  161. package/dist/clis/instagram/saved.yaml +40 -0
  162. package/dist/clis/instagram/search.yaml +43 -0
  163. package/dist/clis/instagram/unfollow.yaml +38 -0
  164. package/dist/clis/instagram/unlike.yaml +46 -0
  165. package/dist/clis/instagram/unsave.yaml +46 -0
  166. package/dist/clis/instagram/user.yaml +54 -0
  167. package/dist/clis/jike/comment.js +2 -3
  168. package/dist/clis/jike/create.js +1 -2
  169. package/dist/clis/jike/feed.js +0 -1
  170. package/dist/clis/jike/like.js +1 -2
  171. package/dist/clis/jike/notifications.js +0 -1
  172. package/dist/clis/jike/post.yaml +1 -0
  173. package/dist/clis/jike/repost.js +2 -3
  174. package/dist/clis/jike/search.js +2 -3
  175. package/dist/clis/jike/topic.yaml +1 -0
  176. package/dist/clis/jike/user.yaml +1 -0
  177. package/dist/clis/jimeng/generate.yaml +1 -0
  178. package/dist/clis/jimeng/history.yaml +0 -1
  179. package/dist/clis/linkedin/search.js +7 -7
  180. package/dist/clis/linux-do/category.yaml +2 -0
  181. package/dist/clis/linux-do/search.yaml +4 -3
  182. package/dist/clis/linux-do/topic.yaml +1 -0
  183. package/dist/clis/lobsters/active.yaml +29 -0
  184. package/dist/clis/lobsters/hot.yaml +29 -0
  185. package/dist/clis/lobsters/newest.yaml +29 -0
  186. package/dist/clis/lobsters/tag.yaml +34 -0
  187. package/dist/clis/medium/feed.d.ts +1 -0
  188. package/dist/clis/medium/feed.js +15 -0
  189. package/dist/clis/medium/search.d.ts +1 -0
  190. package/dist/clis/medium/search.js +15 -0
  191. package/dist/clis/medium/shared.d.ts +5 -0
  192. package/dist/clis/medium/shared.js +78 -0
  193. package/dist/clis/medium/user.d.ts +1 -0
  194. package/dist/clis/medium/user.js +15 -0
  195. package/dist/clis/notion/export.js +1 -1
  196. package/dist/clis/reddit/comment.js +3 -4
  197. package/dist/clis/reddit/read.js +4 -5
  198. package/dist/clis/reddit/save.js +2 -3
  199. package/dist/clis/reddit/saved.js +0 -1
  200. package/dist/clis/reddit/search.yaml +1 -0
  201. package/dist/clis/reddit/subreddit.yaml +1 -0
  202. package/dist/clis/reddit/subscribe.js +1 -2
  203. package/dist/clis/reddit/upvote.js +2 -3
  204. package/dist/clis/reddit/upvoted.js +0 -1
  205. package/dist/clis/reddit/user-comments.yaml +1 -0
  206. package/dist/clis/reddit/user-posts.yaml +1 -0
  207. package/dist/clis/reddit/user.yaml +1 -0
  208. package/dist/clis/reuters/search.js +1 -1
  209. package/dist/clis/sinablog/article.d.ts +1 -0
  210. package/dist/clis/sinablog/article.js +14 -0
  211. package/dist/clis/sinablog/hot.d.ts +1 -0
  212. package/dist/clis/sinablog/hot.js +14 -0
  213. package/dist/clis/sinablog/search.d.ts +1 -0
  214. package/dist/clis/sinablog/search.js +51 -0
  215. package/dist/clis/sinablog/shared.d.ts +7 -0
  216. package/dist/clis/sinablog/shared.js +187 -0
  217. package/dist/clis/sinablog/user.d.ts +1 -0
  218. package/dist/clis/sinablog/user.js +15 -0
  219. package/dist/clis/smzdm/search.js +2 -3
  220. package/dist/clis/stackoverflow/search.yaml +1 -0
  221. package/dist/clis/steam/top-sellers.yaml +29 -0
  222. package/dist/clis/substack/feed.d.ts +1 -0
  223. package/dist/clis/substack/feed.js +15 -0
  224. package/dist/clis/substack/publication.d.ts +1 -0
  225. package/dist/clis/substack/publication.js +15 -0
  226. package/dist/clis/substack/search.d.ts +1 -0
  227. package/dist/clis/substack/search.js +77 -0
  228. package/dist/clis/substack/shared.d.ts +4 -0
  229. package/dist/clis/substack/shared.js +129 -0
  230. package/dist/clis/tiktok/comment.yaml +66 -0
  231. package/dist/clis/tiktok/explore.yaml +39 -0
  232. package/dist/clis/tiktok/follow.yaml +39 -0
  233. package/dist/clis/tiktok/following.yaml +46 -0
  234. package/dist/clis/tiktok/friends.yaml +47 -0
  235. package/dist/clis/tiktok/like.yaml +38 -0
  236. package/dist/clis/tiktok/live.yaml +51 -0
  237. package/dist/clis/tiktok/notifications.yaml +52 -0
  238. package/dist/clis/tiktok/profile.yaml +45 -0
  239. package/dist/clis/tiktok/save.yaml +34 -0
  240. package/dist/clis/tiktok/search.yaml +46 -0
  241. package/dist/clis/tiktok/unfollow.yaml +44 -0
  242. package/dist/clis/tiktok/unlike.yaml +38 -0
  243. package/dist/clis/tiktok/unsave.yaml +36 -0
  244. package/dist/clis/tiktok/user.yaml +44 -0
  245. package/dist/clis/twitter/accept.js +2 -2
  246. package/dist/clis/twitter/article.js +2 -2
  247. package/dist/clis/twitter/block.d.ts +1 -0
  248. package/dist/clis/twitter/block.js +88 -0
  249. package/dist/clis/twitter/delete.js +1 -1
  250. package/dist/clis/twitter/download.d.ts +1 -1
  251. package/dist/clis/twitter/download.js +3 -3
  252. package/dist/clis/twitter/followers.js +1 -1
  253. package/dist/clis/twitter/following.js +1 -1
  254. package/dist/clis/twitter/hide-reply.d.ts +1 -0
  255. package/dist/clis/twitter/hide-reply.js +66 -0
  256. package/dist/clis/twitter/like.js +1 -1
  257. package/dist/clis/twitter/post.js +1 -1
  258. package/dist/clis/twitter/reply-dm.js +1 -1
  259. package/dist/clis/twitter/reply.js +2 -2
  260. package/dist/clis/twitter/search.js +1 -1
  261. package/dist/clis/twitter/thread.js +2 -2
  262. package/dist/clis/twitter/timeline.d.ts +23 -0
  263. package/dist/clis/twitter/timeline.js +42 -14
  264. package/dist/clis/twitter/timeline.test.d.ts +1 -0
  265. package/dist/clis/twitter/timeline.test.js +102 -0
  266. package/dist/clis/twitter/trending.d.ts +1 -0
  267. package/dist/clis/twitter/trending.js +91 -0
  268. package/dist/clis/twitter/unblock.d.ts +1 -0
  269. package/dist/clis/twitter/unblock.js +71 -0
  270. package/dist/clis/v2ex/topic.yaml +1 -0
  271. package/dist/clis/weibo/hot.js +0 -1
  272. package/dist/clis/weread/book.js +1 -1
  273. package/dist/clis/weread/highlights.js +1 -1
  274. package/dist/clis/weread/notes.js +1 -1
  275. package/dist/clis/weread/search.js +1 -1
  276. package/dist/clis/wikipedia/random.d.ts +1 -0
  277. package/dist/clis/wikipedia/random.js +19 -0
  278. package/dist/clis/wikipedia/search.js +4 -4
  279. package/dist/clis/wikipedia/summary.js +4 -9
  280. package/dist/clis/wikipedia/trending.d.ts +1 -0
  281. package/dist/clis/wikipedia/trending.js +35 -0
  282. package/dist/clis/wikipedia/utils.d.ts +28 -0
  283. package/dist/clis/wikipedia/utils.js +13 -0
  284. package/dist/clis/xiaohongshu/creator-note-detail.d.ts +15 -0
  285. package/dist/clis/xiaohongshu/creator-note-detail.js +69 -5
  286. package/dist/clis/xiaohongshu/creator-note-detail.test.js +82 -33
  287. package/dist/clis/xiaohongshu/creator-notes.js +35 -5
  288. package/dist/clis/xiaohongshu/creator-notes.test.js +37 -6
  289. package/dist/clis/xiaohongshu/creator-profile.js +0 -1
  290. package/dist/clis/xiaohongshu/creator-stats.js +0 -1
  291. package/dist/clis/xiaohongshu/download.js +2 -3
  292. package/dist/clis/xiaohongshu/feed.yaml +0 -1
  293. package/dist/clis/xiaohongshu/notifications.yaml +0 -1
  294. package/dist/clis/xiaohongshu/search.js +2 -2
  295. package/dist/clis/xiaohongshu/user.js +1 -2
  296. package/dist/clis/xueqiu/earnings-date.yaml +69 -0
  297. package/dist/clis/xueqiu/search.yaml +2 -1
  298. package/dist/clis/xueqiu/stock.yaml +2 -0
  299. package/dist/clis/yahoo-finance/quote.js +1 -2
  300. package/dist/clis/youtube/search.js +1 -1
  301. package/dist/clis/youtube/transcript.js +1 -1
  302. package/dist/clis/youtube/video.js +1 -1
  303. package/dist/clis/zhihu/download.js +1 -2
  304. package/dist/clis/zhihu/question.js +1 -1
  305. package/dist/clis/zhihu/search.yaml +4 -3
  306. package/dist/commanderAdapter.d.ts +21 -0
  307. package/dist/commanderAdapter.js +117 -0
  308. package/dist/{engine.d.ts → discovery.d.ts} +6 -4
  309. package/dist/{engine.js → discovery.js} +93 -104
  310. package/dist/doctor.js +3 -1
  311. package/dist/doctor.test.js +46 -2
  312. package/dist/download/index.d.ts +2 -6
  313. package/dist/download/index.js +19 -46
  314. package/dist/engine.test.d.ts +0 -3
  315. package/dist/engine.test.js +80 -11
  316. package/dist/execution.d.ts +24 -0
  317. package/dist/execution.js +153 -0
  318. package/dist/explore.d.ts +76 -3
  319. package/dist/explore.js +132 -111
  320. package/dist/external-clis.yaml +48 -0
  321. package/dist/external.d.ts +7 -2
  322. package/dist/external.js +11 -14
  323. package/dist/generate.d.ts +41 -2
  324. package/dist/generate.js +5 -4
  325. package/dist/main.js +2 -1
  326. package/dist/pipeline/executor.d.ts +2 -2
  327. package/dist/pipeline/executor.js +2 -2
  328. package/dist/pipeline/executor.test.js +33 -6
  329. package/dist/pipeline/registry.d.ts +1 -1
  330. package/dist/pipeline/steps/browser.d.ts +7 -7
  331. package/dist/pipeline/steps/browser.js +21 -7
  332. package/dist/pipeline/steps/fetch.d.ts +1 -1
  333. package/dist/pipeline/steps/fetch.js +11 -7
  334. package/dist/pipeline/steps/transform.d.ts +6 -5
  335. package/dist/pipeline/steps/transform.js +30 -9
  336. package/dist/pipeline/template.d.ts +6 -6
  337. package/dist/pipeline/template.js +43 -5
  338. package/dist/pipeline/template.test.js +18 -0
  339. package/dist/pipeline/transform.test.js +11 -0
  340. package/dist/plugin.d.ts +31 -0
  341. package/dist/plugin.js +216 -0
  342. package/dist/plugin.test.d.ts +4 -0
  343. package/dist/plugin.test.js +76 -0
  344. package/dist/registry-api.d.ts +11 -0
  345. package/dist/registry-api.js +9 -0
  346. package/dist/registry.d.ts +13 -0
  347. package/dist/registry.js +8 -1
  348. package/dist/runtime.d.ts +5 -0
  349. package/dist/runtime.js +8 -0
  350. package/dist/serialization.d.ts +34 -0
  351. package/dist/serialization.js +63 -0
  352. package/dist/synthesize.d.ts +94 -4
  353. package/dist/synthesize.js +5 -4
  354. package/dist/types.d.ts +43 -27
  355. package/dist/validate.js +8 -2
  356. package/docs/.vitepress/config.mts +20 -7
  357. package/docs/adapters/browser/arxiv.md +27 -0
  358. package/docs/adapters/browser/barchart.md +33 -0
  359. package/docs/adapters/browser/bilibili.md +9 -0
  360. package/docs/adapters/browser/bloomberg.md +70 -0
  361. package/docs/adapters/browser/chaoxing.md +39 -0
  362. package/docs/adapters/browser/devto.md +35 -0
  363. package/docs/adapters/browser/douban.md +38 -0
  364. package/docs/adapters/browser/facebook.md +36 -0
  365. package/docs/adapters/browser/google.md +62 -0
  366. package/docs/adapters/browser/grok.md +53 -0
  367. package/docs/adapters/browser/hf.md +42 -0
  368. package/docs/adapters/browser/instagram.md +46 -0
  369. package/docs/adapters/browser/jike.md +45 -0
  370. package/docs/adapters/browser/jimeng.md +39 -0
  371. package/docs/adapters/browser/linux-do.md +45 -0
  372. package/docs/adapters/browser/lobsters.md +32 -0
  373. package/docs/adapters/browser/medium.md +32 -0
  374. package/docs/adapters/browser/reddit.md +9 -0
  375. package/docs/adapters/browser/sinablog.md +36 -0
  376. package/docs/adapters/browser/sinafinance.md +35 -0
  377. package/docs/adapters/browser/stackoverflow.md +35 -0
  378. package/docs/adapters/browser/steam.md +26 -0
  379. package/docs/adapters/browser/substack.md +38 -0
  380. package/docs/adapters/browser/tiktok.md +68 -0
  381. package/docs/adapters/browser/twitter.md +3 -0
  382. package/docs/adapters/browser/weread.md +48 -0
  383. package/docs/adapters/browser/wikipedia.md +39 -0
  384. package/docs/adapters/browser/xiaohongshu.md +5 -1
  385. package/docs/adapters/browser/xueqiu.md +10 -0
  386. package/docs/adapters/browser/yahoo-finance.md +6 -5
  387. package/docs/adapters/desktop/antigravity.md +6 -0
  388. package/docs/adapters/desktop/chatgpt.md +5 -4
  389. package/docs/adapters/desktop/codex.md +5 -1
  390. package/docs/adapters/desktop/cursor.md +4 -0
  391. package/docs/adapters/desktop/discord.md +7 -7
  392. package/docs/adapters/index.md +14 -4
  393. package/docs/advanced/download.md +4 -4
  394. package/docs/developer/architecture.md +17 -4
  395. package/docs/guide/getting-started.md +1 -0
  396. package/docs/guide/plugins.md +153 -0
  397. package/docs/zh/guide/plugins.md +107 -0
  398. package/extension/src/background.ts +18 -11
  399. package/package.json +10 -5
  400. package/scripts/check-doc-coverage.sh +69 -0
  401. package/scripts/clean-dist.cjs +13 -0
  402. package/scripts/copy-yaml.cjs +7 -0
  403. package/src/browser/cdp.ts +77 -32
  404. package/src/browser/daemon-client.ts +2 -1
  405. package/src/browser/dom-helpers.ts +38 -7
  406. package/src/browser/dom-snapshot.test.ts +249 -0
  407. package/src/browser/dom-snapshot.ts +770 -0
  408. package/src/browser/index.ts +2 -0
  409. package/src/browser/page.ts +57 -20
  410. package/src/build-manifest.test.ts +70 -2
  411. package/src/build-manifest.ts +114 -40
  412. package/src/cli.ts +287 -139
  413. package/src/clis/apple-podcasts/commands.test.ts +95 -0
  414. package/src/clis/apple-podcasts/search.ts +2 -2
  415. package/src/clis/apple-podcasts/top.ts +12 -2
  416. package/src/clis/arxiv/search.ts +1 -1
  417. package/src/clis/barchart/greeks.ts +1 -1
  418. package/src/clis/barchart/options.ts +1 -1
  419. package/src/clis/barchart/quote.ts +1 -1
  420. package/src/clis/bilibili/download.ts +1 -1
  421. package/src/clis/bilibili/dynamic.ts +1 -1
  422. package/src/clis/bilibili/favorite.ts +1 -1
  423. package/src/clis/bilibili/feed.ts +1 -1
  424. package/src/clis/bilibili/following.ts +2 -2
  425. package/src/clis/bilibili/history.ts +1 -1
  426. package/src/clis/bilibili/me.ts +1 -1
  427. package/src/clis/bilibili/ranking.ts +1 -1
  428. package/src/clis/bilibili/search.ts +3 -3
  429. package/src/clis/bilibili/subtitle.ts +2 -2
  430. package/src/clis/bilibili/user-videos.ts +2 -2
  431. package/src/{bilibili.ts → clis/bilibili/utils.ts} +1 -1
  432. package/src/clis/bloomberg/businessweek.ts +18 -0
  433. package/src/clis/bloomberg/economics.ts +18 -0
  434. package/src/clis/bloomberg/feeds.ts +16 -0
  435. package/src/clis/bloomberg/industries.ts +18 -0
  436. package/src/clis/bloomberg/main.ts +18 -0
  437. package/src/clis/bloomberg/markets.ts +18 -0
  438. package/src/clis/bloomberg/news.ts +136 -0
  439. package/src/clis/bloomberg/opinions.ts +18 -0
  440. package/src/clis/bloomberg/politics.ts +18 -0
  441. package/src/clis/bloomberg/tech.ts +18 -0
  442. package/src/clis/bloomberg/utils.test.ts +135 -0
  443. package/src/clis/bloomberg/utils.ts +429 -0
  444. package/src/clis/boss/batchgreet.ts +16 -108
  445. package/src/clis/boss/chatlist.ts +13 -27
  446. package/src/clis/boss/chatmsg.ts +16 -40
  447. package/src/clis/boss/common.ts +287 -0
  448. package/src/clis/boss/detail.ts +9 -55
  449. package/src/clis/boss/exchange.ts +15 -89
  450. package/src/clis/boss/greet.ts +25 -162
  451. package/src/clis/boss/invite.ts +36 -133
  452. package/src/clis/boss/joblist.ts +7 -36
  453. package/src/clis/boss/mark.ts +13 -94
  454. package/src/clis/boss/recommend.ts +12 -57
  455. package/src/clis/boss/resume.ts +19 -124
  456. package/src/clis/boss/search.ts +14 -67
  457. package/src/clis/boss/send.ts +22 -162
  458. package/src/clis/boss/stats.ts +21 -76
  459. package/src/clis/chaoxing/assignments.ts +1 -1
  460. package/src/clis/chaoxing/exams.ts +1 -1
  461. package/src/{chaoxing.test.ts → clis/chaoxing/utils.test.ts} +1 -1
  462. package/src/{chaoxing.ts → clis/chaoxing/utils.ts} +1 -3
  463. package/src/clis/chatgpt/read.ts +1 -1
  464. package/src/clis/chatwise/export.ts +1 -1
  465. package/src/clis/chatwise/model.ts +2 -2
  466. package/src/clis/chatwise/screenshot.ts +1 -1
  467. package/src/clis/codex/export.ts +1 -1
  468. package/src/clis/codex/model.ts +2 -2
  469. package/src/clis/codex/screenshot.ts +1 -1
  470. package/src/clis/coupang/add-to-cart.ts +3 -4
  471. package/src/clis/coupang/search.ts +2 -4
  472. package/src/{coupang.test.ts → clis/coupang/utils.test.ts} +1 -1
  473. package/src/clis/ctrip/search.ts +1 -1
  474. package/src/clis/cursor/export.ts +1 -1
  475. package/src/clis/cursor/model.ts +2 -2
  476. package/src/clis/cursor/screenshot.ts +1 -1
  477. package/src/clis/devto/tag.yaml +34 -0
  478. package/src/clis/devto/top.yaml +29 -0
  479. package/src/clis/devto/user.yaml +33 -0
  480. package/src/clis/douban/book-hot.ts +15 -0
  481. package/src/clis/douban/marks.ts +135 -0
  482. package/src/clis/douban/movie-hot.ts +15 -0
  483. package/src/clis/douban/reviews.ts +127 -0
  484. package/src/clis/douban/search.ts +17 -0
  485. package/src/clis/douban/shared.ts +165 -0
  486. package/src/clis/douban/subject.yaml +76 -0
  487. package/src/clis/douban/top250.yaml +70 -0
  488. package/src/clis/douban/utils.ts +81 -0
  489. package/src/clis/facebook/add-friend.yaml +43 -0
  490. package/src/clis/facebook/events.yaml +44 -0
  491. package/src/clis/facebook/feed.yaml +63 -0
  492. package/src/clis/facebook/friends.yaml +42 -0
  493. package/src/clis/facebook/groups.yaml +50 -0
  494. package/src/clis/facebook/join-group.yaml +44 -0
  495. package/src/clis/facebook/memories.yaml +39 -0
  496. package/src/clis/facebook/notifications.yaml +40 -0
  497. package/src/clis/facebook/profile.yaml +37 -0
  498. package/src/clis/facebook/search.yaml +46 -0
  499. package/src/clis/google/news.ts +66 -0
  500. package/src/clis/google/search.ts +133 -0
  501. package/src/clis/google/suggest.ts +40 -0
  502. package/src/clis/google/trends.ts +44 -0
  503. package/src/clis/google/utils.test.ts +82 -0
  504. package/src/clis/google/utils.ts +24 -0
  505. package/src/clis/grok/ask.test.ts +53 -0
  506. package/src/clis/grok/ask.ts +300 -69
  507. package/src/clis/instagram/comment.yaml +52 -0
  508. package/src/clis/instagram/explore.yaml +43 -0
  509. package/src/clis/instagram/follow.yaml +41 -0
  510. package/src/clis/instagram/followers.yaml +51 -0
  511. package/src/clis/instagram/following.yaml +51 -0
  512. package/src/clis/instagram/like.yaml +46 -0
  513. package/src/clis/instagram/profile.yaml +42 -0
  514. package/src/clis/instagram/save.yaml +46 -0
  515. package/src/clis/instagram/saved.yaml +40 -0
  516. package/src/clis/instagram/search.yaml +43 -0
  517. package/src/clis/instagram/unfollow.yaml +38 -0
  518. package/src/clis/instagram/unlike.yaml +46 -0
  519. package/src/clis/instagram/unsave.yaml +46 -0
  520. package/src/clis/instagram/user.yaml +54 -0
  521. package/src/clis/jike/comment.ts +2 -3
  522. package/src/clis/jike/create.ts +1 -2
  523. package/src/clis/jike/feed.ts +0 -1
  524. package/src/clis/jike/like.ts +1 -2
  525. package/src/clis/jike/notifications.ts +0 -1
  526. package/src/clis/jike/post.yaml +1 -0
  527. package/src/clis/jike/repost.ts +2 -3
  528. package/src/clis/jike/search.ts +2 -3
  529. package/src/clis/jike/topic.yaml +1 -0
  530. package/src/clis/jike/user.yaml +1 -0
  531. package/src/clis/jimeng/generate.yaml +1 -0
  532. package/src/clis/jimeng/history.yaml +0 -1
  533. package/src/clis/linkedin/search.ts +7 -7
  534. package/src/clis/linux-do/category.yaml +2 -0
  535. package/src/clis/linux-do/search.yaml +4 -3
  536. package/src/clis/linux-do/topic.yaml +1 -0
  537. package/src/clis/lobsters/active.yaml +29 -0
  538. package/src/clis/lobsters/hot.yaml +29 -0
  539. package/src/clis/lobsters/newest.yaml +29 -0
  540. package/src/clis/lobsters/tag.yaml +34 -0
  541. package/src/clis/medium/feed.ts +16 -0
  542. package/src/clis/medium/search.ts +16 -0
  543. package/src/clis/medium/shared.ts +83 -0
  544. package/src/clis/medium/user.ts +16 -0
  545. package/src/clis/notion/export.ts +1 -1
  546. package/src/clis/reddit/comment.ts +3 -4
  547. package/src/clis/reddit/read.ts +4 -5
  548. package/src/clis/reddit/save.ts +2 -3
  549. package/src/clis/reddit/saved.ts +0 -1
  550. package/src/clis/reddit/search.yaml +1 -0
  551. package/src/clis/reddit/subreddit.yaml +1 -0
  552. package/src/clis/reddit/subscribe.ts +1 -2
  553. package/src/clis/reddit/upvote.ts +2 -3
  554. package/src/clis/reddit/upvoted.ts +0 -1
  555. package/src/clis/reddit/user-comments.yaml +1 -0
  556. package/src/clis/reddit/user-posts.yaml +1 -0
  557. package/src/clis/reddit/user.yaml +1 -0
  558. package/src/clis/reuters/search.ts +1 -1
  559. package/src/clis/sinablog/article.ts +15 -0
  560. package/src/clis/sinablog/hot.ts +15 -0
  561. package/src/clis/sinablog/search.ts +56 -0
  562. package/src/clis/sinablog/shared.ts +198 -0
  563. package/src/clis/sinablog/user.ts +16 -0
  564. package/src/clis/smzdm/search.ts +2 -3
  565. package/src/clis/stackoverflow/search.yaml +1 -0
  566. package/src/clis/steam/top-sellers.yaml +29 -0
  567. package/src/clis/substack/feed.ts +16 -0
  568. package/src/clis/substack/publication.ts +16 -0
  569. package/src/clis/substack/search.ts +91 -0
  570. package/src/clis/substack/shared.ts +132 -0
  571. package/src/clis/tiktok/comment.yaml +66 -0
  572. package/src/clis/tiktok/explore.yaml +39 -0
  573. package/src/clis/tiktok/follow.yaml +39 -0
  574. package/src/clis/tiktok/following.yaml +46 -0
  575. package/src/clis/tiktok/friends.yaml +47 -0
  576. package/src/clis/tiktok/like.yaml +38 -0
  577. package/src/clis/tiktok/live.yaml +51 -0
  578. package/src/clis/tiktok/notifications.yaml +52 -0
  579. package/src/clis/tiktok/profile.yaml +45 -0
  580. package/src/clis/tiktok/save.yaml +34 -0
  581. package/src/clis/tiktok/search.yaml +46 -0
  582. package/src/clis/tiktok/unfollow.yaml +44 -0
  583. package/src/clis/tiktok/unlike.yaml +38 -0
  584. package/src/clis/tiktok/unsave.yaml +36 -0
  585. package/src/clis/tiktok/user.yaml +44 -0
  586. package/src/clis/twitter/accept.ts +2 -2
  587. package/src/clis/twitter/article.ts +2 -2
  588. package/src/clis/twitter/block.ts +92 -0
  589. package/src/clis/twitter/delete.ts +1 -1
  590. package/src/clis/twitter/download.ts +3 -3
  591. package/src/clis/twitter/followers.ts +1 -1
  592. package/src/clis/twitter/following.ts +1 -1
  593. package/src/clis/twitter/hide-reply.ts +70 -0
  594. package/src/clis/twitter/like.ts +1 -1
  595. package/src/clis/twitter/post.ts +1 -1
  596. package/src/clis/twitter/reply-dm.ts +1 -1
  597. package/src/clis/twitter/reply.ts +2 -2
  598. package/src/clis/twitter/search.ts +1 -1
  599. package/src/clis/twitter/thread.ts +2 -2
  600. package/src/clis/twitter/timeline.test.ts +109 -0
  601. package/src/clis/twitter/timeline.ts +59 -19
  602. package/src/clis/twitter/trending.ts +113 -0
  603. package/src/clis/twitter/unblock.ts +75 -0
  604. package/src/clis/v2ex/topic.yaml +1 -0
  605. package/src/clis/weibo/hot.ts +0 -1
  606. package/src/clis/weread/book.ts +1 -1
  607. package/src/clis/weread/highlights.ts +1 -1
  608. package/src/clis/weread/notes.ts +1 -1
  609. package/src/clis/weread/search.ts +1 -1
  610. package/src/clis/wikipedia/random.ts +19 -0
  611. package/src/clis/wikipedia/search.ts +11 -5
  612. package/src/clis/wikipedia/summary.ts +4 -9
  613. package/src/clis/wikipedia/trending.ts +41 -0
  614. package/src/clis/wikipedia/utils.ts +31 -0
  615. package/src/clis/xiaohongshu/creator-note-detail.test.ts +84 -33
  616. package/src/clis/xiaohongshu/creator-note-detail.ts +89 -5
  617. package/src/clis/xiaohongshu/creator-notes.test.ts +41 -6
  618. package/src/clis/xiaohongshu/creator-notes.ts +44 -5
  619. package/src/clis/xiaohongshu/creator-profile.ts +0 -1
  620. package/src/clis/xiaohongshu/creator-stats.ts +0 -1
  621. package/src/clis/xiaohongshu/download.ts +2 -3
  622. package/src/clis/xiaohongshu/feed.yaml +0 -1
  623. package/src/clis/xiaohongshu/notifications.yaml +0 -1
  624. package/src/clis/xiaohongshu/search.ts +2 -2
  625. package/src/clis/xiaohongshu/user.ts +1 -2
  626. package/src/clis/xueqiu/earnings-date.yaml +69 -0
  627. package/src/clis/xueqiu/search.yaml +2 -1
  628. package/src/clis/xueqiu/stock.yaml +2 -0
  629. package/src/clis/yahoo-finance/quote.ts +1 -2
  630. package/src/clis/youtube/search.ts +1 -1
  631. package/src/clis/youtube/transcript.ts +1 -1
  632. package/src/clis/youtube/video.ts +1 -1
  633. package/src/clis/zhihu/download.ts +1 -2
  634. package/src/clis/zhihu/question.ts +1 -1
  635. package/src/clis/zhihu/search.yaml +4 -3
  636. package/src/commanderAdapter.ts +120 -0
  637. package/src/discovery.ts +277 -0
  638. package/src/doctor.test.ts +59 -2
  639. package/src/doctor.ts +4 -2
  640. package/src/download/index.ts +21 -54
  641. package/src/engine.test.ts +85 -11
  642. package/src/execution.ts +164 -0
  643. package/src/explore.ts +211 -117
  644. package/src/external-clis.yaml +9 -0
  645. package/src/external.ts +15 -12
  646. package/src/generate.ts +58 -9
  647. package/src/main.ts +2 -1
  648. package/src/pipeline/executor.test.ts +35 -6
  649. package/src/pipeline/executor.ts +11 -7
  650. package/src/pipeline/registry.ts +3 -3
  651. package/src/pipeline/steps/browser.ts +29 -15
  652. package/src/pipeline/steps/fetch.ts +18 -13
  653. package/src/pipeline/steps/transform.ts +40 -15
  654. package/src/pipeline/template.test.ts +18 -0
  655. package/src/pipeline/template.ts +86 -13
  656. package/src/pipeline/transform.test.ts +15 -2
  657. package/src/plugin.test.ts +86 -0
  658. package/src/plugin.ts +254 -0
  659. package/src/registry-api.ts +12 -0
  660. package/src/registry.ts +24 -1
  661. package/src/runtime.ts +9 -0
  662. package/src/serialization.ts +79 -0
  663. package/src/synthesize.ts +102 -21
  664. package/src/types.ts +45 -13
  665. package/src/validate.ts +19 -4
  666. package/tests/e2e/browser-public.test.ts +36 -0
  667. package/tests/e2e/public-commands.test.ts +119 -1
  668. package/dist/clis/feishu/new.d.ts +0 -1
  669. package/dist/clis/feishu/new.js +0 -27
  670. package/dist/clis/feishu/read.d.ts +0 -1
  671. package/dist/clis/feishu/read.js +0 -40
  672. package/dist/clis/feishu/search.d.ts +0 -1
  673. package/dist/clis/feishu/search.js +0 -30
  674. package/dist/clis/feishu/send.d.ts +0 -1
  675. package/dist/clis/feishu/send.js +0 -39
  676. package/dist/clis/feishu/status.d.ts +0 -1
  677. package/dist/clis/feishu/status.js +0 -28
  678. package/dist/clis/neteasemusic/like.d.ts +0 -1
  679. package/dist/clis/neteasemusic/like.js +0 -25
  680. package/dist/clis/neteasemusic/lyrics.d.ts +0 -1
  681. package/dist/clis/neteasemusic/lyrics.js +0 -47
  682. package/dist/clis/neteasemusic/next.d.ts +0 -1
  683. package/dist/clis/neteasemusic/next.js +0 -26
  684. package/dist/clis/neteasemusic/play.d.ts +0 -1
  685. package/dist/clis/neteasemusic/play.js +0 -26
  686. package/dist/clis/neteasemusic/playing.d.ts +0 -1
  687. package/dist/clis/neteasemusic/playing.js +0 -59
  688. package/dist/clis/neteasemusic/playlist.d.ts +0 -1
  689. package/dist/clis/neteasemusic/playlist.js +0 -46
  690. package/dist/clis/neteasemusic/prev.d.ts +0 -1
  691. package/dist/clis/neteasemusic/prev.js +0 -25
  692. package/dist/clis/neteasemusic/search.d.ts +0 -1
  693. package/dist/clis/neteasemusic/search.js +0 -52
  694. package/dist/clis/neteasemusic/status.d.ts +0 -1
  695. package/dist/clis/neteasemusic/status.js +0 -16
  696. package/dist/clis/neteasemusic/volume.d.ts +0 -1
  697. package/dist/clis/neteasemusic/volume.js +0 -54
  698. package/dist/clis/twitter/trending.yaml +0 -46
  699. package/dist/clis/wechat/chats.d.ts +0 -1
  700. package/dist/clis/wechat/chats.js +0 -28
  701. package/dist/clis/wechat/contacts.d.ts +0 -1
  702. package/dist/clis/wechat/contacts.js +0 -28
  703. package/dist/clis/wechat/read.d.ts +0 -1
  704. package/dist/clis/wechat/read.js +0 -58
  705. package/dist/clis/wechat/search.d.ts +0 -1
  706. package/dist/clis/wechat/search.js +0 -31
  707. package/dist/clis/wechat/send.d.ts +0 -1
  708. package/dist/clis/wechat/send.js +0 -42
  709. package/dist/clis/wechat/status.d.ts +0 -1
  710. package/dist/clis/wechat/status.js +0 -29
  711. package/dist/pipeline.d.ts +0 -7
  712. package/dist/pipeline.js +0 -7
  713. package/docs/adapters/browser/github.md +0 -26
  714. package/docs/adapters/desktop/feishu.md +0 -20
  715. package/docs/adapters/desktop/neteasemusic.md +0 -31
  716. package/docs/adapters/desktop/wechat.md +0 -28
  717. package/docs/public/CNAME +0 -1
  718. package/src/clis/antigravity/README.md +0 -5
  719. package/src/clis/antigravity/README.zh-CN.md +0 -51
  720. package/src/clis/chaoxing/README.md +0 -14
  721. package/src/clis/chaoxing/README.zh-CN.md +0 -35
  722. package/src/clis/chatgpt/README.md +0 -5
  723. package/src/clis/chatgpt/README.zh-CN.md +0 -44
  724. package/src/clis/chatwise/README.md +0 -5
  725. package/src/clis/chatwise/README.zh-CN.md +0 -38
  726. package/src/clis/codex/README.md +0 -5
  727. package/src/clis/codex/README.zh-CN.md +0 -33
  728. package/src/clis/cursor/README.md +0 -5
  729. package/src/clis/cursor/README.zh-CN.md +0 -33
  730. package/src/clis/discord-app/README.md +0 -5
  731. package/src/clis/discord-app/README.zh-CN.md +0 -28
  732. package/src/clis/feishu/README.md +0 -5
  733. package/src/clis/feishu/README.zh-CN.md +0 -20
  734. package/src/clis/feishu/new.ts +0 -32
  735. package/src/clis/feishu/read.ts +0 -48
  736. package/src/clis/feishu/search.ts +0 -35
  737. package/src/clis/feishu/send.ts +0 -46
  738. package/src/clis/feishu/status.ts +0 -34
  739. package/src/clis/neteasemusic/README.md +0 -5
  740. package/src/clis/neteasemusic/README.zh-CN.md +0 -31
  741. package/src/clis/neteasemusic/like.ts +0 -28
  742. package/src/clis/neteasemusic/lyrics.ts +0 -53
  743. package/src/clis/neteasemusic/next.ts +0 -30
  744. package/src/clis/neteasemusic/play.ts +0 -30
  745. package/src/clis/neteasemusic/playing.ts +0 -62
  746. package/src/clis/neteasemusic/playlist.ts +0 -51
  747. package/src/clis/neteasemusic/prev.ts +0 -29
  748. package/src/clis/neteasemusic/search.ts +0 -58
  749. package/src/clis/neteasemusic/status.ts +0 -18
  750. package/src/clis/neteasemusic/volume.ts +0 -61
  751. package/src/clis/notion/README.md +0 -5
  752. package/src/clis/notion/README.zh-CN.md +0 -29
  753. package/src/clis/twitter/trending.yaml +0 -46
  754. package/src/clis/wechat/README.md +0 -5
  755. package/src/clis/wechat/README.zh-CN.md +0 -28
  756. package/src/clis/wechat/chats.ts +0 -33
  757. package/src/clis/wechat/contacts.ts +0 -33
  758. package/src/clis/wechat/read.ts +0 -72
  759. package/src/clis/wechat/search.ts +0 -36
  760. package/src/clis/wechat/send.ts +0 -49
  761. package/src/clis/wechat/status.ts +0 -35
  762. package/src/engine.ts +0 -274
  763. package/src/pipeline.ts +0 -8
  764. /package/dist/{bilibili.js → clis/bilibili/utils.js} +0 -0
  765. /package/dist/{chaoxing.test.d.ts → clis/bloomberg/businessweek.d.ts} +0 -0
  766. /package/dist/{coupang.test.d.ts → clis/bloomberg/economics.d.ts} +0 -0
  767. /package/dist/{coupang.d.ts → clis/coupang/utils.d.ts} +0 -0
  768. /package/dist/{coupang.js → clis/coupang/utils.js} +0 -0
  769. /package/src/{coupang.ts → clis/coupang/utils.ts} +0 -0
package/src/synthesize.ts CHANGED
@@ -7,16 +7,96 @@ import * as fs from 'node:fs';
7
7
  import * as path from 'node:path';
8
8
  import yaml from 'js-yaml';
9
9
  import { VOLATILE_PARAMS, SEARCH_PARAMS, LIMIT_PARAMS, PAGINATION_PARAMS } from './constants.js';
10
+ import type { ExploreAuthSummary, ExploreEndpointArtifact, ExploreManifest } from './explore.js';
10
11
 
11
12
  /** Renamed aliases for backward compatibility with local references */
12
13
  const SEARCH_PARAM_NAMES = SEARCH_PARAMS;
13
14
  const LIMIT_PARAM_NAMES = LIMIT_PARAMS;
14
15
  const PAGE_PARAM_NAMES = PAGINATION_PARAMS;
15
16
 
17
+ interface RecommendedArg {
18
+ name: string;
19
+ type?: string;
20
+ required?: boolean;
21
+ default?: unknown;
22
+ }
23
+
24
+ interface StoreHint {
25
+ store: string;
26
+ action: string;
27
+ }
28
+
29
+ export interface SynthesizeCapability {
30
+ name: string;
31
+ description: string;
32
+ strategy: string;
33
+ confidence?: number;
34
+ endpoint?: string;
35
+ itemPath?: string | null;
36
+ recommendedColumns?: string[];
37
+ recommendedArgs?: RecommendedArg[];
38
+ recommended_args?: RecommendedArg[];
39
+ recommendedColumnsLegacy?: string[];
40
+ recommended_columns?: string[];
41
+ storeHint?: StoreHint;
42
+ }
43
+
44
+ export interface GeneratedArgDefinition {
45
+ type: string;
46
+ required?: boolean;
47
+ default?: unknown;
48
+ description?: string;
49
+ }
50
+
51
+ type CandidatePipelineStep =
52
+ | { navigate: string }
53
+ | { wait: number }
54
+ | { evaluate: string }
55
+ | { select: string }
56
+ | { map: Record<string, string> }
57
+ | { limit: string }
58
+ | { fetch: { url: string } }
59
+ | { tap: { store: string; action: string; timeout: number; capture?: string; select?: string | null } };
60
+
61
+ export interface CandidateYaml {
62
+ site: string;
63
+ name: string;
64
+ description: string;
65
+ domain: string;
66
+ strategy: string;
67
+ browser: boolean;
68
+ args: Record<string, GeneratedArgDefinition>;
69
+ pipeline: CandidatePipelineStep[];
70
+ columns: string[];
71
+ }
72
+
73
+ export interface SynthesizeCandidateSummary {
74
+ name: string;
75
+ path: string;
76
+ strategy: string;
77
+ confidence?: number;
78
+ }
79
+
80
+ export interface SynthesizeResult {
81
+ site: string;
82
+ explore_dir: string;
83
+ out_dir: string;
84
+ candidate_count: number;
85
+ candidates: SynthesizeCandidateSummary[];
86
+ }
87
+
88
+ type ExploreManifestLike = Pick<ExploreManifest, 'target_url' | 'final_url'> & Partial<ExploreManifest>;
89
+ interface LoadedExploreBundle {
90
+ manifest: ExploreManifest;
91
+ endpoints: ExploreEndpointArtifact[];
92
+ capabilities: SynthesizeCapability[];
93
+ auth: ExploreAuthSummary;
94
+ }
95
+
16
96
  export function synthesizeFromExplore(
17
97
  target: string,
18
98
  opts: { outDir?: string; top?: number } = {},
19
- ): Record<string, any> {
99
+ ): SynthesizeResult {
20
100
  const exploreDir = resolveExploreDir(target);
21
101
  const bundle = loadExploreBundle(exploreDir);
22
102
 
@@ -25,9 +105,9 @@ export function synthesizeFromExplore(
25
105
 
26
106
  const site = bundle.manifest.site;
27
107
  const capabilities = (bundle.capabilities ?? [])
28
- .sort((a: any, b: any) => (b.confidence ?? 0) - (a.confidence ?? 0))
108
+ .sort((a, b) => (b.confidence ?? 0) - (a.confidence ?? 0))
29
109
  .slice(0, opts.top ?? 3);
30
- const candidates: any[] = [];
110
+ const candidates: SynthesizeCandidateSummary[] = [];
31
111
 
32
112
  for (const cap of capabilities) {
33
113
  const endpoint = chooseEndpoint(cap, bundle.endpoints);
@@ -44,7 +124,7 @@ export function synthesizeFromExplore(
44
124
  return { site, explore_dir: exploreDir, out_dir: targetDir, candidate_count: candidates.length, candidates };
45
125
  }
46
126
 
47
- export function renderSynthesizeSummary(result: Record<string, any>): string {
127
+ export function renderSynthesizeSummary(result: SynthesizeResult): string {
48
128
  const lines = ['opencli synthesize: OK', `Site: ${result.site}`, `Source: ${result.explore_dir}`, `Candidates: ${result.candidate_count}`];
49
129
  for (const c of result.candidates ?? []) lines.push(` • ${c.name} (${c.strategy}, ${((c.confidence ?? 0) * 100).toFixed(0)}% confidence) → ${c.path}`);
50
130
  return lines.join('\n');
@@ -57,33 +137,34 @@ export function resolveExploreDir(target: string): string {
57
137
  throw new Error(`Explore directory not found: ${target}`);
58
138
  }
59
139
 
60
- export function loadExploreBundle(exploreDir: string): Record<string, any> {
140
+ export function loadExploreBundle(exploreDir: string): LoadedExploreBundle {
61
141
  return {
62
- manifest: JSON.parse(fs.readFileSync(path.join(exploreDir, 'manifest.json'), 'utf-8')),
63
- endpoints: JSON.parse(fs.readFileSync(path.join(exploreDir, 'endpoints.json'), 'utf-8')),
64
- capabilities: JSON.parse(fs.readFileSync(path.join(exploreDir, 'capabilities.json'), 'utf-8')),
142
+ manifest: JSON.parse(fs.readFileSync(path.join(exploreDir, 'manifest.json'), 'utf-8')) as ExploreManifest,
143
+ endpoints: JSON.parse(fs.readFileSync(path.join(exploreDir, 'endpoints.json'), 'utf-8')) as ExploreEndpointArtifact[],
144
+ capabilities: JSON.parse(fs.readFileSync(path.join(exploreDir, 'capabilities.json'), 'utf-8')) as SynthesizeCapability[],
65
145
  auth: JSON.parse(fs.readFileSync(path.join(exploreDir, 'auth.json'), 'utf-8')),
66
146
  };
67
147
  }
68
148
 
69
- function chooseEndpoint(cap: any, endpoints: any[]): any | null {
149
+ function chooseEndpoint(cap: SynthesizeCapability, endpoints: ExploreEndpointArtifact[]): ExploreEndpointArtifact | null {
70
150
  if (!endpoints.length) return null;
71
151
  // Match by endpoint pattern from capability
72
152
  if (cap.endpoint) {
73
- const match = endpoints.find((e: any) => e.pattern === cap.endpoint || e.url?.includes(cap.endpoint));
153
+ const endpointPattern = cap.endpoint;
154
+ const match = endpoints.find((endpoint) => endpoint.pattern === endpointPattern || endpoint.url?.includes(endpointPattern));
74
155
  if (match) return match;
75
156
  }
76
- return endpoints.sort((a: any, b: any) => (b.score ?? 0) - (a.score ?? 0))[0];
157
+ return [...endpoints].sort((a, b) => (b.score ?? 0) - (a.score ?? 0))[0];
77
158
  }
78
159
 
79
160
  // ── URL templating ─────────────────────────────────────────────────────────
80
161
 
81
- function buildTemplatedUrl(rawUrl: string, cap: any, _endpoint: any): string {
162
+ function buildTemplatedUrl(rawUrl: string, cap: SynthesizeCapability, _endpoint: ExploreEndpointArtifact): string {
82
163
  try {
83
164
  const u = new URL(rawUrl);
84
165
  const base = `${u.protocol}//${u.host}${u.pathname}`;
85
166
  const params: Array<[string, string]> = [];
86
- const hasKeyword = cap.recommendedArgs?.some((a: any) => a.name === 'keyword');
167
+ const hasKeyword = cap.recommendedArgs?.some((arg) => arg.name === 'keyword');
87
168
 
88
169
  u.searchParams.forEach((v, k) => {
89
170
  if (VOLATILE_PARAMS.has(k)) return;
@@ -101,7 +182,7 @@ function buildTemplatedUrl(rawUrl: string, cap: any, _endpoint: any): string {
101
182
  * Build inline evaluate script for browser-based fetch+parse.
102
183
  * Follows patterns from bilibili/hot.yaml and twitter/trending.yaml.
103
184
  */
104
- function buildEvaluateScript(url: string, itemPath: string, endpoint: any): string {
185
+ function buildEvaluateScript(url: string, itemPath: string, endpoint: ExploreEndpointArtifact): string {
105
186
  const pathChain = itemPath.split('.').map((p: string) => `?.${p}`).join('');
106
187
  const detectedFields = endpoint?.detectedFields ?? {};
107
188
  const hasFields = Object.keys(detectedFields).length > 0;
@@ -127,9 +208,9 @@ function buildEvaluateScript(url: string, itemPath: string, endpoint: any): stri
127
208
 
128
209
  // ── YAML pipeline generation ───────────────────────────────────────────────
129
210
 
130
- function buildCandidateYaml(site: string, manifest: any, cap: any, endpoint: any): { name: string; yaml: any } {
211
+ function buildCandidateYaml(site: string, manifest: ExploreManifestLike, cap: SynthesizeCapability, endpoint: ExploreEndpointArtifact): { name: string; yaml: CandidateYaml } {
131
212
  const needsBrowser = cap.strategy !== 'public';
132
- const pipeline: any[] = [];
213
+ const pipeline: CandidatePipelineStep[] = [];
133
214
  const templatedUrl = buildTemplatedUrl(endpoint?.url ?? manifest.target_url, cap, endpoint);
134
215
 
135
216
  let domain = '';
@@ -139,7 +220,7 @@ function buildCandidateYaml(site: string, manifest: any, cap: any, endpoint: any
139
220
  // Store Action: navigate + wait + tap (declarative, clean)
140
221
  pipeline.push({ navigate: manifest.target_url });
141
222
  pipeline.push({ wait: 3 });
142
- const tapStep: Record<string, any> = {
223
+ const tapStep: { store: string; action: string; timeout: number; capture?: string; select?: string | null } = {
143
224
  store: cap.storeHint.store,
144
225
  action: cap.storeHint.action,
145
226
  timeout: 8,
@@ -170,7 +251,7 @@ function buildCandidateYaml(site: string, manifest: any, cap: any, endpoint: any
170
251
  // Map fields
171
252
  const mapStep: Record<string, string> = {};
172
253
  const columns = cap.recommendedColumns ?? ['title', 'url'];
173
- if (!cap.recommendedArgs?.some((a: any) => a.name === 'keyword')) mapStep['rank'] = '${{ index + 1 }}';
254
+ if (!cap.recommendedArgs?.some((arg) => arg.name === 'keyword')) mapStep['rank'] = '${{ index + 1 }}';
174
255
  const detectedFields = endpoint?.detectedFields ?? {};
175
256
  for (const col of columns) {
176
257
  const fieldPath = detectedFields[col];
@@ -180,9 +261,9 @@ function buildCandidateYaml(site: string, manifest: any, cap: any, endpoint: any
180
261
  pipeline.push({ limit: '${{ args.limit | default(20) }}' });
181
262
 
182
263
  // Args
183
- const argsDef: Record<string, any> = {};
264
+ const argsDef: Record<string, GeneratedArgDefinition> = {};
184
265
  for (const arg of cap.recommendedArgs ?? []) {
185
- const def: any = { type: arg.type ?? 'str' };
266
+ const def: GeneratedArgDefinition = { type: arg.type ?? 'str' };
186
267
  if (arg.required) def.required = true;
187
268
  if (arg.default != null) def.default = arg.default;
188
269
  if (arg.name === 'keyword') def.description = 'Search keyword';
@@ -203,7 +284,7 @@ function buildCandidateYaml(site: string, manifest: any, cap: any, endpoint: any
203
284
  }
204
285
 
205
286
  /** Backward-compatible export for scaffold.ts */
206
- export function buildCandidate(site: string, targetUrl: string, cap: any, endpoint: any): any {
287
+ export function buildCandidate(site: string, targetUrl: string, cap: SynthesizeCapability, endpoint: ExploreEndpointArtifact): { name: string; yaml: CandidateYaml } {
207
288
  // Map old-style field names to new ones
208
289
  const normalizedCap = {
209
290
  ...cap,
package/src/types.ts CHANGED
@@ -5,23 +5,55 @@
5
5
  * instead of `any` for browser interactions.
6
6
  */
7
7
 
8
+ export interface BrowserCookie {
9
+ name: string;
10
+ value: string;
11
+ domain: string;
12
+ path?: string;
13
+ secure?: boolean;
14
+ httpOnly?: boolean;
15
+ expirationDate?: number;
16
+ }
17
+
18
+ export interface SnapshotOptions {
19
+ interactive?: boolean;
20
+ compact?: boolean;
21
+ maxDepth?: number;
22
+ raw?: boolean;
23
+ viewportExpand?: number;
24
+ maxTextLength?: number;
25
+ }
26
+
27
+ export interface WaitOptions {
28
+ text?: string;
29
+ time?: number;
30
+ timeout?: number;
31
+ }
32
+
33
+ export interface ScreenshotOptions {
34
+ format?: 'png' | 'jpeg';
35
+ quality?: number;
36
+ fullPage?: boolean;
37
+ path?: string;
38
+ }
39
+
40
+ export interface BrowserSessionInfo {
41
+ workspace?: string;
42
+ connected?: boolean;
43
+ [key: string]: unknown;
44
+ }
45
+
8
46
  export interface IPage {
9
- goto(url: string): Promise<void>;
47
+ goto(url: string, options?: { waitUntil?: 'load' | 'none'; settleMs?: number }): Promise<void>;
10
48
  evaluate(js: string): Promise<any>;
11
- getCookies(opts?: { domain?: string; url?: string }): Promise<Array<{
12
- name: string;
13
- value: string;
14
- domain: string;
15
- path?: string;
16
- secure?: boolean;
17
- httpOnly?: boolean;
18
- expirationDate?: number;
19
- }>>;
20
- snapshot(opts?: { interactive?: boolean; compact?: boolean; maxDepth?: number; raw?: boolean }): Promise<any>;
49
+ getCookies(opts?: { domain?: string; url?: string }): Promise<BrowserCookie[]>;
50
+ snapshot(opts?: SnapshotOptions): Promise<any>;
21
51
  click(ref: string): Promise<void>;
22
52
  typeText(ref: string, text: string): Promise<void>;
23
53
  pressKey(key: string): Promise<void>;
24
- wait(options: number | { text?: string; time?: number; timeout?: number }): Promise<void>;
54
+ scrollTo(ref: string): Promise<any>;
55
+ getFormState(): Promise<any>;
56
+ wait(options: number | WaitOptions): Promise<void>;
25
57
  tabs(): Promise<any>;
26
58
  closeTab(index?: number): Promise<void>;
27
59
  newTab(): Promise<void>;
@@ -32,5 +64,5 @@ export interface IPage {
32
64
  autoScroll(options?: { times?: number; delayMs?: number }): Promise<void>;
33
65
  installInterceptor(pattern: string): Promise<void>;
34
66
  getInterceptedRequests(): Promise<any[]>;
35
- screenshot(options?: { format?: 'png' | 'jpeg'; quality?: number; fullPage?: boolean; path?: string }): Promise<string>;
67
+ screenshot(options?: ScreenshotOptions): Promise<string>;
36
68
  }
package/src/validate.ts CHANGED
@@ -25,6 +25,22 @@ export interface ValidationReport {
25
25
  files: number;
26
26
  }
27
27
 
28
+ interface ValidatedYamlCliDefinition {
29
+ site?: string;
30
+ name?: string;
31
+ pipeline?: unknown[];
32
+ columns?: unknown[];
33
+ args?: Record<string, unknown>;
34
+ }
35
+
36
+ function isRecord(value: unknown): value is Record<string, unknown> {
37
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
38
+ }
39
+
40
+ function getErrorMessage(error: unknown): string {
41
+ return error instanceof Error ? error.message : String(error);
42
+ }
43
+
28
44
  export function validateClisWithTarget(dirs: string[], target?: string): ValidationReport {
29
45
  const results: FileValidationResult[] = [];
30
46
  let errors = 0; let warnings = 0; let files = 0;
@@ -53,8 +69,8 @@ function validateYamlFile(filePath: string): FileValidationResult {
53
69
  const errors: string[] = []; const warnings: string[] = [];
54
70
  try {
55
71
  const raw = fs.readFileSync(filePath, 'utf-8');
56
- const def = yaml.load(raw) as any;
57
- if (!def || typeof def !== 'object') { errors.push('Not a valid YAML object'); return { path: filePath, errors, warnings }; }
72
+ const def = yaml.load(raw) as ValidatedYamlCliDefinition | null;
73
+ if (!isRecord(def)) { errors.push('Not a valid YAML object'); return { path: filePath, errors, warnings }; }
58
74
  if (!def.site) errors.push('Missing "site"');
59
75
  if (!def.name) errors.push('Missing "name"');
60
76
  if (def.pipeline && !Array.isArray(def.pipeline)) errors.push('"pipeline" must be an array');
@@ -74,7 +90,7 @@ function validateYamlFile(filePath: string): FileValidationResult {
74
90
  }
75
91
  }
76
92
  }
77
- } catch (e: any) { errors.push(`YAML parse error: ${e.message}`); }
93
+ } catch (e) { errors.push(`YAML parse error: ${getErrorMessage(e)}`); }
78
94
  return { path: filePath, errors, warnings };
79
95
  }
80
96
 
@@ -89,4 +105,3 @@ export function renderValidationReport(report: ValidationReport): string {
89
105
  }
90
106
  return lines.join('\n');
91
107
  }
92
-
@@ -46,6 +46,31 @@ describe('browser public-data commands E2E', () => {
46
46
  }
47
47
  }, 60_000);
48
48
 
49
+ it('bloomberg news returns article detail when the article page is accessible', async () => {
50
+ const feedResult = await runCli(['bloomberg', 'tech', '--limit', '1', '-f', 'json']);
51
+ if (feedResult.code !== 0) {
52
+ console.warn('bloomberg news: skipped — could not load Bloomberg tech feed');
53
+ return;
54
+ }
55
+
56
+ const feedItems = parseJsonOutput(feedResult.stdout);
57
+ const link = Array.isArray(feedItems) ? feedItems[0]?.link : null;
58
+ if (!link) {
59
+ console.warn('bloomberg news: skipped — tech feed returned no link');
60
+ return;
61
+ }
62
+
63
+ const data = await tryBrowserCommand(['bloomberg', 'news', link, '-f', 'json']);
64
+ expectDataOrSkip(data, 'bloomberg news');
65
+ if (data) {
66
+ expect(data[0]).toHaveProperty('title');
67
+ expect(data[0]).toHaveProperty('summary');
68
+ expect(data[0]).toHaveProperty('link');
69
+ expect(data[0]).toHaveProperty('mediaLinks');
70
+ expect(data[0]).toHaveProperty('content');
71
+ }
72
+ }, 60_000);
73
+
49
74
  // ── v2ex daily (browser: true) ──
50
75
  it('v2ex daily returns topics', async () => {
51
76
  const data = await tryBrowserCommand(['v2ex', 'daily', '--limit', '3', '-f', 'json']);
@@ -161,6 +186,17 @@ describe('browser public-data commands E2E', () => {
161
186
  expectDataOrSkip(data, 'xiaohongshu search');
162
187
  }, 60_000);
163
188
 
189
+ // ── google search (browser: true, public strategy) ──
190
+ it('google search returns results', async () => {
191
+ const data = await tryBrowserCommand(['google', 'search', 'typescript', '--limit', '5', '-f', 'json']);
192
+ expectDataOrSkip(data, 'google search');
193
+ if (data) {
194
+ expect(data[0]).toHaveProperty('type');
195
+ expect(data[0]).toHaveProperty('title');
196
+ expect(data[0]).toHaveProperty('url');
197
+ }
198
+ }, 60_000);
199
+
164
200
  // ── yahoo-finance (browser: true) ──
165
201
  it('yahoo-finance quote returns stock data', async () => {
166
202
  const data = await tryBrowserCommand(['yahoo-finance', 'quote', '--symbol', 'AAPL', '-f', 'json']);
@@ -11,10 +11,66 @@ function isExpectedChineseSiteRestriction(code: number, stderr: string): boolean
11
11
  return /Error \[FETCH_ERROR\]: HTTP (403|429|451|503)\b/.test(stderr);
12
12
  }
13
13
 
14
+ function isExpectedApplePodcastsRestriction(code: number, stderr: string): boolean {
15
+ if (code === 0) return false;
16
+ return /Error \[FETCH_ERROR\]: (Charts API HTTP \d+|Unable to reach Apple Podcasts charts)/.test(stderr);
17
+ }
18
+
19
+ function isExpectedGoogleRestriction(code: number, stderr: string): boolean {
20
+ if (code === 0) return false;
21
+ // Network unreachable (DNS/proxy) or HTTP error from Google
22
+ return /fetch failed/.test(stderr) || /Error \[FETCH_ERROR\]: HTTP (403|429|451|503)\b/.test(stderr);
23
+ }
24
+
14
25
  // Keep old name as alias for existing tests
15
26
  const isExpectedXiaoyuzhouRestriction = isExpectedChineseSiteRestriction;
16
27
 
17
28
  describe('public commands E2E', () => {
29
+ // ── bloomberg (RSS-backed, browser: false) ──
30
+ it('bloomberg main returns structured headline data', async () => {
31
+ const { stdout, code } = await runCli(['bloomberg', 'main', '--limit', '1', '-f', 'json']);
32
+ expect(code).toBe(0);
33
+ const data = parseJsonOutput(stdout);
34
+ expect(Array.isArray(data)).toBe(true);
35
+ expect(data.length).toBe(1);
36
+ expect(data[0]).toHaveProperty('title');
37
+ expect(data[0]).toHaveProperty('summary');
38
+ expect(data[0]).toHaveProperty('link');
39
+ expect(data[0]).toHaveProperty('mediaLinks');
40
+ expect(Array.isArray(data[0].mediaLinks)).toBe(true);
41
+ }, 30_000);
42
+
43
+ it.each(['markets', 'economics', 'industries', 'tech', 'politics', 'businessweek', 'opinions'])(
44
+ 'bloomberg %s returns structured RSS items',
45
+ async (section) => {
46
+ const { stdout, code } = await runCli(['bloomberg', section, '--limit', '1', '-f', 'json']);
47
+ expect(code).toBe(0);
48
+ const data = parseJsonOutput(stdout);
49
+ expect(Array.isArray(data)).toBe(true);
50
+ expect(data.length).toBe(1);
51
+ expect(data[0]).toHaveProperty('title');
52
+ expect(data[0]).toHaveProperty('summary');
53
+ expect(data[0]).toHaveProperty('link');
54
+ expect(data[0]).toHaveProperty('mediaLinks');
55
+ },
56
+ 30_000,
57
+ );
58
+
59
+ it('bloomberg feeds lists the supported RSS aliases', async () => {
60
+ const { stdout, code } = await runCli(['bloomberg', 'feeds', '-f', 'json']);
61
+ expect(code).toBe(0);
62
+ const data = parseJsonOutput(stdout);
63
+ expect(Array.isArray(data)).toBe(true);
64
+ expect(data).toEqual(
65
+ expect.arrayContaining([
66
+ expect.objectContaining({ name: 'main' }),
67
+ expect.objectContaining({ name: 'markets' }),
68
+ expect.objectContaining({ name: 'tech' }),
69
+ expect.objectContaining({ name: 'opinions' }),
70
+ ]),
71
+ );
72
+ }, 30_000);
73
+
18
74
  // ── apple-podcasts ──
19
75
  it('apple-podcasts search returns structured podcast results', async () => {
20
76
  const { stdout, code } = await runCli(['apple-podcasts', 'search', 'technology', '--limit', '3', '-f', 'json']);
@@ -39,7 +95,11 @@ describe('public commands E2E', () => {
39
95
  }, 30_000);
40
96
 
41
97
  it('apple-podcasts top returns ranked podcasts', async () => {
42
- const { stdout, code } = await runCli(['apple-podcasts', 'top', '--limit', '3', '--country', 'us', '-f', 'json']);
98
+ const { stdout, stderr, code } = await runCli(['apple-podcasts', 'top', '--limit', '3', '--country', 'us', '-f', 'json']);
99
+ if (isExpectedApplePodcastsRestriction(code, stderr)) {
100
+ console.warn(`apple-podcasts top skipped: ${stderr.trim()}`);
101
+ return;
102
+ }
43
103
  expect(code).toBe(0);
44
104
  const data = parseJsonOutput(stdout);
45
105
  expect(Array.isArray(data)).toBe(true);
@@ -153,6 +213,64 @@ describe('public commands E2E', () => {
153
213
  expect(stderr).toMatch(/limit must be a positive integer|Argument "limit" must be a valid number/);
154
214
  }, 30_000);
155
215
 
216
+ // ── google suggest (public JSON API) ──
217
+ it('google suggest returns suggestions', async () => {
218
+ const { stdout, stderr, code } = await runCli(['google', 'suggest', 'python', '-f', 'json']);
219
+ if (isExpectedGoogleRestriction(code, stderr)) {
220
+ console.warn(`google suggest skipped: ${stderr.trim()}`);
221
+ return;
222
+ }
223
+ expect(code).toBe(0);
224
+ const data = parseJsonOutput(stdout);
225
+ expect(Array.isArray(data)).toBe(true);
226
+ expect(data.length).toBeGreaterThanOrEqual(1);
227
+ expect(data[0]).toHaveProperty('suggestion');
228
+ }, 30_000);
229
+
230
+ // ── google news (public RSS) ──
231
+ it('google news returns headlines', async () => {
232
+ const { stdout, stderr, code } = await runCli(['google', 'news', '--limit', '3', '-f', 'json']);
233
+ if (isExpectedGoogleRestriction(code, stderr)) {
234
+ console.warn(`google news skipped: ${stderr.trim()}`);
235
+ return;
236
+ }
237
+ expect(code).toBe(0);
238
+ const data = parseJsonOutput(stdout);
239
+ expect(Array.isArray(data)).toBe(true);
240
+ expect(data.length).toBeGreaterThanOrEqual(1);
241
+ expect(data[0]).toHaveProperty('title');
242
+ expect(data[0]).toHaveProperty('source');
243
+ expect(data[0]).toHaveProperty('url');
244
+ }, 30_000);
245
+
246
+ it('google news search returns results', async () => {
247
+ const { stdout, stderr, code } = await runCli(['google', 'news', 'AI', '--limit', '3', '-f', 'json']);
248
+ if (isExpectedGoogleRestriction(code, stderr)) {
249
+ console.warn(`google news search skipped: ${stderr.trim()}`);
250
+ return;
251
+ }
252
+ expect(code).toBe(0);
253
+ const data = parseJsonOutput(stdout);
254
+ expect(Array.isArray(data)).toBe(true);
255
+ expect(data.length).toBeGreaterThanOrEqual(1);
256
+ expect(data[0]).toHaveProperty('title');
257
+ }, 30_000);
258
+
259
+ // ── google trends (public RSS) ──
260
+ it('google trends returns trending searches', async () => {
261
+ const { stdout, stderr, code } = await runCli(['google', 'trends', '--region', 'US', '--limit', '3', '-f', 'json']);
262
+ if (isExpectedGoogleRestriction(code, stderr)) {
263
+ console.warn(`google trends skipped: ${stderr.trim()}`);
264
+ return;
265
+ }
266
+ expect(code).toBe(0);
267
+ const data = parseJsonOutput(stdout);
268
+ expect(Array.isArray(data)).toBe(true);
269
+ expect(data.length).toBeGreaterThanOrEqual(1);
270
+ expect(data[0]).toHaveProperty('title');
271
+ expect(data[0]).toHaveProperty('traffic');
272
+ }, 30_000);
273
+
156
274
  // ── weread (Chinese site — may return empty on overseas CI runners) ──
157
275
  it('weread search returns books', async () => {
158
276
  const { stdout, stderr, code } = await runCli(['weread', 'search', 'python', '--limit', '3', '-f', 'json']);
@@ -1 +0,0 @@
1
- export declare const newCommand: import("../../registry.js").CliCommand;
@@ -1,27 +0,0 @@
1
- import { execSync } from 'node:child_process';
2
- import { cli, Strategy } from '../../registry.js';
3
- export const newCommand = cli({
4
- site: 'feishu',
5
- name: 'new',
6
- description: 'Create a new message or document in Feishu',
7
- domain: 'localhost',
8
- strategy: Strategy.PUBLIC,
9
- browser: false,
10
- args: [],
11
- columns: ['Status'],
12
- func: async (page) => {
13
- try {
14
- execSync("osascript -e 'tell application \"Lark\" to activate'");
15
- execSync("osascript -e 'delay 0.3'");
16
- // Cmd+N for new conversation/document
17
- execSync("osascript " +
18
- "-e 'tell application \"System Events\"' " +
19
- "-e 'keystroke \"n\" using command down' " +
20
- "-e 'end tell'");
21
- return [{ Status: 'New item dialog opened (Cmd+N)' }];
22
- }
23
- catch (err) {
24
- return [{ Status: 'Error: ' + err.message }];
25
- }
26
- },
27
- });
@@ -1 +0,0 @@
1
- export declare const readCommand: import("../../registry.js").CliCommand;
@@ -1,40 +0,0 @@
1
- import { execSync, spawnSync } from 'node:child_process';
2
- import { cli, Strategy } from '../../registry.js';
3
- export const readCommand = cli({
4
- site: 'feishu',
5
- name: 'read',
6
- description: 'Read the current chat content by selecting all and copying',
7
- domain: 'localhost',
8
- strategy: Strategy.PUBLIC,
9
- browser: false,
10
- args: [],
11
- columns: ['Content'],
12
- func: async (page) => {
13
- try {
14
- let clipBackup = '';
15
- try {
16
- clipBackup = execSync('pbpaste', { encoding: 'utf-8' });
17
- }
18
- catch { /* empty */ }
19
- execSync("osascript -e 'tell application \"Lark\" to activate'");
20
- execSync("osascript -e 'delay 0.3'");
21
- execSync("osascript " +
22
- "-e 'tell application \"System Events\"' " +
23
- "-e 'keystroke \"a\" using command down' " +
24
- "-e 'delay 0.2' " +
25
- "-e 'keystroke \"c\" using command down' " +
26
- "-e 'delay 0.2' " +
27
- "-e 'end tell'");
28
- const content = execSync('pbpaste', { encoding: 'utf-8' }).trim();
29
- if (clipBackup) {
30
- spawnSync('pbcopy', { input: clipBackup });
31
- }
32
- // Deselect
33
- execSync("osascript -e 'tell application \"System Events\" to key code 53'");
34
- return [{ Content: content || '(no content captured)' }];
35
- }
36
- catch (err) {
37
- return [{ Content: 'Error: ' + err.message }];
38
- }
39
- },
40
- });
@@ -1 +0,0 @@
1
- export declare const searchCommand: import("../../registry.js").CliCommand;
@@ -1,30 +0,0 @@
1
- import { execSync } from 'node:child_process';
2
- import { cli, Strategy } from '../../registry.js';
3
- export const searchCommand = cli({
4
- site: 'feishu',
5
- name: 'search',
6
- description: 'Open Feishu global search and type a query (Cmd+K)',
7
- domain: 'localhost',
8
- strategy: Strategy.PUBLIC,
9
- browser: false,
10
- args: [{ name: 'query', required: true, positional: true, help: 'Search query' }],
11
- columns: ['Status'],
12
- func: async (page, kwargs) => {
13
- const query = kwargs.query;
14
- try {
15
- execSync("osascript -e 'tell application \"Lark\" to activate'");
16
- execSync("osascript -e 'delay 0.3'");
17
- // Feishu uses Cmd+K for global search (similar to Slack/Notion)
18
- execSync("osascript " +
19
- "-e 'tell application \"System Events\"' " +
20
- "-e 'keystroke \"k\" using command down' " +
21
- "-e 'delay 0.5' " +
22
- `-e 'keystroke ${JSON.stringify(query)}' ` +
23
- "-e 'end tell'");
24
- return [{ Status: `Searching for: ${query}` }];
25
- }
26
- catch (err) {
27
- return [{ Status: 'Error: ' + err.message }];
28
- }
29
- },
30
- });
@@ -1 +0,0 @@
1
- export declare const sendCommand: import("../../registry.js").CliCommand;