#!/usr/bin/env python3 """SessionStart hook — staleness check + detached graph rebuild. Fail-open. Must return sub-second; heavy work is detached in the background. Context injection is handled by session_context.py (UserPromptSubmit hook). """ import os import sys import time import subprocess from datetime import datetime, timezone sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) import config as config_mod import hook_io HOOK_LOG = "/tmp/memory-hook.log" def _utc(): return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") def _log(line): try: with open(HOOK_LOG, "a") as f: f.write(line + "\n") except Exception: pass def _needs_rebuild(stamp, stale_days): if not os.path.exists(stamp): return True try: age_days = (time.time() - os.path.getmtime(stamp)) / 86400 return age_days > stale_days except Exception: return True def main(): inp = hook_io.read_input() source = inp.source or "unknown" _log(f"[{_utc()}] session-start fired: source={source} cwd={os.getcwd()}") cfg = config_mod.load_config() if os.environ.get("OS_VAULT_SKIP_REBUILD"): _log(f"[{_utc()}] session-start: rebuild skipped (OS_VAULT_SKIP_REBUILD set)") return cache_dir = os.path.expanduser("~/.cache/graphify") stamp = os.path.join(cache_dir, "vault-rebuild.stamp") lock = os.path.join(cache_dir, "vault-rebuild.lock") logfile = os.path.join(cache_dir, "vault-rebuild.log") try: os.makedirs(cache_dir, exist_ok=True) except Exception: pass if _needs_rebuild(stamp, cfg.stale_days): if os.path.exists(lock): try: with open(logfile, "a") as f: f.write("[memory/session-start] rebuild already running (lock present), skipping\n") except Exception: pass _log(f"[{_utc()}] session-start: rebuild skipped (lock present)") else: try: open(lock, "a").close() except Exception: pass env = dict(os.environ) env.update(cfg.env) env["VAULT_PATH"] = cfg.vault_path env["MODEL"] = cfg.model env["STAMP"] = stamp env["LOCK"] = lock env["LOGFILE"] = logfile cmd = ( 'graphify extract "$VAULT_PATH" --backend ollama --model "$MODEL" --force ' '>> "$LOGFILE" 2>&1 ' '&& date > "$STAMP" && rm -f "$LOCK" ' '|| (rm -f "$LOCK"; echo "rebuild failed" >> "$LOGFILE")' ) try: devnull = open(os.devnull, "wb") subprocess.Popen( ["bash", "-c", cmd], stdin=subprocess.DEVNULL, stdout=devnull, stderr=devnull, env=env, start_new_session=True, ) except Exception: pass _log(f"[{_utc()}] session-start: rebuild triggered") else: _log(f"[{_utc()}] session-start: rebuild not needed") if __name__ == "__main__": try: main() except Exception as e: print(f"[session-start] error: {e}", file=sys.stderr) sys.exit(0)