)
oh-my-openagent 卸载残留修复实录Codex 安装 bin 目录记录与 Windows 大小写加固PR #6569 QA 复盘【免费下载链接】oh-my-openagentOmO: Just type mass ulw keyword with your prompt. Now you are the master of graph engineering.项目地址: https://gitcode.com/gh_mirrors/oh/oh-my-openagent本文基于 oh-my-openagent 仓库内 PR #6569 review hardening 的 QA 总结 及其配套证据文件完整复盘两个产品级 P2 缺陷的根因、修复设计与验证方法一是安装时通过一次性CODEX_LOCAL_BIN_DIR覆盖写入的包装器wrapper在卸载时全部残留二是托管在 Windows 上以OMO.CMD大小写形式存储的包装器因大小写敏感判断而漏删。读完本文你将掌握 oh-my-openagentomo cleanup --platformcodex卸载清理的 bin 目录解析优先级、.installed-bin-dir.json记录机制、Windows 平台大小写规范化判定的源码级实现以及一套可复用的隔离安装/卸载端到端 QA 验证方法。缺陷背景两个跨安装/卸载边界的 P2QA 记录于 2026-08-04环境为 Windows 11、bun 1.3.12、node v24.18.0、codex-cli 0.146.0覆盖 PR #6569 评审后遗留的两个产品发现product findingcodex-cleanup.ts缺陷如果一次安装使用了一次性的CODEX_LOCAL_BIN_DIR环境变量仅本次安装生效卸载时因为没有该变量程序会重新计算默认bin 目录从而把真正装过包装器的自定义目录漏掉13 个包装器全部残留。codex-cleanup-bins.ts缺陷Windows 上安装器生成的包装器以.cmd结尾但文件系统在创建时保留大小写安装器写入的小写omo.cmd路径可能落到磁盘上的OMO.CMD由于后缀判断与托管名称查找都是大小写敏感的这个托管包装器在卸载时幸存下来。这两个缺陷的共同特点是只有在 install → uninstall 的跨边界场景下才可见单元测试若不构造完整生命周期很难暴露。修复一记录安装时的 bin 目录卸载时优先回放缺陷机理一次性覆盖导致卸载算错目录在修复前卸载清理通过resolveCodexInstallerBinDir重新推导 bin 目录codex-installer-bin-dir.ts 的逻辑是——显式binDir或CODEX_LOCAL_BIN_DIR优先否则当codexHome等于默认~/.codex时返回~/.local/bin否则返回codexHome/bin。问题在于CODEX_LOCAL_BIN_DIR是安装时一次性传入的例如 QA 脚本中的CODEX_LOCAL_BIN_DIR$CUSTOM_BIN node ... install用户后续卸载时环境里不再有这个变量于是卸载重新推导出默认目录去扫一个从未写入过的位置而真实包装器所在的CUSTOM_BIN完全没被触碰。修复设计.installed-bin-dir.json清单修复的核心思路是安装时记录、卸载时回放。由于包装器内部嵌入了CODEX_HOME但并未嵌入 bin 目录记录必须放在卸载已经知道如何找到的位置——即插件缓存旁边。实现位于 codex-installed-bin-dir.tswriteInstalledCodexBinDir({ pluginRoot, binDir })把{binDir: ...}写入pluginRoot/.installed-bin-dir.jsonreadInstalledCodexBinDir(codexHome)会依次检查两个候选位置marketplace 快照目录codexHome/.tmp/marketplaces/sisyphuslabs/plugins/omo/以及版本缓存目录codexHome/plugins/cache/sisyphuslabs/omo/version/命中即返回什么都没有记录则返回null由调用方回退到常规解析。关键细节cleanupCodexLight在 codex-cleanup.ts 里先读取记录再开始删除——因为清单本身存放在将被删除的受管目录树内部先删就读不到了这是注释中特别强调的read before anything is removed顺序约束。优先级显式参数 环境变量 安装记录 默认推导卸载时的 bin 目录最终由firstConfiguredPath聚合codex-cleanup.ts 传入input.binDir、env.CODEX_LOCAL_BIN_DIR、installedBinDir三者中的第一个非空值。firstConfiguredPathcodex-cleanup.ts会把空白字符串视为未设置因此空CODEX_LOCAL_BIN_DIR不会遮蔽安装时记录——这与resolveCodexInstallerBinDir对空白值的处理保持一致。完整的解析顺序为优先级来源说明1显式binDir参数调用方CLI 参数明确指定必胜2CODEX_LOCAL_BIN_DIR环境变量本次运行显式设置视为有意指令3.installed-bin-dir.json安装记录本次修复新增回放安装时实际落盘位置4默认推导~/.local/bin默认codexHome或codexHome/bin配套的优先级测试与畸形数据处理测试见 codex-installed-bin-dir.test.ts覆盖版本缓存路径回读、快照路径回读、无记录返回null、以及畸形 JSON{ not json与空白值{binDir: }一律返回null而不是产生一个坏清扫目标。修复二Windows 平台大小写不敏感的托管包装器识别缺陷机理.cmd后缀与名称查找的双重大小写陷阱Windows 文件系统对名称解析不区分大小写但会保留创建时的大小写。安装器写的是小写omo.cmd磁盘上却可能以OMO.CMD存在。修复前的卸载逻辑里.cmd后缀判断用endsWith(.cmd)托管名称查找用MANAGED_CODEX_BIN_NAMES.has(name)两者对OMO.CMD都返回 false——于是这个由安装器自己创建的包装器被当作非托管保留下来。修复设计名称规范化与所有权双重要件核心改动在 codex-cleanup-bins.ts 的managedBinNameForEntry非 win32 平台名称原样返回POSIX 上OMO确实是另一个文件不应误伤win32 平台先toLowerCase()再判断.cmd后缀并去掉后缀得到规范化名称供托管集合查找。这样OMO.CMD被规范化为omo落入MANAGED_CODEX_BIN_NAMES而 POSIX 名称完全不受影响大小写匹配没有扩大所有权范围。所有权判定名称 标记/目标双重确认removeManagedCodexBinscodex-cleanup-bins.ts遍历 bin 目录只有同时满足两个条件才会删除规范化后的名称在MANAGED_CODEX_BIN_NAMES中——该集合包含根运行时包装器omo以及各组件package.json的 bin 键omo-comment-checker、omo-git-bash-hook、omo-lsp、omo-rules、omo-telemetry、omo-ultrawork、omo-ulw-execute-continuation、omo-ulw-loop、lazycodex-executor-verify、ulw、ulw-loop外加LEGACY_CODEX_COMPONENT_BIN_NAMES中的旧版名称isManagedCodexBincodex-cleanup-bins.ts判定为受管符号链接仅 POSIX解析目标后命中isManagedComponentBinTarget或isLegacyCodexBinTarget普通文件则读取内容包含RUNTIME_WRAPPER_MARKER或COMMAND_SHIM_MARKER安装器标记。设计要点是标记本身不足以证明所有权——用户复制或重命名生成的包装器会保留标记所以还必须同时满足名称是安装器会写的名称。用户自己的omo、改名后的副本、无关的符号链接都能幸存。防漂移保障覆盖率测试MANAGED_CODEX_BIN_NAMES与插件组件实际 bin 声明之间存在防漂移约束codex-cleanup-bins-coverage.test.ts 递归扫描packages/omo-codex/plugin下所有package.json的bin声明断言每个声明名都在托管集合中——任何组件新增 bin 而不同步登记该测试会直接失败从机制上防止新组件在卸载后残留回归。验证方法单元 RED/GREEN、回归基线、隔离端到端单元测试与回归基线Windows 大小写谓词与记录 bin 目录分别走 RED/GREENbun test packages/omo-codex/src/install/codex-cleanup.test.ts与bun test packages/omo-codex/src/install/codex-installed-bin-dir.test.ts回归范围bun test packages/omo-codex/src/install并与 stash 掉产品改动后的同一运行对比——从261 pass / 2 fail基线变为269 pass / 2 fail8 个新增测试全部通过失败集合不变那 2 个失败是既有项目本地清理失败已有记录见 .omo/evidence/20260803-fix-6320-uninstall-bins/preexisting-projlocal-fails.txt类型检查bun run typecheck:packages退出码 0。隔离端到端证明BEFORE / AFTER 对照QA 的关键是把缺陷放到真实安装/卸载边界上证明。驱动脚本 live-bindir-driver.sh 的流程是用一次性CODEX_LOCAL_BIN_DIR指向mktemp -d生成的自定义目录执行真实本地安装器断言包装器落在自定义目录并检查.installed-bin-dir.json是否记录不带CODEX_LOCAL_BIN_DIR执行卸载完全复刻用户后来的场景断言自定义目录中包装器已被清除且真实~/.codex未被动过。结果对照完整输出见 live-bindir-BEFORE.txt 与 live-bindir-AFTER.txtmanifest 记录卸载后残留结果BEFOREPR head无13 个残留fails1AFTER修复后有指向自定义目录无目录为空fails0BEFORE 是对照组没有修复时精确复现了报告症状说明 AFTER 是真实结果而非 harness 产物。AFTER 中清单内容为{binDir:C:\\Users\\pss\\AppData\\Local\\Temp\\omo-6569-custombin-jTGy45}位于codexHome/plugins/cache/sisyphuslabs/omo/4.19.4/.installed-bin-dir.json。隔离性与安全边界所有安装使用隔离的CODEX_HOME临时目录下每次运行都断言真实~/.codex/config.toml的 shasum05cb7d5a3b6147a929bff1781ba258237c7744e0不变QA 开始前独立确认过其 sha256 为2D70A22821B092AACB25ABE1E129CE37ADA71AA15EB5BC23BB09F03D01019B14、9957 字节未记录任何密钥、认证头、provider token 或环境转储隔离安装验证来自codex-qaskill 的install-verify.sh --self-testinstall-verify.txt 显示插件缓存存在4.19.4、config.toml启用了omosisyphuslabs、9 个组件 bin 链接、agent TOML 链接、退出码 0。一个假阴性的 harness以及为什么被替换验证过程中第一版 live driver 调用的是node packages/omo-codex/scripts/install-local.mjs uninstall结果即使修复已应用也报告包装器残留——假阴性。排查发现install-local.mjs的uninstall是一个 pass-through会通过npx拉起已发布的 omo CLI因此测试的是发布构建而非当前 worktree 的代码且该发布包中甚至不存在cleanupCodexLight。修正后的 driver 改为调用bun packages/omo-opencode/src/cli/index.ts cleanup --platformcodex——与用户实际获得的命令面一致且运行的是本 worktree 的源码。live-bindir-AFTER.txt来自修正后的 driver。这是一条重要的 QA 方法论教训验证目标命令时必须确认驱动的是被测代码而不是被npx解析到的发布版本。残余风险与已知限制QA 总结明确列出的边界记录只在没有显式binDir参数、也没有CODEX_LOCAL_BIN_DIR时被采纳该优先级由测试钉死畸形或空白记录回退到常规解析不会产生错误清扫目标bun run test:codex未在本地跑完Windows 主机上它在 vendored 的packages/lsp-tools-mcp步骤因rm -rf不可用而失败与本次改动无关该门禁由 CI 的ci.ymlcodex-compatibilityubuntu/macos/windows执行重新生成的构建产物packages/omo-codex/scripts/install-dist/install-local.mjs、packages/omo-codex/plugin/components/codegraph/dist/cli.js按仓库惯例被回退而非提交publish.yml会在打包前运行bun run build:codex-install因此发布安装器由当前源码重建上述 live 证明正是基于这些源码重新生成的 bundle 捕获的。小结PR #6569 的这两处加固把卸载干净从推导安装时的意图改为回放安装时的事实CODEX_LOCAL_BIN_DIR是安装事件的一次性上下文卸载端无法重建所以安装端把 bin 目录落盘为.installed-bin-dir.json卸载端按显式参数 → 环境变量 → 安装记录 → 默认推导的优先级消费它同时用toLowerCase().cmd后缀剥离处理 Windows 的大小写保留语义并用名称 标记/目标双重确认避免扩大所有权。配合覆盖率测试与 BEFORE/AFTER 隔离端到端对照这类跨 install/uninstall 边界的残留缺陷得到了可复现、可验证的收敛。相关证据与实现均可从 QA 总结、codex-cleanup.ts、codex-cleanup-bins.ts 继续深入。【免费下载链接】oh-my-openagentOmO: Just type mass ulw keyword with your prompt. Now you are the master of graph engineering.项目地址: https://gitcode.com/gh_mirrors/oh/oh-my-openagent创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考