@kira905/dsh-session-title-live
Live session-title provider for dsh that regenerates the title after every user message, summarizing the most recent messages within a byte budget.
Install
dsh plugin --profile web add @kira905/dsh-session-title-live
Sandbox test results
| Stage | Result |
|---|---|
| 1 install | ✓ |
| 2 list | ✓ |
| 3 mount | ✓ |
| 4 boot | — |
Four stages run in an isolated sandbox: install (network on) → list → mount → boot (last three with no network).
README
dsh-session-title-live
### 这是什么
一个小插件:让会话标题实时反映状态(运行中 / 已完成),并且不会把已 pin 的标题搞乱。
### 它解决什么
侧边栏里十几个会话,光看标题分不出"正在干活"和"早就结束了"。这个插件把状态前缀直接写进标题,并且把"自动改标题"和"用户手工 pin"这两件事分开处理 —— 你 pin 住的标题它不碰。
### 一条命令跑起来
```powershell
dsh plugin --profile web add @kira905/dsh-session-title-live
```
装完标题就会自己带状态前缀;规则可通过插件设置调整。
### 它长什么样
侧边栏标题变成「【运行】…」/「【完成】…」这种形态。⚠️ 本仓暂无截图。
### 它不附带什么(先看清楚,省得装完失望)
这套开源出来的是能用的工具 + 装完自检 + 设计文档。有两块不在开源范围里:
1. 「自己盯着活干」的那套引擎:定时调度、队列盯守、管家日报、自主决定要不要动手 —— 这几件还没整理出来放(整理完会陆续放)。它的设计本身是公开的,写在 ops-handoff-design 仓里,想自己实现的人照着做得到。
2. 「出事喊到人」的通道:企业微信、语音播报这类 —— 不随开源发布。
所以:装完你拿到的是一套能用的工具,不是一个会自己上班的管家。
### 支持哪个版本的 DSH
DSH 0.2.x —— 现在发出来的 0.2.1 / 0.2.2 各个 rc 都能用。
为什么不用 peerDependencies 卡版本:宿主目前发布的都是预发布版,而按 node-semver 的规则,
预发布版本只有当区间里存在「同 major.minor.patch 且带预发布比较器」的条目时才放行 ——
也就是说 >=0.2.0-rc.2 <0.3.0 这种写法在任何一个真实宿主上都必然报警,纯噪音(实测不阻断安装、也不阻断挂载)。
所以本包的做法是:装的时候不拦你;运行时按能力探测,探测不到就走降级路径,不会硬崩。
本仓装完即用:dsh plugin --profile <profile> add @kira905/dsh-session-title-live一条命令,dsh.bundle会让它自动挂进 profile 的组合列表,不需要再手工写cordis.patch.yml。
装完自检(三条只读验法)
<profile> 换成你实际用的 profile(默认 web),<数据根> 换成你的 DSH 数据根(默认 ~/.dsh)。
# ① 组合树里有没有它(只读、约 0.6 秒、不启服务) dsh --profile <profile> --dump-config | Select-String "dsh-session-title-live" # 期望:bundle 层出现一行 "# == <登记名>"、insert 层出现 "- id: <entry>"(问的都是「它挂上没」); # 本仓包名 @kira905/dsh-session-title-live —— 带 scope 装的写带 scope 名、老工装 / 手写的可能是裸名,两种都搜一遍 # ⚠️ 若该包会 insert 一行,还要数一遍"同一个 id 出现了几次",必须 == 1 # ② 组合列表里有没有它(只读) Get-Content <数据根>/profiles/<profile>/package.json | Select-String "@kira905/dsh-session-title-live" # 期望:dependencies 与 dsh.profile.bundles 两处都有(CLI 类只需要 dependencies;bundles 里也可能写裸名 dsh-session-title-live) # ③ 本仓是插件、没有命令入口 —— 跳过这一步(判据看 ① 与 ②)
English: [README.en.md](./README.en.md)
一个 DeepSeek Harness (DSH) 插件:让会话标题跟着对话实时更新。
为什么需要它
DSH 自带的标题机制只在会话第一条用户消息时生成一次标题(automatic: "first-prompt")。
长会话聊到十几轮之后,侧边栏显示的还是开头那句话,跟会话实际内容完全脱节 ——
而会话列表恰恰是你找会话的唯一入口。
本插件注册一个 automatic: "all-prompts" 的标题 provider:每条人类消息之后都会用
「字节预算内最近的人类消息」重新生成一次标题。它不替换核心的 session-title 服务,
而是注册进它(和官方 provider 同一个扩展点)。
顺带解决一个相关问题:回合边界自动状态前缀。如果团队约定「干活写【运行】、收尾写【完成】」,
只靠 agent 自觉去写,实测绝大多数会话都不会有标记;本插件在 turn/start / turn/end
边界自动把前缀写上(前缀文案可配置,不想用可以关)。
- 零第三方依赖:只用
node:fs/node:os/node:path(node:zlib只在验证脚本里用)。 - 零主包 import:插件随 profile 部署,运行期解析不到全局 npm 里的
@deepseek-ai/*包,
因此事件名 / 服务名内联在 lib/host-protocol.js 一个文件里(升级主包时只核对这一处)。
- 不读会话文件:只订阅会话事件、只 append
session/title事件(写标题是主包公开的事件契约)。
设计依据
本组件是「ops-handoff-design」所述运维体系的一个实现,
设计依据(对应文档仓约定的固定四问):
- 它为什么存在、边界在哪 → 见《自治式运维管家》§2 会话生命周期覆盖矩阵,以及《体系全景与家规》§3.8 会话生命周期的自治
- 它与宿主版本的兼容区间 → 见《多机交接与云中继》§4.5「兼容性要求」(另见本 README 第七节「兼容性」)
- 本组件特有的坑与实测 → 见本 README「已知限制」一节
- 文档仓地址 → Gitee(镜像)<https://gitee.com/kira905/ops-handoff-design>
| GitHub(主)<https://github.com/kira905/ops-handoff-design>
(文档仓的组件索引表回指本仓;两仓互链、版本各自独立)
设计稿里不写具体仓库地址(写死即死链),实现清单统一收在文档仓的组件索引表里——本仓只负责回链章节。
一、能力
功能 · 说明
实时重生成标题 · 每条人类消息后重新生成;选材 = 上一版标题的依据(主题锚)+ 最近消息,按字节预算收拢
不覆盖人工改名 · 你在 GUI 里手动改过标题之后,本插件不再动它(pin,与打标路径共用同一份判定)
回合边界状态前缀 · turn/start → 【运行】,turn/end → 【完成】(文案可配、可关)
预置标题保护 · 会话创建阶段已写好的标题(任务卡 / 外部流程预置):只换前缀、不被摘要顶掉
自建调度 · 主包的自动调度在首轮之后拿不到启动时机(见 lib/index.js 文件头),所以本插件自己在 llm/stream 钩子里触发;两条通路由轮次认领去重,一轮最多一次生成
最小信息门槛 · 已有标题时,本轮新增消息太少(默认 < 20 字)就不重生成,避免「好」「收到」这类短噪声把标题带跑
活开关 · 一个 JSON 文件 / 一个环境变量即可停掉(不重启),关掉后零写入、零 token
主线名直写(可选) · 宿主侧有「会话 → 主线」账本时,标题直接写主线名(不猜、不花模型调用);账本缺失即回落自动生成,两条触发链都拦(见第六节)
子代理会话跳过 · 子代理 / 派生会话不打标、不生成
二、前置条件
- DSH 主包
>= 0.2.0-rc.2 < 0.3.0(兼容性细节见第七节) - Node.js
>= 18 - 一个能改
profiles/<name>/的 DSH 安装(默认 profile 名为web)
三、安装(从零开始)
0. 先备份
改 profile 之前把 cordis.patch.yml(必要)与 package.json、.package-map.json(若你会改)
各复制一份留底。
1. 把包放进去
包已发布到 npm:@kira905/dsh-session-title-live。
方式 0(推荐,0.2.5 起)—— 走 DSH 插件管理器,bundle 层自动挂载:
dsh plugin --profile web add @kira905/dsh-session-title-live
本包自带 cordis.patch.yml(package.json#dsh.bundle),装它 = profile 拿到一个层,不用手工改 profile 的 cordis.patch.yml(也就跳过后面的第 2 步)。
下面的方式 A/B/C 是「手工装」的三个变体,装完还要按第 2 步手工注册。
方式 A/B/C 统一叫「手工装(旧版 / 离线用)」 —— 只在离线、要改源码、或装旧版(不带 dsh.bundle)时才走。
两条路别混用:混用会在组合里留下同一件的两份登记(dsh.profile.bundles里同一包名两行,或cordis.patch.yml里同一个 id 两行;后者不一定会报错,光看日志发现不了)⇒ 判据 = 两处各数一遍,每一处必须 == 1。
方式 A(推荐,声明式) —— 在 profiles/<name>/package.json 的 dependencies 里加一条,再安装:
"dependencies": {
"@kira905/dsh-session-title-live": "^0.2.5"
}
cd <DSH_HOME>/profiles/<name> # 用你平时给这个 profile 装插件的那条命令安装(pnpm / npm 均可)
方式 B(npm 直接装进 profile):
npm install @kira905/dsh-session-title-live --prefix <DSH_HOME>/profiles/<name>
方式 C(git 克隆,离线 / 要改源码时) —— 直接把包目录复制成实体目录:
git clone <仓库地址> dsh-session-title-live cp -r dsh-session-title-live <DSH_HOME>/profiles/<name>/node_modules/@kira905/dsh-session-title-live
三种方式差别只在「谁负责把文件放到 node_modules 下」,插件行为一致。
2. 注册插件(只有「手工装法」要这一步)
走方式 0 就跳过本节 —— bundle 层已经把插件插好了。下面只给手工装(方式 A/B/C)用。
把 [cordis.patch.yml.example](./cordis.patch.yml.example) 的 insert 段追加到
profiles/<name>/cordis.patch.yml 末尾:
- insert:
- id: session-title-live
name: '@kira905/dsh-session-title-live'
必须同时关掉官方「只在首轮生成标题」的 provider(session-title-llm):
两条 provider 注册的是同一个 provider id,同时挂载时后一个会报
session-title provider "dsh-session-title-live" is already registered、整条 entry 不激活
(隔离实例实测)。所以手工装时也要加:
- id: session-title-llm disabled: true
写法注意:宿主认的是针对某一条的覆盖id+disabled: true;disable:列表不是
loader patch 的语法,会被静默跳过(只在 --dump-config 里留一行
`patch: id is required
…(truncated)
Rendered from the README published on npm. Formatted only, not edited.
Versions
Published on npm::7,最后更新 2026-11-06