在 Windows 环境下,SuperPowers Brainstorm Server 默认以前台模式运行,这是为了防止 MSYS/Git Bash 的 nohup 后台进程被系统自动回收而导致服务器“秒退”。其启动脚本会自动检测操作系统环境(如 OSTYPEMSYSTEMCODEX_CI),并禁用 owner-PID 生命周期监控,转而依赖 30 分钟空闲超时作为保障。本文结合 start-server.shserver.cjs 源码和 windows-lifecycle.test.sh 测试用例,详解跨平台启动逻辑、Windows 生命周期管理及排错方法。

SuperPowers Brainstorm Server 跨平台启动与 Windows 生命周期排错

Brainstorm Server 是 Superpowers 可视化头脑风暴 功能的核心组件,是一个零依赖的 Node.js HTTP/WebSocket 服务器。在 Windows 环境下,其后台进程管理与 Unix 系统存在差异,容易导致服务器在启动约 60 秒后意外退出。本文基于源码和测试,提供从启动到停止的完整排错指南。

1. 启动模式:自动检测与显式控制

启动入口是 start-server.sh 脚本。它通过环境变量和命令行参数决定以前台(foreground)还是后台(background)模式运行服务器。

核心逻辑片段 (start-server.sh)

# Windows/Git Bash reaps nohup background processes. Auto-foreground when detected.
if [[ "$FOREGROUND" != "true" && "$FORCE_BACKGROUND" != "true" ]]; then
  case "${OSTYPE:-}" in
    msys*|cygwin*|mingw*) FOREGROUND="true" ;;
  esac
  if [[ -n "${MSYSTEM:-}" ]]; then
    FOREGROUND="true"
  fi
fi

行为说明

  1. 显式参数优先:使用 --foreground 强制前台,--background 强制后台。
  2. 环境自动检测
    • CODEX_CI:如果设置了此环境变量(通常为 Codex 运行环境),脚本将自动切换到前台模式,以防止后台进程被回收。
    • OSTYPE / MSYSTEM:这是 Windows 排错的关键。当 OSTYPE 匹配 msys*cygwin*mingw*,或者存在 MSYSTEM 环境变量(Git Bash 通常会设置此变量)时,脚本会自动强制使用前台模式
  3. 默认行为:在不指定参数且未命中上述自动检测条件时,脚本默认使用 nohupdisown 以后台模式启动服务器,并将输出重定向到日志文件 server.log

排错提示:在 Windows 的 CMD 或 PowerShell 中直接运行 .sh 脚本通常会失败,应通过 Git Bash 或 WSL 执行。如果服务器启动后“秒退”,请检查是否因上述环境被识别为后台模式,而系统回收了该进程。

2. 服务器生命周期:Owner-PID 与空闲超时

服务器能否长期稳定运行,取决于 server.cjs 中的生命周期管理策略。

Owner-PID 监控

服务器启动时会尝试解析并监控其父进程(即调用它的 harness,如 Claude Code)的 PID (BRAINSTORM_OWNER_PID)。该逻辑每 60 秒检查一次:

function ownerAlive() {
  if (!ownerPid) return true;
  try { process.kill(ownerPid, 0); return true; } catch (e) { return e.code === 'EPERM'; }
}
// ...
if (!ownerAlive()) shutdown('owner process exited');

关键排错点

  • 在 Windows/MSYS2 环境下,Node.js 进程无法看到 MSYS2 层的 PID,process.kill(ownerPid, 0) 调用会失败。
  • 因此,start-server.sh 在检测到 Windows 环境时,会OWNER_PID 解析为空(或在 server.cjs 中验证失败后置空),从而禁用此监控机制。这是 v5.0.5 版本的重要修复,解决了服务器在 Windows 上运行约 1 分钟后自行关闭的问题。

空闲超时保障

作为 owner-PID 监控的补充,如果没有任何浏览器连接或用户交互活动,服务器会在 30 分钟后自动关闭:

const IDLE_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes
// ...
else if (Date.now() - lastActivity > IDLE_TIMEOUT_MS) shutdown('idle timeout');

这确保了即使 owner 进程已意外退出,服务器也不会成为孤立的孤儿进程。

3. Windows 专用生命周期测试验证

仓库中的 tests/brainstorm-server/windows-lifecycle.test.sh 提供了严格的验证方法。它模拟了 Windows 环境,并运行关键测试用例:

测试 4:存活验证

  • 以空 BRAINSTORM_OWNER_PID 启动服务器,然后等待 75 秒(这覆盖了 60 秒的生命周期检查周期),验证服务器是否依然存活并响应 HTTP 请求。这是确保 Windows 修复(禁用 owner-PID 监控)有效的直接证据。

测试 5:坏 PID 控制测试

  • 以一个不存在的 PID 作为 BRAINSTORM_OWNER_PID 启动服务器,同样等待 75 秒。预期结果是服务器因检测到 owner 进程死亡而自动关闭(日志中将出现 owner process exited)。

测试 6:停止验证

  • 验证 stop-server.sh 脚本能否干净地终止服务器进程。

排错应用:如果你的服务器在 Windows 上仍会意外退出,可参考此测试脚本,手动设置 BRAINSTORM_OWNER_PID 为空值并启动,观察是否稳定运行超过 1 分钟。

4. 彻底停止服务器

始终使用 stop-server.sh 脚本来停止服务器。它采用先礼貌(SIGTERM)后强制(SIGKILL)的策略,并验证进程是否真正死亡

# Try to stop gracefully, fallback to force if still alive
kill "$pid" 2>/dev/null || true
# Wait for graceful shutdown (up to ~2s)
# If still running, escalate to SIGKILL
kill -9 "$pid" 2>/dev/null || true

脚本在退出前会检查进程是否仍然存活,如果 SIGKILL 后进程仍在运行,则报告失败。这避免了“僵尸进程”问题。

5. 跨平台钩子:CMD/bash Polyglot 包装器

为了确保 Superpowers 在所有平台(包括 Windows CMD)上被正确加载,其使用了一种 CMD/bash 双模式包装器技术(详见 docs/windows/polyglot-hooks.md)。同一个 .cmd 文件在 Windows CMD 和 Unix Shell 下会有不同的行为:

: << 'CMDBLOCK'
@echo off
"C:\Program Files\Git\bin\bash.exe" -l -c "\"$(cygpath -u \"$CLAUDE_PLUGIN_ROOT\")/hooks/session-start.sh\""
exit /b
CMDBLOCK

# Unix shell runs from here
"${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh"
  • 在 Windows CMD 中: 被视为标签,@echo off 后的 bash.exe 命令被执行,exit /b 确保后续命令不被执行。
  • 在 Unix bash 中: << 'CMDBLOCK' 是一个空操作和 heredoc 开始,CMDBLOCK 之间的内容被忽略,直接执行下方的 session-start.sh

这种设计保证了 using-superpowers 技能在会话开始时能在任何环境被加载。

6. 完整排错流程

  1. 服务器启动失败,无输出
    • 确认通过 Git Bash 执行脚本。
    • 尝试添加 --foreground 参数在前台运行,查看直接报错信息。
    • 确认 Node.js 已安装且在系统 PATH 中。
  2. 服务器启动后一分钟内退出
    • 检查 server.log 日志,搜索 owner process exitedowner-pid-invalid。如果存在 owner process exited,说明 owner-PID 监控错误触发。
    • 确认你的 Superpowers 版本 >= v5.0.5,该版本已修复 Windows owner-PID 问题。
    • 在 Windows 上,启动时应确保脚本能自动检测到 MSYS 环境(见第 1 点),从而将 OWNER_PID 设置为空。
  3. 服务器闲置一段时间后自动关闭
    • 这是正常行为,受 30 分钟空闲超时控制。日志中会有 idle timeout 记录。
    • 如果需要服务器长期运行,请保持浏览器页面打开(WebSocket 连接会重置空闲计时)。
  4. 无法停止服务器
    • 使用 stop-server.sh <session_dir> 命令。<session_dir> 通常是 /tmp/brainstorm-<id> 或项目下的 .superpowers/brainstorm/<id>
    • 如果脚本失败,根据日志中的 PID 手动执行 kill -9 <pid>(在 Git Bash 或 WSL 中)。

FAQ

Q: 为什么在 Windows 上启动服务器时,即使不加 --foreground 参数,它也以前台模式运行? A: 因为 start-server.sh 脚本内部检测到了 Windows/MSYS 环境(通过 OSTYPEMSYSTEM 环境变量),并自动启用了前台模式。这是为了防止 nohup 后台进程被系统回收,是预期的安全行为。

Q: owner-pid-invalid 在日志中出现意味着什么? A: 这表示服务器在启动时验证了 BRAINSTORM_OWNER_PID 指向的进程,发现它已经死亡(在第一次生命周期检查之前)。服务器会因此禁用 owner-PID 监控,转而依赖 30 分钟空闲超时。这常见于 PID 解析不正确的环境(如某些 WSL 或远程 SSH 场景),并不直接导致服务器退出。