dsh-fork-edit
No description
- Stars
- 0
- Language
- JavaScript
- Created
- Sep 8, 2026
- Updated
- Sep 11, 2026
Introduction
dsh-fork-edit
dsh (DeepSeek Harness) web 客户端的回合级对话编辑 / 重试插件。
在任意一条已落定的历史用户消息上悬停,即可看到 ✎ 编辑 / ↻ 重试图标:
- 编辑 —— 修改那条消息的输入(支持直接粘贴图片),从该回合之前分叉出一个新会话并自动执行;
- 重试 —— 原输入不变,从该回合之前分叉重放。
原会话原样保留,随时可以切回。
为什么用 fork 实现
常见的做法是给消息编辑写一套自定义事件(版本树 + undo/redo),但自定义事件写入 session log 后,历史会话可能因事件白名单拒读而无法冷加载。
dsh-fork-edit 反其道而行:不写入任何自定义事件。编辑/重试 = 在目标回合之前的闭合边界处 fork 出新会话,编辑后的文本作为新会话里的普通用户回合执行。谱系关系只靠 parentSession header meta 记录。
结果:
- 日志里只有核心已知事件,历史会话永远可读;
- 编辑语义天然简单 —— 分支就是一个普通会话,没有任何待修复的历史数据;
- 核心事务在源 Agent 的
runMaintenance()缝隙内执行,失败时逐项回滚,不产生半成品会话。
inverses = []
child = agents.create({ seed: 目标回合之前的闭合边界前缀, meta: { parentSession, seedLength, cwd, agentPreset } })
inverses.push(() => child.dispose())
workspace? → attachSession(childId)
await sessions.flush(child.session) # 耐久性屏障
child.agent.followup(编辑后文本 || 原回合用户输入) # 新会话自动执行
失败 → recoverOperation(inverses.reverse()) # 无半成品残留
功能
编辑 / 重试
- 悬停任意已落定的用户消息行,官方操作按钮旁出现 ✎ / ↻ 图标;对话进行中按钮也会在数秒内自动出现,无需刷新或切换会话。
- 编辑弹窗预填原输入;输入框内可直接粘贴图片(持久化后作为 image block 并入新消息),纯图片编辑亦可提交。
- Enter 直接提交,Shift+Enter 换行;输入法组合态不误触发。
- 弹窗内带会话 timeline:纵排列出所有已闭合的用户回合(序号 + 单行预览),点击即在弹窗内跳转切换编辑目标。
- 新分支自动以首条用户输入命名,各分支一眼可辨;新会话自动打开。
侧边栏分支分组
官方侧边栏是平铺展示的,fork 出的后代挤在顶部难以辨认。本插件以 sessions.list 谱系为权威,把根会话的全部后代分组渲染在根行下方:
- 单一层级,视觉缩进 + 树状连接线(
└形),一组连线自成一体; - 行识别基于 React fiber 的会话 id,标题只作降级兜底 —— 不受 fork 子会话暂无标题、标题重名的影响;
- 根行(或根不可见时的组头行)带折叠开关,折叠状态存 localStorage,随会话切换智能展开;
- 官方只渲染最近 N 个会话时,后代自动锚定到最近可见的祖先,整组不散架。
级联归档
官方的「归档会话」只归档单个会话。本插件在 client 侧对服务方法做级联包装:归档任一会话时,自动收集并归档其整棵后代子树(部分失败不静默)。
注意:归档目前没有官方 unarchive 入口,不可逆。
HTTP API
Host 侧通过 ctx.webServer.register 暴露路由,Client 以同源 fetch 调用:
| 请求 | 作用 |
|---|---|
GET /fork-edit?sessionId=… | 已落定回合列表 |
POST /fork-edit { kind: "prefill", sessionId, turn? } | 目标回合原文本 |
POST /fork-edit { sessionId, turn?, mode, text? } | 执行分叉 |
mode 取值:edit-user(编辑用户输入)/ retry-turn(重试回合)。出错返回结构化错误(400 参数 / 409 业务)。
安装
~/.dsh/profiles/web/package.json:
{
"dependencies": {
"dsh-fork-edit": "link:/path/to/dsh-fork-edit"
}
// 并在 bundles 数组加入 "dsh-fork-edit"
}
若同时装有同类消息编辑插件(如 dsh-message-edit),请移除 —— 相同注入点会出双按钮。
工程结构
dsh-fork-edit/
├── package.json # dsh.bundle.patch / dsh.client 注入清单
├── cordis.patch.yml # 插件注册入口
├── index.mjs # host 侧:fork 事务 + HTTP 路由
├── client.js # client 侧:按钮注入 + 编辑弹窗 + 侧边栏分组
└── README.md