aboutsummaryrefslogtreecommitdiffstats
path: root/hooks/session-start.hook.sh
blob: b1fbf1d0667e5ea770d16f9fb53d386a08bcb3d5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#!/usr/bin/env bash
set -Eeuo pipefail

# SessionStart-hook wrapper around the bin/ implementation memory-status.sh --
# surfaces the project's Claude memory status to the user. Wired in the user-level
# settings.json (hooks.SessionStart).
# - reads the hook payload as JSON on stdin (.cwd) and runs the util with it.
# - the util prints the memory status block (the CLAUDE.md memory rows); this
#   wrapper wraps it in a single systemMessage.
# - when cwd is $HOME, appends a warning: $HOME is not treated as a project, so
#   home skills (~/.claude/skills) only load with --add-dir $HOME. The hook can't
#   tell whether that flag was passed (no payload exposes it), so it always warns.
# - ANSI-colours the message: memory rows cyan, a "(missing)" row red with an ❌,
#   the $HOME warning yellow with ⚠️. jq encodes the ESC byte as an escape in the
#   JSON; the harness turns it back into a real ESC when it prints the message.
#   Colours wrap each line around its already-computed padding, so the util's
#   column alignment stays intact (ANSI bytes never count toward printf's width).
# - leads the message with a newline so the harness's "SessionStart:... says:"
#   header sits on its own line and the table starts at column 0.
# - never blocks the session: a util failure yields an empty message.

self=$(realpath -- "${BASH_SOURCE[0]}")
util="$(dirname -- "$(dirname -- "$self")")/bin/memory-status.sh"

input=$(cat)
cwd=$(jq --raw-output '.cwd // empty' <<<"$input" 2>/dev/null) || cwd=""
[ -n "$cwd" ] || cwd=$PWD

esc=$'\033'
cyan="${esc}[36m" red="${esc}[31m" yellow="${esc}[33m" reset="${esc}[0m"

out=$(bash "$util" "$cwd") || out=""

# Colour the memory block line by line: a "(missing)" row red with an ❌ error
# sign, every other row cyan.
if [ -n "$out" ]; then
	block=""
	while IFS= read -r line; do
		[ -n "$block" ] && block+=$'\n'
		case $line in
		*'(missing)'*) block+="${red}${line}${reset}" ;;
		*) block+="${cyan}${line}${reset}" ;;
		esac
	done <<<"$out"
	out=$block
fi

if [ "$cwd" = "$HOME" ]; then
	warn="⚠️  Started from \$HOME: home skills (~/.claude/skills) don't auto-load here."
	warn+=$'\n'"⚠️  Did you think to --add-dir \$HOME? Restart with it to surface them."
	[ -n "$out" ] && out+=$'\n\n'
	out+="${yellow}${warn}${reset}"
fi

[ -n "$out" ] && out=$'\n'$out

jq --null-input --arg msg "$out" '{systemMessage: $msg}'