Sky-lll27/DSH-chat-keeper ↗★ 1
dsh-conversation-manager
DeepSeek Harness(DSH)对话管家:跨工作区总表、正文搜索(中文子串 / 未打开的旧对话也能搜 / 定位到命中那句并读出上下文)、按时间批量归档,以及 DSH 界面没有的磁盘层面删除(回收站式,可恢复)。 适合有大量历史会话,需要跨工作区深度搜索、批量整理和安全删除的用户。
Other repositories with this package name
Install
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:Sky-lll27/DSH-chat-keeperREADME
Read the full README ↗使用
页签正文是一张跨工作区的会话总表:
- 顶部:正文搜索框、
共 N 个 · M 运行中 · K 已归档、时间筛选下拉(全部 / 7 / 30 / 90 天前的)、「显示已归档」开关、全选。 - 「显示已归档」开关(默认打开,与历史行为一致):关掉后总表里不再列出已归档的对话,
顶部统计仍如实报告归档数,旁边补一个
符合条件 N 个说明当前可见几条。 选择写进localStorage,面板重开后保持。 两条边界:只管总表——搜索结果不受它限制(搜到什么就显示什么,否则会被当成"搜索坏了"); 关掉期间无法从总表批量「取消归档」,需要时把开关再打开即可。 - 表格:勾选框、状态点(运行中 / 等待交互 / 已完成未读 / 空闲)、标题、工作区、最近活动。 点击标题可打开该对话。
- 勾选后出现批量条:
归档/取消归档/删除所选/清除。 归档自己就能完成;若某行仍有工作在进行,会先弹出「停止并归档?」确认。 - 搜索时:表格被命中的对话替换(每条带工作区、状态与高亮摘要),可一键复制结果清单。
- 底部:回收站一览(批次数、批次名、条数、大小)与「刷新」。
搜索对话正文
搜索有两条路,能力不一样——先说清楚各自的边界(都经真机实测):
| DSH 原生侧栏搜索 | 本插件面板搜索 | 本插件工具搜索(conversation_search) | |
|---|---|---|---|
| 匹配标题 / 工作区名 | ✅ 立即 | 表格里直接看 | ✅ |
| 匹配对话正文 | ✅ 但默认是关的(见下) | ✅ 走同一个索引 | ✅ 而且读磁盘,冷对话也能搜 |
| 中文子串(如在一整句里搜「检索」) | ✅ 装了本插件后(宿主侧字面兜底,见②);没装插件时按词元匹配 | ✅ 同一条兜底 | ✅ 字面子串,中文无障碍 |
| 结果条数 | 最多 20 个会话(宿主服务端就截到 20) | 同一上限,不承诺更多 | 默认 10(可调到 50),扫描范围另受时间预算约束 |
| 摘要片段 / 高亮 | 有片段、无高亮 | ✅ 片段 + 关键词高亮 | ✅ 片段 + 命中次数 |
| 复制结果清单 | ❌ | ✅ | ❌(结果直接回给模型) |
① 为什么"正文搜索默认是关的":dsh-base 与 dsh-web-app 两个组合包都把内容索引
session-query-sqlite 设成 openAt: never。此时 ctx.sessionQuery 虽然挂着,但一调用搜索就
失败,界面静默退化成只匹配标题与工作区名(官方文档原话:"内容搜索失败时,元数据匹配项
仍会显示,不另给警告")—— 所以"搜不到正文"的体验,真实原因是索引没打开,而不是缺功能。
本插件的组合包 patch 替你把它打开(openAt: first-search,默认内存索引不落文件)。
② 中文子串原来为什么搜不到,现在怎么补上的:这个索引建在 SQLite FTS5 上,
分词器 unicode61 写死在建表语句里,查询又被包成一个字面短语送进 MATCH。
unicode61 把连续字母串当一个词元:英文单词天然被空格隔开,所以英文搜得准;
中文整句连成一片,只有查询词正好等于被标点或英文切出来的那一段时才命中。
实测(同一份索引,未装本插件时):
| 查询 | 结果 |
|---|---|
session(英文) | ✅ 命中 |
"内容检索示例"(整段中文) | ✅ 命中 |
"检索"(中文子串,原文是「内容检索示例」) | ❌ 0 条 |
0.5.1 起:本插件在宿主侧把网关的搜索入口 sessionController.search 包了一层
(ctx.sessions 是会话存储,不是同一个对象——0.5.0 包错了对象、补丁从未被调用,
工程笔记里记了这次返工);查询里含中日韩文字时,
额外读一遍磁盘日志做字面子串扫描,把命中的会话合并进结果。因为官方放大镜与
本插件面板走的是同一个入口,所以两处一起变好;纯英文查询连扫描都不触发,
错误语义(比如"索引没打开")也原样保留。不改 DSH 的任何文件。
边界照实说:
- 兜底是尽力而为:默认时间预算 2 秒、最多读 120 个对话(按最近活动倒序), 超预算只返回已经扫到的,不假装"搜完了";
- 官方结果始终排在前面,兜底只往后面补,不改变官方的排序与授权过滤; 两边都有的会话保留官方片段;
- 扫描是同步读日志(与工具同一实现),中文查询时界面可能有轻微停顿;
调小
cjkSearchBudgetMs或设cjkSearch: false可以关掉; - 这是运行时包一层宿主方法。DSH 升级若改了
sessionController.search的返回形状, 兜底会自动退化成官方行为(形状不认识就原样返回 + 记一条 warn),不会把搜索搞坏。
工具那条路仍然不同(也仍是能力最全的):它直接读会话日志(多帧 zstd 逐帧解压)
做字面子串匹配,返回命中 seq / 事件类型 / 前后原文与命中次数,
扫描范围与预算可调,结果直接给模型用。用法就是跟模型说:
「帮我搜含『某个关键词』的对话」
工具自带三道刹车:最多读 max_conversations 个对话(默认 60,按最近活动倒序)、
时间预算 budget_ms(默认 5 秒)、结果上限 limit。超出预算时结果里会如实标注
diskTimedOut,而不是假装"搜完了没有"。
想要持久化索引(重启后不必重建)就把组合包 patch 里那行的
path从:memory:改成真实路径, 例如$DSH_HOME/storages/session-search.db;它只是派生数据,随时可删、删了会自动重建。
关于删除:为什么是"复制指令"
删除与恢复是宿主的磁盘操作,而浏览器半没有文件访问权。DSH 只允许浏览器半通过
生成的 Remote 命名空间与宿主通信;外部插件要声明自己的 Remote 需依赖内部包,代价不小。
因此面板负责选择,「删除所选」把一条带确切会话 id 的指令复制到剪贴板,
粘贴到输入框发送即可,由宿主的 conversation_delete 执行。
这样做的两个好处:不会偷偷往你的对话里发消息;指令带确切 id,不会误删。
刷新:让原生侧栏立刻少掉已删的行
删除发生在磁盘上,宿主不会为此推事件,客户端只在重连时重拉会话列表 ——
所以删完之后原生侧栏里的行会一直留着,直到重连或重启。
面板的「刷新」调用 sessions.refresh() 重新拉取列表基线,顺手也重读回收站;
打开面板时也会自动重拉一次。所以:删完点一下「刷新」就够了,不必重启。
配置
config 全部有默认值,不传也能用:
| 键 | 默认 | 说明 |
|---|---|---|
maxTracked | 500 | 索引最多保留多少条记录 |
titleMax | 80 | 自动标题的最大字符数 |
persistPath | ''(关闭) | 非空时把索引快照写入该文件,重启后仍能看到历史对话元数据 |
saveDebounceMs | 1000 | 写盘防抖间隔 |
trashMirror | true | 是否把回收站概览写进各存活会话的工作区(/.dsh-conversation-manager/trash.json),供面板显示。镜像只含批次名/时间/条数/大小,不含正文或标题;设为 false 则不往你的工程目录写任何文件(连下面的状态快照一起停) |
statusFile | true | 是否把宿主状态快照(/.dsh-conversation-manager/status.json)写进各存活会话的工作区:只有插件版本、补丁装在哪些对象上、扫描计数,不含任何对话内容或你的输入。想知道"中文兜底到底装上没有"就看它 |
cjkSearch | true | 中文(中日韩)查询的字面兜底:查询含 CJK 文字时额外扫一遍磁盘,把命中的会话合并进官方结果——官方放大镜与本插件面板同时受益。设为 false 则完全交还给官方索引(英文查询本来就不触发) |
cjkSearchBudgetMs | 2000 | 兜底扫描的时间预算(毫秒)。扫描是同步读日志,预算越大、中文查询时可能顿得越久 |
cjkSearchMaxConversations | 120 | 兜底最多读几个对话(按最近活动倒序,先搜最可能相关的) |
- insert:
- id: conversation-manager
name: 'dsh-conversation-manager'
config:
trashMirror: true