dsh-page-annotate
Manifest validDSH page annotate 网页标注插件,用于页面批注、元素标记
dsh-page-annotate
在 DSH 右侧边栏的 HTML 预览里直接圈选元素、写批注,然后把整批批注作为一条消息发进当前会话,让模型按批注改页面。
这就是 Codex 那种「预览里标注 → 回到会话修改」的体验,只是做成了 DSH 的插件。
它解决什么
DSH 自带的文档预览是只读的:没有元素选择器、没有批注模型,iframe 是 sandbox="allow-scripts" 的跨源沙箱,父页面也无法注入脚本进去。所以想「在预览里标注」,只有一条路——由插件自己渲染预览。
这个插件就是这么做的:它注册自己的边栏标签类型,自己建 iframe、自己注入 overlay,因此 postMessage 通道是可控的同源通道,不依赖任何宿主路由,也不依赖「开发者工具」开关。
用法
- 在会话里打开一个 HTML 文件的预览(工作区文件树里点它)。
- 默认选择「HTML · 页面批注」预览实现,点击预览头部的 「批注」,在同一个 iframe 上开启选择,不新增标签、不重读文件、不关闭已经打开的弹窗,输入与脚本状态保留。 更新前的内置预览或手动选择的其他渲染器无法原地注入;升级后请重新打开页面,并确认使用「HTML · 页面批注」。已有旧批注标签仍兼容旧的读取路径。
- 直接在页面上选择元素,无需再点击「选择元素」:
- 移动鼠标高亮元素,点击它弹出批注框;
- 默认只显示编号、配置按钮、评论输入框和 ✓,自动聚焦输入;
- 点配置按钮才展开样式参数(文字颜色、背景颜色、字号、字重、不透明度);元素路径和分类按钮不再显示,但后台定位证据照常发送。颜色支持点击色块打开可视取色面板,调整明暗/饱和度、色相、透明度或输入十六进制值;这些参数读取元素当前值,修改后记录为批注目标,不直接修改页面;
- Enter 或 ✓ 保存,Shift+Enter 换行,输入法确认不会误保存;取色面板打开时 Esc 先关闭取色器,再按 Esc 才取消未保存编辑并退出选择;已保存批注保留。
- 继续标注下一个——保存后不会退出选择模式,所以可以连着点若干个元素、逐个写批注,不必每次重新点「选择元素」。 每个元素上会出现编号角标,点角标可以重新编辑,「删除」可以移除。
- 全部标完后二选一:
- 发送到会话:把所有批注编译成一条消息,直接进会话队列;成功后原地退出批注,保留当前弹窗与输入,失败则保留批注以便重试;
- 填入输入框:只写进输入框,你可以补充说明再自己发。
多条批注是一次发送、一条消息,按编号成组,不是一条一条发——这样会话侧能一次看到全部修改点,也不会触发多次生成。
页面本身不会被改动——overlay 只在内存里注入,原文件保持可 diff。
防止修改到错误位置
每条批注附带当前 DOM 的精确 CSS 选择器、匹配数量、所属区域/弹窗唯一 ID 与标题、经过限长和清理的目标 HTML 片段。面包屑保留更深祖先,避免多弹窗相似 class 导致混淆。这些是运行时定位证据,不是源文件行号。
消息要求模型先核对源码位置,禁止只按相同文案/通用 class 全局替换;不能唯一确定时先询问,改后检查同名非目标区域不变。此举降低误改风险,但不保证模型完全不会犯错。
蓝色序号、选择框、批注栏均为临时工具标记,消息明确禁止将其写入最终页面;页面原有的业务序号列不受此约束影响。
截图随批注发送
底部默认勾选「附带截图」。保存每条批注时留存当前视口 PNG,编辑该条批注后更新它的截图;发送时同批附带多张真正的 image 附件。不同弹窗/滚动位置可以保留各自画面,不再只截发送时的最后一个视口。
-
按最终批注顺序排列图片,提示词逐张列出「附图1(S1)对应批注1」,文件名也标注对应批注;完全相同PNG可去重共用一张,映射仍保留。
-
删除其他批注可能改变最终编号,因此对应表额外保留捕获任务创建时编号;以对应表和元素定位为准,不把历史图里的旧编号当作当前顺序。
-
排队后的捕获、旧会话恢复/失败后发送时补拍会明确注明不是保存瞬间,绝不声称恢复了历史画面。截图仅内存保留,关闭标签或重启不持久化。
-
每批最多保留12条批注截图,base64总量最多20MiB;超额会阻止带图发送,须减少批注或取消附图,不能静默丢图。
-
截图保留批注编号,并为各已保存批注对应的目标绘制蓝色边框与淡蓝底,编号与位置可以直观对应;不包含评论输入浮层或无关的鼠标悬停高亮。边框只在截图克隆中绘制,不改原页面;屏幕外元素以文字定位为准。
-
可取消勾选,只发送文字;「填入输入框」目前只填文字,不插入图片。
-
截图失败会明确提示并保留批注,不会自动退回只发文字。模型不支持图片时可取消勾选再重试。
-
截图库离线随包附带,不访问 CDN 或第三方截图服务;会读取并可能重新请求页面自身的资源。
-
技术上是 html2canvas DOM 重绘,不是原生屏幕像素截图。部分 CSS、无 CORS 授权的跨域图片、跨域 iframe、视频/WebGL 可能无法准确还原。发送前请确认页面可视内容适合分享给会话模型。
-
为控制体积,截图最长边不超过 1600px,不按 Retina 倍率放大。
送到会话的消息长什么样
插件启用时,新的批注消息默认折叠显示「2条批注 · 2张截图」,点击即可展开原样完整提示词,再点击收起。缩略图仍使用DSH原生图片附件展示。完整文本与图片照常进入模型上下文,并非删掉定位信息;刷新会话后仍可从稳定标记识别。关闭插件会回退显示完整普通消息,旧版已发送的无标记消息不会自动折叠。「填入输入框」仍是纯文字,不插入图片、不封装为折叠消息。
展开内容示意(实际含定位证据与逐图映射):
请按下面的批注调整「提交工单AI预处理改造设计」。
文件:`业务需求/20260923-提交工单AI预处理改造设计.html`
1. [调整] `table#orders > th.cell`
> 是否二级订单
这里调整成加粗字体
2. [删除] `td.cell`
这一列不需要
批注里没有提到的部分保持原样,只改这里列出的内容。
安装
包声明了 dsh.bundle.patch,所以插件管理器会自己完成三件事:装依赖、把这个包加进 profile 的组合层、插入 Loader 行。不需要手改任何 YAML。
给别人装(推荐:图形界面)
- 插件页 →「安装插件」
- 粘贴 tgz 的绝对路径(
~不行),或选「本地目录」 - 装完重启一次 DSH
命令行等价写法
# 注意 flags 紧跟在 profile 名后面,否则会被当成 app 参数
dsh plugin --profile <profile> add /绝对路径/dsh-page-annotate-0.1.0.tgz
开发时(软链到自己改的目录)
ln -sfn /Users/baigo/Documents/workspace/projects/dsh-page-annotate \
~/.dsh/profiles/desktop/node_modules/dsh-page-annotate
# 并在 profile 的 package.json 里写:
# "dsh-page-annotate": "link:/Users/baigo/Documents/workspace/projects/dsh-page-annotate"
软链的好处是改完源码立刻生效;代价是目录一移动插件就失效(link: 不是副本)。给别人用请用 tgz,那是 file: 副本,删掉 tgz 也不影响运行。
重启只在首次安装时需要。 profile 对插件包的解析在启动时缓存(profile resolution 不允许热替换同名包),所以第一次把包挂进去必须重启一次。
更新预编译客户端产物后,建议刷新 DSH 页面并重新打开 HTML 预览。宿主包含 HMR 接收机制,但不保证当前安装环境正在构建或推送更新;若仍是旧版本,再重启 DSH。
判断依据:bundle 以 ?rev=<12位hash> 下发且带 cache-control: immutable,rev 不变浏览器就不会重新请求——所以"页面没变"通常意味着 rev 没变(HMR 没看到文件变化),而不是需要重启。
怎么确认自己看到的是哪一次构建:把鼠标停在批注面板左上角的文件名上,tooltip 末尾有 build 2026-10-22 16:34 这样的本地时间戳(构建时写入)。没看到时间戳或时间偏旧,就是旧 bundle 还在跑。
卸载
rm ~/.dsh/profiles/desktop/node_modules/dsh-page-annotate
# 然后从 cordis.patch.yml 删掉那个 insert 条目、从 package.json 删掉依赖
开发
npm run build # 把 src/ 组装成 lib/client.js
npm test # 运行全部回归测试
npm run check # build + 语法检查 + 全部测试
源码结构
| 文件 | 作用 |
|---|---|
src/core.mjs | 纯逻辑:元素定位串、批注规范化、消息编译。无 DOM、无 React,浏览器和 node --test 共用同一份。 |
src/overlay.js | 注入到被标注页面里的脚本:选择、高亮、批注框、角标、postMessage 协议。 |
src/client.factory.js | 客户端 React 半部分:标签类型注册、边栏 tab body、文档操作按钮、iframe 与协议桥接。 |
tools/build.mjs | 组装 lib/client.js。没有打包器、没有 TypeScript——client.js 的格式就是 DSH 的 loader 信封,源码即产物形状,构建只是拼接。 |
构建做三件事:
- 把
src/core.mjs的export去掉后拼进 factory(这样它的 helper 在客户端作用域里可见); - 把
core.mjs + overlay.js作为字符串嵌进去——overlay 要在被标注页面里跑,那里没法require; - 套上
window.__ModuleLoader__.load({ id, factory })外壳。
客户端 bundle 契约
lib/client.js 不是模块,是 loader 注册脚本:
window.__ModuleLoader__.load({
id: "dsh-page-annotate",
factory: (require) => {
var module = { exports: {} };
var exports = module.exports;
let react = require("react"); // 共享模块表,缺什么 require 什么
/* ... concatenated core + client body ... */
exports.apply = apply; // 客户端插件入口
exports.inject = inject; // 需要的 service 名数组
return module.exports;
}
});
package.json 里 dsh.client 的 inject 是包名依赖(决定 bundle 加载顺序),exports.inject 是服务名依赖。两者不同,都要维护。
测试覆盖
tests/core.test.mjs— 定位串、批注规范化、消息编译等纯逻辑测试。tests/overlay.browser.test.mjs— 真实 Chromium 测试:元素选择、多条批注、Esc 取消与已保存内容保留,并读取真实设计稿验证。tests/client.wiring.test.mjs— 装配与生命周期测试:同位置替换标签、自动选择、加载握手不覆盖 Esc、读取 Remote 信封。tests/packaging.test.mjs— 组合包声明、补丁与中文元数据发布契约。
浏览器测试在缺 Playwright 时自动跳过。
设计取舍
为什么自定义地址。 批注标签的地址是 dsh-resource://page-annotate/session/<sessionId>/<path>,而不是复用 dsh-resource://file/...。因为边栏布局持久化的是 contentId(地址)本身,把 Session 和路径编进地址,刷新后标签页仍然知道自己在显示哪个文件,不需要额外的桥接表。canOpen 会重新解析地址,所以文档预览的地址不会被抢走。
为什么 overlay 不写进文件。 设计稿要保持可 diff、可交付;overlay 是运行期注入的,文件一个字节都不动。
为什么要重新校验。 批注来自一个沙箱 iframe,属于不可信输入。normalizeAnnotations 会在进入 prompt 之前重新检查每个字段(长度上限、类型、kind 白名单)。
发送路径的取舍。 优先「填入输入框」——文本留在编辑器里可见可改。直接发送走 sessions.binding(id).session.prompt([{type:"text",text}], "queue");不用 conversation.send(),因为那个要求调用方处在会话作用域内,而从标签页的 inject 里拿不到。
已知边界
- 只处理 HTML;Markdown/Excel/图片的预览不显示「批注」按钮。
- overlay 需要 iframe 允许脚本,因此用
sandbox="allow-scripts allow-same-origin"。被标注的页面里的脚本会照常运行——和自带的交互式预览一致。 - 页面重挂载时批注会保留(按地址存放在内存 Map 里),但不跨应用重启持久化。
- 元素在重挂载后按 CSS 选择器重新绑定;页面结构变化后再次标注即可。
Comments
Loading…
Similar plugins
by DDDFXYqiming
DSH Web annotation/quote plugin (fork enhanced)
★ 2
MIT
JavaScript
Oct 15, 2026
dsh plugin --profile web add @dsh-external/dsh-annotation-patchedAdds text selection annotation tools and annotation chips to the dsh web composer.
★ 0
dsh plugin --profile web add dsh-annotationby xujian519
对DSH的交付物进行标注的插件,人工标注后,DSH会根据标注执行
★ 0
NOASSERTION
TypeScript
Sep 28, 2026
dsh plugin --profile web add dsh-annotatorby zhxnix
Codex-style DSH right-sidebar browser preview, element annotations, context notes, and debugging tools.
★ 0
MIT
JavaScript
Sep 22, 2026
dsh plugin --profile web add dsh-sidebar-annotationsby cslkkl
Annotate pages and ask questions inside the existing DeepSeek Harness Browser.
★ 0
MIT
TypeScript
Oct 3, 2026
dsh plugin --profile web add dsh-web-annotatorby AnLifeX
dsh 提醒插件:别错过需要你的时刻
★ 3
↓ 60/wk
MIT
JavaScript
Sep 10, 2026
dsh plugin --profile web add dsh-attention