@zenalexa/unicli 0.219.0 → 0.220.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 (430) hide show
  1. package/AGENTS.md +9 -9
  2. package/README.md +55 -249
  3. package/README.zh-CN.md +55 -249
  4. package/dist/adapters/1point3acres/forum.d.ts +58 -0
  5. package/dist/adapters/1point3acres/forum.d.ts.map +1 -0
  6. package/dist/adapters/1point3acres/forum.js +708 -0
  7. package/dist/adapters/1point3acres/forum.js.map +1 -0
  8. package/dist/adapters/aibase/news.d.ts +21 -0
  9. package/dist/adapters/aibase/news.d.ts.map +1 -0
  10. package/dist/adapters/aibase/news.js +96 -0
  11. package/dist/adapters/aibase/news.js.map +1 -0
  12. package/dist/adapters/arxiv/papers.d.ts +27 -0
  13. package/dist/adapters/arxiv/papers.d.ts.map +1 -0
  14. package/dist/adapters/arxiv/papers.js +193 -0
  15. package/dist/adapters/arxiv/papers.js.map +1 -0
  16. package/dist/adapters/bbc/topic.d.ts +24 -0
  17. package/dist/adapters/bbc/topic.d.ts.map +1 -0
  18. package/dist/adapters/bbc/topic.js +122 -0
  19. package/dist/adapters/bbc/topic.js.map +1 -0
  20. package/dist/adapters/chatgpt/web.d.ts +24 -0
  21. package/dist/adapters/chatgpt/web.d.ts.map +1 -0
  22. package/dist/adapters/chatgpt/web.js +242 -0
  23. package/dist/adapters/chatgpt/web.js.map +1 -0
  24. package/dist/adapters/claude/web.d.ts +24 -0
  25. package/dist/adapters/claude/web.d.ts.map +1 -0
  26. package/dist/adapters/claude/web.js +575 -0
  27. package/dist/adapters/claude/web.js.map +1 -0
  28. package/dist/adapters/codex/projects.d.ts +27 -0
  29. package/dist/adapters/codex/projects.d.ts.map +1 -0
  30. package/dist/adapters/codex/projects.js +147 -0
  31. package/dist/adapters/codex/projects.js.map +1 -0
  32. package/dist/adapters/coingecko/markets.d.ts +19 -0
  33. package/dist/adapters/coingecko/markets.d.ts.map +1 -0
  34. package/dist/adapters/coingecko/markets.js +474 -0
  35. package/dist/adapters/coingecko/markets.js.map +1 -0
  36. package/dist/adapters/coupang/product.d.ts +27 -0
  37. package/dist/adapters/coupang/product.d.ts.map +1 -0
  38. package/dist/adapters/coupang/product.js +211 -0
  39. package/dist/adapters/coupang/product.js.map +1 -0
  40. package/dist/adapters/crates/registry.d.ts +44 -0
  41. package/dist/adapters/crates/registry.d.ts.map +1 -0
  42. package/dist/adapters/crates/registry.js +186 -0
  43. package/dist/adapters/crates/registry.js.map +1 -0
  44. package/dist/adapters/ctrip/travel.d.ts +83 -0
  45. package/dist/adapters/ctrip/travel.d.ts.map +1 -0
  46. package/dist/adapters/ctrip/travel.js +630 -0
  47. package/dist/adapters/ctrip/travel.js.map +1 -0
  48. package/dist/adapters/dblp/publications.d.ts +41 -0
  49. package/dist/adapters/dblp/publications.d.ts.map +1 -0
  50. package/dist/adapters/dblp/publications.js +409 -0
  51. package/dist/adapters/dblp/publications.js.map +1 -0
  52. package/dist/adapters/deepseek/web.d.ts +1 -1
  53. package/dist/adapters/deepseek/web.d.ts.map +1 -1
  54. package/dist/adapters/deepseek/web.js +66 -1
  55. package/dist/adapters/deepseek/web.js.map +1 -1
  56. package/dist/adapters/defillama/protocols.d.ts +13 -0
  57. package/dist/adapters/defillama/protocols.d.ts.map +1 -0
  58. package/dist/adapters/defillama/protocols.js +218 -0
  59. package/dist/adapters/defillama/protocols.js.map +1 -0
  60. package/dist/adapters/devto/read.d.ts +26 -0
  61. package/dist/adapters/devto/read.d.ts.map +1 -0
  62. package/dist/adapters/devto/read.js +110 -0
  63. package/dist/adapters/devto/read.js.map +1 -0
  64. package/dist/adapters/dianping/shop.d.ts +38 -0
  65. package/dist/adapters/dianping/shop.d.ts.map +1 -0
  66. package/dist/adapters/dianping/shop.js +194 -0
  67. package/dist/adapters/dianping/shop.js.map +1 -0
  68. package/dist/adapters/dockerhub/registry.d.ts +36 -0
  69. package/dist/adapters/dockerhub/registry.d.ts.map +1 -0
  70. package/dist/adapters/dockerhub/registry.js +172 -0
  71. package/dist/adapters/dockerhub/registry.js.map +1 -0
  72. package/dist/adapters/endoflife/product.d.ts +11 -0
  73. package/dist/adapters/endoflife/product.d.ts.map +1 -0
  74. package/dist/adapters/endoflife/product.js +113 -0
  75. package/dist/adapters/endoflife/product.js.map +1 -0
  76. package/dist/adapters/facebook/marketplace-extra.d.ts +9 -0
  77. package/dist/adapters/facebook/marketplace-extra.d.ts.map +1 -0
  78. package/dist/adapters/facebook/marketplace-extra.js +170 -0
  79. package/dist/adapters/facebook/marketplace-extra.js.map +1 -0
  80. package/dist/adapters/flathub/apps.d.ts +17 -0
  81. package/dist/adapters/flathub/apps.d.ts.map +1 -0
  82. package/dist/adapters/flathub/apps.js +220 -0
  83. package/dist/adapters/flathub/apps.js.map +1 -0
  84. package/dist/adapters/goproxy/module.d.ts +24 -0
  85. package/dist/adapters/goproxy/module.d.ts.map +1 -0
  86. package/dist/adapters/goproxy/module.js +221 -0
  87. package/dist/adapters/goproxy/module.js.map +1 -0
  88. package/dist/adapters/grok/web.d.ts +29 -0
  89. package/dist/adapters/grok/web.d.ts.map +1 -0
  90. package/dist/adapters/grok/web.js +553 -0
  91. package/dist/adapters/grok/web.js.map +1 -0
  92. package/dist/adapters/hackernews/read.d.ts +31 -0
  93. package/dist/adapters/hackernews/read.d.ts.map +1 -0
  94. package/dist/adapters/hackernews/read.js +201 -0
  95. package/dist/adapters/hackernews/read.js.map +1 -0
  96. package/dist/adapters/hf/paper.d.ts +22 -0
  97. package/dist/adapters/hf/paper.d.ts.map +1 -0
  98. package/dist/adapters/hf/paper.js +112 -0
  99. package/dist/adapters/hf/paper.js.map +1 -0
  100. package/dist/adapters/homebrew/packages.d.ts +52 -0
  101. package/dist/adapters/homebrew/packages.d.ts.map +1 -0
  102. package/dist/adapters/homebrew/packages.js +240 -0
  103. package/dist/adapters/homebrew/packages.js.map +1 -0
  104. package/dist/adapters/indeed/jobs.d.ts +38 -0
  105. package/dist/adapters/indeed/jobs.d.ts.map +1 -0
  106. package/dist/adapters/indeed/jobs.js +300 -0
  107. package/dist/adapters/indeed/jobs.js.map +1 -0
  108. package/dist/adapters/instagram/collections.d.ts +9 -0
  109. package/dist/adapters/instagram/collections.d.ts.map +1 -0
  110. package/dist/adapters/instagram/collections.js +174 -0
  111. package/dist/adapters/instagram/collections.js.map +1 -0
  112. package/dist/adapters/lichess/players.d.ts +46 -0
  113. package/dist/adapters/lichess/players.d.ts.map +1 -0
  114. package/dist/adapters/lichess/players.js +221 -0
  115. package/dist/adapters/lichess/players.js.map +1 -0
  116. package/dist/adapters/lobsters/read-domain.d.ts +35 -0
  117. package/dist/adapters/lobsters/read-domain.d.ts.map +1 -0
  118. package/dist/adapters/lobsters/read-domain.js +306 -0
  119. package/dist/adapters/lobsters/read-domain.js.map +1 -0
  120. package/dist/adapters/maven/artifact.d.ts +30 -0
  121. package/dist/adapters/maven/artifact.d.ts.map +1 -0
  122. package/dist/adapters/maven/artifact.js +121 -0
  123. package/dist/adapters/maven/artifact.js.map +1 -0
  124. package/dist/adapters/mdn/search.d.ts +11 -0
  125. package/dist/adapters/mdn/search.d.ts.map +1 -0
  126. package/dist/adapters/mdn/search.js +115 -0
  127. package/dist/adapters/mdn/search.js.map +1 -0
  128. package/dist/adapters/medium/tag.d.ts +15 -0
  129. package/dist/adapters/medium/tag.d.ts.map +1 -0
  130. package/dist/adapters/medium/tag.js +148 -0
  131. package/dist/adapters/medium/tag.js.map +1 -0
  132. package/dist/adapters/npm/package.d.ts +32 -0
  133. package/dist/adapters/npm/package.d.ts.map +1 -0
  134. package/dist/adapters/npm/package.js +141 -0
  135. package/dist/adapters/npm/package.js.map +1 -0
  136. package/dist/adapters/nuget/package.d.ts +34 -0
  137. package/dist/adapters/nuget/package.d.ts.map +1 -0
  138. package/dist/adapters/nuget/package.js +135 -0
  139. package/dist/adapters/nuget/package.js.map +1 -0
  140. package/dist/adapters/nvd/cve.d.ts +42 -0
  141. package/dist/adapters/nvd/cve.d.ts.map +1 -0
  142. package/dist/adapters/nvd/cve.js +132 -0
  143. package/dist/adapters/nvd/cve.js.map +1 -0
  144. package/dist/adapters/oeis/sequences.d.ts +14 -0
  145. package/dist/adapters/oeis/sequences.d.ts.map +1 -0
  146. package/dist/adapters/oeis/sequences.js +219 -0
  147. package/dist/adapters/oeis/sequences.js.map +1 -0
  148. package/dist/adapters/openalex/works.d.ts +43 -0
  149. package/dist/adapters/openalex/works.d.ts.map +1 -0
  150. package/dist/adapters/openalex/works.js +267 -0
  151. package/dist/adapters/openalex/works.js.map +1 -0
  152. package/dist/adapters/openfda/records.d.ts +18 -0
  153. package/dist/adapters/openfda/records.d.ts.map +1 -0
  154. package/dist/adapters/openfda/records.js +209 -0
  155. package/dist/adapters/openfda/records.js.map +1 -0
  156. package/dist/adapters/openreview/papers.d.ts +34 -0
  157. package/dist/adapters/openreview/papers.d.ts.map +1 -0
  158. package/dist/adapters/openreview/papers.js +463 -0
  159. package/dist/adapters/openreview/papers.js.map +1 -0
  160. package/dist/adapters/osv/security.d.ts +36 -0
  161. package/dist/adapters/osv/security.d.ts.map +1 -0
  162. package/dist/adapters/osv/security.js +247 -0
  163. package/dist/adapters/osv/security.js.map +1 -0
  164. package/dist/adapters/packagist/package.d.ts +31 -0
  165. package/dist/adapters/packagist/package.d.ts.map +1 -0
  166. package/dist/adapters/packagist/package.js +108 -0
  167. package/dist/adapters/packagist/package.js.map +1 -0
  168. package/dist/adapters/pubmed/articles.d.ts +31 -0
  169. package/dist/adapters/pubmed/articles.d.ts.map +1 -0
  170. package/dist/adapters/pubmed/articles.js +385 -0
  171. package/dist/adapters/pubmed/articles.js.map +1 -0
  172. package/dist/adapters/pypi/package.d.ts +38 -0
  173. package/dist/adapters/pypi/package.d.ts.map +1 -0
  174. package/dist/adapters/pypi/package.js +235 -0
  175. package/dist/adapters/pypi/package.js.map +1 -0
  176. package/dist/adapters/qwen/web.d.ts +26 -0
  177. package/dist/adapters/qwen/web.d.ts.map +1 -0
  178. package/dist/adapters/qwen/web.js +672 -0
  179. package/dist/adapters/qwen/web.js.map +1 -0
  180. package/dist/adapters/reddit/account.d.ts +12 -0
  181. package/dist/adapters/reddit/account.d.ts.map +1 -0
  182. package/dist/adapters/reddit/account.js +409 -0
  183. package/dist/adapters/reddit/account.js.map +1 -0
  184. package/dist/adapters/rednote/web.d.ts +30 -0
  185. package/dist/adapters/rednote/web.d.ts.map +1 -0
  186. package/dist/adapters/rednote/web.js +858 -0
  187. package/dist/adapters/rednote/web.js.map +1 -0
  188. package/dist/adapters/rest-countries/countries.d.ts +14 -0
  189. package/dist/adapters/rest-countries/countries.d.ts.map +1 -0
  190. package/dist/adapters/rest-countries/countries.js +231 -0
  191. package/dist/adapters/rest-countries/countries.js.map +1 -0
  192. package/dist/adapters/reuters/article-detail.d.ts +37 -0
  193. package/dist/adapters/reuters/article-detail.d.ts.map +1 -0
  194. package/dist/adapters/reuters/article-detail.js +139 -0
  195. package/dist/adapters/reuters/article-detail.js.map +1 -0
  196. package/dist/adapters/rfc/rfc.d.ts +11 -0
  197. package/dist/adapters/rfc/rfc.d.ts.map +1 -0
  198. package/dist/adapters/rfc/rfc.js +121 -0
  199. package/dist/adapters/rfc/rfc.js.map +1 -0
  200. package/dist/adapters/rubygems/gem.d.ts +26 -0
  201. package/dist/adapters/rubygems/gem.d.ts.map +1 -0
  202. package/dist/adapters/rubygems/gem.js +96 -0
  203. package/dist/adapters/rubygems/gem.js.map +1 -0
  204. package/dist/adapters/stackoverflow/questions.d.ts +79 -0
  205. package/dist/adapters/stackoverflow/questions.d.ts.map +1 -0
  206. package/dist/adapters/stackoverflow/questions.js +504 -0
  207. package/dist/adapters/stackoverflow/questions.js.map +1 -0
  208. package/dist/adapters/steam/app.d.ts +39 -0
  209. package/dist/adapters/steam/app.d.ts.map +1 -0
  210. package/dist/adapters/steam/app.js +165 -0
  211. package/dist/adapters/steam/app.js.map +1 -0
  212. package/dist/adapters/tiktok/creator-videos.d.ts +52 -0
  213. package/dist/adapters/tiktok/creator-videos.d.ts.map +1 -0
  214. package/dist/adapters/tiktok/creator-videos.js +267 -0
  215. package/dist/adapters/tiktok/creator-videos.js.map +1 -0
  216. package/dist/adapters/tvmaze/shows.d.ts +13 -0
  217. package/dist/adapters/tvmaze/shows.d.ts.map +1 -0
  218. package/dist/adapters/tvmaze/shows.js +240 -0
  219. package/dist/adapters/tvmaze/shows.js.map +1 -0
  220. package/dist/adapters/twitter/bookmark-folders.d.ts +33 -0
  221. package/dist/adapters/twitter/bookmark-folders.d.ts.map +1 -0
  222. package/dist/adapters/twitter/bookmark-folders.js +290 -0
  223. package/dist/adapters/twitter/bookmark-folders.js.map +1 -0
  224. package/dist/adapters/twitter/quote.d.ts +18 -0
  225. package/dist/adapters/twitter/quote.d.ts.map +1 -0
  226. package/dist/adapters/twitter/quote.js +285 -0
  227. package/dist/adapters/twitter/quote.js.map +1 -0
  228. package/dist/adapters/twitter/tweet-actions.d.ts +12 -0
  229. package/dist/adapters/twitter/tweet-actions.d.ts.map +1 -0
  230. package/dist/adapters/twitter/tweet-actions.js +145 -0
  231. package/dist/adapters/twitter/tweet-actions.js.map +1 -0
  232. package/dist/adapters/twitter/tweet-url.d.ts +15 -0
  233. package/dist/adapters/twitter/tweet-url.d.ts.map +1 -0
  234. package/dist/adapters/twitter/tweet-url.js +57 -0
  235. package/dist/adapters/twitter/tweet-url.js.map +1 -0
  236. package/dist/adapters/uisdc/news.d.ts +22 -0
  237. package/dist/adapters/uisdc/news.d.ts.map +1 -0
  238. package/dist/adapters/uisdc/news.js +91 -0
  239. package/dist/adapters/uisdc/news.js.map +1 -0
  240. package/dist/adapters/weibo/favorites-publish.d.ts +28 -0
  241. package/dist/adapters/weibo/favorites-publish.d.ts.map +1 -0
  242. package/dist/adapters/weibo/favorites-publish.js +356 -0
  243. package/dist/adapters/weibo/favorites-publish.js.map +1 -0
  244. package/dist/adapters/wikidata/entities.d.ts +15 -0
  245. package/dist/adapters/wikidata/entities.d.ts.map +1 -0
  246. package/dist/adapters/wikidata/entities.js +219 -0
  247. package/dist/adapters/wikidata/entities.js.map +1 -0
  248. package/dist/adapters/wikipedia/page.d.ts +21 -0
  249. package/dist/adapters/wikipedia/page.d.ts.map +1 -0
  250. package/dist/adapters/wikipedia/page.js +116 -0
  251. package/dist/adapters/wikipedia/page.js.map +1 -0
  252. package/dist/adapters/wttr/weather.d.ts +12 -0
  253. package/dist/adapters/wttr/weather.d.ts.map +1 -0
  254. package/dist/adapters/wttr/weather.js +207 -0
  255. package/dist/adapters/wttr/weather.js.map +1 -0
  256. package/dist/adapters/xianyu/publish.d.ts +31 -0
  257. package/dist/adapters/xianyu/publish.d.ts.map +1 -0
  258. package/dist/adapters/xianyu/publish.js +349 -0
  259. package/dist/adapters/xianyu/publish.js.map +1 -0
  260. package/dist/adapters/xiaohongshu/user-helpers.d.ts +2 -2
  261. package/dist/adapters/xiaohongshu/user-helpers.d.ts.map +1 -1
  262. package/dist/adapters/xiaohongshu/user-helpers.js +5 -4
  263. package/dist/adapters/xiaohongshu/user-helpers.js.map +1 -1
  264. package/dist/adapters/yuanbao/web.d.ts +27 -0
  265. package/dist/adapters/yuanbao/web.d.ts.map +1 -0
  266. package/dist/adapters/yuanbao/web.js +365 -0
  267. package/dist/adapters/yuanbao/web.js.map +1 -0
  268. package/dist/adapters/zhihu/collection.d.ts +33 -0
  269. package/dist/adapters/zhihu/collection.d.ts.map +1 -0
  270. package/dist/adapters/zhihu/collection.js +185 -0
  271. package/dist/adapters/zhihu/collection.js.map +1 -0
  272. package/dist/adapters/zlibrary/web.d.ts +19 -0
  273. package/dist/adapters/zlibrary/web.d.ts.map +1 -0
  274. package/dist/adapters/zlibrary/web.js +153 -0
  275. package/dist/adapters/zlibrary/web.js.map +1 -0
  276. package/dist/browser/daemon-client.js +2 -2
  277. package/dist/browser/daemon-client.js.map +1 -1
  278. package/dist/discovery/macos-dynamic.d.ts.map +1 -1
  279. package/dist/discovery/macos-dynamic.js +17 -3
  280. package/dist/discovery/macos-dynamic.js.map +1 -1
  281. package/dist/manifest-compact.txt +10 -10
  282. package/dist/manifest-search.json +1 -1
  283. package/dist/manifest.json +5130 -112
  284. package/dist/transport/refs.d.ts +5 -3
  285. package/dist/transport/refs.d.ts.map +1 -1
  286. package/dist/transport/refs.js +8 -1
  287. package/dist/transport/refs.js.map +1 -1
  288. package/dist/transport/sidecar-binary.d.ts +7 -0
  289. package/dist/transport/sidecar-binary.d.ts.map +1 -1
  290. package/dist/transport/sidecar-binary.js +28 -8
  291. package/dist/transport/sidecar-binary.js.map +1 -1
  292. package/package.json +4 -3
  293. package/server.json +3 -3
  294. package/skills/unicli/SKILL.md +1 -1
  295. package/skills/unicli-claude-code/SKILL.md +1 -1
  296. package/skills/unicli-hermes/SKILL.md +1 -1
  297. package/src/adapters/1point3acres/forum.test.ts +300 -0
  298. package/src/adapters/1point3acres/forum.ts +852 -0
  299. package/src/adapters/aibase/news.test.ts +42 -0
  300. package/src/adapters/aibase/news.ts +118 -0
  301. package/src/adapters/arxiv/papers.test.ts +59 -0
  302. package/src/adapters/arxiv/papers.ts +226 -0
  303. package/src/adapters/bbc/topic.test.ts +52 -0
  304. package/src/adapters/bbc/topic.ts +149 -0
  305. package/src/adapters/chatgpt/web.test.ts +121 -0
  306. package/src/adapters/chatgpt/web.ts +286 -0
  307. package/src/adapters/claude/web.test.ts +206 -0
  308. package/src/adapters/claude/web.ts +684 -0
  309. package/src/adapters/codex/projects.test.ts +77 -0
  310. package/src/adapters/codex/projects.ts +178 -0
  311. package/src/adapters/coingecko/markets.test.ts +156 -0
  312. package/src/adapters/coingecko/markets.ts +574 -0
  313. package/src/adapters/coupang/product.test.ts +111 -0
  314. package/src/adapters/coupang/product.ts +256 -0
  315. package/src/adapters/crates/registry.test.ts +89 -0
  316. package/src/adapters/crates/registry.ts +247 -0
  317. package/src/adapters/ctrip/travel.test.ts +359 -0
  318. package/src/adapters/ctrip/travel.ts +792 -0
  319. package/src/adapters/dblp/publications.test.ts +123 -0
  320. package/src/adapters/dblp/publications.ts +494 -0
  321. package/src/adapters/deepseek/web.test.ts +69 -0
  322. package/src/adapters/deepseek/web.ts +78 -1
  323. package/src/adapters/defillama/protocols.test.ts +75 -0
  324. package/src/adapters/defillama/protocols.ts +253 -0
  325. package/src/adapters/devto/read.test.ts +49 -0
  326. package/src/adapters/devto/read.ts +145 -0
  327. package/src/adapters/dianping/shop.test.ts +134 -0
  328. package/src/adapters/dianping/shop.ts +261 -0
  329. package/src/adapters/dockerhub/registry.test.ts +97 -0
  330. package/src/adapters/dockerhub/registry.ts +223 -0
  331. package/src/adapters/endoflife/product.test.ts +50 -0
  332. package/src/adapters/endoflife/product.ts +128 -0
  333. package/src/adapters/facebook/marketplace-extra.test.ts +132 -0
  334. package/src/adapters/facebook/marketplace-extra.ts +213 -0
  335. package/src/adapters/flathub/apps.test.ts +85 -0
  336. package/src/adapters/flathub/apps.ts +254 -0
  337. package/src/adapters/goproxy/module.test.ts +72 -0
  338. package/src/adapters/goproxy/module.ts +258 -0
  339. package/src/adapters/grok/web.test.ts +181 -0
  340. package/src/adapters/grok/web.ts +640 -0
  341. package/src/adapters/hackernews/read.test.ts +68 -0
  342. package/src/adapters/hackernews/read.ts +265 -0
  343. package/src/adapters/hf/paper.test.ts +48 -0
  344. package/src/adapters/hf/paper.ts +138 -0
  345. package/src/adapters/homebrew/packages.test.ts +109 -0
  346. package/src/adapters/homebrew/packages.ts +304 -0
  347. package/src/adapters/indeed/jobs.test.ts +230 -0
  348. package/src/adapters/indeed/jobs.ts +375 -0
  349. package/src/adapters/instagram/collections.test.ts +94 -0
  350. package/src/adapters/instagram/collections.ts +206 -0
  351. package/src/adapters/lichess/players.test.ts +99 -0
  352. package/src/adapters/lichess/players.ts +277 -0
  353. package/src/adapters/lobsters/read-domain.test.ts +121 -0
  354. package/src/adapters/lobsters/read-domain.ts +400 -0
  355. package/src/adapters/maven/artifact.test.ts +67 -0
  356. package/src/adapters/maven/artifact.ts +155 -0
  357. package/src/adapters/mdn/search.test.ts +39 -0
  358. package/src/adapters/mdn/search.ts +133 -0
  359. package/src/adapters/medium/tag.test.ts +64 -0
  360. package/src/adapters/medium/tag.ts +164 -0
  361. package/src/adapters/npm/package.test.ts +53 -0
  362. package/src/adapters/npm/package.ts +177 -0
  363. package/src/adapters/nuget/package.test.ts +102 -0
  364. package/src/adapters/nuget/package.ts +193 -0
  365. package/src/adapters/nvd/cve.test.ts +66 -0
  366. package/src/adapters/nvd/cve.ts +182 -0
  367. package/src/adapters/oeis/sequences.test.ts +71 -0
  368. package/src/adapters/oeis/sequences.ts +234 -0
  369. package/src/adapters/openalex/works.test.ts +99 -0
  370. package/src/adapters/openalex/works.ts +319 -0
  371. package/src/adapters/openfda/records.test.ts +90 -0
  372. package/src/adapters/openfda/records.ts +239 -0
  373. package/src/adapters/openreview/papers.test.ts +139 -0
  374. package/src/adapters/openreview/papers.ts +560 -0
  375. package/src/adapters/osv/security.test.ts +91 -0
  376. package/src/adapters/osv/security.ts +298 -0
  377. package/src/adapters/packagist/package.test.ts +62 -0
  378. package/src/adapters/packagist/package.ts +146 -0
  379. package/src/adapters/pubmed/articles.test.ts +96 -0
  380. package/src/adapters/pubmed/articles.ts +497 -0
  381. package/src/adapters/pypi/package.test.ts +131 -0
  382. package/src/adapters/pypi/package.ts +297 -0
  383. package/src/adapters/qwen/web.test.ts +176 -0
  384. package/src/adapters/qwen/web.ts +758 -0
  385. package/src/adapters/reddit/account.test.ts +56 -0
  386. package/src/adapters/reddit/account.ts +493 -0
  387. package/src/adapters/rednote/web.test.ts +354 -0
  388. package/src/adapters/rednote/web.ts +968 -0
  389. package/src/adapters/rest-countries/countries.test.ts +80 -0
  390. package/src/adapters/rest-countries/countries.ts +271 -0
  391. package/src/adapters/reuters/article-detail.test.ts +65 -0
  392. package/src/adapters/reuters/article-detail.ts +186 -0
  393. package/src/adapters/rfc/rfc.test.ts +37 -0
  394. package/src/adapters/rfc/rfc.ts +133 -0
  395. package/src/adapters/rubygems/gem.test.ts +43 -0
  396. package/src/adapters/rubygems/gem.ts +126 -0
  397. package/src/adapters/stackoverflow/questions.test.ts +207 -0
  398. package/src/adapters/stackoverflow/questions.ts +765 -0
  399. package/src/adapters/steam/app.test.ts +68 -0
  400. package/src/adapters/steam/app.ts +218 -0
  401. package/src/adapters/tiktok/creator-videos.test.ts +158 -0
  402. package/src/adapters/tiktok/creator-videos.ts +370 -0
  403. package/src/adapters/tvmaze/shows.test.ts +93 -0
  404. package/src/adapters/tvmaze/shows.ts +271 -0
  405. package/src/adapters/twitter/bookmark-folders.test.ts +164 -0
  406. package/src/adapters/twitter/bookmark-folders.ts +366 -0
  407. package/src/adapters/twitter/quote.test.ts +157 -0
  408. package/src/adapters/twitter/quote.ts +332 -0
  409. package/src/adapters/twitter/tweet-actions.test.ts +51 -0
  410. package/src/adapters/twitter/tweet-actions.ts +187 -0
  411. package/src/adapters/twitter/tweet-url.ts +65 -0
  412. package/src/adapters/uisdc/news.test.ts +46 -0
  413. package/src/adapters/uisdc/news.ts +111 -0
  414. package/src/adapters/weibo/favorites-publish.test.ts +177 -0
  415. package/src/adapters/weibo/favorites-publish.ts +426 -0
  416. package/src/adapters/wikidata/entities.test.ts +103 -0
  417. package/src/adapters/wikidata/entities.ts +253 -0
  418. package/src/adapters/wikipedia/page.test.ts +49 -0
  419. package/src/adapters/wikipedia/page.ts +158 -0
  420. package/src/adapters/wttr/weather.test.ts +99 -0
  421. package/src/adapters/wttr/weather.ts +239 -0
  422. package/src/adapters/xianyu/publish.test.ts +210 -0
  423. package/src/adapters/xianyu/publish.ts +420 -0
  424. package/src/adapters/xiaohongshu/user-helpers.ts +5 -2
  425. package/src/adapters/yuanbao/web.test.ts +144 -0
  426. package/src/adapters/yuanbao/web.ts +435 -0
  427. package/src/adapters/zhihu/collection.test.ts +96 -0
  428. package/src/adapters/zhihu/collection.ts +239 -0
  429. package/src/adapters/zlibrary/web.test.ts +104 -0
  430. package/src/adapters/zlibrary/web.ts +192 -0
@@ -0,0 +1,223 @@
1
+ /**
2
+ * @owner src/adapters/dockerhub/registry.ts
3
+ * @does Register agent-facing Docker Hub search and image metadata commands.
4
+ * @needs Public Docker Hub API, TypeScript adapter loader, bounded argument parsing.
5
+ * @feeds surface coverage ledger, container registry command surface, agent-readable image rows.
6
+ * @breaks Docker Hub API envelope drift, weak image parsing, or silent empty results hide registry lookup failures.
7
+ */
8
+
9
+ import { cli, Strategy } from "../../registry.js";
10
+
11
+ const HUB_BASE = "https://hub.docker.com/v2";
12
+
13
+ interface DockerHubSearchItem {
14
+ repo_owner?: unknown;
15
+ repo_name?: unknown;
16
+ is_official?: unknown;
17
+ star_count?: unknown;
18
+ pull_count?: unknown;
19
+ short_description?: unknown;
20
+ }
21
+
22
+ interface DockerHubImageBody {
23
+ namespace?: unknown;
24
+ name?: unknown;
25
+ star_count?: unknown;
26
+ pull_count?: unknown;
27
+ description?: unknown;
28
+ last_updated?: unknown;
29
+ last_modified?: unknown;
30
+ date_registered?: unknown;
31
+ status_description?: unknown;
32
+ }
33
+
34
+ function stringField(value: unknown): string {
35
+ return typeof value === "string" ? value : "";
36
+ }
37
+
38
+ function numberField(value: unknown): number | null {
39
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
40
+ }
41
+
42
+ export function requireDockerHubString(value: unknown, name: string): string {
43
+ const text = String(value ?? "").trim();
44
+ if (!text) throw new Error(`${name} is required.`);
45
+ return text;
46
+ }
47
+
48
+ export function requireDockerHubLimit(
49
+ value: unknown,
50
+ fallback: number,
51
+ ): number {
52
+ if (value === undefined || value === null || value === "") return fallback;
53
+ const n = Number(value);
54
+ if (!Number.isInteger(n) || n < 1 || n > 100) {
55
+ throw new Error(
56
+ `limit must be an integer in [1, 100]. Got: ${String(value)}`,
57
+ );
58
+ }
59
+ return n;
60
+ }
61
+
62
+ export function parseDockerHubImage(value: unknown): {
63
+ owner: string;
64
+ name: string;
65
+ } {
66
+ const raw = requireDockerHubString(value, "image");
67
+ const parts = raw.split("/").filter(Boolean);
68
+ if (parts.length === 1) return { owner: "library", name: parts[0] };
69
+ if (parts.length === 2) return { owner: parts[0], name: parts[1] };
70
+ throw new Error(
71
+ "image must be a Docker Hub image name like nginx or bitnami/redis.",
72
+ );
73
+ }
74
+
75
+ function trimDate(value: unknown): string | null {
76
+ const text = stringField(value).trim();
77
+ if (!text) return null;
78
+ const noFraction = text.replace(/\.\d+/, "");
79
+ return noFraction.endsWith("Z") ? noFraction : `${noFraction}Z`;
80
+ }
81
+
82
+ async function fetchDockerHubJson(url: string): Promise<unknown> {
83
+ const response = await fetch(url, {
84
+ headers: { Accept: "application/json" },
85
+ });
86
+ if (!response.ok) {
87
+ throw new Error(`Docker Hub request failed: HTTP ${response.status}`);
88
+ }
89
+ return response.json();
90
+ }
91
+
92
+ export function mapDockerHubSearchRows(
93
+ items: DockerHubSearchItem[],
94
+ limit: number,
95
+ ): Array<Record<string, unknown>> {
96
+ return items.slice(0, limit).map((item, index) => {
97
+ const owner = stringField(item.repo_owner).trim();
98
+ const name = stringField(item.repo_name).trim();
99
+ const official = Boolean(item.is_official);
100
+ const image = owner
101
+ ? `${owner}/${name}`
102
+ : official
103
+ ? `library/${name}`
104
+ : name;
105
+ return {
106
+ rank: index + 1,
107
+ image,
108
+ official,
109
+ stars: numberField(item.star_count),
110
+ pulls: numberField(item.pull_count),
111
+ description: stringField(item.short_description).trim(),
112
+ url: image ? `https://hub.docker.com/r/${image}` : "",
113
+ };
114
+ });
115
+ }
116
+
117
+ export function mapDockerHubImageRow(
118
+ body: DockerHubImageBody,
119
+ fallbackOwner: string,
120
+ fallbackName: string,
121
+ ): Record<string, unknown> {
122
+ const namespace = stringField(body.namespace).trim() || fallbackOwner;
123
+ const name = stringField(body.name).trim() || fallbackName;
124
+ if (!name) throw new Error("Docker Hub returned no image metadata.");
125
+ const official = namespace === "library" || namespace === "_";
126
+ const image = official ? `library/${name}` : `${namespace}/${name}`;
127
+ return {
128
+ image,
129
+ official,
130
+ stars: numberField(body.star_count),
131
+ pulls: numberField(body.pull_count),
132
+ description: stringField(body.description).trim(),
133
+ lastUpdated: trimDate(body.last_updated),
134
+ lastModified: trimDate(body.last_modified),
135
+ registered: trimDate(body.date_registered),
136
+ status: stringField(body.status_description).trim(),
137
+ url: `https://hub.docker.com/r/${image}`,
138
+ };
139
+ }
140
+
141
+ cli({
142
+ site: "dockerhub",
143
+ name: "search",
144
+ description: "Search Docker Hub repositories by keyword",
145
+ domain: "hub.docker.com",
146
+ strategy: Strategy.PUBLIC,
147
+ args: [
148
+ {
149
+ name: "query",
150
+ type: "str",
151
+ required: true,
152
+ positional: true,
153
+ description: "Search keyword",
154
+ },
155
+ {
156
+ name: "limit",
157
+ type: "int",
158
+ default: 25,
159
+ description: "Max repositories",
160
+ },
161
+ ],
162
+ columns: [
163
+ "rank",
164
+ "image",
165
+ "official",
166
+ "stars",
167
+ "pulls",
168
+ "description",
169
+ "url",
170
+ ],
171
+ func: async (_page, kwargs) => {
172
+ const query = requireDockerHubString(kwargs.query, "query");
173
+ const limit = requireDockerHubLimit(kwargs.limit, 25);
174
+ const url = `${HUB_BASE}/search/repositories/?query=${encodeURIComponent(query)}&page_size=${limit}`;
175
+ const body = (await fetchDockerHubJson(url)) as {
176
+ results?: DockerHubSearchItem[];
177
+ };
178
+ const rows = mapDockerHubSearchRows(
179
+ Array.isArray(body.results) ? body.results : [],
180
+ limit,
181
+ );
182
+ if (rows.length === 0) {
183
+ throw new Error(`No Docker Hub repositories matched "${query}".`);
184
+ }
185
+ return rows;
186
+ },
187
+ });
188
+
189
+ cli({
190
+ site: "dockerhub",
191
+ name: "image",
192
+ description: "Fetch a Docker Hub repository's public metadata",
193
+ domain: "hub.docker.com",
194
+ strategy: Strategy.PUBLIC,
195
+ args: [
196
+ {
197
+ name: "image",
198
+ type: "str",
199
+ required: true,
200
+ positional: true,
201
+ description: "Image name, e.g. nginx or bitnami/redis",
202
+ },
203
+ ],
204
+ columns: [
205
+ "image",
206
+ "official",
207
+ "stars",
208
+ "pulls",
209
+ "description",
210
+ "lastUpdated",
211
+ "lastModified",
212
+ "registered",
213
+ "status",
214
+ "url",
215
+ ],
216
+ func: async (_page, kwargs) => {
217
+ const { owner, name } = parseDockerHubImage(kwargs.image);
218
+ const body = (await fetchDockerHubJson(
219
+ `${HUB_BASE}/repositories/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/`,
220
+ )) as DockerHubImageBody;
221
+ return [mapDockerHubImageRow(body, owner, name)];
222
+ },
223
+ });
@@ -0,0 +1,50 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import {
3
+ mapEndoflifeRows,
4
+ normalizeEndoflifeDateOrFlag,
5
+ requireEndoflifeProduct,
6
+ } from "./product.js";
7
+
8
+ describe("endoflife agent-facing product command", () => {
9
+ it("validates product slugs", () => {
10
+ expect(requireEndoflifeProduct(" NodeJS ")).toBe("nodejs");
11
+ expect(requireEndoflifeProduct("ubuntu-24.04")).toBe("ubuntu-24.04");
12
+ expect(() => requireEndoflifeProduct("../node")).toThrow("valid slug");
13
+ });
14
+
15
+ it("normalizes date and boolean lifecycle fields", () => {
16
+ expect(normalizeEndoflifeDateOrFlag(true)).toBe("ongoing");
17
+ expect(normalizeEndoflifeDateOrFlag(false)).toBeNull();
18
+ expect(normalizeEndoflifeDateOrFlag(" 2027-01-01 ")).toBe("2027-01-01");
19
+ });
20
+
21
+ it("maps cycle rows with derived EOL status", () => {
22
+ expect(
23
+ mapEndoflifeRows(
24
+ "nodejs",
25
+ [
26
+ {
27
+ cycle: "22",
28
+ releaseDate: "2024-04-24",
29
+ latest: "22.1.0",
30
+ latestReleaseDate: "2024-05-01",
31
+ lts: true,
32
+ support: "2027-04-30",
33
+ eol: "2027-04-30",
34
+ },
35
+ { cycle: "10", eol: "2021-04-30" },
36
+ ],
37
+ "2026-05-12",
38
+ ),
39
+ ).toMatchObject([
40
+ {
41
+ product: "nodejs",
42
+ cycle: "22",
43
+ lts: "ongoing",
44
+ eolStatus: "active",
45
+ url: "https://endoflife.date/nodejs",
46
+ },
47
+ { cycle: "10", eolStatus: "eol" },
48
+ ]);
49
+ });
50
+ });
@@ -0,0 +1,128 @@
1
+ /**
2
+ * @owner src/adapters/endoflife/product.ts
3
+ * @does Register agent-facing endoflife.date product lifecycle command.
4
+ * @needs endoflife.date public API, product slug validation, date/flag normalization.
5
+ * @feeds surface coverage ledger, product support lifecycle rows, version planning data.
6
+ * @breaks endoflife.date API drift, weak slug validation, or silent empty rows hide lifecycle data failures.
7
+ */
8
+
9
+ import { cli, Strategy } from "../../registry.js";
10
+
11
+ const API_BASE = "https://endoflife.date/api";
12
+ const PRODUCT_RE = /^[a-z0-9][a-z0-9._-]{0,79}$/;
13
+
14
+ export function requireEndoflifeProduct(value: unknown): string {
15
+ const product = String(value ?? "")
16
+ .trim()
17
+ .toLowerCase();
18
+ if (!product) throw new Error("endoflife product cannot be empty.");
19
+ if (!PRODUCT_RE.test(product)) {
20
+ throw new Error(
21
+ `endoflife product "${String(value)}" is not a valid slug.`,
22
+ );
23
+ }
24
+ return product;
25
+ }
26
+
27
+ export function normalizeEndoflifeDateOrFlag(value: unknown): string | null {
28
+ if (value === true) return "ongoing";
29
+ if (value === false || value == null) return null;
30
+ if (typeof value !== "string") return null;
31
+ const text = value.trim();
32
+ return text || null;
33
+ }
34
+
35
+ function stringField(value: unknown): string {
36
+ return typeof value === "string" ? value.trim() : "";
37
+ }
38
+
39
+ export function mapEndoflifeRows(
40
+ product: string,
41
+ cycles: Array<Record<string, unknown>>,
42
+ today: string,
43
+ ): Array<Record<string, unknown>> {
44
+ return cycles.map((cycle) => {
45
+ const eol = normalizeEndoflifeDateOrFlag(cycle.eol);
46
+ const eolStatus =
47
+ eol === "ongoing"
48
+ ? "ongoing"
49
+ : typeof eol === "string" && eol >= today
50
+ ? "active"
51
+ : typeof eol === "string"
52
+ ? "eol"
53
+ : null;
54
+ return {
55
+ product,
56
+ cycle: stringField(cycle.cycle),
57
+ releaseDate: stringField(cycle.releaseDate),
58
+ latest: stringField(cycle.latest),
59
+ latestReleaseDate: stringField(cycle.latestReleaseDate),
60
+ lts: normalizeEndoflifeDateOrFlag(cycle.lts),
61
+ support: normalizeEndoflifeDateOrFlag(cycle.support),
62
+ eol,
63
+ extendedSupport: normalizeEndoflifeDateOrFlag(cycle.extendedSupport),
64
+ eolStatus,
65
+ url: `https://endoflife.date/${product}`,
66
+ };
67
+ });
68
+ }
69
+
70
+ async function fetchJson(url: URL | string, label: string): Promise<unknown> {
71
+ const response = await fetch(url, {
72
+ headers: {
73
+ accept: "application/json",
74
+ "user-agent": "unicli-endoflife (https://github.com/olo-dot-io/Uni-CLI)",
75
+ },
76
+ });
77
+ if (response.status === 404) throw new Error(`${label} returned no result.`);
78
+ if (response.status === 429) throw new Error(`${label} returned HTTP 429.`);
79
+ if (!response.ok)
80
+ throw new Error(`${label} returned HTTP ${response.status}.`);
81
+ return response.json();
82
+ }
83
+
84
+ cli({
85
+ site: "endoflife",
86
+ name: "product",
87
+ description: "Release cycles and support dates for an endoflife.date product",
88
+ domain: "endoflife.date",
89
+ strategy: Strategy.PUBLIC,
90
+ args: [
91
+ {
92
+ name: "product",
93
+ type: "str",
94
+ required: true,
95
+ positional: true,
96
+ description: "endoflife.date product slug",
97
+ },
98
+ ],
99
+ columns: [
100
+ "product",
101
+ "cycle",
102
+ "releaseDate",
103
+ "latest",
104
+ "latestReleaseDate",
105
+ "lts",
106
+ "support",
107
+ "eol",
108
+ "extendedSupport",
109
+ "eolStatus",
110
+ "url",
111
+ ],
112
+ func: async (_page, kwargs) => {
113
+ const product = requireEndoflifeProduct(kwargs.product);
114
+ const body = await fetchJson(
115
+ `${API_BASE}/${encodeURIComponent(product)}.json`,
116
+ "endoflife product",
117
+ );
118
+ const rows = mapEndoflifeRows(
119
+ product,
120
+ Array.isArray(body) ? (body as Array<Record<string, unknown>>) : [],
121
+ new Date().toISOString().slice(0, 10),
122
+ );
123
+ if (rows.length === 0) {
124
+ throw new Error(`endoflife product returned no cycles for "${product}".`);
125
+ }
126
+ return rows;
127
+ },
128
+ });
@@ -0,0 +1,132 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { resolveCommand } from "../../registry.js";
3
+ import { requireFacebookMarketplaceLimit } from "./marketplace-extra.js";
4
+
5
+ function pageMock(evaluateResults: unknown[]) {
6
+ return {
7
+ goto: vi.fn().mockResolvedValue(undefined),
8
+ wait: vi.fn().mockResolvedValue(undefined),
9
+ evaluate: vi.fn(async () => evaluateResults.shift()),
10
+ };
11
+ }
12
+
13
+ describe("facebook marketplace agent-facing commands", () => {
14
+ it("validates limits without silent clamps", () => {
15
+ expect(requireFacebookMarketplaceLimit(undefined)).toBe(20);
16
+ expect(requireFacebookMarketplaceLimit(2)).toBe(2);
17
+ expect(() => requireFacebookMarketplaceLimit(0)).toThrow(
18
+ "positive integer",
19
+ );
20
+ expect(() => requireFacebookMarketplaceLimit(101)).toThrow("<= 100");
21
+ });
22
+
23
+ it("lists Marketplace seller listings", async () => {
24
+ const command = resolveCommand("facebook", "marketplace-listings")?.command;
25
+ const page = pageMock([
26
+ {
27
+ authRequired: false,
28
+ rows: [
29
+ {
30
+ title: "Black electric standing desk",
31
+ price: "CA$80",
32
+ status: "Active",
33
+ listed: "Listed on 4/26",
34
+ clicks: "87",
35
+ actions: ["Mark as sold", "Share"],
36
+ },
37
+ {
38
+ title: "Large gray corduroy beanbag chair",
39
+ price: "CA$30",
40
+ },
41
+ ],
42
+ },
43
+ ]);
44
+ await expect(command!.func!(page, { limit: 1 })).resolves.toEqual([
45
+ {
46
+ index: 1,
47
+ title: "Black electric standing desk",
48
+ price: "CA$80",
49
+ status: "Active",
50
+ listed: "Listed on 4/26",
51
+ clicks: "87",
52
+ actions: "Mark as sold, Share",
53
+ },
54
+ ]);
55
+ expect(page.goto).toHaveBeenCalledWith(
56
+ "https://www.facebook.com/marketplace/you/selling/",
57
+ );
58
+ expect(page.wait).toHaveBeenCalledWith(4);
59
+ });
60
+
61
+ it("lists Marketplace inbox conversations", async () => {
62
+ const command = resolveCommand("facebook", "marketplace-inbox")?.command;
63
+ const page = pageMock([
64
+ {
65
+ authRequired: false,
66
+ rows: [
67
+ {
68
+ buyer: "Kulwant",
69
+ listing: "White 3-tier rolling utility cart",
70
+ snippet: "Can I pick up today?",
71
+ time: "3:43 PM",
72
+ unread: true,
73
+ },
74
+ {
75
+ buyer: "Gabriel",
76
+ listing: "Black electric standing desk",
77
+ snippet: "Yes, still available.",
78
+ time: "12:17 PM",
79
+ unread: false,
80
+ },
81
+ ],
82
+ },
83
+ ]);
84
+ await expect(command!.func!(page, { limit: 2 })).resolves.toEqual([
85
+ {
86
+ index: 1,
87
+ buyer: "Kulwant",
88
+ listing: "White 3-tier rolling utility cart",
89
+ snippet: "Can I pick up today?",
90
+ time: "3:43 PM",
91
+ unread: true,
92
+ },
93
+ {
94
+ index: 2,
95
+ buyer: "Gabriel",
96
+ listing: "Black electric standing desk",
97
+ snippet: "Yes, still available.",
98
+ time: "12:17 PM",
99
+ unread: false,
100
+ },
101
+ ]);
102
+ expect(page.goto).toHaveBeenCalledWith(
103
+ "https://www.facebook.com/marketplace/inbox/",
104
+ );
105
+ expect(page.wait).toHaveBeenCalledWith(4);
106
+ });
107
+
108
+ it("fails before navigation on invalid limits", async () => {
109
+ const command = resolveCommand("facebook", "marketplace-listings")?.command;
110
+ const page = pageMock([]);
111
+ await expect(command!.func!(page, { limit: 0 })).rejects.toThrow(
112
+ "positive integer",
113
+ );
114
+ expect(page.goto).not.toHaveBeenCalled();
115
+ });
116
+
117
+ it("classifies auth and empty Marketplace pages", async () => {
118
+ const listings = resolveCommand(
119
+ "facebook",
120
+ "marketplace-listings",
121
+ )?.command;
122
+ const inbox = resolveCommand("facebook", "marketplace-inbox")?.command;
123
+ await expect(
124
+ listings!.func!(pageMock([{ authRequired: true, rows: [] }]), {
125
+ limit: 5,
126
+ }),
127
+ ).rejects.toThrow("requires an active signed-in Facebook session");
128
+ await expect(
129
+ inbox!.func!(pageMock([{ authRequired: false, rows: [] }]), { limit: 5 }),
130
+ ).rejects.toThrow("No Facebook Marketplace inbox conversations");
131
+ });
132
+ });