@jackwener/opencli 1.6.8 → 1.6.10

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 (572) hide show
  1. package/README.md +117 -59
  2. package/README.zh-CN.md +123 -79
  3. package/dist/clis/_shared/common.d.ts +3 -0
  4. package/dist/clis/_shared/common.js +22 -0
  5. package/dist/clis/bilibili/hot.d.ts +1 -0
  6. package/dist/clis/bilibili/hot.js +35 -0
  7. package/dist/clis/bluesky/feeds.d.ts +1 -0
  8. package/dist/clis/bluesky/feeds.js +27 -0
  9. package/dist/clis/bluesky/followers.d.ts +1 -0
  10. package/dist/clis/bluesky/followers.js +27 -0
  11. package/dist/clis/bluesky/following.d.ts +1 -0
  12. package/dist/clis/bluesky/following.js +27 -0
  13. package/dist/clis/bluesky/profile.d.ts +1 -0
  14. package/dist/clis/bluesky/profile.js +29 -0
  15. package/dist/clis/bluesky/search.d.ts +1 -0
  16. package/dist/clis/bluesky/search.js +28 -0
  17. package/dist/clis/bluesky/starter-packs.d.ts +1 -0
  18. package/dist/clis/bluesky/starter-packs.js +28 -0
  19. package/dist/clis/bluesky/thread.d.ts +1 -0
  20. package/dist/clis/bluesky/thread.js +30 -0
  21. package/dist/clis/bluesky/trending.d.ts +1 -0
  22. package/dist/clis/bluesky/trending.js +19 -0
  23. package/dist/clis/bluesky/user.d.ts +1 -0
  24. package/dist/clis/bluesky/user.js +33 -0
  25. package/dist/clis/cnki/search.d.ts +1 -0
  26. package/dist/clis/cnki/search.js +60 -0
  27. package/dist/clis/cnki/search.test.d.ts +1 -0
  28. package/dist/clis/cnki/search.test.js +18 -0
  29. package/dist/clis/devto/tag.d.ts +1 -0
  30. package/dist/clis/devto/tag.js +32 -0
  31. package/dist/clis/devto/top.d.ts +1 -0
  32. package/dist/clis/devto/top.js +26 -0
  33. package/dist/clis/devto/user.d.ts +1 -0
  34. package/dist/clis/devto/user.js +31 -0
  35. package/dist/clis/dictionary/examples.d.ts +1 -0
  36. package/dist/clis/dictionary/examples.js +27 -0
  37. package/dist/clis/dictionary/search.d.ts +1 -0
  38. package/dist/clis/dictionary/search.js +29 -0
  39. package/dist/clis/dictionary/synonyms.d.ts +1 -0
  40. package/dist/clis/dictionary/synonyms.js +27 -0
  41. package/dist/clis/douban/subject.d.ts +1 -0
  42. package/dist/clis/douban/subject.js +118 -0
  43. package/dist/clis/douban/top250.d.ts +1 -0
  44. package/dist/clis/douban/top250.js +67 -0
  45. package/dist/clis/facebook/add-friend.d.ts +1 -0
  46. package/dist/clis/facebook/add-friend.js +43 -0
  47. package/dist/clis/facebook/events.d.ts +1 -0
  48. package/dist/clis/facebook/events.js +40 -0
  49. package/dist/clis/facebook/feed.d.ts +1 -0
  50. package/dist/clis/facebook/feed.js +59 -0
  51. package/dist/clis/facebook/friends.d.ts +1 -0
  52. package/dist/clis/facebook/friends.js +38 -0
  53. package/dist/clis/facebook/groups.d.ts +1 -0
  54. package/dist/clis/facebook/groups.js +46 -0
  55. package/dist/clis/facebook/join-group.d.ts +1 -0
  56. package/dist/clis/facebook/join-group.js +44 -0
  57. package/dist/clis/facebook/memories.d.ts +1 -0
  58. package/dist/clis/facebook/memories.js +35 -0
  59. package/dist/clis/facebook/notifications.d.ts +1 -0
  60. package/dist/clis/facebook/notifications.js +36 -0
  61. package/dist/clis/facebook/profile.d.ts +1 -0
  62. package/dist/clis/facebook/profile.js +37 -0
  63. package/dist/clis/facebook/search.d.ts +1 -0
  64. package/dist/clis/facebook/search.js +38 -0
  65. package/dist/clis/facebook/search.test.d.ts +1 -1
  66. package/dist/clis/facebook/search.test.js +6 -9
  67. package/dist/clis/gitee/index.d.ts +3 -0
  68. package/dist/clis/gitee/index.js +3 -0
  69. package/dist/clis/gitee/search.d.ts +1 -0
  70. package/dist/clis/gitee/search.js +136 -0
  71. package/dist/clis/gitee/trending.d.ts +1 -0
  72. package/dist/clis/gitee/trending.js +567 -0
  73. package/dist/clis/gitee/user.d.ts +1 -0
  74. package/dist/clis/gitee/user.js +199 -0
  75. package/dist/clis/gitee/user.test.d.ts +1 -0
  76. package/dist/clis/gitee/user.test.js +63 -0
  77. package/dist/clis/hackernews/ask.d.ts +1 -0
  78. package/dist/clis/hackernews/ask.js +29 -0
  79. package/dist/clis/hackernews/best.d.ts +1 -0
  80. package/dist/clis/hackernews/best.js +29 -0
  81. package/dist/clis/hackernews/jobs.d.ts +1 -0
  82. package/dist/clis/hackernews/jobs.js +27 -0
  83. package/dist/clis/hackernews/new.d.ts +1 -0
  84. package/dist/clis/hackernews/new.js +29 -0
  85. package/dist/clis/hackernews/search.d.ts +1 -0
  86. package/dist/clis/hackernews/search.js +36 -0
  87. package/dist/clis/hackernews/show.d.ts +1 -0
  88. package/dist/clis/hackernews/show.js +29 -0
  89. package/dist/clis/hackernews/top.d.ts +1 -0
  90. package/dist/clis/hackernews/top.js +29 -0
  91. package/dist/clis/hackernews/user.d.ts +1 -0
  92. package/dist/clis/hackernews/user.js +22 -0
  93. package/dist/clis/hupu/hot.d.ts +1 -0
  94. package/dist/clis/hupu/hot.js +40 -0
  95. package/dist/clis/instagram/comment.d.ts +1 -0
  96. package/dist/clis/instagram/comment.js +47 -0
  97. package/dist/clis/instagram/explore.d.ts +1 -0
  98. package/dist/clis/instagram/explore.js +41 -0
  99. package/dist/clis/instagram/follow.d.ts +1 -0
  100. package/dist/clis/instagram/follow.js +43 -0
  101. package/dist/clis/instagram/followers.d.ts +1 -0
  102. package/dist/clis/instagram/followers.js +45 -0
  103. package/dist/clis/instagram/following.d.ts +1 -0
  104. package/dist/clis/instagram/following.js +45 -0
  105. package/dist/clis/instagram/like.d.ts +1 -0
  106. package/dist/clis/instagram/like.js +45 -0
  107. package/dist/clis/instagram/profile.d.ts +1 -0
  108. package/dist/clis/instagram/profile.js +39 -0
  109. package/dist/clis/instagram/save.d.ts +1 -0
  110. package/dist/clis/instagram/save.js +45 -0
  111. package/dist/clis/instagram/saved.d.ts +1 -0
  112. package/dist/clis/instagram/saved.js +38 -0
  113. package/dist/clis/instagram/search.d.ts +1 -0
  114. package/dist/clis/instagram/search.js +38 -0
  115. package/dist/clis/instagram/unfollow.d.ts +1 -0
  116. package/dist/clis/instagram/unfollow.js +40 -0
  117. package/dist/clis/instagram/unlike.d.ts +1 -0
  118. package/dist/clis/instagram/unlike.js +45 -0
  119. package/dist/clis/instagram/unsave.d.ts +1 -0
  120. package/dist/clis/instagram/unsave.js +45 -0
  121. package/dist/clis/instagram/user.d.ts +1 -0
  122. package/dist/clis/instagram/user.js +48 -0
  123. package/dist/clis/jd/add-cart.d.ts +1 -0
  124. package/dist/clis/jd/add-cart.js +71 -0
  125. package/dist/clis/jd/cart.d.ts +1 -0
  126. package/dist/clis/jd/cart.js +79 -0
  127. package/dist/clis/jd/commands.test.d.ts +5 -0
  128. package/dist/clis/jd/commands.test.js +64 -0
  129. package/dist/clis/jd/detail.d.ts +1 -0
  130. package/dist/clis/jd/detail.js +62 -0
  131. package/dist/clis/jd/reviews.d.ts +1 -0
  132. package/dist/clis/jd/reviews.js +54 -0
  133. package/dist/clis/jd/search.d.ts +1 -0
  134. package/dist/clis/jd/search.js +65 -0
  135. package/dist/clis/jianyu/search.d.ts +14 -0
  136. package/dist/clis/jianyu/search.js +135 -0
  137. package/dist/clis/jianyu/search.test.d.ts +1 -0
  138. package/dist/clis/jianyu/search.test.js +23 -0
  139. package/dist/clis/jike/post.d.ts +1 -0
  140. package/dist/clis/jike/post.js +61 -0
  141. package/dist/clis/jike/topic.d.ts +1 -0
  142. package/dist/clis/jike/topic.js +51 -0
  143. package/dist/clis/jike/user.d.ts +1 -0
  144. package/dist/clis/jike/user.js +50 -0
  145. package/dist/clis/jimeng/generate.d.ts +1 -0
  146. package/dist/clis/jimeng/generate.js +83 -0
  147. package/dist/clis/jimeng/history.d.ts +1 -0
  148. package/dist/clis/jimeng/history.js +47 -0
  149. package/dist/clis/jimeng/new.d.ts +1 -0
  150. package/dist/clis/jimeng/new.js +43 -0
  151. package/dist/clis/jimeng/workspaces.d.ts +1 -0
  152. package/dist/clis/jimeng/workspaces.js +41 -0
  153. package/dist/clis/linux-do/categories.d.ts +1 -0
  154. package/dist/clis/linux-do/categories.js +65 -0
  155. package/dist/clis/linux-do/search.d.ts +1 -0
  156. package/dist/clis/linux-do/search.js +41 -0
  157. package/dist/clis/linux-do/tags.d.ts +1 -0
  158. package/dist/clis/linux-do/tags.js +39 -0
  159. package/dist/clis/linux-do/topic-content.test.js +5 -5
  160. package/dist/clis/linux-do/topic.d.ts +1 -0
  161. package/dist/clis/linux-do/topic.js +56 -0
  162. package/dist/clis/linux-do/user-posts.d.ts +1 -0
  163. package/dist/clis/linux-do/user-posts.js +61 -0
  164. package/dist/clis/linux-do/user-topics.d.ts +1 -0
  165. package/dist/clis/linux-do/user-topics.js +48 -0
  166. package/dist/clis/lobsters/active.d.ts +1 -0
  167. package/dist/clis/lobsters/active.js +26 -0
  168. package/dist/clis/lobsters/hot.d.ts +1 -0
  169. package/dist/clis/lobsters/hot.js +26 -0
  170. package/dist/clis/lobsters/newest.d.ts +1 -0
  171. package/dist/clis/lobsters/newest.js +26 -0
  172. package/dist/clis/lobsters/tag.d.ts +1 -0
  173. package/dist/clis/lobsters/tag.js +32 -0
  174. package/dist/clis/pixiv/detail.d.ts +1 -0
  175. package/dist/clis/pixiv/detail.js +58 -0
  176. package/dist/clis/pixiv/ranking.d.ts +1 -0
  177. package/dist/clis/pixiv/ranking.js +59 -0
  178. package/dist/clis/pixiv/user.d.ts +1 -0
  179. package/dist/clis/pixiv/user.js +52 -0
  180. package/dist/clis/quark/ls.d.ts +1 -0
  181. package/dist/clis/quark/ls.js +63 -0
  182. package/dist/clis/quark/mkdir.d.ts +1 -0
  183. package/dist/clis/quark/mkdir.js +36 -0
  184. package/dist/clis/quark/mv.d.ts +1 -0
  185. package/dist/clis/quark/mv.js +53 -0
  186. package/dist/clis/quark/rename.d.ts +1 -0
  187. package/dist/clis/quark/rename.js +26 -0
  188. package/dist/clis/quark/rm.d.ts +1 -0
  189. package/dist/clis/quark/rm.js +24 -0
  190. package/dist/clis/quark/save.d.ts +1 -0
  191. package/dist/clis/quark/save.js +80 -0
  192. package/dist/clis/quark/share-tree.d.ts +1 -0
  193. package/dist/clis/quark/share-tree.js +45 -0
  194. package/dist/clis/quark/utils.d.ts +50 -0
  195. package/dist/clis/quark/utils.js +146 -0
  196. package/dist/clis/quark/utils.test.d.ts +1 -0
  197. package/dist/clis/quark/utils.test.js +58 -0
  198. package/dist/clis/reddit/frontpage.d.ts +1 -0
  199. package/dist/clis/reddit/frontpage.js +31 -0
  200. package/dist/clis/reddit/hot.d.ts +1 -0
  201. package/dist/clis/reddit/hot.js +45 -0
  202. package/dist/clis/reddit/popular.d.ts +1 -0
  203. package/dist/clis/reddit/popular.js +41 -0
  204. package/dist/clis/reddit/search.d.ts +1 -0
  205. package/dist/clis/reddit/search.js +65 -0
  206. package/dist/clis/reddit/subreddit.d.ts +1 -0
  207. package/dist/clis/reddit/subreddit.js +52 -0
  208. package/dist/clis/reddit/user-comments.d.ts +1 -0
  209. package/dist/clis/reddit/user-comments.js +44 -0
  210. package/dist/clis/reddit/user-posts.d.ts +1 -0
  211. package/dist/clis/reddit/user-posts.js +42 -0
  212. package/dist/clis/reddit/user.d.ts +1 -0
  213. package/dist/clis/reddit/user.js +37 -0
  214. package/dist/clis/stackoverflow/bounties.d.ts +1 -0
  215. package/dist/clis/stackoverflow/bounties.js +27 -0
  216. package/dist/clis/stackoverflow/hot.d.ts +1 -0
  217. package/dist/clis/stackoverflow/hot.js +24 -0
  218. package/dist/clis/stackoverflow/search.d.ts +1 -0
  219. package/dist/clis/stackoverflow/search.js +27 -0
  220. package/dist/clis/stackoverflow/unanswered.d.ts +1 -0
  221. package/dist/clis/stackoverflow/unanswered.js +26 -0
  222. package/dist/clis/steam/top-sellers.d.ts +1 -0
  223. package/dist/clis/steam/top-sellers.js +25 -0
  224. package/dist/clis/taobao/add-cart.d.ts +1 -0
  225. package/dist/clis/taobao/add-cart.js +149 -0
  226. package/dist/clis/taobao/cart.d.ts +1 -0
  227. package/dist/clis/taobao/cart.js +95 -0
  228. package/dist/clis/taobao/commands.test.d.ts +5 -0
  229. package/dist/clis/taobao/commands.test.js +64 -0
  230. package/dist/clis/taobao/detail.d.ts +1 -0
  231. package/dist/clis/taobao/detail.js +70 -0
  232. package/dist/clis/taobao/reviews.d.ts +1 -0
  233. package/dist/clis/taobao/reviews.js +76 -0
  234. package/dist/clis/taobao/search.d.ts +1 -0
  235. package/dist/clis/taobao/search.js +96 -0
  236. package/dist/clis/tiktok/comment.d.ts +1 -0
  237. package/dist/clis/tiktok/comment.js +57 -0
  238. package/dist/clis/tiktok/explore.d.ts +1 -0
  239. package/dist/clis/tiktok/explore.js +35 -0
  240. package/dist/clis/tiktok/follow.d.ts +1 -0
  241. package/dist/clis/tiktok/follow.js +39 -0
  242. package/dist/clis/tiktok/following.d.ts +1 -0
  243. package/dist/clis/tiktok/following.js +42 -0
  244. package/dist/clis/tiktok/friends.d.ts +1 -0
  245. package/dist/clis/tiktok/friends.js +43 -0
  246. package/dist/clis/tiktok/like.d.ts +1 -0
  247. package/dist/clis/tiktok/like.js +33 -0
  248. package/dist/clis/tiktok/live.d.ts +1 -0
  249. package/dist/clis/tiktok/live.js +47 -0
  250. package/dist/clis/tiktok/notifications.d.ts +1 -0
  251. package/dist/clis/tiktok/notifications.js +49 -0
  252. package/dist/clis/tiktok/profile.d.ts +1 -0
  253. package/dist/clis/tiktok/profile.js +54 -0
  254. package/dist/clis/tiktok/save.d.ts +1 -0
  255. package/dist/clis/tiktok/save.js +29 -0
  256. package/dist/clis/tiktok/search.d.ts +1 -0
  257. package/dist/clis/tiktok/search.js +39 -0
  258. package/dist/clis/tiktok/unfollow.d.ts +1 -0
  259. package/dist/clis/tiktok/unfollow.js +44 -0
  260. package/dist/clis/tiktok/unlike.d.ts +1 -0
  261. package/dist/clis/tiktok/unlike.js +33 -0
  262. package/dist/clis/tiktok/unsave.d.ts +1 -0
  263. package/dist/clis/tiktok/unsave.js +31 -0
  264. package/dist/clis/tiktok/user.d.ts +1 -0
  265. package/dist/clis/tiktok/user.js +41 -0
  266. package/dist/clis/twitter/reply.js +3 -8
  267. package/dist/clis/twitter/reply.test.js +5 -5
  268. package/dist/clis/v2ex/hot.d.ts +1 -0
  269. package/dist/clis/v2ex/hot.js +25 -0
  270. package/dist/clis/v2ex/latest.d.ts +1 -0
  271. package/dist/clis/v2ex/latest.js +25 -0
  272. package/dist/clis/v2ex/member.d.ts +1 -0
  273. package/dist/clis/v2ex/member.js +27 -0
  274. package/dist/clis/v2ex/node.d.ts +1 -0
  275. package/dist/clis/v2ex/node.js +38 -0
  276. package/dist/clis/v2ex/nodes.d.ts +1 -0
  277. package/dist/clis/v2ex/nodes.js +25 -0
  278. package/dist/clis/v2ex/replies.d.ts +1 -0
  279. package/dist/clis/v2ex/replies.js +26 -0
  280. package/dist/clis/v2ex/topic.d.ts +1 -0
  281. package/dist/clis/v2ex/topic.js +30 -0
  282. package/dist/clis/v2ex/user.d.ts +1 -0
  283. package/dist/clis/v2ex/user.js +33 -0
  284. package/dist/clis/xiaoe/catalog.d.ts +1 -0
  285. package/dist/clis/xiaoe/catalog.js +125 -0
  286. package/dist/clis/xiaoe/content.d.ts +1 -0
  287. package/dist/clis/xiaoe/content.js +39 -0
  288. package/dist/clis/xiaoe/courses.d.ts +1 -0
  289. package/dist/clis/xiaoe/courses.js +69 -0
  290. package/dist/clis/xiaoe/detail.d.ts +1 -0
  291. package/dist/clis/xiaoe/detail.js +35 -0
  292. package/dist/clis/xiaoe/play-url.d.ts +1 -0
  293. package/dist/clis/xiaoe/play-url.js +120 -0
  294. package/dist/clis/xiaohongshu/feed.d.ts +1 -0
  295. package/dist/clis/xiaohongshu/feed.js +32 -0
  296. package/dist/clis/xiaohongshu/note.js +8 -3
  297. package/dist/clis/xiaohongshu/note.test.js +11 -0
  298. package/dist/clis/xiaohongshu/notifications.d.ts +1 -0
  299. package/dist/clis/xiaohongshu/notifications.js +38 -0
  300. package/dist/clis/xueqiu/earnings-date.d.ts +1 -0
  301. package/dist/clis/xueqiu/earnings-date.js +61 -0
  302. package/dist/clis/xueqiu/feed.d.ts +1 -0
  303. package/dist/clis/xueqiu/feed.js +48 -0
  304. package/dist/clis/xueqiu/groups.d.ts +1 -0
  305. package/dist/clis/xueqiu/groups.js +25 -0
  306. package/dist/clis/xueqiu/hot-stock.d.ts +1 -0
  307. package/dist/clis/xueqiu/hot-stock.js +44 -0
  308. package/dist/clis/xueqiu/hot.d.ts +1 -0
  309. package/dist/clis/xueqiu/hot.js +44 -0
  310. package/dist/clis/xueqiu/kline.d.ts +1 -0
  311. package/dist/clis/xueqiu/kline.js +64 -0
  312. package/dist/clis/xueqiu/search.d.ts +1 -0
  313. package/dist/clis/xueqiu/search.js +49 -0
  314. package/dist/clis/xueqiu/stock.d.ts +1 -0
  315. package/dist/clis/xueqiu/stock.js +72 -0
  316. package/dist/clis/xueqiu/watchlist.d.ts +1 -0
  317. package/dist/clis/xueqiu/watchlist.js +45 -0
  318. package/dist/clis/zhihu/answer.d.ts +1 -0
  319. package/dist/clis/zhihu/answer.js +194 -0
  320. package/dist/clis/zhihu/answer.test.d.ts +1 -0
  321. package/dist/clis/zhihu/answer.test.js +81 -0
  322. package/dist/clis/zhihu/comment.d.ts +1 -0
  323. package/dist/clis/zhihu/comment.js +335 -0
  324. package/dist/clis/zhihu/comment.test.d.ts +1 -0
  325. package/dist/clis/zhihu/comment.test.js +54 -0
  326. package/dist/clis/zhihu/favorite.d.ts +1 -0
  327. package/dist/clis/zhihu/favorite.js +224 -0
  328. package/dist/clis/zhihu/favorite.test.d.ts +1 -0
  329. package/dist/clis/zhihu/favorite.test.js +196 -0
  330. package/dist/clis/zhihu/follow.d.ts +1 -0
  331. package/dist/clis/zhihu/follow.js +80 -0
  332. package/dist/clis/zhihu/follow.test.d.ts +1 -0
  333. package/dist/clis/zhihu/follow.test.js +45 -0
  334. package/dist/clis/zhihu/hot.d.ts +1 -0
  335. package/dist/clis/zhihu/hot.js +43 -0
  336. package/dist/clis/zhihu/like.d.ts +1 -0
  337. package/dist/clis/zhihu/like.js +91 -0
  338. package/dist/clis/zhihu/like.test.d.ts +1 -0
  339. package/dist/clis/zhihu/like.test.js +64 -0
  340. package/dist/clis/zhihu/search.d.ts +1 -0
  341. package/dist/clis/zhihu/search.js +52 -0
  342. package/dist/clis/zhihu/target.d.ts +24 -0
  343. package/dist/clis/zhihu/target.js +91 -0
  344. package/dist/clis/zhihu/target.test.d.ts +1 -0
  345. package/dist/clis/zhihu/target.test.js +77 -0
  346. package/dist/clis/zhihu/write-shared.d.ts +32 -0
  347. package/dist/clis/zhihu/write-shared.js +221 -0
  348. package/dist/clis/zhihu/write-shared.test.d.ts +1 -0
  349. package/dist/clis/zhihu/write-shared.test.js +175 -0
  350. package/dist/src/browser/bridge.d.ts +2 -0
  351. package/dist/src/browser/bridge.js +30 -24
  352. package/dist/src/browser/daemon-client.d.ts +30 -10
  353. package/dist/src/browser/daemon-client.js +42 -27
  354. package/dist/src/browser/daemon-client.test.js +32 -25
  355. package/dist/src/browser/dom-helpers.test.js +3 -2
  356. package/dist/src/browser/errors.d.ts +26 -1
  357. package/dist/src/browser/errors.js +40 -7
  358. package/dist/src/browser/errors.test.d.ts +1 -0
  359. package/dist/src/browser/errors.test.js +51 -0
  360. package/dist/src/browser/index.d.ts +2 -1
  361. package/dist/src/browser/index.js +1 -1
  362. package/dist/src/browser/page.d.ts +9 -8
  363. package/dist/src/browser/page.js +33 -31
  364. package/dist/src/browser.test.js +27 -8
  365. package/dist/src/build-manifest.d.ts +5 -11
  366. package/dist/src/build-manifest.js +6 -75
  367. package/dist/src/build-manifest.test.js +1 -39
  368. package/dist/src/cascade.js +3 -2
  369. package/dist/src/cli.d.ts +3 -3
  370. package/dist/src/cli.js +73 -65
  371. package/dist/src/cli.test.js +20 -15
  372. package/dist/src/clis/binance/asks.d.ts +1 -0
  373. package/dist/src/clis/binance/asks.js +20 -0
  374. package/dist/src/clis/binance/commands.test.d.ts +3 -0
  375. package/dist/src/clis/binance/commands.test.js +58 -0
  376. package/dist/src/clis/binance/depth.d.ts +1 -0
  377. package/dist/src/clis/binance/depth.js +20 -0
  378. package/dist/src/clis/binance/gainers.d.ts +1 -0
  379. package/dist/src/clis/binance/gainers.js +21 -0
  380. package/dist/src/clis/binance/klines.d.ts +1 -0
  381. package/dist/src/clis/binance/klines.js +20 -0
  382. package/dist/src/clis/binance/losers.d.ts +1 -0
  383. package/dist/src/clis/binance/losers.js +21 -0
  384. package/dist/src/clis/binance/pairs.d.ts +1 -0
  385. package/dist/src/clis/binance/pairs.js +20 -0
  386. package/dist/src/clis/binance/price.d.ts +1 -0
  387. package/dist/src/clis/binance/price.js +17 -0
  388. package/dist/src/clis/binance/prices.d.ts +1 -0
  389. package/dist/src/clis/binance/prices.js +18 -0
  390. package/dist/src/clis/binance/ticker.d.ts +1 -0
  391. package/dist/src/clis/binance/ticker.js +20 -0
  392. package/dist/src/clis/binance/top.d.ts +1 -0
  393. package/dist/src/clis/binance/top.js +20 -0
  394. package/dist/src/clis/binance/trades.d.ts +1 -0
  395. package/dist/src/clis/binance/trades.js +19 -0
  396. package/dist/src/commanderAdapter.js +19 -6
  397. package/dist/src/completion-fast.d.ts +25 -0
  398. package/dist/src/completion-fast.js +140 -0
  399. package/dist/src/completion.d.ts +1 -0
  400. package/dist/src/completion.js +1 -0
  401. package/dist/src/diagnostic.d.ts +1 -0
  402. package/dist/src/diagnostic.js +64 -2
  403. package/dist/src/diagnostic.test.js +93 -3
  404. package/dist/src/discovery.d.ts +3 -3
  405. package/dist/src/discovery.js +34 -97
  406. package/dist/src/doctor.d.ts +2 -0
  407. package/dist/src/doctor.js +59 -31
  408. package/dist/src/doctor.test.js +89 -16
  409. package/dist/src/download/index.d.ts +1 -1
  410. package/dist/src/engine.test.js +4 -19
  411. package/dist/src/execution.js +1 -13
  412. package/dist/src/explore.js +1 -1
  413. package/dist/src/generate-verified.d.ts +105 -0
  414. package/dist/src/generate-verified.js +696 -0
  415. package/dist/src/generate-verified.test.d.ts +1 -0
  416. package/dist/src/generate-verified.test.js +925 -0
  417. package/dist/src/generate.d.ts +11 -6
  418. package/dist/src/generate.js +4 -7
  419. package/dist/src/main.js +65 -12
  420. package/dist/src/pipeline/steps/download.d.ts +1 -17
  421. package/dist/src/pipeline/steps/download.js +20 -31
  422. package/dist/src/pipeline/steps/intercept.d.ts +1 -1
  423. package/dist/src/pipeline/steps/intercept.js +1 -1
  424. package/dist/src/pipeline/steps/tap.d.ts +1 -1
  425. package/dist/src/pipeline/steps/tap.js +1 -1
  426. package/dist/src/plugin-scaffold.d.ts +2 -2
  427. package/dist/src/plugin-scaffold.js +24 -21
  428. package/dist/src/plugin-scaffold.test.js +1 -1
  429. package/dist/src/plugin.d.ts +3 -2
  430. package/dist/src/plugin.js +29 -14
  431. package/dist/src/plugin.test.js +47 -32
  432. package/dist/src/record.js +26 -25
  433. package/dist/src/runtime-detect.js +3 -7
  434. package/dist/src/scripts/framework.d.ts +3 -0
  435. package/dist/src/scripts/framework.js +8 -4
  436. package/dist/src/scripts/store.d.ts +5 -1
  437. package/dist/src/scripts/store.js +5 -1
  438. package/dist/src/skill-generate.d.ts +30 -0
  439. package/dist/src/skill-generate.js +75 -0
  440. package/dist/src/skill-generate.test.d.ts +1 -0
  441. package/dist/src/skill-generate.test.js +173 -0
  442. package/dist/src/synthesize.d.ts +1 -1
  443. package/dist/src/synthesize.js +7 -8
  444. package/dist/src/types.d.ts +3 -1
  445. package/package.json +5 -5
  446. package/dist/clis/bilibili/hot.yaml +0 -38
  447. package/dist/clis/bluesky/feeds.yaml +0 -29
  448. package/dist/clis/bluesky/followers.yaml +0 -33
  449. package/dist/clis/bluesky/following.yaml +0 -33
  450. package/dist/clis/bluesky/profile.yaml +0 -27
  451. package/dist/clis/bluesky/search.yaml +0 -34
  452. package/dist/clis/bluesky/starter-packs.yaml +0 -34
  453. package/dist/clis/bluesky/thread.yaml +0 -32
  454. package/dist/clis/bluesky/trending.yaml +0 -27
  455. package/dist/clis/bluesky/user.yaml +0 -34
  456. package/dist/clis/devto/tag.yaml +0 -34
  457. package/dist/clis/devto/top.yaml +0 -29
  458. package/dist/clis/devto/user.yaml +0 -33
  459. package/dist/clis/dictionary/examples.yaml +0 -25
  460. package/dist/clis/dictionary/search.yaml +0 -27
  461. package/dist/clis/dictionary/synonyms.yaml +0 -25
  462. package/dist/clis/douban/subject.yaml +0 -107
  463. package/dist/clis/douban/top250.yaml +0 -70
  464. package/dist/clis/facebook/add-friend.yaml +0 -43
  465. package/dist/clis/facebook/events.yaml +0 -44
  466. package/dist/clis/facebook/feed.yaml +0 -63
  467. package/dist/clis/facebook/friends.yaml +0 -42
  468. package/dist/clis/facebook/groups.yaml +0 -50
  469. package/dist/clis/facebook/join-group.yaml +0 -44
  470. package/dist/clis/facebook/memories.yaml +0 -39
  471. package/dist/clis/facebook/notifications.yaml +0 -40
  472. package/dist/clis/facebook/profile.yaml +0 -37
  473. package/dist/clis/facebook/search.yaml +0 -47
  474. package/dist/clis/hackernews/ask.yaml +0 -38
  475. package/dist/clis/hackernews/best.yaml +0 -38
  476. package/dist/clis/hackernews/jobs.yaml +0 -36
  477. package/dist/clis/hackernews/new.yaml +0 -38
  478. package/dist/clis/hackernews/search.yaml +0 -44
  479. package/dist/clis/hackernews/show.yaml +0 -38
  480. package/dist/clis/hackernews/top.yaml +0 -38
  481. package/dist/clis/hackernews/user.yaml +0 -25
  482. package/dist/clis/hupu/hot.yaml +0 -43
  483. package/dist/clis/instagram/comment.yaml +0 -52
  484. package/dist/clis/instagram/explore.yaml +0 -43
  485. package/dist/clis/instagram/follow.yaml +0 -41
  486. package/dist/clis/instagram/followers.yaml +0 -51
  487. package/dist/clis/instagram/following.yaml +0 -51
  488. package/dist/clis/instagram/like.yaml +0 -46
  489. package/dist/clis/instagram/profile.yaml +0 -42
  490. package/dist/clis/instagram/save.yaml +0 -46
  491. package/dist/clis/instagram/saved.yaml +0 -40
  492. package/dist/clis/instagram/search.yaml +0 -44
  493. package/dist/clis/instagram/unfollow.yaml +0 -38
  494. package/dist/clis/instagram/unlike.yaml +0 -46
  495. package/dist/clis/instagram/unsave.yaml +0 -46
  496. package/dist/clis/instagram/user.yaml +0 -54
  497. package/dist/clis/jike/post.yaml +0 -59
  498. package/dist/clis/jike/topic.yaml +0 -53
  499. package/dist/clis/jike/user.yaml +0 -52
  500. package/dist/clis/jimeng/generate.yaml +0 -85
  501. package/dist/clis/jimeng/history.yaml +0 -46
  502. package/dist/clis/linux-do/categories.yaml +0 -70
  503. package/dist/clis/linux-do/search.yaml +0 -48
  504. package/dist/clis/linux-do/tags.yaml +0 -41
  505. package/dist/clis/linux-do/topic.yaml +0 -62
  506. package/dist/clis/linux-do/user-posts.yaml +0 -67
  507. package/dist/clis/linux-do/user-topics.yaml +0 -54
  508. package/dist/clis/lobsters/active.yaml +0 -29
  509. package/dist/clis/lobsters/hot.yaml +0 -29
  510. package/dist/clis/lobsters/newest.yaml +0 -29
  511. package/dist/clis/lobsters/tag.yaml +0 -34
  512. package/dist/clis/pixiv/detail.yaml +0 -49
  513. package/dist/clis/pixiv/ranking.yaml +0 -53
  514. package/dist/clis/pixiv/user.yaml +0 -46
  515. package/dist/clis/reddit/frontpage.yaml +0 -30
  516. package/dist/clis/reddit/hot.yaml +0 -47
  517. package/dist/clis/reddit/popular.yaml +0 -40
  518. package/dist/clis/reddit/search.yaml +0 -61
  519. package/dist/clis/reddit/subreddit.yaml +0 -50
  520. package/dist/clis/reddit/user-comments.yaml +0 -46
  521. package/dist/clis/reddit/user-posts.yaml +0 -44
  522. package/dist/clis/reddit/user.yaml +0 -40
  523. package/dist/clis/stackoverflow/bounties.yaml +0 -29
  524. package/dist/clis/stackoverflow/hot.yaml +0 -28
  525. package/dist/clis/stackoverflow/search.yaml +0 -33
  526. package/dist/clis/stackoverflow/unanswered.yaml +0 -28
  527. package/dist/clis/steam/top-sellers.yaml +0 -29
  528. package/dist/clis/tiktok/comment.yaml +0 -66
  529. package/dist/clis/tiktok/explore.yaml +0 -39
  530. package/dist/clis/tiktok/follow.yaml +0 -39
  531. package/dist/clis/tiktok/following.yaml +0 -46
  532. package/dist/clis/tiktok/friends.yaml +0 -47
  533. package/dist/clis/tiktok/like.yaml +0 -38
  534. package/dist/clis/tiktok/live.yaml +0 -51
  535. package/dist/clis/tiktok/notifications.yaml +0 -52
  536. package/dist/clis/tiktok/profile.yaml +0 -45
  537. package/dist/clis/tiktok/save.yaml +0 -34
  538. package/dist/clis/tiktok/search.yaml +0 -47
  539. package/dist/clis/tiktok/unfollow.yaml +0 -44
  540. package/dist/clis/tiktok/unlike.yaml +0 -38
  541. package/dist/clis/tiktok/unsave.yaml +0 -36
  542. package/dist/clis/tiktok/user.yaml +0 -44
  543. package/dist/clis/v2ex/hot.yaml +0 -28
  544. package/dist/clis/v2ex/latest.yaml +0 -28
  545. package/dist/clis/v2ex/member.yaml +0 -29
  546. package/dist/clis/v2ex/node.yaml +0 -34
  547. package/dist/clis/v2ex/nodes.yaml +0 -31
  548. package/dist/clis/v2ex/replies.yaml +0 -32
  549. package/dist/clis/v2ex/topic.yaml +0 -33
  550. package/dist/clis/v2ex/user.yaml +0 -34
  551. package/dist/clis/xiaoe/catalog.yaml +0 -129
  552. package/dist/clis/xiaoe/content.yaml +0 -43
  553. package/dist/clis/xiaoe/courses.yaml +0 -73
  554. package/dist/clis/xiaoe/detail.yaml +0 -39
  555. package/dist/clis/xiaoe/play-url.yaml +0 -124
  556. package/dist/clis/xiaohongshu/feed.yaml +0 -31
  557. package/dist/clis/xiaohongshu/notifications.yaml +0 -37
  558. package/dist/clis/xueqiu/earnings-date.yaml +0 -69
  559. package/dist/clis/xueqiu/feed.yaml +0 -53
  560. package/dist/clis/xueqiu/groups.yaml +0 -23
  561. package/dist/clis/xueqiu/hot-stock.yaml +0 -49
  562. package/dist/clis/xueqiu/hot.yaml +0 -46
  563. package/dist/clis/xueqiu/kline.yaml +0 -65
  564. package/dist/clis/xueqiu/search.yaml +0 -55
  565. package/dist/clis/xueqiu/stock.yaml +0 -69
  566. package/dist/clis/xueqiu/watchlist.yaml +0 -46
  567. package/dist/clis/zhihu/hot.yaml +0 -46
  568. package/dist/clis/zhihu/search.yaml +0 -59
  569. package/dist/src/browser/discover.d.ts +0 -15
  570. package/dist/src/browser/discover.js +0 -19
  571. package/dist/src/yaml-schema.d.ts +0 -29
  572. package/dist/src/yaml-schema.js +0 -22
@@ -1,10 +1,10 @@
1
1
  /**
2
- * CLI discovery: finds YAML/TS CLI definitions and registers them.
2
+ * CLI discovery: finds TS CLI definitions and registers them.
3
3
  *
4
4
  * Supports two modes:
5
5
  * 1. FAST PATH (manifest): If a pre-compiled cli-manifest.json exists,
6
- * registers all YAML commands instantly without runtime YAML parsing.
7
- * TS modules are loaded lazily only when their command is executed.
6
+ * registers commands instantly. TS modules are loaded lazily only
7
+ * when their command is executed.
8
8
  * 2. FALLBACK (filesystem scan): Traditional runtime discovery for development.
9
9
  */
10
10
  /** User runtime directory: ~/.opencli */
@@ -1,17 +1,16 @@
1
1
  /**
2
- * CLI discovery: finds YAML/TS CLI definitions and registers them.
2
+ * CLI discovery: finds TS CLI definitions and registers them.
3
3
  *
4
4
  * Supports two modes:
5
5
  * 1. FAST PATH (manifest): If a pre-compiled cli-manifest.json exists,
6
- * registers all YAML commands instantly without runtime YAML parsing.
7
- * TS modules are loaded lazily only when their command is executed.
6
+ * registers commands instantly. TS modules are loaded lazily only
7
+ * when their command is executed.
8
8
  * 2. FALLBACK (filesystem scan): Traditional runtime discovery for development.
9
9
  */
10
10
  import * as fs from 'node:fs';
11
11
  import * as os from 'node:os';
12
12
  import * as path from 'node:path';
13
13
  import { fileURLToPath, pathToFileURL } from 'node:url';
14
- import yaml from 'js-yaml';
15
14
  import { Strategy, registerCommand } from './registry.js';
16
15
  import { getErrorMessage } from './errors.js';
17
16
  import { log } from './logger.js';
@@ -24,14 +23,12 @@ export const USER_CLIS_DIR = path.join(USER_OPENCLI_DIR, 'clis');
24
23
  export const PLUGINS_DIR = path.join(USER_OPENCLI_DIR, 'plugins');
25
24
  /** Matches files that register commands via cli() or lifecycle hooks */
26
25
  const PLUGIN_MODULE_PATTERN = /\b(?:cli|onStartup|onBeforeExecute|onAfterExecute)\s*\(/;
27
- import { parseYamlArgs } from './yaml-schema.js';
28
26
  function parseStrategy(rawStrategy, fallback = Strategy.COOKIE) {
29
27
  if (!rawStrategy)
30
28
  return fallback;
31
29
  const key = rawStrategy.toUpperCase();
32
30
  return Strategy[key] ?? fallback;
33
31
  }
34
- import { isRecord } from './utils.js';
35
32
  const PACKAGE_ROOT = findPackageRoot(fileURLToPath(import.meta.url));
36
33
  /**
37
34
  * Ensure ~/.opencli/node_modules/@jackwener/opencli symlink exists so that
@@ -140,7 +137,6 @@ export async function discoverClis(...dirs) {
140
137
  }
141
138
  /**
142
139
  * Fast-path: register commands from pre-compiled manifest.
143
- * YAML pipelines are inlined — zero YAML parsing at runtime.
144
140
  * TS modules are deferred — loaded lazily on first execution.
145
141
  */
146
142
  async function loadFromManifest(manifestPath, clisDir) {
@@ -148,53 +144,30 @@ async function loadFromManifest(manifestPath, clisDir) {
148
144
  const raw = await fs.promises.readFile(manifestPath, 'utf-8');
149
145
  const manifest = JSON.parse(raw);
150
146
  for (const entry of manifest) {
151
- if (entry.type === 'yaml') {
152
- // YAML pipelines fully inlined in manifest — register directly
153
- const strategy = parseStrategy(entry.strategy);
154
- const cmd = {
155
- site: entry.site,
156
- name: entry.name,
157
- aliases: entry.aliases,
158
- description: entry.description ?? '',
159
- domain: entry.domain,
160
- strategy,
161
- browser: entry.browser,
162
- args: entry.args ?? [],
163
- columns: entry.columns,
164
- pipeline: entry.pipeline,
165
- timeoutSeconds: entry.timeout,
166
- source: entry.sourceFile ? path.resolve(clisDir, entry.sourceFile) : `manifest:${entry.site}/${entry.name}`,
167
- deprecated: entry.deprecated,
168
- replacedBy: entry.replacedBy,
169
- navigateBefore: entry.navigateBefore,
170
- };
171
- registerCommand(cmd);
172
- }
173
- else if (entry.type === 'ts' && entry.modulePath) {
174
- // TS adapters: register a lightweight stub.
175
- // The actual module is loaded lazily on first executeCommand().
176
- const strategy = parseStrategy(entry.strategy ?? 'cookie');
177
- const modulePath = path.resolve(clisDir, entry.modulePath);
178
- const cmd = {
179
- site: entry.site,
180
- name: entry.name,
181
- aliases: entry.aliases,
182
- description: entry.description ?? '',
183
- domain: entry.domain,
184
- strategy,
185
- browser: entry.browser ?? true,
186
- args: entry.args ?? [],
187
- columns: entry.columns,
188
- timeoutSeconds: entry.timeout,
189
- source: entry.sourceFile ? path.resolve(clisDir, entry.sourceFile) : modulePath,
190
- deprecated: entry.deprecated,
191
- replacedBy: entry.replacedBy,
192
- navigateBefore: entry.navigateBefore,
193
- _lazy: true,
194
- _modulePath: modulePath,
195
- };
196
- registerCommand(cmd);
197
- }
147
+ if (!entry.modulePath)
148
+ continue;
149
+ const strategy = parseStrategy(entry.strategy ?? 'cookie');
150
+ const modulePath = path.resolve(clisDir, entry.modulePath);
151
+ const cmd = {
152
+ site: entry.site,
153
+ name: entry.name,
154
+ aliases: entry.aliases,
155
+ description: entry.description ?? '',
156
+ domain: entry.domain,
157
+ strategy,
158
+ browser: entry.browser ?? true,
159
+ args: entry.args ?? [],
160
+ columns: entry.columns,
161
+ pipeline: entry.pipeline,
162
+ timeoutSeconds: entry.timeout,
163
+ source: entry.sourceFile ? path.resolve(clisDir, entry.sourceFile) : modulePath,
164
+ deprecated: entry.deprecated,
165
+ replacedBy: entry.replacedBy,
166
+ navigateBefore: entry.navigateBefore,
167
+ _lazy: true,
168
+ _modulePath: modulePath,
169
+ };
170
+ registerCommand(cmd);
198
171
  }
199
172
  return true;
200
173
  }
@@ -223,9 +196,10 @@ async function discoverClisFromFs(dir) {
223
196
  await Promise.all(files.map(async (file) => {
224
197
  const filePath = path.join(siteDir, file);
225
198
  if (file.endsWith('.yaml') || file.endsWith('.yml')) {
226
- await registerYamlCli(filePath, site);
199
+ log.warn(`Ignoring YAML adapter ${filePath} — YAML format is no longer supported. Convert to TypeScript using cli() from '@jackwener/opencli/registry'.`);
200
+ return;
227
201
  }
228
- else if ((file.endsWith('.js') && !file.endsWith('.d.js')) ||
202
+ if ((file.endsWith('.js') && !file.endsWith('.d.js')) ||
229
203
  (file.endsWith('.ts') && !file.endsWith('.d.ts') && !file.endsWith('.test.ts'))) {
230
204
  if (!(await isCliModule(filePath)))
231
205
  return;
@@ -237,44 +211,6 @@ async function discoverClisFromFs(dir) {
237
211
  });
238
212
  await Promise.all(sitePromises);
239
213
  }
240
- async function registerYamlCli(filePath, defaultSite) {
241
- try {
242
- const raw = await fs.promises.readFile(filePath, 'utf-8');
243
- const def = yaml.load(raw);
244
- if (!isRecord(def))
245
- return;
246
- const cliDef = def;
247
- const site = cliDef.site ?? defaultSite;
248
- const name = cliDef.name ?? path.basename(filePath, path.extname(filePath));
249
- const strategyStr = cliDef.strategy ?? (cliDef.browser === false ? 'public' : 'cookie');
250
- const strategy = parseStrategy(strategyStr);
251
- const browser = cliDef.browser ?? (strategy !== Strategy.PUBLIC);
252
- const args = parseYamlArgs(cliDef.args);
253
- const cmd = {
254
- site,
255
- name,
256
- aliases: isRecord(cliDef) && Array.isArray(cliDef.aliases)
257
- ? cliDef.aliases.filter((value) => typeof value === 'string')
258
- : undefined,
259
- description: cliDef.description ?? '',
260
- domain: cliDef.domain,
261
- strategy,
262
- browser,
263
- args,
264
- columns: cliDef.columns,
265
- pipeline: cliDef.pipeline,
266
- timeoutSeconds: cliDef.timeout,
267
- source: filePath,
268
- deprecated: cliDef.deprecated,
269
- replacedBy: cliDef.replacedBy,
270
- navigateBefore: cliDef.navigateBefore,
271
- };
272
- registerCommand(cmd);
273
- }
274
- catch (err) {
275
- log.warn(`Failed to load ${filePath}: ${getErrorMessage(err)}`);
276
- }
277
- }
278
214
  /**
279
215
  * Discover and register plugins from ~/.opencli/plugins/.
280
216
  * Each subdirectory is treated as a plugin (site = directory name).
@@ -296,7 +232,7 @@ export async function discoverPlugins() {
296
232
  }));
297
233
  }
298
234
  /**
299
- * Flat scan: read yaml/ts files directly in a plugin directory.
235
+ * Flat scan: read ts/js files directly in a plugin directory.
300
236
  * Unlike discoverClisFromFs, this does NOT expect nested site subdirectories.
301
237
  */
302
238
  async function discoverPluginDir(dir, site) {
@@ -305,9 +241,10 @@ async function discoverPluginDir(dir, site) {
305
241
  await Promise.all(files.map(async (file) => {
306
242
  const filePath = path.join(dir, file);
307
243
  if (file.endsWith('.yaml') || file.endsWith('.yml')) {
308
- await registerYamlCli(filePath, site);
244
+ log.warn(`Ignoring YAML plugin ${filePath} — YAML format is no longer supported. Convert to TypeScript using cli() from '@jackwener/opencli/registry'.`);
245
+ return;
309
246
  }
310
- else if (file.endsWith('.js') && !file.endsWith('.d.js')) {
247
+ if (file.endsWith('.js') && !file.endsWith('.d.js')) {
311
248
  if (!(await isCliModule(filePath)))
312
249
  return;
313
250
  await import(pathToFileURL(filePath).href).catch((err) => {
@@ -17,7 +17,9 @@ export type ConnectivityResult = {
17
17
  export type DoctorReport = {
18
18
  cliVersion?: string;
19
19
  daemonRunning: boolean;
20
+ daemonFlaky?: boolean;
20
21
  extensionConnected: boolean;
22
+ extensionFlaky?: boolean;
21
23
  extensionVersion?: string;
22
24
  connectivity?: ConnectivityResult;
23
25
  sessions?: Array<{
@@ -5,11 +5,11 @@
5
5
  */
6
6
  import chalk from 'chalk';
7
7
  import { DEFAULT_DAEMON_PORT } from './constants.js';
8
- import { checkDaemonStatus } from './browser/discover.js';
9
8
  import { BrowserBridge } from './browser/index.js';
10
- import { listSessions } from './browser/daemon-client.js';
9
+ import { getDaemonHealth, listSessions } from './browser/daemon-client.js';
11
10
  import { getErrorMessage } from './errors.js';
12
11
  import { getRuntimeLabel } from './runtime-detect.js';
12
+ const DOCTOR_LIVE_TIMEOUT_SECONDS = 8;
13
13
  /**
14
14
  * Test connectivity by attempting a real browser command.
15
15
  */
@@ -17,7 +17,7 @@ export async function checkConnectivity(opts) {
17
17
  const start = Date.now();
18
18
  try {
19
19
  const bridge = new BrowserBridge();
20
- const page = await bridge.connect({ timeout: opts?.timeout ?? 8 });
20
+ const page = await bridge.connect({ timeout: opts?.timeout ?? DOCTOR_LIVE_TIMEOUT_SECONDS });
21
21
  // Try a simple eval to verify end-to-end connectivity
22
22
  await page.evaluate('1 + 1');
23
23
  await bridge.close();
@@ -28,33 +28,48 @@ export async function checkConnectivity(opts) {
28
28
  }
29
29
  }
30
30
  export async function runBrowserDoctor(opts = {}) {
31
- // Try to auto-start daemon if it's not running, so we show accurate status.
32
- let initialStatus = await checkDaemonStatus();
33
- if (!initialStatus.running) {
34
- try {
35
- const bridge = new BrowserBridge();
36
- await bridge.connect({ timeout: 5 });
37
- await bridge.close();
38
- }
39
- catch {
40
- // Auto-start failed; we'll report it below.
41
- }
42
- }
43
- // Run the live connectivity check — it may also auto-start the daemon as a
44
- // side-effect, so we read daemon status only *after* all side-effects settle.
31
+ // Live connectivity check doubles as auto-start (bridge.connect spawns daemon).
45
32
  let connectivity;
46
33
  if (opts.live) {
47
34
  connectivity = await checkConnectivity();
48
35
  }
49
- const status = await checkDaemonStatus();
50
- const sessions = opts.sessions && status.running && status.extensionConnected
36
+ else {
37
+ // No live probe daemon may have idle-exited. Do a minimal auto-start
38
+ // so we don't misreport a lazy-lifecycle stop as a real failure.
39
+ const initialHealth = await getDaemonHealth();
40
+ if (initialHealth.state === 'stopped') {
41
+ try {
42
+ const bridge = new BrowserBridge();
43
+ await bridge.connect({ timeout: 5 });
44
+ await bridge.close();
45
+ }
46
+ catch {
47
+ // Auto-start failed; we'll report it below.
48
+ }
49
+ }
50
+ }
51
+ // Single status read *after* all side-effects (live check / auto-start) settle.
52
+ const health = await getDaemonHealth();
53
+ const daemonRunning = health.state !== 'stopped';
54
+ const extensionConnected = health.state === 'ready';
55
+ const daemonFlaky = !!(connectivity?.ok && !daemonRunning);
56
+ const extensionFlaky = !!(connectivity?.ok && daemonRunning && !extensionConnected);
57
+ const sessions = opts.sessions && health.state === 'ready'
51
58
  ? await listSessions()
52
59
  : undefined;
53
60
  const issues = [];
54
- if (!status.running) {
61
+ if (daemonFlaky) {
62
+ issues.push('Daemon connectivity is unstable. The live browser test succeeded, but the daemon was no longer running immediately afterward.\n' +
63
+ 'This usually means the daemon crashed or exited right after serving the live probe.');
64
+ }
65
+ else if (!daemonRunning) {
55
66
  issues.push('Daemon is not running. It should start automatically when you run an opencli browser command.');
56
67
  }
57
- if (status.running && !status.extensionConnected) {
68
+ if (extensionFlaky) {
69
+ issues.push('Extension connection is unstable. The live browser test succeeded, but the daemon reported the extension disconnected immediately afterward.\n' +
70
+ 'This usually means the Browser Bridge service worker is reconnecting slowly or Chrome suspended it.');
71
+ }
72
+ else if (daemonRunning && !extensionConnected) {
58
73
  issues.push('Daemon is running but the Chrome/Chromium extension is not connected.\n' +
59
74
  'Please install the opencli Browser Bridge extension:\n' +
60
75
  ' 1. Download from https://github.com/jackwener/opencli/releases\n' +
@@ -64,19 +79,22 @@ export async function runBrowserDoctor(opts = {}) {
64
79
  if (connectivity && !connectivity.ok) {
65
80
  issues.push(`Browser connectivity test failed: ${connectivity.error ?? 'unknown'}`);
66
81
  }
67
- if (status.extensionVersion && opts.cliVersion) {
68
- const extMajor = status.extensionVersion.split('.')[0];
82
+ const extensionVersion = health.status?.extensionVersion;
83
+ if (extensionVersion && opts.cliVersion) {
84
+ const extMajor = extensionVersion.split('.')[0];
69
85
  const cliMajor = opts.cliVersion.split('.')[0];
70
86
  if (extMajor !== cliMajor) {
71
- issues.push(`Extension major version mismatch: extension v${status.extensionVersion} ≠ CLI v${opts.cliVersion}\n` +
87
+ issues.push(`Extension major version mismatch: extension v${extensionVersion} ≠ CLI v${opts.cliVersion}\n` +
72
88
  ' Download the latest extension from: https://github.com/jackwener/opencli/releases');
73
89
  }
74
90
  }
75
91
  return {
76
92
  cliVersion: opts.cliVersion,
77
- daemonRunning: status.running,
78
- extensionConnected: status.extensionConnected,
79
- extensionVersion: status.extensionVersion,
93
+ daemonRunning,
94
+ daemonFlaky,
95
+ extensionConnected,
96
+ extensionFlaky,
97
+ extensionVersion,
80
98
  connectivity,
81
99
  sessions,
82
100
  issues,
@@ -85,12 +103,22 @@ export async function runBrowserDoctor(opts = {}) {
85
103
  export function renderBrowserDoctorReport(report) {
86
104
  const lines = [chalk.bold(`opencli v${report.cliVersion ?? 'unknown'} doctor`) + chalk.dim(` (${getRuntimeLabel()})`), ''];
87
105
  // Daemon status
88
- const daemonIcon = report.daemonRunning ? chalk.green('[OK]') : chalk.red('[MISSING]');
89
- lines.push(`${daemonIcon} Daemon: ${report.daemonRunning ? `running on port ${DEFAULT_DAEMON_PORT}` : 'not running'}`);
106
+ const daemonIcon = report.daemonFlaky
107
+ ? chalk.yellow('[WARN]')
108
+ : report.daemonRunning ? chalk.green('[OK]') : chalk.red('[MISSING]');
109
+ const daemonLabel = report.daemonFlaky
110
+ ? 'unstable (running during live check, then stopped)'
111
+ : report.daemonRunning ? `running on port ${DEFAULT_DAEMON_PORT}` : 'not running';
112
+ lines.push(`${daemonIcon} Daemon: ${daemonLabel}`);
90
113
  // Extension status
91
- const extIcon = report.extensionConnected ? chalk.green('[OK]') : chalk.yellow('[MISSING]');
114
+ const extIcon = report.extensionFlaky
115
+ ? chalk.yellow('[WARN]')
116
+ : report.extensionConnected ? chalk.green('[OK]') : chalk.yellow('[MISSING]');
92
117
  const extVersion = report.extensionVersion ? chalk.dim(` (v${report.extensionVersion})`) : '';
93
- lines.push(`${extIcon} Extension: ${report.extensionConnected ? 'connected' : 'not connected'}${extVersion}`);
118
+ const extLabel = report.extensionFlaky
119
+ ? 'unstable (connected during live check, then disconnected)'
120
+ : report.extensionConnected ? 'connected' : 'not connected';
121
+ lines.push(`${extIcon} Extension: ${extLabel}${extVersion}`);
94
122
  // Connectivity
95
123
  if (report.connectivity) {
96
124
  const connIcon = report.connectivity.ok ? chalk.green('[OK]') : chalk.red('[FAIL]');
@@ -1,14 +1,12 @@
1
1
  import { beforeEach, describe, expect, it, vi } from 'vitest';
2
- const { mockCheckDaemonStatus, mockListSessions, mockConnect, mockClose } = vi.hoisted(() => ({
3
- mockCheckDaemonStatus: vi.fn(),
2
+ const { mockGetDaemonHealth, mockListSessions, mockConnect, mockClose } = vi.hoisted(() => ({
3
+ mockGetDaemonHealth: vi.fn(),
4
4
  mockListSessions: vi.fn(),
5
5
  mockConnect: vi.fn(),
6
6
  mockClose: vi.fn(),
7
7
  }));
8
- vi.mock('./browser/discover.js', () => ({
9
- checkDaemonStatus: mockCheckDaemonStatus,
10
- }));
11
8
  vi.mock('./browser/daemon-client.js', () => ({
9
+ getDaemonHealth: mockGetDaemonHealth,
12
10
  listSessions: mockListSessions,
13
11
  }));
14
12
  vi.mock('./browser/index.js', () => ({
@@ -69,23 +67,98 @@ describe('doctor report rendering', () => {
69
67
  }));
70
68
  expect(text).toContain('[SKIP] Connectivity: skipped (--no-live)');
71
69
  });
72
- it('reports consistent status when live check auto-starts the daemon', async () => {
73
- // checkDaemonStatus is called twice: once for auto-start check, once for final status.
74
- // First call: daemon not running (triggers auto-start attempt)
75
- mockCheckDaemonStatus.mockResolvedValueOnce({ running: false, extensionConnected: false });
76
- // Auto-start attempt via BrowserBridge.connect fails
70
+ it('renders unstable extension state when live connectivity and status disagree', () => {
71
+ const text = strip(renderBrowserDoctorReport({
72
+ daemonRunning: true,
73
+ extensionConnected: true,
74
+ extensionFlaky: true,
75
+ connectivity: { ok: true, durationMs: 1234 },
76
+ issues: ['Extension connection is unstable.'],
77
+ }));
78
+ expect(text).toContain('[WARN] Extension: unstable');
79
+ expect(text).toContain('Extension connection is unstable.');
80
+ });
81
+ it('renders unstable daemon state when live connectivity and status disagree', () => {
82
+ const text = strip(renderBrowserDoctorReport({
83
+ daemonRunning: false,
84
+ daemonFlaky: true,
85
+ extensionConnected: false,
86
+ connectivity: { ok: true, durationMs: 1234 },
87
+ issues: ['Daemon connectivity is unstable.'],
88
+ }));
89
+ expect(text).toContain('[WARN] Daemon: unstable');
90
+ expect(text).toContain('Daemon connectivity is unstable.');
91
+ });
92
+ it('reports daemon not running when no-live and auto-start fails', async () => {
93
+ // no-live mode: getDaemonHealth called twice (initial check + final status)
94
+ // Initial: stopped → triggers auto-start attempt
95
+ mockGetDaemonHealth.mockResolvedValueOnce({ state: 'stopped', status: null });
96
+ // Auto-start fails
77
97
  mockConnect.mockRejectedValueOnce(new Error('Could not start daemon'));
78
- // Second call: daemon still not running after failed auto-start
79
- mockCheckDaemonStatus.mockResolvedValueOnce({ running: false, extensionConnected: false });
98
+ // Final: still stopped
99
+ mockGetDaemonHealth.mockResolvedValueOnce({ state: 'stopped', status: null });
80
100
  const report = await runBrowserDoctor({ live: false });
81
- // Status reflects daemon not running
82
101
  expect(report.daemonRunning).toBe(false);
83
102
  expect(report.extensionConnected).toBe(false);
84
- // checkDaemonStatus called twice (initial + final)
85
- expect(mockCheckDaemonStatus).toHaveBeenCalledTimes(2);
86
- // Should report daemon not running
103
+ expect(mockGetDaemonHealth).toHaveBeenCalledTimes(2);
87
104
  expect(report.issues).toEqual(expect.arrayContaining([
88
105
  expect.stringContaining('Daemon is not running'),
89
106
  ]));
90
107
  });
108
+ it('reports flapping when live check succeeds but final status shows extension disconnected', async () => {
109
+ // Live check succeeds
110
+ mockConnect.mockResolvedValueOnce({
111
+ evaluate: vi.fn().mockResolvedValue(2),
112
+ });
113
+ mockClose.mockResolvedValueOnce(undefined);
114
+ // After live check, getDaemonHealth shows no-extension
115
+ mockGetDaemonHealth.mockResolvedValueOnce({ state: 'no-extension', status: { extensionConnected: false } });
116
+ const report = await runBrowserDoctor({ live: true });
117
+ expect(report.daemonRunning).toBe(true);
118
+ expect(report.extensionConnected).toBe(false);
119
+ expect(report.extensionFlaky).toBe(true);
120
+ expect(report.issues).toEqual(expect.arrayContaining([
121
+ expect.stringContaining('Extension connection is unstable'),
122
+ ]));
123
+ });
124
+ it('reports daemon flapping when live check succeeds but daemon disappears afterward', async () => {
125
+ // Live check succeeds
126
+ mockConnect.mockResolvedValueOnce({
127
+ evaluate: vi.fn().mockResolvedValue(2),
128
+ });
129
+ mockClose.mockResolvedValueOnce(undefined);
130
+ // After live check, getDaemonHealth shows stopped
131
+ mockGetDaemonHealth.mockResolvedValueOnce({ state: 'stopped', status: null });
132
+ const report = await runBrowserDoctor({ live: true });
133
+ expect(report.daemonRunning).toBe(false);
134
+ expect(report.daemonFlaky).toBe(true);
135
+ expect(report.extensionConnected).toBe(false);
136
+ expect(report.issues).toEqual(expect.arrayContaining([
137
+ expect.stringContaining('Daemon connectivity is unstable'),
138
+ ]));
139
+ });
140
+ it('uses the fast default timeout for live connectivity checks', async () => {
141
+ let timeoutSeen;
142
+ mockConnect.mockImplementationOnce(async (opts) => {
143
+ timeoutSeen = opts?.timeout;
144
+ return {
145
+ evaluate: vi.fn().mockResolvedValue(2),
146
+ };
147
+ });
148
+ mockClose.mockResolvedValueOnce(undefined);
149
+ mockGetDaemonHealth.mockResolvedValueOnce({ state: 'ready', status: { extensionConnected: true } });
150
+ await runBrowserDoctor({ live: true });
151
+ expect(timeoutSeen).toBe(8);
152
+ });
153
+ it('skips auto-start in no-live mode when daemon is already running', async () => {
154
+ // no-live mode but daemon already running (no-extension)
155
+ mockGetDaemonHealth.mockResolvedValueOnce({ state: 'no-extension', status: { extensionConnected: false } });
156
+ // Final status: same
157
+ mockGetDaemonHealth.mockResolvedValueOnce({ state: 'no-extension', status: { extensionConnected: false } });
158
+ const report = await runBrowserDoctor({ live: false });
159
+ // Should NOT have tried auto-start since daemon was already running
160
+ expect(mockConnect).not.toHaveBeenCalled();
161
+ expect(report.daemonRunning).toBe(true);
162
+ expect(report.extensionConnected).toBe(false);
163
+ });
91
164
  });
@@ -52,7 +52,7 @@ export declare function ytdlpDownload(url: string, destPath: string, options?: Y
52
52
  /**
53
53
  * Save document content to file.
54
54
  */
55
- export declare function saveDocument(content: string, destPath: string, format?: 'json' | 'markdown' | 'html' | 'text', metadata?: Record<string, any>): Promise<{
55
+ export declare function saveDocument(content: string, destPath: string, format?: 'json' | 'markdown' | 'html' | 'text', metadata?: Record<string, unknown>): Promise<{
56
56
  success: boolean;
57
57
  size: number;
58
58
  error?: string;
@@ -127,8 +127,7 @@ describe('discoverPlugins', () => {
127
127
  }
128
128
  catch { }
129
129
  });
130
- it('discovers YAML plugins from ~/.opencli/plugins/', async () => {
131
- // Create a simple YAML adapter in the plugins directory
130
+ it('ignores YAML files in plugin directories (YAML format removed)', async () => {
132
131
  await fs.promises.mkdir(testPluginDir, { recursive: true });
133
132
  await fs.promises.writeFile(yamlPath, `
134
133
  site: __test-plugin__
@@ -136,25 +135,17 @@ name: greeting
136
135
  description: Test plugin greeting
137
136
  strategy: public
138
137
  browser: false
139
-
140
- pipeline:
141
- - evaluate: "() => [{ message: 'hello from plugin' }]"
142
-
143
- columns: [message]
144
138
  `);
145
139
  await discoverPlugins();
146
140
  const registry = getRegistry();
147
141
  const cmd = registry.get('__test-plugin__/greeting');
148
- expect(cmd).toBeDefined();
149
- expect(cmd.site).toBe('__test-plugin__');
150
- expect(cmd.name).toBe('greeting');
151
- expect(cmd.description).toBe('Test plugin greeting');
142
+ expect(cmd).toBeUndefined();
152
143
  });
153
144
  it('handles non-existent plugins directory gracefully', async () => {
154
145
  // discoverPlugins should not throw if ~/.opencli/plugins/ does not exist
155
146
  await expect(discoverPlugins()).resolves.not.toThrow();
156
147
  });
157
- it('discovers YAML plugins from symlinked plugin directories', async () => {
148
+ it('ignores YAML files in symlinked plugin directories (YAML format removed)', async () => {
158
149
  await fs.promises.mkdir(PLUGINS_DIR, { recursive: true });
159
150
  await fs.promises.mkdir(symlinkTargetDir, { recursive: true });
160
151
  await fs.promises.writeFile(path.join(symlinkTargetDir, 'hello.yaml'), `
@@ -163,17 +154,11 @@ name: hello
163
154
  description: Test plugin greeting via symlink
164
155
  strategy: public
165
156
  browser: false
166
-
167
- pipeline:
168
- - evaluate: "() => [{ message: 'hello from symlink plugin' }]"
169
-
170
- columns: [message]
171
157
  `);
172
158
  await fs.promises.symlink(symlinkTargetDir, symlinkPluginDir, 'dir');
173
159
  await discoverPlugins();
174
160
  const cmd = getRegistry().get('__test-plugin-symlink__/hello');
175
- expect(cmd).toBeDefined();
176
- expect(cmd.description).toBe('Test plugin greeting via symlink');
161
+ expect(cmd).toBeUndefined();
177
162
  });
178
163
  it('skips broken plugin symlinks without throwing', async () => {
179
164
  await fs.promises.mkdir(PLUGINS_DIR, { recursive: true });
@@ -12,12 +12,11 @@
12
12
  import { Strategy, getRegistry, fullName } from './registry.js';
13
13
  import { pathToFileURL } from 'node:url';
14
14
  import { executePipeline } from './pipeline/index.js';
15
- import { AdapterLoadError, ArgumentError, BrowserConnectError, CommandExecutionError, getErrorMessage } from './errors.js';
15
+ import { AdapterLoadError, ArgumentError, CommandExecutionError, getErrorMessage } from './errors.js';
16
16
  import { isDiagnosticEnabled, collectDiagnostic, emitDiagnostic } from './diagnostic.js';
17
17
  import { shouldUseBrowserSession } from './capabilityRouting.js';
18
18
  import { getBrowserFactory, browserSession, runWithTimeout, DEFAULT_BROWSER_COMMAND_TIMEOUT } from './runtime.js';
19
19
  import { emitHook } from './hooks.js';
20
- import { checkDaemonStatus } from './browser/discover.js';
21
20
  import { log } from './logger.js';
22
21
  import { isElectronApp } from './electron-apps.js';
23
22
  import { probeCDP, resolveElectronEndpoint } from './launcher.js';
@@ -149,17 +148,6 @@ export async function executeCommand(cmd, rawKwargs, debug = false) {
149
148
  cdpEndpoint = await resolveElectronEndpoint(cmd.site);
150
149
  }
151
150
  }
152
- else {
153
- // Browser Bridge: fail-fast when daemon is up but extension is missing.
154
- // 300ms timeout avoids a full 2s wait on cold-start.
155
- const status = await checkDaemonStatus({ timeout: 300 });
156
- if (status.running && !status.extensionConnected) {
157
- throw new BrowserConnectError('Browser Bridge extension not connected', 'Install the Browser Bridge:\n' +
158
- ' 1. Download: https://github.com/jackwener/opencli/releases\n' +
159
- ' 2. In Chrome or Chromium, open chrome://extensions → Developer Mode → Load unpacked\n' +
160
- ' Then run: opencli doctor');
161
- }
162
- }
163
151
  ensureRequiredEnv(cmd);
164
152
  const BrowserFactory = getBrowserFactory(cmd.site);
165
153
  result = await browserSession(BrowserFactory, async (page) => {
@@ -257,7 +257,7 @@ export async function exploreUrl(url, opts) {
257
257
  return browserSession(opts.BrowserFactory, async (page) => {
258
258
  return runWithTimeout((async () => {
259
259
  // Step 1: Navigate
260
- await page.startNetworkCapture?.();
260
+ await page.startNetworkCapture?.().catch(() => { });
261
261
  await page.goto(url);
262
262
  await page.wait(waitSeconds);
263
263
  // Step 2: Auto-scroll to trigger lazy loading intelligently