Replies: 3 comments 1 reply
|
同盘、profile 外的目录这个我也复现了。在 Windows 上用了当前 master(5badb15)的 ignored 判断和 Chokidar 4.0.3:分别修改文件三次,profile 内的目录收到三次 change,外面的目录一次都没收到;同一个外部目录去掉 ignored 后,三次都能收到。 不过 patch 文件那一段在当前 master 上没有复现。watchConfig 会先去掉 ignored 和 cwd,再单独监听配置文件。我把配置放在测试目录的 .dsh 下面,用现有的 watchConfig 跑,三次修改都收到了。 这里测的是真实文件监听和 watchConfig,没有启动完整 DSH。修法上想先确认一下:自定义 ignored 现在是相对 profile 目录匹配的,这个语义需要继续保留吗?改成相对每个 root 后,一些现有规则的含义可能会变。 |
|
感谢复现,也感谢指出 patch 那一段 —— 你是对的,那一段我撤回。 关于 patch/config 那一段:我错了,而且是我自己不严谨那一段是我从谓词推断出来的("同一谓词也管着 manifest/patch 的监视"),我把它写成了断言,没有实测。按你指出的
也就是说:配置文件确实是被单独监听的,profile patch 的改动会即时生效,你和我各自的测试在这一点上一致。原文第二段("第二个后果:点号目录下的配置也不会被热重载")请当作无效。 关于修法:
|
| 配置的监视根 | 结果 |
|---|---|
工作区在另一个盘(X:\...) |
改动 Host 模块会在进程内重载(复现两次) |
| 同盘、profile 之外(两处不同路径) | 同样改动 30 秒内毫无反应 |
| 同盘、profile 之内 | 改动 2 秒内生效(/status 的 revision 翻转) |
这与你 chokidar 层面的结果是同一个根因:跨盘时 path.relative 退化成绝对路径、不带 ..,所以"恰好能工作" —— 这也是它长期没被发现的原因。
|
感谢补测 —— 你这两条反例都成立,而且我上一轮给的修法是错的,我撤回。 你的两条反例:一条我复现了,一条我没有,如实说我把你的场景做成了真实文件监听(真的
你的第 2 条(自定义规则)我确认成立: 你的第 1 条(
我们大概不是同一套归一化代码:我测的是 还有一条你可能也会关心:
|
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
更正(2026-10-05,本正文已按实测重写)
原文的核心结论 ——「默认忽略规则会静默丢弃整个同盘、profile 之外的监视根,热重载等于关闭」—— 是错的,我撤回。经复测:
**/.*把开头的..段当成点号文件段匹配掉」)不成立:**/.*对单个..匹配,..后面还有内容才失配(picomatch('**/.*')('..') = true,('../..') = false,'../a/.cache') = false);**/.*一条 —— 前导..让四条默认规则全部失配(../a/node_modules、../a/cache、../a/.cache均为false,去掉前缀均为true);normalizePath()(sysPath.normalize()再replace(/\\/g, '/')),所以那是应用里不会出现的输入;原文的
摘要、根因两节与那张表因此作废,下文是重写后的版本。原文中仍然成立的部分("不是安全问题"、环境)保留在末尾。摘要(重写)
dsh-hmr的ignored谓词不感知「监视根相对 profile 目录的前缀」。当监视根位于 profile 之外时,relative(profileDir, path)以..开头,默认的["**/node_modules", "**/.*", "cache", "data"]全部失配,于是node_modules、.cache、cache、data这些本该排除的目录不再被排除 —— 而故障是静默的:没有报错、没有警告日志。另外cache与data两条默认规则是基名锚定的,只在相对路径最顶层生效,与 root 位置无关,因此在 profile 内它对本就是失效的。根因(重写)
dsh/node_modules/@deepseek-ai/dsh-hmr/lib/index.js(默认配置在:240-246,谓词与 watcher 在:379-392):relative(profileDir, path)对「同盘但在 profile 之外」的候选返回以..开头的路径,而四条默认规则没有一条是为这种前缀写的:同时,
cache与data这两条没有**/前缀,是基名锚定的,只在相对路径最顶层匹配:也就是说这两条对任何嵌套的
cache/data目录从来就不生效,profile 内也一样。实测证据(重写)
A. 谓词层(真
picomatch4.0.4 回放) —— 上节命令即证据,结论是"前导..让四条默认规则全部失配",而不是"整棵树被忽略"。B. 监听层(真
chokidar4.0.3 + 真picomatch4.0.4,真实目录树) —— 同一份谓词,两种监视根布局各跑一遍,判据为「源码文件必须触发;node_modules/.cache/cache/data必须静默」:node_modules.cachecachedata两栏的"泄漏"是同一个根因:候选路径不被任何默认规则覆盖;差别只是前缀。
C. 说明等级,避免又一次把结论说过头 —— 上表来自复现监听环境的测量(真实的
chokidar/picomatch/目录树,shipped 的调用形状),不是在「以外部 root 启动的完整应用」里测的。我没有那个直接证据,理由见下节。另一件独立的事(这条是完整应用里实测的):运行中改
root不会重建监视器原文那句"线上行为与表格完全一致(外部同盘根 30 秒无反应)"的观测本身是真的,但真因不是谓词:
root改成同盘、profile 之外的目录(目录先建好,再触发一次配置重载):之后连改三次 revision 常量,30 秒以上毫无反应;改回 profile 内那份,立刻恢复;hmr服务:它自报的root始终是原来的%DSH_HOME%\profiles\desktop\dev-plugins—— 那个外部 root 根本没有被建成监视根;watch(root, …)只在start()里出现一次,配置重载路径只调用reconcileProfilePatches。所以那句话应该写成:改 patch 里的
root不会重建已在运行的监视器,外部 root 只会(可能)在下次启动时生效 —— 后半句我没有验证,不断言。原文据此得出的"整个根被静默丢弃"是把这个真因误记到了谓词头上。建议修法(重写,且不作为结论)
我原来推荐「剥掉开头的
..」是错的:剥掉的正是 pattern 需要的信息,node_modules/.cache的排除会一起坏掉,自定义规则也对不上候选。在我实际对照过的三种谓词里(shipped / 剥前缀 / 相对每个 root),只有"判定相对每个 root"同时满足两种布局,也能连
cache/data那条一起修好:但我不把它写成结论:判据(以外部 root 启动一次应用、改一次源码、看是否触发)我还没做。下面两条我认为属于维护者的 API 决策,不该由报告者顺手定:
ignoreBase: 'profile' | 'root'或别的方式;cache/data若本意是全局排除,应写成**/cache/**/data(或移出默认表)。无论如何建议保留一条:当某条 ignore 规则把某个配置的 root 整个吞掉时打 warn。这个 bug 每一版的代价都在「静默」上。
不是安全问题
明确一点:这不是认证或沙箱绕过。与安全相关的只有「排除规则静默失效会让被监视的范围超出预期」。它对
/api围栏或插件加载器的信任模型没有任何影响。环境
Windows 11 x64,DSH
0.2.0-rc.2(desktop profile),Node 24。All reactions