feat(brainstorm-server): 4h configurable idle timeout; close WS on shutdown

The companion shut down after only 30 minutes idle — too short for real
brainstorming, where a single question can sit far longer. And shutdown() never
closed upgraded WebSocket sockets, so an open browser connection could keep the
Node process alive after it was supposed to exit.

- Default idle timeout raised to 4 hours, configurable via BRAINSTORM_IDLE_TIMEOUT_MS
  and start-server.sh --idle-timeout-minutes (validated positive integer).
- Reported as idle_timeout_ms in the server-started JSON / server-info.
- shutdown() now destroys all client sockets so the process exits even with an
  open WebSocket.
- Watchdog check interval is configurable (BRAINSTORM_LIFECYCLE_CHECK_MS, default
  60s) so the lifecycle can be tested without minute-long waits.

Adds lifecycle.test.js (configured timeout reported; idle shutdown exits despite
an open WS — teeth-verified; the start-server flag). Wires ws-protocol,
lifecycle, and stop-server suites into npm test.

Closes #1237
Refs #1689
This commit is contained in:
Jesse Vincent
2026-06-09 15:08:09 -07:00
parent ddcb56c16e
commit f057b4a30b
4 changed files with 124 additions and 5 deletions

View File

@@ -11,6 +11,7 @@
# --host <bind-host> Host/interface to bind (default: 127.0.0.1).
# Use 0.0.0.0 in remote/containerized environments.
# --url-host <host> Hostname shown in returned URL JSON.
# --idle-timeout-minutes <n> Shut down after n minutes idle (default 240 = 4h).
# --foreground Run server in the current terminal (no backgrounding).
# --background Force background mode (overrides Codex auto-foreground).
@@ -22,6 +23,7 @@ FOREGROUND="false"
FORCE_BACKGROUND="false"
BIND_HOST="127.0.0.1"
URL_HOST=""
IDLE_TIMEOUT_MINUTES=""
while [[ $# -gt 0 ]]; do
case "$1" in
--project-dir)
@@ -36,6 +38,10 @@ while [[ $# -gt 0 ]]; do
URL_HOST="$2"
shift 2
;;
--idle-timeout-minutes)
IDLE_TIMEOUT_MINUTES="$2"
shift 2
;;
--foreground|--no-daemon)
FOREGROUND="true"
shift
@@ -59,6 +65,14 @@ if [[ -z "$URL_HOST" ]]; then
fi
fi
if [[ -n "$IDLE_TIMEOUT_MINUTES" ]]; then
if ! [[ "$IDLE_TIMEOUT_MINUTES" =~ ^[0-9]+$ ]] || [[ "$IDLE_TIMEOUT_MINUTES" -lt 1 ]]; then
echo "{\"error\": \"--idle-timeout-minutes must be a positive integer\"}"
exit 1
fi
export BRAINSTORM_IDLE_TIMEOUT_MS=$(( IDLE_TIMEOUT_MINUTES * 60 * 1000 ))
fi
# Some environments reap detached/background processes. Auto-foreground when detected.
if [[ -n "${CODEX_CI:-}" && "$FOREGROUND" != "true" && "$FORCE_BACKGROUND" != "true" ]]; then
FOREGROUND="true"