oh-my-openagent 卸载清理实战:修复 lazycodex6320「omo 命令残留」的 bin 链接所有权判定与端到端验证
oh-my-openagent 卸载清理实战修复 lazycodex#6320「omo 命令残留」的 bin 链接所有权判定与端到端验证【免费下载链接】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 仓库中 lazycodex 议题 #6320 的修复过程展开omo uninstall --platformcodex等价于npx lazycodex-ai uninstall在执行cleanupCodexLight()清理~/.codex下的配置块、agent 链接、插件缓存等状态后却把安装器写入 bin 目录的omo/omo.cmd运行时包装器与组件 shim 遗留在了 PATH 上。文章完整还原了该缺陷的根因、修复设计新增 codex-cleanup-bins.ts 的removeManagedCodexBins、三轮 RED→GREEN 验证、评审加固的三个所有权漏洞以及基于真实安装/卸载入口的端到端证明。读完你将掌握如何用「安装器标记 受管 bin 名称」双重条件安全识别可删除文件、如何复用安装器自身的 bin 目录解析保证卸载与安装目标一致以及如何用负控制实验与真实 surface 驱动证明卸载清理不误伤用户文件。缺陷根因卸载清扫了~/.codex却漏掉了 PATH 上的omoomo uninstall --platformcodex与npx lazycodex-ai uninstall最终都汇入cleanupCodexLight()定义于 codex-cleanup.ts经由 packages/omo-opencode/src/cli/cleanup.ts 的 re-export shim 对外暴露。该函数的工作范围覆盖移除受管的配置块cleanupCodexConfig按清单移除 agent 链接removeManifestListedAgentLinks删除插件缓存、marketplace 快照、运行时与 bootstrap 数据managedGlobalStatePaths与collectBootstrapDataDirsByGlob位于~/.codex之下。问题在于安装器写入的 bin 目录从头到尾不在清理范围之内。安装阶段codex-cache-bins.ts 的linkRootRuntimeBin与linkCachedPluginBins会把根级omoWindows 上为omo.cmd运行时包装器以及各组件 shimomo-ulw-loop、omo-lsp等写入由resolveCodexInstallerBinDir解析出的目录env.CODEX_LOCAL_BIN_DIR ?? ~/.local/bin具体规则见后文。卸载时这些命令原封不动地留在 PATH 上——这正是报告者标记为 MOST CRITICAL 的抱怨用户卸载后依然能敲出omo命令。从源码结构看这个缺陷属于「bin 链接移除」这一类问题议题 #6320 的另外两个部分被明确划在本次修复之外part 2误导性指南属于文档问题part 3配置/agent 残留则由既有cleanupCodexConfig/removeManifestListedAgentLinks路径覆盖。修复方案64 / -1、三个文件的改动本次产品改动仅涉及三个文件文件改动职责codex-cleanup-bins.ts新增64新增removeManagedCodexBins(binDir, platform)扫描 bin 目录并删除携带安装器标记或指向受管组件目标的条目codex-cache-dangling-bins.ts1将既有的isManagedComponentBinTarget导出供卸载复用codex-cleanup.ts接入用安装器自身的resolveCodexInstallerBinDir解析 binDir调用removeManagedCodexBins并在结果上暴露removedBinLinks识别「该删」的三个判据removeManagedCodexBins对 bin 目录中的每个条目按以下顺序判定名称必须命中受管清单MANAGED_CODEX_BIN_NAMES包含根运行时omo、每个组件的package.jsonbin键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并与 codex-cache-legacy-bins.ts 导出的LEGACY_CODEX_COMPONENT_BIN_NAMES取并集保证「单一事实来源」。内容必须携带安装器标记RUNTIME_WRAPPER_MARKEROMO_GENERATED_RUNTIME_WRAPPER出现在根omo包装器里——见 codex-cache-runtime-wrapper.ts 中 POSIX 包装器的# OMO_GENERATED_RUNTIME_WRAPPER注释与 Windows 包装器的rem OMO_GENERATED_RUNTIME_WRAPPER或COMMAND_SHIM_MARKER:: generated by oh-my-openagent Codex installer出现在组件.cmdshim 里——见 codex-cache-command-shim.ts。POSIX 下的符号链接解析链接目标若其解析到 omo 缓存下受管的components/*/dist/cli.jsisManagedComponentBinTarget匹配plugins/cache/sisyphuslabs/omo/.../components/*/dist/cli.js或packages/omo-codex/plugin/...布局则视为受管。以标记为准的关键收益是用户自己放在 PATH 上、与omo无关的同名文件永远不会被误删。另一个与安装期 dangling 清理的区别是安装期的removeDanglingManagedComponentBins见 codex-cache-dangling-bins.ts只删除缓存目标已不存在的链接而卸载期由于缓存本身也要被删除removeManagedCodexBins不管缓存目标是否还在都会移除受管 bin。bin 目录解析卸载必须对准安装写过的目录codex-cleanup.ts 在调用前用resolveCodexInstallerBinDir见 codex-installer-bin-dir.ts确定目标目录优先级为显式传入的binDir参数或CODEX_LOCAL_BIN_DIR环境变量本轮运行显式设置即视为有意为之优先采用安装时记录的installedBinDirreadInstalledCodexBinDir从~/.codex下读取防止安装期用了临时覆盖而卸载时重算默认值扫错目录若codexHome不是默认的~/.codex则为codexHome/bin否则为~/.local/bin。测试证据从 RED 到 GREEN 到真实 surface单元级 RED→GREENREDred-6320.txt在未修改的 dev 上cleanupCodexLight会留下受管的omo.cmd因此expect(await pathExists(rootBin)).toBe(false)失败且result.removedBinLinks为undefined。结果为 11 pass / 1 skip / 2 fail。GREENgreen-6320.txt修复后 codex-cleanup.test.ts 在 Windows 上 13 pass / 1 skip / 0 fail。新增用例覆盖受管根 bin 组件 bin 被移除而未带标记的用户omo与无关.cmd被保留S1/S2platform:win32bin 目录不存在时返回removedBinLinks: []且不抛错S4。POSIX 符号链接分支符号链接用例在 Windows 上skipIf(win32)因此通过 WSLbun 1.3.12在真实 Linux 上执行结果为14 pass / 0 fail证明受管组件符号链接被删除、无关符号链接被保留。负控制实验negative-control-6320.txt仅回滚产品改动保留测试会让两个新增 bin 测试重新失败恢复后回到 13 pass / 1 skip / 0 fail。这直接把测试与修复绑定——测试失败确实由缺陷引起。回滚时第三个失败removes only managed global state是既有的 5 秒超时 flake与 bin 测试无关。真实 surface 端到端证明live-driver.mtslive-driver-output.txtPASS / exit 0用真实的安装器linkRootRuntimeBin向隔离的CODEX_LOCAL_BIN_DIR写入携带RUNTIME_WRAPPER_MARKER的omo.cmd与真实组件 shim外加一个未受管的omo-user.cmd随后调用真实的cleanupCodexLightomo.cmd与omo-ulw-loop.cmd都进入removedBinLinks而omo-user.cmd存活。开发者真实的~/.codex/config.tomlsha256 未变与真实的~/.local/bin列表未变全程未被触碰。类型检查与回归bun run typecheck:packagestsgo全包EXIT 0。bun test packages/omo-codex/src/install/在分支上 257 pass / 8 skip / 2 fail而 pristine dev 为 255 / 7 / 2——2 pass / 1 skip 恰好对应新增的 3 个测试。两处失败均为project-local cleanup的既有环境性问题单独跑这两个文件在回滚产品的情况下结果一致均为 8 pass / 2 fail。此前一次 18-fail 的劣化发生在与typecheck:packages并发运行时的负载之下空闲时为 2。评审加固三个真实漏洞与对应修复2026-08-03首轮评审在第一次修订中发现三个真实缺陷全部修复且每个都有独立 RED 佐证1. 仅凭标记判定所有权不够codex P2 cubic P2标记不能证明文件由安装器创建用户把生成的包装器复制或改名如~/.local/bin/omo.backup后标记仍在POSIX 上指向「看起来像受管目标」的用户符号链接也会被误判。加固后删除必须**同时满足「安装器 bin 名称」与「标记/受管目标」**两个条件MANAGED_CODEX_BIN_NAMES列出根omo与每个组件package.json的 bin 键并与 legacy 名称从 codex-cache-legacy-bins.ts re-export取并集保证单一事实来源Windows 上只考虑name.cmd.backup副本被直接跳过同时 Windows 文件名大小写不敏感条目可能以OMO.CMD形式存在因此先toLowerCase()再判断.cmd后缀与名称POSIX 上OMO是不同文件名称不做小写化所有权判定并未因此放宽。2. 文件系统根目录的 codexHome 绕过了根安全不变式cubic P1当codexHome位于文件系统根目录时resolveCodexInstallerBinDir会得出一个共享系统 bin 目录bin 清扫将扫描它而其余所有清理路径都通过validateManagedCleanupTarget拒绝此情况。加固方案是把该检查导出为codexHomeResolvesToFilesystemRoot见 codex-cleanup-safety.ts并在validateManagedCleanupTarget内部复用同一实现使不变式只有一处定义bin 清扫遇到此类 home 直接跳过。3. 允许清单可能静默漂移新增 codex-cleanup-bins-coverage.test.ts测试遍历真实的packages/omo-codex/plugin目录树一旦任何组件声明了不在MANAGED_CODEX_BIN_NAMES中的bin测试即失败——新组件 bin 不可能悄悄逃过卸载清理。加固的 REDred-review-hardening-20260803.txt根保护用例在根 home 下仍删除了包装器用户复制用例删掉了omo.backup与omo-mine.cmd。GREENgreen-review-hardening-20260803.txt16 pass / 2 skip / 0 fail。真实 proof 被替换而非打补丁第一次修订的 live driver 直接调用linkRootRuntimeBin与cleanupCodexLight评审正确指出这无法验证「出货的安装器/卸载器」集成。它被删除并替换为live-install-uninstall.ps1该脚本只通过生产环境变量配置任何位置都不出现binDir参数也顺带回应了「此前 driver 从未真正走CODEX_LOCAL_BIN_DIR」的评审意见端到端驱动出货入口REAL INSTALL node packages/omo-codex/scripts/install-local.mjs exit0 bin dir after install: lazycodex-executor-verify.cmd, omo.cmd, omo-codegraph.cmd, omo-comment-checker.cmd, omo-git-bash-hook.cmd, omo-lsp.cmd, omo-rules.cmd, omo-start-work-continuation.cmd, omo-telemetry.cmd, omo-ultrawork.cmd, omo-ulw-loop.cmd, ulw.cmd, ulw-loop.cmd REAL UNINSTALL bun packages/omo-opencode/src/cli/index.ts uninstall --platformcodex exit0 bin dir after uninstall: omo.backup installed root omo.cmd: True | uninstall removed omo.cmd: True kept user copy omo.backup: True | no managed bins left behind: True real ~/.codex/config.toml same: True | real ~/.local/bin listing same: True RESULT: PASS真实安装器创建的 13 个 shim 与MANAGED_CODEX_BIN_NAMES完全一致独立印证了允许清单的完整性omo.backup存活则是所有权修复在真实 surface 上的证明而非仅靠单元测试。已知的 Windows 包装器缺陷lazycodex#142与回退路径评审要求优先调用「安装器产出的卸载器」而非仓库源码。driver 先尝试BIN\omo.cmd但在 Windows 上该包装器因另一个已报告的缺陷而完全无法运行 REAL UNINSTALL: the INSTALLED wrapper first installed wrapper present: True BIN\omo.cmd uninstall --platformcodex - exit255 The syntax of the command is incorrect. wrapper failed (known lazycodex#142 on Windows); falling back to the bundle it execs REAL UNINSTALL: bun dist/cli/index.js uninstall --platformcodex (the SHIPPED bundle) path used: shipped dist/cli bundle (bun, as the wrapper execs it) uninstall exit0 bin dir after uninstall: omo.backup根因是 lazycodex#142windowsNodeDiscoveryLines()codex-cache-command-shim.ts生成的^不是合法的 CMD 比较语法cmd.exe 在到达任何运行时之前就中止了解析。这与本次改动无关且有姊妹 PR#5859 时代 #5923在推进。运行因此回退到该包装器实际 exec 的同一个 bundle——dist/cli/index.jsbun 目标dist/cli-node是 node 回退 bundle所以dist/cli在 node 下会因__require失败并如实记录两次尝试而非静默改用仓库源码。本次使用的 shipped bundle 在分支上重建过且包含改动removeManagedCodexBins出现在dist/cli/index.js中因此走的是出货代码路径。强制 Codex 兼容性门禁bun run test:codex无法在本 Windows 主机上运行内置的packages/lsp-tools-mcp构建脚本以rm -rf dist开头cmd.exe 不提供该命令运行在build:lsp-tools-mcp处即停止——这是既有的主机限制与本次改动无关。因此门禁在 LinuxWSL Ubuntunode v24.18.0bun 1.3.12——CI 的工具链上对本分支执行bun run test:codex 399 pass / 1 skip / 1 fail (401 tests across 66 files)所有触及本改动的测试均通过包括 Windows 上被跳过的两个(pass) codex cleanup ... removes managed component symlinks and keeps unrelated ones (pass) codex cleanup ... a user symlink whose target resembles a managed component ... is kept (pass) codex cleanup ... a codex home resolving to a filesystem root ... no bin link is scanned (pass) codex cleanup ... a user copy of a generated wrapper ... only installer bin names are removed (pass) managed Codex bin coverage ... each name is a managed bin name唯一的失败是#given unreadable existing config #when updating config #then rejects and preserves content这是基于 chmod 的权限测试而 WSL 以 uid 0 运行root 会绕过文件权限。已证明其先前存在而非本次引入baseline-unreadable-config-preexisting.txt同一文件在 pristineupstream/dev55ea9490b 上得到完全一致的 0 pass / 1 fail。为什么这就足够了单元级 RED→GREEN 把确切回归钉死在卸载边界负控制把测试与修复绑定POSIX 运行覆盖了 Windows 跳过的符号链接分支live driver 在报告所指的平台上证明了真实的「先安装后卸载」闭环删除了用户残留的omo.cmd却从未触碰未受管的omo或真实主机配置。标记/目标双重判定与安装器自身的识别逻辑完全一致因此删除无法触及任何非受管文件。风险与遗留删除范围限定为携带安装器标记或解析到受管组件目标的文件/符号链接用户自行放置的omo被保留S2 与 live driver 均已证明。bin 目录按安装器同一套规则解析CODEX_LOCAL_BIN_DIR→ 非默认 home 的codexHome/bin→~/.local/bin卸载与安装写入的目录一致。范围外议题 part 2/3README 的双命令引导以及任何配置/agent 残留后者继续走既有cleanupCodexConfig/removeManifestListedAgentLinks路径。补充本次未记录的内容隔离的mktemp沙箱路径按工具打印原样展示文档中不含任何密钥、token、凭据、环境变量转储或认证头记录的唯一主机细节是真实~/.codex/config.toml的截断 sha256仅用于证明其未被修改。延伸阅读安装器 bin 布局codex-cache-bins.ts、codex-installer-bin-dir.ts标记定义与 shim 生成codex-cache-runtime-wrapper.ts、codex-cache-command-shim.ts目标识别与 dangling 清理codex-cache-dangling-bins.ts、codex-cache-legacy-bins.ts清理安全不变式codex-cleanup-safety.ts卸载入口与测试codex-cleanup.ts、codex-cleanup.test.ts、codex-cleanup-bins-coverage.test.ts、packages/omo-opencode/src/cli/cleanup.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),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →