# verify_session.py — session UUID verification logic # Extracted from lib.sh VERIFY_SESSION_PYTHON block _MAM_ORC_CACHE = None def mam_orchestrator_uuids(): global _MAM_ORC_CACHE if _MAM_ORC_CACHE is not None: return _MAM_ORC_CACHE import os, sys, json, sqlite3, yaml override = os.environ.get("MAM_ORCHESTRATOR_UUIDS") if override is not None: if not override.strip(): _MAM_ORC_CACHE = [] return _MAM_ORC_CACHE if override.strip().startswith("["): try: parsed = json.loads(override) if isinstance(parsed, list): _MAM_ORC_CACHE = [str(x) for x in parsed if x] return _MAM_ORC_CACHE except Exception: pass _MAM_ORC_CACHE = [x.strip() for x in override.split(",") if x.strip()] return _MAM_ORC_CACHE res = [] d_obj = None try: if "MAM_STATE_JSON" in os.environ and os.environ.get("MAM_STATE_JSON"): d_obj = json.loads(os.environ.get("MAM_STATE_JSON")) except Exception: d_obj = None if d_obj is None or "orchestrator_uuids" not in d_obj: yaml_p = os.environ.get("AGENT_SESSIONS_YAML") or os.environ.get("YAML_PATH") if yaml_p: db_p = os.path.splitext(yaml_p)[0] + ".db" if os.path.exists(db_p): try: conn = sqlite3.connect(db_p, timeout=5.0) r = conn.execute("SELECT data FROM state WHERE id=1").fetchone() if r and r[0]: d_obj = json.loads(r[0]) conn.close() except Exception: pass if (d_obj is None or "orchestrator_uuids" not in d_obj) and os.path.exists(yaml_p): try: with open(yaml_p) as f: d_obj = yaml.safe_load(f) or {} except Exception: pass raw = d_obj.get("orchestrator_uuids") if isinstance(d_obj, dict) else None if raw is not None: if isinstance(raw, list) and all(isinstance(x, str) and x.strip() for x in raw): res = list(raw) else: sys.stderr.write("WARNING: malformed orchestrator_uuids in state, disabling orchestrator exclusion gate\n") res = [] _MAM_ORC_CACHE = res return _MAM_ORC_CACHE def mam_row_own_uuid(row): if not isinstance(row, dict): return None for k in ["claude_session_id_own", "agy_conversation_id_own", "hermes_conversation_id_own", "cline_conversation_id_own"]: v = row.get(k) if v: return v return None def workspace_key(path): import os try: p = os.path.realpath(path) except Exception: p = path return p.replace("/", "-").replace("_", "-") from lib_py.paths import resolve_home def verify_session_uuid(ws, agent, uuid, row=None, home_dir=None, claude_dir=None, mode="discover"): import os, json, sqlite3 home = resolve_home(home_dir) c_dir = claude_dir or os.environ.get("CLAUDE_PROJECT_DIR", f"{home}/.claude/projects") row = row or {} _iso = row.get("isolation") iso_root = _iso.get("root") if isinstance(_iso, dict) and _iso.get("root") else None epoch = row.get("herdr_session_epoch", 0) if mode == "discover" else 0 cwd = row.get("pane", {}).get("cwd", "") or ws if workspace_key(cwd) != workspace_key(ws): return False if mode == "discover" and uuid in mam_orchestrator_uuids(): if uuid != mam_row_own_uuid(row): return False if (mode == "revalidate" and row.get("session_id_source") == "assigned" and not row.get("session_id_verified")): return True if agent == "claude": base = (iso_root + "/projects") if iso_root else c_dir key = workspace_key(ws) path = f"{base}/{key}/{uuid}.jsonl" if not os.path.exists(path): return False if epoch and os.path.getmtime(path) < epoch: return False try: valid_session = False found_cwd = None with open(path) as f: for _ in range(50): line = f.readline() if not line: break line = line.strip() if not line: continue try: payload = json.loads(line) if payload.get("sessionId") == uuid: valid_session = True if payload.get("cwd"): found_cwd = payload.get("cwd") break except Exception: pass if not valid_session: return False if found_cwd and workspace_key(found_cwd) != workspace_key(cwd): return False except Exception: return False elif agent == "agy": base = f"{iso_root or home}/.gemini/antigravity-cli/conversations" path = f"{base}/{uuid}.db" if not os.path.exists(path): return False if epoch and os.path.getmtime(path) < epoch: return False if mode == "discover": lc = f"{iso_root or home}/.gemini/antigravity-cli/cache/last_conversations.json" cache_match = False if os.path.exists(lc): try: with open(lc) as f: lc_data = json.load(f) cache_match = (lc_data.get(cwd) == uuid) except Exception: cache_match = False if not cache_match: if uuid in (row.get("_sibling_claimed_uuids") or []): return False try: conn = sqlite3.connect(path) r = conn.execute("SELECT count(*) FROM steps").fetchone() conn.close() if not r or r[0] < 1: return False except Exception: return False elif agent == "hermes": hdb = f"{iso_root or home}/.hermes/state.db" if not os.path.exists(hdb): return False if epoch and os.path.getmtime(hdb) < epoch: return False try: conn = sqlite3.connect(hdb) r = conn.execute("SELECT cwd FROM sessions WHERE id=?", (uuid,)).fetchone() conn.close() if not r: return False found_cwd = r[0] if found_cwd and workspace_key(found_cwd) != workspace_key(cwd): return False except Exception: return False elif agent == "cline": base = (iso_root + "/sessions") if iso_root else f"{home}/.cline/data/sessions" path = f"{base}/{uuid}/{uuid}.json" if not os.path.exists(path): return False if epoch and os.path.getmtime(path) < epoch: return False try: with open(path) as f: sdata = json.load(f) if sdata.get("session_id") != uuid: return False found_cwd = sdata.get("cwd") or sdata.get("workspace_root") if found_cwd and workspace_key(found_cwd) != workspace_key(cwd): return False except Exception: return False return True