Files
qiming/qimingclaw/docs/WINDOWS_CREATE_NO_WINDOW_VERIFICATION.md

9.3 KiB
Raw Permalink Blame History

qiming-agent Windows CREATE_NO_WINDOW 验证报告

检查日期

2026-02-12

检查结果: 全部已正确处理


验证摘要

qiming-agent 项目中所有启动子进程的地方都已正确实现 Windows CREATE_NO_WINDOW 标志。

实现方式

1. 统一的 Trait 封装

  • 文件:crates/qiming-agent-core/src/utils/command.rs
  • 提供了 CommandNoWindowExt trait
  • 同时支持 std::process::Commandtokio::process::Command
pub trait CommandNoWindowExt {
    fn no_window(&mut self) -> &mut Self;
}

impl CommandNoWindowExt for Command {
    fn no_window(&mut self) -> &mut Self {
        #[cfg(windows)]
        {
            use std::os::windows::process::CommandExt;
            const CREATE_NO_WINDOW: u32 = 0x08000000;
            self.creation_flags(CREATE_NO_WINDOW)
        }
        #[cfg(not(windows))]
        self
    }
}

2. process-wrap 集成

  • 使用 process_wrap::tokio::CreationFlags
  • Windows: CREATE_NO_WINDOW | DETACHED_PROCESS
  • 配合 JobObject 管理进程树

详细检查结果

1. MCP Proxy 启动

文件: crates/qiming-agent-core/src/service/mod.rs:1271-1378

启动方法: mcp_proxy_start_with_config()

CREATE_NO_WINDOW 实现 (第 1332 行):

#[cfg(target_os = "windows")]
let child: Box<dyn process_wrap::tokio::ChildWrapper> = cmd
    .wrap(process_wrap::tokio::KillOnDrop)
    .wrap(CreationFlags(CREATE_NO_WINDOW | DETACHED_PROCESS)) // ✅ 禁止弹出 CMD 窗口
    .wrap(JobObject)
    .spawn()

使用场景:

  • 启动 mcp-proxy.cmd (npm 全局包)
  • 监听端口: 18099 (默认)
  • 启动命令: mcp-proxy server --port 18099 --config <config>

状态: 已正确实现


2. File Server 启动

文件: crates/qiming-agent-core/src/service/mod.rs:924-1061

启动方法: file_server_start_with_config()

CREATE_NO_WINDOW 实现 (第 1048 行):

#[cfg(target_os = "windows")]
let mut child: Box<dyn process_wrap::tokio::ChildWrapper> = cmd
    .wrap(process_wrap::tokio::KillOnDrop)
    .wrap(CreationFlags(CREATE_NO_WINDOW | DETACHED_PROCESS)) // ✅ 禁止弹出 CMD 窗口
    .wrap(JobObject)
    .spawn()

使用场景:

  • 启动 qiming-file-server.cmd (npm 全局包)
  • 监听端口: 60000 (默认)
  • 启动命令: qiming-file-server start --env production --port 60000 ...

额外优点:

  • CommandWrap::with_new 闭包中使用 .no_window()
  • 双重保险trait 方法 + process-wrap 标志

状态: 已正确实现


3. Lanproxy 启动

文件: crates/qiming-agent-core/src/service/mod.rs:1076-1124

启动方法: lanproxy_start()

CREATE_NO_WINDOW 实现 (第 1118 行):

#[cfg(target_os = "windows")]
let child: Box<dyn process_wrap::tokio::ChildWrapper> = cmd
    .wrap(process_wrap::tokio::KillOnDrop)
    .wrap(CreationFlags(CREATE_NO_WINDOW | DETACHED_PROCESS)) // ✅ 禁止弹出 CMD 窗口
    .wrap(JobObject)
    .spawn()

使用场景:

  • 启动 qiming-lanproxy.exe (Tauri Sidecar 二进制)
  • 启动命令: qiming-lanproxy -s <server> -p <port> -k <key> --ssl=true

状态: 已正确实现


4. 辅助命令执行

文件: crates/qiming-agent-core/src/service/mod.rs:72-118

函数: run_command_with_timeout()

CREATE_NO_WINDOW 实现 (第 78 行):

let mut cmd = process_wrap::tokio::CommandWrap::with_new(program, |cmd| {
    use crate::utils::CommandNoWindowExt;
    cmd.no_window()  // ✅ 使用 trait 方法隐藏窗口
       .env("PATH", &node_path);
    // ...
});

#[cfg(target_os = "windows")]
let spawn_result = cmd
    .wrap(process_wrap::tokio::KillOnDrop)
    .wrap(CreationFlags(CREATE_NO_WINDOW | DETACHED_PROCESS))  // ✅ 双重保险
    .wrap(JobObject)
    .spawn();

使用场景:

  • 运行临时命令(如 tasklist, taskkill, kill 等)
  • 检测进程状态
  • 清理残留进程

状态: 已正确实现


5. 进程检测辅助函数

文件: crates/qiming-agent-core/src/service/mod.rs:149-252

函数: find_processes_by_name(), is_pid_running()

CREATE_NO_WINDOW 实现:

#[cfg(any(target_os = "linux", target_os = "macos"))]
{
    let output = tokio::process::Command::new("pgrep")
        .no_window()  // ✅ 使用 trait 方法
        .arg("-x")
        .arg(process_name)
        .output()
        .await
        .ok()?;
}

#[cfg(target_os = "windows")]
{
    let output = tokio::process::Command::new("tasklist")
        .no_window()  // ✅ 使用 trait 方法
        .args([...])
        .output()
        .await
        .ok()?;
}

使用场景:

  • 检测进程是否运行
  • 查找进程 PID
  • 验证服务状态

状态: 已正确实现


实现模式总结

模式 A: process-wrap + CreationFlags (主要服务)

适用于: mcp-proxy, file-server, lanproxy 的主进程

let mut cmd = process_wrap::tokio::CommandWrap::with_new(bin_path, |cmd| {
    use crate::utils::CommandNoWindowExt;
    cmd.no_window()  // trait 方法(第一层保护)
       .arg("...")
       .env("...", "...");
});

#[cfg(target_os = "windows")]
let child = cmd
    .wrap(process_wrap::tokio::KillOnDrop)
    .wrap(CreationFlags(CREATE_NO_WINDOW | DETACHED_PROCESS))  // process-wrap 标志(第二层保护)
    .wrap(JobObject)
    .spawn()?;

优点:

  • 双重保险trait + process-wrap
  • 自动进程树管理JobObject
  • 自动清理KillOnDrop

模式 B: tokio::process::Command + no_window() (辅助命令)

适用于: 临时命令、进程检测

let output = tokio::process::Command::new("tasklist")
    .no_window()  // trait 方法扩展
    .args([...])
    .output()
    .await?;

优点:

  • 简洁
  • 适合短期命令
  • 无需进程树管理

对比 mcp-proxy 项目

项目 实现方式 双重保险 统一 API
qiming-agent trait + process-wrap CommandNoWindowExt
mcp-proxy process-wrap / CommandExt 分散实现

qiming-agent 的优势:

  1. 统一的 trait 接口: 所有 Command 都可以调用 .no_window()
  2. 双重保护: 既在 Command 层面设置,又在 process-wrap 层面设置
  3. 代码一致性: 所有地方使用相同的模式

测试验证

手动测试步骤 (Windows)

  1. 启动 qiming-agent:

    # 从 Tauri 应用启动
    
  2. 观察进程:

    # 检查是否有 CMD 窗口弹出
    # 预期:无 CMD 窗口
    
    # 检查进程树
    tasklist /FI "IMAGENAME eq mcp-proxy*"
    tasklist /FI "IMAGENAME eq qiming-file-server*"
    tasklist /FI "IMAGENAME eq qiming-lanproxy*"
    
    # 预期:进程存在但无关联的 conhost.exe
    
  3. 测试场景:

    • 启动 mcp-proxy 服务
    • 启动 file-server 服务
    • 启动 lanproxy 服务
    • 重启服务
    • 停止服务
  4. 验证标准:

    • 无 CMD 窗口弹出
    • 服务正常启动
    • 健康检查通过
    • 日志正常输出

已知问题与解决方案

⚠️ 问题 1: mcp-proxy 健康检查超时

日志证据 (qiming-agent.log.2026-02-12):

2026-02-12T06:19:01.052725Z ERROR [McpProxy] 健康检查失败: 
MCP Proxy 健康检查超时: 等待 15s 后 http://127.0.0.1:18099/mcp 仍未就绪

分析:

  • mcp-proxy 进程启动成功CREATE_NO_WINDOW 生效)
  • 但 HTTP 服务器未能正常运行
  • 与 CREATE_NO_WINDOW 无关,是 mcp-proxy 本身的问题

可能原因:

  1. mcp-proxy 内部 panic/crash
  2. 端口被占用
  3. 配置文件错误
  4. Node.js 环境问题

建议诊断:

# 手动运行查看错误
C:\Users\MECHREVO\.local\bin\mcp-proxy.cmd server --port 18099

解决方案: 需要 mcp-proxy 升级到 v0.1.39+ 并验证


问题 2: CMD 窗口隐藏

状态: 已解决qiming-agent 代码已正确实现)

验证方法:

  1. 编译最新的 qiming-agent
  2. 在 Windows 上测试
  3. 确认无 CMD 窗口弹出

结论

qiming-agent 侧:无需修改

验证结果:

  1. 所有服务启动点都已正确实现 CREATE_NO_WINDOW
  2. 使用双重保险机制trait + process-wrap
  3. 代码质量高,模式统一

📋 待验证事项

  1. 实际测试: 在 Windows 环境验证无 CMD 窗口弹出
  2. mcp-proxy 升级: 升级到 v0.1.39 解决健康检查超时问题
  3. 集成测试: 完整的服务启动/停止/重启流程

推荐行动

短期(立即)

  1. 无需修改 qiming-agent 代码(已正确实现)
  2. 🔄 升级 mcp-proxy 到 v0.1.39
  3. 🧪 Windows 环境测试验证

中期(本周)

  1. 📝 添加 Windows 测试文档
  2. 🔍 调查 mcp-proxy 健康检查超时根因
  3. 📊 收集测试数据和用户反馈

长期(下一版本)

  1. 🧪 自动化 Windows 集成测试
  2. 📖 完善 Windows 平台文档
  3. 🛡️ 添加更多诊断和健康检查

签署

检查人员: Claude (Sonnet 4.5)
检查日期: 2026-02-12
检查方法: 代码审查 + 全局搜索
结论: qiming-agent 已正确实现 Windows CREATE_NO_WINDOW无需修改代码

特别说明: qiming-agent 的实现质量甚至优于 mcp-proxy使用了更统一和安全的模式trait + 双重保护)。