dsh-browser-view
Verifieddsh-browser-view · v0.4.1 · MIT · Web UI
DSH 插件:共享 Playwright 浏览器自动化(36 个 browser_* 工具,含语义元素查找、批处理、视觉回归、选择器自愈、参数化/数据驱动回放、失败自动重试、结构化抽取与字段建议、增量快照历史版本、回归报告与隔离 context)+ 人机协作(人工接管等待、敏感操作审批(confirmMode:auto 宿主层硬拦截)、人机混合录制、面板一键重跑、面板双向化:操作预告高亮/内嵌报告)+ 实时画面面板与录制管理。仅依赖 playwright-core,不依赖任何 @deepseek-ai 运
Install
dsh plugin add dsh-browser-view Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Tags
Creators
Readme
dsh-browser-view
DSH 插件:共享 Playwright 浏览器自动化 + 原生界面实时画面面板。一次安装,三件事:
| 模块 | 做什么 |
|---|---|
| 🧭 浏览器自动化 | 共享 Playwright 浏览器:多标签、多 profile、隔离 context、下载/上传、Cookie、表单回放、增量快照(历史版本环形缓存,窗口内任意 since 可 diff)、抽取字段自动建议(action:suggest),36 个 browser_* 工具 |
| 🖥️ 实时画面 | 注入 DSH 界面右下角悬浮面板:浏览器状态 + 实时缩略图,点开大屏模态框(2 秒轮询画面 + 访问历史);双向协作——agent 等待人工操作/敏感审批时显示交互横幅、执行点击/输入前目标元素琥珀色高亮预告(confirmMode:auto 时敏感动作由宿主层强制拦截弹审批,agent 无法绕过),「最近回归」行与报告模态可一键重跑(agent 忙碌自动置灰) |
| ✅ 回归测试闭环 | 录制回放 + 选择器自愈 + 参数化/数据驱动 + 失败自动重试(retryFailed)+ 视觉回归 + 运行历史/报告导出 + 面板一键重跑(/runs/rerun,agent 忙碌置灰) |
设计原则:能做的一次性操作交给 agent 用 bash 完成,插件只做 bash 做不到的常驻浏览器自动化。唯一第三方运行时依赖是 playwright-core(复用系统已装的 Edge/Chrome,无需下载 Chromium),不依赖任何 @deepseek-ai 运行时包。
安装
dsh plugin --profile web add dsh-browser-view
重启 DSH 生效。不需要时在 $DSH_HOME/profiles/web/cordis.patch.yml 里删除 browser 行或加 config: { enabled: false }。
配置(全在 cordis.patch.yml)
- insert:
- id: browser
name: 'dsh-browser-view'
config:
channel: auto # auto | msedge | chrome | chromium | ""(playwright 默认)
executablePath: "" # 显式指定浏览器可执行文件(优先于 channel)
headless: false # 默认有头(本机调试/人工登录);服务器场景可改 true
userDataDir: "" # 设置后登录态跨 DSH 重启保留
profiles: {} # { work: { userDataDir, channel, headless }, ... }
workspaceDir: "" # 截图/下载/上传的落盘基准目录(默认探测会话 cwd,多工作区/服务器场景可钉死)
screenshotDir: .dsh-browser/screenshots
downloadDir: .dsh-browser/downloads
screenshotMaxAgeDays: 7 # 截图保留天数(0 = 不按时间清理)
screenshotMaxCount: 200 # 截图保留数量上限(0 = 不按数量清理)
basePath: /browser # 面板嵌入 + 实时画面 API 基路径(重启生效)
maxTextChars: 20000
maxLinks: 50
timeoutMs: 30000
baselineDir: .dsh-browser/baselines # 视觉回归基线目录(不受截图清理约束)
selectorHealing: true # 回放/批处理选择器自愈(默认开;只作用于失败路径)
healTimeoutMs: 3000 # 自愈时单次尝试的超时
maxRefs: 200 # ARIA 快照每次分配的 ref 上限
maxRows: 1000 # browser_extract 单次聚合行数上限
snapshotHistory: 5 # 增量快照保留的历史版本数 K(1-20;since 命中窗口内任意版本都能 diff)
confirmMode: off # off | manual | auto(auto: 宿主层在敏感动作前强制弹审批,agent 无法绕过)
confirmTimeoutMs: 60000 # browser_confirm 等待人工决策的默认超时
sensitivePatterns: [提交, 删除, 支付] # auto 模式敏感文本模式(子串匹配 role/name/text/id/testid/tag)
sensitiveTools: [browser_click] # auto 模式参与判定的工具(默认只拦 click;type 误报率高,需拦时显式加入)
confirmInReplay: true # replay/batch 是否同样走 auto 审批闸(false = 回放不弹审批,风险自担)
toolset: all # all(默认全量 36 个)| core(高频核心集 24 个,降 systemPrompt 常驻 token)
工具集裁剪(toolset):默认 all 注册全部工具。日常浏览/操作/人机协作为主的会话可设 toolset: core——只注册 24 个高频核心工具(打开/快照/查找/点击/输入/等待/断言/网络/标签/下载上传/登录等待/人工接管/审批/诊断),browser_record / replay / report / extract / form / profile / context / cookies 等低频工具不注册、不占 systemPrompt 常驻 token(低频工具的录制管理界面不受影响,已有录制仍可回放,只是 agent 会话内无这些工具)。需要做回归测试或数据抓取时把配置改回 all 并重启 DSH 即可。
浏览器工具
| 工具 | 说明 |
|---|---|
browser_open |
打开 URL |
browser_tabs |
标签管理:list / new / switch / close(按 id 或 index) |
browser_snapshot |
页面快照:mode: "text"(默认)返回压缩后的文本/链接/输入框;mode: "aria" 返回可访问性树,可交互元素带 [ref=eN] 短引用;scope(CSS 选择器)限定提取区域(text/aria 都生效);since(上次返回的 contentVersion)增量重读——未变返回 unchanged,变了只返回变化行(diff + changedFrom/removed),翻页后重读 token 降一个量级 |
browser_find |
语义元素定位:按名称/id/data-testid 查找可交互元素,只返回命中 ref + ancestors 区域链(大页面定位单目标比全量 aria 快照省 95%+ token);exact 精确匹配、scope 限定容器;多命中全返回,零命中附相近候选 |
browser_elements |
可交互元素结构化清单(input/button/select/链接 + 关联 label + 现成 CSS 选择器;有展开下拉时附可见选项) |
browser_click / browser_type / browser_press |
点击 / 输入(可清空、可回车提交)/ 按键;selector(CSS)与 ref(aria 快照)二选一 |
browser_select |
下拉选择原语:原生 <select> 与 antd / element-plus / ARIA listbox 通用,selector/ref + option 文本一步完成;找不到选项时报错并列出可见选项 |
browser_eval |
在页面上下文执行 JS(结果自动净化成 lossless JSON) |
browser_batch |
动作批处理:一次调用顺序执行多个步骤 [{tool, args}](点击→等待→输入→提交类小序列减少往返;禁止嵌套;可录制可回放) |
browser_screenshot |
截图存为 PNG(自动清理,见下);baseline: "<名>" 存为视觉回归基线(不受清理约束) |
browser_wait / browser_back / browser_reload |
等待 / 后退 / 刷新 |
browser_wait_for_login |
等待人工登录完成(配 headless: false 使用,见下) |
browser_pause_for_human |
人工接管等待:agent 把控制权暂时交还给用户(验证码/二次确认/人工复核),instruction 显示在实时画面面板;successSelector / successUrl 指定完成条件,都不给则 URL/页面内容变化即视为完成;轮询 2 秒,超时返回 completed: false 不抛错 |
browser_confirm |
敏感操作审批:提交/删除/支付类动作前调用,审批请求推送到实时画面面板等待用户点「允许/拒绝」;允许返回 decision: "allowed",拒绝/超时(fail-closed)抛错,live 与 replay/batch 统一按失败处理 |
browser_wait_for |
通用显式等待(元素状态 / URL / 文本 / 数量 / eval,超时抛错) |
browser_assert |
结构化断言(失败自动截图存证据目录并报错);visual: { baseline } 做视觉回归断言(见下) |
browser_network |
接口记录查询:list / failed(4xx/5xx)/ wait(命中返回 waitMs,超时附最近请求摘要)/ stats(按 host 聚合计数/失败数/均耗时/状态码分布)/ clear,含请求/响应体(截断) |
browser_extract |
规则化结构化抽取:fields 定义 CSS 字段(支持嵌套/multiple),next 自动翻页聚合,导出 json / csv / jsonl / markdown 落盘工作区;action: "suggest" 自动推断字段(表格首行/列表卡片 → 单元格文本/链接 href/图片 src),返回建议 fields + 首行样本,微调后直接交给抽取模式(往返 3-4 次降到 2 次);推断不出规律结构返回原因与容器概览,不猜 |
browser_record |
操作录制:start / stop / save(list/delete 管理;save 支持 stripReads 剔除只读步骤、vars 把指定步骤字段抽成 {{占位符}};selector 步骤自动附带元素指纹供回放自愈;录制期间用户在浏览器中的手动输入/点击/选择也会进录制,标记 source: "human") |
browser_replay |
回放录制或步骤序列(回归测试,遇错可停);vars 注入占位符,data / dataFile(CSV)逐行数据驱动;选择器失效自动按指纹自愈;retryFailed: N 失败步骤自动重试 N 次(500ms×n 退避,重试耗尽才停),返回 retries: { attempted, recovered } |
browser_report |
回归报告:list / show / export(运行历史自动记录,export 聚合为 Markdown / 自包含 HTML 落盘) |
browser_status / browser_close |
状态 / 关闭会话 |
browser_doctor |
健康诊断(不启动浏览器):可执行文件/channel、playwright-core、userDataDir 与截图/下载/基线目录写权限、工作区基准目录解析来源、会话状态、面板 API 可达性;失败项附修复建议。环境异常(文件落错位置/浏览器起不来)先跑它定位 |
browser_download / browser_upload |
下载(保存到工作区;wait: true 可轮询等待新下载)/ 上传本地文件 |
browser_cookies |
Cookie 管理(list / set / clear,登录态处理) |
browser_form / browser_form_save / browser_forms |
批量填表 / 保存回放 / 管理已存表单 |
browser_profile |
多配置文件:work/personal 等独立会话与登录态(userDataDir 持久化) |
browser_context |
命名隔离上下文:同一浏览器内 cookies/storage 完全隔离的"标签组"(new/list/switch/close),适合多账号并行验证与干净会话抓取;页进普通标签表,所有工具直接可用。与 profile 的分工:context = 临时并行隔离(不持久化),profile = 持久配置与登录态;持久模式(userDataDir)不支持,用 profiles |
截图自动清理:browser_screenshot 保存的 .png 自动修剪——每次截图后即时清理 + 每小时定时清扫;默认保留最近 7 天、最多 200 张(screenshotMaxAgeDays / screenshotMaxCount,设为 0 关闭对应规则),只清理截图目录直属文件。视觉回归基线(baselineDir)不参与清理。
首次调用浏览器工具时自动启动浏览器;启动失败会提示安装 Chromium(
npx playwright install chromium)或配置executablePath。
自动化测试
插件提供完整的测试原语,agent 可以写出「等待 + 断言 + 网络校验 + 回放」的测试流程:
# 典型流程
browser_open 打开目标页
browser_wait_for { selector: "#app", state: "visible" } # 等页面稳定
browser_assert { text: "登录成功" } # 断言文本
browser_assert { count: { selector: ".row", op: "gte", value: 10 } } # 断言数量
browser_network { action: "failed" } # 检查 4xx/5xx
browser_network { action: "wait", url: "api/orders", status: 200 } # 等接口返回
browser_screenshot # 证据
接口出入参:browser_network 自动记录每个 XHR/fetch 的请求体(postData)与响应体(body,均截断:请求体 2000 字符、响应体 4000 字符;SSE 流与 >500KB 响应跳过;config.recordBodies: false 可关闭)。wait 匹配到的记录同样带出入参,可直接断言接口返回结构。
条件格式(browser_wait_for / browser_assert 共用):
| 字段 | 示例 | 说明 |
|---|---|---|
selector |
{ selector: "#btn", state: "visible" } |
元素状态:visible / hidden / attached / detached |
ref |
{ ref: "e3", state: "visible" } |
aria 快照 ref 的状态等待 |
url |
{ url: "https://.*\\.example\\.com" } |
当前 URL 正则匹配 |
text |
{ text: "保存成功" } |
页面可见文本包含 |
count |
{ count: { selector: ".row", op: "gte", value: 10 } } |
元素数量比较(eq/gt/gte/lt/lte) |
eval |
{ eval: "location.hash === '#done'" } |
任意 JS 表达式求值 truthy |
browser_assert 失败时自动截图(assert-fail-*.png,存截图目录,受清理策略约束)并抛错,错误消息含原因与截图路径。
ARIA 快照 + ref 引用(推荐的定位方式):browser_snapshot { mode: "aria" } 返回页面的可访问性树,可交互元素带 ref=eN 短引用:
- navigation "主导航"
- link "首页" [ref=e1]
- main
- textbox "用户名" [ref=e2]
- button "登录" [ref=e3]
后续 browser_click { ref: "e3" }、browser_type { ref: "e2", text }、browser_select { ref, option }、browser_press { ref, key } 直接用 ref 代替 CSS 选择器——比手写选择器更稳、比文本快照更省 token。ref 解析时会校验元素的 role/name 仍一致(防漂移误点),不一致自动降级 getByRole;页面导航或重新快照后旧 ref 失效(报错提示重取)。读正文仍用默认 mode: "text"。
动作批处理:固定小序列用 browser_batch 一次往返执行:
browser_batch { steps: [
{ tool: "browser_type", args: { ref: "e2", text: "user", clear: true } },
{ tool: "browser_type", args: { ref: "e3", text: "pass", clear: true } },
{ tool: "browser_click", args: { ref: "e4" } },
{ tool: "browser_wait_for", args: { condition: { text: "欢迎" } } },
] }
步骤内禁止嵌套 batch/replay/record;批整体在操作轨迹与录制里记为单条步骤。
回归测试:agent 跑通一轮流程后 browser_record save <name>,以后用 browser_replay { name } 一键回放(默认遇错即停,failFast: false 可继续);也可直接传 steps 数组。save 的数据源:做过 browser_record start → stop 的,保存该段录制;从未录制的,保存最近 100 次工具调用(返回值的 source 字段会标明 recording / recent-log)。save 时会检查 browser_upload 步骤引用的本地文件,缺失的以 warnings 返回(回放将失败,请及时重建或改用稳定路径)。已保存录制写入 $DSH_HOME/.dsh-browser/recordings/<name>.json(原子替换,名字自动安全化防路径穿越),重启 DSH 后自动加载,可跨会话复用;browser_record list / delete 管理。录制管理界面:DSH 设置弹窗 → 左侧导航「浏览器」页,可查看列表、展开步骤详情、删除录制。所有工具调用自动记录操作轨迹(面板显示最近 8 条,/browser/log 可取全量)。
选择器自愈:录制(save)时每个 selector 步骤自动附带元素指纹(data-testid / role+name / 可见文本 / id / 标签)。回放时原选择器失败会按 testid → role+name → text → id → tag+text 降级重试(每次尝试限时 healTimeoutMs,默认 3s,避免等满全局超时),自愈成功的步骤在结果中标记 healed: true, via: "role+name", resolved: "<新选择器>" 并计入 healedCount——提示你该修录制里的选择器了,而不是默默吞掉页面漂移。仅作用于 replay/batch 的失败路径,live 工具不受影响;config.selectorHealing: false 可整体关闭。录制格式为 formatVersion 2,旧格式录制正常回放(无自愈)。
人机混合录制:录制(browser_record start → stop)期间,用户在浏览器窗口中的手动操作——可交互元素上的点击、输入框的输入(change 提交时记当前值,非逐键)、原生下拉的选择——会自动进录制 buffer,映射为 browser_click / browser_type / browser_select 步骤并带同样的选择器指纹,meta.source: "human" 标记来源。典型范式:agent 打底导航到表单页 → browser_record start → 用户补验证码/短信等关键步 → stop + save → 之后整条流程可无人回放。agent 工具自己触发的页内事件用 1.5s 去重窗口排除,不会双记;文件选择(file input)与清空输入无法可靠回放,自动跳过。
参数化与数据驱动:save 时用 vars 把指定步骤的字段抽成占位符:
browser_record { action: "save", name: "login",
vars: { username: "#1.args.text", password: "#2.args.text" } } # 步骤号 1 起
browser_replay { name: "login", vars: { username: "[email protected]", password: "***" } } # 单次注入
browser_replay { name: "login", data: [{ username: "[email protected]", password: "1" },
{ username: "[email protected]", password: "2" }] } # 逐行回放
browser_replay { name: "login", dataFile: "testdata/users.csv" } # CSV 首行为变量名
缺失的占位符直接报错(不做空串替换);data 模式每行独立 failFast、失败不中断后续行,返回 runs 按行聚合。注意 vars 值会随运行记录写入报告,敏感值请自行管理数据文件。
视觉回归:先用 browser_screenshot { baseline: "login" } 建立基线(存 .dsh-browser/baselines/,不受截图清理约束),之后在断言中比对:
browser_assert { visual: { baseline: "login", threshold: 0.1, maxDiffRatio: 0.005,
mask: [".timestamp", ".ad-banner"] } }
- 逐像素加权亮度差超过
threshold(0–1,默认 0.1)计为差异;diffRatio超过maxDiffRatio(默认 0.5%)判失败; mask为忽略区域选择器数组(时钟/广告位/随机头像等动态内容),两图同步填白后比对;- 尺寸不一致直接失败;失败时落盘当前截图与红标 diff 图,路径在错误消息里;
- 超过 1000px 边长的大图会先等比缩放再比对(性能折中,亚像素级差异可能漏检);
- 零额外依赖:像素比对在浏览器内 canvas 完成。
回归报告:每次 browser_replay / browser_batch 自动记入运行历史($DSH_HOME/.dsh-browser/reports/runs.jsonl,上限 1000 条):
browser_report { action: "list" } # 最近运行
browser_report { action: "show" } # 最近一条详情
browser_report { action: "export", format: "html", file: "reports/r.html" }
browser_report { action: "export", source: "login" } # 只聚合某录制
报告含运行趋势、失败步骤 Top、自愈步骤清单(建议修复录制选择器)。面板状态行会显示最近一次回归结果。定时回归:用 DSH 的 schedule 能力组合即可——定时触发 browser_replay { name } + browser_report { action: "export" },早上看报告。
结构化抽取:browser_extract 做规则化抓取(CSS/属性,不含模型),支持翻页与导出:
browser_extract {
fields: [
{ name: "title", selector: "h1" },
{ name: "rows", selector: "table tbody tr", multiple: true,
fields: [{ name: "name", selector: "td:nth-of-type(1)" },
{ name: "link", selector: "a", attr: "href" }] },
],
next: ".pagination .next", maxPages: 5,
format: "csv", file: "output/rows.csv",
}
attr 缺省取可见文本,可指定 href / src 等属性;next 翻页直到消失/禁用或达 maxPages;路径限工作区内。语义化抽取(「总结要点」「按 schema 出 JSON」)不在此工具范围——用 browser_snapshot 读文本后交给 jev_extract 等模型侧工具,插件负责拿到干净的候选文本。
人工登录(验证码 / 扫码 / 双因素)
很多网站需要登录。插件支持"agent 打开登录页 → 人工在浏览器窗口完成登录 → agent 继续"的协作流程:
config:
userDataDir: ~/.dsh-browser/profile-work # 登录态持久化,重启/切回无头后仍有效
headless默认已是false(有头窗口);服务器等无 GUI 场景请显式覆盖为true。
- agent 用
browser_open打开登录页(此时弹出真实浏览器窗口); - agent 告知用户完成登录,并调用
browser_wait_for_login(可选successSelector/successUrl指定完成条件); - 用户在窗口中输入账号 / 扫码 / 完成双因素;
browser_wait_for_login检测到完成条件(默认 URL 跳转)后返回,agent 继续后续操作。
配置 userDataDir 后,登录态(Cookie / localStorage)会保存到该目录,后续即使切回 headless: true 或重启 DSH,已登录的网站仍保持登录态。
人工接管:验证码 / 二次确认 / 人工复核
browser_wait_for_login 的通用版:browser_pause_for_human 适用于任何需要人补一步的场景。
browser_pause_for_human({
instruction: "请输入短信验证码并提交",
successSelector: ".dashboard", // 或 successUrl: "dashboard",都不给则页面变化即完成
timeoutMs: 300000,
})
// → { completed, status: "completed" | "timedOut", instruction, detail, waitedMs, url, title }
- 调用后提示语会显示在界面右下角实时画面面板(琥珀色横幅),用户去浏览器窗口完成操作;
- 完成条件默认为 URL 或页面内容发生变化(比登录场景的「URL 跳转」更宽,适合弹层/验证码);
- 超时不抛错,返回
completed: false,agent 可再次调用或改走其他路径; - 也可用于录制中的人机混合回放:回放到该步即暂停等人。
敏感操作审批(browser_confirm)
browser_confirm({
reason: "提交白名单表单,会产生线上数据变更",
tool: "browser_click", // 可选:即将执行的工具
args: { selector: "#submit" }, // 可选:面板展示用
timeoutMs: 60000,
})
// 用户允许 → { decision: "allowed", id, reason, waitedMs, detail }
// 用户拒绝 / 超时 → 抛错「敏感操作被拒绝: …」,replay/batch 该步记为失败
- 审批卡片(红色横幅 + 允许/拒绝按钮)显示在界面右下角实时画面面板;
- fail-closed:等待超时按拒绝处理,绝不默认放行;
- 配置
confirmMode: manual后,systemPrompt 会要求 agent 在提交/删除/支付类动作前必须先调用本工具(默认off,不改变既有行为,工具仍可随时手动调用); - 回放含 browser_confirm 步骤时同样弹卡等人,人机混合回归的安全闸。
失败自动重跑 + 面板一键重跑
browser_replay { retryFailed: N }:整轮回放中失败(自愈链耗尽)的步骤自动重试 N 次(0-10,步骤间 500ms×n 线性退避);failFast 语义保持——重试耗尽才停;偶发超时/网络抖动导致的失败在重试中挽回时,结果行标recovered: true,返回值与运行历史(reports/runs.jsonl)记retries: { attempted, recovered }。- 面板一键重跑:实时画面面板「最近回归」行与内嵌报告模态均有「↻ 重跑」按钮,POST
/browser/runs/rerun { source, retryOf }走与browser_replay完全相同的路径(stepImpls+ auto 审批闸);agent 忙碌(有工具调用或回放在途)时端点回 409,按钮置灰;重跑产生的运行在历史中标retryOf: <原 runId>,报告可见重试挽回次数。纯 web 进程(无 tools 服务)回 503。
自动拦截(confirmMode: auto,硬约束)
manual 依赖 agent 自觉,auto 把信任边界收回到宿主层:配置后,sensitiveTools(默认只拦 browser_click)执行前,宿主层自动解析目标 selector/ref → 页内取元素统一描述(role/name/text/id/testid/tag)→ 与 sensitivePatterns(默认 提交/删除/支付)子串匹配(大小写不敏感);命中即复用上面的审批管线弹卡等人,拒绝/超时该步直接失败,agent 无法绕过;未命中(翻页、展开下拉等)直接放行,每次判定只多一次页内 evaluate,无感知延迟。live 调用与 replay/batch 默认同样拦截;定时/数据驱动回归可设 confirmInReplay: false 关掉回放侧审批——⚠️ 这意味着无人值守的回放可以不经审批执行提交/删除/支付类动作,仅在受控环境使用,风险自担。
实时画面面板
安装后 DSH 界面右下角出现 🌐 悬浮按钮(跟随 DSH 亮/暗主题):
- 状态行:浏览器开关、标签数、当前 URL;
- 实时缩略图:浏览器打开时显示,点击弹出大屏模态框——2 秒轮询实时画面,下方列出访问历史(最近 50 条,点击可在新标签打开);
- 最近回归:面板底部一行显示最近一次
browser_replay/browser_batch的结果(通过数 / 自愈数 / 时间)。
开发
pnpm install
pnpm verify # typecheck + test + build
License
MIT