publishport-opencli 1.0.20 → 1.0.21

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 (1041) hide show
  1. package/clis/12306/me.js +2 -2
  2. package/clis/12306/orders.js +3 -3
  3. package/clis/12306/passengers.js +3 -3
  4. package/clis/12306/price.js +1 -1
  5. package/clis/12306/stations.js +1 -1
  6. package/clis/12306/train.js +1 -1
  7. package/clis/12306/trains.js +1 -1
  8. package/clis/12306/utils.js +1 -1
  9. package/clis/1688/download.js +1 -1
  10. package/clis/1688/item.js +4 -4
  11. package/clis/1688/search.js +4 -4
  12. package/clis/1688/store.js +4 -4
  13. package/clis/1point3acres/forum.js +1 -1
  14. package/clis/1point3acres/forums.js +1 -1
  15. package/clis/1point3acres/notifications.js +1 -1
  16. package/clis/1point3acres/search.js +1 -1
  17. package/clis/1point3acres/thread.js +2 -2
  18. package/clis/1point3acres/user.js +1 -1
  19. package/clis/1point3acres/utils.js +2 -2
  20. package/clis/36kr/article.js +2 -2
  21. package/clis/36kr/hot.js +2 -2
  22. package/clis/36kr/news.js +1 -1
  23. package/clis/36kr/search.js +2 -2
  24. package/clis/51job/company.js +2 -2
  25. package/clis/51job/detail.js +2 -2
  26. package/clis/51job/hot.js +1 -1
  27. package/clis/51job/search.js +1 -1
  28. package/clis/51job/utils.js +7 -7
  29. package/clis/_atlassian/shared.js +9 -9
  30. package/clis/_shared/article/auth.js +4 -4
  31. package/clis/_shared/article/douban-md2draft.js +4 -4
  32. package/clis/_shared/article/format.js +1 -1
  33. package/clis/_shared/article/images.js +7 -7
  34. package/clis/_shared/article/login.js +1 -1
  35. package/clis/_shared/article/publish.js +11 -11
  36. package/clis/_shared/common.js +1 -1
  37. package/clis/_shared/content-guard.js +1 -1
  38. package/clis/_shared/desktop-commands.js +1 -1
  39. package/clis/_shared/file-inject.js +12 -12
  40. package/clis/_shared/self-hosted-sites.js +2 -2
  41. package/clis/_shared/site-auth.js +1 -1
  42. package/clis/_shared/token-auth.js +2 -2
  43. package/clis/_shared/video-publish.js +9 -9
  44. package/clis/amazon/offer.js +3 -3
  45. package/clis/amazon/product.js +5 -5
  46. package/clis/amazon/shared.js +6 -6
  47. package/clis/antigravity/_actions.js +13 -13
  48. package/clis/antigravity/audit-extras.js +10 -10
  49. package/clis/antigravity/delete.js +1 -1
  50. package/clis/antigravity/model.js +6 -6
  51. package/clis/antigravity/new.js +2 -2
  52. package/clis/antigravity/read.js +2 -2
  53. package/clis/antigravity/rename.js +1 -1
  54. package/clis/antigravity/send.js +3 -3
  55. package/clis/antigravity/serve.js +17 -17
  56. package/clis/antigravity/storage.js +6 -6
  57. package/clis/antigravity/watch.js +2 -2
  58. package/clis/apple-podcasts/episodes.js +1 -1
  59. package/clis/apple-podcasts/top.js +1 -1
  60. package/clis/apple-podcasts/utils.js +1 -1
  61. package/clis/archive/item.js +1 -1
  62. package/clis/archive/search.js +1 -1
  63. package/clis/archive/snapshots.js +1 -1
  64. package/clis/archive/wayback.js +1 -1
  65. package/clis/arxiv/author.js +1 -1
  66. package/clis/arxiv/utils.js +1 -1
  67. package/clis/autohome/brand.js +1 -1
  68. package/clis/autohome/score.js +1 -1
  69. package/clis/autohome/utils.js +1 -1
  70. package/clis/baijiahao/article.js +1 -1
  71. package/clis/baijiahao/lists.js +1 -1
  72. package/clis/baijiahao/login.js +1 -1
  73. package/clis/baijiahao/publish.js +9 -9
  74. package/clis/baijiahao/stats.js +1 -1
  75. package/clis/baijiahao/whoami.js +1 -1
  76. package/clis/band/bands.js +2 -2
  77. package/clis/band/mentions.js +2 -2
  78. package/clis/band/post.js +4 -4
  79. package/clis/band/posts.js +3 -3
  80. package/clis/barchart/flow.js +3 -3
  81. package/clis/barchart/greeks.js +2 -2
  82. package/clis/barchart/quote.js +3 -3
  83. package/clis/bbc/news.js +1 -1
  84. package/clis/bbc/topic.js +1 -1
  85. package/clis/bbc/utils.js +1 -1
  86. package/clis/bilibili/article.js +1 -1
  87. package/clis/bilibili/categories.js +1 -1
  88. package/clis/bilibili/coin.js +1 -1
  89. package/clis/bilibili/comment-del.js +1 -1
  90. package/clis/bilibili/comment-like.js +1 -1
  91. package/clis/bilibili/comment.js +1 -1
  92. package/clis/bilibili/comments.js +1 -1
  93. package/clis/bilibili/dm-list.js +1 -1
  94. package/clis/bilibili/dm-read.js +1 -1
  95. package/clis/bilibili/dm-send.js +1 -1
  96. package/clis/bilibili/download.js +2 -2
  97. package/clis/bilibili/drafts.js +1 -1
  98. package/clis/bilibili/dynamic-post.js +3 -3
  99. package/clis/bilibili/favorite-add.js +1 -1
  100. package/clis/bilibili/favorite.js +1 -1
  101. package/clis/bilibili/feed.js +2 -2
  102. package/clis/bilibili/follow.js +1 -1
  103. package/clis/bilibili/following.js +1 -1
  104. package/clis/bilibili/like.js +1 -1
  105. package/clis/bilibili/partitions.js +1 -1
  106. package/clis/bilibili/stats.js +1 -1
  107. package/clis/bilibili/subtitle.js +3 -3
  108. package/clis/bilibili/summary.js +1 -1
  109. package/clis/bilibili/topics.js +1 -1
  110. package/clis/bilibili/unfollow.js +1 -1
  111. package/clis/bilibili/upload.js +1 -1
  112. package/clis/bilibili/utils.js +10 -10
  113. package/clis/bilibili/video-drafts.js +1 -1
  114. package/clis/bilibili/video.js +1 -1
  115. package/clis/bloomberg/businessweek.js +4 -4
  116. package/clis/bloomberg/news.js +2 -2
  117. package/clis/bloomberg/utils.js +13 -13
  118. package/clis/bluesky/post.js +1 -1
  119. package/clis/bluesky/shared.js +11 -11
  120. package/clis/bluesky/whoami.js +1 -1
  121. package/clis/booking/search.js +2 -2
  122. package/clis/boss/accept.js +1 -1
  123. package/clis/boss/applied.js +1 -1
  124. package/clis/boss/auth.js +1 -1
  125. package/clis/boss/batchgreet.js +1 -1
  126. package/clis/boss/bossinfo.js +1 -1
  127. package/clis/boss/chatlist.js +1 -1
  128. package/clis/boss/chatmsg.js +1 -1
  129. package/clis/boss/cities.js +1 -1
  130. package/clis/boss/detail.js +1 -1
  131. package/clis/boss/exchange.js +1 -1
  132. package/clis/boss/greet.js +1 -1
  133. package/clis/boss/interviews.js +1 -1
  134. package/clis/boss/invite.js +1 -1
  135. package/clis/boss/joblist.js +1 -1
  136. package/clis/boss/mark.js +1 -1
  137. package/clis/boss/me.js +2 -2
  138. package/clis/boss/recommend.js +1 -1
  139. package/clis/boss/resumedelete.js +1 -1
  140. package/clis/boss/resumelist.js +1 -1
  141. package/clis/boss/resumeupload.js +11 -11
  142. package/clis/boss/search.js +1 -1
  143. package/clis/boss/send.js +1 -1
  144. package/clis/boss/sendresume.js +1 -1
  145. package/clis/boss/stats.js +1 -1
  146. package/clis/boss/unread.js +1 -1
  147. package/clis/boss/utils.js +13 -13
  148. package/clis/chaoxing/assignments.js +1 -1
  149. package/clis/chaoxing/exams.js +1 -1
  150. package/clis/chaoxing/utils.js +9 -9
  151. package/clis/chatgpt/ask.js +1 -1
  152. package/clis/chatgpt/auth.js +2 -2
  153. package/clis/chatgpt/detail.js +1 -1
  154. package/clis/chatgpt/image.js +1 -1
  155. package/clis/chatgpt/read.js +1 -1
  156. package/clis/chatgpt/send.js +1 -1
  157. package/clis/chatgpt/utils.js +59 -59
  158. package/clis/chatgpt-app/ask.js +1 -1
  159. package/clis/chatgpt-app/send.js +1 -1
  160. package/clis/chatwise/model.js +6 -6
  161. package/clis/chess/analyze.js +1 -1
  162. package/clis/chess/game.js +1 -1
  163. package/clis/chess/games.js +1 -1
  164. package/clis/chess/stats.js +1 -1
  165. package/clis/chess/utils.js +1 -1
  166. package/clis/claude/ask.js +2 -2
  167. package/clis/claude/detail.js +1 -1
  168. package/clis/claude/new.js +1 -1
  169. package/clis/claude/read.js +1 -1
  170. package/clis/claude/send.js +1 -1
  171. package/clis/claude/utils.js +23 -23
  172. package/clis/cnblogs/article.js +1 -1
  173. package/clis/cnblogs/login.js +1 -1
  174. package/clis/cnblogs/stats.js +7 -7
  175. package/clis/cnblogs/whoami.js +1 -1
  176. package/clis/codex/_actions.js +3 -3
  177. package/clis/codex/archive.js +1 -1
  178. package/clis/codex/ask.js +6 -6
  179. package/clis/codex/model.js +8 -8
  180. package/clis/codex/pin.js +1 -1
  181. package/clis/codex/rename.js +4 -4
  182. package/clis/codex/send.js +3 -3
  183. package/clis/codex/sidebar.js +1 -1
  184. package/clis/coingecko/categories.js +1 -1
  185. package/clis/coingecko/coin.js +1 -1
  186. package/clis/coingecko/derivatives.js +1 -1
  187. package/clis/coingecko/exchanges.js +1 -1
  188. package/clis/coingecko/global.js +1 -1
  189. package/clis/coingecko/trending.js +1 -1
  190. package/clis/confluence/search.js +1 -1
  191. package/clis/coupang/product.js +3 -3
  192. package/clis/coupang/utils.js +1 -1
  193. package/clis/crates/crate.js +1 -1
  194. package/clis/crates/search.js +1 -1
  195. package/clis/crates/utils.js +1 -1
  196. package/clis/csdn/article.js +13 -13
  197. package/clis/csdn/columns.js +1 -1
  198. package/clis/csdn/login.js +1 -1
  199. package/clis/csdn/stats.js +4 -4
  200. package/clis/csdn/whoami.js +1 -1
  201. package/clis/cto51/article.js +1 -1
  202. package/clis/cto51/whoami.js +1 -1
  203. package/clis/ctrip/flight.js +2 -2
  204. package/clis/ctrip/hotel-search.js +3 -3
  205. package/clis/ctrip/hotel-suggest.js +1 -1
  206. package/clis/ctrip/search.js +1 -1
  207. package/clis/ctrip/utils.js +6 -6
  208. package/clis/cursor/ask.js +5 -5
  209. package/clis/cursor/composer.js +2 -2
  210. package/clis/cursor/model.js +4 -4
  211. package/clis/cursor/send.js +2 -2
  212. package/clis/dblp/author.js +1 -1
  213. package/clis/dblp/paper.js +1 -1
  214. package/clis/dblp/search.js +1 -1
  215. package/clis/dblp/utils.js +1 -1
  216. package/clis/dblp/venue.js +1 -1
  217. package/clis/deepseek/ask.js +1 -1
  218. package/clis/deepseek/auth.js +2 -2
  219. package/clis/deepseek/detail.js +1 -1
  220. package/clis/deepseek/new.js +1 -1
  221. package/clis/deepseek/read.js +1 -1
  222. package/clis/deepseek/send.js +7 -7
  223. package/clis/deepseek/utils.js +25 -25
  224. package/clis/defillama/protocol.js +1 -1
  225. package/clis/defillama/protocols.js +1 -1
  226. package/clis/defillama/utils.js +1 -1
  227. package/clis/devto/auth.js +2 -2
  228. package/clis/devto/latest.js +1 -1
  229. package/clis/devto/publish.js +5 -5
  230. package/clis/devto/read.js +2 -2
  231. package/clis/devto/stats.js +3 -3
  232. package/clis/dianping/auth.js +2 -2
  233. package/clis/dianping/cityResolver.js +2 -2
  234. package/clis/dianping/search.js +1 -1
  235. package/clis/dianping/shop.js +1 -1
  236. package/clis/dianping/utils.js +1 -1
  237. package/clis/discord-app/delete.js +3 -3
  238. package/clis/discord-app/read.js +1 -1
  239. package/clis/discord-app/thread-read.js +1 -1
  240. package/clis/discord-web/auth.js +2 -2
  241. package/clis/discord-web/send.js +5 -5
  242. package/clis/dockerhub/image.js +1 -1
  243. package/clis/dockerhub/search.js +1 -1
  244. package/clis/dockerhub/utils.js +1 -1
  245. package/clis/dongchedi/koubei.js +1 -1
  246. package/clis/dongchedi/models.js +1 -1
  247. package/clis/dongchedi/score.js +1 -1
  248. package/clis/dongchedi/search.js +1 -1
  249. package/clis/dongchedi/series.js +1 -1
  250. package/clis/dongchedi/specs.js +1 -1
  251. package/clis/dongchedi/utils.js +1 -1
  252. package/clis/douban/article.js +3 -3
  253. package/clis/douban/auth.js +2 -2
  254. package/clis/douban/download.js +1 -1
  255. package/clis/douban/utils.js +23 -23
  256. package/clis/doubao/auth.js +3 -3
  257. package/clis/doubao/utils.js +39 -39
  258. package/clis/doubao-app/ask.js +1 -1
  259. package/clis/doubao-app/utils.js +4 -4
  260. package/clis/douyin/_shared/browser-fetch.js +7 -7
  261. package/clis/douyin/_shared/draft-cache.js +1 -1
  262. package/clis/douyin/_shared/imagex-upload.js +1 -1
  263. package/clis/douyin/_shared/sts2.js +1 -1
  264. package/clis/douyin/_shared/text-extra.js +1 -1
  265. package/clis/douyin/_shared/tos-upload.js +4 -4
  266. package/clis/douyin/_shared/transcode.js +1 -1
  267. package/clis/douyin/_shared/vod-upload.js +4 -4
  268. package/clis/douyin/draft.js +18 -18
  269. package/clis/douyin/drafts.js +1 -1
  270. package/clis/douyin/publish-image.js +12 -12
  271. package/clis/douyin/publish.js +9 -9
  272. package/clis/douyin/search.js +3 -3
  273. package/clis/douyin/videos.js +1 -1
  274. package/clis/eastmoney/_secid.js +1 -1
  275. package/clis/eastmoney/announcement.js +1 -1
  276. package/clis/eastmoney/article.js +1 -1
  277. package/clis/eastmoney/convertible.js +1 -1
  278. package/clis/eastmoney/etf.js +1 -1
  279. package/clis/eastmoney/holders.js +1 -1
  280. package/clis/eastmoney/index-board.js +1 -1
  281. package/clis/eastmoney/kline.js +1 -1
  282. package/clis/eastmoney/kuaixun.js +1 -1
  283. package/clis/eastmoney/longhu.js +1 -1
  284. package/clis/eastmoney/money-flow.js +1 -1
  285. package/clis/eastmoney/northbound.js +1 -1
  286. package/clis/eastmoney/quote.js +1 -1
  287. package/clis/eastmoney/rank.js +1 -1
  288. package/clis/eastmoney/sectors.js +1 -1
  289. package/clis/endoflife/product.js +1 -1
  290. package/clis/endoflife/utils.js +1 -1
  291. package/clis/facebook/comment.js +8 -8
  292. package/clis/facebook/feed.js +4 -4
  293. package/clis/facebook/like.js +5 -5
  294. package/clis/facebook/notifications.js +3 -3
  295. package/clis/facebook/post.js +11 -11
  296. package/clis/facebook/search.js +3 -3
  297. package/clis/flathub/app.js +1 -1
  298. package/clis/flathub/search.js +1 -1
  299. package/clis/flathub/utils.js +1 -1
  300. package/clis/flomo/memos.js +1 -1
  301. package/clis/gemini/deep-research-result.js +4 -4
  302. package/clis/gemini/deep-research.js +1 -1
  303. package/clis/gemini/detail.js +1 -1
  304. package/clis/gemini/history.js +1 -1
  305. package/clis/gemini/image.js +2 -2
  306. package/clis/gemini/status.js +1 -1
  307. package/clis/gemini/utils.js +43 -43
  308. package/clis/geogebra/hexagon.js +1 -1
  309. package/clis/geogebra/info.js +3 -3
  310. package/clis/geogebra/triangle.js +1 -1
  311. package/clis/geogebra/utils.js +11 -11
  312. package/clis/ghost/login.js +1 -1
  313. package/clis/ghost/shared.js +2 -2
  314. package/clis/gitee/auth.js +2 -2
  315. package/clis/github-trending/repos.js +1 -1
  316. package/clis/google/news.js +1 -1
  317. package/clis/google/search.js +2 -2
  318. package/clis/google/suggest.js +1 -1
  319. package/clis/google/trends.js +1 -1
  320. package/clis/google/utils.js +1 -1
  321. package/clis/goproxy/module.js +1 -1
  322. package/clis/goproxy/utils.js +1 -1
  323. package/clis/goproxy/versions.js +1 -1
  324. package/clis/gov-policy/recent.js +2 -2
  325. package/clis/gov-policy/search.js +2 -2
  326. package/clis/grok/ask.js +1 -1
  327. package/clis/grok/detail.js +1 -1
  328. package/clis/grok/image.js +8 -8
  329. package/clis/grok/pin.js +1 -1
  330. package/clis/grok/send.js +1 -1
  331. package/clis/grok/status.js +1 -1
  332. package/clis/grok/utils.js +21 -21
  333. package/clis/guazi/browse.js +1 -1
  334. package/clis/guazi/car.js +1 -1
  335. package/clis/guazi/utils.js +1 -1
  336. package/clis/hackernews/auth.js +2 -2
  337. package/clis/hackernews/comment.js +8 -8
  338. package/clis/hackernews/read.js +7 -7
  339. package/clis/hackernews/submit.js +7 -7
  340. package/clis/hashnode/auth.js +3 -3
  341. package/clis/hashnode/publish.js +14 -14
  342. package/clis/hf/auth.js +2 -2
  343. package/clis/hf/models.js +1 -1
  344. package/clis/hf/paper.js +1 -1
  345. package/clis/hf/spaces.js +1 -1
  346. package/clis/hf/top.js +1 -1
  347. package/clis/homebrew/cask.js +1 -1
  348. package/clis/homebrew/formula.js +1 -1
  349. package/clis/homebrew/popular.js +1 -1
  350. package/clis/homebrew/utils.js +1 -1
  351. package/clis/huodongxing/events.js +1 -1
  352. package/clis/hupu/detail.js +4 -4
  353. package/clis/hupu/hot.js +3 -3
  354. package/clis/hupu/reply.js +1 -1
  355. package/clis/hupu/search.js +1 -1
  356. package/clis/hupu/unlike.js +1 -1
  357. package/clis/hupu/utils.js +10 -10
  358. package/clis/imdb/person.js +2 -2
  359. package/clis/imdb/reviews.js +3 -3
  360. package/clis/imdb/search.js +2 -2
  361. package/clis/imdb/title.js +1 -1
  362. package/clis/imdb/top.js +1 -1
  363. package/clis/imdb/trending.js +1 -1
  364. package/clis/imdb/utils.js +13 -13
  365. package/clis/imooc/article.js +6 -6
  366. package/clis/imooc/login.js +1 -1
  367. package/clis/imooc/whoami.js +1 -1
  368. package/clis/indeed/job.js +2 -2
  369. package/clis/indeed/search.js +2 -2
  370. package/clis/indeed/utils.js +1 -1
  371. package/clis/infoq/article.js +2 -2
  372. package/clis/infoq/login.js +1 -1
  373. package/clis/infoq/whoami.js +1 -1
  374. package/clis/instagram/_shared/private-publish.js +4 -4
  375. package/clis/instagram/_shared/protocol-capture.js +9 -9
  376. package/clis/instagram/detail.js +3 -3
  377. package/clis/instagram/post.js +25 -25
  378. package/clis/instagram/reel.js +18 -18
  379. package/clis/instagram/story.js +4 -4
  380. package/clis/instagram/user.js +2 -2
  381. package/clis/jd/item.js +65 -65
  382. package/clis/jianshu/article.js +1 -1
  383. package/clis/jianshu/login.js +1 -1
  384. package/clis/jianshu/notebooks.js +1 -1
  385. package/clis/jianshu/whoami.js +1 -1
  386. package/clis/jianyu/search.js +6 -6
  387. package/clis/jianyu/shared/procurement-contract.js +1 -1
  388. package/clis/jike/api.js +6 -6
  389. package/clis/jike/auth.js +3 -3
  390. package/clis/jike/comment.js +1 -1
  391. package/clis/jike/create.js +6 -6
  392. package/clis/jike/feed.js +3 -3
  393. package/clis/jike/like.js +1 -1
  394. package/clis/jike/notifications.js +3 -3
  395. package/clis/jike/repost.js +13 -13
  396. package/clis/jike/search.js +3 -3
  397. package/clis/jimeng/auth.js +2 -2
  398. package/clis/jimeng/generate.js +10 -10
  399. package/clis/jira/shared.js +1 -1
  400. package/clis/juejin/article.js +4 -4
  401. package/clis/juejin/categories.js +1 -1
  402. package/clis/juejin/hot.js +1 -1
  403. package/clis/juejin/login.js +1 -1
  404. package/clis/juejin/recommend.js +1 -1
  405. package/clis/juejin/stats.js +3 -3
  406. package/clis/juejin/tags.js +1 -1
  407. package/clis/juejin/utils.js +1 -1
  408. package/clis/juejin/whoami.js +1 -1
  409. package/clis/ke/utils.js +4 -4
  410. package/clis/kimi/_utils.js +7 -7
  411. package/clis/kimi/audit-extras.js +14 -14
  412. package/clis/kimi/auth.js +3 -3
  413. package/clis/kimi/chat.js +15 -15
  414. package/clis/kimi/storage.js +5 -5
  415. package/clis/kimi/ui.js +13 -13
  416. package/clis/kimi/usage.js +3 -3
  417. package/clis/kuaishou/auth.js +1 -1
  418. package/clis/kuaishou/publish.js +6 -6
  419. package/clis/lesswrong/_helpers.js +5 -5
  420. package/clis/lesswrong/comments.js +5 -5
  421. package/clis/lichess/top.js +1 -1
  422. package/clis/lichess/user.js +1 -1
  423. package/clis/lichess/utils.js +1 -1
  424. package/clis/linkedin/comment.js +1 -1
  425. package/clis/linkedin/connect.js +11 -11
  426. package/clis/linkedin/create.js +5 -5
  427. package/clis/linkedin/follow.js +1 -1
  428. package/clis/linkedin/inbox.js +1 -1
  429. package/clis/linkedin/job-detail.js +3 -3
  430. package/clis/linkedin/like.js +1 -1
  431. package/clis/linkedin/notifications.js +1 -1
  432. package/clis/linkedin/people-search.js +1 -1
  433. package/clis/linkedin/post-comments.js +1 -1
  434. package/clis/linkedin/post-detail.js +1 -1
  435. package/clis/linkedin/profile-analytics.js +1 -1
  436. package/clis/linkedin/profile-api.js +13 -13
  437. package/clis/linkedin/profile-experience.js +1 -1
  438. package/clis/linkedin/profile-projects.js +1 -1
  439. package/clis/linkedin/profile-read.js +3 -3
  440. package/clis/linkedin/reply.js +1 -1
  441. package/clis/linkedin/repost.js +1 -1
  442. package/clis/linkedin/safe-send.js +8 -8
  443. package/clis/linkedin/salesnav-inbox.js +5 -5
  444. package/clis/linkedin/salesnav-message.js +3 -3
  445. package/clis/linkedin/salesnav-search.js +4 -4
  446. package/clis/linkedin/salesnav-thread.js +1 -1
  447. package/clis/linkedin/search-api.js +3 -3
  448. package/clis/linkedin/search.js +8 -8
  449. package/clis/linkedin/social-api.js +31 -31
  450. package/clis/linkedin/timeline.js +3 -3
  451. package/clis/linkedin-learning/search.js +2 -2
  452. package/clis/linkedin-learning/trending.js +2 -2
  453. package/clis/linux-do/feed.js +4 -4
  454. package/clis/linux-do/topic-content.js +8 -8
  455. package/clis/lobsters/domain.js +1 -1
  456. package/clis/lobsters/read.js +7 -7
  457. package/clis/maimai/auth.js +2 -2
  458. package/clis/maimai/search-talents.js +4 -4
  459. package/clis/manus/_utils.js +1 -1
  460. package/clis/mastodon/login.js +1 -1
  461. package/clis/mastodon/post.js +1 -1
  462. package/clis/mastodon/shared.js +12 -12
  463. package/clis/mastodon/whoami.js +1 -1
  464. package/clis/maven/artifact.js +1 -1
  465. package/clis/maven/search.js +1 -1
  466. package/clis/maven/utils.js +1 -1
  467. package/clis/mdn/search.js +1 -1
  468. package/clis/medium/article.js +5 -5
  469. package/clis/medium/login.js +1 -1
  470. package/clis/medium/stats.js +3 -3
  471. package/clis/medium/tag.js +1 -1
  472. package/clis/medium/whoami.js +1 -1
  473. package/clis/mubu/notes.js +1 -1
  474. package/clis/mubu/utils.js +15 -15
  475. package/clis/note/auth.js +2 -2
  476. package/clis/note/note-utils.js +2 -2
  477. package/clis/note/publish.js +8 -8
  478. package/clis/notebooklm/add-source.js +8 -8
  479. package/clis/notebooklm/create.js +1 -1
  480. package/clis/notebooklm/generate-slides.js +1 -1
  481. package/clis/notebooklm/notes-get.js +1 -1
  482. package/clis/notebooklm/rpc.js +8 -8
  483. package/clis/notebooklm/source-fulltext.js +1 -1
  484. package/clis/notebooklm/utils.js +10 -10
  485. package/clis/nowcoder/auth.js +2 -2
  486. package/clis/nowcoder/comment.js +1 -1
  487. package/clis/nowcoder/comments.js +1 -1
  488. package/clis/nowcoder/dm-list.js +1 -1
  489. package/clis/nowcoder/dm-read.js +1 -1
  490. package/clis/nowcoder/dm-send.js +1 -1
  491. package/clis/nowcoder/drafts.js +1 -1
  492. package/clis/nowcoder/inbox.js +1 -1
  493. package/clis/nowcoder/like.js +1 -1
  494. package/clis/nowcoder/my.js +1 -1
  495. package/clis/nowcoder/post.js +1 -1
  496. package/clis/nowcoder/utils.js +13 -13
  497. package/clis/npm/downloads.js +1 -1
  498. package/clis/npm/package.js +1 -1
  499. package/clis/npm/search.js +1 -1
  500. package/clis/npm/utils.js +1 -1
  501. package/clis/nuget/package.js +1 -1
  502. package/clis/nuget/search.js +1 -1
  503. package/clis/nuget/utils.js +1 -1
  504. package/clis/nvd/cve.js +1 -1
  505. package/clis/oeis/search.js +1 -1
  506. package/clis/oeis/sequence.js +1 -1
  507. package/clis/oeis/utils.js +1 -1
  508. package/clis/ones/common.js +6 -6
  509. package/clis/ones/enrich-tasks.js +1 -1
  510. package/clis/ones/my-tasks.js +1 -1
  511. package/clis/ones/resolve-labels.js +1 -1
  512. package/clis/ones/task-helpers.js +1 -1
  513. package/clis/ones/task.js +1 -1
  514. package/clis/ones/worklog.js +7 -7
  515. package/clis/openalex/search.js +1 -1
  516. package/clis/openalex/utils.js +1 -1
  517. package/clis/openalex/work.js +1 -1
  518. package/clis/openfda/drug-label.js +1 -1
  519. package/clis/openfda/food-recall.js +1 -1
  520. package/clis/openfda/utils.js +1 -1
  521. package/clis/openreview/author.js +1 -1
  522. package/clis/openreview/paper.js +1 -1
  523. package/clis/openreview/reviews.js +3 -3
  524. package/clis/openreview/search.js +1 -1
  525. package/clis/openreview/utils.js +1 -1
  526. package/clis/openreview/venue.js +1 -1
  527. package/clis/oschina/article.js +1 -1
  528. package/clis/oschina/catalogs.js +1 -1
  529. package/clis/oschina/login.js +1 -1
  530. package/clis/oschina/stats.js +6 -6
  531. package/clis/oschina/whoami.js +1 -1
  532. package/clis/osv/query.js +1 -1
  533. package/clis/osv/utils.js +1 -1
  534. package/clis/osv/vulnerability.js +1 -1
  535. package/clis/packagist/package.js +1 -1
  536. package/clis/packagist/search.js +1 -1
  537. package/clis/packagist/utils.js +1 -1
  538. package/clis/pinterest/api.js +1 -1
  539. package/clis/pinterest/auth.js +1 -1
  540. package/clis/pinterest/boards.js +1 -1
  541. package/clis/pinterest/client.js +6 -6
  542. package/clis/pinterest/publish.js +5 -5
  543. package/clis/pixiv/auth.js +2 -2
  544. package/clis/pixiv/download.js +1 -1
  545. package/clis/pixiv/illusts.js +1 -1
  546. package/clis/pixiv/search.js +1 -1
  547. package/clis/pixiv/utils.js +3 -3
  548. package/clis/powerchina/auth.js +2 -2
  549. package/clis/powerchina/search.js +1 -1
  550. package/clis/producthunt/browse.js +2 -2
  551. package/clis/producthunt/hot.js +2 -2
  552. package/clis/producthunt/posts.js +1 -1
  553. package/clis/producthunt/today.js +1 -1
  554. package/clis/producthunt/utils.js +1 -1
  555. package/clis/pypi/downloads.js +1 -1
  556. package/clis/pypi/package.js +1 -1
  557. package/clis/pypi/utils.js +1 -1
  558. package/clis/qiita/auth.js +1 -1
  559. package/clis/qiita/gql.js +6 -6
  560. package/clis/qiita/publish.js +4 -4
  561. package/clis/qiita/stats.js +4 -4
  562. package/clis/qoder/_utils.js +16 -16
  563. package/clis/qoder/composer.js +1 -1
  564. package/clis/qoder/quest.js +1 -1
  565. package/clis/qoder/ui.js +14 -14
  566. package/clis/quark/auth.js +2 -2
  567. package/clis/quark/utils.js +2 -2
  568. package/clis/quora/answer-comments.js +3 -3
  569. package/clis/quora/create-answer.js +4 -4
  570. package/clis/quora/create-question.js +3 -3
  571. package/clis/quora/shared.js +17 -17
  572. package/clis/quora/whoami.js +1 -1
  573. package/clis/qwen/ask.js +1 -1
  574. package/clis/qwen/auth.js +3 -3
  575. package/clis/qwen/detail.js +1 -1
  576. package/clis/qwen/image.js +5 -5
  577. package/clis/qwen/status.js +1 -1
  578. package/clis/qwen/utils.js +16 -16
  579. package/clis/reddit/home.js +3 -3
  580. package/clis/reddit/read.js +10 -10
  581. package/clis/reddit/reply.js +4 -4
  582. package/clis/reddit/submit.js +11 -11
  583. package/clis/reddit/subreddit-info.js +3 -3
  584. package/clis/reddit/subscribed.js +4 -4
  585. package/clis/reddit/whoami.js +2 -2
  586. package/clis/rednote/comments.js +1 -1
  587. package/clis/rednote/download.js +1 -1
  588. package/clis/rednote/feed.js +1 -1
  589. package/clis/rednote/note.js +1 -1
  590. package/clis/rednote/notifications.js +2 -2
  591. package/clis/rednote/search.js +2 -2
  592. package/clis/rest-countries/country.js +1 -1
  593. package/clis/rest-countries/region.js +1 -1
  594. package/clis/rest-countries/utils.js +1 -1
  595. package/clis/reuters/article-detail.js +1 -1
  596. package/clis/reuters/auth.js +3 -3
  597. package/clis/reuters/search.js +1 -1
  598. package/clis/reuters/utils.js +4 -4
  599. package/clis/rfc/rfc.js +1 -1
  600. package/clis/rfc/utils.js +1 -1
  601. package/clis/rubygems/gem.js +1 -1
  602. package/clis/rubygems/search.js +1 -1
  603. package/clis/rubygems/utils.js +1 -1
  604. package/clis/segmentfault/article.js +3 -3
  605. package/clis/segmentfault/channels.js +1 -1
  606. package/clis/segmentfault/login.js +1 -1
  607. package/clis/segmentfault/stats.js +4 -4
  608. package/clis/segmentfault/tags.js +1 -1
  609. package/clis/segmentfault/whoami.js +1 -1
  610. package/clis/semanticscholar/citations.js +1 -1
  611. package/clis/semanticscholar/paper.js +1 -1
  612. package/clis/semanticscholar/recommendations.js +1 -1
  613. package/clis/semanticscholar/search.js +1 -1
  614. package/clis/semanticscholar/utils.js +1 -1
  615. package/clis/sinafinance/news.js +1 -1
  616. package/clis/sinafinance/stock-rank.js +1 -1
  617. package/clis/sinafinance/stock.js +1 -1
  618. package/clis/slock/attachment-download.js +1 -1
  619. package/clis/slock/attachment-upload.js +7 -7
  620. package/clis/slock/attachment-url.js +1 -1
  621. package/clis/slock/auth-verify.js +1 -1
  622. package/clis/slock/bookmark-add.js +1 -1
  623. package/clis/slock/bookmark-remove.js +1 -1
  624. package/clis/slock/channel-action.js +1 -1
  625. package/clis/slock/channel-create.js +1 -1
  626. package/clis/slock/channel-files.js +1 -1
  627. package/clis/slock/channel-list.js +1 -1
  628. package/clis/slock/channel-mark.js +1 -1
  629. package/clis/slock/channel-members.js +1 -1
  630. package/clis/slock/channel-unarchive.js +1 -1
  631. package/clis/slock/dm-list.js +1 -1
  632. package/clis/slock/errors.js +1 -1
  633. package/clis/slock/in-page.js +28 -28
  634. package/clis/slock/inbox-done.js +5 -5
  635. package/clis/slock/inbox.js +1 -1
  636. package/clis/slock/message-read.js +22 -22
  637. package/clis/slock/message-search.js +10 -10
  638. package/clis/slock/message-send.js +25 -25
  639. package/clis/slock/reaction-add.js +1 -1
  640. package/clis/slock/reaction-remove.js +1 -1
  641. package/clis/slock/resolve.js +1 -1
  642. package/clis/slock/server-list.js +2 -2
  643. package/clis/slock/task-claim.js +4 -4
  644. package/clis/slock/task-convert.js +13 -13
  645. package/clis/slock/task-create.js +1 -1
  646. package/clis/slock/task-delete.js +5 -5
  647. package/clis/slock/task-get.js +5 -5
  648. package/clis/slock/task-list-server.js +4 -4
  649. package/clis/slock/task-list.js +5 -5
  650. package/clis/slock/task-status.js +3 -3
  651. package/clis/slock/task-unclaim.js +3 -3
  652. package/clis/slock/thread-follow.js +1 -1
  653. package/clis/slock/thread-state.js +1 -1
  654. package/clis/slock/unread-summary.js +5 -5
  655. package/clis/slock/whoami.js +1 -1
  656. package/clis/smzdm/search.js +3 -3
  657. package/clis/sohu/article.js +1 -1
  658. package/clis/sohu/attributes.js +1 -1
  659. package/clis/sohu/categories.js +1 -1
  660. package/clis/sohu/channels.js +1 -1
  661. package/clis/sohu/columns.js +1 -1
  662. package/clis/sohu/login.js +1 -1
  663. package/clis/sohu/stats.js +3 -3
  664. package/clis/sohu/topics.js +1 -1
  665. package/clis/sohu/whoami.js +1 -1
  666. package/clis/spotify/spotify.js +1 -1
  667. package/clis/stackoverflow/read.js +6 -6
  668. package/clis/stackoverflow/related.js +1 -1
  669. package/clis/stackoverflow/tag.js +1 -1
  670. package/clis/stackoverflow/user.js +1 -1
  671. package/clis/stackoverflow/utils.js +1 -1
  672. package/clis/steam/app.js +1 -1
  673. package/clis/steam/search.js +1 -1
  674. package/clis/steam/utils.js +1 -1
  675. package/clis/substack/auth.js +2 -2
  676. package/clis/substack/post-utils.js +2 -2
  677. package/clis/substack/publish.js +5 -5
  678. package/clis/suno/auth.js +2 -2
  679. package/clis/suno/download.js +5 -5
  680. package/clis/suno/generate.js +3 -3
  681. package/clis/suno/list.js +1 -1
  682. package/clis/suno/status.js +1 -1
  683. package/clis/suno/utils.js +29 -29
  684. package/clis/telegram/send.js +7 -7
  685. package/clis/telegram/shared.js +2 -2
  686. package/clis/telegram/whoami.js +1 -1
  687. package/clis/test-utils.js +1 -1
  688. package/clis/threads/post.js +23 -23
  689. package/clis/threads/shared.js +3 -3
  690. package/clis/threads/whoami.js +1 -1
  691. package/clis/tieba/hot.js +3 -3
  692. package/clis/tieba/posts.js +1 -1
  693. package/clis/tieba/read.js +2 -2
  694. package/clis/tieba/search.js +3 -3
  695. package/clis/tieba/utils.js +1 -1
  696. package/clis/tiktok/comment.js +2 -2
  697. package/clis/tiktok/creator-videos.js +3 -3
  698. package/clis/tiktok/explore.js +3 -3
  699. package/clis/tiktok/follow.js +8 -8
  700. package/clis/tiktok/following.js +4 -4
  701. package/clis/tiktok/friends.js +7 -7
  702. package/clis/tiktok/live.js +3 -3
  703. package/clis/tiktok/notifications.js +6 -6
  704. package/clis/tiktok/publish.js +17 -17
  705. package/clis/tiktok/unfollow.js +4 -4
  706. package/clis/tiktok/user.js +2 -2
  707. package/clis/tiktok/utils.js +1 -1
  708. package/clis/toutiao/article.js +1 -1
  709. package/clis/toutiao/articles.js +2 -2
  710. package/clis/toutiao/auth.js +2 -2
  711. package/clis/toutiao/hot.js +1 -1
  712. package/clis/toutiao/recommend.js +1 -1
  713. package/clis/toutiao/utils.js +2 -2
  714. package/clis/trae-solo/_actions.js +4 -4
  715. package/clis/trae-solo/_fs.js +5 -5
  716. package/clis/trae-solo/_state.js +2 -2
  717. package/clis/trae-solo/automation.js +4 -4
  718. package/clis/trae-solo/mode.js +4 -4
  719. package/clis/trae-solo/model.js +4 -4
  720. package/clis/trae-solo/renderer-storage.js +4 -4
  721. package/clis/trae-solo/settings.js +1 -1
  722. package/clis/trae-solo/skill-fs.js +1 -1
  723. package/clis/trae-solo/skill.js +12 -12
  724. package/clis/trae-solo/state-fs.js +2 -2
  725. package/clis/trae-solo/task-fs.js +5 -5
  726. package/clis/trae-solo/workspaces-fs.js +1 -1
  727. package/clis/tumblr/auth.js +2 -2
  728. package/clis/tumblr/publish.js +3 -3
  729. package/clis/tvmaze/search.js +1 -1
  730. package/clis/tvmaze/show.js +1 -1
  731. package/clis/tvmaze/utils.js +1 -1
  732. package/clis/twitter/accept.js +7 -7
  733. package/clis/twitter/article.js +7 -7
  734. package/clis/twitter/bookmark-folder.js +3 -3
  735. package/clis/twitter/bookmark-folders.js +3 -3
  736. package/clis/twitter/bookmarks.js +4 -4
  737. package/clis/twitter/delete.js +5 -5
  738. package/clis/twitter/device-follow.js +3 -3
  739. package/clis/twitter/dm-list.js +1 -1
  740. package/clis/twitter/dm-read.js +1 -1
  741. package/clis/twitter/dm-send.js +5 -5
  742. package/clis/twitter/dm-shared.js +3 -3
  743. package/clis/twitter/download.js +6 -6
  744. package/clis/twitter/followers.js +5 -5
  745. package/clis/twitter/following.js +2 -2
  746. package/clis/twitter/like.js +3 -3
  747. package/clis/twitter/likes.js +8 -8
  748. package/clis/twitter/list-add-core.js +9 -9
  749. package/clis/twitter/list-create.js +5 -5
  750. package/clis/twitter/list-remove-core.js +9 -9
  751. package/clis/twitter/list-tweets.js +7 -7
  752. package/clis/twitter/lists.js +6 -6
  753. package/clis/twitter/notifications.js +2 -2
  754. package/clis/twitter/post.js +24 -24
  755. package/clis/twitter/profile.js +7 -7
  756. package/clis/twitter/quote.js +7 -7
  757. package/clis/twitter/reply-dm.js +7 -7
  758. package/clis/twitter/reply.js +12 -12
  759. package/clis/twitter/retweet.js +3 -3
  760. package/clis/twitter/scheduled-delete.js +3 -3
  761. package/clis/twitter/scheduled-list.js +2 -2
  762. package/clis/twitter/scheduled-utils.js +3 -3
  763. package/clis/twitter/search.js +5 -5
  764. package/clis/twitter/shared.js +6 -6
  765. package/clis/twitter/thread.js +4 -4
  766. package/clis/twitter/timeline.js +3 -3
  767. package/clis/twitter/trending.js +2 -2
  768. package/clis/twitter/tweets.js +11 -11
  769. package/clis/twitter/unlike.js +3 -3
  770. package/clis/twitter/unretweet.js +3 -3
  771. package/clis/twitter/utils.js +6 -6
  772. package/clis/upwork/detail.js +2 -2
  773. package/clis/upwork/feed.js +2 -2
  774. package/clis/upwork/search.js +2 -2
  775. package/clis/upwork/utils.js +1 -1
  776. package/clis/v2ex/auth.js +2 -2
  777. package/clis/v2ex/daily.js +3 -3
  778. package/clis/v2ex/me.js +2 -2
  779. package/clis/v2ex/notifications.js +2 -2
  780. package/clis/vk/post.js +1 -1
  781. package/clis/vk/shared.js +2 -2
  782. package/clis/vk/whoami.js +1 -1
  783. package/clis/web/read.js +8 -8
  784. package/clis/wechat-channels/auth.js +2 -2
  785. package/clis/wechat-channels/publish.js +30 -30
  786. package/clis/weibo/article.js +1 -1
  787. package/clis/weibo/auth.js +3 -3
  788. package/clis/weibo/comments.js +1 -1
  789. package/clis/weibo/delete.js +2 -2
  790. package/clis/weibo/feed.js +3 -3
  791. package/clis/weibo/hot.js +1 -1
  792. package/clis/weibo/publish.js +10 -10
  793. package/clis/weibo/search.js +2 -2
  794. package/clis/weibo/user-posts.js +3 -3
  795. package/clis/weibo/user.js +2 -2
  796. package/clis/weibo/utils.js +3 -3
  797. package/clis/weixin/article.js +1 -1
  798. package/clis/weixin/create-draft.js +26 -26
  799. package/clis/weixin/download.js +2 -2
  800. package/clis/weixin/login.js +1 -1
  801. package/clis/weixin/search.js +2 -2
  802. package/clis/weixin/stats.js +3 -3
  803. package/clis/weixin/whoami.js +1 -1
  804. package/clis/weread/ai-outline.js +2 -2
  805. package/clis/weread/book-search.js +2 -2
  806. package/clis/weread/book.js +2 -2
  807. package/clis/weread/notebooks.js +1 -1
  808. package/clis/weread/search.js +1 -1
  809. package/clis/weread/shelf.js +1 -1
  810. package/clis/weread/utils.js +6 -6
  811. package/clis/weread-official/book.js +1 -1
  812. package/clis/weread-official/discover.js +1 -1
  813. package/clis/weread-official/list-apis.js +1 -1
  814. package/clis/weread-official/notes.js +1 -1
  815. package/clis/weread-official/readdata.js +1 -1
  816. package/clis/weread-official/review.js +1 -1
  817. package/clis/weread-official/search.js +1 -1
  818. package/clis/weread-official/shelf.js +1 -1
  819. package/clis/weread-official/utils.js +1 -1
  820. package/clis/wikidata/entity.js +1 -1
  821. package/clis/wikidata/search.js +1 -1
  822. package/clis/wikidata/utils.js +1 -1
  823. package/clis/wikipedia/page.js +1 -1
  824. package/clis/wikipedia/trending.js +1 -1
  825. package/clis/wikipedia/utils.js +1 -1
  826. package/clis/wordpress/login.js +1 -1
  827. package/clis/wordpress/publish.js +1 -1
  828. package/clis/wordpress/shared.js +3 -3
  829. package/clis/wordpress/whoami.js +1 -1
  830. package/clis/woshipm/article.js +1 -1
  831. package/clis/woshipm/login.js +1 -1
  832. package/clis/woshipm/stats.js +4 -4
  833. package/clis/woshipm/whoami.js +1 -1
  834. package/clis/wttr/current.js +1 -1
  835. package/clis/wttr/forecast.js +1 -1
  836. package/clis/wttr/utils.js +1 -1
  837. package/clis/xianyu/collect.js +1 -1
  838. package/clis/xianyu/inbox.js +1 -1
  839. package/clis/xianyu/item-stats.js +2 -2
  840. package/clis/xianyu/location.js +1 -1
  841. package/clis/xianyu/manage.js +1 -1
  842. package/clis/xianyu/messages.js +1 -1
  843. package/clis/xianyu/mtop.js +5 -5
  844. package/clis/xianyu/order.js +1 -1
  845. package/clis/xianyu/promote-stats.js +2 -2
  846. package/clis/xianyu/publish.js +17 -17
  847. package/clis/xianyu/rate.js +1 -1
  848. package/clis/xianyu/reply.js +1 -1
  849. package/clis/xianyu/search.js +8 -8
  850. package/clis/xianyu/seller-data.js +1 -1
  851. package/clis/xianyu/seller-list.js +1 -1
  852. package/clis/xianyu/user.js +1 -1
  853. package/clis/xiaoe/catalog.js +2 -2
  854. package/clis/xiaoe/content.js +2 -2
  855. package/clis/xiaoe/courses.js +2 -2
  856. package/clis/xiaohongshu/ask.js +6 -6
  857. package/clis/xiaohongshu/comments.js +6 -6
  858. package/clis/xiaohongshu/creator-note-detail.js +7 -7
  859. package/clis/xiaohongshu/creator-notes-summary.js +1 -1
  860. package/clis/xiaohongshu/creator-notes.js +13 -13
  861. package/clis/xiaohongshu/creator-profile.js +2 -2
  862. package/clis/xiaohongshu/creator-stats.js +2 -2
  863. package/clis/xiaohongshu/delete-note.js +7 -7
  864. package/clis/xiaohongshu/download.js +4 -4
  865. package/clis/xiaohongshu/feed.js +2 -2
  866. package/clis/xiaohongshu/follow.js +3 -3
  867. package/clis/xiaohongshu/human.js +3 -3
  868. package/clis/xiaohongshu/note-helpers.js +1 -1
  869. package/clis/xiaohongshu/note.js +2 -2
  870. package/clis/xiaohongshu/notifications.js +1 -1
  871. package/clis/xiaohongshu/publish-video.js +8 -8
  872. package/clis/xiaohongshu/publish.js +59 -59
  873. package/clis/xiaohongshu/search.js +8 -8
  874. package/clis/xiaohongshu/unfollow.js +4 -4
  875. package/clis/xiaohongshu/user-helpers.js +1 -1
  876. package/clis/xiaohongshu/user.js +2 -2
  877. package/clis/xiaoyuzhou/auth.js +3 -3
  878. package/clis/xiaoyuzhou/download.js +1 -1
  879. package/clis/xiaoyuzhou/utils.js +1 -1
  880. package/clis/xueqiu/article.js +4 -4
  881. package/clis/xueqiu/comments.js +4 -4
  882. package/clis/xueqiu/danjuan-utils.js +4 -4
  883. package/clis/xueqiu/earnings-date.js +1 -1
  884. package/clis/xueqiu/events.js +3 -3
  885. package/clis/xueqiu/hashtags.js +3 -3
  886. package/clis/xueqiu/stocks.js +3 -3
  887. package/clis/xueqiu/users.js +3 -3
  888. package/clis/xueqiu/utils.js +3 -3
  889. package/clis/yahoo-finance/quote.js +1 -1
  890. package/clis/yollomi/background.js +1 -1
  891. package/clis/yollomi/edit.js +1 -1
  892. package/clis/yollomi/face-swap.js +1 -1
  893. package/clis/yollomi/generate.js +1 -1
  894. package/clis/yollomi/object-remover.js +1 -1
  895. package/clis/yollomi/remove-bg.js +1 -1
  896. package/clis/yollomi/restore.js +1 -1
  897. package/clis/yollomi/try-on.js +1 -1
  898. package/clis/yollomi/upload.js +4 -4
  899. package/clis/yollomi/upscale.js +1 -1
  900. package/clis/yollomi/utils.js +4 -4
  901. package/clis/yollomi/video.js +1 -1
  902. package/clis/youtube/channel.js +4 -4
  903. package/clis/youtube/feed.js +2 -2
  904. package/clis/youtube/like.js +5 -5
  905. package/clis/youtube/playlist.js +7 -7
  906. package/clis/youtube/publish.js +11 -11
  907. package/clis/youtube/search.js +3 -3
  908. package/clis/youtube/subscribe.js +7 -7
  909. package/clis/youtube/subscriptions.js +1 -1
  910. package/clis/youtube/transcript-group.js +2 -2
  911. package/clis/youtube/transcript.js +13 -13
  912. package/clis/youtube/unlike.js +5 -5
  913. package/clis/youtube/unsubscribe.js +7 -7
  914. package/clis/youtube/utils.js +3 -3
  915. package/clis/youtube/video.js +4 -4
  916. package/clis/youtube/watch-later.js +2 -2
  917. package/clis/yuanbao/ask.js +18 -18
  918. package/clis/yuanbao/detail.js +1 -1
  919. package/clis/yuanbao/read.js +1 -1
  920. package/clis/yuanbao/shared.js +9 -9
  921. package/clis/yuanbao/status.js +1 -1
  922. package/clis/yuque/article.js +1 -1
  923. package/clis/yuque/whoami.js +1 -1
  924. package/clis/zhihu/answer-comments.js +2 -2
  925. package/clis/zhihu/answer-detail.js +3 -3
  926. package/clis/zhihu/answer.js +1 -1
  927. package/clis/zhihu/article-transform.js +1 -1
  928. package/clis/zhihu/article.js +1 -1
  929. package/clis/zhihu/auth.js +2 -2
  930. package/clis/zhihu/collection.js +3 -3
  931. package/clis/zhihu/collections.js +3 -3
  932. package/clis/zhihu/download.js +2 -2
  933. package/clis/zhihu/image-profile.js +6 -6
  934. package/clis/zhihu/paginate.js +3 -3
  935. package/clis/zhihu/pin.js +4 -4
  936. package/clis/zhihu/question.js +3 -3
  937. package/clis/zhihu/recommend.js +3 -3
  938. package/clis/zhihu/search.js +3 -3
  939. package/clis/zhihu/stats.js +3 -3
  940. package/clis/zhihu/user-arg.js +1 -1
  941. package/clis/zhihu/write-shared.js +7 -7
  942. package/clis/zlibrary/utils.js +6 -6
  943. package/clis/zsxq/auth.js +3 -3
  944. package/clis/zsxq/search.js +1 -1
  945. package/clis/zsxq/topic.js +1 -1
  946. package/clis/zsxq/utils.js +5 -5
  947. package/dist/src/adapter-source.js +1 -1
  948. package/dist/src/browser/analyze.js +1 -1
  949. package/dist/src/browser/article-extract.js +2 -2
  950. package/dist/src/browser/ax-snapshot.js +2 -2
  951. package/dist/src/browser/base-page.js +25 -25
  952. package/dist/src/browser/bridge.js +1 -1
  953. package/dist/src/browser/cdp.js +1 -1
  954. package/dist/src/browser/daemon-client.js +1 -1
  955. package/dist/src/browser/daemon-lifecycle.js +7 -7
  956. package/dist/src/browser/dom-helpers.js +35 -35
  957. package/dist/src/browser/dom-snapshot.js +19 -19
  958. package/dist/src/browser/errors.js +3 -3
  959. package/dist/src/browser/extract.js +5 -5
  960. package/dist/src/browser/find.js +13 -13
  961. package/dist/src/browser/fingerprint.js +2 -2
  962. package/dist/src/browser/html-tree.js +6 -6
  963. package/dist/src/browser/managed-chrome.js +1 -1
  964. package/dist/src/browser/network-cache.js +1 -1
  965. package/dist/src/browser/network-key.js +1 -1
  966. package/dist/src/browser/page.js +7 -7
  967. package/dist/src/browser/profile.js +2 -2
  968. package/dist/src/browser/proxy-test.js +8 -8
  969. package/dist/src/browser/shape-filter.js +1 -1
  970. package/dist/src/browser/shape.js +1 -1
  971. package/dist/src/browser/stealth.js +3 -3
  972. package/dist/src/browser/tabs.js +2 -2
  973. package/dist/src/browser/target-errors.js +1 -1
  974. package/dist/src/browser/target-resolver.js +23 -23
  975. package/dist/src/browser/trace.js +2 -2
  976. package/dist/src/browser/utils.js +1 -1
  977. package/dist/src/browser/verify-fixture.js +2 -2
  978. package/dist/src/browser-session-lock.js +1 -1
  979. package/dist/src/build-manifest.js +11 -11
  980. package/dist/src/capabilityRouting.js +1 -1
  981. package/dist/src/cli-argv-preprocess.js +1 -1
  982. package/dist/src/cli.js +32 -32
  983. package/dist/src/commanderAdapter.js +3 -3
  984. package/dist/src/commands/auth.js +3 -3
  985. package/dist/src/commands/daemon.js +1 -1
  986. package/dist/src/completion-fast.js +1 -1
  987. package/dist/src/completion.js +1 -1
  988. package/dist/src/constants.js +1 -1
  989. package/dist/src/convention-audit.js +2 -2
  990. package/dist/src/daemon-utils.js +1 -1
  991. package/dist/src/daemon.js +1 -1
  992. package/dist/src/discovery.js +2 -2
  993. package/dist/src/doctor.js +9 -9
  994. package/dist/src/download/article-download.js +15 -15
  995. package/dist/src/download/index.js +4 -4
  996. package/dist/src/download/media-download.js +1 -1
  997. package/dist/src/download/progress.js +3 -3
  998. package/dist/src/electron-apps.js +1 -1
  999. package/dist/src/errors.js +2 -2
  1000. package/dist/src/execution.js +2 -2
  1001. package/dist/src/external.js +1 -1
  1002. package/dist/src/help.js +8 -8
  1003. package/dist/src/hooks.js +1 -1
  1004. package/dist/src/interceptor.js +21 -21
  1005. package/dist/src/launcher.js +7 -7
  1006. package/dist/src/logger.js +8 -8
  1007. package/dist/src/main.js +7 -7
  1008. package/dist/src/observation/artifact.js +5 -5
  1009. package/dist/src/observation/retention.js +1 -1
  1010. package/dist/src/output.js +2 -2
  1011. package/dist/src/package-paths.js +1 -1
  1012. package/dist/src/pipeline/executor.js +1 -1
  1013. package/dist/src/pipeline/registry.js +1 -1
  1014. package/dist/src/pipeline/steps/browser.js +1 -1
  1015. package/dist/src/pipeline/steps/download.js +1 -1
  1016. package/dist/src/pipeline/steps/fetch.js +6 -6
  1017. package/dist/src/pipeline/steps/intercept.js +1 -1
  1018. package/dist/src/pipeline/steps/tap.js +17 -17
  1019. package/dist/src/pipeline/steps/transform.js +1 -1
  1020. package/dist/src/pipeline/template.js +1 -1
  1021. package/dist/src/plugin-manifest.js +1 -1
  1022. package/dist/src/plugin-scaffold.js +19 -19
  1023. package/dist/src/plugin.js +12 -12
  1024. package/dist/src/rate-limit.js +1 -1
  1025. package/dist/src/registry.js +1 -1
  1026. package/dist/src/runtime-detect.js +1 -1
  1027. package/dist/src/runtime.js +1 -1
  1028. package/dist/src/scripts/framework.js +1 -1
  1029. package/dist/src/scripts/interact.js +1 -1
  1030. package/dist/src/scripts/store.js +1 -1
  1031. package/dist/src/serialization.js +2 -2
  1032. package/dist/src/session-lease.js +1 -1
  1033. package/dist/src/snapshotFormatter.js +2 -2
  1034. package/dist/src/tui.js +12 -12
  1035. package/dist/src/user-runtime.js +1 -1
  1036. package/dist/src/utils.d.ts +12 -0
  1037. package/dist/src/utils.js +4 -4
  1038. package/dist/src/validate.js +2 -2
  1039. package/dist/src/verify.js +2 -2
  1040. package/dist/src/version.js +1 -1
  1041. package/package.json +1 -1
@@ -1,3 +1,3 @@
1
- import{log as w}from"./logger.js";import y from"js-yaml";import{fullName as F,getRegistry as T}from"./registry.js";import{render as A}from"./output.js";import{executeCommand as N,prepareCommandArgs as H}from"./execution.js";import{enforceRateLimit as x}from"./rate-limit.js";import{commandHelpData as S,formatCommandHelpText as R,formatCommandListTerm as f,formatSiteCommandDescription as v,formatSiteHelpText as b,getRequestedHelpFormat as j,renderStructuredHelp as E,siteHelpData as C}from"./help.js";import{CliError as u,EXIT_CODES as g,toEnvelope as p}from"./errors.js";export function registerCommandToProgram(Z,J){if(Z.commands.some((z)=>z.name()===J.name))return;const Q=Z.command(J.name).description(v(J));if(J.aliases?.length)Q.aliases(J.aliases);const P=[];for(const z of J.args)if(z.positional){const U=z.required?`<${z.name}>`:`[${z.name}]`;Q.argument(U,z.help??"");P.push(z)}else{const V=z.required||z.valueRequired?`--${z.name} <value>`:`--${z.name} [value]`;if(z.required)Q.requiredOption(V,z.help??"");else if(z.default!=null)Q.option(V,z.help??"",String(z.default));else Q.option(V,z.help??"")}Q.option("-f, --format <fmt>","Output format: table, plain, json, yaml, md, csv","table").option("--trace <mode>","Trace capture: off, on, retain-on-failure","off").option("-v, --verbose","Debug output",!1);if(J.browser)Q.option("--window <mode>","Browser window mode: foreground or background").option("--site-session <mode>","Adapter site session lifecycle: ephemeral or persistent").option("--keep-tab <bool>","Keep the browser tab lease after the command finishes");const W=Q.helpInformation.bind(Q);Q.helpInformation=(z)=>{const U=j();if(U)return E(S(J),U);W(z);return R(J)};Q.action(async(...z)=>{const U=z[P.length]??{},V=typeof U==="object"&&U!==null?U:{},I=Date.now();try{const Y={};for(let $=0;$<P.length;$++){const L=z[$];if(L!==void 0)Y[P[$].name]=L}for(const $ of J.args){if($.positional)continue;const L=$.name.replace(/-([a-z])/g,(O,K)=>K.toUpperCase()),k=V[$.name]??V[L];if(k!==void 0)Y[$.name]=k}const _={};for(const $ of J.args){if($.positional)continue;const L=$.name.replace(/-([a-z])/g,(O,K)=>K.toUpperCase()),k=Q.getOptionValueSource(L)??Q.getOptionValueSource($.name);if(k==="cli")_[$.name]=k}if(Object.keys(_).length>0)Y.__opencliOptionSources=_;const h=H(J,Y);x(F(J));const B=V.verbose===!0;let D=typeof V.format==="string"?V.format:"table";const M=Q.getOptionValueSource("format")==="cli";if(B)process.env.OPENCLI_VERBOSE="1";const G=typeof Q.optsWithGlobals==="function"?Q.optsWithGlobals():{},q=await N(J,h,B,{prepared:!0,...typeof G.profile==="string"&&G.profile.trim()?{profile:G.profile.trim()}:{},...typeof V.trace==="string"&&V.trace!=="off"?{trace:V.trace}:{},...J.browser&&typeof V.window==="string"?{windowMode:V.window}:{},...J.browser&&typeof V.siteSession==="string"?{siteSession:V.siteSession}:{},...J.browser&&typeof V.keepTab==="string"?{keepTab:V.keepTab}:{}});if(q===null||q===void 0)return;const X=T().get(F(J))??J;if(!M&&D==="table"&&X.defaultFormat)D=X.defaultFormat;if(B&&(!q||Array.isArray(q)&&q.length===0))w.warn("Command returned an empty result.");A(q,{fmt:D,fmtExplicit:M,columns:X.columns,title:`${X.site}/${X.name}`,elapsed:(Date.now()-I)/1000,source:F(X),footerExtra:X.footerExtra?.(h)})}catch(Y){i(Y,F(J),V.verbose===!0,V.trace);process.exitCode=l(Y)}})}function l(Z){if(Z instanceof u)return Z.exitCode;return g.GENERIC_ERROR}function n(Z,J,Q){if(Q==="on"||Q==="retain-on-failure")return Z;const P=J.replace("/"," ");return Z+`# AutoFix: re-run with --trace=retain-on-failure for trace artifact
2
- # ppcli ${P} --trace retain-on-failure
3
- `}function i(Z,J,Q,P){const W=p(Z);if(Q&&Z instanceof Error&&Z.stack)W.error.stack=Z.stack;let z=y.dump(W,{sortKeys:!1,lineWidth:120,noRefs:!0});const U=W.error.code;if(U==="SELECTOR"||U==="EMPTY_RESULT"||U==="ADAPTER_LOAD"||U==="UNKNOWN")z=n(z,J,P);process.stderr.write(z)}export function registerAllCommands(Z,J){const Q=new Set,P=new Map;for(const[,W]of T()){if(Q.has(W))continue;Q.add(W);const z=P.get(W.site)??[];z.push(W);P.set(W.site,z)}for(const[W,z]of P){let U=J.get(W);if(!U){U=Z.command(W);J.set(W,U)}for(const Y of z)registerCommandToProgram(U,Y);const V=new Map(z.map((Y)=>[Y.name,f(Y)]));U.configureHelp({subcommandTerm:(Y)=>V.get(Y.name())??Y.name()});const I=U.helpInformation.bind(U);U.helpInformation=(Y)=>{const _=j();if(_)return E(C(W,z),_);I(Y);return b(W,z)}}return[...P.keys()].sort((W,z)=>W.localeCompare(z))}
1
+ import{log as R}from"./logger.js";import k from"js-yaml";import{fullName as g,getRegistry as v}from"./registry.js";import{render as A}from"./output.js";import{executeCommand as H,prepareCommandArgs as D}from"./execution.js";import{enforceRateLimit as I}from"./rate-limit.js";import{commandHelpData as _,formatCommandHelpText as N,formatCommandListTerm as q,formatSiteCommandDescription as L,formatSiteHelpText as V,getRequestedHelpFormat as x,renderStructuredHelp as O,siteHelpData as F}from"./help.js";import{CliError as K,EXIT_CODES as P,toEnvelope as U}from"./errors.js";export function registerCommandToProgram(s,o){if(s.commands.some((e)=>e.name()===o.name))return;const t=s.command(o.name).description(L(o));if(o.aliases?.length)t.aliases(o.aliases);const l=[];for(const e of o.args)if(e.positional){const r=e.required?`<${e.name}>`:`[${e.name}]`;t.argument(r,e.help??"");l.push(e)}else{const n=e.required||e.valueRequired?`--${e.name} <value>`:`--${e.name} [value]`;if(e.required)t.requiredOption(n,e.help??"");else if(e.default!=null)t.option(n,e.help??"",String(e.default));else t.option(n,e.help??"")}t.option("-f, --format <fmt>","Output format: table, plain, json, yaml, md, csv","table").option("--trace <mode>","Trace capture: off, on, retain-on-failure","off").option("-v, --verbose","Debug output",!1);if(o.browser)t.option("--window <mode>","Browser window mode: foreground or background").option("--site-session <mode>","Adapter site session lifecycle: ephemeral or persistent").option("--keep-tab <bool>","Keep the browser tab lease after the command finishes");const a=t.helpInformation.bind(t);t.helpInformation=(e)=>{const r=x();if(r)return O(_(o),r);a(e);return N(o)};t.action(async(...e)=>{const r=e[l.length]??{},n=typeof r==="object"&&r!==null?r:{},b=Date.now();try{const i={};for(let f=0;f<l.length;f++){const u=e[f];if(u!==void 0)i[l[f].name]=u}for(const f of o.args){if(f.positional)continue;const u=f.name.replace(/-([a-z])/g,(T,y)=>y.toUpperCase()),d=n[f.name]??n[u];if(d!==void 0)i[f.name]=d}const p={};for(const f of o.args){if(f.positional)continue;const u=f.name.replace(/-([a-z])/g,(T,y)=>y.toUpperCase()),d=t.getOptionValueSource(u)??t.getOptionValueSource(f.name);if(d==="cli")p[f.name]=d}if(Object.keys(p).length>0)i.__opencliOptionSources=p;const C=D(o,i);I(g(o));const w=n.verbose===!0;let h=typeof n.format==="string"?n.format:"table";const S=t.getOptionValueSource("format")==="cli";if(w)process.env.OPENCLI_VERBOSE="1";const E=typeof t.optsWithGlobals==="function"?t.optsWithGlobals():{},c=await H(o,C,w,{prepared:!0,...typeof E.profile==="string"&&E.profile.trim()?{profile:E.profile.trim()}:{},...typeof n.trace==="string"&&n.trace!=="off"?{trace:n.trace}:{},...o.browser&&typeof n.window==="string"?{windowMode:n.window}:{},...o.browser&&typeof n.siteSession==="string"?{siteSession:n.siteSession}:{},...o.browser&&typeof n.keepTab==="string"?{keepTab:n.keepTab}:{}});if(c===null||c===void 0)return;const m=v().get(g(o))??o;if(!S&&h==="table"&&m.defaultFormat)h=m.defaultFormat;if(w&&(!c||Array.isArray(c)&&c.length===0))R.warn("Command returned an empty result.");A(c,{fmt:h,fmtExplicit:S,columns:m.columns,title:`${m.site}/${m.name}`,elapsed:(Date.now()-b)/1000,source:g(m),footerExtra:m.footerExtra?.(C)})}catch(i){B(i,g(o),n.verbose===!0,n.trace);process.exitCode=W(i)}})}function W(s){if(s instanceof K)return s.exitCode;return P.GENERIC_ERROR}function j(s,o,t){if(t==="on"||t==="retain-on-failure")return s;const l=o.replace("/"," ");return s+`# AutoFix: re-run with --trace=retain-on-failure for trace artifact
2
+ # ppcli ${l} --trace retain-on-failure
3
+ `}function B(s,o,t,l){const a=U(s);if(t&&s instanceof Error&&s.stack)a.error.stack=s.stack;let e=k.dump(a,{sortKeys:!1,lineWidth:120,noRefs:!0});const r=a.error.code;if(r==="SELECTOR"||r==="EMPTY_RESULT"||r==="ADAPTER_LOAD"||r==="UNKNOWN")e=j(e,o,l);process.stderr.write(e)}export function registerAllCommands(s,o){const t=new Set,l=new Map;for(const[,a]of v()){if(t.has(a))continue;t.add(a);const e=l.get(a.site)??[];e.push(a);l.set(a.site,e)}for(const[a,e]of l){let r=o.get(a);if(!r){r=s.command(a);o.set(a,r)}for(const i of e)registerCommandToProgram(r,i);const n=new Map(e.map((i)=>[i.name,q(i)]));r.configureHelp({subcommandTerm:(i)=>n.get(i.name())??i.name()});const b=r.helpInformation.bind(r);r.helpInformation=(i)=>{const p=x();if(p)return O(F(a,e),p);b(i);return V(a,e)}}return[...l.keys()].sort((a,e)=>a.localeCompare(e))}
@@ -1,3 +1,3 @@
1
- import{mkdir as w,readFile as u,rename as WG,writeFile as l}from"node:fs/promises";import{homedir as p}from"node:os";import{dirname as n,join as c}from"node:path";import{pathToFileURL as KG}from"node:url";import{InvalidArgumentError as O,Option as LG}from"commander";import{AuthRequiredError as i,CliError as m,getErrorMessage as x}from"../errors.js";import{executeCommand as N}from"../execution.js";import{ensureBrowserBridgeReady as jG}from"../browser/daemon-lifecycle.js";import{resolveProfile as zG}from"../browser/profile.js";import{isElectronApp as P}from"../electron-apps.js";import{fullName as qG,getRegistry as a}from"../registry.js";import{render as d}from"../output.js";const T=1,k=86400000;function M(G,J,Y){if(G===void 0||G===null||G==="")return Y;const $=Number(G);if(!Number.isInteger($)||$<=0)throw new O(`${J} must be a positive integer. Received: "${String(G)}"`);return $}function s(G,J,Y){if(G===void 0||G===null||G==="")return Y;const $=Number(G);if(!Number.isInteger($)||$<0)throw new O(`${J} must be a non-negative integer. Received: "${String(G)}"`);return $}function o(G){if(!G||!G.trim())return null;const J=G.split(",").map((Y)=>Y.trim()).filter(Boolean);return J.length>0?new Set(J):null}function UG(){return c(p(),".ppcli","auth-refresh.json")}const b=1,dG=600000;function VG(){return c(p(),".ppcli","auth-state.json")}async function BG(G){try{const J=JSON.parse(await u(G,"utf8"));if(J&&J.version===b&&J.profiles&&typeof J.profiles==="object")return{version:b,profiles:J.profiles}}catch{}return{version:b,profiles:{}}}async function OG(G,J){await w(n(G),{recursive:!0});const Y=`${G}.${process.pid}.tmp`;await l(Y,`${JSON.stringify(J,null,2)}
2
- `,"utf8");await WG(Y,G)}function NG(G,J){return{site:G,status:J.status,logged_in:J.logged_in,identity:J.identity,checked:"cached",error:J.error,checked_at:new Date(J.at).toISOString(),verified:J.verifiedAt!==void 0}}function MG(G,J,Y,$){return{status:G.status,logged_in:G.logged_in,identity:G.identity,checked:G.checked,error:G.error,at:J,...Y!==void 0?{verifiedAt:Y}:{},...$!==void 0?{verifyAttemptAt:$}:{}}}function HG(){return{version:T,sites:{}}}async function IG(G){try{const J=JSON.parse(await u(G,"utf8"));if(J&&J.version===T&&J.sites&&typeof J.sites==="object")return{version:T,sites:J.sites}}catch(J){if(J.code!=="ENOENT")throw J}return HG()}async function CG(G,J){await w(n(G),{recursive:!0});await l(G,`${JSON.stringify(J,null,2)}
3
- `,"utf8")}function r(G){if(!G?.last_touched_at)return null;const J=Date.parse(G.last_touched_at);return Number.isFinite(J)?J:null}function _G(G,J){const Y=r(G);return Y!==null&&J.getTime()-Y<k}function q(G){const J=r(G);return J===null?"":new Date(J+k).toISOString()}function t(){const G=new Set;return[...a().values()].filter((J)=>{if(G.has(J))return!1;G.add(J);return J.name==="whoami"&&J.access==="read"}).sort((J,Y)=>J.site.localeCompare(Y.site))}async function R(G){const J=G;if(!J._lazy||!J._modulePath)return G;await import(KG(J._modulePath).href);return a().get(qG(G))??G}function H(G,J){const Y=G.args.some(($)=>$.name==="timeout");return{...G,args:Y?G.args:[...G.args,{name:"timeout",type:"int",default:J,help:"Per-site auth command timeout in seconds"}]}}function FG(G,J){if(G.browser!==!0||typeof G.authStatus?.quickCheck!=="function")return null;return H({...G,func:G.authStatus.quickCheck,navigateBefore:!1,siteSession:"ephemeral",defaultWindowMode:"background"},J)}function e(G){if(typeof G==="boolean")return G;if(G&&typeof G==="object"&&!Array.isArray(G)){const J=G.logged_in;if(typeof J==="boolean")return J}return null}function xG(G){const J=Array.isArray(G)?G[0]:G;if(J&&typeof J==="object"&&!Array.isArray(J)){const Y=J.logged_in;if(typeof Y==="boolean")return Y}return null}function PG(G){const J=Array.isArray(G)?G[0]:G;if(J&&typeof J==="object"&&!Array.isArray(J)){const Y=J.error;if(typeof Y==="string"&&Y.trim())return Y.trim()}return""}function GG(G){if(G===void 0||G===null)return"";if(typeof G==="string"||typeof G==="number"||typeof G==="boolean")return String(G);return""}function JG(G){const J=Array.isArray(G)?G[0]:G;if(!J||typeof J!=="object"||Array.isArray(J))return"";const Y=J,$=/(?:email|phone|real.?name|first.?name|last.?name|cookie|token|session|secret|password|csrf|jwt|bearer|wt2)/i;for(const Z of["username","handle","user_id","id","name","nickname","user_type","url"]){if($.test(Z))continue;const X=GG(Y[Z]);if(X)return X}for(const[Z,X]of Object.entries(Y)){if(Z==="site"||Z==="logged_in"||$.test(Z))continue;const Q=GG(X);if(Q)return Q}return""}function E(G){return G instanceof i||typeof G==="object"&&G!==null&&G.code==="AUTH_REQUIRED"}function YG(G,J,Y){if(E(Y))return{site:G,status:"not_logged_in",logged_in:!1,identity:"",checked:J,error:""};const $=Y instanceof m?Y.code:"",Z=x(Y);return{site:G,status:"error",logged_in:"",identity:"",checked:J,error:$?`${$}: ${Z}`:Z}}function TG(G,J){if(G.browser!==!0)return null;let Y=G.authStatus?.refresh;if(typeof Y!=="function"){const $=G.authStatus?.quickCheck;if(typeof $!=="function"||!G.domain)return null;const Z=G.domain.startsWith("http://")||G.domain.startsWith("https://")?G.domain:`https://${G.domain}`;Y=async(X,Q,W)=>{await X.goto(Z);await X.wait(1);if(e(await $(X,Q,W))!==!0)throw new i(G.domain??G.site,`Auth refresh quickCheck failed for ${G.site}`);return{status:"touched"}}}return H({...G,func:Y,navigateBefore:!1,siteSession:"persistent",defaultWindowMode:"background"},J)}function kG(G){if(G&&typeof G==="object"&&!Array.isArray(G)){const J=G;if(J.status==="refreshed"||J.refreshed===!0)return"refreshed"}return"touched"}function bG(G,J,Y){if(E(Y))return{site:G,status:"not_logged_in",last_touched_at:J?.last_touched_at??"",next_refresh_at:q(J),error:""};const $=Y instanceof m?Y.code:"",Z=x(Y);return{site:G,status:"error",last_touched_at:J?.last_touched_at??"",next_refresh_at:q(J),error:$?`${$}: ${Z}`:Z}}function ZG(){return process.env.PUBLISHPORT_SITE_SESSION==="ephemeral"?{siteSession:"ephemeral",keepTab:"false"}:{siteSession:"persistent",keepTab:"true"}}async function RG(G,J){try{const Y=await R(G);if(Y.browser!==!0){const Q=H(Y,J.timeoutSeconds),W=await N(Q,{timeout:J.timeoutSeconds},!1,{...J.profile?{profile:J.profile}:{}});return{site:G.site,status:"logged_in",logged_in:!0,identity:JG(W),checked:"quick",error:""}}if(Y.authStatus?.quickCheckRequiresNavigation===!0)return{site:G.site,status:"unknown",logged_in:"",identity:"",checked:"navigation_required",error:""};const $=FG(Y,J.timeoutSeconds);if(!$)return{site:G.site,status:"unknown",logged_in:"",identity:"",checked:"skipped",error:"quickCheck not implemented; use --full to run whoami"};const Z=await N($,{timeout:J.timeoutSeconds},!1,{...ZG(),windowMode:"background",...J.profile?{profile:J.profile}:{}}),X=e(Z);if(X===!0)return{site:G.site,status:"logged_in",logged_in:!0,identity:"",checked:"quick",error:""};if(X===!1)return{site:G.site,status:"not_logged_in",logged_in:!1,identity:"",checked:"quick",error:""};return{site:G.site,status:"unknown",logged_in:"",identity:"",checked:"quick",error:"quickCheck returned no boolean logged_in signal"}}catch(Y){return YG(G.site,"quick",Y)}}async function EG(G,J){try{const Y=await R(G),$=H(Y,J.timeoutSeconds),Z=await N($,{timeout:J.timeoutSeconds},!1,{...ZG(),windowMode:"background",...J.profile?{profile:J.profile}:{}});if(xG(Z)===!1)return{site:G.site,status:"not_logged_in",logged_in:!1,identity:"",checked:"full",error:PG(Z)};return{site:G.site,status:"logged_in",logged_in:!0,identity:JG(Z),checked:"full",error:""}}catch(Y){return YG(G.site,"full",Y)}}function SG(G,J){return J?`${G}@${J}`:G}async function vG(G,J){const Y=SG(G.site,J.profile),$=J.state.sites[Y];if(!J.force&&_G($,J.now))return{site:G.site,status:"skipped",last_touched_at:$?.last_touched_at??"",next_refresh_at:q($),error:""};const Z=J.now.toISOString();try{const X=await R(G),Q=TG(X,J.timeoutSeconds);if(!Q){J.state.sites[Y]={...$,last_attempt_at:Z,last_status:"unsupported"};return{site:G.site,status:"unsupported",last_touched_at:$?.last_touched_at??"",next_refresh_at:q($),error:"refresh probe is not available for this site"}}const W=await N(Q,{timeout:J.timeoutSeconds},!1,{siteSession:"persistent",keepTab:"true",windowMode:"background",...J.profile?{profile:J.profile}:{}}),j=kG(W);J.state.sites[Y]={...$,last_attempt_at:Z,last_touched_at:Z,last_status:j};return{site:G.site,status:j,last_touched_at:Z,next_refresh_at:new Date(J.now.getTime()+k).toISOString(),error:""}}catch(X){const Q=E(X)?"not_logged_in":"error";J.state.sites[Y]={...$,last_attempt_at:Z,last_status:Q};return bG(G.site,$,X)}}async function $G(G,J){const Y=zG(J);if(Y.kind!=="extension")return null;if(!G.some((Z)=>Z.browser===!0&&!P(Z.site)))return null;try{await jG({timeoutSeconds:15,contextId:Y.contextId,verbose:!1});return null}catch(Z){return x(Z)}}function fG(G,J,Y){return{site:G,status:"error",logged_in:"",identity:"",checked:J,error:`BROWSER_CONNECT: ${Y}`}}async function DG(G,J,Y){const $=Array(G.length);let Z=0;const X=Array.from({length:Math.min(J,G.length)},async()=>{while(Z<G.length){const Q=Z++;$[Q]=await Y(G[Q])}});await Promise.all(X);return $}export async function collectAuthStatus(G){const J=o(G.sites),Y=G.full?"full":"quick",$=M(G.concurrency,"--concurrency",Y==="full"?3:8),Z=M(G.timeout,"--timeout",Y==="full"?20:8),X=String(G.only??"all");if(!["all","logged-in","not-logged-in","unknown","error"].includes(X))throw new O("--only must be one of: all, logged-in, not-logged-in, unknown, error");if(Y==="full"&&!J)throw new O("--full 会对每个站点真实打开页面,不允许全量使用。"+"要实证某个站点请点名:auth status --site <site> --full;"+"想看全部站点就用默认的 quick(纯 cookie,不开任何页面)。");const Q=s(G.maxAge,"--max-age",0)*1000,W=s(G.verify,"--verify",0),j=G.statePath??VG(),z=(G.now??new Date).getTime(),K=G.profile??"",I=t().filter((D)=>!J||J.has(D.site)),C=await BG(j),U=C.profiles[K]??{},_=new Map,V=[];for(const D of I){const L=U[D.site];if(Q>0&&L&&z-L.at<Q)_.set(D.site,NG(D.site,L));else V.push(D)}const S=V.length>0?await $G(V,G.profile):null,XG=await DG(V,$,(D)=>S&&D.browser===!0&&!P(D.site)?Promise.resolve(fG(D.site,Y,S)):Y==="full"?EG(D,{timeoutSeconds:Z,profile:G.profile}):RG(D,{timeoutSeconds:Z,profile:G.profile})),gG=new Map(I.map((D)=>[D.site,D])),B=new Map(_),v=new Map,f=new Map;for(const D of XG){B.set(D.site,D);if(Y==="full"){f.set(D.site,z);if(D.status!=="error")v.set(D.site,z)}}const g=(D)=>{const L=v.get(D.site);if(L!==void 0)return L;const F=U[D.site];return F&&F.status===D.status?F.verifiedAt:void 0},QG=(D)=>f.get(D.site)??U[D.site]?.verifyAttemptAt,A={...U};for(const D of B.keys()){if(_.has(D))continue;const L=B.get(D);if(!L)continue;A[D]=MG(L,z,g(L),QG(L))}C.profiles[K]=A;await OG(j,C).catch(()=>{});const y=I.map((D)=>B.get(D.site)).filter((D)=>D!==void 0).map((D)=>({...D,checked_at:D.checked_at??new Date(z).toISOString(),verified:D.verified??g(D)!==void 0})),h=X.replace(/-/g,"_");return h==="all"?y:y.filter((D)=>D.status===h)}export async function collectAuthRefresh(G){const J=o(G.sites),Y=M(G.concurrency,"--concurrency",3),$=M(G.timeout,"--timeout",20),Z=G.statePath??UG(),X=G.now??new Date,Q=await IG(Z),W=t().filter((K)=>!J||J.has(K.site)),j=await $G(W,G.profile),z=await DG(W,Y,(K)=>j&&K.browser===!0&&!P(K.site)?Promise.resolve({site:K.site,status:"error",last_touched_at:Q.sites[K.site]?.last_touched_at??"",next_refresh_at:q(Q.sites[K.site]),error:`BROWSER_CONNECT: ${j}`}):vG(K,{timeoutSeconds:$,profile:G.profile,now:X,state:Q,force:G.all===!0}));await CG(Z,Q);return z}export function registerAuthCommands(G){const J=G.command("auth").description("Inspect website login status"),Y=J.command("status").description("Show login status for sites with auth adapters").option("--site <sites>","Comma-separated site names to check, e.g. github,chatgpt").option("--full","Run full per-site whoami probes instead of quick no-navigation checks",!1).option("--concurrency <n>","Maximum sites to check at once").option("--timeout <seconds>","Per-site timeout in seconds").option("--max-age <seconds>","Reuse a local cached verdict younger than this instead of probing").option("--verify <n>","Deprecated and ignored: batch auth status never navigates. Use --site <s> --full to confirm one site with a real whoami").addOption(new LG("--only <status>","Filter rows by status").choices(["all","logged-in","not-logged-in","unknown","error"]).default("all")).option("-f, --format <fmt>","Output format: table, plain, json, yaml, md, csv","table").action(async(Z)=>{const X=typeof Y.optsWithGlobals==="function"?Y.optsWithGlobals():{},Q=await collectAuthStatus({sites:Z.site,full:Z.full===!0,concurrency:Z.concurrency,timeout:Z.timeout,only:Z.only,maxAge:Z.maxAge,verify:Z.verify,profile:typeof X.profile==="string"&&X.profile.trim()?X.profile.trim():void 0}),W=typeof Z.format==="string"?Z.format:"table";d(Q,{fmt:W,fmtExplicit:Y.getOptionValueSource("format")==="cli",columns:["site","status","identity","checked","error"],title:"ppcli/auth status",source:Z.full?"full whoami probe":"quick auth check"})}),$=J.command("refresh").description("Touch logged-in site sessions to keep browser auth fresh").option("--site <sites>","Comma-separated site names to refresh, e.g. github,claude").option("--all","Ignore the 24h refresh throttle and force every selected site",!1).option("--concurrency <n>","Maximum sites to refresh at once").option("--timeout <seconds>","Per-site timeout in seconds").option("-f, --format <fmt>","Output format: table, plain, json, yaml, md, csv","table").action(async(Z)=>{const X=typeof $.optsWithGlobals==="function"?$.optsWithGlobals():{},Q=await collectAuthRefresh({sites:Z.site,all:Z.all===!0,concurrency:Z.concurrency,timeout:Z.timeout,profile:typeof X.profile==="string"&&X.profile.trim()?X.profile.trim():void 0}),W=typeof Z.format==="string"?Z.format:"table";d(Q,{fmt:W,fmtExplicit:$.getOptionValueSource("format")==="cli",columns:["site","status","last_touched_at","next_refresh_at","error"],title:"ppcli/auth refresh",source:Z.all?"forced persistent touch":"persistent touch with 24h throttle"})});return J}
1
+ import{mkdir as W,readFile as D,rename as ce,writeFile as U}from"node:fs/promises";import{homedir as H}from"node:os";import{dirname as V,join as z}from"node:path";import{pathToFileURL as le}from"node:url";import{InvalidArgumentError as y,Option as fe}from"commander";import{AuthRequiredError as L,CliError as G,getErrorMessage as R}from"../errors.js";import{executeCommand as _}from"../execution.js";import{ensureBrowserBridgeReady as de}from"../browser/daemon-lifecycle.js";import{resolveProfile as he}from"../browser/profile.js";import{isElectronApp as E}from"../electron-apps.js";import{fullName as ge,getRegistry as J}from"../registry.js";import{render as K}from"../output.js";const x=1,T=86400000;function w(e,t,r){if(e===void 0||e===null||e==="")return r;const i=Number(e);if(!Number.isInteger(i)||i<=0)throw new y(`${t} must be a positive integer. Received: "${String(e)}"`);return i}function Q(e,t,r){if(e===void 0||e===null||e==="")return r;const i=Number(e);if(!Number.isInteger(i)||i<0)throw new y(`${t} must be a non-negative integer. Received: "${String(e)}"`);return i}function Y(e){if(!e||!e.trim())return null;const t=e.split(",").map((r)=>r.trim()).filter(Boolean);return t.length>0?new Set(t):null}function me(){return z(H(),".ppcli","auth-refresh.json")}const C=1,Ke=600000;function pe(){return z(H(),".ppcli","auth-state.json")}async function ye(e){try{const t=JSON.parse(await D(e,"utf8"));if(t&&t.version===C&&t.profiles&&typeof t.profiles==="object")return{version:C,profiles:t.profiles}}catch{}return{version:C,profiles:{}}}async function _e(e,t){await W(V(e),{recursive:!0});const r=`${e}.${process.pid}.tmp`;await U(r,`${JSON.stringify(t,null,2)}
2
+ `,"utf8");await ce(r,e)}function we(e,t){return{site:e,status:t.status,logged_in:t.logged_in,identity:t.identity,checked:"cached",error:t.error,checked_at:new Date(t.at).toISOString(),verified:t.verifiedAt!==void 0}}function ke(e,t,r,i){return{status:e.status,logged_in:e.logged_in,identity:e.identity,checked:e.checked,error:e.error,at:t,...r!==void 0?{verifiedAt:r}:{},...i!==void 0?{verifyAttemptAt:i}:{}}}function Se(){return{version:x,sites:{}}}async function be(e){try{const t=JSON.parse(await D(e,"utf8"));if(t&&t.version===x&&t.sites&&typeof t.sites==="object")return{version:x,sites:t.sites}}catch(t){if(t.code!=="ENOENT")throw t}return Se()}async function Ae(e,t){await W(V(e),{recursive:!0});await U(e,`${JSON.stringify(t,null,2)}
3
+ `,"utf8")}function X(e){if(!e?.last_touched_at)return null;const t=Date.parse(e.last_touched_at);return Number.isFinite(t)?t:null}function ve(e,t){const r=X(e);return r!==null&&t.getTime()-r<T}function h(e){const t=X(e);return t===null?"":new Date(t+T).toISOString()}function Z(){const e=new Set;return[...J().values()].filter((t)=>{if(e.has(t))return!1;e.add(t);return t.name==="whoami"&&t.access==="read"}).sort((t,r)=>t.site.localeCompare(r.site))}async function O(e){const t=e;if(!t._lazy||!t._modulePath)return e;await import(le(t._modulePath).href);return J().get(ge(e))??e}function k(e,t){const r=e.args.some((i)=>i.name==="timeout");return{...e,args:r?e.args:[...e.args,{name:"timeout",type:"int",default:t,help:"Per-site auth command timeout in seconds"}]}}function Re(e,t){if(e.browser!==!0||typeof e.authStatus?.quickCheck!=="function")return null;return k({...e,func:e.authStatus.quickCheck,navigateBefore:!1,siteSession:"ephemeral",defaultWindowMode:"background"},t)}function ee(e){if(typeof e==="boolean")return e;if(e&&typeof e==="object"&&!Array.isArray(e)){const t=e.logged_in;if(typeof t==="boolean")return t}return null}function Ee(e){const t=Array.isArray(e)?e[0]:e;if(t&&typeof t==="object"&&!Array.isArray(t)){const r=t.logged_in;if(typeof r==="boolean")return r}return null}function xe(e){const t=Array.isArray(e)?e[0]:e;if(t&&typeof t==="object"&&!Array.isArray(t)){const r=t.error;if(typeof r==="string"&&r.trim())return r.trim()}return""}function te(e){if(e===void 0||e===null)return"";if(typeof e==="string"||typeof e==="number"||typeof e==="boolean")return String(e);return""}function re(e){const t=Array.isArray(e)?e[0]:e;if(!t||typeof t!=="object"||Array.isArray(t))return"";const r=t,i=/(?:email|phone|real.?name|first.?name|last.?name|cookie|token|session|secret|password|csrf|jwt|bearer|wt2)/i;for(const n of["username","handle","user_id","id","name","nickname","user_type","url"]){if(i.test(n))continue;const s=te(r[n]);if(s)return s}for(const[n,s]of Object.entries(r)){if(n==="site"||n==="logged_in"||i.test(n))continue;const a=te(s);if(a)return a}return""}function I(e){return e instanceof L||typeof e==="object"&&e!==null&&e.code==="AUTH_REQUIRED"}function ne(e,t,r){if(I(r))return{site:e,status:"not_logged_in",logged_in:!1,identity:"",checked:t,error:""};const i=r instanceof G?r.code:"",n=R(r);return{site:e,status:"error",logged_in:"",identity:"",checked:t,error:i?`${i}: ${n}`:n}}function Te(e,t){if(e.browser!==!0)return null;let r=e.authStatus?.refresh;if(typeof r!=="function"){const i=e.authStatus?.quickCheck;if(typeof i!=="function"||!e.domain)return null;const n=e.domain.startsWith("http://")||e.domain.startsWith("https://")?e.domain:`https://${e.domain}`;r=async(s,a,u)=>{await s.goto(n);await s.wait(1);if(ee(await i(s,a,u))!==!0)throw new L(e.domain??e.site,`Auth refresh quickCheck failed for ${e.site}`);return{status:"touched"}}}return k({...e,func:r,navigateBefore:!1,siteSession:"persistent",defaultWindowMode:"background"},t)}function Ce(e){if(e&&typeof e==="object"&&!Array.isArray(e)){const t=e;if(t.status==="refreshed"||t.refreshed===!0)return"refreshed"}return"touched"}function Oe(e,t,r){if(I(r))return{site:e,status:"not_logged_in",last_touched_at:t?.last_touched_at??"",next_refresh_at:h(t),error:""};const i=r instanceof G?r.code:"",n=R(r);return{site:e,status:"error",last_touched_at:t?.last_touched_at??"",next_refresh_at:h(t),error:i?`${i}: ${n}`:n}}function ie(){return process.env.PUBLISHPORT_SITE_SESSION==="ephemeral"?{siteSession:"ephemeral",keepTab:"false"}:{siteSession:"persistent",keepTab:"true"}}async function Ie(e,t){try{const r=await O(e);if(r.browser!==!0){const a=k(r,t.timeoutSeconds),u=await _(a,{timeout:t.timeoutSeconds},!1,{...t.profile?{profile:t.profile}:{}});return{site:e.site,status:"logged_in",logged_in:!0,identity:re(u),checked:"quick",error:""}}if(r.authStatus?.quickCheckRequiresNavigation===!0)return{site:e.site,status:"unknown",logged_in:"",identity:"",checked:"navigation_required",error:""};const i=Re(r,t.timeoutSeconds);if(!i)return{site:e.site,status:"unknown",logged_in:"",identity:"",checked:"skipped",error:"quickCheck not implemented; use --full to run whoami"};const n=await _(i,{timeout:t.timeoutSeconds},!1,{...ie(),windowMode:"background",...t.profile?{profile:t.profile}:{}}),s=ee(n);if(s===!0)return{site:e.site,status:"logged_in",logged_in:!0,identity:"",checked:"quick",error:""};if(s===!1)return{site:e.site,status:"not_logged_in",logged_in:!1,identity:"",checked:"quick",error:""};return{site:e.site,status:"unknown",logged_in:"",identity:"",checked:"quick",error:"quickCheck returned no boolean logged_in signal"}}catch(r){return ne(e.site,"quick",r)}}async function qe(e,t){try{const r=await O(e),i=k(r,t.timeoutSeconds),n=await _(i,{timeout:t.timeoutSeconds},!1,{...ie(),windowMode:"background",...t.profile?{profile:t.profile}:{}});if(Ee(n)===!1)return{site:e.site,status:"not_logged_in",logged_in:!1,identity:"",checked:"full",error:xe(n)};return{site:e.site,status:"logged_in",logged_in:!0,identity:re(n),checked:"full",error:""}}catch(r){return ne(e.site,"full",r)}}function Ne(e,t){return t?`${e}@${t}`:e}async function Me(e,t){const r=Ne(e.site,t.profile),i=t.state.sites[r];if(!t.force&&ve(i,t.now))return{site:e.site,status:"skipped",last_touched_at:i?.last_touched_at??"",next_refresh_at:h(i),error:""};const n=t.now.toISOString();try{const s=await O(e),a=Te(s,t.timeoutSeconds);if(!a){t.state.sites[r]={...i,last_attempt_at:n,last_status:"unsupported"};return{site:e.site,status:"unsupported",last_touched_at:i?.last_touched_at??"",next_refresh_at:h(i),error:"refresh probe is not available for this site"}}const u=await _(a,{timeout:t.timeoutSeconds},!1,{siteSession:"persistent",keepTab:"true",windowMode:"background",...t.profile?{profile:t.profile}:{}}),f=Ce(u);t.state.sites[r]={...i,last_attempt_at:n,last_touched_at:n,last_status:f};return{site:e.site,status:f,last_touched_at:n,next_refresh_at:new Date(t.now.getTime()+T).toISOString(),error:""}}catch(s){const a=I(s)?"not_logged_in":"error";t.state.sites[r]={...i,last_attempt_at:n,last_status:a};return Oe(e.site,i,s)}}async function oe(e,t){const r=he(t);if(r.kind!=="extension")return null;if(!e.some((n)=>n.browser===!0&&!E(n.site)))return null;try{await de({timeoutSeconds:15,contextId:r.contextId,verbose:!1});return null}catch(n){return R(n)}}function $e(e,t,r){return{site:e,status:"error",logged_in:"",identity:"",checked:t,error:`BROWSER_CONNECT: ${r}`}}async function se(e,t,r){const i=Array(e.length);let n=0;const s=Array.from({length:Math.min(t,e.length)},async()=>{while(n<e.length){const a=n++;i[a]=await r(e[a])}});await Promise.all(s);return i}export async function collectAuthStatus(e){const t=Y(e.sites),r=e.full?"full":"quick",i=w(e.concurrency,"--concurrency",r==="full"?3:8),n=w(e.timeout,"--timeout",r==="full"?20:8),s=String(e.only??"all");if(!["all","logged-in","not-logged-in","unknown","error"].includes(s))throw new y("--only must be one of: all, logged-in, not-logged-in, unknown, error");if(r==="full"&&!t)throw new y("--full 会对每个站点真实打开页面,不允许全量使用。"+"要实证某个站点请点名:auth status --site <site> --full;"+"想看全部站点就用默认的 quick(纯 cookie,不开任何页面)。");const a=Q(e.maxAge,"--max-age",0)*1000,u=Q(e.verify,"--verify",0),f=e.statePath??pe(),d=(e.now??new Date).getTime(),c=e.profile??"",S=Z().filter((o)=>!t||t.has(o.site)),b=await ye(f),g=b.profiles[c]??{},A=new Map,m=[];for(const o of S){const l=g[o.site];if(a>0&&l&&d-l.at<a)A.set(o.site,we(o.site,l));else m.push(o)}const q=m.length>0?await oe(m,e.profile):null,ae=await se(m,i,(o)=>q&&o.browser===!0&&!E(o.site)?Promise.resolve($e(o.site,r,q)):r==="full"?qe(o,{timeoutSeconds:n,profile:e.profile}):Ie(o,{timeoutSeconds:n,profile:e.profile})),Fe=new Map(S.map((o)=>[o.site,o])),p=new Map(A),N=new Map,M=new Map;for(const o of ae){p.set(o.site,o);if(r==="full"){M.set(o.site,d);if(o.status!=="error")N.set(o.site,d)}}const F=(o)=>{const l=N.get(o.site);if(l!==void 0)return l;const v=g[o.site];return v&&v.status===o.status?v.verifiedAt:void 0},ue=(o)=>M.get(o.site)??g[o.site]?.verifyAttemptAt,P={...g};for(const o of p.keys()){if(A.has(o))continue;const l=p.get(o);if(!l)continue;P[o]=ke(l,d,F(l),ue(l))}b.profiles[c]=P;await _e(f,b).catch(()=>{});const j=S.map((o)=>p.get(o.site)).filter((o)=>o!==void 0).map((o)=>({...o,checked_at:o.checked_at??new Date(d).toISOString(),verified:o.verified??F(o)!==void 0})),B=s.replace(/-/g,"_");return B==="all"?j:j.filter((o)=>o.status===B)}export async function collectAuthRefresh(e){const t=Y(e.sites),r=w(e.concurrency,"--concurrency",3),i=w(e.timeout,"--timeout",20),n=e.statePath??me(),s=e.now??new Date,a=await be(n),u=Z().filter((c)=>!t||t.has(c.site)),f=await oe(u,e.profile),d=await se(u,r,(c)=>f&&c.browser===!0&&!E(c.site)?Promise.resolve({site:c.site,status:"error",last_touched_at:a.sites[c.site]?.last_touched_at??"",next_refresh_at:h(a.sites[c.site]),error:`BROWSER_CONNECT: ${f}`}):Me(c,{timeoutSeconds:i,profile:e.profile,now:s,state:a,force:e.all===!0}));await Ae(n,a);return d}export function registerAuthCommands(e){const t=e.command("auth").description("Inspect website login status"),r=t.command("status").description("Show login status for sites with auth adapters").option("--site <sites>","Comma-separated site names to check, e.g. github,chatgpt").option("--full","Run full per-site whoami probes instead of quick no-navigation checks",!1).option("--concurrency <n>","Maximum sites to check at once").option("--timeout <seconds>","Per-site timeout in seconds").option("--max-age <seconds>","Reuse a local cached verdict younger than this instead of probing").option("--verify <n>","Deprecated and ignored: batch auth status never navigates. Use --site <s> --full to confirm one site with a real whoami").addOption(new fe("--only <status>","Filter rows by status").choices(["all","logged-in","not-logged-in","unknown","error"]).default("all")).option("-f, --format <fmt>","Output format: table, plain, json, yaml, md, csv","table").action(async(n)=>{const s=typeof r.optsWithGlobals==="function"?r.optsWithGlobals():{},a=await collectAuthStatus({sites:n.site,full:n.full===!0,concurrency:n.concurrency,timeout:n.timeout,only:n.only,maxAge:n.maxAge,verify:n.verify,profile:typeof s.profile==="string"&&s.profile.trim()?s.profile.trim():void 0}),u=typeof n.format==="string"?n.format:"table";K(a,{fmt:u,fmtExplicit:r.getOptionValueSource("format")==="cli",columns:["site","status","identity","checked","error"],title:"ppcli/auth status",source:n.full?"full whoami probe":"quick auth check"})}),i=t.command("refresh").description("Touch logged-in site sessions to keep browser auth fresh").option("--site <sites>","Comma-separated site names to refresh, e.g. github,claude").option("--all","Ignore the 24h refresh throttle and force every selected site",!1).option("--concurrency <n>","Maximum sites to refresh at once").option("--timeout <seconds>","Per-site timeout in seconds").option("-f, --format <fmt>","Output format: table, plain, json, yaml, md, csv","table").action(async(n)=>{const s=typeof i.optsWithGlobals==="function"?i.optsWithGlobals():{},a=await collectAuthRefresh({sites:n.site,all:n.all===!0,concurrency:n.concurrency,timeout:n.timeout,profile:typeof s.profile==="string"&&s.profile.trim()?s.profile.trim():void 0}),u=typeof n.format==="string"?n.format:"table";K(a,{fmt:u,fmtExplicit:i.getOptionValueSource("format")==="cli",columns:["site","status","last_touched_at","next_refresh_at","error"],title:"ppcli/auth refresh",source:n.all?"forced persistent touch":"persistent touch with 24h throttle"})});return t}
@@ -1 +1 @@
1
- import{fetchDaemonStatus as M,requestDaemonShutdown as X}from"../browser/daemon-transport.js";import{restartDaemon as Y}from"../browser/daemon-lifecycle.js";import{formatDuration as Z}from"../download/progress.js";import{log as C}from"../logger.js";import{PKG_VERSION as U}from"../version.js";import{formatDaemonVersion as W,isDaemonStale as $}from"../browser/daemon-version.js";import{browserSession as q,getBrowserFactory as T}from"../runtime.js";export async function daemonStatus(){const k=await M();if(!k){console.log("Daemon: not running");return}let z;if(k.extensionConnected)z=k.extensionVersion?`connected (v${k.extensionVersion})`:"connected (version unknown)";else if(k.profileRequired){const A=k.profiles?.length??0;z=`${A} ${A===1?"profile":"profiles"} connected, none selected — run \`ppcli profile use <name>\``}else if(k.profileDisconnected)z="requested profile not connected — run `ppcli profile use <name>`";else z="disconnected";const H=W(k),J=$(k,U);console.log(`Daemon: ${J?"stale":"running"} (PID ${k.pid})`);console.log(`Version: ${H}${J?` (CLI v${U}; run: ppcli daemon restart)`:""}`);console.log(`Uptime: ${Z(Math.round(k.uptime*1000))}`);console.log(`Extension: ${z}`);if(k.profiles&&k.profiles.length>0)console.log(`Profiles: ${k.profiles.map((A)=>{const Q=A.extensionVersion?` v${A.extensionVersion}`:"";return`${A.contextId}${Q}`}).join(", ")}`);console.log(`Memory: ${k.memoryMB} MB`);console.log(`Port: ${k.port}`)}export async function daemonStop(){if(!await M()){C.info("Daemon is not running.");return}if(await X())C.success("Daemon stopped.");else{C.error("Failed to stop daemon.");process.exitCode=1}}export async function daemonRestart(){const k=await M();if(k?.profiles&&k.profiles.length>0)C.warn(`Restarting daemon will disconnect ${k.profiles.length} browser profile(s); the extension should reconnect automatically.`);const z=await Y();if(!z.stopped){C.error("Failed to stop daemon before restart.");process.exitCode=1;return}if(!z.status){C.error("Daemon restart timed out before the new daemon reported status.");process.exitCode=1;return}const H=z.previousStatus?"restarted":"started",J=W(z.status);C.success(`Daemon ${H} on port ${z.status.port} (${J}).`);if(z.status.extensionConnected){const A=z.status.profiles?.length??0,Q=A>0?`; profiles connected: ${A}`:"";C.status(`Extension connected${Q}.`)}else C.warn("Daemon is running, but the Browser Bridge extension has not connected yet.")}export async function daemonWarm(k){const z=await M();if(!z){C.warn("Daemon/extension not ready; skip warm (retry after the browser extension connects).");return}if(!z.extensionConnected){C.warn("Browser extension not connected yet; skip warm.");return}const H=k&&/^https?:\/\//i.test(k)?k:"about:blank",J=T("__warm__");try{await q(J,async(A)=>{await A.goto(H).catch(()=>{})},{session:"site:__warm__",windowMode:"background",surface:"adapter",siteSession:"persistent"});C.success(`Automation window warmed (${H}, kept alive for reuse).`)}catch(A){C.warn(`Warm failed (non-fatal): ${A instanceof Error?A.message:String(A)}`)}}
1
+ import{fetchDaemonStatus as i,requestDaemonShutdown as p}from"../browser/daemon-transport.js";import{restartDaemon as m}from"../browser/daemon-lifecycle.js";import{formatDuration as f}from"../download/progress.js";import{log as n}from"../logger.js";import{PKG_VERSION as c}from"../version.js";import{formatDaemonVersion as l,isDaemonStale as u}from"../browser/daemon-version.js";import{browserSession as d,getBrowserFactory as w}from"../runtime.js";export async function daemonStatus(){const e=await i();if(!e){console.log("Daemon: not running");return}let o;if(e.extensionConnected)o=e.extensionVersion?`connected (v${e.extensionVersion})`:"connected (version unknown)";else if(e.profileRequired){const t=e.profiles?.length??0;o=`${t} ${t===1?"profile":"profiles"} connected, none selected — run \`ppcli profile use <name>\``}else if(e.profileDisconnected)o="requested profile not connected — run `ppcli profile use <name>`";else o="disconnected";const s=l(e),r=u(e,c);console.log(`Daemon: ${r?"stale":"running"} (PID ${e.pid})`);console.log(`Version: ${s}${r?` (CLI v${c}; run: ppcli daemon restart)`:""}`);console.log(`Uptime: ${f(Math.round(e.uptime*1000))}`);console.log(`Extension: ${o}`);if(e.profiles&&e.profiles.length>0)console.log(`Profiles: ${e.profiles.map((t)=>{const a=t.extensionVersion?` v${t.extensionVersion}`:"";return`${t.contextId}${a}`}).join(", ")}`);console.log(`Memory: ${e.memoryMB} MB`);console.log(`Port: ${e.port}`)}export async function daemonStop(){if(!await i()){n.info("Daemon is not running.");return}if(await p())n.success("Daemon stopped.");else{n.error("Failed to stop daemon.");process.exitCode=1}}export async function daemonRestart(){const e=await i();if(e?.profiles&&e.profiles.length>0)n.warn(`Restarting daemon will disconnect ${e.profiles.length} browser profile(s); the extension should reconnect automatically.`);const o=await m();if(!o.stopped){n.error("Failed to stop daemon before restart.");process.exitCode=1;return}if(!o.status){n.error("Daemon restart timed out before the new daemon reported status.");process.exitCode=1;return}const s=o.previousStatus?"restarted":"started",r=l(o.status);n.success(`Daemon ${s} on port ${o.status.port} (${r}).`);if(o.status.extensionConnected){const t=o.status.profiles?.length??0,a=t>0?`; profiles connected: ${t}`:"";n.status(`Extension connected${a}.`)}else n.warn("Daemon is running, but the Browser Bridge extension has not connected yet.")}export async function daemonWarm(e){const o=await i();if(!o){n.warn("Daemon/extension not ready; skip warm (retry after the browser extension connects).");return}if(!o.extensionConnected){n.warn("Browser extension not connected yet; skip warm.");return}const s=e&&/^https?:\/\//i.test(e)?e:"about:blank",r=w("__warm__");try{await d(r,async(t)=>{await t.goto(s).catch(()=>{})},{session:"site:__warm__",windowMode:"background",surface:"adapter",siteSession:"persistent"});n.success(`Automation window warmed (${s}, kept alive for reuse).`)}catch(t){n.warn(`Warm failed (non-fatal): ${t instanceof Error?t.message:String(t)}`)}}
@@ -1 +1 @@
1
- import*as V from"node:fs";import{BUILTIN_COMMANDS as W,bashCompletionScript as X,zshCompletionScript as Y,fishCompletionScript as Z}from"./completion-shared.js";export function hasAllManifests(x){for(const q of x)try{V.accessSync(q)}catch{return!1}return x.length>0}export function getCompletionsFromManifest(x,q,K){const J=j(K);if(J===null)return[];if(q<=1){const F=new Set;for(const G of J)F.add(G.site);return[...W,...F].sort()}const Q=x[0];if(W.includes(Q))return[];if(q===2){const F=[];for(const G of J)if(G.site===Q){F.push(G.name);if(G.aliases?.length)F.push(...G.aliases)}return[...new Set(F)].sort()}return[]}const $={bash:X,zsh:Y,fish:Z};export function printCompletionScriptFast(x){const q=$[x];if(!q)return!1;process.stdout.write(q());return!0}function j(x){const q=[];let K=!1;for(const J of x)try{const Q=V.readFileSync(J,"utf-8"),F=JSON.parse(Q);q.push(...F);K=!0}catch{}return K?q:null}
1
+ import*as f from"node:fs";import{BUILTIN_COMMANDS as c,bashCompletionScript as a,zshCompletionScript as u,fishCompletionScript as l}from"./completion-shared.js";export function hasAllManifests(n){for(const t of n)try{f.accessSync(t)}catch{return!1}return n.length>0}export function getCompletionsFromManifest(n,t,o){const r=h(o);if(r===null)return[];if(t<=1){const e=new Set;for(const s of r)e.add(s.site);return[...c,...e].sort()}const i=n[0];if(c.includes(i))return[];if(t===2){const e=[];for(const s of r)if(s.site===i){e.push(s.name);if(s.aliases?.length)e.push(...s.aliases)}return[...new Set(e)].sort()}return[]}const p={bash:a,zsh:u,fish:l};export function printCompletionScriptFast(n){const t=p[n];if(!t)return!1;process.stdout.write(t());return!0}function h(n){const t=[];let o=!1;for(const r of n)try{const i=f.readFileSync(r,"utf-8"),e=JSON.parse(i);t.push(...e);o=!0}catch{}return o?t:null}
@@ -1 +1 @@
1
- import{getRegistry as H}from"./registry.js";import{CliError as K}from"./errors.js";import{BUILTIN_COMMANDS as J,bashCompletionScript,zshCompletionScript,fishCompletionScript}from"./completion-shared.js";export{bashCompletionScript,zshCompletionScript,fishCompletionScript};export function getCompletions(x,F){if(F<=1){const k=new Set;for(const[,v]of H())k.add(v.site);return[...J,...k].sort()}const G=x[0];if(J.includes(G))return[];if(F===2){const k=[];for(const[,v]of H())if(v.site===G){k.push(v.name);if(v.aliases?.length)k.push(...v.aliases)}return[...new Set(k)].sort()}return[]}export function printCompletionScript(x){switch(x){case"bash":process.stdout.write(bashCompletionScript());break;case"zsh":process.stdout.write(zshCompletionScript());break;case"fish":process.stdout.write(fishCompletionScript());break;default:throw new K("UNSUPPORTED_SHELL",`Unsupported shell: ${x}. Supported: bash, zsh, fish`)}}
1
+ import{getRegistry as i}from"./registry.js";import{CliError as p}from"./errors.js";import{BUILTIN_COMMANDS as n,bashCompletionScript,zshCompletionScript,fishCompletionScript}from"./completion-shared.js";export{bashCompletionScript,zshCompletionScript,fishCompletionScript};export function getCompletions(e,o){if(o<=1){const t=new Set;for(const[,s]of i())t.add(s.site);return[...n,...t].sort()}const r=e[0];if(n.includes(r))return[];if(o===2){const t=[];for(const[,s]of i())if(s.site===r){t.push(s.name);if(s.aliases?.length)t.push(...s.aliases)}return[...new Set(t)].sort()}return[]}export function printCompletionScript(e){switch(e){case"bash":process.stdout.write(bashCompletionScript());break;case"zsh":process.stdout.write(zshCompletionScript());break;case"fish":process.stdout.write(fishCompletionScript());break;default:throw new p("UNSUPPORTED_SHELL",`Unsupported shell: ${e}. Supported: bash, zsh, fish`)}}
@@ -1 +1 @@
1
- export const DEFAULT_DAEMON_PORT=19825,PUBLISHPORT_DAEMON_PORT=19826;export function unsupportedDaemonPortEnvMessage(b){return`OPENCLI_DAEMON_PORT is no longer supported${b?` (received ${b})`:""}. The ppcli Chrome extension can only connect to localhost:${DEFAULT_DAEMON_PORT}. Unset OPENCLI_DAEMON_PORT and rerun ppcli.`}export const VOLATILE_PARAMS=new Set(["w_rid","wts","_","callback","timestamp","t","nonce","sign"]),SEARCH_PARAMS=new Set(["q","query","keyword","search","wd","kw","search_query","w"]),PAGINATION_PARAMS=new Set(["page","pn","offset","cursor","next","page_num"]),LIMIT_PARAMS=new Set(["limit","count","size","per_page","page_size","ps","num"]),FIELD_ROLES={title:["title","name","text","content","desc","description","headline","subject"],url:["url","uri","link","href","permalink","jump_url","web_url","share_url"],author:["author","username","user_name","nickname","nick","owner","creator","up_name","uname"],score:["score","hot","heat","likes","like_count","view_count","views","play","favorite_count","reply_count"],time:["time","created_at","publish_time","pub_time","date","ctime","mtime","pubdate","created"],id:["id","aid","bvid","mid","uid","oid","note_id","item_id"],cover:["cover","pic","image","thumbnail","poster","avatar"],category:["category","tag","type","tname","channel","section"]};
1
+ export const DEFAULT_DAEMON_PORT=19825,PUBLISHPORT_DAEMON_PORT=19826;export function unsupportedDaemonPortEnvMessage(e){return`OPENCLI_DAEMON_PORT is no longer supported${e?` (received ${e})`:""}. The ppcli Chrome extension can only connect to localhost:${DEFAULT_DAEMON_PORT}. Unset OPENCLI_DAEMON_PORT and rerun ppcli.`}export const VOLATILE_PARAMS=new Set(["w_rid","wts","_","callback","timestamp","t","nonce","sign"]),SEARCH_PARAMS=new Set(["q","query","keyword","search","wd","kw","search_query","w"]),PAGINATION_PARAMS=new Set(["page","pn","offset","cursor","next","page_num"]),LIMIT_PARAMS=new Set(["limit","count","size","per_page","page_size","ps","num"]),FIELD_ROLES={title:["title","name","text","content","desc","description","headline","subject"],url:["url","uri","link","href","permalink","jump_url","web_url","share_url"],author:["author","username","user_name","nickname","nick","owner","creator","up_name","uname"],score:["score","hot","heat","likes","like_count","view_count","views","play","favorite_count","reply_count"],time:["time","created_at","publish_time","pub_time","date","ctime","mtime","pubdate","created"],id:["id","aid","bvid","mid","uid","oid","note_id","item_id"],cover:["cover","pic","image","thumbnail","poster","avatar"],category:["category","tag","type","tname","channel","section"]};
@@ -1,2 +1,2 @@
1
- import*as D from"node:fs";import*as _ from"node:path";const S=["silent-column-drop","camelCase-in-columns","missing-access-metadata","silent-clamp","silent-empty-fallback","silent-sentinel","write-without-delete-pair"],C=new Set(["ok","error"]),E=[{match:/(^|[-_])like($|[-_])/,describe:"like",expected:(H)=>[H.replace(/like/g,"unlike"),"unlike"]},{match:/(^|[-_])follow($|[-_])/,describe:"follow",expected:(H)=>[H.replace(/follow/g,"unfollow"),"unfollow"]},{match:/(^|[-_])subscribe($|[-_])/,describe:"subscribe",expected:(H)=>[H.replace(/subscribe/g,"unsubscribe"),"unsubscribe"]},{match:/(^|[-_])bookmark($|[-_])/,describe:"bookmark",expected:(H)=>[H.replace(/bookmark/g,"unbookmark"),"unbookmark"]},{match:/(^|[-_])save($|[-_])/,describe:"save",expected:(H)=>[H.replace(/save/g,"unsave"),"unsave","delete","remove","rm"]},{match:/(^|[-_])create($|[-_])/,describe:"create",expected:(H)=>[H.replace(/create/g,"delete"),H.replace(/create/g,"remove"),"delete","remove","rm"]},{match:/(^|[-_])post($|[-_])/,describe:"post",expected:(H)=>[H.replace(/post/g,"delete"),"delete","remove","rm"]}];export function runConventionAudit(H){const J=H.manifestPath??_.join(H.projectRoot,"cli-manifest.json"),$=JSON.parse(D.readFileSync(J,"utf-8")).filter((Y)=>w(Y,H)),Z=[],G=new Map,X=new Set;for(const Y of $){const A=K(Y);if(!A)continue;if(Y.access!=="read"&&Y.access!=="write")Z.push({rule:"missing-access-metadata",...A,message:`${A.command} must declare access: 'read' | 'write'`});for(const M of Y.columns??[])if(/[a-z][A-Z]/.test(M))Z.push({rule:"camelCase-in-columns",...A,message:`${A.command} column "${M}" should use snake_case for agent-stable keys`,details:{column:M}});const W=T(H.projectRoot,Y);if(!W)continue;const U=O(W,G);if(U==null)continue;X.add(W);Z.push(...q(A,Y,U,W,H.projectRoot));Z.push(...I(A,U,W,H.projectRoot))}Z.push(...b($));const N=S.map((Y)=>{const A=Z.filter((W)=>W.rule===Y);return{rule:Y,count:A.length,violations:A}}),V=$.filter((Y)=>K(Y)!=null).length,z=new Set($.map((Y)=>Y.site).filter((Y)=>typeof Y==="string"));return{ok:Z.length===0,summary:{commands:V,sites:z.size,files_scanned:X.size,violations:Z.length},categories:N}}export function renderConventionAuditText(H){const J=[];J.push("Convention Audit Report");J.push(`Scanned ${H.summary.commands} command(s) across ${H.summary.sites} site(s), ${H.summary.files_scanned} source file(s).`);J.push(`Violations: ${H.summary.violations}`);J.push("");for(const Q of H.categories){const $=Q.count===0?"OK":String(Q.count);J.push(`${Q.rule}: ${$}`);for(const Z of Q.violations){const G=Z.file?` (${Z.file}${Z.line?`:${Z.line}`:""})`:"";J.push(` - ${Z.command}${G}`);J.push(` ${Z.message}`);const X=l(Z.details);if(X)J.push(` ${X}`)}J.push("")}if(H.ok)J.push("OK - no convention violations found.");else J.push("Run with -f yaml or -f json for machine-readable output.");return J.join(`
2
- `)}function K(H){if(typeof H.site!=="string"||typeof H.name!=="string")return null;return{site:H.site,name:H.name,command:`${H.site}/${H.name}`}}function w(H,J){const Q=J.target?.trim(),$=J.site?.trim();if($&&H.site!==$)return!1;if(!Q)return!0;if(Q.includes("/"))return`${H.site}/${H.name}`===Q;return H.site===Q}function T(H,J){const Q=J.sourceFile??J.modulePath;if(!Q)return null;const $=_.join(H,"clis",Q);return D.existsSync($)?$:null}function O(H,J){if(J.has(H))return J.get(H)??null;try{const Q=D.readFileSync(H,"utf-8");J.set(H,Q);return Q}catch{J.set(H,null);return null}}function q(H,J,Q,$,Z){const G=new Set(J.columns??[]);if(G.size===0)return[];const X=y(Q,G),N=new Set,V=[];for(const z of j(Q)){if(v(z.text))continue;const Y=g(z.text).filter((M)=>!C.has(M));if(Y.length<2)continue;if(u(Y))continue;if(Y.filter((M)=>G.has(M)).length===0)continue;const W=Y.filter((M)=>!G.has(M)&&!X.has(M));if(W.length===0)continue;const U=W.sort().join(",");if(N.has(U))continue;N.add(U);V.push({rule:"silent-column-drop",...H,file:L(Z,$),line:p(Q,z.index),message:`${H.command} row emits key(s) not present in columns: ${W.join(", ")}`,details:{emitted_keys:Y,columns:[...G],missing:W}})}return V}function I(H,J,Q,$){const Z=[],G=L($,Q),X=J.split(/\r?\n/),N=k(J);let V=0;X.forEach((z,Y)=>{if(/Math\.min\s*\([^)]*limit[^)]*\)/i.test(z))Z.push({rule:"silent-clamp",...H,file:G,line:Y+1,message:"limit is clamped with Math.min; prefer validating and throwing ArgumentError on invalid input",details:{text:z.trim()}});const A=z.search(/\breturn\s+\[\s*\]\s*;?/);if(A>=0&&P(V+A,N))Z.push({rule:"silent-empty-fallback",...H,file:G,line:Y+1,message:"empty array fallback hides fetch/parse failures from agents; prefer a typed error when data is expected",details:{text:z.trim()}});const W=/(?:\?\?|\|\|)\s*(['"])(unknown|Unknown|UNKNOWN|N\/A|n\/a|NA|未知|-)\1/.exec(z);if(W){if(!R(z))Z.push({rule:"silent-sentinel",...H,file:G,line:Y+1,message:`sentinel fallback ${W[0].trim()} can turn missing data into fake data; prefer dropping the field or throwing a typed error`,details:{text:z.trim()}})}V+=z.length+1});return c(Z)}function R(H){return/\bthrow\s+new\b/.test(H)}function b(H){const J=new Map;for(const $ of H){if(!$.site||!$.name)continue;const Z=J.get($.site)??[];Z.push($);J.set($.site,Z)}const Q=[];for(const[$,Z]of J){const G=new Set(Z.map((X)=>X.name).filter((X)=>typeof X==="string"));for(const X of Z){if(X.access!=="write"||!X.name)continue;const N=E.find((z)=>z.match.test(X.name));if(!N)continue;const V=[...new Set(N.expected(X.name).filter((z)=>z!==X.name))];if(V.some((z)=>G.has(z)))continue;Q.push({rule:"write-without-delete-pair",site:$,name:X.name,command:`${$}/${X.name}`,message:`write command "${X.name}" looks like ${N.describe} but no matching undo/delete command exists on this site`,details:{expected_any_of:V}})}}return Q}function j(H){const J=[],Q=[/\.push\s*\(\s*{/g,/\breturn\s+(?:\(\s*)?{/g,/=>\s*\(\s*{/g,/\bmap\s*:\s*{/g];for(const $ of Q)for(const Z of H.matchAll($)){const X=Z[0].lastIndexOf("{");if(Z.index===void 0||X<0)continue;const N=Z.index+X,V=B(H,N);if(V)J.push({text:V,index:N})}return J}function k(H){const J=[];for(const Q of H.matchAll(/\bcatch\s*(?:\([^)]*\))?\s*{/g)){if(Q.index===void 0)continue;const $=Q.index+Q[0].lastIndexOf("{"),Z=f(H,$);if(Z>=0)J.push({start:$,end:Z})}return J}function f(H,J){let Q=0,$=null,Z=!1;for(let G=J;G<H.length;G++){const X=H[G];if($){if(Z)Z=!1;else if(X==="\\")Z=!0;else if(X===$)$=null;continue}if(X==='"'||X==="'"||X==="`"){$=X;continue}if(X==="{")Q++;if(X==="}"){Q--;if(Q===0)return G}}return-1}function P(H,J){return J.some((Q)=>H>=Q.start&&H<=Q.end)}function B(H,J){let Q=0,$=null,Z=!1;for(let G=J;G<H.length;G++){const X=H[G];if($){if(Z)Z=!1;else if(X==="\\")Z=!0;else if(X===$)$=null;continue}if(X==='"'||X==="'"||X==="`"){$=X;continue}if(X==="{")Q++;if(X==="}"){Q--;if(Q===0)return H.slice(J,G+1)}}return null}function g(H){return[...new Set(F(H).map((J)=>J.key))]}function F(H){const J=H.trim().replace(/^\{/,"").replace(/\}$/,""),Q=m(J,","),$=[];for(const Z of Q){const G=x(Z);if(G)$.push(G)}return $}function x(H){const J=H.trim();if(!J||J.startsWith("...")||J.startsWith("["))return null;const Q=d(J,":");if(Q>=0){const Z=J.slice(0,Q).trim(),G=J.slice(Q+1).trim();if(/^['"][^'"]+['"]$/.test(Z))return{key:Z.slice(1,-1),value:G};const X=/^([A-Za-z_$][\w$]*)$/.exec(Z);return X?{key:X[1],value:G}:null}const $=/^([A-Za-z_$][\w$]*)\b/.exec(J);return $?{key:$[1],value:$[1]}:null}function v(H){const J=F(H).find((Q)=>Q.key==="ok");return J!=null&&/^false\b/.test(J.value)}function y(H,J){const Q=new Set;for(const $ of h(H))for(const Z of F($.text)){if(!J.has(Z.key))continue;for(const G of Z.value.matchAll(/\b([A-Za-z_$][\w$]*(?:Raw|Class))\b/g)){const X=G[1];if(X!==Z.key)Q.add(X)}}return Q}function h(H){const J=[];for(const Q of H.matchAll(/=>\s*\(\s*{/g)){const Z=Q[0].lastIndexOf("{");if(Q.index===void 0||Z<0)continue;const G=Q.index+Z,X=B(H,G);if(X)J.push({text:X,index:G})}return J}function m(H,J){const Q=[];let $=0,Z=0,G=null,X=!1;for(let N=0;N<H.length;N++){const V=H[N];if(G){if(X)X=!1;else if(V==="\\")X=!0;else if(V===G)G=null;continue}if(V==='"'||V==="'"||V==="`"){G=V;continue}if(V==="{"||V==="["||V==="(")Z++;if(V==="}"||V==="]"||V===")")Z--;if(Z===0&&V===J){Q.push(H.slice($,N));$=N+1}}Q.push(H.slice($));return Q}function d(H,J){let Q=0,$=null,Z=!1;for(let G=0;G<H.length;G++){const X=H[G];if($){if(Z)Z=!1;else if(X==="\\")Z=!0;else if(X===$)$=null;continue}if(X==='"'||X==="'"||X==="`"){$=X;continue}if(X==="{"||X==="["||X==="(")Q++;if(X==="}"||X==="]"||X===")")Q--;if(Q===0&&X===J)return G}return-1}function u(H){const J=new Set(H);return J.has("site")&&(J.has("description")||J.has("access")||J.has("strategy"))}function p(H,J){return H.slice(0,J).split(/\r?\n/).length}function L(H,J){return _.relative(H,J).replaceAll(_.sep,"/")}function l(H){if(!H)return"";return Object.entries(H).map(([J,Q])=>`${J}: ${Array.isArray(Q)?Q.join(", "):String(Q)}`).join(" | ")}function c(H){const J=new Set;return H.filter((Q)=>{const $=`${Q.rule}:${Q.command}:${Q.file}:${Q.line}:${Q.message}`;if(J.has($))return!1;J.add($);return!0})}
1
+ import*as g from"node:fs";import*as h from"node:path";const y=["silent-column-drop","camelCase-in-columns","missing-access-metadata","silent-clamp","silent-empty-fallback","silent-sentinel","write-without-delete-pair"],v=new Set(["ok","error"]),_=[{match:/(^|[-_])like($|[-_])/,describe:"like",expected:(e)=>[e.replace(/like/g,"unlike"),"unlike"]},{match:/(^|[-_])follow($|[-_])/,describe:"follow",expected:(e)=>[e.replace(/follow/g,"unfollow"),"unfollow"]},{match:/(^|[-_])subscribe($|[-_])/,describe:"subscribe",expected:(e)=>[e.replace(/subscribe/g,"unsubscribe"),"unsubscribe"]},{match:/(^|[-_])bookmark($|[-_])/,describe:"bookmark",expected:(e)=>[e.replace(/bookmark/g,"unbookmark"),"unbookmark"]},{match:/(^|[-_])save($|[-_])/,describe:"save",expected:(e)=>[e.replace(/save/g,"unsave"),"unsave","delete","remove","rm"]},{match:/(^|[-_])create($|[-_])/,describe:"create",expected:(e)=>[e.replace(/create/g,"delete"),e.replace(/create/g,"remove"),"delete","remove","rm"]},{match:/(^|[-_])post($|[-_])/,describe:"post",expected:(e)=>[e.replace(/post/g,"delete"),"delete","remove","rm"]}];export function runConventionAudit(e){const t=e.manifestPath??h.join(e.projectRoot,"cli-manifest.json"),o=JSON.parse(g.readFileSync(t,"utf-8")).filter((a)=>S(a,e)),i=[],r=new Map,s=new Set;for(const a of o){const m=k(a);if(!m)continue;if(a.access!=="read"&&a.access!=="write")i.push({rule:"missing-access-metadata",...m,message:`${m.command} must declare access: 'read' | 'write'`});for(const d of a.columns??[])if(/[a-z][A-Z]/.test(d))i.push({rule:"camelCase-in-columns",...m,message:`${m.command} column "${d}" should use snake_case for agent-stable keys`,details:{column:d}});const f=j(e.projectRoot,a);if(!f)continue;const p=A(f,r);if(p==null)continue;s.add(f);i.push(...R(m,a,p,f,e.projectRoot));i.push(...O(m,p,f,e.projectRoot))}i.push(...I(o));const u=y.map((a)=>{const m=i.filter((f)=>f.rule===a);return{rule:a,count:m.length,violations:m}}),c=o.filter((a)=>k(a)!=null).length,l=new Set(o.map((a)=>a.site).filter((a)=>typeof a==="string"));return{ok:i.length===0,summary:{commands:c,sites:l.size,files_scanned:s.size,violations:i.length},categories:u}}export function renderConventionAuditText(e){const t=[];t.push("Convention Audit Report");t.push(`Scanned ${e.summary.commands} command(s) across ${e.summary.sites} site(s), ${e.summary.files_scanned} source file(s).`);t.push(`Violations: ${e.summary.violations}`);t.push("");for(const n of e.categories){const o=n.count===0?"OK":String(n.count);t.push(`${n.rule}: ${o}`);for(const i of n.violations){const r=i.file?` (${i.file}${i.line?`:${i.line}`:""})`:"";t.push(` - ${i.command}${r}`);t.push(` ${i.message}`);const s=q(i.details);if(s)t.push(` ${s}`)}t.push("")}if(e.ok)t.push("OK - no convention violations found.");else t.push("Run with -f yaml or -f json for machine-readable output.");return t.join(`
2
+ `)}function k(e){if(typeof e.site!=="string"||typeof e.name!=="string")return null;return{site:e.site,name:e.name,command:`${e.site}/${e.name}`}}function S(e,t){const n=t.target?.trim(),o=t.site?.trim();if(o&&e.site!==o)return!1;if(!n)return!0;if(n.includes("/"))return`${e.site}/${e.name}`===n;return e.site===n}function j(e,t){const n=t.sourceFile??t.modulePath;if(!n)return null;const o=h.join(e,"clis",n);return g.existsSync(o)?o:null}function A(e,t){if(t.has(e))return t.get(e)??null;try{const n=g.readFileSync(e,"utf-8");t.set(e,n);return n}catch{t.set(e,null);return null}}function R(e,t,n,o,i){const r=new Set(t.columns??[]);if(r.size===0)return[];const s=L(n,r),u=new Set,c=[];for(const l of E(n)){if(F(l.text))continue;const a=N(l.text).filter((d)=>!v.has(d));if(a.length<2)continue;if(U(a))continue;if(a.filter((d)=>r.has(d)).length===0)continue;const f=a.filter((d)=>!r.has(d)&&!s.has(d));if(f.length===0)continue;const p=f.sort().join(",");if(u.has(p))continue;u.add(p);c.push({rule:"silent-column-drop",...e,file:x(i,o),line:W(n,l.index),message:`${e.command} row emits key(s) not present in columns: ${f.join(", ")}`,details:{emitted_keys:a,columns:[...r],missing:f}})}return c}function O(e,t,n,o){const i=[],r=x(o,n),s=t.split(/\r?\n/),u=P(t);let c=0;s.forEach((l,a)=>{if(/Math\.min\s*\([^)]*limit[^)]*\)/i.test(l))i.push({rule:"silent-clamp",...e,file:r,line:a+1,message:"limit is clamped with Math.min; prefer validating and throwing ArgumentError on invalid input",details:{text:l.trim()}});const m=l.search(/\breturn\s+\[\s*\]\s*;?/);if(m>=0&&K(c+m,u))i.push({rule:"silent-empty-fallback",...e,file:r,line:a+1,message:"empty array fallback hides fetch/parse failures from agents; prefer a typed error when data is expected",details:{text:l.trim()}});const f=/(?:\?\?|\|\|)\s*(['"])(unknown|Unknown|UNKNOWN|N\/A|n\/a|NA|未知|-)\1/.exec(l);if(f){if(!C(l))i.push({rule:"silent-sentinel",...e,file:r,line:a+1,message:`sentinel fallback ${f[0].trim()} can turn missing data into fake data; prefer dropping the field or throwing a typed error`,details:{text:l.trim()}})}c+=l.length+1});return Z(i)}function C(e){return/\bthrow\s+new\b/.test(e)}function I(e){const t=new Map;for(const o of e){if(!o.site||!o.name)continue;const i=t.get(o.site)??[];i.push(o);t.set(o.site,i)}const n=[];for(const[o,i]of t){const r=new Set(i.map((s)=>s.name).filter((s)=>typeof s==="string"));for(const s of i){if(s.access!=="write"||!s.name)continue;const u=_.find((l)=>l.match.test(s.name));if(!u)continue;const c=[...new Set(u.expected(s.name).filter((l)=>l!==s.name))];if(c.some((l)=>r.has(l)))continue;n.push({rule:"write-without-delete-pair",site:o,name:s.name,command:`${o}/${s.name}`,message:`write command "${s.name}" looks like ${u.describe} but no matching undo/delete command exists on this site`,details:{expected_any_of:c}})}}return n}function E(e){const t=[],n=[/\.push\s*\(\s*{/g,/\breturn\s+(?:\(\s*)?{/g,/=>\s*\(\s*{/g,/\bmap\s*:\s*{/g];for(const o of n)for(const i of e.matchAll(o)){const s=i[0].lastIndexOf("{");if(i.index===void 0||s<0)continue;const u=i.index+s,c=w(e,u);if(c)t.push({text:c,index:u})}return t}function P(e){const t=[];for(const n of e.matchAll(/\bcatch\s*(?:\([^)]*\))?\s*{/g)){if(n.index===void 0)continue;const o=n.index+n[0].lastIndexOf("{"),i=z(e,o);if(i>=0)t.push({start:o,end:i})}return t}function z(e,t){let n=0,o=null,i=!1;for(let r=t;r<e.length;r++){const s=e[r];if(o){if(i)i=!1;else if(s==="\\")i=!0;else if(s===o)o=null;continue}if(s==='"'||s==="'"||s==="`"){o=s;continue}if(s==="{")n++;if(s==="}"){n--;if(n===0)return r}}return-1}function K(e,t){return t.some((n)=>e>=n.start&&e<=n.end)}function w(e,t){let n=0,o=null,i=!1;for(let r=t;r<e.length;r++){const s=e[r];if(o){if(i)i=!1;else if(s==="\\")i=!0;else if(s===o)o=null;continue}if(s==='"'||s==="'"||s==="`"){o=s;continue}if(s==="{")n++;if(s==="}"){n--;if(n===0)return e.slice(t,r+1)}}return null}function N(e){return[...new Set(b(e).map((t)=>t.key))]}function b(e){const t=e.trim().replace(/^\{/,"").replace(/\}$/,""),n=D(t,","),o=[];for(const i of n){const r=T(i);if(r)o.push(r)}return o}function T(e){const t=e.trim();if(!t||t.startsWith("...")||t.startsWith("["))return null;const n=B(t,":");if(n>=0){const i=t.slice(0,n).trim(),r=t.slice(n+1).trim();if(/^['"][^'"]+['"]$/.test(i))return{key:i.slice(1,-1),value:r};const s=/^([A-Za-z_$][\w$]*)$/.exec(i);return s?{key:s[1],value:r}:null}const o=/^([A-Za-z_$][\w$]*)\b/.exec(t);return o?{key:o[1],value:o[1]}:null}function F(e){const t=b(e).find((n)=>n.key==="ok");return t!=null&&/^false\b/.test(t.value)}function L(e,t){const n=new Set;for(const o of M(e))for(const i of b(o.text)){if(!t.has(i.key))continue;for(const r of i.value.matchAll(/\b([A-Za-z_$][\w$]*(?:Raw|Class))\b/g)){const s=r[1];if(s!==i.key)n.add(s)}}return n}function M(e){const t=[];for(const n of e.matchAll(/=>\s*\(\s*{/g)){const i=n[0].lastIndexOf("{");if(n.index===void 0||i<0)continue;const r=n.index+i,s=w(e,r);if(s)t.push({text:s,index:r})}return t}function D(e,t){const n=[];let o=0,i=0,r=null,s=!1;for(let u=0;u<e.length;u++){const c=e[u];if(r){if(s)s=!1;else if(c==="\\")s=!0;else if(c===r)r=null;continue}if(c==='"'||c==="'"||c==="`"){r=c;continue}if(c==="{"||c==="["||c==="(")i++;if(c==="}"||c==="]"||c===")")i--;if(i===0&&c===t){n.push(e.slice(o,u));o=u+1}}n.push(e.slice(o));return n}function B(e,t){let n=0,o=null,i=!1;for(let r=0;r<e.length;r++){const s=e[r];if(o){if(i)i=!1;else if(s==="\\")i=!0;else if(s===o)o=null;continue}if(s==='"'||s==="'"||s==="`"){o=s;continue}if(s==="{"||s==="["||s==="(")n++;if(s==="}"||s==="]"||s===")")n--;if(n===0&&s===t)return r}return-1}function U(e){const t=new Set(e);return t.has("site")&&(t.has("description")||t.has("access")||t.has("strategy"))}function W(e,t){return e.slice(0,t).split(/\r?\n/).length}function x(e,t){return h.relative(e,t).replaceAll(h.sep,"/")}function q(e){if(!e)return"";return Object.entries(e).map(([t,n])=>`${t}: ${Array.isArray(n)?n.join(", "):String(n)}`).join(" | ")}function Z(e){const t=new Set;return e.filter((n)=>{const o=`${n.rule}:${n.command}:${n.file}:${n.line}:${n.message}`;if(t.has(o))return!1;t.add(o);return!0})}
@@ -1 +1 @@
1
- export const COMMAND_RESULT_UNKNOWN_CODE="command_result_unknown",COMMAND_RESULT_UNKNOWN_HINT="Inspect the browser/session state before retrying. Do not blindly retry write commands such as navigate, click, type, or eval.",PROFILE_DISCONNECTED_HINT="Open that Chrome profile and make sure the ppcli extension is enabled, or choose another profile with ppcli profile use <name>.";export function commandResultUnknownMessage(f){return`Browser connection dropped after the ${f} command was dispatched; it may have completed.`}export function buildExtensionDisconnectFailure(f){if(f.dispatched)return{message:commandResultUnknownMessage(f.action),errorCode:COMMAND_RESULT_UNKNOWN_CODE,errorHint:COMMAND_RESULT_UNKNOWN_HINT,status:503,countAsCommandResultUnknown:!0};return buildCommandDispatchFailure(f.contextId)}export function buildCommandTimeoutFailure(f,j){return{message:`Browser ${f} command timed out after ${Math.round(j/1000)}s; it may still complete in the browser.`,errorCode:COMMAND_RESULT_UNKNOWN_CODE,errorHint:COMMAND_RESULT_UNKNOWN_HINT,status:408,countAsCommandResultUnknown:!0}}export function buildCommandDispatchFailure(f){return{message:`Browser profile "${f}" disconnected before command dispatch`,errorCode:"profile_disconnected",errorHint:PROFILE_DISCONNECTED_HINT,status:503,countAsCommandResultUnknown:!1}}export function getResponseCorsHeaders(f,j){if(f!=="/ping")return;if(!j||!j.startsWith("chrome-extension://"))return;return{"Access-Control-Allow-Origin":j,Vary:"Origin"}}export function resolveProfileRoute(f,j,G){const J=G==="write",v=typeof j==="string"&&j.trim()?j.trim():void 0;if(v){if(f.includes(v))return{kind:"use",contextId:v};if(f.length===1){const z=f[0];if(J)return{kind:"error",errorCode:"profile_disconnected",error:`浏览器环境 "${v}" 未连接,且这是写操作——拒绝改用其它环境,以免把内容发到别的账号。`,errorHint:`当前在线的是 "${z}"。请让用户在 PublishPort 客户端启动 "${v}";`+`若确实要用当前在线的这个账号,请显式指定 --profile ${z} 后重试。`};return{kind:"fallback",contextId:z,requestedContextId:v}}return{kind:"error",errorCode:"profile_disconnected",error:`浏览器环境 "${v}" 未连接。`,errorHint:PROFILE_DISCONNECTED_HINT}}if(f.length===1)return{kind:"use",contextId:f[0]};if(f.length>1)return{kind:"error",errorCode:"profile_required",error:"Multiple Browser Bridge profiles are connected; choose one with --profile.",errorHint:"Run ppcli profile list, then use ppcli --profile <name> ... or ppcli profile use <name>."};return{kind:"error",errorCode:"extension_not_connected",error:"浏览器桥未连接:这台机器上的 PublishPort 托管浏览器没在运行。",errorHint:"请用户打开 PublishPort 客户端,在平台列表里点一次「检测登录」把托管浏览器拉起来;仍不行就重启客户端。"}}
1
+ export const COMMAND_RESULT_UNKNOWN_CODE="command_result_unknown",COMMAND_RESULT_UNKNOWN_HINT="Inspect the browser/session state before retrying. Do not blindly retry write commands such as navigate, click, type, or eval.",PROFILE_DISCONNECTED_HINT="Open that Chrome profile and make sure the ppcli extension is enabled, or choose another profile with ppcli profile use <name>.";export function commandResultUnknownMessage(e){return`Browser connection dropped after the ${e} command was dispatched; it may have completed.`}export function buildExtensionDisconnectFailure(e){if(e.dispatched)return{message:commandResultUnknownMessage(e.action),errorCode:COMMAND_RESULT_UNKNOWN_CODE,errorHint:COMMAND_RESULT_UNKNOWN_HINT,status:503,countAsCommandResultUnknown:!0};return buildCommandDispatchFailure(e.contextId)}export function buildCommandTimeoutFailure(e,r){return{message:`Browser ${e} command timed out after ${Math.round(r/1000)}s; it may still complete in the browser.`,errorCode:COMMAND_RESULT_UNKNOWN_CODE,errorHint:COMMAND_RESULT_UNKNOWN_HINT,status:408,countAsCommandResultUnknown:!0}}export function buildCommandDispatchFailure(e){return{message:`Browser profile "${e}" disconnected before command dispatch`,errorCode:"profile_disconnected",errorHint:PROFILE_DISCONNECTED_HINT,status:503,countAsCommandResultUnknown:!1}}export function getResponseCorsHeaders(e,r){if(e!=="/ping")return;if(!r||!r.startsWith("chrome-extension://"))return;return{"Access-Control-Allow-Origin":r,Vary:"Origin"}}export function resolveProfileRoute(e,r,t){const i=t==="write",o=typeof r==="string"&&r.trim()?r.trim():void 0;if(o){if(e.includes(o))return{kind:"use",contextId:o};if(e.length===1){const n=e[0];if(i)return{kind:"error",errorCode:"profile_disconnected",error:`浏览器环境 "${o}" 未连接,且这是写操作——拒绝改用其它环境,以免把内容发到别的账号。`,errorHint:`当前在线的是 "${n}"。请让用户在 PublishPort 客户端启动 "${o}";`+`若确实要用当前在线的这个账号,请显式指定 --profile ${n} 后重试。`};return{kind:"fallback",contextId:n,requestedContextId:o}}return{kind:"error",errorCode:"profile_disconnected",error:`浏览器环境 "${o}" 未连接。`,errorHint:PROFILE_DISCONNECTED_HINT}}if(e.length===1)return{kind:"use",contextId:e[0]};if(e.length>1)return{kind:"error",errorCode:"profile_required",error:"Multiple Browser Bridge profiles are connected; choose one with --profile.",errorHint:"Run ppcli profile list, then use ppcli --profile <name> ... or ppcli profile use <name>."};return{kind:"error",errorCode:"extension_not_connected",error:"浏览器桥未连接:这台机器上的 PublishPort 托管浏览器没在运行。",errorHint:"请用户打开 PublishPort 客户端,在平台列表里点一次「检测登录」把托管浏览器拉起来;仍不行就重启客户端。"}}
@@ -1 +1 @@
1
- import{createServer as y}from"node:http";import{WebSocketServer as t,WebSocket as p}from"ws";import{DEFAULT_DAEMON_PORT as n,PUBLISHPORT_DAEMON_PORT as s,unsupportedDaemonPortEnvMessage as o}from"./constants.js";import{EXIT_CODES as j}from"./errors.js";import{log as Y}from"./logger.js";import{PKG_VERSION as r}from"./version.js";import{DEFAULT_CONTEXT_ID as e}from"./browser/profile.js";import{buildCommandDispatchFailure as g,buildCommandTimeoutFailure as JJ,buildExtensionDisconnectFailure as QJ,getResponseCorsHeaders as $J,resolveProfileRoute as VJ}from"./daemon-utils.js";import*as F from"./browser/trace.js";import{SessionLeaseRegistry as ZJ,buildSessionBusyFailure as zJ,getSessionLeaseKey as GJ,isSessionLeaseCommand as YJ}from"./session-lease.js";const T=n,P=s;if(process.env.OPENCLI_DAEMON_PORT){Y.error(o(process.env.OPENCLI_DAEMON_PORT));process.exit(j.USAGE_ERROR)}const U=new Map,W=new Map,R=new ZJ;function m(Q){for(const $ of W.values())if($.runId===Q)return!0;return!1}function v(Q,$,z){clearTimeout($.timer);W.delete(Q);if($.leaseKey&&$.runId)R.heartbeat($.leaseKey,$.runId,Date.now());for(const Z of $.settlers)if(z.error)Z.reject(z.error);else Z.resolve(z.data)}let q=0;const NJ=200,E=[];class S extends Error{errorCode;errorHint;status;constructor(Q,$,z,Z=400){super(Q);this.errorCode=$;this.errorHint=z;this.status=Z;this.name="DaemonCommandFailure"}}function KJ(Q){E.push(Q);if(E.length>NJ)E.shift()}function c(){return[...U.values()].filter((Q)=>Q.ws.readyState===p.OPEN)}function u(Q,$){const z=c(),Z=VJ(z.map((J)=>J.contextId),Q,$);if(Z.kind==="error"){if(Z.errorCode==="profile_disconnected"&&$==="write"&&z.length===1)Y.warn(`[daemon] Refusing to route a WRITE to fallback profile "${z[0].contextId}" (requested "${Q}")`);return{errorCode:Z.errorCode,error:Z.error,errorHint:Z.errorHint}}if(Z.kind==="fallback")Y.warn(`[daemon] Requested profile "${Z.requestedContextId}" not connected; falling back to the only connected profile "${Z.contextId}"`);const V=z.find((J)=>J.contextId===Z.contextId);if(!V)return{errorCode:"extension_not_connected",error:"浏览器桥未连接:这台机器上的 PublishPort 托管浏览器没在运行。",errorHint:"请用户打开 PublishPort 客户端,在平台列表里点一次「检测登录」把托管浏览器拉起来;仍不行就重启客户端。"};return{connection:V}}function WJ(Q,$){const z=typeof $==="string"&&$.trim()?$.trim():e,Z=U.get(z);if(Z&&Z.ws!==Q)Z.ws.close();const V=[...U.entries()].find(([,H])=>H.ws===Q);if(V&&V[0]!==z)U.delete(V[0]);const J=U.get(z),G={contextId:z,ws:Q,extensionVersion:J?.ws===Q?J.extensionVersion:null,extensionCompatRange:J?.ws===Q?J.extensionCompatRange:null,lastSeenAt:Date.now()};U.set(z,G);return G}function l(Q){for(const[$,z]of U.entries()){if(z.ws!==Q)continue;U.delete($);F.traceExtDisconnect($);for(const[Z,V]of W){if(V.contextId!==$)continue;const J=QJ({contextId:$,action:V.action,dispatched:V.dispatched});if(J.countAsCommandResultUnknown){q++;Y.warn(`[daemon] Command result unknown after extension disconnect (id=${Z}, action=${V.action}, context=${$})`)}F.traceResult(Z,!1,Date.now()-V.dispatchTs,J.errorCode);v(Z,V,{error:new S(J.message,J.errorCode,J.errorHint,J.status)})}}}const d=33554432;class b extends Error{status=413;constructor(){super(`请求体超过 ${d/1024/1024} MB 上限(正文内联图片过多/过大?可减少单次发布的图片体积)`);this.name="BodyTooLargeError"}}function AJ(Q){return new Promise(($,z)=>{const Z=[];let V=0,J=!1;Q.on("data",(G)=>{if(J)return;V+=G.length;if(V>d){J=!0;Z.length=0;z(new b);return}Z.push(G)});Q.on("end",()=>{if(!J)$(Buffer.concat(Z).toString("utf-8"))});Q.on("error",(G)=>{if(!J)z(G)})})}function N(Q,$,z,Z){Q.writeHead($,{"Content-Type":"application/json",...Z});Q.end(JSON.stringify(z))}async function a(Q,$){const z=Q.headers.origin;if(z&&!z.startsWith("chrome-extension://")){N($,403,{ok:!1,error:"Forbidden: cross-origin request blocked"});return}if(Q.method==="OPTIONS"){$.writeHead(204);$.end();return}const Z=Q.url??"/",V=Z.split("?")[0];if(Q.method==="GET"&&V==="/ping"){N($,200,{ok:!0},$J(V,z));return}if(!Q.headers["x-opencli"]){N($,403,{ok:!1,error:"Forbidden: missing X-OpenCLI header"});return}if(Q.method==="GET"&&V==="/status"){const J=process.uptime(),G=process.memoryUsage(),L=new URL(Z,`http://localhost:${T}`).searchParams.get("contextId")?.trim()||void 0,A=u(L),C=c().map((_)=>({contextId:_.contextId,extensionConnected:!0,extensionVersion:_.extensionVersion??void 0,extensionCompatRange:_.extensionCompatRange??void 0,pending:[...W.values()].filter((k)=>k.contextId===_.contextId).length,lastSeenAt:_.lastSeenAt}));N($,200,{ok:!0,pid:process.pid,uptime:J,daemonVersion:r,extensionConnected:!!A.connection,extensionVersion:A.connection?.extensionVersion??void 0,extensionCompatRange:A.connection?.extensionCompatRange??void 0,contextId:A.connection?.contextId??L,profileRequired:A.errorCode==="profile_required",profileDisconnected:A.errorCode==="profile_disconnected",profiles:C,pending:W.size,sessionLeases:R.list(Date.now(),m),commandResultUnknown:q,memoryMB:Math.round(G.rss/1024/1024*10)/10,port:T});return}if(Q.method==="GET"&&V==="/logs"){const G=new URL(Z,`http://localhost:${T}`).searchParams.get("level"),H=G?E.filter((L)=>L.level===G):E;N($,200,{ok:!0,logs:H});return}if(Q.method==="DELETE"&&V==="/logs"){E.length=0;N($,200,{ok:!0});return}if(Q.method==="POST"&&V==="/shutdown"){N($,200,{ok:!0,message:"Shutting down"});setTimeout(()=>w(),100);return}if(Q.method==="POST"&&Z==="/command"){try{const J=JSON.parse(await AJ(Q));if(!J.id){N($,400,{ok:!1,error:"Missing command id"});return}if(J.action==="lease-release"){if(typeof J.runId==="string")R.releaseByRunId(J.runId);N($,200,{id:J.id,ok:!0});return}const G=u(typeof J.contextId==="string"?J.contextId:void 0,J.access);if(!G.connection){N($,G.errorCode==="profile_required"?409:503,{id:J.id,ok:!1,errorCode:G.errorCode,error:G.error,...G.errorHint?{errorHint:G.errorHint}:{}});return}let H,L;if(YJ(J)){const D=Date.now(),O=GJ(G.connection.contextId,J.surface,J.session),B=R.touch(O,{runId:J.runId,command:typeof J.command==="string"&&J.command?J.command:J.action,now:D,hasPendingWork:m});if(!B.granted){const X=zJ(J.session,B.holder,D);Y.warn(`[daemon] Session ${O} busy — rejected ${J.command??J.action} (runId=${J.runId}); held by ${B.holder.command} (runId=${B.holder.runId})`);N($,X.status,{id:J.id,ok:!1,errorCode:X.errorCode,error:X.message,errorHint:X.errorHint});return}H=O;L=J.runId}const A=typeof J.deadlineAt==="number"&&J.deadlineAt>0?Math.max(1000,J.deadlineAt-Date.now()):typeof J.timeout==="number"&&J.timeout>0?J.timeout*1000:120000,C=W.get(J.id);if(C){const D=await new Promise((O,B)=>{C.settlers.push({resolve:O,reject:B})});N($,200,D);return}const _=G.connection.contextId,k=await new Promise((D,O)=>{const B=setTimeout(()=>{const K=W.get(J.id);if(!K)return;F.traceTimeout(J.id,A,typeof J.action==="string"?J.action:void 0);const M=JJ(K.action,A);if(M.countAsCommandResultUnknown&&K.dispatched){q++;Y.warn(`[daemon] Command timed out after dispatch (id=${J.id}, action=${K.action}, timeout=${A}ms)`)}v(J.id,K,{error:new S(M.message,M.errorCode,M.errorHint,M.status)})},A),X={contextId:G.connection.contextId,action:typeof J.action==="string"?J.action:"unknown",dispatched:!1,dispatchTs:Date.now(),settlers:[{resolve:D,reject:O}],timer:B,...H&&L?{leaseKey:H,runId:L}:{}};W.set(J.id,X);const f=(K)=>{if(W.get(J.id)!==X)return;const M=g(X.contextId);v(J.id,X,{error:new S(M.message,M.errorCode,M.errorHint,M.status)});Y.warn(`[daemon] Failed to dispatch command ${J.id}: ${K instanceof Error?K.message:String(K)}`)};try{G.connection.ws.send(JSON.stringify(J),(K)=>{if(K&&!X.dispatched)f(K)});X.dispatched=!0;F.traceDispatch(J)}catch(K){f(K)}});N($,200,k&&typeof k==="object"&&!Array.isArray(k)?{...k,routedContextId:_}:k)}catch(J){const G=J instanceof S?J:null;if(J instanceof b){N($,413,{ok:!1,error:J.message,errorCode:"body_too_large"});return}N($,G?.status??(J instanceof Error&&J.message.includes("timeout")?408:400),{ok:!1,error:J instanceof Error?J.message:"Invalid request",...G?.errorCode?{errorCode:G.errorCode}:{},...G?.errorHint?{errorHint:G.errorHint}:{}})}return}N($,404,{error:"Not found"})}const h=y((Q,$)=>{a(Q,$).catch(()=>{$.writeHead(500);$.end()})}),I=y((Q,$)=>{a(Q,$).catch(()=>{$.writeHead(500);$.end()})}),x=new t({noServer:!0});function i(Q,$,z){if((Q.url??"/").split("?")[0]!=="/ext"){$.destroy();return}const V=Q.headers.origin;if(V&&!V.startsWith("chrome-extension://")){$.destroy();return}x.handleUpgrade(Q,$,z,(J)=>{x.emit("connection",J,Q)})}h.on("upgrade",i);I.on("upgrade",i);x.on("connection",(Q)=>{Y.info("[daemon] Extension connected");let $=0;const z=setInterval(()=>{if(Q.readyState!==p.OPEN){clearInterval(z);return}if($>=2){Y.warn("[daemon] Extension heartbeat lost, closing connection");clearInterval(z);Q.terminate();return}$++;Q.ping()},15000);Q.on("pong",()=>{$=0});Q.on("message",(Z)=>{try{const V=JSON.parse(Z.toString());if(V.type==="hello"){if(V.brand!=="publishport"){Y.warn(`[daemon] 拒绝非 PublishPort 官方扩展连接(brand=${JSON.stringify(V.brand)})`);Q.close(4003,"Only the official PublishPort extension is supported");return}const G=WJ(Q,V.contextId);G.extensionVersion=typeof V.version==="string"?V.version:null;G.extensionCompatRange=typeof V.compatRange==="string"?V.compatRange:null;G.lastSeenAt=Date.now();Y.info(`[daemon] Extension profile connected: ${G.contextId}`);F.traceExtConnect(G.contextId,G.extensionVersion);return}if(V.type==="log"){if(V.level==="error")Y.error(`[ext] ${V.msg}`);else if(V.level==="warn")Y.warn(`[ext] ${V.msg}`);else Y.info(`[ext] ${V.msg}`);KJ({level:V.level,msg:V.msg,ts:V.ts??Date.now()});F.traceExtLog(V.level,V.msg);return}if(V.type==="ping")return;const J=W.get(V.id);if(J){F.traceResult(V.id,!!V.ok,Date.now()-J.dispatchTs,typeof V.errorCode==="string"?V.errorCode:void 0,typeof V.page==="string"?V.page:void 0);v(V.id,J,{data:V})}}catch(V){const J=Z.toString().slice(0,200);Y.warn(`[daemon] Ignoring malformed WS message from extension: ${V instanceof Error?V.message:String(V)} (first 200 chars: ${JSON.stringify(J)})`)}});Q.on("close",()=>{Y.info("[daemon] Extension disconnected");clearInterval(z);l(Q)});Q.on("error",()=>{clearInterval(z);l(Q)})});h.listen(T,"127.0.0.1",()=>{Y.info(`[daemon] Listening on http://127.0.0.1:${T}`)});h.on("error",(Q)=>{if(Q.code==="EADDRINUSE"){Y.error(`[daemon] Port ${T} already in use — another daemon is likely running. Exiting.`);process.exit(j.SERVICE_UNAVAIL)}Y.error(`[daemon] Server error: ${Q.message}`);process.exit(j.GENERIC_ERROR)});I.listen(P,"127.0.0.1",()=>{Y.info(`[daemon] Listening on http://127.0.0.1:${P} (PublishPort extension)`)});I.on("error",(Q)=>{Y.warn(`[daemon] PublishPort port ${P} unavailable (${Q.message}) — extension will fall back to ${T}`)});function w(){for(const[Q,$]of W){const z=$.dispatched?new S("Daemon shutting down before the command completed.","daemon_shutting_down","The daemon is being replaced; a journaling extension replays the command result on retry.",503):(()=>{const Z=g($.contextId);return new S(Z.message,Z.errorCode,Z.errorHint,Z.status)})();v(Q,$,{error:z})}W.clear();for(const Q of U.values())Q.ws.close();I.close();h.close(()=>process.exit(j.SUCCESS));setTimeout(()=>{h.closeIdleConnections?.();I.closeIdleConnections?.();setTimeout(()=>process.exit(j.SUCCESS),500).unref()},100).unref()}process.on("SIGTERM",w);process.on("SIGINT",w);
1
+ import{createServer as M}from"node:http";import{WebSocketServer as z,WebSocket as V}from"ws";import{DEFAULT_DAEMON_PORT as Y,PUBLISHPORT_DAEMON_PORT as Z,unsupportedDaemonPortEnvMessage as Q}from"./constants.js";import{EXIT_CODES as b}from"./errors.js";import{log as a}from"./logger.js";import{PKG_VERSION as q}from"./version.js";import{DEFAULT_CONTEXT_ID as ee}from"./browser/profile.js";import{buildCommandDispatchFailure as B,buildCommandTimeoutFailure as ne,buildExtensionDisconnectFailure as te,getResponseCorsHeaders as oe,resolveProfileRoute as re}from"./daemon-utils.js";import*as w from"./browser/trace.js";import{SessionLeaseRegistry as ie,buildSessionBusyFailure as se,getSessionLeaseKey as ae,isSessionLeaseCommand as ce}from"./session-lease.js";const y=Y,D=Z;if(process.env.OPENCLI_DAEMON_PORT){a.error(Q(process.env.OPENCLI_DAEMON_PORT));process.exit(b.USAGE_ERROR)}const p=new Map,u=new Map,_=new ie;function G(n){for(const t of u.values())if(t.runId===n)return!0;return!1}function v(n,t,i){clearTimeout(t.timer);u.delete(n);if(t.leaseKey&&t.runId)_.heartbeat(t.leaseKey,t.runId,Date.now());for(const r of t.settlers)if(i.error)r.reject(i.error);else r.resolve(i.data)}let H=0;const de=200,P=[];class S extends Error{errorCode;errorHint;status;constructor(n,t,i,r=400){super(n);this.errorCode=t;this.errorHint=i;this.status=r;this.name="DaemonCommandFailure"}}function ue(n){P.push(n);if(P.length>de)P.shift()}function F(){return[...p.values()].filter((n)=>n.ws.readyState===V.OPEN)}function W(n,t){const i=F(),r=re(i.map((e)=>e.contextId),n,t);if(r.kind==="error"){if(r.errorCode==="profile_disconnected"&&t==="write"&&i.length===1)a.warn(`[daemon] Refusing to route a WRITE to fallback profile "${i[0].contextId}" (requested "${n}")`);return{errorCode:r.errorCode,error:r.error,errorHint:r.errorHint}}if(r.kind==="fallback")a.warn(`[daemon] Requested profile "${r.requestedContextId}" not connected; falling back to the only connected profile "${r.contextId}"`);const o=i.find((e)=>e.contextId===r.contextId);if(!o)return{errorCode:"extension_not_connected",error:"浏览器桥未连接:这台机器上的 PublishPort 托管浏览器没在运行。",errorHint:"请用户打开 PublishPort 客户端,在平台列表里点一次「检测登录」把托管浏览器拉起来;仍不行就重启客户端。"};return{connection:o}}function le(n,t){const i=typeof t==="string"&&t.trim()?t.trim():ee,r=p.get(i);if(r&&r.ws!==n)r.ws.close();const o=[...p.entries()].find(([,g])=>g.ws===n);if(o&&o[0]!==i)p.delete(o[0]);const e=p.get(i),s={contextId:i,ws:n,extensionVersion:e?.ws===n?e.extensionVersion:null,extensionCompatRange:e?.ws===n?e.extensionCompatRange:null,lastSeenAt:Date.now()};p.set(i,s);return s}function J(n){for(const[t,i]of p.entries()){if(i.ws!==n)continue;p.delete(t);w.traceExtDisconnect(t);for(const[r,o]of u){if(o.contextId!==t)continue;const e=te({contextId:t,action:o.action,dispatched:o.dispatched});if(e.countAsCommandResultUnknown){H++;a.warn(`[daemon] Command result unknown after extension disconnect (id=${r}, action=${o.action}, context=${t})`)}w.traceResult(r,!1,Date.now()-o.dispatchTs,e.errorCode);v(r,o,{error:new S(e.message,e.errorCode,e.errorHint,e.status)})}}}const j=33554432;class L extends Error{status=413;constructor(){super(`请求体超过 ${j/1024/1024} MB 上限(正文内联图片过多/过大?可减少单次发布的图片体积)`);this.name="BodyTooLargeError"}}function fe(n){return new Promise((t,i)=>{const r=[];let o=0,e=!1;n.on("data",(s)=>{if(e)return;o+=s.length;if(o>j){e=!0;r.length=0;i(new L);return}r.push(s)});n.on("end",()=>{if(!e)t(Buffer.concat(r).toString("utf-8"))});n.on("error",(s)=>{if(!e)i(s)})})}function c(n,t,i,r){n.writeHead(t,{"Content-Type":"application/json",...r});n.end(JSON.stringify(i))}async function K(n,t){const i=n.headers.origin;if(i&&!i.startsWith("chrome-extension://")){c(t,403,{ok:!1,error:"Forbidden: cross-origin request blocked"});return}if(n.method==="OPTIONS"){t.writeHead(204);t.end();return}const r=n.url??"/",o=r.split("?")[0];if(n.method==="GET"&&o==="/ping"){c(t,200,{ok:!0},oe(o,i));return}if(!n.headers["x-opencli"]){c(t,403,{ok:!1,error:"Forbidden: missing X-OpenCLI header"});return}if(n.method==="GET"&&o==="/status"){const e=process.uptime(),s=process.memoryUsage(),h=new URL(r,`http://localhost:${y}`).searchParams.get("contextId")?.trim()||void 0,l=W(h),k=F().map((I)=>({contextId:I.contextId,extensionConnected:!0,extensionVersion:I.extensionVersion??void 0,extensionCompatRange:I.extensionCompatRange??void 0,pending:[...u.values()].filter((C)=>C.contextId===I.contextId).length,lastSeenAt:I.lastSeenAt}));c(t,200,{ok:!0,pid:process.pid,uptime:e,daemonVersion:q,extensionConnected:!!l.connection,extensionVersion:l.connection?.extensionVersion??void 0,extensionCompatRange:l.connection?.extensionCompatRange??void 0,contextId:l.connection?.contextId??h,profileRequired:l.errorCode==="profile_required",profileDisconnected:l.errorCode==="profile_disconnected",profiles:k,pending:u.size,sessionLeases:_.list(Date.now(),G),commandResultUnknown:H,memoryMB:Math.round(s.rss/1024/1024*10)/10,port:y});return}if(n.method==="GET"&&o==="/logs"){const s=new URL(r,`http://localhost:${y}`).searchParams.get("level"),g=s?P.filter((h)=>h.level===s):P;c(t,200,{ok:!0,logs:g});return}if(n.method==="DELETE"&&o==="/logs"){P.length=0;c(t,200,{ok:!0});return}if(n.method==="POST"&&o==="/shutdown"){c(t,200,{ok:!0,message:"Shutting down"});setTimeout(()=>N(),100);return}if(n.method==="POST"&&r==="/command"){try{const e=JSON.parse(await fe(n));if(!e.id){c(t,400,{ok:!1,error:"Missing command id"});return}if(e.action==="lease-release"){if(typeof e.runId==="string")_.releaseByRunId(e.runId);c(t,200,{id:e.id,ok:!0});return}const s=W(typeof e.contextId==="string"?e.contextId:void 0,e.access);if(!s.connection){c(t,s.errorCode==="profile_required"?409:503,{id:e.id,ok:!1,errorCode:s.errorCode,error:s.error,...s.errorHint?{errorHint:s.errorHint}:{}});return}let g,h;if(ce(e)){const R=Date.now(),E=ae(s.connection.contextId,e.surface,e.session),x=_.touch(E,{runId:e.runId,command:typeof e.command==="string"&&e.command?e.command:e.action,now:R,hasPendingWork:G});if(!x.granted){const f=se(e.session,x.holder,R);a.warn(`[daemon] Session ${E} busy — rejected ${e.command??e.action} (runId=${e.runId}); held by ${x.holder.command} (runId=${x.holder.runId})`);c(t,f.status,{id:e.id,ok:!1,errorCode:f.errorCode,error:f.message,errorHint:f.errorHint});return}g=E;h=e.runId}const l=typeof e.deadlineAt==="number"&&e.deadlineAt>0?Math.max(1000,e.deadlineAt-Date.now()):typeof e.timeout==="number"&&e.timeout>0?e.timeout*1000:120000,k=u.get(e.id);if(k){const R=await new Promise((E,x)=>{k.settlers.push({resolve:E,reject:x})});c(t,200,R);return}const I=s.connection.contextId,C=await new Promise((R,E)=>{const x=setTimeout(()=>{const d=u.get(e.id);if(!d)return;w.traceTimeout(e.id,l,typeof e.action==="string"?e.action:void 0);const m=ne(d.action,l);if(m.countAsCommandResultUnknown&&d.dispatched){H++;a.warn(`[daemon] Command timed out after dispatch (id=${e.id}, action=${d.action}, timeout=${l}ms)`)}v(e.id,d,{error:new S(m.message,m.errorCode,m.errorHint,m.status)})},l),f={contextId:s.connection.contextId,action:typeof e.action==="string"?e.action:"unknown",dispatched:!1,dispatchTs:Date.now(),settlers:[{resolve:R,reject:E}],timer:x,...g&&h?{leaseKey:g,runId:h}:{}};u.set(e.id,f);const U=(d)=>{if(u.get(e.id)!==f)return;const m=B(f.contextId);v(e.id,f,{error:new S(m.message,m.errorCode,m.errorHint,m.status)});a.warn(`[daemon] Failed to dispatch command ${e.id}: ${d instanceof Error?d.message:String(d)}`)};try{s.connection.ws.send(JSON.stringify(e),(d)=>{if(d&&!f.dispatched)U(d)});f.dispatched=!0;w.traceDispatch(e)}catch(d){U(d)}});c(t,200,C&&typeof C==="object"&&!Array.isArray(C)?{...C,routedContextId:I}:C)}catch(e){const s=e instanceof S?e:null;if(e instanceof L){c(t,413,{ok:!1,error:e.message,errorCode:"body_too_large"});return}c(t,s?.status??(e instanceof Error&&e.message.includes("timeout")?408:400),{ok:!1,error:e instanceof Error?e.message:"Invalid request",...s?.errorCode?{errorCode:s.errorCode}:{},...s?.errorHint?{errorHint:s.errorHint}:{}})}return}c(t,404,{error:"Not found"})}const O=M((n,t)=>{K(n,t).catch(()=>{t.writeHead(500);t.end()})}),T=M((n,t)=>{K(n,t).catch(()=>{t.writeHead(500);t.end()})}),A=new z({noServer:!0});function X(n,t,i){if((n.url??"/").split("?")[0]!=="/ext"){t.destroy();return}const o=n.headers.origin;if(o&&!o.startsWith("chrome-extension://")){t.destroy();return}A.handleUpgrade(n,t,i,(e)=>{A.emit("connection",e,n)})}O.on("upgrade",X);T.on("upgrade",X);A.on("connection",(n)=>{a.info("[daemon] Extension connected");let t=0;const i=setInterval(()=>{if(n.readyState!==V.OPEN){clearInterval(i);return}if(t>=2){a.warn("[daemon] Extension heartbeat lost, closing connection");clearInterval(i);n.terminate();return}t++;n.ping()},15000);n.on("pong",()=>{t=0});n.on("message",(r)=>{try{const o=JSON.parse(r.toString());if(o.type==="hello"){if(o.brand!=="publishport"){a.warn(`[daemon] 拒绝非 PublishPort 官方扩展连接(brand=${JSON.stringify(o.brand)})`);n.close(4003,"Only the official PublishPort extension is supported");return}const s=le(n,o.contextId);s.extensionVersion=typeof o.version==="string"?o.version:null;s.extensionCompatRange=typeof o.compatRange==="string"?o.compatRange:null;s.lastSeenAt=Date.now();a.info(`[daemon] Extension profile connected: ${s.contextId}`);w.traceExtConnect(s.contextId,s.extensionVersion);return}if(o.type==="log"){if(o.level==="error")a.error(`[ext] ${o.msg}`);else if(o.level==="warn")a.warn(`[ext] ${o.msg}`);else a.info(`[ext] ${o.msg}`);ue({level:o.level,msg:o.msg,ts:o.ts??Date.now()});w.traceExtLog(o.level,o.msg);return}if(o.type==="ping")return;const e=u.get(o.id);if(e){w.traceResult(o.id,!!o.ok,Date.now()-e.dispatchTs,typeof o.errorCode==="string"?o.errorCode:void 0,typeof o.page==="string"?o.page:void 0);v(o.id,e,{data:o})}}catch(o){const e=r.toString().slice(0,200);a.warn(`[daemon] Ignoring malformed WS message from extension: ${o instanceof Error?o.message:String(o)} (first 200 chars: ${JSON.stringify(e)})`)}});n.on("close",()=>{a.info("[daemon] Extension disconnected");clearInterval(i);J(n)});n.on("error",()=>{clearInterval(i);J(n)})});O.listen(y,"127.0.0.1",()=>{a.info(`[daemon] Listening on http://127.0.0.1:${y}`)});O.on("error",(n)=>{if(n.code==="EADDRINUSE"){a.error(`[daemon] Port ${y} already in use — another daemon is likely running. Exiting.`);process.exit(b.SERVICE_UNAVAIL)}a.error(`[daemon] Server error: ${n.message}`);process.exit(b.GENERIC_ERROR)});T.listen(D,"127.0.0.1",()=>{a.info(`[daemon] Listening on http://127.0.0.1:${D} (PublishPort extension)`)});T.on("error",(n)=>{a.warn(`[daemon] PublishPort port ${D} unavailable (${n.message}) — extension will fall back to ${y}`)});function N(){for(const[n,t]of u){const i=t.dispatched?new S("Daemon shutting down before the command completed.","daemon_shutting_down","The daemon is being replaced; a journaling extension replays the command result on retry.",503):(()=>{const r=B(t.contextId);return new S(r.message,r.errorCode,r.errorHint,r.status)})();v(n,t,{error:i})}u.clear();for(const n of p.values())n.ws.close();T.close();O.close(()=>process.exit(b.SUCCESS));setTimeout(()=>{O.closeIdleConnections?.();T.closeIdleConnections?.();setTimeout(()=>process.exit(b.SUCCESS),500).unref()},100).unref()}process.on("SIGTERM",N);process.on("SIGINT",N);
@@ -1,2 +1,2 @@
1
- import*as H from"node:fs";import*as j from"node:os";import*as Y from"node:path";import{fileURLToPath as F,pathToFileURL as v}from"node:url";import{Strategy as A,registerCommand as J}from"./registry.js";import{getErrorMessage as $}from"./errors.js";import{log as Z}from"./logger.js";import{findPackageRoot as O,getCliManifestPath as N}from"./package-paths.js";import{migrateLegacyUserRuntime as T}from"./user-runtime.js";T();export const USER_OPENCLI_DIR=Y.join(j.homedir(),".ppcli"),USER_CLIS_DIR=Y.join(USER_OPENCLI_DIR,"clis"),PLUGINS_DIR=Y.join(USER_OPENCLI_DIR,"plugins");const b=/\b(?:cli|registerSiteAuthCommands|onStartup|onBeforeExecute|onAfterExecute)\s*\(/;function M(z,x=A.COOKIE){if(!z)return x;const B=z.toUpperCase();return A[B]??x}const C=O(F(import.meta.url));export async function ensureUserCliCompatShims(z=USER_OPENCLI_DIR){await H.promises.mkdir(z,{recursive:!0});const x=Y.join(z,"package.json"),B=`${JSON.stringify({name:"opencli-user-runtime",private:!0,type:"module"},null,2)}
2
- `;try{if(await H.promises.readFile(x,"utf-8")!==B)await H.promises.writeFile(x,B,"utf-8")}catch{await H.promises.writeFile(x,B,"utf-8")}const V=C,q=Y.join(z,"node_modules","@jackwener"),Q=Y.join(q,"opencli");try{let W=!0;try{if(await H.promises.readlink(Q)===V)W=!1}catch{}if(W){await H.promises.mkdir(q,{recursive:!0});try{await H.promises.rm(Q,{recursive:!0,force:!0})}catch{}const X=process.platform==="win32"?"junction":"dir";await H.promises.symlink(V,Q,X)}}catch(W){Z.warn(`Could not create symlink at ${Q}: ${$(W)}`)}}export async function ensureUserAdapters(){await H.promises.mkdir(USER_CLIS_DIR,{recursive:!0})}export async function discoverClis(...z){for(const x of z){const B=N(x);try{await H.promises.access(B);if(await L(B,x))continue}catch{}await _(x)}}async function L(z,x){try{const B=await H.promises.readFile(z,"utf-8"),V=JSON.parse(B);for(const q of V){if(!q.modulePath)continue;const Q=Y.resolve(x,q.modulePath),W={site:q.site,name:q.name,aliases:q.aliases,description:q.description??"",access:q.access,example:q.example,domain:q.domain,strategy:M(q.strategy),browser:q.browser,args:q.args??[],columns:q.columns,defaultFormat:q.defaultFormat,pipeline:q.pipeline,source:q.sourceFile?Y.resolve(x,q.sourceFile):Q,navigateBefore:q.navigateBefore,siteSession:q.siteSession,defaultWindowMode:q.defaultWindowMode,_lazy:!0,_modulePath:Q};J(W)}return!0}catch(B){Z.warn(`Failed to load manifest ${z}: ${$(B)}`);return!1}}async function _(z){try{await H.promises.access(z)}catch{return}const B=(await H.promises.readdir(z,{withFileTypes:!0})).filter((V)=>V.isDirectory()).map(async(V)=>{const q=V.name,Q=Y.join(z,q),W=await H.promises.readdir(Q);await Promise.all(W.map(async(X)=>{const K=Y.join(Q,X);if(X.endsWith(".yaml")||X.endsWith(".yml"))return;if(X.endsWith(".ts")&&!X.endsWith(".d.ts")&&!X.endsWith(".test.ts")){Z.warn(`Ignoring TypeScript adapter ${K} — .ts adapters are no longer loaded. Rename to .js or convert to JavaScript.`);return}if(X.endsWith(".js")&&!X.endsWith(".d.js")&&!X.endsWith(".test.js")){if(!await w(K))return;await import(v(K).href).catch((G)=>{Z.warn(`Failed to load module ${K}: ${$(G)}`)})}}))});await Promise.all(B)}export async function discoverPlugins(){try{await H.promises.access(PLUGINS_DIR)}catch{return}const z=await H.promises.readdir(PLUGINS_DIR,{withFileTypes:!0});await Promise.all(z.map(async(x)=>{const B=Y.join(PLUGINS_DIR,x.name);if(!await U(x,B))return;await I(B,x.name)}))}async function I(z,x){let B;try{B=await H.promises.readdir(z)}catch(q){const Q=q.code;if(Q!=="ENOENT"&&Q!=="ENOTDIR")Z.warn(`Failed to scan plugin directory ${z}: ${$(q)}`);return}const V=new Set(B);await Promise.all(B.map(async(q)=>{const Q=Y.join(z,q);if(q.endsWith(".yaml")||q.endsWith(".yml"))return;if(q.endsWith(".js")&&!q.endsWith(".d.js")){if(!await w(Q))return;await import(v(Q).href).catch((W)=>{Z.warn(`Plugin ${x}/${q}: ${$(W)}`)})}else if(q.endsWith(".ts")&&!q.endsWith(".d.ts")&&!q.endsWith(".test.ts")){const W=q.replace(/\.ts$/,".js");if(V.has(W))return;Z.warn(`Plugin ${x}/${q}: no compiled .js found. Run "ppcli plugin update ${x}" to re-transpile, or install esbuild.`)}}))}async function w(z){try{const x=await H.promises.readFile(z,"utf-8");return b.test(x)}catch(x){Z.warn(`Failed to inspect module ${z}: ${$(x)}`);return!1}}async function U(z,x){if(z.isDirectory())return!0;if(!z.isSymbolicLink())return!1;try{return(await H.promises.stat(x)).isDirectory()}catch(B){const V=B.code;if(V!=="ENOENT"&&V!=="ENOTDIR")Z.warn(`Failed to inspect plugin link ${x}: ${$(B)}`);return!1}}
1
+ import*as r from"node:fs";import*as h from"node:os";import*as m from"node:path";import{fileURLToPath as g,pathToFileURL as p}from"node:url";import{Strategy as f,registerCommand as P}from"./registry.js";import{getErrorMessage as l}from"./errors.js";import{log as u}from"./logger.js";import{findPackageRoot as j,getCliManifestPath as F}from"./package-paths.js";import{migrateLegacyUserRuntime as S}from"./user-runtime.js";S();export const USER_OPENCLI_DIR=m.join(h.homedir(),".ppcli"),USER_CLIS_DIR=m.join(USER_OPENCLI_DIR,"clis"),PLUGINS_DIR=m.join(USER_OPENCLI_DIR,"plugins");const W=/\b(?:cli|registerSiteAuthCommands|onStartup|onBeforeExecute|onAfterExecute)\s*\(/;function k(s,e=f.COOKIE){if(!s)return e;const i=s.toUpperCase();return f[i]??e}const v=j(g(import.meta.url));export async function ensureUserCliCompatShims(s=USER_OPENCLI_DIR){await r.promises.mkdir(s,{recursive:!0});const e=m.join(s,"package.json"),i=`${JSON.stringify({name:"opencli-user-runtime",private:!0,type:"module"},null,2)}
2
+ `;try{if(await r.promises.readFile(e,"utf-8")!==i)await r.promises.writeFile(e,i,"utf-8")}catch{await r.promises.writeFile(e,i,"utf-8")}const o=v,t=m.join(s,"node_modules","@jackwener"),a=m.join(t,"opencli");try{let n=!0;try{if(await r.promises.readlink(a)===o)n=!1}catch{}if(n){await r.promises.mkdir(t,{recursive:!0});try{await r.promises.rm(a,{recursive:!0,force:!0})}catch{}const c=process.platform==="win32"?"junction":"dir";await r.promises.symlink(o,a,c)}}catch(n){u.warn(`Could not create symlink at ${a}: ${l(n)}`)}}export async function ensureUserAdapters(){await r.promises.mkdir(USER_CLIS_DIR,{recursive:!0})}export async function discoverClis(...s){for(const e of s){const i=F(e);try{await r.promises.access(i);if(await E(i,e))continue}catch{}await R(e)}}async function E(s,e){try{const i=await r.promises.readFile(s,"utf-8"),o=JSON.parse(i);for(const t of o){if(!t.modulePath)continue;const a=m.resolve(e,t.modulePath),n={site:t.site,name:t.name,aliases:t.aliases,description:t.description??"",access:t.access,example:t.example,domain:t.domain,strategy:k(t.strategy),browser:t.browser,args:t.args??[],columns:t.columns,defaultFormat:t.defaultFormat,pipeline:t.pipeline,source:t.sourceFile?m.resolve(e,t.sourceFile):a,navigateBefore:t.navigateBefore,siteSession:t.siteSession,defaultWindowMode:t.defaultWindowMode,_lazy:!0,_modulePath:a};P(n)}return!0}catch(i){u.warn(`Failed to load manifest ${s}: ${l(i)}`);return!1}}async function R(s){try{await r.promises.access(s)}catch{return}const i=(await r.promises.readdir(s,{withFileTypes:!0})).filter((o)=>o.isDirectory()).map(async(o)=>{const t=o.name,a=m.join(s,t),n=await r.promises.readdir(a);await Promise.all(n.map(async(c)=>{const d=m.join(a,c);if(c.endsWith(".yaml")||c.endsWith(".yml"))return;if(c.endsWith(".ts")&&!c.endsWith(".d.ts")&&!c.endsWith(".test.ts")){u.warn(`Ignoring TypeScript adapter ${d} — .ts adapters are no longer loaded. Rename to .js or convert to JavaScript.`);return}if(c.endsWith(".js")&&!c.endsWith(".d.js")&&!c.endsWith(".test.js")){if(!await w(d))return;await import(p(d).href).catch((y)=>{u.warn(`Failed to load module ${d}: ${l(y)}`)})}}))});await Promise.all(i)}export async function discoverPlugins(){try{await r.promises.access(PLUGINS_DIR)}catch{return}const s=await r.promises.readdir(PLUGINS_DIR,{withFileTypes:!0});await Promise.all(s.map(async(e)=>{const i=m.join(PLUGINS_DIR,e.name);if(!await C(e,i))return;await x(i,e.name)}))}async function x(s,e){let i;try{i=await r.promises.readdir(s)}catch(t){const a=t.code;if(a!=="ENOENT"&&a!=="ENOTDIR")u.warn(`Failed to scan plugin directory ${s}: ${l(t)}`);return}const o=new Set(i);await Promise.all(i.map(async(t)=>{const a=m.join(s,t);if(t.endsWith(".yaml")||t.endsWith(".yml"))return;if(t.endsWith(".js")&&!t.endsWith(".d.js")){if(!await w(a))return;await import(p(a).href).catch((n)=>{u.warn(`Plugin ${e}/${t}: ${l(n)}`)})}else if(t.endsWith(".ts")&&!t.endsWith(".d.ts")&&!t.endsWith(".test.ts")){const n=t.replace(/\.ts$/,".js");if(o.has(n))return;u.warn(`Plugin ${e}/${t}: no compiled .js found. Run "ppcli plugin update ${e}" to re-transpile, or install esbuild.`)}}))}async function w(s){try{const e=await r.promises.readFile(s,"utf-8");return W.test(e)}catch(e){u.warn(`Failed to inspect module ${s}: ${l(e)}`);return!1}}async function C(s,e){if(s.isDirectory())return!0;if(!s.isSymbolicLink())return!1;try{return(await r.promises.stat(e)).isDirectory()}catch(i){const o=i.code;if(o!=="ENOENT"&&o!=="ENOTDIR")u.warn(`Failed to inspect plugin link ${e}: ${l(i)}`);return!1}}
@@ -1,13 +1,13 @@
1
- import{DEFAULT_DAEMON_PORT as M}from"./constants.js";import{BrowserBridge as k}from"./browser/index.js";import{setDaemonCommandTimeoutSeconds as P}from"./browser/daemon-client.js";import{getDaemonHealth as _}from"./browser/daemon-transport.js";import{getErrorMessage as F}from"./errors.js";import{getRuntimeLabel as E}from"./runtime-detect.js";import{aliasForContextId as I,loadProfileConfig as O}from"./browser/profile.js";import{formatDaemonVersion as N,isDaemonStale as T,staleDaemonIssue as b}from"./browser/daemon-version.js";import{findShadowedUserAdapters as j,formatAdapterShadowIssue as y}from"./adapter-shadow.js";const w=8,V="__doctor__";function U(q){const z=q.replace(/^v/,"").split("-")[0].split(".").map(Number);if(z.length<3||z.some(isNaN))return null;return[z[0],z[1],z[2]]}function D(q,z){const G=z.match(/^(>=?)\s*(\S+)$/);if(!G)return!0;const[,K,W]=G,Y=U(q),Z=U(W);if(!Y||!Z)return!0;const Q=Y[0]-Z[0]||Y[1]-Z[1]||Y[2]-Z[2];return K===">="?Q>=0:Q>0}export async function checkConnectivity(q){const z=Date.now(),G=q?.timeout??w;P(G);try{const K=new k,W=await K.connect({timeout:G,session:V,surface:"browser"});try{await W.evaluate("1 + 1");await W.closeWindow?.()}finally{await K.close()}return{ok:!0,durationMs:Date.now()-z}}catch(K){return{ok:!1,error:F(K),durationMs:Date.now()-z}}finally{P(null)}}export async function runBrowserDoctor(q={}){const z=await checkConnectivity(),G=await _(),K=G.state!=="stopped",W=G.state==="ready",Y=z.ok&&!K,Z=z.ok&&K&&!W,Q=T(G.status,q.cliVersion),$=G.status?.profiles,X=G.status?.extensionVersion,H=j(),J=[];if(Y)J.push(`Daemon connectivity is unstable. The live browser test succeeded, but the daemon was no longer running immediately afterward.
2
- This usually means the daemon crashed or exited right after serving the live probe.`);else if(!K)J.push("Daemon is not running. It should start automatically when you run an ppcli browser command.");if(Q&&q.cliVersion)J.push(b(G.status,q.cliVersion));if(Z)J.push(`Extension connection is unstable. The live browser test succeeded, but the daemon reported the extension disconnected immediately afterward.
3
- This usually means the Browser Bridge service worker is reconnecting slowly or Chrome suspended it.`);else if(K&&!W)if(G.state==="profile-required")J.push(`Multiple Chrome profiles are connected to the daemon, but no default profile was selected.
4
- Run ppcli profile list, then ppcli profile use <name>, or pass --profile <name>.`);else if(G.state==="profile-disconnected")J.push(`Selected browser profile is not connected: ${G.status?.contextId??"unknown"}.
5
- Open that Chrome profile and make sure the ppcli extension is enabled.`);else J.push(`Daemon is running but the Chrome/Chromium extension is not connected.
1
+ import{DEFAULT_DAEMON_PORT as v}from"./constants.js";import{BrowserBridge as g}from"./browser/index.js";import{setDaemonCommandTimeoutSeconds as h}from"./browser/daemon-client.js";import{getDaemonHealth as b}from"./browser/daemon-transport.js";import{getErrorMessage as y}from"./errors.js";import{getRuntimeLabel as k}from"./runtime-detect.js";import{aliasForContextId as I,loadProfileConfig as C}from"./browser/profile.js";import{formatDaemonVersion as f,isDaemonStale as V,staleDaemonIssue as S}from"./browser/daemon-version.js";import{findShadowedUserAdapters as D,formatAdapterShadowIssue as P}from"./adapter-shadow.js";const R=8,T="__doctor__";function p(e){const n=e.replace(/^v/,"").split("-")[0].split(".").map(Number);if(n.length<3||n.some(isNaN))return null;return[n[0],n[1],n[2]]}function O(e,n){const o=n.match(/^(>=?)\s*(\S+)$/);if(!o)return!0;const[,s,a]=o,c=p(e),l=p(a);if(!c||!l)return!0;const i=c[0]-l[0]||c[1]-l[1]||c[2]-l[2];return s===">="?i>=0:i>0}export async function checkConnectivity(e){const n=Date.now(),o=e?.timeout??R;h(o);try{const s=new g,a=await s.connect({timeout:o,session:T,surface:"browser"});try{await a.evaluate("1 + 1");await a.closeWindow?.()}finally{await s.close()}return{ok:!0,durationMs:Date.now()-n}}catch(s){return{ok:!1,error:y(s),durationMs:Date.now()-n}}finally{h(null)}}export async function runBrowserDoctor(e={}){const n=await checkConnectivity(),o=await b(),s=o.state!=="stopped",a=o.state==="ready",c=n.ok&&!s,l=n.ok&&s&&!a,i=V(o.status,e.cliVersion),u=o.status?.profiles,r=o.status?.extensionVersion,d=D(),t=[];if(c)t.push(`Daemon connectivity is unstable. The live browser test succeeded, but the daemon was no longer running immediately afterward.
2
+ This usually means the daemon crashed or exited right after serving the live probe.`);else if(!s)t.push("Daemon is not running. It should start automatically when you run an ppcli browser command.");if(i&&e.cliVersion)t.push(S(o.status,e.cliVersion));if(l)t.push(`Extension connection is unstable. The live browser test succeeded, but the daemon reported the extension disconnected immediately afterward.
3
+ This usually means the Browser Bridge service worker is reconnecting slowly or Chrome suspended it.`);else if(s&&!a)if(o.state==="profile-required")t.push(`Multiple Chrome profiles are connected to the daemon, but no default profile was selected.
4
+ Run ppcli profile list, then ppcli profile use <name>, or pass --profile <name>.`);else if(o.state==="profile-disconnected")t.push(`Selected browser profile is not connected: ${o.status?.contextId??"unknown"}.
5
+ Open that Chrome profile and make sure the ppcli extension is enabled.`);else t.push(`Daemon is running but the Chrome/Chromium extension is not connected.
6
6
  If the extension is already installed, try: ppcli daemon restart
7
7
  If the extension is not installed, install the PublishPort browser extension
8
- from the PublishPort desktop app.`);if(W&&!X)J.push(`Extension is connected but did not report a version.
8
+ from the PublishPort desktop app.`);if(a&&!r)t.push(`Extension is connected but did not report a version.
9
9
  This usually means an outdated Browser Bridge extension.
10
- Reload or reinstall the PublishPort browser extension via the PublishPort desktop app.`);if(!z.ok)J.push(`Browser connectivity test failed: ${z.error??"unknown"}`);const B=G.status?.extensionCompatRange;if(X&&q.cliVersion&&B){if(!D(q.cliVersion,B))J.push(`CLI version incompatible with extension: extension v${X} requires CLI ${B}, but CLI is v${q.cliVersion}
11
- Update via the PublishPort desktop app (or: npm install -g publishport-ppcli).`)}else if(X&&q.cliVersion){const A=X.split(".")[0],L=q.cliVersion.split(".")[0];if(A!==L)J.push(`Extension major version mismatch: extension v${X} ≠ CLI v${q.cliVersion}
12
- Update the PublishPort browser extension via the PublishPort desktop app.`)}if(H.length>0)J.push(y(H));return{cliVersion:q.cliVersion,daemonRunning:K,daemonFlaky:Y,daemonStale:Q,daemonVersion:G.status?.daemonVersion,extensionConnected:W,extensionFlaky:Z,extensionVersion:X,connectivity:z,profiles:$,adapterShadows:H,issues:J}}export function renderBrowserDoctorReport(q){const z=[`ppcli v${q.cliVersion??"unknown"} doctor (${E()})`,""],G=q.daemonFlaky?"[WARN]":q.daemonStale?"[WARN]":q.daemonRunning?"[OK]":"[MISSING]",K=q.daemonFlaky?"unstable (running during live check, then stopped)":q.daemonRunning?`running on port ${M} (${q.daemonStale?`${N(q)}, stale; CLI v${q.cliVersion??"unknown"}`:N(q)})`:"not running";z.push(`${G} Daemon: ${K}`);const W=q.extensionFlaky||q.extensionConnected&&!q.extensionVersion?"[WARN]":q.extensionConnected?"[OK]":"[MISSING]",Y=!q.extensionConnected?"":q.extensionVersion?` (v${q.extensionVersion})`:" (version unknown)",Z=q.extensionFlaky?"unstable (connected during live check, then disconnected)":q.extensionConnected?"connected":"not connected";z.push(`${W} Extension: ${Z}${Y}`);if(q.profiles&&q.profiles.length>0){const Q=O();z.push("","Profiles:");for(const $ of q.profiles){const X=I(Q,$.contextId),H=X?` (${X})`:"",J=Q.defaultContextId===$.contextId?", default":"",B=$.extensionVersion?`v${$.extensionVersion}`:"version unknown";z.push(` • ${$.contextId}${H}: connected ${B}${J}`)}}if(q.connectivity){const Q=q.connectivity.ok?"[OK]":"[FAIL]",$=q.connectivity.ok?`connected in ${(q.connectivity.durationMs/1000).toFixed(1)}s`:`failed (${q.connectivity.error??"unknown"})`;z.push(`${Q} Connectivity: ${$}`)}if(q.issues.length){z.push("","Issues:");for(const Q of q.issues)z.push(` • ${Q}`)}else if(q.daemonRunning&&q.extensionConnected)z.push("","Everything looks good!");return z.join(`
10
+ Reload or reinstall the PublishPort browser extension via the PublishPort desktop app.`);if(!n.ok)t.push(`Browser connectivity test failed: ${n.error??"unknown"}`);const m=o.status?.extensionCompatRange;if(r&&e.cliVersion&&m){if(!O(e.cliVersion,m))t.push(`CLI version incompatible with extension: extension v${r} requires CLI ${m}, but CLI is v${e.cliVersion}
11
+ Update via the PublishPort desktop app (or: npm install -g publishport-ppcli).`)}else if(r&&e.cliVersion){const x=r.split(".")[0],w=e.cliVersion.split(".")[0];if(x!==w)t.push(`Extension major version mismatch: extension v${r} ≠ CLI v${e.cliVersion}
12
+ Update the PublishPort browser extension via the PublishPort desktop app.`)}if(d.length>0)t.push(P(d));return{cliVersion:e.cliVersion,daemonRunning:s,daemonFlaky:c,daemonStale:i,daemonVersion:o.status?.daemonVersion,extensionConnected:a,extensionFlaky:l,extensionVersion:r,connectivity:n,profiles:u,adapterShadows:d,issues:t}}export function renderBrowserDoctorReport(e){const n=[`ppcli v${e.cliVersion??"unknown"} doctor (${k()})`,""],o=e.daemonFlaky?"[WARN]":e.daemonStale?"[WARN]":e.daemonRunning?"[OK]":"[MISSING]",s=e.daemonFlaky?"unstable (running during live check, then stopped)":e.daemonRunning?`running on port ${v} (${e.daemonStale?`${f(e)}, stale; CLI v${e.cliVersion??"unknown"}`:f(e)})`:"not running";n.push(`${o} Daemon: ${s}`);const a=e.extensionFlaky||e.extensionConnected&&!e.extensionVersion?"[WARN]":e.extensionConnected?"[OK]":"[MISSING]",c=!e.extensionConnected?"":e.extensionVersion?` (v${e.extensionVersion})`:" (version unknown)",l=e.extensionFlaky?"unstable (connected during live check, then disconnected)":e.extensionConnected?"connected":"not connected";n.push(`${a} Extension: ${l}${c}`);if(e.profiles&&e.profiles.length>0){const i=C();n.push("","Profiles:");for(const u of e.profiles){const r=I(i,u.contextId),d=r?` (${r})`:"",t=i.defaultContextId===u.contextId?", default":"",m=u.extensionVersion?`v${u.extensionVersion}`:"version unknown";n.push(` • ${u.contextId}${d}: connected ${m}${t}`)}}if(e.connectivity){const i=e.connectivity.ok?"[OK]":"[FAIL]",u=e.connectivity.ok?`connected in ${(e.connectivity.durationMs/1000).toFixed(1)}s`:`failed (${e.connectivity.error??"unknown"})`;n.push(`${i} Connectivity: ${u}`)}if(e.issues.length){n.push("","Issues:");for(const i of e.issues)n.push(` • ${i}`)}else if(e.daemonRunning&&e.extensionConnected)n.push("","Everything looks good!");return n.join(`
13
13
  `)}
@@ -1,21 +1,21 @@
1
- import*as P from"node:fs";import*as H from"node:path";import k from"turndown";import{gfm as x}from"turndown-plugin-gfm";import{httpDownload as C,sanitizeFilename as E}from"./index.js";import{formatBytes as I}from"./progress.js";const b=5,M={author:"作者",publishTime:"发布时间",sourceUrl:"原文链接"},T=["script","style","noscript","canvas","form","button","dialog","header","footer","nav","aside"];function D(J,$){const V=new k({headingStyle:"atx",codeBlockStyle:"fenced",bulletListMarker:"-"});V.use(x);V.remove(T);V.addRule("canonicalStrikethrough",{filter:(K)=>["DEL","S","STRIKE"].includes(K.nodeName),replacement:(K)=>`~~${K}~~`});V.addRule("stripSvg",{filter:(K)=>K.nodeName==="svg"||K.nodeName==="SVG",replacement:()=>""});V.addRule("linebreak",{filter:"br",replacement:()=>`
2
- `});V.addRule("ignoreBase64Images",{filter:(K)=>{if(K.nodeName!=="IMG")return!1;return(K.getAttribute?.("src")??"").startsWith("data:")},replacement:()=>""});V.addRule("videoElement",{filter:(K)=>K.nodeName==="VIDEO",replacement:(K,Q)=>{const W=Q,Z=W.getAttribute("src")||W.querySelector("source")?.getAttribute("src")||"";if(!Z)return"";const X=W.getAttribute("poster")||"";return`
3
- <video src="${Z}" controls${X?` poster="${X}"`:""}></video>
4
- `}});V.addRule("audioElement",{filter:(K)=>K.nodeName==="AUDIO",replacement:(K,Q)=>{const W=Q,Z=W.getAttribute("src")||W.querySelector("source")?.getAttribute("src")||"";return Z?`
5
- <audio src="${Z}" controls></audio>
6
- `:""}});V.addRule("iframeToLink",{filter:(K)=>K.nodeName==="IFRAME",replacement:(K,Q)=>{const W=Q,Z=W.getAttribute("src")||"";if(!Z)return"";return`
7
- [${W.getAttribute("title")||"Embedded content"}](${Z})
8
- `}});const q=($??[]).map((K)=>K.trim()).filter(Boolean);if(q.length>0)V.addRule("cleanSelectors",{filter:(K)=>{const Q=K.matches;if(typeof Q!=="function")return!1;return q.some((W)=>{try{return Q.call(K,W)}catch{return!1}})},replacement:()=>""});if(J)J(V);return V}function w(J,$,V,q){let Q=D(V,q).turndown(J);$.forEach((W,Z)=>{const X=`CODEBLOCK-PLACEHOLDER-${Z}`,y=`
9
- \`\`\`${W.lang}
10
- ${W.code}
1
+ import*as S from"node:fs";import*as p from"node:path";import L from"turndown";import{gfm as U}from"turndown-plugin-gfm";import{httpDownload as _,sanitizeFilename as k}from"./index.js";import{formatBytes as A}from"./progress.js";const R=5,N={author:"作者",publishTime:"发布时间",sourceUrl:"原文链接"},x=["script","style","noscript","canvas","form","button","dialog","header","footer","nav","aside"];function B(e,c){const n=new L({headingStyle:"atx",codeBlockStyle:"fenced",bulletListMarker:"-"});n.use(U);n.remove(x);n.addRule("canonicalStrikethrough",{filter:(t)=>["DEL","S","STRIKE"].includes(t.nodeName),replacement:(t)=>`~~${t}~~`});n.addRule("stripSvg",{filter:(t)=>t.nodeName==="svg"||t.nodeName==="SVG",replacement:()=>""});n.addRule("linebreak",{filter:"br",replacement:()=>`
2
+ `});n.addRule("ignoreBase64Images",{filter:(t)=>{if(t.nodeName!=="IMG")return!1;return(t.getAttribute?.("src")??"").startsWith("data:")},replacement:()=>""});n.addRule("videoElement",{filter:(t)=>t.nodeName==="VIDEO",replacement:(t,r)=>{const o=r,i=o.getAttribute("src")||o.querySelector("source")?.getAttribute("src")||"";if(!i)return"";const s=o.getAttribute("poster")||"";return`
3
+ <video src="${i}" controls${s?` poster="${s}"`:""}></video>
4
+ `}});n.addRule("audioElement",{filter:(t)=>t.nodeName==="AUDIO",replacement:(t,r)=>{const o=r,i=o.getAttribute("src")||o.querySelector("source")?.getAttribute("src")||"";return i?`
5
+ <audio src="${i}" controls></audio>
6
+ `:""}});n.addRule("iframeToLink",{filter:(t)=>t.nodeName==="IFRAME",replacement:(t,r)=>{const o=r,i=o.getAttribute("src")||"";if(!i)return"";return`
7
+ [${o.getAttribute("title")||"Embedded content"}](${i})
8
+ `}});const l=(c??[]).map((t)=>t.trim()).filter(Boolean);if(l.length>0)n.addRule("cleanSelectors",{filter:(t)=>{const r=t.matches;if(typeof r!=="function")return!1;return l.some((o)=>{try{return r.call(t,o)}catch{return!1}})},replacement:()=>""});if(e)e(n);return n}function M(e,c,n,l){let r=B(n,l).turndown(e);c.forEach((o,i)=>{const s=`CODEBLOCK-PLACEHOLDER-${i}`,f=`
9
+ \`\`\`${o.lang}
10
+ ${o.code}
11
11
  \`\`\`
12
- `;Q=Q.replace(X,y)});Q=Q.replace(/\u00a0/g," ");Q=Q.replace(/^[ \t]*[-·][ \t]*$/gm,"");Q=Q.replace(/^[ \t]+$/gm,"");Q=Q.replace(/[ \t]+$/gm,"");Q=Q.replace(/\n{3,}/g,`
12
+ `;r=r.replace(s,f)});r=r.replace(/\u00a0/g," ");r=r.replace(/^[ \t]*[-·][ \t]*$/gm,"");r=r.replace(/^[ \t]+$/gm,"");r=r.replace(/[ \t]+$/gm,"");r=r.replace(/\n{3,}/g,`
13
13
 
14
- `);return Q}function U(J,$){return J.replace(/!\[([^\]]*)\]\(([^)]+)\)/g,(V,q,K)=>{const Q=$[K];return Q?`![${q}](${Q})`:V})}function h(J){const $=J.match(/\.(\w{3,4})(?:\?|$)/);return $?$[1]:"jpg"}async function p(J,$,V,q){const K={};if(J.length===0)return K;const Q=q||h,W=new Set,Z=J.filter((X)=>{if(W.has(X))return!1;W.add(X);return!0});for(let X=0;X<Z.length;X+=b){const y=Z.slice(X,X+b),j=await Promise.all(y.map(async(F,z)=>{const G=X+z+1;let O=F;if(O.startsWith("//"))O=`https:${O}`;const v=Q(O),Y=`img_${String(G).padStart(3,"0")}.${v}`,N=H.join($,Y);try{if((await C(O,N,{headers:V,timeout:15000})).success)return{remoteUrl:F,localPath:`images/${Y}`}}catch{}return null}));for(const F of j)if(F)K[F.remoteUrl]=F.localPath}return K}export async function downloadArticle(J,$){const{output:V,downloadImages:q=!0,imageHeaders:K,maxTitleLength:Q=80,configureTurndown:W,detectImageExt:Z,frontmatterLabels:X,cleanSelectors:y,stdout:j=!1}=$,F={...M,...X};if(!J.title)return[{title:"Error",author:"-",publish_time:"-",status:"failed — no title",size:"-",saved:"-"}];if(!J.contentHtml)return[{title:J.title,author:J.author||"-",publish_time:J.publishTime||"-",status:"failed — no content",size:"-",saved:"-"}];let z=w(J.contentHtml,J.codeBlocks||[],W,y);const G=E(J.title,Q);if(!j&&q&&J.imageUrls&&J.imageUrls.length>0){const B=H.join(V,G);P.mkdirSync(B,{recursive:!0});const R=H.join(B,"images");P.mkdirSync(R,{recursive:!0});const S=await p(J.imageUrls,R,K,Z);z=U(z,S)}const O=[`# ${J.title}`];if(J.author)O.push(`> ${F.author}: ${J.author}`);if(J.publishTime)O.push(`> ${F.publishTime}: ${J.publishTime}`);if(J.sourceUrl)O.push(`> ${F.sourceUrl}: ${J.sourceUrl}`);const Y=O.join(`
14
+ `);return r}function j(e,c){return e.replace(/!\[([^\]]*)\]\(([^)]+)\)/g,(n,l,t)=>{const r=c[t];return r?`![${l}](${r})`:n})}function C(e){const c=e.match(/\.(\w{3,4})(?:\?|$)/);return c?c[1]:"jpg"}async function P(e,c,n,l){const t={};if(e.length===0)return t;const r=l||C,o=new Set,i=e.filter((s)=>{if(o.has(s))return!1;o.add(s);return!0});for(let s=0;s<i.length;s+=R){const f=i.slice(s,s+R),g=await Promise.all(f.map(async(u,d)=>{const h=s+d+1;let a=u;if(a.startsWith("//"))a=`https:${a}`;const w=r(a),m=`img_${String(h).padStart(3,"0")}.${w}`,b=p.join(c,m);try{if((await _(a,b,{headers:n,timeout:15000})).success)return{remoteUrl:u,localPath:`images/${m}`}}catch{}return null}));for(const u of g)if(u)t[u.remoteUrl]=u.localPath}return t}export async function downloadArticle(e,c){const{output:n,downloadImages:l=!0,imageHeaders:t,maxTitleLength:r=80,configureTurndown:o,detectImageExt:i,frontmatterLabels:s,cleanSelectors:f,stdout:g=!1}=c,u={...N,...s};if(!e.title)return[{title:"Error",author:"-",publish_time:"-",status:"failed — no title",size:"-",saved:"-"}];if(!e.contentHtml)return[{title:e.title,author:e.author||"-",publish_time:e.publishTime||"-",status:"failed — no content",size:"-",saved:"-"}];let d=M(e.contentHtml,e.codeBlocks||[],o,f);const h=k(e.title,r);if(!g&&l&&e.imageUrls&&e.imageUrls.length>0){const v=p.join(n,h);S.mkdirSync(v,{recursive:!0});const y=p.join(v,"images");S.mkdirSync(y,{recursive:!0});const D=await P(e.imageUrls,y,t,i);d=j(d,D)}const a=[`# ${e.title}`];if(e.author)a.push(`> ${u.author}: ${e.author}`);if(e.publishTime)a.push(`> ${u.publishTime}: ${e.publishTime}`);if(e.sourceUrl)a.push(`> ${u.sourceUrl}: ${e.sourceUrl}`);const m=a.join(`
15
15
  `)+`
16
16
 
17
17
  ---
18
18
 
19
- `+z,N=Buffer.byteLength(Y,"utf-8");if(j){process.stdout.write(Y.endsWith(`
20
- `)?Y:Y+`
21
- `);return[{title:J.title,author:J.author||"-",publish_time:J.publishTime||"-",status:"success",size:I(N),saved:"-"}]}const _=H.join(V,G);P.mkdirSync(_,{recursive:!0});const L=`${G}.md`,A=H.join(_,L);P.writeFileSync(A,Y,"utf-8");return[{title:J.title,author:J.author||"-",publish_time:J.publishTime||"-",status:"success",size:I(N),saved:A}]}
19
+ `+d,b=Buffer.byteLength(m,"utf-8");if(g){process.stdout.write(m.endsWith(`
20
+ `)?m:m+`
21
+ `);return[{title:e.title,author:e.author||"-",publish_time:e.publishTime||"-",status:"success",size:A(b),saved:"-"}]}const E=p.join(n,h);S.mkdirSync(E,{recursive:!0});const I=`${h}.md`,T=p.join(E,I);S.writeFileSync(T,m,"utf-8");return[{title:e.title,author:e.author||"-",publish_time:e.publishTime||"-",status:"success",size:A(b),saved:T}]}