@jackwener/opencli 1.5.6 → 1.5.8

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 (338) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +4 -2
  3. package/README.zh-CN.md +4 -1
  4. package/SKILL.md +879 -0
  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 +7 -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.js +22 -2
  13. package/dist/browser/page.test.d.ts +1 -0
  14. package/dist/browser/page.test.js +44 -0
  15. package/dist/browser/stealth.js +198 -0
  16. package/dist/browser/stealth.test.d.ts +1 -0
  17. package/dist/browser/stealth.test.js +134 -0
  18. package/dist/browser.test.js +1 -1
  19. package/dist/build-manifest.d.ts +1 -0
  20. package/dist/build-manifest.js +5 -1
  21. package/dist/build-manifest.test.js +2 -0
  22. package/dist/cli-manifest.json +544 -137
  23. package/dist/cli.js +20 -3
  24. package/dist/clis/antigravity/serve.d.ts +1 -1
  25. package/dist/clis/antigravity/serve.js +5 -8
  26. package/dist/clis/bilibili/subtitle.js +4 -0
  27. package/dist/clis/bilibili/subtitle.test.d.ts +1 -0
  28. package/dist/clis/bilibili/subtitle.test.js +48 -0
  29. package/dist/clis/chatwise/ask.js +0 -2
  30. package/dist/clis/chatwise/export.js +0 -2
  31. package/dist/clis/chatwise/history.js +0 -2
  32. package/dist/clis/chatwise/model.js +0 -2
  33. package/dist/clis/chatwise/new.js +1 -2
  34. package/dist/clis/chatwise/read.js +0 -2
  35. package/dist/clis/chatwise/screenshot.js +1 -2
  36. package/dist/clis/chatwise/send.js +0 -2
  37. package/dist/clis/chatwise/status.js +1 -2
  38. package/dist/clis/ctrip/search.d.ts +13 -0
  39. package/dist/clis/ctrip/search.js +73 -48
  40. package/dist/clis/ctrip/search.test.d.ts +1 -0
  41. package/dist/clis/ctrip/search.test.js +64 -0
  42. package/dist/clis/douyin/_shared/sts2.js +8 -2
  43. package/dist/clis/douyin/_shared/sts2.test.d.ts +1 -0
  44. package/dist/clis/douyin/_shared/sts2.test.js +27 -0
  45. package/dist/clis/douyin/activities.js +4 -2
  46. package/dist/clis/douyin/activities.test.js +34 -1
  47. package/dist/clis/douyin/collections.js +1 -1
  48. package/dist/clis/douyin/collections.test.js +24 -2
  49. package/dist/clis/douyin/draft.d.ts +8 -11
  50. package/dist/clis/douyin/draft.js +302 -185
  51. package/dist/clis/douyin/draft.test.d.ts +1 -1
  52. package/dist/clis/douyin/draft.test.js +357 -2
  53. package/dist/clis/douyin/hashtag.js +9 -2
  54. package/dist/clis/douyin/hashtag.test.js +35 -2
  55. package/dist/clis/douyin/profile.js +1 -1
  56. package/dist/clis/douyin/profile.test.js +36 -1
  57. package/dist/clis/douyin/videos.js +22 -5
  58. package/dist/clis/douyin/videos.test.js +45 -2
  59. package/dist/clis/facebook/search.test.d.ts +5 -0
  60. package/dist/clis/facebook/search.test.js +60 -0
  61. package/dist/clis/facebook/search.yaml +4 -3
  62. package/dist/clis/instagram/download.d.ts +16 -0
  63. package/dist/clis/instagram/download.js +225 -0
  64. package/dist/clis/instagram/download.test.d.ts +1 -0
  65. package/dist/clis/instagram/download.test.js +118 -0
  66. package/dist/clis/notebooklm/bind-current.d.ts +1 -0
  67. package/dist/clis/notebooklm/bind-current.js +29 -0
  68. package/dist/clis/notebooklm/bind-current.test.d.ts +1 -0
  69. package/dist/clis/notebooklm/bind-current.test.js +35 -0
  70. package/dist/clis/notebooklm/binding.test.d.ts +1 -0
  71. package/dist/clis/notebooklm/binding.test.js +44 -0
  72. package/dist/clis/notebooklm/compat.test.d.ts +3 -0
  73. package/dist/clis/notebooklm/compat.test.js +16 -0
  74. package/dist/clis/notebooklm/current.d.ts +1 -0
  75. package/dist/clis/notebooklm/current.js +28 -0
  76. package/dist/clis/notebooklm/get.d.ts +1 -0
  77. package/dist/clis/notebooklm/get.js +37 -0
  78. package/dist/clis/notebooklm/history.d.ts +1 -0
  79. package/dist/clis/notebooklm/history.js +25 -0
  80. package/dist/clis/notebooklm/history.test.d.ts +1 -0
  81. package/dist/clis/notebooklm/history.test.js +58 -0
  82. package/dist/clis/notebooklm/list.d.ts +1 -0
  83. package/dist/clis/notebooklm/list.js +35 -0
  84. package/dist/clis/notebooklm/note-list.d.ts +1 -0
  85. package/dist/clis/notebooklm/note-list.js +28 -0
  86. package/dist/clis/notebooklm/note-list.test.d.ts +1 -0
  87. package/dist/clis/notebooklm/note-list.test.js +56 -0
  88. package/dist/clis/notebooklm/notes-get.d.ts +1 -0
  89. package/dist/clis/notebooklm/notes-get.js +47 -0
  90. package/dist/clis/notebooklm/notes-get.test.d.ts +1 -0
  91. package/dist/clis/notebooklm/notes-get.test.js +72 -0
  92. package/dist/clis/notebooklm/rpc.d.ts +36 -0
  93. package/dist/clis/notebooklm/rpc.js +189 -0
  94. package/dist/clis/notebooklm/rpc.test.d.ts +1 -0
  95. package/dist/clis/notebooklm/rpc.test.js +105 -0
  96. package/dist/clis/notebooklm/shared.d.ts +87 -0
  97. package/dist/clis/notebooklm/shared.js +3 -0
  98. package/dist/clis/notebooklm/source-fulltext.d.ts +1 -0
  99. package/dist/clis/notebooklm/source-fulltext.js +44 -0
  100. package/dist/clis/notebooklm/source-fulltext.test.d.ts +1 -0
  101. package/dist/clis/notebooklm/source-fulltext.test.js +106 -0
  102. package/dist/clis/notebooklm/source-get.d.ts +1 -0
  103. package/dist/clis/notebooklm/source-get.js +40 -0
  104. package/dist/clis/notebooklm/source-get.test.d.ts +1 -0
  105. package/dist/clis/notebooklm/source-get.test.js +84 -0
  106. package/dist/clis/notebooklm/source-guide.d.ts +1 -0
  107. package/dist/clis/notebooklm/source-guide.js +44 -0
  108. package/dist/clis/notebooklm/source-guide.test.d.ts +1 -0
  109. package/dist/clis/notebooklm/source-guide.test.js +104 -0
  110. package/dist/clis/notebooklm/source-list.d.ts +1 -0
  111. package/dist/clis/notebooklm/source-list.js +30 -0
  112. package/dist/clis/notebooklm/status.d.ts +1 -0
  113. package/dist/clis/notebooklm/status.js +31 -0
  114. package/dist/clis/notebooklm/summary.d.ts +1 -0
  115. package/dist/clis/notebooklm/summary.js +30 -0
  116. package/dist/clis/notebooklm/summary.test.d.ts +1 -0
  117. package/dist/clis/notebooklm/summary.test.js +78 -0
  118. package/dist/clis/notebooklm/utils.d.ts +37 -0
  119. package/dist/clis/notebooklm/utils.js +739 -0
  120. package/dist/clis/notebooklm/utils.test.d.ts +1 -0
  121. package/dist/clis/notebooklm/utils.test.js +390 -0
  122. package/dist/clis/substack/utils.d.ts +4 -0
  123. package/dist/clis/substack/utils.js +8 -2
  124. package/dist/clis/substack/utils.test.d.ts +1 -0
  125. package/dist/clis/substack/utils.test.js +46 -0
  126. package/dist/clis/v2ex/hot.yaml +4 -1
  127. package/dist/clis/v2ex/latest.yaml +4 -1
  128. package/dist/clis/v2ex/topic.yaml +6 -1
  129. package/dist/clis/weixin/download.d.ts +9 -0
  130. package/dist/clis/weixin/download.js +76 -6
  131. package/dist/clis/weread/book.js +108 -2
  132. package/dist/clis/weread/commands.test.js +262 -152
  133. package/dist/clis/weread/utils.d.ts +10 -0
  134. package/dist/clis/weread/utils.js +27 -7
  135. package/dist/clis/xiaohongshu/comments.d.ts +3 -0
  136. package/dist/clis/xiaohongshu/comments.js +76 -17
  137. package/dist/clis/xiaohongshu/comments.test.js +70 -9
  138. package/dist/clis/xiaohongshu/download.d.ts +4 -1
  139. package/dist/clis/xiaohongshu/download.js +83 -22
  140. package/dist/clis/xiaohongshu/download.test.d.ts +1 -0
  141. package/dist/clis/xiaohongshu/download.test.js +75 -0
  142. package/dist/clis/xiaohongshu/note-helpers.d.ts +12 -0
  143. package/dist/clis/xiaohongshu/note-helpers.js +23 -0
  144. package/dist/clis/xiaohongshu/note.d.ts +7 -0
  145. package/dist/clis/xiaohongshu/note.js +76 -0
  146. package/dist/clis/xiaohongshu/note.test.d.ts +1 -0
  147. package/dist/clis/xiaohongshu/note.test.js +136 -0
  148. package/dist/clis/xiaohongshu/search.js +9 -0
  149. package/dist/clis/xiaohongshu/search.test.js +10 -4
  150. package/dist/clis/youtube/search.js +57 -17
  151. package/dist/clis/zhihu/question.js +19 -17
  152. package/dist/clis/zhihu/question.test.d.ts +1 -0
  153. package/dist/clis/zhihu/question.test.js +54 -0
  154. package/dist/commanderAdapter.js +9 -0
  155. package/dist/commanderAdapter.test.js +25 -0
  156. package/dist/commands/daemon.d.ts +9 -0
  157. package/dist/commands/daemon.js +124 -0
  158. package/dist/commands/daemon.test.d.ts +1 -0
  159. package/dist/commands/daemon.test.js +185 -0
  160. package/dist/completion.js +3 -1
  161. package/dist/constants.d.ts +2 -0
  162. package/dist/constants.js +2 -0
  163. package/dist/daemon.d.ts +1 -1
  164. package/dist/daemon.js +25 -14
  165. package/dist/daemon.test.d.ts +1 -0
  166. package/dist/daemon.test.js +65 -0
  167. package/dist/discovery.d.ts +9 -0
  168. package/dist/discovery.js +47 -2
  169. package/dist/electron-apps.d.ts +29 -0
  170. package/dist/electron-apps.js +65 -0
  171. package/dist/electron-apps.test.d.ts +1 -0
  172. package/dist/electron-apps.test.js +43 -0
  173. package/dist/engine.test.js +41 -9
  174. package/dist/execution.js +20 -16
  175. package/dist/extension-manifest-regression.test.js +1 -0
  176. package/dist/idle-manager.d.ts +19 -0
  177. package/dist/idle-manager.js +54 -0
  178. package/dist/launcher.d.ts +36 -0
  179. package/dist/launcher.js +152 -0
  180. package/dist/launcher.test.d.ts +1 -0
  181. package/dist/launcher.test.js +57 -0
  182. package/dist/main.js +3 -3
  183. package/dist/registry.d.ts +1 -0
  184. package/dist/registry.js +31 -3
  185. package/dist/registry.test.js +13 -0
  186. package/dist/runtime.d.ts +5 -3
  187. package/dist/runtime.js +12 -5
  188. package/dist/serialization.d.ts +1 -0
  189. package/dist/serialization.js +3 -0
  190. package/dist/serialization.test.js +17 -1
  191. package/dist/tui.d.ts +7 -0
  192. package/dist/tui.js +52 -0
  193. package/dist/tui.test.d.ts +1 -0
  194. package/dist/tui.test.js +19 -0
  195. package/dist/weixin-download.test.js +14 -0
  196. package/docs/.vitepress/config.mts +1 -0
  197. package/docs/adapters/browser/notebooklm.md +69 -0
  198. package/docs/adapters/browser/xiaohongshu.md +19 -10
  199. package/docs/adapters/index.md +67 -66
  200. package/docs/guide/browser-bridge.md +12 -0
  201. package/docs/guide/troubleshooting.md +9 -4
  202. package/docs/superpowers/plans/2026-03-31-daemon-lifecycle-redesign.md +857 -0
  203. package/docs/superpowers/specs/2026-03-31-daemon-lifecycle-redesign.md +208 -0
  204. package/docs/zh/guide/browser-bridge.md +12 -0
  205. package/extension/dist/background.js +250 -11
  206. package/extension/manifest.json +2 -1
  207. package/extension/src/background.test.ts +202 -2
  208. package/extension/src/background.ts +175 -10
  209. package/extension/src/cdp.test.ts +75 -0
  210. package/extension/src/cdp.ts +89 -3
  211. package/extension/src/protocol.ts +7 -5
  212. package/package.json +1 -1
  213. package/src/browser/cdp.ts +24 -17
  214. package/src/browser/daemon-client.ts +7 -1
  215. package/src/browser/dom-helpers.test.ts +15 -1
  216. package/src/browser/dom-helpers.ts +1 -0
  217. package/src/browser/mcp.ts +18 -13
  218. package/src/browser/page.test.ts +58 -0
  219. package/src/browser/page.ts +18 -2
  220. package/src/browser/stealth.test.ts +153 -0
  221. package/src/browser/stealth.ts +198 -0
  222. package/src/browser.test.ts +1 -1
  223. package/src/build-manifest.test.ts +2 -0
  224. package/src/build-manifest.ts +6 -1
  225. package/src/cli.ts +21 -3
  226. package/src/clis/antigravity/SKILL.md +3 -12
  227. package/src/clis/antigravity/serve.ts +5 -10
  228. package/src/clis/bilibili/subtitle.test.ts +60 -0
  229. package/src/clis/bilibili/subtitle.ts +4 -0
  230. package/src/clis/chatwise/ask.ts +0 -2
  231. package/src/clis/chatwise/export.ts +0 -2
  232. package/src/clis/chatwise/history.ts +0 -2
  233. package/src/clis/chatwise/model.ts +0 -2
  234. package/src/clis/chatwise/new.ts +1 -2
  235. package/src/clis/chatwise/read.ts +0 -2
  236. package/src/clis/chatwise/screenshot.ts +1 -2
  237. package/src/clis/chatwise/send.ts +0 -2
  238. package/src/clis/chatwise/status.ts +1 -2
  239. package/src/clis/ctrip/search.test.ts +73 -0
  240. package/src/clis/ctrip/search.ts +97 -47
  241. package/src/clis/douyin/_shared/sts2.test.ts +31 -0
  242. package/src/clis/douyin/_shared/sts2.ts +11 -3
  243. package/src/clis/douyin/activities.test.ts +41 -1
  244. package/src/clis/douyin/activities.ts +12 -3
  245. package/src/clis/douyin/collections.test.ts +35 -2
  246. package/src/clis/douyin/collections.ts +1 -1
  247. package/src/clis/douyin/draft.test.ts +444 -2
  248. package/src/clis/douyin/draft.ts +382 -218
  249. package/src/clis/douyin/hashtag.test.ts +42 -2
  250. package/src/clis/douyin/hashtag.ts +11 -3
  251. package/src/clis/douyin/profile.test.ts +43 -1
  252. package/src/clis/douyin/profile.ts +9 -2
  253. package/src/clis/douyin/videos.test.ts +52 -2
  254. package/src/clis/douyin/videos.ts +49 -15
  255. package/src/clis/facebook/search.test.ts +70 -0
  256. package/src/clis/facebook/search.yaml +4 -3
  257. package/src/clis/instagram/download.test.ts +159 -0
  258. package/src/clis/instagram/download.ts +286 -0
  259. package/src/clis/notebooklm/bind-current.test.ts +43 -0
  260. package/src/clis/notebooklm/bind-current.ts +36 -0
  261. package/src/clis/notebooklm/binding.test.ts +53 -0
  262. package/src/clis/notebooklm/compat.test.ts +19 -0
  263. package/src/clis/notebooklm/current.ts +38 -0
  264. package/src/clis/notebooklm/get.ts +53 -0
  265. package/src/clis/notebooklm/history.test.ts +70 -0
  266. package/src/clis/notebooklm/history.ts +36 -0
  267. package/src/clis/notebooklm/list.ts +40 -0
  268. package/src/clis/notebooklm/note-list.test.ts +64 -0
  269. package/src/clis/notebooklm/note-list.ts +42 -0
  270. package/src/clis/notebooklm/notes-get.test.ts +88 -0
  271. package/src/clis/notebooklm/notes-get.ts +67 -0
  272. package/src/clis/notebooklm/rpc.test.ts +126 -0
  273. package/src/clis/notebooklm/rpc.ts +286 -0
  274. package/src/clis/notebooklm/shared.ts +98 -0
  275. package/src/clis/notebooklm/source-fulltext.test.ts +123 -0
  276. package/src/clis/notebooklm/source-fulltext.ts +69 -0
  277. package/src/clis/notebooklm/source-get.test.ts +100 -0
  278. package/src/clis/notebooklm/source-get.ts +60 -0
  279. package/src/clis/notebooklm/source-guide.test.ts +121 -0
  280. package/src/clis/notebooklm/source-guide.ts +69 -0
  281. package/src/clis/notebooklm/source-list.ts +45 -0
  282. package/src/clis/notebooklm/status.ts +34 -0
  283. package/src/clis/notebooklm/summary.test.ts +94 -0
  284. package/src/clis/notebooklm/summary.ts +45 -0
  285. package/src/clis/notebooklm/utils.test.ts +446 -0
  286. package/src/clis/notebooklm/utils.ts +893 -0
  287. package/src/clis/substack/utils.test.ts +54 -0
  288. package/src/clis/substack/utils.ts +10 -2
  289. package/src/clis/v2ex/hot.yaml +4 -1
  290. package/src/clis/v2ex/latest.yaml +4 -1
  291. package/src/clis/v2ex/topic.yaml +6 -1
  292. package/src/clis/weixin/download.ts +95 -6
  293. package/src/clis/weread/book.ts +142 -2
  294. package/src/clis/weread/commands.test.ts +314 -154
  295. package/src/clis/weread/utils.ts +33 -4
  296. package/src/clis/xiaohongshu/comments.test.ts +85 -9
  297. package/src/clis/xiaohongshu/comments.ts +76 -17
  298. package/src/clis/xiaohongshu/download.test.ts +96 -0
  299. package/src/clis/xiaohongshu/download.ts +83 -22
  300. package/src/clis/xiaohongshu/note-helpers.ts +25 -0
  301. package/src/clis/xiaohongshu/note.test.ts +164 -0
  302. package/src/clis/xiaohongshu/note.ts +86 -0
  303. package/src/clis/xiaohongshu/search.test.ts +11 -4
  304. package/src/clis/xiaohongshu/search.ts +13 -0
  305. package/src/clis/youtube/search.ts +57 -17
  306. package/src/clis/zhihu/question.test.ts +71 -0
  307. package/src/clis/zhihu/question.ts +27 -15
  308. package/src/commanderAdapter.test.ts +30 -0
  309. package/src/commanderAdapter.ts +7 -0
  310. package/src/commands/daemon.test.ts +238 -0
  311. package/src/commands/daemon.ts +135 -0
  312. package/src/completion.ts +2 -1
  313. package/src/constants.ts +3 -0
  314. package/src/daemon.test.ts +88 -0
  315. package/src/daemon.ts +26 -14
  316. package/src/discovery.ts +52 -2
  317. package/src/electron-apps.test.ts +50 -0
  318. package/src/electron-apps.ts +89 -0
  319. package/src/engine.test.ts +45 -9
  320. package/src/execution.ts +24 -19
  321. package/src/extension-manifest-regression.test.ts +1 -0
  322. package/src/idle-manager.ts +60 -0
  323. package/src/launcher.test.ts +67 -0
  324. package/src/launcher.ts +185 -0
  325. package/src/main.ts +3 -2
  326. package/src/registry.test.ts +15 -0
  327. package/src/registry.ts +32 -3
  328. package/src/runtime.ts +13 -7
  329. package/src/serialization.test.ts +19 -1
  330. package/src/serialization.ts +2 -0
  331. package/src/tui.test.ts +23 -0
  332. package/src/tui.ts +65 -0
  333. package/src/weixin-download.test.ts +27 -0
  334. package/tests/e2e/browser-public-extended.test.ts +6 -2
  335. package/chatwise-opencli.ps1 +0 -82
  336. package/dist/clis/chatwise/shared.d.ts +0 -2
  337. package/dist/clis/chatwise/shared.js +0 -6
  338. package/src/clis/chatwise/shared.ts +0 -8
package/src/registry.ts CHANGED
@@ -33,6 +33,7 @@ export type CommandArgs = Record<string, any>;
33
33
  export interface CliCommand {
34
34
  site: string;
35
35
  name: string;
36
+ aliases?: string[];
36
37
  description: string;
37
38
  domain?: string;
38
39
  strategy?: Strategy;
@@ -85,9 +86,11 @@ const _registry: Map<string, CliCommand> =
85
86
  export function cli(opts: CliOptions): CliCommand {
86
87
  const strategy = opts.strategy ?? (opts.browser === false ? Strategy.PUBLIC : Strategy.COOKIE);
87
88
  const browser = opts.browser ?? (strategy !== Strategy.PUBLIC);
89
+ const aliases = normalizeAliases(opts.aliases, opts.name);
88
90
  const cmd: CliCommand = {
89
91
  site: opts.site,
90
92
  name: opts.name,
93
+ aliases,
91
94
  description: opts.description ?? '',
92
95
  domain: opts.domain,
93
96
  strategy,
@@ -104,8 +107,7 @@ export function cli(opts: CliOptions): CliCommand {
104
107
  navigateBefore: opts.navigateBefore,
105
108
  };
106
109
 
107
- const key = fullName(cmd);
108
- _registry.set(key, cmd);
110
+ registerCommand(cmd);
109
111
  return cmd;
110
112
  }
111
113
 
@@ -122,5 +124,32 @@ export function strategyLabel(cmd: CliCommand): string {
122
124
  }
123
125
 
124
126
  export function registerCommand(cmd: CliCommand): void {
125
- _registry.set(fullName(cmd), cmd);
127
+ const canonicalKey = fullName(cmd);
128
+ const existing = _registry.get(canonicalKey);
129
+ if (existing) {
130
+ for (const [key, value] of _registry.entries()) {
131
+ if (value === existing && key !== canonicalKey) _registry.delete(key);
132
+ }
133
+ }
134
+
135
+ const aliases = normalizeAliases(cmd.aliases, cmd.name);
136
+ cmd.aliases = aliases.length > 0 ? aliases : undefined;
137
+ _registry.set(canonicalKey, cmd);
138
+ for (const alias of aliases) {
139
+ _registry.set(`${cmd.site}/${alias}`, cmd);
140
+ }
141
+ }
142
+
143
+ function normalizeAliases(aliases: string[] | undefined, commandName: string): string[] {
144
+ if (!Array.isArray(aliases) || aliases.length === 0) return [];
145
+
146
+ const seen = new Set<string>();
147
+ const normalized: string[] = [];
148
+ for (const alias of aliases) {
149
+ const value = typeof alias === 'string' ? alias.trim() : '';
150
+ if (!value || value === commandName || seen.has(value)) continue;
151
+ seen.add(value);
152
+ normalized.push(value);
153
+ }
154
+ return normalized;
126
155
  }
package/src/runtime.ts CHANGED
@@ -1,13 +1,15 @@
1
1
  import { BrowserBridge, CDPBridge } from './browser/index.js';
2
2
  import type { IPage } from './types.js';
3
3
  import { TimeoutError } from './errors.js';
4
+ import { isElectronApp } from './electron-apps.js';
4
5
 
5
6
  /**
6
- * Returns the appropriate browser factory based on environment config.
7
- * Uses CDPBridge when OPENCLI_CDP_ENDPOINT is set, otherwise BrowserBridge.
7
+ * Returns the appropriate browser factory based on site type.
8
+ * Uses CDPBridge for registered Electron apps, otherwise BrowserBridge.
8
9
  */
9
- export function getBrowserFactory(): new () => IBrowserFactory {
10
- return process.env.OPENCLI_CDP_ENDPOINT ? CDPBridge : BrowserBridge;
10
+ export function getBrowserFactory(site?: string): new () => IBrowserFactory {
11
+ if (site && isElectronApp(site)) return CDPBridge;
12
+ return BrowserBridge;
11
13
  }
12
14
 
13
15
  function parseEnvTimeout(envVar: string, fallback: number): number {
@@ -61,18 +63,22 @@ export function withTimeoutMs<T>(
61
63
 
62
64
  /** Interface for browser factory (BrowserBridge or test mocks) */
63
65
  export interface IBrowserFactory {
64
- connect(opts?: { timeout?: number; workspace?: string }): Promise<IPage>;
66
+ connect(opts?: { timeout?: number; workspace?: string; cdpEndpoint?: string }): Promise<IPage>;
65
67
  close(): Promise<void>;
66
68
  }
67
69
 
68
70
  export async function browserSession<T>(
69
71
  BrowserFactory: new () => IBrowserFactory,
70
72
  fn: (page: IPage) => Promise<T>,
71
- opts: { workspace?: string } = {},
73
+ opts: { workspace?: string; cdpEndpoint?: string } = {},
72
74
  ): Promise<T> {
73
75
  const mcp = new BrowserFactory();
74
76
  try {
75
- const page = await mcp.connect({ timeout: DEFAULT_BROWSER_CONNECT_TIMEOUT, workspace: opts.workspace });
77
+ const page = await mcp.connect({
78
+ timeout: DEFAULT_BROWSER_CONNECT_TIMEOUT,
79
+ workspace: opts.workspace,
80
+ cdpEndpoint: opts.cdpEndpoint,
81
+ });
76
82
  return await fn(page);
77
83
  } finally {
78
84
  await mcp.close().catch(() => {});
@@ -1,7 +1,7 @@
1
1
  import { describe, expect, it } from 'vitest';
2
2
  import type { CliCommand } from './registry.js';
3
3
  import { Strategy } from './registry.js';
4
- import { formatRegistryHelpText } from './serialization.js';
4
+ import { formatRegistryHelpText, serializeCommand } from './serialization.js';
5
5
 
6
6
  describe('formatRegistryHelpText', () => {
7
7
  it('summarizes long choices lists so help text stays readable', () => {
@@ -23,4 +23,22 @@ describe('formatRegistryHelpText', () => {
23
23
 
24
24
  expect(formatRegistryHelpText(cmd)).toContain('--field: all-fields, topic, title, author, ... (+3 more)');
25
25
  });
26
+
27
+ it('includes aliases in structured serialization and help text', () => {
28
+ const cmd: CliCommand = {
29
+ site: 'demo',
30
+ name: 'get',
31
+ aliases: ['metadata'],
32
+ description: 'Demo command',
33
+ strategy: Strategy.COOKIE,
34
+ browser: true,
35
+ args: [],
36
+ };
37
+
38
+ expect(serializeCommand(cmd)).toMatchObject({
39
+ command: 'demo/get',
40
+ aliases: ['metadata'],
41
+ });
42
+ expect(formatRegistryHelpText(cmd)).toContain('Aliases: metadata');
43
+ });
26
44
  });
@@ -39,6 +39,7 @@ export function serializeCommand(cmd: CliCommand) {
39
39
  command: fullName(cmd),
40
40
  site: cmd.site,
41
41
  name: cmd.name,
42
+ aliases: cmd.aliases ?? [],
42
43
  description: cmd.description,
43
44
  strategy: strategyLabel(cmd),
44
45
  browser: !!cmd.browser,
@@ -82,6 +83,7 @@ export function formatRegistryHelpText(cmd: CliCommand): string {
82
83
  if (cmd.domain) meta.push(`Domain: ${cmd.domain}`);
83
84
  if (cmd.deprecated) meta.push(`Deprecated: ${typeof cmd.deprecated === 'string' ? cmd.deprecated : 'yes'}`);
84
85
  if (cmd.replacedBy) meta.push(`Use instead: ${cmd.replacedBy}`);
86
+ if (cmd.aliases?.length) meta.push(`Aliases: ${cmd.aliases.join(', ')}`);
85
87
  lines.push(meta.join(' | '));
86
88
  if (cmd.columns?.length) lines.push(`Output columns: ${cmd.columns.join(', ')}`);
87
89
  return '\n' + lines.join('\n') + '\n';
@@ -0,0 +1,23 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { confirmPrompt } from './tui.js';
3
+
4
+ describe('confirmPrompt', () => {
5
+ beforeEach(() => {
6
+ vi.restoreAllMocks();
7
+ });
8
+
9
+ it('returns defaultYes when stdin is not TTY', async () => {
10
+ const result = await confirmPrompt('Restart?', true);
11
+ expect(result).toBe(true);
12
+ });
13
+
14
+ it('returns false when defaultYes is false and non-TTY', async () => {
15
+ const result = await confirmPrompt('Restart?', false);
16
+ expect(result).toBe(false);
17
+ });
18
+
19
+ it('defaults to true when defaultYes is omitted and non-TTY', async () => {
20
+ const result = await confirmPrompt('Restart?');
21
+ expect(result).toBe(true);
22
+ });
23
+ });
package/src/tui.ts CHANGED
@@ -170,3 +170,68 @@ export async function checkboxPrompt(
170
170
  draw();
171
171
  });
172
172
  }
173
+
174
+ /**
175
+ * Simple yes/no confirmation prompt.
176
+ *
177
+ * In non-TTY environments, returns `defaultYes` (defaults to true) without blocking.
178
+ * In TTY, waits for a single keypress: y/Enter → true, n/Esc/q → false.
179
+ */
180
+ export async function confirmPrompt(
181
+ message: string,
182
+ defaultYes: boolean = true,
183
+ ): Promise<boolean> {
184
+ const { stdin, stdout } = process;
185
+ if (!stdin.isTTY) return defaultYes;
186
+
187
+ const hint = defaultYes ? '[Y/n]' : '[y/N]';
188
+ stdout.write(` ${message} ${chalk.dim(hint)} `);
189
+
190
+ return new Promise<boolean>((resolve) => {
191
+ const wasRaw = stdin.isRaw;
192
+ stdin.setRawMode(true);
193
+ stdin.resume();
194
+
195
+ function cleanup() {
196
+ stdin.setRawMode(wasRaw ?? false);
197
+ stdin.pause();
198
+ stdin.removeListener('data', onData);
199
+ stdout.write('\n');
200
+ }
201
+
202
+ function onData(data: Buffer) {
203
+ const key = data.toString();
204
+
205
+ // Ctrl+C
206
+ if (key === '\x03') {
207
+ cleanup();
208
+ process.exit(EXIT_CODES.INTERRUPTED);
209
+ }
210
+
211
+ // Enter — use default
212
+ if (key === '\r' || key === '\n') {
213
+ cleanup();
214
+ resolve(defaultYes);
215
+ return;
216
+ }
217
+
218
+ // y/Y — yes
219
+ if (key === 'y' || key === 'Y') {
220
+ cleanup();
221
+ resolve(true);
222
+ return;
223
+ }
224
+
225
+ // n/N/q/Esc — no
226
+ if (key === 'n' || key === 'N' || key === 'q' || key === '\x1b') {
227
+ cleanup();
228
+ resolve(false);
229
+ return;
230
+ }
231
+
232
+ // Ignore other keys
233
+ }
234
+
235
+ stdin.on('data', onData);
236
+ });
237
+ }
@@ -61,4 +61,31 @@ describe('weixin publish time extraction', () => {
61
61
  'var create_time = "1711291080";',
62
62
  )).toBe('2026年3月24日 22:38');
63
63
  });
64
+
65
+ it('detects WeChat verification gate pages', async () => {
66
+ const mod = await loadModule();
67
+
68
+ expect(mod.detectWechatAccessIssue(
69
+ '环境异常 当前环境异常,完成验证后即可继续访问。 去验证',
70
+ '<html><body><a id="js_verify">去验证</a></body></html>',
71
+ )).toBe('environment verification required');
72
+ });
73
+
74
+ it('browser access detector matches the server-side verifier', async () => {
75
+ const mod = await loadModule();
76
+
77
+ const detectInPage = eval(mod.buildDetectWechatAccessIssueJs()) as (pageText: string, htmlStr: string) => string;
78
+
79
+ expect(detectInPage(
80
+ '环境异常 当前环境异常,完成验证后即可继续访问。 去验证',
81
+ '<html>secitptpage/verify.html<a id="js_verify">去验证</a></html>',
82
+ )).toBe('environment verification required');
83
+ });
84
+
85
+ it('picks the first non-empty WeChat metadata field', async () => {
86
+ const mod = await loadModule();
87
+
88
+ expect(mod.pickFirstWechatMetaText('', 'Name cleared', '数字生命卡兹克')).toBe('数字生命卡兹克');
89
+ expect(mod.pickFirstWechatMetaText('', ' 聊聊刚刚上线的PixVerse V6视频模型。 ')).toBe('聊聊刚刚上线的PixVerse V6视频模型。');
90
+ });
64
91
  });
@@ -126,9 +126,13 @@ describe('browser extended public-data commands E2E', () => {
126
126
  }, 60_000);
127
127
 
128
128
  // ── ctrip ──
129
- it('ctrip search returns flights', async () => {
130
- const data = await tryBrowserCommand(['ctrip', 'search', '-f', 'json']);
129
+ it('ctrip search returns destination suggestions', async () => {
130
+ const data = await tryBrowserCommand(['ctrip', 'search', '苏州', '--limit', '3', '-f', 'json']);
131
131
  expectDataOrSkip(data, 'ctrip search');
132
+ if (data) {
133
+ expect(data[0]).toHaveProperty('name');
134
+ expect(data[0]).toHaveProperty('type');
135
+ }
132
136
  }, 60_000);
133
137
 
134
138
  // ── coupang ──
@@ -1,82 +0,0 @@
1
- [CmdletBinding()]
2
- param(
3
- [Parameter(ValueFromRemainingArguments = $true)]
4
- [string[]]$OpenCliArgs
5
- )
6
-
7
- $ErrorActionPreference = 'Stop'
8
-
9
- $chatwiseExe = 'C:\Program Files\ChatWise\ChatWise.exe'
10
- if (-not (Test-Path $chatwiseExe)) {
11
- throw "ChatWise executable not found at $chatwiseExe"
12
- }
13
-
14
- $opencli = Get-Command opencli -ErrorAction SilentlyContinue
15
- if (-not $opencli) {
16
- throw 'opencli was not found in PATH'
17
- }
18
-
19
- function Clear-LocalProxyEnv {
20
- $vars = 'http_proxy','https_proxy','HTTP_PROXY','HTTPS_PROXY'
21
- foreach ($name in $vars) {
22
- Set-Item -Path "Env:$name" -Value ''
23
- }
24
- $noProxy = '127.0.0.1,localhost'
25
- Set-Item -Path 'Env:NO_PROXY' -Value $noProxy
26
- Set-Item -Path 'Env:no_proxy' -Value $noProxy
27
- }
28
-
29
- function Stop-ChatWiseTree {
30
- $candidates = Get-CimInstance Win32_Process |
31
- Where-Object { $_.Name -match '^ChatWise\.exe$|^chatwise\.exe$' }
32
-
33
- foreach ($proc in $candidates) {
34
- try {
35
- Stop-Process -Id $proc.ProcessId -Force -ErrorAction Stop
36
- } catch {}
37
- }
38
-
39
- Start-Sleep -Seconds 2
40
- }
41
-
42
- function Wait-ChatWiseDebugPort {
43
- param(
44
- [int]$Port = 9228,
45
- [int]$TimeoutSeconds = 20
46
- )
47
-
48
- $deadline = (Get-Date).AddSeconds($TimeoutSeconds)
49
- while ((Get-Date) -lt $deadline) {
50
- try {
51
- $resp = Invoke-WebRequest -UseBasicParsing -TimeoutSec 2 -Uri "http://127.0.0.1:$Port/json/version"
52
- if ($resp.StatusCode -ge 200 -and $resp.StatusCode -lt 300) {
53
- return
54
- }
55
- } catch {}
56
- Start-Sleep -Milliseconds 500
57
- }
58
-
59
- throw "ChatWise debugging endpoint did not come up on 127.0.0.1:$Port"
60
- }
61
-
62
- Clear-LocalProxyEnv
63
- Stop-ChatWiseTree
64
-
65
- $proc = Start-Process -FilePath $chatwiseExe -ArgumentList '--remote-debugging-port=9228' -PassThru
66
- Start-Sleep -Seconds 4
67
-
68
- if ($proc.HasExited) {
69
- throw "ChatWise exited early with code $($proc.ExitCode)"
70
- }
71
-
72
- Wait-ChatWiseDebugPort
73
-
74
- $env:OPENCLI_CDP_ENDPOINT = 'http://127.0.0.1:9228'
75
-
76
- if (-not $OpenCliArgs -or $OpenCliArgs.Count -eq 0) {
77
- & $opencli.Source 'chatwise' 'status'
78
- exit $LASTEXITCODE
79
- }
80
-
81
- & $opencli.Source @OpenCliArgs
82
- exit $LASTEXITCODE
@@ -1,2 +0,0 @@
1
- import type { RequiredEnv } from '../../registry.js';
2
- export declare const chatwiseRequiredEnv: RequiredEnv[];
@@ -1,6 +0,0 @@
1
- export const chatwiseRequiredEnv = [
2
- {
3
- name: 'OPENCLI_CDP_ENDPOINT',
4
- help: 'Launch ChatWise with --remote-debugging-port=9228, then run OPENCLI_CDP_ENDPOINT=http://127.0.0.1:9228 opencli chatwise status. If you use a local proxy, also set NO_PROXY=127.0.0.1,localhost.',
5
- },
6
- ];
@@ -1,8 +0,0 @@
1
- import type { RequiredEnv } from '../../registry.js';
2
-
3
- export const chatwiseRequiredEnv: RequiredEnv[] = [
4
- {
5
- name: 'OPENCLI_CDP_ENDPOINT',
6
- help: 'Launch ChatWise with --remote-debugging-port=9228, then run OPENCLI_CDP_ENDPOINT=http://127.0.0.1:9228 opencli chatwise status. If you use a local proxy, also set NO_PROXY=127.0.0.1,localhost.',
7
- },
8
- ];