feat(harness): manifest archived/group fields + session mutation helpers

This commit is contained in:
2026-06-29 12:16:52 +02:00
parent 8167d41621
commit 60fa665d73
4 changed files with 111 additions and 0 deletions
+3
View File
@@ -44,6 +44,9 @@ def _list_sessions(sessions_root: Path) -> list[dict]:
"created_at": m.created_at.isoformat(),
"updated_at": m.updated_at.isoformat() if m.updated_at else None,
"author": m.author,
"name": m.name,
"group": m.group,
"archived": m.archived,
})
out.sort(key=lambda r: r["created_at"], reverse=True)
return out
+2
View File
@@ -43,6 +43,8 @@ class SessionManifest(_YamlModel):
model: str | None = None
thinking: str | None = None
name: str | None = None
archived: bool = False
group: str | None = None
class Candidate(BaseModel):
+37
View File
@@ -1,4 +1,5 @@
import os
import shutil
from datetime import UTC, datetime
from pathlib import Path
@@ -127,3 +128,39 @@ def close_session(session_id: str, sessions_root: Path) -> SessionManifest:
manifest.updated_by = current_author()
manifest.to_yaml(sessions_root / session_id / MANIFEST)
return manifest
def _save_touched(manifest: SessionManifest, sessions_root: Path) -> SessionManifest:
"""Persist `manifest` updating updated_at/updated_by (single save path for mutations)."""
manifest.updated_at = datetime.now(UTC)
manifest.updated_by = current_author()
manifest.to_yaml(sessions_root / manifest.id / MANIFEST)
return manifest
def set_name(session_id: str, name: str | None, sessions_root: Path) -> SessionManifest:
"""Set the descriptive name (empty/blank clears it back to None)."""
manifest = load_session(session_id, sessions_root)
manifest.name = (name or "").strip() or None
return _save_touched(manifest, sessions_root)
def set_group(session_id: str, group: str | None, sessions_root: Path) -> SessionManifest:
"""Set the group (empty/blank clears it back to None)."""
manifest = load_session(session_id, sessions_root)
manifest.group = (group or "").strip() or None
return _save_touched(manifest, sessions_root)
def set_archived(session_id: str, archived: bool, sessions_root: Path) -> SessionManifest:
"""Flip the archived flag. Archiving does NOT change resumability (a finalized
session stays read-only); unarchive only moves it back to the active list."""
manifest = load_session(session_id, sessions_root)
manifest.archived = archived
return _save_touched(manifest, sessions_root)
def delete_session(session_id: str, sessions_root: Path) -> None:
"""Hard-delete the session directory. SessionError if it does not exist."""
load_session(session_id, sessions_root) # raises SessionError if absent
shutil.rmtree(sessions_root / session_id)