From 62186d8dec5d1f077ff9031aff09a231d9579280 Mon Sep 17 00:00:00 2001 From: PeninsulaInd Date: Fri, 20 Feb 2026 13:35:54 -0600 Subject: [PATCH] Fix folder watcher matching, notifications, and BLM venv isolation - Remove status filter from folder watcher so tasks in any open status (including "internal review") are matched by keyword - Add retry logic for stuck processing/blocked/unmatched KV states - Fix notification ordering (newest first, limit 50) and date parsing - Use BLM's own .venv Python instead of uv run for subprocess calls - Document external tools venv convention in CLAUDE.md Co-Authored-By: Claude Opus 4.6 --- CLAUDE.md | 1 + cheddahbot/api.py | 7 +++++-- cheddahbot/scheduler.py | 9 ++++++--- cheddahbot/tools/linkbuilding.py | 11 ++++++++++- dashboard/index.html | 2 +- 5 files changed, 23 insertions(+), 7 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 5a7735c..92fe768 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -109,6 +109,7 @@ uv add --group test - **Notifications**: All scheduler events go through `NotificationBus.push()`, never directly to a UI - **Tests**: Use `respx` to mock httpx calls, `tmp_db` fixture for isolated SQLite instances - **ClickUp attachments**: `ClickUpClient.upload_attachment()` uses module-level `httpx.post()` (not the shared client) for multipart uploads +- **External tools**: Subprocess calls to external projects (e.g. Big-Link-Man) must use the tool's own `.venv` Python, never `uv run` from CheddahBot's environment. Resolve the venv python at `{tool_dir}/.venv/Scripts/python.exe` (Windows) or `{tool_dir}/.venv/bin/python` (Linux/Mac). Fail if no venv exists. ## Multi-Agent Configuration diff --git a/cheddahbot/api.py b/cheddahbot/api.py index eefaf18..f26ddd4 100644 --- a/cheddahbot/api.py +++ b/cheddahbot/api.py @@ -345,8 +345,11 @@ async def get_notifications(): if not _db: return {"notifications": []} - notes = _db.get_notifications_after(0, limit=100) - return {"notifications": notes} + rows = _db._conn.execute( + "SELECT id, message, category, created_at FROM notifications" + " ORDER BY id DESC LIMIT 50" + ).fetchall() + return {"notifications": [dict(r) for r in rows]} @router.get("/system/kv-states") diff --git a/cheddahbot/scheduler.py b/cheddahbot/scheduler.py index 54be1ff..0a31af4 100644 --- a/cheddahbot/scheduler.py +++ b/cheddahbot/scheduler.py @@ -488,13 +488,16 @@ class Scheduler: filename = xlsx_path.name kv_key = f"linkbuilding:watched:{filename}" - # Skip already processed files + # Skip completed/failed; retry "processing" (killed run) and "blocked" (missing field) existing = self.db.kv_get(kv_key) if existing: try: state = json.loads(existing) - if state.get("status") in ("completed", "processing", "failed"): + if state.get("status") in ("completed", "failed"): continue + if state.get("status") in ("processing", "blocked", "unmatched"): + log.info("Retrying '%s' state for %s", state["status"], filename) + self.db.kv_delete(kv_key) except json.JSONDecodeError: continue @@ -672,7 +675,7 @@ class Scheduler: return None try: - tasks = client.get_tasks_from_space(space_id, statuses=["to do"]) + tasks = client.get_tasks_from_overall_lists(space_id) except Exception as e: log.warning("ClickUp query failed in _match_xlsx_to_clickup: %s", e) return None diff --git a/cheddahbot/tools/linkbuilding.py b/cheddahbot/tools/linkbuilding.py index 2ec466a..6042664 100644 --- a/cheddahbot/tools/linkbuilding.py +++ b/cheddahbot/tools/linkbuilding.py @@ -38,7 +38,16 @@ def _run_blm_command( Always injects -u/-p from BLM_USERNAME/BLM_PASSWORD env vars. """ - cmd = ["uv", "run", "python", "main.py", *args] + # Use BLM's own venv Python so its dependencies are available + venv_python = Path(blm_dir) / ".venv" / "Scripts" / "python.exe" + if not venv_python.exists(): + # Fallback for Linux/Mac + venv_python = Path(blm_dir) / ".venv" / "bin" / "python" + if not venv_python.exists(): + raise FileNotFoundError( + f"No .venv found in {blm_dir}. External tools must have their own venv." + ) + cmd = [str(venv_python), "main.py", *args] # Inject credentials from env vars username = os.getenv("BLM_USERNAME", "") diff --git a/dashboard/index.html b/dashboard/index.html index bdc915a..9eb3f39 100644 --- a/dashboard/index.html +++ b/dashboard/index.html @@ -888,7 +888,7 @@ async function loadNotifications() { let html = '
    '; notes.slice(0, 100).forEach(n => { - const time = n.created_at ? new Date(n.created_at * 1000).toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit' }) : ''; + const time = n.created_at ? new Date(n.created_at).toLocaleString('en-US', { month:'short', day:'numeric', hour:'2-digit', minute:'2-digit' }) : ''; const level = (n.level || 'info').toLowerCase(); const typeCls = level === 'error' ? 'error' : level === 'warning' ? 'error' : 'heartbeat'; html += `