@jackwener/opencli 0.9.6 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (307) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.yml +83 -0
  2. package/.github/ISSUE_TEMPLATE/config.yml +8 -0
  3. package/.github/ISSUE_TEMPLATE/feature_request.yml +42 -0
  4. package/.github/ISSUE_TEMPLATE/new_site_adapter.yml +57 -0
  5. package/.github/dependabot.yml +27 -0
  6. package/.github/pull_request_template.md +24 -0
  7. package/.github/workflows/ci.yml +14 -8
  8. package/.github/workflows/e2e-headed.yml +6 -2
  9. package/.github/workflows/pkg-pr-new.yml +2 -2
  10. package/.github/workflows/release-please.yml +25 -0
  11. package/.github/workflows/release.yml +2 -2
  12. package/.github/workflows/security.yml +36 -0
  13. package/CDP.md +1 -1
  14. package/CDP.zh-CN.md +1 -1
  15. package/CLI-ELECTRON.md +89 -36
  16. package/CLI-EXPLORER.md +4 -4
  17. package/CONTRIBUTING.md +167 -0
  18. package/README.md +113 -89
  19. package/README.zh-CN.md +114 -91
  20. package/SKILL.md +10 -8
  21. package/TESTING.md +7 -7
  22. package/dist/browser/daemon-client.d.ts +37 -0
  23. package/dist/browser/daemon-client.js +82 -0
  24. package/dist/browser/discover.d.ts +11 -34
  25. package/dist/browser/discover.js +15 -190
  26. package/dist/browser/errors.d.ts +6 -20
  27. package/dist/browser/errors.js +24 -63
  28. package/dist/browser/index.d.ts +2 -11
  29. package/dist/browser/index.js +5 -11
  30. package/dist/browser/mcp.d.ts +9 -18
  31. package/dist/browser/mcp.js +70 -284
  32. package/dist/browser/page.d.ts +28 -6
  33. package/dist/browser/page.js +210 -85
  34. package/dist/browser.test.js +4 -202
  35. package/dist/build-manifest.d.ts +26 -0
  36. package/dist/build-manifest.js +132 -60
  37. package/dist/build-manifest.test.d.ts +1 -0
  38. package/dist/build-manifest.test.js +26 -0
  39. package/dist/cli-manifest.json +1582 -29
  40. package/dist/clis/bilibili/download.d.ts +10 -0
  41. package/dist/clis/bilibili/download.js +135 -0
  42. package/dist/clis/chatwise/ask.d.ts +1 -0
  43. package/dist/clis/chatwise/ask.js +76 -0
  44. package/dist/clis/chatwise/export.d.ts +1 -0
  45. package/dist/clis/chatwise/export.js +46 -0
  46. package/dist/clis/chatwise/history.d.ts +1 -0
  47. package/dist/clis/chatwise/history.js +43 -0
  48. package/dist/clis/chatwise/model.d.ts +1 -0
  49. package/dist/clis/chatwise/model.js +81 -0
  50. package/dist/clis/chatwise/new.d.ts +1 -0
  51. package/dist/clis/chatwise/new.js +18 -0
  52. package/dist/clis/chatwise/read.d.ts +1 -0
  53. package/dist/clis/chatwise/read.js +39 -0
  54. package/dist/clis/chatwise/screenshot.d.ts +1 -0
  55. package/dist/clis/chatwise/screenshot.js +27 -0
  56. package/dist/clis/chatwise/send.d.ts +1 -0
  57. package/dist/clis/chatwise/send.js +45 -0
  58. package/dist/clis/chatwise/status.d.ts +1 -0
  59. package/dist/clis/chatwise/status.js +22 -0
  60. package/dist/clis/discord-app/channels.d.ts +1 -0
  61. package/dist/clis/discord-app/channels.js +45 -0
  62. package/dist/clis/discord-app/members.d.ts +1 -0
  63. package/dist/clis/discord-app/members.js +38 -0
  64. package/dist/clis/discord-app/read.d.ts +1 -0
  65. package/dist/clis/discord-app/read.js +45 -0
  66. package/dist/clis/discord-app/search.d.ts +1 -0
  67. package/dist/clis/discord-app/search.js +56 -0
  68. package/dist/clis/discord-app/send.d.ts +1 -0
  69. package/dist/clis/discord-app/send.js +27 -0
  70. package/dist/clis/discord-app/servers.d.ts +1 -0
  71. package/dist/clis/discord-app/servers.js +36 -0
  72. package/dist/clis/discord-app/status.d.ts +1 -0
  73. package/dist/clis/discord-app/status.js +16 -0
  74. package/dist/clis/feishu/new.d.ts +1 -0
  75. package/dist/clis/feishu/new.js +27 -0
  76. package/dist/clis/feishu/read.d.ts +1 -0
  77. package/dist/clis/feishu/read.js +40 -0
  78. package/dist/clis/feishu/search.d.ts +1 -0
  79. package/dist/clis/feishu/search.js +30 -0
  80. package/dist/clis/feishu/send.d.ts +1 -0
  81. package/dist/clis/feishu/send.js +39 -0
  82. package/dist/clis/feishu/status.d.ts +1 -0
  83. package/dist/clis/feishu/status.js +28 -0
  84. package/dist/clis/grok/ask.d.ts +1 -0
  85. package/dist/clis/grok/ask.js +82 -0
  86. package/dist/clis/grok/debug.d.ts +1 -0
  87. package/dist/clis/grok/debug.js +45 -0
  88. package/dist/clis/jimeng/generate.yaml +84 -0
  89. package/dist/clis/jimeng/history.yaml +47 -0
  90. package/dist/clis/linux-do/categories.yaml +41 -0
  91. package/dist/clis/linux-do/category.yaml +49 -0
  92. package/dist/clis/linux-do/hot.yaml +50 -0
  93. package/dist/clis/linux-do/latest.yaml +40 -0
  94. package/dist/clis/linux-do/search.yaml +45 -0
  95. package/dist/clis/linux-do/topic.yaml +38 -0
  96. package/dist/clis/neteasemusic/like.d.ts +1 -0
  97. package/dist/clis/neteasemusic/like.js +25 -0
  98. package/dist/clis/neteasemusic/lyrics.d.ts +1 -0
  99. package/dist/clis/neteasemusic/lyrics.js +47 -0
  100. package/dist/clis/neteasemusic/next.d.ts +1 -0
  101. package/dist/clis/neteasemusic/next.js +26 -0
  102. package/dist/clis/neteasemusic/play.d.ts +1 -0
  103. package/dist/clis/neteasemusic/play.js +26 -0
  104. package/dist/clis/neteasemusic/playing.d.ts +1 -0
  105. package/dist/clis/neteasemusic/playing.js +59 -0
  106. package/dist/clis/neteasemusic/playlist.d.ts +1 -0
  107. package/dist/clis/neteasemusic/playlist.js +46 -0
  108. package/dist/clis/neteasemusic/prev.d.ts +1 -0
  109. package/dist/clis/neteasemusic/prev.js +25 -0
  110. package/dist/clis/neteasemusic/search.d.ts +1 -0
  111. package/dist/clis/neteasemusic/search.js +52 -0
  112. package/dist/clis/neteasemusic/status.d.ts +1 -0
  113. package/dist/clis/neteasemusic/status.js +16 -0
  114. package/dist/clis/neteasemusic/volume.d.ts +1 -0
  115. package/dist/clis/neteasemusic/volume.js +54 -0
  116. package/dist/clis/notion/export.d.ts +1 -0
  117. package/dist/clis/notion/export.js +31 -0
  118. package/dist/clis/notion/favorites.d.ts +1 -0
  119. package/dist/clis/notion/favorites.js +84 -0
  120. package/dist/clis/notion/new.d.ts +1 -0
  121. package/dist/clis/notion/new.js +34 -0
  122. package/dist/clis/notion/read.d.ts +1 -0
  123. package/dist/clis/notion/read.js +30 -0
  124. package/dist/clis/notion/search.d.ts +1 -0
  125. package/dist/clis/notion/search.js +46 -0
  126. package/dist/clis/notion/sidebar.d.ts +1 -0
  127. package/dist/clis/notion/sidebar.js +41 -0
  128. package/dist/clis/notion/status.d.ts +1 -0
  129. package/dist/clis/notion/status.js +16 -0
  130. package/dist/clis/notion/write.d.ts +1 -0
  131. package/dist/clis/notion/write.js +40 -0
  132. package/dist/clis/twitter/download.d.ts +8 -0
  133. package/dist/clis/twitter/download.js +204 -0
  134. package/dist/clis/wechat/chats.d.ts +1 -0
  135. package/dist/clis/wechat/chats.js +28 -0
  136. package/dist/clis/wechat/contacts.d.ts +1 -0
  137. package/dist/clis/wechat/contacts.js +28 -0
  138. package/dist/clis/wechat/read.d.ts +1 -0
  139. package/dist/clis/wechat/read.js +58 -0
  140. package/dist/clis/wechat/search.d.ts +1 -0
  141. package/dist/clis/wechat/search.js +31 -0
  142. package/dist/clis/wechat/send.d.ts +1 -0
  143. package/dist/clis/wechat/send.js +42 -0
  144. package/dist/clis/wechat/status.d.ts +1 -0
  145. package/dist/clis/wechat/status.js +29 -0
  146. package/dist/clis/xiaohongshu/creator-note-detail.d.ts +10 -0
  147. package/dist/clis/xiaohongshu/creator-note-detail.js +88 -0
  148. package/dist/clis/xiaohongshu/creator-notes.d.ts +11 -0
  149. package/dist/clis/xiaohongshu/creator-notes.js +109 -0
  150. package/dist/clis/xiaohongshu/creator-profile.d.ts +10 -0
  151. package/dist/clis/xiaohongshu/creator-profile.js +54 -0
  152. package/dist/clis/xiaohongshu/creator-stats.d.ts +10 -0
  153. package/dist/clis/xiaohongshu/creator-stats.js +74 -0
  154. package/dist/clis/xiaohongshu/download.d.ts +7 -0
  155. package/dist/clis/xiaohongshu/download.js +155 -0
  156. package/dist/clis/xiaohongshu/search.js +1 -1
  157. package/dist/clis/xiaohongshu/user-helpers.d.ts +15 -0
  158. package/dist/clis/xiaohongshu/user-helpers.js +67 -0
  159. package/dist/clis/xiaohongshu/user-helpers.test.d.ts +1 -0
  160. package/dist/clis/xiaohongshu/user-helpers.test.js +81 -0
  161. package/dist/clis/xiaohongshu/user.js +46 -29
  162. package/dist/clis/zhihu/download.d.ts +11 -0
  163. package/dist/clis/zhihu/download.js +186 -0
  164. package/dist/clis/zhihu/download.test.d.ts +1 -0
  165. package/dist/clis/zhihu/download.test.js +10 -0
  166. package/dist/daemon.d.ts +13 -0
  167. package/dist/daemon.js +187 -0
  168. package/dist/doctor.d.ts +27 -61
  169. package/dist/doctor.js +70 -601
  170. package/dist/doctor.test.js +30 -170
  171. package/dist/download/index.d.ts +79 -0
  172. package/dist/download/index.js +325 -0
  173. package/dist/download/progress.d.ts +36 -0
  174. package/dist/download/progress.js +111 -0
  175. package/dist/engine.test.js +15 -0
  176. package/dist/main.js +22 -28
  177. package/dist/pipeline/executor.test.js +1 -0
  178. package/dist/pipeline/registry.js +2 -0
  179. package/dist/pipeline/steps/browser.js +2 -2
  180. package/dist/pipeline/steps/download.d.ts +34 -0
  181. package/dist/pipeline/steps/download.js +251 -0
  182. package/dist/pipeline/steps/intercept.js +1 -2
  183. package/dist/pipeline/template.js +28 -0
  184. package/dist/setup.d.ts +6 -0
  185. package/dist/setup.js +46 -160
  186. package/dist/types.d.ts +6 -0
  187. package/extension/icons/icon-128.png +0 -0
  188. package/extension/icons/icon-16.png +0 -0
  189. package/extension/icons/icon-32.png +0 -0
  190. package/extension/icons/icon-48.png +0 -0
  191. package/extension/manifest.json +31 -0
  192. package/extension/package.json +16 -0
  193. package/extension/src/background.ts +293 -0
  194. package/extension/src/cdp.ts +125 -0
  195. package/extension/src/protocol.ts +57 -0
  196. package/extension/store-assets/screenshot-1280x800.png +0 -0
  197. package/extension/tsconfig.json +15 -0
  198. package/extension/vite.config.ts +18 -0
  199. package/package.json +8 -7
  200. package/scripts/test-site.mjs +70 -0
  201. package/src/browser/daemon-client.ts +113 -0
  202. package/src/browser/discover.ts +18 -216
  203. package/src/browser/errors.ts +30 -100
  204. package/src/browser/index.ts +6 -12
  205. package/src/browser/mcp.ts +78 -278
  206. package/src/browser/page.ts +222 -88
  207. package/src/browser.test.ts +3 -210
  208. package/src/build-manifest.test.ts +28 -0
  209. package/src/build-manifest.ts +147 -57
  210. package/src/clis/bilibili/download.ts +161 -0
  211. package/src/clis/chatgpt/README.md +1 -1
  212. package/src/clis/chatgpt/README.zh-CN.md +1 -1
  213. package/src/clis/chatwise/README.md +38 -0
  214. package/src/clis/chatwise/README.zh-CN.md +38 -0
  215. package/src/clis/chatwise/ask.ts +87 -0
  216. package/src/clis/chatwise/export.ts +51 -0
  217. package/src/clis/chatwise/history.ts +47 -0
  218. package/src/clis/chatwise/model.ts +87 -0
  219. package/src/clis/chatwise/new.ts +21 -0
  220. package/src/clis/chatwise/read.ts +42 -0
  221. package/src/clis/chatwise/screenshot.ts +33 -0
  222. package/src/clis/chatwise/send.ts +50 -0
  223. package/src/clis/chatwise/status.ts +25 -0
  224. package/src/clis/discord-app/README.md +28 -0
  225. package/src/clis/discord-app/README.zh-CN.md +28 -0
  226. package/src/clis/discord-app/channels.ts +48 -0
  227. package/src/clis/discord-app/members.ts +41 -0
  228. package/src/clis/discord-app/read.ts +49 -0
  229. package/src/clis/discord-app/search.ts +64 -0
  230. package/src/clis/discord-app/send.ts +32 -0
  231. package/src/clis/discord-app/servers.ts +39 -0
  232. package/src/clis/discord-app/status.ts +18 -0
  233. package/src/clis/feishu/README.md +20 -0
  234. package/src/clis/feishu/README.zh-CN.md +20 -0
  235. package/src/clis/feishu/new.ts +32 -0
  236. package/src/clis/feishu/read.ts +48 -0
  237. package/src/clis/feishu/search.ts +35 -0
  238. package/src/clis/feishu/send.ts +46 -0
  239. package/src/clis/feishu/status.ts +34 -0
  240. package/src/clis/grok/ask.ts +90 -0
  241. package/src/clis/grok/debug.ts +49 -0
  242. package/src/clis/jimeng/generate.yaml +84 -0
  243. package/src/clis/jimeng/history.yaml +47 -0
  244. package/src/clis/linux-do/categories.yaml +41 -0
  245. package/src/clis/linux-do/category.yaml +49 -0
  246. package/src/clis/linux-do/hot.yaml +50 -0
  247. package/src/clis/linux-do/latest.yaml +40 -0
  248. package/src/clis/linux-do/search.yaml +45 -0
  249. package/src/clis/linux-do/topic.yaml +38 -0
  250. package/src/clis/neteasemusic/README.md +31 -0
  251. package/src/clis/neteasemusic/README.zh-CN.md +31 -0
  252. package/src/clis/neteasemusic/like.ts +28 -0
  253. package/src/clis/neteasemusic/lyrics.ts +53 -0
  254. package/src/clis/neteasemusic/next.ts +30 -0
  255. package/src/clis/neteasemusic/play.ts +30 -0
  256. package/src/clis/neteasemusic/playing.ts +62 -0
  257. package/src/clis/neteasemusic/playlist.ts +51 -0
  258. package/src/clis/neteasemusic/prev.ts +29 -0
  259. package/src/clis/neteasemusic/search.ts +58 -0
  260. package/src/clis/neteasemusic/status.ts +18 -0
  261. package/src/clis/neteasemusic/volume.ts +61 -0
  262. package/src/clis/notion/README.md +29 -0
  263. package/src/clis/notion/README.zh-CN.md +29 -0
  264. package/src/clis/notion/export.ts +36 -0
  265. package/src/clis/notion/favorites.ts +87 -0
  266. package/src/clis/notion/new.ts +39 -0
  267. package/src/clis/notion/read.ts +33 -0
  268. package/src/clis/notion/search.ts +54 -0
  269. package/src/clis/notion/sidebar.ts +44 -0
  270. package/src/clis/notion/status.ts +18 -0
  271. package/src/clis/notion/write.ts +45 -0
  272. package/src/clis/twitter/download.ts +227 -0
  273. package/src/clis/wechat/README.md +28 -0
  274. package/src/clis/wechat/README.zh-CN.md +28 -0
  275. package/src/clis/wechat/chats.ts +33 -0
  276. package/src/clis/wechat/contacts.ts +33 -0
  277. package/src/clis/wechat/read.ts +72 -0
  278. package/src/clis/wechat/search.ts +36 -0
  279. package/src/clis/wechat/send.ts +49 -0
  280. package/src/clis/wechat/status.ts +35 -0
  281. package/src/clis/xiaohongshu/creator-note-detail.ts +95 -0
  282. package/src/clis/xiaohongshu/creator-notes.ts +116 -0
  283. package/src/clis/xiaohongshu/creator-profile.ts +60 -0
  284. package/src/clis/xiaohongshu/creator-stats.ts +81 -0
  285. package/src/clis/xiaohongshu/download.ts +173 -0
  286. package/src/clis/xiaohongshu/search.ts +1 -1
  287. package/src/clis/xiaohongshu/user-helpers.test.ts +106 -0
  288. package/src/clis/xiaohongshu/user-helpers.ts +85 -0
  289. package/src/clis/xiaohongshu/user.ts +52 -32
  290. package/src/clis/zhihu/download.test.ts +12 -0
  291. package/src/clis/zhihu/download.ts +223 -0
  292. package/src/daemon.ts +217 -0
  293. package/src/doctor.test.ts +32 -193
  294. package/src/doctor.ts +74 -668
  295. package/src/download/index.ts +395 -0
  296. package/src/download/progress.ts +125 -0
  297. package/src/engine.test.ts +17 -0
  298. package/src/main.ts +18 -26
  299. package/src/pipeline/executor.test.ts +1 -0
  300. package/src/pipeline/registry.ts +2 -0
  301. package/src/pipeline/steps/browser.ts +2 -2
  302. package/src/pipeline/steps/download.ts +310 -0
  303. package/src/pipeline/steps/intercept.ts +1 -2
  304. package/src/pipeline/template.ts +26 -0
  305. package/src/setup.ts +47 -183
  306. package/src/types.ts +1 -0
  307. package/tests/e2e/browser-auth.test.ts +25 -0
package/dist/daemon.js ADDED
@@ -0,0 +1,187 @@
1
+ /**
2
+ * opencli micro-daemon — HTTP + WebSocket bridge between CLI and Chrome Extension.
3
+ *
4
+ * Architecture:
5
+ * CLI → HTTP POST /command → daemon → WebSocket → Extension
6
+ * Extension → WebSocket result → daemon → HTTP response → CLI
7
+ *
8
+ * Lifecycle:
9
+ * - Auto-spawned by opencli on first browser command
10
+ * - Auto-exits after 5 minutes of idle
11
+ * - Listens on localhost:19825
12
+ */
13
+ import { createServer } from 'node:http';
14
+ import { WebSocketServer, WebSocket } from 'ws';
15
+ const PORT = parseInt(process.env.OPENCLI_DAEMON_PORT ?? '19825', 10);
16
+ const IDLE_TIMEOUT = 5 * 60 * 1000; // 5 minutes
17
+ // ─── State ───────────────────────────────────────────────────────────
18
+ let extensionWs = null;
19
+ const pending = new Map();
20
+ let idleTimer = null;
21
+ const LOG_BUFFER_SIZE = 200;
22
+ const logBuffer = [];
23
+ function pushLog(entry) {
24
+ logBuffer.push(entry);
25
+ if (logBuffer.length > LOG_BUFFER_SIZE)
26
+ logBuffer.shift();
27
+ }
28
+ // ─── Idle auto-exit ──────────────────────────────────────────────────
29
+ function resetIdleTimer() {
30
+ if (idleTimer)
31
+ clearTimeout(idleTimer);
32
+ idleTimer = setTimeout(() => {
33
+ console.error('[daemon] Idle timeout, shutting down');
34
+ process.exit(0);
35
+ }, IDLE_TIMEOUT);
36
+ }
37
+ // ─── HTTP Server ─────────────────────────────────────────────────────
38
+ function readBody(req) {
39
+ return new Promise((resolve, reject) => {
40
+ const chunks = [];
41
+ req.on('data', (c) => chunks.push(c));
42
+ req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
43
+ req.on('error', reject);
44
+ });
45
+ }
46
+ function jsonResponse(res, status, data) {
47
+ res.writeHead(status, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
48
+ res.end(JSON.stringify(data));
49
+ }
50
+ async function handleRequest(req, res) {
51
+ res.setHeader('Access-Control-Allow-Origin', '*');
52
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
53
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
54
+ if (req.method === 'OPTIONS') {
55
+ res.writeHead(204);
56
+ res.end();
57
+ return;
58
+ }
59
+ const url = req.url ?? '/';
60
+ const pathname = url.split('?')[0];
61
+ if (req.method === 'GET' && pathname === '/status') {
62
+ jsonResponse(res, 200, {
63
+ ok: true,
64
+ extensionConnected: extensionWs?.readyState === WebSocket.OPEN,
65
+ pending: pending.size,
66
+ });
67
+ return;
68
+ }
69
+ if (req.method === 'GET' && pathname === '/logs') {
70
+ const params = new URL(url, `http://localhost:${PORT}`).searchParams;
71
+ const level = params.get('level');
72
+ const filtered = level
73
+ ? logBuffer.filter(e => e.level === level)
74
+ : logBuffer;
75
+ jsonResponse(res, 200, { ok: true, logs: filtered });
76
+ return;
77
+ }
78
+ if (req.method === 'DELETE' && pathname === '/logs') {
79
+ logBuffer.length = 0;
80
+ jsonResponse(res, 200, { ok: true });
81
+ return;
82
+ }
83
+ if (req.method === 'POST' && url === '/command') {
84
+ resetIdleTimer();
85
+ try {
86
+ const body = JSON.parse(await readBody(req));
87
+ if (!body.id) {
88
+ jsonResponse(res, 400, { ok: false, error: 'Missing command id' });
89
+ return;
90
+ }
91
+ if (!extensionWs || extensionWs.readyState !== WebSocket.OPEN) {
92
+ jsonResponse(res, 503, { id: body.id, ok: false, error: 'Extension not connected. Please install the opencli Browser Bridge extension.' });
93
+ return;
94
+ }
95
+ const result = await new Promise((resolve, reject) => {
96
+ const timer = setTimeout(() => {
97
+ pending.delete(body.id);
98
+ reject(new Error('Command timeout (30s)'));
99
+ }, 30000);
100
+ pending.set(body.id, { resolve, reject, timer });
101
+ extensionWs.send(JSON.stringify(body));
102
+ });
103
+ jsonResponse(res, 200, result);
104
+ }
105
+ catch (err) {
106
+ jsonResponse(res, err instanceof Error && err.message.includes('timeout') ? 408 : 400, {
107
+ ok: false,
108
+ error: err instanceof Error ? err.message : 'Invalid request',
109
+ });
110
+ }
111
+ return;
112
+ }
113
+ jsonResponse(res, 404, { error: 'Not found' });
114
+ }
115
+ // ─── WebSocket for Extension ─────────────────────────────────────────
116
+ const httpServer = createServer((req, res) => { handleRequest(req, res).catch(() => { res.writeHead(500); res.end(); }); });
117
+ const wss = new WebSocketServer({ server: httpServer, path: '/ext' });
118
+ wss.on('connection', (ws) => {
119
+ console.error('[daemon] Extension connected');
120
+ extensionWs = ws;
121
+ ws.on('message', (data) => {
122
+ try {
123
+ const msg = JSON.parse(data.toString());
124
+ // Handle log messages from extension
125
+ if (msg.type === 'log') {
126
+ const prefix = msg.level === 'error' ? '❌' : msg.level === 'warn' ? '⚠️' : '📋';
127
+ console.error(`${prefix} [ext] ${msg.msg}`);
128
+ pushLog({ level: msg.level, msg: msg.msg, ts: msg.ts ?? Date.now() });
129
+ return;
130
+ }
131
+ // Handle command results
132
+ const p = pending.get(msg.id);
133
+ if (p) {
134
+ clearTimeout(p.timer);
135
+ pending.delete(msg.id);
136
+ p.resolve(msg);
137
+ }
138
+ }
139
+ catch {
140
+ // Ignore malformed messages
141
+ }
142
+ });
143
+ ws.on('close', () => {
144
+ console.error('[daemon] Extension disconnected');
145
+ if (extensionWs === ws) {
146
+ extensionWs = null;
147
+ // Reject all pending requests since the extension is gone
148
+ for (const [id, p] of pending) {
149
+ clearTimeout(p.timer);
150
+ p.reject(new Error('Extension disconnected'));
151
+ }
152
+ pending.clear();
153
+ }
154
+ });
155
+ ws.on('error', () => {
156
+ if (extensionWs === ws)
157
+ extensionWs = null;
158
+ });
159
+ });
160
+ // ─── Start ───────────────────────────────────────────────────────────
161
+ httpServer.listen(PORT, '127.0.0.1', () => {
162
+ console.error(`[daemon] Listening on http://127.0.0.1:${PORT}`);
163
+ resetIdleTimer();
164
+ });
165
+ httpServer.on('error', (err) => {
166
+ if (err.code === 'EADDRINUSE') {
167
+ console.error(`[daemon] Port ${PORT} already in use — another daemon is likely running. Exiting.`);
168
+ process.exit(0);
169
+ }
170
+ console.error('[daemon] Server error:', err.message);
171
+ process.exit(1);
172
+ });
173
+ // Graceful shutdown
174
+ function shutdown() {
175
+ // Reject all pending requests so CLI doesn't hang
176
+ for (const [, p] of pending) {
177
+ clearTimeout(p.timer);
178
+ p.reject(new Error('Daemon shutting down'));
179
+ }
180
+ pending.clear();
181
+ if (extensionWs)
182
+ extensionWs.close();
183
+ httpServer.close();
184
+ process.exit(0);
185
+ }
186
+ process.on('SIGTERM', shutdown);
187
+ process.on('SIGINT', shutdown);
package/dist/doctor.d.ts CHANGED
@@ -1,29 +1,15 @@
1
- export declare const PLAYWRIGHT_TOKEN_ENV = "PLAYWRIGHT_MCP_EXTENSION_TOKEN";
1
+ /**
2
+ * opencli doctor — diagnose and fix browser connectivity.
3
+ *
4
+ * Simplified for the daemon-based architecture. No more token management,
5
+ * MCP path discovery, or config file scanning.
6
+ */
2
7
  export type DoctorOptions = {
3
8
  fix?: boolean;
4
9
  yes?: boolean;
5
10
  live?: boolean;
6
- shellRc?: string;
7
- configPaths?: string[];
8
- token?: string;
9
11
  cliVersion?: string;
10
12
  };
11
- export type ShellFileStatus = {
12
- path: string;
13
- exists: boolean;
14
- token: string | null;
15
- fingerprint: string | null;
16
- };
17
- export type McpConfigFormat = 'json' | 'toml';
18
- export type McpConfigStatus = {
19
- path: string;
20
- exists: boolean;
21
- format: McpConfigFormat;
22
- token: string | null;
23
- fingerprint: string | null;
24
- writable: boolean;
25
- parseError?: string;
26
- };
27
13
  export type ConnectivityResult = {
28
14
  ok: boolean;
29
15
  error?: string;
@@ -31,57 +17,37 @@ export type ConnectivityResult = {
31
17
  };
32
18
  export type DoctorReport = {
33
19
  cliVersion?: string;
34
- envToken: string | null;
35
- envFingerprint: string | null;
36
- extensionToken: string | null;
37
- extensionFingerprint: string | null;
38
- extensionInstalled: boolean;
39
- extensionBrowsers: string[];
40
- shellFiles: ShellFileStatus[];
41
- configs: McpConfigStatus[];
42
- recommendedToken: string | null;
43
- recommendedFingerprint: string | null;
20
+ daemonRunning: boolean;
21
+ extensionConnected: boolean;
44
22
  connectivity?: ConnectivityResult;
45
- warnings: string[];
46
23
  issues: string[];
47
24
  };
48
- export declare function shortenPath(p: string): string;
49
- export declare function toolName(p: string): string;
50
- export declare function getDefaultShellRcPath(): string;
51
- export declare function getDefaultMcpConfigPaths(cwd?: string): string[];
52
- export declare function readTokenFromShellContent(content: string): string | null;
53
- export declare function upsertShellToken(content: string, token: string, filePath?: string): string;
54
- export declare function upsertJsonConfigToken(content: string, token: string, filePath?: string): string;
55
- export declare function readTomlConfigToken(content: string): string | null;
56
- export declare function upsertTomlConfigToken(content: string, token: string): string;
57
- export declare function fileExists(filePath: string): boolean;
58
25
  /**
59
- * Discover the auth token stored by the Playwright MCP Bridge extension
60
- * by scanning Chrome's LevelDB localStorage files directly.
61
- *
62
- * Reads LevelDB .ldb/.log files as raw binary and searches for the
63
- * extension ID near base64url token values. This works reliably across
64
- * platforms because LevelDB's internal encoding can split ASCII strings
65
- * like "auth-token" and the extension ID across byte boundaries, making
66
- * text-based tools like `strings` + `grep` unreliable.
26
+ * Test connectivity by attempting a real browser command.
67
27
  */
28
+ export declare function checkConnectivity(opts?: {
29
+ timeout?: number;
30
+ }): Promise<ConnectivityResult>;
31
+ export declare function runBrowserDoctor(opts?: DoctorOptions): Promise<DoctorReport>;
32
+ export declare function renderBrowserDoctorReport(report: DoctorReport): string;
33
+ export declare const PLAYWRIGHT_TOKEN_ENV = "PLAYWRIGHT_MCP_EXTENSION_TOKEN";
68
34
  export declare function discoverExtensionToken(): string | null;
69
- /**
70
- * Check whether the Playwright MCP Bridge extension is installed in any browser.
71
- * Scans Chrome/Chromium/Edge Extensions directories for the known extension ID.
72
- */
73
35
  export declare function checkExtensionInstalled(): {
74
36
  installed: boolean;
75
37
  browsers: string[];
76
38
  };
77
- /**
78
- * Test token connectivity by attempting a real MCP connection.
79
- * Connects, does the JSON-RPC handshake, and immediately closes.
80
- */
39
+ export declare function applyBrowserDoctorFix(): Promise<string[]>;
40
+ export declare function getDefaultShellRcPath(): string;
41
+ export declare function getDefaultMcpConfigPaths(): string[];
42
+ export declare function readTokenFromShellContent(_content: string): string | null;
43
+ export declare function upsertShellToken(content: string): string;
44
+ export declare function upsertJsonConfigToken(content: string): string;
45
+ export declare function readTomlConfigToken(_content: string): string | null;
46
+ export declare function upsertTomlConfigToken(content: string): string;
47
+ export declare function shortenPath(p: string): string;
48
+ export declare function toolName(_p: string): string;
49
+ export declare function fileExists(filePath: string): boolean;
50
+ export declare function writeFileWithMkdir(_p: string, _c: string): void;
81
51
  export declare function checkTokenConnectivity(opts?: {
82
52
  timeout?: number;
83
53
  }): Promise<ConnectivityResult>;
84
- export declare function runBrowserDoctor(opts?: DoctorOptions): Promise<DoctorReport>;
85
- export declare function renderBrowserDoctorReport(report: DoctorReport): string;
86
- export declare function writeFileWithMkdir(filePath: string, content: string): void;
87
- export declare function applyBrowserDoctorFix(report: DoctorReport, opts?: DoctorOptions): Promise<string[]>;