Files
pxpipe/scripts/restart.sh
T
teamchong a66a558b55 refactor: remove all CLI flags and behavior env vars — single codepath
The proxy used to expose ~20 behavior toggles (--no-compress,
--no-tools, --no-schemas, --no-reminders, --no-tool-results,
--history, --no-history, --history-keep-tail N, --history-min-prefix N,
--min-chars N, --min-reminder-chars N, --min-tool-result-chars N,
--cols N, --multi-col N, --no-track, --events-file PATH, --port N,
--upstream URL) plus matching env vars. Each one was a dead branch in
the common case and a configuration knob nobody had a principled
reason to pick a value for.

Replaced with: exactly one way to run the proxy. Every compression
mode on, every tuning parameter at its measured-best value, history
compression always active (was opt-in dead code). The only adjustable
surface is deployment concerns — where to listen, what to forward,
where to log — env-var only:

  PORT                 default 47821
  ANTHROPIC_UPSTREAM   default https://api.anthropic.com
  PIXELPIPE_LOG        default ~/.pixelpipe/events.jsonl

CLI accepts only --help and --version. Anything else exits with
non-zero and a one-line error.

Notable behavior change:
- DEFAULTS.compressHistory flipped false → true. Variant-C history-
  image compression now runs on every request (was opt-in via
  --history / COMPRESS_HISTORY=1). The static-slab cache_control
  placement is on the system image, not on the history-replacement
  chain, so the published cache-topology risk does not apply.

Touched:
- src/node.ts: CliOpts → RuntimeConfig (3 fields). parseCli is now
  ~25 lines. printHelp reduced to env-var-only doc.
- src/core/transform.ts: DEFAULTS.compressHistory = true. Comment
  updated.
- scripts/restart.sh: drops PROXY_ARGS array entirely. Port read
  from PORT= env var. Unknown args rejected.
- tests/restart.test.sh: replaces flag-passthrough test with a
  reject-unknown-args test. 4/4 pass.
- tests/history.test.ts: renames the "compressHistory:false (default)"
  test to reflect the new always-on default; asserts the input-not-
  mutated invariant remains.
- README.md: configuration table reduced to 3 env vars; restart
  examples drop CLI flag passthrough.

Tests: 277/277. Typecheck + build clean. Restart script tests: 4/4.
2026-05-19 17:01:05 -04:00

116 lines
4.1 KiB
Bash
Executable File

#!/usr/bin/env bash
# Restart the local pixelpipe proxy.
#
# What this does, in order:
# 1. Discover every running pixelpipe proxy via `pgrep -f "node.*bin/cli.js"`
# and list them. If multiple are running (orphans from a prior crashed
# session), kill all of them — there's no "right" oldest in a graceful
# restart, we want a clean slate.
# 2. Send SIGTERM. The proxy's SIGTERM handler flushes the JSONL tracker
# and exits. Poll up to 5s for clean exit.
# 3. Anything still alive after 5s gets SIGKILL with a warning.
# 4. Rebuild (`pnpm run build`) unless --no-build is passed. Build errors
# abort the restart so we never start a stale binary.
# 5. Check the target port is actually free; if not, name the process
# holding it (with a hint for the user — common cause: another tool, or
# step 3 didn't fully release).
# 6. Start a fresh proxy via `exec node bin/cli.js "$@"` so Ctrl-C reaches
# Node directly.
#
# Flags:
# --no-build Skip the rebuild step. Use when you know dist/ is fresh.
#
# Examples:
# pnpm run restart
# pnpm run restart -- --no-build
# PORT=47899 pnpm run restart
set -euo pipefail
cd "$(dirname "$0")/.."
# --- Parse our own flags out of "$@". --no-build only — pixelpipe takes none. ----
DO_BUILD=1
for arg in "$@"; do
case "$arg" in
--no-build)
DO_BUILD=0
;;
*)
echo "[restart] unknown argument: $arg" >&2
echo "[restart] this script only accepts --no-build (pixelpipe takes no flags)" >&2
exit 2
;;
esac
done
# --- Figure out which port the new proxy will bind. PORT env var or 47821.
TARGET_PORT="${PORT:-47821}"
# --- 1. Discover running proxies ------------------------------------------
# `[c]li.js` keeps pgrep from matching itself if anyone pipes us through grep.
PIDS_RAW=$(pgrep -f 'node.*bin/[c]li\.js' 2>/dev/null || true)
if [ -n "$PIDS_RAW" ]; then
# Convert to space-separated list, sorted numerically for stable output.
PIDS=$(echo "$PIDS_RAW" | tr '\n' ' ' | xargs -n1 | sort -n | tr '\n' ' ')
echo "[restart] found running pixelpipe proxy PID(s): $PIDS"
# --- 2. SIGTERM all of them ---
for pid in $PIDS; do
if kill -0 "$pid" 2>/dev/null; then
echo "[restart] SIGTERM $pid (graceful — tracker flushes on shutdown)"
kill -TERM "$pid" 2>/dev/null || true
fi
done
# Poll up to 5s for graceful exit.
for _ in $(seq 1 50); do
STILL=$(pgrep -f 'node.*bin/[c]li\.js' 2>/dev/null || true)
[ -z "$STILL" ] && break
sleep 0.1
done
# --- 3. Escalate to SIGKILL only if still alive ---
STILL=$(pgrep -f 'node.*bin/[c]li\.js' 2>/dev/null || true)
if [ -n "$STILL" ]; then
echo "[restart] WARNING: PID(s) still alive after 5s, escalating to SIGKILL: $STILL"
for pid in $STILL; do
kill -KILL "$pid" 2>/dev/null || true
done
sleep 0.3
fi
else
echo "[restart] no running proxy found"
fi
# --- 4. Rebuild (skippable) ----------------------------------------------
if [ "$DO_BUILD" -eq 1 ]; then
echo "[restart] rebuilding…"
if ! pnpm run build; then
echo "[restart] ERROR: build failed. Not starting a stale binary." >&2
exit 1
fi
else
echo "[restart] --no-build: skipping rebuild (assuming dist/ is fresh)"
fi
# --- 5. Sanity-check the target port is free -----------------------------
# `lsof` is preinstalled on macOS and most Linux distros. If it isn't, we
# skip the check rather than failing — the new proxy will surface the same
# EADDRINUSE error via Node's listen() callback.
if command -v lsof >/dev/null 2>&1; then
HOLDER=$(lsof -nP -iTCP:"$TARGET_PORT" -sTCP:LISTEN -t 2>/dev/null || true)
if [ -n "$HOLDER" ]; then
HOLDER_CMD=$(ps -o command= -p "$HOLDER" 2>/dev/null || echo "?")
echo "[restart] ERROR: port $TARGET_PORT is still held by PID $HOLDER:" >&2
echo " $HOLDER_CMD" >&2
echo " Hint: if that's a pixelpipe proxy our SIGTERM should have cleared," >&2
echo " it may have been started outside this repo. Free the port and rerun." >&2
exit 1
fi
fi
# --- 6. Start fresh in the foreground. exec so Ctrl-C goes straight to Node.
echo "[restart] starting fresh proxy on :$TARGET_PORT (Ctrl-C to stop)"
exec node bin/cli.js