右键删除会话,连同磁盘日志与缓存一并清除
29.9/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/1 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add Theworld7/dsh-session-delete-plugin该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:需留意
是什么
dsh 原生插件 · browser
装得上吗
实装验证未通过(unknown),装前请到仓库确认最近更新与 issue
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 35 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
⚠︎ 实装验证未通过(unknown · 2026/10/2) ——可能是验证环境差异,装前建议到 GitHub 仓库确认最近更新与 issue。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
读写/删除本地文件
查看扫描证据(共 5 处,展示前 5 条)
- 读取本地文件src/eraser.js:129
projects = await readdir(this.sessionsRoot, { withFileTypes: true }) - 读取本地文件src/eraser.js:140
if ((await stat(candidate)).isDirectory()) found.push(candidate) - 读取本地文件src/eraser.js:160
if ((await stat(cachePath)).isFile()) cache = cachePath - 删除本地文件递归src/eraser.js:207
await rm(directory, { recursive: true, force: true }) - 删除本地文件src/eraser.js:212
await rm(plan.cachePath, { force: true })
扫描于 2026/11/3(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 右键删除会话
- 清除磁盘日志
- 清除缓存
一个 DeepSeek Harness(DSH)插件,在侧边栏会话右键菜单里加一个常驻的「删除会话」操作。
README
由 DeepSeek 最新模型翻译生成dsh-session-delete-plugin
给 DeepSeek Harness 会话的 ... 菜单加上 Delete session,并把该会话从磁盘上删掉。
Harness 没有针对会话的删除操作:它自带的功能里最接近的是 archive,只把 id 追加到一个持久化的隐藏集合里,磁盘上的每个字节都原样留着。这个插件补上真正的删除——会话日志目录、缓存投影、归档/固定注册表条目,统统清掉。
右键点会话行 → ... → Delete session → 确认 → 没了。
src/index.js Host half: the delete-session command and its safety policy
src/eraser.js the deletion itself, against the on-disk layout
client/client.js Client half: the menu row and the confirmation dialog
tests/ behavioural checks, run against a synthetic Harness home
cordis.patch.yml the bundle layer and this plugin's config
安装
展开完整文档(README 剩余 1 节)
dsh-session-delete-plugin
给 DeepSeek Harness 会话的 ... 菜单加上 Delete session,并把该会话从磁盘上删掉。
Harness 没有针对会话的删除操作:它自带的功能里最接近的是 archive,只把 id 追加到一个持久化的隐藏集合里,磁盘上的每个字节都原样留着。这个插件补上真正的删除——会话日志目录、缓存投影、归档/固定注册表条目,统统清掉。
右键点会话行 → ... → Delete session → 确认 → 没了。
src/index.js Host half: the delete-session command and its safety policy
src/eraser.js the deletion itself, against the on-disk layout
client/client.js Client half: the menu row and the confirmation dialog
tests/ behavioural checks, run against a synthetic Harness home
cordis.patch.yml the bundle layer and this plugin's config
安装
git clone git@github.com:Theworld7/dsh-session-delete-plugin.git
dsh plugin --profile <profile> add <path-to-the-clone>
或者在智能体会话里用 plugin_manager,action: install_bundle,target 填这个目录。配置档会记录这个包,并把它追加到 dsh.profile.bundles;之后直接跑 dsh web 就能加载,不用带 --patch 参数。
装完立刻生效:Host 那一半通过 HMR 激活,浏览器那一半在页面的模块图更新后马上注册进侧边栏槽位。
卸载
dsh plugin --profile <profile> remove dsh-session-delete-plugin
dsh plugin 会把参数原样转发给配置档的包管理器(add、remove、why……),所以卸载和安装走同一条通道。包本身和它在 dsh.profile.bundles 里的条目一起消失;已经删掉的会话保持删除状态,配置档里的其他东西一概不动。
兼容性
| | 声明位置 | 值 |
| Node.js | engines.node 和 dsh.compatibility.node | >=20 |
| Harness | dsh.compatibility.dshReleases | 0.2.0-rc.2 → compatible |
只有这一个 Harness 版本标了 compatible。其他版本一律不表态,按 Store 的规则读作未知——这是诚实的答案,因为没在别的版本上跑过。之所以说更大范围有可能可用,是因为这个插件对 @deepseek-ai/ 零导入:它通过槽位、命令注册表、声明式事件和磁盘布局接触 Host,所以只要某个版本保留这些,就能继续工作。有可能不等于测过,所以不写进声明。
权限
如实声明,而不是怎么方便怎么来:这个插件干的活本身就是破坏性的,给出一份干净的能力报告等于撒谎。
| 类型 | 是否使用 | 在这里意味着什么 |
| 文件 | 是 | 删除 <DSH_HOME> 下的会话日志目录及其缓存投影,并重写 <DSH_HOME>/registry.json,把该 id 从 archivedSessionIds / pinnedSessionIds 中移除。除 <DSH_HOME>/sessions 和 <DSH_HOME>/storages 之外,不读取也不写入任何内容,每个删除目标都会重新检查,确认严格位于这两个根目录之内。 |
| 网络 | 否 | 不抓取、不上传、不向任何地方上报。 |
| 命令 | 否 | 不启动进程,不调用 shell。 |
| 凭据 | 否 | 不读取任何 token、密钥、cookie 或密码。唯一读取的环境变量是 DSH_HOME,它是一个目录路径,用来定位 Harness 主目录,本身不含机密。 |
给自动审计的人两点说明:
- 扫描器会标记第一行,这是应该的:插件只要会删除目录,无论 manifest 怎么声明,都属于高权限,Store 政策把 files 信号视为拒绝自动批准的理由。这个结果是正确的,本插件也不把自己说成别的样子。
- 扫描器还可能把 DSH_HOME 的读取当成凭据信号。这是对路径查找的误报。之所以保留,是因为只有遵循 DSH_HOME,插件才能找到非默认的 Harness 主目录;去掉它只会让插件删错地方,不会让它更安全。
实际删除的内容
| 目标 | 路径 |
| 会话日志目录 | <DSH_HOME>/sessions/<projectKey>/<sessionId>/ |
| 缓存投影 | <DSH_HOME>/storages/session_projcache/sessions/<sessionId>.json |
| 注册表集合 | 把该 id 从 archivedSessionIds 和 pinnedSessionIds 中移除 |
删掉日志目录就足以让会话保持删除状态,这是 Harness 自身的特性,不是什么技巧:
- JSONL 后端枚举会话时是遍历 sessions/<projectKey>/<sessionId>/。没有任何索引会继续指向已删除的目录。
- 工作区通过 sessionPath(id) 过滤自己记录的账号,得出可见的 sessionIds,所以目录已消失的 id 会自动从扁平列表以及每个工作区分组中消失。插件不必修复 workspace.json;那样做反而会跟 Harness 自己的协调逻辑打架。
剩下要插件做的,是 Harness 自己不会做的事:
- 停止会话正在运行的工作,避免还有活跃写入者往即将被 unlink 的文件里追加;
- 把该 id 从两个注册表全局 id 数组中移除,这两个数组不受任何路径过滤影响;
- 在 api-session/removed 上宣告移除,这是会话列表已经在监听的转发事件。打开的页面把行数据放在内存里,底下消失的目录它自己发现不了——没有这个事件,那一行会一直待着,直到下次刷新列表,用户看到的就是「删了,但侧边栏里还在」。
配置
每个可调项都放在插件的 Config 里,所以你写的覆盖配置能扛住 Harness 升级。覆盖行 id session-delete,可以在配置档的 cordis.patch.yml 里改,也可以用 --patch 叠加层改:
| 键 | 默认值 | 含义 |
| sessionsRoot | '' | 会话日志根目录。留空则先取 $DSH_HOME,再取 ~/.dsh。 |
| storagesRoot | '' | 存放投影缓存的存储根目录。留空按同样方式推导。 |
| blockActive | true | 拒绝删除当前 Harness 中已打开的会话。 |
| stopActivity | true | 先停掉已打开会话的工作,走 Harness 自己的 workspace/session-stop 钩子。 |
| cleanWorkspaceRegistry | true | 从归档集合和固定集合中删掉这个 id。 |
| cleanProjectionCache | true | 删除缓存的投影。 |
补丁行会替换整个 config 值,所以还想保留的键都要重新写一遍:
- id: session-delete
name: 'dsh-session-delete-plugin'
config:
sessionsRoot: ''
storagesRoot: ''
blockActive: true
stopActivity: true
cleanWorkspaceRegistry: true
cleanProjectionCache: false # keep projections, delete only logs
热插拔
插件就是普通的配置档 bundle,所以它遵守配置档自身的生命周期。在运行中的页面上验证过:
- plugin_manager 的 set_plugin 设 include:session-delete → false,会把 dsh-session-delete 行从 sidebar.workspaces.session.menu.item 里移除,Host 命令也一并消失。
- 再设回 true,这一行就恢复。
因为这一行和命令都注册在插件自己的 Context 上,卸载会同时移除两者——不需要单独的清理步骤,也不会留下任何残留。样式由插件持有的 effect 追加,随 effect 一起移除。
有一条注意事项适用于所有客户端插件:改过的 client/client.js 只有刷新浏览器后才会到达页面。 启用、禁用和只改配置都能实时生效,但新的客户端代码必须重新加载。
为什么它能扛住 Harness 升级
插件从 Harness 里什么都不导入——没有 @deepseek-ai/ 包,没有内部模块,没有生成产物。它只通过稳定、有文档的契约接触框架:
1. 插槽系统。 两个入口,都走 ctx.slots.inject / ctx.slots.register:一行进 sidebar.workspaces.session.menu.item,用 owner 有文档的 props(sessionId、displayTitle、useMenuOpenState);一个对话框进 shell.overlay,由 shell 布局渲染。这一行所在插槽的 replaceRisk 是 none。
2. 命令注册表。 客户端用 ctx.remote.commands.execute(sessionId, '/delete-session <id>', [], signal) 联系 Host,读取随附的 { ok, value } 信封——这是 Remote 方法,不是私有通道。
3. 公开事件与 Service。 workspace/session-stop 是声明过的并行事件,api-session/removed 在转发事件允许列表里;agents workspaceRegistry 用 ctx.get 查找,并当作可选处理,所以插件在缺少它们的配置档里也能加载。
4. 主题 token。 样式只用 Theme inspect 服务商列出的 --dsw-alias- token。token 改名只会让外观变差,不会让渲染崩掉。
5. 磁盘上的目录结构,插件读取它时靠发现而非靠结构:它遍历 <sessionsRoot> 下的项目目录,找以 id 命名的会话目录,而不是重建 Harness 的 projectKey(cwd) 编码。目录结构一旦变化,发现逻辑会报 not-found,而不是删错目录。
一个值得了解的设计决策
插件无法新增 Remote 命名空间。Client 的可调用接口在构建时由生成的 Typert 贡献生成,所以要暴露 ctx.remote.sessionDelete 就得加一步代码生成。备选方案有两个:动态 Cordis 包(它有真正的 host.call 桥,但页面一刷新就没了,撑不起持久的菜单操作),以及现成的命令通道。本插件用的是命令通道。
由此带来一个后果:删除操作会在目标会话里记为 command/run / command/done,紧挨着日志被移除之前。这是框架自带的命令审计轨迹,无法屏蔽。
安全
- 会话 id 必须匹配 ^session-[A-Za-z0-9][A-Za-z0-9._-]$,并且每个即将被移除的路径都会重新检查,确认严格位于 sessions 根目录之内,所以精心构造的 id 逃不出它自己的项目目录。
- 在本 Harness 中处于打开状态的会话会被拒绝,除非 stopActivity 打开;这时会先通过 Harness 自己的钩子停掉它的工作。
- 删除只在带 --confirm 时执行。对话框的第一次调用是试运行,只返回将要移除的内容,不写任何东西。
- 注册表清理失败时,会在删除本身成功的前提下报一条警告:日志反正已经没了,同时告诉用户哪条记录可能还留着。
开发与验证
node tests/check-eraser.mjs # 15 checks: the Host deletion logic
node tests/check-client.mjs # 30 checks: the Client contract, the row and the dialog
两者都不需要 Harness,也不需要安装。eraser 检查会在临时目录里搭一个合成的 Harness home,所以不会碰到任何真实会话;它们覆盖发现、缓存与注册表清理、not-found、id 拒绝、活动会话拒绝、停止钩子、注册表清理失败、移除公告、不碰无关项目,以及试运行/--confirm 闸门。client 检查通过模块加载器的桩加载 client/client.js——和页面完全一样——并渲染两个入口:行,以及在行未挂载的情况下渲染的对话框,这正是实际页面用的排布。
三个值得记下的坑
1. 槽位条目的 inject 是被调用的,不是被读取的
插槽条目的 inject 由渲染器调用,而不是读取:
// dsh-client-ui-renderer, runInject
const inject = entry.inject
if (!inject) return EMPTY_INJECTED_PROPS
return bindInjectSources(inject(...args)) // ← must be callable
所以 inject: { slots, remote }(普通对象)会在该行首次渲染时抛出 inject is not a function。后果比少一行更严重,值得弄清楚:
// dsh-client-ui-renderer:1117
host.reportEntryError(slotKey, entry, error, { abdicate: spec.kind !== 'chain' })
// dsh-client-ui-slots:286 entriesOfSlot() — what the outlet renders
if (this.abdicated.has(entry)) continue
抛错的列表条目会被弃用:加入退役集合,此后 entriesOfSlot() 一律跳过。注册本身成功了,所以 snapshot()——也就是 Slots Inspect 服务商报告的内容——仍会列出该条目,状态为 active。结果就是:Inspect 发誓这一行在,菜单却再也不画它,直到页面生命周期结束。
因此这一行包在自己的错误边界(SafeRow)里。渲染一旦抛错,条目照样退役,但插件会记录原因,并在原处渲染一行可见的故障提示,而不是直接消失:
删除会话菜单项无法显示 TypeError: …
出于同样的原因,它订阅了 slots.onEntryError。没有这些,渲染缺陷和「插件没装」根本分不出来。
tests/check-client.mjs 把 inject 契约钉死:拿注册信息重放 runInject;也把可选属性的容错钉死:在 owner 的可选属性一个都不存在的情况下渲染该行。
2. 一行活不过它的菜单
会话菜单的 owner 在自己的重命名操作上方这样说:
对话框活在行菜单之外,因为行会随菜单一起卸载;浏览器从标题双击发起同样的请求。
这个插件的第一版从行自身的 effect 注册确认对话框——点击时注册,卸载时销毁——这是个自我抵消的安排:点击关闭菜单,菜单卸载该行,清理又在创建注册的同一个 commit 里把它移除。什么都没画出来,什么都没记日志,症状就是菜单项做了个彻头彻尾的「无」。
所以对话框和结果通知都由 apply 贡献,伴随插件整个生命周期,行只在双方共享的信号上发起请求。tests/check-client.mjs 会在卸载该行之后渲染对话框,所以退回旧安排会让测试套件失败。
3. Remote 调用返回的是信封
ctx.remote.commands.execute(...) 不会 resolve 成命令的结果。它 resolve 成 { ok, value }(或 { ok: false, error }),最终落定的 CommandResult 在 value.result。第一版从信封上读 result,永远拿到 undefined,于是报告「Harness 没有返回结果」
每次尝试都会遇到——看起来像 Host 的问题,实际上是缺了 .value。
tests/check-client.mjs 里的 fixture 返回的是信封,不是裸结果,所以拆包逻辑是被真正跑到的,而不是假设出来的。
对齐宿主图标的几何尺寸
宿主菜单图标画在 viewBox="0 0 16 16" 上,图形铺满整个框,渲染尺寸是 14px。图标的视觉大小等于路径范围加上两侧各半个描边,所以如果字形的路径只占 viewBox 的一部分,在相同的 width/height 下看起来就比邻居小——这一行字形的第一版就是这样,而且光调 CSS 尺寸怎么都修不好,除非把图标调得相对整行过大。
因此这里的字形画在半像素网格上,以 ±7.5 居中,绘制范围正好是完整的 16 单位;它还用了宿主的中等描边(1.3),而不是 1px 常规描边,因为 1px 描边在 14px 下显得太细。
tests/check-client.mjs 会测量路径范围,并断言绘制跨度覆盖整个框,所以以后哪次改动把图标缩小了,测试套件就会失败。
验证状态
| 结论 | 如何确认 |
| 宿主行已激活 | plugin_manager list_plugins → include:session-delete,fiberPhase: active |
| 客户端行已注册 | 插槽 listSubTree → sidebar.workspaces.session.menu.item 占用者 dsh-session-delete,顺序 500 |
| 热插拔可用 | 在运行中的页面上,禁用后该行消失,启用后回来 |
| 删除逻辑正确 | tests/check-eraser.mjs 中 15/15 项检查通过 |
| 客户端契约正确 | tests/check-client.mjs 中 30/30 项检查通过,包括重放渲染器的 runInject、{ ok, value } 信封、服务注入列表、图标几何尺寸,以及在行未挂载的情况下渲染对话框 |
| 该行在菜单中渲染 | 用户已确认,与置顶会话 / 重命名 / 分叉会话 / 归档会话一起出现在上下文中 |
| 对话框和真实删除 | 用户已在实时页面上确认:对话框打开,列出了将被移除的内容,确认删除成功,通知出现,侧边栏那一行也随之消失。 |
| 卸载 | dsh plugin --profile remove <pkg> 原样转发给该配置档的包管理器(dsh/lib/bin.js:116)。这个往返流程尚未在一次性配置档上端到端跑过。 |
如果确认对话框报出 "The Harness command channel is unavailable",说明 ctx.get('remote.commands') 在这个页面的组合中不存在——这一行会主动禁用自己,而不是在操作中途失败。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
Theworld7/dsh-session-delete-plugin
右键删除会话,连同磁盘日志与缓存一并清除
相关插件 · 浏览器
智能体插件框架deepseek-ai/deepseek-harness
DeepSeek Harnessdsh是由 DeepSeek AI 开发的开源 agent harness智能体框架。
★ 270,422已汉化DSH
71.9
多设备 Agent 看板YaoApp/yao
✨ 所有 Agent 和工作区集中管理,覆盖你的每一台设备。任务看板追踪进度,桌面端、移动端、浏览器、API…
★ 8,147已汉化DSH
71.2
可扩展侧边栏工作台omdsh-dev/DSH-better-sidebar
DSH 的双工作台:原生右侧栏 + 自绘底部面板,并把 ctx.betterSidebar 服务开放给所有插件
★ 4,761已汉化DSH
71.1
浏览器自动化桥Tencent/BrowserSkill
你的 Agent。你的浏览器。连接,就能协作。
★ 9,967已汉化DSH
71
AI 小说创作工作台EthanYoQ/AI-Novel-Writer
AI 小说作家 / AI Novel Writer
★ 1,591已汉化DSH
70.7
智能体浏览器引擎platonai/Browser4
DeepSeek Harness 集成
★ 1,175已汉化DSH
70.4
这是你的仓库?认领条目