74 lines
2.5 KiB
Python
74 lines
2.5 KiB
Python
#!/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/<encoded-cwd>/sessions/<session-id>.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())
|