@jackwener/opencli 1.6.9 → 1.7.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 (531) hide show
  1. package/README.md +128 -59
  2. package/README.zh-CN.md +134 -78
  3. package/dist/clis/_shared/common.d.ts +3 -0
  4. package/dist/clis/_shared/common.js +22 -0
  5. package/dist/clis/bilibili/hot.js +35 -0
  6. package/dist/clis/bluesky/feeds.d.ts +1 -0
  7. package/dist/clis/bluesky/feeds.js +27 -0
  8. package/dist/clis/bluesky/followers.d.ts +1 -0
  9. package/dist/clis/bluesky/followers.js +27 -0
  10. package/dist/clis/bluesky/following.d.ts +1 -0
  11. package/dist/clis/bluesky/following.js +27 -0
  12. package/dist/clis/bluesky/profile.d.ts +1 -0
  13. package/dist/clis/bluesky/profile.js +29 -0
  14. package/dist/clis/bluesky/search.d.ts +1 -0
  15. package/dist/clis/bluesky/search.js +28 -0
  16. package/dist/clis/bluesky/starter-packs.d.ts +1 -0
  17. package/dist/clis/bluesky/starter-packs.js +28 -0
  18. package/dist/clis/bluesky/thread.d.ts +1 -0
  19. package/dist/clis/bluesky/thread.js +30 -0
  20. package/dist/clis/bluesky/trending.d.ts +1 -0
  21. package/dist/clis/bluesky/trending.js +19 -0
  22. package/dist/clis/bluesky/user.d.ts +1 -0
  23. package/dist/clis/bluesky/user.js +33 -0
  24. package/dist/clis/cnki/search.d.ts +1 -0
  25. package/dist/clis/cnki/search.js +60 -0
  26. package/dist/clis/cnki/search.test.d.ts +1 -0
  27. package/dist/clis/cnki/search.test.js +18 -0
  28. package/dist/clis/devto/tag.d.ts +1 -0
  29. package/dist/clis/devto/tag.js +32 -0
  30. package/dist/clis/devto/top.d.ts +1 -0
  31. package/dist/clis/devto/top.js +26 -0
  32. package/dist/clis/devto/user.d.ts +1 -0
  33. package/dist/clis/devto/user.js +31 -0
  34. package/dist/clis/dictionary/examples.d.ts +1 -0
  35. package/dist/clis/dictionary/examples.js +27 -0
  36. package/dist/clis/dictionary/search.d.ts +1 -0
  37. package/dist/clis/dictionary/search.js +29 -0
  38. package/dist/clis/dictionary/synonyms.d.ts +1 -0
  39. package/dist/clis/dictionary/synonyms.js +27 -0
  40. package/dist/clis/douban/subject.d.ts +1 -0
  41. package/dist/clis/douban/subject.js +118 -0
  42. package/dist/clis/douban/top250.d.ts +1 -0
  43. package/dist/clis/douban/top250.js +67 -0
  44. package/dist/clis/facebook/add-friend.d.ts +1 -0
  45. package/dist/clis/facebook/add-friend.js +43 -0
  46. package/dist/clis/facebook/events.d.ts +1 -0
  47. package/dist/clis/facebook/events.js +40 -0
  48. package/dist/clis/facebook/feed.d.ts +1 -0
  49. package/dist/clis/facebook/feed.js +59 -0
  50. package/dist/clis/facebook/friends.d.ts +1 -0
  51. package/dist/clis/facebook/friends.js +38 -0
  52. package/dist/clis/facebook/groups.d.ts +1 -0
  53. package/dist/clis/facebook/groups.js +46 -0
  54. package/dist/clis/facebook/join-group.d.ts +1 -0
  55. package/dist/clis/facebook/join-group.js +44 -0
  56. package/dist/clis/facebook/memories.d.ts +1 -0
  57. package/dist/clis/facebook/memories.js +35 -0
  58. package/dist/clis/facebook/notifications.d.ts +1 -0
  59. package/dist/clis/facebook/notifications.js +36 -0
  60. package/dist/clis/facebook/profile.d.ts +1 -0
  61. package/dist/clis/facebook/profile.js +37 -0
  62. package/dist/clis/facebook/search.d.ts +1 -0
  63. package/dist/clis/facebook/search.js +38 -0
  64. package/dist/clis/facebook/search.test.d.ts +1 -1
  65. package/dist/clis/facebook/search.test.js +6 -9
  66. package/dist/clis/gitee/index.d.ts +3 -0
  67. package/dist/clis/gitee/index.js +3 -0
  68. package/dist/clis/gitee/search.d.ts +1 -0
  69. package/dist/clis/gitee/search.js +136 -0
  70. package/dist/clis/gitee/trending.d.ts +1 -0
  71. package/dist/clis/gitee/trending.js +567 -0
  72. package/dist/clis/gitee/user.d.ts +1 -0
  73. package/dist/clis/gitee/user.js +199 -0
  74. package/dist/clis/gitee/user.test.d.ts +1 -0
  75. package/dist/clis/gitee/user.test.js +63 -0
  76. package/dist/clis/hackernews/ask.d.ts +1 -0
  77. package/dist/clis/hackernews/ask.js +29 -0
  78. package/dist/clis/hackernews/best.d.ts +1 -0
  79. package/dist/clis/hackernews/best.js +29 -0
  80. package/dist/clis/hackernews/jobs.d.ts +1 -0
  81. package/dist/clis/hackernews/jobs.js +27 -0
  82. package/dist/clis/hackernews/new.d.ts +1 -0
  83. package/dist/clis/hackernews/new.js +29 -0
  84. package/dist/clis/hackernews/search.d.ts +1 -0
  85. package/dist/clis/hackernews/search.js +36 -0
  86. package/dist/clis/hackernews/show.d.ts +1 -0
  87. package/dist/clis/hackernews/show.js +29 -0
  88. package/dist/clis/hackernews/top.d.ts +1 -0
  89. package/dist/clis/hackernews/top.js +29 -0
  90. package/dist/clis/hackernews/user.d.ts +1 -0
  91. package/dist/clis/hackernews/user.js +22 -0
  92. package/dist/clis/hupu/hot.d.ts +1 -0
  93. package/dist/clis/hupu/hot.js +40 -0
  94. package/dist/clis/instagram/comment.d.ts +1 -0
  95. package/dist/clis/instagram/comment.js +47 -0
  96. package/dist/clis/instagram/explore.d.ts +1 -0
  97. package/dist/clis/instagram/explore.js +41 -0
  98. package/dist/clis/instagram/follow.d.ts +1 -0
  99. package/dist/clis/instagram/follow.js +43 -0
  100. package/dist/clis/instagram/followers.d.ts +1 -0
  101. package/dist/clis/instagram/followers.js +45 -0
  102. package/dist/clis/instagram/following.d.ts +1 -0
  103. package/dist/clis/instagram/following.js +45 -0
  104. package/dist/clis/instagram/like.d.ts +1 -0
  105. package/dist/clis/instagram/like.js +45 -0
  106. package/dist/clis/instagram/profile.d.ts +1 -0
  107. package/dist/clis/instagram/profile.js +39 -0
  108. package/dist/clis/instagram/save.d.ts +1 -0
  109. package/dist/clis/instagram/save.js +45 -0
  110. package/dist/clis/instagram/saved.d.ts +1 -0
  111. package/dist/clis/instagram/saved.js +38 -0
  112. package/dist/clis/instagram/search.d.ts +1 -0
  113. package/dist/clis/instagram/search.js +38 -0
  114. package/dist/clis/instagram/unfollow.d.ts +1 -0
  115. package/dist/clis/instagram/unfollow.js +40 -0
  116. package/dist/clis/instagram/unlike.d.ts +1 -0
  117. package/dist/clis/instagram/unlike.js +45 -0
  118. package/dist/clis/instagram/unsave.d.ts +1 -0
  119. package/dist/clis/instagram/unsave.js +45 -0
  120. package/dist/clis/instagram/user.d.ts +1 -0
  121. package/dist/clis/instagram/user.js +48 -0
  122. package/dist/clis/jd/add-cart.d.ts +1 -0
  123. package/dist/clis/jd/add-cart.js +71 -0
  124. package/dist/clis/jd/cart.d.ts +1 -0
  125. package/dist/clis/jd/cart.js +79 -0
  126. package/dist/clis/jd/commands.test.d.ts +5 -0
  127. package/dist/clis/jd/commands.test.js +64 -0
  128. package/dist/clis/jd/detail.d.ts +1 -0
  129. package/dist/clis/jd/detail.js +62 -0
  130. package/dist/clis/jd/reviews.d.ts +1 -0
  131. package/dist/clis/jd/reviews.js +54 -0
  132. package/dist/clis/jd/search.d.ts +1 -0
  133. package/dist/clis/jd/search.js +65 -0
  134. package/dist/clis/jianyu/detail.d.ts +1 -0
  135. package/dist/clis/jianyu/detail.js +20 -0
  136. package/dist/clis/jianyu/search.d.ts +41 -4
  137. package/dist/clis/jianyu/search.js +458 -96
  138. package/dist/clis/jianyu/search.test.js +105 -0
  139. package/dist/clis/jianyu/shared/china-bid-search.d.ts +12 -0
  140. package/dist/clis/jianyu/shared/china-bid-search.js +165 -0
  141. package/dist/clis/jianyu/shared/procurement-contract.d.ts +68 -0
  142. package/dist/clis/jianyu/shared/procurement-contract.js +324 -0
  143. package/dist/clis/jianyu/shared/procurement-contract.test.d.ts +1 -0
  144. package/dist/clis/jianyu/shared/procurement-contract.test.js +72 -0
  145. package/dist/clis/jianyu/shared/procurement-detail.d.ts +6 -0
  146. package/dist/clis/jianyu/shared/procurement-detail.js +92 -0
  147. package/dist/clis/jianyu/shared/procurement-detail.test.d.ts +1 -0
  148. package/dist/clis/jianyu/shared/procurement-detail.test.js +72 -0
  149. package/dist/clis/jike/post.d.ts +1 -0
  150. package/dist/clis/jike/post.js +61 -0
  151. package/dist/clis/jike/topic.d.ts +1 -0
  152. package/dist/clis/jike/topic.js +51 -0
  153. package/dist/clis/jike/user.d.ts +1 -0
  154. package/dist/clis/jike/user.js +50 -0
  155. package/dist/clis/jimeng/generate.d.ts +1 -0
  156. package/dist/clis/jimeng/generate.js +83 -0
  157. package/dist/clis/jimeng/history.d.ts +1 -0
  158. package/dist/clis/jimeng/history.js +47 -0
  159. package/dist/clis/jimeng/new.d.ts +1 -0
  160. package/dist/clis/jimeng/new.js +43 -0
  161. package/dist/clis/jimeng/workspaces.d.ts +1 -0
  162. package/dist/clis/jimeng/workspaces.js +41 -0
  163. package/dist/clis/linux-do/categories.d.ts +1 -0
  164. package/dist/clis/linux-do/categories.js +65 -0
  165. package/dist/clis/linux-do/search.d.ts +1 -0
  166. package/dist/clis/linux-do/search.js +41 -0
  167. package/dist/clis/linux-do/tags.d.ts +1 -0
  168. package/dist/clis/linux-do/tags.js +39 -0
  169. package/dist/clis/linux-do/topic-content.test.js +5 -5
  170. package/dist/clis/linux-do/topic.d.ts +1 -0
  171. package/dist/clis/linux-do/topic.js +56 -0
  172. package/dist/clis/linux-do/user-posts.d.ts +1 -0
  173. package/dist/clis/linux-do/user-posts.js +61 -0
  174. package/dist/clis/linux-do/user-topics.d.ts +1 -0
  175. package/dist/clis/linux-do/user-topics.js +48 -0
  176. package/dist/clis/lobsters/active.d.ts +1 -0
  177. package/dist/clis/lobsters/active.js +26 -0
  178. package/dist/clis/lobsters/hot.d.ts +1 -0
  179. package/dist/clis/lobsters/hot.js +26 -0
  180. package/dist/clis/lobsters/newest.d.ts +1 -0
  181. package/dist/clis/lobsters/newest.js +26 -0
  182. package/dist/clis/lobsters/tag.d.ts +1 -0
  183. package/dist/clis/lobsters/tag.js +32 -0
  184. package/dist/clis/pixiv/detail.d.ts +1 -0
  185. package/dist/clis/pixiv/detail.js +58 -0
  186. package/dist/clis/pixiv/ranking.d.ts +1 -0
  187. package/dist/clis/pixiv/ranking.js +59 -0
  188. package/dist/clis/pixiv/user.d.ts +1 -0
  189. package/dist/clis/pixiv/user.js +52 -0
  190. package/dist/clis/reddit/frontpage.d.ts +1 -0
  191. package/dist/clis/reddit/frontpage.js +31 -0
  192. package/dist/clis/reddit/hot.d.ts +1 -0
  193. package/dist/clis/reddit/hot.js +45 -0
  194. package/dist/clis/reddit/popular.d.ts +1 -0
  195. package/dist/clis/reddit/popular.js +41 -0
  196. package/dist/clis/reddit/search.d.ts +1 -0
  197. package/dist/clis/reddit/search.js +65 -0
  198. package/dist/clis/reddit/subreddit.d.ts +1 -0
  199. package/dist/clis/reddit/subreddit.js +52 -0
  200. package/dist/clis/reddit/user-comments.d.ts +1 -0
  201. package/dist/clis/reddit/user-comments.js +44 -0
  202. package/dist/clis/reddit/user-posts.d.ts +1 -0
  203. package/dist/clis/reddit/user-posts.js +42 -0
  204. package/dist/clis/reddit/user.d.ts +1 -0
  205. package/dist/clis/reddit/user.js +37 -0
  206. package/dist/clis/stackoverflow/bounties.d.ts +1 -0
  207. package/dist/clis/stackoverflow/bounties.js +27 -0
  208. package/dist/clis/stackoverflow/hot.d.ts +1 -0
  209. package/dist/clis/stackoverflow/hot.js +24 -0
  210. package/dist/clis/stackoverflow/search.d.ts +1 -0
  211. package/dist/clis/stackoverflow/search.js +27 -0
  212. package/dist/clis/stackoverflow/unanswered.d.ts +1 -0
  213. package/dist/clis/stackoverflow/unanswered.js +26 -0
  214. package/dist/clis/steam/top-sellers.d.ts +1 -0
  215. package/dist/clis/steam/top-sellers.js +25 -0
  216. package/dist/clis/taobao/add-cart.d.ts +1 -0
  217. package/dist/clis/taobao/add-cart.js +149 -0
  218. package/dist/clis/taobao/cart.d.ts +1 -0
  219. package/dist/clis/taobao/cart.js +95 -0
  220. package/dist/clis/taobao/commands.test.d.ts +5 -0
  221. package/dist/clis/taobao/commands.test.js +64 -0
  222. package/dist/clis/taobao/detail.d.ts +1 -0
  223. package/dist/clis/taobao/detail.js +70 -0
  224. package/dist/clis/taobao/reviews.d.ts +1 -0
  225. package/dist/clis/taobao/reviews.js +76 -0
  226. package/dist/clis/taobao/search.d.ts +1 -0
  227. package/dist/clis/taobao/search.js +96 -0
  228. package/dist/clis/tiktok/comment.d.ts +1 -0
  229. package/dist/clis/tiktok/comment.js +57 -0
  230. package/dist/clis/tiktok/explore.d.ts +1 -0
  231. package/dist/clis/tiktok/explore.js +35 -0
  232. package/dist/clis/tiktok/follow.d.ts +1 -0
  233. package/dist/clis/tiktok/follow.js +39 -0
  234. package/dist/clis/tiktok/following.d.ts +1 -0
  235. package/dist/clis/tiktok/following.js +42 -0
  236. package/dist/clis/tiktok/friends.d.ts +1 -0
  237. package/dist/clis/tiktok/friends.js +43 -0
  238. package/dist/clis/tiktok/like.d.ts +1 -0
  239. package/dist/clis/tiktok/like.js +33 -0
  240. package/dist/clis/tiktok/live.d.ts +1 -0
  241. package/dist/clis/tiktok/live.js +47 -0
  242. package/dist/clis/tiktok/notifications.d.ts +1 -0
  243. package/dist/clis/tiktok/notifications.js +49 -0
  244. package/dist/clis/tiktok/profile.d.ts +1 -0
  245. package/dist/clis/tiktok/profile.js +54 -0
  246. package/dist/clis/tiktok/save.d.ts +1 -0
  247. package/dist/clis/tiktok/save.js +29 -0
  248. package/dist/clis/tiktok/search.d.ts +1 -0
  249. package/dist/clis/tiktok/search.js +39 -0
  250. package/dist/clis/tiktok/unfollow.d.ts +1 -0
  251. package/dist/clis/tiktok/unfollow.js +44 -0
  252. package/dist/clis/tiktok/unlike.d.ts +1 -0
  253. package/dist/clis/tiktok/unlike.js +33 -0
  254. package/dist/clis/tiktok/unsave.d.ts +1 -0
  255. package/dist/clis/tiktok/unsave.js +31 -0
  256. package/dist/clis/tiktok/user.d.ts +1 -0
  257. package/dist/clis/tiktok/user.js +41 -0
  258. package/dist/clis/v2ex/hot.d.ts +1 -0
  259. package/dist/clis/v2ex/hot.js +25 -0
  260. package/dist/clis/v2ex/latest.d.ts +1 -0
  261. package/dist/clis/v2ex/latest.js +25 -0
  262. package/dist/clis/v2ex/member.d.ts +1 -0
  263. package/dist/clis/v2ex/member.js +27 -0
  264. package/dist/clis/v2ex/node.d.ts +1 -0
  265. package/dist/clis/v2ex/node.js +38 -0
  266. package/dist/clis/v2ex/nodes.d.ts +1 -0
  267. package/dist/clis/v2ex/nodes.js +25 -0
  268. package/dist/clis/v2ex/replies.d.ts +1 -0
  269. package/dist/clis/v2ex/replies.js +26 -0
  270. package/dist/clis/v2ex/topic.d.ts +1 -0
  271. package/dist/clis/v2ex/topic.js +30 -0
  272. package/dist/clis/v2ex/user.d.ts +1 -0
  273. package/dist/clis/v2ex/user.js +33 -0
  274. package/dist/clis/xiaoe/catalog.d.ts +1 -0
  275. package/dist/clis/xiaoe/catalog.js +161 -0
  276. package/dist/clis/xiaoe/content.d.ts +1 -0
  277. package/dist/clis/xiaoe/content.js +39 -0
  278. package/dist/clis/xiaoe/courses.d.ts +1 -0
  279. package/dist/clis/xiaoe/courses.js +69 -0
  280. package/dist/clis/xiaoe/detail.d.ts +1 -0
  281. package/dist/clis/xiaoe/detail.js +35 -0
  282. package/dist/clis/xiaoe/play-url.d.ts +1 -0
  283. package/dist/clis/xiaoe/play-url.js +120 -0
  284. package/dist/clis/xiaohongshu/feed.d.ts +1 -0
  285. package/dist/clis/xiaohongshu/feed.js +32 -0
  286. package/dist/clis/xiaohongshu/notifications.d.ts +1 -0
  287. package/dist/clis/xiaohongshu/notifications.js +38 -0
  288. package/dist/clis/xueqiu/earnings-date.d.ts +1 -0
  289. package/dist/clis/xueqiu/earnings-date.js +61 -0
  290. package/dist/clis/xueqiu/feed.d.ts +1 -0
  291. package/dist/clis/xueqiu/feed.js +48 -0
  292. package/dist/clis/xueqiu/groups.d.ts +1 -0
  293. package/dist/clis/xueqiu/groups.js +25 -0
  294. package/dist/clis/xueqiu/hot-stock.d.ts +1 -0
  295. package/dist/clis/xueqiu/hot-stock.js +44 -0
  296. package/dist/clis/xueqiu/hot.d.ts +1 -0
  297. package/dist/clis/xueqiu/hot.js +44 -0
  298. package/dist/clis/xueqiu/kline.d.ts +1 -0
  299. package/dist/clis/xueqiu/kline.js +64 -0
  300. package/dist/clis/xueqiu/search.d.ts +1 -0
  301. package/dist/clis/xueqiu/search.js +49 -0
  302. package/dist/clis/xueqiu/stock.d.ts +1 -0
  303. package/dist/clis/xueqiu/stock.js +72 -0
  304. package/dist/clis/xueqiu/watchlist.d.ts +1 -0
  305. package/dist/clis/xueqiu/watchlist.js +45 -0
  306. package/dist/clis/zhihu/hot.d.ts +1 -0
  307. package/dist/clis/zhihu/hot.js +43 -0
  308. package/dist/clis/zhihu/search.d.ts +1 -0
  309. package/dist/clis/zhihu/search.js +52 -0
  310. package/dist/src/browser/bridge.js +1 -1
  311. package/dist/src/browser/daemon-client.d.ts +16 -4
  312. package/dist/src/browser/daemon-client.js +33 -15
  313. package/dist/src/browser/daemon-client.test.js +0 -3
  314. package/dist/src/browser/dom-helpers.test.js +3 -2
  315. package/dist/src/browser/errors.d.ts +26 -1
  316. package/dist/src/browser/errors.js +40 -7
  317. package/dist/src/browser/errors.test.d.ts +1 -0
  318. package/dist/src/browser/errors.test.js +51 -0
  319. package/dist/src/browser/page.d.ts +9 -8
  320. package/dist/src/browser/page.js +33 -31
  321. package/dist/src/browser.test.js +25 -6
  322. package/dist/src/build-manifest.d.ts +5 -11
  323. package/dist/src/build-manifest.js +6 -75
  324. package/dist/src/build-manifest.test.js +1 -39
  325. package/dist/src/cascade.js +3 -2
  326. package/dist/src/cli.d.ts +3 -3
  327. package/dist/src/cli.js +71 -71
  328. package/dist/src/cli.test.js +20 -15
  329. package/dist/src/clis/binance/asks.d.ts +1 -0
  330. package/dist/src/clis/binance/asks.js +20 -0
  331. package/dist/src/clis/binance/commands.test.d.ts +3 -1
  332. package/dist/src/clis/binance/commands.test.js +10 -6
  333. package/dist/src/clis/binance/depth.d.ts +1 -0
  334. package/dist/src/clis/binance/depth.js +20 -0
  335. package/dist/src/clis/binance/gainers.d.ts +1 -0
  336. package/dist/src/clis/binance/gainers.js +21 -0
  337. package/dist/src/clis/binance/klines.d.ts +1 -0
  338. package/dist/src/clis/binance/klines.js +20 -0
  339. package/dist/src/clis/binance/losers.d.ts +1 -0
  340. package/dist/src/clis/binance/losers.js +21 -0
  341. package/dist/src/clis/binance/pairs.d.ts +1 -0
  342. package/dist/src/clis/binance/pairs.js +20 -0
  343. package/dist/src/clis/binance/price.d.ts +1 -0
  344. package/dist/src/clis/binance/price.js +17 -0
  345. package/dist/src/clis/binance/prices.d.ts +1 -0
  346. package/dist/src/clis/binance/prices.js +18 -0
  347. package/dist/src/clis/binance/ticker.d.ts +1 -0
  348. package/dist/src/clis/binance/ticker.js +20 -0
  349. package/dist/src/clis/binance/top.d.ts +1 -0
  350. package/dist/src/clis/binance/top.js +20 -0
  351. package/dist/src/clis/binance/trades.d.ts +1 -0
  352. package/dist/src/clis/binance/trades.js +19 -0
  353. package/dist/src/commands/daemon.d.ts +2 -6
  354. package/dist/src/commands/daemon.js +2 -58
  355. package/dist/src/commands/daemon.test.js +24 -120
  356. package/dist/src/completion-fast.d.ts +25 -0
  357. package/dist/src/completion-fast.js +140 -0
  358. package/dist/src/completion.d.ts +1 -0
  359. package/dist/src/completion.js +1 -0
  360. package/dist/src/constants.d.ts +0 -2
  361. package/dist/src/constants.js +0 -2
  362. package/dist/src/daemon.d.ts +1 -1
  363. package/dist/src/daemon.js +2 -15
  364. package/dist/src/diagnostic.test.js +2 -2
  365. package/dist/src/discovery.d.ts +3 -3
  366. package/dist/src/discovery.js +34 -97
  367. package/dist/src/download/index.d.ts +1 -1
  368. package/dist/src/engine.test.js +4 -19
  369. package/dist/src/execution.js +5 -1
  370. package/dist/src/generate-verified.d.ts +105 -0
  371. package/dist/src/generate-verified.js +696 -0
  372. package/dist/src/generate-verified.test.d.ts +1 -0
  373. package/dist/src/generate-verified.test.js +925 -0
  374. package/dist/src/generate.d.ts +9 -1
  375. package/dist/src/generate.js +2 -2
  376. package/dist/src/main.js +65 -12
  377. package/dist/src/pipeline/steps/download.d.ts +1 -17
  378. package/dist/src/pipeline/steps/download.js +20 -31
  379. package/dist/src/pipeline/steps/intercept.d.ts +1 -1
  380. package/dist/src/pipeline/steps/intercept.js +1 -1
  381. package/dist/src/pipeline/steps/tap.d.ts +1 -1
  382. package/dist/src/pipeline/steps/tap.js +1 -1
  383. package/dist/src/plugin-scaffold.d.ts +2 -2
  384. package/dist/src/plugin-scaffold.js +24 -21
  385. package/dist/src/plugin-scaffold.test.js +1 -1
  386. package/dist/src/plugin.d.ts +1 -1
  387. package/dist/src/plugin.js +4 -6
  388. package/dist/src/plugin.test.js +31 -31
  389. package/dist/src/record.js +26 -25
  390. package/dist/src/runtime-detect.js +3 -7
  391. package/dist/src/scripts/framework.d.ts +3 -0
  392. package/dist/src/scripts/framework.js +8 -4
  393. package/dist/src/scripts/store.d.ts +5 -1
  394. package/dist/src/scripts/store.js +5 -1
  395. package/dist/src/skill-generate.d.ts +30 -0
  396. package/dist/src/skill-generate.js +75 -0
  397. package/dist/src/skill-generate.test.d.ts +1 -0
  398. package/dist/src/skill-generate.test.js +173 -0
  399. package/dist/src/synthesize.d.ts +1 -1
  400. package/dist/src/synthesize.js +7 -8
  401. package/dist/src/types.d.ts +3 -1
  402. package/package.json +4 -3
  403. package/dist/clis/bilibili/hot.yaml +0 -38
  404. package/dist/clis/bluesky/feeds.yaml +0 -29
  405. package/dist/clis/bluesky/followers.yaml +0 -33
  406. package/dist/clis/bluesky/following.yaml +0 -33
  407. package/dist/clis/bluesky/profile.yaml +0 -27
  408. package/dist/clis/bluesky/search.yaml +0 -34
  409. package/dist/clis/bluesky/starter-packs.yaml +0 -34
  410. package/dist/clis/bluesky/thread.yaml +0 -32
  411. package/dist/clis/bluesky/trending.yaml +0 -27
  412. package/dist/clis/bluesky/user.yaml +0 -34
  413. package/dist/clis/devto/tag.yaml +0 -34
  414. package/dist/clis/devto/top.yaml +0 -29
  415. package/dist/clis/devto/user.yaml +0 -33
  416. package/dist/clis/dictionary/examples.yaml +0 -25
  417. package/dist/clis/dictionary/search.yaml +0 -27
  418. package/dist/clis/dictionary/synonyms.yaml +0 -25
  419. package/dist/clis/douban/subject.yaml +0 -107
  420. package/dist/clis/douban/top250.yaml +0 -70
  421. package/dist/clis/facebook/add-friend.yaml +0 -43
  422. package/dist/clis/facebook/events.yaml +0 -44
  423. package/dist/clis/facebook/feed.yaml +0 -63
  424. package/dist/clis/facebook/friends.yaml +0 -42
  425. package/dist/clis/facebook/groups.yaml +0 -50
  426. package/dist/clis/facebook/join-group.yaml +0 -44
  427. package/dist/clis/facebook/memories.yaml +0 -39
  428. package/dist/clis/facebook/notifications.yaml +0 -40
  429. package/dist/clis/facebook/profile.yaml +0 -37
  430. package/dist/clis/facebook/search.yaml +0 -47
  431. package/dist/clis/hackernews/ask.yaml +0 -38
  432. package/dist/clis/hackernews/best.yaml +0 -38
  433. package/dist/clis/hackernews/jobs.yaml +0 -36
  434. package/dist/clis/hackernews/new.yaml +0 -38
  435. package/dist/clis/hackernews/search.yaml +0 -44
  436. package/dist/clis/hackernews/show.yaml +0 -38
  437. package/dist/clis/hackernews/top.yaml +0 -38
  438. package/dist/clis/hackernews/user.yaml +0 -25
  439. package/dist/clis/hupu/hot.yaml +0 -43
  440. package/dist/clis/instagram/comment.yaml +0 -52
  441. package/dist/clis/instagram/explore.yaml +0 -43
  442. package/dist/clis/instagram/follow.yaml +0 -41
  443. package/dist/clis/instagram/followers.yaml +0 -51
  444. package/dist/clis/instagram/following.yaml +0 -51
  445. package/dist/clis/instagram/like.yaml +0 -46
  446. package/dist/clis/instagram/profile.yaml +0 -42
  447. package/dist/clis/instagram/save.yaml +0 -46
  448. package/dist/clis/instagram/saved.yaml +0 -40
  449. package/dist/clis/instagram/search.yaml +0 -44
  450. package/dist/clis/instagram/unfollow.yaml +0 -38
  451. package/dist/clis/instagram/unlike.yaml +0 -46
  452. package/dist/clis/instagram/unsave.yaml +0 -46
  453. package/dist/clis/instagram/user.yaml +0 -54
  454. package/dist/clis/jike/post.yaml +0 -59
  455. package/dist/clis/jike/topic.yaml +0 -53
  456. package/dist/clis/jike/user.yaml +0 -52
  457. package/dist/clis/jimeng/generate.yaml +0 -85
  458. package/dist/clis/jimeng/history.yaml +0 -46
  459. package/dist/clis/linux-do/categories.yaml +0 -70
  460. package/dist/clis/linux-do/search.yaml +0 -48
  461. package/dist/clis/linux-do/tags.yaml +0 -41
  462. package/dist/clis/linux-do/topic.yaml +0 -62
  463. package/dist/clis/linux-do/user-posts.yaml +0 -67
  464. package/dist/clis/linux-do/user-topics.yaml +0 -54
  465. package/dist/clis/lobsters/active.yaml +0 -29
  466. package/dist/clis/lobsters/hot.yaml +0 -29
  467. package/dist/clis/lobsters/newest.yaml +0 -29
  468. package/dist/clis/lobsters/tag.yaml +0 -34
  469. package/dist/clis/pixiv/detail.yaml +0 -49
  470. package/dist/clis/pixiv/ranking.yaml +0 -53
  471. package/dist/clis/pixiv/user.yaml +0 -46
  472. package/dist/clis/reddit/frontpage.yaml +0 -30
  473. package/dist/clis/reddit/hot.yaml +0 -47
  474. package/dist/clis/reddit/popular.yaml +0 -40
  475. package/dist/clis/reddit/search.yaml +0 -61
  476. package/dist/clis/reddit/subreddit.yaml +0 -50
  477. package/dist/clis/reddit/user-comments.yaml +0 -46
  478. package/dist/clis/reddit/user-posts.yaml +0 -44
  479. package/dist/clis/reddit/user.yaml +0 -40
  480. package/dist/clis/stackoverflow/bounties.yaml +0 -29
  481. package/dist/clis/stackoverflow/hot.yaml +0 -28
  482. package/dist/clis/stackoverflow/search.yaml +0 -33
  483. package/dist/clis/stackoverflow/unanswered.yaml +0 -28
  484. package/dist/clis/steam/top-sellers.yaml +0 -29
  485. package/dist/clis/tiktok/comment.yaml +0 -66
  486. package/dist/clis/tiktok/explore.yaml +0 -39
  487. package/dist/clis/tiktok/follow.yaml +0 -39
  488. package/dist/clis/tiktok/following.yaml +0 -46
  489. package/dist/clis/tiktok/friends.yaml +0 -47
  490. package/dist/clis/tiktok/like.yaml +0 -38
  491. package/dist/clis/tiktok/live.yaml +0 -51
  492. package/dist/clis/tiktok/notifications.yaml +0 -52
  493. package/dist/clis/tiktok/profile.yaml +0 -45
  494. package/dist/clis/tiktok/save.yaml +0 -34
  495. package/dist/clis/tiktok/search.yaml +0 -47
  496. package/dist/clis/tiktok/unfollow.yaml +0 -44
  497. package/dist/clis/tiktok/unlike.yaml +0 -38
  498. package/dist/clis/tiktok/unsave.yaml +0 -36
  499. package/dist/clis/tiktok/user.yaml +0 -44
  500. package/dist/clis/v2ex/hot.yaml +0 -28
  501. package/dist/clis/v2ex/latest.yaml +0 -28
  502. package/dist/clis/v2ex/member.yaml +0 -29
  503. package/dist/clis/v2ex/node.yaml +0 -34
  504. package/dist/clis/v2ex/nodes.yaml +0 -31
  505. package/dist/clis/v2ex/replies.yaml +0 -32
  506. package/dist/clis/v2ex/topic.yaml +0 -33
  507. package/dist/clis/v2ex/user.yaml +0 -34
  508. package/dist/clis/xiaoe/catalog.yaml +0 -129
  509. package/dist/clis/xiaoe/content.yaml +0 -43
  510. package/dist/clis/xiaoe/courses.yaml +0 -73
  511. package/dist/clis/xiaoe/detail.yaml +0 -39
  512. package/dist/clis/xiaoe/play-url.yaml +0 -124
  513. package/dist/clis/xiaohongshu/feed.yaml +0 -31
  514. package/dist/clis/xiaohongshu/notifications.yaml +0 -37
  515. package/dist/clis/xueqiu/earnings-date.yaml +0 -69
  516. package/dist/clis/xueqiu/feed.yaml +0 -53
  517. package/dist/clis/xueqiu/groups.yaml +0 -23
  518. package/dist/clis/xueqiu/hot-stock.yaml +0 -49
  519. package/dist/clis/xueqiu/hot.yaml +0 -46
  520. package/dist/clis/xueqiu/kline.yaml +0 -65
  521. package/dist/clis/xueqiu/search.yaml +0 -55
  522. package/dist/clis/xueqiu/stock.yaml +0 -69
  523. package/dist/clis/xueqiu/watchlist.yaml +0 -46
  524. package/dist/clis/zhihu/hot.yaml +0 -46
  525. package/dist/clis/zhihu/search.yaml +0 -59
  526. package/dist/src/daemon.test.js +0 -65
  527. package/dist/src/idle-manager.d.ts +0 -19
  528. package/dist/src/idle-manager.js +0 -54
  529. package/dist/src/yaml-schema.d.ts +0 -29
  530. package/dist/src/yaml-schema.js +0 -22
  531. /package/dist/{src/daemon.test.d.ts → clis/bilibili/hot.d.ts} +0 -0
@@ -3,10 +3,39 @@
3
3
  */
4
4
  import { cli, Strategy } from '@jackwener/opencli/registry';
5
5
  import { AuthRequiredError } from '@jackwener/opencli/errors';
6
+ import { buildSearchCandidates, cleanText, dedupeCandidates, detectAuthPrompt, normalizeDate, searchRowsFromEntries, } from './shared/china-bid-search.js';
7
+ import { toProcurementSearchRecords } from './shared/procurement-contract.js';
8
+ const SITE = 'jianyu';
9
+ const DOMAIN = 'www.jianyu360.cn';
6
10
  const SEARCH_ENTRY = 'https://www.jianyu360.cn/jylab/supsearch/index.html';
7
- function cleanText(value) {
8
- return typeof value === 'string' ? value.replace(/\s+/g, ' ').trim() : '';
9
- }
11
+ const SEARCH_ENTRIES = [
12
+ SEARCH_ENTRY,
13
+ 'https://www.jianyu360.cn/list/stype/ZBGG.html',
14
+ 'https://www.jianyu360.cn/',
15
+ ];
16
+ const SEARCH_INDEX_PROXY = 'https://r.jina.ai/http://duckduckgo.com/html/?q=';
17
+ const PROCUREMENT_TITLE_HINT = /(公告|招标|采购|中标|成交|项目|投标|结果|notice|tender|procurement|bidding)/i;
18
+ const AUTH_REQUIRED_HINT = /(请在下图依次点击|登录即可获得更多浏览权限|验证登录|请完成验证|图形验证码)/;
19
+ const NAVIGATION_PATH_PREFIXES = [
20
+ '/product/',
21
+ '/front/',
22
+ '/helpcenter/',
23
+ '/brand/',
24
+ '/page_workdesktop/',
25
+ '/list/',
26
+ '/list/stype/',
27
+ '/list/rmxm',
28
+ '/big/page/',
29
+ '/jylab/',
30
+ '/tags/',
31
+ '/sitemap',
32
+ '/datasmt/',
33
+ '/bank/',
34
+ '/hj/',
35
+ '/exhibition/',
36
+ '/swordfish/page_big_pc/search/',
37
+ ];
38
+ const JIANYU_API_TYPES = ['fType', 'eType', 'vType', 'mType'];
10
39
  export function buildSearchUrl(query) {
11
40
  const url = new URL(SEARCH_ENTRY);
12
41
  url.searchParams.set('keywords', query.trim());
@@ -14,122 +43,455 @@ export function buildSearchUrl(query) {
14
43
  url.searchParams.set('searchGroup', '1');
15
44
  return url.toString();
16
45
  }
17
- export function normalizeDate(raw) {
18
- const normalized = cleanText(raw);
19
- const match = normalized.match(/(20\d{2})[.\-/年](\d{1,2})[.\-/月](\d{1,2})/);
20
- if (!match)
46
+ function siteSearchCandidates(query) {
47
+ const preferred = buildSearchUrl(query);
48
+ const fallbacks = buildSearchCandidates(query, SEARCH_ENTRIES, ['keywords', 'keyword', 'q', 'search', 'title']);
49
+ const ordered = [];
50
+ const seen = new Set();
51
+ for (const candidate of [preferred, ...fallbacks]) {
52
+ const value = cleanText(candidate);
53
+ if (!value || seen.has(value))
54
+ continue;
55
+ seen.add(value);
56
+ ordered.push(value);
57
+ }
58
+ return ordered;
59
+ }
60
+ function isLikelyNavigationUrl(rawUrl) {
61
+ const urlText = cleanText(rawUrl);
62
+ if (!urlText)
63
+ return true;
64
+ try {
65
+ const parsed = new URL(urlText);
66
+ const path = cleanText(parsed.pathname).toLowerCase().replace(/\/+$/, '/') || '/';
67
+ if (path === '/')
68
+ return true;
69
+ if (NAVIGATION_PATH_PREFIXES.some((prefix) => path.startsWith(prefix)))
70
+ return true;
71
+ return false;
72
+ }
73
+ catch {
74
+ return true;
75
+ }
76
+ }
77
+ function filterNavigationRows(query, items) {
78
+ const queryTokens = cleanText(query).split(/\s+/).filter(Boolean).map((token) => token.toLowerCase());
79
+ return items
80
+ .map((item) => ({
81
+ title: cleanText(item.title),
82
+ url: cleanText(item.url),
83
+ date: normalizeDate(cleanText(item.date)),
84
+ contextText: cleanText(item.contextText),
85
+ }))
86
+ .filter((item) => {
87
+ if (!item.title || !item.url)
88
+ return false;
89
+ const haystack = `${item.title} ${item.contextText}`.toLowerCase();
90
+ const hasQuery = queryTokens.length === 0 || queryTokens.some((token) => haystack.includes(token));
91
+ const hasProcurementHint = PROCUREMENT_TITLE_HINT.test(`${item.title} ${item.contextText}`);
92
+ const hasDate = !!item.date;
93
+ if (!hasQuery)
94
+ return false;
95
+ if (!isLikelyNavigationUrl(item.url))
96
+ return true;
97
+ return hasDate && hasProcurementHint;
98
+ });
99
+ }
100
+ async function isAuthRequired(page) {
101
+ const pageText = cleanText(await page.evaluate('document.body ? document.body.innerText : ""'));
102
+ if (AUTH_REQUIRED_HINT.test(pageText))
103
+ return true;
104
+ return detectAuthPrompt(page);
105
+ }
106
+ function toAbsoluteJianyuUrl(rawUrl) {
107
+ const value = cleanText(rawUrl);
108
+ if (!value)
109
+ return '';
110
+ if (value.startsWith('http://') || value.startsWith('https://'))
111
+ return value;
112
+ if (value.startsWith('//'))
113
+ return `https:${value}`;
114
+ if (value.startsWith('/')) {
115
+ try {
116
+ return new URL(value, SEARCH_ENTRY).toString();
117
+ }
118
+ catch {
119
+ return '';
120
+ }
121
+ }
122
+ return '';
123
+ }
124
+ function extractDateFromJianyuUrl(rawUrl) {
125
+ const value = cleanText(rawUrl);
126
+ if (!value)
127
+ return '';
128
+ const matched = value.match(/\/(20\d{2})(\d{2})(\d{2})(?:[_/]|$)/);
129
+ if (!matched)
130
+ return '';
131
+ return `${matched[1]}-${matched[2]}-${matched[3]}`;
132
+ }
133
+ function flattenStrings(input, depth = 0) {
134
+ if (depth > 2 || input == null)
135
+ return [];
136
+ if (typeof input === 'string' || typeof input === 'number') {
137
+ const text = cleanText(String(input));
138
+ return text ? [text] : [];
139
+ }
140
+ if (Array.isArray(input)) {
141
+ return input.flatMap((item) => flattenStrings(item, depth + 1));
142
+ }
143
+ if (typeof input === 'object') {
144
+ return Object.values(input).flatMap((item) => flattenStrings(item, depth + 1));
145
+ }
146
+ return [];
147
+ }
148
+ function pickString(record, keys) {
149
+ for (const key of keys) {
150
+ const value = record[key];
151
+ if (typeof value === 'string' || typeof value === 'number') {
152
+ const text = cleanText(String(value));
153
+ if (text)
154
+ return text;
155
+ }
156
+ }
157
+ return '';
158
+ }
159
+ function normalizeApiRow(item) {
160
+ if (!item || typeof item !== 'object')
161
+ return null;
162
+ const record = item;
163
+ const allStrings = flattenStrings(record);
164
+ let url = toAbsoluteJianyuUrl(pickString(record, [
165
+ 'url',
166
+ 'detailUrl',
167
+ 'detailURL',
168
+ 'link',
169
+ 'href',
170
+ 'articleUrl',
171
+ 'newsUrl',
172
+ 'contentUrl',
173
+ 'jumpUrl',
174
+ 'sourceUrl',
175
+ ]));
176
+ if (!url) {
177
+ const maybeUrl = allStrings.find((value) => /jianyu360\.cn|\/jybx\/|\/nologin\/content\//i.test(value)) || '';
178
+ url = toAbsoluteJianyuUrl(maybeUrl);
179
+ }
180
+ let title = cleanText(pickString(record, [
181
+ 'title',
182
+ 'noticeTitle',
183
+ 'bidTitle',
184
+ 'projectName',
185
+ 'name',
186
+ 'articleTitle',
187
+ 'newsTitle',
188
+ 'tenderTitle',
189
+ 'contentTitle',
190
+ ]));
191
+ if (!title) {
192
+ title = allStrings.find((value) => value.length >= 8 && PROCUREMENT_TITLE_HINT.test(value)) || '';
193
+ }
194
+ const date = normalizeDate(pickString(record, [
195
+ 'publishTime',
196
+ 'publishDate',
197
+ 'pubDate',
198
+ 'createTime',
199
+ 'time',
200
+ 'releaseTime',
201
+ 'date',
202
+ ])) || extractDateFromJianyuUrl(url);
203
+ const contextText = cleanText([
204
+ pickString(record, ['content', 'summary', 'desc', 'description', 'buyer', 'winner', 'agency', 'industry']),
205
+ ...allStrings.slice(0, 6),
206
+ ].filter(Boolean).join(' '));
207
+ if (!title || !url)
208
+ return null;
209
+ return {
210
+ title,
211
+ url,
212
+ date,
213
+ contextText,
214
+ };
215
+ }
216
+ function parseSearchIndexMarkdown(markdown) {
217
+ const rows = [];
218
+ for (const line of markdown.split('\n')) {
219
+ const text = line.trim();
220
+ if (!text.startsWith('## ['))
221
+ continue;
222
+ const right = text.slice(3);
223
+ const sep = right.lastIndexOf('](');
224
+ if (sep <= 0 || !right.endsWith(')'))
225
+ continue;
226
+ const title = cleanText(right.slice(1, sep));
227
+ const url = cleanText(right.slice(sep + 2, -1));
228
+ if (!title || !url)
229
+ continue;
230
+ rows.push({ title, url });
231
+ }
232
+ return rows;
233
+ }
234
+ function unwrapDuckDuckGoUrl(rawUrl) {
235
+ const candidate = cleanText(rawUrl);
236
+ if (!candidate)
237
+ return '';
238
+ const normalized = candidate.startsWith('//') ? `https:${candidate}` : candidate;
239
+ try {
240
+ const parsed = new URL(normalized);
241
+ const host = parsed.hostname.toLowerCase();
242
+ if (!host.endsWith('duckduckgo.com'))
243
+ return normalized;
244
+ const uddg = parsed.searchParams.get('uddg');
245
+ if (!uddg)
246
+ return normalized;
247
+ try {
248
+ return decodeURIComponent(uddg);
249
+ }
250
+ catch {
251
+ return uddg;
252
+ }
253
+ }
254
+ catch {
21
255
  return '';
22
- const year = match[1];
23
- const month = match[2].padStart(2, '0');
24
- const day = match[3].padStart(2, '0');
25
- return `${year}-${month}-${day}`;
256
+ }
26
257
  }
27
- function dedupeCandidates(items) {
28
- const deduped = [];
258
+ function isJianyuHost(rawUrl) {
259
+ const value = cleanText(rawUrl);
260
+ if (!value)
261
+ return false;
262
+ try {
263
+ return new URL(value).hostname.toLowerCase().endsWith('jianyu360.cn');
264
+ }
265
+ catch {
266
+ return false;
267
+ }
268
+ }
269
+ function buildIndexQueryVariants(query) {
270
+ const tokens = cleanText(query).split(/\s+/).filter(Boolean);
271
+ const values = [cleanText(query), ...tokens];
272
+ const ordered = [];
29
273
  const seen = new Set();
30
- for (const item of items) {
31
- const key = `${item.title}\t${item.url}`;
32
- if (seen.has(key))
274
+ for (const value of values) {
275
+ const text = cleanText(value);
276
+ if (!text || seen.has(text))
33
277
  continue;
34
- seen.add(key);
35
- deduped.push(item);
278
+ seen.add(text);
279
+ ordered.push(text);
36
280
  }
37
- return deduped;
281
+ return ordered;
282
+ }
283
+ async function fetchDuckDuckGoIndexRows(query, limit) {
284
+ const results = [];
285
+ const seen = new Set();
286
+ for (const variant of buildIndexQueryVariants(query)) {
287
+ if (results.length >= limit)
288
+ break;
289
+ const fullQuery = `site:jianyu360.cn ${variant}`;
290
+ const url = `${SEARCH_INDEX_PROXY}${encodeURIComponent(fullQuery)}`;
291
+ let responseText = '';
292
+ try {
293
+ const response = await fetch(url, {
294
+ headers: {
295
+ Accept: 'text/plain, text/markdown, */*',
296
+ 'User-Agent': 'opencli-jianyu-search/1.0',
297
+ },
298
+ });
299
+ if (!response.ok)
300
+ continue;
301
+ responseText = await response.text();
302
+ }
303
+ catch {
304
+ continue;
305
+ }
306
+ const indexedRows = parseSearchIndexMarkdown(responseText);
307
+ for (const row of indexedRows) {
308
+ const unwrapped = unwrapDuckDuckGoUrl(row.url);
309
+ const absoluteUrl = toAbsoluteJianyuUrl(unwrapped) || cleanText(unwrapped);
310
+ if (!isJianyuHost(absoluteUrl))
311
+ continue;
312
+ const key = `${row.title}\t${absoluteUrl}`;
313
+ if (seen.has(key))
314
+ continue;
315
+ seen.add(key);
316
+ results.push({
317
+ title: cleanText(row.title),
318
+ url: absoluteUrl,
319
+ date: extractDateFromJianyuUrl(absoluteUrl),
320
+ contextText: cleanText(`${row.title} ${variant}`),
321
+ });
322
+ if (results.length >= limit)
323
+ break;
324
+ }
325
+ }
326
+ return results;
327
+ }
328
+ async function fetchJianyuApiRows(page, query, limit) {
329
+ try {
330
+ await page.goto(buildSearchUrl(query));
331
+ await page.wait(2);
332
+ const payload = await page.evaluate(`
333
+ (async () => {
334
+ const now = Math.floor(Date.now() / 1000);
335
+ const body = {
336
+ searchGroup: 1,
337
+ reqType: 'lastNews',
338
+ pageNum: 1,
339
+ pageSize: Math.max(20, Math.min(${Math.max(20, limit)}, 50)),
340
+ keyWords: ${JSON.stringify(query)},
341
+ searchMode: 0,
342
+ bidField: '',
343
+ publishTime: \`\${now - 3600 * 24 * 365 * 3}-\${now}\`,
344
+ selectType: 'title,content',
345
+ subtype: '',
346
+ exclusionWords: '',
347
+ buyer: '',
348
+ winner: '',
349
+ agency: '',
350
+ industry: '',
351
+ province: '',
352
+ city: '',
353
+ district: '',
354
+ buyerClass: '',
355
+ fileExists: '',
356
+ price: '',
357
+ buyerTel: '',
358
+ winnerTel: '',
359
+ };
360
+ const responses = [];
361
+ const types = ${JSON.stringify([...JIANYU_API_TYPES])};
362
+ for (const type of types) {
363
+ try {
364
+ const response = await fetch('/jyapi/jybx/core/' + type + '/searchList', {
365
+ method: 'POST',
366
+ headers: {
367
+ Accept: 'application/json, text/plain, */*',
368
+ 'Content-Type': 'application/json',
369
+ },
370
+ credentials: 'include',
371
+ body: JSON.stringify(body),
372
+ });
373
+ let raw = null;
374
+ try {
375
+ raw = await response.json();
376
+ } catch {
377
+ raw = null;
378
+ }
379
+ const dataList = raw && raw.data && Array.isArray(raw.data.list) ? raw.data.list : [];
380
+ responses.push({
381
+ type,
382
+ ok: response.ok,
383
+ status: response.status,
384
+ payload: {
385
+ antiVerify: raw && typeof raw.antiVerify === 'number' ? raw.antiVerify : undefined,
386
+ error_code: raw && typeof raw.error_code === 'number' ? raw.error_code : undefined,
387
+ hasLogin: raw && typeof raw.hasLogin === 'boolean' ? raw.hasLogin : undefined,
388
+ textVerify: raw && typeof raw.textVerify === 'string' ? raw.textVerify.slice(0, 16) : undefined,
389
+ list: dataList,
390
+ },
391
+ });
392
+ } catch {
393
+ responses.push({
394
+ type,
395
+ ok: false,
396
+ status: 0,
397
+ });
398
+ }
399
+ }
400
+ const challenge = responses.some((item) => item && item.payload && item.payload.antiVerify === -1);
401
+ return { challenge, responses };
402
+ })()
403
+ `);
404
+ const responses = Array.isArray(payload?.responses) ? payload.responses : [];
405
+ const rows = collectApiRowsFromResponses(responses);
406
+ const challenge = Boolean(payload?.challenge);
407
+ return { rows, challenge };
408
+ }
409
+ catch {
410
+ return { rows: [], challenge: false };
411
+ }
412
+ }
413
+ function collectApiRowsFromResponses(responses) {
414
+ const rows = [];
415
+ const seen = new Set();
416
+ for (const response of responses) {
417
+ if (!response || typeof response !== 'object')
418
+ continue;
419
+ const meta = response;
420
+ const body = meta.payload;
421
+ if (!body || typeof body !== 'object')
422
+ continue;
423
+ const list = body.list;
424
+ if (!Array.isArray(list))
425
+ continue;
426
+ for (const item of list) {
427
+ const row = normalizeApiRow(item);
428
+ if (!row)
429
+ continue;
430
+ const key = `${row.title}\t${row.url}`;
431
+ if (seen.has(key))
432
+ continue;
433
+ seen.add(key);
434
+ rows.push(row);
435
+ }
436
+ }
437
+ return rows;
38
438
  }
39
439
  cli({
40
- site: 'jianyu',
440
+ site: SITE,
41
441
  name: 'search',
42
442
  description: '搜索剑鱼标讯公告',
43
- domain: 'www.jianyu360.cn',
443
+ domain: DOMAIN,
44
444
  strategy: Strategy.COOKIE,
45
445
  browser: true,
46
446
  args: [
47
447
  { name: 'query', required: true, positional: true, help: 'Search keyword, e.g. "procurement"' },
48
448
  { name: 'limit', type: 'int', default: 20, help: 'Number of results (max 50)' },
49
449
  ],
50
- columns: ['rank', 'title', 'date', 'url'],
450
+ columns: ['rank', 'content_type', 'title', 'publish_time', 'project_code', 'budget_or_limit', 'url'],
51
451
  func: async (page, kwargs) => {
52
452
  const query = cleanText(kwargs.query);
53
453
  const limit = Math.max(1, Math.min(Number(kwargs.limit) || 20, 50));
54
- const searchUrl = buildSearchUrl(query);
55
- await page.goto(searchUrl);
56
- await page.wait(2);
57
- const payload = await page.evaluate(`
58
- (() => {
59
- const clean = (value) => (value || '').replace(/\\s+/g, ' ').trim();
60
- const toAbsolute = (href) => {
61
- if (!href) return '';
62
- if (href.startsWith('http://') || href.startsWith('https://')) return href;
63
- if (href.startsWith('/')) return new URL(href, window.location.origin).toString();
64
- return '';
65
- };
66
- const parseDate = (text) => {
67
- const normalized = clean(text);
68
- const match = normalized.match(/(20\\d{2})[.\\-/年](\\d{1,2})[.\\-/月](\\d{1,2})/);
69
- if (!match) return '';
70
- const month = String(match[2]).padStart(2, '0');
71
- const day = String(match[3]).padStart(2, '0');
72
- return match[1] + '-' + month + '-' + day;
73
- };
74
- const pickDateText = (node) => {
75
- let cursor = node;
76
- for (let i = 0; i < 4 && cursor; i++) {
77
- const text = clean(cursor.innerText || cursor.textContent || '');
78
- const date = parseDate(text);
79
- if (date) return date;
80
- cursor = cursor.parentElement;
81
- }
82
- return '';
83
- };
84
-
85
- const anchors = Array.from(
86
- document.querySelectorAll('a[href*="/nologin/content/"], a[href*="/content/"]'),
87
- );
88
- const rows = [];
89
- const seen = new Set();
90
- for (const anchor of anchors) {
91
- const url = toAbsolute(anchor.getAttribute('href') || anchor.href || '');
92
- const title = clean(anchor.textContent || '');
93
- if (!url || !title || title.length < 4) continue;
94
- const key = title + '\\t' + url;
95
- if (seen.has(key)) continue;
96
- seen.add(key);
97
- rows.push({
98
- title,
99
- url,
100
- date: pickDateText(anchor),
101
- });
102
- }
103
- return rows;
104
- })()
105
- `);
106
- const pageText = cleanText(await page.evaluate('document.body ? document.body.innerText : ""'));
107
- if (!Array.isArray(payload)
108
- && /(请先登录|登录后|未登录|验证码)/.test(pageText)) {
109
- throw new AuthRequiredError('www.jianyu360.cn', 'Jianyu search results require login or human verification');
454
+ const apiResult = await fetchJianyuApiRows(page, query, limit);
455
+ const mergedRows = dedupeCandidates(filterNavigationRows(query, apiResult.rows));
456
+ const extractedRows = await searchRowsFromEntries(page, {
457
+ query,
458
+ candidateUrls: siteSearchCandidates(query),
459
+ allowedHostFragments: ['jianyu360.cn'],
460
+ limit,
461
+ });
462
+ const domRows = dedupeCandidates(filterNavigationRows(query, extractedRows));
463
+ const rows = dedupeCandidates([...mergedRows, ...domRows]);
464
+ if (rows.length === 0) {
465
+ const indexedRows = await fetchDuckDuckGoIndexRows(query, limit);
466
+ const filteredIndexedRows = dedupeCandidates(filterNavigationRows(query, indexedRows));
467
+ if (filteredIndexedRows.length > 0) {
468
+ return toProcurementSearchRecords(filteredIndexedRows, {
469
+ site: SITE,
470
+ query,
471
+ limit,
472
+ });
473
+ }
474
+ if (apiResult.challenge || await isAuthRequired(page)) {
475
+ throw new AuthRequiredError(DOMAIN, '[taxonomy=selector_drift] site=jianyu command=search blocked by human verification / access challenge');
476
+ }
110
477
  }
111
- const rows = Array.isArray(payload)
112
- ? payload
113
- .filter((item) => !!item && typeof item === 'object')
114
- .map((item) => ({
115
- title: cleanText(item.title),
116
- url: cleanText(item.url),
117
- date: normalizeDate(cleanText(item.date)),
118
- }))
119
- .filter((item) => item.title && item.url)
120
- : [];
121
- return dedupeCandidates(rows)
122
- .slice(0, limit)
123
- .map((item, index) => ({
124
- rank: index + 1,
125
- title: item.title,
126
- date: item.date,
127
- url: item.url,
128
- }));
478
+ return toProcurementSearchRecords(rows, {
479
+ site: SITE,
480
+ query,
481
+ limit,
482
+ });
129
483
  },
130
484
  });
131
485
  export const __test__ = {
486
+ buildSearchCandidates: siteSearchCandidates,
132
487
  buildSearchUrl,
133
488
  normalizeDate,
134
489
  dedupeCandidates,
490
+ filterNavigationRows,
491
+ parseSearchIndexMarkdown,
492
+ unwrapDuckDuckGoUrl,
493
+ extractDateFromJianyuUrl,
494
+ normalizeApiRow,
495
+ fetchJianyuApiRows,
496
+ collectApiRowsFromResponses,
135
497
  };