fix(hooks): run CodeBuddy's Windows hooks through cmd.exe - #637
Merged
jeff-r2026 merged 5 commits intoSep 21, 2026
Merged
Conversation
bundled-runtime: CodeBuddy provides cmd.exe on Windows, so the /bin/sh shell gate is a false negative there. POSIX keeps the old check. builtin-hooks: render cmd-syntax commands for codebuddy on win32 and write a teamai.cmd shim, so the PATHEXT lookup can resolve the CLI. hooks: render the project gate in the host shell's syntax and recognise both renderings, so a platform switch cannot leave dead duplicates. tests: win32 cases with a spied platform, so ubuntu CI covers them.
Closed
zdGrande
force-pushed
the
fix/codebuddy-ide-windows-hooks
branch
from
September 18, 2026 09:41
f362ada to
7d1cc4b
Compare
|
发现
测试说明
|
zdGrande
force-pushed
the
fix/codebuddy-ide-windows-hooks
branch
from
September 20, 2026 03:21
6100d6a to
7d1cc4b
Compare
|
审查发现
测试说明
|
added 2 commits
September 20, 2026 11:25
hooks: the cmd gate `${gate} && (payload)` let a gate miss inherit findstr's
exit status — non-zero is surfaced as a hook error, and exit 2 blocks
UserPromptSubmit. Use `& if not errorlevel 1 (payload) else exit /b 0`: a miss
exits 0, a match still passes the payload's own status through.
builtin-hooks: the cmd wrapper searched `%USERPROFILE%\.teamai\bin` while the
writer uses getUserHome(), so HOME/USERPROFILE could diverge and `teamai` was
never found. Embed the resolved bin dir; drop TEAMAI_BIN_DIR_WIN.
tests: update the cmd-gate and codebuddy PATH assertions.
|
审查结论
PR 描述包含单元测试计划、构建检查以及 Windows + CodeBuddy 真实 CLI 端到端记录,测试说明本身充分。 |
Collaborator
|
Please resolve the P1 finding and conflicts. |
|
审查发现
PR 描述包含构建、测试计划及真实 Windows + CodeBuddy 端到端验证记录,测试说明本身充分。 |
Cmd shell metacharacters in project roots break the team-hook project gate; escape the root literal and match with findstr. Sync tests and docs.
|
审查发现
PR 描述包含构建、类型检查、单测以及 Windows + CodeBuddy 真实 CLI 端到端验证记录,测试说明本身充分。 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
问题
CodeBuddy 在 Windows 上一向跑不起来 teamai 的 hook。原因有两个,彼此独立。
1. 被当成"这个环境没有 shell"直接跳过
skipToolsWithoutShell()的门禁只问一件事:existsSync('/bin/sh')。而 Windows 版 CodeBuddy 的安装树里没有任何 POSIX shell(没有sh.exe/bash.exe),于是门禁判定"该环境无法执行 hook 命令",把codebuddy整个从注入名单里摘掉、只留一条 warn,其它工具则不受影响。但这个问题问错了对象。CodeBuddy 的 hook 运行器是把
command字符串交给child_process.spawn(command, [], { shell: true })(genie 的HookExecutorImpl),Windows 上这条路径走的是%ComSpec%—— 也就是操作系统一定提供的 cmd.exe。新增的resolveCodebuddyShell()正是回答这个问题;POSIX 平台继续保留/bin/sh的保守判定。2. 渲染出来的命令是 POSIX 形态,cmd.exe 读不懂
即便放行,命令串也仍是 POSIX 形态:
cmd.exe 没有
VAR=value command前缀、没有/dev/null、也没有|| true,这条串在第一个 token 就会失败。而失败比"静默不生效"更糟:CodeBuddy 会把非 0 的UserPromptSubmit判定为allowed: false,直接挡掉用户提问。因此改为 cmd 形态,并逐字复刻 POSIX 的 fail-open 语义:toolUsesCmdShell()负责在两种形态间切换,范围刻意收得很窄:win32 && codebuddy。WorkBuddy 在 Windows 上继续用 POSIX 形态 —— 它的 hook 运行器是自带 PortableGit 里的 MSYS sh,这一点resolveWorkbuddyShell()早已确立 —— POSIX 平台则完全不受影响。项目作用域的团队 hook 门禁按同样的原则渲染,理由也相同:一条 POSIX 的
if [ "$PWD" = … ]挡在 cmd 命令前面就是语法错误,会把门禁和载荷一起打死,于是那台机器上团队的遥测注入与上报从来没执行过。两种门禁在 reconcile 侧都能被识别,所以机器在两种形态之间来回切换,也不会留下没有东西能清理的条目。3. cmd.exe 需要一个
teamai.cmd才解析得到PATH="<bin>:$PATH" teamai …对 POSIX shell 成立,是因为teamai本身是一个无扩展名的 sh 脚本。cmd.exe 按 PATHEXT(.COM;.EXE;.BAT;.CMD)解析命令名,永远不会执行无扩展名文件 —— 所以只把~/.teamai/bin前置到 PATH 没有任何作用。ensureTeamaiWrapper()现在会在 Windows 上于原有 shim 旁边多写一份teamai.cmd:两份 wrapper 都使用 node 与 CLI 入口的绝对路径,因此都不依赖 hook 子进程的 PATH。node 的解析顺序是 WorkBuddy 自带运行时 → CodeBuddy 自带运行时 →
process.argv[0],而最后这个就是当前这个函数自己正在运行的解释器,所以它不可能缺失。该文件在每次init/pull/hooks inject都会幂等重写,删掉后下一次开会话即可自愈。测试
四个既有测试套件补齐了 Windows 用例,全部通过 spy 驱动
process.platform,因此在 ubuntu CI 上是真正执行、而不是被跳过:hooks-shell-check.test.ts—— win32 下 codebuddy 不再被跳过(不再出现 "no shell is available" 警告),且产出的命令是 cmd 形态;POSIX 门禁保持原样。hooks-wrapper.test.ts—— win32 下会在 POSIX shim 旁边写出teamai.cmd(含解析到的 node 与入口),其它平台不写。hooks-reconcile-scope.test.ts—— 由任一渲染器写出的项目门禁都能被识别并清理。hooks-golden.test.ts—— codebuddy 在非 Windows 下的输出仍与跨平台 golden fixture 逐字节一致;仅在 win32 跳过,因为该 fixture 是 POSIX 基线,Windows 形态由hooks-shell-check.test.ts另钉。tsc --noEmit、npm run build与上述四个套件全绿(53 passed,1 skipped)。平台影响
process.platform === 'win32'之后。package.json未改动。验证
在安装树内不含任何 POSIX shell 的 Windows + CodeBuddy CN 4.9.8 上验证:注入不再报警、
~/.codebuddy/settings.json为 cmd 形态、%USERPROFILE%\.teamai\bin\teamai.cmd被创建(删除后于下一次开会话时自动重建)、hook-dispatch端到端可运行。Issue
Fixes #579 —— 「windows codebuddy跳过hook」:Windows 下 init 直接把该工具跳过,即上面的原因 (1);而原因 (2) 会在 (1) 被解除后立刻显形。