# dsh-reply-forge v3 使用说明 本文面向使用者,讲清「界面上每个东西是什么、点了会发生什么、出问题怎么办」。 原理与宿主源码证据见 [PLAN.md](./PLAN.md)。 --- ## 一、快速上手 0. **前提**:已装 DSH 桌面端,且机器上有 **Node.js**(安装脚本靠它改配置; bat 会自动找 PATH / `C:\Program Files\nodejs` / `%LOCALAPPDATA%\Programs\nodejs`。 没装 Node 也能装——bat 会印出完整手动步骤,照做即可); 1. 双击 `安装插件.bat` → **完全退出 DSH** → 重新启动; 2. 随便聊几句,鼠标移到某条 AI 回复上,右上角出现一条操作条; 3. 点「**伪造**」→ 编辑器展开; 4. 改文本框里的内容; 5. 点「**写入伪造**」→ 确认 → 完成。 编辑器顶部会先告诉你这次生效的时机: ``` ⚡ 自动:这个会话在内存里 → 写活会话,下一轮对话立即生效(不用重启)。 💾 自动:这个会话不在内存里 → 落盘写入会话记录文件,该会话下次载入时生效。 ``` 看到 `⚡` 就可以直接继续对话,模型下一轮就读到你改的版本。 > **新会话注意**:刚开的会话里宿主可能还没把这条回复登记进活会话 > (尤其回复还在输出时)。这时编辑器会提示「⏳ 宿主还没把这条回复登记进会话」, > 插件会自动重读,通常一两秒内就好;急的话点一下「重新读取」。 --- ## 二、界面上有什么 ### 操作条(鼠标悬浮在 AI 回复上时出现) | 按钮 | 作用 | |---|---| | **伪造** | 打开编辑器。按钮左侧的小绿点表示「这条已经定位到会话记录里了」 | | **还原** | 删除这条的本机渲染覆盖(只影响页面显示) | ### 编辑器 从上到下依次是: 1. **状态行** —— 定位结果 + 生效模式。 - `✓ 已定位到会话记录 seq=42(块 1)` - `⚠ 与记录中的位置是按顺序推断的` —— 页面文本和记录对不上(公式、表格渲染差异等), 位置是按顺序推出来的,写入前请自己确认正文没错。 - `⚠ 未在会话记录中定位到这条回复` —— 写不了,下面「写入伪造」是灰的。 2. **目标下拉框** —— 见下一节。 3. **写入方式下拉框** —— 见第四节。 4. **文本框** —— 要写入的内容。 5. **按钮行**: - `取消` - `重新读取` —— 丢掉缓存,重新从宿主拉一次块清单 - `还原原文` —— 删掉这条的本机渲染覆盖 - `仅本机渲染`(Ctrl+Enter)—— 只改页面,模型看不见。可逆 - `写入伪造` —— 改「模型看到的对话」 --- ## 三、目标下拉框:改哪一条 默认是「**跟随页面上的这条**」,也就是你点开的那条。 下拉框里会列出**这个会话里所有可编辑块**,每条带一个标记: ``` 【正文】 seq=42 块 1 · 这是 AI 原本输出的回复内容… 【思维链】 seq=42 块 0 · 用户想让我改这个函数,先看看它… ``` 为什么需要它:**思维链在界面上是折叠的**(一个可点开的「思考」行), 插件拿不到它的 DOM 节点,所以没法像正文那样在页面上挂按钮。 但会话记录里有它的位置(`seq` + 块序号),所以从下拉框里能直接选中它。 > 选了下拉框里的**别的**消息时,「仅本机渲染」会被禁用 —— > 那条出口只能改本节点在页面上的样子,改不到别的消息。 > 「写入伪造」不受影响。 --- ## 四、写入方式:这次走哪条路 编辑器里的「**写入方式**」下拉框,三选一: | 选项 | 什么时候用 | 效果 | |---|---|---| | **自动(推荐)** | 默认 | 会话在内存里 → 走在线(立即生效);不在 → 走落盘(下次载入生效) | | **仅在线(立即生效)** | 你想确认「这次一定不碰磁盘」 | 只写活会话。会话不在内存里会**直接失败并报错**,不会偷偷去改文件 | | **仅落盘(重载后生效)** | 你想留一份磁盘上的改动 / 想用 `.bak-forge-*` 备份 | 只写会话记录文件。会话在内存里时,要等它被重新载入才对模型生效 | 「自动」在两条路之间选,是因为多数人只关心「改完能不能马上被模型看到」; 但两条路的前提差别很大(动不动磁盘、要不要重启),所以给你一个显式的开关。 ### ⚡ 在线模式 **什么时候**:这个会话正在 DSH 内存里(你正在聊它)。 **做什么**:往活会话对象上追加一条 `reply-forge/patch` 事件, 由插件注册的 message projection 把目标消息改写掉。 **特点**: - 立即生效,下一轮对话模型就看到; - 写的是内存,**不碰磁盘文件**,所以当场没有备份,也**不可逆**; - 但事件本身会被宿主落盘层写进会话文件,所以**重启后伪造仍在**; - 想还原:再改一次,把原文写回去。 ### 💾 落盘模式 **什么时候**:这个会话不在内存里(没打开、或刚启动还没进它)。 **做什么**:改写会话落盘文件(`.jsonl.zstd`),走的是 v2 的老路。 **特点**: - 该会话**下次被载入时**生效; - 写前自动备份到 `<文件>.bak-forge-<时间戳>`,可以手工还原; - 写后自动「自读校验」(事件数、seq 连续、新文本在、旧文本不在), 任一不过**自动从备份还原**并报错。 --- ## 五、常见问题 ### 改了,但模型好像没认 先看编辑器顶部是哪种模式。 - `💾 落盘` 时:需要让这个会话重新载入。最简单是完全退出并重启 DSH。 如果你在同一个会话里继续聊,宿主内存里还是旧内容,这一轮模型读到的会是原文。 - `⚡ 在线` 时:应该立即生效。如果还是不对,检查你是不是改到了别的消息 (看目标下拉框选的是哪条)。 ### 「未在会话记录中定位到这条回复」 三种原因,编辑器里的提示会区分开: | 提示 | 含义 | 怎么办 | |---|---|---| | `正在读取会话记录…` | 还没读完 | 稍等,或点「重新读取」 | | `读取会话记录失败:…` | 路由读不到 | 点「重新读取」重试;还不行就重启 DSH | | `宿主还没把这条回复登记进会话(新会话或还在输出中)` | **在线**空快照:宿主先渲染、后登记 | 插件会自动重读,一两秒就好;急就点「重新读取」 | | `会话记录里没有可定位的助手正文` | **落盘**空清单:这个会话还没落盘过 | 聊一轮再看 | | `未在会话记录中定位到这条回复(记录里有 N 条正文…)` | 页面文本与记录对不上 | 用**目标下拉框**直接选,不依赖 DOM 匹配 | > 最后一种最常见的原因是渲染差异:页面是渲染后的文本,记录里是 markdown 源码 > (`**粗体**` 在页面上是「粗体」)。下拉框走的是记录里的位置,绕开了这个问题。 ### 「内容与界面看到的不一致(界面已过期),已拒绝写入」 编辑器开着的时候,这条消息在别处被改过(或者你从下拉框选了别的消息但没刷新)。 点「重新读取」,再改一次。 这条拒绝是**故意**的:不校验就会把「你以为在改 A」的编辑写到 B 上。 ### 目标被压缩摘要遮蔽了 长会话里宿主会做上下文压缩,被摘要覆盖掉的旧消息模型已经看不见了。 这时写入会被拒(`SHADOWED`),提示会说清楚。改最近的消息就好。 ### 「本会话有 N 条正文完全相同的消息」 宿主不提供稳定的消息 id,本机渲染覆盖是按「正文指纹」分组的, 所以正文完全相同的多条消息**共享**同一条本机覆盖。 「写入伪造」不受影响 —— 它走 `seq + 块索引`,只作用于你选的那一条。 ### 保存完伪造成,下方输入框打不了字 / 没有光标 3.1.0 已修复(保存时先把焦点交还输入框再重写消息块)。 若你用的是更早的版本:点一下工具栏的「+ 添加文件」再关掉, 或点一下输入框任意位置即可恢复 —— 那是宿主工具栏自带的拉焦点行为在治症状, 不是你的操作有问题。升级到 3.1.0 后不再出现。 ### 运行 bat 提示「未找到 node.exe」 四个 bat(安装 / 启用 / 关闭 / 修复会话)都需要 Node.js 来改静态配置, 但**插件本身跑在 DSH 内部,不要求你额外装运行时**——只有跑脚本的这一刻需要。 两个选择: 1. 装一个 Node.js(LTS 即可),或把它加进 PATH,然后重跑 bat; 2. 不装也行:bat 报错时会把完整的手动步骤印在屏幕上(改两处配置 + 建一条 junction),照着做一遍即可,效果与自动安装完全相同。 --- ## 六、安全与回滚 ### 关掉插件 双击 `关闭插件.bat`(从 `bundles` 里摘掉),然后**重启 DSH**。 **注意**:如果某个会话里已经有本插件的伪造事件,插件被禁用且重启之后: **伪造会静默失效、退回原文**,历史对话一字不少——会话本身照常打得开。 前提是这些事件都带了 `ignorable: true` 标记(v3 的两条写路径都会自动补上)。 这一点是**两层结构**共同保证的,不是「碰巧没事」: | 层 | 校验者 | 标记正确时 | 缺标记时 | |---|---|---|---| | 投影层 | `planSurfaceEvent` | 插件缺席 → 事件被静默跳过,伪造退回原文,不报错 | 同左 | | 持久化层 | `validateStoredEvents`(持久化包) | 闸门放行,事件按「不认识的记录」原样保留 | **拒读整条日志,会话打不开** | 宿主只对硬编码表里的类型强制要求投影存在,本插件的 `reply-forge/patch` 不在表里、也不带 `surfaceOp`,所以投影缺席时宿主直接跳过它; 但持久化层有它自己的闸门,这条就是「标记必须齐全」的原因。 **唯一要避免的**:别在 DSH **运行时**热卸载插件。宿主对「用过某投影的会话」 有硬保护,投影被摘掉后再读那个会话会报 `session message projection "reply-forge/patch" was removed`。 用我们的 bat 关闭(静态配置 + 重启)不会走到这条路。 **会话打不开怎么办**(日志里有缺标记的 patch 事件时):先**退出 DSH**, 双击 `修复会话.bat` 看诊断(只读,不动文件);确认是它说的那个问题后, 再跑 `修复会话.bat apply` 补标记。它会先备份、只改有毒行、写完自读复验, 修不好会自动还原,不会把你的会话改坏。 ### 插件加载异常 双击 `关闭插件.bat` → 重启 DSH。脚本会把插件从 `bundles` 摘掉。 配置文件也都有 `.bak-install-*` 备份,可以手工还原。 ### 会话打不开(用 `修复会话.bat` 救) 如果某个会话打开时宿主报「事件类型不认识 / 拒绝解释日志」之类, 多半是日志里有缺 `ignorable` 标记的 patch 事件(早期版本或写入中途损坏)。 1. **先完全退出 DSH**(工具要改的是会话文件,不能和宿主抢); 2. 双击 `修复会话.bat`:**只诊断,不动任何文件**,会列出每个受损会话、 缺标记的行号、以及宿主闸门的预演结果; 3. 确认是它说的问题后,运行 `修复会话.bat apply`(或在 node 里按提示输入 `yes`): 它会先逐字节备份,只改有毒的那些行,写完自己重读复验, 修不好会自动还原,不会把你的会话改坏。 想限制范围就编辑 `修复会话.bat`,或直接用 `node scripts/repair-sessions.mjs --session <会话id> --apply --yes`。 修复备份永不自动删除(与会话文件同目录,`.bak-repair-<时间戳>` 后缀)。 ### 数据在哪 | 东西 | 位置 | |---|---| | 本机渲染覆盖 | 浏览器 localStorage,键 `dsh-reply-forge-v3:<会话id>` | | 偏好设置 | localStorage,键 `dsh-reply-forge-v3:prefs` | | 在线伪造 | 会话日志里的 `reply-forge/patch` 事件 | | 落盘备份 | `<会话文件>.bak-forge-<时间戳>` | | 修复备份 | `<会话文件>.bak-repair-<时间戳>`(`修复会话.bat` 生成,永不自动删除) | 关插件**不会**删这些数据。 --- ## 七、命令行(离线改写) 需要先完全退出 DSH。 ```bash # 列出这个会话里所有可编辑块(含推理块) node scripts/forge-session.mjs --session <会话id> --list --kind both # 先看会改什么(不落盘) node scripts/forge-session.mjs --session <会话id> --seq 42 --block-index 1 \ --kind text --text "改后的正文" --dry-run # 真写 node scripts/forge-session.mjs --session <会话id> --seq 42 --block-index 1 \ --kind text --text "改后的正文" ``` `--kind`:`text`(默认)/ `reasoning` / `both`。 `seq` 与 `block-index` 从 `--list` 的输出里拿。`block-index` 是 `content` 数组下标,**包含工具调用块**,所以不一定是 0/1 连号。 ### 诊断 / 修复受损会话 修复需要先完全退出 DSH(只诊断不要求退出)。不想用 bat 时: ```bash # 只诊断:扫全部会话,列出缺 ignorable 标记的事件(只读,不动文件) node scripts/repair-sessions.mjs # 修复指定会话(扫描后会要求输入 yes 确认) node scripts/repair-sessions.mjs --session <会话id> --apply ``` `--apply` 必须配 `--session ` 或 `--all`(不猜修哪些);DSH 在运行时会拒绝 (确需强行修复可 `--force`,后果自负)。每个文件先备份,写完自读复验, 修不好自动还原。 --- ## 八、已知限制 - **思维链没有页面按钮**。它渲染成折叠行,插件拿不到 DOM,只能从编辑器的 目标下拉框里选。 - **在线伪造当场不可逆**。追加的事件进了日志,当场没有自动备份。 要还原就再改一次写回原文。 - **agent 正在输出时不要改**。客户端在运行状态会锁住入口,避免和流式输出抢同一段文本。 - 三代插件(v1 / v2 / v3)**共用同一条操作条**,同时启用会挂出多条。 安装脚本默认只留 v3。