dongasai/dsh_debug_web

dsh_debug_web

让 DSH 的 agent 在页面里执行 JS、读控制台 —— 一个模型工具 dsh_debug_web,走既有 Cordis Host→Client Inspect 通道 | Let the agent run JS inside the live DSH web page and read its console, over the existing inspect channel

待分类browser-debuggingdeepseek-harnessdsh

dsh-debug-web — 让 agent 在页面里执行 JS、读控制台

DSH 官方给模型的客户端感知只有只读 Inspect:能读槽位树、主题令牌、Service/Event 契约,读不到 DOM、读不到控制台、不能执行代码。本插件补的就是这一半:一个模型工具 dsh_debug_web,请求浏览器页面执行 JavaScript 并取回结果,同时把页面自己捕获的 console/异常缓冲交给模型。

它不新造协议:请求走的是 DSH 已有的 Cordis Host→Client Inspect 通道(cordis/inspect-query),本包只在两端各挂一层——宿主侧一个工具,页面侧一个 Inspect Provider。

文档 · 只写 · 不写 README(本文) · 怎么装、怎么用、参数口径、排错、验证、边界 · 设计取舍、给 agent 的约束 AGENTS.md · 给 agent 的硬规则与改动连带项 · 用户用法

功能

模型能力(一个工具,四个动作)

action · 作用 · 必填 pages · 列出响应页面:pageId、URL、标题、视口、可见性、已捕获条数 · — eval · 在页面里执行表达式或语句体,支持 await,返回 JSON 值 · code logs · 读页面捕获的 console/异常缓冲,可按 since / level / limit 切片 · — clear · 清空缓冲并返回清掉多少条 · —

页面能力(客户端半边自动做,不需要用户操作)

  • 包一层 console.log/info/warn/error/debug,保留原输出。
  • 挂 window.onerror(捕获阶段,含 `/ 资源加载失败)与 unhandledrejection`。
  • 300 条环形缓冲,单条正文截到 2000 字符,序号单调递增,不落盘、不发送。

不提供:截图、网络瀑布、DOM 快照接口、宿主文件访问。这些不在本插件的通道里(见已知边界)。

快速开始

1. 装插件

方式一:本地目录(开发时用这个)

dsh plugin --profile web add link:/data/ai/dsh/dsh_debug_web

装成 link: 依赖,改代码立刻是「已装的那份」。

方式二:命令行 · git 源(分发)

dsh plugin --profile web add github:dongasai/dsh_debug_web
dsh plugin --profile web add github:dongasai/dsh_debug_web#0.1

仓库地址 ,#0.1 钉在已推送的 tag 上;tag 被改动或删除后这条会装失败。

方式三:Web 界面

DSH Web → 左侧栏插件 → 添加插件 → 填本仓库绝对路径 → 安装 → 点立即启用。

四条通用坑:

  1. --profile 必填,不写直接报 required option '--profile not specified'。
  2. 只加依赖不加 dsh.profile.bundles = 装了不挂载(本包带 dsh.bundle,装完会自动进 bundles)。
  3. git 规格必须 github: / git+,git@… 会被 pnpm 当本地路径,装出死链。
  4. 钉版本的 tag 必须真实存在。

2. 让两半各就各位

改了哪半 · 怎么生效 client.js(页面侧 Provider) · 刷新浏览器页面即可,不需要重启 Harness index.js / cordis.patch.yml / package.json 的 dsh.* · 重启 `dsh web`

装完第一次必须重启一次:工具是在宿主启动合成插件行时注册的。

3. 确认它在工作

dsh --profile web --dump-config | grep -A1 dsh-debug-web

期望:

- id: dsh-debug-web
  name: '@dongasai/dsh-debug-web'

重启后让模型调一次 dsh_debug_web,action=pages。成功的样子:

响应页面 1 个(查询广播到所有已连接页面,宿主只采纳第一个有效结果):
- pageId=page-xxxxxxxx visible 1440x900 Harness <http://127.0.0.1:3080/...>;已捕获 0 条,缓冲区 0 条

看不到工具 → 宿主半边没挂上(重启);工具报 provider-missing → 页面还是旧的客户端半边(刷新)。

结构

文件 · 作用 index.js · 宿主半边:注册 dsh_debug_web,把 action 转成 Inspect 查询并渲染结果 client.js · 页面半边:捕获 console/异常,注册 DebugWeb provider 执行 eval cordis.patch.yml · 宿主层装配行(- id: dsh-debug-web) package.json · dsh.bundle + dsh.client(platform: web、immediately: true)

Host inject:tools、cordisInspect。后者由 @deepseek-ai/dsh-cordis-host-runner 提供,缺失时本插件不会激活(没有别的通道可用)。

占用的扩展点:

扩展点 · 注册物 宿主工具 · dsh_debug_web(全局层,本 profile 每个 agent 都可见) 客户端 Inspect Provider · id DebugWeb,方法 pages / logs / eval / clear

槽位、页签、路由都不占——本插件没有界面。

通道契约

一次调用的完整路径:

模型 → dsh_debug_web(index.js)
     → ctx.cordisInspect.query('client', 'DebugWeb', <method>, <input>, agent, signal)
     → 宿主广播 cordis/inspect-query 给所有已连接页面
     → 每个页面的 DebugWeb provider 执行,第一个有效结果被采纳
     → 结果校验(无损 JSON + outputSchema)后原路返回

action → method 一一对应。input 只在下面这些字段里取值,多传未声明字段会被宿主 validateInput 拒绝(additionalProperties: false):

method · input · 说明 pages · 无 · 空对象即全部省略 logs · since? level? limit? · since 是 seq;limit 默认 100、上限 300 eval · code(必填) pageId? · pageId 不匹配的页面直接拒绝本次查询 clear · pageId? · 返回 cleared 条数

共通口径:

  • 超时:宿主默认等 10000ms(cordis-host-runner 的 clientInspectTimeoutMs),页面侧 eval 自己 3000ms 先超时,所以模型拿到的通常是可读的错误而不是"通道超时"。
  • 首答优先:查询是广播,所有已连接的 Harness 页面都会执行,只有第一个有效结果被采纳,其余被取消(cancelled)。
  • 错误口径:页面 provider 抛错 → provider-error: ;方法不存在 → method-missing;页面没连 → has no connected Harness page。

安全模型

  1. `eval` 等于页面同权:它在用户的浏览器标签页里以该页面的权限执行,能读写 localStorage、发同源请求、改 DOM。想安全就只用只读表达式。
  2. 通道里没有审批闸门:cordis_inspect_query 与 Inspect 通道本身不做二次确认;本插件也没加。要不要给 eval 加审批是使用者的选择,不是内建保证。
  3. 信任围栏只有"本机 + 已连接页面":谁能操作这个 Harness 页面,谁就能让模型在页面里执行代码。它不是沙箱,也不隔离同源资源。
  4. 缓冲不离开页面:捕获的日志只存在页面内存里,由宿主按需拉取,不写磁盘、不发第三方。

这不是什么:不是权限隔离,不是审计日志,不是远端浏览器控制(它只作用于已经打开这个 URL 的那个标签页)。

与 Agent 的关系

  • 工具只有一个:dsh_debug_web。参数里没有"宿主路径""shell""目标机器"——它只能作用于当前连接的页面。
  • 多标签页有歧义:先 action=pages 拿 pageId,再把它传给 eval/logs,否则可能打到后台标签页。
  • 页面侧读的是插件加载之后的日志;插件装好前的历史输出拿不到。
  • 不给模型截图与网络请求的能力:那需要 CDP 层,不在本通道里。

排错

症状 · 原因 · 处置 工具列表里没有 dsh_debug_web · 宿主半边没生效 · 重启 dsh web;确认 --dump-config 里有 dsh-debug-web 行 provider-missing: Client inspect provider "DebugWeb" is unavailable · 页面还是旧 bundle · 刷新浏览器页面 has no connected Harness page · 没有页面连着(全关或断线) · 打开/刷新 Harness 页面 报超时 after 10000ms · 页面在执行长任务、或标签页被节流 · 把慢活拆小;切到该标签页再试 rejected input: ... additionalProperties · 传了方法未声明的字段 · 只传表里那几列 returned non-JSON value · provider 返回了函数/循环引用 · 用能 JSON 化的表达式(DOM 节点会自动转 outerHTML 前缀) eval 失败:... 超时:超过 3000ms · 页面侧 Promise 没在 3s 内完成 · 缩短等待,或改用 logs 看异步结果 页面 page-xxx 跳过 · pageId 指到了另一个标签页 · 用 action=pages 的当前 pageId 日志条数比自己看到的多 · 别的页面也在回 · 只有一个响应是正常的,缓冲各自独立 eval 里读不到别人控制的变量 · 页面是打包产物,模块不挂 window · 用 DOM/fetch/localStorage 侧证据,别指望内部符号 刷新后日志全没了 · 缓冲在内存里,随页面重载清空 · 重要的先 logs 读完再刷新 装了但界面没有任何变化 · 本插件没有界面 · 它只加工具,去工具列表/模型侧看

怎么验证

命令行

node --check index.js && node --check client.js   # 两半语法
node probe-debug-web.mjs                          # 31 例探针,见下表(探针不进仓库)

覆盖面 · 例数 · 覆盖点 客户端 manifest · 2 · id、方法清单、描述与 schema 齐全 eval · 6 · 表达式 / await / 语句体 / DOM 兜底 / 语法错 / 执行期 console 捕获与缓冲 · 5 · console 三级别、error 事件、unhandledrejection、环形上限 300、seq 不回退 logs · 2 · since 增量、level 过滤、limit clamp 定向与清理 · 3 · pageId 不匹配拒绝 / 匹配执行、clear 保留 seq HMR · 1 · 重载后钩子不重复安装(一次 console.log 只记 1 条) 宿主工具 · 12 · 注册形态、四个 action 透传、缺参拒绝、无 agent 兜底、通道失败文案

浏览器清单

  • [ ] 重启后工具列表出现 dsh_debug_web。
  • [ ] action=pages 返回当前 pageId 与真实视口。
  • [ ] eval 读 document.title 与页面标签一致。
  • [ ] eval 计算样式值(如 getComputedStyle(document.body).backgroundColor)与 F12 一致。
  • [ ] eval 里 console.warn('x') 后,action=logs level=warn 能查到,且 F12 里也有这条。
  • [ ] 页面上故意抛一个未捕获异常,action=logs level=error 能看到消息与来源行。
  • [ ] clear 之后 pages 的 buffered 归零、captured 不回退。
  • [ ] 多标签页时传错 pageId 得到"跳过"报错,传对能执行。
  • [ ] 刷新页面后缓冲清空、pageId 变化。

已知边界

边界 · 原因 · 代价 查询广播到所有已连接页面 · 通道没有"定向某个页面"的字段 · 不传 pageId 时,eval 的副作用可能在每个标签页各跑一次 10 秒通道上限 · clientInspectTimeoutMs 默认 10000 · 长轮询、watch 型需求做不了;页面侧 3s 先失败 只有第一个结果被采纳 · 首答优先 · 多页面时无法比较各页结果 无 push · 通道是请求/响应 · 日志只能模型主动拉,不能"出错即通知" 装好之前的日志拿不到 · 钩子在插件加载时安装 · 排查早期启动错误得先刷新再复现 缓冲区在内存里 · 不落盘 · 页面重载即丢;单页上限 300 条 只覆盖 console 五级与两类未捕获异常 · 没包 console.trace/assert、没接 fetch 失败 · 网络错误要从 error 事件或自己的 try/catch 里看 返回值必须是无损 JSON · Host 侧 validateOutput 硬校验 · 返回函数/循环引用会整条查询失败 eval 不支持顶层 await import() 的模块图操作以外的注入 · 只有 AsyncFunction 上下文 · 拿不到打包器的模块表,只能用页面现有全局 不能截图、不能读网络瀑布 · 那需要 CDP,本通道没有 · 视觉回归、性能分析要另找工具

相关文件

文件 · 关系 index.js · 宿主半边;改工具参数、渲染、错误文案看这里 client.js · 页面半边;改捕获范围、缓冲口径、eval 语义看这里 cordis.patch.yml · 装配行;改插件 id 要连 package.json 与 notes 一起改 AGENTS.md · 给 agent 的硬规则:两半生效、provider id、schema 一致性 LICENSE · MIT @deepseek-ai/dsh-cordis-host-runner/lib/index.js · 通道宿主侧:queryClient、超时、输出校验 @deepseek-ai/dsh-cordis-client-runner/lib/client.js · 通道页面侧:ClientCordisInspectRegistry.register/query

许可证

MIT © 2026 dongasai