🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

会话删除 SereinHK/dsh-plugin-session-delete

DeepSeek 客户端
SereinHK35 天前有提交已提供中文文档扫描:含敏感能力兼容 / 相关生态

从磁盘永久删除对话,并批量清理空会话

29.9/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/1 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

相关生态插件(非 dsh 原生,按其对应运行时安装)
git clone https://github.com/SereinHK/dsh-plugin-session-delete.git

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:待复验
是什么[目录]—
生态应用
桌面端 / Web 外壳,不以 dsh plugin add 安装
暂无时间戳·判据 →
装得上吗[实装验证]—
曾在 dsh 0.2.0-rc.2 下真实安装成功,但当前 dsh 已更新至 0.2.1-rc.5,本站尚未在新版下复验
L4 · 真实安装等级说明 →
数据截至 2026/10/01·判据 →
安全吗[自动扫描]—
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
数据截至 2026/11/05·判据 →
还在维护吗[仓库]—
更新放缓:最近一次提交在 35 天前
暂无时间戳·判据 →
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →

可信度证据

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

读写/删除本地文件发起外部网络请求
查看扫描证据(共 55 处,展示前 35 条)
  • 读取本地文件
    lib/index.js:374
    const entries = await readdir(directory, { withFileTypes: true })
  • 读取本地文件
    lib/index.js:378
    total += (await stat(join(directory, entry.name))).size
  • 读取本地文件
    lib/index.js:505
    const raw = await readFile(trashPaths(root, sessionId).record, 'utf8')
  • 读取本地文件
    lib/index.js:542
    names = (await readdir(base)).filter((name) => name.endsWith('.json'))
  • 读取本地文件
    lib/index.js:577
    const files = (await readdir(directory, { withFileTypes: true })).map((entry) => entry.name)
  • 读取本地文件
    lib/index.js:579
    for (const entry of await readdir(directory, { withFileTypes: true })) {
  • 写入本地文件
    lib/index.js:584
    await mkdir(paths.directory, { recursive: true })
  • 删除本地文件递归
    lib/index.js:585
    await rm(paths.directory, { recursive: true, force: true })
  • 写入本地文件
    lib/index.js:586
    await rename(directory, paths.directory)
  • 写入本地文件
    lib/index.js:596
    await writeFile(paths.record, `${JSON.stringify(record, undefined, 2)}\n`, 'utf8')
  • 删除本地文件递归
    lib/index.js:685
    await rm(paths.directory, { recursive: true, force: true })
  • 删除本地文件
    lib/index.js:686
    await rm(paths.record, { force: true })
  • 写入本地文件
    lib/index.js:743
    await mkdir(project, { recursive: true })
  • 写入本地文件
    lib/index.js:744
    await rename(paths.directory, target)
  • 删除本地文件
    lib/index.js:745
    await rm(paths.record, { force: true })
  • 删除本地文件
    lib/index.js:962
    await rm(join(storageRoot, `${encodeSegment(sessionId)}.json`), { force: true })
  • 发起网络请求
    lib/client.js:229
    const response = await fetch(DELETE_PATH, {
  • 发起网络请求
    lib/client.js:267
    const response = await fetch(UNUSED_PATH, {
  • 发起网络请求
    lib/client.js:311
    const response = await fetch(path, {
  • 读取本地文件
    install.mjs:52
    const PACKAGE_NAME = JSON.parse(readFileSync(join(here, 'package.json'), 'utf8')).name
  • 读取本地文件
    install.mjs:89
    if (!existsSync(join(source, 'package.json'))) throw new Error(`no plugin package at ${source}`)
  • 读取本地文件
    install.mjs:90
    if (!existsSync(profileDir)) throw new Error(`profile directory not found: ${profileDir}`)
  • 读取本地文件
    install.mjs:92
    if (!existsSync(patchPath)) throw new Error(`profile patch not found: ${patchPath}`)
  • 读取本地文件
    install.mjs:193
    if (!existsSync(dir)) continue
  • 删除本地文件递归
    install.mjs:194
    rmSync(dir, { recursive: true, force: true })
  • 读取本地文件
    install.mjs:197
    const lines = stripPluginRows(stripPluginRows(readFileSync(patchPath, 'utf8').split('\n'), LEGACY.name, ROW_ID), PACKAGE_NAME, ROW_ID)
  • 写入本地文件
    install.mjs:200
    writeFileSync(patchPath, next, 'utf8')
  • 写入本地文件
    install.mjs:218
    writeFileSync(`${manifestPath}.bak-${stamp}`, manifestBefore, 'utf8')
  • 写入本地文件
    install.mjs:219
    writeFileSync(manifestPath, `${JSON.stringify(manifest, undefined, 2)}\n`, 'utf8')
  • 删除本地文件递归
    install.mjs:246
    rmSync(moduleDir, { recursive: true, force: true })
  • 写入本地文件
    install.mjs:247
    mkdirSync(moduleDir, { recursive: true })
  • 写入本地文件
    install.mjs:294
    writeFileSync(`${profileManifestPath}.bak-${stamp}`, before, 'utf8')
  • 写入本地文件
    install.mjs:295
    writeFileSync(profileManifestPath, next, 'utf8')
  • 删除本地文件递归
    install.mjs:360
    rmSync(legacyDir, { recursive: true, force: true })
  • 发起网络请求
    install.mjs:393
    const response = await fetch(`${origin}/plugins/events`, { signal: controller.signal, headers: { accept: 'text/event-stream' } })
扫描于 2026/11/5(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

社区实装还没有人打卡 · 装过的第一个就是你
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 从磁盘永久删除会话
  • 批量清理空会话

一个 DSH 插件,从磁盘删除会话——DSH 故意不提供的破坏性会话操作——外加批量清理空会话。适用于 DSH 0.2.x。

README

由 DeepSeek 最新模型翻译生成
description: "在 Web 侧边栏永久删除一个对话,并批量清理从未使用过的空会话。" kind: "package-reference" dsh-plugin-session-delete 一个 DSH 插件:真正从磁盘删除一个对话, 外加批量清理空会话。 安装 从 GitHub 安装 —— 用 https 形式(原因见下方提示) dsh plugin --profile <profile> add https://github.com/SereinHK/dsh-plugin-session-delete.git 或者用挂在 Release 上的打包文件:装的那台机器不需要 git dsh plugin --profile <profile> add https://github.com/SereinHK/dsh-plugin-session-delete/releases/download/v0.1.2/dsh-plugin-session-delete-0.1.2.tgz 或者把同一个 spec 粘进侧边栏的 Plugins 页。包自带 bundle 补丁(dsh.bundle.patch), 那一行插件行会被自动插入,不需要手改 profile 的 cordis.patch.yml。
展开完整文档(README 剩余 1 节)
description: "在 Web 侧边栏永久删除一个对话,并批量清理从未使用过的空会话。"
kind: "package-reference"

dsh-plugin-session-delete

一个 DSH 插件:真正从磁盘删除一个对话, 外加批量清理空会话。

安装

从 GitHub 安装 —— 用 https 形式(原因见下方提示)
dsh plugin --profile <profile> add https://github.com/SereinHK/dsh-plugin-session-delete.git

或者用挂在 Release 上的打包文件:装的那台机器不需要 git
dsh plugin --profile <profile> add https://github.com/SereinHK/dsh-plugin-session-delete/releases/download/v0.1.2/dsh-plugin-session-delete-0.1.2.tgz

或者把同一个 spec 粘进侧边栏的 Plugins 页。包自带 bundle 补丁(dsh.bundle.patch), 那一行插件行会被自动插入,不需要手改 profile 的 cordis.patch.yml。
装完刷新窗口(或那个实例)即可;lib/ 随仓库提供,安装时不编译任何东西。

两种分发形式,同一个包。 git 地址是项目自己用的方式,跟随分支;Release 上的 tarball 是同一份字节的冻结快照,而且装的那台机器不需要装 git —— pnpm 只是照常拉一个 https 地址。
两者装出来的东西完全一样:tarball 里同样带 lib/、cordis.patch.yml 和声明 bundle 补丁的清单。

没有发布到 npm。 仓库就是分发渠道,所以直接写包名的 registry 形式 (dsh plugin --profile <profile> add dsh-plugin-session-delete)解析不到 —— 请用上面那个 https://… 地址。

请用 https://… 地址,不要用 github:owner/repo 简写。 pnpm 会把简写规范化成 SSH 地址(git+ssh://git@github.com/…),在任何没配 GitHub SSH key 的机器上直接失败。
两种写法指向同一个提交,但 https 只需要一个公开仓库。

桌面应用自带包管理器,所以从 Plugins 页安装不需要 pnpm 在 PATH 上; 直接用 dsh plugin 命令则需要。

版本要求:DSH 0.2.x。 本插件注册的会话行菜单槽位 (sidebar.workspaces.session.menu.item)在 0.1.x 那条线上不存在 ——在那个构建上只可能出现侧边栏的清理入口。实测环境:@deepseek-ai/dsh-desktop-runtime 0.2.0-rc.2。

卸载:在 Plugins 页移除,或 dsh plugin --profile <profile> remove dsh-plugin-session-delete; 从源码目录装卸用 node install.mjs --uninstall。

概要

补上 DSH 刻意没有提供的那一个破坏性动作:真正从磁盘删除一个对话。

- sidebar.workspaces.session.menu.item —— 每个会话 ... 菜单里的红色 「删除对话」,排在自带的 pin/rename/fork/archive 之后。
- sidebar.footer.action —— 设置旁的 「清理空会话」:一次删掉所有 blank: true(从未开始过任何一轮对话)的空会话。
- shell.overlay —— 两个确认框,都会先列出「到底要删什么」。
- Node 面在 Connection 的 /api 认证围栏内注册两条路由:POST /api/session.delete 删一个对话, POST /api/session.unused 报告每个会话的持久事实(日志是否从未使用过、最后一次提问时间)——这些事实页面自己拿不到。
两个入口都走这一条路由。

删除不可恢复:会话根目录下该会话的整个目录(含全部格式世代)与它的投影缓存记录一并删除。已导出的文件、附件与工作区文件不受影响。

使用

会话行的 ... 菜单多出一行:

置顶 / 重命名 / 派生 / 归档 ───────────────────────────── 删除对话 ← 本包,order 900,danger

对话框先说明是哪个对话、删什么范围,然后才提供「永久删除」。删除成功后 Host 发 api-session/removed(列表行立刻消失),浏览器再拉一次权威列表。

清理入口会先列出发现的空会话(工作区路径 + 闲置时长),再给出带数量的确认按钮;执行时逐个删除,结束后报告 已删除 / 失败 / 跳过。

什么会被跳过,为什么

| 情况 | 行为 | 原因 |
| 对话正被某个窗口打开 | Host 返回 409 session-live | 它的写句柄会把日志写回来或写坏 |
| 空会话最近一小时内还有活动 | 客户端计划里跳过 | 「新建会话」也是空会话,别的窗口可能正停在上面 |
| 空会话的 Agent 正在运行 | 客户端计划里跳过 | 那不是被遗弃的草稿 |
| id 不是会话 id 形状 | Host 返回 400 invalid-session-id | id 会变成一个路径段,任何路径操作之前先校验 |
| 目标不是 <root>/<项目>/<编码 id> | Host 返回 500 unsafe-target | 递归删除前最后一道闸 |
| 附件(<DSH_HOME>/attachments) | 绝不触碰 | 内容寻址、跨会话共享、没有引用计数 |

失败

路由返回 { ok: false, error: { code, message } };对话框用当前语言翻译它自己拥有的错误码(session-live、session-not-found、unsafe-target),下面再附 Host 原始诊断。

实现要点

SessionPersistence 只有 create/open/flush/stat/list,/clear 只清选中,归档只隐藏行 —— 所以「删除」必须由插件自己完成。本包按 JSONL 后端的真实布局寻址:

<root>/<projectKey(header.cwd)>/<encodeSegment(sessionId)>/session[.vN].jsonl[.zstd]
<root> → dshHomePath('sessions')

projectKey 与 encodeSegment 是逐字复刻(后端没有导出),并由测试套件对着真实会话根目录做断言。根目录下的目录扫描作为兜底,因此布局变化只会退化成 session-not-found,不会删错地方;containmentRefusal 还会再确认目标正好在根目录下一层、且以编码后的 id 命名。

整个交互只用一个路由而不是 Typert Remote:插件的浏览器面在没有仓库内生成器的情况下无法产出 ./remote 贡献,而 ctx.connection.fetch.register 正是「插件自有端点」的官方缝,并且天然继承 Host/Origin + 浏览器令牌围栏。

对着哪个版本写的

| 项目 | 值 |
| 运行时 | @deepseek-ai/dsh-desktop-runtime 0.2.0-rc.2(cordis 4.0.4) |
| 槽位 | sidebar.workspaces.session.menu.item、sidebar.footer.action、shell.overlay |
| Host 服务 | connection、sessionPersistence、sessions |
| 浏览器种子模块 | react、@deepseek-ai/dsh-client-ui-primitives |
| 存储 | JSONL 会话后端 dshHomePath('sessions');投影缓存 dshHomePath('storages')/session_projcache |

已知边界

- 活会话删不掉,这是契约里有意的另一半:先切走再删才是被支持的路径。
如果核心提供 SessionPersistence.remove 加一个 session-controller 端点,Host 就能先停止并释放该会话;提案见本工作区的 docs/upstream-issue-session-persistence-location.md。
- 删父会话会留下孤儿子会话:子会话日志各自独立(parentSession 只是 lineage 元数据), sessionQuery.traceSession 会退化成「第一个解析不到的父级」而不是报错。
- 没有回收站、不能撤销:删除就是对会话目录 rm -rf;重要的对话请先用 /export 导出。
- 故意不做版本门禁:app-boot 会把 @deepseek-ai/dsh- peer 和运行时版本比对,所以 ^0.2.0 会拒绝正在运行的 0.2.0-rc.2。本包按稳定的服务/槽位形状编程,宁可使用时明确报错,也不肯拒绝挂载。
- 这里没有手写 README.i18n.yaml:那些分节哈希由仓库工具生成(pnpm run verify-translation-pairing --write …)。

开发说明

仓库用 pnpm run bundle(tsdown)构建。本工作区没有工具链,所以同一份 lib/ 由 tools/build.mjs 从这些源码生成(用 Node 自带的类型剥离),并把 src/client/ 模块图拼成 Host 原样提供的 window.__ModuleLoader__.load({ id, factory }) 脚本。
两份产物随后由 tools/verify-artifact.mjs(对构建产物跑 59 项路由断言)、tools/verify-browser.mjs (47 项渲染与交互断言,含拒绝路径)和 tools/verify-boot.mjs(读取运行中应用的浏览器插件图)验证。

node --test "tests/*.test.ts" # 21 个测试:Host 路由、清理计划、词典对齐
预览分享卡片长什么样 ↓SereinHK/dsh-plugin-session-delete
分享 · DeepSeek Harness Hub
SereinHK/dsh-plugin-session-delete

从磁盘永久删除对话,并批量清理空会话

这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。
认领条目 →
回到顶部