Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,23 @@ sudo apt install xsel
```
</details>

<details>
<summary><strong>Windows: garbled CJK (Chinese/Japanese/Korean) output in the shell</strong></summary>

On Windows with a non-UTF-8 system locale (e.g. zh-CN, whose active code page is 936/GBK),
command output containing CJK characters may appear garbled (mojibake). MiMoCode forces
UTF-8 output for spawned PowerShell/cmd subprocesses. If you still encounter garbled output
in cases this does not yet cover, enable Windows' system-wide UTF-8 support:

**Settings → Time & language → Language & region → Administrative language settings →
Change system locale → check "Beta: Use Unicode UTF-8 for worldwide language support" →
reboot.**

This switches the active code page (ACP) to UTF-8 (65001) for all programs, so subprocesses
no longer inherit the legacy code page. Note it is a system-wide Beta toggle and may cause
some older non-Unicode programs to display incorrectly, so treat it as a workaround.
</details>

---

## Core Features
Expand Down
14 changes: 14 additions & 0 deletions README.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,20 @@ sudo apt install xsel
```
</details>

<details>
<summary><strong>Windows:shell 输出中文(CJK)乱码</strong></summary>

在系统区域为非 UTF-8 的 Windows 上(如简体中文,活动代码页为 936/GBK),命令输出里的
中日韩字符可能显示为乱码。MiMoCode 已为 PowerShell/cmd 子进程强制开启 UTF-8 输出。
如果在尚未覆盖的场景下仍遇到乱码,可以开启 Windows 的系统级 UTF-8 支持:

**设置 → 时间和语言 → 语言和区域 → 管理语言设置 → 更改系统区域设置 →
勾选「Beta 版: 使用 Unicode UTF-8 提供全球语言支持」→ 重启。**

这会把活动代码页(ACP)切换为 UTF-8(65001),所有程序都生效,子进程不再继承旧代码页。
注意这是系统级 Beta 开关,可能导致部分老的非 Unicode 程序显示异常,建议作为临时方案。
</details>

---

## 核心特性
Expand Down
16 changes: 12 additions & 4 deletions packages/opencode/src/session/prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1256,9 +1256,13 @@ NOTE: At any point in time through this workflow you should feel free to ask the
`,
],
},
cmd: { args: ["/c", input.command] },
powershell: { args: ["-NoProfile", "-Command", input.command] },
pwsh: { args: ["-NoProfile", "-Command", input.command] },
cmd: { args: ["/c", `${Shell.CMD_UTF8_PREFIX}${input.command}`] },
powershell: {
args: ["-NoProfile", "-Command", `${Shell.POWERSHELL_UTF8_PREFIX}${input.command}`],
},
pwsh: {
args: ["-NoProfile", "-Command", `${Shell.POWERSHELL_UTF8_PREFIX}${input.command}`],
},
"": { args: ["-c", input.command] },
}

Expand All @@ -1273,7 +1277,11 @@ NOTE: At any point in time through this workflow you should feel free to ask the
const cmd = ChildProcess.make(sh, args, {
cwd,
extendEnv: true,
env: { ...shellEnv.env, TERM: "dumb" },
env: {
...shellEnv.env,
...(process.platform === "win32" ? { PYTHONIOENCODING: "utf-8" } : {}),
TERM: "dumb",
},
stdin: "ignore",
forceKillAfter: "3 seconds",
})
Expand Down
14 changes: 14 additions & 0 deletions packages/opencode/src/shell/shell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,18 @@ export const preferred = lazy(() => select(process.env.SHELL))

export const acceptable = lazy(() => select(process.env.SHELL, { acceptable: true }))

// On non-UTF-8 Windows locales (e.g. zh-CN ACP 936/GBK) shell subprocesses emit
// output in the legacy code page, which we decode as UTF-8 → mojibake. These
// prefixes force UTF-8 output before the user command runs.

// PowerShell/pwsh: set both the output pipe encoding and the console encoding.
// UTF8Encoding($false) is BOM-less to avoid leading garbage bytes.
export const POWERSHELL_UTF8_PREFIX =
"$OutputEncoding = [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false);"

// cmd.exe: switch the code page to 65001. `&` (not `&&`) so the user command's
// exit code is preserved and a chcp failure doesn't block it; redirect both
// stdout and stderr so chcp output never pollutes the result.
export const CMD_UTF8_PREFIX = "chcp 65001 >nul 2>nul & "

export * as Shell from "./shell"
12 changes: 10 additions & 2 deletions packages/opencode/src/tool/bash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -308,15 +308,19 @@ const ask = Effect.fn("BashTool.ask")(function* (ctx: Tool.Context, scan: Scan)

function cmd(shell: string, name: string, command: string, cwd: string, env: NodeJS.ProcessEnv) {
if (process.platform === "win32" && PS.has(name)) {
return ChildProcess.make(shell, ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command", command], {
const prefixed = `${Shell.POWERSHELL_UTF8_PREFIX}${command}`
return ChildProcess.make(shell, ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command", prefixed], {
cwd,
env,
stdin: "ignore",
detached: false,
})
}

return ChildProcess.make(command, [], {
const finalCommand =
process.platform === "win32" && name === "cmd" ? `${Shell.CMD_UTF8_PREFIX}${command}` : command

return ChildProcess.make(finalCommand, [], {
shell,
cwd,
env,
Expand Down Expand Up @@ -429,6 +433,10 @@ export const BashTool = Tool.define(
)
return {
...process.env,
// Python ignores the console code page when stdout is a pipe and falls
// back to the ANSI code page (GBK on zh-CN), producing mojibake. Force
// UTF-8 for child Python processes on Windows.
...(process.platform === "win32" ? { PYTHONIOENCODING: "utf-8" } : {}),
...extra.env,
}
})
Expand Down
Loading