DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

runcat-tommy /

runcat-tommy/dsh-windows-c-cleanup

Verified

DSH plugin: scan, grade and clean up Windows C: drive - five-tier safety grading, staging area, UAC elevation, and migration.

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@806707b8

dsh-windows-c-cleanup

English | 中文

仓库:https://github.com/runcat-tommy/dsh-windows-c-cleanup(npm:dsh-windows-c-cleanup)

给 DeepSeek Harness(DSH)加上** Windows 系统盘(C 盘)清理能力**的插件。

它不是「一键删缓存」脚本,而是把清理拆成一条可审计的流水线:

扫描 → 五级分级 → 生成可视化报告 → 用户选择 → 分层执行 / 迁移到其他盘

为什么需要它

C 盘爆满通常不是「垃圾文件」造成的,而是本该放在别的盘的东西放错了地方:包管理器缓存、IDE 索引、浏览器端侧 AI 模型、升级包残留、虚拟磁盘。

直接删风险很高(删掉 IDE 索引要重建几小时,删掉虚拟磁盘等于毁掉整个 Linux 环境)。本插件的做法是:

  1. 先量后删:按规则库把每个候选项测出真实大小,产出可视化 Markdown 报告;
  2. 五级分级:每个候选项都带判定理由,用户看得懂再决定;
  3. 保护名单是硬约束:未收录规则的一律按保护处理(不明即不删);
  4. 能迁移就不删除:有多个盘时,优先用 junction / 改配置把缓存搬到别的盘,长期不再回涨。

五级分级

级别 含义 执行策略
🟢 可安全删除 缓存 / 临时文件 / 升级包残留,无数据损失 确认一次后可批量执行
🟡 谨慎删除 可重建但代价高(IDE 索引、端侧 AI 模型、包管理器仓库),或需管理员权限(WinSxS 走 DISM) 逐项确认
🟠 建议迁移 搬到其他盘后应用无感,可用 junction 或改配置 迁移 + 建链接 + 记台账,可回滚
🔴 保护名单 用户文档、凭据、聊天数据、虚拟磁盘、IDE 配置、未识别路径 永不自动删除(硬约束,用户规则也不得覆盖)
🔵 长期防护 配置类动作:缓存重定向、存储感知、虚拟磁盘位置核查 一次性做好,长期少清理

安装

dsh plugin 是 pnpm 的转发壳:它把插件装进指定 profile,再按装载后的真实状态把它登记进 dsh.profile.bundles(本包声明了 dsh.bundle.patch,所以会被加进层叠列表)。三条路任选其一,装完都要重启 DSH 才生效。

方式一:直接从 GitHub 安装

dsh plugin --profile web add github:runcat-tommy/dsh-windows-c-cleanup
  • 适合:想直接装仓库里的最新提交,本机已装 git。
  • 注意:本仓库的 lib/ 与 client/client.js 是构建产物、没有提交进仓库(靠 prepare 脚本在安装时现构建),所以这条路会跑一次构建、需要你审批,dsh plugin 会打印审批提示。
  • 更新:重跑同一条命令(pnpm 会重新拉取该 git 源的最新提交)。

方式二:先从 GitHub 下载到本地,再从本地目录安装

# 第 1 步:把代码取到本地(git 克隆,或者在 GitHub 页面点 Code → Download ZIP 后解压)
git clone https://github.com/runcat-tommy/dsh-windows-c-cleanup.git D:\dsh-plugins\dsh-windows-c-cleanup

# 第 2 步:从本地目录安装
dsh plugin --profile web add D:\dsh-plugins\dsh-windows-c-cleanup
  • 适合:想装之前先看一眼代码、想自己改、或者网络不稳(可以先下载 ZIP 再解压,不必用 git)。
  • 注意:本地目录会以 link: 形式装进 profile,你改的代码立即生效——宿主侧改动重启 dsh web,只改客户端界面则 npm run build:client 后刷新页面即可。
  • 更新:在本地目录 git pull,再跑一次 npm run build,然后重启 dsh web。

方式三:从 npm 安装(推荐)

dsh plugin --profile web add dsh-windows-c-cleanup

# 想钉住某个版本时
dsh plugin --profile web add dsh-windows-c-cleanup@0.5.2
  • 适合:日常使用,最省心。npm 包里已经带了构建产物,所以不需要本机编译、不需要 git、也没有构建审批。
  • 更新:dsh plugin --profile web up dsh-windows-c-cleanup
  • 卸载(三条路都一样):dsh plugin --profile web remove dsh-windows-c-cleanup
  • 看装了哪些:dsh plugin --profile web list

三条路怎么选

命令 需要什么 装进来的东西 更新方式
一、GitHub 直装 add github:runcat-tommy/dsh-windows-c-cleanup 本机有 git;要过一次构建审批 仓库最新提交(安装时构建) 重跑同一命令
二、下载到本地 add D:\dsh-plugins\dsh-windows-c-cleanup 无(ZIP 也行) 本地目录(link:,改代码即生效) git pull + npm run build + 重启
三、npm add dsh-windows-c-cleanup 无 npm 上的发布版(已带产物) up dsh-windows-c-cleanup

一句话:npm 最省心,GitHub 直装最省事(但要构建审批),下载到本地最灵活(改动立即可见)。

装完重启

三条路都一样,重启 DSH 后插件才会被加载:

dsh web

重启后打开任意会话,就能在会话视图顶部看到「磁盘清理」tab。

开发时也可以不安装,直接挂 overlay(注意 Windows 必须用 file:// URL):

node -e "const{pathToFileURL}=require('node:url');console.log(pathToFileURL(process.argv[1]).href)" "$PWD\src\index.ts"
dsh web --patch .\dev.cordis.yml

使用

插件注册一个工具 disk_cleanup:

参数 取值 说明
action scan | plan | apply | migrate | rollback | trash 必填。scan/plan 只读;apply/trash 执行清理(M2);migrate/rollback 迁移与回滚(M3)
scope hotspots | full hotspots 只按规则库测热点(快);full 追加全盘 Top-N 大目录(默认)
reportPath 路径 报告落盘位置,缺省 工作目录/C盘清理报告-<时间戳>.md
format markdown | json | both 报告格式,缺省取配置 defaultReportFormat;json 产出机器可读报告(传 x.md 时会同时写同名 x.json)
items 路径数组 要清理的具体路径(谨慎层必填:只接受用户逐项确认过的路径)
grade safe | caution | migrate 按层级选范围:safe 可批量;caution 必须同时给出 items;migrate 配合 action=migrate 自动挑选迁移层
mode permanent | trash 删除模式:trash 移到其他盘暂存区(可恢复,默认);permanent 永久删除
trashPath 路径 暂存区位置,必须位于其他盘(同盘移动不释放空间);缺省 <空闲最大的非系统盘>:\to_delete
dryRun 布尔 默认 true:只列出将要执行的动作,不删任何文件;用户确认后才传 false
elevation none | dism | cleanmgr | dism+cleanmgr 是否一并触发管理员级系统清理(会弹 UAC)
targetDrive 如 D: 迁移目标盘;缺省自动选空闲最大的非系统盘
extraRulesFile 路径 本次扫描叠加的用户规则文件

调用示例(自然语言即可,模型会映射到工具):

帮我扫一下 C 盘,看看哪里占地方最大

工具会产出:

  • 工具返回值:盘符、剩余空间、各层可释放字节数、大头 Top-N、迁移目标盘建议;
  • 可视化报告(Markdown):汇总 → 🟥 大头 → 🟢/🟡/🟠/🔴/🔵 五级清单 → 执行结果。

执行清理(M2)

执行是两阶段的,安全默认值不靠调用方自觉:

  1. 预演:apply 不传 dryRun 时默认 dryRun: true,只输出「将要删什么、多大、为什么」的逐项清单,并落盘一份 C盘清理执行报告-<时间戳>.md;
  2. 执行:用户确认后,才用 dryRun: false 真正执行。
// 1) 安全层批量预演(不删文件)
{ "action": "apply", "grade": "safe" }

// 2) 用户逐项确认后的谨慎层(必须列出具体路径)
{ "action": "apply", "items": ["C:\\Users\\<你>\\AppData\\Local\\Temp\\某缓存"], "mode": "trash", "dryRun": false }

// 3) 永久删除(需用户明确同意)
{ "action": "apply", "items": ["..."], "mode": "permanent", "dryRun": false }

// 4) 附带管理员级系统清理(会弹 UAC,用户拒绝则如实回报)
{ "action": "apply", "grade": "safe", "dryRun": false, "elevation": "dism+cleanmgr" }

执行报告与返回值会给出:逐项结果(已删除 / 已入暂存区 / 部分删除 / 已拒绝 / 需提权)、逐项测量合计释放量、盘符空闲净增、被拒绝项的完整理由、提权脚本路径与日志摘要。

迁移与回滚(M3)

「删掉」只是治标——企业微信、WPS、浏览器、包管理器的缓存删完会再长回来(实测一轮清理后约 11 GB 被应用自己重建)。迁移是治本:把目录搬到其他盘,在原位置留一个目录联接(junction),应用完全无感。

// 1) 预演迁移(不动数据)
{ "action": "migrate", "items": ["C:\\Users\\<你>\\AppData\\Local\\npm-cache"], "targetDrive": "D" }

// 2) 用户确认后执行;原目录变成 junction,数据在 D:\dsh-cc-migrated\npm-cache
{ "action": "migrate", "items": ["..."], "targetDrive": "D", "dryRun": false }

// 3) 自动挑选规则库里的 🟠 迁移层
{ "action": "migrate", "grade": "migrate", "dryRun": false }

// 4) 后悔了:依据台账搬回并删除联接
{ "action": "rollback", "dryRun": false }

不可让步的执行顺序:复制 → 校验(大小与文件数)→ 删除源 → 建立联接 → 校验联接可读。任何一步失败都会清理副本并保持原状,绝不留下「半迁移」状态让用户自己收拾。具体保证:

情况 行为
目标与源在同一盘 拒绝(移动不释放空间)
目标同名目录已存在 拒绝并提示,绝不合并
目标盘空间不足 拒绝,并给出需要的空间
源目录被应用占用、删不掉 回滚已复制的副本,原状态不变,提示先关闭应用
复制成功但建联接失败 明确报告数据已在新位置、老路径不可用,绝不谎报成功
回滚时源位置不是联接或指向不一致 拒绝回滚,避免覆盖用户后来放回的数据
迁移台账 <migrationRoot>\ledger.jsonl,逐条记录源/目标/大小/时间/方法

app-config 类规则(如 npm 缓存)除搬数据外,还会返回建议命令(例如 npm config set cache "D:\..."),但不自动修改应用配置。目录联接在 Windows 上不需要管理员权限。

历史趋势与 JSON 报告(M4)

删掉的缓存会长回来——本机实测一轮清理后约 11 GB 被应用自己重建(企业微信升级 1.93 GB、%TEMP% 1.47 GB、WPS 插件 1.97 GB、Chrome ~0.8 GB、uv 327 MB)。所以每次扫描都会往 <DSH_HOME>\windows-c-cleanup\history.jsonl 追加一条记录,并与上一次对比:

📈 与上一次扫描(24 小时前):剩余空间 −1.20 GB | 长回来 3 项 | 被释放 1 项 | 增长最多:…\WXWork\upgrade +1.93 GB

Markdown 报告里渲染成「📈 历史趋势」区块(长回来的 / 被释放的 / 新出现的 / 本次未再测到的);机器可读版本用 format:

{ "action": "scan", "format": "both" }   // → C盘清理报告-<时间戳>.md + 同名 .json

JSON 报告带 schema: "dsh-windows-c-cleanup/report@1" 版本号,含五级分组、大头、趋势与告警,可直接喂给 GUI / 脚本 / 监控。趋势只在路径交集上比较:扫描被时间预算截断时,「上次有、这次没有」不等于「已被清理」,报告里用 previousPartial 标注。

定时扫描与告警(M4)

默认关闭——后台扫盘会占用你的磁盘 I/O,属于需要你点头的行为。打开后:

- id: windows-c-cleanup
  name: dsh-windows-c-cleanup
  config:
    schedule:
      enabled: true
      intervalHours: 24
      alertFreePercent: 10
      scope: hotspots
  • 低于 alertFreePercent 时写一条告警记录(下次扫描的工具输出 / 报告顶部会显示),并经 ctx.logger 输出 warn 日志;
  • 宿主只提供 ctx.logger / ctx.effect,没有定时器服务,所以用 Node 定时器 + unref() + ctx.effect 托管释放;
  • 四道保护:单飞(上一轮没跑完就跳过本轮)、首次延迟 1 分钟(避开启动抢 I/O)、整轮 try/catch(失败只记日志)、unref()(不阻止宿主退出)。

清理面板(M5)

插件在 Web GUI 里注册一个对话视图 tab(conversation.view,additive list 插槽,不覆盖任何现有界面):打开任意会话,切到「磁盘清理」就能完成「看懂 → 勾选 → 预演 → 执行」。

实拍(中文界面,与本文档语言一致;英文界面见 README.en.md):

中文界面
磁盘清理面板中文界面

面板是薄的:它不做任何业务判断,分级、安全闸、测量、释放量核算全部复用宿主侧既有模块;面板调用的「预演」和「真执行」走的是同一个 executeCleanup(只有 dryRun 不同),所以预演里出现的每一项、每个理由都与真执行一致。

功能区对照表(每个区块左上角都有名字标签)

面板从上到下分成这些区块,每块左上角都有一个固定名字的小标签(中英各一套,测试 10.1–10.6 守着)。要指哪一块,直接说名字就行:

模块名 位置 里面有什么
概览 最上方标题栏 盘符剩余/总量与已用比例;右侧两个状态片:迁移目标(盘符 + 可用空间)、定时扫描开关
操作区(扫描 → 选择 → 预演) 标题栏下方 三组相邻控件,组间有向右箭头:① 范围 + 扫描 C 盘 ② 已选 N 项 + 清空选择 ③ 删除方式 + 预演 + ?。这里没有「确认执行」——执行入口只有一处,在「预演结果」里
预演结果 紧跟在操作区下方(点「预演」后出现) 每项会发生什么(移到暂存区 / 永久删除 / 需提权 / 被拒)、合计释放量、被拒清单;面板唯一的「确认执行」按钮就在这里,旁边还有「再预演一次」。标题右侧的动态文字才是"这次预演算出了什么"
状态与提示 预演结果下方 进行中的操作(⏳)、上一次操作的结果提示、报错,以及扫描被时间预算截断时的告警
清理候选(🟢/🟡/🟠/🔴) 中部四列卡片 可安全删除 / 谨慎删除 / 可迁移 / 保护名单,逐项路径、大小、判定理由;保护层不可勾选
长期防护 候选下方(可折叠) 改设置或使用习惯就能反复受益的 6 条长期措施
执行进度 点「确认执行」后出现(候选下方) 任务号与状态、进度条(来自宿主逐项记账)、逐项明细、释放量、取消任务
迁移预览 点卡片里的「迁移预览」后出现 源 → 目标映射、文件数、目标盘是否够、需要你手动改的应用配置;底部是迁移按钮
记录与产物 面板最底部 历史台账与报告目录的绝对路径(报告落到磁盘、保持中文)

有两点值得注意:

  • 「预演结果」是唯一被上移到操作区正下方的动态区块(其余动态区块仍在候选卡片下方)。这样点完「预演」,结果和它的执行按钮就在你刚点的那排按钮下面,不用翻过四列候选卡片;没有预演结果时,这个位置留给「状态与提示」,扫描完的提示同样紧贴操作区。
  • 执行入口只有一处:「确认执行」只存在于「预演结果」里。工具栏不再提供执行按钮,于是"没预演就执行"在界面上根本没有入口(宿主侧的 guardTargets 与 dryRun 契约不变,仍是最终防线)。预演后改动勾选或删除方式会让预演作废、整块结果消失、需要重新预演;永久删除未勾确认框时按钮不可点,原因写在按钮旁边(测试 8.1–8.9)。
  • 按用户要求,原「历史对比」模块(与上次扫描的时间差、长回来的目录)已从界面移除;宿主的 state.trend 字段仍照常返回,需要恢复时接回来即可。

工具栏按「同组相邻」排成三组,组间各有一个向右箭头标明先后关系,从左到右:

组 控件 说明
① 扫描 范围 下拉 + 扫描 C 盘 选 hotspots/full,然后开扫(已扫过则显示「重新扫描」)→
② 选择 已选 N 项 + 清空选择 实时计数与一键清空 →
③ 预演 删除方式 下拉 + 预演 + ? 「预演」右边就是问号说明按钮;执行按钮不在这里(见「预演结果」)

箭头是纯装饰(aria-hidden,读屏会跳过),左右各留 12px 再加组内 6px 间距,所以留白明显,读起来就是「先扫描 → 再选择 → 最后预演」。

可辨识度(专门调过,不是默认样式):

  • 「扫描 C 盘」「清空选择」「预演」三个动作按钮在可用时是品牌色加粗描边 + 底色淡染 + 投影 + 加粗字,一眼就能看出是按钮;不可用时保持原来的浅底灰边半透明样式——不能点的按钮绝不能画得像能点;

  • 「确认执行」(在「预演结果」里)是实心品牌色:实心=最后一步动作,描边=可点的普通动作,层级不混;

  • 「预演」右边的 ? 是 24px 圆形按钮(2px 品牌色描边、底色淡染、加粗问号、悬停放大)。点开就地说明,文案刻意写得直白:第一句就是「点「预演」= 先干跑一遍,什么都不删」,再列三条要点(真的检查能不能删 / 真的算权限与空间 / 每项写明会发生什么),最后才提两点注意(数字是估算、查不出文件被占用)。

  • 五级卡片:🟢安全 / 🟡谨慎 / 🟠可迁移 / 🔴保护,逐项显示路径、大小、判定理由;保护层不可勾选;

  • 两步执行:执行入口只有一个,在「预演结果」里,所以必须先「预演」才可能执行;勾选或模式一变,预演即作废、结果整块消失,得重新预演。唯一还能拦住执行按钮的是"永久删除未勾确认框",此时按钮不可点,原因直接写在按钮旁边(禁用按钮的 tooltip 在多数浏览器里根本弹不出来,只写 tooltip 等于没写)——由 runGate() 纯函数判定,测试 8.1–8.9 钉住;

  • 真实进度:进度条来自宿主的逐项记账回调(不是猜日志文本),随时可「取消任务」;

  • 迁移预览:先看「源 → 目标」映射、文件数、目标盘是否够,再决定是否迁移;需要你改的应用配置只提示、不代改。

切到对话页再切回来,正在做的事不会丢

面板是插在会话视图里的,切走会卸载组件(本地 React 状态随之清空)。所以凡是"正在发生的事",面板都以宿主为准去认领,而不是自己记着:

你切走时 宿主的权威状态 切回来看到
正在「扫描 C 盘」 panelState().scan = {running, scope, startedAt}(扫描本来就跑在宿主侧,组件卸载不影响它) 「正在扫描 C 盘」的 ⏳ 立刻回来,之后每 1.2 秒问一次宿主
扫描刚在你切走时跑完 结果在宿主缓存里(scan-view) 候选卡片直接出现,并补一条「扫描完成」提示 —— 不用重新点一次扫描
正在真清理 / 迁移(有任务在跑) panelState().runningJobIds 拿 jobId 接上进度轮询,「执行进度」的进度条与逐项明细继续走

宿主同一时刻只扫一次:面板回来后你要是又点了「扫描」,会接上还在跑的那一次(省一次全盘遍历,也不会让两份结果互相覆盖;测试 12.3–12.5)。

有一点如实说明:勾选与预演结果不跨卸载保留(改动勾选或删除方式本来就会让预演作废,回到面板时按"重新勾选 → 重新预演"走)。scan 与 runningJobIds 这两个字段是 0.5.1 加的,老宿主(还没重启 dsh web)缺字段时面板退化成原样行为、不报错(测试 11.6)。

中英双语

面板与宿主文案都是中英两套,跟随 DSH 的语言设置自动切换,不需要手动选语言:

  • 界面文案由客户端字典提供(client/src/i18n.ts,中英各 120 条,键集合严格一致),tab 标题是函数式标签,语言一换标题即跟着换,无需重新注册;
  • 面板每次调用宿主 RPC 都会带上当前 locale,所以宿主生成的文案也跟着切换:规则库的每一条判定理由、安全闸的 12 条拒绝理由、执行器的逐项计划动作、迁移配置提示、调度状态。英文文案放在 src/rules/default-rules.en.json,按规则 id 与中文严格对齐(101 条规则 + 6 条长期防护,有测试守着覆盖率和「英文里不得出现中文」);
  • 切语言不会让你重扫一遍(scan-view 端点):扫描结果里的规则说明、截断告警都是宿主生成那一刻渲染好的字符串,切语言本来不会变——所以宿主额外提供「用缓存里那次扫描按目标语言重新出视图」(不碰盘、不测量,实测 0ms),面板在语言变化时自动调它,并顺带重跑一次预演与迁移预览,让界面不再中英混杂(实测截图暴露过这个问题);
  • 提示句存的是「键 + 参数」(Notice,见 client/src/panel.tsx):渲染时才取当前语言的 t,所以「扫描完成…」「预演完成…」这类提示会跟着语言切换,而不是冻结在生成时的语言(类型上也堵住了:传字符串编译不过);
  • 默认中文:模型工具(disk_cleanup)那条路不传 locale,输出与历史完全一致;只有 Web 面板会传 en;
  • 英文缺项一律回退中文原文,宁可显示中文也不显示空洞;
  • 接线有时序要求:字典必须在框架渲染带 locale: 的注册项之前登记好,所以客户端插件用 ctx.inject(['locale']) 等语言服务就绪再接线;相应地 dsh.client.inject 里也声明了 @deepseek-ai/dsh-client-locale(这属于包元数据变更 → 首次升级要重启 dsh web,之后改文案只刷新页面即可)。

浏览器与宿主之间走 Connection 的通用 RPC 通道 /dsh-c-cleanup(authority: loopback,只接受本机调用),端点包括 state / scan / scan-view / preview / execute / migrate / progress / cancel / history 等。任务表是宿主内存态,宿主重启即清空。

state 端点是面板的"重新挂载入口",除了盘符与调度状态,还如实报告此刻在不在扫盘(scan)与有哪些任务在跑(runningJobIds)——面板切走再回来靠这两个字段把界面接上(见上一节),扫描本身与任务本身都跑在宿主侧,不受组件卸载影响。

落地条件(平台机制决定,不是本插件的选择):

改动 需要做什么
新增/删除插件包、改 dsh.client 字段 重启 dsh web(包元数据判定被宿主永久缓存)
只改 client/client.js 内容 刷新页面即可(bundle 带 no-cache;本 profile 的 HMR 是关闭的)

配置

在 profile 的 cordis.patch.yml 中覆盖(patch 会整体替换该行 config,不做深合并):

- id: windows-c-cleanup
  name: 'dsh-windows-c-cleanup'
  config:
    reportDir: 'D:\reports'
    defaultScope: full
    hotspotTimeBudgetMs: 70000
    topTreeTimeBudgetMs: 70000
    topTreeMaxDepth: 3
    bigItemThresholdBytes: 2147483648
    allowProtectedOverride: false
    allowExplicitUnmatched: false
    defaultDeleteMode: trash
    trashPath: 'D:\to_delete'
    migrationRoot: 'D:\dsh-cc-migrated'
    historyPath: 'C:\Users\<你>\.dsh\windows-c-cleanup\history.jsonl'
    defaultReportFormat: markdown
    schedule:
      enabled: true          # 默认 false:不主动占用你的磁盘 I/O
      intervalHours: 24
      alertFreePercent: 10
      initialDelayMinutes: 1
      scope: hotspots
    extraRulesFile: 'D:\my-rules.json'
配置项 默认 说明
reportDir 当前工作目录 报告输出目录
defaultScope full 默认扫描范围
hotspotTimeBudgetMs 70000 热点清单时间预算(超时截断并标记)
topTreeTimeBudgetMs 70000 全盘 Top-N 时间预算(两个扫描并行,总时长约等于较大者)
topTreeMaxDepth 3 Top-N 遍历深度
bigItemThresholdBytes 2 GiB 「大头」判定阈值
allowProtectedOverride false 是否允许用户规则覆盖保护名单(默认禁止;硬约束项永不放行)
allowExplicitUnmatched false 是否允许清理未收录规则库的显式路径(默认「不明即不删」)
defaultDeleteMode trash 默认删除模式:trash 移到其他盘暂存区,permanent 直接删除
trashPath <空闲最大的非系统盘>:\to_delete 暂存区位置(必须与其他盘同盘不同卷才释放空间)
migrationRoot <空闲最大的非系统盘>:\dsh-cc-migrated 迁移根目录;迁移台账 ledger.jsonl 与之同目录
historyPath <DSH_HOME>\windows-c-cleanup\history.jsonl 扫描历史(趋势对比数据源);故意放在不会被清理的位置
defaultReportFormat markdown 默认报告格式:markdown / json / both
schedule.enabled false 是否启用定时扫描(默认关闭,需你显式同意)
schedule.intervalHours 24 定时扫描间隔(小时)
schedule.alertFreePercent 10 剩余空间占比低于该值时写告警
schedule.initialDelayMinutes 1 首次执行延迟,避开宿主启动抢 I/O
schedule.scope hotspots 定时扫描范围(比 full 快且省 I/O)
extraRulesFile 无 用户附加规则文件

规则库

内置 100+ 条规则位于 src/rules/default-rules.json,全部用占位符书写(%LOCALAPPDATA%、%APPDATA%、%USERPROFILE%、%WINDIR%…),不含用户名硬编码,可跨机器复用。

规则形态:

{
  "id": "npm-cache-local",
  "path": "%LOCALAPPDATA%\\npm-cache",
  "grade": "migrate",
  "reason": "npm 包缓存,体积常达数 GB;建议迁移到其他盘并从 C 盘释放",
  "migrate": {
    "method": "app-config",
    "targetHint": "<其他盘>:\\npm-cache",
    "configHint": "npm config set cache \"<目标路径>\""
  }
}

匹配语义:候选路径等于规则路径或位于其下即命中;* 只匹配单段目录名(如 %LOCALAPPDATA%\*-updater)。 优先级:最具体的路径胜出,同长度时 protected 优先;未命中任何规则 → 按 protected 处理。

自定义规则文件只需同结构:

{ "rules": [{ "id": "my-cache", "path": "%LOCALAPPDATA%\\my-app\\cache", "grade": "safe", "reason": "自建应用缓存" }] }

试图覆盖 overridable: false 的保护名单项会被拒绝并告警(除非显式开启 allowProtectedOverride)。

安全设计

  • 保护名单硬约束:用户文档、桌面、下载、SSH/云凭据、.dsh 配置、聊天数据(企业微信/飞书/微信)、IDE 配置、pagefile.sys / hiberfil.sys / 虚拟磁盘、Program Files、Windows —— 永不自动删除。
  • 未识别即保护:规则库没收录的目录不会被删(除非显式开启 allowExplicitUnmatched)。
  • 分层确认:安全层可一次确认;谨慎层逐项确认;保护层不出现执行入口。
  • 默认预演:apply / trash 的 dryRun 默认为 true,不显式传 false 就不会删任何文件。
  • 结构性禁忌:盘根、C:\Users 等关键目录、目录联接/符号链接、父目录含 junction 的路径、非系统盘路径,执行前一律拒绝。
  • 同盘暂存被拒绝:暂存区与源在同一卷时移动不释放任何空间,因此直接拒绝并说明原因。
  • 如实汇报:被占用/无权限的文件删不掉时返回「部分删除」与残留字节数;用户拒绝 UAC 时返回 elevation-canceled,绝不谎报成功。
  • 两种释放量都给:同时给出「逐项测量合计」与「盘符空闲净增」——清理量较小时后者会被其他进程的写入掩盖。
  • 时间预算:扫描超时会截断并在报告与返回值里明确标记 partial,不会静默给出残缺结论。
  • 不跟随链接:junction / 符号链接一律不跟随,避免重复计数与递归踩坑。
  • 迁移可回滚:迁移用 junction 或应用配置改路径,并记录台账(M3 起提供 rollback)。

当前状态(M1 + M2 + M3)

  • 规则库(100+ 条,占位符化)+ 长期防护清单
  • 扫描:盘符信息、热点清单、全盘 Top-N、junction 安全测量、时间预算
  • 五级分级 + 未识别即保护
  • 可视化 Markdown 报告
  • DSH 工具注册(disk_cleanup,参数/输出 schema 校验通过)
  • M2 执行层:删除(安全层批量 / 谨慎层逐项)、暂存区与台账、UAC 提权(Windows\Temp / WinSxS / DISM / cleanmgr)、执行报告与 dryRun 默认
  • M3 迁移层:目录联接迁移(应用无感)、迁移台账与 rollback、对同盘/同名冲突/空间不足/源被占用的拒绝与回滚、app-config 建议命令
  • M4 打磨:扫描历史与趋势对比、JSON 报告、定时扫描与告警(cleanmgr/DISM 提权已在 M2 落地)
  • M5 Client GUI 面板:conversation.view 五级卡片、勾选、两步执行(预演 → 确认)、逐项进度与取消、迁移预览
  • M6 发布:npm + 社区插件市场(GitHub 已完成)

已知限制(M1 + M2 + M3 + M4 + M5)

  • 执行需要明确授权:apply / trash 默认预演;真正的执行路径必须先跑扫描并把报告交给用户确认。migrate / rollback 仍是 not-implemented(M3)。
  • 管理员级清理依赖 UAC 弹窗:DSH 的权限栈没有 UAC 原语,插件通过 Start-Process -Verb RunAs 触发系统弹窗(脚本落在 %TEMP%\dsh-cc-elevated-*.ps1);用户不点「是」就无法清理 Windows\Temp、SoftwareDistribution、WinSxS 等,此时结果里会明确标记为「用户取消」。
  • 被占用的文件删不掉:浏览器、IDE、企业微信正在运行时其缓存文件会被锁定,结果中记为「部分删除」并给出残留量——这是 Windows 的正常行为,不是插件故障。
  • 全盘 Top-N 覆盖度受 I/O 上限约束:Node 的文件操作走 libuv 线程池(默认 4 线程),目录测量成本基本由文件数决定,加并发也提不上去。因此在 70 秒预算内,153 GB 已用盘的热点规则可 100% 覆盖,但全盘 Top-N 只能遍历部分目录(实测约 160 个顶层/浅层目录后截断)。 截断时报告与工具返回值都会标记 partial 并说明原因,不会伪装成完整结论;需要更高覆盖率可调大 topTreeTimeBudgetMs(代价是等待更久)。可执行结论来自热点规则,Top-N 只作兜底,因此截断不影响五级清单的可用性。
  • 释放量核算的两种口径:小体量清理(数十 MB 级)时「盘符空闲净增」可能为 0(被其他进程同时写入掩盖),此时以「逐项测量合计」为准,报告里会同时给出并注明。
  • 迁移耗时与被迁移体积成正比:迁移是「复制 → 校验 → 删源 → 建联接」,数十 GB 的目录会很慢(工具超时上限 15 分钟);被应用占用的目录会在删源阶段中止并回滚副本。
  • app-config 类迁移不自动改配置:插件只搬数据(并建立目录联接保证应用仍可用)并给出建议命令;是否让应用改用新路径由用户确认后自己执行,避免静默改坏环境。
  • 扫描可能被时间预算截断:热点清单与全盘 Top-N 各有 70 秒预算(可配 hotspotTimeBudgetMs / topTreeTimeBudgetMs),超时即截断并在报告与工具输出里标注,绝不当成「扫全了」。
  • 定时扫描默认关闭且不做系统级唤醒:依赖宿主进程存活(DSH 没跑就不会扫);需要开机级定时请用 Windows 任务计划调用 dsh 或本插件的 action=scan。
  • 趋势不跨机器迁移:历史文件是本机的,换机或删掉历史后第一次扫描没有对比基准(不会报错,只是不显示趋势)。
  • 尚未提供交互式确认界面:目前由模型把报告交给用户,用户选定范围后再进入执行链路(M4 提供 GUI 卡片)。
  • 面板的落地条件由平台决定:新增/删除插件包或改 dsh.client 字段必须重启 dsh web(包元数据判定被永久缓存);只改 bundle 内容刷新页面即可(本 profile 的 HMR 关闭)。
  • 面板与工具共用同一套判断,但入口不同:面板只能做「扫描 / 预演 / 执行 / 迁移 / 回滚」这些已在工具里实现的动作,配置类改动(如定时扫描开关、reportDir)仍走 cordis.yml,面板只显示状态、不做持久化设置。
  • 面板任务表在内存里:宿主重启后面板会显示「任务已随宿主重启消失」,正在跑的任务随之中止(已落盘的报告与台账不受影响)。

开发

npm install --legacy-peer-deps   # DSH 类型包 peer 冲突,本地用 legacy 解析
npm run deps:link                # 把宿主自己的 @deepseek-ai/* 链接进 node_modules(见下方说明)
npm run typecheck                # 类型检查
npm run smoke                    # 快速自检:规则匹配 / 盘信息 / 限时测量
npm run m2                       # M2 执行层隔离用例(真实删除只发生在 %TEMP% 沙箱)
npm run m3                       # M3 迁移层隔离用例(真实迁移只发生在 %TEMP% 沙箱 + D:\dsh-cc-m3-test)
npm run m4                       # M4 历史/趋势/JSON/调度语义(假扫描,秒级;含一次真实热点扫描)
npm run m4:live                  # M4 定时扫描端到端(真扫盘,约 1 分钟;历史数字与 fs.statfs 实测对比)
npm run m5                       # M5 面板宿主侧:分级/预演=执行同一条路/真暂存区/真迁移/取消/RPC 端点(含一次真实热点扫描)
npm run m5:client                # M5 客户端 bundle 契约:重放浏览器的模块加载并真渲染一次面板(离线,秒级)
npm run m5:live                  # M5 活体验证:直接问运行中的 dsh web 要 boot manifest 与产物(含与本地构建的哈希比对)
npm run market:check             # 发布体检:把"能不能被 DSH 市场自动收录"的硬门槛钉成测试(离线,秒级)
npx tsx tests/tool-run.ts full    # 无头跑完整扫描,产出真实报告
npm run build                     # 编译到 lib/ 并打包 client/client.js(发布物)
npm run build:client              # 只重新打包客户端 bundle(改了 client/src 之后)

⚠️ 不要用 PowerShell 的 Get-Content/Set-Content 管道改写本仓库的 UTF-8 文本文件 (默认编码会把中文写成乱码并使 package.json 变成非法 JSON);请用编辑工具直接改。

⚠️ 不要跑不带 --legacy-peer-deps 的 npm install:它会按 peer 解析 prune 掉 @deepseek-ai/dsh-tools / dsh-llm 等提供类型的包,导致 npm run build 报 implicit any。装完请复验 npm run build。

⚠️ @deepseek-ai/dsh-tools 一族把自己的运行时依赖声明成 peerDependencies,所以 --legacy-peer-deps 永远不会装它们(测试会以 ERR_MODULE_NOT_FOUND: Cannot find package '@deepseek-ai/dsh-xxx' 崩掉), 而普通 npm install 又会把它们 prune 掉。npm run deps:link 用目录联接把宿主自己那份副本挂进 node_modules,于是测试跑的就是宿主真实加载的包,且与宿主版本严格一致。该命令幂等,装完依赖重跑一次即可。

许可

MIT

—/ 5

No ratings yet

Verified DSH bundle

Commit 806707b80e35

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout