mengyundawang123/dsh-quoted ↗★ 0

dsh-quoted

将选中的对话文本转化为临时注释引用文件供模型读取 适合需要在提问时快速引用历史对话片段作为临时参考背景的用户。

包名
dsh-quoted
兼容性
待验证
版本
0.1.0
许可证
MIT
最近更新
2026年10月18日

安装

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:mengyundawang123/dsh-quoted

注释引用(Annotation Capture)

在对话里选中一段文字,把它变成一个临时的注释文件,并以独立的引用块(chip)附到输入框。模型读完本轮内容后,文件自动删除。

Quote a passage in a DSH conversation: it becomes a temporary annotation file attached to the composer as a reference chip, and is deleted once the turn reads it.

安装

# npm(推荐:预构建,装完即用,不需要构建授权)
dsh plugin --profile web add dsh-quoted

# 或直接从 GitHub 源码安装(本插件没有构建步骤,不需要 allowBuilds)
dsh plugin --profile web add github:mengyundawang123/dsh-quoted#v0.1.0

装完重启 dsh web,在对话里选中一段文字试一下。

兼容与权限

项说明
已验证版本dsh 0.2.1-rc.2(Windows + Web UI)
网络无外部请求、无遥测
磁盘在当前工作区写 .dsh-annotations/*.md,目录内自带 .gitignore,不会污染仓库
进程Host 侧注册同源路由 POST /api/dsh-quoted,只接受带 x-dsh-quoted: 1 的请求
依赖无运行时依赖

用法

  1. 在对话区选中一段文字(只认 [data-chat-flow] 之内、且不在输入框里的选区);
  2. 右键 →「引用」,或点输入框工具行左侧的「引用」按钮;
  3. 输入框里出现 chip:📄 注释 17:51,原文会被淡蓝高亮并在末尾标上序号;
  4. 接着写你的问题,发送。

规则:同一段文字 3 秒内重复触发只生成一个文件;输入法组词期间会延后写入,避免吃掉正在输入的字。

文件生命周期

选中 → 写 /.dsh-annotations/-.md
     → 发送(消息里是 @.dsh-annotations/xxx.md)
     → 模型 read 该文件
     → 本轮正常结束 → 删除
情况行为
本轮读过、且属于本轮回合结束即删
本轮没读过保留,交给 1 小时后清扫(宁可留着,也不静默丢内容)
回合被中断不删(宿主不会触发 turn-stopping),留给你重发
我干活时你又标注了下一条不删:它属于下一条消息,不在本轮的归属快照里
进程重启丢了登记启动 5 秒后扫已注册工作区,删 1 小时前的孤儿

判定「属于本轮」用的是回合开始时的文件集合快照,不是时间戳 —— 时间戳在同一毫秒内无法区分先后。

失败码

按钮失败时悬停可看到原因:

码含义
no-workspace无法确定写入目录
no-draft读不到输入框草稿,因此不写文件(避免产生没有分隔符的坏引用)
forbidden请求头缺失
write-failed落盘失败
network / http-error请求失败 / 服务返回异常

安全边界

  • 路由只接受带 x-dsh-quoted: 1 的 POST,跨站表单打不进来;
  • 写入目录由 Host 决定:会话目录优先,客户端传来的 cwd 只有落在已注册工作区之内才被采纳;
  • 单次请求体上限 256 KiB。

测试

node tests/host.test.mjs     # 16 项:不变量 + 300 步模型随机游走 + 清扫/重启/HTTP 面
node tests/client.test.mjs   # 28 项:选区范围、去重、输入法、chip 载荷、角标、失败码
npm test                     # 串跑

Host 套件用假 Cordis 上下文驱动真实模块:只有 inject 声明的服务是上下文属性,其余必须走 ctx.get —— 与运行时语义一致,所以「漏声明依赖」这类问题会被测出来。

Client 套件把真实 client.js 装进 vm,配一个带 hook 运行时和卸载清理的 React 仿真、假 DOM、假 fetch,直接调用它注册的组件与事件处理器。

覆盖不到的部分

  • 没有真浏览器:CSS Custom Highlight 与角标定位在仿真中被跳过/打桩;
  • 仿真的 React 不比较依赖,闭包过期类问题测不出;
  • HTTP 用例串行,没有真并发;
  • 「重启扫描」用重新 import 模块实例模拟,不是真的重启进程。

分隔符

宿主解析 @引用 需要前导空白:

@ 前面结果
消息开头解析成文件引用(蓝色)
空格 / 换行解析成文件引用(蓝色)
紧贴文字(1111@path)不解析,整段按纯文本显示

两个位置各自处理:

  • 前导(你的文字 → chip):由 SEPARATOR 决定,默认 ' '。宿主会丢掉 chip 前紧贴的空格,所以文字直接贴着 chip 打字时,引用会退化为纯文本 —— 这是宿主行为,插件改不动。改成 '\n' 可以让 chip 单独起一行、恒为蓝色,代价是拆行。
  • 尾随(chip → 你的后续文字):必须是独立的空格文本节点。已验证 clipboardText 里的空格不会进入存储的消息(宿主用编辑器文本序列化,不读该字段),把它挪进 chip 会导致后续文字并进引用、整段变蓝。
const SEPARATOR = ' '   // 同一行(当前);改成 '\n' 即拆行模式
const text = `${prefix} `   // chip 之后必须有这个空格节点,不能省

改完刷新页面即可生效,不需要重启 DSH。

已知限制

  • 用户消息气泡是纯文本渲染,宿主没有「引用块」节点类型,所以 chip 只是一种文件引用,不是原生引用卡片;
  • 输入框里如果有 /命令 chip,重建草稿时会退化成纯文本(宿主的 Enter 仍按命令判定);
  • Host 半改动需要重启 DSH 才装载,客户端半刷新页面即可。