dsh-session-title-stamp
Keeps DSH session titles in DATE | CATEGORY | NAME with turn-aware auto-retitle, a settings page, and hover duration/cost/token stats.
Install
dsh plugin --profile web add dsh-session-title-stamp
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-stamp
[English](./README.md) | 中文
给 DSH 会话一个稳定的「日期 | 分类 | 名称」标题。除了自动命名,还包括:
- 自动重算:回答完成后更新,2 分钟冷却,超过 100 条消息后冻结;fork、子代理和手动固定的标题跳过。
- 生成标题:会话头 ↻ 按钮、会话行
···菜单「自动生成标题」、或/retitle。 - 复制标题:会话行
···菜单多一项复制完整标题。 - 设置页:可视化调整格式、emoji 和重算节奏,带实时预览,不用改 YAML。
- 可选 emoji 分类:
categoryEmoji: true后标题形如1027 | ⚡ 优化 | ...。 - 悬停统计:不打开面板,一眼看到耗时、估算 CNY 成本、token 数。
- 分类语言:
categoryPreset: zh | en,也可以用categories自定义。 - 失败保护:重算失败保留当前标题,不被兜底标题覆盖。
- 零构建:纯 Host 逻辑 + 小型手写浏览器半边。
标题告诉你这个会话在做什么,悬停卡片告诉你它花了多少。
耗时、估算 CNY 成本和 token 数,悬停即见,不需要打开面板。
默认格式:
日期 | 分类 | 名称
例如:
1028 | 分析 | 绿洲短剧平台验证 1027 | 修复 | 四台设备第十题验收返修 1026 | 发布 | Ubuntu 环境初始化 1025 | 优化 | 降低渲染器内存占用
日期由插件从会话创建时间计算,不交给模型;分类只能从可配置词表中选择,并在本地校验;模型只负责提出分类和名称,最终格式由模板决定。
为什么
工作区里的会话一多,侧栏标题要么是首条消息的前几个字,要么是容易漂移的自动摘要。固定成 日期 | 分类 | 名称 后,跨项目扫侧栏会快很多,也和其它 coding agent 的命名习惯一致。
要求
- DeepSeek Harness
>=0.2.1-rc.3 <0.3.0。 - 会话有可用的模型路由;标题请求默认跟随会话当前的 provider/model,也可用
provider/model单独指定。
安装
DSH Desktop / Web(Discover)
在 插件 → 发现(Discover)→ 索引源 添加:
https://cdn.jsdelivr.net/gh/xuedipiaofei/dsh-session-title-stamp@v0.7.1/market/index.json
然后在列表里安装 Session title stamp / 会话标题印章。插件以 profile bundle 的形式安装,之后可在插件页启停。
CLI
从 GitHub 安装:
dsh plugin --profile <profile> add github:xuedipiaofei/dsh-session-title-stamp
从 npm 安装:
dsh plugin --profile <profile> add dsh-session-title-stamp
本地 checkout:
dsh plugin --profile <profile> add ./dsh-session-title-stamp
Electron Desktop 的 profile 由应用管理,请在应用的插件页安装,不要用 dsh plugin --profile desktop。
bundle 的 patch 会禁用内置的 session-title-llm 行并插入本插件。不要同时启用官方的 @deepseek-ai/dsh-experimental-session-titles-bundle:两者替换的是同一个 provider 槽位,标题服务只接受一个 provider。如果别的插件先注册成功,本插件只打一条 warn 并保持 inactive,不会让启动失败。
实现方式
cordis.patch.yml关闭session-title-llm,插入本包的session-title-stamp行。lib/index.js通过ctx.sessionTitle.register()注册提供者,并复用官方的
@deepseek-ai/dsh-session-title-llm 处理路由、超时、取消、token 上限和请求日志。
client.js是手写的浏览器模块:会话头刷新按钮 + 悬停卡片成本/耗时行。
插件从 session.header.createdAt 按本机时区计算日期,让模型返回
{"category":"...","name":"..."},校验分类,再按模板拼装。{type} 或 {topic} 为空时,相邻分隔符会一起消失,不会留下 ||。
重算节奏
provider 注册为 first-prompt,首条消息由标题服务自动命名。之后插件在每次 turn/end(回答完成)时判断,并有两道闸:
- 冷却:距上次自动刷新不足
refreshMinIntervalMs(默认 2 分钟)就跳过; - 冻结:用户消息数超过
refreshMaxTurns(默认 100)后停止自动刷新;/retitle仍可用。
fork 子会话、子代理会话,以及用户手动改名固定的标题都会跳过。refreshOnTurnEnd: false 时回退到旧的「每 N 条消息」模式(retitleEvery)。
会话头按钮与悬停统计
0.7.0 增加了一个很小的浏览器半边:
- 会话头有一个刷新图标,效果等同输入
/retitle,会话运行中禁用;
- 鼠标悬停会话行时,在原生相对时间下面多一行:
耗时 1h 51m · 估算 ≈¥4.11 · 131.7M tokens;
- 会话行
···菜单最上面多一项「自动生成标题」,下面多一项「复制标题」;
两者都不新开弹窗。
数字来自 sessionStats / tokenUsage 投影,按 DeepSeek 当前 CNY 价格估算,并标注「估算」。只在悬停时向宿主请求,不会为了显示数字去恢复未加载的会话。DSH 原生已经有运行中/待交互/完成未读的状态点与 loader,所以本插件不再加一层状态颜色。
悬停卡片字段说明
字段 · 含义
耗时 1h 51m · 来自 sessionStats 的模型 + 工具累计执行时间,不是墙钟耗时
估算 ≈¥4.11 · tokenUsage × DeepSeek 当前 CNY 价格表,是粗略估算,不是账单
131.7M tokens · 输入、输出、缓存读、缓存写的 token 合计
空闲 / 定时任务行 · DSH 原生状态内容,本插件不添加或替换
混合模型的会话按“最近使用的模型”估算,成本可能和实际账单不同。宿主没有该会话统计时,这一行会刻意不显示。
如果悬停行不显示,说明浏览器半边没连上宿主统计路由;刷新按钮和自动标题不受影响。
设置页
0.7.0 增加 设置 → 插件设置 → 会话标题:
- 顶部实时预览当前模板会生成的标题;
- 分类语言(中文/English)、可选分类 emoji、日期格式、标题模板;
- 自动重算开关、最小间隔、消息数冻结、启动补刷,并把额外模型成本写在说明里;
- 高级项只放名称长度和最近消息数;超时、预算、模型路由仍在配置文件里。
保存会写入当前 profile 的插件配置,对下一次生成的标题生效,不需要重启;已有标题不会被改写。
失败时
- 已经有标题时,重算失败会保留旧标题:provider 抛错,标题服务据此不提交新修订。
- 只有还没有标题的会话才用本地兜底:日期 + 推断分类 + 首条消息开头。
- 模型以
max-tokens结束时,只要还能解析出可用文本就继续用;只有完全不可用才算失败。
配置
在 profile 的 cordis.patch.yml 里覆盖:
- id: session-title-stamp
config:
refreshOnTurnEnd: true
refreshMinIntervalMs: 120000
refreshMaxTurns: 100
categoryPreset: zh
template: '{date} | {type} | {topic}'
timeZone: Asia/Shanghai
maxNameChars: 20
字段 · 默认 · 说明
refreshOnTurnEnd · true · 回答完成后刷新;false 时回退到 retitleEvery
refreshMinIntervalMs · 120000 · 自动刷新最小间隔;0 关闭冷却
refreshMaxTurns · 100 · 超过多少条用户消息后冻结自动刷新;0 不冻结
retitleEvery · 10 · 旧的按消息条数模式,仅在 refreshOnTurnEnd: false 时使用
backfillOnStart · false · 启动时对仍是 fallback 标题的 live 会话逐个补刷
backfillMaxSessions · 30 · 单次回填最多处理多少个会话
backfillIntervalMs · 2000 · 回填两次刷新之间的间隔
template · {date} \ · {type} \ · {topic} · 标题模板,占位符见下
dateFormat · MMDD · {date} 使用:MMDD(1028)/ YYMM(2610)/ YYYYMMDD
timeZone · 本机时区 · 日期/时间占位符使用的 IANA 时区
categoryPreset · zh · 内置分类语言:zh 或 en
categories · 预设 · 显式分类词表,优先级高于 categoryPreset
categoryEmoji · false · 给分类加 emoji 前缀(⚡ 优化、🐛 修复……)
maxNameChars · 20 · 名称字符上限(最终还受字节上限约束)
maxTitleBytes · 标题服务上限(80) · 实际取它与 session-title 的较小值
recentMessages · 8 · 发送首条消息 + 最近 N 条消息
maxInputBytes · 4096 · 单次标题请求输入上限
maxOutputTokens · 4096 · 输出上限(含推理 token)
timeoutMs · 90000 · 标题请求超时
provider / model · 跟随会话 · 可选,成对设置时用独立模型生成标题
模板占位符
占位符 · 含义
{date} · 按 dateFormat 渲染的日期(1028、2610、20261028)
{YYYY} {YY} {MM} {DD} {HH} {mm} {ss} · 日期/时间部件,可任意拼接({YYYYMMDD}、{HHmm})
{type} · 分类;为空时整段及相邻分隔符一起消失
{topic} · 名称;为空时整段及相邻分隔符一起消失
不认识的占位符会原样保留({MMDD} {bogus} 会保留 {bogus}),方便一眼看出模板写错,而不是悄悄消失。最终仍受 maxTitleBytes 截断。
设置页覆盖常用字段;下面的 YAML 表仍用于自动化和高级配置。默认分类是中文。categoryPreset: en 可切到
Analysis / Build / Fix / Optimize / Debug / QA / Release / Docs / Other;categories
可以覆盖任意预设。提示词使用配置的标签,本地兜底也会把常见中英文关键词映射过去。
隐私与成本
- 发送首条有效用户消息,加上最多
recentMessages - 1条最近消息。消息以 JSON 包裹,避免用户文本破坏分隔符。 - 请求使用会话当前的 provider/model,或可选的
provider/model覆盖。插件没有其它网络请求,也不收集遥测。 - 首条标题一次辅助请求,之后每个完成的 turn 最多一次(受冷却/冻结约束)。标题生成是异步的,不会阻塞主回复;
maxOutputTokens、maxInputBytes、timeoutMs都会约束它。 - 标题作为普通
…(truncated)
Rendered from the README published on npm. Formatted only, not edited.
Versions
Published on npm::9,最后更新 2026-11-03