@agentrhq/webcmd 0.1.1 → 0.2.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 (1290) hide show
  1. package/README.md +278 -20
  2. package/cli-manifest.json +16247 -34913
  3. package/clis/_atlassian/shared.js +1 -1
  4. package/clis/booking/search.js +4 -4
  5. package/clis/chatgpt/ask.js +2 -2
  6. package/clis/chatgpt/utils.js +41 -42
  7. package/clis/chatgpt/utils.test.js +23 -23
  8. package/clis/chatgpt-app/ax.js +5 -5
  9. package/clis/chatgpt-app/ax.test.js +8 -8
  10. package/clis/chatgpt-app/new.js +2 -2
  11. package/clis/codex/sidebar.js +1 -1
  12. package/clis/codex/sidebar.test.js +12 -12
  13. package/clis/coingecko/top.js +3 -3
  14. package/clis/dblp/dblp.test.js +1 -1
  15. package/clis/discord-app/search.js +1 -1
  16. package/clis/discord-app/utils.js +6 -6
  17. package/clis/facebook/__fixtures__/notifications-page.html +6 -6
  18. package/clis/facebook/add-friend.js +2 -2
  19. package/clis/facebook/feed.js +18 -18
  20. package/clis/facebook/friends.js +4 -4
  21. package/clis/facebook/groups.js +3 -3
  22. package/clis/facebook/join-group.js +2 -2
  23. package/clis/facebook/marketplace-inbox.js +3 -3
  24. package/clis/facebook/marketplace-listings.js +1 -1
  25. package/clis/facebook/notifications.js +14 -15
  26. package/clis/facebook/notifications.test.js +28 -29
  27. package/clis/gemini/ask.test.js +12 -12
  28. package/clis/gemini/deep-research-result.js +2 -2
  29. package/clis/gemini/deep-research-result.test.js +2 -2
  30. package/clis/gemini/deep-research.js +2 -2
  31. package/clis/gemini/deep-research.test.js +1 -1
  32. package/clis/gemini/models.js +11 -11
  33. package/clis/gemini/models.test.js +1 -1
  34. package/clis/gemini/reply-state.test.js +89 -89
  35. package/clis/gemini/utils.js +41 -41
  36. package/clis/gemini/utils.test.js +30 -30
  37. package/clis/geogebra/utils.js +1 -1
  38. package/clis/google-scholar/search.js +3 -3
  39. package/clis/grok/delete.js +1 -1
  40. package/clis/grok/export-all.js +2 -2
  41. package/clis/grok/export.js +2 -2
  42. package/clis/grok/pin.js +3 -3
  43. package/clis/grok/utils.js +12 -12
  44. package/clis/grok/utils.test.js +2 -2
  45. package/clis/indeed/indeed.test.js +3 -3
  46. package/clis/indeed/utils.js +1 -1
  47. package/clis/instagram/post.js +19 -19
  48. package/clis/instagram/post.test.js +2 -2
  49. package/clis/instagram/reel.js +6 -6
  50. package/clis/linkedin/connect.js +3 -3
  51. package/clis/linkedin/people-search.js +4 -4
  52. package/clis/linkedin/profile-experience.js +6 -6
  53. package/clis/linkedin/profile-experience.test.js +10 -10
  54. package/clis/linkedin/profile-read.js +1 -1
  55. package/clis/linkedin/safe-send.js +1 -1
  56. package/clis/linkedin/search.js +1 -1
  57. package/clis/linkedin/shared.js +2 -2
  58. package/clis/linkedin/timeline.js +5 -5
  59. package/clis/manus/manus.test.js +2 -2
  60. package/clis/medium/feed.js +3 -3
  61. package/clis/medium/search.js +3 -3
  62. package/clis/medium/user.js +3 -3
  63. package/clis/notebooklm/auth.js +2 -2
  64. package/clis/notebooklm/note-list.test.js +4 -4
  65. package/clis/notebooklm/notes-get.test.js +8 -8
  66. package/clis/notebooklm/source-fulltext.test.js +11 -11
  67. package/clis/notebooklm/utils.js +28 -28
  68. package/clis/notebooklm/utils.test.js +10 -10
  69. package/clis/pixiv/search.test.js +3 -3
  70. package/clis/qoder/quest.js +2 -2
  71. package/clis/reddit/home.js +2 -2
  72. package/clis/reddit/hot.js +1 -1
  73. package/clis/reddit/read.js +2 -2
  74. package/clis/reddit/read.test.js +1 -1
  75. package/clis/reddit/reply.js +2 -2
  76. package/clis/reddit/whoami.js +2 -2
  77. package/clis/reuters/article-detail.js +1 -1
  78. package/clis/reuters/search.js +1 -1
  79. package/clis/slock/attachment-upload.test.js +1 -1
  80. package/clis/slock/task-convert.js +1 -1
  81. package/clis/substack/feed.js +3 -3
  82. package/clis/substack/publication.js +3 -3
  83. package/clis/substack/search.js +4 -4
  84. package/clis/tiktok/comment.js +2 -2
  85. package/clis/tiktok/follow.js +4 -4
  86. package/clis/tiktok/like.js +1 -1
  87. package/clis/tiktok/save.js +1 -1
  88. package/clis/tiktok/unfollow.js +4 -4
  89. package/clis/tiktok/unlike.js +1 -1
  90. package/clis/tiktok/unsave.js +2 -2
  91. package/clis/tiktok/write-refactor.test.js +5 -5
  92. package/clis/twitter/accept.js +3 -3
  93. package/clis/twitter/followers.js +1 -1
  94. package/clis/twitter/list-remove-core.js +2 -2
  95. package/clis/twitter/list-tweets.test.js +3 -3
  96. package/clis/twitter/lists.js +6 -6
  97. package/clis/twitter/lists.test.js +2 -2
  98. package/clis/twitter/reply-dm.js +1 -1
  99. package/clis/twitter/shared.test.js +4 -5
  100. package/clis/twitter/trending.js +1 -1
  101. package/clis/twitter/utils.js +1 -1
  102. package/clis/web/read.js +1 -1
  103. package/clis/web/read.test.js +2 -2
  104. package/clis/yahoo-finance/quote.js +1 -1
  105. package/clis/youtube/history.js +4 -4
  106. package/clis/youtube/transcript-group.js +1 -1
  107. package/clis/youtube/transcript-group.test.js +5 -5
  108. package/clis/youtube/transcript.js +5 -5
  109. package/clis/youtube/video.js +4 -4
  110. package/clis/youtube/video.test.js +6 -6
  111. package/dist/src/adapter-shadow.d.ts +11 -0
  112. package/dist/src/adapter-shadow.js +72 -0
  113. package/dist/src/adapter-shadow.test.js +49 -0
  114. package/dist/src/adapter-source.d.ts +11 -0
  115. package/dist/src/adapter-source.js +24 -0
  116. package/dist/src/adapter-source.test.d.ts +1 -0
  117. package/dist/src/adapter-source.test.js +29 -0
  118. package/dist/src/brand.d.ts +9 -0
  119. package/dist/src/brand.js +9 -0
  120. package/dist/src/brand.test.d.ts +1 -0
  121. package/dist/src/brand.test.js +15 -0
  122. package/dist/src/browser/analyze.d.ts +118 -0
  123. package/dist/src/browser/analyze.js +405 -0
  124. package/dist/src/browser/analyze.test.d.ts +1 -0
  125. package/dist/src/browser/analyze.test.js +209 -0
  126. package/dist/src/browser/article-extract.d.ts +57 -0
  127. package/dist/src/browser/article-extract.e2e.test.d.ts +1 -0
  128. package/dist/src/browser/article-extract.e2e.test.js +105 -0
  129. package/dist/src/browser/article-extract.js +169 -0
  130. package/dist/src/browser/article-extract.test.d.ts +1 -0
  131. package/dist/src/browser/article-extract.test.js +94 -0
  132. package/dist/src/browser/ax-snapshot.d.ts +37 -0
  133. package/dist/src/browser/ax-snapshot.js +217 -0
  134. package/dist/src/browser/ax-snapshot.test.d.ts +1 -0
  135. package/dist/src/browser/ax-snapshot.test.js +91 -0
  136. package/dist/src/browser/base-page.d.ts +151 -0
  137. package/dist/src/browser/base-page.js +1060 -0
  138. package/dist/src/browser/base-page.test.d.ts +1 -0
  139. package/dist/src/browser/base-page.test.js +803 -0
  140. package/dist/src/browser/bridge-readiness.d.ts +14 -0
  141. package/dist/src/browser/bridge-readiness.js +24 -0
  142. package/dist/src/browser/bridge-readiness.test.d.ts +1 -0
  143. package/dist/src/browser/bridge-readiness.test.js +58 -0
  144. package/dist/src/browser/bridge.d.ts +26 -0
  145. package/dist/src/browser/bridge.js +58 -0
  146. package/dist/src/browser/cdp-click-fixture.test.d.ts +1 -0
  147. package/dist/src/browser/cdp-click-fixture.test.js +87 -0
  148. package/dist/src/browser/cdp.d.ts +46 -0
  149. package/dist/src/browser/cdp.js +536 -0
  150. package/dist/src/browser/cdp.test.d.ts +1 -0
  151. package/dist/src/browser/cdp.test.js +79 -0
  152. package/dist/src/browser/compound.d.ts +59 -0
  153. package/dist/src/browser/compound.js +112 -0
  154. package/dist/src/browser/compound.test.d.ts +1 -0
  155. package/dist/src/browser/compound.test.js +175 -0
  156. package/dist/src/browser/config.d.ts +2 -0
  157. package/dist/src/browser/config.js +14 -0
  158. package/dist/src/browser/daemon-client.d.ts +33 -0
  159. package/dist/src/browser/daemon-client.js +187 -0
  160. package/dist/src/browser/daemon-client.test.d.ts +1 -0
  161. package/dist/src/browser/daemon-client.test.js +411 -0
  162. package/dist/src/browser/daemon-lifecycle.d.ts +37 -0
  163. package/dist/src/browser/daemon-lifecycle.js +147 -0
  164. package/dist/src/browser/daemon-transport.d.ts +54 -0
  165. package/dist/src/browser/daemon-transport.js +68 -0
  166. package/dist/src/browser/daemon-version.d.ts +4 -0
  167. package/dist/src/browser/daemon-version.js +12 -0
  168. package/dist/src/browser/dom-helpers.d.ts +41 -0
  169. package/dist/src/browser/dom-helpers.js +239 -0
  170. package/dist/src/browser/dom-helpers.test.d.ts +1 -0
  171. package/dist/src/browser/dom-helpers.test.js +106 -0
  172. package/dist/src/browser/dom-snapshot.d.ts +93 -0
  173. package/dist/src/browser/dom-snapshot.js +894 -0
  174. package/dist/src/browser/dom-snapshot.test.d.ts +11 -0
  175. package/dist/src/browser/dom-snapshot.test.js +313 -0
  176. package/dist/src/browser/errors.d.ts +38 -0
  177. package/dist/src/browser/errors.js +90 -0
  178. package/dist/src/browser/errors.test.d.ts +1 -0
  179. package/dist/src/browser/errors.test.js +60 -0
  180. package/dist/src/browser/extract.d.ts +69 -0
  181. package/dist/src/browser/extract.js +132 -0
  182. package/dist/src/browser/extract.test.d.ts +1 -0
  183. package/dist/src/browser/extract.test.js +129 -0
  184. package/dist/src/browser/find.d.ts +84 -0
  185. package/dist/src/browser/find.js +398 -0
  186. package/dist/src/browser/find.test.d.ts +1 -0
  187. package/dist/src/browser/find.test.js +180 -0
  188. package/dist/src/browser/html-tree.d.ts +75 -0
  189. package/dist/src/browser/html-tree.js +112 -0
  190. package/dist/src/browser/html-tree.test.d.ts +1 -0
  191. package/dist/src/browser/html-tree.test.js +181 -0
  192. package/dist/src/browser/index.d.ts +14 -0
  193. package/dist/src/browser/index.js +12 -0
  194. package/dist/src/browser/network-cache.d.ts +49 -0
  195. package/dist/src/browser/network-cache.js +78 -0
  196. package/dist/src/browser/network-cache.test.d.ts +1 -0
  197. package/dist/src/browser/network-cache.test.js +75 -0
  198. package/dist/src/browser/network-interceptor.d.ts +11 -0
  199. package/dist/src/browser/network-interceptor.js +11 -0
  200. package/dist/src/browser/network-key.d.ts +22 -0
  201. package/dist/src/browser/network-key.js +66 -0
  202. package/dist/src/browser/network-key.test.d.ts +1 -0
  203. package/dist/src/browser/network-key.test.js +49 -0
  204. package/dist/src/browser/page.d.ts +83 -0
  205. package/dist/src/browser/page.js +453 -0
  206. package/dist/src/browser/page.test.d.ts +1 -0
  207. package/dist/src/browser/page.test.js +406 -0
  208. package/dist/src/browser/profile.d.ts +14 -0
  209. package/dist/src/browser/profile.js +86 -0
  210. package/dist/src/browser/protocol.d.ts +65 -0
  211. package/dist/src/browser/protocol.js +1 -0
  212. package/dist/src/browser/runtime/local-cloak/actions.d.ts +3 -0
  213. package/dist/src/browser/runtime/local-cloak/actions.js +240 -0
  214. package/dist/src/browser/runtime/local-cloak/downloads.d.ts +3 -0
  215. package/dist/src/browser/runtime/local-cloak/downloads.js +28 -0
  216. package/dist/src/browser/runtime/local-cloak/network.d.ts +28 -0
  217. package/dist/src/browser/runtime/local-cloak/network.js +120 -0
  218. package/dist/src/browser/runtime/local-cloak/network.test.d.ts +1 -0
  219. package/dist/src/browser/runtime/local-cloak/network.test.js +124 -0
  220. package/dist/src/browser/runtime/local-cloak/profiles.d.ts +6 -0
  221. package/dist/src/browser/runtime/local-cloak/profiles.js +17 -0
  222. package/dist/src/browser/runtime/local-cloak/profiles.test.d.ts +1 -0
  223. package/dist/src/browser/runtime/local-cloak/profiles.test.js +19 -0
  224. package/dist/src/browser/runtime/local-cloak/provider.d.ts +15 -0
  225. package/dist/src/browser/runtime/local-cloak/provider.js +27 -0
  226. package/dist/src/browser/runtime/local-cloak/provider.test.d.ts +1 -0
  227. package/dist/src/browser/runtime/local-cloak/provider.test.js +244 -0
  228. package/dist/src/browser/runtime/local-cloak/session-manager.d.ts +77 -0
  229. package/dist/src/browser/runtime/local-cloak/session-manager.js +280 -0
  230. package/dist/src/browser/runtime/local-cloak/session-manager.test.d.ts +1 -0
  231. package/dist/src/browser/runtime/local-cloak/session-manager.test.js +92 -0
  232. package/dist/src/browser/runtime/provider.d.ts +9 -0
  233. package/dist/src/browser/runtime/provider.js +1 -0
  234. package/dist/src/browser/runtime/provider.test.d.ts +2 -0
  235. package/dist/src/browser/runtime/provider.test.js +49 -0
  236. package/dist/src/browser/shape-filter.d.ts +52 -0
  237. package/dist/src/browser/shape-filter.js +101 -0
  238. package/dist/src/browser/shape-filter.test.d.ts +1 -0
  239. package/dist/src/browser/shape-filter.test.js +101 -0
  240. package/dist/src/browser/shape.d.ts +23 -0
  241. package/dist/src/browser/shape.js +95 -0
  242. package/dist/src/browser/shape.test.d.ts +1 -0
  243. package/dist/src/browser/shape.test.js +82 -0
  244. package/dist/src/browser/stealth.d.ts +11 -0
  245. package/dist/src/browser/stealth.js +359 -0
  246. package/dist/src/browser/stealth.test.d.ts +1 -0
  247. package/dist/src/browser/stealth.test.js +134 -0
  248. package/dist/src/browser/tabs.d.ts +13 -0
  249. package/dist/src/browser/tabs.js +70 -0
  250. package/dist/src/browser/target-errors.d.ts +39 -0
  251. package/dist/src/browser/target-errors.js +45 -0
  252. package/dist/src/browser/target-errors.test.d.ts +1 -0
  253. package/dist/src/browser/target-errors.test.js +94 -0
  254. package/dist/src/browser/target-resolver.d.ts +158 -0
  255. package/dist/src/browser/target-resolver.js +570 -0
  256. package/dist/src/browser/target-resolver.test.d.ts +1 -0
  257. package/dist/src/browser/target-resolver.test.js +118 -0
  258. package/dist/src/browser/utils.d.ts +20 -0
  259. package/dist/src/browser/utils.js +64 -0
  260. package/dist/src/browser/utils.test.d.ts +1 -0
  261. package/dist/src/browser/utils.test.js +29 -0
  262. package/dist/src/browser/verify-fixture.d.ts +65 -0
  263. package/dist/src/browser/verify-fixture.js +318 -0
  264. package/dist/src/browser/verify-fixture.test.d.ts +1 -0
  265. package/dist/src/browser/verify-fixture.test.js +219 -0
  266. package/dist/src/browser/visual-refs.d.ts +11 -0
  267. package/dist/src/browser/visual-refs.js +108 -0
  268. package/dist/src/browser.test.d.ts +1 -0
  269. package/dist/src/browser.test.js +297 -0
  270. package/dist/src/build-manifest.d.ts +103 -0
  271. package/dist/src/build-manifest.js +363 -0
  272. package/dist/src/build-manifest.test.d.ts +1 -0
  273. package/dist/src/build-manifest.test.js +341 -0
  274. package/dist/src/capabilityRouting.d.ts +19 -0
  275. package/dist/src/capabilityRouting.js +56 -0
  276. package/dist/src/capabilityRouting.test.d.ts +1 -0
  277. package/dist/src/capabilityRouting.test.js +63 -0
  278. package/dist/src/cli-argv-preprocess.d.ts +63 -0
  279. package/dist/src/cli-argv-preprocess.js +303 -0
  280. package/dist/src/cli-argv-preprocess.test.d.ts +1 -0
  281. package/dist/src/cli-argv-preprocess.test.js +304 -0
  282. package/dist/src/cli.d.ts +79 -0
  283. package/dist/src/cli.js +3350 -0
  284. package/dist/src/cli.test.d.ts +1 -0
  285. package/dist/src/cli.test.js +3041 -0
  286. package/dist/src/commanderAdapter.d.ts +21 -0
  287. package/dist/src/commanderAdapter.js +208 -0
  288. package/dist/src/commanderAdapter.test.d.ts +1 -0
  289. package/dist/src/commanderAdapter.test.js +352 -0
  290. package/dist/src/commands/auth.d.ts +40 -0
  291. package/dist/src/commands/auth.js +434 -0
  292. package/dist/src/commands/auth.test.d.ts +1 -0
  293. package/dist/src/commands/auth.test.js +252 -0
  294. package/dist/src/commands/daemon.d.ts +9 -0
  295. package/dist/src/commands/daemon.js +91 -0
  296. package/dist/src/commands/daemon.test.d.ts +1 -0
  297. package/dist/src/commands/daemon.test.js +293 -0
  298. package/dist/src/completion-fast.d.ts +22 -0
  299. package/dist/src/completion-fast.js +88 -0
  300. package/dist/src/completion-shared.d.ts +13 -0
  301. package/dist/src/completion-shared.js +61 -0
  302. package/dist/src/completion.d.ts +21 -0
  303. package/dist/src/completion.js +68 -0
  304. package/dist/src/completion.test.d.ts +1 -0
  305. package/dist/src/completion.test.js +24 -0
  306. package/dist/src/constants.d.ts +18 -0
  307. package/dist/src/constants.js +41 -0
  308. package/dist/src/convention-audit.d.ts +50 -0
  309. package/dist/src/convention-audit.js +553 -0
  310. package/dist/src/convention-audit.test.d.ts +1 -0
  311. package/dist/src/convention-audit.test.js +255 -0
  312. package/dist/src/daemon/server.d.ts +13 -0
  313. package/dist/src/daemon/server.js +190 -0
  314. package/dist/src/daemon/server.test.d.ts +1 -0
  315. package/dist/src/daemon/server.test.js +184 -0
  316. package/dist/src/daemon-utils.d.ts +19 -0
  317. package/dist/src/daemon-utils.js +46 -0
  318. package/dist/src/daemon.d.ts +1 -0
  319. package/dist/src/daemon.js +27 -0
  320. package/dist/src/daemon.test.d.ts +1 -0
  321. package/dist/src/daemon.test.js +69 -0
  322. package/dist/src/discovery.d.ts +46 -0
  323. package/dist/src/discovery.js +341 -0
  324. package/dist/src/doctor.d.ts +39 -0
  325. package/dist/src/doctor.js +174 -0
  326. package/dist/src/doctor.test.d.ts +1 -0
  327. package/dist/src/doctor.test.js +309 -0
  328. package/dist/src/download/article-download.d.ts +72 -0
  329. package/dist/src/download/article-download.js +305 -0
  330. package/dist/src/download/article-download.test.d.ts +1 -0
  331. package/dist/src/download/article-download.test.js +235 -0
  332. package/dist/src/download/index.d.ts +71 -0
  333. package/dist/src/download/index.js +363 -0
  334. package/dist/src/download/index.test.d.ts +1 -0
  335. package/dist/src/download/index.test.js +173 -0
  336. package/dist/src/download/media-download.d.ts +49 -0
  337. package/dist/src/download/media-download.js +127 -0
  338. package/dist/src/download/media-download.test.d.ts +1 -0
  339. package/dist/src/download/media-download.test.js +112 -0
  340. package/dist/src/download/progress.d.ts +36 -0
  341. package/dist/src/download/progress.js +120 -0
  342. package/dist/src/download/progress.test.d.ts +1 -0
  343. package/dist/src/download/progress.test.js +36 -0
  344. package/dist/src/electron-apps.d.ts +31 -0
  345. package/dist/src/electron-apps.js +83 -0
  346. package/dist/src/electron-apps.test.d.ts +1 -0
  347. package/dist/src/electron-apps.test.js +67 -0
  348. package/dist/src/engine.test.d.ts +1 -0
  349. package/dist/src/engine.test.js +312 -0
  350. package/dist/src/errors.d.ts +114 -0
  351. package/dist/src/errors.js +174 -0
  352. package/dist/src/errors.test.d.ts +1 -0
  353. package/dist/src/errors.test.js +109 -0
  354. package/dist/src/execution.d.ts +24 -0
  355. package/dist/src/execution.js +511 -0
  356. package/dist/src/execution.test.d.ts +1 -0
  357. package/dist/src/execution.test.js +657 -0
  358. package/dist/src/external-clis.yaml +0 -37
  359. package/dist/src/external.d.ts +49 -0
  360. package/dist/src/external.js +211 -0
  361. package/dist/src/external.test.d.ts +1 -0
  362. package/dist/src/external.test.js +95 -0
  363. package/dist/src/generate-release-notes-cli.test.d.ts +1 -0
  364. package/dist/src/generate-release-notes-cli.test.js +140 -0
  365. package/dist/src/help.d.ts +88 -0
  366. package/dist/src/help.js +556 -0
  367. package/dist/src/help.test.d.ts +1 -0
  368. package/dist/src/help.test.js +58 -0
  369. package/dist/src/hooks.d.ts +46 -0
  370. package/dist/src/hooks.js +58 -0
  371. package/dist/src/hooks.test.d.ts +4 -0
  372. package/dist/src/hooks.test.js +92 -0
  373. package/dist/src/interceptor.d.ts +44 -0
  374. package/dist/src/interceptor.js +183 -0
  375. package/dist/src/interceptor.test.d.ts +4 -0
  376. package/dist/src/interceptor.test.js +81 -0
  377. package/dist/src/launcher.d.ts +41 -0
  378. package/dist/src/launcher.js +226 -0
  379. package/dist/src/launcher.test.d.ts +1 -0
  380. package/dist/src/launcher.test.js +153 -0
  381. package/dist/src/logger.d.ts +26 -0
  382. package/dist/src/logger.js +49 -0
  383. package/dist/src/main.d.ts +5 -0
  384. package/dist/src/main.js +177 -0
  385. package/dist/src/manifest-types.d.ts +43 -0
  386. package/dist/src/manifest-types.js +9 -0
  387. package/dist/src/node-network.d.ts +10 -0
  388. package/dist/src/node-network.js +174 -0
  389. package/dist/src/node-network.test.d.ts +1 -0
  390. package/dist/src/node-network.test.js +55 -0
  391. package/dist/src/observation/artifact.d.ts +16 -0
  392. package/dist/src/observation/artifact.js +260 -0
  393. package/dist/src/observation/artifact.test.d.ts +1 -0
  394. package/dist/src/observation/artifact.test.js +121 -0
  395. package/dist/src/observation/events.d.ts +89 -0
  396. package/dist/src/observation/events.js +1 -0
  397. package/dist/src/observation/index.d.ts +7 -0
  398. package/dist/src/observation/index.js +7 -0
  399. package/dist/src/observation/manager.d.ts +9 -0
  400. package/dist/src/observation/manager.js +27 -0
  401. package/dist/src/observation/manager.test.d.ts +1 -0
  402. package/dist/src/observation/manager.test.js +13 -0
  403. package/dist/src/observation/redaction.d.ts +11 -0
  404. package/dist/src/observation/redaction.js +81 -0
  405. package/dist/src/observation/redaction.test.d.ts +1 -0
  406. package/dist/src/observation/redaction.test.js +32 -0
  407. package/dist/src/observation/retention.d.ts +32 -0
  408. package/dist/src/observation/retention.js +160 -0
  409. package/dist/src/observation/retention.test.d.ts +1 -0
  410. package/dist/src/observation/retention.test.js +118 -0
  411. package/dist/src/observation/ring-buffer.d.ts +22 -0
  412. package/dist/src/observation/ring-buffer.js +45 -0
  413. package/dist/src/observation/ring-buffer.test.d.ts +1 -0
  414. package/dist/src/observation/ring-buffer.test.js +22 -0
  415. package/dist/src/observation/session.d.ts +25 -0
  416. package/dist/src/observation/session.js +50 -0
  417. package/dist/src/output.d.ts +14 -0
  418. package/dist/src/output.js +152 -0
  419. package/dist/src/output.test.d.ts +1 -0
  420. package/dist/src/output.test.js +53 -0
  421. package/dist/src/package-exports.test.d.ts +1 -0
  422. package/dist/src/package-exports.test.js +112 -0
  423. package/dist/src/package-paths.d.ts +8 -0
  424. package/dist/src/package-paths.js +41 -0
  425. package/dist/src/pipeline/executor.d.ts +11 -0
  426. package/dist/src/pipeline/executor.js +93 -0
  427. package/dist/src/pipeline/executor.test.d.ts +4 -0
  428. package/dist/src/pipeline/executor.test.js +182 -0
  429. package/dist/src/pipeline/index.d.ts +5 -0
  430. package/dist/src/pipeline/index.js +5 -0
  431. package/dist/src/pipeline/registry.d.ts +28 -0
  432. package/dist/src/pipeline/registry.js +55 -0
  433. package/dist/src/pipeline/steps/browser.d.ts +13 -0
  434. package/dist/src/pipeline/steps/browser.js +86 -0
  435. package/dist/src/pipeline/steps/download.d.ts +18 -0
  436. package/dist/src/pipeline/steps/download.js +252 -0
  437. package/dist/src/pipeline/steps/download.test.d.ts +1 -0
  438. package/dist/src/pipeline/steps/download.test.js +102 -0
  439. package/dist/src/pipeline/steps/fetch.d.ts +5 -0
  440. package/dist/src/pipeline/steps/fetch.js +122 -0
  441. package/dist/src/pipeline/steps/fetch.test.d.ts +1 -0
  442. package/dist/src/pipeline/steps/fetch.test.js +117 -0
  443. package/dist/src/pipeline/steps/intercept.d.ts +5 -0
  444. package/dist/src/pipeline/steps/intercept.js +50 -0
  445. package/dist/src/pipeline/steps/tap.d.ts +12 -0
  446. package/dist/src/pipeline/steps/tap.js +93 -0
  447. package/dist/src/pipeline/steps/transform.d.ts +9 -0
  448. package/dist/src/pipeline/steps/transform.js +70 -0
  449. package/dist/src/pipeline/template.d.ts +17 -0
  450. package/dist/src/pipeline/template.js +344 -0
  451. package/dist/src/pipeline/template.test.d.ts +4 -0
  452. package/dist/src/pipeline/template.test.js +197 -0
  453. package/dist/src/pipeline/transform.test.d.ts +4 -0
  454. package/dist/src/pipeline/transform.test.js +133 -0
  455. package/dist/src/plugin-manifest.d.ts +70 -0
  456. package/dist/src/plugin-manifest.js +160 -0
  457. package/dist/src/plugin-manifest.test.d.ts +4 -0
  458. package/dist/src/plugin-manifest.test.js +179 -0
  459. package/dist/src/plugin-scaffold.d.ts +28 -0
  460. package/dist/src/plugin-scaffold.js +143 -0
  461. package/dist/src/plugin-scaffold.test.d.ts +4 -0
  462. package/dist/src/plugin-scaffold.test.js +83 -0
  463. package/dist/src/plugin.d.ts +146 -0
  464. package/dist/src/plugin.js +1303 -0
  465. package/dist/src/plugin.test.d.ts +4 -0
  466. package/dist/src/plugin.test.js +1363 -0
  467. package/dist/src/registry-api.d.ts +13 -0
  468. package/dist/src/registry-api.js +10 -0
  469. package/dist/src/registry.d.ts +123 -0
  470. package/dist/src/registry.js +125 -0
  471. package/dist/src/registry.test.d.ts +4 -0
  472. package/dist/src/registry.test.js +209 -0
  473. package/dist/src/release-notes.d.ts +38 -0
  474. package/dist/src/release-notes.js +99 -0
  475. package/dist/src/release-notes.test.d.ts +1 -0
  476. package/dist/src/release-notes.test.js +61 -0
  477. package/dist/src/runtime-copy.test.d.ts +1 -0
  478. package/dist/src/runtime-copy.test.js +29 -0
  479. package/dist/src/runtime-detect.d.ts +31 -0
  480. package/dist/src/runtime-detect.js +47 -0
  481. package/dist/src/runtime-detect.test.d.ts +1 -0
  482. package/dist/src/runtime-detect.test.js +39 -0
  483. package/dist/src/runtime-identity.test.d.ts +1 -0
  484. package/dist/src/runtime-identity.test.js +18 -0
  485. package/dist/src/runtime.d.ts +47 -0
  486. package/dist/src/runtime.js +54 -0
  487. package/dist/src/scripts/framework.d.ts +7 -0
  488. package/dist/src/scripts/framework.js +25 -0
  489. package/dist/src/scripts/interact.d.ts +4 -0
  490. package/dist/src/scripts/interact.js +20 -0
  491. package/dist/src/scripts/store.d.ts +13 -0
  492. package/dist/src/scripts/store.js +48 -0
  493. package/dist/src/serialization.d.ts +42 -0
  494. package/dist/src/serialization.js +103 -0
  495. package/dist/src/serialization.test.d.ts +1 -0
  496. package/dist/src/serialization.test.js +78 -0
  497. package/dist/src/skills.d.ts +14 -0
  498. package/dist/src/skills.js +127 -0
  499. package/dist/src/skills.test.d.ts +1 -0
  500. package/dist/src/skills.test.js +71 -0
  501. package/dist/src/snapshotFormatter.d.ts +11 -0
  502. package/dist/src/snapshotFormatter.js +336 -0
  503. package/dist/src/snapshotFormatter.test.d.ts +7 -0
  504. package/dist/src/snapshotFormatter.test.js +521 -0
  505. package/dist/src/tui.d.ts +28 -0
  506. package/dist/src/tui.js +179 -0
  507. package/dist/src/tui.test.d.ts +1 -0
  508. package/dist/src/tui.test.js +19 -0
  509. package/dist/src/types.d.ts +236 -0
  510. package/dist/src/types.js +7 -0
  511. package/dist/src/update-check.d.ts +66 -0
  512. package/dist/src/update-check.js +206 -0
  513. package/dist/src/update-check.test.d.ts +1 -0
  514. package/dist/src/update-check.test.js +117 -0
  515. package/dist/src/utils.d.ts +57 -0
  516. package/dist/src/utils.js +152 -0
  517. package/dist/src/utils.test.d.ts +1 -0
  518. package/dist/src/utils.test.js +155 -0
  519. package/dist/src/validate.d.ts +21 -0
  520. package/dist/src/validate.js +130 -0
  521. package/dist/src/validate.test.d.ts +9 -0
  522. package/dist/src/validate.test.js +90 -0
  523. package/dist/src/verify.d.ts +26 -0
  524. package/dist/src/verify.js +67 -0
  525. package/dist/src/version.d.ts +4 -0
  526. package/dist/src/version.js +22 -0
  527. package/package.json +7 -3
  528. package/scripts/check-package-bin.mjs +95 -0
  529. package/scripts/generate-release-notes.ts +234 -0
  530. package/scripts/postinstall.js +1 -1
  531. package/scripts/silent-column-drop-baseline.json +0 -498
  532. package/scripts/typed-error-lint-baseline.json +0 -464
  533. package/skills/webcmd-adapter-author/SKILL.md +216 -213
  534. package/skills/webcmd-adapter-author/references/adapter-template.md +206 -399
  535. package/skills/webcmd-adapter-author/references/api-discovery.md +111 -220
  536. package/skills/webcmd-adapter-author/references/coverage-matrix.md +34 -68
  537. package/skills/webcmd-adapter-author/references/field-conventions.md +84 -167
  538. package/skills/webcmd-adapter-author/references/field-decode-playbook.md +60 -146
  539. package/skills/webcmd-adapter-author/references/jsdom-fixture-pattern.md +111 -178
  540. package/skills/webcmd-adapter-author/references/output-design.md +47 -125
  541. package/skills/webcmd-adapter-author/references/site-memory.md +116 -166
  542. package/skills/webcmd-adapter-author/references/site-recon.md +74 -78
  543. package/skills/webcmd-adapter-author/references/strategy-selection.md +80 -124
  544. package/skills/webcmd-adapter-author/references/success-rate-pitfalls.md +80 -105
  545. package/skills/webcmd-adapter-author/references/typed-errors.md +87 -178
  546. package/skills/webcmd-autofix/SKILL.md +136 -143
  547. package/skills/webcmd-sitemap-author/SKILL.md +58 -67
  548. package/skills/webcmd-sitemap-author/references/sitemap-schema.md +354 -494
  549. package/skills/webcmd-usage/SKILL.md +106 -97
  550. package/clis/12306/auth.js +0 -59
  551. package/clis/12306/me.js +0 -73
  552. package/clis/12306/orders.js +0 -96
  553. package/clis/12306/passengers.js +0 -90
  554. package/clis/12306/price.js +0 -166
  555. package/clis/12306/stations.js +0 -66
  556. package/clis/12306/train.js +0 -91
  557. package/clis/12306/trains.js +0 -166
  558. package/clis/12306/utils.js +0 -272
  559. package/clis/12306/utils.test.js +0 -424
  560. package/clis/1688/assets.js +0 -205
  561. package/clis/1688/assets.test.js +0 -39
  562. package/clis/1688/auth.js +0 -46
  563. package/clis/1688/download.js +0 -77
  564. package/clis/1688/download.test.js +0 -31
  565. package/clis/1688/item.js +0 -188
  566. package/clis/1688/item.test.js +0 -67
  567. package/clis/1688/search.js +0 -310
  568. package/clis/1688/search.test.js +0 -75
  569. package/clis/1688/shared.js +0 -557
  570. package/clis/1688/shared.test.js +0 -57
  571. package/clis/1688/store.js +0 -227
  572. package/clis/1688/store.test.js +0 -62
  573. package/clis/1point3acres/auth.js +0 -52
  574. package/clis/1point3acres/digest.js +0 -35
  575. package/clis/1point3acres/forum.js +0 -51
  576. package/clis/1point3acres/forums.js +0 -44
  577. package/clis/1point3acres/hot.js +0 -35
  578. package/clis/1point3acres/latest.js +0 -35
  579. package/clis/1point3acres/notifications.js +0 -64
  580. package/clis/1point3acres/search.js +0 -71
  581. package/clis/1point3acres/thread.js +0 -117
  582. package/clis/1point3acres/user.js +0 -77
  583. package/clis/1point3acres/utils.js +0 -247
  584. package/clis/36kr/article.js +0 -66
  585. package/clis/36kr/article.test.js +0 -46
  586. package/clis/36kr/hot.js +0 -87
  587. package/clis/36kr/hot.test.js +0 -15
  588. package/clis/36kr/news.js +0 -52
  589. package/clis/36kr/news.test.js +0 -85
  590. package/clis/36kr/search.js +0 -79
  591. package/clis/51job/company.js +0 -126
  592. package/clis/51job/detail.js +0 -109
  593. package/clis/51job/hot.js +0 -56
  594. package/clis/51job/search.js +0 -80
  595. package/clis/51job/utils.js +0 -302
  596. package/clis/51job/utils.test.js +0 -69
  597. package/clis/aibase/news.js +0 -110
  598. package/clis/aibase/news.test.js +0 -59
  599. package/clis/autohome/__fixtures__/catalog.html +0 -11
  600. package/clis/autohome/__fixtures__/koubei.json +0 -116
  601. package/clis/autohome/autohome.test.js +0 -115
  602. package/clis/autohome/brand.js +0 -108
  603. package/clis/autohome/score.js +0 -103
  604. package/clis/autohome/utils.js +0 -157
  605. package/clis/baidu-scholar/search.js +0 -87
  606. package/clis/baidu-scholar/search.test.js +0 -23
  607. package/clis/bilibili/auth.js +0 -36
  608. package/clis/bilibili/comment.js +0 -107
  609. package/clis/bilibili/comment.test.js +0 -153
  610. package/clis/bilibili/comments.js +0 -136
  611. package/clis/bilibili/comments.test.js +0 -142
  612. package/clis/bilibili/download.js +0 -178
  613. package/clis/bilibili/download.test.js +0 -173
  614. package/clis/bilibili/dynamic.js +0 -34
  615. package/clis/bilibili/dynamic.test.js +0 -68
  616. package/clis/bilibili/favorite.js +0 -47
  617. package/clis/bilibili/feed.js +0 -220
  618. package/clis/bilibili/follow.js +0 -140
  619. package/clis/bilibili/follow.test.js +0 -203
  620. package/clis/bilibili/following.js +0 -44
  621. package/clis/bilibili/history.js +0 -45
  622. package/clis/bilibili/hot.js +0 -40
  623. package/clis/bilibili/hot.test.js +0 -17
  624. package/clis/bilibili/me.js +0 -13
  625. package/clis/bilibili/ranking.js +0 -25
  626. package/clis/bilibili/search.js +0 -24
  627. package/clis/bilibili/subtitle.js +0 -141
  628. package/clis/bilibili/subtitle.test.js +0 -240
  629. package/clis/bilibili/summary.js +0 -167
  630. package/clis/bilibili/summary.test.js +0 -210
  631. package/clis/bilibili/unfollow.js +0 -121
  632. package/clis/bilibili/user-videos.js +0 -39
  633. package/clis/bilibili/utils.js +0 -273
  634. package/clis/bilibili/utils.test.js +0 -97
  635. package/clis/bilibili/video.js +0 -155
  636. package/clis/bilibili/video.test.js +0 -308
  637. package/clis/boss/auth.js +0 -47
  638. package/clis/boss/batchgreet.js +0 -61
  639. package/clis/boss/chatlist.js +0 -116
  640. package/clis/boss/chatlist.test.js +0 -211
  641. package/clis/boss/chatmsg.js +0 -117
  642. package/clis/boss/chatmsg.test.js +0 -230
  643. package/clis/boss/detail.js +0 -63
  644. package/clis/boss/exchange.js +0 -46
  645. package/clis/boss/greet.js +0 -49
  646. package/clis/boss/invite.js +0 -64
  647. package/clis/boss/joblist.js +0 -31
  648. package/clis/boss/mark.js +0 -70
  649. package/clis/boss/recommend.js +0 -45
  650. package/clis/boss/resume.js +0 -150
  651. package/clis/boss/search.js +0 -197
  652. package/clis/boss/search.test.js +0 -78
  653. package/clis/boss/send.js +0 -44
  654. package/clis/boss/stats.js +0 -66
  655. package/clis/boss/utils.js +0 -468
  656. package/clis/boss/utils.test.js +0 -34
  657. package/clis/chaoxing/assignments.js +0 -76
  658. package/clis/chaoxing/auth.js +0 -54
  659. package/clis/chaoxing/exams.js +0 -75
  660. package/clis/chaoxing/utils.js +0 -223
  661. package/clis/chaoxing/utils.test.js +0 -45
  662. package/clis/cnki/search.js +0 -61
  663. package/clis/cnki/search.test.js +0 -18
  664. package/clis/ctrip/auth.js +0 -50
  665. package/clis/ctrip/ctrip.test.js +0 -719
  666. package/clis/ctrip/flight.js +0 -136
  667. package/clis/ctrip/hotel-search.js +0 -132
  668. package/clis/ctrip/hotel-suggest.js +0 -45
  669. package/clis/ctrip/search.js +0 -41
  670. package/clis/ctrip/utils.js +0 -473
  671. package/clis/deepseek/ask.js +0 -158
  672. package/clis/deepseek/ask.test.js +0 -399
  673. package/clis/deepseek/auth.js +0 -54
  674. package/clis/deepseek/detail.js +0 -46
  675. package/clis/deepseek/detail.test.js +0 -81
  676. package/clis/deepseek/history.js +0 -27
  677. package/clis/deepseek/new.js +0 -33
  678. package/clis/deepseek/read.js +0 -25
  679. package/clis/deepseek/send.js +0 -140
  680. package/clis/deepseek/send.test.js +0 -107
  681. package/clis/deepseek/status.js +0 -26
  682. package/clis/deepseek/utils.js +0 -487
  683. package/clis/deepseek/utils.test.js +0 -370
  684. package/clis/dianping/__fixtures__/search.html +0 -168
  685. package/clis/dianping/__fixtures__/shop.html +0 -6
  686. package/clis/dianping/auth.js +0 -49
  687. package/clis/dianping/cityResolver.js +0 -185
  688. package/clis/dianping/dianping.test.js +0 -578
  689. package/clis/dianping/search.js +0 -157
  690. package/clis/dianping/shop.js +0 -173
  691. package/clis/dianping/utils.js +0 -157
  692. package/clis/dongchedi/__fixtures__/search.json +0 -60
  693. package/clis/dongchedi/__fixtures__/series-detail.json +0 -911
  694. package/clis/dongchedi/__fixtures__/series-score.json +0 -1396
  695. package/clis/dongchedi/dongchedi.test.js +0 -191
  696. package/clis/dongchedi/koubei.js +0 -85
  697. package/clis/dongchedi/models.js +0 -91
  698. package/clis/dongchedi/score.js +0 -83
  699. package/clis/dongchedi/search.js +0 -83
  700. package/clis/dongchedi/series.js +0 -87
  701. package/clis/dongchedi/specs.js +0 -115
  702. package/clis/dongchedi/utils.js +0 -180
  703. package/clis/douban/auth.js +0 -50
  704. package/clis/douban/book-hot.js +0 -15
  705. package/clis/douban/download.js +0 -68
  706. package/clis/douban/download.test.js +0 -170
  707. package/clis/douban/marks.js +0 -116
  708. package/clis/douban/movie-hot.js +0 -15
  709. package/clis/douban/movie-hot.test.js +0 -14
  710. package/clis/douban/photos.js +0 -35
  711. package/clis/douban/reviews.js +0 -107
  712. package/clis/douban/search.js +0 -18
  713. package/clis/douban/search.test.js +0 -11
  714. package/clis/douban/subject.js +0 -46
  715. package/clis/douban/subject.test.js +0 -11
  716. package/clis/douban/top250.js +0 -68
  717. package/clis/douban/utils.js +0 -657
  718. package/clis/douban/utils.test.js +0 -488
  719. package/clis/doubao/ask.js +0 -40
  720. package/clis/doubao/auth.js +0 -66
  721. package/clis/doubao/detail.js +0 -35
  722. package/clis/doubao/detail.test.js +0 -42
  723. package/clis/doubao/history.js +0 -30
  724. package/clis/doubao/history.test.js +0 -37
  725. package/clis/doubao/meeting-summary.js +0 -41
  726. package/clis/doubao/meeting-transcript.js +0 -38
  727. package/clis/doubao/new.js +0 -22
  728. package/clis/doubao/read.js +0 -21
  729. package/clis/doubao/send.js +0 -24
  730. package/clis/doubao/status.js +0 -26
  731. package/clis/doubao/utils.js +0 -1156
  732. package/clis/doubao/utils.test.js +0 -396
  733. package/clis/doubao-app/ask.js +0 -54
  734. package/clis/doubao-app/dump.js +0 -25
  735. package/clis/doubao-app/new.js +0 -21
  736. package/clis/doubao-app/read.js +0 -19
  737. package/clis/doubao-app/screenshot.js +0 -19
  738. package/clis/doubao-app/send.js +0 -28
  739. package/clis/doubao-app/status.js +0 -17
  740. package/clis/doubao-app/utils.js +0 -110
  741. package/clis/douyin/_shared/browser-fetch.js +0 -66
  742. package/clis/douyin/_shared/browser-fetch.test.js +0 -64
  743. package/clis/douyin/_shared/creation-id.js +0 -5
  744. package/clis/douyin/_shared/creation-id.test.js +0 -22
  745. package/clis/douyin/_shared/evaluate-result.js +0 -16
  746. package/clis/douyin/_shared/imagex-upload.js +0 -53
  747. package/clis/douyin/_shared/imagex-upload.test.js +0 -87
  748. package/clis/douyin/_shared/public-api.js +0 -29
  749. package/clis/douyin/_shared/sts2.js +0 -21
  750. package/clis/douyin/_shared/sts2.test.js +0 -27
  751. package/clis/douyin/_shared/text-extra.js +0 -15
  752. package/clis/douyin/_shared/text-extra.test.js +0 -37
  753. package/clis/douyin/_shared/timing.js +0 -22
  754. package/clis/douyin/_shared/timing.test.js +0 -28
  755. package/clis/douyin/_shared/tos-upload-short-read.test.js +0 -83
  756. package/clis/douyin/_shared/tos-upload.js +0 -331
  757. package/clis/douyin/_shared/tos-upload.test.js +0 -229
  758. package/clis/douyin/_shared/transcode.js +0 -45
  759. package/clis/douyin/_shared/transcode.test.js +0 -91
  760. package/clis/douyin/_shared/vod-upload.js +0 -212
  761. package/clis/douyin/_shared/vod-upload.test.js +0 -38
  762. package/clis/douyin/activities.js +0 -23
  763. package/clis/douyin/activities.test.js +0 -55
  764. package/clis/douyin/auth.js +0 -39
  765. package/clis/douyin/collections.js +0 -23
  766. package/clis/douyin/collections.test.js +0 -45
  767. package/clis/douyin/delete.js +0 -152
  768. package/clis/douyin/delete.test.js +0 -100
  769. package/clis/douyin/draft.js +0 -355
  770. package/clis/douyin/draft.test.js +0 -335
  771. package/clis/douyin/drafts.js +0 -24
  772. package/clis/douyin/drafts.test.js +0 -11
  773. package/clis/douyin/hashtag.js +0 -114
  774. package/clis/douyin/hashtag.test.js +0 -171
  775. package/clis/douyin/location.js +0 -25
  776. package/clis/douyin/location.test.js +0 -23
  777. package/clis/douyin/profile.js +0 -29
  778. package/clis/douyin/profile.test.js +0 -46
  779. package/clis/douyin/publish-upload-id.test.js +0 -206
  780. package/clis/douyin/publish.js +0 -341
  781. package/clis/douyin/publish.test.js +0 -38
  782. package/clis/douyin/search.js +0 -308
  783. package/clis/douyin/search.test.js +0 -307
  784. package/clis/douyin/stats.js +0 -28
  785. package/clis/douyin/stats.test.js +0 -22
  786. package/clis/douyin/update.js +0 -32
  787. package/clis/douyin/update.test.js +0 -11
  788. package/clis/douyin/user-videos.js +0 -82
  789. package/clis/douyin/user-videos.test.js +0 -151
  790. package/clis/douyin/videos.js +0 -52
  791. package/clis/douyin/videos.test.js +0 -54
  792. package/clis/eastmoney/_secid.js +0 -78
  793. package/clis/eastmoney/announcement.js +0 -53
  794. package/clis/eastmoney/convertible.js +0 -74
  795. package/clis/eastmoney/etf.js +0 -66
  796. package/clis/eastmoney/holders.js +0 -79
  797. package/clis/eastmoney/hot-rank.js +0 -51
  798. package/clis/eastmoney/hot-rank.test.js +0 -59
  799. package/clis/eastmoney/index-board.js +0 -97
  800. package/clis/eastmoney/kline.js +0 -88
  801. package/clis/eastmoney/kuaixun.js +0 -55
  802. package/clis/eastmoney/longhu.js +0 -68
  803. package/clis/eastmoney/money-flow.js +0 -79
  804. package/clis/eastmoney/northbound.js +0 -58
  805. package/clis/eastmoney/quote.js +0 -108
  806. package/clis/eastmoney/rank.js +0 -95
  807. package/clis/eastmoney/sectors.js +0 -77
  808. package/clis/flomo/auth.js +0 -55
  809. package/clis/flomo/memos.js +0 -228
  810. package/clis/flomo/memos.test.js +0 -144
  811. package/clis/gitee/auth.js +0 -41
  812. package/clis/gitee/index.js +0 -3
  813. package/clis/gitee/search.js +0 -137
  814. package/clis/gitee/search.test.js +0 -65
  815. package/clis/gitee/trending.js +0 -568
  816. package/clis/gitee/user.js +0 -200
  817. package/clis/gitee/user.test.js +0 -63
  818. package/clis/gov-law/commands.test.js +0 -39
  819. package/clis/gov-law/recent.js +0 -22
  820. package/clis/gov-law/search.js +0 -41
  821. package/clis/gov-law/shared.js +0 -51
  822. package/clis/gov-policy/__fixtures__/recent.html +0 -16
  823. package/clis/gov-policy/__fixtures__/search.html +0 -41
  824. package/clis/gov-policy/gov-policy.test.js +0 -224
  825. package/clis/gov-policy/recent.js +0 -90
  826. package/clis/gov-policy/search.js +0 -91
  827. package/clis/gov-policy/utils.js +0 -54
  828. package/clis/guazi/__fixtures__/detail.html +0 -7
  829. package/clis/guazi/__fixtures__/list.html +0 -5
  830. package/clis/guazi/browse.js +0 -95
  831. package/clis/guazi/car.js +0 -110
  832. package/clis/guazi/guazi.test.js +0 -126
  833. package/clis/guazi/utils.js +0 -133
  834. package/clis/huodongxing/events.js +0 -322
  835. package/clis/huodongxing/events.test.js +0 -296
  836. package/clis/hupu/__fixtures__/hot-home.html +0 -64
  837. package/clis/hupu/auth.js +0 -47
  838. package/clis/hupu/detail.js +0 -72
  839. package/clis/hupu/hot.js +0 -163
  840. package/clis/hupu/hot.test.js +0 -224
  841. package/clis/hupu/like.js +0 -76
  842. package/clis/hupu/mentions.js +0 -160
  843. package/clis/hupu/reply.js +0 -72
  844. package/clis/hupu/search.js +0 -60
  845. package/clis/hupu/unlike.js +0 -76
  846. package/clis/hupu/utils.js +0 -319
  847. package/clis/jd/add-cart.js +0 -72
  848. package/clis/jd/auth.js +0 -46
  849. package/clis/jd/cart.js +0 -80
  850. package/clis/jd/commands.test.js +0 -41
  851. package/clis/jd/detail.js +0 -63
  852. package/clis/jd/item.js +0 -730
  853. package/clis/jd/item.test.js +0 -354
  854. package/clis/jd/item.test.ts +0 -517
  855. package/clis/jd/reviews.js +0 -55
  856. package/clis/jd/search.js +0 -66
  857. package/clis/jianyu/auth.js +0 -62
  858. package/clis/jianyu/detail.js +0 -21
  859. package/clis/jianyu/search.js +0 -634
  860. package/clis/jianyu/search.test.js +0 -153
  861. package/clis/jianyu/shared/china-bid-search.js +0 -165
  862. package/clis/jianyu/shared/procurement-contract.js +0 -324
  863. package/clis/jianyu/shared/procurement-contract.test.js +0 -72
  864. package/clis/jianyu/shared/procurement-detail.js +0 -107
  865. package/clis/jianyu/shared/procurement-detail.test.js +0 -84
  866. package/clis/jike/auth.js +0 -48
  867. package/clis/jike/comment.js +0 -107
  868. package/clis/jike/create.js +0 -106
  869. package/clis/jike/feed.js +0 -68
  870. package/clis/jike/like.js +0 -61
  871. package/clis/jike/notifications.js +0 -169
  872. package/clis/jike/post.js +0 -72
  873. package/clis/jike/read.test.js +0 -86
  874. package/clis/jike/repost.js +0 -103
  875. package/clis/jike/search.js +0 -68
  876. package/clis/jike/topic.js +0 -65
  877. package/clis/jike/user.js +0 -65
  878. package/clis/jike/utils.js +0 -25
  879. package/clis/jimeng/auth.js +0 -46
  880. package/clis/jimeng/generate.js +0 -84
  881. package/clis/jimeng/history.js +0 -48
  882. package/clis/jimeng/new.js +0 -44
  883. package/clis/jimeng/workspaces.js +0 -42
  884. package/clis/juejin/hot.js +0 -37
  885. package/clis/juejin/juejin.test.js +0 -241
  886. package/clis/juejin/recommend.js +0 -61
  887. package/clis/juejin/utils.js +0 -199
  888. package/clis/ke/auth.js +0 -46
  889. package/clis/ke/chengjiao.js +0 -78
  890. package/clis/ke/ershoufang.js +0 -101
  891. package/clis/ke/utils.js +0 -104
  892. package/clis/ke/xiaoqu.js +0 -78
  893. package/clis/ke/zufang.js +0 -95
  894. package/clis/kimi/_utils.js +0 -110
  895. package/clis/kimi/audit-extras.js +0 -268
  896. package/clis/kimi/auth.js +0 -57
  897. package/clis/kimi/chat.js +0 -470
  898. package/clis/kimi/kimi.test.js +0 -187
  899. package/clis/kimi/storage.js +0 -169
  900. package/clis/kimi/ui.js +0 -314
  901. package/clis/kimi/usage.js +0 -144
  902. package/clis/linux-do/auth.js +0 -55
  903. package/clis/linux-do/categories.js +0 -50
  904. package/clis/linux-do/feed.js +0 -395
  905. package/clis/linux-do/feed.test.js +0 -153
  906. package/clis/linux-do/search.js +0 -29
  907. package/clis/linux-do/tags.js +0 -28
  908. package/clis/linux-do/topic-content.js +0 -155
  909. package/clis/linux-do/topic-content.test.js +0 -59
  910. package/clis/linux-do/topic.js +0 -53
  911. package/clis/linux-do/user-posts.js +0 -57
  912. package/clis/linux-do/user-topics.js +0 -37
  913. package/clis/maimai/auth.js +0 -47
  914. package/clis/maimai/search-talents.js +0 -192
  915. package/clis/maimai/search-talents.test.js +0 -29
  916. package/clis/mubu/doc.js +0 -41
  917. package/clis/mubu/docs.js +0 -44
  918. package/clis/mubu/notes.js +0 -245
  919. package/clis/mubu/recent.js +0 -28
  920. package/clis/mubu/search.js +0 -63
  921. package/clis/mubu/utils.js +0 -304
  922. package/clis/nowcoder/auth.js +0 -65
  923. package/clis/nowcoder/companies.js +0 -24
  924. package/clis/nowcoder/creators.js +0 -28
  925. package/clis/nowcoder/detail.js +0 -62
  926. package/clis/nowcoder/experience.js +0 -37
  927. package/clis/nowcoder/hot.js +0 -25
  928. package/clis/nowcoder/jobs.js +0 -22
  929. package/clis/nowcoder/notifications.js +0 -30
  930. package/clis/nowcoder/papers.js +0 -41
  931. package/clis/nowcoder/practice.js +0 -38
  932. package/clis/nowcoder/recommend.js +0 -31
  933. package/clis/nowcoder/referral.js +0 -40
  934. package/clis/nowcoder/salary.js +0 -41
  935. package/clis/nowcoder/search.js +0 -50
  936. package/clis/nowcoder/suggest.js +0 -34
  937. package/clis/nowcoder/topics.js +0 -28
  938. package/clis/nowcoder/trending.js +0 -26
  939. package/clis/ones/common.js +0 -144
  940. package/clis/ones/enrich-tasks.js +0 -37
  941. package/clis/ones/login.js +0 -81
  942. package/clis/ones/logout.js +0 -18
  943. package/clis/ones/me.js +0 -31
  944. package/clis/ones/my-tasks.js +0 -121
  945. package/clis/ones/resolve-labels.js +0 -64
  946. package/clis/ones/task-helpers.js +0 -212
  947. package/clis/ones/task-helpers.test.js +0 -12
  948. package/clis/ones/task.js +0 -67
  949. package/clis/ones/tasks.js +0 -80
  950. package/clis/ones/token-info.js +0 -43
  951. package/clis/ones/worklog.js +0 -268
  952. package/clis/ones/worklog.test.js +0 -20
  953. package/clis/powerchina/auth.js +0 -52
  954. package/clis/powerchina/search.js +0 -251
  955. package/clis/powerchina/search.test.js +0 -93
  956. package/clis/quark/auth.js +0 -47
  957. package/clis/quark/ls.js +0 -64
  958. package/clis/quark/mkdir.js +0 -37
  959. package/clis/quark/mv.js +0 -54
  960. package/clis/quark/rename.js +0 -27
  961. package/clis/quark/rm.js +0 -25
  962. package/clis/quark/save.js +0 -81
  963. package/clis/quark/share-tree.js +0 -46
  964. package/clis/quark/utils.js +0 -146
  965. package/clis/quark/utils.test.js +0 -58
  966. package/clis/qwen/ask.js +0 -104
  967. package/clis/qwen/ask.test.js +0 -36
  968. package/clis/qwen/auth.js +0 -56
  969. package/clis/qwen/detail.js +0 -62
  970. package/clis/qwen/history.js +0 -61
  971. package/clis/qwen/image.js +0 -179
  972. package/clis/qwen/new.js +0 -23
  973. package/clis/qwen/read.js +0 -41
  974. package/clis/qwen/send.js +0 -55
  975. package/clis/qwen/status.js +0 -37
  976. package/clis/qwen/utils.js +0 -461
  977. package/clis/qwen/utils.test.js +0 -128
  978. package/clis/rednote/auth.js +0 -52
  979. package/clis/rednote/comments.js +0 -85
  980. package/clis/rednote/download.js +0 -59
  981. package/clis/rednote/feed.js +0 -27
  982. package/clis/rednote/navigation.test.js +0 -26
  983. package/clis/rednote/note.js +0 -68
  984. package/clis/rednote/notifications.js +0 -139
  985. package/clis/rednote/rednote.test.js +0 -240
  986. package/clis/rednote/search.js +0 -107
  987. package/clis/rednote/user.js +0 -55
  988. package/clis/sinablog/article.js +0 -15
  989. package/clis/sinablog/hot.js +0 -15
  990. package/clis/sinablog/search.js +0 -52
  991. package/clis/sinablog/user.js +0 -16
  992. package/clis/sinablog/utils.js +0 -186
  993. package/clis/sinafinance/news.js +0 -62
  994. package/clis/sinafinance/rolling-news.js +0 -41
  995. package/clis/sinafinance/stock-rank.js +0 -66
  996. package/clis/sinafinance/stock.js +0 -121
  997. package/clis/sinafinance/stock.test.js +0 -59
  998. package/clis/smzdm/search.js +0 -149
  999. package/clis/smzdm/search.test.js +0 -114
  1000. package/clis/taobao/add-cart.js +0 -150
  1001. package/clis/taobao/auth.js +0 -58
  1002. package/clis/taobao/cart.js +0 -96
  1003. package/clis/taobao/commands.test.js +0 -41
  1004. package/clis/taobao/detail.js +0 -71
  1005. package/clis/taobao/reviews.js +0 -77
  1006. package/clis/taobao/search.js +0 -97
  1007. package/clis/tdx/hot-rank.js +0 -48
  1008. package/clis/tdx/hot-rank.test.js +0 -59
  1009. package/clis/ths/hot-rank.js +0 -50
  1010. package/clis/ths/hot-rank.test.js +0 -64
  1011. package/clis/tieba/commands.test.js +0 -79
  1012. package/clis/tieba/hot.js +0 -48
  1013. package/clis/tieba/posts.js +0 -86
  1014. package/clis/tieba/read.js +0 -141
  1015. package/clis/tieba/search.js +0 -109
  1016. package/clis/tieba/utils.js +0 -240
  1017. package/clis/tieba/utils.test.js +0 -290
  1018. package/clis/toutiao/articles.js +0 -55
  1019. package/clis/toutiao/auth.js +0 -70
  1020. package/clis/toutiao/hot.js +0 -63
  1021. package/clis/toutiao/toutiao.test.js +0 -378
  1022. package/clis/toutiao/utils.js +0 -161
  1023. package/clis/trae-cn/activity.js +0 -22
  1024. package/clis/trae-cn/approve.js +0 -52
  1025. package/clis/trae-cn/ask.js +0 -99
  1026. package/clis/trae-cn/dump.js +0 -5
  1027. package/clis/trae-cn/export.js +0 -40
  1028. package/clis/trae-cn/model.js +0 -22
  1029. package/clis/trae-cn/new.js +0 -63
  1030. package/clis/trae-cn/read.js +0 -23
  1031. package/clis/trae-cn/screenshot.js +0 -5
  1032. package/clis/trae-cn/select-model.js +0 -25
  1033. package/clis/trae-cn/send.js +0 -23
  1034. package/clis/trae-cn/setup.js +0 -75
  1035. package/clis/trae-cn/status.js +0 -27
  1036. package/clis/trae-cn/targets.js +0 -96
  1037. package/clis/trae-cn/trae-cn.test.js +0 -412
  1038. package/clis/trae-cn/utils.js +0 -750
  1039. package/clis/trae-cn/watch.js +0 -119
  1040. package/clis/uisdc/news.js +0 -105
  1041. package/clis/uisdc/news.test.js +0 -66
  1042. package/clis/v2ex/auth.js +0 -44
  1043. package/clis/v2ex/daily.js +0 -99
  1044. package/clis/v2ex/hot.js +0 -26
  1045. package/clis/v2ex/latest.js +0 -26
  1046. package/clis/v2ex/me.js +0 -100
  1047. package/clis/v2ex/member.js +0 -28
  1048. package/clis/v2ex/node.js +0 -39
  1049. package/clis/v2ex/nodes.js +0 -26
  1050. package/clis/v2ex/notifications.js +0 -72
  1051. package/clis/v2ex/replies.js +0 -27
  1052. package/clis/v2ex/topic.js +0 -31
  1053. package/clis/v2ex/user.js +0 -34
  1054. package/clis/wanfang/search.js +0 -66
  1055. package/clis/wanfang/search.test.js +0 -23
  1056. package/clis/wechat-channels/auth.js +0 -62
  1057. package/clis/wechat-channels/publish.js +0 -732
  1058. package/clis/wechat-channels/publish.test.js +0 -144
  1059. package/clis/weibo/auth.js +0 -53
  1060. package/clis/weibo/comments.js +0 -53
  1061. package/clis/weibo/delete.js +0 -172
  1062. package/clis/weibo/delete.test.js +0 -94
  1063. package/clis/weibo/envelope.test.js +0 -85
  1064. package/clis/weibo/favorites.js +0 -170
  1065. package/clis/weibo/favorites.test.js +0 -114
  1066. package/clis/weibo/feed.js +0 -69
  1067. package/clis/weibo/hot.js +0 -39
  1068. package/clis/weibo/me.js +0 -75
  1069. package/clis/weibo/post.js +0 -75
  1070. package/clis/weibo/publish.js +0 -306
  1071. package/clis/weibo/publish.test.js +0 -192
  1072. package/clis/weibo/search.js +0 -80
  1073. package/clis/weibo/user-posts.js +0 -234
  1074. package/clis/weibo/user-posts.test.js +0 -92
  1075. package/clis/weibo/user.js +0 -63
  1076. package/clis/weibo/utils.js +0 -59
  1077. package/clis/weibo/utils.test.js +0 -36
  1078. package/clis/weixin/create-draft.js +0 -226
  1079. package/clis/weixin/download.js +0 -371
  1080. package/clis/weixin/download.test.js +0 -106
  1081. package/clis/weixin/drafts.js +0 -66
  1082. package/clis/weixin/drafts.test.js +0 -69
  1083. package/clis/weixin/search.js +0 -157
  1084. package/clis/weixin/search.test.js +0 -227
  1085. package/clis/weread/ai-outline.js +0 -171
  1086. package/clis/weread/ai-outline.test.js +0 -83
  1087. package/clis/weread/auth.js +0 -59
  1088. package/clis/weread/book-search.js +0 -438
  1089. package/clis/weread/book-search.test.js +0 -242
  1090. package/clis/weread/book.js +0 -233
  1091. package/clis/weread/commands.test.js +0 -398
  1092. package/clis/weread/highlights.js +0 -24
  1093. package/clis/weread/notebooks.js +0 -22
  1094. package/clis/weread/notes.js +0 -30
  1095. package/clis/weread/private-api-regression.test.js +0 -369
  1096. package/clis/weread/ranking.js +0 -29
  1097. package/clis/weread/search-regression.test.js +0 -494
  1098. package/clis/weread/search.js +0 -186
  1099. package/clis/weread/shelf.js +0 -66
  1100. package/clis/weread/utils.js +0 -321
  1101. package/clis/weread/utils.test.js +0 -128
  1102. package/clis/weread-official/book.js +0 -135
  1103. package/clis/weread-official/commands.test.js +0 -385
  1104. package/clis/weread-official/discover.js +0 -107
  1105. package/clis/weread-official/list-apis.js +0 -95
  1106. package/clis/weread-official/notes.js +0 -171
  1107. package/clis/weread-official/readdata.js +0 -158
  1108. package/clis/weread-official/review.js +0 -93
  1109. package/clis/weread-official/search.js +0 -106
  1110. package/clis/weread-official/shelf.js +0 -97
  1111. package/clis/weread-official/utils.js +0 -293
  1112. package/clis/weread-official/utils.test.js +0 -242
  1113. package/clis/xianyu/auth.js +0 -68
  1114. package/clis/xianyu/chat.js +0 -74
  1115. package/clis/xianyu/chat.test.js +0 -84
  1116. package/clis/xianyu/im.js +0 -322
  1117. package/clis/xianyu/im.test.js +0 -253
  1118. package/clis/xianyu/inbox.js +0 -96
  1119. package/clis/xianyu/item.js +0 -153
  1120. package/clis/xianyu/item.test.js +0 -56
  1121. package/clis/xianyu/messages.js +0 -91
  1122. package/clis/xianyu/publish.js +0 -485
  1123. package/clis/xianyu/publish.test.js +0 -220
  1124. package/clis/xianyu/reply.js +0 -82
  1125. package/clis/xianyu/search.js +0 -262
  1126. package/clis/xianyu/search.test.js +0 -104
  1127. package/clis/xianyu/utils.js +0 -8
  1128. package/clis/xiaoe/auth.js +0 -55
  1129. package/clis/xiaoe/catalog.js +0 -227
  1130. package/clis/xiaoe/content.js +0 -175
  1131. package/clis/xiaoe/courses.js +0 -127
  1132. package/clis/xiaoe/detail.js +0 -36
  1133. package/clis/xiaoe/play-url.js +0 -121
  1134. package/clis/xiaoe/xiaoe.test.js +0 -486
  1135. package/clis/xiaohongshu/ask.js +0 -426
  1136. package/clis/xiaohongshu/ask.test.js +0 -271
  1137. package/clis/xiaohongshu/auth.js +0 -53
  1138. package/clis/xiaohongshu/collection-helpers.js +0 -283
  1139. package/clis/xiaohongshu/collection-helpers.test.js +0 -125
  1140. package/clis/xiaohongshu/comments.js +0 -228
  1141. package/clis/xiaohongshu/comments.test.js +0 -320
  1142. package/clis/xiaohongshu/creator-note-detail.js +0 -482
  1143. package/clis/xiaohongshu/creator-note-detail.test.js +0 -451
  1144. package/clis/xiaohongshu/creator-notes-summary.js +0 -98
  1145. package/clis/xiaohongshu/creator-notes-summary.test.js +0 -94
  1146. package/clis/xiaohongshu/creator-notes.js +0 -479
  1147. package/clis/xiaohongshu/creator-notes.test.js +0 -281
  1148. package/clis/xiaohongshu/creator-profile.js +0 -55
  1149. package/clis/xiaohongshu/creator-stats.js +0 -76
  1150. package/clis/xiaohongshu/creator-stats.test.js +0 -24
  1151. package/clis/xiaohongshu/delete-note.js +0 -260
  1152. package/clis/xiaohongshu/delete-note.test.js +0 -172
  1153. package/clis/xiaohongshu/download.js +0 -249
  1154. package/clis/xiaohongshu/download.test.js +0 -339
  1155. package/clis/xiaohongshu/draft-clear.js +0 -91
  1156. package/clis/xiaohongshu/draft-delete.js +0 -103
  1157. package/clis/xiaohongshu/draft-open.js +0 -43
  1158. package/clis/xiaohongshu/draft-utils.js +0 -142
  1159. package/clis/xiaohongshu/drafts.js +0 -28
  1160. package/clis/xiaohongshu/drafts.test.js +0 -172
  1161. package/clis/xiaohongshu/feed.js +0 -163
  1162. package/clis/xiaohongshu/feed.test.js +0 -126
  1163. package/clis/xiaohongshu/follow.js +0 -226
  1164. package/clis/xiaohongshu/follow.test.js +0 -211
  1165. package/clis/xiaohongshu/liked.js +0 -29
  1166. package/clis/xiaohongshu/liked.test.js +0 -82
  1167. package/clis/xiaohongshu/navigation.test.js +0 -38
  1168. package/clis/xiaohongshu/note-helpers.js +0 -69
  1169. package/clis/xiaohongshu/note.js +0 -104
  1170. package/clis/xiaohongshu/note.test.js +0 -249
  1171. package/clis/xiaohongshu/notifications.js +0 -46
  1172. package/clis/xiaohongshu/publish.js +0 -1423
  1173. package/clis/xiaohongshu/publish.test.js +0 -1141
  1174. package/clis/xiaohongshu/saved.js +0 -29
  1175. package/clis/xiaohongshu/saved.test.js +0 -143
  1176. package/clis/xiaohongshu/search.js +0 -330
  1177. package/clis/xiaohongshu/search.test.js +0 -325
  1178. package/clis/xiaohongshu/unfollow.js +0 -285
  1179. package/clis/xiaohongshu/user-helpers.js +0 -78
  1180. package/clis/xiaohongshu/user-helpers.test.js +0 -160
  1181. package/clis/xiaohongshu/user.js +0 -140
  1182. package/clis/xiaohongshu/user.test.js +0 -141
  1183. package/clis/xiaoyuzhou/auth.js +0 -303
  1184. package/clis/xiaoyuzhou/auth.test.js +0 -124
  1185. package/clis/xiaoyuzhou/download.js +0 -54
  1186. package/clis/xiaoyuzhou/download.test.js +0 -135
  1187. package/clis/xiaoyuzhou/episode.js +0 -34
  1188. package/clis/xiaoyuzhou/podcast-episodes.js +0 -41
  1189. package/clis/xiaoyuzhou/podcast-episodes.test.js +0 -78
  1190. package/clis/xiaoyuzhou/podcast.js +0 -33
  1191. package/clis/xiaoyuzhou/transcript.js +0 -77
  1192. package/clis/xiaoyuzhou/transcript.test.js +0 -195
  1193. package/clis/xiaoyuzhou/utils.js +0 -15
  1194. package/clis/xiaoyuzhou/utils.test.js +0 -39
  1195. package/clis/xueqiu/auth.js +0 -63
  1196. package/clis/xueqiu/comments.js +0 -355
  1197. package/clis/xueqiu/comments.test.js +0 -696
  1198. package/clis/xueqiu/danjuan-utils.js +0 -126
  1199. package/clis/xueqiu/danjuan-utils.test.js +0 -41
  1200. package/clis/xueqiu/earnings-date.js +0 -45
  1201. package/clis/xueqiu/feed.js +0 -39
  1202. package/clis/xueqiu/fund-holdings.js +0 -29
  1203. package/clis/xueqiu/fund-snapshot.js +0 -26
  1204. package/clis/xueqiu/groups.js +0 -23
  1205. package/clis/xueqiu/hot-stock.js +0 -32
  1206. package/clis/xueqiu/hot.js +0 -37
  1207. package/clis/xueqiu/kline.js +0 -44
  1208. package/clis/xueqiu/search.js +0 -37
  1209. package/clis/xueqiu/stock.js +0 -65
  1210. package/clis/xueqiu/utils.js +0 -48
  1211. package/clis/xueqiu/utils.test.js +0 -26
  1212. package/clis/xueqiu/watchlist.js +0 -37
  1213. package/clis/youdao/note.js +0 -258
  1214. package/clis/youdao/note.test.js +0 -99
  1215. package/clis/yuanbao/ask.js +0 -362
  1216. package/clis/yuanbao/ask.test.js +0 -124
  1217. package/clis/yuanbao/auth.js +0 -59
  1218. package/clis/yuanbao/detail.js +0 -65
  1219. package/clis/yuanbao/history.js +0 -51
  1220. package/clis/yuanbao/new.js +0 -72
  1221. package/clis/yuanbao/new.test.js +0 -30
  1222. package/clis/yuanbao/read.js +0 -38
  1223. package/clis/yuanbao/send.js +0 -57
  1224. package/clis/yuanbao/shared.js +0 -341
  1225. package/clis/yuanbao/shared.test.js +0 -80
  1226. package/clis/yuanbao/status.js +0 -44
  1227. package/clis/zhihu/answer-comments.js +0 -280
  1228. package/clis/zhihu/answer-comments.test.js +0 -287
  1229. package/clis/zhihu/answer-detail.js +0 -216
  1230. package/clis/zhihu/answer-detail.test.js +0 -338
  1231. package/clis/zhihu/answer.js +0 -54
  1232. package/clis/zhihu/answer.test.js +0 -54
  1233. package/clis/zhihu/auth.js +0 -59
  1234. package/clis/zhihu/collection.js +0 -199
  1235. package/clis/zhihu/collection.test.js +0 -337
  1236. package/clis/zhihu/collections.js +0 -128
  1237. package/clis/zhihu/collections.test.js +0 -182
  1238. package/clis/zhihu/comment.js +0 -55
  1239. package/clis/zhihu/comment.test.js +0 -50
  1240. package/clis/zhihu/download.js +0 -80
  1241. package/clis/zhihu/download.test.js +0 -12
  1242. package/clis/zhihu/favorite.js +0 -87
  1243. package/clis/zhihu/favorite.test.js +0 -59
  1244. package/clis/zhihu/follow.js +0 -50
  1245. package/clis/zhihu/follow.test.js +0 -42
  1246. package/clis/zhihu/followers.js +0 -40
  1247. package/clis/zhihu/followers.test.js +0 -42
  1248. package/clis/zhihu/following.js +0 -40
  1249. package/clis/zhihu/following.test.js +0 -44
  1250. package/clis/zhihu/hot.js +0 -44
  1251. package/clis/zhihu/like.js +0 -47
  1252. package/clis/zhihu/like.test.js +0 -41
  1253. package/clis/zhihu/paginate.js +0 -128
  1254. package/clis/zhihu/pins.js +0 -41
  1255. package/clis/zhihu/pins.test.js +0 -44
  1256. package/clis/zhihu/question.js +0 -113
  1257. package/clis/zhihu/question.test.js +0 -251
  1258. package/clis/zhihu/recommend.js +0 -103
  1259. package/clis/zhihu/recommend.test.js +0 -143
  1260. package/clis/zhihu/search.js +0 -206
  1261. package/clis/zhihu/search.test.js +0 -198
  1262. package/clis/zhihu/target.js +0 -91
  1263. package/clis/zhihu/target.test.js +0 -77
  1264. package/clis/zhihu/text.js +0 -29
  1265. package/clis/zhihu/text.test.js +0 -24
  1266. package/clis/zhihu/user-answers.js +0 -41
  1267. package/clis/zhihu/user-answers.test.js +0 -69
  1268. package/clis/zhihu/user-arg.js +0 -34
  1269. package/clis/zhihu/user-articles.js +0 -40
  1270. package/clis/zhihu/user-articles.test.js +0 -44
  1271. package/clis/zhihu/user.js +0 -59
  1272. package/clis/zhihu/user.test.js +0 -73
  1273. package/clis/zhihu/write-shared.js +0 -228
  1274. package/clis/zhihu/write-shared.test.js +0 -176
  1275. package/clis/zsxq/auth.js +0 -68
  1276. package/clis/zsxq/dynamics.js +0 -48
  1277. package/clis/zsxq/groups.js +0 -33
  1278. package/clis/zsxq/search.js +0 -44
  1279. package/clis/zsxq/search.test.js +0 -24
  1280. package/clis/zsxq/topic.js +0 -50
  1281. package/clis/zsxq/topic.test.js +0 -30
  1282. package/clis/zsxq/topics.js +0 -26
  1283. package/clis/zsxq/topics.test.js +0 -24
  1284. package/clis/zsxq/utils.js +0 -233
  1285. package/clis/zsxq/utils.test.js +0 -31
  1286. package/skills/webcmd-adapter-author/references/site-memory/bilibili.md +0 -70
  1287. package/skills/webcmd-adapter-author/references/site-memory/eastmoney.md +0 -70
  1288. package/skills/webcmd-adapter-author/references/site-memory/tonghuashun.md +0 -51
  1289. package/skills/webcmd-adapter-author/references/site-memory/xueqiu.md +0 -58
  1290. /package/{clis/douyin/_shared/types.js → dist/src/adapter-shadow.test.d.ts} +0 -0
@@ -1,1423 +0,0 @@
1
- /**
2
- * Xiaohongshu 图文笔记 publisher — creator center UI automation.
3
- *
4
- * Flow:
5
- * 1. Navigate to creator publish page
6
- * 2. Upload images via CDP DOM.setFileInputFiles (with base64 fallback)
7
- * 3. Fill title and body text
8
- * 4. Add topic hashtags
9
- * 5. Publish (or save as draft)
10
- *
11
- * Requires: logged into creator.xiaohongshu.com in Chrome.
12
- *
13
- * Usage:
14
- * webcmd xiaohongshu publish --title "标题" "正文内容" \
15
- * --images /path/a.jpg,/path/b.jpg \
16
- * --topics 生活,旅行
17
- */
18
- import * as fs from 'node:fs';
19
- import * as path from 'node:path';
20
- import { CommandExecutionError, ArgumentError } from '@agentrhq/webcmd/errors';
21
- import { cli, Strategy } from '@agentrhq/webcmd/registry';
22
- const PUBLISH_URL = 'https://creator.xiaohongshu.com/publish/publish?from=menu_left&target=image';
23
- const MAX_IMAGES = 9;
24
- const MAX_TITLE_LEN = 20;
25
- const UPLOAD_SETTLE_MS = 3000;
26
- const CARD_TEXT_DELIM = '|||';
27
- const DEFAULT_CARD_STYLE = '基础';
28
- // Example styles for help text only — the real options are read live from the
29
- // (virtualized, content-dependent) 预览图片 strip at runtime, so this list is NOT
30
- // used to validate input; an unavailable requested style fails before submit.
31
- // 文字配图 --card-style catalog: each style name → the content it suits.
32
- // Styles are read live from the page at runtime (see selectCardStyle); this list
33
- // only powers --help, and an unmatched requested style is a typed failure.
34
- const CARD_STYLE_GUIDE = [
35
- ['基础', '默认兜底,万能'],
36
- ['边框', '金句/要点卡'],
37
- ['备忘', '提醒/随手记'],
38
- ['清新', '日常/清单贴士'],
39
- ['涂写', '随笔/碎碎念'],
40
- ['便签', '笔记/提醒'],
41
- ['光影', '情绪/文艺'],
42
- ['涂鸦', '趣味/童话'],
43
- ['简约', '干货/观点'],
44
- ['手写', '日记/情感'],
45
- ['插图', '生活方式/轻松话题'],
46
- ['美漫', '活力/趣味/故事感'],
47
- ['弥散', '弥散光氛围'],
48
- ['柔和', '柔和/温柔金句'],
49
- ['印刷', '印刷海报/排版'],
50
- ['科技', '科技/产品'],
51
- ['贺卡', '节日祝福'],
52
- ['札记', '艺术/水彩氛围'],
53
- ['书摘', '书摘/引用'],
54
- ['手帐', '手帐拼贴'],
55
- ['几何', '醒目/有力主张'],
56
- ];
57
- const CARD_STYLES = CARD_STYLE_GUIDE.map(([name]) => name);
58
- const TEXT_IMAGE_ENTRY_LABEL = '文字配图';
59
- const ADD_CARD_LABEL = '再写一张';
60
- const GENERATE_LABEL = '生成图片';
61
- const PREVIEW_NEXT_LABEL = '下一步';
62
- /** tiptap/ProseMirror card editor inside the 写文字 swiper. */
63
- const CARD_EDITOR_SELECTOR = '.tiptap.ProseMirror';
64
- /**
65
- * XHS creator center wraps the publish/save button in an `<xhs-publish-btn>`
66
- * web component backed by a CLOSED shadow root. Host-level `.click()` does
67
- * not dispatch into the internal handler. Invoke these instance methods on
68
- * the host element to trigger publish / save-draft directly (#1606).
69
- */
70
- const PUBLISH_METHOD_NAMES = ['_onPublish', 'onPublish', '_onSubmit', '_handlePublish'];
71
- const DRAFT_METHOD_NAMES = ['_onSave', '_onSaveDraft', '_onDraft'];
72
- /** Selectors for the title field, ordered by priority across current UI variants. */
73
- const TITLE_SELECTORS = [
74
- // Some creator-center variants expose the title as contenteditable,
75
- // others use a normal <input> with the same placeholder. Visible
76
- // user-facing variants always carry a Chinese placeholder; class-based
77
- // variants also match a pair of 4 px wide hidden scaffolding inputs
78
- // (same `class*="title"`, empty placeholder, no v-model commit on save)
79
- // so placeholder-based selectors take precedence to avoid filling those.
80
- '[contenteditable="true"][placeholder*="标题"]',
81
- '[contenteditable="true"][placeholder*="赞"]',
82
- 'input[placeholder*="标题"]',
83
- 'input[placeholder*="title" i]',
84
- '[contenteditable="true"][class*="title"]',
85
- 'input[maxlength="20"]',
86
- 'input[class*="title"]',
87
- '.title-input input',
88
- '.note-title input',
89
- 'input[maxlength]',
90
- ];
91
- /** Selectors for the note body / content editor, ordered by priority. */
92
- const BODY_SELECTORS = [
93
- '[contenteditable="true"][class*="content"]',
94
- '[contenteditable="true"][class*="editor"]',
95
- '[contenteditable="true"][placeholder*="描述"]',
96
- '[contenteditable="true"][placeholder*="正文"]',
97
- '[contenteditable="true"][placeholder*="内容"]',
98
- '.note-content [contenteditable="true"]',
99
- '.editor-content [contenteditable="true"]',
100
- // Broad fallback — last resort; filter out any title contenteditable
101
- '[contenteditable="true"]:not([placeholder*="标题"]):not([placeholder*="赞"]):not([placeholder*="title" i])',
102
- ];
103
- const SUPPORTED_EXTENSIONS = {
104
- '.jpg': 'image/jpeg',
105
- '.jpeg': 'image/jpeg',
106
- '.png': 'image/png',
107
- '.gif': 'image/gif',
108
- '.webp': 'image/webp',
109
- };
110
- function unwrapBrowserResult(value) {
111
- if (
112
- value
113
- && typeof value === 'object'
114
- && typeof value.session === 'string'
115
- && Object.prototype.hasOwnProperty.call(value, 'data')
116
- ) {
117
- return value.data;
118
- }
119
- return value;
120
- }
121
- /**
122
- * Validate image paths: check existence and extension.
123
- * Returns resolved absolute paths.
124
- */
125
- function validateImagePaths(filePaths) {
126
- return filePaths.map((filePath) => {
127
- const absPath = path.resolve(filePath);
128
- if (!fs.existsSync(absPath))
129
- throw new ArgumentError(`Image file not found: ${absPath}`);
130
- const ext = path.extname(absPath).toLowerCase();
131
- if (!SUPPORTED_EXTENSIONS[ext]) {
132
- throw new ArgumentError(`Unsupported image format "${ext}". Supported: jpg, png, gif, webp`);
133
- }
134
- return absPath;
135
- });
136
- }
137
- /** CSS selector for image-accepting file inputs. */
138
- const IMAGE_INPUT_SELECTOR = 'input[type="file"][accept*="image"],'
139
- + 'input[type="file"][accept*=".jpg"],'
140
- + 'input[type="file"][accept*=".jpeg"],'
141
- + 'input[type="file"][accept*=".png"],'
142
- + 'input[type="file"][accept*=".gif"],'
143
- + 'input[type="file"][accept*=".webp"]';
144
- /**
145
- * Upload images via CDP DOM.setFileInputFiles — Chrome reads files directly
146
- * from the local filesystem, avoiding base64 payload size limits.
147
- *
148
- * Falls back to the legacy base64 DataTransfer approach if the extension
149
- * does not support set-file-input (e.g. older extension version).
150
- */
151
- async function uploadImages(page, absPaths) {
152
- // ── Primary: CDP DOM.setFileInputFiles ──────────────────────────────
153
- if (page.setFileInput) {
154
- try {
155
- // Find image-accepting file input on the page
156
- const selector = await page.evaluate(`
157
- (() => {
158
- const sels = ${JSON.stringify(IMAGE_INPUT_SELECTOR)};
159
- const el = document.querySelector(sels);
160
- return el ? sels : null;
161
- })()
162
- `);
163
- if (!selector) {
164
- return { ok: false, count: 0, error: 'No file input found on page' };
165
- }
166
- await page.setFileInput(absPaths, selector);
167
- return { ok: true, count: absPaths.length };
168
- }
169
- catch (err) {
170
- // If set-file-input action is not supported by extension, fall through to legacy
171
- const msg = err instanceof Error ? err.message : String(err);
172
- if (msg.includes('Unknown action') || msg.includes('not supported') || msg.includes('Not allowed')) {
173
- // Extension too old — fall through to legacy base64 method
174
- }
175
- else {
176
- return { ok: false, count: 0, error: msg };
177
- }
178
- }
179
- }
180
- // ── Fallback: legacy base64 DataTransfer injection ─────────────────
181
- const images = absPaths.map((absPath) => {
182
- const base64 = fs.readFileSync(absPath).toString('base64');
183
- const ext = path.extname(absPath).toLowerCase();
184
- return { name: path.basename(absPath), mimeType: SUPPORTED_EXTENSIONS[ext], base64 };
185
- });
186
- // Warn if total payload is large — this may fail with older extensions
187
- const totalBytes = images.reduce((sum, img) => sum + img.base64.length, 0);
188
- if (totalBytes > 500_000) {
189
- console.warn(`[warn] Total image payload is ${(totalBytes / 1024 / 1024).toFixed(1)}MB (base64). ` +
190
- 'This may fail with the browser bridge. Update the extension to v1.6+ for CDP-based upload, ' +
191
- 'or compress images before publishing.');
192
- }
193
- const payload = JSON.stringify(images);
194
- return page.evaluate(`
195
- (async () => {
196
- const images = ${payload};
197
-
198
- const inputs = Array.from(document.querySelectorAll('input[type="file"]'));
199
- const input = inputs.find(el => {
200
- const accept = el.getAttribute('accept') || '';
201
- return (
202
- accept.includes('image') ||
203
- accept.includes('.jpg') ||
204
- accept.includes('.jpeg') ||
205
- accept.includes('.png') ||
206
- accept.includes('.gif') ||
207
- accept.includes('.webp')
208
- );
209
- });
210
-
211
- if (!input) return { ok: false, count: 0, error: 'No image file input found on page' };
212
-
213
- const dt = new DataTransfer();
214
- for (const img of images) {
215
- try {
216
- const binary = atob(img.base64);
217
- const bytes = new Uint8Array(binary.length);
218
- for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
219
- const blob = new Blob([bytes], { type: img.mimeType });
220
- dt.items.add(new File([blob], img.name, { type: img.mimeType }));
221
- } catch (e) {
222
- return { ok: false, count: 0, error: 'Failed to create File: ' + e.message };
223
- }
224
- }
225
-
226
- Object.defineProperty(input, 'files', { value: dt.files, writable: false });
227
- input.dispatchEvent(new Event('change', { bubbles: true }));
228
- input.dispatchEvent(new Event('input', { bubbles: true }));
229
-
230
- return { ok: true, count: dt.files.length };
231
- })()
232
- `);
233
- }
234
- /**
235
- * Wait until all upload progress indicators have disappeared (up to maxWaitMs).
236
- */
237
- async function waitForUploads(page, maxWaitMs = 30_000) {
238
- const pollMs = 2_000;
239
- const maxAttempts = Math.ceil(maxWaitMs / pollMs);
240
- for (let i = 0; i < maxAttempts; i++) {
241
- const uploading = await page.evaluate(`
242
- () => !!document.querySelector(
243
- '[class*="upload"][class*="progress"], [class*="uploading"], [class*="loading"][class*="image"]'
244
- )
245
- `);
246
- if (!uploading)
247
- return;
248
- await page.wait({ time: pollMs / 1_000 });
249
- }
250
- }
251
- /**
252
- * Fill a visible text input or contenteditable with the given text.
253
- * Tries multiple selectors in priority order.
254
- * Returns { ok, sel }.
255
- */
256
- async function fillField(page, selectors, text, fieldName) {
257
- const located = await page.evaluate(`
258
- (function(selectors) {
259
- const __webcmd_xhs_fill_phase = "locate";
260
- for (const sel of selectors) {
261
- const candidates = document.querySelectorAll(sel);
262
- for (const el of candidates) {
263
- if (!el || el.offsetParent === null) continue;
264
- const kind = el.isContentEditable
265
- ? 'contenteditable'
266
- : (el.tagName === 'TEXTAREA' ? 'textarea' : 'input');
267
- return { ok: true, sel, kind };
268
- }
269
- }
270
- return { ok: false };
271
- })(${JSON.stringify(selectors)})
272
- `);
273
- if (!located.ok) {
274
- await page.screenshot({ path: `/tmp/xhs_publish_${fieldName}_debug.png` });
275
- throw new Error(`Could not find ${fieldName} input. Debug screenshot: /tmp/xhs_publish_${fieldName}_debug.png`);
276
- }
277
- const applyInPage = () => page.evaluate(`
278
- ((selector, expectedText) => {
279
- const __webcmd_xhs_fill_phase = "apply";
280
- const normalize = (value) => (value || '').replace(/\\s+/g, ' ').trim();
281
- const fireBeforeInput = (el, value) => {
282
- try {
283
- el.dispatchEvent(new InputEvent('beforeinput', {
284
- bubbles: true,
285
- data: value,
286
- inputType: 'insertText',
287
- }));
288
- } catch {
289
- el.dispatchEvent(new Event('beforeinput', { bubbles: true }));
290
- }
291
- };
292
- const fireInput = (el, value) => {
293
- try {
294
- el.dispatchEvent(new InputEvent('input', {
295
- bubbles: true,
296
- data: value,
297
- inputType: 'insertText',
298
- }));
299
- } catch {
300
- el.dispatchEvent(new Event('input', { bubbles: true }));
301
- }
302
- };
303
- const el = Array.from(document.querySelectorAll(selector)).find(node => node && node.offsetParent !== null);
304
- if (!el) return { ok: false, actual: '' };
305
- el.focus();
306
- fireBeforeInput(el, expectedText);
307
- if (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA') {
308
- const proto = el.tagName === 'TEXTAREA'
309
- ? HTMLTextAreaElement.prototype
310
- : HTMLInputElement.prototype;
311
- const nativeSetter = Object.getOwnPropertyDescriptor(proto, 'value')?.set;
312
- if (nativeSetter) nativeSetter.call(el, expectedText);
313
- else el.value = expectedText;
314
- fireInput(el, expectedText);
315
- el.dispatchEvent(new Event('change', { bubbles: true }));
316
- el.blur();
317
- return { ok: el.value === expectedText, actual: el.value || '' };
318
- }
319
- el.textContent = '';
320
- const selection = window.getSelection();
321
- const range = document.createRange();
322
- range.selectNodeContents(el);
323
- range.collapse(false);
324
- selection?.removeAllRanges();
325
- selection?.addRange(range);
326
- const inserted = document.execCommand('insertText', false, expectedText);
327
- if (!inserted) el.textContent = expectedText;
328
- fireInput(el, expectedText);
329
- el.dispatchEvent(new Event('change', { bubbles: true }));
330
- el.blur();
331
- const actual = normalize(el.innerText || el.textContent || '');
332
- return { ok: actual === normalize(expectedText), actual };
333
- })(${JSON.stringify(located.sel)}, ${JSON.stringify(text)})
334
- `);
335
- let result;
336
- if (located.kind === 'contenteditable' && page.insertText) {
337
- const prepared = await page.evaluate(`
338
- ((selector, nextText) => {
339
- const __webcmd_xhs_fill_phase = "prepare";
340
- const fireBeforeInput = (el, value) => {
341
- try {
342
- el.dispatchEvent(new InputEvent('beforeinput', {
343
- bubbles: true,
344
- data: value,
345
- inputType: 'insertText',
346
- }));
347
- } catch {
348
- el.dispatchEvent(new Event('beforeinput', { bubbles: true }));
349
- }
350
- };
351
- const el = Array.from(document.querySelectorAll(selector)).find(node => node && node.offsetParent !== null);
352
- if (!el) return { ok: false };
353
- el.focus();
354
- el.textContent = '';
355
- const selection = window.getSelection();
356
- const range = document.createRange();
357
- range.selectNodeContents(el);
358
- range.collapse(false);
359
- selection?.removeAllRanges();
360
- selection?.addRange(range);
361
- fireBeforeInput(el, nextText);
362
- return { ok: true };
363
- })(${JSON.stringify(located.sel)}, ${JSON.stringify(text)})
364
- `);
365
- if (!prepared?.ok) {
366
- await page.screenshot({ path: `/tmp/xhs_publish_${fieldName}_debug.png` });
367
- throw new Error(`Could not prepare ${fieldName} input. Debug screenshot: /tmp/xhs_publish_${fieldName}_debug.png`);
368
- }
369
- try {
370
- await page.insertText(text);
371
- result = await page.evaluate(`
372
- ((selector, expectedText) => {
373
- const __webcmd_xhs_fill_phase = "verify";
374
- const normalize = (value) => (value || '').replace(/\\s+/g, ' ').trim();
375
- const fireInput = (el, value) => {
376
- try {
377
- el.dispatchEvent(new InputEvent('input', {
378
- bubbles: true,
379
- data: value,
380
- inputType: 'insertText',
381
- }));
382
- } catch {
383
- el.dispatchEvent(new Event('input', { bubbles: true }));
384
- }
385
- };
386
- const el = Array.from(document.querySelectorAll(selector)).find(node => node && node.offsetParent !== null);
387
- if (!el) return { ok: false, actual: '' };
388
- fireInput(el, expectedText);
389
- el.dispatchEvent(new Event('change', { bubbles: true }));
390
- el.blur();
391
- const actual = normalize(el.innerText || el.textContent || '');
392
- return { ok: actual === normalize(expectedText), actual };
393
- })(${JSON.stringify(located.sel)}, ${JSON.stringify(text)})
394
- `);
395
- }
396
- catch {
397
- result = await applyInPage();
398
- }
399
- }
400
- else {
401
- result = await applyInPage();
402
- }
403
- if (!result?.ok) {
404
- await page.screenshot({ path: `/tmp/xhs_publish_${fieldName}_debug.png` });
405
- const actual = typeof result?.actual === 'string' ? result.actual : '';
406
- throw new Error(`Failed to set ${fieldName}. Expected "${text}", got "${actual}". Debug screenshot: /tmp/xhs_publish_${fieldName}_debug.png`);
407
- }
408
- }
409
- /**
410
- * Add topic hashtags by driving the editor's native inline "#" flow.
411
- *
412
- * Modern XHS creator-center editors turn a "#keyword" typed into the note body
413
- * into a linked topic entity only after the author picks an item from the
414
- * suggestion dropdown that appears while typing. There is no standalone
415
- * "添加话题" search input anymore, so we type directly into the body editor.
416
- *
417
- * For each topic we:
418
- * 1. focus the body contenteditable and move the caret to the end,
419
- * 2. type " #<topic>" using native CDP insertion (falls back to execCommand)
420
- * so XHS fires its inline suggestion dropdown,
421
- * 3. wait for the dropdown, then click the suggestion whose text best matches
422
- * the topic (falling back to the first suggestion, then to Enter),
423
- * 4. confirm a topic chip/link was produced before moving on.
424
- *
425
- * A requested topic is a write-side postcondition: if XHS does not create a
426
- * real topic entity, fail before publishing instead of silently emitting a note
427
- * with bare "#text".
428
- */
429
- async function focusBodyEnd(page, bodySelectors) {
430
- return unwrapBrowserResult(await page.evaluate(`
431
- (selectors => {
432
- const el = selectors
433
- .map(sel => Array.from(document.querySelectorAll(sel)))
434
- .flat()
435
- .find(node => node && node.offsetParent !== null && node.isContentEditable);
436
- if (!el) return false;
437
- el.focus();
438
- const selection = window.getSelection();
439
- const range = document.createRange();
440
- range.selectNodeContents(el);
441
- range.collapse(false);
442
- selection?.removeAllRanges();
443
- selection?.addRange(range);
444
- return true;
445
- })(${JSON.stringify(bodySelectors)})
446
- `));
447
- }
448
- function topicSuggestionScript(topic, { click = false } = {}) {
449
- // Returns the best matching suggestion's screen coordinates (center) so the
450
- // caller can issue a real click.
451
- return `
452
- (topicName => {
453
- const norm = (value) => (value || '').replace(/^#/, '').replace(/\\s+/g, '').trim();
454
- const want = norm(topicName);
455
- const SUGGESTION_SELECTORS = [
456
- '[class*="topic-item"]',
457
- '[class*="hashtag-item"]',
458
- '[class*="suggest-item"]',
459
- '[class*="suggestion"] li',
460
- '[class*="mention"] li',
461
- '[class*="dropdown"] li',
462
- '[id*="topic"] li',
463
- '[class*="topic"] li',
464
- ];
465
- const seen = new Set();
466
- const items = [];
467
- for (const sel of SUGGESTION_SELECTORS) {
468
- for (const node of document.querySelectorAll(sel)) {
469
- if (!node || seen.has(node)) continue;
470
- if (node.offsetParent === null) continue;
471
- const rect = node.getBoundingClientRect();
472
- if (rect.width <= 0 || rect.height <= 0) continue;
473
- seen.add(node);
474
- items.push(node);
475
- }
476
- }
477
- if (!items.length) return { ok: false, count: 0 };
478
- let target = items.find(node => norm(node.innerText || node.textContent) === want);
479
- if (!target) target = items.find(node => norm(node.innerText || node.textContent).includes(want));
480
- if (!target) target = items[0];
481
- const rect = target.getBoundingClientRect();
482
- ${click ? "try { target.click(); } catch (e) { return { ok: false, count: items.length, message: String(e) }; }" : ''}
483
- return {
484
- ok: true,
485
- count: items.length,
486
- x: Math.round(rect.left + rect.width / 2),
487
- y: Math.round(rect.top + rect.height / 2),
488
- text: (target.innerText || target.textContent || '').trim().slice(0, 40),
489
- };
490
- })(${JSON.stringify(topic)})
491
- `;
492
- }
493
- function topicEntityCountScript(topic, bodySelectors) {
494
- return `
495
- ((topicName, selectors) => {
496
- const norm = (value) => (value || '').replace(/^#/, '').replace(/\\s+/g, '').trim();
497
- const want = norm(topicName);
498
- const editor = selectors
499
- .map(sel => Array.from(document.querySelectorAll(sel)))
500
- .flat()
501
- .find(node => node && node.offsetParent !== null && node.isContentEditable);
502
- if (!editor || !want) return 0;
503
- const hasTopicSignal = (node) => {
504
- const tag = (node.tagName || '').toLowerCase();
505
- const role = (node.getAttribute && node.getAttribute('role')) || '';
506
- const cls = String(node.className || '');
507
- const id = String(node.id || '');
508
- const href = (node.getAttribute && node.getAttribute('href')) || '';
509
- const dataKeys = node.dataset ? Object.keys(node.dataset).join(' ') : '';
510
- const haystack = [tag, role, cls, id, href, dataKeys].join(' ');
511
- return tag === 'a'
512
- || /link/i.test(role)
513
- || /topic|hashtag|hash-tag|tag|mention|keyword/i.test(haystack)
514
- || node.isContentEditable === false;
515
- };
516
- let count = 0;
517
- for (const node of Array.from(editor.querySelectorAll('*'))) {
518
- if (!node || node.offsetParent === null) continue;
519
- if (!hasTopicSignal(node)) continue;
520
- const text = norm(node.innerText || node.textContent || '');
521
- if (text === want || text === '#' + want) count += 1;
522
- }
523
- return count;
524
- })(${JSON.stringify(topic)}, ${JSON.stringify(bodySelectors)})
525
- `;
526
- }
527
- function topicMarkerCountScript(topic, bodySelectors) {
528
- return `
529
- ((topicName, selectors) => {
530
- const __webcmd_xhs_topic_marker_count = true;
531
- const marker = '#' + topicName + '[话题]';
532
- const editor = selectors
533
- .map(sel => Array.from(document.querySelectorAll(sel)))
534
- .flat()
535
- .find(node => node && node.offsetParent !== null && node.isContentEditable);
536
- if (!editor || !marker) return 0;
537
- const text = editor.innerText || editor.textContent || '';
538
- let count = 0;
539
- let index = text.indexOf(marker);
540
- while (index !== -1) {
541
- count += 1;
542
- index = text.indexOf(marker, index + marker.length);
543
- }
544
- return count;
545
- })(${JSON.stringify(topic)}, ${JSON.stringify(bodySelectors)})
546
- `;
547
- }
548
- async function typeTopicQuery(page, topic) {
549
- // Type "#<topic>" so XHS recognizes it as a topic query and pops the inline
550
- // suggestion dropdown. The caller separates topics with Enter beforehand so
551
- // each query starts on its own line and matches cleanly.
552
- const query = `#${topic}`;
553
- if (typeof page.insertText === 'function') {
554
- try {
555
- await page.insertText(query);
556
- return true;
557
- }
558
- catch {
559
- // fall through to execCommand path
560
- }
561
- }
562
- return unwrapBrowserResult(await page.evaluate(`
563
- (text => {
564
- const ok = document.execCommand('insertText', false, text);
565
- const active = document.activeElement;
566
- if (active) active.dispatchEvent(new Event('input', { bubbles: true }));
567
- return ok;
568
- })(${JSON.stringify(query)})
569
- `));
570
- }
571
- async function addTopics(page, bodySelectors, topics) {
572
- const added = [];
573
- for (const topic of topics) {
574
- const focused = await focusBodyEnd(page, bodySelectors);
575
- if (!focused) {
576
- throw new CommandExecutionError(`Could not attach topic "${topic}": body editor not found`);
577
- }
578
- const beforeMarkerCount = Number(unwrapBrowserResult(await page.evaluate(topicMarkerCountScript(topic, bodySelectors)))) || 0;
579
- // Separate this topic from the preceding text so the dropdown is clean.
580
- if (typeof page.pressKey === 'function') {
581
- try {
582
- await page.pressKey('Enter');
583
- }
584
- catch { /* non-fatal */ }
585
- }
586
- // Type the inline "#<topic>" query so XHS pops the inline suggestion
587
- // dropdown. We must use `page.insertText` (CDP) rather than the legacy
588
- // `execCommand` path, otherwise XHS's editor doesn't fire its keyup
589
- // listener and no dropdown appears.
590
- if (typeof page.insertText !== 'function') {
591
- throw new CommandExecutionError(`Could not attach topic "${topic}": page.insertText is unavailable`);
592
- }
593
- try {
594
- await page.insertText(`#${topic}`);
595
- }
596
- catch {
597
- throw new CommandExecutionError(`Could not attach topic "${topic}": failed to type inline topic query`);
598
- }
599
- await page.wait({ time: 1.2 }); // Let the suggestion dropdown render.
600
- // The suggestion dropdown lives inside the editor's closed shadow root,
601
- // so light-DOM queries cannot enumerate its items. XHS auto-highlights
602
- // the first matching suggestion as soon as the query is typed, so
603
- // pressing Enter accepts it directly. `page.nativeClick` would also
604
- // work but is not always wired up in the browser-bridge wrapper.
605
- if (typeof page.pressKey !== 'function') {
606
- throw new CommandExecutionError(`Could not attach topic "${topic}": page.pressKey is unavailable`);
607
- }
608
- try {
609
- await page.pressKey('Enter');
610
- }
611
- catch (err) {
612
- throw new CommandExecutionError(`Could not attach topic "${topic}": failed to accept suggestion (${err && err.message || err})`);
613
- }
614
- await page.wait({ time: 0.8 });
615
- // Verify the topic chip actually rendered. The chip itself lives in a
616
- // closed shadow root so we cannot count `<a>` elements, but XHS exposes
617
- // a stable "#<topic>[话题]" marker in the body editor's innerText once
618
- // the suggestion is accepted. Require the scoped marker count to
619
- // increase so an existing marker elsewhere cannot satisfy the write
620
- // postcondition.
621
- const afterMarkerCount = Number(unwrapBrowserResult(await page.evaluate(topicMarkerCountScript(topic, bodySelectors)))) || 0;
622
- if (afterMarkerCount <= beforeMarkerCount) {
623
- throw new CommandExecutionError(`Could not attach topic "${topic}": no real topic entity appeared after selection`);
624
- }
625
- added.push(topic);
626
- await page.wait({ time: 0.4 });
627
- }
628
- return added;
629
- }
630
- async function selectImageTextTab(page) {
631
- const result = await page.evaluate(`
632
- () => {
633
- const isVisible = (el) => {
634
- if (!el || el.offsetParent === null) return false;
635
- const rect = el.getBoundingClientRect();
636
- return rect.width > 0 && rect.height > 0;
637
- };
638
-
639
- const normalize = (value) => (value || '').replace(/\\s+/g, ' ').trim();
640
- const selector = 'button, [role="tab"], [role="button"], a, label, div, span, li';
641
- const nodes = Array.from(document.querySelectorAll(selector));
642
- const targets = ['上传图文', '图文', '图片'];
643
-
644
- for (const target of targets) {
645
- for (const node of nodes) {
646
- if (!isVisible(node)) continue;
647
- const text = normalize(node.innerText || node.textContent || '');
648
- if (!text || text.includes('视频')) continue;
649
- if (text === target) {
650
- const clickable = node.closest('button, [role="tab"], [role="button"], a, label') || node;
651
- clickable.click();
652
- return { ok: true, target, text };
653
- }
654
- }
655
- }
656
-
657
- for (const target of targets) {
658
- for (const node of nodes) {
659
- if (!isVisible(node)) continue;
660
- const text = normalize(node.innerText || node.textContent || '');
661
- if (!text || text.includes('视频')) continue;
662
- if (text.startsWith(target) || text.includes(target)) {
663
- const clickable = node.closest('button, [role="tab"], [role="button"], a, label') || node;
664
- clickable.click();
665
- return { ok: true, target, text };
666
- }
667
- }
668
- }
669
-
670
- const visibleTexts = [];
671
- for (const node of nodes) {
672
- if (!isVisible(node)) continue;
673
- const text = normalize(node.innerText || node.textContent || '');
674
- if (!text || text.length > 20) continue;
675
- visibleTexts.push(text);
676
- if (visibleTexts.length >= 20) break;
677
- }
678
- return { ok: false, visibleTexts };
679
- }
680
- `);
681
- if (result?.ok) {
682
- await page.wait({ time: 1 });
683
- }
684
- return result;
685
- }
686
- /**
687
- * Click the first visible element whose trimmed text equals `label`.
688
- * Marker constant `__webcmd_xhs_click_label` lets the test mock branch on it.
689
- */
690
- async function clickByText(page, label, maxWaitMs = 7_000) {
691
- const pollMs = 500;
692
- const maxAttempts = Math.max(1, Math.ceil(maxWaitMs / pollMs));
693
- let result = { ok: false };
694
- // Retry until the control appears: 生成图片 → 下一步 advances through async
695
- // render/generation steps, so the target may not exist on the first probe.
696
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
697
- result = unwrapBrowserResult(await page.evaluate(`
698
- ((cfg) => {
699
- const __webcmd_xhs_click_label = { wantLabel: ${JSON.stringify(label)} };
700
- const wantLabel = ${JSON.stringify(label)};
701
- const isVisible = (el) => {
702
- if (!el || el.offsetParent === null) return false;
703
- const r = el.getBoundingClientRect();
704
- return r.width > 0 && r.height > 0;
705
- };
706
- const norm = (v) => (v || '').replace(/\\s+/g, ' ').trim();
707
- const clickable = (el) => el.closest('button, [role="button"], a, label') || el;
708
- const enabled = (el) =>
709
- !(el.getAttribute && el.getAttribute('aria-disabled') === 'true')
710
- && !el.disabled
711
- && !(el.className && String(el.className).split(/\\s+/).includes('disabled'));
712
- // Exact-text matches, innermost first. The real click handler usually lives on
713
- // an inner control (.edit-text-button 生成图片, .add-text-item-button-text 再写一张);
714
- // an outer wrapper that merely *contains* the label is a no-op, so prefer the
715
- // deepest matching node and let the event bubble up to the handler.
716
- const nodes = Array.from(document.querySelectorAll('button, [role="button"], div, span, a, label, li'));
717
- const exact = nodes.filter((n) => isVisible(n) && norm(n.innerText || n.textContent) === wantLabel);
718
- const innermost = exact.filter((n) => !exact.some((o) => o !== n && n.contains(o)));
719
- const contains = nodes.filter((n) => {
720
- if (!isVisible(n)) return false;
721
- const t = norm(n.innerText || n.textContent);
722
- return t && t.length <= wantLabel.length + 4 && t.includes(wantLabel);
723
- });
724
- for (const node of [...(innermost.length ? innermost : exact), ...contains]) {
725
- const c = clickable(node);
726
- if (!enabled(c)) continue;
727
- c.click();
728
- return { ok: true, text: norm(node.innerText || node.textContent) || wantLabel };
729
- }
730
- return { ok: false };
731
- })()
732
- `));
733
- if (result?.ok)
734
- return result;
735
- await page.wait({ time: pollMs / 1_000 });
736
- }
737
- return result;
738
- }
739
- /**
740
- * Focus the currently-active 写文字 card editor (tiptap/ProseMirror) and move the
741
- * caret to the end so insertText appends into it.
742
- */
743
- async function focusActiveCard(page) {
744
- const result = await page.evaluate(`
745
- (() => {
746
- const __webcmd_xhs_focus_card = true;
747
- const sel = ${JSON.stringify(CARD_EDITOR_SELECTOR)};
748
- const editors = Array.from(document.querySelectorAll(sel)).filter((el) => el.offsetParent !== null);
749
- // Prefer the editor inside the active swiper slide if present.
750
- const active = editors.find((el) => el.closest('.swiper-slide-active')) || editors[editors.length - 1];
751
- if (!active) return { ok: false };
752
- active.focus();
753
- const selection = window.getSelection();
754
- const range = document.createRange();
755
- range.selectNodeContents(active);
756
- range.collapse(false);
757
- selection?.removeAllRanges();
758
- selection?.addRange(range);
759
- return { ok: true };
760
- })()
761
- `);
762
- return unwrapBrowserResult(result);
763
- }
764
- /** Confirm the active card editor holds non-empty text (guards against empty cards). */
765
- async function activeCardText(page) {
766
- const result = await page.evaluate(`
767
- (() => {
768
- const __webcmd_xhs_card_text = true;
769
- const sel = ${JSON.stringify(CARD_EDITOR_SELECTOR)};
770
- const editors = Array.from(document.querySelectorAll(sel)).filter((el) => el.offsetParent !== null);
771
- const active = editors.find((el) => el.closest('.swiper-slide-active')) || editors[editors.length - 1];
772
- const text = active ? (active.innerText || active.textContent || '').trim() : '';
773
- return { ok: !!text, text };
774
- })()
775
- `);
776
- return unwrapBrowserResult(result);
777
- }
778
- /**
779
- * Count visible card editors and report whether the active one is still empty.
780
- * Used to wait out the swiper render lag after clicking 再写一张.
781
- */
782
- async function cardEditorState(page) {
783
- const result = await page.evaluate(`
784
- (() => {
785
- const __webcmd_xhs_card_count = true;
786
- const sel = ${JSON.stringify(CARD_EDITOR_SELECTOR)};
787
- const editors = Array.from(document.querySelectorAll(sel)).filter((el) => el.offsetParent !== null);
788
- const active = editors.find((el) => el.closest('.swiper-slide-active')) || editors[editors.length - 1];
789
- const activeText = active ? (active.innerText || active.textContent || '').trim() : '';
790
- return { ok: true, count: editors.length, activeEmpty: !activeText };
791
- })()
792
- `);
793
- return unwrapBrowserResult(result);
794
- }
795
- /** Poll until at least one card editor has rendered (after entering 文字配图). */
796
- async function waitForFirstCard(page, maxWaitMs = 8_000) {
797
- const pollMs = 300;
798
- const maxAttempts = Math.ceil(maxWaitMs / pollMs);
799
- for (let i = 0; i < maxAttempts; i++) {
800
- const state = await cardEditorState(page);
801
- if (state?.count >= 1)
802
- return true;
803
- await page.wait({ time: pollMs / 1_000 });
804
- }
805
- return false;
806
- }
807
- /**
808
- * After clicking 再写一张, the new card editor renders asynchronously and only
809
- * then becomes the active swiper slide. Wait for the fresh empty card to be
810
- * active before typing — otherwise the text lands in the previous card and the
811
- * cards get merged.
812
- */
813
- async function waitForNewCard(page, expectedCount, maxWaitMs = 6_000) {
814
- const pollMs = 300;
815
- const maxAttempts = Math.ceil(maxWaitMs / pollMs);
816
- for (let i = 0; i < maxAttempts; i++) {
817
- const state = await cardEditorState(page);
818
- if (state?.count >= expectedCount && state?.activeEmpty)
819
- return true;
820
- await page.wait({ time: pollMs / 1_000 });
821
- }
822
- return false;
823
- }
824
- /**
825
- * Click 再写一张 and wait for the new card to render. Retries the click because
826
- * 再写一张 only adds a card once the current card's text has registered in the
827
- * editor model — a click fired too early no-ops. Re-clicking is safe: once the
828
- * fresh empty card is active, 再写一张 no-ops, so this never over-adds.
829
- */
830
- async function addCard(page, expectedCount, maxAttempts = 4) {
831
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
832
- const clicked = await clickByText(page, ADD_CARD_LABEL);
833
- if (!clicked?.ok)
834
- return false;
835
- if (await waitForNewCard(page, expectedCount, 2_500))
836
- return true;
837
- }
838
- return false;
839
- }
840
- /** True once the 预览图片 step has rendered (its 下一步 button is present). */
841
- async function previewStepReady(page) {
842
- const result = await page.evaluate(`
843
- (() => {
844
- const __webcmd_xhs_preview_ready = true;
845
- const ready = Array.from(document.querySelectorAll('button'))
846
- .some((b) => b.offsetParent !== null && (b.innerText || '').replace(/\\s+/g, '') === '下一步');
847
- return { ok: ready };
848
- })()
849
- `);
850
- return unwrapBrowserResult(result);
851
- }
852
- /**
853
- * Click 生成图片 and wait for the 预览图片 step. Retries the click because 生成图片
854
- * no-ops until the card text has registered in the editor model (same timing quirk as
855
- * 再写一张). Re-clicking is safe: once the preview step is showing, 生成图片 is gone.
856
- */
857
- async function clickGenerate(page, maxAttempts = 6) {
858
- const pollMs = 400;
859
- const polls = Math.ceil(3_000 / pollMs);
860
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
861
- const clicked = await clickByText(page, GENERATE_LABEL);
862
- if (!clicked?.ok && attempt === 0)
863
- return false; // 生成图片 not on the page at all
864
- for (let i = 0; i < polls; i++) {
865
- if ((await previewStepReady(page))?.ok)
866
- return true;
867
- await page.wait({ time: pollMs / 1_000 });
868
- }
869
- }
870
- return false;
871
- }
872
- /**
873
- * Type one card's text into the active card editor, then verify it stuck.
874
- *
875
- * tiptap/ProseMirror swallows a "\n" embedded in a single insertText call, so a
876
- * multi-line card would collapse onto one line. Split the text on "\n" and press
877
- * Enter between segments to produce real line breaks (same Enter mechanism
878
- * addTopics relies on). An empty segment (consecutive "\n") yields a blank line.
879
- *
880
- * Single-quoted shell args (the most natural way to pass `--card-text`) deliver a
881
- * literal backslash + "n", not a real LF, so we normalize those to real newlines
882
- * first — both `$'a\nb'` and `'a\nb'` then break lines identically.
883
- */
884
- async function fillCard(page, text, index) {
885
- text = String(text).replace(/\\n/g, '\n');
886
- const focused = await focusActiveCard(page);
887
- if (!focused?.ok)
888
- throw new CommandExecutionError(`文字配图: could not focus card editor #${index + 1}`);
889
- if (typeof page.insertText === 'function') {
890
- const lines = text.split('\n');
891
- for (let i = 0; i < lines.length; i++) {
892
- if (i > 0 && typeof page.pressKey === 'function')
893
- await page.pressKey('Enter');
894
- if (lines[i])
895
- await page.insertText(lines[i]);
896
- }
897
- }
898
- else {
899
- await page.evaluate(`(t => document.execCommand('insertText', false, t))(${JSON.stringify(text)})`);
900
- }
901
- await page.wait({ time: 0.4 });
902
- const state = await activeCardText(page);
903
- if (!state?.ok)
904
- throw new CommandExecutionError(`文字配图: card editor #${index + 1} is empty after typing`);
905
- }
906
- /**
907
- * On the 预览图片 step, optionally pick a style. The style picker is a
908
- * scrollable strip whose options are loaded lazily, so we scroll it to the end
909
- * to surface every option, then read the real on-page labels (no hard-coded
910
- * whitelist — XHS adds/removes styles over time). The strip is located by
911
- * anchoring on a known seed label (e.g. 基础) rather than a volatile class name.
912
- *
913
- * If the caller requested a style, it is a write-side postcondition: either
914
- * that style is available and clicked, or publishing fails before submit.
915
- */
916
- async function selectCardStyle(page, styleName) {
917
- if (!styleName || styleName === DEFAULT_CARD_STYLE)
918
- return DEFAULT_CARD_STYLE; // default 基础 is preselected — nothing to do.
919
- // The style strip (".cover-list-container") is VIRTUALIZED: only the items
920
- // near the viewport are in the DOM, so a single read sees ~10 of ~20 options
921
- // and an option scrolled out of view cannot be clicked. Step-scroll the strip
922
- // (".cover-list-container-wrapper"), accumulating every label seen; stop as
923
- // soon as the requested style appears and scroll it into view so the
924
- // subsequent click lands. XHS also shows a content-dependent subset, so the
925
- // real options vary per note — hence no static whitelist.
926
- const available = unwrapBrowserResult(await page.evaluate(`
927
- (async () => {
928
- const __webcmd_xhs_card_styles = true;
929
- const want = ${JSON.stringify(styleName)};
930
- const norm = (el) => ((el && (el.innerText || el.textContent)) || '').trim();
931
- const names = () => Array.from(document.querySelectorAll('.cover-list-container .cover-name'));
932
- const seen = [];
933
- const readAll = () => { for (const el of names()) { const t = norm(el); if (t && !seen.includes(t)) seen.push(t); } };
934
- const target = () => names().find((el) => norm(el) === want);
935
- const reveal = (el) => { el.scrollIntoView({ block: 'center' }); };
936
- readAll();
937
- let hit = target();
938
- if (hit) { reveal(hit); return { ok: true, styles: seen, found: true }; }
939
- const scroller = document.querySelector('.cover-list-container-wrapper')
940
- || document.querySelector('.cover-list-container');
941
- if (scroller) {
942
- const ch = scroller.clientHeight || 200;
943
- const sh = scroller.scrollHeight;
944
- for (let y = 0; y <= sh + ch; y += Math.max(60, Math.floor(ch / 2))) {
945
- scroller.scrollTop = y;
946
- await new Promise((r) => setTimeout(r, 180));
947
- readAll();
948
- hit = target();
949
- if (hit) { reveal(hit); await new Promise((r) => setTimeout(r, 150)); return { ok: true, styles: seen, found: true }; }
950
- }
951
- scroller.scrollTop = 0;
952
- }
953
- return { ok: seen.length > 0, styles: seen, found: false };
954
- })()
955
- `));
956
- if (!available?.found) {
957
- throw new CommandExecutionError(`文字配图: requested style "${styleName}" is not available for this content `
958
- + `(options: ${(available?.styles || []).join(' / ') || 'none'}). `
959
- + `Choose an available style or omit --card-style to use ${DEFAULT_CARD_STYLE}.`);
960
- }
961
- const clicked = await clickByText(page, styleName);
962
- if (!clicked?.ok) {
963
- throw new CommandExecutionError(`文字配图: could not click requested style "${styleName}".`);
964
- }
965
- await page.wait({ time: 0.6 });
966
- return styleName;
967
- }
968
- /**
969
- * Count visible media in the current editor/composer. Text-image generation must
970
- * produce real image cards before we fill title/body or submit; otherwise a
971
- * no-op 生成图片 / 下一步 sequence can publish the wrong draft surface.
972
- */
973
- async function currentComposerMediaCount(page) {
974
- const result = await page.evaluate(`
975
- (() => {
976
- const __webcmd_xhs_composer_media_count = true;
977
- const visibleBox = (el) => {
978
- if (!el || el.offsetParent === null) return false;
979
- const r = el.getBoundingClientRect();
980
- return r.width > 0 && r.height > 0;
981
- };
982
- const visibleMedia = (el) => {
983
- if (!visibleBox(el)) return false;
984
- const r = el.getBoundingClientRect();
985
- return r.width >= 48 && r.height >= 48;
986
- };
987
- const titleSelectors = ${JSON.stringify(TITLE_SELECTORS)};
988
- const titleEl = titleSelectors
989
- .map((sel) => Array.from(document.querySelectorAll(sel)))
990
- .flat()
991
- .find((el) => visibleBox(el));
992
- const root = titleEl?.closest('form, [class*="publish"], [class*="editor"], [class*="note"]') || document.body;
993
- const seen = new Set();
994
- let count = 0;
995
- for (const el of Array.from(root.querySelectorAll('img, video, canvas, [style*="background-image"]'))) {
996
- if (!visibleMedia(el)) continue;
997
- const rect = el.getBoundingClientRect();
998
- const src = el.currentSrc || el.src || el.getAttribute('src') || el.style?.backgroundImage || '';
999
- const key = src || String(Math.round(rect.left)) + ':' + String(Math.round(rect.top));
1000
- if (seen.has(key)) continue;
1001
- seen.add(key);
1002
- count += 1;
1003
- }
1004
- return { ok: true, count };
1005
- })()
1006
- `);
1007
- return unwrapBrowserResult(result);
1008
- }
1009
- async function assertComposerMediaCount(page, expectedCount, label) {
1010
- const state = await currentComposerMediaCount(page);
1011
- if (!state || typeof state.count !== 'number') {
1012
- throw new CommandExecutionError(`${label}: could not verify current composer media count`);
1013
- }
1014
- if (state.count < expectedCount) {
1015
- await page.screenshot({ path: '/tmp/xhs_publish_media_debug.png' });
1016
- throw new CommandExecutionError(`${label}: expected at least ${expectedCount} visible media item(s), got ${state.count}. ` +
1017
- 'Debug screenshot: /tmp/xhs_publish_media_debug.png');
1018
- }
1019
- }
1020
- /**
1021
- * Drive the full 文字配图 sub-flow: entry → type cards → 生成图片 → pick style → 下一步.
1022
- * Leaves the page on the standard editor (caller then runs waitForEditForm).
1023
- */
1024
- async function runTextImageFlow(page, cards, cardStyle) {
1025
- const entry = await clickByText(page, TEXT_IMAGE_ENTRY_LABEL);
1026
- if (!entry?.ok) {
1027
- await page.screenshot({ path: '/tmp/xhs_publish_textimage_debug.png' });
1028
- throw new CommandExecutionError(`文字配图: could not click "${TEXT_IMAGE_ENTRY_LABEL}" entry. ` +
1029
- 'Debug: /tmp/xhs_publish_textimage_debug.png');
1030
- }
1031
- if (!(await waitForFirstCard(page))) {
1032
- await page.screenshot({ path: '/tmp/xhs_publish_textimage_debug.png' });
1033
- throw new CommandExecutionError(`文字配图: 写文字 card editor did not appear after clicking "${TEXT_IMAGE_ENTRY_LABEL}". ` +
1034
- 'Debug: /tmp/xhs_publish_textimage_debug.png');
1035
- }
1036
- for (let i = 0; i < cards.length; i++) {
1037
- if (i > 0) {
1038
- const added = await addCard(page, i + 1);
1039
- if (!added) {
1040
- await page.screenshot({ path: '/tmp/xhs_publish_addcard_debug.png' });
1041
- throw new CommandExecutionError(`文字配图: new card editor #${i + 1} did not render after "${ADD_CARD_LABEL}". ` +
1042
- 'Debug: /tmp/xhs_publish_addcard_debug.png');
1043
- }
1044
- }
1045
- await fillCard(page, cards[i], i);
1046
- }
1047
- const generated = await clickGenerate(page);
1048
- if (!generated) {
1049
- await page.screenshot({ path: '/tmp/xhs_publish_generate_debug.png' });
1050
- throw new CommandExecutionError(`文字配图: "${GENERATE_LABEL}" did not advance to the 预览图片 step. ` +
1051
- 'Debug: /tmp/xhs_publish_generate_debug.png');
1052
- }
1053
- const appliedStyle = await selectCardStyle(page, cardStyle);
1054
- const next = await clickByText(page, PREVIEW_NEXT_LABEL);
1055
- if (!next?.ok) {
1056
- await page.screenshot({ path: '/tmp/xhs_publish_next_debug.png' });
1057
- throw new CommandExecutionError(`文字配图: could not click "${PREVIEW_NEXT_LABEL}". ` +
1058
- 'Debug: /tmp/xhs_publish_next_debug.png');
1059
- }
1060
- await page.wait({ time: 2 }); // editor render
1061
- return appliedStyle;
1062
- }
1063
- async function inspectPublishSurfaceState(page) {
1064
- return page.evaluate(`
1065
- () => {
1066
- const text = (document.body?.innerText || '').replace(/\s+/g, ' ').trim();
1067
- const hasTitleInput = !!Array.from(document.querySelectorAll('input, textarea')).find((el) => {
1068
- if (!el || el.offsetParent === null) return false;
1069
- const placeholder = (el.getAttribute('placeholder') || '').trim();
1070
- const cls = el.className ? String(el.className) : '';
1071
- const maxLength = Number(el.getAttribute('maxlength') || 0);
1072
- return (
1073
- placeholder.includes('标题') ||
1074
- /title/i.test(placeholder) ||
1075
- /title/i.test(cls) ||
1076
- maxLength === 20
1077
- );
1078
- });
1079
- const hasImageInput = !!Array.from(document.querySelectorAll('input[type="file"]')).find((el) => {
1080
- const accept = el.getAttribute('accept') || '';
1081
- return (
1082
- accept.includes('image') ||
1083
- accept.includes('.jpg') ||
1084
- accept.includes('.jpeg') ||
1085
- accept.includes('.png') ||
1086
- accept.includes('.gif') ||
1087
- accept.includes('.webp')
1088
- );
1089
- });
1090
- const hasVideoSurface = text.includes('拖拽视频到此处点击上传') || text.includes('上传视频');
1091
- const state = hasTitleInput ? 'editor_ready' : hasImageInput || !hasVideoSurface ? 'image_surface' : 'video_surface';
1092
- return { state, hasTitleInput, hasImageInput, hasVideoSurface };
1093
- }
1094
- `);
1095
- }
1096
- async function waitForPublishSurfaceState(page, maxWaitMs = 5_000) {
1097
- const pollMs = 500;
1098
- const maxAttempts = Math.max(1, Math.ceil(maxWaitMs / pollMs));
1099
- let surface = await inspectPublishSurfaceState(page);
1100
- for (let i = 0; i < maxAttempts; i++) {
1101
- if (surface.state !== 'video_surface') {
1102
- return surface;
1103
- }
1104
- if (i < maxAttempts - 1) {
1105
- await page.wait({ time: pollMs / 1_000 });
1106
- surface = await inspectPublishSurfaceState(page);
1107
- }
1108
- }
1109
- return surface;
1110
- }
1111
- /**
1112
- * Poll until the title/content editing form appears on the page.
1113
- * The new creator center UI only renders the editor after images are uploaded.
1114
- */
1115
- async function waitForEditForm(page, maxWaitMs = 10_000) {
1116
- const pollMs = 1_000;
1117
- const maxAttempts = Math.ceil(maxWaitMs / pollMs);
1118
- for (let i = 0; i < maxAttempts; i++) {
1119
- const found = await page.evaluate(`
1120
- (() => {
1121
- const sels = ${JSON.stringify(TITLE_SELECTORS)};
1122
- for (const sel of sels) {
1123
- const el = document.querySelector(sel);
1124
- if (el && el.offsetParent !== null) return true;
1125
- }
1126
- return false;
1127
- })()`);
1128
- if (found)
1129
- return true;
1130
- if (i < maxAttempts - 1)
1131
- await page.wait({ time: pollMs / 1_000 });
1132
- }
1133
- return false;
1134
- }
1135
- cli({
1136
- site: 'xiaohongshu',
1137
- name: 'publish',
1138
- access: 'write',
1139
- description: '小红书发布图文笔记 (creator center UI automation)',
1140
- domain: 'creator.xiaohongshu.com',
1141
- strategy: Strategy.COOKIE,
1142
- browser: true,
1143
- navigateBefore: false,
1144
- args: [
1145
- { name: 'content', required: true, positional: true, help: '笔记正文' },
1146
- { name: 'title', required: true, help: '笔记标题 (最多20字)' },
1147
- { name: 'images', required: false, help: '图片路径,逗号分隔,最多9张 (jpg/png/gif/webp)' },
1148
- { name: 'card-text', required: false, help: `文字配图卡片文字,多张卡片用 ${CARD_TEXT_DELIM} 分隔,卡内换行用 \\n` },
1149
- { name: 'card-style', required: false, help: `文字配图卡片样式,运行时按页面实际选项匹配;找不到会失败。省略时使用${DEFAULT_CARD_STYLE}。可选: ${CARD_STYLE_GUIDE.map(([n, s]) => `${n}(${s})`).join(' ')}` },
1150
- { name: 'topics', required: false, help: '话题标签,逗号分隔,不含 # 号' },
1151
- { name: 'draft', type: 'bool', default: false, help: '保存为草稿,不直接发布' },
1152
- ],
1153
- columns: ['status', 'detail'],
1154
- func: async (page, kwargs) => {
1155
- if (!page)
1156
- throw new Error('Browser page required');
1157
- const title = String(kwargs.title ?? '').trim();
1158
- const content = String(kwargs.content ?? '').trim();
1159
- const imagePaths = kwargs.images
1160
- ? String(kwargs.images).split(',').map((s) => s.trim()).filter(Boolean)
1161
- : [];
1162
- const topics = kwargs.topics
1163
- ? String(kwargs.topics).split(',').map((s) => s.trim()).filter(Boolean)
1164
- : [];
1165
- const isDraft = Boolean(kwargs.draft);
1166
- const cardText = kwargs['card-text'] ? String(kwargs['card-text']) : '';
1167
- const cards = cardText
1168
- ? cardText.split(CARD_TEXT_DELIM).map((s) => s.trim()).filter(Boolean)
1169
- : [];
1170
- const cardStyle = kwargs['card-style'] ? String(kwargs['card-style']).trim() : '';
1171
- const isTextImage = cards.length > 0;
1172
- // ── Validate inputs ────────────────────────────────────────────────────────
1173
- if (!title)
1174
- throw new ArgumentError('--title is required');
1175
- if (title.length > MAX_TITLE_LEN)
1176
- throw new ArgumentError(`Title is ${title.length} chars — must be ≤ ${MAX_TITLE_LEN}`);
1177
- if (!content)
1178
- throw new ArgumentError('Positional argument <content> is required');
1179
- if (!isTextImage && imagePaths.length === 0)
1180
- throw new ArgumentError('Provide --card-text (text-image mode) or --images (upload mode); neither was given.');
1181
- if (imagePaths.length > MAX_IMAGES)
1182
- throw new ArgumentError(`Too many images: ${imagePaths.length} (max ${MAX_IMAGES})`);
1183
- // The editor-page image input (text-image append) rejects gif.
1184
- if (isTextImage && imagePaths.some((p) => path.extname(p).toLowerCase() === '.gif'))
1185
- throw new ArgumentError('文字配图模式追加的图片不支持 .gif(编辑器图片入口只接受 jpg/jpeg/png/webp)');
1186
- // Validate image paths before navigating (fast-fail on bad paths / unsupported formats)
1187
- const absImagePaths = validateImagePaths(imagePaths);
1188
- // ── Step 1: Navigate to publish page ──────────────────────────────────────
1189
- await page.goto(PUBLISH_URL);
1190
- await page.wait({ time: 3 });
1191
- // Verify we landed on the creator site (not redirected to login)
1192
- const pageUrl = await page.evaluate('() => location.href');
1193
- if (!pageUrl.includes('creator.xiaohongshu.com')) {
1194
- throw new Error('Redirected away from creator center — session may have expired. ' +
1195
- 'Re-capture browser login via: webcmd xiaohongshu creator-profile');
1196
- }
1197
- // ── Step 2: Select 图文 (image+text) note type if tabs are present ─────────
1198
- const tabResult = await selectImageTextTab(page);
1199
- const surface = await waitForPublishSurfaceState(page, tabResult?.ok ? 5_000 : 2_000);
1200
- if (surface.state === 'video_surface') {
1201
- await page.screenshot({ path: '/tmp/xhs_publish_tab_debug.png' });
1202
- const detail = tabResult?.ok
1203
- ? `clicked "${tabResult.text}"`
1204
- : `visible candidates: ${(tabResult?.visibleTexts || []).join(' | ') || 'none'}`;
1205
- throw new Error('Still on the video publish page after trying to select 图文. ' +
1206
- `Details: ${detail}. Debug screenshot: /tmp/xhs_publish_tab_debug.png`);
1207
- }
1208
- // ── Step 3: Acquire images — text-image generation and/or upload ──────────
1209
- let appliedCardStyle = cardStyle;
1210
- if (isTextImage) {
1211
- // Drive 文字配图: type cards → 生成图片 → pick style → 下一步 → standard editor.
1212
- appliedCardStyle = await runTextImageFlow(page, cards, cardStyle);
1213
- }
1214
- else {
1215
- const upload = await uploadImages(page, absImagePaths);
1216
- if (!upload.ok) {
1217
- await page.screenshot({ path: '/tmp/xhs_publish_upload_debug.png' });
1218
- throw new CommandExecutionError(`Image injection failed: ${upload.error ?? 'unknown'}. ` +
1219
- 'Debug screenshot: /tmp/xhs_publish_upload_debug.png');
1220
- }
1221
- await page.wait({ time: UPLOAD_SETTLE_MS / 1_000 });
1222
- await waitForUploads(page);
1223
- }
1224
- // ── Step 3b: Wait for editor form to render ───────────────────────────────
1225
- const formReady = await waitForEditForm(page);
1226
- if (!formReady) {
1227
- await page.screenshot({ path: '/tmp/xhs_publish_form_debug.png' });
1228
- throw new CommandExecutionError('Editing form did not appear after image acquisition. The page layout may have changed. ' +
1229
- 'Debug screenshot: /tmp/xhs_publish_form_debug.png');
1230
- }
1231
- if (isTextImage) {
1232
- await assertComposerMediaCount(page, cards.length, '文字配图 generated images');
1233
- }
1234
- // ── Step 3c: In text-image mode, optionally append uploaded images ────────
1235
- if (isTextImage && absImagePaths.length > 0) {
1236
- const upload = await uploadImages(page, absImagePaths);
1237
- if (!upload.ok) {
1238
- await page.screenshot({ path: '/tmp/xhs_publish_append_debug.png' });
1239
- throw new CommandExecutionError(`Appending images failed: ${upload.error ?? 'unknown'}. ` +
1240
- 'Debug screenshot: /tmp/xhs_publish_append_debug.png');
1241
- }
1242
- await page.wait({ time: UPLOAD_SETTLE_MS / 1_000 });
1243
- await waitForUploads(page);
1244
- await assertComposerMediaCount(page, cards.length + absImagePaths.length, '文字配图 appended images');
1245
- }
1246
- // ── Step 4: Fill title ─────────────────────────────────────────────────────
1247
- await fillField(page, TITLE_SELECTORS, title, 'title');
1248
- await page.wait({ time: 0.5 });
1249
- // ── Step 5: Fill content / body ────────────────────────────────────────────
1250
- await fillField(page, BODY_SELECTORS, content, 'content');
1251
- await page.wait({ time: 0.5 });
1252
- // ── Step 6: Add topic hashtags ─────────────────────────────────────────────
1253
- // XHS converts a "#keyword" typed into the body editor into a real topic
1254
- // entity only when the user picks an item from the inline suggestion
1255
- // dropdown that pops up while typing. The previous implementation looked
1256
- // for a standalone "添加话题" button + dedicated search <input>, which the
1257
- // current creator-center editor no longer exposes — it left bare "#"
1258
- // characters in the body with no linked topics. We now drive the native
1259
- // inline flow: focus the body editor, type "#keyword" (firing the
1260
- // dropdown), then select the matching suggestion.
1261
- let addedTopics = [];
1262
- if (topics.length) {
1263
- addedTopics = await addTopics(page, BODY_SELECTORS, topics);
1264
- }
1265
- // ── Step 7: Publish or save draft ─────────────────────────────────────────
1266
- const actionLabels = isDraft ? ['暂存离开', '存草稿'] : ['发布', '发布笔记'];
1267
- const invokeResult = await page.evaluate(`
1268
- (cfg => {
1269
- const { isDraftMode, publishNames, draftNames, labels } = cfg;
1270
- const isVisible = (el) => {
1271
- if (!el || el.offsetParent === null) return false;
1272
- const rect = el.getBoundingClientRect();
1273
- return rect.width > 0 && rect.height > 0;
1274
- };
1275
- // Path 1: web component method invoke on <xhs-publish-btn>.
1276
- const hosts = Array.from(document.querySelectorAll('xhs-publish-btn')).filter(isVisible);
1277
- const wanted = isDraftMode ? draftNames : publishNames;
1278
- // Try every host + every candidate; do NOT bail on the first throw
1279
- // (multiple hosts can exist, and a later name may succeed).
1280
- let lastMethodError = null;
1281
- for (const host of hosts) {
1282
- for (const name of wanted) {
1283
- if (typeof host[name] !== 'function') continue;
1284
- try {
1285
- host[name]();
1286
- return { ok: true, via: 'method', name };
1287
- } catch (err) {
1288
- lastMethodError = String(err && err.message || err);
1289
- }
1290
- }
1291
- }
1292
- // Path 2: legacy <button>/[role=button] text-match click fallback.
1293
- const buttons = document.querySelectorAll('button, [role="button"]');
1294
- for (const btn of buttons) {
1295
- const text = (btn.innerText || btn.textContent || '').trim();
1296
- if (
1297
- labels.some(l => text === l || text.includes(l)) &&
1298
- isVisible(btn) &&
1299
- !btn.disabled
1300
- ) {
1301
- btn.click();
1302
- return { ok: true, via: 'click', text };
1303
- }
1304
- }
1305
- return { ok: false, via: 'none', hosts: hosts.length, lastMethodError };
1306
- })(${JSON.stringify({
1307
- isDraftMode: isDraft,
1308
- publishNames: PUBLISH_METHOD_NAMES,
1309
- draftNames: DRAFT_METHOD_NAMES,
1310
- labels: actionLabels,
1311
- })})
1312
- `);
1313
- if (!invokeResult?.ok) {
1314
- // ── Draft fallback: try leave-and-save flow ──────────────────────────
1315
- if (isDraft) {
1316
- const leaveTriggered = await page.evaluate(`
1317
- (() => {
1318
- const labels = ['返回', '关闭', '取消', '离开'];
1319
- const buttons = document.querySelectorAll('button, [role="button"], div, span');
1320
- for (const btn of buttons) {
1321
- const text = (btn.innerText || btn.textContent || '').trim();
1322
- if (labels.some(l => text === l || text.includes(l)) && btn.offsetParent !== null) {
1323
- btn.click();
1324
- return true;
1325
- }
1326
- }
1327
- return false;
1328
- })()
1329
- `);
1330
- if (leaveTriggered) {
1331
- await page.wait({ time: 1 });
1332
- const saveLabels = ['暂存离开', '存草稿', '保存草稿'];
1333
- const saved = await page.evaluate(`
1334
- (labels => {
1335
- const buttons = document.querySelectorAll('button, [role="button"]');
1336
- for (const btn of buttons) {
1337
- const text = (btn.innerText || btn.textContent || '').trim();
1338
- if (
1339
- labels.some(l => text === l || text.includes(l)) &&
1340
- btn.offsetParent !== null &&
1341
- !btn.disabled
1342
- ) {
1343
- btn.click();
1344
- return true;
1345
- }
1346
- }
1347
- return false;
1348
- })(${JSON.stringify(saveLabels)})
1349
- `);
1350
- if (saved) {
1351
- invokeResult.ok = true;
1352
- invokeResult.via = 'leave-save-fallback';
1353
- }
1354
- }
1355
- // Check if auto-saved
1356
- if (!invokeResult?.ok) {
1357
- await page.wait({ time: 2 });
1358
- const autoSaved = await page.evaluate(`
1359
- () => {
1360
- const markers = ['草稿箱(', '保存于', '编辑于'];
1361
- for (const el of document.querySelectorAll('*')) {
1362
- const text = (el.innerText || el.textContent || '').trim();
1363
- if (text && markers.some(marker => text.includes(marker))) return true;
1364
- }
1365
- return false;
1366
- }
1367
- `);
1368
- if (autoSaved) {
1369
- invokeResult.ok = true;
1370
- invokeResult.via = 'auto-save';
1371
- }
1372
- }
1373
- }
1374
- }
1375
- if (!invokeResult?.ok) {
1376
- await page.screenshot({ path: '/tmp/xhs_publish_submit_debug.png' });
1377
- const viaClause = invokeResult?.via ? ` (via=${invokeResult.via})` : '';
1378
- const errorClause = invokeResult?.error ? `, error=${invokeResult.error}` : '';
1379
- const lastMethodClause = invokeResult?.lastMethodError ? `, lastMethodError=${invokeResult.lastMethodError}` : '';
1380
- throw new Error(`Could not trigger "${actionLabels[0]}" action${viaClause}${errorClause}${lastMethodClause}. ` +
1381
- 'Debug screenshot: /tmp/xhs_publish_submit_debug.png');
1382
- }
1383
- // ── Step 8: Verify success ─────────────────────────────────────────────────
1384
- await page.wait({ time: 4 });
1385
- const finalUrl = await page.evaluate('() => location.href');
1386
- const successMarkers = isDraft
1387
- ? ['草稿已保存', '暂存成功', '保存成功', '保存于', '图文笔记(']
1388
- : ['发布成功', '上传成功'];
1389
- const successMsg = await page.evaluate(`
1390
- (markers => {
1391
- for (const el of document.querySelectorAll('*')) {
1392
- if (el.tagName === 'STYLE' || el.tagName === 'SCRIPT') continue;
1393
- const text = (el.innerText || '').trim();
1394
- if (text.length > 200) continue;
1395
- if (el.children.length === 0 && markers.some(marker => text.includes(marker))) return text;
1396
- }
1397
- return '';
1398
- })(${JSON.stringify(successMarkers)})
1399
- `);
1400
- const navigatedAway = !finalUrl.includes('/publish/publish');
1401
- const isSuccess = successMsg.length > 0 || navigatedAway;
1402
- const verb = isDraft ? '暂存成功' : '发布成功';
1403
- if (!isSuccess) {
1404
- throw new CommandExecutionError(`${verb} could not be verified: no success marker or post-submit navigation was observed. ` +
1405
- (finalUrl ? `Current URL: ${finalUrl}` : 'Current URL was empty.'));
1406
- }
1407
- return [
1408
- {
1409
- status: `✅ ${verb}`,
1410
- detail: [
1411
- `"${title}"`,
1412
- isTextImage
1413
- ? `${cards.length}张文字配图${absImagePaths.length ? ` + ${absImagePaths.length}张图片` : ''}${appliedCardStyle && appliedCardStyle !== DEFAULT_CARD_STYLE ? ` (${appliedCardStyle})` : ''}`
1414
- : `${absImagePaths.length}张图片`,
1415
- addedTopics.length ? `话题: ${addedTopics.join(' ')}` : '',
1416
- successMsg || finalUrl || '',
1417
- ]
1418
- .filter(Boolean)
1419
- .join(' · '),
1420
- },
1421
- ];
1422
- },
1423
- });