Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions clawmetry/sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -950,12 +950,16 @@ def sync_sessions_recent(

# Build subagent map (same logic as sync_sessions)
# Cache sessions.json for 60 seconds to avoid re-parsing every call
global _sessions_json_cache
file_to_subagent_id: dict[str, str] = {}
index_path = os.path.join(sessions_dir, "sessions.json")
if os.path.isfile(index_path):
try:
current_mtime = os.path.getmtime(index_path)
if _sessions_json_cache["data"] is not None and _sessions_json_cache["mtime"] == current_mtime:
if (
_sessions_json_cache["data"] is not None
and _sessions_json_cache["mtime"] == current_mtime
):
file_to_subagent_id = _sessions_json_cache["data"]
else:
with open(index_path) as _fi:
Expand All @@ -964,8 +968,14 @@ def sync_sessions_recent(
if ":subagent:" in _k and isinstance(_meta, dict):
_sf = _meta.get("sessionFile", "")
if _sf:
file_to_subagent_id[os.path.basename(_sf)] = _k.split(":")[-1]
_sessions_json_cache = {"ts": time.time(), "data": file_to_subagent_id.copy(), "mtime": current_mtime}
file_to_subagent_id[os.path.basename(_sf)] = _k.split(":")[
-1
]
_sessions_json_cache = {
"ts": time.time(),
"data": file_to_subagent_id.copy(),
"mtime": current_mtime,
}
except Exception:
pass

Expand Down Expand Up @@ -2976,8 +2986,6 @@ def _build_gateway_data(paths: dict = None) -> dict:
time.sleep(15)




def run_daemon() -> None:
"""Run the sync daemon - main loop for continuous synchronization."""
config = load_config()
Expand Down
70 changes: 70 additions & 0 deletions tests/test_sync_sessions_recent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
"""
Tests for sync_sessions_recent function - GH #007

Validates:
- sync_sessions_recent properly declares _sessions_json_cache as global
- Cache works correctly across multiple calls
"""

from __future__ import annotations

import ast
import json
import os
import tempfile
import unittest


os.environ["CLAWMETRY_NO_INTERCEPT"] = "1"


class TestSyncSessionsRecentCache(unittest.TestCase):
def test_sync_sessions_recent_has_global_declaration(self):
"""sync_sessions_recent should declare _sessions_json_cache as global."""
from clawmetry import sync

source = open(sync.__file__).read()
tree = ast.parse(source)

func_name = "sync_sessions_recent"
has_global = False
for node in ast.walk(tree):
if isinstance(node, ast.FunctionDef) and node.name == func_name:
for stmt in ast.walk(node):
if isinstance(stmt, ast.Global):
if "_sessions_json_cache" in stmt.names:
has_global = True
break

self.assertTrue(
has_global,
"sync_sessions_recent is missing 'global _sessions_json_cache' declaration",
)

def test_sync_sessions_recent_cache_functional(self):
"""sync_sessions_recent should work with sessions.json cache."""
from clawmetry.sync import sync_sessions_recent

with tempfile.TemporaryDirectory() as tmpdir:
sessions_dir = os.path.join(tmpdir, "sessions")
os.makedirs(sessions_dir)

sessions_json = os.path.join(sessions_dir, "sessions.json")
with open(sessions_json, "w") as f:
json.dump({}, f)

config = {
"api_key": "test-key",
"node_id": "test-node",
}
state = {}
paths = {
"sessions_dir": sessions_dir,
}

result = sync_sessions_recent(config, state, paths, minutes=60)
self.assertIsInstance(result, int)


if __name__ == "__main__":
unittest.main()
Loading