@zenalexa/unicli 0.215.1 → 0.216.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (407) hide show
  1. package/AGENTS.md +15 -15
  2. package/README.md +233 -389
  3. package/README.zh-CN.md +235 -362
  4. package/dist/adapters/1688/assets.d.ts +2 -0
  5. package/dist/adapters/1688/assets.d.ts.map +1 -0
  6. package/dist/adapters/1688/assets.js +102 -0
  7. package/dist/adapters/1688/assets.js.map +1 -0
  8. package/dist/adapters/51job/jobs.d.ts +2 -0
  9. package/dist/adapters/51job/jobs.d.ts.map +1 -0
  10. package/dist/adapters/51job/jobs.js +292 -0
  11. package/dist/adapters/51job/jobs.js.map +1 -0
  12. package/dist/adapters/_shared/browser-tools.d.ts +10 -0
  13. package/dist/adapters/_shared/browser-tools.d.ts.map +1 -0
  14. package/dist/adapters/_shared/browser-tools.js +42 -0
  15. package/dist/adapters/_shared/browser-tools.js.map +1 -0
  16. package/dist/adapters/antigravity/extra.d.ts +2 -0
  17. package/dist/adapters/antigravity/extra.d.ts.map +1 -0
  18. package/dist/adapters/antigravity/extra.js +52 -0
  19. package/dist/adapters/antigravity/extra.js.map +1 -0
  20. package/dist/adapters/baidu-scholar/search.d.ts +2 -0
  21. package/dist/adapters/baidu-scholar/search.d.ts.map +1 -0
  22. package/dist/adapters/baidu-scholar/search.js +34 -0
  23. package/dist/adapters/baidu-scholar/search.js.map +1 -0
  24. package/dist/adapters/bilibili/compat.d.ts +2 -0
  25. package/dist/adapters/bilibili/compat.d.ts.map +1 -0
  26. package/dist/adapters/bilibili/compat.js +114 -0
  27. package/dist/adapters/bilibili/compat.js.map +1 -0
  28. package/dist/adapters/chatgpt/image.d.ts +2 -0
  29. package/dist/adapters/chatgpt/image.d.ts.map +1 -0
  30. package/dist/adapters/chatgpt/image.js +81 -0
  31. package/dist/adapters/chatgpt/image.js.map +1 -0
  32. package/dist/adapters/chatgpt-app/chatgpt-app.d.ts +2 -0
  33. package/dist/adapters/chatgpt-app/chatgpt-app.d.ts.map +1 -0
  34. package/dist/adapters/chatgpt-app/chatgpt-app.js +9 -0
  35. package/dist/adapters/chatgpt-app/chatgpt-app.js.map +1 -0
  36. package/dist/adapters/chatwise/extra.d.ts +2 -0
  37. package/dist/adapters/chatwise/extra.d.ts.map +1 -0
  38. package/dist/adapters/chatwise/extra.js +35 -0
  39. package/dist/adapters/chatwise/extra.js.map +1 -0
  40. package/dist/adapters/codex/extra.d.ts +2 -0
  41. package/dist/adapters/codex/extra.d.ts.map +1 -0
  42. package/dist/adapters/codex/extra.js +35 -0
  43. package/dist/adapters/codex/extra.js.map +1 -0
  44. package/dist/adapters/deepseek/web.d.ts +2 -0
  45. package/dist/adapters/deepseek/web.d.ts.map +1 -0
  46. package/dist/adapters/deepseek/web.js +187 -0
  47. package/dist/adapters/deepseek/web.js.map +1 -0
  48. package/dist/adapters/doubao/web.d.ts +2 -0
  49. package/dist/adapters/doubao/web.d.ts.map +1 -0
  50. package/dist/adapters/doubao/web.js +138 -0
  51. package/dist/adapters/doubao/web.js.map +1 -0
  52. package/dist/adapters/eastmoney/market-data.d.ts +2 -0
  53. package/dist/adapters/eastmoney/market-data.d.ts.map +1 -0
  54. package/dist/adapters/eastmoney/market-data.js +753 -0
  55. package/dist/adapters/eastmoney/market-data.js.map +1 -0
  56. package/dist/adapters/gitee/user.d.ts +2 -0
  57. package/dist/adapters/gitee/user.d.ts.map +1 -0
  58. package/dist/adapters/gitee/user.js +54 -0
  59. package/dist/adapters/gitee/user.js.map +1 -0
  60. package/dist/adapters/google-scholar/cite.d.ts +2 -0
  61. package/dist/adapters/google-scholar/cite.d.ts.map +1 -0
  62. package/dist/adapters/google-scholar/cite.js +82 -0
  63. package/dist/adapters/google-scholar/cite.js.map +1 -0
  64. package/dist/adapters/google-scholar/profile.d.ts +2 -0
  65. package/dist/adapters/google-scholar/profile.d.ts.map +1 -0
  66. package/dist/adapters/google-scholar/profile.js +80 -0
  67. package/dist/adapters/google-scholar/profile.js.map +1 -0
  68. package/dist/adapters/google-scholar/search.d.ts +2 -0
  69. package/dist/adapters/google-scholar/search.d.ts.map +1 -0
  70. package/dist/adapters/google-scholar/search.js +54 -0
  71. package/dist/adapters/google-scholar/search.js.map +1 -0
  72. package/dist/adapters/gov-law/laws.d.ts +2 -0
  73. package/dist/adapters/gov-law/laws.d.ts.map +1 -0
  74. package/dist/adapters/gov-law/laws.js +58 -0
  75. package/dist/adapters/gov-law/laws.js.map +1 -0
  76. package/dist/adapters/gov-policy/policy.d.ts +2 -0
  77. package/dist/adapters/gov-policy/policy.d.ts.map +1 -0
  78. package/dist/adapters/gov-policy/policy.js +58 -0
  79. package/dist/adapters/gov-policy/policy.js.map +1 -0
  80. package/dist/adapters/jd/commerce.d.ts +2 -0
  81. package/dist/adapters/jd/commerce.d.ts.map +1 -0
  82. package/dist/adapters/jd/commerce.js +133 -0
  83. package/dist/adapters/jd/commerce.js.map +1 -0
  84. package/dist/adapters/jianyu/detail.d.ts +2 -0
  85. package/dist/adapters/jianyu/detail.d.ts.map +1 -0
  86. package/dist/adapters/jianyu/detail.js +27 -0
  87. package/dist/adapters/jianyu/detail.js.map +1 -0
  88. package/dist/adapters/jimeng/workspace.d.ts +2 -0
  89. package/dist/adapters/jimeng/workspace.d.ts.map +1 -0
  90. package/dist/adapters/jimeng/workspace.js +49 -0
  91. package/dist/adapters/jimeng/workspace.js.map +1 -0
  92. package/dist/adapters/ke/rent-transaction.d.ts +2 -0
  93. package/dist/adapters/ke/rent-transaction.d.ts.map +1 -0
  94. package/dist/adapters/ke/rent-transaction.js +63 -0
  95. package/dist/adapters/ke/rent-transaction.js.map +1 -0
  96. package/dist/adapters/linux-do/search.d.ts +2 -0
  97. package/dist/adapters/linux-do/search.d.ts.map +1 -0
  98. package/dist/adapters/linux-do/search.js +75 -0
  99. package/dist/adapters/linux-do/search.js.map +1 -0
  100. package/dist/adapters/linux-do/topic-content.d.ts +2 -0
  101. package/dist/adapters/linux-do/topic-content.d.ts.map +1 -0
  102. package/dist/adapters/linux-do/topic-content.js +32 -0
  103. package/dist/adapters/linux-do/topic-content.js.map +1 -0
  104. package/dist/adapters/maimai/talents.d.ts +2 -0
  105. package/dist/adapters/maimai/talents.d.ts.map +1 -0
  106. package/dist/adapters/maimai/talents.js +64 -0
  107. package/dist/adapters/maimai/talents.js.map +1 -0
  108. package/dist/adapters/mubu/docs.d.ts +2 -0
  109. package/dist/adapters/mubu/docs.d.ts.map +1 -0
  110. package/dist/adapters/mubu/docs.js +96 -0
  111. package/dist/adapters/mubu/docs.js.map +1 -0
  112. package/dist/adapters/nowcoder/nowcoder.d.ts +2 -0
  113. package/dist/adapters/nowcoder/nowcoder.d.ts.map +1 -0
  114. package/dist/adapters/nowcoder/nowcoder.js +480 -0
  115. package/dist/adapters/nowcoder/nowcoder.js.map +1 -0
  116. package/dist/adapters/powerchina/search.d.ts +2 -0
  117. package/dist/adapters/powerchina/search.d.ts.map +1 -0
  118. package/dist/adapters/powerchina/search.js +41 -0
  119. package/dist/adapters/powerchina/search.js.map +1 -0
  120. package/dist/adapters/quark/actions.d.ts +2 -0
  121. package/dist/adapters/quark/actions.d.ts.map +1 -0
  122. package/dist/adapters/quark/actions.js +151 -0
  123. package/dist/adapters/quark/actions.js.map +1 -0
  124. package/dist/adapters/reddit/browser-utils.d.ts +7 -0
  125. package/dist/adapters/reddit/browser-utils.d.ts.map +1 -0
  126. package/dist/adapters/reddit/browser-utils.js +68 -0
  127. package/dist/adapters/reddit/browser-utils.js.map +1 -0
  128. package/dist/adapters/reddit/listings.d.ts +2 -0
  129. package/dist/adapters/reddit/listings.d.ts.map +1 -0
  130. package/dist/adapters/reddit/listings.js +193 -0
  131. package/dist/adapters/reddit/listings.js.map +1 -0
  132. package/dist/adapters/reddit/search.d.ts +2 -0
  133. package/dist/adapters/reddit/search.d.ts.map +1 -0
  134. package/dist/adapters/reddit/search.js +66 -0
  135. package/dist/adapters/reddit/search.js.map +1 -0
  136. package/dist/adapters/spotify/api.d.ts +2 -0
  137. package/dist/adapters/spotify/api.d.ts.map +1 -0
  138. package/dist/adapters/spotify/api.js +252 -0
  139. package/dist/adapters/spotify/api.js.map +1 -0
  140. package/dist/adapters/taobao/commerce.d.ts +2 -0
  141. package/dist/adapters/taobao/commerce.d.ts.map +1 -0
  142. package/dist/adapters/taobao/commerce.js +130 -0
  143. package/dist/adapters/taobao/commerce.js.map +1 -0
  144. package/dist/adapters/tdx/hot-rank.d.ts +2 -0
  145. package/dist/adapters/tdx/hot-rank.d.ts.map +1 -0
  146. package/dist/adapters/tdx/hot-rank.js +34 -0
  147. package/dist/adapters/tdx/hot-rank.js.map +1 -0
  148. package/dist/adapters/ths/hot-rank.d.ts +2 -0
  149. package/dist/adapters/ths/hot-rank.d.ts.map +1 -0
  150. package/dist/adapters/ths/hot-rank.js +34 -0
  151. package/dist/adapters/ths/hot-rank.js.map +1 -0
  152. package/dist/adapters/toutiao/articles.d.ts +2 -0
  153. package/dist/adapters/toutiao/articles.d.ts.map +1 -0
  154. package/dist/adapters/toutiao/articles.js +41 -0
  155. package/dist/adapters/toutiao/articles.js.map +1 -0
  156. package/dist/adapters/twitter/lists-extra.d.ts +2 -0
  157. package/dist/adapters/twitter/lists-extra.d.ts.map +1 -0
  158. package/dist/adapters/twitter/lists-extra.js +125 -0
  159. package/dist/adapters/twitter/lists-extra.js.map +1 -0
  160. package/dist/adapters/uiverse/components.d.ts +2 -0
  161. package/dist/adapters/uiverse/components.d.ts.map +1 -0
  162. package/dist/adapters/uiverse/components.js +138 -0
  163. package/dist/adapters/uiverse/components.js.map +1 -0
  164. package/dist/adapters/wanfang/search.d.ts +2 -0
  165. package/dist/adapters/wanfang/search.d.ts.map +1 -0
  166. package/dist/adapters/wanfang/search.js +34 -0
  167. package/dist/adapters/wanfang/search.js.map +1 -0
  168. package/dist/adapters/weixin/drafts.d.ts +2 -0
  169. package/dist/adapters/weixin/drafts.d.ts.map +1 -0
  170. package/dist/adapters/weixin/drafts.js +69 -0
  171. package/dist/adapters/weixin/drafts.js.map +1 -0
  172. package/dist/adapters/weread/ai-outline.d.ts +2 -0
  173. package/dist/adapters/weread/ai-outline.d.ts.map +1 -0
  174. package/dist/adapters/weread/ai-outline.js +28 -0
  175. package/dist/adapters/weread/ai-outline.js.map +1 -0
  176. package/dist/adapters/xiaoyuzhou/media.d.ts +2 -0
  177. package/dist/adapters/xiaoyuzhou/media.d.ts.map +1 -0
  178. package/dist/adapters/xiaoyuzhou/media.js +105 -0
  179. package/dist/adapters/xiaoyuzhou/media.js.map +1 -0
  180. package/dist/adapters/xueqiu/extra.d.ts +2 -0
  181. package/dist/adapters/xueqiu/extra.d.ts.map +1 -0
  182. package/dist/adapters/xueqiu/extra.js +74 -0
  183. package/dist/adapters/xueqiu/extra.js.map +1 -0
  184. package/dist/adapters/youtube/personal.d.ts +2 -0
  185. package/dist/adapters/youtube/personal.d.ts.map +1 -0
  186. package/dist/adapters/youtube/personal.js +183 -0
  187. package/dist/adapters/youtube/personal.js.map +1 -0
  188. package/dist/adapters/zhihu/actions.d.ts +2 -0
  189. package/dist/adapters/zhihu/actions.d.ts.map +1 -0
  190. package/dist/adapters/zhihu/actions.js +110 -0
  191. package/dist/adapters/zhihu/actions.js.map +1 -0
  192. package/dist/browser/adapter-authoring.d.ts.map +1 -1
  193. package/dist/browser/adapter-authoring.js +3 -3
  194. package/dist/browser/adapter-authoring.js.map +1 -1
  195. package/dist/browser/bridge.d.ts.map +1 -1
  196. package/dist/browser/bridge.js +2 -3
  197. package/dist/browser/bridge.js.map +1 -1
  198. package/dist/browser/daemon-client.d.ts.map +1 -1
  199. package/dist/browser/daemon-client.js +17 -5
  200. package/dist/browser/daemon-client.js.map +1 -1
  201. package/dist/browser/network-cache.js +2 -2
  202. package/dist/browser/network-cache.js.map +1 -1
  203. package/dist/browser/site-memory.d.ts.map +1 -1
  204. package/dist/browser/site-memory.js +11 -8
  205. package/dist/browser/site-memory.js.map +1 -1
  206. package/dist/browser/target-errors.d.ts +2 -2
  207. package/dist/browser/target-errors.js +2 -2
  208. package/dist/browser/verify-fixture.d.ts.map +1 -1
  209. package/dist/browser/verify-fixture.js +2 -2
  210. package/dist/browser/verify-fixture.js.map +1 -1
  211. package/dist/cli.d.ts.map +1 -1
  212. package/dist/cli.js +9 -4
  213. package/dist/cli.js.map +1 -1
  214. package/dist/commands/agents.d.ts.map +1 -1
  215. package/dist/commands/agents.js +5 -2
  216. package/dist/commands/agents.js.map +1 -1
  217. package/dist/commands/auth.d.ts.map +1 -1
  218. package/dist/commands/auth.js +8 -2
  219. package/dist/commands/auth.js.map +1 -1
  220. package/dist/commands/browser-operator-runtime.d.ts.map +1 -1
  221. package/dist/commands/browser-operator-runtime.js +2 -2
  222. package/dist/commands/browser-operator-runtime.js.map +1 -1
  223. package/dist/commands/browser-operator.d.ts.map +1 -1
  224. package/dist/commands/browser-operator.js +2 -2
  225. package/dist/commands/browser-operator.js.map +1 -1
  226. package/dist/commands/describe.d.ts +2 -2
  227. package/dist/commands/describe.d.ts.map +1 -1
  228. package/dist/commands/describe.js +14 -3
  229. package/dist/commands/describe.js.map +1 -1
  230. package/dist/commands/dispatch.d.ts.map +1 -1
  231. package/dist/commands/dispatch.js +7 -6
  232. package/dist/commands/dispatch.js.map +1 -1
  233. package/dist/commands/explore.js +2 -2
  234. package/dist/commands/explore.js.map +1 -1
  235. package/dist/commands/generate.js +3 -3
  236. package/dist/commands/generate.js.map +1 -1
  237. package/dist/commands/health.d.ts.map +1 -1
  238. package/dist/commands/health.js +4 -10
  239. package/dist/commands/health.js.map +1 -1
  240. package/dist/commands/migrate.d.ts +9 -9
  241. package/dist/commands/migrate.d.ts.map +1 -1
  242. package/dist/commands/migrate.js +22 -22
  243. package/dist/commands/migrate.js.map +1 -1
  244. package/dist/commands/repair.d.ts.map +1 -1
  245. package/dist/commands/repair.js +9 -4
  246. package/dist/commands/repair.js.map +1 -1
  247. package/dist/commands/search.d.ts +3 -3
  248. package/dist/commands/search.js +4 -4
  249. package/dist/commands/skills.d.ts +3 -0
  250. package/dist/commands/skills.d.ts.map +1 -1
  251. package/dist/commands/skills.js +8 -4
  252. package/dist/commands/skills.js.map +1 -1
  253. package/dist/commands/synthesize.js +2 -2
  254. package/dist/commands/synthesize.js.map +1 -1
  255. package/dist/discovery/aliases.d.ts.map +1 -1
  256. package/dist/discovery/aliases.js +69 -0
  257. package/dist/discovery/aliases.js.map +1 -1
  258. package/dist/discovery/loader.d.ts.map +1 -1
  259. package/dist/discovery/loader.js +130 -0
  260. package/dist/discovery/loader.js.map +1 -1
  261. package/dist/engine/kernel/execute.d.ts.map +1 -1
  262. package/dist/engine/kernel/execute.js +27 -4
  263. package/dist/engine/kernel/execute.js.map +1 -1
  264. package/dist/engine/user-home.d.ts +9 -0
  265. package/dist/engine/user-home.d.ts.map +1 -0
  266. package/dist/engine/user-home.js +12 -0
  267. package/dist/engine/user-home.js.map +1 -0
  268. package/dist/fast-path.d.ts +14 -0
  269. package/dist/fast-path.d.ts.map +1 -0
  270. package/dist/fast-path.js +565 -0
  271. package/dist/fast-path.js.map +1 -0
  272. package/dist/hub/index.d.ts +1 -1
  273. package/dist/hub/index.d.ts.map +1 -1
  274. package/dist/hub/index.js +28 -17
  275. package/dist/hub/index.js.map +1 -1
  276. package/dist/main.js +6 -3
  277. package/dist/main.js.map +1 -1
  278. package/dist/manifest-compact.txt +11 -11
  279. package/dist/manifest-search.json +1 -1
  280. package/dist/manifest.json +27600 -1016
  281. package/dist/mcp/tools.js +1 -1
  282. package/dist/mcp/tools.js.map +1 -1
  283. package/dist/output/error-map.d.ts.map +1 -1
  284. package/dist/output/error-map.js +16 -5
  285. package/dist/output/error-map.js.map +1 -1
  286. package/dist/protocol/acp.js +1 -1
  287. package/dist/protocol/acp.js.map +1 -1
  288. package/dist/registry.d.ts +3 -0
  289. package/dist/registry.d.ts.map +1 -1
  290. package/dist/registry.js +34 -1
  291. package/dist/registry.js.map +1 -1
  292. package/dist/runtime/usage-ledger.d.ts +6 -7
  293. package/dist/runtime/usage-ledger.d.ts.map +1 -1
  294. package/dist/runtime/usage-ledger.js +6 -7
  295. package/dist/runtime/usage-ledger.js.map +1 -1
  296. package/dist/types.d.ts +2 -0
  297. package/dist/types.d.ts.map +1 -1
  298. package/dist/types.js.map +1 -1
  299. package/package.json +12 -6
  300. package/src/adapters/1688/assets.ts +114 -0
  301. package/src/adapters/51job/jobs.ts +327 -0
  302. package/src/adapters/_shared/browser-tools.ts +59 -0
  303. package/src/adapters/antigravity/extra.ts +53 -0
  304. package/src/adapters/baidu-scholar/search.ts +38 -0
  305. package/src/adapters/bilibili/compat.ts +132 -0
  306. package/src/adapters/binance/asks.yaml +41 -0
  307. package/src/adapters/binance/depth.yaml +41 -0
  308. package/src/adapters/binance/gainers.yaml +42 -0
  309. package/src/adapters/binance/hot.yaml +1 -1
  310. package/src/adapters/binance/kline.yaml +1 -1
  311. package/src/adapters/binance/klines.yaml +46 -0
  312. package/src/adapters/binance/losers.yaml +42 -0
  313. package/src/adapters/binance/pairs.yaml +38 -0
  314. package/src/adapters/binance/price.yaml +32 -0
  315. package/src/adapters/binance/prices.yaml +30 -0
  316. package/src/adapters/binance/ticker.yaml +2 -2
  317. package/src/adapters/binance/top.yaml +46 -0
  318. package/src/adapters/binance/trades.yaml +42 -0
  319. package/src/adapters/chatgpt/image.ts +84 -0
  320. package/src/adapters/chatgpt-app/chatgpt-app.ts +11 -0
  321. package/src/adapters/chatwise/extra.ts +36 -0
  322. package/src/adapters/codex/extra.ts +36 -0
  323. package/src/adapters/deepseek/web.ts +203 -0
  324. package/src/adapters/doubao/web.ts +154 -0
  325. package/src/adapters/eastmoney/market-data.ts +829 -0
  326. package/src/adapters/excel/insert-image.yaml +80 -0
  327. package/src/adapters/excel/insert-link.yaml +90 -0
  328. package/src/adapters/excel/list.yaml +63 -0
  329. package/src/adapters/excel/read.yaml +74 -0
  330. package/src/adapters/excel/set-cell.yaml +77 -0
  331. package/src/adapters/excel/set-font.yaml +87 -0
  332. package/src/adapters/excel/status.yaml +29 -0
  333. package/src/adapters/gh/search-repos.yaml +62 -0
  334. package/src/adapters/gitee/user.ts +59 -0
  335. package/src/adapters/google-scholar/cite.ts +95 -0
  336. package/src/adapters/google-scholar/profile.ts +91 -0
  337. package/src/adapters/google-scholar/search.ts +58 -0
  338. package/src/adapters/gov-law/laws.ts +61 -0
  339. package/src/adapters/gov-policy/policy.ts +61 -0
  340. package/src/adapters/imessage/contact.yaml +7 -2
  341. package/src/adapters/imessage/recent.yaml +7 -2
  342. package/src/adapters/imessage/search.yaml +7 -2
  343. package/src/adapters/jd/commerce.ts +142 -0
  344. package/src/adapters/jianyu/detail.ts +28 -0
  345. package/src/adapters/jimeng/workspace.ts +53 -0
  346. package/src/adapters/ke/rent-transaction.ts +70 -0
  347. package/src/adapters/linux-do/search.ts +92 -0
  348. package/src/adapters/linux-do/topic-content.ts +45 -0
  349. package/src/adapters/maimai/talents.ts +65 -0
  350. package/src/adapters/mubu/docs.ts +107 -0
  351. package/src/adapters/nowcoder/nowcoder.ts +570 -0
  352. package/src/adapters/powerchina/search.ts +45 -0
  353. package/src/adapters/powerpoint/add-slide.yaml +93 -0
  354. package/src/adapters/powerpoint/insert-image.yaml +71 -0
  355. package/src/adapters/powerpoint/insert-link.yaml +94 -0
  356. package/src/adapters/powerpoint/list.yaml +58 -0
  357. package/src/adapters/powerpoint/set-font.yaml +101 -0
  358. package/src/adapters/powerpoint/slides.yaml +73 -0
  359. package/src/adapters/powerpoint/status.yaml +29 -0
  360. package/src/adapters/quark/actions.ts +169 -0
  361. package/src/adapters/reddit/browser-utils.ts +93 -0
  362. package/src/adapters/reddit/listings.ts +223 -0
  363. package/src/adapters/reddit/search.ts +74 -0
  364. package/src/adapters/spotify/api.ts +292 -0
  365. package/src/adapters/taobao/commerce.ts +134 -0
  366. package/src/adapters/tdx/hot-rank.ts +35 -0
  367. package/src/adapters/ths/hot-rank.ts +35 -0
  368. package/src/adapters/toutiao/articles.ts +45 -0
  369. package/src/adapters/twitter/lists-extra.ts +139 -0
  370. package/src/adapters/uiverse/components.ts +154 -0
  371. package/src/adapters/vercel/list.yaml +2 -1
  372. package/src/adapters/wanfang/search.ts +38 -0
  373. package/src/adapters/weixin/drafts.ts +74 -0
  374. package/src/adapters/weread/ai-outline.ts +32 -0
  375. package/src/adapters/word/insert-image.yaml +73 -0
  376. package/src/adapters/word/insert-link.yaml +82 -0
  377. package/src/adapters/word/insert-text.yaml +72 -0
  378. package/src/adapters/word/list.yaml +63 -0
  379. package/src/adapters/word/read.yaml +63 -0
  380. package/src/adapters/word/set-font.yaml +97 -0
  381. package/src/adapters/word/status.yaml +29 -0
  382. package/src/adapters/xiaoyuzhou/media.ts +139 -0
  383. package/src/adapters/xueqiu/extra.ts +78 -0
  384. package/src/adapters/youtube/personal.ts +215 -0
  385. package/src/adapters/zhihu/actions.ts +111 -0
  386. package/src/hub/external-clis-harness.yaml +211 -0
  387. package/src/hub/index.ts +29 -25
  388. package/src/adapters/linux-do/search.yaml +0 -44
  389. package/src/adapters/meituan/hot.yaml +0 -34
  390. package/src/adapters/reddit/frontpage.test.ts +0 -15
  391. package/src/adapters/reddit/frontpage.yaml +0 -41
  392. package/src/adapters/reddit/hot.test.ts +0 -15
  393. package/src/adapters/reddit/hot.yaml +0 -41
  394. package/src/adapters/reddit/new.test.ts +0 -15
  395. package/src/adapters/reddit/new.yaml +0 -42
  396. package/src/adapters/reddit/popular.test.ts +0 -15
  397. package/src/adapters/reddit/popular.yaml +0 -41
  398. package/src/adapters/reddit/rising.test.ts +0 -15
  399. package/src/adapters/reddit/rising.yaml +0 -41
  400. package/src/adapters/reddit/search.test.ts +0 -15
  401. package/src/adapters/reddit/search.yaml +0 -52
  402. package/src/adapters/reddit/subreddit.test.ts +0 -15
  403. package/src/adapters/reddit/subreddit.yaml +0 -50
  404. package/src/adapters/reddit/top.test.ts +0 -15
  405. package/src/adapters/reddit/top.yaml +0 -48
  406. package/src/adapters/reddit/trending.test.ts +0 -15
  407. package/src/adapters/reddit/trending.yaml +0 -33
@@ -0,0 +1,95 @@
1
+ import { cli, Strategy } from "../../registry.js";
2
+ import type { IPage } from "../../types.js";
3
+ import { intArg, js, str, visibleText } from "../_shared/browser-tools.js";
4
+
5
+ const STYLE_LABELS: Record<string, string> = {
6
+ bibtex: "BibTeX",
7
+ endnote: "EndNote",
8
+ refman: "RefMan",
9
+ refworks: "RefWorks",
10
+ };
11
+
12
+ cli({
13
+ site: "google-scholar",
14
+ name: "cite",
15
+ description: "Fetch a Google Scholar citation for a paper",
16
+ domain: "scholar.google.com",
17
+ strategy: Strategy.PUBLIC,
18
+ browser: true,
19
+ args: [
20
+ { name: "query", type: "str", required: true, positional: true },
21
+ {
22
+ name: "style",
23
+ type: "str",
24
+ default: "bibtex",
25
+ choices: Object.keys(STYLE_LABELS),
26
+ },
27
+ { name: "index", type: "int", default: 1 },
28
+ ],
29
+ columns: ["title", "format", "citation"],
30
+ func: async (page, kwargs) => {
31
+ const p = page as IPage;
32
+ const query = str(kwargs.query).trim();
33
+ const style = str(kwargs.style, "bibtex").toLowerCase();
34
+ const label = STYLE_LABELS[style] ?? STYLE_LABELS.bibtex;
35
+ const index = intArg(kwargs.index, 1, 20);
36
+
37
+ await p.goto(
38
+ `https://scholar.google.com/scholar?q=${encodeURIComponent(query)}&hl=en`,
39
+ { settleMs: 2500 },
40
+ );
41
+
42
+ const clickResult = (await p.evaluate(`(() => {
43
+ const normalize = (value) => (value || '').replace(/\\s+/g, ' ').trim();
44
+ const cards = [...document.querySelectorAll('.gs_r.gs_or.gs_scl, .gs_r.gs_or')];
45
+ const card = cards[${js(index - 1)}];
46
+ if (!card) return { ok: false, reason: 'result_not_found' };
47
+ const title = normalize(card.querySelector('.gs_rt, h3')?.textContent);
48
+ const button = card.querySelector('a.gs_or_cit, .gs_or_cit');
49
+ if (!(button instanceof HTMLElement)) {
50
+ return { ok: false, title, reason: 'cite_button_not_found' };
51
+ }
52
+ button.click();
53
+ return { ok: true, title };
54
+ })()`)) as { ok?: boolean; title?: string; reason?: string };
55
+
56
+ if (!clickResult.ok) {
57
+ return [
58
+ {
59
+ title: clickResult.title ?? query,
60
+ format: style,
61
+ citation: clickResult.reason ?? "citation_unavailable",
62
+ },
63
+ ];
64
+ }
65
+
66
+ await p.waitForSelector("#gs_cit", 5000).catch(() => undefined);
67
+ const citationUrl = str(
68
+ await p.evaluate(`(() => {
69
+ const wanted = ${js(label)};
70
+ const links = [...document.querySelectorAll('#gs_citi a, #gs_cit a')];
71
+ const link = links.find((a) => (a.textContent || '').trim().toLowerCase() === wanted.toLowerCase());
72
+ return link ? new URL(link.getAttribute('href') || '', location.href).href : '';
73
+ })()`),
74
+ );
75
+
76
+ if (!citationUrl) {
77
+ return [
78
+ {
79
+ title: clickResult.title ?? query,
80
+ format: style,
81
+ citation: "citation_link_not_found",
82
+ },
83
+ ];
84
+ }
85
+
86
+ await p.goto(citationUrl, { settleMs: 1200 });
87
+ return [
88
+ {
89
+ title: clickResult.title ?? query,
90
+ format: style,
91
+ citation: await visibleText(p),
92
+ },
93
+ ];
94
+ },
95
+ });
@@ -0,0 +1,91 @@
1
+ import { cli, Strategy } from "../../registry.js";
2
+ import type { IPage } from "../../types.js";
3
+ import { intArg, js, str } from "../_shared/browser-tools.js";
4
+
5
+ function isScholarUserId(value: string): boolean {
6
+ return /^[A-Za-z0-9_-]{8,20}$/.test(value) && !/\s/.test(value);
7
+ }
8
+
9
+ cli({
10
+ site: "google-scholar",
11
+ name: "profile",
12
+ description: "Read a Google Scholar author profile and top papers",
13
+ domain: "scholar.google.com",
14
+ strategy: Strategy.PUBLIC,
15
+ browser: true,
16
+ args: [
17
+ { name: "author", type: "str", required: true, positional: true },
18
+ { name: "limit", type: "int", default: 10 },
19
+ ],
20
+ columns: ["rank", "kind", "title", "authors", "year", "cited", "url"],
21
+ func: async (page, kwargs) => {
22
+ const p = page as IPage;
23
+ const author = str(kwargs.author).trim();
24
+ const limit = intArg(kwargs.limit, 10, 100);
25
+
26
+ if (isScholarUserId(author)) {
27
+ await p.goto(
28
+ `https://scholar.google.com/citations?user=${encodeURIComponent(author)}&hl=en`,
29
+ { settleMs: 2500 },
30
+ );
31
+ } else {
32
+ await p.goto(
33
+ `https://scholar.google.com/citations?view_op=search_authors&mauthors=${encodeURIComponent(author)}&hl=en`,
34
+ { settleMs: 2500 },
35
+ );
36
+ const profileUrl = str(
37
+ await p.evaluate(`(() => {
38
+ const link = document.querySelector('.gsc_1usr_name a, a[href*="citations?user="]');
39
+ return link ? new URL(link.getAttribute('href') || '', location.href).href : '';
40
+ })()`),
41
+ );
42
+ if (!profileUrl) {
43
+ return [
44
+ {
45
+ rank: 0,
46
+ kind: "profile",
47
+ title: author,
48
+ cited: "profile_not_found",
49
+ url: "",
50
+ },
51
+ ];
52
+ }
53
+ await p.goto(profileUrl, { settleMs: 2500 });
54
+ }
55
+
56
+ const rows = await p.evaluate(`(() => {
57
+ const normalize = (value) => (value || '').replace(/\\s+/g, ' ').trim();
58
+ const metric = (label) => {
59
+ const rows = [...document.querySelectorAll('#gsc_rsb_st tr')];
60
+ const row = rows.find((item) => normalize(item.children?.[0]?.textContent).toLowerCase() === label.toLowerCase());
61
+ return normalize(row?.children?.[1]?.textContent);
62
+ };
63
+ const name = normalize(document.querySelector('#gsc_prf_in')?.textContent);
64
+ const affiliation = normalize(document.querySelector('.gsc_prf_il')?.textContent);
65
+ const output = [{
66
+ rank: 0,
67
+ kind: 'profile',
68
+ title: affiliation ? name + ' (' + affiliation + ')' : name,
69
+ authors: '',
70
+ year: '',
71
+ cited: 'h=' + metric('h-index') + ' i10=' + metric('i10-index') + ' total=' + metric('Citations'),
72
+ url: location.href,
73
+ }];
74
+ const papers = [...document.querySelectorAll('#gsc_a_b .gsc_a_tr')];
75
+ for (const paper of papers.slice(0, ${js(limit)})) {
76
+ const titleLink = paper.querySelector('.gsc_a_at');
77
+ output.push({
78
+ rank: output.length,
79
+ kind: 'paper',
80
+ title: normalize(titleLink?.textContent),
81
+ authors: normalize(paper.querySelector('.gs_gray')?.textContent),
82
+ year: normalize(paper.querySelector('.gsc_a_y')?.textContent),
83
+ cited: normalize(paper.querySelector('.gsc_a_c')?.textContent) || '0',
84
+ url: titleLink ? new URL(titleLink.getAttribute('href') || '', location.href).href : '',
85
+ });
86
+ }
87
+ return output;
88
+ })()`);
89
+ return Array.isArray(rows) ? (rows as Record<string, unknown>[]) : [];
90
+ },
91
+ });
@@ -0,0 +1,58 @@
1
+ import { cli, Strategy } from "../../registry.js";
2
+ import type { IPage } from "../../types.js";
3
+ import { intArg, js, str } from "../_shared/browser-tools.js";
4
+
5
+ cli({
6
+ site: "google-scholar",
7
+ name: "search",
8
+ description: "Search Google Scholar papers",
9
+ domain: "scholar.google.com",
10
+ strategy: Strategy.PUBLIC,
11
+ browser: true,
12
+ args: [
13
+ { name: "query", type: "str", required: true, positional: true },
14
+ { name: "limit", type: "int", default: 10 },
15
+ ],
16
+ columns: ["rank", "title", "authors", "source", "year", "cited", "url"],
17
+ func: async (page, kwargs) => {
18
+ const p = page as IPage;
19
+ const limit = intArg(kwargs.limit, 10, 20);
20
+ await p.goto(
21
+ `https://scholar.google.com/scholar?q=${encodeURIComponent(str(kwargs.query))}&hl=en`,
22
+ { settleMs: 2500 },
23
+ );
24
+ const rows = await p.evaluate(`(() => {
25
+ const normalize = (value) => (value || '').replace(/\\s+/g, ' ').trim();
26
+ const rows = [];
27
+ const seen = new Set();
28
+ const cards = [...document.querySelectorAll('.gs_r.gs_or.gs_scl, .gs_r.gs_or')];
29
+ for (const card of cards) {
30
+ const body = card.querySelector('.gs_ri') || card;
31
+ const link = body.querySelector('.gs_rt a, h3 a');
32
+ const title = normalize(body.querySelector('.gs_rt, h3')?.textContent);
33
+ if (!title) continue;
34
+ const url = link ? new URL(link.getAttribute('href') || '', location.href).href : '';
35
+ const dedupeKey = url || title.toLowerCase();
36
+ if (seen.has(dedupeKey)) continue;
37
+ seen.add(dedupeKey);
38
+
39
+ const infoLine = normalize(body.querySelector('.gs_a')?.textContent);
40
+ const parts = infoLine.split(' - ');
41
+ const sourceParts = (parts[1] || '').split(',');
42
+ const citedText = normalize(body.querySelector('.gs_fl a[href*="cites"]')?.textContent);
43
+ rows.push({
44
+ rank: rows.length + 1,
45
+ title,
46
+ authors: (parts[0] || '').trim(),
47
+ source: sourceParts.slice(0, -1).join(',').trim() || sourceParts[0]?.trim() || '',
48
+ year: infoLine.match(/(19|20)\\d{2}/)?.[0] || '',
49
+ cited: citedText.match(/(\\d+)/)?.[1] || '0',
50
+ url,
51
+ });
52
+ if (rows.length >= ${js(limit)}) break;
53
+ }
54
+ return rows;
55
+ })()`);
56
+ return Array.isArray(rows) ? (rows as Record<string, unknown>[]) : [];
57
+ },
58
+ });
@@ -0,0 +1,61 @@
1
+ import { cli, Strategy } from "../../registry.js";
2
+ import type { IPage } from "../../types.js";
3
+ import { intArg, js, str } from "../_shared/browser-tools.js";
4
+
5
+ function lawRowsScript(limit: number): string {
6
+ return `(() => {
7
+ const cards = [...document.querySelectorAll('a[href], .el-card, .list-item, li')];
8
+ const seen = new Set();
9
+ return cards.map((card) => {
10
+ const link = card.matches?.('a[href]') ? card : card.querySelector?.('a[href]');
11
+ const text = (card.textContent || '').replace(/\\s+/g, ' ').trim();
12
+ const title = (link?.textContent || text).replace(/\\s+/g, ' ').trim();
13
+ const href = link?.getAttribute('href') || '';
14
+ const url = href ? new URL(href, location.href).href : '';
15
+ if (!title || (url && seen.has(url))) return null;
16
+ if (url) seen.add(url);
17
+ const date = (text.match(/\\d{4}[-年.]\\d{1,2}[-月.]\\d{1,2}/) || [''])[0];
18
+ return { title, date, url, snippet: text.slice(0, 240) };
19
+ }).filter((row) => row && row.title.length > 4).slice(0, ${js(limit)});
20
+ })()`;
21
+ }
22
+
23
+ cli({
24
+ site: "gov-law",
25
+ name: "search",
26
+ description: "Search the National Laws and Regulations Database",
27
+ domain: "flk.npc.gov.cn",
28
+ strategy: Strategy.PUBLIC,
29
+ browser: true,
30
+ args: [
31
+ { name: "query", type: "str", required: true, positional: true },
32
+ { name: "limit", type: "int", default: 20 },
33
+ ],
34
+ columns: ["title", "date", "url"],
35
+ func: async (page, kwargs) => {
36
+ const p = page as IPage;
37
+ const limit = intArg(kwargs.limit, 20, 100);
38
+ const url = `https://flk.npc.gov.cn/search.html?keyword=${encodeURIComponent(str(kwargs.query))}`;
39
+ await p.goto(url, { settleMs: 2500 });
40
+ const rows = await p.evaluate(lawRowsScript(limit));
41
+ return Array.isArray(rows) ? (rows as Record<string, unknown>[]) : [];
42
+ },
43
+ });
44
+
45
+ cli({
46
+ site: "gov-law",
47
+ name: "recent",
48
+ description: "List recent laws and regulations",
49
+ domain: "flk.npc.gov.cn",
50
+ strategy: Strategy.PUBLIC,
51
+ browser: true,
52
+ args: [{ name: "limit", type: "int", default: 20 }],
53
+ columns: ["title", "date", "url"],
54
+ func: async (page, kwargs) => {
55
+ const p = page as IPage;
56
+ const limit = intArg(kwargs.limit, 20, 100);
57
+ await p.goto("https://flk.npc.gov.cn/", { settleMs: 2500 });
58
+ const rows = await p.evaluate(lawRowsScript(limit));
59
+ return Array.isArray(rows) ? (rows as Record<string, unknown>[]) : [];
60
+ },
61
+ });
@@ -0,0 +1,61 @@
1
+ import { cli, Strategy } from "../../registry.js";
2
+ import type { IPage } from "../../types.js";
3
+ import { intArg, js, str } from "../_shared/browser-tools.js";
4
+
5
+ function policyRowsScript(limit: number): string {
6
+ return `(() => {
7
+ const links = [...document.querySelectorAll('a[href]')];
8
+ const seen = new Set();
9
+ return links.map((a) => {
10
+ const title = (a.textContent || '').replace(/\\s+/g, ' ').trim();
11
+ const href = a.getAttribute('href') || '';
12
+ const url = href ? new URL(href, location.href).href : '';
13
+ if (!title || title.length < 4 || seen.has(url)) return null;
14
+ seen.add(url);
15
+ const parent = a.closest('li, .item, .list, div') || a;
16
+ const text = (parent.textContent || '').replace(/\\s+/g, ' ').trim();
17
+ const date = (text.match(/\\d{4}[-年.]\\d{1,2}[-月.]\\d{1,2}/) || [''])[0];
18
+ return { title, date, url, snippet: text.slice(0, 240) };
19
+ }).filter(Boolean).slice(0, ${js(limit)});
20
+ })()`;
21
+ }
22
+
23
+ cli({
24
+ site: "gov-policy",
25
+ name: "search",
26
+ description: "Search gov.cn policy documents",
27
+ domain: "www.gov.cn",
28
+ strategy: Strategy.PUBLIC,
29
+ browser: true,
30
+ args: [
31
+ { name: "query", type: "str", required: true, positional: true },
32
+ { name: "limit", type: "int", default: 20 },
33
+ ],
34
+ columns: ["title", "date", "url"],
35
+ func: async (page, kwargs) => {
36
+ const p = page as IPage;
37
+ const limit = intArg(kwargs.limit, 20, 100);
38
+ const url = `https://sousuo.www.gov.cn/zcwjk/policyDocumentLibrary?q=${encodeURIComponent(str(kwargs.query))}&t=zhengcelibrary`;
39
+ await p.goto(url, { settleMs: 2500 });
40
+ const rows = await p.evaluate(policyRowsScript(limit));
41
+ return Array.isArray(rows) ? (rows as Record<string, unknown>[]) : [];
42
+ },
43
+ });
44
+
45
+ cli({
46
+ site: "gov-policy",
47
+ name: "recent",
48
+ description: "List latest State Council policy documents",
49
+ domain: "www.gov.cn",
50
+ strategy: Strategy.PUBLIC,
51
+ browser: true,
52
+ args: [{ name: "limit", type: "int", default: 20 }],
53
+ columns: ["title", "date", "url"],
54
+ func: async (page, kwargs) => {
55
+ const p = page as IPage;
56
+ const limit = intArg(kwargs.limit, 20, 100);
57
+ await p.goto("https://www.gov.cn/zhengce/zuixin/", { settleMs: 2500 });
58
+ const rows = await p.evaluate(policyRowsScript(limit));
59
+ return Array.isArray(rows) ? (rows as Record<string, unknown>[]) : [];
60
+ },
61
+ });
@@ -53,7 +53,7 @@ pipeline:
53
53
  # Force integer on limit
54
54
  lim=${UNICLI_LIMIT//[^0-9]/}
55
55
  : "${lim:=50}"
56
- sqlite3 -json "$db" \
56
+ out=$(sqlite3 -json "$db" \
57
57
  "SELECT datetime(m.date/1000000000 + 978307200, 'unixepoch', 'localtime') AS ts, \
58
58
  m.text, \
59
59
  m.is_from_me, \
@@ -63,7 +63,12 @@ pipeline:
63
63
  WHERE h.id = '$h' AND m.text IS NOT NULL \
64
64
  ORDER BY m.date DESC \
65
65
  LIMIT $lim;" \
66
- 2>/dev/null || echo "[]"
66
+ 2>/dev/null) || { echo "[]"; exit 0; }
67
+ if [ -z "$out" ]; then
68
+ echo "[]"
69
+ else
70
+ printf '%s\n' "$out"
71
+ fi
67
72
  env:
68
73
  UNICLI_HANDLE: "${{ args.name }}"
69
74
  UNICLI_LIMIT: "${{ args.limit }}"
@@ -48,7 +48,7 @@ pipeline:
48
48
  # Force integer on limit (strip non-digits, default 50)
49
49
  lim=${UNICLI_LIMIT//[^0-9]/}
50
50
  : "${lim:=50}"
51
- sqlite3 -json "$db" \
51
+ out=$(sqlite3 -json "$db" \
52
52
  "SELECT datetime(date/1000000000 + 978307200, 'unixepoch', 'localtime') AS ts, \
53
53
  text, \
54
54
  is_from_me, \
@@ -57,7 +57,12 @@ pipeline:
57
57
  WHERE text IS NOT NULL \
58
58
  ORDER BY date DESC \
59
59
  LIMIT $lim;" \
60
- 2>/dev/null || echo "[]"
60
+ 2>/dev/null) || { echo "[]"; exit 0; }
61
+ if [ -z "$out" ]; then
62
+ echo "[]"
63
+ else
64
+ printf '%s\n' "$out"
65
+ fi
61
66
  env:
62
67
  UNICLI_LIMIT: "${{ args.limit }}"
63
68
  parse: json
@@ -55,7 +55,7 @@ pipeline:
55
55
  # Force integer on limit
56
56
  lim=${UNICLI_LIMIT//[^0-9]/}
57
57
  : "${lim:=50}"
58
- sqlite3 -json "$db" \
58
+ out=$(sqlite3 -json "$db" \
59
59
  "SELECT datetime(m.date/1000000000 + 978307200, 'unixepoch', 'localtime') AS ts, \
60
60
  m.text, \
61
61
  m.is_from_me, \
@@ -65,7 +65,12 @@ pipeline:
65
65
  WHERE m.text LIKE '%$q%' \
66
66
  ORDER BY m.date DESC \
67
67
  LIMIT $lim;" \
68
- 2>/dev/null || echo "[]"
68
+ 2>/dev/null) || { echo "[]"; exit 0; }
69
+ if [ -z "$out" ]; then
70
+ echo "[]"
71
+ else
72
+ printf '%s\n' "$out"
73
+ fi
69
74
  env:
70
75
  UNICLI_QUERY: "${{ args.text }}"
71
76
  UNICLI_LIMIT: "${{ args.limit }}"
@@ -0,0 +1,142 @@
1
+ import { cli, Strategy } from "../../registry.js";
2
+ import type { IPage } from "../../types.js";
3
+ import { clickFirst, intArg, js, str } from "../_shared/browser-tools.js";
4
+
5
+ async function jdDetail(sku: string): Promise<Record<string, unknown>> {
6
+ const body = JSON.stringify({ skuId: sku });
7
+ const url = new URL("https://api.m.jd.com/api");
8
+ url.searchParams.set("appid", "item-v3");
9
+ url.searchParams.set("functionId", "pc_detailpage_wareBusiness");
10
+ url.searchParams.set("body", body);
11
+ const response = await fetch(url);
12
+ const data = (await response.json()) as Record<string, unknown>;
13
+ const ware = (data.wareInfo ?? {}) as Record<string, unknown>;
14
+ const price = (data.priceInfo ?? {}) as Record<string, unknown>;
15
+ const shop = (data.shopInfo ?? {}) as Record<string, unknown>;
16
+ const stock = (data.stockInfo ?? {}) as Record<string, unknown>;
17
+ return {
18
+ sku,
19
+ title: str(ware.wname),
20
+ brand: str(ware.brand),
21
+ price: str(price.price),
22
+ shop: str(shop.shop),
23
+ stock: str(stock.stockDesc),
24
+ url: `https://item.jd.com/${sku}.html`,
25
+ };
26
+ }
27
+
28
+ cli({
29
+ site: "jd",
30
+ name: "detail",
31
+ description: "Fetch JD product detail by SKU",
32
+ domain: "jd.com",
33
+ strategy: Strategy.PUBLIC,
34
+ args: [{ name: "sku", type: "str", required: true, positional: true }],
35
+ columns: ["title", "price", "shop", "stock", "sku"],
36
+ func: async (_page, kwargs) => [await jdDetail(str(kwargs.sku))],
37
+ });
38
+
39
+ cli({
40
+ site: "jd",
41
+ name: "reviews",
42
+ description: "Fetch JD product reviews by SKU",
43
+ domain: "jd.com",
44
+ strategy: Strategy.PUBLIC,
45
+ args: [
46
+ { name: "sku", type: "str", required: true, positional: true },
47
+ { name: "limit", type: "int", default: 10 },
48
+ ],
49
+ columns: ["nickname", "score", "content", "creationTime"],
50
+ func: async (_page, kwargs) => {
51
+ const sku = str(kwargs.sku);
52
+ const limit = intArg(kwargs.limit, 10, 50);
53
+ const url = new URL(
54
+ "https://club.jd.com/comment/productPageComments.action",
55
+ );
56
+ url.searchParams.set("productId", sku);
57
+ url.searchParams.set("score", "0");
58
+ url.searchParams.set("sortType", "5");
59
+ url.searchParams.set("page", "0");
60
+ url.searchParams.set("pageSize", String(limit));
61
+ const response = await fetch(url, {
62
+ headers: { "user-agent": "Mozilla/5.0 (compatible; Uni-CLI)" },
63
+ });
64
+ const data = (await response.json()) as {
65
+ comments?: Record<string, unknown>[];
66
+ };
67
+ return (data.comments ?? []).slice(0, limit).map((item) => ({
68
+ nickname: str(item.nickname),
69
+ score: item.score ?? "",
70
+ content: str(item.content).slice(0, 300),
71
+ creationTime: str(item.creationTime),
72
+ }));
73
+ },
74
+ });
75
+
76
+ cli({
77
+ site: "jd",
78
+ name: "cart",
79
+ description: "Read JD cart items from the active browser session",
80
+ domain: "jd.com",
81
+ strategy: Strategy.COOKIE,
82
+ browser: true,
83
+ args: [{ name: "limit", type: "int", default: 30 }],
84
+ columns: ["title", "price", "quantity", "url"],
85
+ func: async (page, kwargs) => {
86
+ const p = page as IPage;
87
+ await p.goto("https://cart.jd.com/cart_index", { settleMs: 3000 });
88
+ const limit = intArg(kwargs.limit, 30, 100);
89
+ const rows = (await p.evaluate(`(() => {
90
+ const cards = [...document.querySelectorAll('.item-list .item-item, .cart-item-list .item-form')];
91
+ return cards.map((card) => {
92
+ const link = card.querySelector('.p-name a, a[href*="item.jd.com"]');
93
+ return {
94
+ title: (link?.textContent || '').replace(/\\s+/g, ' ').trim(),
95
+ price: (card.querySelector('.p-price, .price')?.textContent || '').replace(/\\s+/g, ' ').trim(),
96
+ quantity: (card.querySelector('input.itxt, input[type="text"]')?.value || '').trim(),
97
+ url: link ? new URL(link.getAttribute('href') || '', location.href).href : ''
98
+ };
99
+ }).filter((row) => row.title).slice(0, ${js(limit)});
100
+ })()`)) as Record<string, unknown>[];
101
+ return rows;
102
+ },
103
+ });
104
+
105
+ cli({
106
+ site: "jd",
107
+ name: "add-cart",
108
+ description: "Add a JD product to cart in the active browser session",
109
+ domain: "jd.com",
110
+ strategy: Strategy.COOKIE,
111
+ browser: true,
112
+ args: [
113
+ { name: "sku", type: "str", required: true, positional: true },
114
+ { name: "quantity", type: "int", default: 1 },
115
+ ],
116
+ columns: ["ok", "selector", "url"],
117
+ func: async (page, kwargs) => {
118
+ const p = page as IPage;
119
+ const sku = str(kwargs.sku);
120
+ await p.goto(`https://item.jd.com/${encodeURIComponent(sku)}.html`, {
121
+ settleMs: 3000,
122
+ });
123
+ const quantity = intArg(kwargs.quantity, 1, 99);
124
+ if (quantity > 1) {
125
+ await p.evaluate(`(() => {
126
+ const input = document.querySelector('#buy-num, input.quantity, input[type="text"]');
127
+ if (input) {
128
+ input.value = ${js(String(quantity))};
129
+ input.dispatchEvent(new Event('input', { bubbles: true }));
130
+ input.dispatchEvent(new Event('change', { bubbles: true }));
131
+ }
132
+ })()`);
133
+ }
134
+ const selector = await clickFirst(p, [
135
+ "#InitCartUrl",
136
+ "#btn-add-cart",
137
+ ".btn-append",
138
+ "a[href*='cart']",
139
+ ]);
140
+ return [{ ok: selector !== null, selector, url: await p.url() }];
141
+ },
142
+ });
@@ -0,0 +1,28 @@
1
+ import { cli, Strategy } from "../../registry.js";
2
+ import type { IPage } from "../../types.js";
3
+ import { str, visibleText } from "../_shared/browser-tools.js";
4
+
5
+ cli({
6
+ site: "jianyu",
7
+ name: "detail",
8
+ description: "Extract Jianyu procurement notice detail evidence",
9
+ domain: "www.jianyu360.cn",
10
+ strategy: Strategy.COOKIE,
11
+ browser: true,
12
+ args: [{ name: "url", type: "str", required: true, positional: true }],
13
+ columns: ["title", "published_at", "detail_text", "url"],
14
+ func: async (page, kwargs) => {
15
+ const p = page as IPage;
16
+ await p.goto(str(kwargs.url), { settleMs: 2500 });
17
+ const text = await visibleText(p);
18
+ const date = (text.match(/\d{4}[-年.]\d{1,2}[-月.]\d{1,2}/) ?? [""])[0];
19
+ return [
20
+ {
21
+ title: await p.title(),
22
+ published_at: date,
23
+ detail_text: text.slice(0, 8000),
24
+ url: await p.url(),
25
+ },
26
+ ];
27
+ },
28
+ });
@@ -0,0 +1,53 @@
1
+ import { cli, Strategy } from "../../registry.js";
2
+ import type { IPage } from "../../types.js";
3
+ import { clickFirst, intArg, js } from "../_shared/browser-tools.js";
4
+
5
+ const JIMENG =
6
+ "https://jimeng.jianying.com/ai-tool/generate?type=image&workspace=0";
7
+
8
+ cli({
9
+ site: "jimeng",
10
+ name: "new",
11
+ description: "Open a new Jimeng generation workspace",
12
+ domain: "jimeng.jianying.com",
13
+ strategy: Strategy.COOKIE,
14
+ browser: true,
15
+ columns: ["ok", "url"],
16
+ func: async (page) => {
17
+ const p = page as IPage;
18
+ await p.goto(JIMENG, { settleMs: 2500 });
19
+ const selector = await clickFirst(p, [
20
+ "button[aria-label*='新建']",
21
+ "button[title*='新建']",
22
+ ".lv-btn-primary",
23
+ ]);
24
+ return [{ ok: true, selector, url: await p.url() }];
25
+ },
26
+ });
27
+
28
+ cli({
29
+ site: "jimeng",
30
+ name: "workspaces",
31
+ description: "List Jimeng visible workspaces",
32
+ domain: "jimeng.jianying.com",
33
+ strategy: Strategy.COOKIE,
34
+ browser: true,
35
+ args: [{ name: "limit", type: "int", default: 20 }],
36
+ columns: ["name", "url"],
37
+ func: async (page, kwargs) => {
38
+ const p = page as IPage;
39
+ const limit = intArg(kwargs.limit, 20, 100);
40
+ await p.goto(JIMENG, { settleMs: 2500 });
41
+ const rows = await p.evaluate(`(() => {
42
+ const links = [...document.querySelectorAll('a[href*="workspace"], [class*="workspace"] a[href]')];
43
+ const seen = new Set();
44
+ return links.map((a) => {
45
+ const url = new URL(a.getAttribute('href') || '', location.href).href;
46
+ if (seen.has(url)) return null;
47
+ seen.add(url);
48
+ return { name: (a.textContent || '').replace(/\\s+/g, ' ').trim(), url };
49
+ }).filter((row) => row && row.name).slice(0, ${js(limit)});
50
+ })()`);
51
+ return Array.isArray(rows) ? (rows as Record<string, unknown>[]) : [];
52
+ },
53
+ });