中文EN

dsh-session-inherit

session已测通过npmMIT

会话菜单新增「继承」:把长会话里的具体锚点(任务原文、最近的用户指令、改过的文件、最近的失败、命令、待办)机械提取成交接单,在干净的新会话里接着干——预设默认一并继承,不复制历史,也不调用模型。

下载量 / Downloads
857
依赖体积 / node_modules
0.17 MB
测试时间 / Tested
2026-11-07
DSH 版本 / Version
0.2.2-rc.1

安装

dsh plugin --profile web add dsh-session-inherit

沙箱测试结果

阶段结果
1 安装✓
2 列装✓
3 挂载✓
4 启动—

四阶段在隔离沙箱里跑:安装(有网)→ 列装 → 挂载 → 启动(后三步断网)。

README

dsh-session-inherit(继承)

![DSH Market](https://dsh.market/)

[English](README.md) | [简体中文](README.zh-CN.md)

把一段跑了很久的会话,交接给一个干净的新会话。

在会话行的「…」菜单里多出一行 继承。点它 → 预览一份从源会话机械提取出来的

交接单 → 确认 → 新建一个不带旧历史的会话,把这份交接单作为它的第一条消息发出,

工作在新会话里继续。原会话原样保留。

<p>

<img src="docs/session-menu.png" width="170" alt="会话菜单里多出的「继承」">

<img src="docs/inherit-dialog.png" width="330" alt="继承预览对话框">

</p>

/inherit 命令是同一个入口(指令提示里能搜到):

<p>

<img src="docs/inherit-command.png" width="700" alt="/inherit 命令提示">

</p>

置顶          ← DSH 原版(Pin)
重命名        ← DSH 原版(Rename)
分叉          ← DSH 原版(Fork)
继承          ← 本插件(order 350)
归档          ← DSH 原版(Archive)

除「继承」外的四行都是 DSH 原版自带的条目(sidebar.workspaces.session.menu.item

slot 的官方内容)。如果装了别的会话菜单插件,你的列表里还会多出它们的条目——

本插件只负责「继承」这一行。


为什么不是 /compact、也不是「分叉」

现在的 DSH 里已经有两条"继续干"的路,但这个需求是第三条:

做法 · 它搬过去的东西 · 对本场景的问题

/compact · 把历史换成摘要,会话不变 · 实测把 541,227 token 压到 25,602,4 步之内退化又犯了,重复词还从「做。」变成了「好。」——可见既不是长度的问题,也不是上下文内容的问题

官方分叉 · 复制源会话的整段历史前缀 · 等于把退化诱因一起带走,新会话一睁眼就是几十万 token 的历史

本插件的继承 · 只搬可核对的具体锚点,历史一律不带 · 新会话的上下文从几千字符起步

为什么不用 LLM 做摘要

/compact 那次的证据很直接:摘要留下的是"要做验收、要写报告"这类抽象意图,

丢掉的恰恰是文件路径、下一步参数这类具体锚点。模型攥着几句模糊意图,在抽象层反复

自我告诫,而每次告诫的句式几乎一模一样——这本身就是在喂重复退化。

所以本插件的交接单一次模型调用都不发,只做机械提取:任务原文、最近的用户指令

(原话,不改写)、动过的文件、跑过的命令、最后一次待办状态、源会话最后一条回复。

每条都能追回源会话去核对。

交接单开头还写死三条执行规约:

不要复述本单,不要总结本单,不要回应"收到/了解了"。
读完直接做「下一步」。第一步只做一个具体动作,做完停下汇报;不要同时铺开多个方向。

交接单长什么样

交接单正文的语言跟随界面语言(客户端在 preview/commit 请求里带 lang):中文界面

生成中文交接单,英文界面生成英文交接单——不然英文用户拿到的正文,他自己和模型都读不顺。

下面这份是中文输出。

📋 会话继承单

> 来源:`session-xxx`(标题) · 共 15 轮 · 最后活动 2026-10-08 19:37
> **执行规则**:不要复述本单…

## 任务目标                    ← 源会话第一条真实用户消息
## 改过的文件(实际写入/修改过)  ← 来自 edit/write 的 file_path,按最近改动排序
## 最近失败                    ← 源会话最后几次工具报错(带轮次与错误码)
## 最近的用户指令(由旧到新)     ← source.kind === 'user' 的原话
## 读过的文件(只读取过,未修改)
## 文中提到的路径               ← 工具参数正文里扫出来的,可能是噪音
## 项目内相对引用               ← 基准目录未确定,需要时用文件搜索确认
## 最近执行的命令
## 待办(源会话最后一次 todo 状态)
## 源会话最后一次回复
## 下一步                     ← 你在预览框里写

章节标题不带序号。序号是逐节写死的字面量,会随"某一节有没有内容"漂移——

早先版本里客户端提示写死了「## 7. 下一步」而实际生成的是「## 8.」,用户照着找

永远找不到。

「最近的用户指令」只认 source.kind === 'user'。实测某个真实会话的 42 条

user/message 里,有 27 条是 agent-instructions / runtime-context /

skill-catalog / time-context / 记忆提示 / 模型选择 / 压缩检查点 这类运行时注入

——全是噪音,现在被挡在门外。

两个高价值锚点

改过的文件只取 edit / write 这类写入工具的结构化 file_path。实测某真实

会话:写入类调用 85 次、读取类 58 次,改过 17 个文件、读过 43 个——两类混在

一起时,读过的文件会把真正改过的挤出上限。write 的 content、edit 的

new_string 正文里出现的路径只算「文中提到」。

最近失败来自 tool/result 的 isError。实测某真实会话 374 条 tool/result

里 11 条失败,形如:

- (t5) `edit` FS_STALE_VERSION:cannot write "…\inject-codex.ps1": file changed since it was read — re-read the file, then retry

每条都带轮次——同一节里的失败可能横跨好几轮,不标轮次的话新会话分不清哪些是

陈年旧账。这是"接着干什么"最直接的线索,而且纯机械可提取。成功的 363 条、以及

用户主动打断(AbortError)和自动审查被中断这类噪音会被丢掉;同一条报错在多个

工具上重复出现时按文本合并。

绝对路径锚点还会做一次存在性检查,已被删除或改名的会标上 (已不存在)——省掉

新会话去翻一个不存在的文件。

用法

入口一:会话行菜单

1. 鼠标移到侧边栏任一会话,点行尾的「…」;

对哪个会话点都行,包括已经冷掉的会话(读取走 sessionQuery.readSession,不激活 agent)。

2. 点 继承。

3. 弹出预览,从上到下是:源会话信息(标题 / 轮次 / 改过几个文件 / 失败几条 / 命令数 / 待办数)

→ 「下一步」输入框(可以不写)→「创建后立即开始工作」勾选框 →「继承当前对话的

预设」勾选框 → 一行折叠着的交接单。

4. 在「下一步」里写要它做的事——越具体越好(点名哪个文件、做哪一个动作),

然后点「创建并继承」。要改交接单全文时,点「▸ 展开交接单全文(可编辑)」。

交接单默认折叠是因为多数时候你只想写一句话,不想逐字审阅几千字。

新会话会自动打开,标题是 继承: <源标题>,工作目录、模型路由、agent preset 默认

都跟源会话一致;不想继承预设就在预览框里取消那个勾,新会话改用 DSH 默认预设。

勾选框「创建后立即开始工作」默认勾上:交接单会经

sessionController.prompt 作为一条正常用户消息发出并立刻开始。

取消勾选时改为直接写入会话日志(session:append),只记录、不触发首轮,

打开后你自己说要做什么。

「下一步」输入框和交接单是两个独立来源:宿主收到 commit 时,如果两者都在,

会把输入框的内容写进那份交接单的「## 下一步」一节——所以即使你展开改过交接单,

也不会有哪一边被悄悄丢掉。

降级会明说。 如果宿主没能自动开始(prompt 失败或不可用),对话框不会静默

关掉,而是停在原地显示原因和新会话 id,并给一个「打开新会话」按钮——以前这里只

写 console.warn,界面静默消失,用户会以为新会话已经在跑了。

重复继承会被提醒。 源会话(常常是冷的)改不了标题:

sessionTitle.rename(session, title) 的契约要求传入活着的 session 对象(内部断言

ctx.sessions.get(id) === session),而 sessions.get 的文档写明"冷会话返回

undefined"。所以"这个会话被继承到哪儿去了"记在

%DSH_HOME%\session-inherit\history.json,在你再次点开预览框时提示

「这个会话已经被继承过 N 次,最近一次 …→ …」——正好是你准备再次继承的那一刻。

记录只存会话 id 和时间戳,最多保留 200 个源会话、每个 10 条。

入口二:/inherit 命令

/inherit                                  继承当前会话
/inherit <sessionId>                      继承指定会话
/inherit --next 先跑一次 npm test          继承当前会话,并指定第一步
/inherit <sessionId> --next 换个文件继续    两者一起用

不带 --next 的裸文本只可能是会话 id,不合法就如实报错,不会被猜成"下一步"。

入口三:session_inherit 工具

注册给 agent 的同名工具,参数 sessionId(必填)、nextStep、start。

用途是让 agent 自己在上下文变长时提议换会话,或让用户通过 agent 表达意图。

三条入口最终走同一条链路:读源会话 → 机械提取 → 新建会话 → 挂工作区 → 注入交接单。

回查源会话:session_read 工具

交接单首行写着源会话编号,但新会话没法直接读它:会话日志是

%DSH_HOME%\sessions\<工作区转义>\session-<id>\session.vN.jsonl.zstd,多帧 zstd 拼接

(实测 2.7MB 文件切成 1067 帧,Node 的 zstdDecompressSync 只解第一帧就停)。

所以本插件另外注册了一个只读工具补上这一环:

session_read { sessionId, mode: 'search' | 'summary' | 'tail', query?, limit? }
  • search(默认):按关键词搜源会话,返回命中处前后各一段上下文
  • summary:结构化摘要(任务目标 / 改过的文件 / 最近失败 / 待办 / 最后一次回复)
  • tail:最后 N 个有内容的事件——看"上次到底停在哪"

新会话遇到"交接单里那个文件是干什么的"这类问题时可以直接回查,不用你回去翻。

它只读,不创建也不修改任何东西。

「附上原对话编号、让新对话顺着编号去找」这个想法的闭环就在这儿:光有编号没用,
得让它读得到。

安装

从 npm 装(推荐,一条命令):

dsh plugin --profile <profile> add dsh-session-inherit

也可以不经过 npm,直接从仓库装。改 profile 的 package.json,两处都要加:

{
  "dependencies": {
    "dsh-session-inherit": "link:/path/to/dsh-session-inherit"
  },
  "dsh": {
    "profile": {
      "bundles": [
        "dsh-session-inherit"
      ]
    }
  }
}

bundles 才是加载权威——只写进 dependencies 不会挂载。装完重启 DSH。

桌面端的 profile 由 Electron 独占管理,全局 CLI 会拒绝操作它;
那种情况直接改该 profile 的 package.json 再重启即可。

版本适配

在 DSH 0.2.0-rc.2(Windows)上验证通过。插件依赖若干 DSH 内部服务与菜单

slot 名,DSH 升级后可能失配。如果菜单项不出现、或插件页显示「异常」,先查

profile 的 compatibility.json——profile 启动时会校验插件对 @deepseek-ai/dsh

与 dsh-* 的 peerDependencies,不满足的 bundle 会被整体跳过(日志里打印

skipping profile bundle)。把

…(truncated)

以上内容来自 npm 上的 README,我们只做格式化,不改内容。

版本

npm 上共发布:3,最后更新 2026-10-12

链接

GitHub · Homepage · npm

同类插件