#!/usr/bin/env python3 """Anunță când contextul sesiunii depășește un prag, ca să se predea sesiunea. Userul a cerut asta pe 13.09.2026: la ~250k tokeni, sesiunea salvează PROGRESS.md și se oprește, iar munca o continuă o sesiune nouă. Fără un semnal automat, pragul se ratează — contextul crește în tăcere. Rulează ca hook PostToolUse. Primește pe stdin JSON-ul hook-ului, citește `usage` din ultimul mesaj al transcrierii și, dacă totalul depășește pragul, injectează un mesaj în context. Anunță o singură dată per prag, ca să nu umple contextul chiar el. """ import json import os import sys THRESHOLD = int(os.environ.get("CTX_GUARD_THRESHOLD", "250000")) STEP = 50_000 # re-anunță din 50k în 50k peste prag STATE_DIR = os.path.expanduser("~/.claude/ctx_guard") MSG = """[context guard] Contextul sesiunii a ajuns la ~{tokens:,} de tokeni (prag: {threshold:,}). Conform instrucțiunilor userului, acum: 1. Salvează starea în PROGRESS.md — ce s-a făcut, ce a rămas, ce rulează. 2. Comite și fă push. 3. Oprește agenții care au terminat (SendMessage cu shutdown_request). 4. Spune userului că sesiunea e gata de predat și oprește-te. Nu începe o sarcină nouă mare. Dacă un agent încă lucrează, cere-i raportul parțial și notează în PROGRESS.md ce rămâne de reluat.""" def total_tokens(transcript_path: str) -> int: """Suma din ultimul `usage` găsit în transcriere — aproximarea contextului.""" try: with open(transcript_path, "r", encoding="utf-8") as fh: lines = fh.readlines() except OSError: return 0 for line in reversed(lines): try: usage = json.loads(line).get("message", {}).get("usage") except (json.JSONDecodeError, AttributeError): continue if not usage: continue return (usage.get("input_tokens", 0) + usage.get("cache_read_input_tokens", 0) + usage.get("cache_creation_input_tokens", 0) + usage.get("output_tokens", 0)) return 0 def already_warned(session_id: str, bucket: int) -> bool: """Marcăm pragul atins, ca să nu repetăm anunțul la fiecare tool call.""" os.makedirs(STATE_DIR, exist_ok=True) path = os.path.join(STATE_DIR, f"{session_id}.txt") try: with open(path) as fh: if int(fh.read().strip() or 0) >= bucket: return True except (OSError, ValueError): pass with open(path, "w") as fh: fh.write(str(bucket)) return False def main() -> None: try: payload = json.load(sys.stdin) except (json.JSONDecodeError, ValueError): return transcript = payload.get("transcript_path") session_id = payload.get("session_id", "unknown") if not transcript: return tokens = total_tokens(transcript) if tokens < THRESHOLD: return bucket = THRESHOLD + ((tokens - THRESHOLD) // STEP) * STEP if already_warned(session_id, bucket): return text = MSG.format(tokens=tokens, threshold=THRESHOLD) print(json.dumps({ "systemMessage": f"Context la ~{tokens:,} tokeni — salvează PROGRESS.md și predă sesiunea.", "hookSpecificOutput": { "hookEventName": payload.get("hook_event_name", "PostToolUse"), "additionalContext": text, }, })) if __name__ == "__main__": main()