Skip to content

[bug] 仍有 3 处子进程启动点缺少 windowsHide(utils/exec.ts、utils/ai-client.ts、clone.ts),#506 与 #559 未覆盖 #672

Description

@CarlosWonMore

English summary — After #506 (detached hook child) and #559 (update path), windowsHide
exists in only three source files: src/update.ts, src/hook-dispatch-cli.ts,
src/local-agent.ts. Three child-process launch sites still omit it on main:
src/utils/exec.ts:29 (execCommand, which also backs probeBinary),
src/utils/ai-client.ts:121, and src/clone.ts:92.

The first one is reachable from the hooks that run on every session start: src/post-pull.ts,
src/agent-version.ts (probes <cli> --version, and on Windows those are .cmd shims that
cross-spawn launches through cmd.exe) and the src/pkg/adapters/* package probes all go
through execCommand. Whether that surfaces as a visible window depends on whether the
launching process has a console, so it is not a reliable reproduction — our honest position is
that on the released 0.24.0 the dominant visible source was the update check (now fixed by #559,
see the companion issue), and these three sites are the remaining known gap.

Suggested fix: add windowsHide: true to all three call sites, matching src/update.ts:141.

Description

windowsHide 在本仓库的分布(main,代码搜索 repo:Tencent/teamai-cli windowsHide):

文件 状态
src/update.ts :141(fetchLatestVersion)、:520(install)、:552(refresh)
src/hook-dispatch-cli.ts spawnBackground
src/local-agent.ts
src/__tests__/e2e/*__tests__/hook-dispatch-cli.test.ts__tests__/update.test.ts 测试侧引用

以下三处在 main 上仍然没有:

// src/utils/exec.ts:29  —— execCommand,probeBinary 也走它
const child = spawn(command, args, {
  cwd: options.cwd,
  env: options.env,
  stdio: ['ignore', 'pipe', 'pipe'],
  shell: false,
});

// src/utils/ai-client.ts:121
const child = spawn(_cliInfo.absPath, buildCliArgs(_cliInfo.cmd, prompt), { stdio: ['ignore', 'pipe', 'pipe'] });

// src/clone.ts:92  —— runCommand
const child = spawn(cmd, args, {
  stdio: ['ignore', 'pipe', 'pipe'],
  cwd: opts.cwd,
});

为什么值得补

  1. 这几个点都经 cross-spawn/原生 spawn 启动控制台程序。 文件头的注释已经说明原因:

    spawn 使用 cross-spawn:Windows 上 CLI 多为 npm 生成的 .cmd shim,Node 原生 spawn 无权直接执行 .cmd(报 EINVAL),cross-spawn 会正确地经 cmd.exe 启动并转义参数。
    src/utils/ai-client.ts:93-95

    也就是说 Windows 上会实实在在起一个 cmd.exeNodewindowsHide 正是用来抑制这个控制台的开关;不传时是否出现窗口,就取决于发起进程当下有没有控制台 —— 由 GUI 宿主(WorkBuddy / CodeBuddy 这类 Electron 进程)拉起的 hook 属于「没有控制台」那一类。

  2. execCommand 在 hook 路径上可达。 引用它的模块里包含:

    • src/post-pull.ts —— 在 SessionStart 触发的 pull 里执行团队 scripts.postPull
    • src/agent-version.ts —— probeBinary('claude' | 'codebuddy' | 'cursor' | ...),即启动多个 .cmd 去取版本号;
    • src/pkg/env-detect.tssrc/pkg/adapters/* —— 会话开始/提交提示时的包探测。
  3. 这正是 fix(hooks): hide console windows for detached hook child processes #506 / fix(update): hide Windows console windows during self-update #559 / fix(zcode): launch hooks via hidden wscript VBS — no console flash, bounded wait #596 一直在修的那一类问题,看起来只是没收全:

我无法给出的那部分证据(避免误导)

没有办法把「这三个点中的某一个」与「用户看到的那个窗口」一一对应上,原因如实说明:

  • 窗口是否可见取决于发起进程有没有控制台。在 0.24.0 上,updateHandlerbackground: true(detached 子进程)路径,而它调用 fetchLatestVersion 时没有 windowsHide —— 这台机器上「每轮回答结束弹一次」的现象与该路径完全吻合,也已由 fix(update): hide Windows console windows during self-update #559main 上修掉(0.24.0 发布于 2026-09-14,fix(update): hide Windows console windows during self-update #559 于 2026-09-15 合入,差一天,至今没有新的稳定版)。
  • src/clone.ts 目前只被 src/import-repo.ts 引用,src/utils/ai-client.ts 的调用方(codebase / learnings / import-mr 等)也不在 hook 路径上 —— 这两处是「潜在」而非「已确认」。

所以这条 issue 的诉求不是「我复现了」,而是:同类的三处仍缺这个开关,建议补齐,理由是与 #506/#559 保持一致,以及让「是否弹窗」不再依赖祖先进程的控制台状态。改动是一行一处,风险极低。

环境

  • Windows 11 专业版 25H2;Node 22.x;teamai-cli 0.24.0(npm latest
  • 宿主:WorkBuddy / CodeBuddy(GUI 启动 hook)
  • macOS / Linux 不受影响(windowsHide 在非 Windows 上被忽略)

附:CI 层面为什么没兜住

.github/workflows/ci.yml 的矩阵只有 ubuntu-latestmacos-latest没有 Windows runner。这一整类缺陷只能靠 review 发现,这也是它反复出现的原因之一。如果补一个 windows-latest 的 lint/单测 job 成本可接受,边距可能比逐点补 windowsHide 更大 —— 但那是另一件事,不阻塞本 issue。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions