@jackwener/opencli 1.1.1 → 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 (509) hide show
  1. package/CONTRIBUTING.md +39 -1
  2. package/README.md +9 -10
  3. package/README.zh-CN.md +39 -17
  4. package/SKILL.md +10 -5
  5. package/dist/browser/cdp.d.ts +4 -4
  6. package/dist/browser/cdp.js +39 -16
  7. package/dist/browser/daemon-client.d.ts +2 -1
  8. package/dist/browser/dom-helpers.js +38 -7
  9. package/dist/browser/dom-snapshot.d.ts +86 -0
  10. package/dist/browser/dom-snapshot.js +729 -0
  11. package/dist/browser/dom-snapshot.test.d.ts +11 -0
  12. package/dist/browser/dom-snapshot.test.js +212 -0
  13. package/dist/browser/index.d.ts +2 -0
  14. package/dist/browser/index.js +1 -0
  15. package/dist/browser/page.d.ts +14 -24
  16. package/dist/browser/page.js +37 -4
  17. package/dist/build-manifest.d.ts +11 -4
  18. package/dist/build-manifest.js +59 -21
  19. package/dist/build-manifest.test.js +58 -2
  20. package/dist/cli-manifest.json +3856 -1509
  21. package/dist/cli.js +66 -0
  22. package/dist/clis/barchart/greeks.js +1 -1
  23. package/dist/clis/barchart/options.js +1 -1
  24. package/dist/clis/barchart/quote.js +1 -1
  25. package/dist/clis/bilibili/download.js +1 -1
  26. package/dist/clis/bilibili/following.js +1 -1
  27. package/dist/clis/bilibili/subtitle.js +1 -1
  28. package/dist/clis/bilibili/user-videos.js +1 -1
  29. package/dist/clis/boss/batchgreet.js +10 -97
  30. package/dist/clis/boss/chatlist.js +8 -25
  31. package/dist/clis/boss/chatmsg.js +11 -42
  32. package/dist/clis/boss/common.d.ts +92 -0
  33. package/dist/clis/boss/common.js +223 -0
  34. package/dist/clis/boss/detail.js +7 -49
  35. package/dist/clis/boss/exchange.js +13 -79
  36. package/dist/clis/boss/greet.js +18 -145
  37. package/dist/clis/boss/invite.js +26 -121
  38. package/dist/clis/boss/joblist.js +6 -31
  39. package/dist/clis/boss/mark.js +12 -85
  40. package/dist/clis/boss/recommend.js +10 -49
  41. package/dist/clis/boss/resume.js +18 -118
  42. package/dist/clis/boss/search.js +12 -60
  43. package/dist/clis/boss/send.js +17 -151
  44. package/dist/clis/boss/stats.js +18 -69
  45. package/dist/clis/coupang/add-to-cart.js +1 -1
  46. package/dist/clis/devto/tag.yaml +34 -0
  47. package/dist/clis/devto/top.yaml +29 -0
  48. package/dist/clis/devto/user.yaml +33 -0
  49. package/dist/clis/douban/book-hot.d.ts +1 -0
  50. package/dist/clis/douban/book-hot.js +14 -0
  51. package/dist/clis/douban/marks.d.ts +1 -0
  52. package/dist/clis/douban/marks.js +115 -0
  53. package/dist/clis/douban/movie-hot.d.ts +1 -0
  54. package/dist/clis/douban/movie-hot.js +14 -0
  55. package/dist/clis/douban/reviews.d.ts +1 -0
  56. package/dist/clis/douban/reviews.js +106 -0
  57. package/dist/clis/douban/search.d.ts +1 -0
  58. package/dist/clis/douban/search.js +16 -0
  59. package/dist/clis/douban/shared.d.ts +4 -0
  60. package/dist/clis/douban/shared.js +155 -0
  61. package/dist/clis/douban/subject.yaml +76 -0
  62. package/dist/clis/douban/top250.yaml +70 -0
  63. package/dist/clis/douban/utils.d.ts +35 -0
  64. package/dist/clis/douban/utils.js +48 -0
  65. package/dist/clis/facebook/add-friend.yaml +43 -0
  66. package/dist/clis/facebook/events.yaml +44 -0
  67. package/dist/clis/facebook/feed.yaml +63 -0
  68. package/dist/clis/facebook/friends.yaml +42 -0
  69. package/dist/clis/facebook/groups.yaml +50 -0
  70. package/dist/clis/facebook/join-group.yaml +44 -0
  71. package/dist/clis/facebook/memories.yaml +39 -0
  72. package/dist/clis/facebook/notifications.yaml +40 -0
  73. package/dist/clis/facebook/profile.yaml +37 -0
  74. package/dist/clis/facebook/search.yaml +46 -0
  75. package/dist/clis/google/news.d.ts +5 -0
  76. package/dist/clis/google/news.js +58 -0
  77. package/dist/clis/google/search.d.ts +10 -0
  78. package/dist/clis/google/search.js +127 -0
  79. package/dist/clis/google/suggest.d.ts +5 -0
  80. package/dist/clis/google/suggest.js +34 -0
  81. package/dist/clis/google/trends.d.ts +5 -0
  82. package/dist/clis/google/trends.js +38 -0
  83. package/dist/clis/google/utils.d.ts +9 -0
  84. package/dist/clis/google/utils.js +23 -0
  85. package/dist/clis/google/utils.test.d.ts +1 -0
  86. package/dist/clis/google/utils.test.js +75 -0
  87. package/dist/clis/grok/ask.d.ts +14 -0
  88. package/dist/clis/grok/ask.js +257 -65
  89. package/dist/clis/grok/ask.test.d.ts +1 -0
  90. package/dist/clis/grok/ask.test.js +36 -0
  91. package/dist/clis/instagram/comment.yaml +52 -0
  92. package/dist/clis/instagram/explore.yaml +43 -0
  93. package/dist/clis/instagram/follow.yaml +41 -0
  94. package/dist/clis/instagram/followers.yaml +51 -0
  95. package/dist/clis/instagram/following.yaml +51 -0
  96. package/dist/clis/instagram/like.yaml +46 -0
  97. package/dist/clis/instagram/profile.yaml +42 -0
  98. package/dist/clis/instagram/save.yaml +46 -0
  99. package/dist/clis/instagram/saved.yaml +40 -0
  100. package/dist/clis/instagram/search.yaml +43 -0
  101. package/dist/clis/instagram/unfollow.yaml +38 -0
  102. package/dist/clis/instagram/unlike.yaml +46 -0
  103. package/dist/clis/instagram/unsave.yaml +46 -0
  104. package/dist/clis/instagram/user.yaml +54 -0
  105. package/dist/clis/jike/repost.js +1 -1
  106. package/dist/clis/jimeng/generate.yaml +1 -0
  107. package/dist/clis/linux-do/category.yaml +1 -0
  108. package/dist/clis/lobsters/active.yaml +29 -0
  109. package/dist/clis/lobsters/hot.yaml +29 -0
  110. package/dist/clis/lobsters/newest.yaml +29 -0
  111. package/dist/clis/lobsters/tag.yaml +34 -0
  112. package/dist/clis/medium/feed.d.ts +1 -0
  113. package/dist/clis/medium/feed.js +15 -0
  114. package/dist/clis/medium/search.d.ts +1 -0
  115. package/dist/clis/medium/search.js +15 -0
  116. package/dist/clis/medium/shared.d.ts +5 -0
  117. package/dist/clis/medium/shared.js +78 -0
  118. package/dist/clis/medium/user.d.ts +1 -0
  119. package/dist/clis/medium/user.js +15 -0
  120. package/dist/clis/reddit/comment.js +1 -1
  121. package/dist/clis/reddit/read.js +1 -1
  122. package/dist/clis/reddit/save.js +1 -1
  123. package/dist/clis/reddit/subreddit.yaml +1 -0
  124. package/dist/clis/reddit/subscribe.js +1 -1
  125. package/dist/clis/reddit/upvote.js +1 -1
  126. package/dist/clis/sinablog/article.d.ts +1 -0
  127. package/dist/clis/sinablog/article.js +14 -0
  128. package/dist/clis/sinablog/hot.d.ts +1 -0
  129. package/dist/clis/sinablog/hot.js +14 -0
  130. package/dist/clis/sinablog/search.d.ts +1 -0
  131. package/dist/clis/sinablog/search.js +51 -0
  132. package/dist/clis/sinablog/shared.d.ts +7 -0
  133. package/dist/clis/sinablog/shared.js +187 -0
  134. package/dist/clis/sinablog/user.d.ts +1 -0
  135. package/dist/clis/sinablog/user.js +15 -0
  136. package/dist/clis/substack/feed.d.ts +1 -0
  137. package/dist/clis/substack/feed.js +15 -0
  138. package/dist/clis/substack/publication.d.ts +1 -0
  139. package/dist/clis/substack/publication.js +15 -0
  140. package/dist/clis/substack/search.d.ts +1 -0
  141. package/dist/clis/substack/search.js +77 -0
  142. package/dist/clis/substack/shared.d.ts +4 -0
  143. package/dist/clis/substack/shared.js +129 -0
  144. package/dist/clis/tiktok/comment.yaml +66 -0
  145. package/dist/clis/tiktok/explore.yaml +39 -0
  146. package/dist/clis/tiktok/follow.yaml +39 -0
  147. package/dist/clis/tiktok/following.yaml +46 -0
  148. package/dist/clis/tiktok/friends.yaml +47 -0
  149. package/dist/clis/tiktok/like.yaml +38 -0
  150. package/dist/clis/tiktok/live.yaml +51 -0
  151. package/dist/clis/tiktok/notifications.yaml +52 -0
  152. package/dist/clis/tiktok/profile.yaml +45 -0
  153. package/dist/clis/tiktok/save.yaml +34 -0
  154. package/dist/clis/tiktok/search.yaml +46 -0
  155. package/dist/clis/tiktok/unfollow.yaml +44 -0
  156. package/dist/clis/tiktok/unlike.yaml +38 -0
  157. package/dist/clis/tiktok/unsave.yaml +36 -0
  158. package/dist/clis/tiktok/user.yaml +44 -0
  159. package/dist/clis/twitter/download.d.ts +1 -1
  160. package/dist/clis/twitter/download.js +3 -3
  161. package/dist/clis/twitter/followers.js +1 -1
  162. package/dist/clis/twitter/following.js +1 -1
  163. package/dist/clis/twitter/thread.js +1 -1
  164. package/dist/clis/twitter/timeline.d.ts +23 -0
  165. package/dist/clis/twitter/timeline.js +42 -14
  166. package/dist/clis/twitter/timeline.test.d.ts +1 -0
  167. package/dist/clis/twitter/timeline.test.js +102 -0
  168. package/dist/clis/wikipedia/random.d.ts +1 -0
  169. package/dist/clis/wikipedia/random.js +19 -0
  170. package/dist/clis/wikipedia/search.js +3 -3
  171. package/dist/clis/wikipedia/summary.js +4 -9
  172. package/dist/clis/wikipedia/trending.d.ts +1 -0
  173. package/dist/clis/wikipedia/trending.js +35 -0
  174. package/dist/clis/wikipedia/utils.d.ts +28 -0
  175. package/dist/clis/wikipedia/utils.js +13 -0
  176. package/dist/clis/xiaohongshu/creator-note-detail.js +1 -1
  177. package/dist/clis/xiaohongshu/creator-note-detail.test.js +2 -0
  178. package/dist/clis/xiaohongshu/creator-notes.test.js +2 -0
  179. package/dist/clis/xiaohongshu/download.js +1 -1
  180. package/dist/clis/xueqiu/earnings-date.yaml +69 -0
  181. package/dist/clis/xueqiu/search.yaml +2 -1
  182. package/dist/clis/xueqiu/stock.yaml +2 -0
  183. package/dist/clis/yahoo-finance/quote.js +1 -1
  184. package/dist/commanderAdapter.js +13 -7
  185. package/dist/discovery.d.ts +8 -0
  186. package/dist/discovery.js +105 -19
  187. package/dist/doctor.js +3 -1
  188. package/dist/doctor.test.js +46 -2
  189. package/dist/engine.test.d.ts +0 -3
  190. package/dist/engine.test.js +74 -6
  191. package/dist/execution.d.ts +4 -2
  192. package/dist/execution.js +31 -7
  193. package/dist/explore.d.ts +76 -3
  194. package/dist/explore.js +11 -4
  195. package/dist/generate.d.ts +41 -2
  196. package/dist/generate.js +5 -4
  197. package/dist/main.js +2 -1
  198. package/dist/pipeline/executor.d.ts +2 -2
  199. package/dist/pipeline/executor.js +2 -2
  200. package/dist/pipeline/executor.test.js +33 -6
  201. package/dist/pipeline/registry.d.ts +1 -1
  202. package/dist/pipeline/steps/browser.d.ts +7 -7
  203. package/dist/pipeline/steps/browser.js +15 -7
  204. package/dist/pipeline/steps/fetch.d.ts +1 -1
  205. package/dist/pipeline/steps/fetch.js +11 -7
  206. package/dist/pipeline/steps/transform.d.ts +6 -5
  207. package/dist/pipeline/steps/transform.js +30 -9
  208. package/dist/pipeline/template.d.ts +6 -6
  209. package/dist/pipeline/template.js +43 -5
  210. package/dist/pipeline/template.test.js +18 -0
  211. package/dist/pipeline/transform.test.js +11 -0
  212. package/dist/plugin.d.ts +31 -0
  213. package/dist/plugin.js +216 -0
  214. package/dist/plugin.test.d.ts +4 -0
  215. package/dist/plugin.test.js +76 -0
  216. package/dist/registry-api.d.ts +11 -0
  217. package/dist/registry-api.js +9 -0
  218. package/dist/registry.d.ts +11 -0
  219. package/dist/registry.js +6 -1
  220. package/dist/synthesize.d.ts +94 -4
  221. package/dist/synthesize.js +5 -4
  222. package/dist/types.d.ts +39 -26
  223. package/dist/validate.js +8 -2
  224. package/docs/.vitepress/config.mts +6 -4
  225. package/docs/adapters/browser/barchart.md +6 -5
  226. package/docs/adapters/browser/bilibili.md +9 -0
  227. package/docs/adapters/browser/devto.md +35 -0
  228. package/docs/adapters/browser/douban.md +38 -0
  229. package/docs/adapters/browser/facebook.md +36 -0
  230. package/docs/adapters/browser/google.md +62 -0
  231. package/docs/adapters/browser/grok.md +26 -8
  232. package/docs/adapters/browser/instagram.md +46 -0
  233. package/docs/adapters/browser/lobsters.md +32 -0
  234. package/docs/adapters/browser/medium.md +32 -0
  235. package/docs/adapters/browser/reddit.md +9 -0
  236. package/docs/adapters/browser/sinablog.md +36 -0
  237. package/docs/adapters/browser/substack.md +38 -0
  238. package/docs/adapters/browser/tiktok.md +68 -0
  239. package/docs/adapters/browser/wikipedia.md +11 -2
  240. package/docs/adapters/browser/xueqiu.md +10 -0
  241. package/docs/adapters/browser/yahoo-finance.md +6 -5
  242. package/docs/adapters/desktop/antigravity.md +6 -0
  243. package/docs/adapters/desktop/chatgpt.md +2 -1
  244. package/docs/adapters/desktop/codex.md +5 -1
  245. package/docs/adapters/desktop/cursor.md +4 -0
  246. package/docs/adapters/desktop/discord.md +7 -7
  247. package/docs/adapters/index.md +1 -4
  248. package/docs/guide/getting-started.md +1 -0
  249. package/docs/guide/plugins.md +153 -0
  250. package/docs/zh/guide/plugins.md +107 -0
  251. package/extension/src/background.ts +18 -11
  252. package/package.json +10 -5
  253. package/scripts/clean-dist.cjs +13 -0
  254. package/src/browser/cdp.ts +71 -31
  255. package/src/browser/daemon-client.ts +2 -1
  256. package/src/browser/dom-helpers.ts +38 -7
  257. package/src/browser/dom-snapshot.test.ts +249 -0
  258. package/src/browser/dom-snapshot.ts +770 -0
  259. package/src/browser/index.ts +2 -0
  260. package/src/browser/page.ts +50 -19
  261. package/src/build-manifest.test.ts +70 -2
  262. package/src/build-manifest.ts +94 -26
  263. package/src/cli.ts +71 -2
  264. package/src/clis/barchart/greeks.ts +1 -1
  265. package/src/clis/barchart/options.ts +1 -1
  266. package/src/clis/barchart/quote.ts +1 -1
  267. package/src/clis/bilibili/download.ts +1 -1
  268. package/src/clis/bilibili/following.ts +1 -1
  269. package/src/clis/bilibili/subtitle.ts +1 -1
  270. package/src/clis/bilibili/user-videos.ts +1 -1
  271. package/src/clis/boss/batchgreet.ts +14 -106
  272. package/src/clis/boss/chatlist.ts +12 -26
  273. package/src/clis/boss/chatmsg.ts +16 -40
  274. package/src/clis/boss/common.ts +287 -0
  275. package/src/clis/boss/detail.ts +8 -54
  276. package/src/clis/boss/exchange.ts +15 -89
  277. package/src/clis/boss/greet.ts +23 -160
  278. package/src/clis/boss/invite.ts +36 -133
  279. package/src/clis/boss/joblist.ts +7 -36
  280. package/src/clis/boss/mark.ts +13 -94
  281. package/src/clis/boss/recommend.ts +12 -57
  282. package/src/clis/boss/resume.ts +19 -124
  283. package/src/clis/boss/search.ts +13 -66
  284. package/src/clis/boss/send.ts +21 -161
  285. package/src/clis/boss/stats.ts +19 -74
  286. package/src/clis/coupang/add-to-cart.ts +1 -1
  287. package/src/clis/devto/tag.yaml +34 -0
  288. package/src/clis/devto/top.yaml +29 -0
  289. package/src/clis/devto/user.yaml +33 -0
  290. package/src/clis/douban/book-hot.ts +15 -0
  291. package/src/clis/douban/marks.ts +135 -0
  292. package/src/clis/douban/movie-hot.ts +15 -0
  293. package/src/clis/douban/reviews.ts +127 -0
  294. package/src/clis/douban/search.ts +17 -0
  295. package/src/clis/douban/shared.ts +165 -0
  296. package/src/clis/douban/subject.yaml +76 -0
  297. package/src/clis/douban/top250.yaml +70 -0
  298. package/src/clis/douban/utils.ts +81 -0
  299. package/src/clis/facebook/add-friend.yaml +43 -0
  300. package/src/clis/facebook/events.yaml +44 -0
  301. package/src/clis/facebook/feed.yaml +63 -0
  302. package/src/clis/facebook/friends.yaml +42 -0
  303. package/src/clis/facebook/groups.yaml +50 -0
  304. package/src/clis/facebook/join-group.yaml +44 -0
  305. package/src/clis/facebook/memories.yaml +39 -0
  306. package/src/clis/facebook/notifications.yaml +40 -0
  307. package/src/clis/facebook/profile.yaml +37 -0
  308. package/src/clis/facebook/search.yaml +46 -0
  309. package/src/clis/google/news.ts +66 -0
  310. package/src/clis/google/search.ts +133 -0
  311. package/src/clis/google/suggest.ts +40 -0
  312. package/src/clis/google/trends.ts +44 -0
  313. package/src/clis/google/utils.test.ts +82 -0
  314. package/src/clis/google/utils.ts +24 -0
  315. package/src/clis/grok/ask.test.ts +53 -0
  316. package/src/clis/grok/ask.ts +300 -69
  317. package/src/clis/instagram/comment.yaml +52 -0
  318. package/src/clis/instagram/explore.yaml +43 -0
  319. package/src/clis/instagram/follow.yaml +41 -0
  320. package/src/clis/instagram/followers.yaml +51 -0
  321. package/src/clis/instagram/following.yaml +51 -0
  322. package/src/clis/instagram/like.yaml +46 -0
  323. package/src/clis/instagram/profile.yaml +42 -0
  324. package/src/clis/instagram/save.yaml +46 -0
  325. package/src/clis/instagram/saved.yaml +40 -0
  326. package/src/clis/instagram/search.yaml +43 -0
  327. package/src/clis/instagram/unfollow.yaml +38 -0
  328. package/src/clis/instagram/unlike.yaml +46 -0
  329. package/src/clis/instagram/unsave.yaml +46 -0
  330. package/src/clis/instagram/user.yaml +54 -0
  331. package/src/clis/jike/repost.ts +1 -1
  332. package/src/clis/jimeng/generate.yaml +1 -0
  333. package/src/clis/linux-do/category.yaml +1 -0
  334. package/src/clis/lobsters/active.yaml +29 -0
  335. package/src/clis/lobsters/hot.yaml +29 -0
  336. package/src/clis/lobsters/newest.yaml +29 -0
  337. package/src/clis/lobsters/tag.yaml +34 -0
  338. package/src/clis/medium/feed.ts +16 -0
  339. package/src/clis/medium/search.ts +16 -0
  340. package/src/clis/medium/shared.ts +83 -0
  341. package/src/clis/medium/user.ts +16 -0
  342. package/src/clis/reddit/comment.ts +1 -1
  343. package/src/clis/reddit/read.ts +1 -1
  344. package/src/clis/reddit/save.ts +1 -1
  345. package/src/clis/reddit/subreddit.yaml +1 -0
  346. package/src/clis/reddit/subscribe.ts +1 -1
  347. package/src/clis/reddit/upvote.ts +1 -1
  348. package/src/clis/sinablog/article.ts +15 -0
  349. package/src/clis/sinablog/hot.ts +15 -0
  350. package/src/clis/sinablog/search.ts +56 -0
  351. package/src/clis/sinablog/shared.ts +198 -0
  352. package/src/clis/sinablog/user.ts +16 -0
  353. package/src/clis/substack/feed.ts +16 -0
  354. package/src/clis/substack/publication.ts +16 -0
  355. package/src/clis/substack/search.ts +91 -0
  356. package/src/clis/substack/shared.ts +132 -0
  357. package/src/clis/tiktok/comment.yaml +66 -0
  358. package/src/clis/tiktok/explore.yaml +39 -0
  359. package/src/clis/tiktok/follow.yaml +39 -0
  360. package/src/clis/tiktok/following.yaml +46 -0
  361. package/src/clis/tiktok/friends.yaml +47 -0
  362. package/src/clis/tiktok/like.yaml +38 -0
  363. package/src/clis/tiktok/live.yaml +51 -0
  364. package/src/clis/tiktok/notifications.yaml +52 -0
  365. package/src/clis/tiktok/profile.yaml +45 -0
  366. package/src/clis/tiktok/save.yaml +34 -0
  367. package/src/clis/tiktok/search.yaml +46 -0
  368. package/src/clis/tiktok/unfollow.yaml +44 -0
  369. package/src/clis/tiktok/unlike.yaml +38 -0
  370. package/src/clis/tiktok/unsave.yaml +36 -0
  371. package/src/clis/tiktok/user.yaml +44 -0
  372. package/src/clis/twitter/download.ts +3 -3
  373. package/src/clis/twitter/followers.ts +1 -1
  374. package/src/clis/twitter/following.ts +1 -1
  375. package/src/clis/twitter/thread.ts +1 -1
  376. package/src/clis/twitter/timeline.test.ts +109 -0
  377. package/src/clis/twitter/timeline.ts +59 -19
  378. package/src/clis/wikipedia/random.ts +19 -0
  379. package/src/clis/wikipedia/search.ts +10 -4
  380. package/src/clis/wikipedia/summary.ts +4 -9
  381. package/src/clis/wikipedia/trending.ts +41 -0
  382. package/src/clis/wikipedia/utils.ts +31 -0
  383. package/src/clis/xiaohongshu/creator-note-detail.test.ts +2 -0
  384. package/src/clis/xiaohongshu/creator-note-detail.ts +1 -1
  385. package/src/clis/xiaohongshu/creator-notes.test.ts +2 -0
  386. package/src/clis/xiaohongshu/download.ts +1 -1
  387. package/src/clis/xueqiu/earnings-date.yaml +69 -0
  388. package/src/clis/xueqiu/search.yaml +2 -1
  389. package/src/clis/xueqiu/stock.yaml +2 -0
  390. package/src/clis/yahoo-finance/quote.ts +1 -1
  391. package/src/commanderAdapter.ts +17 -10
  392. package/src/discovery.ts +134 -24
  393. package/src/doctor.test.ts +59 -2
  394. package/src/doctor.ts +4 -2
  395. package/src/engine.test.ts +79 -6
  396. package/src/execution.ts +42 -16
  397. package/src/explore.ts +77 -9
  398. package/src/generate.ts +58 -9
  399. package/src/main.ts +2 -1
  400. package/src/pipeline/executor.test.ts +35 -6
  401. package/src/pipeline/executor.ts +11 -7
  402. package/src/pipeline/registry.ts +3 -3
  403. package/src/pipeline/steps/browser.ts +24 -15
  404. package/src/pipeline/steps/fetch.ts +18 -13
  405. package/src/pipeline/steps/transform.ts +40 -15
  406. package/src/pipeline/template.test.ts +18 -0
  407. package/src/pipeline/template.ts +86 -13
  408. package/src/pipeline/transform.test.ts +15 -2
  409. package/src/plugin.test.ts +86 -0
  410. package/src/plugin.ts +254 -0
  411. package/src/registry-api.ts +12 -0
  412. package/src/registry.ts +19 -1
  413. package/src/synthesize.ts +102 -21
  414. package/src/types.ts +44 -12
  415. package/src/validate.ts +19 -4
  416. package/tests/e2e/browser-public.test.ts +11 -0
  417. package/tests/e2e/public-commands.test.ts +64 -0
  418. package/dist/clis/feishu/new.d.ts +0 -1
  419. package/dist/clis/feishu/new.js +0 -27
  420. package/dist/clis/feishu/read.d.ts +0 -1
  421. package/dist/clis/feishu/read.js +0 -40
  422. package/dist/clis/feishu/search.d.ts +0 -1
  423. package/dist/clis/feishu/search.js +0 -30
  424. package/dist/clis/feishu/send.d.ts +0 -1
  425. package/dist/clis/feishu/send.js +0 -39
  426. package/dist/clis/feishu/status.d.ts +0 -1
  427. package/dist/clis/feishu/status.js +0 -28
  428. package/dist/clis/neteasemusic/like.d.ts +0 -1
  429. package/dist/clis/neteasemusic/like.js +0 -25
  430. package/dist/clis/neteasemusic/lyrics.d.ts +0 -1
  431. package/dist/clis/neteasemusic/lyrics.js +0 -47
  432. package/dist/clis/neteasemusic/next.d.ts +0 -1
  433. package/dist/clis/neteasemusic/next.js +0 -26
  434. package/dist/clis/neteasemusic/play.d.ts +0 -1
  435. package/dist/clis/neteasemusic/play.js +0 -26
  436. package/dist/clis/neteasemusic/playing.d.ts +0 -1
  437. package/dist/clis/neteasemusic/playing.js +0 -59
  438. package/dist/clis/neteasemusic/playlist.d.ts +0 -1
  439. package/dist/clis/neteasemusic/playlist.js +0 -46
  440. package/dist/clis/neteasemusic/prev.d.ts +0 -1
  441. package/dist/clis/neteasemusic/prev.js +0 -25
  442. package/dist/clis/neteasemusic/search.d.ts +0 -1
  443. package/dist/clis/neteasemusic/search.js +0 -52
  444. package/dist/clis/neteasemusic/status.d.ts +0 -1
  445. package/dist/clis/neteasemusic/status.js +0 -16
  446. package/dist/clis/neteasemusic/volume.d.ts +0 -1
  447. package/dist/clis/neteasemusic/volume.js +0 -54
  448. package/dist/clis/wechat/chats.d.ts +0 -1
  449. package/dist/clis/wechat/chats.js +0 -28
  450. package/dist/clis/wechat/contacts.d.ts +0 -1
  451. package/dist/clis/wechat/contacts.js +0 -28
  452. package/dist/clis/wechat/read.d.ts +0 -1
  453. package/dist/clis/wechat/read.js +0 -58
  454. package/dist/clis/wechat/search.d.ts +0 -1
  455. package/dist/clis/wechat/search.js +0 -31
  456. package/dist/clis/wechat/send.d.ts +0 -1
  457. package/dist/clis/wechat/send.js +0 -42
  458. package/dist/clis/wechat/status.d.ts +0 -1
  459. package/dist/clis/wechat/status.js +0 -29
  460. package/dist/pipeline.d.ts +0 -7
  461. package/dist/pipeline.js +0 -7
  462. package/docs/adapters/browser/github.md +0 -26
  463. package/docs/adapters/desktop/feishu.md +0 -20
  464. package/docs/adapters/desktop/neteasemusic.md +0 -31
  465. package/docs/adapters/desktop/wechat.md +0 -28
  466. package/src/clis/antigravity/README.md +0 -5
  467. package/src/clis/antigravity/README.zh-CN.md +0 -51
  468. package/src/clis/chaoxing/README.md +0 -14
  469. package/src/clis/chaoxing/README.zh-CN.md +0 -35
  470. package/src/clis/chatgpt/README.md +0 -5
  471. package/src/clis/chatgpt/README.zh-CN.md +0 -44
  472. package/src/clis/chatwise/README.md +0 -5
  473. package/src/clis/chatwise/README.zh-CN.md +0 -38
  474. package/src/clis/codex/README.md +0 -5
  475. package/src/clis/codex/README.zh-CN.md +0 -33
  476. package/src/clis/cursor/README.md +0 -5
  477. package/src/clis/cursor/README.zh-CN.md +0 -33
  478. package/src/clis/discord-app/README.md +0 -5
  479. package/src/clis/discord-app/README.zh-CN.md +0 -28
  480. package/src/clis/feishu/README.md +0 -5
  481. package/src/clis/feishu/README.zh-CN.md +0 -20
  482. package/src/clis/feishu/new.ts +0 -32
  483. package/src/clis/feishu/read.ts +0 -48
  484. package/src/clis/feishu/search.ts +0 -35
  485. package/src/clis/feishu/send.ts +0 -46
  486. package/src/clis/feishu/status.ts +0 -34
  487. package/src/clis/neteasemusic/README.md +0 -5
  488. package/src/clis/neteasemusic/README.zh-CN.md +0 -31
  489. package/src/clis/neteasemusic/like.ts +0 -28
  490. package/src/clis/neteasemusic/lyrics.ts +0 -53
  491. package/src/clis/neteasemusic/next.ts +0 -30
  492. package/src/clis/neteasemusic/play.ts +0 -30
  493. package/src/clis/neteasemusic/playing.ts +0 -62
  494. package/src/clis/neteasemusic/playlist.ts +0 -51
  495. package/src/clis/neteasemusic/prev.ts +0 -29
  496. package/src/clis/neteasemusic/search.ts +0 -58
  497. package/src/clis/neteasemusic/status.ts +0 -18
  498. package/src/clis/neteasemusic/volume.ts +0 -61
  499. package/src/clis/notion/README.md +0 -5
  500. package/src/clis/notion/README.zh-CN.md +0 -29
  501. package/src/clis/wechat/README.md +0 -5
  502. package/src/clis/wechat/README.zh-CN.md +0 -28
  503. package/src/clis/wechat/chats.ts +0 -33
  504. package/src/clis/wechat/contacts.ts +0 -33
  505. package/src/clis/wechat/read.ts +0 -72
  506. package/src/clis/wechat/search.ts +0 -36
  507. package/src/clis/wechat/send.ts +0 -49
  508. package/src/clis/wechat/status.ts +0 -35
  509. package/src/pipeline.ts +0 -8
package/dist/cli.js CHANGED
@@ -210,6 +210,72 @@ export function runCli(BUILTIN_CLIS, USER_CLIS) {
210
210
  .action((shell) => {
211
211
  printCompletionScript(shell);
212
212
  });
213
+ // ── Plugin management ──────────────────────────────────────────────────────
214
+ const pluginCmd = program.command('plugin').description('Manage opencli plugins');
215
+ pluginCmd
216
+ .command('install')
217
+ .description('Install a plugin from GitHub')
218
+ .argument('<source>', 'Plugin source (e.g. github:user/repo)')
219
+ .action(async (source) => {
220
+ const { installPlugin } = await import('./plugin.js');
221
+ try {
222
+ const name = installPlugin(source);
223
+ console.log(chalk.green(`✅ Plugin "${name}" installed successfully.`));
224
+ console.log(chalk.dim(` Restart opencli to use the new commands.`));
225
+ }
226
+ catch (err) {
227
+ console.error(chalk.red(`Error: ${err.message}`));
228
+ process.exitCode = 1;
229
+ }
230
+ });
231
+ pluginCmd
232
+ .command('uninstall')
233
+ .description('Uninstall a plugin')
234
+ .argument('<name>', 'Plugin name')
235
+ .action(async (name) => {
236
+ const { uninstallPlugin } = await import('./plugin.js');
237
+ try {
238
+ uninstallPlugin(name);
239
+ console.log(chalk.green(`✅ Plugin "${name}" uninstalled.`));
240
+ }
241
+ catch (err) {
242
+ console.error(chalk.red(`Error: ${err.message}`));
243
+ process.exitCode = 1;
244
+ }
245
+ });
246
+ pluginCmd
247
+ .command('list')
248
+ .description('List installed plugins')
249
+ .option('-f, --format <fmt>', 'Output format: table, json', 'table')
250
+ .action(async (opts) => {
251
+ const { listPlugins } = await import('./plugin.js');
252
+ const plugins = listPlugins();
253
+ if (plugins.length === 0) {
254
+ console.log(chalk.dim(' No plugins installed.'));
255
+ console.log(chalk.dim(` Install one with: opencli plugin install github:user/repo`));
256
+ return;
257
+ }
258
+ if (opts.format === 'json') {
259
+ renderOutput(plugins, {
260
+ fmt: 'json',
261
+ columns: ['name', 'commands', 'source'],
262
+ title: 'opencli/plugins',
263
+ source: 'opencli plugin list',
264
+ });
265
+ return;
266
+ }
267
+ console.log();
268
+ console.log(chalk.bold(' Installed plugins'));
269
+ console.log();
270
+ for (const p of plugins) {
271
+ const cmds = p.commands.length > 0 ? chalk.dim(` (${p.commands.join(', ')})`) : '';
272
+ const src = p.source ? chalk.dim(` ← ${p.source}`) : '';
273
+ console.log(` ${chalk.cyan(p.name)}${cmds}${src}`);
274
+ }
275
+ console.log();
276
+ console.log(chalk.dim(` ${plugins.length} plugin(s) installed`));
277
+ console.log();
278
+ });
213
279
  // ── External CLIs ─────────────────────────────────────────────────────────
214
280
  const externalClis = loadExternalClis();
215
281
  program
@@ -11,7 +11,7 @@ cli({
11
11
  domain: 'www.barchart.com',
12
12
  strategy: Strategy.COOKIE,
13
13
  args: [
14
- { name: 'symbol', required: true, help: 'Stock ticker (e.g. AAPL)' },
14
+ { name: 'symbol', required: true, positional: true, help: 'Stock ticker (e.g. AAPL)' },
15
15
  { name: 'expiration', type: 'str', help: 'Expiration date (YYYY-MM-DD). Defaults to the nearest available expiration.' },
16
16
  { name: 'limit', type: 'int', default: 10, help: 'Number of near-the-money strikes per type' },
17
17
  ],
@@ -10,7 +10,7 @@ cli({
10
10
  domain: 'www.barchart.com',
11
11
  strategy: Strategy.COOKIE,
12
12
  args: [
13
- { name: 'symbol', required: true, help: 'Stock ticker (e.g. AAPL)' },
13
+ { name: 'symbol', required: true, positional: true, help: 'Stock ticker (e.g. AAPL)' },
14
14
  { name: 'type', type: 'str', default: 'Call', help: 'Option type: Call or Put', choices: ['Call', 'Put'] },
15
15
  { name: 'limit', type: 'int', default: 20, help: 'Max number of strikes to return' },
16
16
  ],
@@ -10,7 +10,7 @@ cli({
10
10
  domain: 'www.barchart.com',
11
11
  strategy: Strategy.COOKIE,
12
12
  args: [
13
- { name: 'symbol', required: true, help: 'Stock ticker (e.g. AAPL, MSFT, TSLA)' },
13
+ { name: 'symbol', required: true, positional: true, help: 'Stock ticker (e.g. AAPL, MSFT, TSLA)' },
14
14
  ],
15
15
  columns: [
16
16
  'symbol', 'name', 'price', 'change', 'changePct',
@@ -19,7 +19,7 @@ cli({
19
19
  domain: 'www.bilibili.com',
20
20
  strategy: Strategy.COOKIE,
21
21
  args: [
22
- { name: 'bvid', required: true, help: 'Video BV ID (e.g., BV1xxx)' },
22
+ { name: 'bvid', required: true, positional: true, help: 'Video BV ID (e.g., BV1xxx)' },
23
23
  { name: 'output', default: './bilibili-downloads', help: 'Output directory' },
24
24
  { name: 'quality', default: 'best', help: 'Video quality (best, 1080p, 720p, 480p)' },
25
25
  ],
@@ -6,7 +6,7 @@ cli({
6
6
  description: '获取 Bilibili 用户的关注列表',
7
7
  strategy: Strategy.COOKIE,
8
8
  args: [
9
- { name: 'uid', required: false, help: '目标用户 ID(默认为当前登录用户)' },
9
+ { name: 'uid', positional: true, required: false, help: '目标用户 ID(默认为当前登录用户)' },
10
10
  { name: 'page', type: 'int', required: false, default: 1, help: '页码' },
11
11
  { name: 'limit', type: 'int', required: false, default: 50, help: '每页数量 (最大 50)' },
12
12
  ],
@@ -6,7 +6,7 @@ cli({
6
6
  description: '获取 Bilibili 视频的字幕',
7
7
  strategy: Strategy.COOKIE,
8
8
  args: [
9
- { name: 'bvid', required: true },
9
+ { name: 'bvid', required: true, positional: true },
10
10
  { name: 'lang', required: false, help: '字幕语言代码 (如 zh-CN, en-US, ai-zh),默认取第一个' },
11
11
  ],
12
12
  columns: ['index', 'from', 'to', 'content'],
@@ -7,7 +7,7 @@ cli({
7
7
  domain: 'www.bilibili.com',
8
8
  strategy: Strategy.COOKIE,
9
9
  args: [
10
- { name: 'uid', required: true, help: 'User UID or username' },
10
+ { name: 'uid', required: true, positional: true, help: 'User UID or username' },
11
11
  { name: 'limit', type: 'int', default: 20, help: 'Number of results' },
12
12
  { name: 'order', default: 'pubdate', help: 'Sort: pubdate, click, stow' },
13
13
  { name: 'page', type: 'int', default: 1, help: 'Page number' },
@@ -1,16 +1,15 @@
1
1
  /**
2
2
  * BOSS直聘 batchgreet — batch greet recommended candidates.
3
- *
4
- * Combines recommend (greetRecSortList) + greet (UI automation).
5
- * Sends greeting messages to multiple candidates sequentially.
6
3
  */
7
4
  import { cli, Strategy } from '../../registry.js';
5
+ import { requirePage, navigateToChat, fetchRecommendList, clickCandidateInList, typeAndSendMessage, verbose, } from './common.js';
8
6
  cli({
9
7
  site: 'boss',
10
8
  name: 'batchgreet',
11
9
  description: 'BOSS直聘批量向推荐候选人发送招呼',
12
10
  domain: 'www.zhipin.com',
13
11
  strategy: Strategy.COOKIE,
12
+ navigateBefore: false,
14
13
  browser: true,
15
14
  args: [
16
15
  { name: 'job-id', default: '', help: 'Filter by encrypted job ID (greet all jobs if empty)' },
@@ -19,38 +18,13 @@ cli({
19
18
  ],
20
19
  columns: ['name', 'status', 'detail'],
21
20
  func: async (page, kwargs) => {
22
- if (!page)
23
- throw new Error('Browser page required');
21
+ requirePage(page);
24
22
  const filterJobId = kwargs['job-id'] || '';
25
23
  const limit = kwargs.limit || 5;
26
24
  const text = kwargs.text || '你好,请问您对这个职位感兴趣吗?';
27
- if (process.env.OPENCLI_VERBOSE) {
28
- console.error(`[opencli:boss] Batch greeting up to ${limit} candidates...`);
29
- }
30
- await page.goto('https://www.zhipin.com/web/chat/index');
31
- await page.wait({ time: 3 });
32
- // Get recommended candidates
33
- const listData = await page.evaluate(`
34
- async () => {
35
- return new Promise((resolve, reject) => {
36
- const xhr = new XMLHttpRequest();
37
- xhr.open('GET', 'https://www.zhipin.com/wapi/zprelation/friend/greetRecSortList', true);
38
- xhr.withCredentials = true;
39
- xhr.timeout = 15000;
40
- xhr.setRequestHeader('Accept', 'application/json');
41
- xhr.onload = () => { try { resolve(JSON.parse(xhr.responseText)); } catch(e) { reject(e); } };
42
- xhr.onerror = () => reject(new Error('Network Error'));
43
- xhr.send();
44
- });
45
- }
46
- `);
47
- if (listData.code !== 0) {
48
- if (listData.code === 7 || listData.code === 37) {
49
- throw new Error('Cookie 已过期!请在当前 Chrome 浏览器中重新登录 BOSS 直聘。');
50
- }
51
- throw new Error(`获取推荐列表失败: ${listData.message}`);
52
- }
53
- let candidates = listData.zpData?.friendList || [];
25
+ verbose(`Batch greeting up to ${limit} candidates...`);
26
+ await navigateToChat(page, 3);
27
+ let candidates = await fetchRecommendList(page);
54
28
  if (filterJobId) {
55
29
  candidates = candidates.filter((f) => f.encryptJobId === filterJobId);
56
30
  }
@@ -63,78 +37,17 @@ cli({
63
37
  const numericUid = candidate.uid;
64
38
  const friendName = candidate.name || '候选人';
65
39
  try {
66
- // Click on candidate
67
- const clicked = await page.evaluate(`
68
- async () => {
69
- const item = document.querySelector('#_${numericUid}-0') || document.querySelector('[id^="_${numericUid}"]');
70
- if (item) {
71
- item.click();
72
- return { clicked: true };
73
- }
74
- const items = document.querySelectorAll('.geek-item');
75
- for (const el of items) {
76
- if (el.id && el.id.startsWith('_${numericUid}')) {
77
- el.click();
78
- return { clicked: true };
79
- }
80
- }
81
- return { clicked: false };
82
- }
83
- `);
84
- if (!clicked.clicked) {
40
+ const clicked = await clickCandidateInList(page, numericUid);
41
+ if (!clicked) {
85
42
  results.push({ name: friendName, status: '❌ 跳过', detail: '在聊天列表中未找到' });
86
43
  continue;
87
44
  }
88
45
  await page.wait({ time: 2 });
89
- // Type message
90
- const typed = await page.evaluate(`
91
- async () => {
92
- const selectors = [
93
- '.chat-editor [contenteditable="true"]',
94
- '.chat-input [contenteditable="true"]',
95
- '[contenteditable="true"]',
96
- 'textarea',
97
- ];
98
- for (const sel of selectors) {
99
- const el = document.querySelector(sel);
100
- if (el && el.offsetParent !== null) {
101
- el.focus();
102
- if (el.tagName === 'TEXTAREA' || el.tagName === 'INPUT') {
103
- el.value = ${JSON.stringify(text)};
104
- el.dispatchEvent(new Event('input', { bubbles: true }));
105
- } else {
106
- el.textContent = '';
107
- el.focus();
108
- document.execCommand('insertText', false, ${JSON.stringify(text)});
109
- el.dispatchEvent(new Event('input', { bubbles: true }));
110
- }
111
- return { found: true };
112
- }
113
- }
114
- return { found: false };
115
- }
116
- `);
117
- if (!typed.found) {
46
+ const sent = await typeAndSendMessage(page, text);
47
+ if (!sent) {
118
48
  results.push({ name: friendName, status: '❌ 失败', detail: '找不到消息输入框' });
119
49
  continue;
120
50
  }
121
- await page.wait({ time: 0.5 });
122
- // Click send
123
- const sent = await page.evaluate(`
124
- async () => {
125
- const btn = document.querySelector('.conversation-editor .submit')
126
- || document.querySelector('.submit-content .submit')
127
- || document.querySelector('.conversation-operate .submit');
128
- if (btn) {
129
- btn.click();
130
- return { clicked: true };
131
- }
132
- return { clicked: false };
133
- }
134
- `);
135
- if (!sent.clicked) {
136
- await page.pressKey('Enter');
137
- }
138
51
  await page.wait({ time: 1.5 });
139
52
  results.push({ name: friendName, status: '✅ 已发送', detail: text });
140
53
  }
@@ -1,10 +1,12 @@
1
1
  import { cli, Strategy } from '../../registry.js';
2
+ import { requirePage, navigateToChat, fetchFriendList } from './common.js';
2
3
  cli({
3
4
  site: 'boss',
4
5
  name: 'chatlist',
5
6
  description: 'BOSS直聘查看聊天列表(招聘端)',
6
7
  domain: 'www.zhipin.com',
7
8
  strategy: Strategy.COOKIE,
9
+ navigateBefore: false,
8
10
  browser: true,
9
11
  args: [
10
12
  { name: 'page', type: 'int', default: 1, help: 'Page number' },
@@ -13,32 +15,13 @@ cli({
13
15
  ],
14
16
  columns: ['name', 'job', 'last_msg', 'last_time', 'uid', 'security_id'],
15
17
  func: async (page, kwargs) => {
16
- if (!page)
17
- throw new Error('Browser page required');
18
- await page.goto('https://www.zhipin.com/web/chat/index');
19
- await page.wait({ time: 2 });
20
- const jobId = kwargs['job-id'] || '0';
21
- const pageNum = kwargs.page || 1;
22
- const limit = kwargs.limit || 20;
23
- const targetUrl = `https://www.zhipin.com/wapi/zprelation/friend/getBossFriendListV2.json?page=${pageNum}&status=0&jobId=${jobId}`;
24
- const data = await page.evaluate(`
25
- async () => {
26
- return new Promise((resolve, reject) => {
27
- const xhr = new XMLHttpRequest();
28
- xhr.open('GET', '${targetUrl}', true);
29
- xhr.withCredentials = true;
30
- xhr.timeout = 15000;
31
- xhr.setRequestHeader('Accept', 'application/json');
32
- xhr.onload = () => { try { resolve(JSON.parse(xhr.responseText)); } catch(e) { reject(new Error('JSON parse failed')); } };
33
- xhr.onerror = () => reject(new Error('Network Error'));
34
- xhr.send();
18
+ requirePage(page);
19
+ await navigateToChat(page);
20
+ const friends = await fetchFriendList(page, {
21
+ pageNum: kwargs.page || 1,
22
+ jobId: kwargs['job-id'] || '0',
35
23
  });
36
- }
37
- `);
38
- if (data.code !== 0)
39
- throw new Error(`API error: ${data.message} (code=${data.code})`);
40
- const friends = (data.zpData?.friendList || []).slice(0, limit);
41
- return friends.map((f) => ({
24
+ return friends.slice(0, kwargs.limit || 20).map((f) => ({
42
25
  name: f.name || '',
43
26
  job: f.jobName || '',
44
27
  last_msg: f.lastMessageInfo?.text || '',
@@ -1,63 +1,32 @@
1
1
  import { cli, Strategy } from '../../registry.js';
2
+ import { requirePage, navigateToChat, bossFetch, findFriendByUid } from './common.js';
2
3
  cli({
3
4
  site: 'boss',
4
5
  name: 'chatmsg',
5
6
  description: 'BOSS直聘查看与候选人的聊天消息',
6
7
  domain: 'www.zhipin.com',
7
8
  strategy: Strategy.COOKIE,
9
+ navigateBefore: false,
8
10
  browser: true,
9
11
  args: [
10
- { name: 'uid', required: true, help: 'Encrypted UID (from chatlist)' },
12
+ { name: 'uid', required: true, positional: true, help: 'Encrypted UID (from chatlist)' },
11
13
  { name: 'page', type: 'int', default: 1, help: 'Page number' },
12
14
  ],
13
15
  columns: ['from', 'type', 'text', 'time'],
14
16
  func: async (page, kwargs) => {
15
- if (!page)
16
- throw new Error('Browser page required');
17
- await page.goto('https://www.zhipin.com/web/chat/index');
18
- await page.wait({ time: 2 });
19
- const uid = kwargs.uid;
20
- const friendData = await page.evaluate(`
21
- async () => {
22
- return new Promise((resolve, reject) => {
23
- const xhr = new XMLHttpRequest();
24
- xhr.open('GET', 'https://www.zhipin.com/wapi/zprelation/friend/getBossFriendListV2.json?page=1&status=0&jobId=0', true);
25
- xhr.withCredentials = true;
26
- xhr.timeout = 15000;
27
- xhr.setRequestHeader('Accept', 'application/json');
28
- xhr.onload = () => { try { resolve(JSON.parse(xhr.responseText)); } catch(e) { reject(e); } };
29
- xhr.onerror = () => reject(new Error('Network Error'));
30
- xhr.send();
31
- });
32
- }
33
- `);
34
- if (friendData.code !== 0)
35
- throw new Error('获取好友列表失败');
36
- const friend = (friendData.zpData?.friendList || []).find((f) => f.encryptUid === uid);
17
+ requirePage(page);
18
+ await navigateToChat(page);
19
+ const friend = await findFriendByUid(page, kwargs.uid);
37
20
  if (!friend)
38
21
  throw new Error('未找到该候选人');
39
22
  const gid = friend.uid;
40
23
  const securityId = encodeURIComponent(friend.securityId);
41
24
  const msgUrl = `https://www.zhipin.com/wapi/zpchat/boss/historyMsg?gid=${gid}&securityId=${securityId}&page=${kwargs.page}&c=20&src=0`;
42
- const msgData = await page.evaluate(`
43
- async () => {
44
- return new Promise((resolve, reject) => {
45
- const xhr = new XMLHttpRequest();
46
- xhr.open('GET', '${msgUrl}', true);
47
- xhr.withCredentials = true;
48
- xhr.timeout = 15000;
49
- xhr.setRequestHeader('Accept', 'application/json');
50
- xhr.onload = () => { try { resolve(JSON.parse(xhr.responseText)); } catch(e) { resolve({raw: xhr.responseText.substring(0,500)}); } };
51
- xhr.onerror = () => reject(new Error('Network Error'));
52
- xhr.send();
53
- });
54
- }
55
- `);
56
- if (msgData.raw)
57
- throw new Error('Non-JSON: ' + msgData.raw);
58
- if (msgData.code !== 0)
59
- throw new Error('API error: ' + (msgData.message || msgData.code));
60
- const TYPE_MAP = { 1: '文本', 2: '图片', 3: '招呼', 4: '简历', 5: '系统', 6: '名片', 7: '语音', 8: '视频', 9: '表情' };
25
+ const msgData = await bossFetch(page, msgUrl);
26
+ const TYPE_MAP = {
27
+ 1: '文本', 2: '图片', 3: '招呼', 4: '简历', 5: '系统',
28
+ 6: '名片', 7: '语音', 8: '视频', 9: '表情',
29
+ };
61
30
  const messages = msgData.zpData?.messages || msgData.zpData?.historyMsgList || [];
62
31
  return messages.map((m) => {
63
32
  const fromObj = m.from || {};
@@ -0,0 +1,92 @@
1
+ /**
2
+ * BOSS直聘 common utilities — shared logic for all boss adapters.
3
+ *
4
+ * Consolidates:
5
+ * - Page navigation with cookie context
6
+ * - XHR-based API calls (GET/POST) with automatic login state detection
7
+ * - Cookie expiry error codes (code 7, 37)
8
+ * - Verbose logging
9
+ */
10
+ import type { IPage } from '../../types.js';
11
+ export interface BossApiResponse {
12
+ code: number;
13
+ message?: string;
14
+ zpData?: any;
15
+ [key: string]: any;
16
+ }
17
+ export interface FetchOptions {
18
+ /** HTTP method, defaults to 'GET' */
19
+ method?: 'GET' | 'POST';
20
+ /** POST body (will be sent as application/x-www-form-urlencoded) */
21
+ body?: string;
22
+ /** XHR timeout in ms, defaults to 15000 */
23
+ timeout?: number;
24
+ /** If true, don't throw on non-zero code — return the raw response */
25
+ allowNonZero?: boolean;
26
+ }
27
+ /**
28
+ * Assert that page is available (non-null).
29
+ */
30
+ export declare function requirePage(page: IPage | null): asserts page is IPage;
31
+ /**
32
+ * Navigate to BOSS chat page and wait for it to settle.
33
+ * This establishes the cookie context needed for subsequent API calls.
34
+ */
35
+ export declare function navigateToChat(page: IPage, waitSeconds?: number): Promise<void>;
36
+ /**
37
+ * Navigate to a custom BOSS page (for search/detail that use different pages).
38
+ */
39
+ export declare function navigateTo(page: IPage, url: string, waitSeconds?: number): Promise<void>;
40
+ /**
41
+ * Check if an API response indicates cookie expiry and throw a clear error.
42
+ * Call this after every BOSS API response with a non-zero code.
43
+ */
44
+ export declare function checkAuth(data: BossApiResponse): void;
45
+ /**
46
+ * Throw if the API response is not code 0.
47
+ * Checks for cookie expiry first, then throws with the provided message.
48
+ */
49
+ export declare function assertOk(data: BossApiResponse, errorPrefix?: string): void;
50
+ /**
51
+ * Make a credentialed XHR request via page.evaluate().
52
+ *
53
+ * This is the single XHR template — no more copy-pasting the same 15-line
54
+ * XMLHttpRequest boilerplate across every adapter.
55
+ *
56
+ * @returns Parsed JSON response
57
+ * @throws On network error, timeout, JSON parse failure, or cookie expiry
58
+ */
59
+ export declare function bossFetch(page: IPage, url: string, opts?: FetchOptions): Promise<BossApiResponse>;
60
+ /**
61
+ * Fetch the boss friend (chat) list.
62
+ */
63
+ export declare function fetchFriendList(page: IPage, opts?: {
64
+ pageNum?: number;
65
+ jobId?: string;
66
+ }): Promise<any[]>;
67
+ /**
68
+ * Fetch the recommended candidates (greetRecSortList).
69
+ */
70
+ export declare function fetchRecommendList(page: IPage): Promise<any[]>;
71
+ /**
72
+ * Find a friend by encryptUid, searching through friend list and optionally greet list.
73
+ * Returns null if not found.
74
+ */
75
+ export declare function findFriendByUid(page: IPage, encryptUid: string, opts?: {
76
+ maxPages?: number;
77
+ checkGreetList?: boolean;
78
+ }): Promise<any | null>;
79
+ /**
80
+ * Click on a candidate in the chat list by their numeric UID.
81
+ * @returns true if clicked, false if not found
82
+ */
83
+ export declare function clickCandidateInList(page: IPage, numericUid: string | number): Promise<boolean>;
84
+ /**
85
+ * Type a message into the chat editor and send it.
86
+ * @returns true if sent successfully
87
+ */
88
+ export declare function typeAndSendMessage(page: IPage, text: string): Promise<boolean>;
89
+ /**
90
+ * Verbose log helper — prints when OPENCLI_VERBOSE or DEBUG=opencli is set.
91
+ */
92
+ export declare function verbose(msg: string): void;