refactor(desktop): drop per-session icons, read-only cross-profile reads

The per-session icon picker added more noise than value — rip it out end
to end (sessions.icon column, set_session_icon, the PATCH field, the
picker UI, and the SessionInfo.icon type).

The cross-profile session aggregator now opens each profile's state.db
read-only (mode=ro, no schema init), so listing other profiles on every
sidebar refresh never DDLs or takes a write lock on their live DBs. The
single-profile hot path stays on par with /api/sessions.
This commit is contained in:
Brooklyn Nicholson
2026-06-04 18:24:35 -05:00
parent 48d8d80771
commit cf9dc366dd
7 changed files with 40 additions and 199 deletions

View File

@ -381,36 +381,6 @@ class TestWebServerEndpoints:
resp = self.client.patch("/api/sessions/no-fields", json={})
assert resp.status_code == 400
def test_set_and_clear_session_icon_via_patch(self):
"""PATCH icon sets a per-session glyph; "" clears it back to None."""
from hermes_state import SessionDB
db = SessionDB()
try:
db.create_session(session_id="icon-me", source="cli")
finally:
db.close()
resp = self.client.patch("/api/sessions/icon-me", json={"icon": "🦊"})
assert resp.status_code == 200
assert resp.json()["icon"] == "🦊"
db = SessionDB()
try:
assert db.get_session("icon-me")["icon"] == "🦊"
finally:
db.close()
resp = self.client.patch("/api/sessions/icon-me", json={"icon": ""})
assert resp.status_code == 200
assert resp.json()["icon"] is None
db = SessionDB()
try:
assert db.get_session("icon-me")["icon"] is None
finally:
db.close()
def test_profiles_sessions_tags_default_profile(self):
"""The cross-profile aggregator returns the default profile's rows
tagged profile="default" (single-profile parity with /api/sessions)."""