Codex 更新后 Computer Use 插件失效?Windows 文件锁自救指南
你遇到的是什么
Codex Desktop 在 Windows 上更新之后,经常会出现 bundled 插件(Computer Use / Chrome)突然不能用:
- 插件页里
computer-use@openai-bundled、chrome@openai-bundled还在,但点进去报错:marketplace file "...\.codex\.tmp\bundled-marketplaces\openai-bundled\.agents\plugins\marketplace.json" does not exist - 插件图标加载不出来
- 设置页里 Computer Use 显示 unavailable
- Codex 日志里能翻到
EBUSY/resource busy or locked/plugin_cache_windows_file_lock/os error 5/extension-host.exe这类关键词
对得上的话,基本就是本篇要修的问题。
根因:Windows 文件锁把插件更新"做了一半"
Codex Desktop 更新插件时,会先把新版本解压到一个临时目录 ~/.codex/.tmp/bundled-marketplaces/openai-bundled,再替换进正式的缓存目录。Windows 上 extension-host.exe、codex-computer-use.exe 这些进程如果还占着旧文件没退干净,替换就会被文件锁打断(EBUSY / os error 5),结果是:
- 临时目录
.tmp\bundled-marketplaces只解压了半截、marketplace.json缺失 - 缓存里的
latest还指向那个残缺的临时目录 - Chrome 的 native host manifest 也指向了损坏路径上的
extension-host.exe
三者叠加,插件就成了"看得到、打不开"。
动手前先记住三条:先诊断再动手,确认是文件锁问题再修,别上来就删目录或改配置;改之前先备份;不要乱改 [windows] sandbox——那是另一个问题(os error 740 / 请求提升权限),本篇不碰它。整个过程也不要去打印或复制任何 API key、auth.json 内容。
前置条件
- Windows 上的 Codex Desktop(命令行 CLI 和桌面 App 共用
~/.codex)。 - 一个 PowerShell 窗口;下面所有路径都用
$env:USERPROFILE这类变量,不写死用户名。 - 先把 Chrome 关掉,并准备好可以重启 Codex Desktop。
最省事的办法:整套丢给 AI 代办
这套流程本来就是写给 AI 执行的。如果你装了 Claude Code、或者 Codex CLI 还能用,直接把下面这段发给它,让它在你 Windows 本机按"诊断 → 备份 → 修复 → 验证"跑完并向你汇报:
text我在 Windows 本机,Codex Desktop 更新后 Computer Use / Chrome 插件失效(插件页报 marketplace.json does not exist、图标不加载、设置里 Computer Use unavailable)。请按下面流程排查并尽量修复,全程用 $env:USERPROFILE 等变量、不要写死用户名: 1. 先诊断、不要一上来删目录或改配置;确认是不是 Windows 文件锁导致的 bundled 插件半更新——看 codex plugin list、~/.codex/.tmp/bundled-marketplaces 下 marketplace.json 是否缺失、缓存 latest 是否指向 .tmp 临时目录、日志里有没有 EBUSY / plugin_cache_windows_file_lock / os error 5。 2. 修之前先把 config.toml、chrome-native-hosts.json、扩展 manifest 备份到带时间戳的目录。 3. 关 Chrome,停掉 extension-host 和 codex-computer-use 进程解锁。 4. 从 ProgramFiles\WindowsApps 里的 OpenAI.Codex 安装包找完整的 app\resources\plugins\openai-bundled 源,重建损坏的 .tmp marketplace,再按 plugin.json 版本号重建 chrome / computer-use 缓存和 latest(junction 优先、失败就复制成普通目录)。 5. 把 native host JSON 里指向 chrome\latest 或 .tmp 的 path 改成固定版本目录里的 extension-host.exe,无 BOM UTF-8 写回。 6. 确认 config.toml 里 chrome / computer-use 插件 enabled,重启 Codex Desktop 验证。 约束:不要改 [windows] sandbox(除非日志是 os error 740 / 请求提升,那是另一个问题);不要打印或复制任何 API key、auth.json;不能直接跑 PowerShell 就生成 .ps1 脚本给我。最后告诉我:确认是不是文件锁问题、证据、备份目录、改了哪些文件、哪些验证通过、卡在哪。
让 AI 代跑时盯紧两点:它必须先备份再改,且只动 openai-bundled 插件缓存和 native host 指向,不许碰模型 provider、API key、登录态。下面是同一套流程的手动版,想自己一步步来就照着走。
第一步:确认是不是文件锁导致的损坏
先把路径变量设好:
powershell$CodexHome = Join-Path $env:USERPROFILE ".codex" $OpenAILocal = Join-Path $env:LOCALAPPDATA "OpenAI" $BundledTmpRoot = Join-Path $CodexHome ".tmp\bundled-marketplaces\openai-bundled" $BundledMarketplaceJson = Join-Path $BundledTmpRoot ".agents\plugins\marketplace.json" $PluginCacheRoot = Join-Path $CodexHome "plugins\cache\openai-bundled" $ChromeCacheRoot = Join-Path $PluginCacheRoot "chrome" $ComputerUseCacheRoot = Join-Path $PluginCacheRoot "computer-use"
看插件状态(命令若因 WindowsApps alias 被拒,别卡住,跳过去继续看文件):
powershellcodex plugin marketplace list codex plugin list
查关键文件在不在:
powershellTest-Path $BundledMarketplaceJson Test-Path (Join-Path $BundledTmpRoot "plugins\chrome\extension-host\windows\x64\extension-host.exe") Test-Path (Join-Path $BundledTmpRoot "plugins\computer-use\scripts\computer-use-client.mjs")
查日志关键词:
powershell$LogRoot = Join-Path $env:LOCALAPPDATA "Packages\OpenAI.Codex_2p2nqsd0c76g0\LocalCache\Local\Codex\Logs" Get-ChildItem $LogRoot -Recurse -File -ErrorAction SilentlyContinue | Sort-Object LastWriteTime -Descending | Select-Object -First 80 | Select-String -Pattern "EBUSY|resource busy or locked|plugin_cache_windows_file_lock|os error 5|marketplace\.json.*does not exist|extension-host\\windows\\x64"
判定:下面这些同时中几条,基本就是本问题——
- 插件页报
marketplace.json does not exist、图标不加载 .tmp\bundled-marketplaces里缺文件、marketplace.json不存在- 缓存
latest指向.tmp临时目录、关键文件缺失 - 日志里有
EBUSY/plugin_cache_windows_file_lock/os error 5
如果日志里主要是 os error 740 / 请求的操作需要提升 / windows sandbox failed,那是 Windows sandbox 权限问题,不是文件锁,到此打住,别用本篇的重建流程,改去查 sandbox 配置。
第二步:备份
powershell$Stamp = Get-Date -Format "yyyyMMdd-HHmmss" $BackupDir = Join-Path $env:USERPROFILE "codex-plugin-backups\openai-bundled-lock-repair-$Stamp" New-Item -ItemType Directory -Force -Path $BackupDir | Out-Null @( (Join-Path $CodexHome "config.toml"), (Join-Path $CodexHome ".codex-global-state.json"), (Join-Path $CodexHome "chrome-native-hosts.json"), (Join-Path $OpenAILocal "Codex\chrome-native-hosts.json"), (Join-Path $OpenAILocal "extension\com.openai.codexextension.json") ) | ForEach-Object { if (Test-Path -LiteralPath $_) { Copy-Item -LiteralPath $_ -Destination $BackupDir -Force } } "备份完成: $BackupDir"
第三步:停掉锁住目录的残留进程
先手动关掉 Chrome。下面只停后台 helper,别强杀当前 Codex Desktop 主进程,否则会中断你正在跑的会话。
powershellGet-Process extension-host -ErrorAction SilentlyContinue | Stop-Process -Force Get-Process codex-computer-use -ErrorAction SilentlyContinue | Stop-Process -Force Start-Sleep -Seconds 2
第四步:从安装包重建 marketplace 和插件缓存
4.1 找到安装包里完整的 openai-bundled 源
powershell$BundledSource = $null Get-ChildItem (Join-Path $env:ProgramFiles "WindowsApps") -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -like "OpenAI.Codex_*_x64__2p2nqsd0c76g0" } | Sort-Object LastWriteTime -Descending | ForEach-Object { $candidate = Join-Path $_.FullName "app\resources\plugins\openai-bundled" if (-not $BundledSource -and (Test-Path (Join-Path $candidate ".agents\plugins\marketplace.json"))) { $BundledSource = $candidate } } if (-not $BundledSource) { throw "找不到 Codex 安装包里的 openai-bundled 源,确认 Codex Desktop 已装好且 WindowsApps 可访问。" } "源目录: $BundledSource"
4.2 重建损坏的 .tmp marketplace
删之前再停一次锁进程,删完从源整目录复制回来,并校验 marketplace.json 能解析:
powershellGet-Process extension-host,codex-computer-use -ErrorAction SilentlyContinue | Stop-Process -Force Start-Sleep -Seconds 2 if (Test-Path -LiteralPath $BundledTmpRoot) { Remove-Item -LiteralPath $BundledTmpRoot -Recurse -Force } New-Item -ItemType Directory -Force -Path (Split-Path -Parent $BundledTmpRoot) | Out-Null Copy-Item -LiteralPath $BundledSource -Destination $BundledTmpRoot -Recurse -Force Get-Content -LiteralPath $BundledMarketplaceJson -Raw | ConvertFrom-Json | Out-Null
4.3 重建 chrome / computer-use 缓存和 latest
从 .codex-plugin\plugin.json 读版本号,把源复制到 缓存\版本号\,再把 latest 用 junction 指过去(junction 失败就复制成普通目录):
powershellfunction Get-PluginVersion($dir) { (Get-Content -LiteralPath (Join-Path $dir ".codex-plugin\plugin.json") -Raw | ConvertFrom-Json).version } $ChromeVersion = Get-PluginVersion (Join-Path $BundledSource "plugins\chrome") $ComputerUseVersion = Get-PluginVersion (Join-Path $BundledSource "plugins\computer-use") $ChromeVersionDir = Join-Path $ChromeCacheRoot $ChromeVersion $ComputerUseVersionDir = Join-Path $ComputerUseCacheRoot $ComputerUseVersion New-Item -ItemType Directory -Force -Path $ChromeCacheRoot,$ComputerUseCacheRoot | Out-Null Copy-Item -LiteralPath (Join-Path $BundledSource "plugins\chrome") -Destination $ChromeVersionDir -Recurse -Force Copy-Item -LiteralPath (Join-Path $BundledSource "plugins\computer-use") -Destination $ComputerUseVersionDir -Recurse -Force function Reset-Latest($latest, $target) { if (Test-Path -LiteralPath $latest) { Remove-Item -LiteralPath $latest -Recurse -Force } cmd /c mklink /J "`"$latest`"" "`"$target`"" | Out-Null if (-not (Test-Path -LiteralPath $latest)) { Copy-Item -LiteralPath $target -Destination $latest -Recurse -Force } } Reset-Latest (Join-Path $ChromeCacheRoot "latest") $ChromeVersionDir Reset-Latest (Join-Path $ComputerUseCacheRoot "latest") $ComputerUseVersionDir
第五步:修复 Chrome native host 指向
如果 native host manifest 还指着 chrome\latest 或 .tmp 这种会变/损坏的路径,把它改成固定版本目录里的 extension-host.exe,并统一写成无 BOM 的 UTF-8(避免 Node/Chromium 解析 BOM 出错):
powershell$ExtensionHostExe = Join-Path $ChromeVersionDir "extension-host\windows\x64\extension-host.exe" if (-not (Test-Path -LiteralPath $ExtensionHostExe)) { throw "找不到 extension-host.exe: $ExtensionHostExe" } function Write-JsonNoBom($path, $obj) { [System.IO.File]::WriteAllText($path, ($obj | ConvertTo-Json -Depth 20), [System.Text.UTF8Encoding]::new($false)) } @( (Join-Path $OpenAILocal "extension\com.openai.codexextension.json"), (Join-Path $CodexHome "chrome-native-hosts.json"), (Join-Path $OpenAILocal "Codex\chrome-native-hosts.json") ) | ForEach-Object { if (-not (Test-Path -LiteralPath $_)) { return } $obj = Get-Content -LiteralPath $_ -Raw | ConvertFrom-Json if ($obj.path -and (($obj.path -like "*\chrome\latest\*") -or ($obj.path -like "*\.tmp\bundled-marketplaces\*"))) { $obj.path = $ExtensionHostExe } Write-JsonNoBom $_ $obj }
第六步:确认插件启用 + 重启验证
确认 ~/.codex/config.toml 里这几个插件是 enabled(已经是就别重复改,也别动模型 provider / API key / 登录态):
toml[plugins."chrome@openai-bundled"] enabled = true [plugins."computer-use@openai-bundled"] enabled = true
验证关键文件 + JSON 能解析:
powershellTest-Path (Join-Path $ChromeCacheRoot "latest\extension-host\windows\x64\extension-host.exe") Test-Path (Join-Path $ComputerUseCacheRoot "latest\node_modules\@oai\sky\bin\windows\codex-computer-use.exe") Get-Content -LiteralPath $BundledMarketplaceJson -Raw | ConvertFrom-Json | Out-Null
重启 Codex Desktop,确认:
- 插件页能打开 Chrome 和 Computer Use
- 图标恢复
- 两个插件是 installed / enabled
- 设置页 Computer Use 不再 unavailable
常见问题
Q:为什么更新一次就坏一次?
Windows 的文件锁机制下,只要替换插件时 extension-host.exe / codex-computer-use.exe 没退干净,更新就可能被打断、留下半截缓存。养成习惯:每次更新前先彻底退出 Codex Desktop 和 Chrome。
Q:这么多命令我不敢手动跑。 用最省事那条:把流程整段丢给 Claude Code 或 Codex 自己,让它先备份再修。它会按诊断 → 备份 → 重建 → 验证跑完,并汇报改了哪些文件。
Q:修完还是 unavailable?
回第一步看日志:如果出现的是 os error 740 / 请求提升权限,那是 sandbox 问题、不是文件锁,本篇修不了;如果还是 EBUSY,说明仍有进程占着文件,确认 Chrome 和所有 extension-host 都退干净,再跑一遍第四步。
Q:会动到我的对话或密钥吗?
不会。整套流程只重建 openai-bundled 插件缓存、改 native host 指向,不碰模型配置、API key、auth.json 和会话记录。