dsh-filekit:DeepSeek Harness 的工作区文件工具

前言

在 DeepSeek Harness 里,右侧「工作区文件」面板只能浏览,不能右键、不能拖拽、没有编辑入口,文件变更也无法直接告知 Agent。做智能体开发时,频繁切换工具、手动复制路径、文件被意外覆盖都会打断上下文。dsh-filekit 接管这个面板,把右键菜单、拖拽移动、编辑与可恢复删除这些操作补齐,并让界面变更自动注入当前会话的 Agent。

是什么

dsh-filekit 是一个客户端插件,由 RestRegular 维护。它扩展了 DSH 的右侧栏,接管工作区文件页、新增 FileKit 独立文件管理页与设置页,并为 Agent 提供 filekit 工具与变更通知机制。

安装与启用

dsh plugin --profile web add @restregular/dsh-filekit

安装后重新打开会话:

  • 右侧边栏「开始页」的「工作区文件」卡片下方会出现「FileKit 文件工具」按钮,点击在侧边栏打开 FileKit 页(非弹窗);
  • 打开「工作区文件」页:文件/目录支持右键菜单与拖拽移动;
  • 设置 → FileKit:可配置显示隐藏文件、Agent 变更提醒、删除确认、自动刷新频率与编辑器字号;
  • 预览文件时,预览标题栏右侧仍有编辑/引用/更多按钮。

核心能力

工作区文件树

文件树接管了原生文件页,支持以下操作:

  • 展开/收起目录:点击目录行,每层懒加载,展开状态保留;
  • 打开预览:点击文件行或右键;
  • 右键菜单:在文件/目录/空白处右键,可新建、重命名、移动、复制、复制路径、引用、删除等;
  • 拖拽移动:将文件或目录拖到目标目录或根目录,拖到目录上即移动,禁止把目录拖进自身;
  • 新建文件/文件夹:右键菜单在当前目录或目标目录创建;
  • 重命名:只改名字,不改变所在目录;
  • 移动到…:右键菜单唤起目录选择器;
  • 复制/剪切:把条目放入 FileKit 剪贴板,不立即写入磁盘;
  • 粘贴:在目录或空白处右键粘贴,重名时自动用 名称 (2).扩展名,不会覆盖;
  • 复制路径:提供相对路径与绝对路径;
  • 引用到对话框:右键菜单插入 @相对路径,输入框不可用时退回复制;
  • 删除到回收站:移动到 <工作区>/.dsh-trash,可恢复;
  • 在 FileKit 中打开:右键菜单或预览标题栏按钮打开完整文件管理页。

FileKit 文件管理页

独立侧边栏标签页(filekit kind),提供:

  • 面包屑导航、新建、复制/剪切/粘贴、移动、删除、回收站;
  • 深路径下面包屑横向滚动,每段有最小宽度,过长自动省略;滚动条默认 3px,鼠标移入 6px,不挤压文字;
  • 滚轮和拖动滑块均支持横向滚动;
  • 右键菜单与拖拽移动。

编辑器标签页

每个文件一个独立标签页(filekit-edit kind),与预览页可切换:

  • 预览标题栏的编辑按钮将当前预览标签页切换为编辑页;
  • 编辑页的保存按钮保存后切回预览页;放弃修改确认后也切回预览;
  • 与内置预览共用 Shiki 高亮器、行内滚动同步,支持 Ctrl/Cmd+S 保存;
  • 未保存时标签页标题右侧显示橙色圆点;关闭未保存标签页会被阻止并提示;
  • 工具栏为图标按钮,悬停显示提示文本(复制相对路径、引用、预览、放弃修改、保存)。

设置页

设置 → FileKit:

设置 默认 作用
显示隐藏文件 开 显示以 . 开头的条目
变更后提醒 Agent 开 关闭后不注入变更提醒,节省上下文 token
删除前确认 开 关闭后删除直接进入回收站
自动刷新 关闭 15 / 30 / 60 秒重新读取展开的目录
编辑器字号 12px FileKit 文本编辑器字号

设置保存在浏览器 localStorage(dsh-filekit.settings.v1),按浏览器/设备生效。

Agent 变更通知

从界面发起写操作(新建、保存、重命名、移动、复制、删除、恢复、清空回收站)时,Host 会向当前会话的 Agent 注入一条不唤醒 Agent 的上下文消息,例如:

[FileKit · 工作区变更] 移动 docs/a.md → docs/b.md(工作区:D:\project\demo)。需要更多操作可调用 filekit 工具。
  • inject() 只把通知放入下一个已准入的步骤,空闲时不会叫醒 Agent;
  • 通知是一条完整的用户消息(id + role: "user" + content + source),不会补默认字段;
  • 读取、展开目录、刷新、复制路径不会产生通知;
  • 原地移动/重命名(unchanged)不会产生通知;
  • 设置里关闭「变更后提醒 Agent」后,界面请求会带 notify: false,Host 跳过注入。

filekit 模型工具

Host 同时注册 filekit 工具,与界面共用同一套操作实现:

action: list | read | write | create | rename | move | copy | delete
        trash | restore | purge | emptyTrash
  • path / toDir 为工作区相对路径,使用 / 分隔;
  • delete 是移动到回收站,不是永久删除;
  • trash 列出回收站,restore / purge / emptyTrash 管理回收站;
  • write 支持 expectedMtimeMs 做乐观并发保护,冲突时返回 conflict。

回收站

回收站位于 <workspace>/.dsh-trash/ 下,每个条目是 <时间戳>-<随机串>/ 目录:

<workspace>/
  .dsh-trash/
    <时间戳>-<随机串>/
      meta.json     # name / originalPath / kind / deletedAt / size
      item          # 被移动的文件或目录

恢复时会把 item 移回 originalPath;原路径已被占用时恢复失败,避免覆盖。.dsh-trash 在文件树和 FileKit 中隐藏。

安全与边界

  • Host 只接受来自回环地址、且 Origin 与 Host 一致的请求(防 CSRF);
  • 每个请求必须给出已注册工作区根目录,或与请求会话工作目录完全一致,否则返回 unknown-workspace;
  • 写文件采用原子写入(同目录临时文件 + rename),并通过 expectedMtimeMs 检测外部修改;
  • 文本读取上限 2 MiB;二进制文件(前 8 KiB 含 NUL)只显示元信息,不能用编辑器修改;
  • 不跟随符号链接写文件;指向工作区外的符号链接读取也会被拒绝;
  • 目录移动/复制会检查目标不是自身或其子目录。

已知限制

  • 文件树只能操作当前会话的工作区根目录;
  • 回收站恢复要求原父目录仍然存在;父目录被改名或删除时需要先手动恢复目录;
  • Host 路由只监听本机回环地址;如果通过 Pocket/公网隧道在另一台设备上打开页面,界面数据请求会被拒绝(有意的安全边界);
  • 编辑器按 UTF-8 读写,不做编码转换;超限文件以只读截断方式展示;
  • 文件剪贴板是页面内存状态,刷新页面或重启 DSH 后清空;
  • 接管文件页后,宿主「在系统中打开目录」按钮不再出现在该页标题栏(宿主把该按钮挂在文件页的子槽位里,接管页不使用该子槽位)。

故障排查

会话报 messages[N]: missing field role(422)

0.2.0 及更早版本的变更通知没有带 role / id。只要从界面操作过文件,该会话的历史里就会留下一条不合法的 user/message,之后每次请求都会被 DeepSeek 以 422 INVALID_REQUEST 拒绝(重启也不会恢复,因为坏记录已经落盘)。0.2.1 起通知按完整用户消息构造,并在注入前做结构校验。

已经写坏的会话可用仓库里的脚本修复(先关闭该会话,或退出 DSH;宿主在会话打开期间持有写锁):

node scripts/repair-session-log.mjs --dry-run          # 只检查,不写盘
node scripts/repair-session-log.mjs <session-id>       # 修复指定会话
node scripts/repair-session-log.mjs                    # 扫描 ~/.dsh/sessions 下全部会话

脚本只补 dsh-filekit 来源的缺失 role / id,其余记录保持字节不变;原日志备份为 session.v4.jsonl.zstd.bak-<时间戳>,修复后重新打开会话即可继续。

变更提醒没有生效

通知依赖插件 Host 半边加载。修改 index.js 后需要重启 DSH(或重新加载插件),客户端 client.js 的热更新不会加载 Host 代码。

重启后插件「启用但不生效」,要关掉再打开才恢复

0.2.4 及更早版本在浏览器端只声明了 slots 一个依赖,然后在 apply() 里用 ctx.get('sidebarRightTabs') / ctx.get('sidebarRight') 一次性取右侧栏服务。sidebarRightTabs 由 @deepseek-ai/dsh-client-ui-sidebar-right 在它自己的 apply() 里 provide,而那个插件要等 slots、layout、locale、resources、sessions、uiSession、shortcuts 全部就绪——冷启动页面时它总是晚于本插件激活。于是标签页类型(files 接管页、filekit 页、每个文件的编辑器页)压根没注册,插件看起来「启用着但没反应」;在插件管理器里关掉再打开会重新跑一遍 apply(),那时服务已就绪,所以立刻恢复。

0.2.5 起改为 ctx.inject(['sidebarRightTabs'], …) / ctx.inject(['sidebarRight'], …) / ctx.inject(['locale'], …),服务一出现就注册,冷启动与热重载走同一条路径。

适用场景

适合需要在 DSH 右侧栏直接操作工作区文件、频繁引用文件路径给 Agent、希望有可恢复删除与编辑入口的开发者。插件以当前 DSH 进程权限运行,安装前建议检查源码与许可证。

短结尾

dsh-filekit 把工作区文件面板从只读浏览升级为具备右键菜单、拖拽移动、编辑与可恢复删除的工具,并让变更自动通知 Agent。更多细节见插件目录页与 GitHub 仓库。

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜