diff options
| -rw-r--r-- | .claude/settings.json | 4 | ||||
| -rwxr-xr-x | .claude/statusline-command.sh | 27 | ||||
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | scripts/tests/statusline-command.bats | 51 |
4 files changed, 83 insertions, 1 deletions
diff --git a/.claude/settings.json b/.claude/settings.json index 2e37bc6..3b8b237 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -1,4 +1,8 @@ { + "statusLine": { + "type": "command", + "command": "~/.claude/statusline-command.sh" + }, "skillListingBudgetFraction": 0.05, "attribution": { "commit": "", diff --git a/.claude/statusline-command.sh b/.claude/statusline-command.sh new file mode 100755 index 0000000..3e5e6fb --- /dev/null +++ b/.claude/statusline-command.sh @@ -0,0 +1,27 @@ +#!/bin/sh +# Claude Code status line — mirrors the zsh prompt from ~/.zshrc +# PROMPT: [%D %*] $WHO $HOST:${PWD/#$HOME/~} %(?..[%?] )$NEWLINE%# +# RPROMPT: ${vcs_info_msg_0_} (format: "on %b") +# +# Wired via the statusLine entry in .claude/settings.json; make install +# symlinks this file to ~/.claude/statusline-command.sh on every machine. + +input=$(cat) + +cwd=$(echo "$input" | jq -r '.cwd') +# Replace $HOME prefix with ~. The replacement tilde must be escaped: +# unquoted, bash tilde-expands it straight back to $HOME. +home="$HOME" +display_dir="${cwd/#$home/\~}" + +# Git branch from cwd (mirrors vcs_info RPROMPT "on %b") +branch=$(git -C "$cwd" symbolic-ref --short HEAD 2>/dev/null) +git_part="" +[ -n "$branch" ] && git_part=" on $branch" + +date_part=$(date "+%y-%m-%d %H:%M:%S") +user_part=$(whoami) +# uname -n, not hostname: Arch doesn't ship hostname by default (inetutils). +host_part=$(uname -n) + +printf "%s %s %s:%s%s" "[$date_part]" "$user_part" "$host_part" "$display_dir" "$git_part" @@ -14,7 +14,7 @@ HOOKS := $(wildcard hooks/*.sh hooks/*.py) # them manually if they want the behavior. Add new opt-ins to this list. OPTIN_HOOKS := hooks/destructive-bash-confirm.py DEFAULT_HOOKS := $(filter-out $(OPTIN_HOOKS),$(HOOKS)) -CLAUDE_CONFIG := $(wildcard .claude/*.json) $(wildcard .claude/.*.json) +CLAUDE_CONFIG := $(wildcard .claude/*.json) $(wildcard .claude/.*.json) $(wildcard .claude/*.sh) LANGUAGES := $(notdir $(wildcard languages/*)) TEAMS := $(notdir $(wildcard teams/*)) PDFTOOLS_VENV ?= $(HOME)/.local/venvs/pdftools diff --git a/scripts/tests/statusline-command.bats b/scripts/tests/statusline-command.bats new file mode 100644 index 0000000..6a8725a --- /dev/null +++ b/scripts/tests/statusline-command.bats @@ -0,0 +1,51 @@ +#!/usr/bin/env bats +# .claude/statusline-command.sh — Claude Code status line mirroring the zsh +# prompt: [yy-mm-dd HH:MM:SS] user host:~/path on <branch> + +setup() { + REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../.." && pwd)" + SCRIPT="$REPO_ROOT/.claude/statusline-command.sh" + TMPDIR_T="$(mktemp -d)" +} + +teardown() { + rm -rf "$TMPDIR_T" +} + +run_statusline() { + printf '{"cwd":"%s"}' "$1" | sh "$SCRIPT" +} + +@test "statusline renders date, user, host, and tilde-abbreviated cwd" { + dir="$HOME/.cache" + run run_statusline "$dir" + [ "$status" -eq 0 ] + host="$(uname -n)" + user="$(whoami)" + [[ "$output" =~ ^\[[0-9]{2}-[0-9]{2}-[0-9]{2}\ [0-9]{2}:[0-9]{2}:[0-9]{2}\]\ $user\ $host:~/\.cache$ ]] +} + +@test "statusline appends the git branch inside a repo" { + git -C "$TMPDIR_T" init -q -b trunk + run run_statusline "$TMPDIR_T" + [ "$status" -eq 0 ] + [[ "$output" == *" on trunk" ]] +} + +@test "statusline omits the branch part outside a git repo" { + mkdir -p "$TMPDIR_T/plain" + run run_statusline "$TMPDIR_T/plain" + [ "$status" -eq 0 ] + [[ "$output" != *" on "* ]] +} + +@test "statusline leaves a cwd outside HOME unabbreviated" { + run run_statusline "/tmp" + [ "$status" -eq 0 ] + [[ "$output" == *":/tmp" ]] +} + +@test "statusline emits no stderr noise" { + err="$(printf '{"cwd":"%s"}' "$HOME" | sh "$SCRIPT" 2>&1 >/dev/null)" + [ -z "$err" ] +} |
