@jackwener/opencli 0.9.8 → 1.0.1
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.
- package/CDP.md +1 -1
- package/CDP.zh-CN.md +1 -1
- package/CLI-ELECTRON.md +2 -2
- package/CLI-EXPLORER.md +4 -4
- package/README.md +35 -58
- package/README.zh-CN.md +36 -60
- package/SKILL.md +10 -8
- package/TESTING.md +7 -7
- package/dist/browser/daemon-client.d.ts +37 -0
- package/dist/browser/daemon-client.js +82 -0
- package/dist/browser/discover.d.ts +11 -34
- package/dist/browser/discover.js +15 -205
- package/dist/browser/errors.d.ts +6 -20
- package/dist/browser/errors.js +24 -63
- package/dist/browser/index.d.ts +2 -12
- package/dist/browser/index.js +2 -12
- package/dist/browser/mcp.d.ts +9 -21
- package/dist/browser/mcp.js +70 -285
- package/dist/browser/page.d.ts +36 -7
- package/dist/browser/page.js +212 -81
- package/dist/browser.test.js +10 -231
- package/dist/cli-manifest.json +561 -14
- package/dist/clis/apple-podcasts/episodes.d.ts +1 -0
- package/dist/clis/apple-podcasts/episodes.js +28 -0
- package/dist/clis/apple-podcasts/search.d.ts +1 -0
- package/dist/clis/apple-podcasts/search.js +29 -0
- package/dist/clis/apple-podcasts/top.d.ts +1 -0
- package/dist/clis/apple-podcasts/top.js +34 -0
- package/dist/clis/apple-podcasts/utils.d.ts +11 -0
- package/dist/clis/apple-podcasts/utils.js +30 -0
- package/dist/clis/apple-podcasts/utils.test.d.ts +1 -0
- package/dist/clis/apple-podcasts/utils.test.js +57 -0
- package/dist/clis/chatwise/history.js +18 -1
- package/dist/clis/discord-app/channels.js +33 -21
- package/dist/clis/neteasemusic/like.d.ts +1 -0
- package/dist/clis/neteasemusic/like.js +25 -0
- package/dist/clis/neteasemusic/lyrics.d.ts +1 -0
- package/dist/clis/neteasemusic/lyrics.js +47 -0
- package/dist/clis/neteasemusic/next.d.ts +1 -0
- package/dist/clis/neteasemusic/next.js +26 -0
- package/dist/clis/neteasemusic/play.d.ts +1 -0
- package/dist/clis/neteasemusic/play.js +26 -0
- package/dist/clis/neteasemusic/playing.d.ts +1 -0
- package/dist/clis/neteasemusic/playing.js +59 -0
- package/dist/clis/neteasemusic/playlist.d.ts +1 -0
- package/dist/clis/neteasemusic/playlist.js +46 -0
- package/dist/clis/neteasemusic/prev.d.ts +1 -0
- package/dist/clis/neteasemusic/prev.js +25 -0
- package/dist/clis/neteasemusic/search.d.ts +1 -0
- package/dist/clis/neteasemusic/search.js +52 -0
- package/dist/clis/neteasemusic/status.d.ts +1 -0
- package/dist/clis/neteasemusic/status.js +16 -0
- package/dist/clis/neteasemusic/volume.d.ts +1 -0
- package/dist/clis/neteasemusic/volume.js +54 -0
- package/dist/clis/twitter/accept.d.ts +1 -0
- package/dist/clis/twitter/accept.js +202 -0
- package/dist/clis/twitter/followers.js +30 -22
- package/dist/clis/twitter/following.js +19 -14
- package/dist/clis/twitter/notifications.js +29 -22
- package/dist/clis/twitter/reply-dm.d.ts +1 -0
- package/dist/clis/twitter/reply-dm.js +181 -0
- package/dist/clis/twitter/search.js +50 -12
- package/dist/clis/weread/book.d.ts +1 -0
- package/dist/clis/weread/book.js +26 -0
- package/dist/clis/weread/highlights.d.ts +1 -0
- package/dist/clis/weread/highlights.js +23 -0
- package/dist/clis/weread/notebooks.d.ts +1 -0
- package/dist/clis/weread/notebooks.js +21 -0
- package/dist/clis/weread/notes.d.ts +1 -0
- package/dist/clis/weread/notes.js +29 -0
- package/dist/clis/weread/ranking.d.ts +1 -0
- package/dist/clis/weread/ranking.js +28 -0
- package/dist/clis/weread/search.d.ts +1 -0
- package/dist/clis/weread/search.js +25 -0
- package/dist/clis/weread/shelf.d.ts +1 -0
- package/dist/clis/weread/shelf.js +24 -0
- package/dist/clis/weread/utils.d.ts +20 -0
- package/dist/clis/weread/utils.js +72 -0
- package/dist/clis/weread/utils.test.d.ts +1 -0
- package/dist/clis/weread/utils.test.js +85 -0
- package/dist/daemon.d.ts +13 -0
- package/dist/daemon.js +187 -0
- package/dist/doctor.d.ts +10 -65
- package/dist/doctor.js +49 -602
- package/dist/doctor.test.js +30 -170
- package/dist/main.js +12 -41
- package/dist/pipeline/executor.test.js +1 -0
- package/dist/pipeline/steps/browser.js +2 -2
- package/dist/pipeline/steps/intercept.js +1 -2
- package/dist/runtime.d.ts +1 -4
- package/dist/runtime.js +1 -4
- package/dist/setup.d.ts +6 -0
- package/dist/setup.js +46 -160
- package/dist/types.d.ts +6 -0
- package/extension/dist/background.js +484 -0
- package/extension/icons/icon-128.png +0 -0
- package/extension/icons/icon-16.png +0 -0
- package/extension/icons/icon-32.png +0 -0
- package/extension/icons/icon-48.png +0 -0
- package/extension/manifest.json +31 -0
- package/extension/package.json +16 -0
- package/extension/src/background.ts +370 -0
- package/extension/src/cdp.ts +125 -0
- package/extension/src/protocol.ts +57 -0
- package/extension/store-assets/screenshot-1280x800.png +0 -0
- package/extension/tsconfig.json +15 -0
- package/extension/vite.config.ts +18 -0
- package/package.json +5 -5
- package/src/browser/daemon-client.ts +113 -0
- package/src/browser/discover.ts +18 -232
- package/src/browser/errors.ts +30 -100
- package/src/browser/index.ts +2 -13
- package/src/browser/mcp.ts +81 -282
- package/src/browser/page.ts +223 -83
- package/src/browser.test.ts +9 -239
- package/src/clis/apple-podcasts/episodes.ts +28 -0
- package/src/clis/apple-podcasts/search.ts +29 -0
- package/src/clis/apple-podcasts/top.ts +34 -0
- package/src/clis/apple-podcasts/utils.test.ts +72 -0
- package/src/clis/apple-podcasts/utils.ts +37 -0
- package/src/clis/chatgpt/README.md +1 -1
- package/src/clis/chatgpt/README.zh-CN.md +1 -1
- package/src/clis/chatwise/history.ts +15 -1
- package/src/clis/discord-app/channels.ts +33 -21
- package/src/clis/neteasemusic/README.md +31 -0
- package/src/clis/neteasemusic/README.zh-CN.md +31 -0
- package/src/clis/neteasemusic/like.ts +28 -0
- package/src/clis/neteasemusic/lyrics.ts +53 -0
- package/src/clis/neteasemusic/next.ts +30 -0
- package/src/clis/neteasemusic/play.ts +30 -0
- package/src/clis/neteasemusic/playing.ts +62 -0
- package/src/clis/neteasemusic/playlist.ts +51 -0
- package/src/clis/neteasemusic/prev.ts +29 -0
- package/src/clis/neteasemusic/search.ts +58 -0
- package/src/clis/neteasemusic/status.ts +18 -0
- package/src/clis/neteasemusic/volume.ts +61 -0
- package/src/clis/twitter/accept.ts +213 -0
- package/src/clis/twitter/followers.ts +36 -29
- package/src/clis/twitter/following.ts +25 -20
- package/src/clis/twitter/notifications.ts +34 -27
- package/src/clis/twitter/reply-dm.ts +193 -0
- package/src/clis/twitter/search.ts +53 -13
- package/src/clis/weread/book.ts +28 -0
- package/src/clis/weread/highlights.ts +25 -0
- package/src/clis/weread/notebooks.ts +23 -0
- package/src/clis/weread/notes.ts +31 -0
- package/src/clis/weread/ranking.ts +29 -0
- package/src/clis/weread/search.ts +26 -0
- package/src/clis/weread/shelf.ts +26 -0
- package/src/clis/weread/utils.test.ts +104 -0
- package/src/clis/weread/utils.ts +74 -0
- package/src/daemon.ts +217 -0
- package/src/doctor.test.ts +32 -193
- package/src/doctor.ts +58 -669
- package/src/main.ts +11 -34
- package/src/pipeline/executor.test.ts +1 -0
- package/src/pipeline/steps/browser.ts +2 -2
- package/src/pipeline/steps/intercept.ts +1 -2
- package/src/runtime.ts +2 -6
- package/src/setup.ts +47 -183
- package/src/types.ts +1 -0
- package/tests/e2e/public-commands.test.ts +68 -1
- package/dist/clis/grok/debug.d.ts +0 -1
- package/dist/clis/grok/debug.js +0 -45
- package/src/clis/grok/debug.ts +0 -49
package/CDP.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Connecting OpenCLI via CDP (Remote/Headless Servers)
|
|
2
2
|
|
|
3
|
-
If you cannot use the
|
|
3
|
+
If you cannot use the opencli Browser Bridge extension (e.g., in a remote headless server environment without a UI), OpenCLI provides an alternative: connecting directly to Chrome via **CDP (Chrome DevTools Protocol)**.
|
|
4
4
|
|
|
5
5
|
Because CDP binds to `localhost` by default for security reasons, accessing it from a remote server requires an additional networking tunnel.
|
|
6
6
|
|
package/CDP.zh-CN.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 通过 CDP 远程连接 OpenCLI (服务器/无头环境)
|
|
2
2
|
|
|
3
|
-
如果你无法使用
|
|
3
|
+
如果你无法使用 opencli Browser Bridge 浏览器扩展(例如:在无界面的远程服务器上运行 OpenCLI 时),OpenCLI 提供了备选方案:通过连接 **CDP (Chrome DevTools Protocol,即 Chrome 开发者工具协议)** 来直接控制本地 Chrome。
|
|
4
4
|
|
|
5
5
|
出于安全考虑,CDP 默认仅绑定在 `localhost` 的本地端口。所以,若是想让**远程服务器**调用本地的 CDP 服务,我们需要依靠一层额外的网络隧道。
|
|
6
6
|
|
package/CLI-ELECTRON.md
CHANGED
|
@@ -8,7 +8,7 @@ Based on the successful automation of **Cursor**, **Codex**, **Antigravity**, **
|
|
|
8
8
|
|
|
9
9
|
## Core Concept
|
|
10
10
|
|
|
11
|
-
Electron apps are essentially local Chromium browser instances. By exposing a debugging port (CDP — Chrome DevTools Protocol) at launch time, we can use
|
|
11
|
+
Electron apps are essentially local Chromium browser instances. By exposing a debugging port (CDP — Chrome DevTools Protocol) at launch time, we can use the Browser Bridge to pierce through the UI layer, accessing and controlling all underlying state including React/Vue components and Shadow DOM.
|
|
12
12
|
|
|
13
13
|
> **Note:** Not all desktop apps are Electron. WeChat (native Cocoa) and Feishu/Lark (custom Lark Framework) embed Chromium but do NOT expose CDP. For those apps, use the AppleScript + clipboard approach instead (see [Non-Electron Pattern](#non-electron-pattern-applescript)).
|
|
14
14
|
|
|
@@ -109,7 +109,7 @@ Core techniques:
|
|
|
109
109
|
## Pitfalls & Gotchas
|
|
110
110
|
|
|
111
111
|
1. **Port conflicts (EADDRINUSE)**: Only one app per port. Use unique ports: Codex=9222, ChatGPT=9224, Cursor=9226, ChatWise=9228, Notion=9230, Discord=9232
|
|
112
|
-
2. **IPage abstraction**: OpenCLI wraps
|
|
112
|
+
2. **IPage abstraction**: OpenCLI wraps the browser page as `IPage` (`src/types.ts`). Use `page.pressKey()` and `page.evaluate()`, NOT direct DOM APIs
|
|
113
113
|
3. **Timing**: Always add `await page.wait(0.5)` to `1.0` after DOM mutations. Returning too early disconnects prematurely
|
|
114
114
|
4. **AppleScript requires Accessibility**: Terminal app must be granted permission in System Settings → Privacy & Security → Accessibility
|
|
115
115
|
|
package/CLI-EXPLORER.md
CHANGED
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
## AI Agent
|
|
12
|
+
## AI Agent 开发者必读:用浏览器探索
|
|
13
13
|
|
|
14
14
|
> [!CAUTION]
|
|
15
|
-
> **你(AI Agent
|
|
15
|
+
> **你(AI Agent)必须通过浏览器打开目标网站去探索!**
|
|
16
16
|
> 不要只靠 `opencli explore` 命令或静态分析来发现 API。
|
|
17
|
-
>
|
|
17
|
+
> 你拥有浏览器工具,必须主动用它们浏览网页、观察网络请求、模拟用户交互。
|
|
18
18
|
|
|
19
19
|
### 为什么?
|
|
20
20
|
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
|
|
37
37
|
| ❌ 错误做法 | ✅ 正确做法 |
|
|
38
38
|
|------------|------------|
|
|
39
|
-
| 只用 `opencli explore` 命令,等结果自动出来 |
|
|
39
|
+
| 只用 `opencli explore` 命令,等结果自动出来 | 用浏览器工具打开页面,主动浏览 |
|
|
40
40
|
| 直接在代码里 `fetch(url)`,不看浏览器实际请求 | 先在浏览器中确认 API 可用,再写代码 |
|
|
41
41
|
| 页面打开后直接抓包,期望所有 API 都出现 | 模拟点击交互(展开评论/切换标签/加载更多) |
|
|
42
42
|
| 遇到 HTTP 200 但空数据就放弃 | 检查是否需要 Wbi 签名或 Cookie 鉴权 |
|
package/README.md
CHANGED
|
@@ -22,6 +22,7 @@ Turn ANY Electron application into a CLI tool! Recombine, script, and extend app
|
|
|
22
22
|
- [Prerequisites](#prerequisites)
|
|
23
23
|
- [Quick Start](#quick-start)
|
|
24
24
|
- [Built-in Commands](#built-in-commands)
|
|
25
|
+
- [Desktop App Adapters](#desktop-app-adapters)
|
|
25
26
|
- [Download Support](#download-support)
|
|
26
27
|
- [Output Formats](#output-formats)
|
|
27
28
|
- [For AI Agents (Developer Guide)](#for-ai-agents-developer-guide)
|
|
@@ -49,69 +50,27 @@ Turn ANY Electron application into a CLI tool! Recombine, script, and extend app
|
|
|
49
50
|
|
|
50
51
|
> **⚠️ Important**: Browser commands reuse your Chrome login session. You must be logged into the target website in Chrome before running commands. If you get empty data or errors, check your login status first.
|
|
51
52
|
|
|
52
|
-
OpenCLI connects to your browser through
|
|
53
|
-
It prefers an existing local/global `@playwright/mcp` install and falls back to `npx -y @playwright/mcp@latest` automatically when no local MCP server is found.
|
|
53
|
+
OpenCLI connects to your browser through a lightweight **Browser Bridge** Chrome Extension + micro-daemon (zero config, auto-start).
|
|
54
54
|
|
|
55
|
-
###
|
|
55
|
+
### Browser Bridge Extension Setup
|
|
56
56
|
|
|
57
|
-
1. Install **
|
|
58
|
-
|
|
57
|
+
1. Install the **opencli Browser Bridge** extension in Chrome:
|
|
58
|
+
- Open `chrome://extensions`, enable **Developer mode** (top-right toggle)
|
|
59
|
+
- Click **Load unpacked**, select the `extension/` folder from this repo
|
|
60
|
+
2. That's it! The daemon auto-starts when you run any browser command. No tokens, no manual configuration.
|
|
59
61
|
|
|
60
|
-
|
|
61
|
-
opencli setup
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
The interactive TUI will:
|
|
65
|
-
- 🔍 Auto-discover `PLAYWRIGHT_MCP_EXTENSION_TOKEN` from Chrome (no manual copy needed)
|
|
66
|
-
- ☑️ Show all detected tools (Codex, Cursor, Claude Code, Gemini CLI, etc.)
|
|
67
|
-
- ✏️ Update only the files you select (Space to toggle, Enter to confirm)
|
|
68
|
-
- 🔌 Auto-verify browser connectivity after writing configs
|
|
69
|
-
|
|
70
|
-
> **Tip**: Use `opencli doctor` for ongoing diagnosis and maintenance:
|
|
62
|
+
> **Tip**: Use `opencli doctor` for ongoing diagnosis:
|
|
71
63
|
> ```bash
|
|
72
|
-
> opencli doctor #
|
|
73
|
-
> opencli doctor --live # Also test live browser
|
|
74
|
-
> opencli doctor --fix # Fix mismatched configs (interactive)
|
|
75
|
-
> opencli doctor --fix -y # Fix all configs non-interactively
|
|
64
|
+
> opencli doctor # Check extension + daemon connectivity
|
|
65
|
+
> opencli doctor --live # Also test live browser commands
|
|
76
66
|
> ```
|
|
77
67
|
|
|
78
|
-
**Alternative: CDP Mode (For Servers/Headless)**
|
|
79
|
-
If you cannot install the browser extension (e.g. running OpenCLI on a remote headless server), you can connect OpenCLI to your local Chrome via CDP using SSH tunnels or reverse proxies. See the [CDP Connection Guide](./CDP.md) for detailed instructions.
|
|
80
|
-
|
|
81
|
-
<details>
|
|
82
|
-
<summary>Manual setup (alternative)</summary>
|
|
83
|
-
|
|
84
|
-
Add token to your MCP client config (e.g. Claude/Cursor):
|
|
85
|
-
|
|
86
|
-
```json
|
|
87
|
-
{
|
|
88
|
-
"mcpServers": {
|
|
89
|
-
"playwright": {
|
|
90
|
-
"command": "npx",
|
|
91
|
-
"args": ["-y", "@playwright/mcp@latest", "--extension"],
|
|
92
|
-
"env": {
|
|
93
|
-
"PLAYWRIGHT_MCP_EXTENSION_TOKEN": "<your-token-here>"
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
Export in shell (e.g. `~/.zshrc`):
|
|
101
|
-
|
|
102
|
-
```bash
|
|
103
|
-
export PLAYWRIGHT_MCP_EXTENSION_TOKEN="<your-token-here>"
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
</details>
|
|
107
|
-
|
|
108
68
|
## Quick Start
|
|
109
69
|
|
|
110
70
|
### Install via npm (recommended)
|
|
111
71
|
|
|
112
72
|
```bash
|
|
113
73
|
npm install -g @jackwener/opencli
|
|
114
|
-
opencli setup # One-time: configure Playwright MCP token
|
|
115
74
|
```
|
|
116
75
|
|
|
117
76
|
Then use directly:
|
|
@@ -148,7 +107,7 @@ Run `opencli list` for the live registry.
|
|
|
148
107
|
|
|
149
108
|
| Site | Commands | Mode |
|
|
150
109
|
|------|----------|------|
|
|
151
|
-
| **twitter** | `trending` `bookmarks` `profile` `search` `timeline` `thread` `following` `followers` `notifications` `post` `reply` `delete` `like` `article` `follow` `unfollow` `bookmark` `unbookmark` `download` | 🔐 Browser |
|
|
110
|
+
| **twitter** | `trending` `bookmarks` `profile` `search` `timeline` `thread` `following` `followers` `notifications` `post` `reply` `delete` `like` `article` `follow` `unfollow` `bookmark` `unbookmark` `download` `accept` `reply-dm` | 🔐 Browser |
|
|
152
111
|
| **reddit** | `hot` `frontpage` `popular` `search` `subreddit` `read` `user` `user-posts` `user-comments` `upvote` `save` `comment` `subscribe` `saved` `upvoted` | 🔐 Browser |
|
|
153
112
|
| **cursor** | `status` `send` `read` `new` `dump` `composer` `model` `extract-code` `ask` `screenshot` `history` `export` | 🖥️ Desktop |
|
|
154
113
|
| **bilibili** | `hot` `search` `me` `favorite` `history` `feed` `subtitle` `dynamic` `ranking` `following` `user-videos` `download` | 🔐 Browser |
|
|
@@ -161,6 +120,7 @@ Run `opencli list` for the live registry.
|
|
|
161
120
|
| **antigravity** | `status` `send` `read` `new` `evaluate` | 🖥️ Desktop |
|
|
162
121
|
| **chatgpt** | `status` `new` `send` `read` `ask` | 🖥️ Desktop |
|
|
163
122
|
| **xiaohongshu** | `search` `notifications` `feed` `me` `user` `download` | 🔐 Browser |
|
|
123
|
+
| **apple-podcasts** | `search` `episodes` `top` | 🌐 Public |
|
|
164
124
|
| **xiaoyuzhou** | `podcast` `podcast-episodes` `episode` | 🌐 Public |
|
|
165
125
|
| **zhihu** | `hot` `search` `question` `download` | 🔐 Browser |
|
|
166
126
|
| **youtube** | `search` `video` `transcript` | 🔐 Browser |
|
|
@@ -176,6 +136,23 @@ Run `opencli list` for the live registry.
|
|
|
176
136
|
| **weibo** | `hot` | 🔐 Browser |
|
|
177
137
|
| **yahoo-finance** | `quote` | 🔐 Browser |
|
|
178
138
|
|
|
139
|
+
### Desktop App Adapters
|
|
140
|
+
|
|
141
|
+
Each desktop adapter has its own detailed documentation with commands reference, setup guide, and examples:
|
|
142
|
+
|
|
143
|
+
| App | Description | Doc |
|
|
144
|
+
|-----|-------------|-----|
|
|
145
|
+
| **Cursor** | Control Cursor IDE — Composer, chat, code extraction | [README](./src/clis/cursor/README.md) |
|
|
146
|
+
| **Codex** | Drive OpenAI Codex CLI agent headlessly | [README](./src/clis/codex/README.md) |
|
|
147
|
+
| **Antigravity** | Control Antigravity Ultra from terminal | [README](./src/clis/antigravity/README.md) |
|
|
148
|
+
| **ChatGPT** | Automate ChatGPT macOS desktop app | [README](./src/clis/chatgpt/README.md) |
|
|
149
|
+
| **ChatWise** | Multi-LLM client (GPT-4, Claude, Gemini) | [README](./src/clis/chatwise/README.md) |
|
|
150
|
+
| **Notion** | Search, read, write Notion pages | [README](./src/clis/notion/README.md) |
|
|
151
|
+
| **Discord** | Discord Desktop — messages, channels, servers | [README](./src/clis/discord-app/README.md) |
|
|
152
|
+
| **Feishu** | 飞书/Lark Desktop via AppleScript | [README](./src/clis/feishu/README.md) |
|
|
153
|
+
| **WeChat** | 微信 Desktop via AppleScript + Accessibility | [README](./src/clis/wechat/README.md) |
|
|
154
|
+
| **NeteaseMusic** | 网易云音乐 Desktop via CEF/CDP | [README](./src/clis/neteasemusic/README.md) |
|
|
155
|
+
|
|
179
156
|
## Download Support
|
|
180
157
|
|
|
181
158
|
OpenCLI supports downloading images, videos, and articles from supported platforms.
|
|
@@ -297,15 +274,15 @@ npx vitest run tests/e2e/ # E2E tests
|
|
|
297
274
|
|
|
298
275
|
## Troubleshooting
|
|
299
276
|
|
|
300
|
-
- **"
|
|
301
|
-
- Ensure the
|
|
302
|
-
- Restart the Chrome browser if you just installed the extension.
|
|
277
|
+
- **"Extension not connected"**
|
|
278
|
+
- Ensure the opencli Browser Bridge extension is installed and **enabled** in `chrome://extensions`.
|
|
303
279
|
- **Empty data returns or 'Unauthorized' error**
|
|
304
|
-
- Your login session in Chrome might have expired. Open a normal Chrome tab, navigate to the target site, and log in or refresh the page
|
|
280
|
+
- Your login session in Chrome might have expired. Open a normal Chrome tab, navigate to the target site, and log in or refresh the page.
|
|
305
281
|
- **Node API errors**
|
|
306
282
|
- Make sure you are using Node.js >= 20. Some dependencies require modern Node APIs.
|
|
307
|
-
- **
|
|
308
|
-
-
|
|
283
|
+
- **Daemon issues**
|
|
284
|
+
- Check daemon status: `curl localhost:19825/status`
|
|
285
|
+
- View extension logs: `curl localhost:19825/logs`
|
|
309
286
|
|
|
310
287
|
## Releasing New Versions
|
|
311
288
|
|
package/README.zh-CN.md
CHANGED
|
@@ -24,6 +24,7 @@ CLI all electron!现在支持把所有 electron 应用 CLI 化,从而组合
|
|
|
24
24
|
- [前置要求](#前置要求)
|
|
25
25
|
- [快速开始](#快速开始)
|
|
26
26
|
- [内置命令](#内置命令)
|
|
27
|
+
- [桌面应用适配器](#桌面应用适配器)
|
|
27
28
|
- [下载支持](#下载支持)
|
|
28
29
|
- [输出格式](#输出格式)
|
|
29
30
|
- [致 AI Agent(开发者指南)](#致-ai-agent开发者指南)
|
|
@@ -50,69 +51,27 @@ CLI all electron!现在支持把所有 electron 应用 CLI 化,从而组合
|
|
|
50
51
|
|
|
51
52
|
> **⚠️ 重要**:大多数命令复用你的 Chrome 登录状态。运行命令前,你必须已在 Chrome 中打开目标网站并完成登录。如果获取到空数据或报错,请先检查你的浏览器登录状态。
|
|
52
53
|
|
|
53
|
-
OpenCLI
|
|
54
|
-
它会优先复用本地或全局已安装的 `@playwright/mcp`,如果没有嗅探到可用 MCP server,则会自动回退到 `npx -y @playwright/mcp@latest` 启动。
|
|
54
|
+
OpenCLI 通过轻量化的 **Browser Bridge** Chrome 扩展 + 微型 daemon 与浏览器通信(零配置,自动启动)。
|
|
55
55
|
|
|
56
|
-
###
|
|
56
|
+
### Browser Bridge 扩展配置
|
|
57
57
|
|
|
58
|
-
1.
|
|
59
|
-
|
|
58
|
+
1. 在 Chrome 中安装 **opencli Browser Bridge** 扩展:
|
|
59
|
+
- 打开 `chrome://extensions`,启用右上角的 **开发者模式**
|
|
60
|
+
- 点击 **加载已解压的扩展程序**,选择本仓库的 `extension/` 文件夹
|
|
61
|
+
2. 完成!运行任何浏览器命令时 daemon 会自动启动。无需 token,无需手动配置。
|
|
60
62
|
|
|
61
|
-
|
|
62
|
-
opencli setup
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
交互式 TUI 会:
|
|
66
|
-
- 🔍 从 Chrome 自动发现 `PLAYWRIGHT_MCP_EXTENSION_TOKEN`(无需手动复制)
|
|
67
|
-
- ☑️ 显示所有支持的工具(Codex、Cursor、Claude Code、Gemini CLI 等)
|
|
68
|
-
- ✏️ 只更新你选中的文件(空格切换,回车确认)
|
|
69
|
-
- 🔌 完成后自动验证浏览器连通性
|
|
70
|
-
|
|
71
|
-
> **Tip**:后续诊断和维护用 `opencli doctor`:
|
|
63
|
+
> **Tip**:后续诊断用 `opencli doctor`:
|
|
72
64
|
> ```bash
|
|
73
|
-
> opencli doctor #
|
|
74
|
-
> opencli doctor --live #
|
|
75
|
-
> opencli doctor --fix # 修复不一致的配置(交互确认)
|
|
76
|
-
> opencli doctor --fix -y # 无交互直接修复所有配置
|
|
65
|
+
> opencli doctor # 检查扩展和 daemon 连通性
|
|
66
|
+
> opencli doctor --live # 额外测试浏览器命令
|
|
77
67
|
> ```
|
|
78
68
|
|
|
79
|
-
**备选方案:CDP 模式 (适用于服务器/无头环境)**
|
|
80
|
-
如果你无法安装浏览器扩展(比如在远程无头服务器上运行 OpenCLI),你可以通过 SSH 隧道或反向代理,利用 CDP (Chrome DevTools Protocol) 连接到本地的 Chrome 浏览器。详细指南请参考 [CDP 连接教程](./CDP.zh-CN.md)。
|
|
81
|
-
|
|
82
|
-
<details>
|
|
83
|
-
<summary>手动配置(备选方案)</summary>
|
|
84
|
-
|
|
85
|
-
配置你的 MCP 客户端(如 Claude/Cursor 等):
|
|
86
|
-
|
|
87
|
-
```json
|
|
88
|
-
{
|
|
89
|
-
"mcpServers": {
|
|
90
|
-
"playwright": {
|
|
91
|
-
"command": "npx",
|
|
92
|
-
"args": ["-y", "@playwright/mcp@latest", "--extension"],
|
|
93
|
-
"env": {
|
|
94
|
-
"PLAYWRIGHT_MCP_EXTENSION_TOKEN": "<你的-token>"
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
在终端环境变量中导出(建议写进 `~/.zshrc`):
|
|
102
|
-
|
|
103
|
-
```bash
|
|
104
|
-
export PLAYWRIGHT_MCP_EXTENSION_TOKEN="<你的-token>"
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
</details>
|
|
108
|
-
|
|
109
69
|
## 快速开始
|
|
110
70
|
|
|
111
71
|
### npm 全局安装(推荐)
|
|
112
72
|
|
|
113
73
|
```bash
|
|
114
74
|
npm install -g @jackwener/opencli
|
|
115
|
-
opencli setup # 首次使用:配置 Playwright MCP token
|
|
116
75
|
```
|
|
117
76
|
|
|
118
77
|
直接使用:
|
|
@@ -149,7 +108,7 @@ npm install -g @jackwener/opencli@latest
|
|
|
149
108
|
|
|
150
109
|
| 站点 | 命令 | 模式 |
|
|
151
110
|
|------|------|------|
|
|
152
|
-
| **twitter** | `trending` `bookmarks` `profile` `search` `timeline` `thread` `following` `followers` `notifications` `post` `reply` `delete` `like` `article` `follow` `unfollow` `bookmark` `unbookmark` `download` | 🔐 浏览器 |
|
|
111
|
+
| **twitter** | `trending` `bookmarks` `profile` `search` `timeline` `thread` `following` `followers` `notifications` `post` `reply` `delete` `like` `article` `follow` `unfollow` `bookmark` `unbookmark` `download` `accept` `reply-dm` | 🔐 浏览器 |
|
|
153
112
|
| **reddit** | `hot` `frontpage` `popular` `search` `subreddit` `read` `user` `user-posts` `user-comments` `upvote` `save` `comment` `subscribe` `saved` `upvoted` | 🔐 浏览器 |
|
|
154
113
|
| **cursor** | `status` `send` `read` `new` `dump` `composer` `model` `extract-code` `ask` `screenshot` `history` `export` | 🖥️ 桌面端 |
|
|
155
114
|
| **bilibili** | `hot` `search` `me` `favorite` `history` `feed` `subtitle` `dynamic` `ranking` `following` `user-videos` `download` | 🔐 浏览器 |
|
|
@@ -162,6 +121,7 @@ npm install -g @jackwener/opencli@latest
|
|
|
162
121
|
| **antigravity** | `status` `send` `read` `new` `evaluate` | 🖥️ 桌面端 |
|
|
163
122
|
| **chatgpt** | `status` `new` `send` `read` `ask` | 🖥️ 桌面端 |
|
|
164
123
|
| **xiaohongshu** | `search` `notifications` `feed` `me` `user` `download` | 🔐 浏览器 |
|
|
124
|
+
| **apple-podcasts** | `search` `episodes` `top` | 🌐 公开 |
|
|
165
125
|
| **xiaoyuzhou** | `podcast` `podcast-episodes` `episode` | 🌐 公开 |
|
|
166
126
|
| **zhihu** | `hot` `search` `question` `download` | 🔐 浏览器 |
|
|
167
127
|
| **youtube** | `search` `video` `transcript` | 🔐 浏览器 |
|
|
@@ -177,6 +137,23 @@ npm install -g @jackwener/opencli@latest
|
|
|
177
137
|
| **weibo** | `hot` | 🔐 浏览器 |
|
|
178
138
|
| **yahoo-finance** | `quote` | 🔐 浏览器 |
|
|
179
139
|
|
|
140
|
+
### 桌面应用适配器
|
|
141
|
+
|
|
142
|
+
每个桌面适配器都有自己详细的文档说明,包括命令参考、启动配置与使用示例:
|
|
143
|
+
|
|
144
|
+
| 应用 | 描述 | 文档 |
|
|
145
|
+
|-----|-------------|-----|
|
|
146
|
+
| **Cursor** | 控制 Cursor IDE — Composer、对话、代码提取等 | [README](./src/clis/cursor/README.md) |
|
|
147
|
+
| **Codex** | 在后台(无头)驱动 OpenAI Codex CLI Agent | [README](./src/clis/codex/README.md) |
|
|
148
|
+
| **Antigravity** | 在终端直接控制 Antigravity Ultra | [README](./src/clis/antigravity/README.md) |
|
|
149
|
+
| **ChatGPT** | 自动化操作 ChatGPT macOS 桌面客户端 | [README](./src/clis/chatgpt/README.md) |
|
|
150
|
+
| **ChatWise** | 多 LLM 客户端(GPT-4、Claude、Gemini) | [README](./src/clis/chatwise/README.md) |
|
|
151
|
+
| **Notion** | 搜索、读取、写入 Notion 页面 | [README](./src/clis/notion/README.md) |
|
|
152
|
+
| **Discord** | Discord 桌面版 — 消息、频道、服务器 | [README](./src/clis/discord-app/README.md) |
|
|
153
|
+
| **Feishu** | 飞书/Lark 桌面版 (AppleScript 驱动) | [README](./src/clis/feishu/README.md) |
|
|
154
|
+
| **WeChat** | 微信 Mac 桌面端 (AppleScript + 无障碍接口) | [README](./src/clis/wechat/README.md) |
|
|
155
|
+
| **NeteaseMusic** | 网易云音乐 (CEF/CDP 驱动) | [README](./src/clis/neteasemusic/README.md) |
|
|
156
|
+
|
|
180
157
|
## 下载支持
|
|
181
158
|
|
|
182
159
|
OpenCLI 支持从各平台下载图片、视频和文章。
|
|
@@ -280,16 +257,15 @@ opencli cascade https://api.example.com/data
|
|
|
280
257
|
|
|
281
258
|
## 常见问题排查
|
|
282
259
|
|
|
283
|
-
- **"
|
|
284
|
-
- 确保你当前的 Chrome 已安装且**开启了**
|
|
285
|
-
- 如果是刚装完插件,需要重启 Chrome 浏览器。
|
|
260
|
+
- **"Extension not connected" 报错**
|
|
261
|
+
- 确保你当前的 Chrome 已安装且**开启了** opencli Browser Bridge 扩展(在 `chrome://extensions` 中检查)。
|
|
286
262
|
- **返回空数据,或者报错 "Unauthorized"**
|
|
287
|
-
- Chrome
|
|
263
|
+
- Chrome 里的登录态可能已经过期。请打开当前 Chrome 页面,在新标签页重新手工登录或刷新该页面。
|
|
288
264
|
- **Node API 错误 (如 parseArgs, fs 等)**
|
|
289
|
-
- 确保 Node.js 版本 `>= 20
|
|
290
|
-
- **
|
|
291
|
-
-
|
|
292
|
-
-
|
|
265
|
+
- 确保 Node.js 版本 `>= 20`。
|
|
266
|
+
- **Daemon 问题**
|
|
267
|
+
- 检查 daemon 状态:`curl localhost:19825/status`
|
|
268
|
+
- 查看扩展日志:`curl localhost:19825/logs`
|
|
293
269
|
|
|
294
270
|
## 版本发布
|
|
295
271
|
|
package/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: opencli
|
|
|
3
3
|
description: "OpenCLI — Make any website or Electron App your CLI. Zero risk, AI-powered, reuse Chrome login. 80+ commands across 19 sites."
|
|
4
4
|
version: 0.7.3
|
|
5
5
|
author: jackwener
|
|
6
|
-
tags: [cli, browser, web,
|
|
6
|
+
tags: [cli, browser, web, chrome-extension, cdp, bilibili, zhihu, twitter, github, v2ex, hackernews, reddit, xiaohongshu, xueqiu, youtube, boss, coupang, AI, agent]
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# OpenCLI
|
|
@@ -12,7 +12,7 @@ tags: [cli, browser, web, mcp, playwright, bilibili, zhihu, twitter, github, v2e
|
|
|
12
12
|
|
|
13
13
|
> [!CAUTION]
|
|
14
14
|
> **AI Agent 必读:创建或修改任何适配器之前,你必须先阅读 [CLI-EXPLORER.md](./CLI-EXPLORER.md)!**
|
|
15
|
-
> 该文档包含完整的 API
|
|
15
|
+
> 该文档包含完整的 API 发现工作流(必须使用浏览器探索)、5 级认证策略决策树、平台 SDK 速查表、`tap` 步骤调试流程、分页 API 模板、级联请求模式、以及常见陷阱。
|
|
16
16
|
> **本文件(SKILL.md)仅提供命令参考和简化模板,不足以正确开发适配器。**
|
|
17
17
|
|
|
18
18
|
## Install & Run
|
|
@@ -34,8 +34,8 @@ npm update -g @jackwener/opencli
|
|
|
34
34
|
|
|
35
35
|
Browser commands require:
|
|
36
36
|
1. Chrome browser running **(logged into target sites)**
|
|
37
|
-
2.
|
|
38
|
-
3.
|
|
37
|
+
2. **opencli Browser Bridge** Chrome extension installed (load `extension/` as unpacked in `chrome://extensions`)
|
|
38
|
+
3. No further setup needed — the daemon auto-starts on first browser command
|
|
39
39
|
|
|
40
40
|
> **Note**: You must be logged into the target website in Chrome before running commands. Tabs opened during command execution are auto-closed afterwards.
|
|
41
41
|
|
|
@@ -227,7 +227,7 @@ opencli bilibili hot -v # Show each pipeline step and data flow
|
|
|
227
227
|
|
|
228
228
|
> [!IMPORTANT]
|
|
229
229
|
> **完整模式 — 在写任何代码之前,先阅读 [CLI-EXPLORER.md](./CLI-EXPLORER.md)。**
|
|
230
|
-
> 它包含:① AI Agent
|
|
230
|
+
> 它包含:① AI Agent 浏览器探索工作流 ② 认证策略决策树 ③ 平台 SDK(如 Bilibili 的 `apiGet`/`fetchJson`)④ YAML vs TS 选择指南 ⑤ `tap` 步骤调试方法 ⑥ 级联请求模板 ⑦ 常见陷阱表。
|
|
231
231
|
> **下方仅为简化模板参考,直接使用极易踩坑。**
|
|
232
232
|
|
|
233
233
|
### YAML Pipeline (declarative, recommended)
|
|
@@ -374,16 +374,18 @@ ${{ index + 1 }}
|
|
|
374
374
|
|
|
375
375
|
| Variable | Default | Description |
|
|
376
376
|
|----------|---------|-------------|
|
|
377
|
+
| `OPENCLI_DAEMON_PORT` | 19825 | Daemon listen port |
|
|
377
378
|
| `OPENCLI_BROWSER_CONNECT_TIMEOUT` | 30 | Browser connection timeout (sec) |
|
|
378
379
|
| `OPENCLI_BROWSER_COMMAND_TIMEOUT` | 45 | Command execution timeout (sec) |
|
|
379
380
|
| `OPENCLI_BROWSER_EXPLORE_TIMEOUT` | 120 | Explore timeout (sec) |
|
|
380
|
-
| `
|
|
381
|
+
| `OPENCLI_VERBOSE` | — | Show daemon/extension logs |
|
|
381
382
|
|
|
382
383
|
## Troubleshooting
|
|
383
384
|
|
|
384
385
|
| Issue | Solution |
|
|
385
386
|
|-------|----------|
|
|
386
387
|
| `npx not found` | Install Node.js: `brew install node` |
|
|
387
|
-
| `
|
|
388
|
+
| `Extension not connected` | 1) Chrome must be open 2) Install opencli Browser Bridge extension |
|
|
388
389
|
| `Target page context` error | Add `navigate:` step before `evaluate:` in YAML |
|
|
389
|
-
| Empty table data | Check if evaluate returns
|
|
390
|
+
| Empty table data | Check if evaluate returns correct data path |
|
|
391
|
+
| Daemon issues | `curl localhost:19825/status` to check, `curl localhost:19825/logs` for extension logs |
|
package/TESTING.md
CHANGED
|
@@ -105,10 +105,10 @@ npx vitest src/
|
|
|
105
105
|
|
|
106
106
|
### 浏览器命令本地测试须知
|
|
107
107
|
|
|
108
|
-
-
|
|
108
|
+
- opencli 通过 Browser Bridge 扩展连接已运行的 Chrome 浏览器
|
|
109
109
|
- `browser-public.test.ts` 使用 `tryBrowserCommand()`,站点反爬导致空数据时 warn + pass
|
|
110
110
|
- `browser-auth.test.ts` 验证 **graceful failure**(不 crash 不 hang 即通过)
|
|
111
|
-
- 如需测试完整登录态,保持 Chrome
|
|
111
|
+
- 如需测试完整登录态,保持 Chrome 登录态并安装 Browser Bridge 扩展,手动跑对应测试
|
|
112
112
|
|
|
113
113
|
---
|
|
114
114
|
|
|
@@ -202,12 +202,12 @@ steps:
|
|
|
202
202
|
|
|
203
203
|
## 浏览器模式
|
|
204
204
|
|
|
205
|
-
opencli
|
|
205
|
+
opencli 通过 Browser Bridge 扩展连接浏览器:
|
|
206
206
|
|
|
207
|
-
| 条件 | 模式 |
|
|
208
|
-
|
|
209
|
-
|
|
|
210
|
-
|
|
|
207
|
+
| 条件 | 模式 | 使用场景 |
|
|
208
|
+
|---|---|---|
|
|
209
|
+
| 扩展已安装 | Extension 模式 | 本地用户,连接已登录的 Chrome |
|
|
210
|
+
| 扩展未安装 | CLI 报错提示安装 | 需要安装 Browser Bridge 扩展 |
|
|
211
211
|
|
|
212
212
|
CI 中使用 `OPENCLI_BROWSER_EXECUTABLE_PATH` 指定真实 Chrome 路径:
|
|
213
213
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP client for communicating with the opencli daemon.
|
|
3
|
+
*
|
|
4
|
+
* Provides a typed send() function that posts a Command and returns a Result.
|
|
5
|
+
*/
|
|
6
|
+
export interface DaemonCommand {
|
|
7
|
+
id: string;
|
|
8
|
+
action: 'exec' | 'navigate' | 'tabs' | 'cookies' | 'screenshot' | 'close-window';
|
|
9
|
+
tabId?: number;
|
|
10
|
+
code?: string;
|
|
11
|
+
url?: string;
|
|
12
|
+
op?: string;
|
|
13
|
+
index?: number;
|
|
14
|
+
domain?: string;
|
|
15
|
+
format?: 'png' | 'jpeg';
|
|
16
|
+
quality?: number;
|
|
17
|
+
fullPage?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface DaemonResult {
|
|
20
|
+
id: string;
|
|
21
|
+
ok: boolean;
|
|
22
|
+
data?: unknown;
|
|
23
|
+
error?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Check if daemon is running.
|
|
27
|
+
*/
|
|
28
|
+
export declare function isDaemonRunning(): Promise<boolean>;
|
|
29
|
+
/**
|
|
30
|
+
* Check if daemon is running AND the extension is connected.
|
|
31
|
+
*/
|
|
32
|
+
export declare function isExtensionConnected(): Promise<boolean>;
|
|
33
|
+
/**
|
|
34
|
+
* Send a command to the daemon and wait for a result.
|
|
35
|
+
* Retries up to 3 times with 500ms delay for transient failures.
|
|
36
|
+
*/
|
|
37
|
+
export declare function sendCommand(action: DaemonCommand['action'], params?: Omit<DaemonCommand, 'id' | 'action'>): Promise<unknown>;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP client for communicating with the opencli daemon.
|
|
3
|
+
*
|
|
4
|
+
* Provides a typed send() function that posts a Command and returns a Result.
|
|
5
|
+
*/
|
|
6
|
+
const DAEMON_PORT = parseInt(process.env.OPENCLI_DAEMON_PORT ?? '19825', 10);
|
|
7
|
+
const DAEMON_URL = `http://127.0.0.1:${DAEMON_PORT}`;
|
|
8
|
+
let _idCounter = 0;
|
|
9
|
+
function generateId() {
|
|
10
|
+
return `cmd_${Date.now()}_${++_idCounter}`;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Check if daemon is running.
|
|
14
|
+
*/
|
|
15
|
+
export async function isDaemonRunning() {
|
|
16
|
+
try {
|
|
17
|
+
const controller = new AbortController();
|
|
18
|
+
const timer = setTimeout(() => controller.abort(), 2000);
|
|
19
|
+
const res = await fetch(`${DAEMON_URL}/status`, { signal: controller.signal });
|
|
20
|
+
clearTimeout(timer);
|
|
21
|
+
return res.ok;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Check if daemon is running AND the extension is connected.
|
|
29
|
+
*/
|
|
30
|
+
export async function isExtensionConnected() {
|
|
31
|
+
try {
|
|
32
|
+
const controller = new AbortController();
|
|
33
|
+
const timer = setTimeout(() => controller.abort(), 2000);
|
|
34
|
+
const res = await fetch(`${DAEMON_URL}/status`, { signal: controller.signal });
|
|
35
|
+
clearTimeout(timer);
|
|
36
|
+
if (!res.ok)
|
|
37
|
+
return false;
|
|
38
|
+
const data = await res.json();
|
|
39
|
+
return !!data.extensionConnected;
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Send a command to the daemon and wait for a result.
|
|
47
|
+
* Retries up to 3 times with 500ms delay for transient failures.
|
|
48
|
+
*/
|
|
49
|
+
export async function sendCommand(action, params = {}) {
|
|
50
|
+
const id = generateId();
|
|
51
|
+
const command = { id, action, ...params };
|
|
52
|
+
const maxRetries = 3;
|
|
53
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
54
|
+
try {
|
|
55
|
+
const controller = new AbortController();
|
|
56
|
+
const timer = setTimeout(() => controller.abort(), 30000);
|
|
57
|
+
const res = await fetch(`${DAEMON_URL}/command`, {
|
|
58
|
+
method: 'POST',
|
|
59
|
+
headers: { 'Content-Type': 'application/json' },
|
|
60
|
+
body: JSON.stringify(command),
|
|
61
|
+
signal: controller.signal,
|
|
62
|
+
});
|
|
63
|
+
clearTimeout(timer);
|
|
64
|
+
const result = (await res.json());
|
|
65
|
+
if (!result.ok) {
|
|
66
|
+
throw new Error(result.error ?? 'Daemon command failed');
|
|
67
|
+
}
|
|
68
|
+
return result.data;
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
const isRetryable = err instanceof TypeError // fetch network error
|
|
72
|
+
|| (err instanceof Error && err.name === 'AbortError');
|
|
73
|
+
if (isRetryable && attempt < maxRetries) {
|
|
74
|
+
await new Promise(r => setTimeout(r, 500));
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
throw err;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Unreachable — the loop always returns or throws
|
|
81
|
+
throw new Error('sendCommand: max retries exhausted');
|
|
82
|
+
}
|
|
@@ -1,38 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* MCP server path discovery
|
|
2
|
+
* Daemon discovery — simplified from MCP server path discovery.
|
|
3
|
+
*
|
|
4
|
+
* Only needs to check if the daemon is running. No more file system
|
|
5
|
+
* scanning for @playwright/mcp locations.
|
|
3
6
|
*/
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
export declare function resetMcpServerPathCache(): void;
|
|
7
|
-
export declare function setMcpDiscoveryTestHooks(input?: {
|
|
8
|
-
existsSync?: typeof fs.existsSync;
|
|
9
|
-
execSync?: typeof execSync;
|
|
10
|
-
}): void;
|
|
11
|
-
export declare function findMcpServerPath(): string | null;
|
|
7
|
+
import { isDaemonRunning } from './daemon-client.js';
|
|
8
|
+
export { isDaemonRunning };
|
|
12
9
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* Starting with Chrome 144, users can enable remote debugging from
|
|
16
|
-
* chrome://inspect#remote-debugging without any command-line flags.
|
|
17
|
-
* Chrome writes the active port and browser GUID to a DevToolsActivePort file
|
|
18
|
-
* in the user data directory, which we read to construct the WebSocket endpoint.
|
|
10
|
+
* Check daemon status and return connection info.
|
|
19
11
|
*/
|
|
20
|
-
export declare function
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
25
|
-
export declare function buildMcpArgs(input: {
|
|
26
|
-
mcpPath: string;
|
|
27
|
-
executablePath?: string | null;
|
|
28
|
-
cdpEndpoint?: string;
|
|
29
|
-
}): string[];
|
|
30
|
-
export declare function buildMcpLaunchSpec(input: {
|
|
31
|
-
mcpPath?: string | null;
|
|
32
|
-
executablePath?: string | null;
|
|
33
|
-
cdpEndpoint?: string;
|
|
34
|
-
}): {
|
|
35
|
-
command: string;
|
|
36
|
-
args: string[];
|
|
37
|
-
usedNpxFallback: boolean;
|
|
38
|
-
};
|
|
12
|
+
export declare function checkDaemonStatus(): Promise<{
|
|
13
|
+
running: boolean;
|
|
14
|
+
extensionConnected: boolean;
|
|
15
|
+
}>;
|