@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,71 @@
1
+ site: powerpoint
2
+ name: insert-image
3
+ description: Insert a local image into the active Microsoft PowerPoint slide
4
+ type: desktop
5
+ strategy: public
6
+ binary: osascript
7
+ detect: "test $(uname) = Darwin"
8
+
9
+ args:
10
+ path:
11
+ type: str
12
+ required: true
13
+ positional: true
14
+ description: Local image path to embed
15
+
16
+ pipeline:
17
+ - exec:
18
+ command: osascript
19
+ args:
20
+ - "-e"
21
+ - |
22
+ on replace_text(theText, searchString, replacementString)
23
+ set AppleScript's text item delimiters to searchString
24
+ set parts to text items of (theText as text)
25
+ set AppleScript's text item delimiters to replacementString
26
+ set outText to parts as text
27
+ set AppleScript's text item delimiters to ""
28
+ return outText
29
+ end replace_text
30
+
31
+ on json_string(valueText)
32
+ set s to valueText as text
33
+ set s to my replace_text(s, "\\", "\\\\")
34
+ set s to my replace_text(s, "\"", "\\\"")
35
+ set s to my replace_text(s, return, "\\n")
36
+ set s to my replace_text(s, linefeed, "\\n")
37
+ set s to my replace_text(s, tab, "\\t")
38
+ return "\"" & s & "\""
39
+ end json_string
40
+
41
+ set imagePath to system attribute "UNICLI_IMAGE_PATH"
42
+
43
+ try
44
+ do shell script "test -f " & quoted form of imagePath
45
+ with timeout of 10 seconds
46
+ tell application "Microsoft PowerPoint"
47
+ activate
48
+ if (count presentations) is 0 then make new presentation
49
+ set p to active presentation
50
+ if (count slides of p) is 0 then make new slide at end of p with properties {layout:slide layout text slide}
51
+ set s to slide (count slides of p) of p
52
+ make new picture at s with properties {file name:imagePath, link to file:false, save with document:true, left position:72, top:144, width:360, height:240}
53
+ return "[{\"presentation\":" & my json_string(name of p as text) & ",\"slide_index\":" & (slide index of s) & ",\"path\":" & my json_string(imagePath) & ",\"embedded\":true,\"pictures\":" & (count pictures of s) & "}]"
54
+ end tell
55
+ end timeout
56
+ on error errMsg number errNum
57
+ return "[{\"ok\":false,\"code\":\"office_automation_unavailable\",\"message\":" & my json_string(errMsg) & ",\"number\":" & errNum & "}]"
58
+ end try
59
+ env:
60
+ UNICLI_IMAGE_PATH: "${{ args.path }}"
61
+ parse: json
62
+ timeout: 15000
63
+
64
+ columns: [presentation, slide_index, path, embedded, pictures]
65
+
66
+ capabilities: ["subprocess.exec"]
67
+ minimum_capability: subprocess.exec
68
+ trust: user
69
+ confidentiality: private
70
+ quarantine: false
71
+ schema_version: v2
@@ -0,0 +1,94 @@
1
+ site: powerpoint
2
+ name: insert-link
3
+ description: Insert linked text on the active Microsoft PowerPoint slide
4
+ type: desktop
5
+ strategy: public
6
+ binary: osascript
7
+ detect: "test $(uname) = Darwin"
8
+
9
+ args:
10
+ url:
11
+ type: str
12
+ required: true
13
+ positional: true
14
+ description: Link URL or file URL
15
+ text:
16
+ type: str
17
+ required: false
18
+ default: ""
19
+ description: Display text; defaults to the URL
20
+
21
+ pipeline:
22
+ - exec:
23
+ command: osascript
24
+ args:
25
+ - "-e"
26
+ - |
27
+ on replace_text(theText, searchString, replacementString)
28
+ set AppleScript's text item delimiters to searchString
29
+ set parts to text items of (theText as text)
30
+ set AppleScript's text item delimiters to replacementString
31
+ set outText to parts as text
32
+ set AppleScript's text item delimiters to ""
33
+ return outText
34
+ end replace_text
35
+
36
+ on json_string(valueText)
37
+ set s to valueText as text
38
+ set s to my replace_text(s, "\\", "\\\\")
39
+ set s to my replace_text(s, "\"", "\\\"")
40
+ set s to my replace_text(s, return, "\\n")
41
+ set s to my replace_text(s, linefeed, "\\n")
42
+ set s to my replace_text(s, tab, "\\t")
43
+ return "\"" & s & "\""
44
+ end json_string
45
+
46
+ set linkUrl to system attribute "UNICLI_URL"
47
+ set linkText to system attribute "UNICLI_TEXT"
48
+ if linkText is "" then set linkText to linkUrl
49
+
50
+ try
51
+ with timeout of 10 seconds
52
+ tell application "Microsoft PowerPoint"
53
+ activate
54
+ if (count presentations) is 0 then make new presentation
55
+ set p to active presentation
56
+ if (count slides of p) is 0 then make new slide at end of p with properties {layout:slide layout text slide}
57
+ set s to slide (count slides of p) of p
58
+ set linkShape to missing value
59
+ repeat with i from 1 to count shapes of s
60
+ set shp to shape i of s
61
+ if (has text frame of shp) is true then
62
+ set linkShape to shp
63
+ exit repeat
64
+ end if
65
+ end repeat
66
+ if linkShape is missing value then
67
+ set s to make new slide at end of p with properties {layout:slide layout text slide}
68
+ set linkShape to shape 1 of s
69
+ end if
70
+ set tr to text range of text frame of linkShape
71
+ set content of tr to linkText
72
+ set clickAction to get action setting for linkShape event mouse activation mouse click
73
+ set action of clickAction to action type hyperlink action
74
+ set hyperlink address of hyperlink of clickAction to linkUrl
75
+ return "[{\"presentation\":" & my json_string(name of p as text) & ",\"slide_index\":" & (slide index of s) & ",\"url\":" & my json_string(linkUrl) & ",\"text\":" & my json_string(linkText) & "}]"
76
+ end tell
77
+ end timeout
78
+ on error errMsg number errNum
79
+ return "[{\"ok\":false,\"code\":\"office_automation_unavailable\",\"message\":" & my json_string(errMsg) & ",\"number\":" & errNum & "}]"
80
+ end try
81
+ env:
82
+ UNICLI_URL: "${{ args.url }}"
83
+ UNICLI_TEXT: "${{ args.text }}"
84
+ parse: json
85
+ timeout: 15000
86
+
87
+ columns: [presentation, slide_index, url, text]
88
+
89
+ capabilities: ["subprocess.exec"]
90
+ minimum_capability: subprocess.exec
91
+ trust: user
92
+ confidentiality: private
93
+ quarantine: false
94
+ schema_version: v2
@@ -0,0 +1,58 @@
1
+ site: powerpoint
2
+ name: list
3
+ description: List open Microsoft PowerPoint presentations
4
+ type: desktop
5
+ strategy: public
6
+ binary: osascript
7
+ detect: "test $(uname) = Darwin"
8
+
9
+ pipeline:
10
+ - exec:
11
+ command: osascript
12
+ args:
13
+ - "-e"
14
+ - |
15
+ on replace_text(theText, searchString, replacementString)
16
+ set AppleScript's text item delimiters to searchString
17
+ set parts to text items of (theText as text)
18
+ set AppleScript's text item delimiters to replacementString
19
+ set outText to parts as text
20
+ set AppleScript's text item delimiters to ""
21
+ return outText
22
+ end replace_text
23
+
24
+ on json_string(valueText)
25
+ set s to valueText as text
26
+ set s to my replace_text(s, "\\", "\\\\")
27
+ set s to my replace_text(s, "\"", "\\\"")
28
+ set s to my replace_text(s, return, "\\n")
29
+ set s to my replace_text(s, linefeed, "\\n")
30
+ set s to my replace_text(s, tab, "\\t")
31
+ return "\"" & s & "\""
32
+ end json_string
33
+
34
+ if not application "Microsoft PowerPoint" is running then return "[]"
35
+
36
+ tell application "System Events"
37
+ tell process "Microsoft PowerPoint"
38
+ set windowCount to count windows
39
+ set outText to "["
40
+ repeat with i from 1 to windowCount
41
+ set presName to name of window i as text
42
+ if i > 1 then set outText to outText & ","
43
+ set outText to outText & "{\"index\":" & i & ",\"name\":" & my json_string(presName) & ",\"path\":\"\",\"slides\":0,\"source\":\"window\"}"
44
+ end repeat
45
+ end tell
46
+ return outText & "]"
47
+ end tell
48
+ parse: json
49
+ timeout: 30000
50
+
51
+ columns: [index, name, path, slides, source]
52
+
53
+ capabilities: ["subprocess.exec"]
54
+ minimum_capability: subprocess.exec
55
+ trust: user
56
+ confidentiality: private
57
+ quarantine: false
58
+ schema_version: v2
@@ -0,0 +1,101 @@
1
+ site: powerpoint
2
+ name: set-font
3
+ description: Apply a font to text on the active Microsoft PowerPoint slide
4
+ type: desktop
5
+ strategy: public
6
+ binary: osascript
7
+ detect: "test $(uname) = Darwin"
8
+
9
+ args:
10
+ font:
11
+ type: str
12
+ required: true
13
+ positional: true
14
+ description: Font family to apply
15
+ size:
16
+ type: str
17
+ required: false
18
+ default: ""
19
+ description: Optional font size in points
20
+ text:
21
+ type: str
22
+ required: false
23
+ default: ""
24
+ description: Optional text filter; defaults to all text on the active slide
25
+
26
+ pipeline:
27
+ - exec:
28
+ command: osascript
29
+ args:
30
+ - "-e"
31
+ - |
32
+ on replace_text(theText, searchString, replacementString)
33
+ set AppleScript's text item delimiters to searchString
34
+ set parts to text items of (theText as text)
35
+ set AppleScript's text item delimiters to replacementString
36
+ set outText to parts as text
37
+ set AppleScript's text item delimiters to ""
38
+ return outText
39
+ end replace_text
40
+
41
+ on json_string(valueText)
42
+ set s to valueText as text
43
+ set s to my replace_text(s, "\\", "\\\\")
44
+ set s to my replace_text(s, "\"", "\\\"")
45
+ set s to my replace_text(s, return, "\\n")
46
+ set s to my replace_text(s, linefeed, "\\n")
47
+ set s to my replace_text(s, tab, "\\t")
48
+ return "\"" & s & "\""
49
+ end json_string
50
+
51
+ set fontName to system attribute "UNICLI_FONT"
52
+ set sizeText to system attribute "UNICLI_SIZE"
53
+ set targetText to system attribute "UNICLI_TEXT"
54
+
55
+ try
56
+ with timeout of 10 seconds
57
+ tell application "Microsoft PowerPoint"
58
+ activate
59
+ if (count presentations) is 0 then return "[]"
60
+ set p to active presentation
61
+ if (count slides of p) is 0 then make new slide at end of p with properties {layout:slide layout text slide}
62
+ set s to slide (count slides of p) of p
63
+ set appliedCount to 0
64
+ repeat with i from 1 to count shapes of s
65
+ set shp to shape i of s
66
+ if (has text frame of shp) is true then
67
+ set tf to text frame of shp
68
+ if (has text of tf) is true then
69
+ set tr to text range of tf
70
+ set shapeText to content of tr as text
71
+ if targetText is "" or shapeText contains targetText then
72
+ set f to font of tr
73
+ set font name of f to fontName
74
+ if sizeText is not "" then set font size of f to (sizeText as real)
75
+ set appliedCount to appliedCount + 1
76
+ end if
77
+ end if
78
+ end if
79
+ end repeat
80
+ if appliedCount is 0 then error "No matching PowerPoint text found"
81
+ return "[{\"presentation\":" & my json_string(name of p as text) & ",\"slide_index\":" & (slide index of s) & ",\"font\":" & my json_string(fontName) & ",\"size\":" & my json_string(sizeText) & ",\"shapes\":" & appliedCount & "}]"
82
+ end tell
83
+ end timeout
84
+ on error errMsg number errNum
85
+ return "[{\"ok\":false,\"code\":\"office_automation_unavailable\",\"message\":" & my json_string(errMsg) & ",\"number\":" & errNum & "}]"
86
+ end try
87
+ env:
88
+ UNICLI_FONT: "${{ args.font }}"
89
+ UNICLI_SIZE: "${{ args.size }}"
90
+ UNICLI_TEXT: "${{ args.text }}"
91
+ parse: json
92
+ timeout: 15000
93
+
94
+ columns: [presentation, slide_index, font, size, shapes]
95
+
96
+ capabilities: ["subprocess.exec"]
97
+ minimum_capability: subprocess.exec
98
+ trust: user
99
+ confidentiality: private
100
+ quarantine: false
101
+ schema_version: v2
@@ -0,0 +1,73 @@
1
+ site: powerpoint
2
+ name: slides
3
+ description: List slide text snippets from the active Microsoft PowerPoint presentation
4
+ type: desktop
5
+ strategy: public
6
+ binary: osascript
7
+ detect: "test $(uname) = Darwin"
8
+
9
+ pipeline:
10
+ - exec:
11
+ command: osascript
12
+ args:
13
+ - "-e"
14
+ - |
15
+ on replace_text(theText, searchString, replacementString)
16
+ set AppleScript's text item delimiters to searchString
17
+ set parts to text items of (theText as text)
18
+ set AppleScript's text item delimiters to replacementString
19
+ set outText to parts as text
20
+ set AppleScript's text item delimiters to ""
21
+ return outText
22
+ end replace_text
23
+
24
+ on json_string(valueText)
25
+ set s to valueText as text
26
+ set s to my replace_text(s, "\\", "\\\\")
27
+ set s to my replace_text(s, "\"", "\\\"")
28
+ set s to my replace_text(s, return, "\\n")
29
+ set s to my replace_text(s, linefeed, "\\n")
30
+ set s to my replace_text(s, tab, "\\t")
31
+ return "\"" & s & "\""
32
+ end json_string
33
+
34
+ if not application "Microsoft PowerPoint" is running then return "[]"
35
+
36
+ try
37
+ with timeout of 10 seconds
38
+ tell application "Microsoft PowerPoint"
39
+ if (count presentations) is 0 then return "[]"
40
+ set p to active presentation
41
+ set outText to "["
42
+ repeat with i from 1 to count slides of p
43
+ set s to slide i of p
44
+ set snippet to ""
45
+ repeat with j from 1 to count shapes of s
46
+ set shp to shape j of s
47
+ try
48
+ if (has text frame of shp) is true then
49
+ set tf to text frame of shp
50
+ if (has text of tf) is true then set snippet to snippet & (content of text range of tf as text) & linefeed
51
+ end if
52
+ end try
53
+ end repeat
54
+ if i > 1 then set outText to outText & ","
55
+ set outText to outText & "{\"index\":" & i & ",\"name\":" & my json_string(name of s as text) & ",\"text\":" & my json_string(snippet) & "}"
56
+ end repeat
57
+ return outText & "]"
58
+ end tell
59
+ end timeout
60
+ on error errMsg number errNum
61
+ return "[{\"ok\":false,\"code\":\"office_automation_unavailable\",\"message\":" & my json_string(errMsg) & ",\"number\":" & errNum & "}]"
62
+ end try
63
+ parse: json
64
+ timeout: 30000
65
+
66
+ columns: [index, name, text]
67
+
68
+ capabilities: ["subprocess.exec"]
69
+ minimum_capability: subprocess.exec
70
+ trust: user
71
+ confidentiality: private
72
+ quarantine: false
73
+ schema_version: v2
@@ -0,0 +1,29 @@
1
+ site: powerpoint
2
+ name: status
3
+ description: Check Microsoft PowerPoint running state without enumerating presentations
4
+ type: desktop
5
+ strategy: public
6
+ binary: osascript
7
+ detect: "test $(uname) = Darwin"
8
+
9
+ pipeline:
10
+ - exec:
11
+ command: osascript
12
+ args:
13
+ - "-l"
14
+ - "JavaScript"
15
+ - "-e"
16
+ - |
17
+ var app = Application('Microsoft PowerPoint');
18
+ JSON.stringify([{ app: 'Microsoft PowerPoint', bundle_id: app.id(), running: app.running() }]);
19
+ parse: json
20
+ timeout: 10000
21
+
22
+ columns: [app, bundle_id, running]
23
+
24
+ capabilities: ["subprocess.exec"]
25
+ minimum_capability: subprocess.exec
26
+ trust: user
27
+ confidentiality: private
28
+ quarantine: false
29
+ schema_version: v2
@@ -0,0 +1,169 @@
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
+ const DRIVE = "https://drive-pc.quark.cn/list#/list/all";
6
+
7
+ async function openDrive(page: IPage): Promise<void> {
8
+ await page.goto(DRIVE, { settleMs: 1800 });
9
+ }
10
+
11
+ async function driveFetch(
12
+ page: IPage,
13
+ path: string,
14
+ body: Record<string, unknown>,
15
+ ): Promise<Record<string, unknown>[]> {
16
+ await openDrive(page);
17
+ const result = await page.evaluate(`(async () => {
18
+ const response = await fetch(${js(path)}, {
19
+ method: 'POST',
20
+ credentials: 'include',
21
+ headers: { 'content-type': 'application/json;charset=utf-8' },
22
+ body: ${js(JSON.stringify(body))}
23
+ });
24
+ let data = null;
25
+ try { data = await response.json(); } catch {}
26
+ return [{
27
+ ok: response.ok,
28
+ status: response.status,
29
+ data,
30
+ message: data?.message || data?.error || ''
31
+ }];
32
+ })()`);
33
+ return Array.isArray(result) ? (result as Record<string, unknown>[]) : [];
34
+ }
35
+
36
+ function fidList(value: unknown): string[] {
37
+ return str(value)
38
+ .split(",")
39
+ .map((item) => item.trim())
40
+ .filter(Boolean);
41
+ }
42
+
43
+ cli({
44
+ site: "quark",
45
+ name: "mkdir",
46
+ description: "Create a folder in Quark Drive",
47
+ domain: "drive-pc.quark.cn",
48
+ strategy: Strategy.COOKIE,
49
+ browser: true,
50
+ args: [
51
+ { name: "name", type: "str", required: true, positional: true },
52
+ { name: "parent_fid", type: "str", default: "0" },
53
+ ],
54
+ columns: ["ok", "status", "message"],
55
+ func: async (page, kwargs) =>
56
+ driveFetch(page as IPage, "/1/clouddrive/file?fr=pc", {
57
+ pdir_fid: str(kwargs.parent_fid, "0"),
58
+ file_name: str(kwargs.name),
59
+ dir_path: "",
60
+ }),
61
+ });
62
+
63
+ cli({
64
+ site: "quark",
65
+ name: "rename",
66
+ description: "Rename a Quark Drive file or folder",
67
+ domain: "drive-pc.quark.cn",
68
+ strategy: Strategy.COOKIE,
69
+ browser: true,
70
+ args: [
71
+ { name: "fid", type: "str", required: true, positional: true },
72
+ { name: "name", type: "str", required: true },
73
+ ],
74
+ columns: ["ok", "status", "message"],
75
+ func: async (page, kwargs) =>
76
+ driveFetch(page as IPage, "/1/clouddrive/file/rename?fr=pc", {
77
+ fid: str(kwargs.fid),
78
+ file_name: str(kwargs.name),
79
+ }),
80
+ });
81
+
82
+ cli({
83
+ site: "quark",
84
+ name: "rm",
85
+ description: "Delete Quark Drive files or folders by fid list",
86
+ domain: "drive-pc.quark.cn",
87
+ strategy: Strategy.COOKIE,
88
+ browser: true,
89
+ args: [{ name: "fids", type: "str", required: true, positional: true }],
90
+ columns: ["ok", "status", "message"],
91
+ func: async (page, kwargs) =>
92
+ driveFetch(page as IPage, "/1/clouddrive/file/delete?fr=pc", {
93
+ action_type: 2,
94
+ filelist: fidList(kwargs.fids).map((fid) => ({ fid })),
95
+ }),
96
+ });
97
+
98
+ cli({
99
+ site: "quark",
100
+ name: "mv",
101
+ description: "Move Quark Drive files to a target folder fid",
102
+ domain: "drive-pc.quark.cn",
103
+ strategy: Strategy.COOKIE,
104
+ browser: true,
105
+ args: [
106
+ { name: "fids", type: "str", required: true, positional: true },
107
+ { name: "to_fid", type: "str", required: true },
108
+ ],
109
+ columns: ["ok", "status", "message"],
110
+ func: async (page, kwargs) =>
111
+ driveFetch(page as IPage, "/1/clouddrive/file/move?fr=pc", {
112
+ to_pdir_fid: str(kwargs.to_fid),
113
+ action_type: 1,
114
+ filelist: fidList(kwargs.fids).map((fid) => ({ fid })),
115
+ }),
116
+ });
117
+
118
+ cli({
119
+ site: "quark",
120
+ name: "share-tree",
121
+ description: "Read a Quark share page directory tree",
122
+ domain: "pan.quark.cn",
123
+ strategy: Strategy.COOKIE,
124
+ browser: true,
125
+ args: [
126
+ { name: "url", type: "str", required: true, positional: true },
127
+ { name: "limit", type: "int", default: 100 },
128
+ ],
129
+ columns: ["name", "type", "size"],
130
+ func: async (page, kwargs) => {
131
+ const p = page as IPage;
132
+ await p.goto(str(kwargs.url), { settleMs: 2500 });
133
+ const limit = intArg(kwargs.limit, 100, 500);
134
+ const rows = await p.evaluate(`(() => {
135
+ const cards = [...document.querySelectorAll('[class*="file"], [class*="item"], [role="row"]')];
136
+ return cards.map((card) => ({
137
+ name: (card.querySelector('[class*="name"], [title]')?.textContent || card.getAttribute('title') || '').replace(/\\s+/g, ' ').trim(),
138
+ type: /folder|文件夹/.test(card.textContent || '') ? 'folder' : 'file',
139
+ size: (card.querySelector('[class*="size"]')?.textContent || '').trim()
140
+ })).filter((row) => row.name).slice(0, ${js(limit)});
141
+ })()`);
142
+ return Array.isArray(rows) ? (rows as Record<string, unknown>[]) : [];
143
+ },
144
+ });
145
+
146
+ cli({
147
+ site: "quark",
148
+ name: "save",
149
+ description: "Save a Quark share into the active Drive account",
150
+ domain: "pan.quark.cn",
151
+ strategy: Strategy.COOKIE,
152
+ browser: true,
153
+ args: [
154
+ { name: "url", type: "str", required: true, positional: true },
155
+ { name: "to_fid", type: "str", required: false },
156
+ ],
157
+ columns: ["ok", "selector", "url"],
158
+ func: async (page, kwargs) => {
159
+ const p = page as IPage;
160
+ await p.goto(str(kwargs.url), { settleMs: 2500 });
161
+ const selector = await clickFirst(p, [
162
+ "button[class*='save']",
163
+ "button[aria-label*='保存']",
164
+ "button[title*='保存']",
165
+ "button",
166
+ ]);
167
+ return [{ ok: selector !== null, selector, url: await p.url() }];
168
+ },
169
+ });
@@ -0,0 +1,93 @@
1
+ import type { IPage } from "../../types.js";
2
+
3
+ interface BrowserJsonResponse {
4
+ ok?: boolean;
5
+ status?: number;
6
+ message?: string;
7
+ data?: unknown;
8
+ }
9
+
10
+ export function clampLimit(value: unknown, fallback = 20): number {
11
+ const n =
12
+ typeof value === "number"
13
+ ? value
14
+ : typeof value === "string"
15
+ ? Number.parseInt(value, 10)
16
+ : fallback;
17
+ if (!Number.isFinite(n) || n <= 0) return fallback;
18
+ return Math.min(Math.trunc(n), 100);
19
+ }
20
+
21
+ export function normalizeSubreddit(value: unknown): string {
22
+ const raw = String(value ?? "").trim();
23
+ return raw.startsWith("r/") ? raw.slice(2) : raw;
24
+ }
25
+
26
+ export async function redditJson(
27
+ page: IPage,
28
+ path: string,
29
+ params: Record<string, string | number | boolean | undefined>,
30
+ ): Promise<unknown> {
31
+ await page.goto("https://www.reddit.com", { settleMs: 500 });
32
+
33
+ const payload = (await page.evaluate(`(async () => {
34
+ const path = ${JSON.stringify(path)};
35
+ const rawParams = ${JSON.stringify(params)};
36
+ const params = new URLSearchParams();
37
+ for (const [key, value] of Object.entries(rawParams)) {
38
+ if (value === undefined || value === null || value === '') continue;
39
+ params.set(key, String(value));
40
+ }
41
+ if (!params.has('raw_json')) params.set('raw_json', '1');
42
+ const res = await fetch(path + '?' + params.toString(), {
43
+ credentials: 'include',
44
+ headers: { accept: 'application/json' }
45
+ });
46
+ const text = await res.text();
47
+ if (!res.ok) {
48
+ return { ok: false, status: res.status, message: text.slice(0, 240) };
49
+ }
50
+ try {
51
+ return { ok: true, data: JSON.parse(text) };
52
+ } catch (err) {
53
+ return { ok: false, status: 0, message: String(err) };
54
+ }
55
+ })()`)) as BrowserJsonResponse;
56
+
57
+ if (!payload?.ok) {
58
+ const status = payload?.status ? `HTTP ${payload.status}` : "unknown";
59
+ throw new Error(
60
+ `Reddit browser JSON failed for ${path}: ${status}. ${payload?.message ?? ""}`,
61
+ );
62
+ }
63
+
64
+ return payload.data;
65
+ }
66
+
67
+ export function redditChildren(data: unknown): Array<Record<string, unknown>> {
68
+ const root = data as { data?: { children?: unknown[] } };
69
+ return Array.isArray(root?.data?.children)
70
+ ? (root.data.children as Array<Record<string, unknown>>)
71
+ : [];
72
+ }
73
+
74
+ export function mapRedditPosts(
75
+ children: Array<Record<string, unknown>>,
76
+ limit: number,
77
+ ): Array<Record<string, unknown>> {
78
+ return children.slice(0, limit).map((child, index) => {
79
+ const data = (child.data ?? {}) as Record<string, unknown>;
80
+ const permalink = String(data.permalink ?? "");
81
+ return {
82
+ rank: index + 1,
83
+ title: String(data.title ?? ""),
84
+ subreddit:
85
+ String(data.subreddit_name_prefixed ?? "") ||
86
+ (data.subreddit ? `r/${String(data.subreddit)}` : ""),
87
+ author: String(data.author ?? ""),
88
+ score: Number(data.score ?? 0),
89
+ comments: Number(data.num_comments ?? 0),
90
+ url: permalink ? `https://www.reddit.com${permalink}` : "",
91
+ };
92
+ });
93
+ }