@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
@@ -0,0 +1,59 @@
1
+ import { createServer } from 'node:http';
2
+ import { type WrapperConfig } from './wrapper-config.js';
3
+ import { WrapperRegistry } from './wrapper-registry.js';
4
+ import { type Metrics } from './wrapper-metrics.js';
5
+ import { type AnalyzeRunner } from './analyze-runner.js';
6
+ import { createAdapterDraft } from '../highlevel/init.js';
7
+ import { type RunnerPortWithLifecycle } from '../runner/runner-port.js';
8
+ /** 结构化日志允许字段(09;forbidden=token/body/seed 类型上就进不来)。 */
9
+ interface LogFields {
10
+ status: string;
11
+ errorCode?: string;
12
+ durationMs?: number;
13
+ requestId?: string;
14
+ }
15
+ export interface WrapperDeps {
16
+ /** 注入时钟(测试 TTL)。 */
17
+ now?: () => number;
18
+ /** 注入 init 实现(测试无需写盘)。默认真实 createAdapterDraft。 */
19
+ createDraft?: typeof createAdapterDraft;
20
+ /** 结构化日志 sink(默认 stderr 单行 JSON)。 */
21
+ logSink?: (line: string) => void;
22
+ /** 注入 metrics(测试断言)。默认 createMetrics()。 */
23
+ metrics?: Metrics;
24
+ /** 注入 verify runner(测试 fake;production = defaultRunnerPort,连回 daemon 拿 Page 跑 browser adapter)。 */
25
+ runner?: RunnerPortWithLifecycle;
26
+ /** 注入 sessionId→HMAC key(测试)。默认进程级 defaultSessionKeyRegistry。 */
27
+ sessionKeyFor?: (sessionId?: string) => string;
28
+ /** 注入 analyze runner(测试 fake;production = daemon-backed Page)。 */
29
+ analyzeRunner?: AnalyzeRunner;
30
+ }
31
+ export interface WrapperCtx {
32
+ cfg: WrapperConfig;
33
+ registry: WrapperRegistry;
34
+ createDraft: typeof createAdapterDraft;
35
+ runner: RunnerPortWithLifecycle;
36
+ sessionKeyFor?: (sessionId?: string) => string;
37
+ analyzeRunner: AnalyzeRunner;
38
+ /** 在飞后台作业(analyze in-process Page);shutdown drain 用(Codex M9 Med)。 */
39
+ inflight: Set<Promise<unknown>>;
40
+ log: (operation: string, fields: LogFields) => void;
41
+ metrics: Metrics;
42
+ }
43
+ /** Shutdown 时等在飞作业跑完(其 finally 释放 Page lease),最多 graceMs;超时则放弃(lease 靠 daemon
44
+ * idle-expire 兜底)。返回时 inflight 要么空、要么已超 grace。 */
45
+ export declare function drainInflight(inflight: Set<Promise<unknown>>, graceMs: number): Promise<void>;
46
+ /**
47
+ * 装配 wrapper app(工厂 + 可注入 deps 供测试)。返回 { server, ctx };调用方负责 server.listen。
48
+ */
49
+ export declare function createWrapperApp(cfg: WrapperConfig, deps?: WrapperDeps): {
50
+ server: ReturnType<typeof createServer>;
51
+ ctx: WrapperCtx;
52
+ };
53
+ /**
54
+ * `bycli internal highlevel-http` 入口:load config → 装配 → bind 127.0.0.1。默认关闭(opt-in)。
55
+ * 绝不打印 token(只打印 listening 行)。**在 server 存活期间不 resolve**(等 'close'),这样 main.ts
56
+ * 的 `await runWrapperCli()` 会一直挂起、绝不 fall-through 到完整 CLI discovery。
57
+ */
58
+ export declare function runWrapperCli(): Promise<void>;
59
+ export {};
@@ -0,0 +1,240 @@
1
+ // M9 High-Level HTTP wrapper —— 独立 loopback HTTP server(07 · Optional HTTP Wrapper)。
2
+ // 形态镜像 dashboard-be/src/server.ts 的 createApp/createServer/finish-logger,但**主仓侧**(直调
3
+ // high-level 模块,不经 daemon bridge,不 import be)。与 daemon 的 /v1/*(daemon-high-level.v1)是
4
+ // 独立 server / 独立路由族(ADR-0007,严禁混淆)。默认关闭,经 `bycli internal highlevel-http` 启动。
5
+ import { createServer } from 'node:http';
6
+ import { loadWrapperConfig } from './wrapper-config.js';
7
+ import { WrapperRegistry } from './wrapper-registry.js';
8
+ import { checkWrapperGates } from './wrapper-gates.js';
9
+ import { errorBody } from './wrapper-envelope.js';
10
+ import { handleHealth, handleInit, handleVerify, handleAnalyze, handleRequestStatus, } from './handlers.js';
11
+ import { createMetrics } from './wrapper-metrics.js';
12
+ import { createAnalyzeRunner } from './analyze-runner.js';
13
+ import { createAdapterDraft } from '../highlevel/init.js';
14
+ import { defaultRunnerPort, setDefaultRunnerDaemonPort, } from '../runner/runner-port.js';
15
+ /** Shutdown 时等在飞作业跑完(其 finally 释放 Page lease),最多 graceMs;超时则放弃(lease 靠 daemon
16
+ * idle-expire 兜底)。返回时 inflight 要么空、要么已超 grace。 */
17
+ export async function drainInflight(inflight, graceMs) {
18
+ if (inflight.size === 0)
19
+ return;
20
+ let timer;
21
+ const deadline = new Promise((r) => { timer = setTimeout(r, graceMs); });
22
+ try {
23
+ await Promise.race([Promise.allSettled([...inflight]).then(() => undefined), deadline]);
24
+ }
25
+ finally {
26
+ if (timer)
27
+ clearTimeout(timer);
28
+ }
29
+ }
30
+ const REQUESTS_PREFIX = '/v1/requests/';
31
+ /** Shutdown 时等在飞 analyze 释放 Page lease 的最长宽限(Codex M9 Med)。 */
32
+ const SHUTDOWN_GRACE_MS = 5000;
33
+ function sendOutcome(res, outcome) {
34
+ if (outcome.errorCode)
35
+ res.__errorCode = outcome.errorCode;
36
+ const payload = JSON.stringify(outcome.body);
37
+ // 04 章:不回 CORS 头(no-CORS);nosniff。
38
+ res.writeHead(outcome.status, { 'Content-Type': 'application/json', 'X-Content-Type-Options': 'nosniff' });
39
+ res.end(payload);
40
+ }
41
+ async function readJson(req, maxBytes) {
42
+ const chunks = [];
43
+ let size = 0;
44
+ for await (const c of req) {
45
+ size += c.length;
46
+ if (size > maxBytes)
47
+ throw new Error('payload too large');
48
+ chunks.push(c);
49
+ }
50
+ if (!chunks.length)
51
+ return {};
52
+ return JSON.parse(Buffer.concat(chunks).toString('utf8'));
53
+ }
54
+ function clampWaitMs(raw, max) {
55
+ if (!raw)
56
+ return 0;
57
+ const n = Number(raw);
58
+ if (!Number.isFinite(n) || n <= 0)
59
+ return 0;
60
+ return Math.min(Math.floor(n), max);
61
+ }
62
+ /** 路由分发:gate(全端点)→ 已注册端点;未匹配 404。 */
63
+ async function route(ctx, req, res) {
64
+ const url = new URL(req.url ?? '/', 'http://127.0.0.1');
65
+ const pathname = url.pathname;
66
+ const method = req.method ?? 'GET';
67
+ // 门禁:所有端点(含 /health)统一过 X-byCLI + Origin + token。
68
+ const gate = checkWrapperGates(req, { allowedOrigins: ctx.cfg.ALLOWED_ORIGINS, token: ctx.cfg.TOKEN });
69
+ if (!gate.ok) {
70
+ sendOutcome(res, {
71
+ status: 403,
72
+ body: { error: errorBody(gate.code ?? 'auth_failed', gate.message ?? 'forbidden') },
73
+ errorCode: gate.code ?? 'auth_failed',
74
+ });
75
+ return;
76
+ }
77
+ if (method === 'GET' && pathname === '/health') {
78
+ sendOutcome(res, handleHealth());
79
+ return;
80
+ }
81
+ // GET /metrics —— loopback metrics scrape(09 · M8 复审遗留,gated 同其它端点)。返回 snapshot JSON
82
+ // (counters/histograms,标签只非敏感 enum)。不入 finish-logger 计数(避免 scrape 自计/噪声)。
83
+ if (method === 'GET' && pathname === '/metrics') {
84
+ sendOutcome(res, { status: 200, body: ctx.metrics.snapshot() });
85
+ return;
86
+ }
87
+ if (method === 'POST' && pathname === '/v1/adapters/init') {
88
+ let body;
89
+ try {
90
+ body = await readJson(req, ctx.cfg.BODY_LIMIT_BYTES);
91
+ }
92
+ catch {
93
+ sendOutcome(res, {
94
+ status: 400,
95
+ body: { error: errorBody('validation_failed', 'request body too large or invalid JSON') },
96
+ errorCode: 'validation_failed',
97
+ });
98
+ return;
99
+ }
100
+ sendOutcome(res, handleInit(ctx, body));
101
+ return;
102
+ }
103
+ if (method === 'POST' && pathname === '/v1/adapters/verify') {
104
+ let body;
105
+ try {
106
+ body = await readJson(req, ctx.cfg.BODY_LIMIT_BYTES);
107
+ }
108
+ catch {
109
+ sendOutcome(res, {
110
+ status: 400,
111
+ body: { error: errorBody('validation_failed', 'request body too large or invalid JSON') },
112
+ errorCode: 'validation_failed',
113
+ });
114
+ return;
115
+ }
116
+ sendOutcome(res, await handleVerify(ctx, body));
117
+ return;
118
+ }
119
+ if (method === 'POST' && pathname === '/v1/browser/analyze') {
120
+ let body;
121
+ try {
122
+ body = await readJson(req, ctx.cfg.BODY_LIMIT_BYTES);
123
+ }
124
+ catch {
125
+ sendOutcome(res, {
126
+ status: 400,
127
+ body: { error: errorBody('validation_failed', 'request body too large or invalid JSON') },
128
+ errorCode: 'validation_failed',
129
+ });
130
+ return;
131
+ }
132
+ sendOutcome(res, handleAnalyze(ctx, body));
133
+ return;
134
+ }
135
+ if (method === 'GET' && pathname.startsWith(REQUESTS_PREFIX)) {
136
+ const requestId = pathname.slice(REQUESTS_PREFIX.length);
137
+ const waitMs = clampWaitMs(url.searchParams.get('waitMs'), ctx.cfg.REQUEST_WAIT_MS_MAX);
138
+ sendOutcome(res, await handleRequestStatus(ctx, requestId, waitMs));
139
+ return;
140
+ }
141
+ // 未注册路由(含 M9b/c 待接的 verify/analyze)→ 404。
142
+ sendOutcome(res, { status: 404, body: { error: { code: 'request_not_found', message: 'not found' } } });
143
+ }
144
+ /**
145
+ * 装配 wrapper app(工厂 + 可注入 deps 供测试)。返回 { server, ctx };调用方负责 server.listen。
146
+ */
147
+ export function createWrapperApp(cfg, deps = {}) {
148
+ const logSink = deps.logSink ?? ((line) => process.stderr.write(line + '\n'));
149
+ // production runner = defaultRunnerPort();browser-verify 子进程经 BYCLI_DAEMON_PORT 连回 daemon 拿 Page,
150
+ // 故必须在首次 defaultRunnerPort() 前注入 daemon 端口(同 daemon.ts:49)。测试注入 deps.runner 绕开全局单例。
151
+ if (!deps.runner)
152
+ setDefaultRunnerDaemonPort(cfg.DAEMON_PORT);
153
+ const ctx = {
154
+ cfg,
155
+ registry: new WrapperRegistry({
156
+ terminalTtlMs: cfg.REQUEST_TERMINAL_STATUS_TTL_MS,
157
+ pollAfterMs: cfg.REQUEST_POLL_AFTER_MS,
158
+ now: deps.now,
159
+ }),
160
+ createDraft: deps.createDraft ?? createAdapterDraft,
161
+ runner: deps.runner ?? defaultRunnerPort(),
162
+ sessionKeyFor: deps.sessionKeyFor,
163
+ analyzeRunner: deps.analyzeRunner ?? createAnalyzeRunner({ timeoutMs: cfg.ANALYZE_TIMEOUT_MS }),
164
+ inflight: new Set(),
165
+ log: (operation, fields) => {
166
+ if (cfg.LOG_LEVEL === 'error' && fields.status === 'ok')
167
+ return; // 静音成功日志(error level)
168
+ logSink(JSON.stringify({ time: Date.now(), level: 'info', operation, ...fields }));
169
+ },
170
+ metrics: deps.metrics ?? createMetrics(),
171
+ };
172
+ const server = createServer((req, res) => {
173
+ // 单点 finish-logger + metrics(09 Structured Logging/Metrics):operation + outcome + latency。只
174
+ // path/method/status/errorCode/durationMs —— 永不含 header/token/body/seed。
175
+ const started = Date.now();
176
+ res.on('finish', () => {
177
+ const path = (req.url ?? '/').split('?')[0] ?? '/';
178
+ if (path === '/metrics')
179
+ return; // 不给 /metrics scrape 自计/记日志
180
+ // 把唯一动态段(GET /v1/requests/{id})collapse 成稳定模板,operation 基数有界。
181
+ const operation = path.startsWith(REQUESTS_PREFIX)
182
+ ? 'highlevel.requests'
183
+ : `highlevel.${path.replace(/^\/+/, '').replace(/\//g, '.') || 'root'}`;
184
+ const status = res.statusCode < 400 ? 'ok' : 'failed';
185
+ const errorCode = res.__errorCode;
186
+ const durationMs = Date.now() - started;
187
+ ctx.log(operation, { status, errorCode, durationMs });
188
+ ctx.metrics.inc('highlevel_requests_total', { operation, status, errorCode });
189
+ ctx.metrics.observe('highlevel_request_duration_ms', durationMs);
190
+ });
191
+ route(ctx, req, res).catch(() => {
192
+ if (!res.headersSent) {
193
+ sendOutcome(res, {
194
+ status: 500,
195
+ body: { error: errorBody('network_error', 'internal error') },
196
+ errorCode: 'network_error',
197
+ });
198
+ }
199
+ });
200
+ });
201
+ // 周期 sweep:回收已过 TTL 的终态记录(getRecord 只在访问时删,abandoned 终态否则常驻内存)。
202
+ // 间隔绑 TTL(Codex M9 Low:固定 5min 对 1min TTL 会多滞留 ~4min)——取 min(5min, max(30s, TTL/2))。
203
+ // unref → 不吊住进程;server 'close' 清掉(测试关 server 即停 timer,不泄漏)。
204
+ const sweepMs = Math.min(300_000, Math.max(30_000, Math.floor(cfg.REQUEST_TERMINAL_STATUS_TTL_MS / 2)));
205
+ const sweepTimer = setInterval(() => ctx.registry.sweepExpired(), sweepMs);
206
+ sweepTimer.unref?.();
207
+ server.on('close', () => clearInterval(sweepTimer));
208
+ return { server, ctx };
209
+ }
210
+ /**
211
+ * `bycli internal highlevel-http` 入口:load config → 装配 → bind 127.0.0.1。默认关闭(opt-in)。
212
+ * 绝不打印 token(只打印 listening 行)。**在 server 存活期间不 resolve**(等 'close'),这样 main.ts
213
+ * 的 `await runWrapperCli()` 会一直挂起、绝不 fall-through 到完整 CLI discovery。
214
+ */
215
+ export async function runWrapperCli() {
216
+ const cfg = loadWrapperConfig();
217
+ // analyze 的 daemon-backed Page 经 daemon-client(模块加载时读 process.env.BYCLI_DAEMON_PORT)连回 daemon;
218
+ // 显式钉到 cfg.DAEMON_PORT,保证 Page 连的是 wrapper 配置的同一 daemon(Page 在首次 analyze 才懒加载)。
219
+ process.env.BYCLI_DAEMON_PORT = String(cfg.DAEMON_PORT);
220
+ const { server, ctx } = createWrapperApp(cfg);
221
+ // 在 server 存活期间不 resolve(阻止 main.ts fall-through);仅在 SIGTERM/SIGINT 优雅关闭后 resolve。
222
+ await new Promise((resolve, reject) => {
223
+ let closing = false;
224
+ const shutdown = () => {
225
+ if (closing)
226
+ return;
227
+ closing = true;
228
+ server.close(); // 停止接新连接
229
+ // 先 drain 在飞 analyze(其 finally closeWindow 释放 daemon Page lease),最多 SHUTDOWN_GRACE_MS,
230
+ // 再 resolve → main.ts process.exit;不再被硬切(Codex M9 Med)。超 grace 则放弃,靠 lease idle-expire。
231
+ void drainInflight(ctx.inflight, SHUTDOWN_GRACE_MS).finally(() => resolve());
232
+ };
233
+ server.once('error', reject);
234
+ process.once('SIGTERM', shutdown);
235
+ process.once('SIGINT', shutdown);
236
+ server.listen(cfg.PORT, cfg.HOST, () => {
237
+ process.stderr.write(JSON.stringify({ time: Date.now(), level: 'info', operation: 'highlevel.listening', status: 'ok', port: cfg.PORT }) + '\n');
238
+ });
239
+ });
240
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ import { type Logger, type LogLevel } from '@sovovs/bycli-recorder-core';
2
+ export type { Logger, LogLevel } from '@sovovs/bycli-recorder-core';
3
+ export type { LogFields } from '@sovovs/bycli-recorder-core';
4
+ /** daemon/runner structured logger: single-line JSON to stderr. Inject `sink` in tests. */
5
+ export declare function createRecorderLogger(level: LogLevel, sink?: (line: string) => void): Logger;
@@ -0,0 +1,13 @@
1
+ // Structured logger for the daemon/runner recording path (#1a · 09 Structured Logging).
2
+ //
3
+ // The main repo keeps TWO loggers on purpose: `src/logger.ts` (human-facing emoji singleton,
4
+ // 17 CLI consumers, unchanged) and THIS one — single-line JSON for the daemon/runner SERVICE path,
5
+ // whose output goes to a detached process's stderr captured to daemon logs, never to an interactive
6
+ // user. The formatter + by-construction redaction (LogFields = only 09 allowed fields) live in
7
+ // recorder-core; this thin factory supplies the stderr sink that core deliberately omits to stay
8
+ // IO-free. Reuses the exact same engine as dashboard-be's logger so daemon/be log shapes match.
9
+ import { createLogger as createCoreLogger } from '@sovovs/bycli-recorder-core';
10
+ /** daemon/runner structured logger: single-line JSON to stderr. Inject `sink` in tests. */
11
+ export function createRecorderLogger(level, sink = (line) => process.stderr.write(line + '\n')) {
12
+ return createCoreLogger(level, { sink });
13
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Verify-runner config — read VERIFY_RUNNER_* from the environment (09 HighLevelConfig).
3
+ *
4
+ * The static range validation is the pure `validateRunnerConfig` in recorder-core (no
5
+ * process.env access, unit-tested there). This thin wrapper reads the env keys and applies
6
+ * the one env-side rule the pure layer can't: clamp `maxConcurrency` to the CPU count
7
+ * (09: "int, 1-CPU count"). A range error is surfaced as a thrown ConfigError (fail closed,
8
+ * 08: unsupported config fails before launch).
9
+ */
10
+ import { type RunnerConfig, type TempCapacity } from '@sovovs/bycli-recorder-core';
11
+ /**
12
+ * Resolve the verify-runner config from `env` (defaults to process.env). Missing/empty →
13
+ * default; out-of-range/non-integer → ConfigError. `maxConcurrency` is additionally clamped
14
+ * down to the CPU count (never below 1).
15
+ */
16
+ export declare function resolveRunnerConfig(env?: NodeJS.ProcessEnv): RunnerConfig;
17
+ /**
18
+ * Temp-store reap policy (M7b · 09:27-29 RecorderConfig). Read on the daemon side (the process
19
+ * that owns verify temp dirs) to drive startup reap + the periodic TTL sweep.
20
+ */
21
+ export interface TempPolicy {
22
+ /** Periodic sweep threshold: a temp dir older than this is a leak (09: default 1h). */
23
+ tempTtlMs: number;
24
+ /** Startup reap age backstop: clean dirs older than this regardless of owner (09: default 24h). */
25
+ startupReapMaxAgeMs: number;
26
+ /** SIGTERM→SIGKILL grace when terminating a reaped child (09: default 1500ms). */
27
+ orphanKillGraceMs: number;
28
+ }
29
+ export declare function resolveTempCapacity(env?: NodeJS.ProcessEnv): TempCapacity;
30
+ /**
31
+ * Resolve the temp-store reap policy from `env` (defaults to process.env). Missing/empty → default;
32
+ * out-of-range / non-integer → ConfigError (fail closed, consistent with resolveRunnerConfig).
33
+ */
34
+ export declare function resolveTempPolicy(env?: NodeJS.ProcessEnv): TempPolicy;
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Verify-runner config — read VERIFY_RUNNER_* from the environment (09 HighLevelConfig).
3
+ *
4
+ * The static range validation is the pure `validateRunnerConfig` in recorder-core (no
5
+ * process.env access, unit-tested there). This thin wrapper reads the env keys and applies
6
+ * the one env-side rule the pure layer can't: clamp `maxConcurrency` to the CPU count
7
+ * (09: "int, 1-CPU count"). A range error is surfaced as a thrown ConfigError (fail closed,
8
+ * 08: unsupported config fails before launch).
9
+ */
10
+ import * as os from 'node:os';
11
+ import { validateRunnerConfig, validateTempCapacity } from '@sovovs/bycli-recorder-core';
12
+ import { ConfigError } from '../../errors.js';
13
+ const ENV_KEYS = {
14
+ maxConcurrency: 'VERIFY_RUNNER_MAX_CONCURRENCY',
15
+ queueLimit: 'HIGH_LEVEL_QUEUE_LIMIT',
16
+ stdoutLimitBytes: 'VERIFY_RUNNER_STDOUT_LIMIT_BYTES',
17
+ stderrLimitBytes: 'VERIFY_RUNNER_STDERR_LIMIT_BYTES',
18
+ jsonlLineLimit: 'VERIFY_RUNNER_JSONL_LINE_LIMIT',
19
+ timeoutMs: 'VERIFY_RUNNER_TIMEOUT_MS',
20
+ killGraceMs: 'VERIFY_RUNNER_KILL_GRACE_MS',
21
+ };
22
+ /**
23
+ * Resolve the verify-runner config from `env` (defaults to process.env). Missing/empty →
24
+ * default; out-of-range/non-integer → ConfigError. `maxConcurrency` is additionally clamped
25
+ * down to the CPU count (never below 1).
26
+ */
27
+ export function resolveRunnerConfig(env = process.env) {
28
+ const raw = {};
29
+ for (const key of Object.keys(ENV_KEYS)) {
30
+ raw[key] = env[ENV_KEYS[key]];
31
+ }
32
+ const r = validateRunnerConfig(raw);
33
+ if (!r.ok)
34
+ throw new ConfigError(r.reason, 'Fix the VERIFY_RUNNER_* environment variable and retry.');
35
+ const cpus = Math.max(1, os.cpus().length || 1);
36
+ return { ...r.config, maxConcurrency: Math.min(r.config.maxConcurrency, cpus) };
37
+ }
38
+ const TEMP_POLICY_FIELDS = {
39
+ tempTtlMs: { key: 'RECORDER_TEMP_TTL_MS', def: 3_600_000, min: 60_000, max: 86_400_000 },
40
+ startupReapMaxAgeMs: { key: 'RECORDER_STARTUP_REAP_MAX_AGE_MS', def: 86_400_000, min: 60_000, max: 86_400_000 },
41
+ orphanKillGraceMs: { key: 'RECORDER_ORPHAN_KILL_GRACE_MS', def: 1_500, min: 100, max: 30_000 },
42
+ };
43
+ /**
44
+ * Temp-store capacity env keys (#1d · 09:33-36). The pure range/band-order validation is
45
+ * `validateTempCapacity` in recorder-core; this maps env key names → field names (mirroring
46
+ * resolveRunnerConfig) and fail-closes via ConfigError. The temp ROOT is restart-only (09:182):
47
+ * these are read at daemon startup, not hot-reloaded.
48
+ */
49
+ const TEMP_CAPACITY_ENV_KEYS = {
50
+ maxBytes: 'RECORDER_TEMP_MAX_BYTES',
51
+ highWatermarkRatio: 'RECORDER_TEMP_HIGH_WATERMARK_RATIO',
52
+ lowWatermarkRatio: 'RECORDER_TEMP_LOW_WATERMARK_RATIO',
53
+ };
54
+ export function resolveTempCapacity(env = process.env) {
55
+ const raw = {};
56
+ for (const k of Object.keys(TEMP_CAPACITY_ENV_KEYS)) {
57
+ raw[k] = env[TEMP_CAPACITY_ENV_KEYS[k]];
58
+ }
59
+ const r = validateTempCapacity(raw);
60
+ if (!r.ok)
61
+ throw new ConfigError(r.reason, 'Fix the RECORDER_TEMP_* environment variable and retry.');
62
+ return r.capacity;
63
+ }
64
+ /**
65
+ * Resolve the temp-store reap policy from `env` (defaults to process.env). Missing/empty → default;
66
+ * out-of-range / non-integer → ConfigError (fail closed, consistent with resolveRunnerConfig).
67
+ */
68
+ export function resolveTempPolicy(env = process.env) {
69
+ const out = {};
70
+ for (const k of Object.keys(TEMP_POLICY_FIELDS)) {
71
+ const f = TEMP_POLICY_FIELDS[k];
72
+ const raw = env[f.key];
73
+ if (raw === undefined || raw === '') {
74
+ out[k] = f.def;
75
+ continue;
76
+ }
77
+ const n = Number(raw);
78
+ if (!Number.isInteger(n) || n < f.min || n > f.max) {
79
+ throw new ConfigError(`${f.key}=${raw} is out of range [${f.min}, ${f.max}]`, `Fix the ${f.key} environment variable and retry.`);
80
+ }
81
+ out[k] = n;
82
+ }
83
+ return out;
84
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,79 @@
1
+ export interface VerifyMarker {
2
+ requestId: string;
3
+ /** The runner child pid (backfilled into marker.json after spawn). */
4
+ pid: number | null;
5
+ /** The process that spawned the runner (daemon/CLI); stands in for 08's localServiceRunId. */
6
+ ownerPid: number | null;
7
+ startedAt: number;
8
+ tempRoot: string;
9
+ operation: 'verify';
10
+ }
11
+ /** Parse + validate marker.json. Returns null unless it is a well-formed verify marker. */
12
+ export declare function parseVerifyMarker(raw: string): VerifyMarker | null;
13
+ /** Does a live process's command line belong to THIS marker's runner? (pid-reuse guard) */
14
+ export declare function cmdlineMatchesMarker(cmdline: string, marker: VerifyMarker): boolean;
15
+ /** Containment: the dir must sit directly under tmpRoot and carry our prefix. */
16
+ export declare function isReapableTempDir(dir: string, tmpRoot: string): boolean;
17
+ /**
18
+ * True orphan iff the spawning owner is gone. An unknown ownerPid (legacy marker without the
19
+ * field) is treated as live → skipped, so we never kill a run we cannot attribute to a dead owner.
20
+ */
21
+ export declare function isOrphan(marker: VerifyMarker, ownerAlive: boolean): boolean;
22
+ /**
23
+ * Aged-out leak (M7b · RECORDER_TEMP_TTL_MS / RECORDER_STARTUP_REAP_MAX_AGE_MS, 09:27-28):
24
+ * a temp dir older than `maxAgeMs` is reaped regardless of owner liveness. CALLERS MUST pass the
25
+ * floored threshold from `effectiveLeakThresholdMs` (never the raw config) — `maxAgeMs` here is
26
+ * assumed to already exceed the run's hard deadline, so a dir older than it is a definite leak,
27
+ * never a live run. An undatable legacy marker (startedAt<=0) is never aged-out (we cannot
28
+ * attribute its age). maxAgeMs<=0 disables age-based reaping (orphan-only, the pre-M7b behavior).
29
+ */
30
+ export declare function isAgedOut(marker: VerifyMarker, now: number, maxAgeMs: number): boolean;
31
+ /**
32
+ * Effective age-reap threshold: the configured `maxAgeMs` floored at the run's hard deadline
33
+ * (`minLeakAgeMs` = timeoutMs + killGraceMs). A threshold below the max legitimate run lifetime would
34
+ * let the sweep kill a still-running verify — a live run can outlive a short TTL but never its own
35
+ * kill deadline, so flooring closes that hole. A 0/negative configured value keeps age-reaping
36
+ * disabled (orphan-only).
37
+ */
38
+ export declare function effectiveLeakThresholdMs(maxAgeMs: number, minLeakAgeMs: number): number;
39
+ export interface ProcProbe {
40
+ isAlive(pid: number): boolean;
41
+ cmdline(pid: number): string | null;
42
+ /** Process start time (epoch ms) for the live pid, or null if undeterminable (win32 / ps failure).
43
+ * Used for the owner pid-reuse guard (#6); optional so injected test probes need not implement it. */
44
+ startTime?(pid: number): number | null;
45
+ kill(pid: number, signal: NodeJS.Signals): void;
46
+ }
47
+ /**
48
+ * Owner pid-reuse guard (#6): the spawning owner necessarily started BEFORE it created this run, so a
49
+ * process now occupying `ownerPid` whose start time is meaningfully AFTER the run was created cannot be
50
+ * that owner — the real owner died and the pid was recycled, making this a true orphan. Undeterminable
51
+ * start time (win32 / ps failure → null) → NOT reused: we never escalate to a kill on a guess, so a
52
+ * live owner is never misclassified (its start time is ≤ runStartedAt, far below the threshold).
53
+ */
54
+ export declare function isOwnerPidReused(liveStartTime: number | null, runStartedAt: number, toleranceMs: number): boolean;
55
+ export interface ReapResult {
56
+ scanned: number;
57
+ orphans: number;
58
+ agedOut: number;
59
+ killed: number;
60
+ deleted: number;
61
+ }
62
+ /**
63
+ * Scan tmpRoot for orphaned / aged-out verify temp dirs and clean them up. Synchronous (runs at
64
+ * daemon startup and on a periodic sweep); the SIGKILL backstop is scheduled async + unref'd so it
65
+ * never blocks. `maxAgeMs` (M7b) enables age-based reaping; 0/undefined keeps orphan-only behavior.
66
+ */
67
+ export declare function reapOrphanedVerifyRuns(opts?: {
68
+ tmpRoot?: string;
69
+ log?: (msg: string) => void;
70
+ graceMs?: number;
71
+ /** Age-based leak threshold (M7b). 0/undefined → orphan-only (pre-M7b behavior). */
72
+ maxAgeMs?: number;
73
+ /** Run hard-deadline floor (timeoutMs + killGraceMs); the age threshold is never lower than this
74
+ * so a still-running verify is never age-reaped (08 / M7b safety floor). */
75
+ minLeakAgeMs?: number;
76
+ /** Injectable clock (tests). */
77
+ now?: number;
78
+ probe?: ProcProbe;
79
+ }): ReapResult;