#!/usr/bin/env python3 """Backend for /aircontext-now — force a compaction synchronously.""" from __future__ import annotations import argparse import json import os import sys from pathlib import Path _HERE = Path(__file__).resolve().parent sys.path.insert(0, str(_HERE)) from core.compactor import run as run_compactor # noqa: E402 from core.state import StateFile # noqa: E402 def _find_transcript(project: Path, session_id: str) -> Path | None: """Locate the JSONL transcript for the given session. Claude Code stores transcripts under ~/.claude/projects//sessions/.jsonl The cwd encoding replaces path separators with `-`. We search defensively. """ home = Path.home() / ".claude" / "projects" if not home.exists(): return None encoded = str(project).replace(os.sep, "-").replace(":", "") # Try direct match first candidate = home / encoded / "sessions" / f"{session_id}.jsonl" if candidate.exists(): return candidate # Fall back: scan for the session id under any project directory for p in home.glob(f"*/sessions/{session_id}.jsonl"): return p return None def main() -> int: p = argparse.ArgumentParser() p.add_argument("--session-id", required=True) args = p.parse_args() project = Path(os.environ.get("CLAUDE_PROJECT_DIR", os.getcwd())) air = project / "AirContext" if not (air / "config.yaml").exists(): print("AirContext not initialised. Run /aircontext-init first.") return 1 transcript = _find_transcript(project, args.session_id) if not transcript: print(f"Could not locate transcript for session {args.session_id}.") return 1 state = StateFile(air / "state.json") # Force one-shot regardless of cooldown state.update(last_compaction_unix=0) print(f"Compacting transcript: {transcript}") rc = run_compactor(project, transcript, args.session_id) snap = state.read() if rc == 0 and snap.get("compaction_ready"): print("Compaction prepared. The wrapper will restart claude shortly.") print("If you launched claude directly (without `aircontext`), exit and " f"run: claude --resume {args.session_id}") elif rc == 0: print("Compactor returned success but no compaction was applied " "(see compactor.log for reason — likely chain too short or paused).") else: print(f"Compactor failed with exit code {rc}. See AirContext/snapshots/compactor.log") return rc if __name__ == "__main__": sys.exit(main())