Skip to content

[Bug] Windows 下 agent setup 无法识别仅大小写不同的重复配置路径 #257

Description

@PaiduiXiaowangzi

[Bug] Windows 下 agent setup 无法识别仅大小写不同的重复配置路径

问题描述

在 Windows 上,如果 CLAUDE_CONFIG_DIRPI_CODING_AGENT_DIR 使用不同的字母大小写指向同一个目录,Claude Code 与 Pi 实际会使用同一个 settings.json,但当前的重复目标预检会把它们识别成两个不同路径。

当前 main 中,writeTarget() 使用 realpathSync() 生成目标路径;Windows 上该调用会保留调用方提供的路径大小写。随后 assertDistinctConfigurationTargets() 使用区分大小写的 Set<string> 判重,因此同一物理路径的不同大小写形式能够绕过预检。

最小复现

在 Windows 上准备一个包含合法 settings.json 的共享目录,让 CLAUDE_CONFIG_DIRPI_CODING_AGENT_DIR 以不同大小写指向该目录,然后同时准备 Claude Code 和 Pi 的配置。

  • 预期:按照现有测试契约,在创建文件或备份前报告重复配置目标。
  • 实际:两个逻辑路径指向同一个物理文件,但因字符串大小写不同而绕过重复目标预检。

核验情况

我已经检索所有状态的 issue 和 PR,并检查开放 PR 涉及的文件,未发现等价报告、现有实现或正在进行的同文件修改。该问题可以使用 Windows 临时目录完全离线验证,不需要 API key、账号或网络。

建议修复方案

我建议保留 writeTarget() 生成的 targetPath 作为唯一真实读写路径,不修改它的大小写;另派生一个只用于判重的路径身份键:

function configurationTargetIdentity(
  targetPath: string,
  platform = process.platform,
): string {
  const normalized = platform === 'win32'
    ? win32.normalize(targetPath)
    : normalize(targetPath);
  return platform === 'win32' ? normalized.toLowerCase() : normalized;
}

assertDistinctConfigurationTargets() 中的 Set 改为保存这个身份键,而不是直接保存 file.targetPath。这样 C:\Users\A\Config\settings.jsonc:\users\a\config\SETTINGS.JSON 在 Windows 下会得到同一个比较键,并在任何写入或备份前触发现有的重复目标错误。

真实的 file.targetPath 仍用于读取、写入、错误提示和回滚,因此不会因为判重而改写用户路径,也不会引入第二份可变路径状态。准备阶段与写入前复检继续调用同一个 assertDistinctConfigurationTargets(),保证只有一套判重规则。

计划补充以下聚焦测试:

  • 保留现有“完全相同路径必须在创建文件或备份前失败”的测试。
  • 给纯身份函数传入 win32 平台语义,验证盘符、目录名和文件名仅大小写不同的路径得到相同身份键;这样现有 Ubuntu CI 也能稳定覆盖 Windows 比较规则。
  • 验证非 Windows 平台仍保持大小写敏感,避免改变其他平台行为。
  • 在 Windows 本地执行端到端回归,确认不同大小写指向同一共享目录时,准备阶段直接失败且没有生成文件或备份。

本次范围只处理 Windows 大小写路径碰撞,不比较文件内容,不改变 Agent 配置格式、安装流程、认证、事务写入或回滚行为,也不扩展到硬链接等其他文件别名。

请问维护者是否同意由我提交这个 PR?在获得明确许可前,我不会开始实现。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions