dsh-revive
DSH 会话回放视图:按轮重放一次会话,用户输入与助手正文保持阅读速度,思考与工具输出高速掠过且每段最多 3.5 秒,每条输入后停顿一秒;可一键把原始请求复刻到一个新会话,也可边回放边录制,把回放录屏导出成 WebM 视频(画布 1280×720,无需系统录屏权限)。
安装
dsh plugin --profile web add dsh-revive
沙箱测试
这个插件还没测过。提交测试 →
README
dsh-revive — 会话回放、复刻与录制 · session replay, re-run and recording
中文 | [English](#english)
中文
DSH 会话视图切换器里新增「回放」视图(与「对话」「轨迹」并列):
- 流式回放动效:⏮ ◀ ▶ ⏭ 游标控制 + 自动播放,内容按字符逐个"打"出来(带光标、视口自动跟随实时边缘),而不是整段 append;
- 一键复刻:把当前会话的全部原始用户请求按顺序重放到一个新会话(走官方
uiWorkspace.connectWorkspace+session.prompt),工具由新会话重新执行——真正的"重跑"; - 会话输出录屏:把回放画面(会话内容本身)逐帧绘制到 1280×720 canvas,用
MediaRecorder录成.webm(VP9),可自动下载;不依赖窗口/屏幕录制权限。
界面
复用宿主自带的 UI 组件库渲染,尽量贴近原生观感并在此之上做信息分层:
- 正文与用户消息走宿主同款 Markdown 渲染(表格、列表、链接、行内代码、代码块语法高亮都可正常显示),流式揭示时也不破坏格式;
- 思考与工具调用默认折叠成一行:思考显示「● 思考 · N 字 · 首句预览」,工具显示「⚒ 工具名 · 实际执行参数」(例如
bash后面直接是命令),点一下展开看全文; - 工具结果折叠行带状态:
✓ 已完成/✕ 失败/运行中,折叠时显示输出首行预览; - 折叠时仍在实时增长:思考/工具那行会边播边显示尾部文字,所以打字机效果不会因为折叠而消失;
- 轮次分隔改成细线 + 居中标签,正文最大宽度 900px,光标带呼吸闪烁。
如果宿主的组件库不可用(例如换到其它 DSH 版本),会自动降级为纯文本渲染,不会白屏。
回放动效
- 代价预算时钟(分类变速):一轮内所有文本被拍平成
segments(用户/思考/正文/工具调用/工具输出),共享一个「代价预算」游标;每类内容每个字符消耗的代价不同,于是同一时钟下快慢不同:
内容 · 权重(代价/字符) · 效果
用户输入 user / steer · 1.00 · 基准阅读速度(60cps ≈ 每秒 60 字)
助手正文 assistant · 1.00 · 基准阅读速度
思考 reasoning · 0.06 · ≈16 倍速刷过
工具调用 toolCall · 0.04 · ≈25 倍速
工具输出 toolResult · 0.12 · ≈8 倍速
- 输入后停顿:用户/steer 内容播完后,时钟在边界上冻结 1 秒(期间显示「⋯ 思考中」),再开始出思考/正文——模拟真实的"发出去后等首字",避免输入一结束就立刻刷屏;
- skim 封顶:思考/工具类内容即使超长也只占最多 3.5 秒/段(权重按当前速度自动抬高),避免一轮几万字的思考把观众晾在那里;而输入与正文永远保持完整阅读节奏。
- 视口跟随:内容不再撑高容器,而是沿用宿主的会话滚动容器;流式期间自动
scrollTop = scrollHeight,用户手动上滚超过 64px 即暂停跟随,滚回底部自动恢复。 - 速度档:慢 25 / 标准 60 / 快 160 / 极速 400 字符/秒(localStorage 记忆)。
- 默认可见:打开视图即完整显示当前轮;按 ▶ 播放才从该轮开头重新流式播放并跨轮连续推进。
录制
- 画布按「片段预排版」(换行切片保留字符偏移),每帧只画已揭示部分,实时边缘随内容下滚,底部有渐隐提示仍在输出;
- 时长档 30 / 60 / 120 秒 / 不限:选定时会自动抬高揭示速率把整段会话塞进目标时长(不限时按 240 秒硬上限加速),避免长会话录出十几分钟;
- 录制结束时自动生成 blob 并触发下载,按钮旁保留「⬇ 下载视频」可再次保存;录制中传输控件与两个下拉均锁定,避免画面被打断;
- 依赖
canvas.captureStream()+MediaRecorder(桌面版 rc.3 实测可用,video/webm;codecs=vp9)。
形态
纯 client 插件,但必须以 bundle 形式声明(见「安装」——这是 0.1.1 的关键修复):
- 无 Node 路由、无文件写入,
lib/index.js只有空apply(),仅作为 loader 行的挂载点; - 会话视图注册:
slots.inject("conversation.view", () => slots.register(def, Component))(与官方 ui-chat / ui-trajectory 同款); - 数据:
uiConversation.binding(sessionId).target("chat")投影 +session.loadOlder()补全历史; - 复刻:
uiWorkspace.connectWorkspace(workspaceId)+sessions.binding(sid).session.prompt([...], "queue")。
安装
已收录到 DSH 插件目录(分类 Sessions & Messages),在 dsh 的插件市场里搜 dsh-revive 即可安装;目录条目页:<https://awesome-dsh-plugin.com/p/zxsimple/dsh-revive/>
也可以一条命令从仓库装:
dsh plugin --profile web add github:zxsimple/dsh-revive
手工挂载(本地开发)则改 profile 的 package.json:
"dependencies": { "dsh-revive": "link:/path/to/dsh-revive" },
"dsh": { "profile": { "bundles": [ /* ... */, "dsh-revive" ] } }
然后 pnpm install(link 依赖会建符号链接)+ 完全重启应用(boot 时才会重新组装 loader 行与 client 模块)。
也可以直接从仓库安装:
git clone https://github.com/zxsimple/dsh-revive.git # 然后把上面的 link: 指向 clone 下来的目录
关键点:纯 client 插件也必须声明dsh.bundle.patch并出现在dsh.profile.bundles里,否则宿主不会为它生成 loader 行(详见下一节)。
平台支持
纯 client 插件,运行在 DSH 的 Web 前端里,不含任何与操作系统相关的代码:没有 fs / path / child_process,没有 process / __dirname,没有绝对路径拼接,也没有构建脚本与原生依赖(pnpm install 对它只是建一个符号链接)。所以平台跟随 DSH 的 Web 客户端。
平台 · 状态
macOS(DSH 桌面版 0.2.1-rc.3) · 已实测:视图注册、流式变速、输入后停顿、canvas 录制全部验证通过
Windows · 预期可用(未实测)。DSH 随包提供 node.cmd 与 command-path.ps1,插件市场也有完整的 win32 分支(link: 依赖走 junction、npm.cmd / pnpm.cmd);插件侧没有需要移植的部分
Linux · 同理,未实测
用到的浏览器能力都是 Chromium 内置的,Windows 上的 Electron / Chromium 同样具备:
MediaRecorder+canvas.captureStream()—— 录制走 VP9/VP8 WebM,Windows 的 Chromium 支持;产物用系统播放器或浏览器都能播;localStorage(速度与时长记忆)、navigator.language(中英文案);- 录制画布的字体栈包含
Microsoft YaHei,中文在 Windows 上不会掉字; - 滚动容器靠
getComputedStyle向上查找,不依赖任何平台布局常量。
Windows 上唯一的注意点:link: 依赖建的是 junction,如果手改过 profile 的 package.json,重启前先确认 node_modules/dsh-revive 指向正确。
如果你在 Windows 上跑出了问题(比如录制拿不到 video/webm,只剩 video/mp4),把控制台报错贴到 issue 里即可。
为什么必须是 bundle:「没有按钮」的根因
1. package.json 缺 dsh.bundle.patch。插件目录里虽然有 cordis.patch.yml,但没有声明它,宿主就永远不会把这条 insert 行并入 loader 树 → 没有 loader 行 → 没有 Node 半边 fiber → plugins/?? 里根本没有 dsh-revive/client.js → 视图切换器自然没有「回放」。dshmarket 自己的校验也会报同一句话:bundle declares no dsh.bundle.patch — the profile will fail to boot。
2. 纯 client 插件(dsh.client 但无 dsh.bundle)在 market 里只能热挂载一个 shim,重启即失效——所以它曾经"装上了"却重启后消失。
3. 另外两处真实的运行时缺陷(0.1.0 即使加载成功也点不出内容):
require("react/jsx-runtime")返回的是命名空间对象,不能直接当函数调用(应取.jsx/.jsxs);- rc.3 的
chat快照不是{timeline, byId},而是{ order: string[], nodes: { get(key) }, timeline: { turnOrder, turns: Map } },节点形如{ key, kind, location, data };用户文本在data.content的分片里,助手文本在data.blocks里(kind:"text" | "reasoning" | "tool-call")。
兼容性(对照 DSH 0.2.1-rc.3 桌面版产物核对)
slots.register({name:"conversation.view",...}, Component)✓(ui-chat 的 id=chat order=0、ui-trajectory 的 id=trajectory order=10 同款)slots.entries("conversation.view")会收集所有注册项并渲染成切换器标签(label经resolveSlotLabel)✓uiConversation.binding(source)接受 sessionId 或 session binding ✓;.target("chat")→{ getSnapshot, subscribe }✓ctx.locale.register(ns, { zh, en })✓(值可以是函数,服务端不校验字符串)session.loadOlder()✓uiWorkspace.connectWorkspace(workspaceId)→Promise<SessionId>✓(服务名uiWorkspace)session.prompt([{type:"text",text}], "queue")→{ ok }✓- 运行期 cordis 注入用服务名:
["slots","sessions","uiSession","uiConversation","locale"](与 ui-trajectory 一致);workspaces/uiWorkspace用ctx.get(...)兜底读取。
English
Adds a Replay view to the DSH conversation view switcher, alongside Chat and Trajectory:
- Streaming replay: cursor controls (⏮ ◀ ▶ ⏭) plus autoplay; text is revealed character by character with a caret and a viewport that follows the live edge, instead of pasting whole blocks;
- One-click re-run: sends the session's original user prompts, in order
…(truncated)
以上内容来自 npm 上的 README,我们只做格式化,不改内容。
版本
npm 上共发布:4,最后更新 2026-11-05