Codex 在 Windows 原生环境、WSL 与 PowerShell 编码问题排查记录
背景
在 Codex 桌面端中,Windows原生环境下,Codex在运行终端命令时使用本地powershell出现文件输出乱码,修复时导致文件损坏。
经过排查发现这更可能来自本地编译和终端执行路径:系统是 Windows,当 Codex 通过 PowerShell 终端执行命令时,Codex 和现代工具链通常倾向于使用 UTF-8,但 Windows PowerShell 或部分 Windows 命令链路可能仍然使用 GBK / UTF-16 / ANSI 等编码。这种不一致会导致中文输出乱码;更严重时,如果文件被再次读写,可能造成源码文件编码变化、BOM 变化,甚至文件内容损坏。
基于这个判断,我尝试将 Codex 设置中的智能体运行环境从 Windows 原生环境切换到 WSL,希望借助 Linux 用户空间和更一致的 UTF-8 工具链来规避 Windows PowerShell 编码问题。
切换后出现两个现象:
历史对话 Session 看起来全部丢失。
智能体无法正常对话或执行任务。
切回 Windows 原生环境后,历史 Session 和对话能力恢复正常。随后我继续沿着编码方向排查,确认真正需要处理的是 Windows 原生环境下 PowerShell 运行时和文件写入编码策略。
本文记录这两个问题的排查、处理方法和最终结论。
一、WSL 切换后历史 Session 消失的问题
现象
在 Codex 设置中将智能体运行环境从 Windows 原生环境切换到 WSL 后:
历史对话不可见。
智能体无法正常使用。
切回 Windows 原生环境后,历史对话恢复。
排查
首先检查 WSL 本体版本:
wsl --version检查结果显示 WSL 本体版本较新:
WSL version: 2.7.3.0
Kernel version: 6.6.114.1-1这说明问题并不是 WSL 本体版本过低。
继续检查 WSL 发行版:
wsl -l -v当时返回的信息表明:系统中没有可用的 Linux 发行版。也就是说,虽然 Docker 安装过程中启用了 WSL 相关组件,但并没有配置好一个可供 Codex 作为运行环境使用的 Linux 发行版。
原因
WSL 本体和 Linux 发行版不是一回事。
WSL 本体:Windows 提供的 Linux 子系统能力。
Linux 发行版:Ubuntu、Debian 等实际的 Linux 用户空间环境。
Docker 安装时可能会启用 WSL2,但这不等价于已经有一个适合 Codex 使用的默认 Linux 发行版。
同时,Codex 的历史 Session 在 Windows 原生环境和 WSL 环境之间大概率是隔离的:
Windows 原生环境使用 Windows 用户目录和本地状态。
WSL 环境使用 Linux 发行版中的
/home/<user>和对应状态。
因此,切换到 WSL 后历史 Session 看起来为空,并不代表 Windows 原生环境下的历史被删除。切回 Windows 后历史恢复,就是这一点的直接证据。
处理建议
如果确实需要使用 WSL,可以安装并设置默认发行版:
wsl --list --online
wsl --install -d Ubuntu-24.04
wsl -l -v
wsl --set-default Ubuntu-24.04首次进入 Ubuntu 后,安装基础工具:
sudo apt update
sudo apt install -y git curl ca-certificates build-essential如果非常依赖已有历史 Session,建议继续使用 Windows 原生环境;只在确实需要 Linux 工具链时切换到 WSL。
二、Windows PowerShell 5.1 的编码风险
现象
在 Windows 原生环境中运行 Codex 时,PowerShell 命令可能出现:
中文输出乱码。
PowerShell 管道输出编码不一致。
文件再次写入后编码被改成 GBK/ANSI。
UTF-8 源码文件被破坏。
初始环境
检查当前 PowerShell 版本和编码:
$PSVersionTable.PSVersion
[Console]::InputEncoding
[Console]::OutputEncoding
$OutputEncoding
chcp最初环境是 Windows PowerShell 5.1:
Major: 5
Minor: 1同时活动代码页为:
Active code page: 936936 是简体中文 GBK 代码页。这个组合很容易导致现代 UTF-8 工具链出现乱码和文件编码问题。
此外,PowerShell profile 中还有一行:
fnm env --use-on-cd | Out-String | Invoke-Expression但当前环境中找不到 fnm,导致每次启动 shell 时都会输出报错,并且报错本身也可能出现乱码。
第一阶段处理:修复 PowerShell profile
对 Windows PowerShell 5.1 的 profile 做了 UTF-8 初始化:
chcp 65001 > $null
$utf8 = New-Object System.Text.UTF8Encoding $false
[Console]::InputEncoding = $utf8
[Console]::OutputEncoding = $utf8
$OutputEncoding = $utf8
if (Get-Command fnm -ErrorAction SilentlyContinue) {
fnm env --use-on-cd | Out-String | Invoke-Expression
}
验证结果:
chcp
[Console]::OutputEncoding.WebName
$OutputEncoding.WebName得到:
Active code page: 65001
utf-8
utf-8这说明控制台输入输出已经切换到 UTF-8。
关键发现:显示正常不等于写入安全
虽然 Windows PowerShell 5.1 的控制台输出已经是 UTF-8,但进一步测试发现,默认 Set-Content 写入中文文件时,真实字节仍然是 GBK。
测试字符串:
微信读书 UTF-8 写入测试:中文正常 abc123Windows PowerShell 5.1 默认写入后的前几个字节:
CE A2 D0 C5 B6 C1 CA E9这是 GBK 编码下的“微信读书”,不是 UTF-8。
真正的 UTF-8 字节应该是:
E5 BE AE E4 BF A1 E8 AF BB E4 B9 A6这个发现说明:仅仅把 chcp 和输出编码改成 UTF-8,还不足以保证 Windows PowerShell 5.1 的文件写入安全。
三、切换到 PowerShell 7
安装和验证
安装 PowerShell 7:
winget install Microsoft.PowerShell进入 PowerShell 7:
pwsh验证版本:
$PSVersionTable.PSVersion最终确认版本为:
PowerShell 7.6.1继续验证编码:
chcp
[Console]::OutputEncoding.WebName
$OutputEncoding.WebName结果:
Active code page: 65001
utf-8
utf-8PowerShell 7 写入测试
Codex 重启后,再次测试“微信读书”中文写入。
结果显示 Codex 当前使用:
PowerShell 7.6.1pwsh.exe 路径为:
C:\Program Files\WindowsApps\Microsoft.PowerShell_7.6.1.0_x64__8wekyb3d8bbwe\pwsh.exe写入文件后的真实字节:
E5 BE AE E4 BF A1 E8 AF BB E4 B9 A6并且:
HasUtf8Bom: False这说明 PowerShell 7 默认写入结果为 UTF-8 no BOM,符合预期。
四、Windows Terminal 默认配置的补充说明
排查过程中还发现,Windows Terminal 的默认 profile 仍然可能指向 Windows PowerShell 5.1:
Name: Windows PowerShell这不一定影响 Codex,因为 Codex 可以单独找到并使用 PowerShell 7。但如果希望手动打开 Windows Terminal 时也默认进入 PowerShell 7,需要修改 Windows Terminal 的默认 profile。
配置文件位置:
$env:LOCALAPPDATA\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json将 defaultProfile 改成 PowerShell 7 对应的 GUID。例如本机 PowerShell 7 profile 是:
"guid": "{574e775e-4f2a-5b96-ac1e-a2962a402336}",
"name": "PowerShell",
"source": "Windows.Terminal.PowershellCore"则可将:
"defaultProfile": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}"改成:
"defaultProfile": "{574e775e-4f2a-5b96-ac1e-a2962a402336}"注意:不同机器上的 GUID 可能不同,应以本机 settings.json 为准。
五、写入 AGENTS.md 作为硬性标准
为了避免后续 Codex 会话再次退回 Windows PowerShell 5.1,在 E:\Project\AGENTS.md 中加入了工作区级约束:
## Local PowerShell Runtime
When running local PowerShell commands on Windows, Codex must use PowerShell 7 (pwsh) rather than Windows PowerShell 5.1 (powershell.exe).This is a hard requirement to avoid Windows PowerShell 5.1 encoding issues, including GBK/ANSI file writes, garbled UTF-8 output, BOM changes, and source file corruption.Before any command that writes files through PowerShell, verify the runtime is PowerShell 7 or invoke pwsh explicitly.Avoid rewriting source files through ambiguous PowerShell pipelines or redirection. Prefer patch-based edits; when shell file writes are unavoidable, use explicit UTF-8 no BOM encoding.
写入后验证:
PSVersion: 7.6.1
HasUtf8Bom: False说明 AGENTS.md 是通过 PowerShell 7 写入,并保持 UTF-8 no BOM。
六、最终结论
1. WSL 问题结论
Codex 切换到 WSL 后历史 Session 消失,并不是历史被删除,也不是 WSL 本体版本过低。
更准确的原因是:
当时没有配置好可用的默认 Linux 发行版。
Windows 原生环境和 WSL 环境的用户目录、配置、缓存、Session 索引大概率是隔离的。
因此,切回 Windows 原生环境后历史恢复是正常现象。
2. PowerShell 编码问题结论
Windows PowerShell 5.1 即使配置了:
chcp 65001
[Console]::OutputEncoding = utf-8
$OutputEncoding = utf-8也仍然可能在默认 Set-Content 写文件时使用 GBK/ANSI,存在破坏 UTF-8 源码文件的风险。
更稳妥的解决方案是:
Codex 在 Windows 本地运行 PowerShell 命令时使用 PowerShell 7
pwsh。避免通过 PowerShell 管道或重定向重写源码文件。
需要写文件时明确使用 UTF-8 no BOM。
将该要求写入
AGENTS.md,作为项目级硬性规范。
3. 当前状态
当前 Codex 环境已经确认:
PowerShell: 7.6.1
中文写入: UTF-8
BOM: False也就是说,Codex 侧的 PowerShell 编码风险已经处理完成。
七、推荐日常规范
后续在 Windows 原生环境下使用 Codex,建议遵循以下规则:
本地 PowerShell 命令优先使用
pwsh,不要使用 Windows PowerShell 5.1。不使用
Get-Content file | Set-Content file这类读写同一文件的管道操作。不用
>或>>重定向生成或覆盖源码文件。源码修改优先使用补丁方式或编辑器。
必须脚本写文件时,显式指定 UTF-8 no BOM。
对包含中文的文件,必要时检查真实字节,而不只看终端显示是否正常。
附:安全写入 UTF-8 no BOM 的示例
PowerShell 7:
Set-Content .\file.md -Value $text -Encoding utf8NoBOMWindows PowerShell 5.1:
[System.IO.File]::WriteAllText(
"C:\path\file.md",
$text,
(New-Object System.Text.UTF8Encoding $false)
)