Skip to content

Instantly share code, notes, and snippets.

@brunos3d
Last active May 18, 2026 07:24
Show Gist options
  • Select an option

  • Save brunos3d/66abd16661cfcfd4b5a943b4baf96f24 to your computer and use it in GitHub Desktop.

Select an option

Save brunos3d/66abd16661cfcfd4b5a943b4baf96f24 to your computer and use it in GitHub Desktop.
Claude Code socket keepalive fix — workaround for 'socket connection was closed unexpectedly' (issue #60133)
#!/usr/bin/env bash
# =============================================================================
# claude-keepalive-fix.sh
# Workaround for: "API Error: The socket connection was closed unexpectedly"
# GitHub issue: https://github.com/anthropics/claude-code/issues/60133
#
# This script applies OS-level TCP keepalive fixes that compensate for
# the Claude Code binary (Bun 1.3.14) not setting SO_KEEPALIVE on its
# TCP sockets, combined with Anthropic's server-side keepalive flags
# being set to 0ms via GrowthBook feature flags.
#
# Supports: Linux, macOS
# Requires: gcc or clang, sudo (for sysctl phase only)
# =============================================================================
set -uo pipefail
# ── colours ──────────────────────────────────────────────────────────────────
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
BLUE='\033[0;34m'; BOLD='\033[1m'; DIM='\033[2m'; NC='\033[0m'
info() { echo -e "${BLUE}[INFO]${NC} $*"; }
success() { echo -e "${GREEN}[OK]${NC} $*"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
error() { echo -e "${RED}[ERR]${NC} $*"; }
step() { echo -e "\n${BOLD}${BLUE}▶ $*${NC}"; }
dim() { echo -e "${DIM} $*${NC}"; }
ask() {
local prompt="$1"
echo -e "\n${BOLD}${YELLOW}?${NC} ${BOLD}${prompt}${NC} ${DIM}[Y/n]${NC} "
read -r -n1 reply 2>/dev/null || read -r reply
echo
[[ "$reply" =~ ^[Yy]$ ]] || [[ -z "$reply" ]]
}
# ── detect OS ────────────────────────────────────────────────────────────────
OS="$(uname -s)"
ARCH="$(uname -m)"
if [[ "$OS" == "Darwin" ]]; then
PLATFORM="macOS"
LIB_EXT="dylib"
LIB_FLAG="-dynamiclib"
PRELOAD_VAR="DYLD_INSERT_LIBRARIES"
CC="clang"
elif [[ "$OS" == "Linux" ]]; then
PLATFORM="Linux"
LIB_EXT="so"
LIB_FLAG="-shared -fPIC"
PRELOAD_VAR="LD_PRELOAD"
CC="gcc"
else
error "Unsupported OS: $OS. Only Linux and macOS are supported."
exit 1
fi
# ── detect shell config ───────────────────────────────────────────────────────
detect_shell_config() {
local shell_name
shell_name="$(basename "${SHELL:-bash}")"
if [[ "$shell_name" == "zsh" ]]; then
echo "${ZDOTDIR:-$HOME}/.zshrc"
elif [[ "$shell_name" == "bash" ]]; then
if [[ "$PLATFORM" == "macOS" ]]; then
echo "$HOME/.bash_profile"
else
echo "$HOME/.bashrc"
fi
else
echo "$HOME/.profile"
fi
}
SHELL_CONFIG="$(detect_shell_config)"
LIB_DIR="$HOME/.local/lib"
LIB_FILE="$LIB_DIR/libkeepalive.$LIB_EXT"
MARKER="# claude-keepalive-fix — managed block"
# ── header ───────────────────────────────────────────────────────────────────
echo
echo -e "${BOLD}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${BOLD}║ Claude Code — Socket Keepalive Fix v1.0 ║${NC}"
echo -e "${BOLD}╚══════════════════════════════════════════════════════════════╝${NC}"
echo
echo -e " Platform : ${BOLD}$PLATFORM${NC} ($ARCH)"
echo -e " Shell cfg: ${BOLD}$SHELL_CONFIG${NC}"
echo -e " Library : ${BOLD}$LIB_FILE${NC}"
echo
echo -e " This script applies ${BOLD}4 independent fixes${NC}. Each one is optional"
echo -e " and will ask for confirmation before making any change."
echo -e " To revert everything, run: ${BOLD}claude-keepalive-uninstall.sh${NC}"
echo
echo -e " Issue ref: ${DIM}https://github.com/anthropics/claude-code/issues/60133${NC}"
echo
echo -e "${YELLOW} ⚠ Read each step before confirming. Some steps require sudo.${NC}"
echo
# ── phase 1: environment variables ───────────────────────────────────────────
step "Phase 1 of 4 — Environment variables"
echo
echo -e " Adds the following exports to ${BOLD}$SHELL_CONFIG${NC}:"
echo
echo -e " ${DIM}CLAUDE_CODE_REMOTE_SEND_KEEPALIVES=true${NC}"
dim " Enables application-level session keepalives in Claude Code"
echo -e " ${DIM}BUN_CONFIG_HTTP_IDLE_TIMEOUT=300${NC}"
dim " Extends Bun's HTTP connection pool idle timeout to 5 minutes"
echo -e " ${DIM}BUN_CONFIG_HTTP_RETRY_COUNT=3${NC}"
dim " Enables automatic HTTP retry on connection failure"
echo -e " ${DIM}CLAUDE_STREAM_IDLE_TIMEOUT_MS=120000${NC}"
dim " Extends the stream idle watchdog timeout to 2 minutes"
echo -e " ${DIM}NODE_OPTIONS=--dns-result-order=ipv4first${NC}"
dim " Prefers IPv4 over IPv6 for DNS results (more stable NAT path)"
echo
if ask "Apply environment variable fixes to $SHELL_CONFIG?"; then
# Check if already applied
if grep -q "$MARKER" "$SHELL_CONFIG" 2>/dev/null; then
warn "Env vars block already present in $SHELL_CONFIG — skipping."
else
cat >> "$SHELL_CONFIG" << ENVBLOCK
$MARKER — begin
export CLAUDE_CODE_REMOTE_SEND_KEEPALIVES=true
export BUN_CONFIG_HTTP_IDLE_TIMEOUT=300
export BUN_CONFIG_HTTP_RETRY_COUNT=3
export CLAUDE_STREAM_IDLE_TIMEOUT_MS=120000
export NODE_OPTIONS="--dns-result-order=ipv4first"
$MARKER — end
ENVBLOCK
success "Environment variables written to $SHELL_CONFIG"
fi
else
warn "Skipped — env vars not applied."
fi
# ── phase 2: SO_KEEPALIVE shim ───────────────────────────────────────────────
step "Phase 2 of 4 — SO_KEEPALIVE LD_PRELOAD shim"
echo
echo -e " Compiles a small C library (${BOLD}~15KB${NC}) that intercepts every"
echo -e " TCP socket() call and forces ${BOLD}SO_KEEPALIVE=1${NC} before returning it."
echo
echo -e " Without this, the OS kernel never sends keepalive probe packets"
echo -e " on Claude's idle connections, even with tcp_keepalive_time set."
echo
echo -e " The library is installed to: ${BOLD}$LIB_FILE${NC}"
echo -e " ${PRELOAD_VAR} is added to your shell config so Claude picks it up."
echo
echo -e " ${DIM}Requires: $CC${NC}"
echo
if ! command -v "$CC" &>/dev/null; then
if [[ "$PLATFORM" == "macOS" ]] && command -v clang &>/dev/null; then
CC="clang"
else
warn "$CC not found. Install build tools and re-run this phase."
warn " macOS: xcode-select --install"
warn " Debian/Ubuntu: sudo apt install gcc"
warn " Arch: sudo pacman -S gcc"
warn "Skipping Phase 2."
CC=""
fi
fi
if [[ -n "${CC:-}" ]]; then
if ask "Build and install the SO_KEEPALIVE shim?"; then
mkdir -p "$LIB_DIR"
# Write the C source
cat > /tmp/claude_keepalive.c << 'CSRC'
#define _GNU_SOURCE
#include <stddef.h>
#include <sys/socket.h>
#include <dlfcn.h>
/*
* Intercepts socket() and forces SO_KEEPALIVE on every SOCK_STREAM fd.
* Installed via LD_PRELOAD (Linux) / DYLD_INSERT_LIBRARIES (macOS).
* See: https://github.com/anthropics/claude-code/issues/60133
*/
int socket(int domain, int type, int protocol) {
static int (*orig_socket)(int, int, int) = NULL;
if (!orig_socket)
orig_socket = dlsym(RTLD_NEXT, "socket");
int fd = orig_socket(domain, type, protocol);
if (fd >= 0 && (type & 0xf) == SOCK_STREAM) {
int opt = 1;
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(opt));
}
return fd;
}
CSRC
# Compile
if [[ "$PLATFORM" == "macOS" ]]; then
$CC -dynamiclib -O2 -o "$LIB_FILE" /tmp/claude_keepalive.c 2>&1
else
$CC -shared -fPIC -O2 -o "$LIB_FILE" /tmp/claude_keepalive.c -ldl 2>&1
fi
if [[ -f "$LIB_FILE" ]]; then
success "Library built: $LIB_FILE ($(du -sh "$LIB_FILE" | cut -f1))"
# Add PRELOAD to shell config (inside the managed block if it exists, else append)
if grep -q "$MARKER" "$SHELL_CONFIG" 2>/dev/null; then
# Insert before the end marker
if [[ "$PLATFORM" == "macOS" ]]; then
sed -i '' "/$MARKER — end/i\\
export ${PRELOAD_VAR}=\"\$HOME/.local/lib/libkeepalive.${LIB_EXT}\${${PRELOAD_VAR}:+:\$${PRELOAD_VAR}}\"
" "$SHELL_CONFIG"
else
sed -i "/$MARKER — end/i export ${PRELOAD_VAR}=\"\$HOME/.local/lib/libkeepalive.${LIB_EXT}\${${PRELOAD_VAR}:+:\$${PRELOAD_VAR}}\"" "$SHELL_CONFIG"
fi
else
cat >> "$SHELL_CONFIG" << PRELOADBLOCK
$MARKER — begin
export ${PRELOAD_VAR}="\$HOME/.local/lib/libkeepalive.${LIB_EXT}\${${PRELOAD_VAR}:+:\$${PRELOAD_VAR}}"
$MARKER — end
PRELOADBLOCK
fi
success "${PRELOAD_VAR} added to $SHELL_CONFIG"
else
error "Compilation failed. Check that $CC is properly installed."
fi
rm -f /tmp/claude_keepalive.c
else
warn "Skipped — SO_KEEPALIVE shim not installed."
fi
fi
# ── phase 3: sysctl tcp_keepalive_time ───────────────────────────────────────
step "Phase 3 of 4 — TCP keepalive probe interval (requires sudo)"
echo
if [[ "$PLATFORM" == "Linux" ]]; then
CURRENT_KA="$(cat /proc/sys/net/ipv4/tcp_keepalive_time 2>/dev/null || echo unknown)"
echo -e " Current ${BOLD}net.ipv4.tcp_keepalive_time${NC} = $CURRENT_KA seconds"
echo
echo -e " This controls how long a TCP connection can be idle before the"
echo -e " kernel starts sending keepalive probe packets."
echo -e " The default is ${BOLD}120s${NC}. This script sets it to ${BOLD}60s${NC}."
echo
echo -e " Only takes effect alongside Phase 2 (SO_KEEPALIVE shim)."
echo -e " ${DIM}Requires: sudo${NC}"
echo
if ask "Set tcp_keepalive_time=60 (requires sudo)?"; then
sudo sysctl -w net.ipv4.tcp_keepalive_time=60
success "tcp_keepalive_time set to 60 seconds (active now)"
else
warn "Skipped — tcp_keepalive_time not changed."
fi
elif [[ "$PLATFORM" == "macOS" ]]; then
CURRENT_MSS="$(sysctl -n net.inet.tcp.mssdflt 2>/dev/null || echo unknown)"
CURRENT_BH="$(sysctl -n net.inet.tcp.blackhole 2>/dev/null || echo unknown)"
echo -e " Current ${BOLD}net.inet.tcp.mssdflt${NC} = $CURRENT_MSS (should be 1440, not 512)"
echo -e " Current ${BOLD}net.inet.tcp.blackhole${NC} = $CURRENT_BH (should be 0)"
echo
echo -e " macOS has non-standard TCP defaults that worsen socket drops:"
echo -e " ${BOLD}mssdflt=512${NC} fragments packets (VPNs like Tailscale set this)"
echo -e " ${BOLD}blackhole=1${NC} silently drops packets instead of sending RST"
echo
echo -e " This step corrects both values. ${DIM}Requires: sudo${NC}"
echo
if ask "Fix macOS TCP defaults (requires sudo)?"; then
sudo sysctl -w net.inet.tcp.mssdflt=1440
sudo sysctl -w net.inet.tcp.blackhole=0
sudo sysctl -w net.inet.tcp.delayed_ack=0
success "macOS TCP sysctl values corrected"
else
warn "Skipped — macOS TCP defaults not changed."
fi
fi
# ── phase 4: persist sysctl across reboots ───────────────────────────────────
step "Phase 4 of 4 — Persist sysctl settings across reboots (requires sudo)"
echo
if [[ "$PLATFORM" == "Linux" ]]; then
SYSCTL_FILE="/etc/sysctl.d/99-claude-keepalive.conf"
echo -e " Writes ${BOLD}$SYSCTL_FILE${NC} so the keepalive time"
echo -e " survives reboots. Without this, Phase 3 resets on next boot."
echo -e " ${DIM}Requires: sudo${NC}"
echo
if ask "Persist tcp_keepalive_time=60 to $SYSCTL_FILE?"; then
echo "net.ipv4.tcp_keepalive_time=60" | sudo tee "$SYSCTL_FILE" > /dev/null
success "Persisted to $SYSCTL_FILE"
else
warn "Skipped — sysctl will reset on next reboot."
fi
elif [[ "$PLATFORM" == "macOS" ]]; then
PLIST="/Library/LaunchDaemons/com.claude.tcp-tuning.plist"
echo -e " Creates a LaunchDaemon plist ${BOLD}$PLIST${NC}"
echo -e " to re-apply the TCP fixes on every boot. ${DIM}Requires: sudo${NC}"
echo
if ask "Create LaunchDaemon to persist macOS TCP fixes?"; then
sudo tee "$PLIST" > /dev/null << 'PLIST'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key> <string>com.claude.tcp-tuning</string>
<key>ProgramArguments</key>
<array>
<string>/usr/sbin/sysctl</string>
<string>net.inet.tcp.mssdflt=1440</string>
<string>net.inet.tcp.blackhole=0</string>
<string>net.inet.tcp.delayed_ack=0</string>
</array>
<key>RunAtLoad</key> <true/>
</dict>
</plist>
PLIST
sudo launchctl load "$PLIST" 2>/dev/null || true
success "LaunchDaemon installed: $PLIST"
else
warn "Skipped — sysctl will reset on next reboot."
fi
fi
# ── done ─────────────────────────────────────────────────────────────────────
echo
echo -e "${BOLD}${GREEN}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${BOLD}${GREEN}║ All phases complete ║${NC}"
echo -e "${BOLD}${GREEN}╚══════════════════════════════════════════════════════════════╝${NC}"
echo
echo -e " ${BOLD}To activate in the current terminal:${NC}"
echo -e " ${DIM}source $SHELL_CONFIG${NC}"
echo
echo -e " ${BOLD}To verify the fix is working:${NC}"
echo -e " ${DIM}ss -tnop state established '( dport = :443 )' | grep claude${NC}"
echo -e " ${DIM}→ You should see timer:(keepalive,...) on all claude connections${NC}"
echo
echo -e " ${BOLD}To revert all changes:${NC}"
echo -e " ${DIM}bash claude-keepalive-uninstall.sh${NC}"
echo
echo -e " ${DIM}Issue: https://github.com/anthropics/claude-code/issues/60133${NC}"
echo
#!/usr/bin/env bash
# =============================================================================
# claude-keepalive-uninstall.sh
# Reverts all changes made by claude-keepalive-fix.sh
#
# Removes:
# - Managed env var / LD_PRELOAD block from your shell config
# - ~/.local/lib/libkeepalive.{so,dylib}
# - /etc/sysctl.d/99-claude-keepalive.conf (Linux)
# - /Library/LaunchDaemons/com.claude.tcp-tuning.plist (macOS)
#
# The live sysctl value (tcp_keepalive_time / net.inet.tcp.*) is reset
# to OS defaults; it will also revert automatically on next reboot once
# the persist file is removed.
# =============================================================================
set -uo pipefail
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
BLUE='\033[0;34m'; BOLD='\033[1m'; DIM='\033[2m'; NC='\033[0m'
info() { echo -e "${BLUE}[INFO]${NC} $*"; }
success() { echo -e "${GREEN}[OK]${NC} $*"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
error() { echo -e "${RED}[ERR]${NC} $*"; }
step() { echo -e "\n${BOLD}${BLUE}▶ $*${NC}"; }
# ── detect OS ────────────────────────────────────────────────────────────────
OS="$(uname -s)"
if [[ "$OS" == "Darwin" ]]; then
PLATFORM="macOS"
LIB_EXT="dylib"
elif [[ "$OS" == "Linux" ]]; then
PLATFORM="Linux"
LIB_EXT="so"
else
error "Unsupported OS: $OS"
exit 1
fi
# ── detect shell config ───────────────────────────────────────────────────────
detect_shell_config() {
local shell_name
shell_name="$(basename "${SHELL:-bash}")"
if [[ "$shell_name" == "zsh" ]]; then
echo "${ZDOTDIR:-$HOME}/.zshrc"
elif [[ "$shell_name" == "bash" ]]; then
if [[ "$PLATFORM" == "macOS" ]]; then
echo "$HOME/.bash_profile"
else
echo "$HOME/.bashrc"
fi
else
echo "$HOME/.profile"
fi
}
SHELL_CONFIG="$(detect_shell_config)"
LIB_FILE="$HOME/.local/lib/libkeepalive.$LIB_EXT"
MARKER="# claude-keepalive-fix — managed block"
# ── header ───────────────────────────────────────────────────────────────────
echo
echo -e "${BOLD}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${BOLD}║ Claude Code — Socket Keepalive Uninstall v1.0 ║${NC}"
echo -e "${BOLD}╚══════════════════════════════════════════════════════════════╝${NC}"
echo
echo -e " Platform : ${BOLD}$PLATFORM${NC}"
echo -e " Shell cfg: ${BOLD}$SHELL_CONFIG${NC}"
echo -e " Library : ${BOLD}$LIB_FILE${NC}"
echo
echo -e " This script reverts all changes made by ${BOLD}claude-keepalive-fix.sh${NC}."
echo -e " Each step will ask for confirmation before making any change."
echo
echo -e "${YELLOW} ⚠ After uninstalling, open a new terminal (or source your shell config)${NC}"
echo -e "${YELLOW} to ensure the environment variables are cleared from your session.${NC}"
echo
# ── step 1: remove managed block from shell config ───────────────────────────
step "Step 1 of 4 — Remove managed block from $SHELL_CONFIG"
echo
if grep -q "$MARKER" "$SHELL_CONFIG" 2>/dev/null; then
echo -e " Found managed block between markers:"
echo -e " ${DIM}$MARKER — begin${NC}"
echo -e " ${DIM}$MARKER — end${NC}"
echo
echo -e " Lines to be removed:"
awk "/^${MARKER} — begin$/,/^${MARKER} — end$/" "$SHELL_CONFIG" | \
while IFS= read -r line; do echo -e " ${DIM}$line${NC}"; done
echo
echo -e " Remove this block from $SHELL_CONFIG?"
echo -e " ${DIM}[Y/n]${NC} "
read -r -n1 reply 2>/dev/null || read -r reply; echo
if [[ "$reply" =~ ^[Yy]$ ]] || [[ -z "$reply" ]]; then
if [[ "$PLATFORM" == "macOS" ]]; then
sed -i '' "/^${MARKER} — begin$/,/^${MARKER} — end$/d" "$SHELL_CONFIG"
else
sed -i "/^${MARKER} — begin$/,/^${MARKER} — end$/d" "$SHELL_CONFIG"
fi
# Remove any blank lines left by the deletion (up to 2 consecutive)
if [[ "$PLATFORM" == "macOS" ]]; then
sed -i '' '/^$/N;/^\n$/d' "$SHELL_CONFIG" 2>/dev/null || true
else
sed -i '/^$/N;/^\n$/d' "$SHELL_CONFIG" 2>/dev/null || true
fi
success "Managed block removed from $SHELL_CONFIG"
else
warn "Skipped — shell config not modified."
fi
else
info "No managed block found in $SHELL_CONFIG — nothing to remove."
fi
# ── step 2: remove the shared library ────────────────────────────────────────
step "Step 2 of 4 — Remove SO_KEEPALIVE shim library"
echo
if [[ -f "$LIB_FILE" ]]; then
echo -e " File: ${BOLD}$LIB_FILE${NC} ($(du -sh "$LIB_FILE" | cut -f1))"
echo
echo -e " Delete this file?"
echo -e " ${DIM}[Y/n]${NC} "
read -r -n1 reply 2>/dev/null || read -r reply; echo
if [[ "$reply" =~ ^[Yy]$ ]] || [[ -z "$reply" ]]; then
rm -f "$LIB_FILE"
success "Removed $LIB_FILE"
else
warn "Skipped — library not removed."
fi
else
info "$LIB_FILE not found — nothing to remove."
fi
# ── step 3: remove sysctl persist file & reset live value ────────────────────
step "Step 3 of 4 — Remove sysctl persist file (requires sudo)"
echo
if [[ "$PLATFORM" == "Linux" ]]; then
SYSCTL_FILE="/etc/sysctl.d/99-claude-keepalive.conf"
if [[ -f "$SYSCTL_FILE" ]]; then
echo -e " File: ${BOLD}$SYSCTL_FILE${NC}"
echo -e " Content: $(cat "$SYSCTL_FILE")"
echo
echo -e " Also reset ${BOLD}net.ipv4.tcp_keepalive_time${NC} to Linux default (${BOLD}7200${NC} seconds) live."
echo -e " ${DIM}Requires: sudo${NC}"
echo
echo -e " Remove file and reset sysctl?"
echo -e " ${DIM}[Y/n]${NC} "
read -r -n1 reply 2>/dev/null || read -r reply; echo
if [[ "$reply" =~ ^[Yy]$ ]] || [[ -z "$reply" ]]; then
sudo rm -f "$SYSCTL_FILE"
sudo sysctl -w net.ipv4.tcp_keepalive_time=7200
success "Removed $SYSCTL_FILE and reset tcp_keepalive_time=7200"
else
warn "Skipped — sysctl persist file not removed."
fi
else
info "$SYSCTL_FILE not found — nothing to remove."
fi
elif [[ "$PLATFORM" == "macOS" ]]; then
PLIST="/Library/LaunchDaemons/com.claude.tcp-tuning.plist"
if [[ -f "$PLIST" ]]; then
echo -e " File: ${BOLD}$PLIST${NC}"
echo
echo -e " Also reset macOS TCP sysctls to system defaults:"
echo -e " ${DIM}net.inet.tcp.mssdflt=512 net.inet.tcp.blackhole=0 net.inet.tcp.delayed_ack=3${NC}"
echo -e " ${DIM}Requires: sudo${NC}"
echo
echo -e " Unload and remove LaunchDaemon, reset sysctl?"
echo -e " ${DIM}[Y/n]${NC} "
read -r -n1 reply 2>/dev/null || read -r reply; echo
if [[ "$reply" =~ ^[Yy]$ ]] || [[ -z "$reply" ]]; then
sudo launchctl unload "$PLIST" 2>/dev/null || true
sudo rm -f "$PLIST"
sudo sysctl -w net.inet.tcp.mssdflt=512
sudo sysctl -w net.inet.tcp.blackhole=0
sudo sysctl -w net.inet.tcp.delayed_ack=3
success "LaunchDaemon removed and macOS TCP sysctls reset"
else
warn "Skipped — LaunchDaemon not removed."
fi
else
info "$PLIST not found — nothing to remove."
fi
fi
# ── step 4: verify ────────────────────────────────────────────────────────────
step "Step 4 of 4 — Verification"
echo
echo -e " Checking for any remaining traces..."
echo
FOUND=0
if grep -q "CLAUDE_CODE_REMOTE_SEND_KEEPALIVES\|libkeepalive\|BUN_CONFIG_HTTP_IDLE_TIMEOUT\|CLAUDE_STREAM_IDLE_TIMEOUT" "$SHELL_CONFIG" 2>/dev/null; then
warn "Residual claude-keepalive entries still found in $SHELL_CONFIG"
warn "You may need to manually review and clean up $SHELL_CONFIG"
FOUND=1
fi
if [[ -f "$LIB_FILE" ]]; then
warn "Library still exists: $LIB_FILE"
FOUND=1
fi
if [[ "$PLATFORM" == "Linux" ]] && [[ -f "/etc/sysctl.d/99-claude-keepalive.conf" ]]; then
warn "Sysctl persist file still exists: /etc/sysctl.d/99-claude-keepalive.conf"
FOUND=1
fi
if [[ "$PLATFORM" == "macOS" ]] && [[ -f "/Library/LaunchDaemons/com.claude.tcp-tuning.plist" ]]; then
warn "LaunchDaemon still exists: /Library/LaunchDaemons/com.claude.tcp-tuning.plist"
FOUND=1
fi
if [[ "$FOUND" -eq 0 ]]; then
success "No traces found — uninstall appears complete."
fi
# ── done ─────────────────────────────────────────────────────────────────────
echo
echo -e "${BOLD}${GREEN}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${BOLD}${GREEN}║ Uninstall complete ║${NC}"
echo -e "${BOLD}${GREEN}╚══════════════════════════════════════════════════════════════╝${NC}"
echo
echo -e " ${BOLD}To activate changes in the current terminal:${NC}"
echo -e " ${DIM}source $SHELL_CONFIG${NC}"
echo
echo -e " ${BOLD}To verify no keepalive timers remain on claude sockets:${NC}"
echo -e " ${DIM}ss -tnop state established '( dport = :443 )' | grep claude${NC}"
echo -e " ${DIM}→ Connections should show no timer:(keepalive,...) entry${NC}"
echo
echo -e " ${DIM}Issue: https://github.com/anthropics/claude-code/issues/60133${NC}"
echo
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment