Skip to content

fix(acp): spawn the real Qoder CLI behind its Windows launchers - #1101

Merged
xintaofei merged 4 commits into
spacering-net:mainfrom
leehom0123:fix/qoder-windows-settings
Nov 10, 2026
Merged

xintaofei merged 4 commits into
spacering-net:mainfrom
leehom0123:fix/qoder-windows-settings

Conversation

@leehom0123

@leehom0123 leehom0123 commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

What

Qoder 1.1.84 起,codeg 用内联参数 --settings '{"mcp":{"lazyLoad":false}}' 关闭 MCP 懒加载(6fcb9ea8)。Windows 上 qoder 命令解析到安装器提供的 cmd wrapper,wrapper 会对命令行做二次解析,JSON 里的双引号在这一步被去掉;qodercli 收到 {mcp:{lazyLoad:false}},判定无效 JSON 并以 config_error 退出,ACP 握手在 codeg 侧表现为 Initialize failed: incoming transport closed。

Fix

双引号只在 wrapper 的二次解析这一步被去掉,直接启动 wrapper 指向的真实程序,参数即可原样送达。新增 acp/qoder.rs,从已解析的 wrapper 出发找到真实程序,--settings 保持内联:

  • 官方安装器按 qoder-dispatcher.ps1 自身的 Find-Cli 顺序解析:QODER_CLI_BIN → PATH 上的 qodercli → 用户安装位。
  • npm 安装按 npm shim 的规则解析:shim 同级 node.exe,其次 PATH 上的 node,入口取包 package.json 的 bin.qodercli。
  • 识别不了的 wrapper 会报错,错误信息带上该 wrapper 的路径,不会悄悄改用其它安装。

版本探测与诊断和启动走同一份解析,探测到的与启动的必然是同一份安装。该解析只在 Windows 启用;unix 上 exec 把参数直接传给进程,本就没有重新解析,保持原有行为。

Verify

  • 在本机 1.1.84 上按同样的调用复现了失败(cmd /c qoder.cmd --acp --settings <json> → config_error);改为直接启动后,initialize 正常应答。
  • qoder 模块 87 个用例,其中包含一个在真实 Node 环境下启动、确认参数原样送达的完整用例;全量 lib 测试 6022 个通过;CI 十个作业全部通过。

@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 分支。

@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 启动解析,最新提交 8f0370a:

  1. --settings 恢复为内联传入,不再写临时文件。
  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 会报错,错误信息带上该 wrapper 的路径,不会悄悄改用其它安装。
  3. 启动、版本探测、诊断三处用同一份解析结果,保证探测到的和启动的是同一份安装。

有一处实现比评审建议的方案更简单:连接前不额外运行 node --version 检查 engines 要求的 Node 版本——其它 npx agent 都不在连接时检查 Node,版本过旧时 qodercli 自身的启动报错已经足够明确。

测试:qoder 模块 87 个用例(含真实 Node 环境下确认参数原样送达的用例),全量 lib 测试 6022 个通过;Windows 真机 1.1.84 实测 initialize 握手成功。模块没有按平台限制编译,unix 侧编译由 CI 覆盖。

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 33dbfd6 to 8f0370a Compare November 9, 2026 02:28
@leehom0123 leehom0123 changed the title fix(acp): hand Qoder launch settings as a file on Windows fix(acp): spawn the real Qoder CLI behind its Windows launchers Nov 9, 2026
@xintaofei

Copy link
Copy Markdown
Collaborator

codeg work task 484 is done — #1101 (3 files, +566/-115).

Diagnostics for Qoder on Windows replaced the launcher row with the
resolved program and dropped the resolver's error, so a failed
resolution read "NOT RESOLVED" under a hint about the new-session check
while the verdict still called the environment healthy. Keep the
launcher row as it is for every npx agent, add a row naming the program
behind it or the resolver's error, and report a failed resolution as
installed_but_unresolved.

Also correct two comments: the purpose line of npx_launch_extra_args,
and the module note on how the npm wrappers differ from the official
dispatcher.
@xintaofei

Copy link
Copy Markdown
Collaborator

codeg work task 487 is done — #1101 (3 files, +45/-12).

…unch test

Homebrew's macOS node loads @rpath/libnode.dylib relative to its real
location, so a copied binary fails to start under dyld. A symlink keeps
that location; Windows still uses a self-contained copy.
@xintaofei
xintaofei merged commit 688a519 into spacering-net:main Nov 10, 2026
0 of 10 checks passed
xintaofei added a commit that referenced this pull request Nov 10, 2026
This release adds support for Claude Fable 5.2, updates Codex and several other agents, and fixes Qoder failing to start on Windows and MiniMax questions not showing as cards.

## Improved

- **Claude Code is updated to 2.1.321 with adapter 0.102.0**, so the Fable model is now Fable 5.2, and a saved Fable 5.1 selection through an API gateway switches to Fable 5.2 automatically instead of falling back to the default model.
- **Codex is updated to adapter 2.6.0 (Codex 0.166.0)**, and its async questions now display as answer cards that stay in sync during the conversation and in history.
- **Grok background sub-agents show live progress after the turn that launched them ends.** (#1109)
- **Updated OpenCode to 2.2.6, CodeBuddy to 2.182.0, Qoder to 1.1.86, the ZCode bridge to 0.82.3 and Command Code to 1.88.5.**

## Fixed

- **Qoder starts normally again on Windows**, and its diagnostics show the actual program being launched or the reason it could not be found. (#1101 by @leehom0123)
- **MiniMax questions to the user appear as interactive question cards instead of raw JSON**, including each option's description. (#1111 by @xy3xy3)
- **When a Codex conversation's model provider no longer matches, codeg shows a clear notice** instead of silently starting an empty session that loses the history.
- **Reopened Claude Code context compaction summaries no longer include internal prompt text meant for the model.**
- **OpenCode 2.2.6 conversation history displays its complete content.**

Thanks to @leehom0123 (#1101) and @xy3xy3 (#1111) for their contributions, and to @momomomo820 (#1109) for the report.

-----------------------------

# 发布版本 0.42.2

这一版支持 Claude Fable 5.2,更新 Codex 及多个智能体,并修复 Qoder 在 Windows 上无法启动、MiniMax 提问不弹出卡片等问题。

## 改进

- **Claude Code 更新至 2.1.321,适配器更新至 0.102.0**,Fable 模型升级为 Fable 5.2,通过 API 网关使用时,已保存的 Fable 5.1 选择会自动切换到 Fable 5.2,不再回落到默认模型。
- **Codex 适配器更新至 2.6.0(Codex 0.166.0)**,异步提问会显示为答题卡片,会话中和历史记录里都能正确展示。
- **Grok 后台子智能体在启动它的回合结束后,仍会实时显示运行进度。**(#1109)
- **OpenCode 更新至 2.2.6,CodeBuddy 更新至 2.182.0,Qoder 更新至 1.1.86,ZCode 桥接更新至 0.82.3,Command Code 更新至 1.88.5。**

## 修复

- **Qoder 在 Windows 上恢复正常启动**,诊断信息也会显示实际启动的程序或无法找到的原因。(#1101 by @leehom0123)
- **MiniMax 向用户提问时会弹出可交互的提问卡片,不再只显示 JSON 参数**,并展示每个选项的说明。(#1111 by @xy3xy3)
- **Codex 会话的模型供应商不再匹配时,会显示明确提示**,不再悄悄新开一个空会话导致历史丢失。
- **重新打开 Claude Code 的上下文压缩摘要时,不再显示写给模型的内部提示文本。**
- **OpenCode 2.2.6 的历史会话能完整显示内容。**

感谢 @leehom0123(#1101)和 @xy3xy3(#1111)的贡献,以及 @momomomo820(#1109)的反馈。
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