DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

xuehun2 /

xuehun2/dsh-files-plus

Verified

Workspace files context menu for DeepSeek Harness with copy, cut, paste and keyboard shortcuts.

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

dsh-files-plus

为 DeepSeek Harness Web 客户端右侧「工作区文件」树提供完整的右键文件操作,并新增复制 / 剪切 / 粘贴与键盘快捷键。

独立插件,不修改 dsh-menu;纯 Host 路由 + 纯前端 React 组件,无第三方依赖、无构建步骤。

GitHub: xuehun2/dsh-files-plus

icon


功能

在右侧栏「工作区文件」树中右键任意文件、文件夹或文件树空白区域:

菜单项 快捷键 说明
粘贴到文件夹 / 所在文件夹 Ctrl+V / ⌘V 目录行粘贴到该目录;文件行粘贴到其父目录;无选中时粘贴到文件树根目录
复制 Ctrl+C / ⌘C 把选中的文件/文件夹放入插件剪贴板(不写系统剪贴板)
剪切 Ctrl+X / ⌘X 标记为移动;粘贴成功后删除源条目
复制文件路径 — 把绝对路径写入系统剪贴板
新建文件夹 — 内联输入;目录行在其内部创建,文件行在其父目录创建
重命名 — 内联输入,支持中文输入法组合输入、Enter 提交、Esc 取消
在文件管理器中显示 — 调用官方 remote.session.openWorkspacePath({ action: "reveal" })
在浏览器中打开 — HTML/SVG/XML 优先使用系统浏览器关联,否则使用默认应用;目录打开可浏览的 HTML 列表
在 VS Code 中打开 — 走宿主官方 open-in-app 目录;文件优先使用系统关联,未找到关联时打开所在文件夹
在此处打开 PowerShell — Windows;优先 pwsh,回退 Windows PowerShell,窗口工作目录为目标目录
在此处打开 cmd — Windows;窗口工作目录为目标目录
下载文件夹 / 文件 — 目录流式打包 ZIP;文件直接下载
删除(红色) — 二次确认后递归删除

空白区域右键(0.1.2)

在文件树空白处右键会打开“当前文件夹”菜单,不再弹浏览器原生菜单。空白区域包括:

  • 文件树根区域下方;
  • 某个已展开目录的子项下方;
  • 当前行按钮之外的目录行内边距。

菜单内容按当前位置推断:

菜单项 说明
粘贴到此处 粘贴到当前推断出的文件夹(有剪贴板时可用)
复制当前文件夹路径 复制该文件夹的绝对路径
新建文件夹 在该文件夹内创建
在此处打开 PowerShell / cmd Windows;在该文件夹打开独立控制台窗口
在文件管理器中显示 打开该文件夹位置
在浏览器中打开 打开该文件夹的 HTML 列表
在 VS Code 中打开 用 VS Code 打开该文件夹

目录行自身的按钮右键仍是原来的行菜单(复制/剪切/重命名/删除等);只有目录展开后的空白子区域才按“当前文件夹”处理。

新增的复制 / 粘贴能力

  • 单击选中:点击文件树任意行即选中,行左侧出现品牌色高亮条;右键也会先选中该行。
  • 快捷键直接操作:选中文件/文件夹后按 Ctrl+C 复制、Ctrl+X 剪切;选中文件夹后按 Ctrl+V 粘贴到该文件夹,选中文件时粘贴到其父文件夹。
  • 粘贴目标推断:
    • 选中目录 → 粘贴进该目录;
    • 选中文件 → 粘贴进文件所在目录;
    • 没有选中、但焦点仍在文件树 → 粘贴到当前树根目录。
  • 冲突自动保留双方:目标已存在同名条目时,自动生成 名称 - 副本、名称 - 副本 2…… 不覆盖、不丢数据。
  • 剪切语义:剪切只做标记,粘贴成功后才删除源文件;粘贴失败时源文件保持不动。
  • 跨会话:剪贴板记录源会话 id,可把 A 会话工作区的文件粘贴到 B 会话工作区;Host 会分别校验两端路径。
  • 状态提示:底部居中 toast 显示复制、粘贴、剪切、重命名、删除等结果;粘贴期间显示常驻「正在粘贴…」提示。

交互与视觉

  • 毛玻璃浮层 + 主题 token(--dsw-alias-*),自动跟随深色 / 浅色模式。
  • 菜单支持 ↑ ↓ Home End 导航、Enter 执行、Esc 关闭、Tab 切换焦点;点击外部、滚动、窗口缩放会自动关闭。
  • 菜单内直接显示当前剪贴板条目,可一键清除。
  • 危险操作(删除)使用错误色,并需二次确认。
  • 中英双语,跟随界面语言。
  • 不替换宿主组件、不改宿主样式表;只通过主题 token 和 data-* 属性做轻量高亮。

快捷键

操作 Windows / Linux macOS
复制选中项 Ctrl+C ⌘C
剪切选中项 Ctrl+X ⌘X
粘贴 Ctrl+V ⌘V

不会劫持快捷键的场景(避免影响正常编辑):

  • 焦点在输入框、文本域、contenteditable、role="textbox" 或终端(.xterm)内;
  • 文件树中已有非空文本选区(此时保留浏览器原生复制);
  • 菜单打开期间(菜单内输入框可正常粘贴文本);
  • 最后一次鼠标交互不在文件树内,且焦点也不在文件树内。

实现上使用 window 捕获阶段监听,因此不会与浏览器默认的复制/粘贴重复触发。

提示:在文件树中单击文件会同时打开预览。若预览已经取得焦点,快捷键会按“最后一次交互是否仍在文件树内”判断;此时请先点回文件树中的行,或直接使用右键菜单里的“复制 / 粘贴”。


安装

方式 A:从本地目录安装 Bundle(推荐)

  1. 保持仓库目录存在(无需构建)。
  2. 打开 Harness 的「插件管理」→ 安装 Bundle,目标选择本仓库目录的绝对路径:
    C:\Users\血魂\Documents\deepseek-harness\default-workspace\dsh-files-plus
    
  3. 安装后确认 bundle 行 workspace-files-plus 为启用状态。
  4. Host 半区若未热更新,重启 DSH 宿主进程;随后浏览器硬刷新(Ctrl+Shift+R)。

方式 B:作为普通本地包链接

如果已配置 pnpm 与 profile,也可以由插件管理器完成安装;不要手工修改 profile 的 package.json / cordis.patch.yml。

与 dsh-menu 共存

本插件是独立实现,不修改也不依赖 dsh-menu。两者的右键入口都监听文件树行,但本插件在 window 捕获阶段处理并阻止事件继续传播,因此两者同时启用时只会弹出本插件的菜单,不会出现两个菜单。

仍建议在确认新插件工作后停用 dsh-menu,避免保留一套不再使用的 Host 路由和 UI 组件。


目录结构

dsh-files-plus/
├── index.js                 # Host 半区:文件操作、复制/移动、ZIP;VS Code 由官方 open-in-app 负责
├── client.js                # Client 半区:右键菜单、选中态、剪贴板、快捷键
├── cordis.patch.yml         # 把插件插入当前 profile
├── package.json             # 包元信息、bundle/client 声明、scripts
├── locale/
│   ├── zh.json              # 插件管理页中文标题/描述
│   └── en.json              # 英文标题/描述
├── icon.svg                 # 插件图标(原创)
├── scripts/
│   └── smoke-host.mjs       # Host 路由冒烟测试(真实临时文件系统)
├── README.md
├── CHANGELOG.md
├── LICENSE
└── NOTICE                   # 对 dsh-menu MIT 代码段落的署名

工作原理

Client 半区(client.js)

  • 在 window 捕获阶段监听 pointerdown / contextmenu / keydown,只处理 [data-files-entry] 行。
  • 通过 ctx.sidebarRight.commandTarget(row) 解析当前会话 id;通过文件树根节点的 data-files-root 读取工作区根。
  • 选中状态保存在插件内存中,并在行上写入 data-dshx-selected / data-dshx-cut,由注入的 CSS 绘制高亮。
  • 右键菜单挂载在 shell.overlay 槽位,是一个独立的 React 浮层;状态用轻量 observable store + useSyncExternalStore。
  • 不依赖 @deepseek-ai/dsh-client-ui-primitives,只使用 React 和主题 token。

Host 半区(index.js)

  • 通过 connection.fetch.register 注册 /api/workspace-files-plus/* 路由。
  • 每个请求都带 sessionId,Host 解析该会话的工作区根,要求路径严格位于工作区内,并做 processPathFromHostPath → fs.resolve → processPath 往返校验。
  • 复制/移动使用 node:fs/promises 的 cp / rename;跨卷移动失败时回退为 cp + rm。
  • 目录下载是手写的流式 stored ZIP(UTF-8 文件名、CRC32、data descriptor),不落临时文件。

Host 路由

错误响应统一为 { ok: false, error: { code, message } }。

路由 方法 参数 行为
/api/workspace-files-plus/transfer POST { sourceSessionId, targetSessionId, sourcePath, targetDirPath, op: "copy"|"cut", conflict: "rename"|"overwrite"|"error" } 复制或移动一个文件/文件夹到目标目录
/api/workspace-files-plus/rename POST { sessionId, path, name } 重命名(仅改名,不移动)
/api/workspace-files-plus/mkdir POST { sessionId, path, name } 在 path(必须是目录)内新建文件夹
/api/workspace-files-plus/delete POST { sessionId, path } 递归删除文件或目录
/api/workspace-files-plus/open-terminal POST { sessionId, path, shell: "powershell"|"cmd" } 在目标目录打开独立 PowerShell/cmd 窗口(Windows)
/api/workspace-files-plus/open GET / HEAD ?sessionId=&path= 文件返回内容;目录返回 HTML 列表
/api/workspace-files-plus/download GET / HEAD ?sessionId=&path= 文件直接下载;目录流式 ZIP

VS Code 与浏览器打开不再走本插件自己的 Host 路由,而是调用宿主已安装的官方能力:

  • 目录 → POST /open-in-app/open,body { app: "vscode", path };由 @deepseek-ai/dsh-host-open-in-app 的目录解析器定位已安装的 VS Code。
  • 文件 → remote.session.workspacePathApplications({ path }) 读取系统文件关联,再用 remote.session.openWorkspacePath({ path, application }) 打开;找不到 VS Code 关联时回退为“在 VS Code 中打开所在文件夹”。
  • 浏览器 → 优先匹配系统关联中的 Edge/Chrome/Firefox 等;没有浏览器关联时用默认应用打开。HTML/SVG/XML 在默认打开失败时回退到 /open 原始文件路由。

这样就不再依赖本进程的 PATH 或自建启动器,能正确找到注册表安装、非默认目录(例如 D:\软件\Microsoft VS Code)的 VS Code。

主要状态码:200 成功;400 非法参数 / 非法文件名 / 目标不是目录 / 粘贴到自身内部 / 非 Windows 请求终端;403 目标在工作区之外;404 目标不存在;409 冲突(conflict: "error");413 请求体过大;500 内部错误。

/open-terminal 打开的是独立控制台窗口,不是右侧栏的终端标签;非 Windows 平台不显示这两个菜单项。


安全设计

  • 工作区边界:所有路径先取会话工作区根,再做严格前缀检查(防 D:/workspace2 这类前缀穿透)与双向路径往返校验。
  • 拒绝越界:源路径必须在工作区内;目标目录允许是工作区根本身,但源路径不允许是根。
  • 拒绝自包含:不允许把文件夹粘贴到它自己或它的子目录里。
  • 不覆盖数据:默认 conflict: "rename",同名时保留双方;只有显式请求 overwrite 才替换。
  • 符号链接:lstat 判断条目类型;fs.cp 使用 dereference: false + verbatimSymlinks: true,复制链接本身而不是跟随到工作区外。
  • 浏览器打开隔离:/open 返回的 text/html 一律附加 Content-Security-Policy: sandbox,避免工作区 HTML 以 GUI 同源权限执行。
  • 非 ASCII 文件名:下载响应头按 RFC 6266 同时输出 ASCII fallback 与 filename*=UTF-8''…。
  • 终端启动:终端路径先经过工作区校验,再作为子进程 cwd 传入;不拼接 shell 命令字符串,避免路径注入。

性能与内存

本插件刻意避开了占用内存过高的实现,因此没有引入需要用户预先决策的“大内存”逻辑:

环节 实现 内存特征
复制 / 移动 OS 级 fs.cp / fs.rename,流式读写 不把文件内容读入 JS 堆;内存不随文件大小增长
目录下载 流式 stored ZIP,64 KiB 缓冲 文件内容不进入 JS 堆;ZIP 中央目录元数据随条目数线性增长
目录列表页 opendir 流式读取,最多渲染 2000 项 有界内存,不会为超大目录构建完整数组
剪贴板 单条 { path, name, type, sessionId, op } 常量级
选中态 单个行引用 + 两个 data-* 属性 常量级
DOM 查询 仅用户交互时扫描可见 [data-files-entry] O(可见行数),无轮询、无 MutationObserver
事件监听 3 个 window 捕获监听 + 1 个 focusin 常量级
Toast 单个定时器 常量级

ZIP 的中央目录必须为每个条目保留名称、CRC、偏移等元数据(约几十字节/项),这部分随条目数增长,但不随文件内容增长;极端数十万文件的目录建议改用系统打包工具。目录列表页已在 2000 项处截断并提示,避免单个超大目录撑爆页面内存。

可选但未采用的方案(需要时再启用)

  1. 复制进度百分比:需要在复制前递归遍历源目录、统计文件数/字节数,复制时再逐项回调。代价是额外一次全树 IO 扫描和 O(条目数) 的进度状态;对超大目录会明显变慢。当前选择“无进度、异步完成 + 忙碌提示”。
  2. 覆盖确认对话框:当前冲突自动重命名,最安全且零额外状态;若需要“替换 / 保留两者 / 跳过”逐项选择,需要增加一个冲突队列和对话框状态。
  3. 持久化剪贴板:写入 localStorage 可跨刷新保留,但重启后路径可能失效,且需要处理过期清理;当前仅内存保存。
  4. 拖拽复制:需要接管宿主文件树的拖拽事件并维护拖拽预览,属于另一套交互,未纳入本版本。

配置

粘贴冲突策略

Client 顶部常量:

// client.js
const PASTE_CONFLICT = "rename"; // "rename" | "overwrite" | "error"
  • rename(默认):同名时生成 名称 - 副本,保留双方。
  • overwrite:删除目标同名条目后粘贴,有数据丢失风险。
  • error:直接提示冲突,不执行。

Host 路由本身接受 conflict 参数,因此三种模式都已实现;修改该常量即可切换 UI 行为。

菜单顺序 / 文案

菜单项顺序写在 client.js 的 FilesPlusOverlay 中;中英文文案在文件顶部的 zh / en 字典里。两者都不依赖构建步骤。


开发

环境

  • Node.js ≥ 20(使用 fs.cp、Web Request/Response、Readable.toWeb)。
  • 无 npm 依赖;不需要 pnpm install、不需要打包。

常用命令

node --check index.js
node --check client.js
node scripts/smoke-host.mjs

npm test 等价于 node scripts/smoke-host.mjs。

冒烟测试覆盖

scripts/smoke-host.mjs 使用临时工作区和最小 Cordis 上下文,直接调用已注册的 Host 路由,覆盖:

  1. 同目录复制自动重命名;
  2. 目录递归复制;
  3. 剪切移动并删除源;
  4. 冲突 error 返回 409;
  5. 冲突 rename 生成副本;
  6. 冲突 overwrite 替换;
  7. 拒绝把目录粘贴到自身;
  8. 拒绝工作区外源路径;
  9. 重命名 / 新建 / 删除;
  10. 目录 ZIP 下载有效;
  11. 目录 HTML 列表有界且带 CSP sandbox;
  12. HTML 文件预览带 CSP sandbox;
  13. 终端路由拒绝非法 shell;
  14. 终端路由拒绝工作区外目录(两项校验都不会真的启动终端)。

Git 工作流

仓库按标准特性分支开发:

git switch -c feat/copy-paste
# 编辑、验证
git add .
git commit -m "feat: add workspace file copy and paste"
git switch main
git merge --ff-only feat/copy-paste

提交信息使用 Conventional Commits(feat: / fix: / docs: / chore: / test:)。


已知限制

  • 单选中:一次只操作一个文件/文件夹;多选批量复制尚未实现。
  • 无复制进度:大目录复制只显示忙碌状态,不显示百分比(见“可选但未采用的方案”)。
  • 剪贴板不持久化:浏览器刷新后清空。
  • 无覆盖确认 UI:默认自动重命名;切换为 overwrite 前请确认风险。
  • 跨会话复制:路径按各自会话工作区校验;若源会话工作区已被移动/删除,粘贴会失败。
  • 快捷键焦点:选中文件并打开预览后,焦点可能离开文件树;此时用右键菜单操作,或先点回文件树。
  • 终端窗口:PowerShell/cmd 以独立控制台窗口打开,不是右侧栏的终端标签;非 Windows 平台不显示这两个菜单项。
  • 视觉验证:本仓库的开发环境没有可用的浏览器自动化控制;Host 逻辑通过 14 项冒烟测试,安装后的 Host 插件与 Client shell.overlay 槽位均已确认激活,但最终视觉效果仍需在已连接的 DSH 页面中确认。

验证记录

开发环境实际执行过的检查:

node --check index.js                         -> OK
node --check client.js                        -> OK
node scripts/smoke-host.mjs                   -> host smoke: 14 checks passed
plugin_manager install_bundle (local path)   -> application: applied
plugin_manager list_bundles                  -> dsh-files-plus 0.1.2 linked
Config.listConfigs (dsh-files-plus)          -> Host row present, packageDir resolved
Slots.listSubTree (shell.overlay)            -> workspace-files-plus occupant active
plugin_manager list_plugins                  -> include:workspace-files-plus active

说明:

  • Host 路由使用最小 Cordis 上下文 + 真实临时工作区做了完整往返测试(复制、剪切、三种冲突模式、边界、重命名/新建/删除、ZIP、CSP)。
  • 对运行中的 Web 端口直接发起未认证请求会得到 401,说明请求在认证层被拒绝,无法用这种方式替代页面内已认证连接来验证路由;因此 Host 运行态以插件 fiber active + 冒烟测试为准。
  • VS Code / 浏览器打开改为调用宿主官方的 open-in-app 路由与 remote.session.openWorkspacePath;open-in-app 相关插件在 profile 中均为 active,但本环境没有浏览器内自动化,未做“真正弹出 VS Code / 浏览器”的端到端验证。
  • 0.1.2 新增了 Host open-terminal 路由。浏览器硬刷新只会加载新的 Client 菜单;必须重启一次 DSH 宿主进程,/api/workspace-files-plus/open-terminal 才会注册,终端菜单项才能成功。
  • 未进行截图或 DOM 级视觉验证;请以浏览器中实际渲染为准。

许可与致谢

MIT。见 LICENSE。

Host 半区的 ZIP 写入器、内容类型表和目录列表页参考/改编自 MIT 许可的 dsh-menu,署名见 NOTICE。VS Code / 浏览器打开使用 DeepSeek Harness 自带的 open-in-app 能力。右键菜单、选中模型、剪贴板、快捷键与复制/剪切/粘贴传输路由为本仓库独立实现。

—/ 5

No ratings yet

Verified DSH bundle

Commit d8322f14be1a

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