@jackwener/opencli 1.5.5 → 1.5.7

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 (540) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +31 -4
  3. package/README.zh-CN.md +40 -5
  4. package/SKILL.md +1 -1
  5. package/dist/browser/cdp.d.ts +1 -0
  6. package/dist/browser/cdp.js +30 -27
  7. package/dist/browser/daemon-client.d.ts +11 -1
  8. package/dist/browser/daemon-client.js +3 -0
  9. package/dist/browser/dom-helpers.js +1 -0
  10. package/dist/browser/dom-helpers.test.js +14 -1
  11. package/dist/browser/mcp.js +18 -13
  12. package/dist/browser/page.d.ts +6 -0
  13. package/dist/browser/page.js +37 -2
  14. package/dist/browser/page.test.d.ts +1 -0
  15. package/dist/browser/page.test.js +44 -0
  16. package/dist/browser/stealth.js +198 -0
  17. package/dist/browser/stealth.test.d.ts +1 -0
  18. package/dist/browser/stealth.test.js +134 -0
  19. package/dist/browser.test.js +1 -1
  20. package/dist/build-manifest.d.ts +1 -0
  21. package/dist/build-manifest.js +5 -1
  22. package/dist/build-manifest.test.js +2 -0
  23. package/dist/cli-manifest.json +1821 -252
  24. package/dist/cli.js +20 -3
  25. package/dist/clis/antigravity/serve.d.ts +1 -1
  26. package/dist/clis/antigravity/serve.js +5 -8
  27. package/dist/clis/band/bands.d.ts +1 -0
  28. package/dist/clis/band/bands.js +72 -0
  29. package/dist/clis/band/mentions.d.ts +1 -0
  30. package/dist/clis/band/mentions.js +127 -0
  31. package/dist/clis/band/post.d.ts +1 -0
  32. package/dist/clis/band/post.js +175 -0
  33. package/dist/clis/band/posts.d.ts +1 -0
  34. package/dist/clis/band/posts.js +94 -0
  35. package/dist/clis/bilibili/subtitle.js +4 -0
  36. package/dist/clis/bilibili/subtitle.test.d.ts +1 -0
  37. package/dist/clis/bilibili/subtitle.test.js +48 -0
  38. package/dist/clis/chatwise/ask.js +0 -2
  39. package/dist/clis/chatwise/export.js +0 -2
  40. package/dist/clis/chatwise/history.js +0 -2
  41. package/dist/clis/chatwise/model.js +0 -2
  42. package/dist/clis/chatwise/new.js +1 -2
  43. package/dist/clis/chatwise/read.js +0 -2
  44. package/dist/clis/chatwise/screenshot.js +1 -2
  45. package/dist/clis/chatwise/send.js +0 -2
  46. package/dist/clis/chatwise/status.js +1 -2
  47. package/dist/clis/ctrip/search.d.ts +13 -0
  48. package/dist/clis/ctrip/search.js +73 -48
  49. package/dist/clis/ctrip/search.test.d.ts +1 -0
  50. package/dist/clis/ctrip/search.test.js +64 -0
  51. package/dist/clis/doubao/detail.d.ts +1 -0
  52. package/dist/clis/doubao/detail.js +33 -0
  53. package/dist/clis/doubao/detail.test.d.ts +1 -0
  54. package/dist/clis/doubao/detail.test.js +42 -0
  55. package/dist/clis/doubao/history.d.ts +1 -0
  56. package/dist/clis/doubao/history.js +28 -0
  57. package/dist/clis/doubao/history.test.d.ts +1 -0
  58. package/dist/clis/doubao/history.test.js +37 -0
  59. package/dist/clis/doubao/meeting-summary.d.ts +1 -0
  60. package/dist/clis/doubao/meeting-summary.js +39 -0
  61. package/dist/clis/doubao/meeting-transcript.d.ts +1 -0
  62. package/dist/clis/doubao/meeting-transcript.js +36 -0
  63. package/dist/clis/doubao/utils.d.ts +27 -0
  64. package/dist/clis/doubao/utils.js +317 -0
  65. package/dist/clis/doubao/utils.test.d.ts +1 -0
  66. package/dist/clis/doubao/utils.test.js +24 -0
  67. package/dist/clis/douyin/_shared/public-api.d.ts +33 -0
  68. package/dist/clis/douyin/_shared/public-api.js +29 -0
  69. package/dist/clis/douyin/_shared/sts2.js +8 -2
  70. package/dist/clis/douyin/_shared/sts2.test.d.ts +1 -0
  71. package/dist/clis/douyin/_shared/sts2.test.js +27 -0
  72. package/dist/clis/douyin/activities.js +4 -2
  73. package/dist/clis/douyin/activities.test.js +34 -1
  74. package/dist/clis/douyin/collections.js +1 -1
  75. package/dist/clis/douyin/collections.test.js +24 -2
  76. package/dist/clis/douyin/draft.d.ts +8 -11
  77. package/dist/clis/douyin/draft.js +302 -185
  78. package/dist/clis/douyin/draft.test.d.ts +1 -1
  79. package/dist/clis/douyin/draft.test.js +357 -2
  80. package/dist/clis/douyin/hashtag.js +9 -2
  81. package/dist/clis/douyin/hashtag.test.js +35 -2
  82. package/dist/clis/douyin/profile.js +1 -1
  83. package/dist/clis/douyin/profile.test.js +36 -1
  84. package/dist/clis/douyin/user-videos.d.ts +5 -0
  85. package/dist/clis/douyin/user-videos.js +74 -0
  86. package/dist/clis/douyin/user-videos.test.d.ts +1 -0
  87. package/dist/clis/douyin/user-videos.test.js +108 -0
  88. package/dist/clis/douyin/videos.js +22 -5
  89. package/dist/clis/douyin/videos.test.js +45 -2
  90. package/dist/clis/facebook/search.test.d.ts +5 -0
  91. package/dist/clis/facebook/search.test.js +60 -0
  92. package/dist/clis/facebook/search.yaml +4 -3
  93. package/dist/clis/instagram/download.d.ts +16 -0
  94. package/dist/clis/instagram/download.js +225 -0
  95. package/dist/clis/instagram/download.test.d.ts +1 -0
  96. package/dist/clis/instagram/download.test.js +118 -0
  97. package/dist/clis/notebooklm/bind-current.d.ts +1 -0
  98. package/dist/clis/notebooklm/bind-current.js +29 -0
  99. package/dist/clis/notebooklm/bind-current.test.d.ts +1 -0
  100. package/dist/clis/notebooklm/bind-current.test.js +35 -0
  101. package/dist/clis/notebooklm/binding.test.d.ts +1 -0
  102. package/dist/clis/notebooklm/binding.test.js +44 -0
  103. package/dist/clis/notebooklm/compat.test.d.ts +3 -0
  104. package/dist/clis/notebooklm/compat.test.js +16 -0
  105. package/dist/clis/notebooklm/current.d.ts +1 -0
  106. package/dist/clis/notebooklm/current.js +28 -0
  107. package/dist/clis/notebooklm/get.d.ts +1 -0
  108. package/dist/clis/notebooklm/get.js +37 -0
  109. package/dist/clis/notebooklm/history.d.ts +1 -0
  110. package/dist/clis/notebooklm/history.js +25 -0
  111. package/dist/clis/notebooklm/history.test.d.ts +1 -0
  112. package/dist/clis/notebooklm/history.test.js +58 -0
  113. package/dist/clis/notebooklm/list.d.ts +1 -0
  114. package/dist/clis/notebooklm/list.js +35 -0
  115. package/dist/clis/notebooklm/note-list.d.ts +1 -0
  116. package/dist/clis/notebooklm/note-list.js +28 -0
  117. package/dist/clis/notebooklm/note-list.test.d.ts +1 -0
  118. package/dist/clis/notebooklm/note-list.test.js +56 -0
  119. package/dist/clis/notebooklm/notes-get.d.ts +1 -0
  120. package/dist/clis/notebooklm/notes-get.js +47 -0
  121. package/dist/clis/notebooklm/notes-get.test.d.ts +1 -0
  122. package/dist/clis/notebooklm/notes-get.test.js +72 -0
  123. package/dist/clis/notebooklm/rpc.d.ts +36 -0
  124. package/dist/clis/notebooklm/rpc.js +189 -0
  125. package/dist/clis/notebooklm/rpc.test.d.ts +1 -0
  126. package/dist/clis/notebooklm/rpc.test.js +105 -0
  127. package/dist/clis/notebooklm/shared.d.ts +87 -0
  128. package/dist/clis/notebooklm/shared.js +3 -0
  129. package/dist/clis/notebooklm/source-fulltext.d.ts +1 -0
  130. package/dist/clis/notebooklm/source-fulltext.js +44 -0
  131. package/dist/clis/notebooklm/source-fulltext.test.d.ts +1 -0
  132. package/dist/clis/notebooklm/source-fulltext.test.js +106 -0
  133. package/dist/clis/notebooklm/source-get.d.ts +1 -0
  134. package/dist/clis/notebooklm/source-get.js +40 -0
  135. package/dist/clis/notebooklm/source-get.test.d.ts +1 -0
  136. package/dist/clis/notebooklm/source-get.test.js +84 -0
  137. package/dist/clis/notebooklm/source-guide.d.ts +1 -0
  138. package/dist/clis/notebooklm/source-guide.js +44 -0
  139. package/dist/clis/notebooklm/source-guide.test.d.ts +1 -0
  140. package/dist/clis/notebooklm/source-guide.test.js +104 -0
  141. package/dist/clis/notebooklm/source-list.d.ts +1 -0
  142. package/dist/clis/notebooklm/source-list.js +30 -0
  143. package/dist/clis/notebooklm/status.d.ts +1 -0
  144. package/dist/clis/notebooklm/status.js +31 -0
  145. package/dist/clis/notebooklm/summary.d.ts +1 -0
  146. package/dist/clis/notebooklm/summary.js +30 -0
  147. package/dist/clis/notebooklm/summary.test.d.ts +1 -0
  148. package/dist/clis/notebooklm/summary.test.js +78 -0
  149. package/dist/clis/notebooklm/utils.d.ts +37 -0
  150. package/dist/clis/notebooklm/utils.js +739 -0
  151. package/dist/clis/notebooklm/utils.test.d.ts +1 -0
  152. package/dist/clis/notebooklm/utils.test.js +390 -0
  153. package/dist/clis/ones/common.d.ts +32 -0
  154. package/dist/clis/ones/common.js +144 -0
  155. package/dist/clis/ones/enrich-tasks.d.ts +5 -0
  156. package/dist/clis/ones/enrich-tasks.js +37 -0
  157. package/dist/clis/ones/login.d.ts +1 -0
  158. package/dist/clis/ones/login.js +80 -0
  159. package/dist/clis/ones/logout.d.ts +1 -0
  160. package/dist/clis/ones/logout.js +17 -0
  161. package/dist/clis/ones/me.d.ts +1 -0
  162. package/dist/clis/ones/me.js +30 -0
  163. package/dist/clis/ones/my-tasks.d.ts +1 -0
  164. package/dist/clis/ones/my-tasks.js +120 -0
  165. package/dist/clis/ones/resolve-labels.d.ts +10 -0
  166. package/dist/clis/ones/resolve-labels.js +64 -0
  167. package/dist/clis/ones/task-helpers.d.ts +29 -0
  168. package/dist/clis/ones/task-helpers.js +212 -0
  169. package/dist/clis/ones/task-helpers.test.d.ts +1 -0
  170. package/dist/clis/ones/task-helpers.test.js +12 -0
  171. package/dist/clis/ones/task.d.ts +1 -0
  172. package/dist/clis/ones/task.js +66 -0
  173. package/dist/clis/ones/tasks.d.ts +1 -0
  174. package/dist/clis/ones/tasks.js +79 -0
  175. package/dist/clis/ones/token-info.d.ts +1 -0
  176. package/dist/clis/ones/token-info.js +42 -0
  177. package/dist/clis/ones/worklog.d.ts +11 -0
  178. package/dist/clis/ones/worklog.js +267 -0
  179. package/dist/clis/ones/worklog.test.d.ts +1 -0
  180. package/dist/clis/ones/worklog.test.js +20 -0
  181. package/dist/clis/spotify/spotify.d.ts +1 -0
  182. package/dist/clis/spotify/spotify.js +316 -0
  183. package/dist/clis/spotify/utils.d.ts +21 -0
  184. package/dist/clis/spotify/utils.js +66 -0
  185. package/dist/clis/spotify/utils.test.d.ts +1 -0
  186. package/dist/clis/spotify/utils.test.js +67 -0
  187. package/dist/clis/substack/utils.d.ts +4 -0
  188. package/dist/clis/substack/utils.js +8 -2
  189. package/dist/clis/substack/utils.test.d.ts +1 -0
  190. package/dist/clis/substack/utils.test.js +46 -0
  191. package/dist/clis/tieba/commands.test.d.ts +4 -0
  192. package/dist/clis/tieba/commands.test.js +79 -0
  193. package/dist/clis/tieba/hot.d.ts +1 -0
  194. package/dist/clis/tieba/hot.js +48 -0
  195. package/dist/clis/tieba/posts.d.ts +1 -0
  196. package/dist/clis/tieba/posts.js +85 -0
  197. package/dist/clis/tieba/read.d.ts +1 -0
  198. package/dist/clis/tieba/read.js +140 -0
  199. package/dist/clis/tieba/search.d.ts +1 -0
  200. package/dist/clis/tieba/search.js +108 -0
  201. package/dist/clis/tieba/utils.d.ts +101 -0
  202. package/dist/clis/tieba/utils.js +240 -0
  203. package/dist/clis/tieba/utils.test.d.ts +1 -0
  204. package/dist/clis/tieba/utils.test.js +290 -0
  205. package/dist/clis/v2ex/hot.yaml +4 -1
  206. package/dist/clis/v2ex/latest.yaml +4 -1
  207. package/dist/clis/v2ex/topic.yaml +6 -1
  208. package/dist/clis/weixin/download.d.ts +9 -0
  209. package/dist/clis/weixin/download.js +76 -6
  210. package/dist/clis/weread/book.js +206 -13
  211. package/dist/clis/weread/commands.test.js +331 -0
  212. package/dist/clis/weread/private-api-regression.test.d.ts +1 -0
  213. package/dist/{weread-private-api-regression.test.js → clis/weread/private-api-regression.test.js} +92 -30
  214. package/dist/clis/weread/search-regression.test.d.ts +1 -0
  215. package/dist/clis/weread/search-regression.test.js +407 -0
  216. package/dist/clis/weread/search.js +143 -7
  217. package/dist/clis/weread/shelf.js +13 -95
  218. package/dist/clis/weread/utils.d.ts +56 -0
  219. package/dist/clis/weread/utils.js +234 -7
  220. package/dist/clis/weread/utils.test.js +71 -1
  221. package/dist/clis/xiaohongshu/comments.d.ts +3 -0
  222. package/dist/clis/xiaohongshu/comments.js +76 -17
  223. package/dist/clis/xiaohongshu/comments.test.js +70 -9
  224. package/dist/clis/xiaohongshu/download.d.ts +4 -1
  225. package/dist/clis/xiaohongshu/download.js +83 -22
  226. package/dist/clis/xiaohongshu/download.test.d.ts +1 -0
  227. package/dist/clis/xiaohongshu/download.test.js +75 -0
  228. package/dist/clis/xiaohongshu/note-helpers.d.ts +12 -0
  229. package/dist/clis/xiaohongshu/note-helpers.js +23 -0
  230. package/dist/clis/xiaohongshu/note.d.ts +7 -0
  231. package/dist/clis/xiaohongshu/note.js +76 -0
  232. package/dist/clis/xiaohongshu/note.test.d.ts +1 -0
  233. package/dist/clis/xiaohongshu/note.test.js +136 -0
  234. package/dist/clis/xiaohongshu/publish.d.ts +1 -1
  235. package/dist/clis/xiaohongshu/publish.js +78 -31
  236. package/dist/clis/xiaohongshu/publish.test.js +66 -1
  237. package/dist/clis/xiaohongshu/search.js +9 -0
  238. package/dist/clis/xiaohongshu/search.test.js +10 -4
  239. package/dist/clis/xiaohongshu/user-helpers.d.ts +1 -0
  240. package/dist/clis/xiaohongshu/user-helpers.js +2 -0
  241. package/dist/clis/xiaohongshu/user-helpers.test.js +18 -0
  242. package/dist/clis/xueqiu/comments.d.ts +118 -0
  243. package/dist/clis/xueqiu/comments.js +354 -0
  244. package/dist/clis/xueqiu/comments.test.d.ts +1 -0
  245. package/dist/clis/xueqiu/comments.test.js +696 -0
  246. package/dist/clis/youtube/search.js +57 -17
  247. package/dist/clis/youtube/transcript.js +2 -4
  248. package/dist/clis/youtube/utils.d.ts +9 -0
  249. package/dist/clis/youtube/utils.js +67 -3
  250. package/dist/clis/youtube/utils.test.d.ts +1 -0
  251. package/dist/clis/youtube/utils.test.js +37 -0
  252. package/dist/clis/youtube/video.js +16 -15
  253. package/dist/clis/zhihu/question.js +19 -17
  254. package/dist/clis/zhihu/question.test.d.ts +1 -0
  255. package/dist/clis/zhihu/question.test.js +54 -0
  256. package/dist/clis/zsxq/dynamics.d.ts +1 -0
  257. package/dist/clis/zsxq/dynamics.js +47 -0
  258. package/dist/clis/zsxq/groups.d.ts +1 -0
  259. package/dist/clis/zsxq/groups.js +32 -0
  260. package/dist/clis/zsxq/search.d.ts +1 -0
  261. package/dist/clis/zsxq/search.js +43 -0
  262. package/dist/clis/zsxq/search.test.d.ts +1 -0
  263. package/dist/clis/zsxq/search.test.js +24 -0
  264. package/dist/clis/zsxq/topic.d.ts +1 -0
  265. package/dist/clis/zsxq/topic.js +47 -0
  266. package/dist/clis/zsxq/topic.test.d.ts +1 -0
  267. package/dist/clis/zsxq/topic.test.js +29 -0
  268. package/dist/clis/zsxq/topics.d.ts +1 -0
  269. package/dist/clis/zsxq/topics.js +25 -0
  270. package/dist/clis/zsxq/topics.test.d.ts +1 -0
  271. package/dist/clis/zsxq/topics.test.js +24 -0
  272. package/dist/clis/zsxq/utils.d.ts +97 -0
  273. package/dist/clis/zsxq/utils.js +230 -0
  274. package/dist/commanderAdapter.js +10 -1
  275. package/dist/commanderAdapter.test.js +64 -0
  276. package/dist/commands/daemon.d.ts +9 -0
  277. package/dist/commands/daemon.js +124 -0
  278. package/dist/commands/daemon.test.d.ts +1 -0
  279. package/dist/commands/daemon.test.js +185 -0
  280. package/dist/completion.js +3 -1
  281. package/dist/constants.d.ts +2 -0
  282. package/dist/constants.js +2 -0
  283. package/dist/daemon.d.ts +1 -1
  284. package/dist/daemon.js +25 -14
  285. package/dist/daemon.test.d.ts +1 -0
  286. package/dist/daemon.test.js +65 -0
  287. package/dist/discovery.d.ts +9 -0
  288. package/dist/discovery.js +47 -2
  289. package/dist/electron-apps.d.ts +29 -0
  290. package/dist/electron-apps.js +65 -0
  291. package/dist/electron-apps.test.d.ts +1 -0
  292. package/dist/electron-apps.test.js +43 -0
  293. package/dist/engine.test.js +41 -9
  294. package/dist/execution.js +20 -16
  295. package/dist/external-clis.yaml +17 -0
  296. package/dist/idle-manager.d.ts +19 -0
  297. package/dist/idle-manager.js +54 -0
  298. package/dist/launcher.d.ts +36 -0
  299. package/dist/launcher.js +152 -0
  300. package/dist/launcher.test.d.ts +1 -0
  301. package/dist/launcher.test.js +57 -0
  302. package/dist/main.js +3 -3
  303. package/dist/registry.d.ts +1 -0
  304. package/dist/registry.js +31 -3
  305. package/dist/registry.test.js +13 -0
  306. package/dist/runtime.d.ts +5 -3
  307. package/dist/runtime.js +12 -5
  308. package/dist/serialization.d.ts +1 -0
  309. package/dist/serialization.js +3 -0
  310. package/dist/serialization.test.js +17 -1
  311. package/dist/tui.d.ts +7 -0
  312. package/dist/tui.js +52 -0
  313. package/dist/tui.test.d.ts +1 -0
  314. package/dist/tui.test.js +19 -0
  315. package/dist/types.d.ts +5 -0
  316. package/dist/weixin-download.test.js +14 -0
  317. package/docs/.vitepress/config.mts +4 -0
  318. package/docs/adapters/browser/band.md +63 -0
  319. package/docs/adapters/browser/notebooklm.md +69 -0
  320. package/docs/adapters/browser/ones.md +59 -0
  321. package/docs/adapters/browser/spotify.md +62 -0
  322. package/docs/adapters/browser/tieba.md +45 -0
  323. package/docs/adapters/browser/xiaohongshu.md +19 -10
  324. package/docs/adapters/browser/xueqiu.md +5 -0
  325. package/docs/adapters/browser/zsxq.md +49 -0
  326. package/docs/adapters/index.md +67 -63
  327. package/docs/adapters-doc/ones.md +32 -0
  328. package/docs/guide/browser-bridge.md +12 -0
  329. package/docs/guide/troubleshooting.md +9 -4
  330. package/docs/superpowers/plans/2026-03-31-daemon-lifecycle-redesign.md +857 -0
  331. package/docs/superpowers/specs/2026-03-31-daemon-lifecycle-redesign.md +208 -0
  332. package/docs/zh/guide/browser-bridge.md +12 -0
  333. package/extension/dist/background.js +794 -513
  334. package/extension/src/background.test.ts +202 -2
  335. package/extension/src/background.ts +189 -10
  336. package/extension/src/cdp.ts +54 -0
  337. package/extension/src/protocol.ts +11 -5
  338. package/package.json +1 -1
  339. package/scripts/postinstall.js +16 -0
  340. package/src/browser/cdp.ts +24 -17
  341. package/src/browser/daemon-client.ts +11 -1
  342. package/src/browser/dom-helpers.test.ts +15 -1
  343. package/src/browser/dom-helpers.ts +1 -0
  344. package/src/browser/mcp.ts +18 -13
  345. package/src/browser/page.test.ts +58 -0
  346. package/src/browser/page.ts +34 -2
  347. package/src/browser/stealth.test.ts +153 -0
  348. package/src/browser/stealth.ts +198 -0
  349. package/src/browser.test.ts +1 -1
  350. package/src/build-manifest.test.ts +2 -0
  351. package/src/build-manifest.ts +6 -1
  352. package/src/cli.ts +21 -3
  353. package/src/clis/antigravity/SKILL.md +3 -12
  354. package/src/clis/antigravity/serve.ts +5 -10
  355. package/src/clis/band/bands.ts +76 -0
  356. package/src/clis/band/mentions.ts +134 -0
  357. package/src/clis/band/post.ts +187 -0
  358. package/src/clis/band/posts.ts +106 -0
  359. package/src/clis/bilibili/subtitle.test.ts +60 -0
  360. package/src/clis/bilibili/subtitle.ts +4 -0
  361. package/src/clis/chatwise/ask.ts +0 -2
  362. package/src/clis/chatwise/export.ts +0 -2
  363. package/src/clis/chatwise/history.ts +0 -2
  364. package/src/clis/chatwise/model.ts +0 -2
  365. package/src/clis/chatwise/new.ts +1 -2
  366. package/src/clis/chatwise/read.ts +0 -2
  367. package/src/clis/chatwise/screenshot.ts +1 -2
  368. package/src/clis/chatwise/send.ts +0 -2
  369. package/src/clis/chatwise/status.ts +1 -2
  370. package/src/clis/ctrip/search.test.ts +73 -0
  371. package/src/clis/ctrip/search.ts +97 -47
  372. package/src/clis/doubao/detail.test.ts +53 -0
  373. package/src/clis/doubao/detail.ts +41 -0
  374. package/src/clis/doubao/history.test.ts +45 -0
  375. package/src/clis/doubao/history.ts +32 -0
  376. package/src/clis/doubao/meeting-summary.ts +53 -0
  377. package/src/clis/doubao/meeting-transcript.ts +48 -0
  378. package/src/clis/doubao/utils.test.ts +45 -0
  379. package/src/clis/doubao/utils.ts +371 -0
  380. package/src/clis/douyin/_shared/public-api.ts +84 -0
  381. package/src/clis/douyin/_shared/sts2.test.ts +31 -0
  382. package/src/clis/douyin/_shared/sts2.ts +11 -3
  383. package/src/clis/douyin/activities.test.ts +41 -1
  384. package/src/clis/douyin/activities.ts +12 -3
  385. package/src/clis/douyin/collections.test.ts +35 -2
  386. package/src/clis/douyin/collections.ts +1 -1
  387. package/src/clis/douyin/draft.test.ts +444 -2
  388. package/src/clis/douyin/draft.ts +382 -218
  389. package/src/clis/douyin/hashtag.test.ts +42 -2
  390. package/src/clis/douyin/hashtag.ts +11 -3
  391. package/src/clis/douyin/profile.test.ts +43 -1
  392. package/src/clis/douyin/profile.ts +9 -2
  393. package/src/clis/douyin/user-videos.test.ts +122 -0
  394. package/src/clis/douyin/user-videos.ts +101 -0
  395. package/src/clis/douyin/videos.test.ts +52 -2
  396. package/src/clis/douyin/videos.ts +49 -15
  397. package/src/clis/facebook/search.test.ts +70 -0
  398. package/src/clis/facebook/search.yaml +4 -3
  399. package/src/clis/instagram/download.test.ts +159 -0
  400. package/src/clis/instagram/download.ts +286 -0
  401. package/src/clis/notebooklm/bind-current.test.ts +43 -0
  402. package/src/clis/notebooklm/bind-current.ts +36 -0
  403. package/src/clis/notebooklm/binding.test.ts +53 -0
  404. package/src/clis/notebooklm/compat.test.ts +19 -0
  405. package/src/clis/notebooklm/current.ts +38 -0
  406. package/src/clis/notebooklm/get.ts +53 -0
  407. package/src/clis/notebooklm/history.test.ts +70 -0
  408. package/src/clis/notebooklm/history.ts +36 -0
  409. package/src/clis/notebooklm/list.ts +40 -0
  410. package/src/clis/notebooklm/note-list.test.ts +64 -0
  411. package/src/clis/notebooklm/note-list.ts +42 -0
  412. package/src/clis/notebooklm/notes-get.test.ts +88 -0
  413. package/src/clis/notebooklm/notes-get.ts +67 -0
  414. package/src/clis/notebooklm/rpc.test.ts +126 -0
  415. package/src/clis/notebooklm/rpc.ts +286 -0
  416. package/src/clis/notebooklm/shared.ts +98 -0
  417. package/src/clis/notebooklm/source-fulltext.test.ts +123 -0
  418. package/src/clis/notebooklm/source-fulltext.ts +69 -0
  419. package/src/clis/notebooklm/source-get.test.ts +100 -0
  420. package/src/clis/notebooklm/source-get.ts +60 -0
  421. package/src/clis/notebooklm/source-guide.test.ts +121 -0
  422. package/src/clis/notebooklm/source-guide.ts +69 -0
  423. package/src/clis/notebooklm/source-list.ts +45 -0
  424. package/src/clis/notebooklm/status.ts +34 -0
  425. package/src/clis/notebooklm/summary.test.ts +94 -0
  426. package/src/clis/notebooklm/summary.ts +45 -0
  427. package/src/clis/notebooklm/utils.test.ts +446 -0
  428. package/src/clis/notebooklm/utils.ts +893 -0
  429. package/src/clis/ones/common.ts +187 -0
  430. package/src/clis/ones/enrich-tasks.ts +47 -0
  431. package/src/clis/ones/login.ts +103 -0
  432. package/src/clis/ones/logout.ts +19 -0
  433. package/src/clis/ones/me.ts +34 -0
  434. package/src/clis/ones/my-tasks.ts +148 -0
  435. package/src/clis/ones/resolve-labels.ts +80 -0
  436. package/src/clis/ones/task-helpers.test.ts +14 -0
  437. package/src/clis/ones/task-helpers.ts +214 -0
  438. package/src/clis/ones/task.ts +79 -0
  439. package/src/clis/ones/tasks.ts +92 -0
  440. package/src/clis/ones/token-info.ts +46 -0
  441. package/src/clis/ones/worklog.test.ts +24 -0
  442. package/src/clis/ones/worklog.ts +306 -0
  443. package/src/clis/spotify/spotify.ts +328 -0
  444. package/src/clis/spotify/utils.test.ts +87 -0
  445. package/src/clis/spotify/utils.ts +92 -0
  446. package/src/clis/substack/utils.test.ts +54 -0
  447. package/src/clis/substack/utils.ts +10 -2
  448. package/src/clis/tieba/commands.test.ts +86 -0
  449. package/src/clis/tieba/hot.ts +52 -0
  450. package/src/clis/tieba/posts.ts +108 -0
  451. package/src/clis/tieba/read.ts +158 -0
  452. package/src/clis/tieba/search.ts +119 -0
  453. package/src/clis/tieba/utils.test.ts +322 -0
  454. package/src/clis/tieba/utils.ts +348 -0
  455. package/src/clis/v2ex/hot.yaml +4 -1
  456. package/src/clis/v2ex/latest.yaml +4 -1
  457. package/src/clis/v2ex/topic.yaml +6 -1
  458. package/src/clis/weixin/download.ts +95 -6
  459. package/src/clis/weread/book.ts +256 -13
  460. package/src/clis/weread/commands.test.ts +409 -0
  461. package/src/{weread-private-api-regression.test.ts → clis/weread/private-api-regression.test.ts} +108 -30
  462. package/src/clis/weread/search-regression.test.ts +440 -0
  463. package/src/clis/weread/search.ts +189 -9
  464. package/src/clis/weread/shelf.ts +20 -122
  465. package/src/clis/weread/utils.test.ts +81 -1
  466. package/src/clis/weread/utils.ts +293 -7
  467. package/src/clis/xiaohongshu/comments.test.ts +85 -9
  468. package/src/clis/xiaohongshu/comments.ts +76 -17
  469. package/src/clis/xiaohongshu/download.test.ts +96 -0
  470. package/src/clis/xiaohongshu/download.ts +83 -22
  471. package/src/clis/xiaohongshu/note-helpers.ts +25 -0
  472. package/src/clis/xiaohongshu/note.test.ts +164 -0
  473. package/src/clis/xiaohongshu/note.ts +86 -0
  474. package/src/clis/xiaohongshu/publish.test.ts +79 -1
  475. package/src/clis/xiaohongshu/publish.ts +84 -30
  476. package/src/clis/xiaohongshu/search.test.ts +11 -4
  477. package/src/clis/xiaohongshu/search.ts +13 -0
  478. package/src/clis/xiaohongshu/user-helpers.test.ts +23 -0
  479. package/src/clis/xiaohongshu/user-helpers.ts +4 -0
  480. package/src/clis/xueqiu/comments.test.ts +823 -0
  481. package/src/clis/xueqiu/comments.ts +461 -0
  482. package/src/clis/youtube/search.ts +57 -17
  483. package/src/clis/youtube/transcript.ts +2 -4
  484. package/src/clis/youtube/utils.test.ts +43 -0
  485. package/src/clis/youtube/utils.ts +69 -0
  486. package/src/clis/youtube/video.ts +16 -15
  487. package/src/clis/zhihu/question.test.ts +71 -0
  488. package/src/clis/zhihu/question.ts +27 -15
  489. package/src/clis/zsxq/dynamics.ts +60 -0
  490. package/src/clis/zsxq/groups.ts +41 -0
  491. package/src/clis/zsxq/search.test.ts +29 -0
  492. package/src/clis/zsxq/search.ts +54 -0
  493. package/src/clis/zsxq/topic.test.ts +34 -0
  494. package/src/clis/zsxq/topic.ts +68 -0
  495. package/src/clis/zsxq/topics.test.ts +29 -0
  496. package/src/clis/zsxq/topics.ts +36 -0
  497. package/src/clis/zsxq/utils.ts +351 -0
  498. package/src/commanderAdapter.test.ts +77 -0
  499. package/src/commanderAdapter.ts +8 -1
  500. package/src/commands/daemon.test.ts +238 -0
  501. package/src/commands/daemon.ts +135 -0
  502. package/src/completion.ts +2 -1
  503. package/src/constants.ts +3 -0
  504. package/src/daemon.test.ts +88 -0
  505. package/src/daemon.ts +26 -14
  506. package/src/discovery.ts +52 -2
  507. package/src/electron-apps.test.ts +50 -0
  508. package/src/electron-apps.ts +89 -0
  509. package/src/engine.test.ts +45 -9
  510. package/src/execution.ts +24 -19
  511. package/src/external-clis.yaml +17 -0
  512. package/src/idle-manager.ts +60 -0
  513. package/src/launcher.test.ts +67 -0
  514. package/src/launcher.ts +185 -0
  515. package/src/main.ts +3 -2
  516. package/src/registry.test.ts +15 -0
  517. package/src/registry.ts +32 -3
  518. package/src/runtime.ts +13 -7
  519. package/src/serialization.test.ts +19 -1
  520. package/src/serialization.ts +2 -0
  521. package/src/tui.test.ts +23 -0
  522. package/src/tui.ts +65 -0
  523. package/src/types.ts +5 -0
  524. package/src/weixin-download.test.ts +27 -0
  525. package/tests/e2e/band-auth.test.ts +20 -0
  526. package/tests/e2e/browser-auth-helpers.ts +18 -0
  527. package/tests/e2e/browser-auth.test.ts +35 -47
  528. package/tests/e2e/browser-public-extended.test.ts +6 -2
  529. package/tests/e2e/browser-public.test.ts +288 -0
  530. package/tests/e2e/management.test.ts +1 -1
  531. package/tests/e2e/plugin-management.test.ts +1 -1
  532. package/vitest.config.ts +1 -0
  533. package/chatwise-opencli.ps1 +0 -82
  534. package/dist/clis/chatwise/shared.d.ts +0 -2
  535. package/dist/clis/chatwise/shared.js +0 -6
  536. package/dist/weread-private-api-regression.test.d.ts +0 -1
  537. package/dist/weread-search-regression.test.d.ts +0 -1
  538. package/dist/weread-search-regression.test.js +0 -39
  539. package/src/clis/chatwise/shared.ts +0 -8
  540. package/src/weread-search-regression.test.ts +0 -44
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.5.7](https://github.com/jackwener/opencli/compare/v1.5.6...v1.5.7) (2026-04-01)
4
+
5
+
6
+ ### Features
7
+
8
+ * **daemon:** replace 5min idle timeout with long-lived daemon model (4h default, dual-condition exit) ([#641](https://github.com/jackwener/opencli/issues/641))
9
+ * **daemon:** add `opencli daemon status/stop/restart` CLI commands ([#641](https://github.com/jackwener/opencli/issues/641))
10
+ * **youtube:** add search filters — `--type` shorts/video/channel, `--upload`, `--sort` ([#616](https://github.com/jackwener/opencli/issues/616))
11
+ * **notebooklm:** add read commands and compatibility layer ([#622](https://github.com/jackwener/opencli/issues/622))
12
+ * **instagram:** add media download command ([#623](https://github.com/jackwener/opencli/issues/623))
13
+ * **stealth:** harden CDP debugger detection countermeasures ([#644](https://github.com/jackwener/opencli/issues/644))
14
+ * **v2ex:** add id, node, url, content, member fields to topic output ([#646](https://github.com/jackwener/opencli/issues/646), [#648](https://github.com/jackwener/opencli/issues/648))
15
+ * **electron:** auto-launcher — zero-config CDP connection ([#653](https://github.com/jackwener/opencli/issues/653))
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * **douyin:** repair creator draft flow — switch from broken API pipeline to UI-driven approach ([#640](https://github.com/jackwener/opencli/issues/640))
21
+ * **douyin:** support current creator API response shapes for activities, profile, collections, hashtag, videos ([#618](https://github.com/jackwener/opencli/issues/618))
22
+ * **bilibili:** distinguish login-gated subtitles from empty results ([#645](https://github.com/jackwener/opencli/issues/645))
23
+ * **facebook:** avoid in-page redirect in search — use navigate step instead of window.location.href ([#642](https://github.com/jackwener/opencli/issues/642))
24
+ * **substack:** update selectors for DOM redesign ([#624](https://github.com/jackwener/opencli/issues/624))
25
+ * **weread:** recover book details from cached shelf fallback ([#628](https://github.com/jackwener/opencli/issues/628))
26
+ * **docs:** use relative links in adapter index ([#629](https://github.com/jackwener/opencli/issues/629))
27
+
28
+
3
29
  ## [1.4.1](https://github.com/jackwener/opencli/compare/v1.4.0...v1.4.1) (2026-03-25)
4
30
 
5
31
 
package/README.md CHANGED
@@ -72,7 +72,8 @@ npm install -g @jackwener/opencli
72
72
  ### 3. Verify & Try
73
73
 
74
74
  ```bash
75
- opencli doctor # Check extension + daemon connectivity
75
+ opencli doctor # Check extension + daemon connectivity
76
+ opencli daemon status # Check daemon state (PID, uptime, memory)
76
77
  ```
77
78
 
78
79
  **Try it out:**
@@ -117,12 +118,15 @@ git clone git@github.com:jackwener/opencli.git && cd opencli && npm install && n
117
118
 
118
119
  | Site | Commands |
119
120
  |------|----------|
120
- | **xiaohongshu** | `search` `feed` `user` `download` `publish` `comments` `notifications` `creator-notes` `creator-notes-summary` `creator-note-detail` `creator-profile` `creator-stats` |
121
+ | **xiaohongshu** | `search` `note` `comments` `feed` `user` `download` `publish` `notifications` `creator-notes` `creator-notes-summary` `creator-note-detail` `creator-profile` `creator-stats` |
121
122
  | **bilibili** | `hot` `search` `history` `feed` `ranking` `download` `comments` `dynamic` `favorite` `following` `me` `subtitle` `user-videos` |
123
+ | **tieba** | `hot` `posts` `search` `read` |
122
124
  | **twitter** | `trending` `search` `timeline` `bookmarks` `post` `download` `profile` `article` `like` `likes` `notifications` `reply` `reply-dm` `thread` `follow` `unfollow` `followers` `following` `block` `unblock` `bookmark` `unbookmark` `delete` `hide-reply` `accept` |
123
125
  | **reddit** | `hot` `frontpage` `popular` `search` `subreddit` `user` `user-posts` `user-comments` `read` `save` `saved` `subscribe` `upvote` `upvoted` `comment` |
126
+ | **notebooklm** | `status` `list` `current` `get` `metadata` `bind-current` `use` `source-list` `source-get` `source-fulltext` `source-guide` `history` `note-list` `notes-list` `notes-get` `summary` |
127
+ | **spotify** | `auth` `status` `play` `pause` `next` `prev` `volume` `search` `queue` `shuffle` `repeat` |
124
128
 
125
- 65+ adapters in total — **[→ see all supported sites & commands](./docs/adapters/index.md)**
129
+ 66+ adapters in total — **[→ see all supported sites & commands](./docs/adapters/index.md)**
126
130
 
127
131
  ## CLI Hub
128
132
 
@@ -133,8 +137,9 @@ OpenCLI acts as a universal hub for your existing command-line tools — unified
133
137
  | **gh** | GitHub CLI | `opencli gh pr list --limit 5` |
134
138
  | **obsidian** | Obsidian vault management | `opencli obsidian search query="AI"` |
135
139
  | **docker** | Docker | `opencli docker ps` |
136
- | **gws** | Google Workspace CLI | `opencli gws docs list` |
137
140
  | **lark-cli** | Lark/Feishu — messages, docs, calendar, tasks, 200+ commands | `opencli lark-cli calendar +agenda` |
141
+ | **dingtalk** | DingTalk — cross-platform CLI for DingTalk's full suite, designed for humans and AI agents | `opencli dingtalk msg send --to user "hello"` |
142
+ | **wecom** | WeCom/企业微信 — CLI for WeCom open platform, for humans and AI agents | `opencli wecom msg send --to user "hello"` |
138
143
  | **vercel** | Vercel — deploy projects, manage domains, env vars, logs | `opencli vercel deploy --prod` |
139
144
 
140
145
  **Register your own** — add any local CLI so AI agents can discover it via `opencli list`:
@@ -192,6 +197,28 @@ opencli bilibili hot -f csv # Spreadsheet-friendly
192
197
  opencli bilibili hot -v # Verbose: show pipeline debug steps
193
198
  ```
194
199
 
200
+ ## Exit Codes
201
+
202
+ opencli follows Unix `sysexits.h` conventions so it integrates naturally with shell pipelines and CI scripts:
203
+
204
+ | Code | Meaning | When |
205
+ |------|---------|------|
206
+ | `0` | Success | Command completed normally |
207
+ | `1` | Generic error | Unexpected / unclassified failure |
208
+ | `2` | Usage error | Bad arguments or unknown command |
209
+ | `66` | Empty result | No data returned (`EX_NOINPUT`) |
210
+ | `69` | Service unavailable | Browser Bridge not connected (`EX_UNAVAILABLE`) |
211
+ | `75` | Temporary failure | Command timed out — retry (`EX_TEMPFAIL`) |
212
+ | `77` | Auth required | Not logged in to target site (`EX_NOPERM`) |
213
+ | `78` | Config error | Missing credentials or bad config (`EX_CONFIG`) |
214
+ | `130` | Interrupted | Ctrl-C / SIGINT |
215
+
216
+ ```bash
217
+ opencli spotify status || echo "exit $?" # 69 if browser not running
218
+ opencli github issues 2>/dev/null
219
+ [ $? -eq 77 ] && opencli github auth # auto-auth if not logged in
220
+ ```
221
+
195
222
  ## Plugins
196
223
 
197
224
  Extend OpenCLI with community-contributed adapters:
package/README.zh-CN.md CHANGED
@@ -73,9 +73,11 @@ OpenCLI 通过轻量化的 **Browser Bridge** Chrome 扩展 + 微型 daemon 与
73
73
 
74
74
  完成!运行任何 opencli 浏览器命令时,后台微型 daemon 会自动启动与浏览器通信。无需配 API Token,零代码配置。
75
75
 
76
- > **Tip**:后续诊断用 `opencli doctor`:
76
+ > **Tip**:后续诊断和 daemon 管理:
77
77
  > ```bash
78
78
  > opencli doctor # 检查扩展和 daemon 连通性
79
+ > opencli daemon status # 查看 daemon 状态
80
+ > opencli daemon stop # 停止 daemon
79
81
  > ```
80
82
 
81
83
  ## 快速开始
@@ -122,16 +124,17 @@ npm install -g @jackwener/opencli@latest
122
124
  |------|------|------|
123
125
  | **twitter** | `trending` `bookmarks` `profile` `search` `timeline` `thread` `following` `followers` `notifications` `post` `reply` `delete` `like` `article` `follow` `unfollow` `bookmark` `unbookmark` `download` `accept` `reply-dm` `block` `unblock` `hide-reply` | 浏览器 |
124
126
  | **reddit** | `hot` `frontpage` `popular` `search` `subreddit` `read` `user` `user-posts` `user-comments` `upvote` `save` `comment` `subscribe` `saved` `upvoted` | 浏览器 |
127
+ | **tieba** | `hot` `posts` `search` `read` | 浏览器 |
125
128
  | **cursor** | `status` `send` `read` `new` `dump` `composer` `model` `extract-code` `ask` `screenshot` `history` `export` | 桌面端 |
126
129
  | **bilibili** | `hot` `search` `me` `favorite` `history` `feed` `subtitle` `dynamic` `ranking` `following` `user-videos` `download` | 浏览器 |
127
130
  | **codex** | `status` `send` `read` `new` `dump` `extract-diff` `model` `ask` `screenshot` `history` `export` | 桌面端 |
128
131
  | **chatwise** | `status` `new` `send` `read` `ask` `model` `history` `export` `screenshot` | 桌面端 |
129
- | **doubao** | `status` `new` `send` `read` `ask` | 浏览器 |
132
+ | **doubao** | `status` `new` `send` `read` `ask` `history` `detail` `meeting-summary` `meeting-transcript` | 浏览器 |
130
133
  | **doubao-app** | `status` `new` `send` `read` `ask` `screenshot` `dump` | 桌面端 |
131
134
  | **notion** | `status` `search` `read` `new` `write` `sidebar` `favorites` `export` | 桌面端 |
132
135
  | **discord-app** | `status` `send` `read` `channels` `servers` `search` `members` | 桌面端 |
133
136
  | **v2ex** | `hot` `latest` `topic` `node` `user` `member` `replies` `nodes` `daily` `me` `notifications` | 公开 / 浏览器 |
134
- | **xueqiu** | `feed` `hot-stock` `hot` `search` `stock` `watchlist` `earnings-date` `fund-holdings` `fund-snapshot` | 浏览器 |
137
+ | **xueqiu** | `feed` `hot-stock` `hot` `search` `stock` `comments` `watchlist` `earnings-date` `fund-holdings` `fund-snapshot` | 浏览器 |
135
138
  | **antigravity** | `status` `send` `read` `new` `dump` `extract-code` `model` `watch` | 桌面端 |
136
139
  | **chatgpt** | `status` `new` `send` `read` `ask` `model` | 桌面端 |
137
140
  | **xiaohongshu** | `search` `notifications` `feed` `user` `download` `publish` `creator-notes` `creator-note-detail` `creator-notes-summary` `creator-profile` `creator-stats` | 浏览器 |
@@ -173,6 +176,8 @@ npm install -g @jackwener/opencli@latest
173
176
  | **douban** | `search` `top250` `subject` `photos` `download` `marks` `reviews` `movie-hot` `book-hot` | 浏览器 |
174
177
  | **facebook** | `feed` `profile` `search` `friends` `groups` `events` `notifications` `memories` `add-friend` `join-group` | 浏览器 |
175
178
  | **google** | `news` `search` `suggest` `trends` | 公开 |
179
+ | **spotify** | `auth` `status` `play` `pause` `next` `prev` `volume` `search` `queue` `shuffle` `repeat` | OAuth API |
180
+ | **notebooklm** | `status` `list` `current` `get` `metadata` `bind-current` `use` `source-list` `source-get` `source-fulltext` `source-guide` `history` `note-list` `notes-list` `notes-get` `summary` | 浏览器 |
176
181
  | **36kr** | `news` `hot` `search` `article` | 公开 / 浏览器 |
177
182
  | **imdb** | `search` `title` `top` `trending` `person` `reviews` | 公开 |
178
183
  | **producthunt** | `posts` `today` `hot` `browse` | 公开 / 浏览器 |
@@ -183,7 +188,10 @@ npm install -g @jackwener/opencli@latest
183
188
  | **substack** | `feed` `search` `publication` | 浏览器 |
184
189
  | **pixiv** | `ranking` `search` `user` `illusts` `detail` `download` | 浏览器 |
185
190
  | **tiktok** | `explore` `search` `profile` `user` `following` `follow` `unfollow` `like` `unlike` `comment` `save` `unsave` `live` `notifications` `friends` | 浏览器 |
191
+ | **bluesky** | `search` `trending` `user` `profile` `thread` `feeds` `followers` `following` `starter-packs` | 公开 |
192
+ | **douyin** | `videos` `publish` `drafts` `draft` `delete` `stats` `profile` `update` `hashtag` `location` `activities` `collections` | 浏览器 |
186
193
 
194
+ 66+ 适配器 — **[→ 查看完整命令列表](./docs/adapters/index.md)**
187
195
 
188
196
  ### 外部 CLI 枢纽
189
197
 
@@ -194,8 +202,10 @@ OpenCLI 也可以作为你现有命令行工具的统一入口,负责发现、
194
202
  | **gh** | GitHub CLI | `opencli gh pr list --limit 5` |
195
203
  | **obsidian** | Obsidian 仓库管理 | `opencli obsidian search query="AI"` |
196
204
  | **docker** | Docker 命令行工具 | `opencli docker ps` |
197
- | **readwise** | Readwise / Reader CLI | `opencli readwise login` |
198
- | **gws** | Google Workspace CLI — Docs, Sheets, Drive, Gmail, Calendar | `opencli gws docs list` |
205
+ | **lark-cli** | 飞书 CLI 消息、文档、日历、任务,200+ 命令 | `opencli lark-cli calendar +agenda` |
206
+ | **dingtalk** | 钉钉 CLI — 钉钉全套产品能力的跨平台命令行工具,支持人类和 AI Agent 使用 | `opencli dingtalk msg send --to user "hello"` |
207
+ | **wecom** | 企业微信 CLI — 企业微信开放平台命令行工具,支持人类和 AI Agent 使用 | `opencli wecom msg send --to user "hello"` |
208
+ | **vercel** | Vercel — 部署项目、管理域名、环境变量、日志 | `opencli vercel deploy --prod` |
199
209
 
200
210
  **零配置透传**:OpenCLI 会把你的输入原样转发给底层二进制,保留原生 stdout / stderr 行为。
201
211
 
@@ -295,6 +305,31 @@ opencli bilibili hot -f csv # CSV
295
305
  opencli bilibili hot -v # 详细模式:展示管线执行步骤调试信息
296
306
  ```
297
307
 
308
+ ## 退出码
309
+
310
+ opencli 遵循 Unix `sysexits.h` 惯例,可无缝接入 shell 管道和 CI 脚本:
311
+
312
+ | 退出码 | 含义 | 触发场景 |
313
+ |--------|------|----------|
314
+ | `0` | 成功 | 命令正常完成 |
315
+ | `1` | 通用错误 | 未分类的意外错误 |
316
+ | `2` | 用法错误 | 参数错误或未知命令 |
317
+ | `66` | 无数据 | 命令返回空结果(`EX_NOINPUT`) |
318
+ | `69` | 服务不可用 | Browser Bridge 未连接(`EX_UNAVAILABLE`) |
319
+ | `75` | 临时失败 | 命令超时,可重试(`EX_TEMPFAIL`) |
320
+ | `77` | 需要认证 | 未登录目标网站(`EX_NOPERM`) |
321
+ | `78` | 配置错误 | 凭证缺失或配置有误(`EX_CONFIG`) |
322
+ | `130` | 中断 | Ctrl-C / SIGINT |
323
+
324
+ ```bash
325
+ opencli bilibili hot 2>/dev/null
326
+ case $? in
327
+ 0) echo "ok" ;;
328
+ 69) echo "请先启动 Browser Bridge" ;;
329
+ 77) echo "请先登录 bilibili.com" ;;
330
+ esac
331
+ ```
332
+
298
333
  ## 插件
299
334
 
300
335
  通过社区贡献的插件扩展 OpenCLI。插件使用与内置命令相同的 YAML/TS 格式,启动时自动发现。
package/SKILL.md CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: opencli
3
3
  description: "OpenCLI — Make any website or Electron App your CLI. Zero risk, AI-powered, reuse Chrome login."
4
- version: 1.4.1
4
+ version: 1.5.6
5
5
  author: jackwener
6
6
  tags: [cli, browser, web, chrome-extension, cdp, bilibili, zhihu, twitter, github, v2ex, hackernews, reddit, xiaohongshu, xueqiu, youtube, boss, coupang, yollomi, AI, agent]
7
7
  ---
@@ -23,6 +23,7 @@ export declare class CDPBridge implements IBrowserFactory {
23
23
  connect(opts?: {
24
24
  timeout?: number;
25
25
  workspace?: string;
26
+ cdpEndpoint?: string;
26
27
  }): Promise<IPage>;
27
28
  close(): Promise<void>;
28
29
  send(method: string, params?: Record<string, unknown>, timeoutMs?: number): Promise<unknown>;
@@ -15,6 +15,7 @@ import { generateSnapshotJs, scrollToRefJs, getFormStateJs } from './dom-snapsho
15
15
  import { generateStealthJs } from './stealth.js';
16
16
  import { clickJs, typeTextJs, pressKeyJs, waitForTextJs, scrollJs, autoScrollJs, networkRequestsJs, waitForDomStableJs, waitForCaptureJs, waitForSelectorJs, } from './dom-helpers.js';
17
17
  import { isRecord, saveBase64ToFile } from '../utils.js';
18
+ import { getAllElectronApps } from '../electron-apps.js';
18
19
  const CDP_SEND_TIMEOUT = 30_000;
19
20
  export class CDPBridge {
20
21
  _ws = null;
@@ -24,9 +25,9 @@ export class CDPBridge {
24
25
  async connect(opts) {
25
26
  if (this._ws)
26
27
  throw new Error('CDPBridge is already connected. Call close() before reconnecting.');
27
- const endpoint = process.env.OPENCLI_CDP_ENDPOINT;
28
+ const endpoint = opts?.cdpEndpoint ?? process.env.OPENCLI_CDP_ENDPOINT;
28
29
  if (!endpoint)
29
- throw new Error('OPENCLI_CDP_ENDPOINT is not set');
30
+ throw new Error('CDP endpoint not provided (pass cdpEndpoint or set OPENCLI_CDP_ENDPOINT)');
30
31
  let wsUrl = endpoint;
31
32
  if (endpoint.startsWith('http')) {
32
33
  const targets = await fetchJsonDirect(`${endpoint.replace(/\/$/, '')}/json`);
@@ -269,7 +270,19 @@ class CDPPage {
269
270
  return [];
270
271
  }
271
272
  async getCurrentUrl() {
272
- return this._lastUrl;
273
+ if (this._lastUrl)
274
+ return this._lastUrl;
275
+ try {
276
+ const current = await this.evaluate('window.location.href');
277
+ if (typeof current === 'string' && current) {
278
+ this._lastUrl = current;
279
+ return current;
280
+ }
281
+ }
282
+ catch {
283
+ // Best-effort: direct CDP sessions may not have a ready page yet.
284
+ }
285
+ return null;
273
286
  }
274
287
  async installInterceptor(pattern) {
275
288
  const { generateInterceptorJs } = await import('../interceptor.js');
@@ -346,30 +359,20 @@ function scoreCDPTarget(target, preferredPattern) {
346
359
  score -= 40;
347
360
  if (title && title !== 'devtools')
348
361
  score += 25;
349
- if (title.includes('antigravity'))
350
- score += 120;
351
- if (title.includes('codex'))
352
- score += 120;
353
- if (title.includes('cursor'))
354
- score += 120;
355
- if (title.includes('chatwise'))
356
- score += 120;
357
- if (title.includes('notion'))
358
- score += 120;
359
- if (title.includes('discord'))
360
- score += 120;
361
- if (url.includes('antigravity'))
362
- score += 100;
363
- if (url.includes('codex'))
364
- score += 100;
365
- if (url.includes('cursor'))
366
- score += 100;
367
- if (url.includes('chatwise'))
368
- score += 100;
369
- if (url.includes('notion'))
370
- score += 100;
371
- if (url.includes('discord'))
372
- score += 100;
362
+ // Boost score for known Electron app names from the registry (builtin + user-defined)
363
+ const appNames = Object.values(getAllElectronApps()).map(a => (a.displayName ?? a.processName).toLowerCase());
364
+ for (const name of appNames) {
365
+ if (title.includes(name)) {
366
+ score += 120;
367
+ break;
368
+ }
369
+ }
370
+ for (const name of appNames) {
371
+ if (url.includes(name)) {
372
+ score += 100;
373
+ break;
374
+ }
375
+ }
373
376
  return score;
374
377
  }
375
378
  function compilePreferredPattern(raw) {
@@ -6,7 +6,7 @@
6
6
  import type { BrowserSessionInfo } from '../types.js';
7
7
  export interface DaemonCommand {
8
8
  id: string;
9
- action: 'exec' | 'navigate' | 'tabs' | 'cookies' | 'screenshot' | 'close-window' | 'sessions';
9
+ action: 'exec' | 'navigate' | 'tabs' | 'cookies' | 'screenshot' | 'close-window' | 'sessions' | 'set-file-input' | 'bind-current';
10
10
  tabId?: number;
11
11
  code?: string;
12
12
  workspace?: string;
@@ -14,9 +14,15 @@ export interface DaemonCommand {
14
14
  op?: string;
15
15
  index?: number;
16
16
  domain?: string;
17
+ matchDomain?: string;
18
+ matchPathPrefix?: string;
17
19
  format?: 'png' | 'jpeg';
18
20
  quality?: number;
19
21
  fullPage?: boolean;
22
+ /** Local file paths for set-file-input action */
23
+ files?: string[];
24
+ /** CSS selector for file input element (set-file-input action) */
25
+ selector?: string;
20
26
  }
21
27
  export interface DaemonResult {
22
28
  id: string;
@@ -39,3 +45,7 @@ export declare function isExtensionConnected(): Promise<boolean>;
39
45
  */
40
46
  export declare function sendCommand(action: DaemonCommand['action'], params?: Omit<DaemonCommand, 'id' | 'action'>): Promise<unknown>;
41
47
  export declare function listSessions(): Promise<BrowserSessionInfo[]>;
48
+ export declare function bindCurrentTab(workspace: string, opts?: {
49
+ matchDomain?: string;
50
+ matchPathPrefix?: string;
51
+ }): Promise<unknown>;
@@ -105,3 +105,6 @@ export async function listSessions() {
105
105
  const result = await sendCommand('sessions');
106
106
  return Array.isArray(result) ? result : [];
107
107
  }
108
+ export async function bindCurrentTab(workspace, opts = {}) {
109
+ return sendCommand('bind-current', { workspace, ...opts });
110
+ }
@@ -103,6 +103,7 @@ export function scrollJs(direction, amount) {
103
103
  export function autoScrollJs(times, delayMs) {
104
104
  return `
105
105
  (async () => {
106
+ if (!document.body) return;
106
107
  for (let i = 0; i < ${times}; i++) {
107
108
  const lastHeight = document.body.scrollHeight;
108
109
  window.scrollTo(0, lastHeight);
@@ -1,5 +1,18 @@
1
1
  import { describe, it, expect } from 'vitest';
2
- import { waitForCaptureJs, waitForSelectorJs } from './dom-helpers.js';
2
+ import { autoScrollJs, waitForCaptureJs, waitForSelectorJs } from './dom-helpers.js';
3
+ describe('autoScrollJs', () => {
4
+ it('returns early without error when document.body is null', async () => {
5
+ const g = globalThis;
6
+ const origDoc = g.document;
7
+ g.document = { body: null, documentElement: {} };
8
+ g.window = g;
9
+ const code = autoScrollJs(3, 500);
10
+ // Should resolve without throwing
11
+ await expect(eval(code)).resolves.not.toThrow();
12
+ g.document = origDoc;
13
+ delete g.window;
14
+ });
15
+ });
3
16
  describe('waitForCaptureJs', () => {
4
17
  it('returns a non-empty string', () => {
5
18
  const code = waitForCaptureJs(1000);
@@ -50,29 +50,36 @@ export class BrowserBridge {
50
50
  this._state = 'closed';
51
51
  }
52
52
  async _ensureDaemon(timeoutSeconds) {
53
- // Use default if not provided, zero, or negative
54
53
  const effectiveSeconds = (timeoutSeconds && timeoutSeconds > 0) ? timeoutSeconds : Math.ceil(DAEMON_SPAWN_TIMEOUT / 1000);
55
54
  const timeoutMs = effectiveSeconds * 1000;
55
+ // Fast path: extension already connected
56
56
  if (await isExtensionConnected())
57
57
  return;
58
+ // Daemon running but no extension — wait for extension with progress
58
59
  if (await isDaemonRunning()) {
60
+ if (process.env.OPENCLI_VERBOSE || process.stderr.isTTY) {
61
+ process.stderr.write('⏳ Waiting for Chrome extension to connect...\n');
62
+ process.stderr.write(' Make sure Chrome is open and the OpenCLI extension is enabled.\n');
63
+ }
64
+ const deadline = Date.now() + timeoutMs;
65
+ while (Date.now() < deadline) {
66
+ await new Promise(resolve => setTimeout(resolve, 200));
67
+ if (await isExtensionConnected())
68
+ return;
69
+ }
59
70
  throw new Error('Daemon is running but the Browser Extension is not connected.\n' +
60
71
  'Please install and enable the opencli Browser Bridge extension in Chrome.');
61
72
  }
62
- // Find daemon relative to this file works for both:
63
- // npx tsx src/main.ts → src/browser/mcp.ts → src/daemon.ts
64
- // node dist/main.js → dist/browser/mcp.js → dist/daemon.js
73
+ // No daemon — spawn one
65
74
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
66
75
  const parentDir = path.resolve(__dirname, '..');
67
76
  const daemonTs = path.join(parentDir, 'daemon.ts');
68
77
  const daemonJs = path.join(parentDir, 'daemon.js');
69
78
  const isTs = fs.existsSync(daemonTs);
70
79
  const daemonPath = isTs ? daemonTs : daemonJs;
71
- if (process.env.OPENCLI_VERBOSE) {
72
- console.error(`[opencli] Starting daemon (${isTs ? 'ts' : 'js'})...`);
80
+ if (process.env.OPENCLI_VERBOSE || process.stderr.isTTY) {
81
+ process.stderr.write('⏳ Starting daemon...\n');
73
82
  }
74
- // For compiled .js, use the current node binary directly (fast).
75
- // For .ts dev mode, node can't run .ts files — use tsx via --import.
76
83
  const spawnArgs = isTs
77
84
  ? [process.execPath, '--import', 'tsx/esm', daemonPath]
78
85
  : [process.execPath, daemonPath];
@@ -82,15 +89,13 @@ export class BrowserBridge {
82
89
  env: { ...process.env },
83
90
  });
84
91
  this._daemonProc.unref();
85
- // Wait for daemon to be ready AND extension to connect (exponential backoff)
86
- const backoffs = [50, 100, 200, 400, 800, 1500, 3000];
92
+ // Wait for daemon + extension with faster polling
87
93
  const deadline = Date.now() + timeoutMs;
88
- for (let i = 0; Date.now() < deadline; i++) {
89
- await new Promise(resolve => setTimeout(resolve, backoffs[Math.min(i, backoffs.length - 1)]));
94
+ while (Date.now() < deadline) {
95
+ await new Promise(resolve => setTimeout(resolve, 200));
90
96
  if (await isExtensionConnected())
91
97
  return;
92
98
  }
93
- // Daemon might be up but extension not connected — give a useful error
94
99
  if (await isDaemonRunning()) {
95
100
  throw new Error('Daemon is running but the Browser Extension is not connected.\n' +
96
101
  'Please install and enable the opencli Browser Bridge extension in Chrome.');
@@ -72,5 +72,11 @@ export declare class Page implements IPage {
72
72
  }): Promise<void>;
73
73
  installInterceptor(pattern: string): Promise<void>;
74
74
  getInterceptedRequests(): Promise<unknown[]>;
75
+ /**
76
+ * Set local file paths on a file input element via CDP DOM.setFileInputFiles.
77
+ * Chrome reads the files directly from the local filesystem, avoiding the
78
+ * payload size limits of base64-in-evaluate.
79
+ */
80
+ setFileInput(files: string[], selector?: string): Promise<void>;
75
81
  waitForCapture(timeout?: number): Promise<void>;
76
82
  }
@@ -96,7 +96,19 @@ export class Page {
96
96
  }
97
97
  }
98
98
  async getCurrentUrl() {
99
- return this._lastUrl;
99
+ if (this._lastUrl)
100
+ return this._lastUrl;
101
+ try {
102
+ const current = await this.evaluate('window.location.href');
103
+ if (typeof current === 'string' && current) {
104
+ this._lastUrl = current;
105
+ return current;
106
+ }
107
+ }
108
+ catch {
109
+ // Best-effort: some commands may run before a debuggable tab is ready.
110
+ }
111
+ return null;
100
112
  }
101
113
  /** Close the automation window in the extension */
102
114
  async closeWindow() {
@@ -109,7 +121,15 @@ export class Page {
109
121
  }
110
122
  async evaluate(js) {
111
123
  const code = wrapForEval(js);
112
- return sendCommand('exec', { code, ...this._cmdOpts() });
124
+ try {
125
+ return await sendCommand('exec', { code, ...this._cmdOpts() });
126
+ }
127
+ catch (err) {
128
+ if (!isRetryableSettleError(err))
129
+ throw err;
130
+ await new Promise((resolve) => setTimeout(resolve, 200));
131
+ return sendCommand('exec', { code, ...this._cmdOpts() });
132
+ }
113
133
  }
114
134
  async getCookies(opts = {}) {
115
135
  const result = await sendCommand('cookies', { ...this._wsOpt(), ...opts });
@@ -308,6 +328,21 @@ export class Page {
308
328
  const result = await this.evaluate(generateReadInterceptedJs('__opencli_xhr'));
309
329
  return Array.isArray(result) ? result : [];
310
330
  }
331
+ /**
332
+ * Set local file paths on a file input element via CDP DOM.setFileInputFiles.
333
+ * Chrome reads the files directly from the local filesystem, avoiding the
334
+ * payload size limits of base64-in-evaluate.
335
+ */
336
+ async setFileInput(files, selector) {
337
+ const result = await sendCommand('set-file-input', {
338
+ files,
339
+ selector,
340
+ ...this._cmdOpts(),
341
+ });
342
+ if (!result?.count) {
343
+ throw new Error('setFileInput returned no count — command may not be supported by the extension');
344
+ }
345
+ }
311
346
  async waitForCapture(timeout = 10) {
312
347
  const maxMs = timeout * 1000;
313
348
  await sendCommand('exec', {
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,44 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
2
+ const { sendCommandMock } = vi.hoisted(() => ({
3
+ sendCommandMock: vi.fn(),
4
+ }));
5
+ vi.mock('./daemon-client.js', () => ({
6
+ sendCommand: sendCommandMock,
7
+ }));
8
+ import { Page } from './page.js';
9
+ describe('Page.getCurrentUrl', () => {
10
+ beforeEach(() => {
11
+ sendCommandMock.mockReset();
12
+ });
13
+ it('reads the real browser URL when no local navigation cache exists', async () => {
14
+ sendCommandMock.mockResolvedValueOnce('https://notebooklm.google.com/notebook/nb-live');
15
+ const page = new Page('site:notebooklm');
16
+ const url = await page.getCurrentUrl();
17
+ expect(url).toBe('https://notebooklm.google.com/notebook/nb-live');
18
+ expect(sendCommandMock).toHaveBeenCalledTimes(1);
19
+ expect(sendCommandMock).toHaveBeenCalledWith('exec', expect.objectContaining({
20
+ workspace: 'site:notebooklm',
21
+ }));
22
+ });
23
+ it('caches the discovered browser URL for later reads', async () => {
24
+ sendCommandMock.mockResolvedValueOnce('https://notebooklm.google.com/notebook/nb-live');
25
+ const page = new Page('site:notebooklm');
26
+ expect(await page.getCurrentUrl()).toBe('https://notebooklm.google.com/notebook/nb-live');
27
+ expect(await page.getCurrentUrl()).toBe('https://notebooklm.google.com/notebook/nb-live');
28
+ expect(sendCommandMock).toHaveBeenCalledTimes(1);
29
+ });
30
+ });
31
+ describe('Page.evaluate', () => {
32
+ beforeEach(() => {
33
+ sendCommandMock.mockReset();
34
+ });
35
+ it('retries once when the inspected target navigated during exec', async () => {
36
+ sendCommandMock
37
+ .mockRejectedValueOnce(new Error('{"code":-32000,"message":"Inspected target navigated or closed"}'))
38
+ .mockResolvedValueOnce(42);
39
+ const page = new Page('site:notebooklm');
40
+ const value = await page.evaluate('21 + 21');
41
+ expect(value).toBe(42);
42
+ expect(sendCommandMock).toHaveBeenCalledTimes(2);
43
+ });
44
+ });