fix(daemon): gateway fails to launch on Windows when the profile path contains CJK characters#107751
Conversation
… can decode gateway.vbs and gateway.cmd were written as UTF-8 without BOM, but wscript.exe only reads .vbs as ANSI or UTF-16 LE with BOM and cmd.exe reads .cmd in the console OEM code page, so installs under CJK profile paths failed with "file not found" (openclaw#107416). Write .vbs as UTF-16 LE with BOM, write non-ASCII .cmd content in the system code page when it matches the console page (CJK/Thai locales), and BOM-sniff plus code-page-fallback on read so launchers from older installs keep parsing and migrate on refresh. The hidden .vbs launch path originates from openclaw#95480, which addressed console visibility only.
Dependency GuardThis PR changes dependency-related files. Maintainers should confirm these changes are intentional. Changed files:
Maintainer follow-up:
|
Dependency graph change authorizedThis PR includes dependency graph changes. A repository admin or member of
A later push changes the PR head SHA and requires a fresh security approval. |
The type is only referenced by encodeWindowsLauncherScript's format parameter within the module, so the export tripped check-deadcode-exports. Keep it module-local.
|
Codex review: needs maintainer review before merge. Reviewed July 15, 2026, 7:27 PM ET / 23:27 UTC. Summary PR surface: Source +133, Tests +389, Config +1, Other +4. Total +527 across 13 files. Reproducibility: yes. Current main's UTF-8 launcher writes match the reported failure path, and the PR includes a real Chinese Windows comparison where the old launchers fail while the encoded launchers execute successfully. Review metrics: 1 noteworthy metric.
Stored data model Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge
Maintainer decision needed
Security Review detailsBest possible solution: Authorize the exact iconv-lite dependency change for the current head, preserve the deterministic marker-based encoder across both launcher and restart-helper paths, rebase onto current main, and rerun the Windows and dependency gates before merging. Do we have a high-confidence way to reproduce the issue? Yes. Current main's UTF-8 launcher writes match the reported failure path, and the PR includes a real Chinese Windows comparison where the old launchers fail while the encoded launchers execute successfully. Is this the best way to solve the issue? Yes. A shared per-format encoder with explicit code-page markers is narrower and safer than scattered write-site fixes, and the latest head also covers the sibling restart-helper path; only dependency authorization and merge-base refresh remain. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 1643f1fd9f4c. Label changesLabel justifications:
Evidence reviewedPR surface: Source +133, Tests +389, Config +1, Other +4. Total +527 across 13 files. View PR surface stats
Security concerns:
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
…erministic readback Prepend an ASCII '@Rem openclaw-launcher-encoding=<label>' line to code-page .cmd launchers and decode by that marker instead of sniffing UTF-8. Some GBK byte sequences are valid UTF-8 (隆 = C2 A1 reads as ¡), so the old sniff silently corrupted readback and rejected valid paths; the marker makes decode deterministic and drops the code-page probe (a PowerShell spawn) from the frequent readScheduledTaskCommand poll path. Also fix the representability guard for euc-kr: Node ICU decodes euc-kr as KS X 1001 only, but Windows code page 949 is cp949/UHC, so the TextDecoder cross-check false-rejected ~8,800 UHC extension syllables (똠 = 8C 63) that iconv encodes and cmd.exe reads fine. Verify euc-kr via iconv's own cp949 round-trip; keep TextDecoder for the other five labels.
… encoder The update-time restart helper wrote its temp .cmd as raw UTF-8 while embedding the restart-log path, task name, and task script path, so a CJK profile path or task name broke the same way as the gateway launchers (openclaw#107416). Route the write through encodeWindowsLauncherScript: ASCII content stays byte-identical UTF-8, CJK content gets the marked code-page encoding, and an unrepresentable task name now fails the restart attempt cleanly instead of writing a script cmd.exe would misread.
Reset pnpm-lock.yaml to origin/main and re-add only the iconv-lite root importer entry, dropping the unrelated @types/node peer-context flips and audio-decode deprecation metadata that a mismatched-toolchain regeneration had pulled in. The diff vs main is now the three-line importer entry only; the version already resolves in main's tree via express -> body-parser/raw-body.
|
/allow-dependencies-change |
Co-authored-by: Jason Yao <[email protected]>
|
/allow-dependencies-change |
|
/allow-dependencies-change |
|
/allow-dependencies-change |
|
/allow-dependencies-change |
|
Merged via squash.
|
… contains CJK characters (openclaw#107751) * fix(daemon): write Windows gateway launchers in encodings wscript/cmd can decode gateway.vbs and gateway.cmd were written as UTF-8 without BOM, but wscript.exe only reads .vbs as ANSI or UTF-16 LE with BOM and cmd.exe reads .cmd in the console OEM code page, so installs under CJK profile paths failed with "file not found" (openclaw#107416). Write .vbs as UTF-16 LE with BOM, write non-ASCII .cmd content in the system code page when it matches the console page (CJK/Thai locales), and BOM-sniff plus code-page-fallback on read so launchers from older installs keep parsing and migrate on refresh. The hidden .vbs launch path originates from openclaw#95480, which addressed console visibility only. * refactor(daemon): drop unused WindowsLauncherScriptFormat export The type is only referenced by encodeWindowsLauncherScript's format parameter within the module, so the export tripped check-deadcode-exports. Keep it module-local. * fix(daemon): mark code-page cmd launchers with their encoding for deterministic readback Prepend an ASCII '@Rem openclaw-launcher-encoding=<label>' line to code-page .cmd launchers and decode by that marker instead of sniffing UTF-8. Some GBK byte sequences are valid UTF-8 (隆 = C2 A1 reads as ¡), so the old sniff silently corrupted readback and rejected valid paths; the marker makes decode deterministic and drops the code-page probe (a PowerShell spawn) from the frequent readScheduledTaskCommand poll path. Also fix the representability guard for euc-kr: Node ICU decodes euc-kr as KS X 1001 only, but Windows code page 949 is cp949/UHC, so the TextDecoder cross-check false-rejected ~8,800 UHC extension syllables (똠 = 8C 63) that iconv encodes and cmd.exe reads fine. Verify euc-kr via iconv's own cp949 round-trip; keep TextDecoder for the other five labels. * fix(infra): write Windows restart helper scripts through the launcher encoder The update-time restart helper wrote its temp .cmd as raw UTF-8 while embedding the restart-log path, task name, and task script path, so a CJK profile path or task name broke the same way as the gateway launchers (openclaw#107416). Route the write through encodeWindowsLauncherScript: ASCII content stays byte-identical UTF-8, CJK content gets the marked code-page encoding, and an unrepresentable task name now fails the restart attempt cleanly instead of writing a script cmd.exe would misread. * chore(deps): minimize pnpm-lock delta for the iconv-lite promotion Reset pnpm-lock.yaml to origin/main and re-add only the iconv-lite root importer entry, dropping the unrelated @types/node peer-context flips and audio-decode deprecation metadata that a mismatched-toolchain regeneration had pulled in. The diff vs main is now the three-line importer entry only; the version already resolves in main's tree via express -> body-parser/raw-body. * refactor(windows): centralize launcher encoding Co-authored-by: Jason Yao <[email protected]> * style(windows): format launcher encoding test --------- Co-authored-by: Peter Steinberger <[email protected]> Co-authored-by: Peter Steinberger <[email protected]>
Closes #107416
What Problem This Solves
Fixes an issue where Windows users whose profile path contains CJK characters (e.g.
C:\Users\苗振) can install OpenClaw but the gateway never starts: the first run fails with a "The system cannot find the file specified" / "找不到 …\gateway.vbs" popup and the Scheduled Task never launches the gateway. Reported against v2026.7.1 on Windows 11 with a Chinese-locale profile path.Why This Change Was Made
The daemon writes the generated launchers (
gateway.cmd, the hiddengateway.vbsintroduced by #95480, and the Startup-folder fallback entry) as UTF-8 without BOM, but neither Windows script host reads that encoding:wscript.exeparses.vbsonly as ANSI or UTF-16 LE with BOM, andcmd.exeparses.cmdin the console (OEM) code page. CJK path bytes inside the launchers garble and the launch chain breaks at the first hop.This PR adds
src/daemon/launcher-encoding.ts— a per-format encoder plus a BOM-sniffing decoder — used at the three launcher write sites and thereadScheduledTaskCommandparse site insrc/daemon/schtasks.ts:.vbs→ always UTF-16 LE with BOM, the one wscript encoding that is correct on every locale..cmd→ ASCII content stays byte-identical UTF-8 (zero change for non-CJK installs). Non-ASCII content is encoded with the system ANSI code page, but only on locales where ANSI == OEM (936/932/949/950/874/GB18030 — the locales where a code-page fix is well-defined). windows-125x locales keep UTF-8: their console OEM page (437/850/852/866…) differs from ANSI and has no WHATWG decoder, so ANSI bytes would just be a different flavor of wrong there. Encoded output is round-trip-verified with the same decoder the read path uses; unmappable characters fail the install with a clear error instead of writing a silently broken launcher.Design notes:
.cmd:cmd.execannot parse UTF-16 batch files (NUL bytes break the parser).TextDecoderonly decodes.[email protected]is already in the dependency tree (express→body-parser/raw-body), so promoting it to a root dependency resolves to the already-locked version and adds no new packages — thenpm-shrinkwrap.jsondelta is one line. If a no-new-root-dependency route is preferred, the alternative is keeping.cmdUTF-8 and prepending@chcp 65001>nul; that mutates the console code page for child processes and relies on cmd's re-read behavior, but I am happy to switch if maintainers prefer it.resolveWindowsSystemEncoding()insrc/infra/windows-encoding.ts(now exported); no new detection code.src/infra/windows-task-restart.tswrites its temp restart.cmdas UTF-8 with the same class of embedded paths, so the update-time restart path on CJK hosts needs the same treatment. Kept out to hold this PR to one concern; I can file the follow-up issue once this lands.User Impact
Windows users with CJK (or Thai) characters anywhere in their profile/state path can now install and start the gateway, and gateway repair/update migrates existing broken installs by rewriting the state-dir launchers. Users with pure-ASCII paths get byte-identical launcher files — no change at all.
Evidence
src/daemon/launcher-encoding.test.ts(12 tests: UTF-16 BOM output incl. a CJK path, ASCII byte-identity under a pinned code page, GBK round-trip, windows-125x gate, unrepresentable-character failure, legacy-UTF-8 and raw-GBK decode).schtasks.test.ts:readScheduledTaskCommandparses both a legacy UTF-8 CJK script and a GBK-encoded script.schtasks.install.test.ts: the hidden.vbslauncher for a CJK profile path starts withFF FEand utf16le-decodes to the exactRun """…""", 0, Falseline; an unrepresentable env value fails the install with no launcher file written.oxlintandoxfmtclean on changed files;tsgo:coreandtsgo:test:srcclean;deps:shrinkwrap:root:checkreports current. (schtasks.stop.test.tsshows 4 failures on this host that reproduce identically on unmodifiedmain— pre-existing and unrelated.)gateway.vbs/gateway.cmdpair written under%TEMP%\苗振\with the new encoder launches viacscript gateway.vbsand the payload createsproof.txt; the same pair written the old way (plain UTF-8) fails withgateway-old.vbs(1, 1) (null): The system cannot find the file specified.— the exact reported symptom — and no proof file appears.