@zenalexa/unicli 0.220.1 → 0.221.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 (471) hide show
  1. package/AGENTS.md +28 -6
  2. package/README.md +8 -8
  3. package/README.zh-CN.md +8 -8
  4. package/dist/adapters/bilibili/comments.js +66 -4
  5. package/dist/adapters/bilibili/comments.js.map +1 -1
  6. package/dist/adapters/bilibili/compat.js +2 -2
  7. package/dist/adapters/bilibili/compat.js.map +1 -1
  8. package/dist/adapters/bilibili/download.js +4 -4
  9. package/dist/adapters/bilibili/download.js.map +1 -1
  10. package/dist/adapters/bilibili/wbi.d.ts.map +1 -1
  11. package/dist/adapters/bilibili/wbi.js +3 -3
  12. package/dist/adapters/bilibili/wbi.js.map +1 -1
  13. package/dist/adapters/cipo/_shared.d.ts +21 -0
  14. package/dist/adapters/cipo/_shared.d.ts.map +1 -0
  15. package/dist/adapters/cipo/_shared.js +67 -0
  16. package/dist/adapters/cipo/_shared.js.map +1 -0
  17. package/dist/adapters/cipo/get.d.ts +19 -0
  18. package/dist/adapters/cipo/get.d.ts.map +1 -0
  19. package/dist/adapters/cipo/get.js +140 -0
  20. package/dist/adapters/cipo/get.js.map +1 -0
  21. package/dist/adapters/cipo/legal-status.d.ts +19 -0
  22. package/dist/adapters/cipo/legal-status.d.ts.map +1 -0
  23. package/dist/adapters/cipo/legal-status.js +111 -0
  24. package/dist/adapters/cipo/legal-status.js.map +1 -0
  25. package/dist/adapters/cipo/search.d.ts +20 -0
  26. package/dist/adapters/cipo/search.d.ts.map +1 -0
  27. package/dist/adapters/cipo/search.js +148 -0
  28. package/dist/adapters/cipo/search.js.map +1 -0
  29. package/dist/adapters/cnipa/_shared.d.ts +47 -0
  30. package/dist/adapters/cnipa/_shared.d.ts.map +1 -0
  31. package/dist/adapters/cnipa/_shared.js +97 -0
  32. package/dist/adapters/cnipa/_shared.js.map +1 -0
  33. package/dist/adapters/cnipa/get.d.ts +19 -0
  34. package/dist/adapters/cnipa/get.d.ts.map +1 -0
  35. package/dist/adapters/cnipa/get.js +149 -0
  36. package/dist/adapters/cnipa/get.js.map +1 -0
  37. package/dist/adapters/cnipa/legal-status.d.ts +19 -0
  38. package/dist/adapters/cnipa/legal-status.d.ts.map +1 -0
  39. package/dist/adapters/cnipa/legal-status.js +119 -0
  40. package/dist/adapters/cnipa/legal-status.js.map +1 -0
  41. package/dist/adapters/cnipa/search.d.ts +21 -0
  42. package/dist/adapters/cnipa/search.d.ts.map +1 -0
  43. package/dist/adapters/cnipa/search.js +170 -0
  44. package/dist/adapters/cnipa/search.js.map +1 -0
  45. package/dist/adapters/espacenet/_shared.d.ts +21 -0
  46. package/dist/adapters/espacenet/_shared.d.ts.map +1 -0
  47. package/dist/adapters/espacenet/_shared.js +67 -0
  48. package/dist/adapters/espacenet/_shared.js.map +1 -0
  49. package/dist/adapters/espacenet/family.d.ts +19 -0
  50. package/dist/adapters/espacenet/family.d.ts.map +1 -0
  51. package/dist/adapters/espacenet/family.js +118 -0
  52. package/dist/adapters/espacenet/family.js.map +1 -0
  53. package/dist/adapters/espacenet/get.d.ts +19 -0
  54. package/dist/adapters/espacenet/get.d.ts.map +1 -0
  55. package/dist/adapters/espacenet/get.js +130 -0
  56. package/dist/adapters/espacenet/get.js.map +1 -0
  57. package/dist/adapters/espacenet/legal-status.d.ts +19 -0
  58. package/dist/adapters/espacenet/legal-status.d.ts.map +1 -0
  59. package/dist/adapters/espacenet/legal-status.js +110 -0
  60. package/dist/adapters/espacenet/legal-status.js.map +1 -0
  61. package/dist/adapters/espacenet/search.d.ts +20 -0
  62. package/dist/adapters/espacenet/search.d.ts.map +1 -0
  63. package/dist/adapters/espacenet/search.js +165 -0
  64. package/dist/adapters/espacenet/search.js.map +1 -0
  65. package/dist/adapters/facebook/subtitles.d.ts +9 -0
  66. package/dist/adapters/facebook/subtitles.d.ts.map +1 -0
  67. package/dist/adapters/facebook/subtitles.js +42 -0
  68. package/dist/adapters/facebook/subtitles.js.map +1 -0
  69. package/dist/adapters/fips/_shared.d.ts +21 -0
  70. package/dist/adapters/fips/_shared.d.ts.map +1 -0
  71. package/dist/adapters/fips/_shared.js +77 -0
  72. package/dist/adapters/fips/_shared.js.map +1 -0
  73. package/dist/adapters/fips/get.d.ts +19 -0
  74. package/dist/adapters/fips/get.d.ts.map +1 -0
  75. package/dist/adapters/fips/get.js +139 -0
  76. package/dist/adapters/fips/get.js.map +1 -0
  77. package/dist/adapters/fips/search.d.ts +20 -0
  78. package/dist/adapters/fips/search.d.ts.map +1 -0
  79. package/dist/adapters/fips/search.js +148 -0
  80. package/dist/adapters/fips/search.js.map +1 -0
  81. package/dist/adapters/freepatentsonline-web/_shared.d.ts +72 -0
  82. package/dist/adapters/freepatentsonline-web/_shared.d.ts.map +1 -0
  83. package/dist/adapters/freepatentsonline-web/_shared.js +216 -0
  84. package/dist/adapters/freepatentsonline-web/_shared.js.map +1 -0
  85. package/dist/adapters/freepatentsonline-web/get.d.ts +21 -0
  86. package/dist/adapters/freepatentsonline-web/get.d.ts.map +1 -0
  87. package/dist/adapters/freepatentsonline-web/get.js +127 -0
  88. package/dist/adapters/freepatentsonline-web/get.js.map +1 -0
  89. package/dist/adapters/freepatentsonline-web/search.d.ts +22 -0
  90. package/dist/adapters/freepatentsonline-web/search.d.ts.map +1 -0
  91. package/dist/adapters/freepatentsonline-web/search.js +149 -0
  92. package/dist/adapters/freepatentsonline-web/search.js.map +1 -0
  93. package/dist/adapters/google-patents-web/_shared.d.ts +110 -0
  94. package/dist/adapters/google-patents-web/_shared.d.ts.map +1 -0
  95. package/dist/adapters/google-patents-web/_shared.js +164 -0
  96. package/dist/adapters/google-patents-web/_shared.js.map +1 -0
  97. package/dist/adapters/google-patents-web/get.d.ts +36 -0
  98. package/dist/adapters/google-patents-web/get.d.ts.map +1 -0
  99. package/dist/adapters/google-patents-web/get.js +187 -0
  100. package/dist/adapters/google-patents-web/get.js.map +1 -0
  101. package/dist/adapters/google-patents-web/search.d.ts +23 -0
  102. package/dist/adapters/google-patents-web/search.d.ts.map +1 -0
  103. package/dist/adapters/google-patents-web/search.js +169 -0
  104. package/dist/adapters/google-patents-web/search.js.map +1 -0
  105. package/dist/adapters/inpi-br/_shared.d.ts +21 -0
  106. package/dist/adapters/inpi-br/_shared.d.ts.map +1 -0
  107. package/dist/adapters/inpi-br/_shared.js +67 -0
  108. package/dist/adapters/inpi-br/_shared.js.map +1 -0
  109. package/dist/adapters/inpi-br/get.d.ts +19 -0
  110. package/dist/adapters/inpi-br/get.d.ts.map +1 -0
  111. package/dist/adapters/inpi-br/get.js +142 -0
  112. package/dist/adapters/inpi-br/get.js.map +1 -0
  113. package/dist/adapters/inpi-br/search.d.ts +20 -0
  114. package/dist/adapters/inpi-br/search.d.ts.map +1 -0
  115. package/dist/adapters/inpi-br/search.js +154 -0
  116. package/dist/adapters/inpi-br/search.js.map +1 -0
  117. package/dist/adapters/instagram/subtitles.d.ts +9 -0
  118. package/dist/adapters/instagram/subtitles.d.ts.map +1 -0
  119. package/dist/adapters/instagram/subtitles.js +42 -0
  120. package/dist/adapters/instagram/subtitles.js.map +1 -0
  121. package/dist/adapters/mastodon/statuses.d.ts +40 -0
  122. package/dist/adapters/mastodon/statuses.d.ts.map +1 -0
  123. package/dist/adapters/mastodon/statuses.js +153 -0
  124. package/dist/adapters/mastodon/statuses.js.map +1 -0
  125. package/dist/adapters/reddit/comments.d.ts +9 -0
  126. package/dist/adapters/reddit/comments.d.ts.map +1 -0
  127. package/dist/adapters/reddit/comments.js +124 -0
  128. package/dist/adapters/reddit/comments.js.map +1 -0
  129. package/dist/adapters/threads/post.d.ts +32 -0
  130. package/dist/adapters/threads/post.d.ts.map +1 -0
  131. package/dist/adapters/threads/post.js +287 -0
  132. package/dist/adapters/threads/post.js.map +1 -0
  133. package/dist/adapters/tiktok/subtitles.d.ts +9 -0
  134. package/dist/adapters/tiktok/subtitles.d.ts.map +1 -0
  135. package/dist/adapters/tiktok/subtitles.js +42 -0
  136. package/dist/adapters/tiktok/subtitles.js.map +1 -0
  137. package/dist/adapters/twitter/accept.js +2 -2
  138. package/dist/adapters/twitter/accept.js.map +1 -1
  139. package/dist/adapters/twitter/browser-fallback.d.ts +26 -0
  140. package/dist/adapters/twitter/browser-fallback.d.ts.map +1 -0
  141. package/dist/adapters/twitter/browser-fallback.js +93 -0
  142. package/dist/adapters/twitter/browser-fallback.js.map +1 -0
  143. package/dist/adapters/twitter/browser-state.d.ts +11 -0
  144. package/dist/adapters/twitter/browser-state.d.ts.map +1 -0
  145. package/dist/adapters/twitter/browser-state.js +46 -0
  146. package/dist/adapters/twitter/browser-state.js.map +1 -0
  147. package/dist/adapters/twitter/client.d.ts.map +1 -1
  148. package/dist/adapters/twitter/client.js +36 -13
  149. package/dist/adapters/twitter/client.js.map +1 -1
  150. package/dist/adapters/twitter/reply-dm.js +2 -2
  151. package/dist/adapters/twitter/reply-dm.js.map +1 -1
  152. package/dist/adapters/twitter/reply.js +1 -0
  153. package/dist/adapters/twitter/reply.js.map +1 -1
  154. package/dist/adapters/twitter/search.js +11 -18
  155. package/dist/adapters/twitter/search.js.map +1 -1
  156. package/dist/adapters/twitter/thread.d.ts +14 -0
  157. package/dist/adapters/twitter/thread.d.ts.map +1 -1
  158. package/dist/adapters/twitter/thread.js +28 -2
  159. package/dist/adapters/twitter/thread.js.map +1 -1
  160. package/dist/adapters/twitter/trending.js +13 -59
  161. package/dist/adapters/twitter/trending.js.map +1 -1
  162. package/dist/adapters/xiaohongshu/browser-state.d.ts +19 -0
  163. package/dist/adapters/xiaohongshu/browser-state.d.ts.map +1 -0
  164. package/dist/adapters/xiaohongshu/browser-state.js +67 -0
  165. package/dist/adapters/xiaohongshu/browser-state.js.map +1 -0
  166. package/dist/adapters/xiaohongshu/comments.js +28 -5
  167. package/dist/adapters/xiaohongshu/comments.js.map +1 -1
  168. package/dist/adapters/xiaohongshu/download.js +49 -11
  169. package/dist/adapters/xiaohongshu/download.js.map +1 -1
  170. package/dist/adapters/xiaohongshu/search.d.ts.map +1 -1
  171. package/dist/adapters/xiaohongshu/search.js +11 -5
  172. package/dist/adapters/xiaohongshu/search.js.map +1 -1
  173. package/dist/adapters/xiaohongshu/trending.d.ts +9 -0
  174. package/dist/adapters/xiaohongshu/trending.d.ts.map +1 -0
  175. package/dist/adapters/xiaohongshu/trending.js +94 -0
  176. package/dist/adapters/xiaohongshu/trending.js.map +1 -0
  177. package/dist/adapters/youtube/comments.d.ts +80 -0
  178. package/dist/adapters/youtube/comments.d.ts.map +1 -1
  179. package/dist/adapters/youtube/comments.js +108 -12
  180. package/dist/adapters/youtube/comments.js.map +1 -1
  181. package/dist/adapters/youtube/subtitles.d.ts +9 -0
  182. package/dist/adapters/youtube/subtitles.d.ts.map +1 -0
  183. package/dist/adapters/youtube/subtitles.js +42 -0
  184. package/dist/adapters/youtube/subtitles.js.map +1 -0
  185. package/dist/adapters/yt-dlp/subtitles.d.ts +9 -0
  186. package/dist/adapters/yt-dlp/subtitles.d.ts.map +1 -0
  187. package/dist/adapters/yt-dlp/subtitles.js +41 -0
  188. package/dist/adapters/yt-dlp/subtitles.js.map +1 -0
  189. package/dist/adapters/zhihu/answer-detail.d.ts +39 -0
  190. package/dist/adapters/zhihu/answer-detail.d.ts.map +1 -0
  191. package/dist/adapters/zhihu/answer-detail.js +204 -0
  192. package/dist/adapters/zhihu/answer-detail.js.map +1 -0
  193. package/dist/adapters/zhihu/comment.d.ts +9 -0
  194. package/dist/adapters/zhihu/comment.d.ts.map +1 -0
  195. package/dist/adapters/zhihu/comment.js +149 -0
  196. package/dist/adapters/zhihu/comment.js.map +1 -0
  197. package/dist/adapters/zhihu/recommend.d.ts +36 -0
  198. package/dist/adapters/zhihu/recommend.d.ts.map +1 -0
  199. package/dist/adapters/zhihu/recommend.js +151 -0
  200. package/dist/adapters/zhihu/recommend.js.map +1 -0
  201. package/dist/browser/bridge.d.ts.map +1 -1
  202. package/dist/browser/bridge.js +14 -3
  203. package/dist/browser/bridge.js.map +1 -1
  204. package/dist/browser/daemon-client.d.ts +6 -0
  205. package/dist/browser/daemon-client.d.ts.map +1 -1
  206. package/dist/browser/daemon-client.js +75 -15
  207. package/dist/browser/daemon-client.js.map +1 -1
  208. package/dist/browser/daemon.js +39 -15
  209. package/dist/browser/daemon.js.map +1 -1
  210. package/dist/browser/protocol.d.ts +1 -0
  211. package/dist/browser/protocol.d.ts.map +1 -1
  212. package/dist/browser/protocol.js +1 -0
  213. package/dist/browser/protocol.js.map +1 -1
  214. package/dist/cli.d.ts.map +1 -1
  215. package/dist/cli.js +6 -0
  216. package/dist/cli.js.map +1 -1
  217. package/dist/commands/approvals.d.ts.map +1 -1
  218. package/dist/commands/approvals.js +1 -37
  219. package/dist/commands/approvals.js.map +1 -1
  220. package/dist/commands/browser/index.d.ts.map +1 -1
  221. package/dist/commands/browser/index.js +7 -2
  222. package/dist/commands/browser/index.js.map +1 -1
  223. package/dist/commands/daemon.d.ts.map +1 -1
  224. package/dist/commands/daemon.js +7 -3
  225. package/dist/commands/daemon.js.map +1 -1
  226. package/dist/commands/dispatch.d.ts.map +1 -1
  227. package/dist/commands/dispatch.js +27 -3
  228. package/dist/commands/dispatch.js.map +1 -1
  229. package/dist/commands/patent-doctor.d.ts +48 -0
  230. package/dist/commands/patent-doctor.d.ts.map +1 -0
  231. package/dist/commands/patent-doctor.js +109 -0
  232. package/dist/commands/patent-doctor.js.map +1 -0
  233. package/dist/commands/patent.d.ts +78 -0
  234. package/dist/commands/patent.d.ts.map +1 -0
  235. package/dist/commands/patent.js +919 -0
  236. package/dist/commands/patent.js.map +1 -0
  237. package/dist/commands/social.d.ts +19 -0
  238. package/dist/commands/social.d.ts.map +1 -0
  239. package/dist/commands/social.js +236 -0
  240. package/dist/commands/social.js.map +1 -0
  241. package/dist/core/registry.d.ts +1 -1
  242. package/dist/core/registry.d.ts.map +1 -1
  243. package/dist/core/registry.js +11 -2
  244. package/dist/core/registry.js.map +1 -1
  245. package/dist/discovery/loader.d.ts.map +1 -1
  246. package/dist/discovery/loader.js +4 -0
  247. package/dist/discovery/loader.js.map +1 -1
  248. package/dist/engine/approval-presenter.d.ts +10 -0
  249. package/dist/engine/approval-presenter.d.ts.map +1 -0
  250. package/dist/engine/approval-presenter.js +45 -0
  251. package/dist/engine/approval-presenter.js.map +1 -0
  252. package/dist/engine/approval-store.d.ts +4 -0
  253. package/dist/engine/approval-store.d.ts.map +1 -1
  254. package/dist/engine/approval-store.js +85 -11
  255. package/dist/engine/approval-store.js.map +1 -1
  256. package/dist/engine/auth/oauth2-cc.d.ts +67 -0
  257. package/dist/engine/auth/oauth2-cc.d.ts.map +1 -0
  258. package/dist/engine/auth/oauth2-cc.js +120 -0
  259. package/dist/engine/auth/oauth2-cc.js.map +1 -0
  260. package/dist/engine/cookies.d.ts +10 -0
  261. package/dist/engine/cookies.d.ts.map +1 -1
  262. package/dist/engine/cookies.js +64 -0
  263. package/dist/engine/cookies.js.map +1 -1
  264. package/dist/engine/download.d.ts +5 -0
  265. package/dist/engine/download.d.ts.map +1 -1
  266. package/dist/engine/download.js +11 -4
  267. package/dist/engine/download.js.map +1 -1
  268. package/dist/engine/executor.d.ts +1 -0
  269. package/dist/engine/executor.d.ts.map +1 -1
  270. package/dist/engine/executor.js +25 -0
  271. package/dist/engine/executor.js.map +1 -1
  272. package/dist/engine/framework.d.ts +5 -5
  273. package/dist/engine/framework.js +5 -5
  274. package/dist/engine/harden.d.ts +1 -1
  275. package/dist/engine/harden.js +1 -1
  276. package/dist/engine/kernel/stages.d.ts.map +1 -1
  277. package/dist/engine/kernel/stages.js +2 -1
  278. package/dist/engine/kernel/stages.js.map +1 -1
  279. package/dist/engine/normalizer/patent-envelope.d.ts +61 -0
  280. package/dist/engine/normalizer/patent-envelope.d.ts.map +1 -0
  281. package/dist/engine/normalizer/patent-envelope.js +132 -0
  282. package/dist/engine/normalizer/patent-envelope.js.map +1 -0
  283. package/dist/engine/research.d.ts +5 -7
  284. package/dist/engine/research.d.ts.map +1 -1
  285. package/dist/engine/research.js +6 -9
  286. package/dist/engine/research.js.map +1 -1
  287. package/dist/engine/steps/browser-helpers.d.ts +2 -2
  288. package/dist/engine/steps/browser-helpers.d.ts.map +1 -1
  289. package/dist/engine/steps/browser-helpers.js +39 -16
  290. package/dist/engine/steps/browser-helpers.js.map +1 -1
  291. package/dist/engine/steps/download.d.ts +1 -0
  292. package/dist/engine/steps/download.d.ts.map +1 -1
  293. package/dist/engine/steps/download.js +3 -1
  294. package/dist/engine/steps/download.js.map +1 -1
  295. package/dist/engine/steps/index.d.ts +2 -0
  296. package/dist/engine/steps/index.d.ts.map +1 -1
  297. package/dist/engine/steps/index.js +2 -0
  298. package/dist/engine/steps/index.js.map +1 -1
  299. package/dist/engine/steps/oauth2-token.d.ts +41 -0
  300. package/dist/engine/steps/oauth2-token.d.ts.map +1 -0
  301. package/dist/engine/steps/oauth2-token.js +115 -0
  302. package/dist/engine/steps/oauth2-token.js.map +1 -0
  303. package/dist/engine/steps/select-xml.d.ts +34 -0
  304. package/dist/engine/steps/select-xml.d.ts.map +1 -0
  305. package/dist/engine/steps/select-xml.js +222 -0
  306. package/dist/engine/steps/select-xml.js.map +1 -0
  307. package/dist/engine/template.d.ts.map +1 -1
  308. package/dist/engine/template.js +7 -0
  309. package/dist/engine/template.js.map +1 -1
  310. package/dist/engine/transport/mcp-browser.d.ts +128 -0
  311. package/dist/engine/transport/mcp-browser.d.ts.map +1 -0
  312. package/dist/engine/transport/mcp-browser.js +120 -0
  313. package/dist/engine/transport/mcp-browser.js.map +1 -0
  314. package/dist/fast-path/handlers/approvals.d.ts +11 -0
  315. package/dist/fast-path/handlers/approvals.d.ts.map +1 -0
  316. package/dist/fast-path/handlers/approvals.js +136 -0
  317. package/dist/fast-path/handlers/approvals.js.map +1 -0
  318. package/dist/fast-path/manifest.d.ts +1 -0
  319. package/dist/fast-path/manifest.d.ts.map +1 -1
  320. package/dist/fast-path/manifest.js.map +1 -1
  321. package/dist/fast-path.d.ts.map +1 -1
  322. package/dist/fast-path.js +3 -0
  323. package/dist/fast-path.js.map +1 -1
  324. package/dist/index.d.ts +23 -0
  325. package/dist/index.d.ts.map +1 -0
  326. package/dist/index.js +38 -0
  327. package/dist/index.js.map +1 -0
  328. package/dist/manifest-compact.txt +3 -3
  329. package/dist/manifest-search.json +1 -1
  330. package/dist/manifest.json +2239 -176
  331. package/dist/output/auth-guidance.d.ts +14 -0
  332. package/dist/output/auth-guidance.d.ts.map +1 -0
  333. package/dist/output/auth-guidance.js +50 -0
  334. package/dist/output/auth-guidance.js.map +1 -0
  335. package/dist/output/error-map.d.ts +1 -1
  336. package/dist/output/error-map.d.ts.map +1 -1
  337. package/dist/output/error-map.js +28 -4
  338. package/dist/output/error-map.js.map +1 -1
  339. package/dist/output/next-actions.d.ts.map +1 -1
  340. package/dist/output/next-actions.js +19 -3
  341. package/dist/output/next-actions.js.map +1 -1
  342. package/dist/registry.d.ts +18 -1
  343. package/dist/registry.d.ts.map +1 -1
  344. package/dist/registry.js +5 -0
  345. package/dist/registry.js.map +1 -1
  346. package/dist/social/browser-errors.d.ts +13 -0
  347. package/dist/social/browser-errors.d.ts.map +1 -0
  348. package/dist/social/browser-errors.js +36 -0
  349. package/dist/social/browser-errors.js.map +1 -0
  350. package/dist/social/capabilities.d.ts +29 -0
  351. package/dist/social/capabilities.d.ts.map +1 -0
  352. package/dist/social/capabilities.js +448 -0
  353. package/dist/social/capabilities.js.map +1 -0
  354. package/dist/social/comments.d.ts +26 -0
  355. package/dist/social/comments.d.ts.map +1 -0
  356. package/dist/social/comments.js +97 -0
  357. package/dist/social/comments.js.map +1 -0
  358. package/dist/social/video-text.d.ts +27 -0
  359. package/dist/social/video-text.d.ts.map +1 -0
  360. package/dist/social/video-text.js +140 -0
  361. package/dist/social/video-text.js.map +1 -0
  362. package/dist/types/patent.d.ts +160 -0
  363. package/dist/types/patent.d.ts.map +1 -0
  364. package/dist/types/patent.js +16 -0
  365. package/dist/types/patent.js.map +1 -0
  366. package/dist/types.d.ts +12 -0
  367. package/dist/types.d.ts.map +1 -1
  368. package/dist/types.js.map +1 -1
  369. package/package.json +9 -4
  370. package/server.json +3 -3
  371. package/skills/unicli/SKILL.md +1 -1
  372. package/skills/unicli-claude-code/SKILL.md +1 -1
  373. package/skills/unicli-hermes/SKILL.md +1 -1
  374. package/src/adapters/bilibili/comments-tree.test.ts +41 -0
  375. package/src/adapters/bilibili/comments.ts +78 -4
  376. package/src/adapters/bilibili/compat.ts +5 -2
  377. package/src/adapters/bilibili/download.ts +7 -4
  378. package/src/adapters/bilibili/wbi.ts +6 -3
  379. package/src/adapters/brave/search.yaml +53 -0
  380. package/src/adapters/cipo/_shared.ts +98 -0
  381. package/src/adapters/cipo/get.ts +188 -0
  382. package/src/adapters/cipo/legal-status.ts +148 -0
  383. package/src/adapters/cipo/search.ts +195 -0
  384. package/src/adapters/cnipa/_shared.ts +138 -0
  385. package/src/adapters/cnipa/get.ts +199 -0
  386. package/src/adapters/cnipa/legal-status.ts +162 -0
  387. package/src/adapters/cnipa/search.ts +229 -0
  388. package/src/adapters/dpma/get.yaml +67 -0
  389. package/src/adapters/dpma/search.yaml +77 -0
  390. package/src/adapters/duckduckgo/search.yaml +54 -0
  391. package/src/adapters/duckduckgo/suggest.yaml +52 -0
  392. package/src/adapters/epo/family.yaml +69 -0
  393. package/src/adapters/epo/get.yaml +74 -0
  394. package/src/adapters/epo/legal-status.yaml +63 -0
  395. package/src/adapters/epo/search.yaml +84 -0
  396. package/src/adapters/espacenet/_shared.ts +98 -0
  397. package/src/adapters/espacenet/family.ts +161 -0
  398. package/src/adapters/espacenet/get.ts +185 -0
  399. package/src/adapters/espacenet/legal-status.ts +151 -0
  400. package/src/adapters/espacenet/search.ts +229 -0
  401. package/src/adapters/facebook/subtitles.ts +44 -0
  402. package/src/adapters/fips/_shared.ts +109 -0
  403. package/src/adapters/fips/get.ts +186 -0
  404. package/src/adapters/fips/search.ts +195 -0
  405. package/src/adapters/freepatentsonline-web/_shared.ts +273 -0
  406. package/src/adapters/freepatentsonline-web/get.ts +144 -0
  407. package/src/adapters/freepatentsonline-web/search.ts +170 -0
  408. package/src/adapters/google-patents-bq/prior-art.yaml +80 -0
  409. package/src/adapters/google-patents-bq/search.yaml +97 -0
  410. package/src/adapters/google-patents-web/_shared.ts +242 -0
  411. package/src/adapters/google-patents-web/get.ts +224 -0
  412. package/src/adapters/google-patents-web/search.ts +196 -0
  413. package/src/adapters/inpi-br/_shared.ts +98 -0
  414. package/src/adapters/inpi-br/get.ts +193 -0
  415. package/src/adapters/inpi-br/search.ts +206 -0
  416. package/src/adapters/inpi-fr/get.yaml +62 -0
  417. package/src/adapters/inpi-fr/search.yaml +74 -0
  418. package/src/adapters/instagram/subtitles.ts +44 -0
  419. package/src/adapters/ipaustralia/get.yaml +67 -0
  420. package/src/adapters/ipaustralia/search.yaml +74 -0
  421. package/src/adapters/jpo/get.yaml +63 -0
  422. package/src/adapters/jpo/search.yaml +76 -0
  423. package/src/adapters/kipris/get.yaml +69 -0
  424. package/src/adapters/kipris/legal-status.yaml +58 -0
  425. package/src/adapters/kipris/search.yaml +79 -0
  426. package/src/adapters/lens/get.yaml +64 -0
  427. package/src/adapters/lens/search.yaml +82 -0
  428. package/src/adapters/mastodon/statuses.test.ts +82 -0
  429. package/src/adapters/mastodon/statuses.ts +208 -0
  430. package/src/adapters/patsnap/get.yaml +65 -0
  431. package/src/adapters/patsnap/search.yaml +77 -0
  432. package/src/adapters/pqai/prior-art.yaml +59 -0
  433. package/src/adapters/pqai/search.yaml +60 -0
  434. package/src/adapters/reddit/comments-tree.test.ts +79 -0
  435. package/src/adapters/reddit/comments.ts +159 -0
  436. package/src/adapters/threads/post.test.ts +64 -0
  437. package/src/adapters/threads/post.ts +366 -0
  438. package/src/adapters/threads/user.yaml +73 -0
  439. package/src/adapters/tiktok/subtitles.ts +44 -0
  440. package/src/adapters/twitter/accept.ts +5 -2
  441. package/src/adapters/twitter/browser-fallback.ts +138 -0
  442. package/src/adapters/twitter/browser-state.ts +74 -0
  443. package/src/adapters/twitter/client.ts +51 -21
  444. package/src/adapters/twitter/reply-dm.ts +5 -2
  445. package/src/adapters/twitter/reply.ts +1 -0
  446. package/src/adapters/twitter/search.ts +12 -38
  447. package/src/adapters/twitter/thread.test.ts +43 -0
  448. package/src/adapters/twitter/thread.ts +44 -2
  449. package/src/adapters/twitter/trending.ts +14 -95
  450. package/src/adapters/ukipo/info.yaml +43 -0
  451. package/src/adapters/uspto/get.yaml +67 -0
  452. package/src/adapters/uspto/legal-status.yaml +58 -0
  453. package/src/adapters/uspto/search.yaml +88 -0
  454. package/src/adapters/wipo-patentscope/info.yaml +43 -0
  455. package/src/adapters/xiaohongshu/browser-state.ts +95 -0
  456. package/src/adapters/xiaohongshu/comments.ts +29 -6
  457. package/src/adapters/xiaohongshu/download.ts +60 -11
  458. package/src/adapters/xiaohongshu/search.ts +18 -6
  459. package/src/adapters/xiaohongshu/trending.ts +112 -0
  460. package/src/adapters/yahoo/search.yaml +52 -0
  461. package/src/adapters/youtube/comments-microformat.test.ts +35 -0
  462. package/src/adapters/youtube/comments-tree.test.ts +74 -0
  463. package/src/adapters/youtube/comments.ts +166 -12
  464. package/src/adapters/youtube/subtitles.ts +44 -0
  465. package/src/adapters/yt-dlp/subtitles.ts +43 -0
  466. package/src/adapters/zhihu/answer-detail.test.ts +83 -0
  467. package/src/adapters/zhihu/answer-detail.ts +275 -0
  468. package/src/adapters/zhihu/comment-tree.test.ts +57 -0
  469. package/src/adapters/zhihu/comment.ts +186 -0
  470. package/src/adapters/zhihu/recommend.test.ts +65 -0
  471. package/src/adapters/zhihu/recommend.ts +207 -0
@@ -0,0 +1,195 @@
1
+ /**
2
+ * @owner src::adapters::cipo::search
3
+ * @does Browser-driven search of the Canadian Patents Database at cipo.ic.gc.ca/opic-cipo/cpd/eng/ — CIPO exposes no general open API for the patents corpus, so the browser route is the only programmatic surface.
4
+ * @needs src/engine/transport/mcp-browser.ts, src/engine/normalizer/patent-envelope.ts, src/adapters/cipo/_shared.ts, src/registry.ts
5
+ * @feeds src/commands/patent.ts (capability tag patent.search)
6
+ * @breaks PATENT_UNSUPPORTED_QUERY (empty), PATENT_NOT_FOUND (empty result), PATENT_API_DEPRECATED with MCP_BUS_MISSING (no outbound MCP transport)
7
+ * @invariants rows are canonical PatentRecord; source_adapter='cipo'
8
+ * @side-effects controls Chrome via MCP
9
+ * @perf single navigate + evaluate
10
+ * @concurrency safe
11
+ * @test tests/unit/adapters/cipo/search.test.ts
12
+ * @stability experimental
13
+ * @since 2026-05-18
14
+ * @verification browser-only
15
+ */
16
+
17
+ import { cli, Strategy } from "../../registry.js";
18
+ import { TransportError } from "../../engine/transport/mcp-browser.js";
19
+ import { assemblePatentRecord } from "../../engine/normalizer/patent-envelope.js";
20
+ import {
21
+ cipoEnvelope,
22
+ cipoNavigateAndExtract,
23
+ transportErrorToCipoEnvelope,
24
+ } from "./_shared.js";
25
+
26
+ const ADAPTER_PATH = "src/adapters/cipo/search.ts";
27
+ const CIPO_SEARCH_URL =
28
+ "https://cipo.ic.gc.ca/opic-cipo/cpd/eng/search/basic.html";
29
+
30
+ interface CipoRow {
31
+ publication_number: string;
32
+ title?: string;
33
+ applicant?: string;
34
+ publication_date?: string;
35
+ source_url?: string;
36
+ }
37
+
38
+ const EXTRACTOR = `(() => {
39
+ const rows = Array.from(
40
+ document.querySelectorAll('table.results tr.result-row, .search-results .result')
41
+ ).map((el) => {
42
+ const text = (sel) => {
43
+ const node = el.querySelector(sel);
44
+ return node ? (node.textContent || '').trim() : '';
45
+ };
46
+ const linkEl = el.querySelector('a[href*="patent/"], a[href]');
47
+ return {
48
+ publication_number: text('.patent-number, td.patent-no, [data-field="patentNo"]'),
49
+ title: text('.patent-title, td.title, [data-field="title"]'),
50
+ applicant: text('.applicant-name, td.applicant, [data-field="applicant"]'),
51
+ publication_date: text('.publication-date, td.pubDate, [data-field="pubDate"]'),
52
+ source_url: linkEl ? linkEl.href : '',
53
+ };
54
+ });
55
+ return { rows };
56
+ })()`;
57
+
58
+ function buildSearchUrl(query: string): string {
59
+ const params = new URLSearchParams({ search: query });
60
+ return `${CIPO_SEARCH_URL}?${params.toString()}`;
61
+ }
62
+
63
+ export async function runCipoSearch(kwargs: {
64
+ query: string;
65
+ limit?: number;
66
+ }): Promise<unknown[]> {
67
+ const limit =
68
+ typeof kwargs.limit === "number" && Number.isFinite(kwargs.limit)
69
+ ? Math.max(1, Math.min(100, Math.floor(kwargs.limit)))
70
+ : 25;
71
+ const query = String(kwargs.query ?? "").trim();
72
+ if (query.length === 0) {
73
+ return [
74
+ {
75
+ envelope: cipoEnvelope(
76
+ "PATENT_UNSUPPORTED_QUERY",
77
+ ADAPTER_PATH,
78
+ "validate",
79
+ "cipo search requires a non-empty query",
80
+ ),
81
+ },
82
+ ];
83
+ }
84
+ const url = buildSearchUrl(query);
85
+ let extract: { rows: CipoRow[] };
86
+ try {
87
+ const result = await cipoNavigateAndExtract<{ rows: CipoRow[] }>(
88
+ url,
89
+ EXTRACTOR,
90
+ );
91
+ if (!result.data) {
92
+ return [
93
+ {
94
+ envelope: cipoEnvelope(
95
+ "PATENT_SCHEMA_DRIFT",
96
+ ADAPTER_PATH,
97
+ "evaluate",
98
+ "cipo evaluate returned no data; selector schema likely changed",
99
+ ),
100
+ },
101
+ ];
102
+ }
103
+ extract = result.data;
104
+ } catch (err) {
105
+ if (err instanceof TransportError) {
106
+ return [
107
+ {
108
+ envelope: transportErrorToCipoEnvelope(err, ADAPTER_PATH, "navigate"),
109
+ },
110
+ ];
111
+ }
112
+ throw err;
113
+ }
114
+ if (extract.rows.length === 0) {
115
+ return [
116
+ {
117
+ envelope: cipoEnvelope(
118
+ "PATENT_NOT_FOUND",
119
+ ADAPTER_PATH,
120
+ "evaluate",
121
+ `cipo returned no rows for query "${query}"`,
122
+ ["uspto", "epo"],
123
+ ),
124
+ },
125
+ ];
126
+ }
127
+ const out: unknown[] = [];
128
+ for (const row of extract.rows.slice(0, limit)) {
129
+ if (!row.publication_number) continue;
130
+ const normalizedPub = /^CA[-]?/.test(row.publication_number)
131
+ ? row.publication_number
132
+ : `CA${row.publication_number}`;
133
+ try {
134
+ out.push(
135
+ assemblePatentRecord({
136
+ publication_number: normalizedPub,
137
+ title: row.title || undefined,
138
+ assignees: row.applicant
139
+ ? [{ name: row.applicant, country: "CA" }]
140
+ : undefined,
141
+ publication_date: row.publication_date || undefined,
142
+ source_adapter: "cipo",
143
+ source_url: row.source_url || url,
144
+ } as Parameters<typeof assemblePatentRecord>[0]),
145
+ );
146
+ } catch {
147
+ // Skip malformed rows.
148
+ }
149
+ }
150
+ if (out.length === 0) {
151
+ out.push({
152
+ envelope: cipoEnvelope(
153
+ "PATENT_NOT_FOUND",
154
+ ADAPTER_PATH,
155
+ "normalize",
156
+ "cipo returned rows but none carried a valid publication_number",
157
+ ["uspto"],
158
+ ),
159
+ });
160
+ }
161
+ return out;
162
+ }
163
+
164
+ cli({
165
+ site: "cipo",
166
+ name: "search",
167
+ description: "Search the Canadian Patents Database (CIPO, browser, no API)",
168
+ domain: "cipo.ic.gc.ca",
169
+ strategy: Strategy.PUBLIC,
170
+ adapter_path: ADAPTER_PATH,
171
+ args: [
172
+ {
173
+ name: "query",
174
+ type: "str",
175
+ required: true,
176
+ positional: true,
177
+ description: "Free-text query — matched on title/abstract/applicant",
178
+ },
179
+ {
180
+ name: "limit",
181
+ type: "int",
182
+ default: 25,
183
+ description: "Max results (1-100)",
184
+ },
185
+ ],
186
+ columns: ["publication_number", "title", "publication_date", "source_url"],
187
+ capabilities: [
188
+ "mcp-browser.navigate",
189
+ "mcp-browser.evaluate",
190
+ "patent.search",
191
+ ],
192
+ minimum_capability: "mcp-browser.evaluate",
193
+ func: async (_page, kwargs) =>
194
+ runCipoSearch(kwargs as { query: string; limit?: number }),
195
+ });
@@ -0,0 +1,138 @@
1
+ /**
2
+ * @owner src::adapters::cnipa::_shared
3
+ * @does Shared helpers for CNIPA browser-driven adapter commands — emits structured PATENT_BROWSER_CAPTCHA / MCP_BUS_MISSING / PATENT_NOT_FOUND error rows so adapters never synthesize results from a failed page.
4
+ * @needs src/engine/transport/mcp-browser.ts, src/engine/normalizer/patent-envelope.ts, src/types/patent.ts
5
+ * @feeds src/adapters/cnipa/search.ts, src/adapters/cnipa/get.ts, src/adapters/cnipa/legal-status.ts
6
+ * @breaks none — pure helpers; bubble TransportError out to the registry func contract
7
+ * @invariants every error path maps to a PatentEnvelope with adapter_path stamped; no silent fallbacks
8
+ * @side-effects none
9
+ * @perf n/a
10
+ * @concurrency safe
11
+ * @test covered transitively by src/adapters/cnipa/*.test.ts
12
+ * @stability experimental
13
+ * @since 2026-05-18
14
+ * @verification browser-only
15
+ */
16
+
17
+ import {
18
+ TransportError,
19
+ initMcpBrowserTransport,
20
+ mcpBrowserEvaluate,
21
+ mcpBrowserNavigate,
22
+ type McpBrowserResult,
23
+ } from "../../engine/transport/mcp-browser.js";
24
+ import { buildPatentEnvelope } from "../../engine/normalizer/patent-envelope.js";
25
+ import type { PatentEnvelope, PatentErrorCode } from "../../types/patent.js";
26
+
27
+ export interface CnipaErrorRow {
28
+ publication_number: string;
29
+ title: string;
30
+ envelope: PatentEnvelope;
31
+ }
32
+
33
+ export function cnipaEnvelope(
34
+ code: PatentErrorCode,
35
+ adapter_path: string,
36
+ step: string,
37
+ suggestion: string,
38
+ alternatives: string[] = [],
39
+ ): PatentEnvelope {
40
+ return buildPatentEnvelope({
41
+ code,
42
+ adapter_path,
43
+ step,
44
+ suggestion,
45
+ alternatives,
46
+ retryable: code === "PATENT_BROWSER_CAPTCHA" ? true : false,
47
+ });
48
+ }
49
+
50
+ /**
51
+ * Wrap a TransportError from mcp-browser into a PatentEnvelope row.
52
+ * MCP_BUS_MISSING is the production state today — surfaced honestly so the
53
+ * agent's repair loop knows the engine is missing the outbound MCP transport.
54
+ */
55
+ export function transportErrorToEnvelope(
56
+ err: TransportError,
57
+ adapter_path: string,
58
+ step: string,
59
+ ): PatentEnvelope {
60
+ if (err.code === "MCP_BUS_MISSING") {
61
+ return buildPatentEnvelope({
62
+ code: "PATENT_API_DEPRECATED",
63
+ adapter_path,
64
+ step,
65
+ suggestion:
66
+ "engine has no outbound MCP transport wired into the bus today; install an McpResolver via src/engine/transport/mcp-browser.installMcpResolver() before invoking this adapter, or try a non-browser source first",
67
+ alternatives: ["uspto", "epo", "lens"],
68
+ retryable: false,
69
+ });
70
+ }
71
+ return buildPatentEnvelope({
72
+ code: "PATENT_API_DEPRECATED",
73
+ adapter_path,
74
+ step,
75
+ suggestion: `mcp-browser transport error (${err.code}): ${err.message}`,
76
+ alternatives: ["uspto", "epo"],
77
+ retryable: false,
78
+ });
79
+ }
80
+
81
+ /**
82
+ * Navigate then evaluate a DOM-extraction expression. Returns the evaluate
83
+ * result on the happy path, or throws a TransportError with a structured
84
+ * code so callers map to a PatentEnvelope row.
85
+ *
86
+ * Adapters MUST treat the result as untrusted and validate shape before
87
+ * normalization — captcha pages tend to return zero-length arrays without
88
+ * throwing.
89
+ */
90
+ export async function navigateAndExtract<T>(
91
+ url: string,
92
+ expression: string,
93
+ ): Promise<McpBrowserResult<T>> {
94
+ const init = await initMcpBrowserTransport();
95
+ if (init.active_server === "none") {
96
+ const code =
97
+ init.reason === "bus-missing" ? "MCP_BUS_MISSING" : "MCP_NO_SERVER";
98
+ throw new TransportError(code, `mcp-browser unavailable (${init.reason})`);
99
+ }
100
+ const navResult = await mcpBrowserNavigate({ url });
101
+ if (!navResult.ok) {
102
+ throw new TransportError(
103
+ navResult.code ?? "MCP_NAVIGATE_FAILED",
104
+ navResult.message ?? "navigate did not succeed",
105
+ );
106
+ }
107
+ const evalResult = await mcpBrowserEvaluate<T>({
108
+ expression,
109
+ tab: navResult.tab,
110
+ });
111
+ if (!evalResult.ok) {
112
+ throw new TransportError(
113
+ evalResult.code ?? "MCP_EVALUATE_FAILED",
114
+ evalResult.message ?? "evaluate did not succeed",
115
+ );
116
+ }
117
+ return evalResult;
118
+ }
119
+
120
+ /**
121
+ * Heuristic — CNIPA public-search captcha is a 验证码 iframe. When the
122
+ * evaluator returns a zero-length result array, the safest assumption is
123
+ * captcha; emit a structured envelope rather than a "no results" message
124
+ * the agent cannot disambiguate.
125
+ */
126
+ export function looksLikeCaptcha(
127
+ rowCount: number,
128
+ htmlMarker?: string,
129
+ ): boolean {
130
+ if (rowCount > 0) return false;
131
+ if (!htmlMarker) return true; // empty result on a browser path = assume captcha
132
+ const lowered = htmlMarker.toLowerCase();
133
+ return (
134
+ lowered.includes("captcha") ||
135
+ lowered.includes("验证码") ||
136
+ lowered.includes("verifycode")
137
+ );
138
+ }
@@ -0,0 +1,199 @@
1
+ /**
2
+ * @owner src::adapters::cnipa::get
3
+ * @does Browser-driven retrieval of a single CNIPA patent document by publication number; loads the detail page through the mcp-browser transport and extracts the bibliographic fields into a PatentRecord.
4
+ * @needs src/engine/transport/mcp-browser.ts, src/engine/normalizer/patent-envelope.ts, src/adapters/cnipa/_shared.ts, src/registry.ts
5
+ * @feeds src/commands/patent.ts (capability tag patent.get)
6
+ * @breaks emits PATENT_INVALID_NUMBER when input is empty or fails canonicalization; emits PATENT_NOT_FOUND when the detail page returns no fields; PATENT_BROWSER_CAPTCHA when the page is captcha-gated; PATENT_API_DEPRECATED with MCP_BUS_MISSING context when no outbound MCP transport is registered
7
+ * @invariants output is a single PatentRecord row when the upstream answers; never falls back to a stub record
8
+ * @side-effects controls the user's Chrome via MCP
9
+ * @perf single navigate + one evaluate
10
+ * @concurrency safe
11
+ * @test tests/unit/adapters/cnipa/search.test.ts (transport-error path) — get-specific tests deferred to integration
12
+ * @stability experimental
13
+ * @since 2026-05-18
14
+ * @verification browser-only
15
+ */
16
+
17
+ import { cli, Strategy } from "../../registry.js";
18
+ import { TransportError } from "../../engine/transport/mcp-browser.js";
19
+ import { assemblePatentRecord } from "../../engine/normalizer/patent-envelope.js";
20
+ import {
21
+ cnipaEnvelope,
22
+ looksLikeCaptcha,
23
+ navigateAndExtract,
24
+ transportErrorToEnvelope,
25
+ } from "./_shared.js";
26
+
27
+ const ADAPTER_PATH = "src/adapters/cnipa/get.ts";
28
+ const CNIPA_DETAIL_URL =
29
+ "https://pss-system.cponline.cnipa.gov.cn/conventionalDetail";
30
+
31
+ interface CnipaDetail {
32
+ publication_number?: string;
33
+ application_number?: string;
34
+ title?: string;
35
+ abstract?: string;
36
+ applicant?: string;
37
+ inventor?: string;
38
+ publication_date?: string;
39
+ filing_date?: string;
40
+ grant_date?: string;
41
+ legal_status?: string;
42
+ source_url?: string;
43
+ html_marker?: string;
44
+ }
45
+
46
+ const DETAIL_EXTRACTOR = `(() => {
47
+ const text = (sel) => {
48
+ const node = document.querySelector(sel);
49
+ return node ? (node.textContent || '').trim() : '';
50
+ };
51
+ return {
52
+ publication_number: text('[data-field="pubNo"], .publication-number'),
53
+ application_number: text('[data-field="appNo"], .application-number'),
54
+ title: text('[data-field="title"], h1.title, .invention-title'),
55
+ abstract: text('[data-field="abstract"], .abstract'),
56
+ applicant: text('[data-field="applicant"], .applicant'),
57
+ inventor: text('[data-field="inventor"], .inventor'),
58
+ publication_date: text('[data-field="pubDate"], .publication-date'),
59
+ filing_date: text('[data-field="appDate"], .filing-date'),
60
+ grant_date: text('[data-field="grantDate"], .grant-date'),
61
+ legal_status: text('[data-field="legalStatus"], .legal-status'),
62
+ source_url: location.href,
63
+ html_marker: document.body && document.body.innerText
64
+ ? document.body.innerText.slice(0, 200)
65
+ : '',
66
+ };
67
+ })()`;
68
+
69
+ export async function runCnipaGet(kwargs: {
70
+ publication_number: string;
71
+ }): Promise<unknown[]> {
72
+ const pubNo = String(kwargs.publication_number ?? "").trim();
73
+ if (pubNo.length === 0) {
74
+ return [
75
+ {
76
+ envelope: cnipaEnvelope(
77
+ "PATENT_INVALID_NUMBER",
78
+ ADAPTER_PATH,
79
+ "validate",
80
+ "cnipa get requires a non-empty publication_number",
81
+ ),
82
+ },
83
+ ];
84
+ }
85
+ const url = `${CNIPA_DETAIL_URL}?pubNo=${encodeURIComponent(pubNo)}`;
86
+ let detail: CnipaDetail;
87
+ try {
88
+ const result = await navigateAndExtract<CnipaDetail>(url, DETAIL_EXTRACTOR);
89
+ if (!result.data) {
90
+ return [
91
+ {
92
+ envelope: cnipaEnvelope(
93
+ "PATENT_SCHEMA_DRIFT",
94
+ ADAPTER_PATH,
95
+ "evaluate",
96
+ "mcp-browser evaluate returned no data; check selector schema in src/adapters/cnipa/get.ts",
97
+ ),
98
+ },
99
+ ];
100
+ }
101
+ detail = result.data;
102
+ } catch (err) {
103
+ if (err instanceof TransportError) {
104
+ return [
105
+ {
106
+ envelope: transportErrorToEnvelope(err, ADAPTER_PATH, "navigate"),
107
+ },
108
+ ];
109
+ }
110
+ throw err;
111
+ }
112
+
113
+ // Captcha heuristic: detail page returned without any of the expected
114
+ // bibliographic fields → almost certainly captcha-gated.
115
+ const fieldCount = [
116
+ detail.publication_number,
117
+ detail.title,
118
+ detail.application_number,
119
+ detail.publication_date,
120
+ ].filter(Boolean).length;
121
+ if (looksLikeCaptcha(fieldCount, detail.html_marker)) {
122
+ return [
123
+ {
124
+ envelope: cnipaEnvelope(
125
+ "PATENT_BROWSER_CAPTCHA",
126
+ ADAPTER_PATH,
127
+ "evaluate",
128
+ "CNIPA detail page returned no bibliographic fields; solve the 验证码 in the open browser tab and re-run",
129
+ ["espacenet"],
130
+ ),
131
+ },
132
+ ];
133
+ }
134
+
135
+ const canonicalPubNo = detail.publication_number || pubNo;
136
+ try {
137
+ return [
138
+ assemblePatentRecord({
139
+ publication_number: canonicalPubNo,
140
+ application_number: detail.application_number || undefined,
141
+ title: detail.title || undefined,
142
+ abstract: detail.abstract || undefined,
143
+ assignees: detail.applicant
144
+ ? [{ name: detail.applicant, country: "CN" }]
145
+ : undefined,
146
+ inventors: detail.inventor
147
+ ? [{ name: detail.inventor, country: "CN" }]
148
+ : undefined,
149
+ publication_date: detail.publication_date || undefined,
150
+ filing_date: detail.filing_date || undefined,
151
+ grant_date: detail.grant_date || undefined,
152
+ legal_status: detail.legal_status || undefined,
153
+ source_adapter: "cnipa",
154
+ source_url: detail.source_url || url,
155
+ } as Parameters<typeof assemblePatentRecord>[0]),
156
+ ];
157
+ } catch {
158
+ return [
159
+ {
160
+ envelope: cnipaEnvelope(
161
+ "PATENT_NOT_FOUND",
162
+ ADAPTER_PATH,
163
+ "normalize",
164
+ `cnipa detail page did not yield a valid publication_number for "${pubNo}"`,
165
+ ["espacenet"],
166
+ ),
167
+ },
168
+ ];
169
+ }
170
+ }
171
+
172
+ cli({
173
+ site: "cnipa",
174
+ name: "get",
175
+ description: "Retrieve a single CNIPA patent document by publication number",
176
+ domain: "pss-system.cponline.cnipa.gov.cn",
177
+ strategy: Strategy.PUBLIC,
178
+ adapter_path: ADAPTER_PATH,
179
+ args: [
180
+ {
181
+ name: "publication_number",
182
+ type: "str",
183
+ required: true,
184
+ positional: true,
185
+ description: "ST.16 publication number (e.g. CN114123456A)",
186
+ },
187
+ ],
188
+ columns: [
189
+ "publication_number",
190
+ "title",
191
+ "publication_date",
192
+ "legal_status",
193
+ "source_url",
194
+ ],
195
+ capabilities: ["mcp-browser.navigate", "mcp-browser.evaluate", "patent.get"],
196
+ minimum_capability: "mcp-browser.evaluate",
197
+ func: async (_page, kwargs) =>
198
+ runCnipaGet(kwargs as { publication_number: string }),
199
+ });
@@ -0,0 +1,162 @@
1
+ /**
2
+ * @owner src::adapters::cnipa::legal-status
3
+ * @does Browser-driven CNIPA legal-status lookup — scrapes the prosecution timeline + grant status from the 公众查询 detail page; emits structured envelopes for captcha / not-found / MCP-bus gaps.
4
+ * @needs src/engine/transport/mcp-browser.ts, src/engine/normalizer/patent-envelope.ts, src/adapters/cnipa/_shared.ts, src/registry.ts
5
+ * @feeds src/commands/patent.ts (capability tag patent.legal-status)
6
+ * @breaks emits PATENT_INVALID_NUMBER, PATENT_BROWSER_CAPTCHA, PATENT_API_DEPRECATED (with MCP_BUS_MISSING context); never synthesizes a status
7
+ * @invariants output row carries `legal_status` exactly as scraped; no normalization beyond trim
8
+ * @side-effects controls Chrome via MCP
9
+ * @perf single navigate + evaluate
10
+ * @concurrency safe
11
+ * @test tests/unit/adapters/cnipa/search.test.ts (shared transport-error path)
12
+ * @stability experimental
13
+ * @since 2026-05-18
14
+ * @verification browser-only
15
+ */
16
+
17
+ import { cli, Strategy } from "../../registry.js";
18
+ import { TransportError } from "../../engine/transport/mcp-browser.js";
19
+ import {
20
+ cnipaEnvelope,
21
+ looksLikeCaptcha,
22
+ navigateAndExtract,
23
+ transportErrorToEnvelope,
24
+ } from "./_shared.js";
25
+
26
+ const ADAPTER_PATH = "src/adapters/cnipa/legal-status.ts";
27
+ const CNIPA_LEGAL_URL = "https://pss-system.cponline.cnipa.gov.cn/legalStatus";
28
+
29
+ interface CnipaLegalRow {
30
+ publication_number: string;
31
+ legal_status?: string;
32
+ status_date?: string;
33
+ source_url?: string;
34
+ html_marker?: string;
35
+ }
36
+
37
+ const EXTRACTOR = `(() => {
38
+ const text = (sel) => {
39
+ const node = document.querySelector(sel);
40
+ return node ? (node.textContent || '').trim() : '';
41
+ };
42
+ return {
43
+ publication_number: text('[data-field="pubNo"], .publication-number'),
44
+ legal_status: text('[data-field="legalStatus"], .legal-status'),
45
+ status_date: text('[data-field="statusDate"], .status-date'),
46
+ source_url: location.href,
47
+ html_marker: document.body && document.body.innerText
48
+ ? document.body.innerText.slice(0, 200)
49
+ : '',
50
+ };
51
+ })()`;
52
+
53
+ export async function runCnipaLegalStatus(kwargs: {
54
+ publication_number: string;
55
+ }): Promise<unknown[]> {
56
+ const pubNo = String(kwargs.publication_number ?? "").trim();
57
+ if (pubNo.length === 0) {
58
+ return [
59
+ {
60
+ envelope: cnipaEnvelope(
61
+ "PATENT_INVALID_NUMBER",
62
+ ADAPTER_PATH,
63
+ "validate",
64
+ "cnipa legal-status requires a non-empty publication_number",
65
+ ),
66
+ },
67
+ ];
68
+ }
69
+ const url = `${CNIPA_LEGAL_URL}?pubNo=${encodeURIComponent(pubNo)}`;
70
+ let detail: CnipaLegalRow;
71
+ try {
72
+ const result = await navigateAndExtract<CnipaLegalRow>(url, EXTRACTOR);
73
+ if (!result.data) {
74
+ return [
75
+ {
76
+ envelope: cnipaEnvelope(
77
+ "PATENT_SCHEMA_DRIFT",
78
+ ADAPTER_PATH,
79
+ "evaluate",
80
+ "mcp-browser evaluate returned no data",
81
+ ),
82
+ },
83
+ ];
84
+ }
85
+ detail = result.data;
86
+ } catch (err) {
87
+ if (err instanceof TransportError) {
88
+ return [
89
+ {
90
+ envelope: transportErrorToEnvelope(err, ADAPTER_PATH, "navigate"),
91
+ },
92
+ ];
93
+ }
94
+ throw err;
95
+ }
96
+ const fieldCount = [detail.publication_number, detail.legal_status].filter(
97
+ Boolean,
98
+ ).length;
99
+ if (looksLikeCaptcha(fieldCount, detail.html_marker)) {
100
+ return [
101
+ {
102
+ envelope: cnipaEnvelope(
103
+ "PATENT_BROWSER_CAPTCHA",
104
+ ADAPTER_PATH,
105
+ "evaluate",
106
+ "CNIPA legal-status page returned no fields; solve the 验证码 and re-run",
107
+ ["espacenet"],
108
+ ),
109
+ },
110
+ ];
111
+ }
112
+ if (!detail.legal_status) {
113
+ return [
114
+ {
115
+ envelope: cnipaEnvelope(
116
+ "PATENT_NOT_FOUND",
117
+ ADAPTER_PATH,
118
+ "normalize",
119
+ `cnipa returned no legal_status for "${pubNo}"`,
120
+ ["espacenet"],
121
+ ),
122
+ },
123
+ ];
124
+ }
125
+ return [
126
+ {
127
+ publication_number: detail.publication_number || pubNo,
128
+ legal_status: detail.legal_status,
129
+ status_date: detail.status_date,
130
+ source_adapter: "cnipa",
131
+ source_url: detail.source_url || url,
132
+ retrieved_at: new Date().toISOString(),
133
+ },
134
+ ];
135
+ }
136
+
137
+ cli({
138
+ site: "cnipa",
139
+ name: "legal-status",
140
+ description: "CNIPA legal-status / prosecution timeline lookup (browser)",
141
+ domain: "pss-system.cponline.cnipa.gov.cn",
142
+ strategy: Strategy.PUBLIC,
143
+ adapter_path: ADAPTER_PATH,
144
+ args: [
145
+ {
146
+ name: "publication_number",
147
+ type: "str",
148
+ required: true,
149
+ positional: true,
150
+ description: "ST.16 publication number",
151
+ },
152
+ ],
153
+ columns: ["publication_number", "legal_status", "status_date", "source_url"],
154
+ capabilities: [
155
+ "mcp-browser.navigate",
156
+ "mcp-browser.evaluate",
157
+ "patent.legal-status",
158
+ ],
159
+ minimum_capability: "mcp-browser.evaluate",
160
+ func: async (_page, kwargs) =>
161
+ runCnipaLegalStatus(kwargs as { publication_number: string }),
162
+ });