dsh-session-title-stamp

sessiontested: passnpmMIT

Keeps DSH session titles in DATE | CATEGORY | NAME with turn-aware auto-retitle, a settings page, and hover duration/cost/token stats.

下载量 / Downloads
1,601
依赖体积 / node_modules
6.91 MB
测试时间 / Tested
2026-11-06
DSH 版本 / Version
0.2.2-rc.1

Install

dsh plugin --profile web add dsh-session-title-stamp

Sandbox test results

StageResult
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

Links

GitHub · Homepage · npm

Same category