#!/usr/bin/env bash set -uo pipefail # memory-status.sh -- render the project's Claude memory status as a text block. # Implementation behind hooks/session-start.hook.sh (the SessionStart wrapper that # pipes this output into a systemMessage); also runnable by hand. # - takes the project cwd as $1 (the only input it cannot derive itself). # - Stats: one row per memory file (User memory, Project memory) -- its size in # whole KB and full path; a missing file shows "(missing)" and no path. # - output: the block on stdout, no leading newline (the wrapper adds it); never # aborts (no `set -e`) so a partial failure still prints rows. cwd=${1:?usage: memory-status.sh } CONFIG_DIR="${CLAUDE_CONFIG_DIR:-$HOME/.claude}" user_md="$CONFIG_DIR/CLAUDE.md" proj_md="$cwd/.claude/CLAUDE.md" # File size in bytes (0 when missing), and rounded to whole KB. bytes() { [ -f "$1" ] && wc --bytes <"$1" | tr --delete ' ' || echo 0; } kb() { echo $((($(bytes "$1") + 512) / 1024)); } # Display metric for a memory file: " KB", or "(missing)". metric() { [ -f "$1" ] || { printf '(missing)' return } printf '%s KB' "$(kb "$1")" } # Stats: one row per memory file -- label, size metric, and path. Columns # aligned; a missing file shows "(missing)" with no path. m_user=$(metric "$user_md") m_proj=$(metric "$proj_md") labels=("User memory" "Project memory") mets=("$m_user" "$m_proj") paths=("$user_md" "$proj_md") lpad=0 mpad=0 for i in 0 1; do [ ${#labels[i]} -gt "$lpad" ] && lpad=${#labels[i]} [ ${#mets[i]} -gt "$mpad" ] && mpad=${#mets[i]} done out="" for i in 0 1; do [ -n "$out" ] && out+=$'\n' if [ "${mets[i]}" = "(missing)" ]; then out+=$(printf '%-*s %s' "$lpad" "${labels[i]}" "${mets[i]}") else out+=$(printf '%-*s %-*s %s' \ "$lpad" "${labels[i]}" "$mpad" "${mets[i]}" "${paths[i]}") fi done printf '%s\n' "$out"