openclaw-multi-auto 1.4.5 → 1.4.7

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 (100) hide show
  1. package/dist/build-info.json +3 -3
  2. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  3. package/dist/plugin-sdk/mattermost.js +3 -3
  4. package/dist/plugin-sdk/signal.js +2 -2
  5. package/docs/browser-architecture.md +602 -0
  6. package/extensions/googlechat/node_modules/.bin/openclaw +2 -2
  7. package/extensions/memory-core/node_modules/.bin/openclaw +2 -2
  8. package/extensions/memory-lancedb/node_modules/.bin/openai +2 -2
  9. package/extensions/page-action-cache/dist/actions-executor.d.ts +62 -0
  10. package/extensions/page-action-cache/dist/actions-executor.d.ts.map +1 -0
  11. package/extensions/page-action-cache/dist/actions-executor.js +339 -0
  12. package/extensions/page-action-cache/dist/actions-executor.js.map +1 -0
  13. package/extensions/page-action-cache/dist/cache-invalidator.d.ts +70 -0
  14. package/extensions/page-action-cache/dist/cache-invalidator.d.ts.map +1 -0
  15. package/extensions/page-action-cache/dist/cache-invalidator.js +212 -0
  16. package/extensions/page-action-cache/dist/cache-invalidator.js.map +1 -0
  17. package/extensions/page-action-cache/dist/cache-store.d.ts +80 -0
  18. package/extensions/page-action-cache/dist/cache-store.d.ts.map +1 -0
  19. package/extensions/page-action-cache/dist/cache-store.js +361 -0
  20. package/extensions/page-action-cache/dist/cache-store.js.map +1 -0
  21. package/extensions/page-action-cache/dist/cache-strategy.d.ts +65 -0
  22. package/extensions/page-action-cache/dist/cache-strategy.d.ts.map +1 -0
  23. package/extensions/page-action-cache/dist/cache-strategy.js +237 -0
  24. package/extensions/page-action-cache/dist/cache-strategy.js.map +1 -0
  25. package/extensions/page-action-cache/dist/hooks-entry.d.ts +18 -0
  26. package/extensions/page-action-cache/dist/hooks-entry.d.ts.map +1 -0
  27. package/extensions/page-action-cache/dist/hooks-entry.js +27 -0
  28. package/extensions/page-action-cache/dist/hooks-entry.js.map +1 -0
  29. package/extensions/page-action-cache/dist/hooks.d.ts +10 -0
  30. package/extensions/page-action-cache/dist/hooks.d.ts.map +1 -0
  31. package/extensions/page-action-cache/dist/hooks.js +277 -0
  32. package/extensions/page-action-cache/dist/hooks.js.map +1 -0
  33. package/extensions/page-action-cache/dist/index.d.ts +24 -0
  34. package/extensions/page-action-cache/dist/index.d.ts.map +1 -0
  35. package/extensions/page-action-cache/dist/index.js +34 -0
  36. package/extensions/page-action-cache/dist/index.js.map +1 -0
  37. package/extensions/page-action-cache/dist/scenario-recognizer.d.ts +45 -0
  38. package/extensions/page-action-cache/dist/scenario-recognizer.d.ts.map +1 -0
  39. package/extensions/page-action-cache/dist/scenario-recognizer.js +213 -0
  40. package/extensions/page-action-cache/dist/scenario-recognizer.js.map +1 -0
  41. package/extensions/page-action-cache/dist/security-policy.d.ts +62 -0
  42. package/extensions/page-action-cache/dist/security-policy.d.ts.map +1 -0
  43. package/extensions/page-action-cache/dist/security-policy.js +219 -0
  44. package/extensions/page-action-cache/dist/security-policy.js.map +1 -0
  45. package/extensions/page-action-cache/dist/tools.d.ts +209 -0
  46. package/extensions/page-action-cache/dist/tools.d.ts.map +1 -0
  47. package/extensions/page-action-cache/dist/tools.js +383 -0
  48. package/extensions/page-action-cache/dist/tools.js.map +1 -0
  49. package/extensions/page-action-cache/dist/types.d.ts +336 -0
  50. package/extensions/page-action-cache/dist/types.d.ts.map +1 -0
  51. package/extensions/page-action-cache/dist/types.js +8 -0
  52. package/extensions/page-action-cache/dist/types.js.map +1 -0
  53. package/extensions/page-action-cache/dist/ux-enhancer.d.ts +60 -0
  54. package/extensions/page-action-cache/dist/ux-enhancer.d.ts.map +1 -0
  55. package/extensions/page-action-cache/dist/ux-enhancer.js +218 -0
  56. package/extensions/page-action-cache/dist/ux-enhancer.js.map +1 -0
  57. package/extensions/page-action-cache/dist/variable-resolver.d.ts +28 -0
  58. package/extensions/page-action-cache/dist/variable-resolver.d.ts.map +1 -0
  59. package/extensions/page-action-cache/dist/variable-resolver.js +201 -0
  60. package/extensions/page-action-cache/dist/variable-resolver.js.map +1 -0
  61. package/extensions/page-action-cache/docs/API.md +555 -0
  62. package/extensions/page-action-cache/docs/IMPLEMENTATION.md +1792 -0
  63. package/extensions/page-action-cache/docs/INTEGRATION.md +387 -0
  64. package/extensions/page-action-cache/docs/README.md +183 -0
  65. package/extensions/page-action-cache/index.ts +118 -0
  66. package/extensions/page-action-cache/node_modules/.bin/nlc +21 -0
  67. package/extensions/page-action-cache/node_modules/.bin/node-llama-cpp +21 -0
  68. package/extensions/page-action-cache/node_modules/.bin/openclaw +21 -0
  69. package/extensions/page-action-cache/node_modules/.bin/tsc +21 -0
  70. package/extensions/page-action-cache/node_modules/.bin/tsserver +21 -0
  71. package/extensions/page-action-cache/node_modules/.bin/vitest +21 -0
  72. package/extensions/page-action-cache/openclaw.plugin.json +208 -0
  73. package/extensions/page-action-cache/package.json +76 -0
  74. package/extensions/page-action-cache/scripts/npm_publish.sh +80 -0
  75. package/extensions/page-action-cache/skills/page-action-cache/SKILL.md +216 -0
  76. package/extensions/page-action-cache/src/actions-executor.ts +441 -0
  77. package/extensions/page-action-cache/src/cache-invalidator.ts +271 -0
  78. package/extensions/page-action-cache/src/cache-store.ts +457 -0
  79. package/extensions/page-action-cache/src/cache-strategy.ts +327 -0
  80. package/extensions/page-action-cache/src/hooks-entry.ts +114 -0
  81. package/extensions/page-action-cache/src/hooks.ts +332 -0
  82. package/extensions/page-action-cache/src/index.ts +104 -0
  83. package/extensions/page-action-cache/src/scenario-recognizer.ts +259 -0
  84. package/extensions/page-action-cache/src/security-policy.ts +268 -0
  85. package/extensions/page-action-cache/src/tools.ts +437 -0
  86. package/extensions/page-action-cache/src/types.ts +482 -0
  87. package/extensions/page-action-cache/src/ux-enhancer.ts +266 -0
  88. package/extensions/page-action-cache/src/variable-resolver.ts +258 -0
  89. package/extensions/page-action-cache/tests/actions-executor.test.ts +424 -0
  90. package/extensions/page-action-cache/tests/cache-store.test.ts +267 -0
  91. package/extensions/page-action-cache/tests/integration-test.ts +62 -0
  92. package/extensions/page-action-cache/tests/scenario-recognizer.test.ts +140 -0
  93. package/extensions/page-action-cache/tests/variable-resolver.test.ts +187 -0
  94. package/extensions/page-action-cache/tsconfig.json +39 -0
  95. package/package.json +1 -1
  96. package/scripts/create-instance.sh +26 -8
  97. package/scripts/npm_publish.sh +59 -1
  98. package/scripts/publish-extension.sh +343 -0
  99. package/ui/node_modules/.bin/vite +2 -2
  100. package/ui/node_modules/.bin/vitest +2 -2
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.4.5",
3
- "commit": "df202fa7f9a7bd1fc1d6e3952536cf7ef51dd863",
4
- "builtAt": "2026-03-12T04:57:39.394Z"
2
+ "version": "1.4.7",
3
+ "commit": "5c8fe8fe2b70abb974559a15a167e8b73bbb9311",
4
+ "builtAt": "2026-03-14T11:22:15.436Z"
5
5
  }
@@ -1 +1 @@
1
- 8c0d874c4ab52df13412c0a0baa22c51ebad5dbd05215b3a90d585e3c2fe3e13
1
+ 1f1043e13f08ffc5f162ce45aec35760fba48253e6e7e69154cde67e68c648e5
@@ -5,7 +5,7 @@ import fs, { constants } from "node:fs";
5
5
  import os from "node:os";
6
6
  import chalk, { Chalk } from "chalk";
7
7
  import { Logger } from "tslog";
8
- import JSON5 from "json5";
8
+ import json5 from "json5";
9
9
  import util, { promisify } from "node:util";
10
10
  import fs$1 from "node:fs/promises";
11
11
  import process$1 from "node:process";
@@ -400,7 +400,7 @@ function readLoggingConfig() {
400
400
  try {
401
401
  if (!fs.existsSync(configPath)) return;
402
402
  const raw = fs.readFileSync(configPath, "utf-8");
403
- const logging = JSON5.parse(raw)?.logging;
403
+ const logging = json5.parse(raw)?.logging;
404
404
  if (!logging || typeof logging !== "object" || Array.isArray(logging)) return;
405
405
  return logging;
406
406
  } catch {
@@ -4481,7 +4481,7 @@ function resolveOpenClawManifestBlock(params) {
4481
4481
  const raw = getFrontmatterString(params.frontmatter, params.key ?? "metadata");
4482
4482
  if (!raw) return;
4483
4483
  try {
4484
- const parsed = JSON5.parse(raw);
4484
+ const parsed = json5.parse(raw);
4485
4485
  if (!parsed || typeof parsed !== "object") return;
4486
4486
  const manifestKeys = [MANIFEST_KEY, ...LEGACY_MANIFEST_KEYS];
4487
4487
  for (const key of manifestKeys) {
@@ -4,7 +4,7 @@ import chalk, { Chalk } from "chalk";
4
4
  import fs, { constants, createWriteStream } from "node:fs";
5
5
  import { Logger } from "tslog";
6
6
  import os from "node:os";
7
- import JSON5 from "json5";
7
+ import json5 from "json5";
8
8
  import { promisify } from "node:util";
9
9
  import fs$1 from "node:fs/promises";
10
10
  import "@clack/prompts";
@@ -766,7 +766,7 @@ function readLoggingConfig() {
766
766
  try {
767
767
  if (!fs.existsSync(configPath)) return;
768
768
  const raw = fs.readFileSync(configPath, "utf-8");
769
- const logging = JSON5.parse(raw)?.logging;
769
+ const logging = json5.parse(raw)?.logging;
770
770
  if (!logging || typeof logging !== "object" || Array.isArray(logging)) return;
771
771
  return logging;
772
772
  } catch {
@@ -0,0 +1,602 @@
1
+ # OpenClaw 浏览器操作架构文档
2
+
3
+ ## 概述
4
+
5
+ OpenClaw 提供完整的浏览器自动化能力,允许用户通过 CLI 或编程接口控制真实浏览器进行页面导航、截图、表单填写、代码执行等操作。
6
+
7
+ ## 整体架构
8
+
9
+ ```
10
+ ┌─────────────────────────────────────────────────────┐
11
+ │ 用户/系统请求 │
12
+ │ ↓ │
13
+ │ ┌─────────────┐ │
14
+ │ │ CLI 命令层 │ │
15
+ │ └─────────────┘ │
16
+ │ ↓ │
17
+ │ ┌─────────────┐ │
18
+ │ │ 浏览器控制 │ │
19
+ │ └─────────────┘ │
20
+ │ ↓ │
21
+ │ ┌─────────────┐ │
22
+ │ │ Browser Server │ │
23
+ │ │ (Express HTTP)│ │
24
+ │ └─────────────┘ │
25
+ │ ↓ │
26
+ │ ┌─────────────┐ │
27
+ │ │ Playwright CDP │ │
28
+ │ └─────────────┘ │
29
+ │ ↓ │
30
+ │ ┌─────────────┐ │
31
+ │ │ Chrome/Edge │ │
32
+ │ └─────────────┘ │
33
+ │ ↓ │
34
+ │ 返回:截图、PDF、页面操作 │
35
+ └─────────────────────────────────────────────────────┘
36
+ ```
37
+
38
+ ## 核心组件
39
+
40
+ ### 1. 浏览器控制服务器
41
+
42
+ **位置**: `src/browser/server.ts`
43
+
44
+ **功能**:
45
+ - 启动 HTTP 服务器监听本地端口 (默认配置的端口)
46
+ - 接收来自 CLI 的控制命令
47
+ - 管理浏览器会话状态和认证
48
+ - 注册浏览器路由处理不同类型的请求
49
+
50
+ **启动流程**:
51
+ ```typescript
52
+ 1. 加载配置 (loadConfig)
53
+ 2. 检查 browser.enabled 是否启用
54
+ 3. 解析浏览器控制认证配置
55
+ 4. 创建 Express 应用实例
56
+ 5. 安装通用中间件和认证中间件
57
+ 6. 创建路由上下文 (createBrowserRouteContext)
58
+ 7. 注册所有浏览器路由 (registerBrowserRoutes)
59
+ 8. 监听配置端口 (app.listen(port, "127.0.0.1"))
60
+ 9. 初始化扩展中继配置
61
+ 10. 返回服务器状态对象
62
+ ```
63
+
64
+ **认证方式**:
65
+ - **Token 认证**: 使用配置的 token (CDP endpoint auth)
66
+ - **Password 认证**: 使用密码方式认证
67
+ - **内置 Token**: 认证失败时自动生成的 gateway.auth.token
68
+ - **关闭模式**: 不启用任何认证 (auth=off)
69
+
70
+ ### 2. 路由分发器
71
+
72
+ **位置**: `src/browser/routes/dispatcher.ts`
73
+
74
+ **功能**:
75
+ - 将 HTTP 请求路由到对应的处理器
76
+ - 支持参数解析和路径规范化
77
+ - 提供统一的错误处理
78
+
79
+ **支持的路由**:
80
+ | 路由 | 方法 | 处理器 | 说明 |
81
+ |------|------|--------|------|
82
+ | `/status` | GET | 获取浏览器运行状态 |
83
+ | `/navigate` | POST | 导航到指定 URL |
84
+ | `/screenshot` | POST | 截取当前页面 |
85
+ | `/pdf` | POST | 生成页面 PDF |
86
+ | `/act` | POST | 执行各种操作 |
87
+ | `/evaluate` | POST | 执行 JavaScript 代码 |
88
+
89
+ ### 3. Agent 操作路由
90
+
91
+ **位置**: `src/browser/routes/agent.ts`
92
+
93
+ **Agent 操作功能**:
94
+
95
+ #### 3.1 导航操作 (`/navigate`)
96
+
97
+ **请求参数**:
98
+ ```typescript
99
+ {
100
+ url: string; // 目标 URL (必需)
101
+ targetId?: string; // 目标标签页 ID
102
+ }
103
+ ```
104
+
105
+ **实现流程**:
106
+ ```typescript
107
+ 1. 接收导航请求
108
+ 2. 获取目标 ID (resolveTargetIdFromBody)
109
+ 3. 进入 Playwright 路由上下文 (withPlaywrightRouteContext)
110
+ 4. 调用 pw.navigateViaPlaywright()
111
+ 5. 传递导航策略 (withBrowserNavigationPolicy)
112
+ 6. 执行导航到目标 URL
113
+ 7. 导航后可能触发渲染器切换 (resolveTargetIdAfterNavigate)
114
+ 8. 获取最新目标 ID
115
+ 9. 返回目标 ID 和 URL
116
+
117
+ 响应示例:
118
+ ```json
119
+ {
120
+ "ok": true,
121
+ "targetId": "chrome-tab-12345",
122
+ "url": "https://example.com"
123
+ }
124
+ ```
125
+
126
+ #### 3.2 截图操作 (`/screenshot`)
127
+
128
+ **请求参数**:
129
+ ```typescript
130
+ {
131
+ targetId?: string; // 目标标签页 ID (可选)
132
+ fullPage?: boolean; // 是否截取整个页面 (可选,默认 false)
133
+ ref?: string; // 引用 ID (可选)
134
+ }
135
+ ```
136
+
137
+ **实现流程**:
138
+ ```typescript
139
+ 1. 接收截图请求
140
+ 2. 获取目标 ID
141
+ 3. 进入 Playwright 路由上下文
142
+ 4. 规范化截图配置 (normalizeBrowserScreenshot)
143
+ 5. 调用 pw.pdfViaPlaywright() - 截取为 PDF
144
+ 6. 检查文件大小是否超过限制
145
+ 7. 调用 saveBrowserMediaResponse() 保存媒体文件
146
+ 8. 返回保存的文件路径和 URL
147
+
148
+ 响应示例:
149
+ ```json
150
+ {
151
+ "ok": true,
152
+ "path": "/media/browser/screenshot-20240313-123456.png",
153
+ "targetId": "chrome-tab-12345",
154
+ "url": "https://example.com"
155
+ }
156
+ ```
157
+
158
+ #### 3.3 PDF 操作 (`/pdf`)
159
+
160
+ **请求参数**:
161
+ ```typescript
162
+ {
163
+ targetId?: string; // 目标标签页 ID
164
+ }
165
+ ```
166
+
167
+ **实现流程**:
168
+ ```typescript
169
+ 1. 接收 PDF 生成请求
170
+ 2. 获取目标 ID
171
+ 3. 进入 Playwright 路由上下文
172
+ 4. 调用 pw.pdfViaPlaywright()
173
+ 5. 生成 PDF 文件
174
+ 6. 保存媒体文件 (saveBrowserMediaResponse)
175
+ 7. 返回保存的文件路径
176
+
177
+ #### 3.4 操作执行 (`/act`)
178
+
179
+ **支持的操作类型**:
180
+
181
+ ##### 点击操作 (`kind=click`)
182
+ ```typescript
183
+ {
184
+ ref?: string; // 元素引用 ID
185
+ button?: string; // 按钮标识 (left/right/middle)
186
+ doubleClick?: boolean; // 是否双击
187
+ timeoutMs?: number; // 超时时间 (毫秒)
188
+ modifiers?: string[]; // 修饰符 (ctrl, shift, alt, meta)
189
+ }
190
+ ```
191
+
192
+ **支持的按钮标识**:
193
+ - `left` - 左键按钮
194
+ - `right` - 右键按钮
195
+ - `middle` - 中间按钮
196
+
197
+ **支持的修饰符**:
198
+ - `ctrl` - Control 键
199
+ - `shift` - Shift 键
200
+ - `alt` - Alt 键
201
+ - `meta` - Meta 键
202
+
203
+ ##### 输入操作 (`kind=type`)
204
+ ```typescript
205
+ {
206
+ ref?: string; // 元素引用 ID
207
+ text?: string; // 要输入的文本
208
+ submit?: boolean; // 是否触发表单提交
209
+ slowly?: boolean; // 是否慢速输入
210
+ timeoutMs?: number; // 超时时间 (毫秒)
211
+ }
212
+ ```
213
+
214
+ ##### 按键操作 (`kind=press`)
215
+ ```typescript
216
+ {
217
+ ref?: string; // 元素引用 ID
218
+ key?: string; // 要按的键
219
+ delayMs?: number; // 按键延迟 (毫秒)
220
+ }
221
+ ```
222
+
223
+ ##### 悬停操作 (`kind=hover`)
224
+ ```typescript
225
+ {
226
+ ref?: string; // 元素引用 ID
227
+ timeoutMs?: number; // 悬停超时 (毫秒)
228
+ }
229
+ ```
230
+
231
+ ##### 滚动操作 (`kind=scroll`)
232
+ ```typescript
233
+ {
234
+ ref?: string; // 元素引用 ID
235
+ }
236
+ ```
237
+
238
+ ### 4. Playwright 集成
239
+
240
+ **位置**: `src/browser/pw-ai.ts`
241
+
242
+ **功能**:
243
+ - 创建 Playwright 客户端连接到 Chrome/Edge
244
+ - 提供 CDP (Chrome DevTools Protocol) 接口
245
+ - 管理浏览器会话和标签页
246
+ - 提供截图、PDF、导航等高级功能
247
+
248
+ **核心 API**:
249
+
250
+ ```typescript
251
+ // 导航
252
+ await pw.navigateViaPlaywright({
253
+ cdpUrl,
254
+ targetId,
255
+ url,
256
+ ...navigationPolicy
257
+ });
258
+
259
+ // 截图
260
+ await pw.pdfViaPlaywright({
261
+ cdpUrl,
262
+ targetId
263
+ });
264
+
265
+ // 点击
266
+ await pw.clickViaPlaywright({
267
+ cdpUrl,
268
+ targetId,
269
+ ref,
270
+ button,
271
+ doubleClick,
272
+ modifiers
273
+ });
274
+
275
+ // 输入
276
+ await pw.typeViaPlaywright({
277
+ cdpUrl,
278
+ targetId,
279
+ ref,
280
+ text,
281
+ submit,
282
+ slowly
283
+ });
284
+
285
+ // 按键
286
+ await pw.pressKeyViaPlaywright({
287
+ cdpUrl,
288
+ targetId,
289
+ key,
290
+ delayMs
291
+ });
292
+
293
+ // 悬停
294
+ await pw.hoverViaPlaywright({
295
+ cdpUrl,
296
+ targetId,
297
+ ref,
298
+ timeoutMs
299
+ });
300
+ ```
301
+
302
+ ### 5. 配置系统
303
+
304
+ **浏览器配置位置**: `src/browser/config.ts`
305
+
306
+ **配置项**:
307
+
308
+ ```typescript
309
+ interface BrowserConfig {
310
+ enabled: boolean; // 是否启用浏览器控制
311
+ headless: boolean; // 是否无头模式
312
+ controlPort: number; // 控制服务器端口
313
+ cdpUrl?: string; // CDP 端点 URL
314
+ token?: string; // CDP 认证 token
315
+ password?: string; // CDP 认证密码
316
+ sandboxed?: boolean; // 是否沙盒模式
317
+ }
318
+ ```
319
+
320
+ **会话状态管理**:
321
+
322
+ ```typescript
323
+ interface BrowserServerState {
324
+ server: Server; // HTTP 服务器实例
325
+ port: number; // 监听端口
326
+ profiles: Map<string, ProfileStatus>; // 浏览器配置文件集合
327
+ }
328
+ ```
329
+
330
+ **Profile 状态**:
331
+
332
+ ```typescript
333
+ interface ProfileStatus {
334
+ name: string; // Profile 名称
335
+ cdpPort: number; // CDP 端口
336
+ cdpUrl: string; // CDP URL
337
+ color: string; // 浏览器颜色标识
338
+ running: boolean; // 是否正在运行
339
+ tabCount: number; // 打开的标签页数量
340
+ isDefault: boolean; // 是否为默认 profile
341
+ isRemote: boolean; // 是否为远程 profile
342
+ }
343
+ ```
344
+
345
+ ### 6. 媒体存储
346
+
347
+ **位置**: `src/media/store.js`
348
+
349
+ **功能**:
350
+ - 保存截图和 PDF 文件
351
+ - 管理媒体文件目录
352
+ - 限制单个文件大小
353
+ - 支持文件大小统计
354
+
355
+ **媒体类型**:
356
+ - PNG 图片 (`.png`)
357
+ - JPEG 图片 (`.jpeg`)
358
+ - PDF 文档 (`.pdf`)
359
+
360
+ **路径规则**:
361
+ - 截图: `/media/browser/`
362
+ - PDF: `/media/browser/`
363
+
364
+ ### 7. 错误处理
365
+
366
+ **错误类型**:
367
+ 1. **配置错误** - 浏览器未启用、认证配置无效
368
+ 2. **连接错误** - CDP 连接失败、浏览器未启动
369
+ 3. **操作错误** - 元素未找到、操作失败
370
+ 4. **超时错误** - 操作执行超时
371
+ 5. **存储错误** - 文件保存失败、磁盘空间不足
372
+
373
+ **错误响应格式**:
374
+ ```json
375
+ {
376
+ "ok": false,
377
+ "error": "错误描述"
378
+ }
379
+ ```
380
+
381
+ ### 8. 安全特性
382
+
383
+ **认证安全**:
384
+ - Token 认证使用配置文件中的安全 token
385
+ - Password 认证使用环境变量或安全存储
386
+ - 认证失败时拒绝操作
387
+
388
+ **沙盒隔离**:
389
+ - 支持沙盒模式运行浏览器
390
+ - 限制文件系统访问
391
+ - 隔离不同 Profile 的会话
392
+
393
+ ### 9. CLI 命令使用
394
+
395
+ **查看浏览器状态**:
396
+ ```bash
397
+ openclaw browser status
398
+ ```
399
+
400
+ **导航到 URL**:
401
+ ```bash
402
+ openclaw browser navigate --url https://example.com
403
+ ```
404
+
405
+ **截图**:
406
+ ```bash
407
+ openclaw browser screenshot
408
+ # 全屏截图
409
+ ```
410
+
411
+ **生成 PDF**:
412
+ ```bash
413
+ openclaw browser pdf --url https://example.com
414
+ ```
415
+
416
+ **执行操作**:
417
+ ```bash
418
+ # 点击按钮
419
+ openclaw browser act --kind click --button submit
420
+
421
+ # 输入文本
422
+ openclaw browser act --kind type --text "Hello, World!"
423
+
424
+ # 按键
425
+ openclaw browser act --kind press --key Enter
426
+
427
+ # 悬停元素
428
+ openclaw browser act --kind hover
429
+ ```
430
+
431
+ **指定 Profile**:
432
+ ```bash
433
+ openclaw browser --profile my-chrome-profile navigate --url https://example.com
434
+ ```
435
+
436
+ ### 10. 扩展性
437
+
438
+ **支持的浏览器**:
439
+ - Google Chrome
440
+ - Microsoft Edge
441
+ - Chromium (通过 CDP)
442
+
443
+ **多 Profile 支持**:
444
+ - 同时管理多个浏览器配置
445
+ - 每个 Profile 独立的会话
446
+ - 支持远程和本地 Profile
447
+
448
+ **插件系统**:
449
+ - 支持浏览器扩展安装
450
+ - 通过 hooks 系统扩展功能
451
+
452
+ ## 使用示例
453
+
454
+ ### 示例 1: 自动化表单填写
455
+
456
+ ```bash
457
+ # 1. 导航到表单页面
458
+ openclaw browser navigate --url https://example.com/form
459
+
460
+ # 2. 等待页面加载 (在代码中添加延迟)
461
+
462
+ # 3. 输入名字
463
+ openclaw browser act --kind type --text "John Doe"
464
+
465
+ # 4. 输入邮箱
466
+ openclaw browser act --kind type --text "john@example.com"
467
+
468
+ # 5. 提交表单
469
+ openclaw browser act --kind click --button submit
470
+
471
+ # 6. 截图确认
472
+ openclaw browser screenshot
473
+ ```
474
+
475
+ ### 示例 2: 生成 PDF 报告
476
+
477
+ ```bash
478
+ # 1. 导航到报告页面
479
+ openclaw browser navigate --url https://example.com/report
480
+
481
+ # 2. 生成 PDF
482
+ openclaw browser pdf
483
+
484
+ # 3. PDF 文件保存到 /media/browser/report-20240313.pdf
485
+ ```
486
+
487
+ ### 示例 3: 页面交互
488
+
489
+ ```bash
490
+ # 导航到页面
491
+ openclaw browser navigate --url https://example.com/dashboard
492
+
493
+ # 点击刷新按钮
494
+ openclaw browser act --kind click --ref refresh-button
495
+
496
+ # 等待页面加载完成
497
+ # 截图确认新内容
498
+ openclaw browser screenshot
499
+ ```
500
+
501
+ ## 技术细节
502
+
503
+ ### Playwright CDP 连接
504
+
505
+ OpenClaw 使用 Playwright 的 CDP (Chrome DevTools Protocol) 连接方式与浏览器通信:
506
+
507
+ ```typescript
508
+ const pw = new PwAi({
509
+ endpoint: config.cdpUrl,
510
+ token: config.cdpToken,
511
+ headless: config.headless
512
+ });
513
+ ```
514
+
515
+ **优点**:
516
+ - 原生浏览器性能
517
+ - 完整的 DevTools 支持
518
+ - 支持所有现代浏览器特性
519
+ - 更好的调试能力
520
+
521
+ **要求**:
522
+ - 浏览器必须支持远程调试
523
+ - 需要正确的端点 URL 和认证信息
524
+
525
+ ### 状态管理
526
+
527
+ 浏览器控制服务器维护以下状态:
528
+
529
+ 1. **服务器状态** - HTTP 服务器是否运行
530
+ 2. **Profile 状态** - 每个 Profile 的连接和使用状态
531
+ 3. **会话状态** - 标签页、导航历史等
532
+ 4. **认证状态** - 当前使用的认证方式
533
+
534
+ ### 日志记录
535
+
536
+ 浏览器操作通过以下日志级别记录:
537
+
538
+ 1. **INFO** - 正常操作日志
539
+ 2. **WARN** - 警告信息 (认证失败、重试等)
540
+ 3. **ERROR** - 错误信息 (连接失败、操作失败等)
541
+ 4. **DEBUG** - 调试信息 (详细的请求/响应)
542
+
543
+ 日志子系统: `browser-server`
544
+
545
+ ## 故障排查
546
+
547
+ ### 常见问题
548
+
549
+ **问题 1**: 浏览器无法连接
550
+ ```
551
+ 解决方案:
552
+ 1. 检查浏览器是否支持远程调试
553
+ 2. 验证 CDP 端点 URL 和端口
554
+ 3. 确认认证信息正确
555
+ 4. 检查浏览器是否正在运行
556
+ ```
557
+
558
+ **问题 2**: 操作超时
559
+ ```
560
+ 解决方案:
561
+ 1. 增加 timeoutMs 参数
562
+ 2. 检查网络连接稳定性
563
+ 3. 确认目标页面已加载完成
564
+ ```
565
+
566
+ **问题 3**: 元素未找到
567
+ ```
568
+ 解决方案:
569
+ 1. 检查选择器表达式是否正确
570
+ 2. 使用 ref 参数引用正确的元素
571
+ 3. 等待页面完全加载后再操作
572
+ ```
573
+
574
+ ### 性能优化
575
+
576
+ 1. **并发控制**: 限制同时进行的浏览器操作数量
577
+ 2. **缓存**: 缓存浏览器连接和会话
578
+ 3. **懒加载**: 按需加载 Playwright 模块
579
+ 4. **资源清理**: 及时清理不再使用的媒体文件
580
+
581
+ ## 安全考虑
582
+
583
+ 1. **认证保护**: Token 和 Password 不应在日志中明文显示
584
+ 2. **输入验证**: 所有用户输入必须经过验证
585
+ 3. **CSRF 防护**: 跨站请求需要适当保护
586
+ 4. **文件大小限制**: 防止过大的媒体文件占用磁盘
587
+ 5. **沙盒隔离**: 不同 Profile 之间的操作应该隔离
588
+
589
+ ## API 参考
590
+
591
+ 详细的 API 文档请参考源代码中的类型定义:
592
+
593
+ - `src/browser/server.ts` - 服务器配置和启动
594
+ - `src/browser/routes/dispatcher.ts` - 路由分发
595
+ - `src/browser/routes/agent.ts` - Agent 操作处理
596
+ - `src/browser/pw-ai.ts` - Playwright 集成
597
+ - `src/browser/client.ts` - 客户端类型和状态
598
+ - `src/browser/routes/types.ts` - 路由类型定义
599
+
600
+ ## 更新日志
601
+
602
+ 本文档描述了 OpenClaw 浏览器操作架构的主要组件和数据流。如有更新,请参考源代码中的最新实现。
@@ -10,9 +10,9 @@ case `uname` in
10
10
  esac
11
11
 
12
12
  if [ -z "$NODE_PATH" ]; then
13
- export NODE_PATH="/Users/zhoujinyu/Documents/projects/repo/node_modules/.pnpm/openclaw@2026.3.8_@napi-rs+canvas@0.1.96_@types+express@5.0.6_hono@4.12.7_node-llama-cpp@3.16.2_typescript@5.9.3_/node_modules/openclaw/node_modules:/Users/zhoujinyu/Documents/projects/repo/node_modules/.pnpm/openclaw@2026.3.8_@napi-rs+canvas@0.1.96_@types+express@5.0.6_hono@4.12.7_node-llama-cpp@3.16.2_typescript@5.9.3_/node_modules:/Users/zhoujinyu/Documents/projects/repo/node_modules/.pnpm/node_modules"
13
+ export NODE_PATH="/Users/zhoujinyu/Documents/projects/repo/node_modules/.pnpm/openclaw@2026.3.13_@napi-rs+canvas@0.1.96_@types+express@5.0.6_node-llama-cpp@3.16.2_typescript@5.9.3_/node_modules/openclaw/node_modules:/Users/zhoujinyu/Documents/projects/repo/node_modules/.pnpm/openclaw@2026.3.13_@napi-rs+canvas@0.1.96_@types+express@5.0.6_node-llama-cpp@3.16.2_typescript@5.9.3_/node_modules:/Users/zhoujinyu/Documents/projects/repo/node_modules/.pnpm/node_modules"
14
14
  else
15
- export NODE_PATH="/Users/zhoujinyu/Documents/projects/repo/node_modules/.pnpm/openclaw@2026.3.8_@napi-rs+canvas@0.1.96_@types+express@5.0.6_hono@4.12.7_node-llama-cpp@3.16.2_typescript@5.9.3_/node_modules/openclaw/node_modules:/Users/zhoujinyu/Documents/projects/repo/node_modules/.pnpm/openclaw@2026.3.8_@napi-rs+canvas@0.1.96_@types+express@5.0.6_hono@4.12.7_node-llama-cpp@3.16.2_typescript@5.9.3_/node_modules:/Users/zhoujinyu/Documents/projects/repo/node_modules/.pnpm/node_modules:$NODE_PATH"
15
+ export NODE_PATH="/Users/zhoujinyu/Documents/projects/repo/node_modules/.pnpm/openclaw@2026.3.13_@napi-rs+canvas@0.1.96_@types+express@5.0.6_node-llama-cpp@3.16.2_typescript@5.9.3_/node_modules/openclaw/node_modules:/Users/zhoujinyu/Documents/projects/repo/node_modules/.pnpm/openclaw@2026.3.13_@napi-rs+canvas@0.1.96_@types+express@5.0.6_node-llama-cpp@3.16.2_typescript@5.9.3_/node_modules:/Users/zhoujinyu/Documents/projects/repo/node_modules/.pnpm/node_modules:$NODE_PATH"
16
16
  fi
17
17
  if [ -x "$basedir/node" ]; then
18
18
  exec "$basedir/node" "$basedir/../openclaw/openclaw.mjs" "$@"
@@ -10,9 +10,9 @@ case `uname` in
10
10
  esac
11
11
 
12
12
  if [ -z "$NODE_PATH" ]; then
13
- export NODE_PATH="/Users/zhoujinyu/Documents/projects/repo/node_modules/.pnpm/openclaw@2026.3.8_@napi-rs+canvas@0.1.96_@types+express@5.0.6_hono@4.12.7_node-llama-cpp@3.16.2_typescript@5.9.3_/node_modules/openclaw/node_modules:/Users/zhoujinyu/Documents/projects/repo/node_modules/.pnpm/openclaw@2026.3.8_@napi-rs+canvas@0.1.96_@types+express@5.0.6_hono@4.12.7_node-llama-cpp@3.16.2_typescript@5.9.3_/node_modules:/Users/zhoujinyu/Documents/projects/repo/node_modules/.pnpm/node_modules"
13
+ export NODE_PATH="/Users/zhoujinyu/Documents/projects/repo/node_modules/.pnpm/openclaw@2026.3.13_@napi-rs+canvas@0.1.96_@types+express@5.0.6_node-llama-cpp@3.16.2_typescript@5.9.3_/node_modules/openclaw/node_modules:/Users/zhoujinyu/Documents/projects/repo/node_modules/.pnpm/openclaw@2026.3.13_@napi-rs+canvas@0.1.96_@types+express@5.0.6_node-llama-cpp@3.16.2_typescript@5.9.3_/node_modules:/Users/zhoujinyu/Documents/projects/repo/node_modules/.pnpm/node_modules"
14
14
  else
15
- export NODE_PATH="/Users/zhoujinyu/Documents/projects/repo/node_modules/.pnpm/openclaw@2026.3.8_@napi-rs+canvas@0.1.96_@types+express@5.0.6_hono@4.12.7_node-llama-cpp@3.16.2_typescript@5.9.3_/node_modules/openclaw/node_modules:/Users/zhoujinyu/Documents/projects/repo/node_modules/.pnpm/openclaw@2026.3.8_@napi-rs+canvas@0.1.96_@types+express@5.0.6_hono@4.12.7_node-llama-cpp@3.16.2_typescript@5.9.3_/node_modules:/Users/zhoujinyu/Documents/projects/repo/node_modules/.pnpm/node_modules:$NODE_PATH"
15
+ export NODE_PATH="/Users/zhoujinyu/Documents/projects/repo/node_modules/.pnpm/openclaw@2026.3.13_@napi-rs+canvas@0.1.96_@types+express@5.0.6_node-llama-cpp@3.16.2_typescript@5.9.3_/node_modules/openclaw/node_modules:/Users/zhoujinyu/Documents/projects/repo/node_modules/.pnpm/openclaw@2026.3.13_@napi-rs+canvas@0.1.96_@types+express@5.0.6_node-llama-cpp@3.16.2_typescript@5.9.3_/node_modules:/Users/zhoujinyu/Documents/projects/repo/node_modules/.pnpm/node_modules:$NODE_PATH"
16
16
  fi
17
17
  if [ -x "$basedir/node" ]; then
18
18
  exec "$basedir/node" "$basedir/../openclaw/openclaw.mjs" "$@"