106 lines
4.6 KiB
Bash
Executable File
106 lines
4.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# SessionStart hook for the memory plugin.
|
|
# Invoked by Claude Code at the start of every session with JSON on stdin.
|
|
# Must return sub-second; heavy work is detached in the background.
|
|
# Context injection is handled by session-context.sh (UserPromptSubmit hook).
|
|
|
|
# Never let any individual failure exit the whole script.
|
|
# Do NOT set -e — grep-no-match, graphify errors, etc. are all expected.
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 0. Read stdin (ignore errors — fields may be absent on older Claude Code)
|
|
# ---------------------------------------------------------------------------
|
|
STDIN_JSON="$(cat 2>/dev/null || true)"
|
|
HOOK_SOURCE="$(printf '%s' "$STDIN_JSON" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('source','unknown'))" 2>/dev/null || true)"
|
|
echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] session-start fired: source=${HOOK_SOURCE:-unknown} cwd=$(pwd)" >> /tmp/memory-hook.log 2>/dev/null || true
|
|
CWD="$(printf '%s' "$STDIN_JSON" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('cwd',''))" 2>/dev/null || true)"
|
|
CWD="${CWD:-$PWD}"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 1. Parse config.yaml — emit shell variable assignments, eval them in.
|
|
# python3 + PyYAML are guaranteed present via graphify.
|
|
# ---------------------------------------------------------------------------
|
|
eval "$(python3 - <<'PY'
|
|
import yaml, os, shlex, sys
|
|
|
|
CONFIG_PATH = os.path.expanduser("~/.claude/plugins/memory/config.yaml")
|
|
try:
|
|
with open(CONFIG_PATH) as f:
|
|
cfg = yaml.safe_load(f) or {}
|
|
except Exception:
|
|
cfg = {}
|
|
|
|
out = {
|
|
"VAULT_PATH": os.path.expanduser(cfg.get("vault_path", "~/Documents/SecondBrain")),
|
|
"GRAPHIFY_OUTPUT_DIR": os.path.expanduser(cfg.get("graphify_output_dir", "~/Documents/SecondBrain/.graphify")),
|
|
"MODEL": cfg.get("ollama_model", "qwen25-coder-7b-16k"),
|
|
"STALE_DAYS": str(cfg.get("stale_threshold_days", 7)),
|
|
}
|
|
for k, v in out.items():
|
|
print(f"{k}={shlex.quote(str(v))}")
|
|
|
|
# Export env block so the background rebuild process inherits them.
|
|
for k, v in (cfg.get("env") or {}).items():
|
|
print(f"export {k}={shlex.quote(str(v))}")
|
|
PY
|
|
2>/dev/null || true)"
|
|
|
|
# Apply fallbacks in case the python3 block produced nothing.
|
|
VAULT_PATH="${VAULT_PATH:-$HOME/Documents/SecondBrain}"
|
|
GRAPHIFY_OUTPUT_DIR="${GRAPHIFY_OUTPUT_DIR:-$HOME/Documents/SecondBrain/.graphify}"
|
|
MODEL="${MODEL:-qwen25-coder-7b-16k}"
|
|
STALE_DAYS="${STALE_DAYS:-7}"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 2. Cache dir + file paths
|
|
# ---------------------------------------------------------------------------
|
|
CACHE_DIR="$HOME/.cache/graphify"
|
|
STAMP="$CACHE_DIR/vault-rebuild.stamp"
|
|
LOCK="$CACHE_DIR/vault-rebuild.lock"
|
|
LOGFILE="$CACHE_DIR/vault-rebuild.log"
|
|
|
|
mkdir -p "$CACHE_DIR" 2>/dev/null || true
|
|
|
|
# Export vars needed by the detached bash -c subprocess.
|
|
export VAULT_PATH MODEL STAMP LOCK LOGFILE
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 3. Staleness check + detached background rebuild
|
|
# ---------------------------------------------------------------------------
|
|
_needs_rebuild() {
|
|
[ ! -f "$STAMP" ] && return 0
|
|
# Use python3 for portable mtime arithmetic (avoids `date -d` vs BSD split).
|
|
python3 - <<PY 2>/dev/null
|
|
import os, time
|
|
stamp = "$STAMP"
|
|
stale_days = int("$STALE_DAYS")
|
|
try:
|
|
age_days = (time.time() - os.path.getmtime(stamp)) / 86400
|
|
exit(0 if age_days > stale_days else 1)
|
|
except Exception:
|
|
exit(0)
|
|
PY
|
|
}
|
|
|
|
if _needs_rebuild; then
|
|
if [ -f "$LOCK" ]; then
|
|
echo "[memory/session-start] rebuild already running (lock present), skipping" >> "$LOGFILE" 2>/dev/null || true
|
|
echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] session-start: rebuild skipped (lock present)" >> /tmp/memory-hook.log 2>/dev/null || true
|
|
else
|
|
# Create lock, then spawn fully detached (no inherited stdin/stdout/stderr).
|
|
touch "$LOCK" 2>/dev/null || true
|
|
# shellcheck disable=SC2016
|
|
nohup bash -c \
|
|
'graphify extract "$VAULT_PATH" --backend ollama --model "$MODEL" --force \
|
|
>> "$LOGFILE" 2>&1 \
|
|
&& date > "$STAMP" && rm -f "$LOCK" \
|
|
|| (rm -f "$LOCK"; echo "rebuild failed" >> "$LOGFILE")' \
|
|
</dev/null >/dev/null 2>&1 &
|
|
echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] session-start: rebuild triggered" >> /tmp/memory-hook.log 2>/dev/null || true
|
|
fi
|
|
else
|
|
echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] session-start: rebuild not needed" >> /tmp/memory-hook.log 2>/dev/null || true
|
|
fi
|
|
|
|
exit 0
|