feat(system): S85: Trigger self-healing live + drone error handler + watchdog v1.1 snapshot + STATUS

Co-Authored-By: @devpulse <devpulse@aipass>
This commit is contained in:
AIOSAI
2026-04-10 13:19:06 -07:00
co-authored by @devpulse
parent 5e119c293b
commit f564996a8f
4 changed files with 20 additions and 2 deletions
@@ -92,11 +92,11 @@ INBOX="path/to/inbox.json"; while true; do sleep 10; UNREAD=$(python3 -c "import
# 4. Wake notification arrives → read mail → process → dispatch next → repeat
```
**Key:** Use `unread_count > 0` (not total_messages — close resets totals). Always `close all` before arming. 10s poll interval. `run_in_background: true` so the completion notification wakes you. On timeout, wake anyway to check if agent crashed — then either restart watchdog or re-dispatch.
**Key:** Snapshot unread_count BEFORE arming, then wake when it increases. Don't require empty inbox — works with existing mail. 10s poll interval. `run_in_background: true` so the completion notification wakes you. On timeout, wake anyway to check if agent crashed.
**Watchdog one-liner (copy-paste ready):**
```
INBOX="/home/patrick/Projects/AIPass/src/aipass/devpulse/.ai_mail.local/inbox.json"; C=0; while [ $C -lt 60 ]; do sleep 10; C=$((C+1)); UNREAD=$(python3 -c "import json; from pathlib import Path; p=Path('$INBOX'); print(json.loads(p.read_text()).get('unread_count',0) if p.exists() else 0)" 2>/dev/null); if [ "$UNREAD" -gt "0" ]; then echo "WOKE: $UNREAD unread"; exit 0; fi; done; echo "TIMEOUT: 10min no reply — check if agent crashed"; exit 0
INBOX="/home/patrick/Projects/AIPass/src/aipass/devpulse/.ai_mail.local/inbox.json"; INITIAL=$(python3 -c "import json; from pathlib import Path; p=Path('$INBOX'); print(json.loads(p.read_text()).get('unread_count',0) if p.exists() else 0)" 2>/dev/null); C=0; while [ $C -lt 60 ]; do sleep 10; C=$((C+1)); CURRENT=$(python3 -c "import json; from pathlib import Path; p=Path('$INBOX'); print(json.loads(p.read_text()).get('unread_count',0) if p.exists() else 0)" 2>/dev/null); if [ "$CURRENT" -gt "$INITIAL" ]; then echo "WOKE: new mail ($INITIAL→$CURRENT)"; exit 0; fi; done; echo "TIMEOUT: 10min no new mail"; exit 0
```
## Memory & Tracking
+4
View File
@@ -431,6 +431,10 @@ def main() -> int:
logger.warning("Registry error during systems listing: %s", exc)
err_console.print(f"drone: {exc}")
return 1
except Exception as exc:
logger.error("[drone] Unhandled error in systems: %s", exc)
err_console.print(f"drone: unexpected error: {exc}")
return 1
# scan — discover available commands in a branch
if command == "scan":
+7
View File
@@ -55,6 +55,13 @@
"subject": "DPLAN-0039 prax audit work items — test coverage, JSON corruption, stale cleanup",
"date_closed": "2026-03-29",
"location": "prax"
},
{
"plan_id": "FPLAN-0097",
"type": "FPLAN",
"subject": "Codex + Gemini log monitoring adapters for prax monitor",
"date_closed": "2026-04-10",
"location": "prax"
}
]
}
+7
View File
@@ -13,6 +13,8 @@ import json
from pathlib import Path
from unittest.mock import patch
import pytest
from aipass.spawn.apps.handlers.file_ops import (
SKIP_NAMES,
_replace_path_placeholders,
@@ -68,6 +70,11 @@ class TestEnsureDirectory:
assert target.exists()
assert target.is_dir()
def test_ensure_directory_none_raises_valueerror(self) -> None:
"""Passing None raises ValueError with clear message."""
with pytest.raises(ValueError, match="ensure_directory received None path"):
ensure_directory(None)
# ---------------------------------------------------------------------------
# copy_template