Archive completed tasks, add cleanup commands, self-documenting dashboard UI
CI / build (push) Has been cancelled

- Archive 79 completed framework-dev tasks from tasks/ -> tasks/complete/
- status.py: add --cleanup-done and --install-cleanup-schedule commands
- Add scripts/automaton-cleanup.sh for periodic task archiving
- Dashboard: rename 'Background' tab -> 'Agent', 'Cleanup' agent -> 'Completed Task Archiver', remove redundant group headers and pill badges, dim inactive agent placeholders
- .rules.md: add Self-Documenting UI Names rule
- New tests: test_cleanup_done.py, expanded test_app.py and test_task.py
This commit is contained in:
Lap Tran
2026-06-24 22:43:33 -04:00
parent e13513faaa
commit 4a2301b077
572 changed files with 856 additions and 101 deletions
+75
View File
@@ -242,3 +242,78 @@ class TestConfigEndpoint:
handler._send_error = lambda c, m: errors.append((c, m))
handler._handle_config_update()
assert errors[0][0] == 400
def test_serve_scheduled_returns_jobs(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
"""`/api/scheduled` returns jobs from `_list_scheduled_jobs`."""
import automaton.dashboard.ui.app as app_mod
class _FakeStatusMod:
def _list_scheduled_jobs(self=None, project=None):
return [
{"label": "com.automaton.cleanup", "kind": "cleanup", "name": "",
"status": "enabled", "next_run_seconds": 86400,
"stub_path": "/x/stub.sh", "runtime_state": None},
{"label": "com.automaton.loop.ci", "kind": "loop", "name": "ci",
"status": "disabled", "next_run_seconds": 60,
"stub_path": None, "runtime_state": {"status": "paused"},
"agent_type": "single"},
]
monkeypatch.setattr(app_mod, "_get_status_module", lambda: _FakeStatusMod())
handler = DashboardHandler.__new__(DashboardHandler)
handler.project_root = tmp_path
response = {}
handler._send_json = lambda d: response.update(d)
handler._serve_scheduled()
assert response["available"] is True
assert len(response["jobs"]) == 2
assert response["jobs"][0]["kind"] == "cleanup"
assert response["jobs"][1]["name"] == "ci"
assert response["jobs"][1]["agent_type"] == "single"
def test_serve_scheduled_unavailable(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
"""When status.py can't be loaded, `/api/scheduled` reports unavailable."""
import automaton.dashboard.ui.app as app_mod
monkeypatch.setattr(app_mod, "_get_status_module", lambda: None)
handler = DashboardHandler.__new__(DashboardHandler)
handler.project_root = tmp_path
response = {}
handler._send_json = lambda d: response.update(d)
handler._serve_scheduled()
assert response["available"] is False
assert response["jobs"] == []
def test_serve_scheduled_handles_errors(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
"""Exceptions from `_list_scheduled_jobs` surface as `error` in the response."""
import automaton.dashboard.ui.app as app_mod
class _FakeStatusMod:
def _list_scheduled_jobs(self=None, project=None):
raise RuntimeError("boom")
monkeypatch.setattr(app_mod, "_get_status_module", lambda: _FakeStatusMod())
handler = DashboardHandler.__new__(DashboardHandler)
handler.project_root = tmp_path
response = {}
handler._send_json = lambda d: response.update(d)
handler._serve_scheduled()
assert response["available"] is True
assert response["jobs"] == []
assert "boom" in response["error"]
def test_get_status_module_returns_none_when_missing(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
"""`_get_status_module` returns None when status.py isn't found in ~/.automaton."""
import automaton.dashboard.ui.app as app_mod
# Reset the cached module, and point HOME at an empty dir so
# `Path.home() / .automaton / scripts / status.py` doesn't exist.
monkeypatch.setattr(app_mod, "_status_module", None)
monkeypatch.setenv("HOME", str(tmp_path))
# pathlib.Path.home() respects $HOME on every platform.
result = app_mod._get_status_module()
assert result is None