Skip to content

fix: un-escape double-quoted YAML so Windows paths round-trip#529

Open
Ashin-LX-98 wants to merge 4 commits into
developfrom
hotfix/launcher-path
Open

fix: un-escape double-quoted YAML so Windows paths round-trip#529
Ashin-LX-98 wants to merge 4 commits into
developfrom
hotfix/launcher-path

Conversation

@Ashin-LX-98

Copy link
Copy Markdown
Collaborator

No description provided.

On a non-English Windows (e.g. GBK/936 console codepage), execSync decoded
`where`/`which` stdout with the wrong codepage, mangling a non-ASCII (Chinese)
username in the path into garbage like
`C:\Users\??.?[\AppData\Roaming\npm\claude.cmd` and producing an ENOENT when
the agent tried to run. Adapters also returned the unverified hit directly,
and codex/gemini returned an empty string on a miss that short-circuited the
Node-derived fallback tiers.

- paths.js: add whereBinary() (chcp 65001 forces UTF-8 `where` output +
  fs.existsSync guard) and harden whichBinary() the same way.
- Route every CLI adapter (claude/cline/codex/copilot/cursor/hermes/opencode/
  gemini, plus claude's openagents MCP lookup) through whereBinary so a mangled
  path is rejected and resolution falls through to Node-derived (APPDATA/
  homedir, correctly-encoded) tiers.
- Bump to 0.2.144.
The previous commit prefixed the Windows `where` lookup with `chcp 65001` to
force UTF-8 output. Under `windowsHide: true` cmd runs console-less
(CREATE_NO_WINDOW), where `chcp` can fail with an invalid-handle error — and
because it was chained with `&&`, that failure would make EVERY binary lookup
return null on Windows (no agent resolvable). The CI windows matrix cells
caught this.

Replace it with a strictly-safer scheme that needs no codepage juggling:
- whereBinary: check `%APPDATA%\npm\<name>.cmd` FIRST (APPDATA is UTF-16 from
  the OS via Node — always correctly encoded, and where npm-global CLIs live),
  then fall back to an existence-guarded `where`/`which`.
- whichBinary: keep the existsSync guard, drop the chcp prefix.

A mangled non-ASCII path still fails existsSync and the caller falls through to
its Node-derived tiers, so the original `C:\Users\<中文>\…\claude.cmd` ENOENT
stays fixed without risking the common case.
The hand-rolled daemon.yaml serializer quotes any value containing a colon and
doubles backslashes (a Windows path like `D:\重要资料` → `"D:\\重要资料"`), but
parseYamlValue only stripped the surrounding quotes and never reversed the
escaping. So the agent's configured working folder came back as `D:\\重要资料`
and gained another backslash on every save/load cycle, corrupting the cwd the
agent reports to the workspace (the "I set D:\… but the workspace shows the
wrong path" bug).

parseYamlValue now reverses the serializer's escaping (\\ → \, \" → ") for
double-quoted values, making parse/serialize true inverses. Existing corrupted
configs self-heal on next load.
@vercel

vercel Bot commented Jun 29, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
openagents-workspace Ready Ready Preview, Comment Jun 29, 2026 4:56am

Request Review

The amp/aider registry entries stored their Windows installer as
`powershell -c \"irm ... | iex\"` with backslash-escaped quotes. After JSON
parse that yields literal `\"`, and because the command starts with
`powershell`, _wrapForWindowsShell skips it — so cmd.exe runs the raw string,
the `\"` breaks quoting, and the `|` is parsed as a cmd pipe. The PowerShell
install never runs (the binary is then "not found" at ~/.amp/bin/amp.exe).

Use the bare `irm <url> | iex` form so _wrapForWindowsShell wraps it as
`powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "..."`, keeping the
pipe inside real double quotes. Mirrors how cursor/goose already work.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant