在 Windows 环境下,SuperPowers Brainstorm Server 默认以前台模式运行,这是为了防止 MSYS/Git Bash 的 nohup 后台进程被系统自动回收而导致服务器“秒退”。其启动脚本会自动检测操作系统环境(如 OSTYPE、MSYSTEM、CODEX_CI),并禁用 owner-PID 生命周期监控,转而依赖 30 分钟空闲超时作为保障。本文结合 start-server.sh、server.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
行为说明:
- 显式参数优先:使用
--foreground强制前台,--background强制后台。 - 环境自动检测:
- CODEX_CI:如果设置了此环境变量(通常为 Codex 运行环境),脚本将自动切换到前台模式,以防止后台进程被回收。
- OSTYPE / MSYSTEM:这是 Windows 排错的关键。当
OSTYPE匹配msys*、cygwin*或mingw*,或者存在MSYSTEM环境变量(Git Bash 通常会设置此变量)时,脚本会自动强制使用前台模式。
- 默认行为:在不指定参数且未命中上述自动检测条件时,脚本默认使用
nohup和disown以后台模式启动服务器,并将输出重定向到日志文件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. 完整排错流程
- 服务器启动失败,无输出:
- 确认通过 Git Bash 执行脚本。
- 尝试添加
--foreground参数在前台运行,查看直接报错信息。 - 确认 Node.js 已安装且在系统
PATH中。
- 服务器启动后一分钟内退出:
- 检查
server.log日志,搜索owner process exited或owner-pid-invalid。如果存在owner process exited,说明 owner-PID 监控错误触发。 - 确认你的 Superpowers 版本 >= v5.0.5,该版本已修复 Windows owner-PID 问题。
- 在 Windows 上,启动时应确保脚本能自动检测到 MSYS 环境(见第 1 点),从而将
OWNER_PID设置为空。
- 检查
- 服务器闲置一段时间后自动关闭:
- 这是正常行为,受 30 分钟空闲超时控制。日志中会有
idle timeout记录。 - 如果需要服务器长期运行,请保持浏览器页面打开(WebSocket 连接会重置空闲计时)。
- 这是正常行为,受 30 分钟空闲超时控制。日志中会有
- 无法停止服务器:
- 使用
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 环境(通过 OSTYPE 或 MSYSTEM 环境变量),并自动启用了前台模式。这是为了防止 nohup 后台进程被系统回收,是预期的安全行为。
Q: owner-pid-invalid 在日志中出现意味着什么?
A: 这表示服务器在启动时验证了 BRAINSTORM_OWNER_PID 指向的进程,发现它已经死亡(在第一次生命周期检查之前)。服务器会因此禁用 owner-PID 监控,转而依赖 30 分钟空闲超时。这常见于 PID 解析不正确的环境(如某些 WSL 或远程 SSH 场景),并不直接导致服务器退出。