Skip to content

[bug] Windows11环境下频繁终端弹窗,干扰鼠标与键盘操作 #79

Description

@DaisyHunter

TL;DR (EN): On Windows, when aoci runs console-less (e.g. as an MCP stdio child of a host), every git probe spawns git.exe via exec.Command without SysProcAttr, so Windows allocates a new visible console for each child — windows flash and steal focus constantly. Suggested fix: HideWindow + CREATE_NO_WINDOW on Windows (patch below, locally verified: 0 windowed git.exe across 1310 samples).

环境

  • Windows 11(10.0.22631)
  • aoci v0.1.0-rc14(commit 92c78bc)
  • MCP stdio 方式(ZCode 宿主,按 README 配置)+ Git for Windows

现象

aoci 每次刷新(MCP 服务启动时的 verify/check、aoci_overview / aoci_maintain / aoci_search 等工具调用中的 git 探测)都会弹出一个新的控制台窗口并抢占前台焦点,git.exe 退出后窗口随即关闭。agent 会话内刷新频繁时几乎无法正常打字,只能杀掉 aoci.exe。弹出的是承载 git.exe 的控制台窗口(不是 bash——aoci 不调 bash)。

根因

internal/fs/git_command.go 的 UntrustedRepositoryGitCommand(全仓读取 Git 事实的唯一通道,rev-parse/ls-files 等全部经它)直接 exec.Command("git", ...),未设置任何 Windows 窗口抑制:

command := exec.Command("git", append(hardened, args...)...)
command.Env = append(os.Environ(), "GIT_OPTIONAL_LOCKS=0")
return command

MCP stdio 场景下宿主以无控制台方式拉起 aoci;无控制台的父进程再拉起控制台子进程时,Windows 会为子进程新分配一个可见控制台窗口(见 Creation of a Console)。全仓目前只有 internal/ui/detach_windows.go 设置了 HideWindow(UI 服务器专用),git 链路没有。installer.go 给 codex 安装的 powershell hook 包装(powershell.exe -NoProfile ...)同样会在无控制台宿主下弹窗。

复现与度量方法

用 PowerShell 以 CreateNoWindow(模拟宿主拉 MCP 的形态)运行任意触发 git 探测的命令(如 aoci check),以 15ms 间隔轮询 Get-Process git 的 MainWindowHandle:补丁前即本 issue 描述的弹窗现象;打补丁后全程采样 1310 次 git.exe 子进程,0 个带窗口句柄。

建议修复(本地已验证)

按平台分文件给 git 构造器加隐藏控制台,共三处改动:

internal/fs/git_command_windows.go(新增):

//go:build windows

// Windows 控制台抑制 —— 与 git_command.go 同包的平台侧实现
//
// 威胁: aoci 常以无控制台形态运行(如 MCP stdio 由宿主拉起)。此时 exec 拉起
// 控制台子进程(git.exe)时,Windows 会为子进程新分配一个可见控制台窗口——
// 刷新期间反复弹窗并抢占用户焦点。
// 边界: CREATE_NO_WINDOW 只抑制控制台分配,不改变 stdio 句柄继承;宿主提供的
// 管道与真实终端下的交互输出不受影响。HideWindow(STARTF_USESHOWWINDOW+SW_HIDE)
// 作为兜底。调用方环境变量属操作者自身信任域,不在此处覆盖。
package fs

import (
	"os/exec"
	"syscall"
)

// createNoWindow 即 Win32 CREATE_NO_WINDOW(0x08000000)。
const createNoWindow = 0x08000000

// hideChildConsole 阻止 Windows 为 git.exe 子进程新建可见控制台窗口。
func hideChildConsole(cmd *exec.Cmd) {
	if cmd.SysProcAttr == nil {
		cmd.SysProcAttr = &syscall.SysProcAttr{}
	}
	cmd.SysProcAttr.HideWindow = true
	cmd.SysProcAttr.CreationFlags |= createNoWindow
}

internal/fs/git_command_other.go(新增):

//go:build !windows

package fs

import "os/exec"

// hideChildConsole 在非 Windows 平台为空操作;可见控制台窗口问题仅 Windows 存在。
func hideChildConsole(*exec.Cmd) {}

internal/fs/git_command.go(一行):

	hideChildConsole(command)

依据:Process Creation Flags — CREATE_NO_WINDOW (0x08000000):"The process is a console application that is being run without a console window."

本地验证结果(rc14 + 上述补丁,仅叠加本修复)

  • gofmt -l 干净;go vet ./... 通过;staticcheck 2026.2.1 零发现
  • go test ./... -count=1:除 internal/cli 外全部通过。internal/cli 的 17 个失败经在未打补丁的 rc14 上复跑确认为 Windows 既有问题(测试夹具以 baseline.json.bak\blocker 路径注入故障在 Windows 不生效),与本修复无关
  • scripts/blackbox/mcp_conformance.py:46 项中 44 项通过;2 项失败(search/get_entries)系套件以 aoci-code 仓自身文件为预期目标、对第三方仓库运行时的目标差异
  • 真实 MCP 会话(ZCode 重连)确认运行版本为打好补丁的构建,刷新全程静默

如需要我可以直接按此提交 PR。

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