Last active
February 24, 2026 11:43
-
-
Save andrewleech/43688422c58510e01818c5fc04e26b28 to your computer and use it in GitHub Desktop.
Fix Claude Code statusline layout (issue #27305) — single-file installer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Installer for claude-statusfix — fixes Claude Code statusline layout. | |
| # https://github.com/anthropics/claude-code/issues/27305 | |
| # | |
| # Usage: curl -fsSL https://gist.githubusercontent.com/andrewleech/43688422c58510e01818c5fc04e26b28/raw/install.sh | bash | |
| # | |
| # Installs claude-statusfix to ~/.local/bin/ and prints alias instructions. | |
| set -euo pipefail | |
| INSTALL_DIR="$HOME/.local/bin" | |
| INSTALL_PATH="$INSTALL_DIR/claude-statusfix" | |
| # --- Write the script -------------------------------------------------------- | |
| mkdir -p "$INSTALL_DIR" | |
| cat > "$INSTALL_PATH" << 'SCRIPT' | |
| #!/bin/bash | |
| # Claude CLI wrapper that patches the footer flex layout so the statusline | |
| # renders on its own row, while hints and notifications share a second row. | |
| # See: https://github.com/anthropics/claude-code/issues/27305 | |
| # | |
| # The patch is applied idempotently to cli.js on each launch, so Claude | |
| # Code updates are automatically re-patched on next run. | |
| set -euo pipefail | |
| # --- Patch definitions ------------------------------------------------------- | |
| PATCH1_ORIG='e=t$.createElement(I,{flexDirection:"column",flexShrink:0},D1,a)' | |
| PATCH1_NEW='e=t$.createElement(I,{flexShrink:0},D1)' | |
| PATCH2_ORIG='H1=t$.createElement(I,{flexDirection:"row",justifyContent:"space-between",paddingX:2,gap:1},e,j1)' | |
| PATCH2_NEW='H1=t$.createElement(I,{flexDirection:"column",paddingX:2},e,t$.createElement(I,{flexDirection:"row",justifyContent:"space-between",gap:1},t$.createElement(I,{flexShrink:1,height:1,overflowY:"hidden"},a),j1))' | |
| PATCH3_ORIG='flexDirection:"column",alignItems:"flex-end",flexShrink:1,overflowX:"hidden"' | |
| PATCH3_NEW='flexDirection:"column",alignItems:"flex-end",flexShrink:0,overflowX:"hidden"' | |
| # --- Locate cli.js ----------------------------------------------------------- | |
| find_claude_cli() { | |
| local claude_cmd | |
| claude_cmd=$(command -v claude 2>/dev/null) || true | |
| if [ -n "$claude_cmd" ] && [ -f "$claude_cmd" ]; then | |
| local resolved self_path | |
| resolved=$(readlink -f "$claude_cmd" 2>/dev/null) || resolved="" | |
| self_path=$(readlink -f "$0" 2>/dev/null) || self_path="" | |
| if [ -n "$resolved" ] && [ -f "$resolved" ] && [ "$resolved" != "$self_path" ]; then | |
| echo "$resolved"; return 0 | |
| fi | |
| if [ "$claude_cmd" != "$self_path" ]; then | |
| echo "$claude_cmd"; return 0 | |
| fi | |
| fi | |
| if command -v npm >/dev/null 2>&1; then | |
| local npm_cli | |
| npm_cli="$(npm root -g 2>/dev/null)/@anthropic-ai/claude-code/cli.js" | |
| if [ -f "$npm_cli" ]; then echo "$npm_cli"; return 0; fi | |
| fi | |
| if [ -d "$HOME/.nvm" ]; then | |
| local nvm_cli | |
| nvm_cli=$(find "$HOME/.nvm/versions/node" \ | |
| -path "*/node_modules/@anthropic-ai/claude-code/cli.js" \ | |
| 2>/dev/null | head -1) | |
| if [ -f "$nvm_cli" ]; then echo "$nvm_cli"; return 0; fi | |
| fi | |
| local p | |
| for p in \ | |
| "/usr/local/lib/node_modules/@anthropic-ai/claude-code/cli.js" \ | |
| "/usr/lib/node_modules/@anthropic-ai/claude-code/cli.js"; do | |
| if [ -f "$p" ]; then echo "$p"; return 0; fi | |
| done | |
| return 1 | |
| } | |
| if [ -n "${CLAUDE_CLI:-}" ] && [ -f "$CLAUDE_CLI" ]; then | |
| : # user override | |
| else | |
| CLAUDE_CLI=$(find_claude_cli) || true | |
| if [ -z "$CLAUDE_CLI" ] || [ ! -f "$CLAUDE_CLI" ]; then | |
| echo "Error: Could not locate Claude CLI (cli.js)" >&2 | |
| echo "Set CLAUDE_CLI=/path/to/cli.js to override." >&2 | |
| exit 1 | |
| fi | |
| fi | |
| # --- Apply patches idempotently ---------------------------------------------- | |
| apply_patches() { | |
| local file="$1" | |
| local backup="${file}.bak" | |
| if grep -qF "$PATCH1_NEW" "$file" 2>/dev/null && | |
| grep -qF "$PATCH2_NEW" "$file" 2>/dev/null && | |
| grep -qF "$PATCH3_NEW" "$file" 2>/dev/null; then | |
| return 0 | |
| fi | |
| if [ -f "$backup" ]; then | |
| if grep -qF "$PATCH2_ORIG" "$backup" 2>/dev/null; then | |
| cp "$backup" "$file" | |
| fi | |
| fi | |
| local missing=0 | |
| if ! grep -qF "$PATCH1_ORIG" "$file" 2>/dev/null; then | |
| if ! grep -qF "$PATCH1_NEW" "$file" 2>/dev/null; then | |
| echo "[statusfix] Warning: pattern 1 (e element) not found in cli.js." >&2 | |
| missing=1 | |
| fi | |
| fi | |
| if ! grep -qF "$PATCH2_ORIG" "$file" 2>/dev/null; then | |
| if ! grep -qF "$PATCH2_NEW" "$file" 2>/dev/null; then | |
| echo "[statusfix] Warning: pattern 2 (H1 footer) not found in cli.js." >&2 | |
| missing=1 | |
| fi | |
| fi | |
| if ! grep -qF "$PATCH3_ORIG" "$file" 2>/dev/null; then | |
| if ! grep -qF "$PATCH3_NEW" "$file" 2>/dev/null; then | |
| echo "[statusfix] Warning: pattern 3 (G0q notif) not found in cli.js." >&2 | |
| missing=1 | |
| fi | |
| fi | |
| if [ "$missing" -eq 1 ]; then | |
| echo "[statusfix] Claude Code version may have changed; patch skipped." >&2 | |
| return 0 | |
| fi | |
| if [ ! -f "$backup" ]; then | |
| cp "$file" "$backup" | |
| fi | |
| python3 -c " | |
| import sys | |
| with open(sys.argv[1], 'r') as f: | |
| c = f.read() | |
| pairs = [(sys.argv[i], sys.argv[i+1]) for i in range(2, len(sys.argv), 2)] | |
| applied = 0 | |
| for old, new in pairs: | |
| if old in c: | |
| c = c.replace(old, new, 1) | |
| applied += 1 | |
| with open(sys.argv[1], 'w') as f: | |
| f.write(c) | |
| print(f'[statusfix] Applied {applied}/3 replacements to {sys.argv[1]}', file=sys.stderr) | |
| " "$file" \ | |
| "$PATCH1_ORIG" "$PATCH1_NEW" \ | |
| "$PATCH2_ORIG" "$PATCH2_NEW" \ | |
| "$PATCH3_ORIG" "$PATCH3_NEW" | |
| } | |
| apply_patches "$CLAUDE_CLI" | |
| # --- Launch ------------------------------------------------------------------ | |
| exec node "$CLAUDE_CLI" "$@" | |
| SCRIPT | |
| chmod +x "$INSTALL_PATH" | |
| # --- Verify ------------------------------------------------------------------ | |
| echo "Installed claude-statusfix to $INSTALL_PATH" | |
| echo "" | |
| # Check if ~/.local/bin is on PATH | |
| if ! echo "$PATH" | tr ':' '\n' | grep -qx "$INSTALL_DIR"; then | |
| echo "Note: $INSTALL_DIR is not on your PATH." | |
| echo "You may need to add it first (most distros source ~/.profile on login)." | |
| echo "" | |
| fi | |
| echo "To launch Claude with the statusline fix, run:" | |
| echo " claude-statusfix" | |
| echo "" | |
| echo "To make it the default, add an alias to your shell rc:" | |
| echo "" | |
| echo " echo 'alias claude=\"claude-statusfix\"' >> ~/.bashrc" | |
| echo "" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment