dsh-agent-webops
浏览器自主操作插件:爱丽丝经 headless Chrome (CDP) 自主打开页面/点击/输入/读取/截图——GUI 验证与网页操作全自主,不依赖主人手动操作。
- Stars
- 1
- Language
- TypeScript
- Created
- Aug 17, 2026
- Updated
- Sep 20, 2026
Introduction
dsh-agent-webops — 浏览器自主操作插件
一句话:给 agent 一个自己的 CDP 会话——打开页面、读文本、点按钮、填输入框、跑 JS、等条件、读控制台、截图,全流程自主,不借用主人的浏览器。
两种模式:
- spawn(
webops_open):自己拉起 headless 浏览器,临时 profile 隔离,close清干净; - attach(
webops_attach):附着到已在运行的外部 CDP 端点(Tauri/WebView2 窗口、Electron 应用、任何带--remote-debugging-port=N的进程)——DOM 级驱动桌面应用界面,且close只断开、绝不碰目标进程。
为什么值得用:验收不再「交还给用户」。改完前端/面板/桌面应用,agent 直接 webops_shot 看图判定,或 webops_eval 取几何/状态断言;attach 模式下连截图都不需要窗口在前台,也不必做 DPI/坐标换算。
能力
| 工具 | 用途 |
|---|---|
webops_open | 拉起自主浏览器(headless)并导航到 URL——自主 GUI/网页操作的第一步。关闭旧实例需先 webops_close |
webops_attach | 附着到已运行的外部 CDP 端点(Tauri/WebView2、Electron、任何开调试端口的进程);不启动进程,close 只断开、不杀目标 |
webops_read | 读取当前页面文本(可选 CSS 选择器限定;缺省取 body 全文) |
webops_click | 点击元素(按可见文本精确/包含匹配 button/a/span 等;返回 CLICKED/NOT_FOUND) |
webops_type | 向输入框写文本(CSS 选择器定位;React 兼容——原生 setter + input/change 事件) |
webops_eval | 执行任意 JS(awaitPromise 支持 async;返回值需 JSON 可序列化) |
webops_wait | 服务端轮询等待页面里的 JS 条件成立(按真值判断;页面异常与「条件为假」区分开)——替代盲等 sleep |
webops_console | 读取页面控制台/异常/日志(连接期间缓冲的最近条目)——白屏与 JS 报错的第一取证入口(程序化 F12) |
webops_shot | 截图(PNG 存到 shotDir,返回路径——配合 read_image 查看;attach 模式下无需窗口在前台) |
webops_close | spawn:关实例(进程 + 临时 profile 清理);attach:只断开连接(目标进程不受影响) |
快速开始
1) 装依赖:
"dsh-agent-webops": "link:<工作区>/self-plugins/dsh-agent-webops"
2) 挂组合:
- id: agent-webops
name: dsh-agent-webops
config:
browserBin: C:/Program Files/Google/Chrome/Application/chrome.exe
shotDir: '' # 缺省 = <DSH_HOME>/webops-shots
attachPort: 9333 # attach 缺省端口;不要与 portMin(9222) 相同
3a) 30 秒验证(spawn 模式):
webops_open { url: "http://127.0.0.1:3080" } → 期望 { ok: true }
webops_eval { expression: "location.href" } → 期望返回该 URL 字符串
webops_close {} → 期望 ok,进程与临时 profile 被清理
3b) 30 秒验证(attach 模式,以 Tauri/WebView2 应用为例):
# 目标进程必须**自己**带调试端口启动(Windows/WebView2 经环境变量):
# set "WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS=--remote-debugging-port=9333" && <app>.exe
webops_attach { port: 9333 } → 期望 { ok:true, title:"…", url:"…" }
webops_console { limit: 20 } → 期望看到页面真实控制台输出(白屏时先看这里)
webops_wait { expression: "document.querySelectorAll('.star').length >= 1" }
webops_shot {} → 截图落盘;read_image 看图
webops_close {} → 只断开:目标进程仍然活着(这是设计,不是缺陷)
配置
| 项 | 默认 | 说明 |
|---|---|---|
browserBin | C:/Program Files/Google/Chrome/Application/chrome.exe | 浏览器可执行文件(仅 spawn 模式用;用 Edge 则指向 msedge.exe) |
portMin | 9222 | spawn 的 CDP 调试端口。固定用 9222:实测非默认端口可能被安全软件拦截导致不监听 |
shotDir | '' | 截图目录;空则用 <DSH_HOME>/webops-shots(DSH_HOME 也缺失时回落 .) |
attachPort | 9333 | attach 的缺省端口(调用时可用 port 覆盖)。必须与 portMin 不同:同一端口两个 owner 会互相堵死 |
落盘与自证(出问题时先看这里)
本插件无轨迹 JSONL(无 *-trace.jsonl)——它的可观测面就是浏览器自身的产物:
| 产物 | 位置 | 含义 |
|---|---|---|
| 截图 PNG | shotDir(缺省 <DSH_HOME>/webops-shots) | webops_shot 落盘,文件名带时间戳(screenshotFileName(nowMs)) |
| 临时 profile | 系统 TEMP 下的新建目录(profileDirFor(TEMP, Date.now())) | 每次 open 新建,close 时清理(attach 模式无此产物) |
| 浏览器进程 | spawn(browserBin, chromeArgs(...), { stdio: 'ignore' }) | 进程即实例;webops_open 时若实例已开则报错(不静默复用) |
| 控制台缓冲 | 内存(连接期间) | webops_console 读取;容量 200 条、单条 ≤1000 字符 |
一条命令答五问(用产物替代轨迹):
ls -lt "$DSH_HOME/webops-shots" | head -3
# ① 跑的是哪个构建 → 无 build 戳;用 lib/index.js mtime + plugin_boot_status 判定(见下节)
# ② 谁发起 → 截图文件名的时间戳 ↔ 会话事件流里的工具调用时间对齐
# ③ 断在哪一段 → 工具返回值:open/attach/click 的 { ok:false, error } 直接给出失败原因(无阶段枚举;
# attach 失败文案已二分:「无端点」vs「有监听但无 page target」)
# ④ 结果质量 → read_image 打开最新 PNG 亲眼看;或 webops_read/eval/console 的返回内容
# ⑤ 耗时与预算 → wait 返回 waitedMs;open/attach 为轮询就绪后返回
行为级自证(推荐,比看文件更直接):webops_eval { expression: "document.title" } → 标题正确 = 连接真的在跑且页面真的加载了。
生效判据与回退
生效判据(三选一,按可靠性排序):
- 行为级:
webops_open/webops_attach返回{ok:true}且webops_eval能取到页面状态 ⇒ 连接与 CDP 链路都通; - 进程级:spawn 模式下任务管理器/
Get-Process里能看到 headless 浏览器进程,命令行包含本次的临时 profile 目录;attach 模式下Get-NetTCPConnection -LocalPort <port> -State Listen命中目标进程; - 生态级:工具面出现 10 个
webops_*,且plugin_boot_status(dsh-plugin-bootreport)返回liveNow含本插件 ⇒ 当前进程跑的是当前构建。
注意:重新构建 ≠ 生效——产物 mtime 新只证明「构建过」,进程启动时间晚于产物 mtime 才算「在跑它」。 另注:CDP 端口被占用 / 浏览器路径写错 / 目标进程没开调试端口时连接会失败——这正是需要先跑 30 秒验证的原因。
回退(三档):
- 源码级:
git -C self-plugins/dsh-agent-webops revert <commit>→ 重新构建 → 预检 → 重启(v0.2.0 的回退 = 失去webops_attach,webops_open行为不变); - 组合级:预设里给
agent-webops行加disabled: true(或移除该行)→ 哨兵重启; - 运行期:spawn 模式
webops_close关实例(异常残留时按进程名清理 headless 浏览器进程 + 删 TEMP 下临时 profile);attach 模式webops_close只断开,无需清理。
测试
npm test # = node --test "tests/*.test.mjs"
31 例离线测试(不需要浏览器、不需要网络):
tests/pure.test.mjs— 纯逻辑(21 例):resolveShotDir、profileDirFor、chromeArgs(含--headless/调试端口/临时 profile/顺序)、cdpJsonUrl、cdpTargetOf(坏响应不抛)、screenshotFileName、isParseableExpression;v0.2.0 新增closePlan尸体测试(attach 分支必须不杀进程)、attachFailureMessage(两态文案必须不同)、consoleEntryOf(三条事件归一 + 非控制台事件 null + 截断)、appendConsole(环形丢最旧、不原地改)、waitExpr/waitDecision(四态:ok/continue/timeout/error)tests/dom.test.mjs— 注入安全(10 例):readExpr/clickJs/typeJs生成的表达式对选择器/文本中的引号、反斜杠做 JSON 转义,不破坏表达式(含注入样本)
真实外部依赖:spawn 模式需本机 Chrome/Edge 可执行文件;attach 模式需目标进程自行开调试端口;两者都需目标页面可达。测试不需要。
设计要点
- 固定调试端口 9222(spawn)/ 独立缺省端口 9333(attach):实测随机偏移端口在部分安全软件下不监听——宁可固定;而两个用途不得共用同一端口(同一端口两个 owner 会互相堵死)。
- attach 的安全不变量:目标进程不是我启动的 ⇒
close()只断 WebSocket(closePlan(attached=true) = {killProc:false, rmProfile:false},有尸体测试);这样「用 agent 驱动别人的应用」不会变成「agent 把别人的应用关了」。 - 单实例、显式生命周期:已连接时再
open/attach直接报错(不静默复用);spawn 的close清理进程 + 临时 profile,不存在「幽灵实例」。 stdio: 'ignore':浏览器 stdout/stderr 与宿主管道解耦——宿主崩溃/管道背压不会波及浏览器,反之亦然。- React 兼容输入:
webops_type用原生 setter + 派发input/change,否则受控组件收不到值(直接改value会被 React 覆盖)。 - 表达式注入边界:选择器/文本一律经 JSON 转义后拼进表达式(
tests/dom.test.mjs覆盖),避免引号破坏选择器语义。 - 等待与服务端轮询:
webops_wait把「条件成立」的判断放在服务端(默认 5s / 250ms),页面内异常转成WAIT_ERR:→ok:false,不与「条件为假」混同。 webops_eval是页面内完全控制:只在受信目标上使用;它给的是「页面上下文里的任意 JS」,不是沙箱逃逸能力。
相关文档
| 文档 | 内容 |
|---|---|
docs/semantic.md | 权威契约:定位与反定位、术语、概念模型与不变量(含 I6「attach 绝不杀目标」)、契约(含调用点清单)、边界与信任、可证伪验收清单 A1–A20、实践修订记录、未决问题 |
| alice-digital-life | 本插件所属生态的中心索引(全部自研插件) |
插件 computer-use | 像素级 GUI 驱动(原生窗口;与本文的 DOM 级驱动互补) |
技能 ui-visual-verification | 界面视觉与交互验收方法论(截图 + 四类断言,本插件的典型用法) |
技能 anti-scraping-bypass | 反爬通道选择与 headless 执行(页面抓不动时的诊断路径) |
License
MIT © jonah791
本插件属于我的数字生命爱丽丝(alice-digital-life)的 DSH 自研插件生态——50 个插件按生命/认知/感知/行动/通信/治理/呈现七层组织。