Codex 更新后 Computer Use 插件失效?Windows 文件锁自救指南

进阶进行中

你遇到的是什么

Codex Desktop 在 Windows 上更新之后,经常会出现 bundled 插件(Computer Use / Chrome)突然不能用:

  • 插件页里 computer-use@openai-bundledchrome@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.execodex-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 被拒,别卡住,跳过去继续看文件):

powershell
codex plugin marketplace list
codex plugin list

查关键文件在不在:

powershell
Test-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 主进程,否则会中断你正在跑的会话。

powershell
Get-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 能解析:

powershell
Get-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 失败就复制成普通目录):

powershell
function 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 能解析:

powershell
Test-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,确认:

  • 插件页能打开 ChromeComputer 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 和会话记录。

Codex 更新后 Computer Use 插件失效?Windows 文件锁自救指南 | 资讯狗 | Zixungou