@sovovs/bycli 1.8.0 → 2.1.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 (539) hide show
  1. package/cli-manifest.json +0 -61
  2. package/clis/twitter/search.js +3 -3
  3. package/dist/src/adapter-shadow.js +2 -2
  4. package/dist/src/browser/analyze.d.ts +10 -99
  5. package/dist/src/browser/analyze.js +10 -226
  6. package/dist/src/browser/cdp.js +67 -7
  7. package/dist/src/browser/daemon-client.d.ts +2 -0
  8. package/dist/src/browser/daemon-client.js +1 -1
  9. package/dist/src/browser/extension-capabilities.d.ts +13 -0
  10. package/dist/src/browser/extension-capabilities.js +22 -0
  11. package/dist/src/browser/extension-capabilities.test.d.ts +1 -0
  12. package/dist/src/browser/extension-version-metadata.test.d.ts +1 -0
  13. package/dist/src/browser/navigation-guard.d.ts +78 -0
  14. package/dist/src/browser/navigation-guard.js +142 -0
  15. package/dist/src/browser/navigation-guard.test.d.ts +1 -0
  16. package/dist/src/browser/page.d.ts +1 -0
  17. package/dist/src/browser/page.js +20 -1
  18. package/dist/src/browser/url-policy.d.ts +89 -0
  19. package/dist/src/browser/url-policy.js +311 -0
  20. package/dist/src/browser/url-policy.test.d.ts +1 -0
  21. package/dist/src/browser/verify-fixture.js +2 -2
  22. package/dist/src/build-manifest.js +4 -2
  23. package/dist/src/capabilityRouting.d.ts +3 -2
  24. package/dist/src/capabilityRouting.js +10 -2
  25. package/dist/src/cli.js +11 -14
  26. package/dist/src/commanderAdapter.js +5 -5
  27. package/dist/src/config-paths.d.ts +19 -0
  28. package/dist/src/config-paths.js +31 -0
  29. package/dist/src/daemon.js +256 -0
  30. package/dist/src/discovery.d.ts +10 -3
  31. package/dist/src/discovery.js +20 -10
  32. package/dist/src/discovery.test.d.ts +1 -0
  33. package/dist/src/execution.d.ts +5 -0
  34. package/dist/src/execution.js +272 -48
  35. package/dist/src/help.js +8 -8
  36. package/dist/src/main.js +18 -2
  37. package/dist/src/manifest-schema.d.ts +9 -0
  38. package/dist/src/manifest-schema.js +162 -0
  39. package/dist/src/manifest-schema.test.d.ts +1 -0
  40. package/dist/src/manifest-types.d.ts +1 -1
  41. package/dist/src/observation/redaction.js +10 -4
  42. package/dist/src/plugin.js +11 -8
  43. package/dist/src/recorder/highlevel/analyze.d.ts +29 -0
  44. package/dist/src/recorder/highlevel/analyze.js +91 -0
  45. package/dist/src/recorder/highlevel/init.d.ts +125 -0
  46. package/dist/src/recorder/highlevel/init.js +279 -0
  47. package/dist/src/recorder/highlevel/init.test.d.ts +1 -0
  48. package/dist/src/recorder/highlevel/verify.d.ts +73 -0
  49. package/dist/src/recorder/highlevel/verify.js +74 -0
  50. package/dist/src/recorder/http/analyze-runner.d.ts +28 -0
  51. package/dist/src/recorder/http/analyze-runner.js +78 -0
  52. package/dist/src/recorder/http/analyze-runner.test.d.ts +1 -0
  53. package/dist/src/recorder/http/handlers.d.ts +51 -0
  54. package/dist/src/recorder/http/handlers.js +219 -0
  55. package/dist/src/recorder/http/wrapper-config.d.ts +20 -0
  56. package/dist/src/recorder/http/wrapper-config.js +82 -0
  57. package/dist/src/recorder/http/wrapper-envelope.d.ts +31 -0
  58. package/dist/src/recorder/http/wrapper-envelope.js +51 -0
  59. package/dist/src/recorder/http/wrapper-gates.d.ts +16 -0
  60. package/dist/src/recorder/http/wrapper-gates.js +28 -0
  61. package/dist/src/recorder/http/wrapper-metrics.d.ts +1 -0
  62. package/dist/src/recorder/http/wrapper-metrics.js +5 -0
  63. package/dist/src/recorder/http/wrapper-registry.d.ts +50 -0
  64. package/dist/src/recorder/http/wrapper-registry.js +98 -0
  65. package/dist/src/recorder/http/wrapper-server.d.ts +59 -0
  66. package/dist/src/recorder/http/wrapper-server.js +240 -0
  67. package/dist/src/recorder/http/wrapper.test.d.ts +1 -0
  68. package/dist/src/recorder/observability/logger.d.ts +5 -0
  69. package/dist/src/recorder/observability/logger.js +13 -0
  70. package/dist/src/recorder/runner/config.d.ts +34 -0
  71. package/dist/src/recorder/runner/config.js +84 -0
  72. package/dist/src/recorder/runner/config.test.d.ts +1 -0
  73. package/dist/src/recorder/runner/reap.d.ts +79 -0
  74. package/dist/src/recorder/runner/reap.js +230 -0
  75. package/dist/src/recorder/runner/reap.test.d.ts +1 -0
  76. package/dist/src/recorder/runner/runner-port.d.ts +95 -0
  77. package/dist/src/recorder/runner/runner-port.js +518 -0
  78. package/dist/src/recorder/runner/runner-port.test.d.ts +1 -0
  79. package/dist/src/recorder/runner/session-keys.d.ts +28 -0
  80. package/dist/src/recorder/runner/session-keys.js +72 -0
  81. package/dist/src/recorder/runner/session-keys.test.d.ts +1 -0
  82. package/dist/src/recorder/runner/verify-runner-main.d.ts +96 -0
  83. package/dist/src/recorder/runner/verify-runner-main.js +292 -0
  84. package/dist/src/recorder/runner/verify-runner-main.test.d.ts +1 -0
  85. package/dist/src/registry-api.d.ts +1 -1
  86. package/dist/src/registry-api.types.test.d.ts +1 -0
  87. package/dist/src/registry-transaction.d.ts +42 -0
  88. package/dist/src/registry-transaction.js +194 -0
  89. package/dist/src/registry-transaction.test.d.ts +1 -0
  90. package/dist/src/registry.d.ts +58 -16
  91. package/dist/src/registry.js +131 -15
  92. package/dist/src/serialization.d.ts +1 -1
  93. package/dist/src/serialization.js +3 -3
  94. package/dist/src/types.d.ts +2 -0
  95. package/package.json +8 -5
  96. package/scripts/m1-daemon-navigate-drive.mjs +138 -0
  97. package/scripts/m1-extension-spike.mjs +237 -0
  98. package/scripts/m1-live-spike.mjs +156 -0
  99. package/scripts/m6b-connect-back-spike.sh +31 -0
  100. package/clis/12306/utils.test.js +0 -331
  101. package/clis/1688/assets.test.js +0 -39
  102. package/clis/1688/download.test.js +0 -31
  103. package/clis/1688/item.test.js +0 -67
  104. package/clis/1688/search.test.js +0 -75
  105. package/clis/1688/shared.test.js +0 -57
  106. package/clis/1688/store.test.js +0 -62
  107. package/clis/36kr/article.test.js +0 -46
  108. package/clis/36kr/hot.test.js +0 -15
  109. package/clis/36kr/news.test.js +0 -85
  110. package/clis/51job/utils.test.js +0 -69
  111. package/clis/_atlassian/shared.test.js +0 -170
  112. package/clis/aibase/news.test.js +0 -59
  113. package/clis/amazon/bestsellers.test.js +0 -29
  114. package/clis/amazon/discussion.test.js +0 -124
  115. package/clis/amazon/offer.test.js +0 -29
  116. package/clis/amazon/product.test.js +0 -24
  117. package/clis/amazon/rankings.test.js +0 -41
  118. package/clis/amazon/search.test.js +0 -22
  119. package/clis/amazon/shared.test.js +0 -44
  120. package/clis/apple-podcasts/commands.test.js +0 -119
  121. package/clis/apple-podcasts/utils.test.js +0 -57
  122. package/clis/arxiv/arxiv.test.js +0 -112
  123. package/clis/baidu-scholar/search.test.js +0 -23
  124. package/clis/barchart/greeks.test.js +0 -138
  125. package/clis/bilibili/comment.test.js +0 -153
  126. package/clis/bilibili/comments.test.js +0 -142
  127. package/clis/bilibili/dynamic.test.js +0 -68
  128. package/clis/bilibili/hot.test.js +0 -17
  129. package/clis/bilibili/subtitle.test.js +0 -196
  130. package/clis/bilibili/summary.test.js +0 -210
  131. package/clis/bilibili/utils.test.js +0 -61
  132. package/clis/bilibili/video.test.js +0 -132
  133. package/clis/binance/commands.test.js +0 -70
  134. package/clis/bloomberg/utils.test.js +0 -129
  135. package/clis/booking/booking.test.js +0 -356
  136. package/clis/boss/chatlist.test.js +0 -211
  137. package/clis/boss/chatmsg.test.js +0 -230
  138. package/clis/boss/search.test.js +0 -78
  139. package/clis/boss/utils.test.js +0 -34
  140. package/clis/brave/search.test.js +0 -76
  141. package/clis/chaoxing/utils.test.js +0 -45
  142. package/clis/chatgpt/commands.test.js +0 -45
  143. package/clis/chatgpt/envelope.test.js +0 -108
  144. package/clis/chatgpt/image.test.js +0 -188
  145. package/clis/chatgpt/utils.test.js +0 -330
  146. package/clis/chatgpt-app/ax.test.js +0 -35
  147. package/clis/chatwise/composer.test.js +0 -186
  148. package/clis/chess/analyze.test.js +0 -79
  149. package/clis/chess/game.test.js +0 -178
  150. package/clis/chess/games.test.js +0 -164
  151. package/clis/chess/stats.test.js +0 -79
  152. package/clis/chess/utils.test.js +0 -230
  153. package/clis/claude/ask.test.js +0 -338
  154. package/clis/claude/commands.test.js +0 -118
  155. package/clis/claude/utils.test.js +0 -148
  156. package/clis/cnki/search.test.js +0 -18
  157. package/clis/codex/sidebar.test.js +0 -329
  158. package/clis/coingecko/coingecko.test.js +0 -109
  159. package/clis/confluence/commands.test.js +0 -195
  160. package/clis/coupang/coupang.test.js +0 -159
  161. package/clis/coupang/utils.test.js +0 -62
  162. package/clis/ctrip/ctrip.test.js +0 -719
  163. package/clis/dblp/dblp.test.js +0 -397
  164. package/clis/deepseek/ask.test.js +0 -312
  165. package/clis/deepseek/detail.test.js +0 -81
  166. package/clis/deepseek/send.test.js +0 -107
  167. package/clis/deepseek/utils.test.js +0 -370
  168. package/clis/defillama/defillama.test.js +0 -99
  169. package/clis/devto/devto.test.js +0 -236
  170. package/clis/dianping/dianping.test.js +0 -578
  171. package/clis/douban/download.test.js +0 -170
  172. package/clis/douban/movie-hot.test.js +0 -14
  173. package/clis/douban/search.test.js +0 -11
  174. package/clis/douban/subject.test.js +0 -11
  175. package/clis/douban/utils.test.js +0 -438
  176. package/clis/doubao/detail.test.js +0 -42
  177. package/clis/doubao/history.test.js +0 -37
  178. package/clis/doubao/utils.test.js +0 -344
  179. package/clis/douyin/_shared/browser-fetch.test.js +0 -64
  180. package/clis/douyin/_shared/creation-id.test.js +0 -22
  181. package/clis/douyin/_shared/imagex-upload.test.js +0 -87
  182. package/clis/douyin/_shared/sts2.test.js +0 -27
  183. package/clis/douyin/_shared/text-extra.test.js +0 -37
  184. package/clis/douyin/_shared/timing.test.js +0 -28
  185. package/clis/douyin/_shared/tos-upload-short-read.test.js +0 -83
  186. package/clis/douyin/_shared/tos-upload.test.js +0 -229
  187. package/clis/douyin/_shared/transcode.test.js +0 -91
  188. package/clis/douyin/_shared/vod-upload.test.js +0 -38
  189. package/clis/douyin/activities.test.js +0 -55
  190. package/clis/douyin/collections.test.js +0 -45
  191. package/clis/douyin/delete.test.js +0 -100
  192. package/clis/douyin/draft.test.js +0 -335
  193. package/clis/douyin/drafts.test.js +0 -11
  194. package/clis/douyin/hashtag.test.js +0 -171
  195. package/clis/douyin/location.test.js +0 -23
  196. package/clis/douyin/profile.test.js +0 -46
  197. package/clis/douyin/publish-upload-id.test.js +0 -170
  198. package/clis/douyin/publish.test.js +0 -38
  199. package/clis/douyin/stats.test.js +0 -22
  200. package/clis/douyin/update.test.js +0 -11
  201. package/clis/douyin/user-videos.test.js +0 -151
  202. package/clis/douyin/videos.test.js +0 -54
  203. package/clis/duckduckgo/search.test.js +0 -128
  204. package/clis/duckduckgo/suggest.test.js +0 -66
  205. package/clis/eastmoney/hot-rank.test.js +0 -59
  206. package/clis/endoflife/endoflife.test.js +0 -51
  207. package/clis/facebook/feed.test.js +0 -169
  208. package/clis/facebook/marketplace.test.js +0 -91
  209. package/clis/facebook/notifications.test.js +0 -458
  210. package/clis/facebook/search.test.js +0 -55
  211. package/clis/flathub/flathub.test.js +0 -90
  212. package/clis/flomo/memos.test.js +0 -144
  213. package/clis/gemini/ask.test.js +0 -100
  214. package/clis/gemini/deep-research-result.test.js +0 -155
  215. package/clis/gemini/deep-research.test.js +0 -181
  216. package/clis/gemini/reply-state.test.js +0 -671
  217. package/clis/gemini/utils.test.js +0 -198
  218. package/clis/geogebra/geogebra.test.js +0 -175
  219. package/clis/gitee/search.test.js +0 -65
  220. package/clis/gitee/user.test.js +0 -63
  221. package/clis/google/utils.test.js +0 -75
  222. package/clis/google-scholar/cite.test.js +0 -47
  223. package/clis/google-scholar/profile.test.js +0 -49
  224. package/clis/google-scholar/search.test.js +0 -71
  225. package/clis/goproxy/goproxy.test.js +0 -103
  226. package/clis/gov-law/commands.test.js +0 -39
  227. package/clis/gov-policy/gov-policy.test.js +0 -224
  228. package/clis/grok/ask.test.js +0 -29
  229. package/clis/grok/utils.test.js +0 -103
  230. package/clis/hackernews/hackernews.test.js +0 -132
  231. package/clis/hf/hf.test.js +0 -16
  232. package/clis/hupu/hot.test.js +0 -224
  233. package/clis/imdb/utils.test.js +0 -88
  234. package/clis/indeed/indeed.test.js +0 -375
  235. package/clis/instagram/_shared/private-publish.test.js +0 -705
  236. package/clis/instagram/_shared/protocol-capture.test.js +0 -114
  237. package/clis/instagram/download.test.js +0 -118
  238. package/clis/instagram/note.test.js +0 -53
  239. package/clis/instagram/post.test.js +0 -1647
  240. package/clis/instagram/reel.test.js +0 -167
  241. package/clis/instagram/story.test.js +0 -134
  242. package/clis/jd/commands.test.js +0 -41
  243. package/clis/jd/item.test.js +0 -354
  244. package/clis/jianyu/search.test.js +0 -153
  245. package/clis/jianyu/shared/procurement-contract.test.js +0 -72
  246. package/clis/jianyu/shared/procurement-detail.test.js +0 -84
  247. package/clis/jike/read.test.js +0 -86
  248. package/clis/jira/commands.test.js +0 -287
  249. package/clis/juejin/search.js +0 -123
  250. package/clis/juejin/search.test.js +0 -98
  251. package/clis/lesswrong/frontpage.test.js +0 -37
  252. package/clis/lichess/lichess.test.js +0 -85
  253. package/clis/linkedin/connect.test.js +0 -213
  254. package/clis/linkedin/inbox.test.js +0 -152
  255. package/clis/linkedin/job-detail.test.js +0 -38
  256. package/clis/linkedin/jobs-preferences.test.js +0 -43
  257. package/clis/linkedin/people-search.test.js +0 -216
  258. package/clis/linkedin/post-analytics.test.js +0 -40
  259. package/clis/linkedin/posts.test.js +0 -40
  260. package/clis/linkedin/profile-analytics.test.js +0 -67
  261. package/clis/linkedin/profile-experience.test.js +0 -152
  262. package/clis/linkedin/profile-projects.test.js +0 -111
  263. package/clis/linkedin/profile-read.test.js +0 -77
  264. package/clis/linkedin/safe-send.test.js +0 -204
  265. package/clis/linkedin/salesnav-inbox.test.js +0 -113
  266. package/clis/linkedin/salesnav-message.test.js +0 -172
  267. package/clis/linkedin/salesnav-search.test.js +0 -76
  268. package/clis/linkedin/salesnav-thread.test.js +0 -79
  269. package/clis/linkedin/search.test.js +0 -222
  270. package/clis/linkedin/sent-invitations.test.js +0 -62
  271. package/clis/linkedin/services-read.test.js +0 -105
  272. package/clis/linkedin/thread-snapshot.test.js +0 -89
  273. package/clis/linkedin/timeline.test.js +0 -81
  274. package/clis/linkedin-learning/course.test.js +0 -114
  275. package/clis/linkedin-learning/search.test.js +0 -144
  276. package/clis/linkedin-learning/trending.test.js +0 -123
  277. package/clis/linux-do/feed.test.js +0 -153
  278. package/clis/linux-do/topic-content.test.js +0 -59
  279. package/clis/lobsters/lobsters.test.js +0 -169
  280. package/clis/notebooklm/add-source.test.js +0 -97
  281. package/clis/notebooklm/compat.test.js +0 -16
  282. package/clis/notebooklm/create.test.js +0 -58
  283. package/clis/notebooklm/generate-audio.test.js +0 -63
  284. package/clis/notebooklm/generate-slides.test.js +0 -75
  285. package/clis/notebooklm/history.test.js +0 -58
  286. package/clis/notebooklm/note-list.test.js +0 -56
  287. package/clis/notebooklm/notes-get.test.js +0 -72
  288. package/clis/notebooklm/open.test.js +0 -63
  289. package/clis/notebooklm/rpc.test.js +0 -131
  290. package/clis/notebooklm/source-fulltext.test.js +0 -106
  291. package/clis/notebooklm/source-get.test.js +0 -84
  292. package/clis/notebooklm/source-guide.test.js +0 -104
  293. package/clis/notebooklm/summary.test.js +0 -78
  294. package/clis/notebooklm/utils.test.js +0 -449
  295. package/clis/notebooklm/write-note.test.js +0 -70
  296. package/clis/nuget/nuget.test.js +0 -111
  297. package/clis/oeis/oeis.test.js +0 -88
  298. package/clis/ones/task-helpers.test.js +0 -12
  299. package/clis/ones/worklog.test.js +0 -20
  300. package/clis/openfda/openfda.test.js +0 -114
  301. package/clis/openreview/openreview.test.js +0 -427
  302. package/clis/osv/osv.test.js +0 -97
  303. package/clis/paperreview/commands.test.js +0 -243
  304. package/clis/paperreview/utils.test.js +0 -49
  305. package/clis/pixiv/download.test.js +0 -87
  306. package/clis/pixiv/illusts.test.js +0 -99
  307. package/clis/pixiv/search.test.js +0 -83
  308. package/clis/powerchina/search.test.js +0 -93
  309. package/clis/producthunt/utils.test.js +0 -64
  310. package/clis/pubmed/pubmed.test.js +0 -276
  311. package/clis/quark/utils.test.js +0 -58
  312. package/clis/qwen/utils.test.js +0 -45
  313. package/clis/reddit/extract-media.test.js +0 -149
  314. package/clis/reddit/frontpage.test.js +0 -34
  315. package/clis/reddit/home.test.js +0 -170
  316. package/clis/reddit/hot.test.js +0 -32
  317. package/clis/reddit/popular.test.js +0 -26
  318. package/clis/reddit/read.test.js +0 -335
  319. package/clis/reddit/reply.test.js +0 -89
  320. package/clis/reddit/search.test.js +0 -26
  321. package/clis/reddit/subreddit-info.test.js +0 -163
  322. package/clis/reddit/subreddit.test.js +0 -31
  323. package/clis/reddit/subscribed.test.js +0 -168
  324. package/clis/reddit/whoami.test.js +0 -105
  325. package/clis/rednote/navigation.test.js +0 -26
  326. package/clis/rednote/rednote.test.js +0 -222
  327. package/clis/rest-countries/rest-countries.test.js +0 -83
  328. package/clis/reuters/reuters.test.js +0 -299
  329. package/clis/rfc/rfc.test.js +0 -74
  330. package/clis/sinafinance/stock.test.js +0 -59
  331. package/clis/spotify/utils.test.js +0 -67
  332. package/clis/stackoverflow/stackoverflow.test.js +0 -404
  333. package/clis/steam/steam.test.js +0 -46
  334. package/clis/substack/utils.test.js +0 -44
  335. package/clis/suno/commands.test.js +0 -188
  336. package/clis/suno/download.test.js +0 -151
  337. package/clis/suno/generate.test.js +0 -252
  338. package/clis/suno/utils.test.js +0 -329
  339. package/clis/taobao/commands.test.js +0 -41
  340. package/clis/tdx/hot-rank.test.js +0 -59
  341. package/clis/ths/hot-rank.test.js +0 -64
  342. package/clis/tieba/commands.test.js +0 -79
  343. package/clis/tieba/utils.test.js +0 -290
  344. package/clis/tiktok/creator-videos.test.js +0 -113
  345. package/clis/tiktok/refactor.test.js +0 -389
  346. package/clis/tiktok/write-refactor.test.js +0 -370
  347. package/clis/toutiao/toutiao.test.js +0 -378
  348. package/clis/tvmaze/tvmaze.test.js +0 -93
  349. package/clis/twitter/bookmark-folder.test.js +0 -395
  350. package/clis/twitter/bookmark-folders.test.js +0 -152
  351. package/clis/twitter/bookmark.test.js +0 -74
  352. package/clis/twitter/bookmarks.test.js +0 -205
  353. package/clis/twitter/delete.test.js +0 -85
  354. package/clis/twitter/device-follow.test.js +0 -287
  355. package/clis/twitter/download.test.js +0 -457
  356. package/clis/twitter/followers.test.js +0 -62
  357. package/clis/twitter/following.test.js +0 -338
  358. package/clis/twitter/hide-reply.test.js +0 -76
  359. package/clis/twitter/like.test.js +0 -73
  360. package/clis/twitter/likes.test.js +0 -220
  361. package/clis/twitter/list-add.test.js +0 -133
  362. package/clis/twitter/list-create.test.js +0 -169
  363. package/clis/twitter/list-remove.test.js +0 -110
  364. package/clis/twitter/list-tweets.test.js +0 -196
  365. package/clis/twitter/lists.test.js +0 -253
  366. package/clis/twitter/post.test.js +0 -258
  367. package/clis/twitter/profile.test.js +0 -39
  368. package/clis/twitter/quote.test.js +0 -194
  369. package/clis/twitter/reply.test.js +0 -237
  370. package/clis/twitter/retweet.test.js +0 -73
  371. package/clis/twitter/search.test.js +0 -349
  372. package/clis/twitter/shared.test.js +0 -794
  373. package/clis/twitter/thread.test.js +0 -58
  374. package/clis/twitter/timeline.test.js +0 -104
  375. package/clis/twitter/trending.test.js +0 -15
  376. package/clis/twitter/tweets.test.js +0 -362
  377. package/clis/twitter/unbookmark.test.js +0 -73
  378. package/clis/twitter/unlike.test.js +0 -75
  379. package/clis/twitter/unretweet.test.js +0 -73
  380. package/clis/twitter/utils.test.js +0 -169
  381. package/clis/uisdc/news.test.js +0 -66
  382. package/clis/uiverse/_shared.test.js +0 -62
  383. package/clis/uiverse/navigation.test.js +0 -12
  384. package/clis/upwork/upwork.test.js +0 -566
  385. package/clis/wanfang/search.test.js +0 -23
  386. package/clis/web/read.test.js +0 -392
  387. package/clis/weibo/delete.test.js +0 -94
  388. package/clis/weibo/envelope.test.js +0 -85
  389. package/clis/weibo/favorites.test.js +0 -114
  390. package/clis/weibo/publish.test.js +0 -192
  391. package/clis/weibo/user-posts.test.js +0 -92
  392. package/clis/weibo/utils.test.js +0 -36
  393. package/clis/weixin/drafts.test.js +0 -69
  394. package/clis/weixin/search.test.js +0 -227
  395. package/clis/weread/ai-outline.test.js +0 -83
  396. package/clis/weread/book-search.test.js +0 -242
  397. package/clis/weread/commands.test.js +0 -398
  398. package/clis/weread/private-api-regression.test.js +0 -369
  399. package/clis/weread/search-regression.test.js +0 -494
  400. package/clis/weread/utils.test.js +0 -128
  401. package/clis/weread-official/commands.test.js +0 -385
  402. package/clis/weread-official/utils.test.js +0 -242
  403. package/clis/wikidata/wikidata.test.js +0 -83
  404. package/clis/wikipedia/trending.test.js +0 -57
  405. package/clis/wttr/wttr.test.js +0 -84
  406. package/clis/xianyu/chat.test.js +0 -84
  407. package/clis/xianyu/im.test.js +0 -253
  408. package/clis/xianyu/item.test.js +0 -56
  409. package/clis/xianyu/publish.test.js +0 -220
  410. package/clis/xianyu/search.test.js +0 -17
  411. package/clis/xiaoe/xiaoe.test.js +0 -486
  412. package/clis/xiaohongshu/comments.test.js +0 -258
  413. package/clis/xiaohongshu/creator-note-detail.test.js +0 -451
  414. package/clis/xiaohongshu/creator-notes-summary.test.js +0 -94
  415. package/clis/xiaohongshu/creator-notes.test.js +0 -281
  416. package/clis/xiaohongshu/creator-stats.test.js +0 -24
  417. package/clis/xiaohongshu/delete-note.test.js +0 -172
  418. package/clis/xiaohongshu/download.test.js +0 -316
  419. package/clis/xiaohongshu/navigation.test.js +0 -34
  420. package/clis/xiaohongshu/note.test.js +0 -249
  421. package/clis/xiaohongshu/publish.test.js +0 -608
  422. package/clis/xiaohongshu/search.test.js +0 -325
  423. package/clis/xiaohongshu/user-helpers.test.js +0 -160
  424. package/clis/xiaoyuzhou/auth.test.js +0 -124
  425. package/clis/xiaoyuzhou/download.test.js +0 -135
  426. package/clis/xiaoyuzhou/podcast-episodes.test.js +0 -78
  427. package/clis/xiaoyuzhou/transcript.test.js +0 -195
  428. package/clis/xiaoyuzhou/utils.test.js +0 -39
  429. package/clis/xueqiu/comments.test.js +0 -696
  430. package/clis/xueqiu/danjuan-utils.test.js +0 -41
  431. package/clis/xueqiu/utils.test.js +0 -26
  432. package/clis/yahoo/search.test.js +0 -94
  433. package/clis/youdao/note.test.js +0 -99
  434. package/clis/youtube/channel.test.js +0 -59
  435. package/clis/youtube/feed.test.js +0 -131
  436. package/clis/youtube/transcript-group.test.js +0 -99
  437. package/clis/youtube/transcript.test.js +0 -296
  438. package/clis/youtube/utils.test.js +0 -84
  439. package/clis/yuanbao/ask.test.js +0 -124
  440. package/clis/yuanbao/new.test.js +0 -30
  441. package/clis/yuanbao/shared.test.js +0 -80
  442. package/clis/zhihu/answer-comments.test.js +0 -287
  443. package/clis/zhihu/answer-detail.test.js +0 -338
  444. package/clis/zhihu/answer.test.js +0 -54
  445. package/clis/zhihu/collection.test.js +0 -337
  446. package/clis/zhihu/collections.test.js +0 -182
  447. package/clis/zhihu/comment.test.js +0 -50
  448. package/clis/zhihu/download.test.js +0 -12
  449. package/clis/zhihu/favorite.test.js +0 -59
  450. package/clis/zhihu/follow.test.js +0 -42
  451. package/clis/zhihu/like.test.js +0 -41
  452. package/clis/zhihu/question.test.js +0 -251
  453. package/clis/zhihu/recommend.test.js +0 -143
  454. package/clis/zhihu/search.test.js +0 -198
  455. package/clis/zhihu/target.test.js +0 -77
  456. package/clis/zhihu/text.test.js +0 -24
  457. package/clis/zhihu/write-shared.test.js +0 -176
  458. package/clis/zlibrary/commands.test.js +0 -65
  459. package/clis/zsxq/search.test.js +0 -24
  460. package/clis/zsxq/topic.test.js +0 -30
  461. package/clis/zsxq/topics.test.js +0 -24
  462. package/clis/zsxq/utils.test.js +0 -31
  463. package/dist/src/adapter-shadow.test.js +0 -49
  464. package/dist/src/adapter-source.test.js +0 -29
  465. package/dist/src/browser/analyze.test.js +0 -166
  466. package/dist/src/browser/article-extract.e2e.test.js +0 -105
  467. package/dist/src/browser/article-extract.test.js +0 -94
  468. package/dist/src/browser/ax-snapshot.test.js +0 -91
  469. package/dist/src/browser/base-page.test.js +0 -758
  470. package/dist/src/browser/cdp-click-fixture.test.js +0 -87
  471. package/dist/src/browser/cdp.test.js +0 -79
  472. package/dist/src/browser/compound.test.js +0 -175
  473. package/dist/src/browser/daemon-client.test.js +0 -199
  474. package/dist/src/browser/dom-helpers.test.js +0 -106
  475. package/dist/src/browser/dom-snapshot.test.js +0 -313
  476. package/dist/src/browser/errors.test.js +0 -60
  477. package/dist/src/browser/extract.test.js +0 -129
  478. package/dist/src/browser/find.test.js +0 -180
  479. package/dist/src/browser/html-tree.test.js +0 -181
  480. package/dist/src/browser/network-cache.test.js +0 -58
  481. package/dist/src/browser/network-key.test.js +0 -49
  482. package/dist/src/browser/page.test.js +0 -378
  483. package/dist/src/browser/shape-filter.test.js +0 -101
  484. package/dist/src/browser/shape.test.js +0 -82
  485. package/dist/src/browser/stealth.test.js +0 -134
  486. package/dist/src/browser/target-errors.test.js +0 -94
  487. package/dist/src/browser/target-resolver.test.js +0 -118
  488. package/dist/src/browser/utils.test.js +0 -29
  489. package/dist/src/browser/verify-fixture.test.js +0 -219
  490. package/dist/src/browser.test.js +0 -232
  491. package/dist/src/build-manifest.test.js +0 -341
  492. package/dist/src/capabilityRouting.test.js +0 -63
  493. package/dist/src/cli-argv-preprocess.test.js +0 -209
  494. package/dist/src/cli.test.js +0 -2803
  495. package/dist/src/commanderAdapter.test.js +0 -352
  496. package/dist/src/commands/daemon.test.js +0 -219
  497. package/dist/src/completion.test.js +0 -24
  498. package/dist/src/convention-audit.test.js +0 -247
  499. package/dist/src/daemon.test.js +0 -60
  500. package/dist/src/doctor.test.js +0 -263
  501. package/dist/src/download/article-download.test.js +0 -235
  502. package/dist/src/download/index.test.js +0 -140
  503. package/dist/src/download/media-download.test.js +0 -112
  504. package/dist/src/download/progress.test.js +0 -36
  505. package/dist/src/electron-apps.test.js +0 -49
  506. package/dist/src/engine.test.js +0 -312
  507. package/dist/src/errors.test.js +0 -109
  508. package/dist/src/execution.test.js +0 -623
  509. package/dist/src/extension-manifest-regression.test.js +0 -12
  510. package/dist/src/external.test.js +0 -146
  511. package/dist/src/help.test.js +0 -58
  512. package/dist/src/hooks.test.js +0 -92
  513. package/dist/src/interceptor.test.js +0 -81
  514. package/dist/src/launcher.test.js +0 -138
  515. package/dist/src/node-network.test.js +0 -55
  516. package/dist/src/observation/artifact.test.js +0 -121
  517. package/dist/src/observation/manager.test.js +0 -13
  518. package/dist/src/observation/redaction.test.js +0 -32
  519. package/dist/src/observation/retention.test.js +0 -118
  520. package/dist/src/observation/ring-buffer.test.js +0 -22
  521. package/dist/src/output.test.js +0 -53
  522. package/dist/src/package-exports.test.js +0 -112
  523. package/dist/src/pipeline/executor.test.js +0 -182
  524. package/dist/src/pipeline/steps/download.test.js +0 -102
  525. package/dist/src/pipeline/steps/fetch.test.js +0 -117
  526. package/dist/src/pipeline/template.test.js +0 -175
  527. package/dist/src/pipeline/transform.test.js +0 -133
  528. package/dist/src/plugin-manifest.test.js +0 -179
  529. package/dist/src/plugin-scaffold.test.js +0 -83
  530. package/dist/src/plugin.test.js +0 -1324
  531. package/dist/src/registry.test.js +0 -209
  532. package/dist/src/runtime-detect.test.js +0 -39
  533. package/dist/src/serialization.test.js +0 -78
  534. package/dist/src/snapshotFormatter.test.js +0 -521
  535. package/dist/src/tui.test.js +0 -19
  536. package/dist/src/update-check.test.js +0 -116
  537. package/dist/src/utils.test.js +0 -155
  538. package/dist/src/validate.test.js +0 -90
  539. package/dist/src/weixin-download.test.js +0 -45
@@ -1,62 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { __test__ } from './store.js';
3
- describe('1688 store normalization', () => {
4
- it('merges store contact text with seller seed data', () => {
5
- const result = __test__.normalizeStorePayload({
6
- resolvedUrl: 'https://yinuoweierfushi.1688.com/?offerId=887904326744',
7
- explicitMemberId: null,
8
- storePayload: {
9
- href: 'https://yinuoweierfushi.1688.com/page/index.html',
10
- bodyText: `
11
- 青岛沁澜衣品服装有限公司
12
- 联系方式
13
- 地址:山东省青岛市即墨区环秀街道办事处湘江二路97号甲
14
- `,
15
- offerLinks: ['https://detail.1688.com/offer/887904326744.html'],
16
- },
17
- contactPayload: {
18
- href: 'https://yinuoweierfushi.1688.com/page/contactinfo.html',
19
- bodyText: `
20
- 青岛沁澜衣品服装有限公司
21
- 电话:86 0532 86655366
22
- 手机:15963238678
23
- 地址:山东省青岛市即墨区环秀街道办事处湘江二路97号甲
24
- `,
25
- },
26
- seed: {
27
- bodyText: `
28
- 入驻13年
29
- 主营:大码女装
30
- 店铺回头率
31
- 87%
32
- 延期必赔
33
- 品质保障
34
- `,
35
- seller: {
36
- companyName: '青岛沁澜衣品服装有限公司',
37
- memberId: 'b2b-1641351767',
38
- winportUrl: 'https://yinuoweierfushi.1688.com/page/index.html?spm=abc',
39
- },
40
- services: [{ serviceName: '延期必赔' }, { serviceName: '品质保障' }],
41
- },
42
- });
43
- expect(result.member_id).toBe('b2b-1641351767');
44
- expect(result.store_url).toBe('https://yinuoweierfushi.1688.com');
45
- expect(result.company_url).toBe('https://yinuoweierfushi.1688.com/page/contactinfo.html');
46
- expect(result.years_on_platform_text).toBe('入驻13年');
47
- expect(result.location).toBe('山东省青岛市即墨区环秀街道办事处湘江二路97号甲');
48
- expect(result.return_rate_text).toContain('87%');
49
- expect(result.top_categories).toEqual(['大码女装']);
50
- expect(result.service_badges).toEqual(['延期必赔', '品质保障']);
51
- });
52
- it('builds contact urls and extracts offer ids', () => {
53
- expect(__test__.safeCanonicalStoreUrl('https://yinuoweierfushi.1688.com/page/index.html?spm=foo')).toBe('https://yinuoweierfushi.1688.com');
54
- expect(__test__.buildContactUrl('https://yinuoweierfushi.1688.com')).toBe('https://yinuoweierfushi.1688.com/page/contactinfo.html');
55
- expect(__test__.firstOfferId([
56
- 'https://detail.1688.com/offer/887904326744.html',
57
- ])).toBe('887904326744');
58
- expect(__test__.firstContactUrl([
59
- 'https://yinuoweierfushi.1688.com/page/contactinfo.html?spm=1',
60
- ])).toBe('https://yinuoweierfushi.1688.com/page/contactinfo.html');
61
- });
62
- });
@@ -1,46 +0,0 @@
1
- import { describe, expect, it, vi } from 'vitest';
2
- import { getRegistry } from '@sovovs/bycli/registry';
3
- import { CliError } from '@sovovs/bycli/errors';
4
- import './article.js';
5
-
6
- function makePage(evaluateResult) {
7
- return {
8
- installInterceptor: vi.fn().mockResolvedValue(undefined),
9
- goto: vi.fn().mockResolvedValue(undefined),
10
- wait: vi.fn().mockResolvedValue(undefined),
11
- evaluate: vi.fn().mockResolvedValue(evaluateResult),
12
- };
13
- }
14
-
15
- describe('36kr article', () => {
16
- it('emits empty-string for missing optional author / date instead of a sentinel', async () => {
17
- const command = getRegistry().get('36kr/article');
18
- expect(command?.func).toBeDefined();
19
- const page = makePage({ title: 'Real Title', author: '', date: '', body: 'Real article body' });
20
- const rows = await command.func(page, { id: '1234567' });
21
- const byField = Object.fromEntries(rows.map((r) => [r.field, r.value]));
22
- expect(byField.title).toBe('Real Title');
23
- expect(byField.author).toBe('');
24
- expect(byField.date).toBe('');
25
- expect(byField.body).toBe('Real article body');
26
- expect(byField.url).toBe('https://36kr.com/p/1234567');
27
- });
28
-
29
- it('throws CliError NOT_FOUND when the page exposes no title', async () => {
30
- const command = getRegistry().get('36kr/article');
31
- const page = makePage({ title: '', author: 'x', date: 'y', body: 'z' });
32
- await expect(command.func(page, { id: '1234567' })).rejects.toBeInstanceOf(CliError);
33
- });
34
-
35
- it('throws CliError PARSE_ERROR when the page exposes title but no body', async () => {
36
- const command = getRegistry().get('36kr/article');
37
- const page = makePage({ title: 'Real Title', author: 'x', date: 'y', body: '' });
38
- await expect(command.func(page, { id: '1234567' })).rejects.toMatchObject({ code: 'PARSE_ERROR' });
39
- });
40
-
41
- it('throws CliError INVALID_ARGUMENT when no numeric id can be parsed', async () => {
42
- const command = getRegistry().get('36kr/article');
43
- const page = makePage({});
44
- await expect(command.func(page, { id: 'not-a-url' })).rejects.toBeInstanceOf(CliError);
45
- });
46
- });
@@ -1,15 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { buildHotListUrl, getShanghaiDate } from './hot.js';
3
- describe('36kr/hot date routing', () => {
4
- it('formats dates in Asia/Shanghai instead of UTC', () => {
5
- const date = new Date('2026-03-25T18:30:00.000Z');
6
- expect(getShanghaiDate(date)).toBe('2026-03-26');
7
- });
8
- it('builds dated hot-list routes with Shanghai-local date', () => {
9
- const date = new Date('2026-03-25T18:30:00.000Z');
10
- expect(buildHotListUrl('renqi', date)).toBe('https://www.36kr.com/hot-list/renqi/2026-03-26/1');
11
- });
12
- it('keeps catalog on the static route', () => {
13
- expect(buildHotListUrl('catalog')).toBe('https://www.36kr.com/hot-list/catalog');
14
- });
15
- });
@@ -1,85 +0,0 @@
1
- import { describe, it, expect, vi, afterEach } from 'vitest';
2
- const SAMPLE_RSS = `<?xml version="1.0" encoding="UTF-8"?>
3
- <rss version="2.0"><channel><title>36氪</title>
4
- <item>
5
- <title>红杉中国领投AI公司「示例」,金额近2亿元</title>
6
- <link><![CDATA[https://36kr.com/p/1111111111111111?f=rss]]></link>
7
- <pubDate>2026-03-26 10:00:00 +0800</pubDate>
8
- </item>
9
- <item>
10
- <title>马斯克旗下xAI估值突破1000亿美元</title>
11
- <link><![CDATA[https://36kr.com/p/2222222222222222?f=rss]]></link>
12
- <pubDate>2026-03-26 09:00:00 +0800</pubDate>
13
- </item>
14
- <item>
15
- <title>OpenAI发布GPT-5,多模态能力大幅提升</title>
16
- <link><![CDATA[https://36kr.com/p/3333333333333333?f=rss]]></link>
17
- <pubDate>2026-03-25 20:00:00 +0800</pubDate>
18
- </item>
19
- </channel></rss>`;
20
- afterEach(() => {
21
- vi.restoreAllMocks();
22
- });
23
- describe('36kr/news RSS parsing', () => {
24
- it('parses RSS feed into ranked news items', async () => {
25
- vi.spyOn(globalThis, 'fetch').mockResolvedValue({
26
- ok: true,
27
- text: async () => SAMPLE_RSS,
28
- });
29
- // Direct RSS parse test using the same regex logic as news.ts
30
- const xml = SAMPLE_RSS;
31
- const items = [];
32
- const itemRegex = /<item>([\s\S]*?)<\/item>/g;
33
- let match;
34
- while ((match = itemRegex.exec(xml)) && items.length < 10) {
35
- const block = match[1];
36
- const title = block.match(/<title>([\s\S]*?)<\/title>/)?.[1]?.trim() ?? '';
37
- const url = block.match(/<link><!\[CDATA\[(.*?)\]\]>/)?.[1] ??
38
- block.match(/<link>(.*?)<\/link>/)?.[1] ??
39
- '';
40
- const pubDate = block.match(/<pubDate>(.*?)<\/pubDate>/)?.[1]?.trim() ?? '';
41
- const date = pubDate.slice(0, 10);
42
- if (title)
43
- items.push({ rank: items.length + 1, title, date, url: url.trim() });
44
- }
45
- expect(items).toHaveLength(3);
46
- expect(items[0].rank).toBe(1);
47
- expect(items[0].title).toBe('红杉中国领投AI公司「示例」,金额近2亿元');
48
- expect(items[0].date).toBe('2026-03-26');
49
- expect(items[0].url).toBe('https://36kr.com/p/1111111111111111?f=rss');
50
- });
51
- it('respects limit — returns at most N items', async () => {
52
- const xml = SAMPLE_RSS;
53
- const limit = 2;
54
- const items = [];
55
- const itemRegex = /<item>([\s\S]*?)<\/item>/g;
56
- let match;
57
- while ((match = itemRegex.exec(xml)) && items.length < limit) {
58
- const block = match[1];
59
- const title = block.match(/<title>([\s\S]*?)<\/title>/)?.[1]?.trim() ?? '';
60
- const url = block.match(/<link><!\[CDATA\[(.*?)\]\]>/)?.[1] ?? '';
61
- const pubDate = block.match(/<pubDate>(.*?)<\/pubDate>/)?.[1]?.trim() ?? '';
62
- const date = pubDate.slice(0, 10);
63
- if (title)
64
- items.push({ rank: items.length + 1, title, date, url: url.trim() });
65
- }
66
- expect(items).toHaveLength(2);
67
- });
68
- it('skips items with empty title', async () => {
69
- const xml = `<rss><channel>
70
- <item><title></title><link>https://36kr.com/p/0</link><pubDate>2026-01-01</pubDate></item>
71
- <item><title>有标题的文章</title><link>https://36kr.com/p/1</link><pubDate>2026-01-01</pubDate></item>
72
- </channel></rss>`;
73
- const items = [];
74
- const itemRegex = /<item>([\s\S]*?)<\/item>/g;
75
- let match;
76
- while ((match = itemRegex.exec(xml))) {
77
- const block = match[1];
78
- const title = block.match(/<title>([\s\S]*?)<\/title>/)?.[1]?.trim() ?? '';
79
- if (title)
80
- items.push({ title });
81
- }
82
- expect(items).toHaveLength(1);
83
- expect(items[0].title).toBe('有标题的文章');
84
- });
85
- });
@@ -1,69 +0,0 @@
1
- import { describe, expect, it, vi } from 'vitest';
2
- import { CliError } from '@sovovs/bycli/errors';
3
- import { parseCompanyJobCard, pageFetchJson, resolveCity } from './utils.js';
4
-
5
- describe('51job resolveCity', () => {
6
- it('maps known city names and explicit national scope', () => {
7
- expect(resolveCity('杭州')).toBe('080200');
8
- expect(resolveCity('all')).toBe('000000');
9
- expect(resolveCity('000000')).toBe('000000');
10
- });
11
-
12
- it('rejects unknown non-empty inputs instead of silently widening to 全国', () => {
13
- expect(() => resolveCity('杭州z')).toThrowError(CliError);
14
- expect(() => resolveCity('杭州z')).toThrow(/Unknown city\/area/);
15
- });
16
- });
17
-
18
- describe('51job pageFetchJson', () => {
19
- it('detects WAF challenge HTML and throws ANTI_BOT', async () => {
20
- const page = {
21
- evaluate: vi.fn().mockResolvedValue({
22
- ok: true,
23
- status: 200,
24
- text: '<html><title>slider</title></html>',
25
- }),
26
- };
27
-
28
- await expect(pageFetchJson(page, 'https://we.51job.com/api/job/search-pc')).rejects.toMatchObject({
29
- code: 'ANTI_BOT',
30
- });
31
- });
32
- });
33
-
34
- describe('51job parseCompanyJobCard', () => {
35
- it('parses sensorsdata JSON into a stable row fragment', () => {
36
- const row = parseCompanyJobCard({
37
- href: 'https://jobs.51job.com/shanghai/123456789.html',
38
- sensorsdata: JSON.stringify({
39
- jobId: '123456789',
40
- jobTitle: 'Senior Engineer',
41
- jobSalary: '20-30K',
42
- jobArea: '上海',
43
- jobYear: '3-5年',
44
- jobDegree: '本科',
45
- funcType: '后端开发',
46
- jobTime: '04-22',
47
- }),
48
- });
49
-
50
- expect(row).toEqual({
51
- jobId: '123456789',
52
- title: 'Senior Engineer',
53
- salary: '20-30K',
54
- city: '上海',
55
- workYear: '3-5年',
56
- degree: '本科',
57
- funcType: '后端开发',
58
- issueDate: '04-22',
59
- url: 'https://jobs.51job.com/shanghai/123456789.html',
60
- });
61
- });
62
-
63
- it('returns null on malformed sensorsdata', () => {
64
- expect(parseCompanyJobCard({
65
- href: 'https://jobs.51job.com/shanghai/123456789.html',
66
- sensorsdata: '{bad json}',
67
- })).toBeNull();
68
- });
69
- });
@@ -1,170 +0,0 @@
1
- import { describe, expect, it, afterEach, vi } from 'vitest';
2
- import { __test__ } from './shared.js';
3
- import { CommandExecutionError } from '@sovovs/bycli/errors';
4
-
5
- const ENV_KEYS = [
6
- 'ATLASSIAN_CONFLUENCE_BASE_URL',
7
- 'ATLASSIAN_DEPLOYMENT',
8
- 'ATLASSIAN_EMAIL',
9
- 'ATLASSIAN_API_TOKEN',
10
- 'ATLASSIAN_PAT',
11
- 'ATLASSIAN_JIRA_BASE_URL',
12
- ];
13
-
14
- function clearEnv() {
15
- for (const key of ENV_KEYS) delete process.env[key];
16
- }
17
-
18
- afterEach(() => {
19
- clearEnv();
20
- vi.unstubAllGlobals();
21
- });
22
-
23
- describe('atlassian shared helpers', () => {
24
- it('infers Confluence Cloud and appends /wiki', () => {
25
- clearEnv();
26
- process.env.ATLASSIAN_CONFLUENCE_BASE_URL = 'https://example.atlassian.net';
27
- process.env.ATLASSIAN_EMAIL = 'bot@example.com';
28
- process.env.ATLASSIAN_API_TOKEN = 'secret';
29
- const config = __test__.getConfluenceConfig();
30
- expect(config.deployment).toBe('cloud');
31
- expect(config.baseUrl).toBe('https://example.atlassian.net/wiki');
32
- expect(config.authHeaders.Authorization).toMatch(/^Basic /);
33
- });
34
-
35
- it('uses Data Center PAT as bearer auth', () => {
36
- clearEnv();
37
- process.env.ATLASSIAN_JIRA_BASE_URL = 'https://jira.example.com';
38
- process.env.ATLASSIAN_DEPLOYMENT = 'datacenter';
39
- process.env.ATLASSIAN_PAT = 'pat-123';
40
- const config = __test__.getJiraConfig();
41
- expect(config.deployment).toBe('datacenter');
42
- expect(config.authHeaders.Authorization).toBe('Bearer pat-123');
43
- });
44
-
45
- it('converts Jira ADF to Markdown', () => {
46
- const markdown = __test__.adfToMarkdown({
47
- type: 'doc',
48
- content: [
49
- {
50
- type: 'paragraph',
51
- content: [
52
- { type: 'text', text: 'Broken ', marks: [{ type: 'strong' }] },
53
- { type: 'text', text: 'checkout', marks: [{ type: 'link', attrs: { href: 'https://example.com' } }] },
54
- ],
55
- },
56
- {
57
- type: 'bulletList',
58
- content: [{ type: 'listItem', content: [{ type: 'paragraph', content: [{ type: 'text', text: 'retry payment' }] }] }],
59
- },
60
- ],
61
- });
62
- expect(markdown).toContain('**Broken **');
63
- expect(markdown).toContain('[checkout](https://example.com)');
64
- expect(markdown).toContain('- retry payment');
65
- });
66
-
67
- it('escapes pipe characters inside ADF table cells', () => {
68
- const markdown = __test__.adfToMarkdown({
69
- type: 'doc',
70
- content: [{
71
- type: 'table',
72
- content: [
73
- {
74
- type: 'tableRow',
75
- content: [
76
- { type: 'tableHeader', content: [{ type: 'paragraph', content: [{ type: 'text', text: 'Service' }] }] },
77
- { type: 'tableHeader', content: [{ type: 'paragraph', content: [{ type: 'text', text: 'Notes' }] }] },
78
- ],
79
- },
80
- {
81
- type: 'tableRow',
82
- content: [
83
- { type: 'tableCell', content: [{ type: 'paragraph', content: [{ type: 'text', text: 'payments' }] }] },
84
- { type: 'tableCell', content: [{ type: 'paragraph', content: [{ type: 'text', text: 'a | b' }] }] },
85
- ],
86
- },
87
- ],
88
- }],
89
- });
90
- expect(markdown).toContain('Service | Notes');
91
- expect(markdown).toContain('--- | ---');
92
- expect(markdown).toContain('payments | a \\| b');
93
- });
94
-
95
- it('converts nested HTML to Markdown through the shared Turndown converter', () => {
96
- const markdown = __test__.htmlToMarkdown('<ul><li><strong>Root</strong><ul><li>Child</li></ul></li></ul><table><tr><th>A</th></tr><tr><td>B</td></tr></table>');
97
- expect(markdown).toContain('**Root**');
98
- expect(markdown).toContain('Child');
99
- expect(markdown).toContain('A');
100
- expect(markdown).toContain('B');
101
- });
102
-
103
- it('converts Markdown to conservative Confluence storage XHTML', () => {
104
- const storage = __test__.markdownToConfluenceStorage([
105
- '# RCA',
106
- '',
107
- '- Impacted checkout',
108
- '',
109
- '| Service | Status |',
110
- '| --- | --- |',
111
- '| payments | fixed |',
112
- ].join('\n'));
113
- expect(storage).toContain('<h1>RCA</h1>');
114
- expect(storage).toContain('<ul>');
115
- expect(storage).toContain('<table>');
116
- expect(storage).toContain('<td>fixed</td>');
117
- });
118
-
119
- it('preserves nested Markdown lists in Confluence storage XHTML', () => {
120
- const storage = __test__.markdownToConfluenceStorage([
121
- '- Parent',
122
- ' - Child',
123
- '- Next',
124
- ].join('\n'));
125
- const compact = storage.replace(/\s*\n\s*/g, '');
126
- expect(compact).toContain('<ul><li>Parent<ul><li>Child</li></ul></li><li>Next</li></ul>');
127
- });
128
-
129
- it('sends JSON requests with configured auth headers', async () => {
130
- const fetchMock = vi.fn(async () => new Response(JSON.stringify({ ok: true }), { status: 200 }));
131
- vi.stubGlobal('fetch', fetchMock);
132
- const data = await __test__.atlassianRequest({
133
- product: 'jira',
134
- baseUrl: 'https://jira.example.com',
135
- deployment: 'datacenter',
136
- authHeaders: { Authorization: 'Bearer token' },
137
- }, '/rest/api/2/myself', { label: 'jira myself' });
138
- expect(data).toEqual({ ok: true });
139
- expect(fetchMock.mock.calls[0][0]).toBe('https://jira.example.com/rest/api/2/myself');
140
- expect(fetchMock.mock.calls[0][1].headers.Authorization).toBe('Bearer token');
141
- });
142
-
143
- it('maps auth and rate-limit responses to typed errors', async () => {
144
- vi.stubGlobal('fetch', vi.fn(async () => new Response(JSON.stringify({ message: 'bad token' }), { status: 401 })));
145
- await expect(__test__.atlassianRequest({
146
- product: 'jira',
147
- baseUrl: 'https://jira.example.com',
148
- deployment: 'datacenter',
149
- authHeaders: { Authorization: 'Bearer token' },
150
- }, '/rest/api/2/myself', { label: 'jira myself' })).rejects.toMatchObject({ code: 'AUTH_REQUIRED' });
151
-
152
- vi.stubGlobal('fetch', vi.fn(async () => new Response(JSON.stringify({ message: 'slow down' }), { status: 429 })));
153
- await expect(__test__.atlassianRequest({
154
- product: 'jira',
155
- baseUrl: 'https://jira.example.com',
156
- deployment: 'datacenter',
157
- authHeaders: { Authorization: 'Bearer token' },
158
- }, '/rest/api/2/myself', { label: 'jira myself' })).rejects.toMatchObject({ code: 'COMMAND_EXEC' });
159
- });
160
-
161
- it('fails typed when a successful Atlassian REST response is not JSON', async () => {
162
- vi.stubGlobal('fetch', vi.fn(async () => new Response('<html>login</html>', { status: 200, headers: { 'content-type': 'text/html' } })));
163
- await expect(__test__.atlassianRequest({
164
- product: 'jira',
165
- baseUrl: 'https://jira.example.com',
166
- deployment: 'datacenter',
167
- authHeaders: { Authorization: 'Bearer token' },
168
- }, '/rest/api/2/myself', { label: 'jira myself' })).rejects.toBeInstanceOf(CommandExecutionError);
169
- });
170
- });
@@ -1,59 +0,0 @@
1
- import { JSDOM } from 'jsdom';
2
- import { describe, expect, it, vi } from 'vitest';
3
- import { ArgumentError, CommandExecutionError, EmptyResultError } from '@sovovs/bycli/errors';
4
- import { aibaseNewsCommand, __test__ } from './news.js';
5
-
6
- function runBrowserScript(html, script, url = 'https://www.aibase.com/zh/daily') {
7
- const dom = new JSDOM(html, { url, runScripts: 'outside-only' });
8
- return dom.window.eval(script);
9
- }
10
-
11
- function makePage(evaluateResult) {
12
- return {
13
- goto: vi.fn().mockResolvedValue(undefined),
14
- evaluate: vi.fn().mockResolvedValue(evaluateResult),
15
- };
16
- }
17
-
18
- describe('aibase/news', () => {
19
- it('registers stable URL in columns', () => {
20
- expect(aibaseNewsCommand.access).toBe('read');
21
- expect(aibaseNewsCommand.columns).toEqual(['rank', 'title', 'url']);
22
- });
23
-
24
- it('validates limit before browser navigation', async () => {
25
- const page = makePage({ ok: true, rows: [] });
26
- await expect(aibaseNewsCommand.func(page, { limit: 0 })).rejects.toBeInstanceOf(ArgumentError);
27
- await expect(aibaseNewsCommand.func(page, { limit: 51 })).rejects.toBeInstanceOf(ArgumentError);
28
- expect(page.goto).not.toHaveBeenCalled();
29
- });
30
-
31
- it('extracts and deduplicates AIbase daily rows', async () => {
32
- const html = `
33
- <div class="bg-white">
34
- <div class="grid">
35
- <a href="/zh/daily/123"> First AI daily item </a>
36
- <a href="/zh/daily/123"> First AI daily item duplicate </a>
37
- <a href="/zh/daily/456"> Second AI daily item </a>
38
- </div>
39
- </div>
40
- `;
41
- const payload = runBrowserScript(html, __test__.buildExtractAibaseNewsJs());
42
- const page = makePage(payload);
43
-
44
- const rows = await aibaseNewsCommand.func(page, { limit: 2 });
45
-
46
- expect(page.goto).toHaveBeenCalledWith('https://www.aibase.com/zh/daily', { waitUntil: 'load', settleMs: 3000 });
47
- expect(rows).toEqual([
48
- { rank: 1, title: 'First AI daily item', url: 'https://www.aibase.com/zh/daily/123' },
49
- { rank: 2, title: 'Second AI daily item', url: 'https://www.aibase.com/zh/daily/456' },
50
- ]);
51
- });
52
-
53
- it('maps selector drift and empty rows to typed errors', async () => {
54
- await expect(aibaseNewsCommand.func(makePage({ ok: false, reason: 'selector-missing' }), { limit: 1 }))
55
- .rejects.toBeInstanceOf(CommandExecutionError);
56
- await expect(aibaseNewsCommand.func(makePage({ ok: true, rows: [{ title: '', url: '' }] }), { limit: 1 }))
57
- .rejects.toBeInstanceOf(EmptyResultError);
58
- });
59
- });
@@ -1,29 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { __test__ } from './rankings.js';
3
- describe('amazon bestsellers normalization', () => {
4
- it('normalizes bestseller cards and infers review counts from card text', () => {
5
- const result = __test__.normalizeRankingCandidate({
6
- asin: 'B0DR31GC3D',
7
- title: '',
8
- href: 'https://www.amazon.com/NUTIKAS-Shelves-Desktop-Orgnizer-Shlef/dp/B0DR31GC3D/ref=zg_bs',
9
- price_text: '$25.92',
10
- rating_text: '4.3 out of 5 stars',
11
- review_count_text: '',
12
- card_text: 'Desk Shelves Desktop Organizer Shlef\n4.3 out of 5 stars\n435\n$25.92',
13
- }, {
14
- listType: 'bestsellers',
15
- rankFallback: 2,
16
- listTitle: 'Amazon Best Sellers: Best Desktop & Off-Surface Shelves',
17
- sourceUrl: 'https://www.amazon.com/example',
18
- categoryTitle: null,
19
- categoryUrl: 'https://www.amazon.com/example',
20
- categoryPath: [],
21
- visibleCategoryLinks: [],
22
- });
23
- expect(result.rank).toBe(2);
24
- expect(result.asin).toBe('B0DR31GC3D');
25
- expect(result.title).toBe('Desk Shelves Desktop Organizer Shlef');
26
- expect(result.review_count).toBe(435);
27
- expect(result.list_title).toBe('Amazon Best Sellers: Best Desktop & Off-Surface Shelves');
28
- });
29
- });
@@ -1,124 +0,0 @@
1
- import { describe, expect, it, vi } from 'vitest';
2
- import { AuthRequiredError } from '@sovovs/bycli/errors';
3
- import { getRegistry } from '@sovovs/bycli/registry';
4
- import { __test__ } from './discussion.js';
5
- import './discussion.js';
6
- import { createPageMock } from '../test-utils.js';
7
-
8
-
9
- describe('amazon discussion normalization', () => {
10
- it('normalizes review summary and sample reviews', () => {
11
- const result = __test__.normalizeDiscussionPayload({
12
- href: 'https://www.amazon.com/product-reviews/B0FJS72893',
13
- average_rating_text: '3.9 out of 5',
14
- total_review_count_text: '27 global ratings',
15
- qa_links: [],
16
- review_samples: [
17
- {
18
- title: '5.0 out of 5 stars Great value and quality',
19
- rating_text: '5.0 out of 5 stars',
20
- author: 'GTreader2',
21
- date_text: 'Reviewed in the United States on February 21, 2026',
22
- body: 'Small but mighty.',
23
- verified: true,
24
- },
25
- ],
26
- });
27
-
28
- expect(result.asin).toBe('B0FJS72893');
29
- expect(result.average_rating_value).toBe(3.9);
30
- expect(result.total_review_count).toBe(27);
31
- expect(result.review_samples).toEqual([
32
- {
33
- title: 'Great value and quality',
34
- rating_text: '5.0 out of 5 stars',
35
- rating_value: 5,
36
- author: 'GTreader2',
37
- date_text: 'Reviewed in the United States on February 21, 2026',
38
- body: 'Small but mighty.',
39
- verified_purchase: true,
40
- },
41
- ]);
42
- });
43
-
44
- it('falls back to the product page when the review page redirects to sign-in', async () => {
45
- const command = getRegistry().get('amazon/discussion');
46
- const page = createPageMock([
47
- {
48
- href: 'https://www.amazon.com/ap/signin?openid.return_to=https%3A%2F%2Fwww.amazon.com%2Fproduct-reviews%2FB09HKN2ZRT',
49
- title: 'Amazon Sign-In',
50
- body_text: 'Sign in Create account',
51
- },
52
- {
53
- href: 'https://www.amazon.com/ap/signin?openid.return_to=https%3A%2F%2Fwww.amazon.com%2Fproduct-reviews%2FB09HKN2ZRT',
54
- average_rating_text: '',
55
- total_review_count_text: '',
56
- review_samples: [],
57
- },
58
- {
59
- href: 'https://www.amazon.com/dp/B09HKN2ZRT',
60
- title: 'Amazon.com: Example product',
61
- body_text: 'Hello, zejia-wu Reviews',
62
- },
63
- {
64
- href: 'https://www.amazon.com/dp/B09HKN2ZRT',
65
- average_rating_text: '4.4 out of 5',
66
- total_review_count_text: '349 global ratings',
67
- review_samples: [
68
- {
69
- title: '5.0 out of 5 stars Perfect for the office',
70
- rating_text: '5.0 out of 5 stars',
71
- author: 'Ken',
72
- date_text: 'Reviewed in the United States on March 19, 2026',
73
- body: 'Good for the office, no complaints.',
74
- verified: true,
75
- },
76
- ],
77
- },
78
- ]);
79
-
80
- const result = await command.func(page, { input: 'B09HKN2ZRT', limit: 1 });
81
-
82
- expect(page.goto.mock.calls.map((call) => call[0])).toEqual([
83
- 'https://www.amazon.com/product-reviews/B09HKN2ZRT',
84
- 'https://www.amazon.com/dp/B09HKN2ZRT',
85
- ]);
86
- expect(result).toEqual([
87
- expect.objectContaining({
88
- asin: 'B09HKN2ZRT',
89
- discussion_url: 'https://www.amazon.com/dp/B09HKN2ZRT',
90
- average_rating_value: 4.4,
91
- total_review_count: 349,
92
- }),
93
- ]);
94
- });
95
-
96
- it('throws AuthRequiredError when both review and product pages are gated', async () => {
97
- const command = getRegistry().get('amazon/discussion');
98
- const authState = {
99
- href: 'https://www.amazon.com/ap/signin?openid.return_to=https%3A%2F%2Fwww.amazon.com%2Fproduct-reviews%2FB09HKN2ZRT',
100
- title: 'Amazon Sign-In',
101
- body_text: 'Sign in Create account',
102
- };
103
- const page = createPageMock([
104
- authState,
105
- {
106
- href: authState.href,
107
- average_rating_text: '',
108
- total_review_count_text: '',
109
- review_samples: [],
110
- },
111
- authState,
112
- ]);
113
-
114
- await expect(command.func(page, { input: 'B09HKN2ZRT', limit: 1 })).rejects.toBeInstanceOf(AuthRequiredError);
115
- });
116
-
117
- it('does not treat a public product page with sign-in copy as a gated page', () => {
118
- expect(__test__.isSignInState({
119
- href: 'https://www.amazon.com/dp/B09HKN2ZRT',
120
- title: 'Amazon.com: Example product',
121
- body_text: 'Hello, sign in Account & Lists Create account',
122
- })).toBe(false);
123
- });
124
- });