linanbuan/dsh-archive-manager ↗★ 0
@local/dsh-archive-manager
归档会话管理 · Archived sessions — DeepSeek Harness (DSH) 设置面板:列出本机全部已归档会话,逐条复原回工作区,或连同日志文件与投影缓存永久删除。 A DSH settings panel that lists archived sessions and either restores one into its workspace or deletes it from disk for good. 在设置中提供归档会话的统计、恢复与彻底清理功能,适合需要释放磁盘空间的用户。
インストール
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:linanbuan/dsh-archive-managerドキュメント
README 全文を読む ↗归档会话管理 · dsh-archive-manager
DeepSeek Harness(DSH)桌面端的设置面板插件:把本机所有已归档会话集中到一页, 逐条复原回工作区,或连同会话日志与投影缓存永久删除。
已归档的会话从项目列表里消失,而 DSH 没有任何界面管理它们。这个插件补上那一页: 每条会话给出标题、所属项目、占用大小、创建与最后写入时间、它在磁盘上的位置, 以及两个动作 —— 复原回工作区,或从磁盘上永久删除。
- 位置:设置 → 归档会话管理(排在所有内置页面与其它插件之后,
settings.section的order: 100) - 行 id:
archive-manager - 依赖:无(零运行时依赖,浏览器半部只
require('react'))
页面内容
- 顶部统计:已归档 / 可删除 / 运行中 / 磁盘占用 / 数据时间。
- 每一条会话:会话标题、所属项目、占用大小、创建时间、最后写入时间、磁盘目录(
~/.dsh/...形式)。 - 每条的按钮:复原回工作区 与 永久删除(行内二次确认,不是弹窗)。
- 操作结果条:列出本次真正被移除的路径,而不是只说「已删除」。
两个操作的确切含义
| 操作 | 做了什么 | 能撤销吗 |
|---|---|---|
| 复原回工作区 | 调用 ctx.workspaceRegistry.unarchiveSession(id):把该 id 从归档集合移除。会话一直保留着它在工作区里的记账槽位,所以它会回到原来的项目与位置。 | 可以再归档回去 |
| 永久删除 | ① 删除会话日志目录 ~/.dsh/sessions///;② 删除投影缓存 ~/.dsh/storages/session_projcache/sessions/.json;③ 调用 unarchiveSession(id) 归位记账,并广播 api-session/removed 让侧栏立刻收起该行。 | 不能。Harness 没有任何恢复入口 |
为什么删除必须由本插件自己做
DSH 的会话存储接缝是故意不可寻址的:ctx.sessionPersistence 的快照只给 header 与不透明的 revision,不给文件路径,也没有任何删除方法;ctx.workspaceRegistry 的文档写明 "Removal never deletes data"。所以「永久删除」不是一个已存在的 API,而是本插件在自己推导出的路径上执行的文件系统操作。
这意味着安全边界必须自己建立。本插件的做法:
- 唯一输入是会话 id,不是路径、不是 cwd。浏览器无法指定要删的文件。
- 路径由 lib/layout.js 按 DSH 自带 JSONL 后端同一套规则推导:
projectKey(cwd)与encodeSegment(id),并用本机真实的项目目录名核对过(见 test/selfcheck.mjs)。 - 删除前逐条证明,任何一条不成立就拒绝(返回业务错误码,不删任何东西):
- 该 id 必须在归档集合中(
NOT_ARCHIVED); - 该会话不能仍在本进程打开或运行(
SESSION_LIVE); - 路径必须严格位于
$DSH_HOME/sessions之内(OUTSIDE_ROOT); - 路径必须恰好是「项目层/会话层」两级(
MISPLACED); - 两级目录名必须等于由该会话 header 推导出的名字(
PROJECT_MISMATCH/ID_MISMATCH); - 目录里必须真的有会话日志文件(
NOT_A_SESSION_DIRECTORY)——否则按「看不懂的目录」处理。
- 该 id 必须在归档集合中(
- 归档集合的记账在最后一步才更新:中途失败时该会话仍然是「已归档」,不会从界面上凭空消失。
数据来源
| 用途 | 来源 |
|---|---|
| 有哪些已归档会话 | ctx.workspaceRegistry.archivedSessionIds(~/.dsh/storages/workspace.json) |
会话 header(cwd / createdAt) | ctx.sessionPersistence.list() + ctx.get('sessions').list() |
| 标题 | ctx.sessionQuery.readTitleSnapshots(ids):每项 value.title 是折叠快照 { title, messageSeqs, source, eventSeq, updatedAt },本插件取它的 title 字段(逐会话失败隔离;12s 超时后本页仍返回,只是没有标题) |
| 所属项目 | ctx.workspaceRegistry.list() 的实体;缺失时退回 header 的 cwd 末段 |
| 大小 / 最后写入 / 是否在磁盘上 | 插件自己 stat 会话目录里的 session*.jsonl(.zstd) |
页面上显示的路径一律是 ~/.dsh/... 或 $DSH_HOME/... 形式(与 dsh-home-paths 的展示约定一致),不把本机绝对路径送给浏览器。
安装
本插件是一个标准 DSH bundle:package.json 里声明了 dsh.bundle.patch 与 dsh.client,装进任何 profile 都走同一条路。先装好 DSH 桌面端(deepseek.com/download),然后下面任选一种。
方式一 · 在 DSH 桌面端里装(推荐)
- 侧栏点 插件 → 添加插件(Add plugin);
- 在输入框里填下面任意一种 spec:
- 本仓库地址:
https://github.com/linanbuan/dsh-archive-manager - 本仓库的压缩包链接(GitHub 页面的
Source code (zip)) - 已经克隆到本机的目录绝对路径
- 包名(若将来发布到 npm)
- 本仓库地址:
- 点 安装:Harness 先读出这个 spec 指向什么(包名、简介、版本),确认后开始装;
- 装完点 立即启用。
整个安装由 Harness 自己的插件管理器完成:把这个包写进当前 profile 的 dsh.profile.bundles,并挂上宿主半边。桌面端装插件不需要命令行,也不需要手改 profile 文件。
方式二 · 让 Agent 自己装
把仓库地址或本机目录直接交给任意会话里的 Agent,它会调用 plugin_manager 工具(action: install_bundle)走同一条路。这是官方给第三方插件推荐的安装方式。
方式三 · 命令行
装了 dsh CLI 的机器上:
dsh plugin --profile
add
`` 与方式一相同(包名、Git 地址、压缩包链接或本地路径);参数以 dsh plugin --help 的实际输出为准。
方式四 · 手工装进某个 profile(排障用,不推荐)
profile 目录默认在 ~/.dsh/profiles/ 。把包放进去,并在 profile 自己的 package.json 里登记两处:
"dependencies": { "@local/dsh-archive-manager": "link:" },
"dsh": { "profile": { "bundles": [ "…", "@local/dsh-archive-manager" ] } }
手改 profile 文件要过权限审批,写坏会让 Harness 起不来,所以正常安装请走前面三种。
装上之后
- 浏览器半边:注册
settings.section页面,随启动图加载;由 HMR 更新时不需要刷新页面。 - 宿主半边:注册三条
/api/archive/*路由。安装时若提示需要重启,重启 DeepSeek Harness 应用(不是刷新页面)—— 桌面 profile 的 base 组合包以root: []启用 HMR(只监听显式注册的配置),而 HMR 的忽略规则默认含**/node_modules,装在node_modules下的插件代码不在监听范围内。 - 确认它在跑:侧栏 插件 → 找到这个包,看组件状态是否为「运行中」。
停用 / 卸载
临时关掉(在 profile 自己的 cordis.patch.yml 里,或直接用插件页那一行的开关):
- id: archive-manager
disabled: true
彻底移除:插件页 → 这个包 → 卸载,它会把包从 profile 的依赖与 dsh.profile.bundles 里去掉。
注意事项
- 本插件不是官方插件:与 DeepSeek AI 无任何关联,不提供服务承诺。它跟随 Harness 的插件接缝工作,Harness 升级后可能失效;失效时页面会以错误码或空列表的形式退化,不会影响 Harness 本身启动。实测环境是 DSH
0.1.7-rc.2桌面版(Windows):它依赖的connection/workspaceRegistry/sessionPersistence/sessionQuery/sessions都是内部实现,不是稳定 API,换版本后可能改名或改形。 - 运行中的会话不能永久删除:它可能还有正在写入的内容。先关闭该会话(或重启应用)再删。界面会把这类行标出「运行中」并禁用删除按钮。
- 删除没有回收站:这就是「永久」的含义,插件与 Harness 都没有恢复入口。删之前请确认这些会话不再需要。
- 只影响本机这一份
$DSH_HOME:删除是本机文件系统操作,不会同步到其它设备,也不会动云端的任何东西。 - 安装后不会自动更新:官方插件管理器目前不支持自动更新,升级=先卸载再装新版。手动替换已安装的包之后,宿主半边要重启应用才会加载新代码(Node 的 ESM 缓存按文件 URL 命中,停用再启用只会重跑旧模块的
apply())。 - 归档记录与日志可能不同步:若某条归档记录已经没有对应日志(被其它工具清过、或换过机器),本页仍会列出它,标「仅归档记录」,并允许把它从归档列表里移除(不删任何文件)。
- 标题依赖会话日志折叠:日志损坏或超时只会让该行退化成「(无标题)」,不影响复原与删除。
- 权限:删除走的是 Harness 进程自己的文件系统权限。若
$DSH_HOME放在需要提权的目录下(例如以管理员身份运行的应用、被安全软件锁定的目录),删除可能以EACCES/EPERM失败 —— 此时插件如实报错,不会假装成功。 - 平台:只要 DSH 能跑(Windows / macOS / Linux)即可用。路径推导对 Windows 的
C:\…cwd、中文与空格目录名都有对应用例。 - 隐私:插件不联网、无遥测,不上报任何会话内容;它只在 Host 侧读本机文件与 Harness 自己的服务,浏览器半边拿到的只是这一页要显示的数据。本仓库自身也不含凭据、会话内容或个人绝对路径 —— 示例路径都已泛化。
自检
node test/selfcheck.mjs # 或 pnpm test
自检不需要网络、不需要 Harness、不需要 React:Host 半边在临时 $DSH_HOME 里跑真实的建目录 / 删目录流程,浏览器半边在一个 stub window.__ModuleLoader__ 里完成注册,最后一节用一个最小 hook 运行时真的驱动页面(渲染 → 跑 effect → 点按钮 → 再渲染)。它覆盖 19 项,全部通过时打印 19/19 checks passed 并以 0 退出,任何一项失败就以非 0 退出(可直接接 CI)。覆盖内容包括:
projectKey/encodeSegment对真实目录名的还原(含中文与空格转义);- 六条删除前置条件都会拒绝:
OUTSIDE_ROOT/MISPLACED/PROJECT_MISMATCH/ID_MISMATCH在路由上按构造不可达,由路由直接调用同一个判定函数来验证;「拒绝时目录原封不动」的断言落在路由层那三条(NOT_ARCHIVED/SESSION_LIVE/NOT_A_SESSION_DIRECTORY)上; - 正常删除确实同时移除了日志目录、投影缓存与归档条目;
- 复原不动日志、只动归档集合;
- 畸形请求体、缺少注册表的组合等边界;
- 客户端只
require('react')、样式只装一次、settings.section注册为order: 100、zh/en 字典键一致; - 按下某一行的「复原回工作区」后,POST body 里是该行的 id(而不是
{}),随后列表按新快照少一行、结果条写着标题; - 一行拿不到 id 时只在页面内提示,绝不向 Host 发空 body;
- 按
dsh-client-connection的 bridge 形态发 POST(Buffer请求体 +application/json; charset=utf-8)时 id 不丢; { id: undefined }(客户端旧缺陷的产物)会得到字面量缺少会话 id。。
它不能证明的部分:自检跑在桩上下文上,不是真的 Harness —— /api 通道的会话鉴权与 Host/Origin 检查、真实 sessionQuery 的折叠口径、真实 settings.section 的渲染与样式回落,都不在覆盖范围内;删除只在临时 $DSH_HOME 里发生,没有在真实 profile 上跑过。
结构
package.json bundle 清单(dsh.bundle.patch + dsh.client)
cordis.patch.yml 一行 insert:装载 Host 半边
index.js Host 半边:三条 /api/archive/* 路由与全部安全判定
client.js 浏览器半边:settings.section 页面(手写 lazy CJS,只用 react)
lib/layout.js DSH 会话存储布局的移植(projectKey / encodeSegment / 路径推导)
locale/{zh,en}.json 插件卡片文案
icon.svg 插件图标
test/selfcheck.mjs 自检
致谢与第三方许可
- 本插件只使用 Harness 自己的公开接缝(
connection、workspaceRegistry、sessionPersistence、sessionQuery、sessions)与 Node 内置模块,没有复制或改编任何第三方插件的代码。 - 会话存储布局的规则(项目键与 id 分段的编码方式)是照着 DSH 自带 JSONL 后端的行为重新实现的,属于与官方实现的接口兼容,不包含官方代码副本;官方包许可为 MIT。
- 页面样式只用主题令牌(
--dsw-*)与自绘控件,没有require官方客户端包,也不需要它们的代码。
License
MIT © 2026 linanbuan