Skip to content

fix(acp): hand Qoder launch settings as a file on Windows - #1101

Open
leehom0123 wants to merge 1 commit into
spacering-net:mainfrom
leehom0123:fix/qoder-windows-settings
Open

leehom0123 wants to merge 1 commit into
spacering-net:mainfrom
leehom0123:fix/qoder-windows-settings

Conversation

@leehom0123

Copy link
Copy Markdown
Contributor

What

Qoder 1.1.84 起 codeg 用 --settings '{"mcp":{"lazyLoad":false}}' 关掉 MCP 懒加载(6fcb9ea8)。Windows 上这个内联 JSON 到不了 CLI:qoder 解析到官方安装器的 qoder.cmd,它把 %* 转给 PowerShell -File 脚本,PowerShell 的命令行解析器把 JSON 内嵌的双引号当字符串引号剥掉,qodercli 收到 {mcp:{lazyLoad:false}},判定无效 JSON,握手约 1 秒后 exit 1(config_error),codeg 侧表现为 Initialize failed: incoming transport closed。

Fix

qodercli 对非 {...} 的 --settings 值按文件路径读取,且纯路径不含引号、可在任何二次解析层中原样存活。Windows 上 codeg 把 settings 写到 <codeg_home>/acp-launch/qoder-settings.json,传文件路径;unix 保持内联 JSON(exec 直传 argv,无解析层)。写文件失败时回退内联(行为不劣于修复前)。

Verify

  • 在本机 1.1.84 上复现失败链(cmd /c qoder.cmd --acp --settings <json> → config_error),改用文件路径后 initialize 正常应答。
  • cargo check / cargo clippy / 相关 lib 测试通过(server-bin feature,--lib qoder 75 个用例全过)。

@xintaofei

Copy link
Copy Markdown
Collaborator

建议将修复点放到 Windows 的 Qoder 启动解析:解析到真实 CLI 后直接启动,让原来的 --settings {"mcp":{"lazyLoad":false}} 按独立 argv 传入,避开 cmd → PowerShell → cmd 的二次解析。

文件参数能解决常规路径下的 JSON 引号问题,但 直接返回文件路径 仍依赖“路径经过包装层保持原样”。Qoder 1.1.84 的官方 PowerShell dispatcher 明确允许再调用 npm 的 qodercli.cmd;这个分支里,无空格路径中的 & 可能重新成为命令分隔符,字面目录名 %USERNAME% 可能被展开。另外,cwd.join 不能把 C:state 这类盘符相对路径变成绝对路径。这些特殊路径风险来自源码分析,尚未在 Windows 实机复现;已有测试和 CI 通过不等于验证了这条完整链路。

建议按以下范围实施:

  1. 增加 Qoder 专用的 Windows 启动解析 helper。 返回“绝对 program 路径 + 前置 argv + 安装来源/运行时信息”,接入现有 build_agent。可参考 ZCode 直接用 Node 启动 JS 入口 的做法,保持改动局限于 Qoder。

  2. 保留现有安装选择。 从 resolve_npx_command_for(Qoder, "qoder") 已选中的安装出发,识别官方 dispatcher、原生 CLI、标准 npm shim。官方 dispatcher 分支按其现有规则处理 QODER_CLI_BIN、有效环境中的 PATH/PATHEXT 和用户安装目录;npm dispatcher 分支解析同一安装包的 bin.qodercli,不要另找一个全局版本。显式路径和相对路径的处理规则要写清楚,运行时不能由工作区内同名文件意外覆盖。未知/损坏 wrapper 返回含路径和修复建议的明确错误,避免静默换装另一份 CLI。

  3. 原生和 npm 分别直接启动。 原生 CLI 用实际的 qodercli.exe;npm 安装用绝对 node.exe 路径加同一包的 qodercli.js。Node 选择需兼容已识别 npm shim 的相邻 Node/PATH 规则,并验证该包的 engines 要求(1.1.84 是 Node >=20);原生分支不新增 Node 依赖。可以借鉴 ZCode 的入口解析方式,但不照搬它专用的 Node 22/node:sqlite 检查。

  4. 参数继续使用 argv。 --acp、--settings、JSON 各占一个参数,通过现有 AcpAgent 传递,保留工作区 cwd、合并后的环境、stdio 和进程树回收逻辑。直接启动成立后可移除本 PR 的 settings 文件写入和内联回退;Unix 保留现有启动方式。无需改写用户的 Qoder 配置文件。

  5. 预检、版本和诊断与实际启动一致。 相关检查复用解析结果,区分原生 CLI 与 npm+Node;避免检测一份安装、实际启动另一份。版本/运行时探测保持超时约束,诊断给出选中的程序和入口路径。

  6. 以真实 Windows 子进程作为验收。 覆盖官方 dispatcher→原生 CLI、官方 dispatcher→npm shim、直接 npm shim 三类入口;在 CLI/Node/工作区路径分别包含空格、中文、&、字面 %USERNAME% 时断言子进程收到的 argv 完全一致,且没有额外命令执行。补充不同父子 cwd、UNC 工作区、多个安装竞争、环境覆盖、缺失 Node/入口及未知 wrapper 用例。随后分别用原生和 npm 的 1.1.84 做 ACP initialize 冒烟,在已配置环境验证 session/new 和 MCP 工具仍按关闭 lazyLoad 的语义暴露,并运行相关 Rust 测试、check、clippy。

这是一份待实施、待 Windows 验证的替代设计计划;尚未提交实现,也没有改动你的 PR 分支。

On Windows the resolved `qoder` command is a cmd wrapper whose
dispatcher strips the quotes from the inline
`--settings {"mcp":{"lazyLoad":false}}` JSON before qodercli sees it,
so the ACP handshake dies ~1s in with `config_error`. Resolve the
wrapper to the program behind it by the rules the wrappers themselves
apply (official installer: QODER_CLI_BIN, PATH, user-install location;
npm: the package entry run by the shim's Node), and spawn that
directly so argv reaches the CLI whole. Version detection and
diagnostics probe that exact program; a wrapper codeg cannot place a
CLI behind is an error naming the wrapper, never a silent switch to
another installation.
@leehom0123
leehom0123 force-pushed the fix/qoder-windows-settings branch from e986ea9 to 33dbfd6 Compare November 7, 2026 06:27
@leehom0123

leehom0123 commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor Author

已按建议改为 Windows 的 Qoder 启动解析,最新提交 33dbfd6:

  1. --settings 恢复内联 argv,不再写临时文件。
  2. 新增 acp/qoder.rs:从 resolve_npx_command_for 已解析的 wrapper 出发解析真实程序——dispatcher 按 qoder-dispatcher.ps1 的 Find-Cli 顺序(QODER_CLI_BIN → PATH qodercli → 用户安装位),npm shim 按 npm 自身规则(shim 同级 node.exe → PATH node + 包 bin.qodercli 入口)。识别不了的 wrapper 报带路径的错误,不回退到其它安装。
  3. 启动、版本探测、诊断三处走同一份解析结果,保证探测到的和启动的是同一份安装。

有意做简于草案的一点:连接前不额外跑 node --version 做 engines 版本检查——其它 npx agent 都不在连接时验 Node,Node 过旧时 qodercli 自身的启动报错已足够明确。

测试:qoder 模块 87 个用例(含真 Node 下断言 argv 原样收到 settings JSON),全量 lib 6022 个用例通过;Windows 真机 1.1.84 实测 initialize 握手成功。unix 侧模块无 cfg 门,编译由 CI 覆盖。

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.

2 participants