@sleepinsummer/agent-browser-cli 0.2.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.
- package/AI_INSTALL.md +126 -0
- package/LICENSE +21 -0
- package/README.md +194 -0
- package/README_EN.md +169 -0
- package/assets/tmwd_cdp_bridge/background.js +436 -0
- package/assets/tmwd_cdp_bridge/config.js +1 -0
- package/assets/tmwd_cdp_bridge/content.js +79 -0
- package/assets/tmwd_cdp_bridge/disable_dialogs.js +24 -0
- package/assets/tmwd_cdp_bridge/manifest.json +40 -0
- package/assets/tmwd_cdp_bridge/popup.html +19 -0
- package/assets/tmwd_cdp_bridge/popup.js +24 -0
- package/npm/bin/agent-browser-cli.js +35 -0
- package/npm/platform/darwin-arm64/bin/agent-browser-cli +0 -0
- package/npm/platform/darwin-arm64/package.json +14 -0
- package/npm/postinstall.js +9 -0
- package/package.json +30 -0
- package/skills/agent-browser-cli/SKILL.md +315 -0
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sleepinsummer/agent-browser-cli",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Agent-oriented browser sensing and control CLI backed by a native Rust daemon.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"bin": {
|
|
7
|
+
"agent-browser-cli": "npm/bin/agent-browser-cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"npm",
|
|
11
|
+
"assets",
|
|
12
|
+
"skills",
|
|
13
|
+
"README.md",
|
|
14
|
+
"README_EN.md",
|
|
15
|
+
"AI_INSTALL.md",
|
|
16
|
+
"LICENSE"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "cargo build --release",
|
|
20
|
+
"postinstall": "node npm/postinstall.js"
|
|
21
|
+
},
|
|
22
|
+
"optionalDependencies": {
|
|
23
|
+
"@sleepinsummer/agent-browser-cli-darwin-arm64": "0.2.0",
|
|
24
|
+
"@sleepinsummer/agent-browser-cli-darwin-x64": "0.2.0",
|
|
25
|
+
"@sleepinsummer/agent-browser-cli-win32-x64": "0.2.0"
|
|
26
|
+
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=18"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agent-browser-cli
|
|
3
|
+
description: 使用 agent-browser-cli 进行浏览器感知与控制。适用于标签页扫描/切换、页面 JS 执行、Cookie、CDP、contentSettings、截图、文件上传、下拉框点击、tmwd_cdp_bridge 初始化和 Web 工具排障。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# agent-browser-cli
|
|
7
|
+
|
|
8
|
+
使用 `agent-browser-cli` 进行浏览器控制。底层通过 Rust 常驻服务和 Chrome 扩展接管用户浏览器,保留登录态和 Cookie;不是 Selenium/Playwright。旧 Python API `web_scan`、`web_execute_js` 只作为兼容和排障入口。
|
|
9
|
+
|
|
10
|
+
## 项目路径
|
|
11
|
+
|
|
12
|
+
安装后必须把下面的占位路径替换为用户本机真实项目路径,避免 AI 在其它项目目录里误找工具:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
<AGENT_BROWSER_CLI_PROJECT_DIR>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
日常调用先进入用户本机真实项目路径:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
cd <AGENT_BROWSER_CLI_PROJECT_DIR>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
优先通过 npm 安装 CLI:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install -g @sleepinsummer/agent-browser-cli
|
|
28
|
+
agent-browser-cli --help
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
如果 npm 平台包不可用,再在项目根目录源码构建:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
cargo build --release
|
|
35
|
+
./target/release/agent-browser-cli --help
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
扩展目录:
|
|
39
|
+
|
|
40
|
+
```text
|
|
41
|
+
assets/tmwd_cdp_bridge
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
扩展配置必须存在:
|
|
45
|
+
|
|
46
|
+
```js
|
|
47
|
+
const TID = '__agent_browser_cli_bridge_26c9f1';
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
对应文件:
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
assets/tmwd_cdp_bridge/config.js
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## 最小自检
|
|
57
|
+
|
|
58
|
+
Chrome 必须已打开,且至少有一个正常网页标签页,不能只停留在 `about:blank`、`chrome://` 等内部页。
|
|
59
|
+
|
|
60
|
+
优先用常驻会话 CLI 自检。它会自动启动 Rust 常驻服务,复用同一个浏览器扩展连接,默认空闲 300 秒自动退出;每次请求都会续期。
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
agent-browser-cli tabs
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
服务状态、停止和重载:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
agent-browser-cli status
|
|
70
|
+
agent-browser-cli stop
|
|
71
|
+
agent-browser-cli restart
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
常驻服务端口:
|
|
75
|
+
- `18765`:底层 `TMWebDriver` WebSocket,Chrome 扩展连接使用。
|
|
76
|
+
- `18766`:底层 `TMWebDriver` HTTP `/link`,用于内部 master/remote 协议。
|
|
77
|
+
- `18767`:外层 `agent-browser-cli` HTTP 服务,供 CLI 复用会话。
|
|
78
|
+
|
|
79
|
+
旧 Python 实现只用于回退排障或开发:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
.venv/bin/python - <<'PY'
|
|
83
|
+
import ga
|
|
84
|
+
print(ga.web_scan(tabs_only=True))
|
|
85
|
+
PY
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
成功标志:
|
|
89
|
+
- 返回 `status=success`
|
|
90
|
+
- 能看到 `tabs_count`
|
|
91
|
+
- 首次运行会拉起本地 WS 服务 `ws://127.0.0.1:18765`
|
|
92
|
+
|
|
93
|
+
## 推荐 CLI 调用
|
|
94
|
+
|
|
95
|
+
日常操作优先使用 `agent-browser-cli`,避免直接操作底层协议。
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
cd <AGENT_BROWSER_CLI_PROJECT_DIR>
|
|
99
|
+
agent-browser-cli status
|
|
100
|
+
agent-browser-cli tabs
|
|
101
|
+
agent-browser-cli scan --tabs-only
|
|
102
|
+
agent-browser-cli scan --tab 303987837 --text-only
|
|
103
|
+
agent-browser-cli open https://www.baidu.com
|
|
104
|
+
agent-browser-cli exec --tab 303987837 'return document.title'
|
|
105
|
+
agent-browser-cli exec --tab 303987837 '{"cmd":"tabs"}'
|
|
106
|
+
agent-browser-cli restart
|
|
107
|
+
agent-browser-cli stop
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
执行较复杂 JS 时,把脚本写入文件再调用:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
agent-browser-cli exec --tab 303987837 --file /tmp/script.js
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
`exec` 默认只执行 JS,不做执行前后 DOM 扫描。需要页面变化摘要时显式加 `--monitor`。
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
agent-browser-cli exec --tab 303987837 --monitor 'return document.title'
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
需要等待页面变化时,不要在脚本里固定 `setTimeout`。优先用 `--wait-js` 做条件等待,条件满足会立即返回;普通页面 JS 会把主脚本和等待条件合并到同一次浏览器执行里,减少往返:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
agent-browser-cli exec --tab 303987837 'document.querySelector("button").click()' --wait-js 'return document.body.innerText.includes("完成")' --wait-timeout 3
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## 基础调用
|
|
129
|
+
|
|
130
|
+
`web_scan` 负责感知,`web_execute_js` 负责精确操作。能精确操作时,不做全量扫描。下面是旧 Python 直接调用方式,主要用于排障或兼容旧脚本;日常命令行操作优先用上面的常驻 CLI。
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
import ga
|
|
134
|
+
|
|
135
|
+
print(ga.web_scan(tabs_only=True))
|
|
136
|
+
print(ga.web_scan())
|
|
137
|
+
print(ga.web_scan(text_only=True))
|
|
138
|
+
print(ga.web_scan(switch_tab_id="303987837"))
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
普通页面 JS:
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
import ga
|
|
145
|
+
|
|
146
|
+
print(ga.web_execute_js("return document.title"))
|
|
147
|
+
print(ga.web_execute_js("""
|
|
148
|
+
return {
|
|
149
|
+
title: document.title,
|
|
150
|
+
url: location.href
|
|
151
|
+
}
|
|
152
|
+
"""))
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
`web_execute_js` 内使用 `await` 时必须显式 `return`,否则结果可能是 `null`。
|
|
156
|
+
|
|
157
|
+
`web_scan` 只读取当前页,不负责导航。切换网站用 `web_execute_js` 执行:
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
import ga
|
|
161
|
+
print(ga.web_execute_js("location.href='https://example.com'; return location.href"))
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
新开标签页优先使用原生 `open` 命令,不要用 `window.open` 加 `--monitor`。`open` 底层走扩展 `chrome.tabs.create`,不会触发 CDP debugger attach。
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
agent-browser-cli open www.baidu.com
|
|
168
|
+
agent-browser-cli new-tab https://example.com --background
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
JS 事件的 `isTrusted=false`,敏感操作可能被页面拦截。JS 点击按钮打不开新 tab 时,优先改用 CDP 点击。
|
|
172
|
+
|
|
173
|
+
## 扩展 JSON 指令
|
|
174
|
+
|
|
175
|
+
跨标签页、Cookie、CDP、扩展管理、浏览器内容权限时,优先用 JSON 字符串直传,不要自己拼 DOM 节点。
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
import ga
|
|
179
|
+
|
|
180
|
+
print(ga.web_execute_js('{"cmd":"tabs"}'))
|
|
181
|
+
print(ga.web_execute_js('{"cmd":"cookies"}'))
|
|
182
|
+
print(ga.web_execute_js('{"cmd":"cdp","tabId":303987837,"method":"Page.captureScreenshot","params":{"format":"png"}}'))
|
|
183
|
+
print(ga.web_execute_js('{"cmd":"batch","tabId":303987837,"commands":[{"cmd":"tabs"},{"cmd":"cookies"}]}'))
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
常用命令:
|
|
187
|
+
- `{"cmd":"tabs"}`:读取或切换标签页。
|
|
188
|
+
- `{"cmd":"openTab","url":"https://example.com","active":true}`:原生创建标签页。
|
|
189
|
+
- `{"cmd":"cookies"}`:读取当前页 Cookie。
|
|
190
|
+
- `{"cmd":"cdp","tabId":N,"method":"...","params":{}}`:执行单个 CDP 命令。
|
|
191
|
+
- `{"cmd":"batch","tabId":N,"commands":[...]}`:同一链路内批量执行,支持 `$N.path` 引用前序结果。
|
|
192
|
+
- `{"cmd":"management","method":"list|reload|disable|enable","extId":"..."}`:管理扩展。
|
|
193
|
+
- `{"cmd":"contentSettings","type":"automaticDownloads","pattern":"https://*/*","setting":"allow"}`:设置内容权限。
|
|
194
|
+
|
|
195
|
+
`contentSettings` 用于绕过 Chrome “下载多个文件”对话框,该对话框会阻塞浏览器 JS 执行。可选 `type` 包括 `automaticDownloads`、`popups`、`notifications` 等;`setting` 包括 `allow`、`block`、`ask`。CDP 的 `Browser.setDownloadBehavior` 在当前扩展环境不可用,因为 `chrome.debugger` 是 tab 级权限。
|
|
196
|
+
|
|
197
|
+
`batch` 前序命令失败时,后续 `$N.path` 引用会静默变成 `undefined`,必须检查 `results` 数组中每项的 `ok` 状态。同一条 CDP 链路内保持 `nodeId` 来源一致,不要混用 `querySelector` 路径和 `performSearch` 路径。
|
|
198
|
+
|
|
199
|
+
CDP 默认使用当前注入页的 `sender.tab.id`,跨 tab 操作必须显式传 `tabId`,或先在 `batch` 里通过 `tabs` 查询目标标签。
|
|
200
|
+
|
|
201
|
+
## CDP 操作要点
|
|
202
|
+
|
|
203
|
+
通用点击使用三事件序列:
|
|
204
|
+
|
|
205
|
+
```text
|
|
206
|
+
mouseMoved -> mousePressed -> mouseReleased
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
省略 `mouseMoved` 可能导致 MUI Tooltip、Ant Design Dropdown 等 hover 依赖组件失效。稳定状态下 CDP 坐标等于 `getBoundingClientRect()` 坐标,不需要修正。
|
|
210
|
+
|
|
211
|
+
首次 CDP attach 会触发 Chrome infobar,页面内容可能下移约 20px。首次操作前先发无害 `mouseMoved(0,0)` 预热,再测量元素坐标。
|
|
212
|
+
|
|
213
|
+
Vue3 自定义 Select/Dropdown 优先走 vnode 实例调用;CDP 坐标点击适合选项少且可见的场景。CDP 下拉框流程是先点击 select 打开下拉,再测量动态 option,再点击 option。
|
|
214
|
+
|
|
215
|
+
某些 SPA 后台标签不会加载数据,需要先用 CDP `Page.bringToFront` 切到前台。跨标签页操作时显式传 `tabId`,不依赖当前页。
|
|
216
|
+
|
|
217
|
+
页面存在 `transform: scale` 或 CSS `zoom` 时,坐标需要按页面缩放修正:
|
|
218
|
+
|
|
219
|
+
```js
|
|
220
|
+
const scale = window.visualViewport ? window.visualViewport.scale : 1;
|
|
221
|
+
const zoom = parseFloat(getComputedStyle(document.documentElement).zoom) || 1;
|
|
222
|
+
const realX = x * zoom;
|
|
223
|
+
const realY = y * zoom;
|
|
224
|
+
return { scale, zoom, realX, realY };
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
需要转物理坐标时:`physX = (screenX + rect中心x) * dpr`,`physY = (screenY + chromeH + rect中心y) * dpr`,其中 `chromeH = outerHeight - innerHeight`。
|
|
228
|
+
|
|
229
|
+
CDP 文本输入:`Input.insertText` 快但没有完整 key 事件,受控组件需要补发 `input` 事件;需要完整键盘模拟时用 `Input.dispatchKeyEvent` 逐键派发。
|
|
230
|
+
|
|
231
|
+
## 文件上传
|
|
232
|
+
|
|
233
|
+
文件上传优先用 DataTransfer API,纯 JS、无 CDP 依赖:
|
|
234
|
+
|
|
235
|
+
```js
|
|
236
|
+
const input = document.querySelector('input[type=file]');
|
|
237
|
+
const file = new File(['content'], 'demo.txt', { type: 'text/plain' });
|
|
238
|
+
const dt = new DataTransfer();
|
|
239
|
+
dt.items.add(file);
|
|
240
|
+
input.files = dt.files;
|
|
241
|
+
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
242
|
+
input.dispatchEvent(new Event('change', { bubbles: true }));
|
|
243
|
+
return input.files.length;
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
不优先使用 CDP `DOM.setFileInputFiles`,因为在 tmwd 桥环境里 `nodeId` 跨调用容易失效。若必须用 CDP,尽量在同一个 `batch` 内完成 `getDocument -> querySelector -> setFileInputFiles`,不要混用不同来源的 `nodeId`。
|
|
247
|
+
|
|
248
|
+
上传前检查 `input.accept`。页面有多个文件 input 时,用 `accept`、父容器文案、相邻 label 区分目标 input。上传后前端框架可能不感知,必要时补发 `input` / `change` 事件。
|
|
249
|
+
|
|
250
|
+
瞬态 input 的核心是缩短“发现 input -> set files”的时间窗:优先同 batch 完成;再不行用 DOM 事件监听;猴子补丁只作兜底思路。
|
|
251
|
+
|
|
252
|
+
## 下载与图片搜索
|
|
253
|
+
|
|
254
|
+
PDF 链接在浏览器内预览而非下载时,用页面 JS 触发 Blob 下载。该方式要求同源或 CORS 允许;跨域时先导航到目标域再执行。
|
|
255
|
+
|
|
256
|
+
```js
|
|
257
|
+
return fetch('PDF_URL').then(r => r.blob()).then(b => {
|
|
258
|
+
const a = document.createElement('a');
|
|
259
|
+
a.href = URL.createObjectURL(b);
|
|
260
|
+
a.download = 'filename.pdf';
|
|
261
|
+
a.click();
|
|
262
|
+
return true;
|
|
263
|
+
});
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Google 图搜场景不要硬编码混淆 class。点击结果优先找 `[role=button]` 容器;`web_scan` 可能过滤边栏,弹出后用 JS 读 `document.body.innerText`;大图遍历 `img` 按 `naturalWidth` 最大取 `src`;“访问”链接遍历 `a` 找 `textContent.includes('访问')` 的 `href`;缩略图直接提取 `img[src^="data:image"]`。
|
|
267
|
+
|
|
268
|
+
## iframe、Shadow DOM 与截图
|
|
269
|
+
|
|
270
|
+
同源 iframe 会被 `web_scan` 自动穿透。跨域 iframe 优先走 CDP:`Page.getFrameTree` 找 `frameId`,再 `Page.createIsolatedWorld` 获取 `contextId`,最后用 `Runtime.evaluate` 在 iframe 上下文执行。
|
|
271
|
+
|
|
272
|
+
iframe 内元素做 CDP 点击时,坐标需要合成:`finalX = iframeRect.x + elRect.x`,`finalY = iframeRect.y + elRect.y`。`Target.getTargets` / `Target.attachToTarget` 在当前 CDP 桥里通常会返回 `Not allowed`,不要优先走这条路。postMessage 中继只在 content script 已注入 iframe 时可靠,第三方支付 iframe 通常不可用。
|
|
273
|
+
|
|
274
|
+
closed Shadow DOM 使用 `DOM.getDocument({depth:-1,pierce:true})`,再逐级 `DOM.querySelector`。`nodeId` 在 DOM 变更后会失效,必要时重新 `getDocument`。
|
|
275
|
+
|
|
276
|
+
`DOM.getBoxModel` 返回 content 四点坐标,中心点用四点平均,不要简化成对角线平均;元素存在 rotate/skew 时四点不一定是矩形。`DOM.querySelector` 不能跨 Shadow 边界写组合选择器,要先找 host,再在 shadow 内找子元素。
|
|
277
|
+
|
|
278
|
+
截图优先 CDP:
|
|
279
|
+
|
|
280
|
+
```python
|
|
281
|
+
import ga
|
|
282
|
+
print(ga.web_execute_js('{"cmd":"cdp","method":"Page.captureScreenshot","params":{"format":"png"}}'))
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
验证码 canvas/img 优先用 JS `canvas.toDataURL()` 或直接读取图片 `src`。
|
|
286
|
+
|
|
287
|
+
## Autofill 与登录
|
|
288
|
+
|
|
289
|
+
`web_scan` 输出的 input 若带 `data-autofilled="true"`,value 可能显示为受保护提示,不是真实值。Chrome 只在前台 tab 释放 autofill 保护值,所以必须先 CDP `Page.bringToFront`。
|
|
290
|
+
|
|
291
|
+
一键释放流程:`Page.bringToFront` -> `mousePressed` 点任一字段,通常不需要 `mouseReleased` -> 等 500ms -> 补发 `input/change` 事件 -> 点登录。
|
|
292
|
+
|
|
293
|
+
## 调试
|
|
294
|
+
|
|
295
|
+
`simphtml` 调试必须注入 JS 到真实浏览器,本地静态解析无法模拟 DOM。
|
|
296
|
+
|
|
297
|
+
```python
|
|
298
|
+
from TMWebDriver import TMWebDriver
|
|
299
|
+
import simphtml
|
|
300
|
+
|
|
301
|
+
d = TMWebDriver()
|
|
302
|
+
d.set_session('url_pattern')
|
|
303
|
+
print(d.execute_js('return document.title'))
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
`simphtml.optimize_html_for_tokens(html)` 返回 BeautifulSoup Tag,展示前用 `str(...)`。
|
|
307
|
+
|
|
308
|
+
## 排障顺序
|
|
309
|
+
|
|
310
|
+
1. 先跑最小自检,确认 `agent-browser-cli` 是否可执行。
|
|
311
|
+
2. 若 npm 安装失败,检查当前平台是否有对应二进制包,必要时用 `cargo build --release`。
|
|
312
|
+
3. 若提示无法加载 `config.js` 或清单,检查 `assets/tmwd_cdp_bridge/config.js`。
|
|
313
|
+
4. 若提示没有可用标签页,先打开正常网页,不要只开内部页。
|
|
314
|
+
5. 若扩展没装,加载 `assets/tmwd_cdp_bridge`。
|
|
315
|
+
6. 仍失败时继续看 `memory/web_setup_sop.md` 和 `memory/tmwebdriver_sop.md`。
|