Put tsx on PATH instead of replacing npx call sites

This commit is contained in:
Rebase Agent
2026-05-14 17:02:48 +00:00
committed by Forgejo
parent 8f631969ff
commit dea5ea4c18
+21 -17
View File
@@ -45,28 +45,32 @@ IDLE_THRESHOLD_MS=180000 # 3 minutes — session considered idle if last_active
# Script paths
SCRIPT_DIR="/app/.opencode/skills/auto-agents-system/scripts"
# Resolve a stable tsx binary path. Using `npx --yes tsx` is unsafe under
# concurrency: when many invocations start simultaneously with a cold (or
# even partially-warm) npm cache, they race on writes to ~/.npm/_npx/.../
# and corrupt each other with `ENOTEMPTY: rename '.../esbuild' ...` errors,
# crashing all but one and leaving the cache in a broken state for some time
# afterwards. We install tsx once into ~/.local/node_modules and call that
# binary directly, bypassing npx entirely.
# Make tsx discoverable on PATH. Running `npx --yes tsx` concurrently with
# a cold or partially-warm npm cache causes a race in `~/.npm/_npx/<hash>/`:
# multiple npm processes simultaneously try to rename `node_modules/esbuild`
# to the same atomic-backup name and fail with
# `ENOTEMPTY: rename '.../esbuild' -> '.../esbuild-7kCFO8Lm'`, crashing
# all but one of them and leaving the cache broken for follow-on calls.
# When tsx is on PATH, npx skips its install/cache logic entirely and just
# execs the existing binary — so the race disappears without changing any
# call sites. We install tsx once into ~/.local/node_modules and prepend
# its bin dir to PATH for the rest of this script's process tree.
TSX_PREFIX="${HOME}/.local"
TSX_BIN="${TSX_PREFIX}/node_modules/.bin/tsx"
if ! [[ -x "$TSX_BIN" ]]; then
TSX_BIN_DIR="${TSX_PREFIX}/node_modules/.bin"
if ! [[ -x "${TSX_BIN_DIR}/tsx" ]]; then
printf "[%s] Installing tsx into %s …\n" "$(date +%H:%M:%S)" "$TSX_PREFIX" >&2
mkdir -p "$TSX_PREFIX"
npm install --prefix "$TSX_PREFIX" --silent tsx >/dev/null 2>&1 \
|| { printf "ERROR: failed to install tsx into %s\n" "$TSX_PREFIX" >&2; exit 1; }
fi
export PATH="${TSX_BIN_DIR}:${PATH}"
SESSION_LIST="$TSX_BIN ${SCRIPT_DIR}/session_list.ts"
SESSION_FIND_PREFIX="$TSX_BIN ${SCRIPT_DIR}/session_find_by_prefix.ts"
SESSION_START="$TSX_BIN ${SCRIPT_DIR}/session_start.ts"
SESSION_MESSAGES="$TSX_BIN ${SCRIPT_DIR}/session_messages.ts"
SESSION_DELETE="$TSX_BIN ${SCRIPT_DIR}/session_delete.ts"
SESSION_STOP="$TSX_BIN ${SCRIPT_DIR}/session_stop.ts"
SESSION_LIST="npx --yes tsx ${SCRIPT_DIR}/session_list.ts"
SESSION_FIND_PREFIX="npx --yes tsx ${SCRIPT_DIR}/session_find_by_prefix.ts"
SESSION_START="npx --yes tsx ${SCRIPT_DIR}/session_start.ts"
SESSION_MESSAGES="npx --yes tsx ${SCRIPT_DIR}/session_messages.ts"
SESSION_DELETE="npx --yes tsx ${SCRIPT_DIR}/session_delete.ts"
SESSION_STOP="npx --yes tsx ${SCRIPT_DIR}/session_stop.ts"
# ── Internal state ───────────────────────────────────────────────────────
SERVER_PID=""
@@ -425,7 +429,7 @@ fetch_list_script() {
fi
local result
result=$(timeout "$SCRIPT_TIMEOUT_SEC" "$TSX_BIN" "$script_path" \
result=$(timeout "$SCRIPT_TIMEOUT_SEC" npx --yes tsx "$script_path" \
--url "$forgejo_url" \
--pat "$forgejo_pat" \
--owner "$forgejo_owner" \
@@ -1076,7 +1080,7 @@ main_loop() {
fi
cache_keys+=("$cache_key")
log "[pool:${prefix}] launching $(basename "$script_path") (cache key: ${cache_key})..."
timeout "$SCRIPT_TIMEOUT_SEC" "$TSX_BIN" "$script_path" \
timeout "$SCRIPT_TIMEOUT_SEC" npx --yes tsx "$script_path" \
--url "$FORGEJO_URL" \
--pat "$FORGEJO_PAT" \
--owner "$FORGEJO_OWNER" \