📦 deps(superpowers): vendor snapshot
Trigger Superpowers Sync / Run main sync script (push) Successful in 1m27s
Details
Trigger Superpowers Sync / Run main sync script (push) Successful in 1m27s
Details
This commit is contained in:
parent
69d12d51b4
commit
1b824559c3
|
|
@ -9,7 +9,7 @@
|
|||
{
|
||||
"name": "superpowers",
|
||||
"description": "Core skills library for Claude Code: TDD, debugging, collaboration patterns, and proven techniques",
|
||||
"version": "5.0.4",
|
||||
"version": "5.0.5",
|
||||
"source": "./",
|
||||
"author": {
|
||||
"name": "Jesse Vincent",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "superpowers",
|
||||
"description": "Core skills library for Claude Code: TDD, debugging, collaboration patterns, and proven techniques",
|
||||
"version": "5.0.4",
|
||||
"version": "5.0.5",
|
||||
"author": {
|
||||
"name": "Jesse Vincent",
|
||||
"email": "jesse@fsck.com"
|
||||
|
|
|
|||
|
|
@ -1,20 +1,13 @@
|
|||
# Changelog
|
||||
|
||||
## Unreleased
|
||||
## [5.0.5] - 2026-03-17
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Brainstorm server on Windows**: Auto-detect Windows/Git Bash (`OSTYPE=msys*`, `MSYSTEM`) and switch to foreground mode, fixing silent server failure caused by `nohup`/`disown` process reaping. Applies to all Windows shells (CMD, PowerShell, Git Bash) since they all route through Git Bash. ([#737](https://github.com/obra/superpowers/issues/737), based on [#740](https://github.com/obra/superpowers/pull/740))
|
||||
- **Portable shebangs**: Replace `#!/bin/bash` with `#!/usr/bin/env bash` in all 13 shell scripts. Fixes execution on NixOS, FreeBSD, and macOS with Homebrew bash where `/bin/bash` is outdated or missing. ([#700](https://github.com/obra/superpowers/pull/700), dupes: [#747](https://github.com/obra/superpowers/pull/747))
|
||||
- **POSIX-safe hook script**: Replace `${BASH_SOURCE[0]:-$0}` with `$0` in `hooks/session-start` and polyglot-hooks docs. Fixes 'Bad substitution' error on Ubuntu/Debian where `/bin/sh` is dash. ([#553](https://github.com/obra/superpowers/pull/553))
|
||||
- **Bash 5.3+ hook hang**: Replace heredoc (`cat <<EOF`) with `printf` in `hooks/session-start`. Fixes indefinite hang on macOS with Homebrew bash 5.3+ caused by a bash regression with large variable expansion in heredocs. ([#572](https://github.com/obra/superpowers/pull/572), [#571](https://github.com/obra/superpowers/issues/571))
|
||||
- **Cursor hooks support**: Add `hooks/hooks-cursor.json` with Cursor's camelCase format (`sessionStart`, `version: 1`) and update `.cursor-plugin/plugin.json` to reference it. Fix platform detection in `session-start` to check `CURSOR_PLUGIN_ROOT` first (Cursor may also set `CLAUDE_PLUGIN_ROOT`). (Based on [#709](https://github.com/obra/superpowers/pull/709))
|
||||
- **Brainstorm server ESM fix**: Renamed `server.js` → `server.cjs` so the brainstorming server starts correctly on Node.js 22+ where the root `package.json` `"type": "module"` caused `require()` to fail. ([PR #784](https://github.com/obra/superpowers/pull/784) by @sarbojitrana, fixes [#774](https://github.com/obra/superpowers/issues/774), [#780](https://github.com/obra/superpowers/issues/780), [#783](https://github.com/obra/superpowers/issues/783))
|
||||
- **Brainstorm owner-PID on Windows**: Skip `BRAINSTORM_OWNER_PID` lifecycle monitoring on Windows/MSYS2 where the PID namespace is invisible to Node.js. Prevents the server from self-terminating after 60 seconds. The 30-minute idle timeout remains as the safety net. ([#770](https://github.com/obra/superpowers/issues/770), docs from [PR #768](https://github.com/obra/superpowers/pull/768) by @lucasyhzhu-debug)
|
||||
- **stop-server.sh reliability**: Verify the server process actually died before reporting success. Waits up to 2 seconds for graceful shutdown, escalates to `SIGKILL`, and reports failure if the process survives. ([#723](https://github.com/obra/superpowers/issues/723))
|
||||
|
||||
### Already fixed on dev (closed PRs)
|
||||
### Changed
|
||||
|
||||
- **Windows hook quoting** ([#630](https://github.com/obra/superpowers/pull/630), [#529](https://github.com/obra/superpowers/issues/529)): `hooks.json` already uses escaped double quotes on dev.
|
||||
- **Windows symlink path** ([#539](https://github.com/obra/superpowers/pull/539)): Closed — the PR introduced a bug (literal `~` in path alongside `$env:USERPROFILE`). Current docs are correct.
|
||||
|
||||
### Known Issues
|
||||
|
||||
- **`BRAINSTORM_OWNER_PID` on Windows (main branch only)**: The main branch's `server.js` uses `process.kill(OWNER_PID, 0)` for lifecycle checks, but receives MSYS2 PIDs which are invisible to Node.js (different PID namespace). This causes the server to self-terminate after 60 seconds. Fix: resolve `OWNER_PID` via `/proc/$PPID/winpid` to get the Windows-native PID. The dev branch's `index.js` does not have this issue since it has no OWNER_PID lifecycle check.
|
||||
- **Execution handoff**: Restore user choice between subagent-driven-development and executing-plans after plan writing. Subagent-driven is recommended but no longer mandatory. (Reverts `5e51c3e`)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,17 @@
|
|||
# Superpowers Release Notes
|
||||
|
||||
## v5.0.5 (2026-03-17)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **Brainstorm server ESM fix** — renamed `server.js` → `server.cjs` so the brainstorming server starts correctly on Node.js 22+ where the root `package.json` `"type": "module"` caused `require()` to fail. (PR #784 by @sarbojitrana, fixes #774, #780, #783)
|
||||
- **Brainstorm owner-PID on Windows** — skip PID lifecycle monitoring on Windows/MSYS2 where the PID namespace is invisible to Node.js, preventing the server from self-terminating after 60 seconds. (#770, docs from PR #768 by @lucasyhzlu-debug)
|
||||
- **stop-server.sh reliability** — verify the server process actually died before reporting success. SIGTERM + 2s wait + SIGKILL fallback. (#723)
|
||||
|
||||
### Changed
|
||||
|
||||
- **Execution handoff** — restore user choice between subagent-driven and inline execution after plan writing. Subagent-driven is recommended but no longer mandatory.
|
||||
|
||||
## v5.0.4 (2026-03-16)
|
||||
|
||||
### Review Loop Refinements
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Source
|
||||
|
||||
- Repo: https://github.com/obra/superpowers
|
||||
- Ref: 3cee13e516e91d44b957c1336c3d08c8a8392702
|
||||
- Snapshot: 2026-03-17
|
||||
- Ref: 7e516434f2a30114300efc9247db32fb37daa5f9
|
||||
- Snapshot: 2026-03-18
|
||||
- Notes: vendored into playbook branch thirdparty/skill
|
||||
|
|
|
|||
|
|
@ -106,16 +106,22 @@ if [[ -z "$OWNER_PID" || "$OWNER_PID" == "1" ]]; then
|
|||
OWNER_PID="$PPID"
|
||||
fi
|
||||
|
||||
# On Windows/MSYS2, the MSYS2 PID namespace is invisible to Node.js.
|
||||
# Skip owner-PID monitoring — the 30-minute idle timeout prevents orphans.
|
||||
case "${OSTYPE:-}" in
|
||||
msys*|cygwin*|mingw*) OWNER_PID="" ;;
|
||||
esac
|
||||
|
||||
# Foreground mode for environments that reap detached/background processes.
|
||||
if [[ "$FOREGROUND" == "true" ]]; then
|
||||
echo "$$" > "$PID_FILE"
|
||||
env BRAINSTORM_DIR="$SCREEN_DIR" BRAINSTORM_HOST="$BIND_HOST" BRAINSTORM_URL_HOST="$URL_HOST" BRAINSTORM_OWNER_PID="$OWNER_PID" node server.js
|
||||
env BRAINSTORM_DIR="$SCREEN_DIR" BRAINSTORM_HOST="$BIND_HOST" BRAINSTORM_URL_HOST="$URL_HOST" BRAINSTORM_OWNER_PID="$OWNER_PID" node server.cjs
|
||||
exit $?
|
||||
fi
|
||||
|
||||
# Start server, capturing output to log file
|
||||
# Use nohup to survive shell exit; disown to remove from job table
|
||||
nohup env BRAINSTORM_DIR="$SCREEN_DIR" BRAINSTORM_HOST="$BIND_HOST" BRAINSTORM_URL_HOST="$URL_HOST" BRAINSTORM_OWNER_PID="$OWNER_PID" node server.js > "$LOG_FILE" 2>&1 &
|
||||
nohup env BRAINSTORM_DIR="$SCREEN_DIR" BRAINSTORM_HOST="$BIND_HOST" BRAINSTORM_URL_HOST="$URL_HOST" BRAINSTORM_OWNER_PID="$OWNER_PID" node server.cjs > "$LOG_FILE" 2>&1 &
|
||||
SERVER_PID=$!
|
||||
disown "$SERVER_PID" 2>/dev/null
|
||||
echo "$SERVER_PID" > "$PID_FILE"
|
||||
|
|
|
|||
|
|
@ -48,12 +48,21 @@ Save `screen_dir` from the response. Tell user to open the URL.
|
|||
|
||||
**Launching the server by platform:**
|
||||
|
||||
**Claude Code:**
|
||||
**Claude Code (macOS / Linux):**
|
||||
```bash
|
||||
# Default mode works — the script backgrounds the server itself
|
||||
scripts/start-server.sh --project-dir /path/to/project
|
||||
```
|
||||
|
||||
**Claude Code (Windows):**
|
||||
```bash
|
||||
# Windows auto-detects and uses foreground mode, which blocks the tool call.
|
||||
# Use run_in_background: true on the Bash tool call so the server survives
|
||||
# across conversation turns.
|
||||
scripts/start-server.sh --project-dir /path/to/project
|
||||
```
|
||||
When calling this via the Bash tool, set `run_in_background: true`. Then read `$SCREEN_DIR/.server-info` on the next turn to get the URL and port.
|
||||
|
||||
**Codex:**
|
||||
```bash
|
||||
# Codex reaps background processes. The script auto-detects CODEX_CI and
|
||||
|
|
@ -61,14 +70,6 @@ scripts/start-server.sh --project-dir /path/to/project
|
|||
scripts/start-server.sh --project-dir /path/to/project
|
||||
```
|
||||
|
||||
**Windows (Git Bash / CMD / PowerShell):**
|
||||
```bash
|
||||
# Windows/Git Bash reaps nohup background processes. The script auto-detects
|
||||
# this via OSTYPE/MSYSTEM and switches to foreground mode automatically.
|
||||
# No extra flags needed — all Windows shells route through Git Bash.
|
||||
scripts/start-server.sh --project-dir /path/to/project
|
||||
```
|
||||
|
||||
**Gemini CLI:**
|
||||
```bash
|
||||
# Use --foreground and set is_background: true on your shell tool call
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ This structure informs the task decomposition. Each task should produce self-con
|
|||
```markdown
|
||||
# [Feature Name] Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** [One sentence describing what this builds]
|
||||
|
||||
|
|
@ -126,17 +126,20 @@ After writing the complete plan:
|
|||
|
||||
## Execution Handoff
|
||||
|
||||
After saving the plan:
|
||||
After saving the plan, offer execution choice:
|
||||
|
||||
**"Plan complete and saved to `docs/superpowers/plans/<filename>.md`. Ready to execute?"**
|
||||
**"Plan complete and saved to `docs/superpowers/plans/<filename>.md`. Two execution options:**
|
||||
|
||||
**Execution path depends on harness capabilities:**
|
||||
**1. Subagent-Driven (recommended)** - I dispatch a fresh subagent per task, review between tasks, fast iteration
|
||||
|
||||
**If harness has subagents (Claude Code, etc.):**
|
||||
- **REQUIRED:** Use superpowers:subagent-driven-development
|
||||
- Do NOT offer a choice - subagent-driven is the standard approach
|
||||
**2. Inline Execution** - Execute tasks in this session using executing-plans, batch execution with checkpoints
|
||||
|
||||
**Which approach?"**
|
||||
|
||||
**If Subagent-Driven chosen:**
|
||||
- **REQUIRED SUB-SKILL:** Use superpowers:subagent-driven-development
|
||||
- Fresh subagent per task + two-stage review
|
||||
|
||||
**If harness does NOT have subagents:**
|
||||
- Execute plan in current session using superpowers:executing-plans
|
||||
**If Inline Execution chosen:**
|
||||
- **REQUIRED SUB-SKILL:** Use superpowers:executing-plans
|
||||
- Batch execution with checkpoints for review
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ const fs = require('fs');
|
|||
const path = require('path');
|
||||
const assert = require('assert');
|
||||
|
||||
const SERVER_PATH = path.join(__dirname, '../../skills/brainstorming/scripts/server.js');
|
||||
const SERVER_PATH = path.join(__dirname, '../../skills/brainstorming/scripts/server.cjs');
|
||||
const TEST_PORT = 3334;
|
||||
const TEST_DIR = '/tmp/brainstorm-test';
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,351 @@
|
|||
#!/usr/bin/env bash
|
||||
# Windows lifecycle tests for the brainstorm server.
|
||||
#
|
||||
# Verifies that the brainstorm server survives the 60-second lifecycle
|
||||
# check on Windows, where OWNER_PID monitoring is disabled because the
|
||||
# MSYS2 PID namespace is invisible to Node.js.
|
||||
#
|
||||
# Requirements:
|
||||
# - Node.js in PATH
|
||||
# - Run from the repository root, or set SUPERPOWERS_ROOT
|
||||
# - On Windows: Git Bash (OSTYPE=msys*)
|
||||
#
|
||||
# Usage:
|
||||
# bash tests/brainstorm-server/windows-lifecycle.test.sh
|
||||
set -uo pipefail
|
||||
|
||||
# ========== Configuration ==========
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
REPO_ROOT="${SUPERPOWERS_ROOT:-$(cd "$SCRIPT_DIR/../.." && pwd)}"
|
||||
START_SCRIPT="$REPO_ROOT/skills/brainstorming/scripts/start-server.sh"
|
||||
STOP_SCRIPT="$REPO_ROOT/skills/brainstorming/scripts/stop-server.sh"
|
||||
SERVER_JS="$REPO_ROOT/skills/brainstorming/scripts/server.js"
|
||||
|
||||
TEST_DIR="${TMPDIR:-/tmp}/brainstorm-win-test-$$"
|
||||
|
||||
passed=0
|
||||
failed=0
|
||||
skipped=0
|
||||
|
||||
# ========== Helpers ==========
|
||||
|
||||
cleanup() {
|
||||
# Kill any server processes we started
|
||||
for pidvar in SERVER_PID CONTROL_PID STOP_TEST_PID; do
|
||||
pid="${!pidvar:-}"
|
||||
if [[ -n "$pid" ]]; then
|
||||
kill "$pid" 2>/dev/null || true
|
||||
wait "$pid" 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
if [[ -n "${TEST_DIR:-}" && -d "$TEST_DIR" ]]; then
|
||||
rm -rf "$TEST_DIR"
|
||||
fi
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
pass() {
|
||||
echo " PASS: $1"
|
||||
passed=$((passed + 1))
|
||||
}
|
||||
|
||||
fail() {
|
||||
echo " FAIL: $1"
|
||||
echo " $2"
|
||||
failed=$((failed + 1))
|
||||
}
|
||||
|
||||
skip() {
|
||||
echo " SKIP: $1 ($2)"
|
||||
skipped=$((skipped + 1))
|
||||
}
|
||||
|
||||
wait_for_server_info() {
|
||||
local dir="$1"
|
||||
for _ in $(seq 1 50); do
|
||||
if [[ -f "$dir/.server-info" ]]; then
|
||||
return 0
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
get_port_from_info() {
|
||||
# Read the port from .server-info. Use grep/sed instead of Node.js
|
||||
# to avoid MSYS2-to-Windows path translation issues.
|
||||
grep -o '"port":[0-9]*' "$1/.server-info" | head -1 | sed 's/"port"://'
|
||||
}
|
||||
|
||||
http_check() {
|
||||
local port="$1"
|
||||
node -e "
|
||||
const http = require('http');
|
||||
http.get('http://localhost:$port/', (res) => {
|
||||
process.exit(res.statusCode === 200 ? 0 : 1);
|
||||
}).on('error', () => process.exit(1));
|
||||
" 2>/dev/null
|
||||
}
|
||||
|
||||
# ========== Platform Detection ==========
|
||||
|
||||
echo ""
|
||||
echo "=== Brainstorm Server Windows Lifecycle Tests ==="
|
||||
echo "Platform: ${OSTYPE:-unknown}"
|
||||
echo "MSYSTEM: ${MSYSTEM:-unset}"
|
||||
echo "Node: $(node --version 2>/dev/null || echo 'not found')"
|
||||
echo ""
|
||||
|
||||
is_windows="false"
|
||||
case "${OSTYPE:-}" in
|
||||
msys*|cygwin*|mingw*) is_windows="true" ;;
|
||||
esac
|
||||
if [[ -n "${MSYSTEM:-}" ]]; then
|
||||
is_windows="true"
|
||||
fi
|
||||
|
||||
if [[ "$is_windows" != "true" ]]; then
|
||||
echo "NOTE: Not running on Windows/MSYS2 (OSTYPE=${OSTYPE:-unset})."
|
||||
echo "Windows-specific tests will be skipped. Tests 4-6 still run."
|
||||
echo ""
|
||||
fi
|
||||
|
||||
mkdir -p "$TEST_DIR"
|
||||
|
||||
SERVER_PID=""
|
||||
CONTROL_PID=""
|
||||
STOP_TEST_PID=""
|
||||
|
||||
# ========== Test 1: OWNER_PID is empty on Windows ==========
|
||||
|
||||
echo "--- Owner PID Resolution ---"
|
||||
|
||||
if [[ "$is_windows" == "true" ]]; then
|
||||
# Replicate the PID resolution logic from start-server.sh lines 104-112
|
||||
TEST_OWNER_PID="$(ps -o ppid= -p "$PPID" 2>/dev/null | tr -d ' ' || true)"
|
||||
if [[ -z "$TEST_OWNER_PID" || "$TEST_OWNER_PID" == "1" ]]; then
|
||||
TEST_OWNER_PID="$PPID"
|
||||
fi
|
||||
# The fix: clear on Windows
|
||||
case "${OSTYPE:-}" in
|
||||
msys*|cygwin*|mingw*) TEST_OWNER_PID="" ;;
|
||||
esac
|
||||
|
||||
if [[ -z "$TEST_OWNER_PID" ]]; then
|
||||
pass "OWNER_PID is empty on Windows after fix"
|
||||
else
|
||||
fail "OWNER_PID is empty on Windows after fix" \
|
||||
"Expected empty, got '$TEST_OWNER_PID'"
|
||||
fi
|
||||
else
|
||||
skip "OWNER_PID is empty on Windows" "not on Windows"
|
||||
fi
|
||||
|
||||
# ========== Test 2: start-server.sh passes empty BRAINSTORM_OWNER_PID ==========
|
||||
|
||||
if [[ "$is_windows" == "true" ]]; then
|
||||
# Use a fake 'node' that captures the env var and exits
|
||||
FAKE_NODE_DIR="$TEST_DIR/fake-bin"
|
||||
mkdir -p "$FAKE_NODE_DIR"
|
||||
cat > "$FAKE_NODE_DIR/node" <<'FAKENODE'
|
||||
#!/usr/bin/env bash
|
||||
echo "CAPTURED_OWNER_PID=${BRAINSTORM_OWNER_PID:-__UNSET__}"
|
||||
exit 0
|
||||
FAKENODE
|
||||
chmod +x "$FAKE_NODE_DIR/node"
|
||||
|
||||
captured=$(PATH="$FAKE_NODE_DIR:$PATH" bash "$START_SCRIPT" --project-dir "$TEST_DIR/session" --foreground 2>/dev/null || true)
|
||||
owner_pid_value=$(echo "$captured" | grep "CAPTURED_OWNER_PID=" | head -1 | sed 's/CAPTURED_OWNER_PID=//')
|
||||
|
||||
if [[ "$owner_pid_value" == "" || "$owner_pid_value" == "__UNSET__" ]]; then
|
||||
pass "start-server.sh passes empty BRAINSTORM_OWNER_PID on Windows"
|
||||
else
|
||||
fail "start-server.sh passes empty BRAINSTORM_OWNER_PID on Windows" \
|
||||
"Expected empty or unset, got '$owner_pid_value'"
|
||||
fi
|
||||
|
||||
rm -rf "$FAKE_NODE_DIR" "$TEST_DIR/session"
|
||||
else
|
||||
skip "start-server.sh passes empty BRAINSTORM_OWNER_PID" "not on Windows"
|
||||
fi
|
||||
|
||||
# ========== Test 3: Auto-foreground detection on Windows ==========
|
||||
|
||||
echo ""
|
||||
echo "--- Foreground Mode Detection ---"
|
||||
|
||||
if [[ "$is_windows" == "true" ]]; then
|
||||
FAKE_NODE_DIR="$TEST_DIR/fake-bin"
|
||||
mkdir -p "$FAKE_NODE_DIR"
|
||||
cat > "$FAKE_NODE_DIR/node" <<'FAKENODE'
|
||||
#!/usr/bin/env bash
|
||||
echo "FOREGROUND_MODE=true"
|
||||
exit 0
|
||||
FAKENODE
|
||||
chmod +x "$FAKE_NODE_DIR/node"
|
||||
|
||||
# Run WITHOUT --foreground flag — Windows should auto-detect
|
||||
captured=$(PATH="$FAKE_NODE_DIR:$PATH" bash "$START_SCRIPT" --project-dir "$TEST_DIR/session2" 2>/dev/null || true)
|
||||
|
||||
if echo "$captured" | grep -q "FOREGROUND_MODE=true"; then
|
||||
pass "Windows auto-detects foreground mode"
|
||||
else
|
||||
fail "Windows auto-detects foreground mode" \
|
||||
"Expected foreground code path, output: $captured"
|
||||
fi
|
||||
|
||||
rm -rf "$FAKE_NODE_DIR" "$TEST_DIR/session2"
|
||||
else
|
||||
skip "Windows auto-detects foreground mode" "not on Windows"
|
||||
fi
|
||||
|
||||
# ========== Test 4: Server survives past 60-second lifecycle check ==========
|
||||
|
||||
echo ""
|
||||
echo "--- Server Survival (lifecycle check) ---"
|
||||
|
||||
mkdir -p "$TEST_DIR/survival"
|
||||
|
||||
echo " Starting server (will wait ~75s to verify survival past lifecycle check)..."
|
||||
|
||||
BRAINSTORM_DIR="$TEST_DIR/survival" \
|
||||
BRAINSTORM_HOST="127.0.0.1" \
|
||||
BRAINSTORM_URL_HOST="localhost" \
|
||||
BRAINSTORM_OWNER_PID="" \
|
||||
BRAINSTORM_PORT=$((49152 + RANDOM % 16383)) \
|
||||
node "$SERVER_JS" > "$TEST_DIR/survival/.server.log" 2>&1 &
|
||||
SERVER_PID=$!
|
||||
|
||||
if ! wait_for_server_info "$TEST_DIR/survival"; then
|
||||
fail "Server starts successfully" "Server did not write .server-info within 5 seconds"
|
||||
kill "$SERVER_PID" 2>/dev/null || true
|
||||
SERVER_PID=""
|
||||
else
|
||||
pass "Server starts successfully with empty OWNER_PID"
|
||||
|
||||
SERVER_PORT=$(get_port_from_info "$TEST_DIR/survival")
|
||||
|
||||
sleep 75
|
||||
|
||||
if kill -0 "$SERVER_PID" 2>/dev/null; then
|
||||
pass "Server is still alive after 75 seconds"
|
||||
else
|
||||
fail "Server is still alive after 75 seconds" \
|
||||
"Server died. Log tail: $(tail -5 "$TEST_DIR/survival/.server.log" 2>/dev/null)"
|
||||
fi
|
||||
|
||||
if http_check "$SERVER_PORT"; then
|
||||
pass "Server responds to HTTP after lifecycle check window"
|
||||
else
|
||||
fail "Server responds to HTTP after lifecycle check window" \
|
||||
"HTTP request to port $SERVER_PORT failed"
|
||||
fi
|
||||
|
||||
if grep -q "owner process exited" "$TEST_DIR/survival/.server.log" 2>/dev/null; then
|
||||
fail "No 'owner process exited' in logs" \
|
||||
"Found spurious owner-exit shutdown in log"
|
||||
else
|
||||
pass "No 'owner process exited' in logs"
|
||||
fi
|
||||
|
||||
kill "$SERVER_PID" 2>/dev/null || true
|
||||
wait "$SERVER_PID" 2>/dev/null || true
|
||||
SERVER_PID=""
|
||||
fi
|
||||
|
||||
# ========== Test 5: Bad OWNER_PID causes shutdown (control) ==========
|
||||
|
||||
echo ""
|
||||
echo "--- Control: Bad OWNER_PID causes shutdown ---"
|
||||
|
||||
mkdir -p "$TEST_DIR/control"
|
||||
|
||||
# Find a PID that does not exist
|
||||
BAD_PID=99999
|
||||
while kill -0 "$BAD_PID" 2>/dev/null; do
|
||||
BAD_PID=$((BAD_PID + 1))
|
||||
done
|
||||
|
||||
BRAINSTORM_DIR="$TEST_DIR/control" \
|
||||
BRAINSTORM_HOST="127.0.0.1" \
|
||||
BRAINSTORM_URL_HOST="localhost" \
|
||||
BRAINSTORM_OWNER_PID="$BAD_PID" \
|
||||
BRAINSTORM_PORT=$((49152 + RANDOM % 16383)) \
|
||||
node "$SERVER_JS" > "$TEST_DIR/control/.server.log" 2>&1 &
|
||||
CONTROL_PID=$!
|
||||
|
||||
if ! wait_for_server_info "$TEST_DIR/control"; then
|
||||
fail "Control server starts" "Server did not write .server-info within 5 seconds"
|
||||
kill "$CONTROL_PID" 2>/dev/null || true
|
||||
CONTROL_PID=""
|
||||
else
|
||||
pass "Control server starts with bad OWNER_PID=$BAD_PID"
|
||||
|
||||
echo " Waiting ~75s for lifecycle check to kill server..."
|
||||
sleep 75
|
||||
|
||||
if kill -0 "$CONTROL_PID" 2>/dev/null; then
|
||||
fail "Control server self-terminates with bad OWNER_PID" \
|
||||
"Server is still alive (expected it to die)"
|
||||
kill "$CONTROL_PID" 2>/dev/null || true
|
||||
else
|
||||
pass "Control server self-terminates with bad OWNER_PID"
|
||||
fi
|
||||
|
||||
if grep -q "owner process exited" "$TEST_DIR/control/.server.log" 2>/dev/null; then
|
||||
pass "Control server logs 'owner process exited'"
|
||||
else
|
||||
fail "Control server logs 'owner process exited'" \
|
||||
"Log tail: $(tail -5 "$TEST_DIR/control/.server.log" 2>/dev/null)"
|
||||
fi
|
||||
fi
|
||||
|
||||
wait "$CONTROL_PID" 2>/dev/null || true
|
||||
CONTROL_PID=""
|
||||
|
||||
# ========== Test 6: stop-server.sh cleanly stops the server ==========
|
||||
|
||||
echo ""
|
||||
echo "--- Clean Shutdown ---"
|
||||
|
||||
mkdir -p "$TEST_DIR/stop-test"
|
||||
|
||||
BRAINSTORM_DIR="$TEST_DIR/stop-test" \
|
||||
BRAINSTORM_HOST="127.0.0.1" \
|
||||
BRAINSTORM_URL_HOST="localhost" \
|
||||
BRAINSTORM_OWNER_PID="" \
|
||||
BRAINSTORM_PORT=$((49152 + RANDOM % 16383)) \
|
||||
node "$SERVER_JS" > "$TEST_DIR/stop-test/.server.log" 2>&1 &
|
||||
STOP_TEST_PID=$!
|
||||
echo "$STOP_TEST_PID" > "$TEST_DIR/stop-test/.server.pid"
|
||||
|
||||
if ! wait_for_server_info "$TEST_DIR/stop-test"; then
|
||||
fail "Stop-test server starts" "Server did not start"
|
||||
kill "$STOP_TEST_PID" 2>/dev/null || true
|
||||
STOP_TEST_PID=""
|
||||
else
|
||||
bash "$STOP_SCRIPT" "$TEST_DIR/stop-test" >/dev/null 2>&1 || true
|
||||
sleep 1
|
||||
|
||||
if ! kill -0 "$STOP_TEST_PID" 2>/dev/null; then
|
||||
pass "stop-server.sh cleanly stops the server"
|
||||
else
|
||||
fail "stop-server.sh cleanly stops the server" \
|
||||
"Server PID $STOP_TEST_PID is still alive after stop"
|
||||
kill "$STOP_TEST_PID" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
|
||||
wait "$STOP_TEST_PID" 2>/dev/null || true
|
||||
STOP_TEST_PID=""
|
||||
|
||||
# ========== Summary ==========
|
||||
|
||||
echo ""
|
||||
echo "=== Results: $passed passed, $failed failed, $skipped skipped ==="
|
||||
|
||||
if [[ $failed -gt 0 ]]; then
|
||||
exit 1
|
||||
fi
|
||||
exit 0
|
||||
|
|
@ -16,7 +16,7 @@ const crypto = require('crypto');
|
|||
const path = require('path');
|
||||
|
||||
// The module under test — will be the new zero-dep server file
|
||||
const SERVER_PATH = path.join(__dirname, '../../skills/brainstorming/scripts/server.js');
|
||||
const SERVER_PATH = path.join(__dirname, '../../skills/brainstorming/scripts/server.cjs');
|
||||
let ws;
|
||||
|
||||
try {
|
||||
|
|
|
|||
Loading…
Reference in New Issue