## Describe the Bug `dws skill setup --mode mono --target all --yes` 报告 installed=7 且逐项 ✓,但它为各 Agent 目录创建的 `skills/dws` 是符号链接。用 Node 的 `fs.statSync` 访问时报 `EPERM`,Agent 的技能加载器只能静默跳过,最终表现为“setup 显示成功,但 Agent 用不到技能”。 只有直接读共享目录 `~/.agents/skills` 的 Agent 不受影响;不读共享目录的 Agent 完全拿不到技能。 ## Steps to Reproduce 1. Windows 上执行: ```powershell dws skill setup --mode mono --target all --yes ``` 2. 用 Node 读取任一新创建的适配入口: ```powershell node -e "require('fs').statSync(process.env.USERPROFILE + '/.pi/agent/skills/dws')" ``` 3. 报错: ``` EPERM: operation not permitted, stat 'C:\Users\<用户>\.pi\agent\skills\dws' ``` 补充:`fs.lstatSync` 能成功且 `isSymbolicLink() === true`,只有跟随符号链接的 `fs.statSync` 失败。 对照实验(同一台机器、同一路径层级,临时目录用完即删)——目录联接可被正常跟随: ```powershell cmd /c mklink /J "$env:TEMP\dws-junc" "$env:USERPROFILE\.agents\skills\dws" node -e "require('fs').statSync(process.env.TEMP + '/dws-junc')" # 正常返回 cmd /c rmdir "$env:TEMP\dws-junc" ``` ## Expected Behavior - setup 为 Agent 创建的入口应可被该 Agent 读取(目录联接,或该 Agent 真正支持的注册方式); - 至少应在创建后做一次可读性校验,校验失败时不要输出 ✓。 ## Actual Behavior 6 个适配入口全部不可读(`EPERM`):`.pi\agent\skills`、`.qoder\skills`、`.qoder-cn\skills`、`.qoderwork\skills`、`.codebuddy\skills`、`.zcode\skills`;setup 仍逐项输出 ✓,用户无法察觉。 已验证的临时处理:把符号链接换成目录联接后,同一路径 `fs.statSync` 正常、`SKILL.md` 可读,技能被正确加载(实测:技能名 `dws` 恰好 1 条、0 碰撞诊断、`cli_version: ">=1.0.61"` 与二进制一致)。 ## Environment - **OS**: Windows 11(10.0.22631,家庭中文版) - **Architecture**: amd64 - **CLI Version**: v1.0.62(build 2026-09-16T08:35:04Z,commit 70323e14),`npm install -g dingtalk-workspace-cli` - **Go Version**: 未从源码构建(n/a) - 复现用 Node: v25.9.0 ## Additional Context - 技能版本与二进制同步(`cli_version: ">=1.0.61"`),不是技能内容问题; - 影响面取决于各 Agent 是否直接读 `~/.agents/skills`:读的(如 pi)侥幸可用,不读的完全不可用; - 相关命令:`dws skill setup --mode mono --target all`。
Activity
fix(skills): use directory junctions on Windows and validate link rea…
fix(skills): use directory junctions on Windows and validate link rea…
fix(skills): use directory junctions on Windows and validate link rea…
fix(skills): use directory junctions on Windows and validate link rea…
Frank-Chan commentedon Oct 10, 2026
补充一个更严重的下游影响,v1.0.63(build 2026-10-03) 仍然存在。
这个形态不只让 Node 读不到,还会静默破坏基于 robocopy 的备份,而且完全不报错。
环境:Windows 11,dws v1.0.63,
dws skill setup生成的 16 个dingtalk-*适配入口。1. robocopy 无法读取该入口
同场对照:把入口换成目录联接(
mklink /J)后,同一目录退出码为 1(正常),内容完整。2. 更严重:
/MIR把它当空目录同步,目标端被写成 0 字节文件我用
robocopy /MIR把各 Agent 的 skills 目录镜像到备份仓库,结果仓库里这 16 个技能目录全部变成 0 字节文件——源端条目读不出来,/MIR就按「空」处理。技能内容静默丢失,过程没有任何报错,备份静默失效近一个月才被发现。也就是说,这个缺陷除了「技能用不上」,还会破坏别人已有的备份数据。
3. 影响范围
.claude/skills、~/.openclaw/skills、hermes skills 各 16 个入口,共 48 个。同一批目录里其他来源安装的lark-*是正常的目录联接,所以问题只出在 dws 创建的这批。4. 判定与临时处理(供其他人参考)
判定:
Get-Item <入口> -Force | Select LinkType→SymbolicLink(异常) vsJunction(正常)cmd /c dir /AL→<SYMLINK>vs<JUNCTION>Test-Path <入口> -PathType Container对异常形态返回 False,不能拿它判目录原地转目录联接(目标不变、无需管理员权限):
两个坑:
rmdir删不掉这个形态,必须按文件删;..\..\.agents\skills\dingtalk-doc),必须先GetFullPath转绝对路径,否则建不了联接。期望
os.Symlink不带目录标志就会得到这个形态);haofeng0705 commentedon Oct 20, 2026
Hi @JohnMax-clearlove,感谢你提供详细的排查和目录联接对照实验,也感谢 @Frank-Chan 补充 robocopy 备份受影响的情况。理解这种“安装成功但技能不可用、甚至影响备份”的体验确实很困扰。
这是 DWS CLI 技能安装链路的缺陷,修复已经合入 #1529(提交
174e2147)。截至本次回复,公开发布的 v1.0.64 和 v1.0.65-beta.2 尚未包含该修复。根因
dws skill setup会先在临时子目录里创建链接,再移动到最终位置;但链接中的相对路径按最终位置计算,在临时位置上解析不到目标。Windows 上,Go 的
os.Symlink会在创建时检查目标是否为目录。目标解析不到时会创建文件型符号链接,所以dir /AL显示的是<SYMLINK>,不是<SYMLINKD>。发布后它实际指向目录,Node、robocopy 等工具跟随访问时就会失败。旧版也缺少发布前可读性检查,因此仍然输出 ✓。以上是静态分析判断;我们在 macOS 隔离环境观察到了临时链接的相对目标无法解析,但没有在 Windows 原生环境实际复现本 Issue 的
EPERM或完整验证 Node/robocopy 场景。修复方式
skill setup发布前检查目录和SKILL.md可读性,检查失败时尝试复制安装,而不是直接报告链接安装成功。dws skill setup,会替换旧版留下的符号链接。如何处理已有入口
新版本发布前,可参考 @Frank-Chan 上方提供的方案,将异常入口改成目录联接。请先备份并确认入口路径;转换后暂不要再次运行旧版
dws skill setup,根据代码分析,它可能把联接重新换回异常符号链接。包含修复的版本发布后,通过原安装方式升级,并显式执行一次 setup,不能只依赖升级时的自动技能同步:
multi 模式请改用
--mode multi。重启 Agent,并检查入口类型和可读性(multi 模式请改成对应的
dingtalk-*入口):预期
LinkType为Junction,Node 不再报错;若联接不可用而回退为普通目录复制,则应同样可读。若使用过
robocopy /MIR备份,请先核对备份中的技能内容,再重新备份;替换入口不会恢复已经丢失的备份内容。我们先按修复已合入关闭此 Issue,不代表修复已发布或你的 Windows 场景已完成验证。包含修复的版本发布后,如果仍有问题,欢迎继续在这里留言,并提供
dws version、Windows/Node 版本、完整命令及上述检查结果(请脱敏),我们会继续跟进。