dsh-new-workdir

DSH PLUGIN工具与能力

仓库 miqian-nomad/dsh-new-workdir

工具与能力 L5 · 运行验证通过 安全审查:低风险 可信度:金 可安装插件
安装这个插件

为 DeepSeek Harness 提供一键新建独立工作目录并开启干净会话的 DSH 插件,目录即沙盒边界,任务产物互不污染,官方文件零改动。

一句话选型结论

按资料字段整理

dsh-new-workdir 是工具与能力类的 DSH 可安装插件,验证等级 L5 · 运行验证通过,安全审查为低风险,列出 4 项功能,有可直接复制的安装命令。验证通过不等于安全:插件会读写文件、执行命令或联网,装前先到仓库确认它做了什么;涉及密钥或系统权限的,建议先在隔离环境试装。

分类工具与能力 收录类型可安装插件 验证等级L5 · 运行验证通过 安全审查低风险
验证等级 L5 L5 · 运行验证通过
GitHub 星标 0 复刻 0 · 未关闭 issue 0
最近更新 2026-09-28 创建于 2026-09-28
README 24.6 KB 正文体量,越大说明说明书写得越细

安装

可安装插件
在 DSH 里执行,装完用 dsh plugin list 确认已挂上;标了 L4 / L5 的命令已在沙盒里真实跑通
dsh plugin --profile web add github:miqian-nomad/dsh-new-workdir#v0.4.1
  1. 1
    确认版本与运行环境

    兼容的 DSH 版本为 0.2.0-rc.2 等 2 个;版本不匹配时安装会报错。

  2. 2
    执行安装命令

    在 DSH 里执行上面的命令;多包仓库要注意区分具体子包名,别装错包。

  3. 3
    确认已挂载

    用 dsh plugin list 查看列表里是否出现这个插件,出现即挂载成功。

  4. 4
    试跑并检查权限

    加载后跑一个最小用例,确认它能正常工作;同时看它申请了哪些文件、命令或网络权限。

兼容 DSH 版本0.2.0-rc.2、0.1.7-rc.2版本不匹配时安装会报错
Node.js 要求未标注来自仓库 package.json 的 engines 字段
前置依赖无需要同时安装的同级依赖
npm 包名未发布到 npm可用 npm view 查看包信息

能做什么

4 项功能
字段来自项目仓库与公开索引,中文说明由本站标注

dsh-new-workdir:DeepSeek Harness 里一键领独立工作目录的 DSH plugin

  • 一键领新目录并开干净会话
  • 目录即沙盒,产物互不污染
  • 接管官方新建会话入口
  • 空目录自动回收,失败可回退

适用场景

文件读写存储

上游标签

cordisdeepseek-harnessdshdsh-pluginsessionworkdirworkspace

验证等级与安全审查

L5 · 运行验证通过
自动化流程结论,不是人工审核
验证等级L5 · 运行验证通过在 dsh 沙盒中完成安装与运行冒烟——装得上、跑得起来
安全审查低风险静态分析结论,未标注不代表已通过审查
仓库健康度活跃按仓库活跃度与最近更新时间给出
可信度金综合仓库活跃度与验证结果

上面的结论来自上游最近一次自动化验证(2026-10-08): 同一套检查会在插件发新版后重跑,页面显示的是最新一次的逐项结果。

逐项检查结果

L1 · 已找到 ✓ 通过
  • L1.0_DEFAULTED_FROM_L3 由 L3 推定 默认通过——L3 安装规范已通过(全库 L3 扫描策略)
L2 · 结构化 ✓ 通过
  • L2.0_DEFAULTED_FROM_L3 由 L3 推定 默认通过——L3 安装规范已通过(全库 L3 扫描策略)
L3 · 安装规范 ✓ 通过
  • L3.1_INSTALL_COMMAND_PARSED 安装命令已解析 方式:安装规范解析
  • L3.2_DSH_VERSION_DECLARED DSH 版本已声明 方式:DSH 版本声明
L4 · 安装已测 ✓ 通过
  • L4.1_INSTALL_EXECUTED_CONFINED 受限沙盒内执行安装 方式:沙盒安装执行
  • L4.2_INSTALL_SUCCESS 沙盒安装成功 方式:沙盒安装执行
  • L4.3_ARTIFACT_CONFIRMED 安装产物已确认 方式:沙盒安装执行
L5 · 运行已测 ✓ 通过
  • L5.1_INSTALL_PASSED_SANDBOXED 沙盒安装通过 方式:沙盒安装执行
  • L5.2_WEB_BOOT_READY Web 启动就绪 方式:Web 启动
  • L5.3_HTTP_SERVED HTTP 服务响应 方式:HTTP 请求
  • L5.4_PLUGIN_INVENTORY_ACTIVE 插件清单中已激活 方式:插件清单查询

风险详情

  • 审查结论 通过
  • 结论说明 vet 静态分析未发现可疑行为,判定为干净(clean)。
  • 风险计数 严重 0 / 高 0 / 中 0
  • 风险详情 未发现严重或警告级问题。

选择建议

装之前先看这几条
按条目字段给出的判断,不替你决定用不用

值得选的地方

  • 验证等级 L5:安装和运行都在沙盒里跑通过,装完能直接用的概率高。
  • 静态安全审查为低风险,没有发现明显可疑行为。
  • 有可直接复制的安装命令,不用自己翻文档找入口。
  • 标注了兼容的 DSH 版本(0.2.0-rc.2 等 2 个),按版本装不容易报错。
  • 列出了 4 项功能,能直接看出它解决什么问题。

先想清楚的地方

  • 没有声明 Node.js 版本要求,版本不匹配可能装不上。
  • 验证通过不等于安全:插件会读写文件、执行命令或联网,装前先到仓库确认它做了什么。

更适合

  • 需要在工具与能力场景里给 DSH 补能力的人。
  • 想装完就能用、不想自己排依赖的人。
  • 能接受在本地装依赖、愿意自己确认权限的人。

不太适合

  • 只使用 DSH 官方内置能力、不接受第三方插件的人。

同类对比

6 个同类
同分类里挑最接近的几条,字段以各自详情页为准
插件验证等级安全审查星标兼容版本安装命令
dsh-new-workdir当前 L5 · 运行验证通过 低风险 0 0.2.0-rc.2 等 2 个 有
loopx 未做沙盒验证 未标注 6,233 未标注 无
dsh-startup-screen 未做沙盒验证 未标注 633 未标注 有
minara-skills L4 · 沙盒安装通过 中风险 360 未标注 有
dsh-blender-plugin 未做沙盒验证 未标注 211 未标注 无
tokenledger L5 · 运行验证通过 低风险 204 0.2.0-rc.2 等 11 个 有

仓库档案

工具与能力
字段来自项目仓库与公开索引,中文说明由本站标注
作者 / 维护方miqian-nomad仓库 dsh-new-workdir · 默认分支 main
分类工具与能力tools
收录类型可安装插件声明了 dsh.bundle、可用 dsh plugin add 安装的条目
开发语言JavaScript仓库主语言
许可证MIT商用或二次分发前请确认条款原文
星标 / 复刻 / issue0 / 0 / 0收录时的数值,非实时
创建 / 更新2026-09-28 · 2026-09-28最后推送 2026-09-28
本站收录2026-09-29首次进入本站目录的时间

README 全文

24.6 KB
作者原文,中文版优先;只做安全转义,不改内容

dsh-new-workdir ・ 新目录会话

一键「领一个独立工作目录 + 开一个干净会话」的 DSH 插件。目录即沙盒边界:
每个任务一个目录,产物不再互相污染;工作区标题就是时间戳,侧栏一眼能认出。

官方文件零改动。 全部走公开接口(slot 注册 + 官方 Remote + 一个 loopback
HTTP 端点),只额外在客户端包了一个 uiWorkspace.startSession(见下文)。
DSH 每两三天发一版,升级后最坏也只是那层包装失效、退回官方行为,不会报错。

English — One click gives you a fresh timestamped working directory under your
chosen root, registered as a DSH workspace with a clean session inside it.
Directory = sandbox boundary, so different tasks stop polluting each other.
Zero changes to official files: public slot registration + official Remote calls
+ one loopback HTTP endpoint (plus a single client-side wrapper around
uiWorkspace.startSession, which one config line turns off).


入口一览

入口 位置 说明
文件夹+加号 新目录 输入框右侧(模型选择器左边) 一次点击跑完整条流程,适合日常
新目录会话 设置页左侧列表 同样的动作,外加根目录 / 已建数量 / 最近目录 / 可选目录名
新对话 / ⌘N / Ctrl+Alt+N 侧栏顶部(官方入口) 已接管:官方「新建会话」现在也领新目录
工作区行上的 ⊕ 侧栏工作区行右侧 保持官方:在那一个目录里开会话(目录里已有空会话时官方会直接复用那个)

这两个官方入口长得像、语义不一样,别搵:顶部那个是「给我个新地方干活」
(已接管成领新目录);行内 ⊕ 是「就在这个目录里再开一个会话」(官方语义,

图标是内联 SVG(lucide folder-plus 的 path 数据),跟 currentColor 走主题色。
这里故意不用 emoji:🗂 在中文 Windows 的字体回退链里会渲染成一坨黑块。


点一下发生了什么

POST /api/new-workdir/mkdir          host 半区用 node:fs 在 root 下领一个目录
GET  /api/new-workdir/state          先问一句 root;已经有空目录会话就直接切过去
ctx.workspaces.create({ path })      官方 Remote:把目录注册成工作区
ctx.sessions.create({ workspaceId }) 官方 Remote:在里面开一个干净会话
ctx.uiWorkspace.openSession(id)      切过去(方法不在就静默退化,会话已在侧栏)
POST /api/new-workdir/prune          回收空目录(只删磁盘上真的空的)

连点不会堆目录:复用只认「本次页面会话里刚建、而且还没聊过」的那一个
(内存里记着,刷新页面就清空)。连点两下 → 第二下回到刚建的那个;一旦在里面
发了消息(不再是空会话)或者刷新过页面 → 下一个点击就是崭新的目录。
面板里填了名字 = 强制新建。

不会把你拽到旧工作区(0.3.2 修的):复用不再去扫 root 下其它旧空会话。
以前那一条会把用户几天前留下的空会话当成候选,点「新对话」直接切过去、
一个目录都不建 —— 看起来就像「新会话跑到旧工作区里去了」。

不会留下死目录:sessions.create 失败会重试一次,还失败就把刚建的工作区退
注册表、把空目录收回去,并往 new-workdir.err.log 记一行。

官方「新建会话」也走这条路:DSH 的 session.new(侧栏顶部按钮 / ⌘N)最终
调 uiWorkspace.startSession()。不带工作区 id 时我们接管 —— 先领新目录;带了
工作区 id(工作区行上的 ⊕、工作区选择器里选一个)则原样交给官方。
所以「点新建会话 → 却掉进当前工作区」不会再发生。
cordis.patch.yml 里 bridgeNewSession: false(或 window.__dshNewWorkdirBridge = false)
可整层关掉,关掉后官方入口一字不变。

这层接管到底盖住了谁(0.4.1 补充,之前 README 写得太省):官方客户端里
uiWorkspace.startSession() 是共享方法,无参调用点不止一个,包了它 =
下面这些地方一起变:

调用点 位置 接管后的行为
session.new 命令 侧栏顶部「新对话」/ ⌘N 领新目录(本插件的目标行为)
onNewTask 任务管理面板的「新建任务」 领新目录(符合「新任务 = 新地方」,但请注意它也会建目录)
startCreatorDraft 设置页「让 Agent 帮我创建预设模式」(需开发者工具) ⚠️ 也会领新目录,且官方那段是同步顺序:seat.stage(...) → startSession() → seat.apply();包壳后 startSession 变成异步,seat.apply() 会跑在新会话出现之前,暂存的 preset 可能落到旧会话上
侧栏工作区行的 ⊕ / 工作区选择器 带工作区 id 调用 原样透传给官方,行为不变
其它插件调 startSession() 任意 一样会被接管(方法本身没有「谁点的」这种信息)

要绝对安全就关掉这层:bridgeNewSession: false。插件自己的两个入口(输入框右侧 chip、
设置页卡片)不依赖它,照常工作;关掉后官方「新对话」退回官方语义(留在当前工作区)。

目录名 = YYYY-MM-DD-HH-MM-SS(可选 -自定义标签),与 D:\work-harness
下的历史目录同构;工作区标题 = YYYY-MM-DD HH:MM:SS(官方默认标题是目录名
basename,这里顺手改名成人读格式)。

任何一步失败都会 fail-soft 并把原因回显在按钮上 / 面板里,目录不会半途丢掉。


安全说明(给审计的人看)

会碰什么 边界
删目录(唯一会删东西的地方) POST /api/new-workdir/prune → pruneEmpty(),只 rmdir 空目录,且必须同时满足四条:① 路径 resolve() 算术归位 + realpath() 后确实落在配置的根目录之下(挡 .. 和指向外面的 junction)② 目录名是本插件的时间戳格式 ③ readdir 结果为空 ④ 不在 keep 名单里。任一条不满足只记一笔 skipped,绝不下手
子进程 / 动态执行 无。不 spawn、不 eval、不下载执行;静态扫描能力面 hasExec: false
网络 只有 loopback:两个 HTTP 端点注册在 DSH 自己的 webServer 上,客户端 fetch 的目标恒为同源 /api/new-workdir/*,没有外部端点
凭据 不读 .credentials.yaml、不读任何密钥环境变量;只读 DSH_HOME / DSH_WORKDIRS 这类路径变量
一键停用 enabled: false → mkdir / prune 直接 403(只留只读展示);bridgeNewSession: false → 完全不碰官方「新会话」

自动化静态扫描(@jieai/dsh-plugin-vet,就是 dsh.so 提交页用的那套):
verdict: clean,无 high / critical;唯一的 medium 是 rmdir 这一族 —— 它的边界就是上表第一行。
rmdir 在 src/index.js 只出现两处,都在 pruneEmpty() 内、前面各有一道 resolveUnderAny() 闸。

dsh.so 的全仓扫描会额外在 test-smoke.mjs 上报一条 warning「向裸 IP 地址发起 HTTP 请求」:
那是测试自己起的临时 HTTP server(http://127.0.0.1:<随机端口>)在做真 TCP 回环测试,
只跑在 os.tmpdir() 的临时目录里,不连任何外部地址 —— 这条是误报,已知并接受。


安装

# 从 GitHub 装(推荐:按 tag 固定版本)
dsh plugin --profile web add github:miqian-nomad/dsh-new-workdir#v0.4.1

# 本机开发用这个:link 到源码目录,改完即时生效
dsh plugin --profile web add link:D:/dsh-plugins/dsh-new-workdir

web profile 由 CLI 托管,上面的命令会自动建 junction / 拉取仓库,并把包名写进
dsh.profile.bundles。安装后到设置页「新目录会话」里把 root 改成你自己的
工作目录(默认的 D:/work-harness 只是示例)。

desktop profile 例外:它由 Electron 应用独占管理,dsh plugin 会直接
拒绝(profile "desktop" is managed exclusively by the Electron application)。
手动两步:

New-Item -ItemType Junction `
-Path "$env:USERPROFILE\.dsh\profiles\desktop\node_modules\dsh-new-workdir" `
-Target "D:\dsh-plugins\dsh-new-workdir"
# 然后往 ~/.dsh/profiles/desktop/package.json 的 dependencies 加
#   "dsh-new-workdir": "link:D:/dsh-plugins/dsh-new-workdir"
# 并往 dsh.profile.bundles 里加一行 "dsh-new-workdir"

改完重启 dsh web / 桌面端。


配置

D:\dsh-plugins\dsh-new-workdir\cordis.patch.yml:

- insert:
- id: new-workdir
name: dsh-new-workdir
config:
enabled: true          # false = mkdir 接口 403,只保留只读展示
root: D:/work-harness  # 主根 = 默认根(不带 root 参数的建目录落这里)
roots:                 # 可选:额外的根,按顺序排在面板里
- D:/work-sandbox
- E:/tmp/workdirs
# recent: 8            # 每个根回显的最近目录条数

root 不写时的后备:DSH_WORKDIRS 环境变量 → 再没有就 ~/.dsh/workdirs
(0.4.0 起不再写死 D:/work-harness)。

多个根到底会怎样(root + roots,见表里每一行):

行为 单根 多根
建目录 都落在 root 默认根是 root(第一个);面板每个根一行、各自一个「在这里新建」
顶部「新对话」/ ⌘N 领新目录(root 下) 同上,落在默认根
面板的「已建 N 个」 一个数 每个根一个数
清理空目录 只扫 root 每个根都扫一遍(白名单路径命中任何一个根都算合格)
请求里传了清单外的 root — 直接拒(HTTP 400 ROOT),不会往任何地方写
复用(刚建的那个) root 内校验 清单内任意一个根都行

注意:“根”是这个插件的概念,DSH 本身不分区。换根之后,旧根下的目录仍然是
DSH 的工作区(照旧显示在侧栏),但只有清单里的根会被清理扫到 —— 所以要把旧根
也收进去(写成 roots 的一项),而不是只改 root。

包名已在 profile 的 bundles 里,所以不要再往 profile 自己的
cordis.patch.yml 里插一条同样的 id(会变成重复 loader entry)。


接口(loopback)

GET  /api/new-workdir/state
→ { ok, enabled, root, roots:[{ path, isDefault, count, recent[] }],
count, recent:[{ name, path, mtime }], version }
(顶层 root/count/recent = 默认根,老客户端也认)

POST /api/new-workdir/mkdir      header: x-dsh-plugin: new-workdir
body: { name?: "可选标签", root?: "清单里的某个根" }
→ { ok, path, name, title, root }     root 不在清单里 → 400 ROOT
POST /api/new-workdir/prune      header: x-dsh-plugin: new-workdir
body: { paths?: ["白名单路径"], keep?: ["不许动的"], sweep?: true }
→ { ok, removed: [path], skipped: [{ path, reason }] }

POST /api/new-workdir/log        header: x-dsh-plugin: new-workdir
body: { level?: "info|error", message: "…" }   → { ok }

三个 POST 的请求体上限 64 KB,超了回 413 BODY_TOO_LARGE(不再把任意大的 body
读进内存)。日志每分钟最多 120 行、单文件超过 5 MB 先轮转成 .1(只留一代),
被限流丢掉的条数会在下一次正常写入时记一笔。

prune 的删条件(host 强制,客户端说啥都越不过):① 算术归位 + realpath 之后
真的在 root 之下 ② 目录名是我们的时间戳格式 ③ 磁盘上一个条目都没有
。
① 故意不是字符串前缀比较:D:/root/../outside/x 的前缀恰好是 D:/root/,
但它落在 root 外面。所以先 resolve() 把 .. 算掉,再用 relative() 判断
(结果以 .. 开头 / 是绝对路径 / 是空串一律拒),目录真的存在时再 realpath()
一次,把「root 里那个名字其实是个 junction / 符号链接,指到外面」也挡掉。
越界的路径只进 skipped(reason: outside-root),绝不下手删。
keep 名单里的路径一律跳过;sweep: true 时额外扫一遍 root,把没工作区认领的
孤儿空目录也收掉。
/log 故意不受 enabled 约束 —— 关掉功能后仍然能看到客户端报的错。

mkdir 必带插件头(与 dsh-search-switch 等自家面板同款 CSRF 约定),
只对 loopback + 同源页面开放。

客户端这边还有一道 fail-closed(0.4.1):清理前要先拿工作区 / 会话快照算出
「哪些空目录可以收、哪些一律别动」。快照拿不到(官方客户端服务形状变了,或者 phase
还不是 ready)时客户端一个请求都不发 —— 既不点名的白名单、也不开扫尾,面板直接
说「这次没有清理、也没有扫尾」。以前它会照样发 sweep: true + keep: [],host 就把
每个根下所有空的时间戳目录全收掉,而工作区一个都退不掉(路径对不上号),侧栏留下一排死行。
扫尾开关宁可不用,也不能扫错。

日志:~/.dsh/logs/new-workdir.log(建 / 删各一行),错误另记 new-workdir.err.log
(host 侧失败 + 客户端 reportFailure 都走 POST /log)。


验证 / 回滚

# 离线冒烟(不启动 DSH):64 项 —— host handler(假 req/res + 真 TCP 各一遍)、
# 复用/清理规则、失败回滚、startSession 接管、路径穿越、链接指到外面、并发建房、
# 多根(root + roots)、版本一致、快照不可信时清理 fail-closed、body 超限 413、
# 日志轮转与限流、UI 入口接线(chip / 设置页卡片)。临时目录用 os.tmpdir(),不写死盘符
# 也可以直接 npm test(package.json 里就是这么写的)
# 真机(在临时 root 上跑,不动 D:/work-harness):
#   官方「新建会话」→ 新目录;面板「清理空目录」→ 孤儿目录被扫尾收掉;
#   多根:点 b 那行的「在这里新建」→ 落在 b;再清理 → a 的空目录被收、b 的留着
node D:\dsh-plugins\dsh-new-workdir\test-smoke.mjs

# 装配检查
dsh --profile web --dump-config | Select-String 'new-workdir' -Context 0,4

# 实时接口
Invoke-WebRequest http://127.0.0.1:4180/api/new-workdir/state -UseBasicParsing | % Content

停用:cordis.patch.yml 里 enabled: false(或删 bundles 里的那一行)。
回滚 profile 改动:~/.dsh/profiles//package.json.bak-before-new-workdir-*。


为什么不用 monkey-patch

老插件 dsh-session-folder 的做法是覆盖 ctx.sessionController.create,
好让「点工作区 / 点 + / 打开页面自动连」这三条不带 cwd 的调用路径也领新
目录。代价:

  • create 的形状、调用点、attachSession 校验规则一变就崩,属于跟着版本
    跑的补丁;
  • 它和本插件会抢同一次 create,把新目录会话再套一层目录;
  • 复用空会话的分支不排除 archivedSessionIds,与客户端 clearArchivedCurrent
    来回打转。

本插件把「自动」换成「一键」:不去拦会话创建本身,入口都在自己注册的 slot 里
(外加一处显式的客户端包壳,见下)。session-folder 保留在 profile 里
(enabled: false),随时可改回 true 复活。

本插件只包了一个方法 —— uiWorkspace.startSession,而且:

  • 只在不带工作区 id 时接管;带 id 的调用(工作区行 ⊕ / 选择器)直接
    original.call(ui, id) 转给官方,行为一字不改;
  • 接管那条路自己抛错时,catch 里再调一次官方实现兜底,并把原因写进
    new-workdir.err.log;
  • 官方改了方法名 / 形状,最坏就是这层包装失效、退回官方行为,插件不会因此崩;
  • 幂等标记 __newWorkdirBridge 防重复包装,配置里一句话可整层关掉。

和 session-folder 的本质区别:它拦的是会话创建(sessionController.create 是所有
调用路径的必经之地),还和 host 端校验耦合;我们包的是客户端服务的一个方法
(startSession),创建本身仍走官方 Remote。代价是包壳会盖住所有无参调用点
(见上面那张表),而不只是「用户点新对话」这一条 —— 官方自己的「新建任务」和
「创建预设」也走同一个方法。

0.4.0:多个根 + 不再写死盘符

  • roots:root 是主根(= 默认根),roots 是额外的根。建目录只能落在清单里;
    清理 / 扫尾每个根都扫一遍;/mkdir 传清单外的 root → HTTP 400 ROOT。
    /state 每根报一份 { path, isDefault, count, recent },顶层 root/count/recent
    仍是默认根(旧客户端不受影响)。
  • 面板:根目录那张卡片变成「每个根一行 + 各自一个『在这里新建』」,各自显示已建数量。
  • 不再写死 D:/work-harness:root 不写 → DSH_WORKDIRS → ~/.dsh/workdirs。
  • 测试也不再写死 D:/tmp:临时目录改用 os.tmpdir()(换机器 / 跨平台能跑)。
  • 多根的删除边界仍然只有一层:resolveUnderAny() —— 路径必须落在清单里某个根之下
    (resolve 算术归位 + realpath),否则只记 skipped;而清单只来自配置,不接受请求方自报。

真机验证(两个临时根 a / b):起点 a=0 b=0;点官方「新建会话」→ a=1;
在面板 b 那一行点「在这里新建」→ b=1;点「清理空目录」→ a=0 b=1
(a 那个空的被收,b 那个正在用 → 留着)。

0.4.1:清理 fail-closed + loopback 加固 + UI 冒烟

  • 清理改成 fail-closed(真 bug 修复):以前客户端读不到工作区 / 会话快照(官方客户端
    服务形状变了、或快照还没 ready)时,pruneCandidates 返回空名单,可请求照样带着
    sweep: true + keep: [] 发出去 —— host 会把每个根下所有「时间戳命名 + 磁盘真空」
    的目录
    全收掉,而且因为 path → workspace 对不上号,一个工作区都退不掉:侧栏留下一排
    指向不存在目录的行,还不会自愈(欠账本没记上)。现在快照不可信就整体跳过,一个请求都不发
    (snapshotOk=false → degraded: true),面板明说「这次没有清理、也没有扫尾」。
    这个 bug 有专门的复现脚本验证过:修之前发出去的是 {"paths":[],"keep":[],"sweep":true}。
  • body 上限:三个 POST 的请求体超过 64 KB 直接 413 BODY_TOO_LARGE,不再把任意大的
    body 读进内存。
  • 日志兜底:/log 与审计日志每分钟最多 120 行,单文件超过 5 MB 先轮转成 .1(只留一代),
    被限流丢掉的条数会在下一次正常写入时记一笔;/log 仍然不受 enabled 约束。
  • mkdir 报错说人话:EACCES / EPERM / ENOSPC / ENAMETOOLONG / EROFS 等错误码
    前面加一句中文说明(原始 message 保留在括号里),不再把 EPERM 原样甩给用户。
  • 接管范围写清楚了:startSession() 是官方共享方法,无参调用点不止「新对话」一个
    (还有任务面板的「新建任务」和设置页的「让 Agent 帮我创建预设模式」)—— 见上面的表。
    这是行为事实,不是配置项;要绝对干净就 bridgeNewSession: false。
  • 测试补到 64 项:新增「快照不可信 → 不发 sweep」「phase 不是 ready → 不发请求」
    「body 超限 413」「日志轮转 + 限流」「chip 点击真的跑完 mkdir → 建工作区 → 开会话」
    「enabled:false 置灰显示已停用」「设置页卡片状态未就绪时不崩」
    「标签的 Windows 边界(保留设备名够不着、结尾空格/点不留)」。
  • 状态按页面隔离:lastClaim(刚领的目录)、单飞槽、退注册欠账本以前是模块级的,
    现在都挂在「页面锚点」(该客户端的 sessions 服务对象)上 —— 另一个客户端 ctx 不会串;
    而 chip(根 ctx)和 bridge(inject scope)拿到的是同一个 sessions 服务,所以「连点两下只领
    一个目录」的行为一个字没变。页面隔离有专门的用例盯着。
  • reveal 不再空等:官方 openSession 根本不存在时(形状变了)直接兜底到
    openWorkspace,不再干等 20 × 150ms;只有真的抛错才重试。
  • 补 LICENSE(MIT)与 npm test。

0.3.2:复用规则收窄(一次真事故)

事故:点侧栏顶部「新建会话」,却被切到了 2026-09-27 16:30:32 那个旧工作区
里一个 9/27 就躺着的空会话,而且一个目录都没建 —— 看起来就是「新会话跑到旧工作
区下面新建了一个」。

原因:复用那一步扫的是「root 下所有时间戳目录里的空会话」。而用户自己历年留
下的工作区目录全都符合这个形状,于是第一个命中的旧空会话就成了候选。

现在:复用只认 lastClaim —— 本次页面会话里、由这个插件刚领出来的那一个
(还得仍然空白、未归档)。刷新页面 = 内存清空 = 下一个点击必定新建目录。别人的旧
空会话、归档过的、已经聊过的,一律不碰。

真机验证(临时 root,刷新页面后再点):第 1 次 → 新建 A(count 1);刷新;再点 →
新建 B(count 2,不再被 A 掳回去);紧接着再点 → 复用 B(count 仍 2);面板建 C
后再点 → 只复用 C(count 仍 3)。

0.3.1:按代码审查改的五处

问题 原来 现在
root 边界可被 .. 绕过(严重) underRoot 只比字符串前缀,D:/root/../outside/<时间戳> 能骗过白名单,prune 会把 root 外的空目录 rmdir 掉 hasDotDot 先拒 + resolve() 算术归位 + relative() 判断 + realpath() 挡链接;越界只记 skipped
并发建房竞争 先 pathExists() 再 mkdir(),中间有窗口:两个请求同时抢同一时间戳,第二个直接 EEXIST 失败 直接 mkdir(),把 EEXIST 当「名字被占」;同一个 root 的建房动作串行排队;客户端再加一层单飞,连点两次只领一个目录
清理顺序会留下悬挂工作区 先删目录、再 workspaces.delete(),后者失败只 console.warn → 侧栏留一行指向不存在的目录 workspaces.delete 重试 3 次(150/300/450ms);三次都失败就记进欠账本,下次点清理先补,并写 err.log;回滚路径同样改成「退不掉就不删目录」
enabled: false 没贯彻到 UI 输入框回车 / chip 照样发请求,用户看到的是失败而不是按钮置灰 chip 读一次 state,关掉时置灰显示「已停用」;面板的建 / 清理都先拦一道,回一句人话
版本号两处不一致 package.json 写 0.1.0,运行时 VERSION 是 0.3.0 统一 0.3.1,并加了一条测试盯着这两处

修完的验证:node test-smoke.mjs 45 项全绿(含 .. 穿越、junction 指到
root 外、四个并发建房、退注册失败 → 下次补上的用例);另在临时 root 上跑了一遍
真机(官方「新建会话」→ 新目录;面板清理 → 孤儿目录被扫尾收掉;再建一个目录
后重清 → 上一个目录连侧栏行一起消失)。你的 D:\work-harness 全程没被碰。

边界

DSH 的会话 cwd 是创建期元数据,创建后没有原地换目录的接口 —— 这也是为
什么「新目录会话」只能是新建会话,而「把这个对话搬进新目录」不在本插件范围内
(要自建 fork + agents.create({ meta.cwd }) 流程)。

几个要知道的边界(0.4.1 补写):

  • loopback 接口不等于鉴权:x-dsh-plugin 头是 CSRF 约定,挡的是「别的网页顺手打这个
    端口」,不是「本机别的进程」。本机任何进程都能调 /mkdir、/prune、/log;
    能造成的后果也被限制在「配置清单内的根目录」里(/prune 还只删空目录)。
  • /state 不带头也能读,它会把这台机器上的绝对路径回给你 —— 只在本机端口上暴露,
    别把这个端口转发到公网。
  • 接管的副作用:只要桥接开着,任何调 uiWorkspace.startSession()(不带工作区 id)的
    代码都会领一个新目录,包括官方自己的「新建任务」和「创建设置预设」两条路(见上表)。
  • DSH 的会话 cwd 是创建期元数据,创建后没有原地换目录的接口 —— 这也是为什么
    「新目录会话」只能是新建会话,而「把这个对话搬进新目录」不在本插件范围内
    (要自建 fork + agents.create({ meta.cwd }) 流程)。

常见问题

8 问
答案由本站依据条目字段整理,不引用上游原文
dsh-new-workdir 怎么安装?

在 DSH 里执行 `dsh plugin --profile web add github:miqian-nomad/dsh-new-workdir#v0.4.1` 即可。

dsh-new-workdir 的验证等级是什么意思?

L5 · 运行验证通过。在 dsh 沙盒中完成安装与运行冒烟——装得上、跑得起来

dsh-new-workdir 安全吗?

低风险。vet 静态分析未发现可疑行为,判定为干净(clean)。

dsh-new-workdir 装之前要先确认什么?

先看它会读写哪些文件、执行哪些命令、连接哪些网络地址;验证等级只说明装得上、跑得起来,不等于安全。涉及密钥或系统权限的,建议先在隔离环境试装。

dsh-new-workdir 支持哪些 DSH 版本?

上游记录的兼容版本包括 0.2.0-rc.2、0.1.7-rc.2。

dsh-new-workdir 用的是什么许可证?

上游标注为 MIT。商用或二次分发前请到仓库确认许可证原文。

dsh-new-workdir 有哪些功能?

一键领新目录并开干净会话、目录即沙盒,产物互不污染、接管官方新建会话入口、空目录自动回收,失败可回退。

这条记录的数据可靠吗?

本站按仓库名去重后合并整理,字段以作者仓库与 npm 元数据为准;安装命令、仓库地址与 README 保持原文,带 L4 / L5 标记的安装命令已在隔离沙盒里真实跑通。

工具与能力
按星标排序,可作替代方案

loopx

loopx

LoopX 是面向长周期 Agent 的本地优先控制平面,作为 DSH plugin 为 DeepSeek Harness 提供持久目标、证

未标注验证等级 6,233 星

dsh-startup-screen

dsh-startup-screen

DeepSeek Harness 的启动界面与启动动画插件。

未标注验证等级 633 星

dsh-blender-plugin

dsh-blender-plugin

让 AI 模型通过直连 TCP 通道实时驱动 Blender 的 DSH plugin:15 个工具覆盖视口取帧、任意角度渲染、内循环搜索、

未标注验证等级 211 星

tokenledger

TokenLedger

TokenLedger 为 DeepSeek Harness 提供零配置的 Token 用量记账,自动归属到实际服务请求的中转站,无需凭据即

L5 · 运行验证通过 204 星

deepseek-harness-jev

deepseek-harness-jev

把 TypeSafe Jev 接入 DeepSeek Harness 作为 System One 决策层,为技能与文件选择、任务监督、纠偏和

未标注验证等级 203 星

miqian-nomad 的其它插件

1 个

插件的元信息来自作者仓库;分类、验证等级与安全结论的中文说明为中文整理,最近核验 2026-10-08。