文章

Windows 绝对路径为什么会让 Hermes 的 Markdown 预览失效

从一个 Windows 本地 Markdown 预览故障出发,记录绝对路径判断、回退逻辑和上游修复的验证过程。

在 Windows 上给 Hermes 打开本地 Markdown 文件时,我遇到过一个很容易被误判的问题。文件本身存在,Markdown 内容也没有损坏,预览页却没有读到目标文件。开发者工具里能看到一条重复路径,当前工作目录被拼到了原本已经完整的 Windows 路径前面。[1]

例如,原本应该直接打开的路径类似这样:

C:\Users\<user>\AppData\Local\hermes\workspaces\article.md

失败后的目标却变成了把当前目录再次放在前面。这个结果看起来像文件系统或 Electron IPC 出错,继续看代码后,问题收缩到了本地预览目标的绝对路径判断。

回退路径把问题暴露出来

Hermes 的本地预览有一条回退路径。当 Electron IPC 的路径规范化没有返回可用目标,或者 bridge 不可用、调用抛出异常时,渲染端仍然会处理传入的路径。[1]

相对路径需要拼接当前工作目录。原来的判断只把以 / 开头的字符串当作绝对路径。这个规则在 POSIX 路径上成立,Windows 的盘符路径却从盘符字母开始,UNC 路径则从反斜杠开始。

于是下面几类路径会被错误地当成相对路径:

C:\Users\<user>\notes\article.md
c:/Users/<user>/notes/article.md
\\server\share\article.md

它们都已经包含了完整的定位信息,却被送进了需要拼接 cwd 的分支。问题不在 Markdown 渲染器,甚至也不需要先怀疑文件权限。路径类型在进入渲染器以前就已经被判断错了。

修复只改变判断,不改写路径

修复的方向很克制。代码继续保留以 / 开头的 POSIX 绝对路径判断,同时增加 Windows 盘符和 UNC 前缀判断:[1]

/^[a-z]:[/\\]/i

以及反斜杠开头的 UNC 路径检查。

这样处理后,绝对路径会原样交给预览逻辑,相对路径仍然按照原来的规则拼接当前工作目录。修复没有把所有字符串都当成绝对路径,也没有在渲染层做一次额外的路径重写。

这点很重要。跨平台修复最容易出现的副作用,是为了覆盖一个平台而破坏另一个平台的相对路径语义。这里保留了路径分类,只补上 Windows 缺失的两类前缀。

测试覆盖了四种边界

这次改动补了四个单元测试,分别覆盖 Windows 盘符路径、小写盘符路径、UNC 路径和相对路径;原有 17 个测试继续通过,总数达到 21 个。[1]

测试重点放在不同类型的输入是否进入正确分支:

  • 大写盘符不被拼接当前目录;
  • 小写盘符也不依赖字符串大小写;
  • UNC 路径保留网络共享语义;
  • 相对路径仍然基于 cwd 解析。

这类测试规模很小,却比只加一个回归样例更有用。它把修复的边界写成了代码,后面再改预览目标处理时,至少能知道哪些路径行为不能被改变。

从本地修复到上游提交

我把这个修复整理成了 Hermes Agent 的上游 PR。文章写作时,PR #101849 仍显示为 Open,尚未合并。[1]

所以这篇文章不会把它写成“问题已经在正式版本中解决”。当前能够确认的是,问题现象已经被缩小到 Windows 绝对路径判断,修复已经提交,测试结果和变更范围也已经放在公开 PR 中。合并状态需要以 GitHub 页面后续变化为准。

这次排查给我的提醒很具体:本地文件预览看起来只是一个小功能,实际会经过路径分类、IPC 规范化、bridge 可用性和渲染端回退等多个边界。只测试 POSIX 路径时,Windows 的盘符和 UNC 语义很容易被遗漏。

跨平台路径处理不需要复杂抽象,先把绝对路径的定义写完整,再把每种输入放进对应的测试分支,通常就能避免一类很隐蔽的回退错误。

Sources

[1] https://github.com/NousResearch/hermes-agent/pull/101849 — Hermes Agent PR 101849