@sleepinsummer/agent-browser-cli 0.2.5 → 0.2.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.
- package/AI_INSTALL.md +37 -11
- package/README.md +52 -27
- package/README_EN.md +50 -29
- package/assets/tmwd_cdp_bridge/background.js +98 -10
- package/assets/tmwd_cdp_bridge/config.js +1 -1
- package/assets/tmwd_cdp_bridge/content.js +94 -13
- package/assets/tmwd_cdp_bridge/manifest.json +2 -1
- package/assets/tmwd_cdp_bridge/popup.html +17 -2
- package/assets/tmwd_cdp_bridge/popup.js +41 -2
- package/npm/bin/agent-browser-cli.js +1 -0
- package/package.json +6 -5
- package/skills/agent-browser-cli/SKILL.md +27 -4
package/AI_INSTALL.md
CHANGED
|
@@ -7,11 +7,12 @@
|
|
|
7
7
|
|
|
8
8
|
要求:
|
|
9
9
|
1. 优先使用 npm 安装:npm install -g @sleepinsummer/agent-browser-cli。
|
|
10
|
-
2.
|
|
11
|
-
3.
|
|
12
|
-
4.
|
|
13
|
-
5.
|
|
14
|
-
6.
|
|
10
|
+
2. 先询问我希望把 Chrome 扩展解压到哪个本地目录。
|
|
11
|
+
3. 从 GitHub 最新 Release 下载 `chrome-extensions.zip`,解压到我指定的目录,并指导我在 Chrome 中加载解压后的 `tmwd_cdp_bridge` 扩展目录。
|
|
12
|
+
4. 如果之前已经加载过扩展,必须在 chrome://extensions 里重新加载该扩展,确保最新 `config.js`、`content.js` 和 `background.js` 生效。
|
|
13
|
+
5. 将 skills/agent-browser-cli/SKILL.md 安装到当前 AI 可识别的 skills 目录。
|
|
14
|
+
6. 执行 agent-browser-cli tabs、open 和 status 验证可用。
|
|
15
|
+
7. 如果 npm 平台包暂不支持当前系统,再回退到源码构建:cargo build --release。
|
|
15
16
|
```
|
|
16
17
|
|
|
17
18
|
## 1. 安装 CLI
|
|
@@ -29,9 +30,20 @@ agent-browser-cli --help
|
|
|
29
30
|
@sleepinsummer/agent-browser-cli
|
|
30
31
|
@sleepinsummer/agent-browser-cli-darwin-arm64
|
|
31
32
|
@sleepinsummer/agent-browser-cli-darwin-x64
|
|
33
|
+
@sleepinsummer/agent-browser-cli-linux-x64
|
|
32
34
|
@sleepinsummer/agent-browser-cli-win32-x64
|
|
33
35
|
```
|
|
34
36
|
|
|
37
|
+
Linux 使用前请确认本机 Chrome / Chromium 支持安装扩展。
|
|
38
|
+
|
|
39
|
+
如果在 WSL 中使用,当前版本依赖 WSL 访问宿主机 `localhost` 上的 Chrome 桥接服务。建议环境:
|
|
40
|
+
|
|
41
|
+
```text
|
|
42
|
+
WSL 2.0.0+
|
|
43
|
+
Windows 11 22H2+
|
|
44
|
+
.wslconfig 中启用 networkingMode=mirrored
|
|
45
|
+
```
|
|
46
|
+
|
|
35
47
|
如果当前平台包暂未发布或安装失败,使用源码构建:
|
|
36
48
|
|
|
37
49
|
```bash
|
|
@@ -43,11 +55,26 @@ cargo build --release
|
|
|
43
55
|
|
|
44
56
|
## 2. 加载 Chrome 扩展
|
|
45
57
|
|
|
46
|
-
|
|
58
|
+
先询问用户希望把扩展解压到哪个本地目录,例如:
|
|
59
|
+
|
|
60
|
+
```text
|
|
61
|
+
请告诉我 Chrome 扩展希望解压到哪个目录,例如 ~/agent-browser-cli-extension。
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
然后下载最新 Release 中的 `chrome-extensions.zip` 并解压到该目录。zip 解压后内部目录仍是 `tmwd_cdp_bridge`:
|
|
47
65
|
|
|
48
66
|
```bash
|
|
49
|
-
|
|
50
|
-
|
|
67
|
+
EXT_PARENT="$HOME/agent-browser-cli-extension"
|
|
68
|
+
mkdir -p "$EXT_PARENT"
|
|
69
|
+
ZIP_URL="$(curl -fsSL https://api.github.com/repos/sleepinginsummer/agent-browser-cli/releases/latest | grep -o '"browser_download_url": "[^"]*chrome-extensions.zip"' | head -n 1 | cut -d '"' -f 4)"
|
|
70
|
+
curl -fL "$ZIP_URL" -o "$EXT_PARENT/chrome-extensions.zip"
|
|
71
|
+
unzip -o "$EXT_PARENT/chrome-extensions.zip" -d "$EXT_PARENT"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
解压后扩展目录应为:
|
|
75
|
+
|
|
76
|
+
```text
|
|
77
|
+
$EXT_PARENT/tmwd_cdp_bridge
|
|
51
78
|
```
|
|
52
79
|
|
|
53
80
|
在 Chrome 打开:
|
|
@@ -59,10 +86,10 @@ chrome://extensions
|
|
|
59
86
|
开启“开发者模式”,加载已解压扩展目录:
|
|
60
87
|
|
|
61
88
|
```text
|
|
62
|
-
|
|
89
|
+
$EXT_PARENT/tmwd_cdp_bridge
|
|
63
90
|
```
|
|
64
91
|
|
|
65
|
-
如果之前已经安装过旧版 GenericAgent 的 `tmwd_cdp_bridge`
|
|
92
|
+
如果之前已经安装过旧版 GenericAgent 的 `tmwd_cdp_bridge` 扩展,可以继续使用同协议旧扩展;但建议加载最新 Release 解压出来的 `tmwd_cdp_bridge` 并点击“重新加载”。
|
|
66
93
|
|
|
67
94
|
当前扩展配置应包含:
|
|
68
95
|
|
|
@@ -123,4 +150,3 @@ agent-browser-cli exec --tab <tabId> 'return document.title'
|
|
|
123
150
|
```text
|
|
124
151
|
skills/agent-browser-cli/SKILL.md
|
|
125
152
|
```
|
|
126
|
-
|
package/README.md
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
<p>
|
|
10
10
|
<a href="https://github.com/sleepinginsummer/agent-browser-cli"><img src="https://img.shields.io/badge/CLI-agentbrowsercli-2ea44f" alt="CLI agentbrowsercli"></a>
|
|
11
11
|
<a href="https://github.com/sleepinginsummer/agent-browser-cli/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-MIT-green" alt="License MIT"></a>
|
|
12
|
-
<a href="https://github.com/sleepinginsummer/agent-browser-cli"><img src="https://img.shields.io/badge/sys-win%2Fmac-0078D6?labelColor=0078D6&color=C0C0C0" alt="sys win/mac"></a>
|
|
13
|
-
<a href="https://github.com/sleepinginsummer/agent-browser-cli/releases"><img src="https://img.shields.io/badge/release-v0.2.
|
|
12
|
+
<a href="https://github.com/sleepinginsummer/agent-browser-cli"><img src="https://img.shields.io/badge/sys-win%2Fmac%2Flinux-0078D6?labelColor=0078D6&color=C0C0C0" alt="sys win/mac/linux"></a>
|
|
13
|
+
<a href="https://github.com/sleepinginsummer/agent-browser-cli/releases"><img src="https://img.shields.io/badge/release-v0.2.8-blue" alt="release v0.2.8"></a>
|
|
14
14
|
<a href="https://github.com/sleepinginsummer/agent-browser-cli/pulls"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen" alt="PRs welcome"></a>
|
|
15
15
|
</p>
|
|
16
16
|
|
|
@@ -26,9 +26,11 @@
|
|
|
26
26
|
|
|
27
27
|
## 项目信息
|
|
28
28
|
|
|
29
|
-
- 当前版本:`0.2.
|
|
30
|
-
- 支持平台:
|
|
31
|
-
- 浏览器:Chrome
|
|
29
|
+
- 当前版本:`0.2.8`
|
|
30
|
+
- 支持平台:Windows(包括 WSL)/ Mac / Linux
|
|
31
|
+
- 浏览器:Chrome,需加载拓展 `assets/tmwd_cdp_bridge`
|
|
32
|
+
- Linux 支持前提:本机 Chrome / Chromium 需要支持安装扩展
|
|
33
|
+
- WSL 支持前提:需使用 `WSL 2.0.0+`,并建议在 Windows `11 22H2+` 下启用 `networkingMode=mirrored`,以便 WSL 连接宿主机 `localhost` 上的 Chrome 桥接服务
|
|
32
34
|
|
|
33
35
|
## 致谢
|
|
34
36
|
|
|
@@ -110,13 +112,51 @@ cargo build --release
|
|
|
110
112
|
|
|
111
113
|
## Chrome 扩展
|
|
112
114
|
|
|
113
|
-
|
|
115
|
+
1. 推荐从 [最新 Release](https://github.com/sleepinginsummer/agent-browser-cli/releases/latest) 下载 `chrome-extensions.zip`,下载后解压,Chrome 打开 `chrome://extensions`,开启“开发者模式”,点击“加载已解压的扩展程序”,选择解压后的 `tmwd_cdp_bridge` 目录。
|
|
116
|
+
|
|
117
|
+
2. 本地源码构建时,也可以直接加载扩展目录:
|
|
114
118
|
|
|
115
119
|
```text
|
|
116
120
|
assets/tmwd_cdp_bridge
|
|
117
121
|
```
|
|
118
122
|
|
|
119
|
-
Chrome 需要至少打开一个正常网页标签页,不要只停留在 `about:blank` 或 `chrome://` 页面。
|
|
123
|
+
3. Chrome 需要至少打开一个正常网页标签页,不要只停留在 `about:blank` 或 `chrome://` 页面。
|
|
124
|
+
4. 扩展连接后会在页面右侧显示 Chrome 插件提示角标。角标支持拖动位置,鼠标悬浮时展开;10 秒无命令后自动隐藏,也可以点击 `本次隐藏` 手动隐藏,本次服务连接周期内不再显示,约 300 秒服务断开并下次重连后恢复。
|
|
125
|
+
|
|
126
|
+
### 自定义Chrome插件的ws监听端口
|
|
127
|
+
|
|
128
|
+
- `18765`:默认插件 WebSocket 端口,Chrome 扩展连接使用,可通过 `agent-browser-cli set-extension-port <port>` 修改。
|
|
129
|
+
- `18767`:CLI HTTP API 端口,供 CLI 复用会话,不能作为插件端口使用。
|
|
130
|
+
|
|
131
|
+
CLI 修改插件端口:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
agent-browser-cli set-extension-port 18766
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
该命令会写入配置文件;如果 daemon 正在运行,会自动重启 daemon,让新端口立即生效。
|
|
138
|
+
|
|
139
|
+
也可以手动修改配置文件。配置文件位于 `~/.agent-browser-cli/config.json`,不存在时会自动生成:
|
|
140
|
+
|
|
141
|
+
```json
|
|
142
|
+
{
|
|
143
|
+
"extension_port": 18765
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
手动修改示例:
|
|
148
|
+
|
|
149
|
+
```json
|
|
150
|
+
{
|
|
151
|
+
"extension_port": 18766
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
手动改配置后需要执行 `agent-browser-cli restart`,daemon 才会按新端口重新监听。
|
|
156
|
+
|
|
157
|
+
Chrome 插件 popup 中也可以修改插件端口并立即重连。插件端口必须和 CLI 配置中的 `extension_port` 一致。
|
|
158
|
+
|
|
159
|
+
|
|
120
160
|
|
|
121
161
|
## 快速自检
|
|
122
162
|
|
|
@@ -149,26 +189,13 @@ agent-browser-cli tabs
|
|
|
149
189
|
|
|
150
190
|
## 更新
|
|
151
191
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
./target/release/agent-browser-cli restart
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
如果 Chrome 扩展有更新,在 `chrome://extensions` 中重新加载 `assets/tmwd_cdp_bridge` 扩展。
|
|
159
|
-
|
|
160
|
-
当前扩展配置标识为:
|
|
161
|
-
|
|
162
|
-
```js
|
|
163
|
-
const TID = '__agent_browser_cli_bridge_26c9f1';
|
|
192
|
+
ai一句话更新
|
|
193
|
+
```text
|
|
194
|
+
请阅读 https://github.com/sleepinginsummer/agent-browser-cli/blob/main/AI_INSTALL.md,按说明更新 CLI、重新下载插件zip让用户指定位置,用户手动加载 Chrome 扩展,并更新相关 SKILL.md`。
|
|
164
195
|
```
|
|
165
196
|
|
|
166
|
-
|
|
197
|
+
如果 Chrome 扩展有更新,在 `chrome://extensions` 中重新下载zpi覆盖,然后重新加载 `assets/tmwd_cdp_bridge` 扩展。
|
|
167
198
|
|
|
168
|
-
```bash
|
|
169
|
-
mkdir -p ~/.agents/skills/agent-browser-cli
|
|
170
|
-
cp skills/agent-browser-cli/SKILL.md ~/.agents/skills/agent-browser-cli/SKILL.md
|
|
171
|
-
```
|
|
172
199
|
|
|
173
200
|
## 卸载
|
|
174
201
|
|
|
@@ -187,14 +214,12 @@ rm -rf ~/.agents/skills/agent-browser-cli
|
|
|
187
214
|
|
|
188
215
|
最后在 Chrome 扩展管理页中移除 `TMWD CDP Bridge` 扩展,或删除已加载的 `assets/tmwd_cdp_bridge` 扩展配置。
|
|
189
216
|
|
|
190
|
-
## 端口
|
|
191
217
|
|
|
192
|
-
- `18765`:底层 `TMWebDriver` WebSocket,Chrome 扩展连接使用。
|
|
193
|
-
- `18767`:外层 `agent-browser-cli` HTTP 服务,供 CLI 复用会话。
|
|
194
218
|
|
|
195
219
|
## 友情链接
|
|
196
220
|
|
|
197
221
|
- [LINUX DO - 新的理想型社区](https://linux.do/)
|
|
222
|
+
- [GenericAgent--复旦团队研发|仅仅~3K行代码 Self-Evolving Agent](https://github.com/lsdefine/GenericAgent/tree/main)
|
|
198
223
|
|
|
199
224
|
## 许可证
|
|
200
225
|
|
package/README_EN.md
CHANGED
|
@@ -9,8 +9,8 @@ Browser perception · Page control · Chrome session reuse · CDP · Conditional
|
|
|
9
9
|
<p>
|
|
10
10
|
<a href="https://github.com/sleepinginsummer/agent-browser-cli"><img src="https://img.shields.io/badge/CLI-agentbrowsercli-2ea44f" alt="CLI agentbrowsercli"></a>
|
|
11
11
|
<a href="https://github.com/sleepinginsummer/agent-browser-cli/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-MIT-green" alt="License MIT"></a>
|
|
12
|
-
<a href="https://github.com/sleepinginsummer/agent-browser-cli"><img src="https://img.shields.io/badge/sys-win%2Fmac-0078D6?labelColor=0078D6&color=C0C0C0" alt="sys win/mac"></a>
|
|
13
|
-
<a href="https://github.com/sleepinginsummer/agent-browser-cli/releases"><img src="https://img.shields.io/badge/release-v0.2.
|
|
12
|
+
<a href="https://github.com/sleepinginsummer/agent-browser-cli"><img src="https://img.shields.io/badge/sys-win%2Fmac%2Flinux-0078D6?labelColor=0078D6&color=C0C0C0" alt="sys win/mac/linux"></a>
|
|
13
|
+
<a href="https://github.com/sleepinginsummer/agent-browser-cli/releases"><img src="https://img.shields.io/badge/release-v0.2.8-blue" alt="release v0.2.8"></a>
|
|
14
14
|
<a href="https://github.com/sleepinginsummer/agent-browser-cli/pulls"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen" alt="PRs welcome"></a>
|
|
15
15
|
</p>
|
|
16
16
|
|
|
@@ -26,9 +26,11 @@ This project is not Selenium or Playwright. It is better suited for helping agen
|
|
|
26
26
|
|
|
27
27
|
## Project Info
|
|
28
28
|
|
|
29
|
-
- Current version: `0.2.
|
|
30
|
-
- Supported platforms:
|
|
31
|
-
- Browser: Chrome
|
|
29
|
+
- Current version: `0.2.8`
|
|
30
|
+
- Supported platforms: Windows (including WSL) / Mac / Linux
|
|
31
|
+
- Browser: Chrome, with the `assets/tmwd_cdp_bridge` extension loaded
|
|
32
|
+
- Linux prerequisite: the local Chrome / Chromium build must support loading extensions
|
|
33
|
+
- WSL prerequisite: use `WSL 2.0.0+`, and preferably enable `networkingMode=mirrored` on Windows `11 22H2+` so WSL can reach the host Chrome bridge service on `localhost`
|
|
32
34
|
|
|
33
35
|
## Acknowledgements
|
|
34
36
|
|
|
@@ -110,13 +112,49 @@ cargo build --release
|
|
|
110
112
|
|
|
111
113
|
## Chrome Extension
|
|
112
114
|
|
|
113
|
-
Load
|
|
115
|
+
1. Recommended: download `chrome-extensions.zip` from the [latest Release](https://github.com/sleepinginsummer/agent-browser-cli/releases/latest), extract it, open `chrome://extensions` in Chrome, enable `Developer mode`, click `Load unpacked`, and select the extracted `tmwd_cdp_bridge` directory.
|
|
116
|
+
|
|
117
|
+
2. When building from local source, you can also load this extension directory directly:
|
|
114
118
|
|
|
115
119
|
```text
|
|
116
120
|
assets/tmwd_cdp_bridge
|
|
117
121
|
```
|
|
118
122
|
|
|
119
|
-
Chrome needs at least one normal web page tab open. Do not leave it only on `about:blank` or `chrome://` pages.
|
|
123
|
+
3. Chrome needs at least one normal web page tab open. Do not leave it only on `about:blank` or `chrome://` pages.
|
|
124
|
+
4. After the extension is connected, a Chrome extension tip badge appears on the right side of the page. The badge position is draggable and expands on hover. It auto-hides after 10 seconds without commands, and you can also click `Hide for this session` to hide it manually. Manual hiding lasts for the current service connection cycle and resets after the service disconnects after about 300 seconds and reconnects.
|
|
125
|
+
|
|
126
|
+
### Custom Chrome Extension WebSocket Port
|
|
127
|
+
|
|
128
|
+
- `18765`: default extension WebSocket port, used by the Chrome extension. It can be changed with `agent-browser-cli set-extension-port <port>`.
|
|
129
|
+
- `18767`: CLI HTTP API port, used by the CLI to reuse the session. It cannot be used as the extension port.
|
|
130
|
+
|
|
131
|
+
Change the extension port from CLI:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
agent-browser-cli set-extension-port 18766
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
This command writes the config file. If the daemon is running, it restarts the daemon so the new port takes effect immediately.
|
|
138
|
+
|
|
139
|
+
You can also edit the config file manually. The config file is `~/.agent-browser-cli/config.json`. It is created automatically when missing:
|
|
140
|
+
|
|
141
|
+
```json
|
|
142
|
+
{
|
|
143
|
+
"extension_port": 18765
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Manual edit example:
|
|
148
|
+
|
|
149
|
+
```json
|
|
150
|
+
{
|
|
151
|
+
"extension_port": 18766
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
After manually editing the config file, run `agent-browser-cli restart` so the daemon listens on the new port.
|
|
156
|
+
|
|
157
|
+
The Chrome extension popup can also update the extension port and reconnect immediately. The popup port must match the CLI `extension_port` config.
|
|
120
158
|
|
|
121
159
|
## Quick Check
|
|
122
160
|
|
|
@@ -149,26 +187,13 @@ agent-browser-cli tabs
|
|
|
149
187
|
|
|
150
188
|
## Update
|
|
151
189
|
|
|
152
|
-
|
|
153
|
-
git pull
|
|
154
|
-
cargo build --release
|
|
155
|
-
./target/release/agent-browser-cli restart
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
If the Chrome extension has updates, reload the `assets/tmwd_cdp_bridge` extension in `chrome://extensions`.
|
|
159
|
-
|
|
160
|
-
Current extension bridge identifier:
|
|
190
|
+
AI one-line update:
|
|
161
191
|
|
|
162
|
-
```
|
|
163
|
-
|
|
192
|
+
```text
|
|
193
|
+
Please read https://github.com/sleepinginsummer/agent-browser-cli/blob/main/AI_INSTALL.md, follow the instructions to update the CLI, download the extension zip again to the user-specified location, ask the user to manually load the Chrome extension, and update the related SKILL.md.
|
|
164
194
|
```
|
|
165
195
|
|
|
166
|
-
If
|
|
167
|
-
|
|
168
|
-
```bash
|
|
169
|
-
mkdir -p ~/.agents/skills/agent-browser-cli
|
|
170
|
-
cp skills/agent-browser-cli/SKILL.md ~/.agents/skills/agent-browser-cli/SKILL.md
|
|
171
|
-
```
|
|
196
|
+
If the Chrome extension has updates, download the zip again, overwrite the existing files, and reload the `assets/tmwd_cdp_bridge` extension in `chrome://extensions`.
|
|
172
197
|
|
|
173
198
|
## Uninstall
|
|
174
199
|
|
|
@@ -187,14 +212,10 @@ rm -rf ~/.agents/skills/agent-browser-cli
|
|
|
187
212
|
|
|
188
213
|
Finally, remove the `TMWD CDP Bridge` extension from Chrome's extension management page, or remove the loaded `assets/tmwd_cdp_bridge` extension configuration.
|
|
189
214
|
|
|
190
|
-
## Ports
|
|
191
|
-
|
|
192
|
-
- `18765`: underlying `TMWebDriver` WebSocket, used by the Chrome extension.
|
|
193
|
-
- `18767`: outer `agent-browser-cli` HTTP service, used by the CLI to reuse the session.
|
|
194
|
-
|
|
195
215
|
## Friendly Links
|
|
196
216
|
|
|
197
217
|
- [LINUX DO - A New Ideal Community](https://linux.do/)
|
|
218
|
+
- [GenericAgent--复旦团队研发|仅仅~3K行代码 Self-Evolving Agent](https://github.com/lsdefine/GenericAgent/tree/main)
|
|
198
219
|
|
|
199
220
|
## License
|
|
200
221
|
|
|
@@ -15,8 +15,15 @@ chrome.runtime.onInstalled.addListener(() => {
|
|
|
15
15
|
});
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
+
let lastCommandAt = 0;
|
|
19
|
+
const DEFAULT_WS_PORT = 18765;
|
|
20
|
+
const CLI_API_PORT = 18767;
|
|
21
|
+
let wsPort = DEFAULT_WS_PORT;
|
|
22
|
+
|
|
18
23
|
async function handleExtMessage(msg, sender) {
|
|
19
24
|
if (msg.cmd === 'status') return handleStatus();
|
|
25
|
+
if (msg.cmd === 'setPort') return await handleSetPort(msg);
|
|
26
|
+
lastCommandAt = Date.now();
|
|
20
27
|
if (msg.cmd === 'cookies') return await handleCookies(msg, sender);
|
|
21
28
|
if (msg.cmd === 'cdp') return await handleCDP(msg, sender);
|
|
22
29
|
if (msg.cmd === 'batch') return await handleBatch(msg, sender);
|
|
@@ -75,7 +82,23 @@ function handleStatus() {
|
|
|
75
82
|
ok: true,
|
|
76
83
|
data: {
|
|
77
84
|
wsConnected: !!ws && ws.readyState === WebSocket.OPEN,
|
|
78
|
-
wsUrl:
|
|
85
|
+
wsUrl: getWsUrl(),
|
|
86
|
+
wsPort,
|
|
87
|
+
lastCommandAt
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function handleSetPort(msg) {
|
|
93
|
+
const port = normalizePort(msg.port);
|
|
94
|
+
await saveWsPort(port);
|
|
95
|
+
reconnectWS();
|
|
96
|
+
return {
|
|
97
|
+
ok: true,
|
|
98
|
+
data: {
|
|
99
|
+
wsPort,
|
|
100
|
+
wsUrl: getWsUrl(),
|
|
101
|
+
wsConnected: !!ws && ws.readyState === WebSocket.OPEN
|
|
79
102
|
}
|
|
80
103
|
};
|
|
81
104
|
}
|
|
@@ -173,6 +196,20 @@ async function handleCDP(msg, sender) {
|
|
|
173
196
|
// Filter out chrome:// and other internal tabs that can't be scripted
|
|
174
197
|
const isScriptable = url => url && /^https?:/.test(url);
|
|
175
198
|
|
|
199
|
+
async function injectContentScriptsIntoExistingTabs() {
|
|
200
|
+
const tabs = (await chrome.tabs.query({})).filter(t => isScriptable(t.url));
|
|
201
|
+
for (const tab of tabs) {
|
|
202
|
+
try {
|
|
203
|
+
await chrome.scripting.executeScript({
|
|
204
|
+
target: { tabId: tab.id, allFrames: true },
|
|
205
|
+
files: ['config.js', 'content.js']
|
|
206
|
+
});
|
|
207
|
+
} catch (e) {
|
|
208
|
+
console.log('[TMWD-WS] Inject content script failed:', tab.id, e.message);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
176
213
|
// --- Shared page/CDP script builder core ---
|
|
177
214
|
function buildExecScript(code, errorHandler) {
|
|
178
215
|
return `(async () => {
|
|
@@ -232,11 +269,36 @@ function buildCdpScript(code) {
|
|
|
232
269
|
|
|
233
270
|
// --- WebSocket Client for TMWebDriver ---
|
|
234
271
|
let ws = null;
|
|
235
|
-
|
|
272
|
+
|
|
273
|
+
function normalizePort(port) {
|
|
274
|
+
const value = Number(port);
|
|
275
|
+
if (!Number.isInteger(value) || value < 1 || value > 65535) {
|
|
276
|
+
throw new Error('端口必须是 1-65535');
|
|
277
|
+
}
|
|
278
|
+
if (value === CLI_API_PORT) {
|
|
279
|
+
throw new Error('18767 是 agent-browser-cli API 端口,请换一个插件端口');
|
|
280
|
+
}
|
|
281
|
+
return value;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
async function loadWsPort() {
|
|
285
|
+
const data = await chrome.storage.local.get({ wsPort: DEFAULT_WS_PORT });
|
|
286
|
+
wsPort = normalizePort(data.wsPort);
|
|
287
|
+
return wsPort;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
async function saveWsPort(port) {
|
|
291
|
+
wsPort = normalizePort(port);
|
|
292
|
+
await chrome.storage.local.set({ wsPort });
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function getWsUrl() {
|
|
296
|
+
return `ws://127.0.0.1:${wsPort}`;
|
|
297
|
+
}
|
|
236
298
|
|
|
237
299
|
function scheduleProbe() {
|
|
238
300
|
// Use chrome.alarms to survive MV3 service worker suspension
|
|
239
|
-
chrome.alarms.create('tmwd-ws-probe', { delayInMinutes: 0.
|
|
301
|
+
chrome.alarms.create('tmwd-ws-probe', { delayInMinutes: 0.017 }); // ~1s
|
|
240
302
|
}
|
|
241
303
|
|
|
242
304
|
function scheduleKeepalive() {
|
|
@@ -248,7 +310,7 @@ async function isServerAlive() {
|
|
|
248
310
|
try {
|
|
249
311
|
const ctrl = new AbortController();
|
|
250
312
|
setTimeout(() => ctrl.abort(), 2000);
|
|
251
|
-
await fetch(
|
|
313
|
+
await fetch(`http://127.0.0.1:${wsPort}`, { signal: ctrl.signal });
|
|
252
314
|
return true; // Got HTTP response → port is listening
|
|
253
315
|
} catch (e) {
|
|
254
316
|
return false; // Network error (connection refused) or timeout → server not alive
|
|
@@ -354,12 +416,20 @@ async function handleWsExec(data) {
|
|
|
354
416
|
}
|
|
355
417
|
}
|
|
356
418
|
|
|
357
|
-
function connectWS() {
|
|
419
|
+
async function connectWS() {
|
|
420
|
+
await loadWsPort();
|
|
358
421
|
if (ws && ws.readyState <= 1) return; // CONNECTING or OPEN
|
|
422
|
+
if (!(await isServerAlive())) {
|
|
423
|
+
console.warn('[TMWD-WS] Server not ready, retrying later:', getWsUrl());
|
|
424
|
+
ws = null;
|
|
425
|
+
scheduleProbe();
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
359
428
|
ws = null;
|
|
360
|
-
|
|
429
|
+
const wsUrl = getWsUrl();
|
|
430
|
+
console.log('[TMWD-WS] Connecting to', wsUrl);
|
|
361
431
|
try {
|
|
362
|
-
ws = new WebSocket(
|
|
432
|
+
ws = new WebSocket(wsUrl);
|
|
363
433
|
} catch (e) {
|
|
364
434
|
console.error('[TMWD-WS] Constructor error:', e);
|
|
365
435
|
ws = null;
|
|
@@ -380,6 +450,7 @@ function connectWS() {
|
|
|
380
450
|
try {
|
|
381
451
|
const data = JSON.parse(event.data);
|
|
382
452
|
if (data.id && data.code) {
|
|
453
|
+
lastCommandAt = Date.now();
|
|
383
454
|
let code = data.code;
|
|
384
455
|
// If code is a JSON string representing an object, parse it
|
|
385
456
|
if (typeof code === 'string') {
|
|
@@ -410,15 +481,32 @@ function connectWS() {
|
|
|
410
481
|
scheduleProbe();
|
|
411
482
|
};
|
|
412
483
|
ws.onerror = (e) => {
|
|
413
|
-
console.
|
|
484
|
+
console.warn('[TMWD-WS] Connection warning:', e);
|
|
414
485
|
// onclose will fire after this, which triggers reconnect
|
|
415
486
|
};
|
|
416
487
|
}
|
|
417
488
|
|
|
489
|
+
function reconnectWS() {
|
|
490
|
+
if (ws) {
|
|
491
|
+
try { ws.onclose = null; ws.close(); } catch (_) {}
|
|
492
|
+
}
|
|
493
|
+
ws = null;
|
|
494
|
+
chrome.alarms.clear('tmwd-ws-probe');
|
|
495
|
+
chrome.alarms.clear('tmwd-ws-keepalive');
|
|
496
|
+
connectWS();
|
|
497
|
+
}
|
|
498
|
+
|
|
418
499
|
// Initial connect + wake-up hooks
|
|
419
500
|
connectWS();
|
|
420
|
-
|
|
421
|
-
chrome.runtime.
|
|
501
|
+
injectContentScriptsIntoExistingTabs();
|
|
502
|
+
chrome.runtime.onStartup.addListener(() => {
|
|
503
|
+
connectWS();
|
|
504
|
+
injectContentScriptsIntoExistingTabs();
|
|
505
|
+
});
|
|
506
|
+
chrome.runtime.onInstalled.addListener(() => {
|
|
507
|
+
connectWS();
|
|
508
|
+
injectContentScriptsIntoExistingTabs();
|
|
509
|
+
});
|
|
422
510
|
|
|
423
511
|
// Sync tab list on changes
|
|
424
512
|
async function sendTabsUpdate() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
globalThis.__agent_browser_cli_TID = '__agent_browser_cli_bridge_26c9f1';
|
|
@@ -1,27 +1,64 @@
|
|
|
1
1
|
;(function(){ if (/streamlit/i.test(document.title)) return;
|
|
2
|
+
const TID = globalThis.__agent_browser_cli_TID || '__agent_browser_cli_bridge_26c9f1';
|
|
3
|
+
if (window.__agentBrowserCliCleanup) window.__agentBrowserCliCleanup();
|
|
4
|
+
if (window.__agentBrowserCliObserverCleanup) window.__agentBrowserCliObserverCleanup();
|
|
5
|
+
document.querySelectorAll('#agent-browser-cli-ind,#agent-browser-cli-style').forEach(e => e.remove());
|
|
2
6
|
|
|
3
7
|
// Remove meta CSP tags
|
|
4
8
|
document.querySelectorAll('meta[http-equiv="Content-Security-Policy"]').forEach(e => e.remove());
|
|
5
9
|
|
|
6
10
|
/**
|
|
7
|
-
* Render a
|
|
11
|
+
* Render a right-side floating badge that reflects the real bridge connection status.
|
|
8
12
|
*/
|
|
9
13
|
(function(){
|
|
10
14
|
if(window.self!==window.top)return;
|
|
15
|
+
const s=document.createElement('style');
|
|
16
|
+
s.id='agent-browser-cli-style';
|
|
17
|
+
s.textContent='#agent-browser-cli-ind{position:fixed;top:40%;right:0;display:flex;align-items:center;gap:10px;width:218px;height:36px;box-sizing:border-box;padding:0 8px 0 9px;color:white;border-radius:18px 0 0 18px;font-size:11px;font-weight:bold;line-height:36px;z-index:99999;cursor:grab;box-shadow:0 4px 12px rgba(0,0,0,0.22);background:#4CAF50;opacity:.72;overflow:visible;white-space:nowrap;user-select:none;transform:translateX(190px);transition:transform .18s ease,opacity .18s ease;}#agent-browser-cli-ind::after{content:"";position:absolute;inset:0;border-radius:18px 0 0 18px;background:#4CAF50;z-index:-1;}#agent-browser-cli-dot{flex:0 0 auto;width:10px;height:10px;border-radius:999px;background:white;}#agent-browser-cli-label{flex:0 0 auto;max-width:150px;overflow:hidden;}#agent-browser-cli-ind[data-expanded="1"]{opacity:.92;transform:translateX(0);}#agent-browser-cli-ind[data-dragging="1"]{cursor:grabbing;transition:none;}#agent-browser-cli-close{position:relative;flex:0 0 auto;width:20px;height:20px;border-radius:999px;line-height:18px;text-align:center;font-size:15px;font-weight:bold;background:#1f7a33;color:white;opacity:0;pointer-events:none;cursor:pointer;}#agent-browser-cli-ind[data-expanded="1"] #agent-browser-cli-close{opacity:1;pointer-events:auto;}#agent-browser-cli-close:hover{background:#145523;}#agent-browser-cli-close::after{content:"本次隐藏";position:absolute;right:0;bottom:28px;padding:4px 7px;border-radius:4px;background:#1f2937;color:white;font-size:12px;font-weight:500;line-height:16px;opacity:0;pointer-events:none;transform:translateY(4px);transition:opacity .12s ease,transform .12s ease;}#agent-browser-cli-close:hover::after{opacity:1;transform:translateY(0);}';
|
|
18
|
+
(document.head||document.documentElement).appendChild(s);
|
|
11
19
|
const d=document.createElement('div');
|
|
12
20
|
d.id='agent-browser-cli-ind';
|
|
13
|
-
|
|
21
|
+
const dot=document.createElement('span');
|
|
22
|
+
dot.id='agent-browser-cli-dot';
|
|
23
|
+
const label=document.createElement('span');
|
|
24
|
+
label.id='agent-browser-cli-label';
|
|
25
|
+
label.textContent='agent_browser_cli: 已连接';
|
|
26
|
+
const close=document.createElement('span');
|
|
27
|
+
close.id='agent-browser-cli-close';
|
|
28
|
+
close.textContent='×';
|
|
29
|
+
d.appendChild(dot);
|
|
30
|
+
d.appendChild(label);
|
|
31
|
+
d.appendChild(close);
|
|
32
|
+
let collapseTimer = null;
|
|
33
|
+
let dragging = false;
|
|
34
|
+
let moved = false;
|
|
35
|
+
let dragOffsetY = 0;
|
|
36
|
+
let dismissed = false;
|
|
37
|
+
let wasConnected = false;
|
|
38
|
+
let lastSeenCommandAt = 0;
|
|
39
|
+
let lastTop = Math.round(window.innerHeight * 0.4);
|
|
40
|
+
d.style.top = lastTop + 'px';
|
|
14
41
|
/**
|
|
15
42
|
* Show the badge only when the bridge is really connected.
|
|
16
43
|
*/
|
|
17
|
-
function setBadgeState(connected, detail) {
|
|
18
|
-
//
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
44
|
+
function setBadgeState(connected, detail, lastCommandAt) {
|
|
45
|
+
// 手动关闭只在当前连接周期生效;断开后下次重新连接会再次显示。
|
|
46
|
+
if (connected && !wasConnected) dismissed = false;
|
|
47
|
+
wasConnected = connected;
|
|
48
|
+
const commandAt = Number(lastCommandAt) || 0;
|
|
49
|
+
if (commandAt > lastSeenCommandAt) lastSeenCommandAt = commandAt;
|
|
50
|
+
const activeRecently = lastSeenCommandAt > 0 && Date.now() - lastSeenCommandAt <= 10000;
|
|
51
|
+
d.style.display = connected && !dismissed && activeRecently ? 'flex' : 'none';
|
|
52
|
+
label.textContent = 'agent_browser_cli: 已连接';
|
|
22
53
|
d.dataset.connected = connected ? '1' : '0';
|
|
23
54
|
d.dataset.detail = detail || '';
|
|
24
55
|
}
|
|
56
|
+
function setExpanded(expanded) {
|
|
57
|
+
d.dataset.expanded = expanded ? '1' : '0';
|
|
58
|
+
}
|
|
59
|
+
function clampTop(top) {
|
|
60
|
+
return Math.max(8, Math.min(window.innerHeight - d.offsetHeight - 8, top));
|
|
61
|
+
}
|
|
25
62
|
/**
|
|
26
63
|
* Poll background status and update the badge visibility.
|
|
27
64
|
*/
|
|
@@ -29,26 +66,70 @@ document.querySelectorAll('meta[http-equiv="Content-Security-Policy"]').forEach(
|
|
|
29
66
|
try {
|
|
30
67
|
const resp = await chrome.runtime.sendMessage({ cmd: 'status' });
|
|
31
68
|
const connected = !!resp?.ok && !!resp?.data?.wsConnected;
|
|
32
|
-
setBadgeState(connected, resp?.data?.wsUrl || '');
|
|
69
|
+
setBadgeState(connected, resp?.data?.wsUrl || '', resp?.data?.lastCommandAt);
|
|
33
70
|
} catch (e) {
|
|
34
|
-
setBadgeState(false, e.message || '');
|
|
71
|
+
setBadgeState(false, e.message || '', 0);
|
|
35
72
|
}
|
|
36
73
|
}
|
|
37
|
-
d.addEventListener('
|
|
74
|
+
d.addEventListener('mouseenter', () => {
|
|
75
|
+
if (collapseTimer) clearTimeout(collapseTimer);
|
|
76
|
+
setExpanded(true);
|
|
77
|
+
});
|
|
78
|
+
d.addEventListener('mouseleave', () => {
|
|
79
|
+
if (collapseTimer) clearTimeout(collapseTimer);
|
|
80
|
+
setExpanded(false);
|
|
81
|
+
});
|
|
82
|
+
d.addEventListener('pointerdown', (e) => {
|
|
83
|
+
dragging = true;
|
|
84
|
+
moved = false;
|
|
85
|
+
dragOffsetY = e.clientY - d.getBoundingClientRect().top;
|
|
86
|
+
d.dataset.dragging = '1';
|
|
87
|
+
d.setPointerCapture(e.pointerId);
|
|
88
|
+
});
|
|
89
|
+
d.addEventListener('pointermove', (e) => {
|
|
90
|
+
if (!dragging) return;
|
|
91
|
+
const nextTop = clampTop(e.clientY - dragOffsetY);
|
|
92
|
+
if (Math.abs(nextTop - lastTop) > 2) moved = true;
|
|
93
|
+
lastTop = nextTop;
|
|
94
|
+
d.style.top = lastTop + 'px';
|
|
95
|
+
});
|
|
96
|
+
d.addEventListener('pointerup', (e) => {
|
|
97
|
+
dragging = false;
|
|
98
|
+
d.dataset.dragging = '0';
|
|
99
|
+
try { d.releasePointerCapture(e.pointerId); } catch (_) {}
|
|
100
|
+
});
|
|
101
|
+
close.addEventListener('pointerdown', (e) => { e.stopPropagation(); });
|
|
102
|
+
close.addEventListener('click', (e) => {
|
|
103
|
+
e.stopPropagation();
|
|
104
|
+
dismissed = true;
|
|
105
|
+
setExpanded(false);
|
|
106
|
+
d.style.display = 'none';
|
|
107
|
+
});
|
|
108
|
+
window.addEventListener('resize', () => {
|
|
109
|
+
lastTop = clampTop(lastTop);
|
|
110
|
+
d.style.top = lastTop + 'px';
|
|
111
|
+
});
|
|
38
112
|
(document.body||document.documentElement).appendChild(d);
|
|
39
113
|
setBadgeState(false, '');
|
|
40
114
|
refreshBadgeState();
|
|
41
|
-
setInterval(refreshBadgeState, 3000);
|
|
115
|
+
const refreshTimer = setInterval(refreshBadgeState, 3000);
|
|
116
|
+
window.__agentBrowserCliCleanup = () => {
|
|
117
|
+
clearInterval(refreshTimer);
|
|
118
|
+
d.remove();
|
|
119
|
+
s.remove();
|
|
120
|
+
};
|
|
42
121
|
})();
|
|
43
122
|
|
|
44
|
-
new MutationObserver(muts => {
|
|
123
|
+
const agentBrowserCliObserver = new MutationObserver(muts => {
|
|
45
124
|
for (const m of muts) for (const n of m.addedNodes) {
|
|
46
125
|
if (n.id === TID || (n.querySelector && n.querySelector('#' + TID))) {
|
|
47
126
|
const el = n.id === TID ? n : n.querySelector('#' + TID);
|
|
48
127
|
handle(el);
|
|
49
128
|
}
|
|
50
129
|
}
|
|
51
|
-
})
|
|
130
|
+
});
|
|
131
|
+
agentBrowserCliObserver.observe(document.documentElement, { childList: true, subtree: true });
|
|
132
|
+
window.__agentBrowserCliObserverCleanup = () => agentBrowserCliObserver.disconnect();
|
|
52
133
|
|
|
53
134
|
/**
|
|
54
135
|
* Consume page-side bridge requests and forward them to the extension background worker.
|
|
@@ -3,17 +3,32 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<style>
|
|
6
|
-
body{width:420px;max-height:
|
|
6
|
+
body{width:420px;max-height:560px;margin:0;padding:8px;font:12px monospace;background:#1e1e1e;color:#d4d4d4;overflow-y:auto}
|
|
7
7
|
h3{margin:4px 0;color:#569cd6}
|
|
8
8
|
button{background:#264f78;color:#fff;border:none;padding:4px 12px;cursor:pointer;border-radius:3px;margin-bottom:6px}
|
|
9
9
|
button:hover{background:#37699e}
|
|
10
|
+
input{width:86px;background:#252526;color:#d4d4d4;border:1px solid #3c3c3c;border-radius:3px;padding:4px;font:12px monospace}
|
|
11
|
+
label{display:inline-flex;align-items:center;gap:6px;margin-right:6px}
|
|
12
|
+
.panel{margin-bottom:8px;padding:6px;background:#252526;border-radius:3px}
|
|
13
|
+
.row{display:flex;align-items:center;gap:6px;margin-top:6px}
|
|
14
|
+
.status{color:#9cdcfe}
|
|
15
|
+
.error{color:#f48771}
|
|
10
16
|
pre{white-space:pre-wrap;word-break:break-all;margin:0;padding:6px;background:#252526;border-radius:3px;max-height:420px;overflow-y:auto}
|
|
11
17
|
</style>
|
|
12
18
|
</head>
|
|
13
19
|
<body>
|
|
20
|
+
<h3>🔌 Bridge</h3>
|
|
21
|
+
<div class="panel">
|
|
22
|
+
<div id="bridgeStatus" class="status">读取连接状态...</div>
|
|
23
|
+
<div class="row">
|
|
24
|
+
<label>端口 <input id="port" type="number" min="1" max="65535"></label>
|
|
25
|
+
<button id="savePort">保存并重连</button>
|
|
26
|
+
</div>
|
|
27
|
+
<div id="portMsg"></div>
|
|
28
|
+
</div>
|
|
14
29
|
<h3>🍪 Cookies</h3>
|
|
15
30
|
<button id="refresh">刷新</button>
|
|
16
31
|
<pre id="out">点击刷新获取 cookies...</pre>
|
|
17
32
|
<script src="popup.js"></script>
|
|
18
33
|
</body>
|
|
19
|
-
</html>
|
|
34
|
+
</html>
|
|
@@ -1,10 +1,49 @@
|
|
|
1
1
|
document.addEventListener('DOMContentLoaded', () => {
|
|
2
|
-
const out = document.getElementById('out');
|
|
3
2
|
const btn = document.getElementById('refresh');
|
|
3
|
+
const savePortBtn = document.getElementById('savePort');
|
|
4
4
|
btn.addEventListener('click', fetchCookies);
|
|
5
|
+
savePortBtn.addEventListener('click', savePort);
|
|
6
|
+
refreshBridgeStatus();
|
|
5
7
|
fetchCookies();
|
|
6
8
|
});
|
|
7
9
|
|
|
10
|
+
async function refreshBridgeStatus() {
|
|
11
|
+
const status = document.getElementById('bridgeStatus');
|
|
12
|
+
const portInput = document.getElementById('port');
|
|
13
|
+
try {
|
|
14
|
+
const resp = await chrome.runtime.sendMessage({ cmd: 'status' });
|
|
15
|
+
if (!resp?.ok) throw new Error(resp?.error || 'unknown');
|
|
16
|
+
const data = resp.data || {};
|
|
17
|
+
portInput.value = data.wsPort || 18765;
|
|
18
|
+
status.textContent = `状态: ${data.wsConnected ? '已连接' : '未连接'} ${data.wsUrl || ''}`;
|
|
19
|
+
} catch (e) {
|
|
20
|
+
status.textContent = '状态读取失败: ' + e.message;
|
|
21
|
+
status.className = 'error';
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function savePort() {
|
|
26
|
+
const portInput = document.getElementById('port');
|
|
27
|
+
const portMsg = document.getElementById('portMsg');
|
|
28
|
+
try {
|
|
29
|
+
const port = Number(portInput.value);
|
|
30
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
31
|
+
throw new Error('端口必须是 1-65535');
|
|
32
|
+
}
|
|
33
|
+
if (port === 18767) {
|
|
34
|
+
throw new Error('18767 是 agent-browser-cli API 端口,请换一个插件端口');
|
|
35
|
+
}
|
|
36
|
+
const resp = await chrome.runtime.sendMessage({ cmd: 'setPort', port });
|
|
37
|
+
if (!resp?.ok) throw new Error(resp?.error || 'unknown');
|
|
38
|
+
portMsg.textContent = `Success: 已保存端口 ${port},正在使用新端口重连`;
|
|
39
|
+
portMsg.className = 'status';
|
|
40
|
+
await refreshBridgeStatus();
|
|
41
|
+
} catch (e) {
|
|
42
|
+
portMsg.textContent = '保存失败: ' + e.message;
|
|
43
|
+
portMsg.className = 'error';
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
8
47
|
async function fetchCookies() {
|
|
9
48
|
const out = document.getElementById('out');
|
|
10
49
|
try {
|
|
@@ -21,4 +60,4 @@ async function fetchCookies() {
|
|
|
21
60
|
const str = resp.data.map(c => `${c.name}=${c.value}`).join('; ');
|
|
22
61
|
await navigator.clipboard.writeText(str);
|
|
23
62
|
} catch (e) { out.textContent = 'Error: ' + e.message; }
|
|
24
|
-
}
|
|
63
|
+
}
|
|
@@ -10,6 +10,7 @@ function platformPackageName() {
|
|
|
10
10
|
if (platform === "darwin" && arch === "arm64") return "@sleepinsummer/agent-browser-cli-darwin-arm64";
|
|
11
11
|
if (platform === "darwin" && arch === "x64") return "@sleepinsummer/agent-browser-cli-darwin-x64";
|
|
12
12
|
if (platform === "linux" && arch === "x64") return "@sleepinsummer/agent-browser-cli-linux-x64";
|
|
13
|
+
if (platform === "linux" && arch === "arm64") return "@sleepinsummer/agent-browser-cli-linux-arm64";
|
|
13
14
|
if (platform === "win32" && arch === "x64") return "@sleepinsummer/agent-browser-cli-win32-x64";
|
|
14
15
|
throw new Error(`Unsupported platform: ${platform}-${arch}`);
|
|
15
16
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sleepinsummer/agent-browser-cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.8",
|
|
4
4
|
"description": "Agent-oriented browser sensing and control CLI backed by a native Rust daemon.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
@@ -21,10 +21,11 @@
|
|
|
21
21
|
"postinstall": "node npm/postinstall.js"
|
|
22
22
|
},
|
|
23
23
|
"optionalDependencies": {
|
|
24
|
-
"@sleepinsummer/agent-browser-cli-darwin-arm64": "0.2.
|
|
25
|
-
"@sleepinsummer/agent-browser-cli-darwin-x64": "0.2.
|
|
26
|
-
"@sleepinsummer/agent-browser-cli-linux-x64": "0.2.
|
|
27
|
-
"@sleepinsummer/agent-browser-cli-
|
|
24
|
+
"@sleepinsummer/agent-browser-cli-darwin-arm64": "0.2.7",
|
|
25
|
+
"@sleepinsummer/agent-browser-cli-darwin-x64": "0.2.7",
|
|
26
|
+
"@sleepinsummer/agent-browser-cli-linux-x64": "0.2.7",
|
|
27
|
+
"@sleepinsummer/agent-browser-cli-linux-arm64": "0.2.7",
|
|
28
|
+
"@sleepinsummer/agent-browser-cli-win32-x64": "0.2.7"
|
|
28
29
|
},
|
|
29
30
|
"engines": {
|
|
30
31
|
"node": ">=18"
|
|
@@ -44,7 +44,7 @@ assets/tmwd_cdp_bridge
|
|
|
44
44
|
扩展配置必须存在:
|
|
45
45
|
|
|
46
46
|
```js
|
|
47
|
-
|
|
47
|
+
globalThis.__agent_browser_cli_TID = '__agent_browser_cli_bridge_26c9f1';
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
对应文件:
|
|
@@ -72,13 +72,36 @@ agent-browser-cli restart
|
|
|
72
72
|
```
|
|
73
73
|
|
|
74
74
|
常驻服务端口:
|
|
75
|
-
- `18765
|
|
76
|
-
- `18767`:外层 `agent-browser-cli` HTTP
|
|
75
|
+
- `18765`:默认插件 WebSocket 端口,Chrome 扩展连接使用,可通过插件 popup 或 `agent-browser-cli set-extension-port <port>` 修改。
|
|
76
|
+
- `18767`:外层 `agent-browser-cli` HTTP API 端口,供 CLI 复用会话,不能作为插件端口使用。
|
|
77
|
+
|
|
78
|
+
插件端口配置文件:
|
|
79
|
+
|
|
80
|
+
```text
|
|
81
|
+
~/.agent-browser-cli/config.json
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
最小配置:
|
|
85
|
+
|
|
86
|
+
```json
|
|
87
|
+
{
|
|
88
|
+
"extension_port": 18765
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
CLI 修改插件端口:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
agent-browser-cli set-extension-port 18766
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Chrome 插件 popup 也可以修改插件端口并立即重连。插件端口必须和 CLI 配置中的 `extension_port` 一致。
|
|
77
99
|
|
|
78
100
|
成功标志:
|
|
79
101
|
- 返回 `status=success`
|
|
80
102
|
- 能看到 `tabs_count`
|
|
81
|
-
-
|
|
103
|
+
- `agent-browser-cli status` 中 `ports.extension.matched=true`
|
|
104
|
+
- `agent-browser-cli status` 中 `connection.extension_connected=true`
|
|
82
105
|
|
|
83
106
|
## 推荐 CLI 调用
|
|
84
107
|
|