会话管理:超期会话自动归档(阈值可配),归档面板支持取消归档,删除移入系统回收站可还原。
安装
# npm 包(预构建)
dsh plugin --profile web add @mzzsfy/dsh-session-manager
# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)
dsh plugin --profile web add github:mzzsfy/dsh-plugin#path:/packages/dsh-session-manager
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本——pnpm 默认拦截,所以安装可能停在 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED 或 ERR_PNPM_IGNORED_BUILDS;dsh 会打印出需要添加的确切键名,把它加进该 profile 的 pnpm-workspace.yaml 的 allowBuilds 下,重跑一次即可装上。放行构建本身就是一次信任判断:请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。
README
DeepSeek Harness 会话生命周期管理插件:自动归档 + 归档面板 + 归档删除 + 回收站还原重挂载。
历史输入浮层、插话撤回与对话分叉已迁至独立插件 dsh-context-manager(会话上下文管理);工作区文件夹运行标记见 dsh-turn-notify。
功能
- 自动归档:host 半区对超期会话走官方
workspace.archiveSession通道,三个触发源共用同一评估与门闩:新会话创建(session/created,按该会话所属工作区限定)、settings 就绪后的启动补扫(全量,清掉停机期间积压)、每日周期轮(全量,经宿主 timer 服务固定短 tick + 到期判断)。幂等:已归档会话不参与评估。阈值autoArchiveDays默认 7,0关闭;周期间隔autoArchiveIntervalHours默认 24,0关闭周期轮,变更经周期 tick 对账(关闭即时暂停、重启用最迟下个 tick 生效、缩短经锚定钳制前移,最长等新间隔而非等满旧周期)。评估筛选:createdAt 纯内存预筛 + 已归档跳过 + stat 后活跃度判定,locate 缺失(第三方后端)与产物不可读的会话一律跳过,宁可漏归档不可误归档。经 settings 命名空间session-manager注册(schema 拒绝负数与非整数)。timer 为软依赖:宿主定时服务不可用时仅周期轮停用,面板顶部提示,插件其余能力不受影响。 - 自动归档配置:归档面板「已删除」区下方的配置行,阈值天数与检查周期小时数两个数字输入,失焦或 Enter 单字段即时提交,非法输入前端拦截不发请求,服务端失败回读生效值回滚;读写经本插件
GET/POST /api/session-manager/auto-archive(POST 部分更新,仅接受出现且为非负整数的字段,空字段拒绝),值存宿主 settings 与评估逻辑同源,0= 关闭,GET 返回含默认回退的当前生效值。配置行的行为说明经原生title悬停展示(设置侧栏为滚动容器,CSS 气泡会被 overflow 裁剪,故不做自绘气泡),文案由源码契约测试锁定。 - 归档面板:设置页「会话归档」分区,数据为 client 侧
session.list行 ∩workspaces.follow归档快照的交集,按更新时间倒序;主列表只展开最近ARCHIVE_PAGE_SIZE(100)条,列表尾部「按工作区浏览」按钮直接进入二级视图查看全部(主列表不翻页,防归档集合无限增长拖垮渲染)。二级视图:无搜索词时按工作区分组(组间按组内最新活跃倒序,分组默认收起,展开即见组内首页并可继续翻页,workspace假值并入「未分组」组);输入搜索词后平铺展示标题命中(不区分大小写子串,标题缺失回退会话 id 天然可搜)的全部归档会话并显示匹配计数,同样分页。行内标题前显示所属工作区徽标——映射优先走 workspace 账本(sessionIds,与官方 dsh-client-ui-workspace 的 workspaceBySession 同构),cwd 命中某登记工作区路径时回退该工作区标题(较官方「cwd basename 直接回退」收紧,防未登记目录名冒充工作区),均未命中显示「未分组」;工作区 title 缺失回退路径末段。镜像函数 client 与 core 双实现由 parity 测试锁定。行内支持取消归档与删除。 - 归档与操作通知:host 归档动作经
workspace.follow的archived增量帧到达 client,集合差分得到新增会话,经公共通知依赖@mzzsfy/dsh-toast顶部居中显示带会话标题的文案:单个显示如「会话「修复登录页」已归档」,多个显示「有 N 个会话已归档:标题1、标题2」(N 恒为真实总数),标题数超过TOAST_MAX_TITLES只列前TOAST_MAX_TITLES个并以「 等」收尾,标题缺失、空白或行不存在回退会话 id;host 侧逐会话归档成功时写一条 info 日志(含会话 id)。面板操作(恢复 / 删除 / 重新挂载等)的成功与失败反馈同样经该依赖展示,失败提示常驻待确认。dsh-toast 为普通 npm 依赖由本插件 dependencies 声明随装(表层 manifest 不再单列,装载经 dsh fallback 沿 bundles 依赖闭包补链),其宿主占位条目由本插件 cordis.patch.yml 代挂。 - 删除:仅对已归档会话生效(运行中守卫先于执行,执行前 TOCTOU 复检,运行中的会话不可删除;OS 回收存在数百 ms 异步窗口,复检通过后仍可能恢复运行——此时回收已完成,响应附警告并落服务端日志)。三次确认:击「删除」展示标题 / 日志体积(产物已缺失时以「产物已丢失」替代体积)→ 行内「移入回收站」确认 → 弹窗强提示(说明删除会影响其他插件的工作、若无特殊需求请不要删除,携会话标题,确认后才发请求)。确认后按 locate → 处置 → 台账 → detach → 归档清理单序执行;同 id 并发删除仅首个生效,其余以「正在删除中」拒绝。处置两级:优先移入系统回收站(Windows PowerShell VisualBasic / macOS Finder / Linux gio;Windows 路径经环境变量传入 PowerShell,含空格或特殊字符的路径安全);系统回收站不可用的环境(Docker 容器无 gio / dbus 等)自动降级为插件回收区(
~/.dsh/trash/session-manager,rename 搬移,跨设备 EXDEV 回退复制),仍可经重挂载移回,不做无暂存的永久删除;双失败才会话保留并拒绝。处置成功即写入已删除台账(独立 storage domainsession_manager,读改写经进程内互斥链串行化且单次操作带超时兜底,条目上限 200 裁最旧),记录会话 id、产物原位置与回收区条目的暂存路径;响应附处置模式(os/quarantine),面板成功文案随之区分。产物目录已缺失的会话,仅当已归档或台账有记录(同 id 重删的残留收尾)时跳过处置与台账、仅解除列表关联,提示「产物已不存在,已完成列表清理」;两者皆无的缺失可能是新建会话尚未落盘,直接拒绝以防剥离活会话。 - 已删除分区与重挂载:面板「已删除」区列出台账条目(标题 / 原位置 / 删除时间)。OS 回收站条目:用户在系统回收站将会话文件夹还原到原位置后点「重新挂载」;回收区暂存条目(heldPath)重挂载自动把产物从回收区移回原位置再挂载,无需手工搬移。挂载经官方
workspace.attachSession并清除台账;「移除记录」幂等清除单条。系统回收站的还原动作始终由用户在回收站完成,插件不驱动系统回收站。
回收站还原与重新挂载
删除移入系统回收站的是会话产物目录,「原位置」形如 C:\Users\<你>\.dsh\sessions\--<工作区路径编码>--\<会话id>\(工作区目录名由宿主对 cwd 做编码,非裸路径;目录内是 session.jsonl.zstd 日志)。辨认以面板「已删除」区记录的原位置为准,无需理解编码规则。
插件回收区条目(环境无系统回收站时降级产生):产物暂存于 ~/.dsh/trash/session-manager,无需手工搬移——直接点「重新挂载」,插件自动把产物移回原位置后挂载。
0.1.3 版本删除的条目回收的是日志文件
session.jsonl.zstd而非目录:还原该文件即可(目录本身未被移除),还原后同样走「重新挂载」。
还原步骤(系统回收站操作):
- Windows:打开桌面「回收站」→ 按「原位置」列(含
.dsh\sessions\)或名称(会话 id)定位目录 → 右键「还原」。 - macOS:打开 Finder「废纸篓」→ 选中会话目录 → 右键「放回原处」。
- Linux(GNOME Files):打开「回收站」→ 右键「还原」;命令行
gio trash --restore。
还原后回到面板「已删除」区点「重新挂载」:会话经官方通道挂回工作区,重新出现在会话列表。注意事项:
- 未还原(持久层读不到产物)时重挂载直接拒绝,提示先还原。
- 还原后重挂载提示「未找到会话所属工作区」:插件按会话 cwd 匹配工作区失败,通常是原工作区目录已删除或更名。
- 清空回收站后产物永久丢失,台账条目仅剩记录价值,应「移除记录」。
- 只还原产物而不重挂载:数据在磁盘上,但会话不会自动回到工作区列表(删除时已 detach)。
失败矩阵
| 失败点 | 表现 |
|---|---|
| locate 返回 undefined(SQLite 等后端) | 拒绝执行,提示后端不支持,无副作用 |
| 产物目录已缺失(且已归档或台账有记录) | 跳过归档资格 / 回收 / 台账,仅 detach 与归档清理,提示「产物已不存在,已完成列表清理」;清理半失败转 partial 并聚合失败点,重试即补全 |
| 产物目录已缺失(未归档且无台账记录) | 拒绝执行(可能是新建会话尚未落盘,剥离活会话属破坏性误删),无副作用 |
| trash 失败、回收区搬移成功 | 降级为插件回收区暂存(容器无 gio / dbus 等场景),台账记录暂存路径,响应 mode=quarantine;原始回收站错误落服务端日志;重挂载时自动移回原位置 |
| trash 失败、回收区搬移也失败 | 整体中止,提示系统回收站与插件回收区均不可用(携回收区错误),目录与台账未动,可重试 |
| trash 成功、detach 失败 | 视为已删除,提示「已移入回收站,但移除列表记录失败」;还原前重试将走产物缺失路径完成列表清理(台账保留),或还原后走「已删除」区重挂载 |
| trash 成功、归档清理失败 | 已删除但归档集合残留,提示「已移入回收站,但移除归档记录失败」;经取消归档重试清理(幂等) |
| trash 成功、台账写入失败 | 已删除,提示「已移入回收站,但重挂载记录失败」,其余步骤照常完成 |
| 重挂载、产物未还原(OS 回收站条目) | 拒绝,提示先到系统回收站还原,无副作用 |
| 重挂载、回收区暂存已缺失(原位置亦无产物) | 拒绝,提示暂存缺失无法找回,无副作用 |
| 重挂载、台账域打开失败 | 入口即拒绝(移回依据不可得,不做静默跳过),无副作用 |
| 重挂载、无匹配工作区 | 拒绝,提示未找到会话所属工作区,无副作用 |
| 重挂载、attachSession 失败 | 拒绝并透出原始错误,台账保留供重试 |
| 重挂载、挂载后台账清除失败 | 挂载已生效,提示 partial「已重新挂载,但清除台账记录失败」,经「移除记录」收尾 |
| trash 执行期间会话恢复运行 | 回收已完成,响应附警告「回收期间会话恢复运行」并落服务端日志;建议检查会话状态(agent 写入已断裂) |
| 台账操作超时(存储域挂起) | 单次读改写超 10s 按失败降级(同「台账写入失败」),互斥链不死锁,后续操作可重试;超时写操作后台落盘仍安全(幂等语义) |
多个失败点并发时按 detach > 归档清理 > 台账的优先级聚合透出:前两者的 partial 消息末尾追加「,且重挂载记录失败」。
已知取舍
- 取消归档:官方 workspace registry 明确归档为 one-way,无移除 API。本插件经
storageDomain.get('workspace')的 global 句柄直写archivedSessionIds(写入经domain/changed驱动 follow 帧),并把注册表进程内快照registry.state同步为写后值——注册表只在自身写路径同步该快照,不同步则其后续全量写回与workspace.list重连基线会复活刚移除的 id,官方归档的幂等判定也会因旧快照静默跳过(即早期版本「取消归档后列表不消失 / 二次归档不出现」的根因)。合并 durable 与快照取并集后再移除:可自愈历史失同步与清理半失败(经取消归档重试即补全),代价是快照中的陈旧 id 会在任一次清理时随全量写回重新落盘,可经再次取消归档清除。registry.state为上游内部字段,缺失即路由报错 loud fail(注册表未就绪或上游形态变更)。域 global 仅支持整体写回,读改写窗口若与注册表两阶段变更交错,理论上可回退其 pendingMutation/workspaceIds 中间态,下次启动校验将 loud fail;同理,恢复操作与进行中的自动归档评估并发时,评估携带的旧快照整包写回也可能复活刚移除的 id,再次恢复即可清除——窗口极窄且域 API 无原子原语可用,属已知取舍。 - 删除:成功路径在 detach 后同样从归档集合移除该 id(域与快照同步),清理失败响应 partial 提示;detach 失败时不清理归档集合,保留归档资格供重试。删除后
session.list的会话行按官方语义仅在宿主发出session/disposed(经api-session/removed)时移除;官方SessionStore无按 id dispose 的公开 API,本进程内打开过的会话被删除后,其列表行会以「未分组」形式残留,直至宿主重启(重启后 live 记录清空,持久层扫描因产物缺失自然不再列出)。残留行仍可再次执行删除:产物缺失路径即为此设计,完成列表关联清理并提示。重挂载复用该语义:删除后会话行短暂残留在 client 会话模型,「已删除」区标题在重连前显示原标题,重连后回退会话 id。 - 已删除台账:独立 storage domain
session_manager(global 单列表),非 workspace 域、非审计层——存在意义仅为重挂载定位产物原位置。trash 成功即记录(位于 detach 前),台账失败仅降级重挂载便利,不回滚删除;同 id 再次删除替换旧条目。台账读改写经进程内互斥链串行化(并发删除不再有丢更新窗口),条目上限 200、超出裁最旧,防无界增长写放大。台账不随产物还原自动清除,以「重新挂载」或「移除记录」收尾;清空回收站后的残留条目无恢复价值,应手动移除。 - 评估的活跃时间:JSONL 后端以产物 mtime 作为最近活跃代理,updatedAt = max(createdAt, mtime);非 JSONL 后端退化为 createdAt。评估两级筛选:先用 createdAt 纯内存预筛(mtime 只会增大 updatedAt,createdAt 未超期必不超期),仅对预筛存活者做产物 stat / blank 探测,活跃会话零 IO。空白判定:live 会话 seq=0,冷会话以 JSONL 产物「仅 header 一行」判定,locate 不可用的后端按非空白处理。评估整体带超时兜底(宿主服务挂起时门闩必然复位,不会永久停摆);单会话归档失败仅告警不中断整轮。
- 无批量操作、无正文内容搜索(归档库仅标题子串检索)、无会话详情预览。
- 归档库的组织与检索:分组键为行投影的工作区标题,同名标题的不同工作区在库视图合并为一组(行投影不含工作区 id,不为分组扩展投影公共形态);搜索仅匹配标题,不做正文全文检索(正文搜索属后续独立任务);分页粒度 100 为统一常量(
ARCHIVE_PAGE_SIZE),搜索命中与组内展开共用同一分页机制,主列表固定首页不翻页;视图切换、展开与搜索状态均为面板内存态,离开设置页即复位,不做持久化。 - 自动归档评估门闩:评估进行中其他触发源(含周期轮与 session/created)的新触发直接丢弃,不做排队;漏掉的会话由下一次触发兜底,启动补扫与每日周期轮保证了积压会话最迟一个周期内归档。产物不可读(mtime 探测失败)的会话视为已删除,不参与归档,防止删除后的会话被重新归档复活。subagent 内部会话(
origin: 'subagent')永不参与归档:官方主列表即以 origin 排除 subagent(归档集合仅服务用户会话),误归档只产出无 title 回退 cwd 名的不可辨认面板行与无意义通知。timer 软依赖:宿主定时服务缺失或调用失败时周期轮停用,设置页显示降级提示(session/created 触发与启动补扫不受影响);timer 服务晚于插件激活时周期轮自动补武装。 - 归档提示以「连续两个 ready 快照」为差分启用条件:基线首装(启动与重连)不提示存量,重连基线携带的离期新增仍会提示。通知展示经公共依赖
@mzzsfy/dsh-toast(external require),本包不再自带通知 UI。client.js 为单文件自包含格式,守卫逻辑与 core.mjs 各存一份镜像,修改需两处同步(projectRows / archiveToastStep / projectDeletedRows / pageArchiveRows / groupArchiveRowsByWorkspace / filterArchiveRows 同规);test/parity.test.mjs 对各组镜像做行为级对照并锁定 client 侧确认态文案与 host MESSAGES 同值。client 已删除列表加载失败时保留旧数据并 console.warn,不渲染成「无记录」。路由错误响应:业务错误原样透传中文文案,系统级错误(带 fs 错误码,message 内嵌绝对路径)收敛为固定文案并落服务端日志。header 查找走 ctx 级 TTL 缓存(归档/删除/重挂载路由不每次全量扫描 listSessions)。 - 重挂载的并发窗口:attachSession 后、台账清除前进程中断,残留条目重挂载时因官方 attachSession 幂等(已在 sessionIds 中则跳过校验直写)无副作用,再次点按或「移除记录」即可收尾。台账域打开失败时已删除 / 重挂载 / forget 以 400 拒绝;删除路由走 partial 降级(其余步骤照常,提示「已移入回收站,但重挂载记录失败」),不做无台账中断——产物进回收站后中断删除只会造成状态不一致。
- 测试基建:trash 与回收区搬移/移回为进程级 OS 副作用出口,经
executor(trashPath / moveToQuarantine / restoreFromQuarantine)注册表注入,删除全流程(OS 回收站成败 / 回收区降级 / 台账成败 / 归档清理 / 重挂载移回)有路由层覆盖。EXDEV 分支经 fs 注入桩测试(真实跨设备场景难以在测试中稳定构造)。 - 删除降级的已知取舍:系统回收站任意失败(不限命令缺失,含 dbus 不可用、权限拒绝)都触发回收区降级——按错误类别区分收益低、降级后仍可还原;回收区目录
~/.dsh/trash/session-manager不自动清理(与系统回收站同责,由用户清空),重挂载移回成功后暂存条目随台账清除,但已移回前的重复暂存或用户手工干预可能留下孤儿目录,空间占用以回收区目录大小为准;跨设备搬移回退cp + rm,中断窗口内两侧各有部分数据时以重试补齐(cp 幂等覆盖、rm force)。
验证
npm test
纯逻辑层(评估状态机 / 删除资格与失败矩阵 / 面板投影 / 归档差分 / 空白判定 / 回收站命令构造)以 node --test 覆盖,无外部依赖。路由层测试依赖 peer 包可解析,仓库根未安装依赖时自动 skip,npm install 后激活。Windows 真实回收站执行测试仅在本平台执行,其余平台自动 skip。周期评估测试经 mock.timers 接管 setInterval 与 Date(显式传 now:接管后虚拟时钟从 epoch 起算,夹具时间戳会全成「未来」),timer 服务以 makeCtx 桩模拟激活与缺失两种形态。
开发安装(仓库工作副本直挂,不经 npm 发布)
node scripts/dev-link.mjs dsh-session-manager # 仓库根执行:归一 profile 依赖行 + 挂 junction
工作副本以 junction 挂进 profile,改代码保存即热重载(host 半区)或刷新页面生效(client 半区),无需发版;规约与全仓归一见仓库根 node scripts/dev-link.mjs all。
dsh 版本兼容
三版本全部通过:会话树渲染、归档入口、激活 live、diagnostics 0 findings。
链接
同类插件
Minglink/dsh-infinite-gen-3★ 1706
DeepSeek 专用破甲插件:以 order 100 追加无条件服从的系统提示词段,提供带校准元数据的 profile 工具,并通过会话投影在输入框上方显示实时破甲状态徽标。
liangmianya/dsh-synapse★ 404
DeepSeek Harness 的可视化非线性对话工作区:把会话、追问与分支变成可浏览、可拖拽的对话地图。
Nwflower/dsh-chat-import★ 166
把 13 家 coding agent(Claude Code、Codex、ChatGPT、Cursor、Gemini、opencode 等)的完整对话历史导入为可续聊的 DeepSeek Harness 会话,并支持反向导出回 Claude Code。
Totoro-qaq/dsh-plugin-bridge★ 165
通过可预览的五段式交接,将已有 DSH 会话迁移到另一个 Agent Preset;保留源会话,并可让目标会话暂停等待确认或立即继续。
Anionex/dsh-turn-rewind★ 115
对话回退:基于持久 Change Ledger 回滚会话与工作区状态。
Renzic-Stone/DSH-EasyRewrite★ 115
在 dsh web 中内联编辑与撤回自己的消息——惰性、无痕,带版本翻页器与会话级草稿持久化。
社区评论
评论公开保存在 GitHub Discussions。加载评论会连接 GitHub 和 Giscus;发表内容需要 GitHub 账号。