fix(tui): harden all Box TUI tabs against nulls, boundary slices, and small screens

This commit is contained in:
operator
2026-10-10 11:59:11 -04:00
parent 0668d257ca
commit 340cc9e85b
3 changed files with 287 additions and 99 deletions
+91 -64
View File
@@ -71,6 +71,12 @@ IterLinesFn = Callable[[Path], Iterable[str]]
EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)
def _safe_str(val: Any, default: str = "") -> str:
"""Safe string converter that turns None into default."""
return default if val is None else str(val)
# =====================================================================
# Default IO primitives (injectable seams for tests)
# =====================================================================
@@ -1074,7 +1080,7 @@ class BoxFleetTUI:
lines: List[Tuple[str, str]]) -> None:
self.safe_addstr(3, 2, title, self._attr("cyan"))
self.safe_addstr(4, 2, "-" * (w - 4), self._attr("dim"))
max_rows = h - 8
max_rows = max(0, h - 8)
visible = lines[self.scroll:self.scroll + max_rows]
for i, (text, attr_name) in enumerate(visible):
self.safe_addstr(5 + i, 2, text, self._attr(attr_name))
@@ -1093,19 +1099,23 @@ class BoxFleetTUI:
% ("TIMER", "NEXT", "IN", "LAST", "AGO", "ACTIVATES"), "dim"),
]
for r in rows:
missing = (r.get("next", NA) == NA and r.get("last", NA) == NA)
attr = "dim" if missing else ("yellow" if r.get("next", NA) == NA else "normal")
if not isinstance(r, dict):
continue
next_val = _safe_str(r.get("next"), NA)
last_val = _safe_str(r.get("last"), NA)
missing = (next_val == NA and last_val == NA)
attr = "dim" if missing else ("yellow" if next_val == NA else "normal")
lines.append((
"%-32s %-11s %-9s %-11s %-9s %s" % (
r.get("timer", "?")[:32], r.get("next", NA)[:11],
r.get("next_rel", NA)[:9], r.get("last", NA)[:11],
r.get("last_rel", NA)[:9],
r.get("activates", NA)[:28]), attr))
_safe_str(r.get("timer"), "?")[:32], next_val[:11],
_safe_str(r.get("next_rel"), NA)[:9], last_val[:11],
_safe_str(r.get("last_rel"), NA)[:9],
_safe_str(r.get("activates"), NA)[:28]), attr))
if not rows:
lines.append(("(No fleet timers discovered in systemd/)", "dim"))
if data.get("note"):
lines.append(("", "normal"))
lines.append(("note: %s" % data["note"][: w - 10], "yellow"))
lines.append(("note: %s" % _safe_str(data["note"])[: max(0, w - 10)], "yellow"))
self._body(h, w, "USER TIMER STATES (NEXT/LAST)", lines)
def _render_harvest(self, h: int, w: int) -> None:
@@ -1116,23 +1126,30 @@ class BoxFleetTUI:
% ("AGENT", "THREAD", "WATERMARK", "LAST", "AGO", "FRESH"), "dim"),
]
for r in rows:
fresh = r.get("freshness", "unknown")
if not isinstance(r, dict):
continue
fresh = _safe_str(r.get("freshness"), "unknown")
if fresh == "fresh":
attr = "green"
elif fresh == "aging":
attr = "yellow"
elif fresh == "stale":
attr = "red"
elif r.get("watermark", NA) == NA:
elif _safe_str(r.get("watermark"), NA) == NA:
attr = "dim"
else:
attr = "normal"
lines.append((
"%-6s %-20s %-24s %-11s %-9s %s" % (
r.get("agent", "?"), r.get("thread_name", "?")[:20],
r.get("watermark", NA)[:24], r.get("last", NA)[:11],
r.get("last_rel", NA)[:9], fresh), attr))
_safe_str(r.get("agent"), "?"), _safe_str(r.get("thread_name"), "?")[:20],
_safe_str(r.get("watermark"), NA)[:24], _safe_str(r.get("last"), NA)[:11],
_safe_str(r.get("last_rel"), NA)[:9], fresh), attr))
if not rows:
lines.append(("(No harvest watermarks found in %s)"
% WATERMARKS_FILE.name, "dim"))
if data.get("note"):
lines.append(("", "normal"))
lines.append(("note: %s" % data["note"][: w - 10], "yellow"))
lines.append(("note: %s" % _safe_str(data["note"])[: max(0, w - 10)], "yellow"))
self._body(h, w, "HARVEST WATERMARKS PER AGENT (freshness highlighted)", lines)
def _render_followups(self, h: int, w: int) -> None:
@@ -1158,16 +1175,16 @@ class BoxFleetTUI:
lines.append((" %-8s %d" % (agent, n), "normal"))
lines.append(("", "normal"))
oldest = data.get("oldest_pending")
if oldest:
if isinstance(oldest, dict):
lines.append(("Oldest pending: %s %s %s sent %s (%s)" % (
oldest.get("dm_id", "?"), oldest.get("route", "?"),
oldest.get("target", "?"), oldest.get("sent", NA),
oldest.get("sent_rel", NA)), "yellow"))
_safe_str(oldest.get("dm_id"), "?"), _safe_str(oldest.get("route"), "?"),
_safe_str(oldest.get("target"), "?"), _safe_str(oldest.get("sent"), NA),
_safe_str(oldest.get("sent_rel"), NA)), "yellow"))
else:
lines.append(("Oldest pending: none", "dim"))
if data.get("note"):
lines.append(("", "normal"))
lines.append(("note: %s" % data["note"][: w - 10], "yellow"))
lines.append(("note: %s" % _safe_str(data["note"])[: max(0, w - 10)], "yellow"))
self._body(h, w, "FOLLOW-UP QUEUE COUNTS BY STATUS", lines)
def _render_approvals(self, h: int, w: int) -> None:
@@ -1185,14 +1202,16 @@ class BoxFleetTUI:
lines.append(("%-6s %-12s %-32s %s"
% ("NODE", "STATUS", "TARGET", "TITLE"), "dim"))
for p in pending:
if not isinstance(p, dict):
continue
lines.append((
"%-6s %-12s %-32s %s" % (
p.get("node", "?"), p.get("status", "?")[:12],
p.get("target", "-")[:32],
p.get("title", "")[: w - 58]), "red"))
_safe_str(p.get("node"), "?"), _safe_str(p.get("status"), "?")[:12],
_safe_str(p.get("target"), "-")[:32],
_safe_str(p.get("title"), "")[: max(0, w - 58)]), "red"))
if data.get("note"):
lines.append(("", "normal"))
lines.append(("note: %s" % data["note"][: w - 10], "yellow"))
lines.append(("note: %s" % _safe_str(data["note"])[: max(0, w - 10)], "yellow"))
self._body(h, w, "PENDING APPROVALS", lines)
def _render_activity(self, h: int, w: int) -> None:
@@ -1203,18 +1222,20 @@ class BoxFleetTUI:
% ("AGENT", "LAST", "AGO", "SRC", "FRESH", "DETAIL"), "dim"),
]
for r in rows:
fresh = r.get("freshness", "unknown")
if not isinstance(r, dict):
continue
fresh = _safe_str(r.get("freshness"), "unknown")
attr = "green" if fresh == "fresh" else (
"yellow" if fresh == "aging" else (
"red" if fresh == "stale" else "dim"))
lines.append((
"%-6s %-11s %-9s %-6s %-7s %s" % (
r.get("agent", "?"), r.get("last", NA)[:11],
r.get("last_rel", NA)[:9], r.get("source", NA)[:6],
fresh, r.get("detail", NA)[: w - 48]), attr))
_safe_str(r.get("agent"), "?"), _safe_str(r.get("last"), NA)[:11],
_safe_str(r.get("last_rel"), NA)[:9], _safe_str(r.get("source"), NA)[:6],
fresh, _safe_str(r.get("detail"), NA)[: max(0, w - 48)]), attr))
if data.get("note"):
lines.append(("", "normal"))
lines.append(("note: %s" % data["note"][: w - 10], "yellow"))
lines.append(("note: %s" % _safe_str(data["note"])[: max(0, w - 10)], "yellow"))
self._body(h, w, "PER-AGENT LAST ACTIVITY", lines)
def _render_runtimes(self, h: int, w: int) -> None:
@@ -1235,70 +1256,74 @@ class BoxFleetTUI:
]
items: List[Dict[str, str]] = []
line_of_item: Dict[int, int] = {}
for agent in data.get("agents", []):
for agent in data.get("agents") or []:
if not isinstance(agent, dict):
continue
live = agent.get("live")
briefed = agent.get("briefed")
if isinstance(briefed, bool):
briefed_txt = "yes" if briefed else "NO"
else:
briefed_txt = str(briefed)
briefed_txt = str(briefed) if briefed is not None else "-"
attr = "dim" if not agent.get("enabled") else (
"red" if not live else (
"yellow" if briefed_txt in ("NO", "stale")
else "normal"))
idx = len(items)
if live:
items.append({"socket": agent.get("socket", "?"),
"session": agent.get("session", "?")})
items.append({"socket": _safe_str(agent.get("socket"), "?"),
"session": _safe_str(agent.get("session"), "?")})
line_of_item[idx] = len(lines)
else:
idx = -1
marker = ">" if idx == self.rt_sel else " "
lines.append((
"%s%-25s %-8s %-5s %-5s %-11s %-10s %-7s %s" % (
marker, agent.get("session", "?")[:25],
agent.get("hat", "?")[:8],
marker, _safe_str(agent.get("session"), "?")[:25],
_safe_str(agent.get("hat"), "?")[:8],
"YES" if live else "NO",
agent.get("pane", NA)[:5],
agent.get("state", NA)[:11],
agent.get("mode", NA)[:10],
_safe_str(agent.get("pane"), NA)[:5],
_safe_str(agent.get("state"), NA)[:11],
_safe_str(agent.get("mode"), NA)[:10],
"ALIVE" if agent.get("watcher") else "-",
briefed_txt), attr))
strays = data.get("strays", [])
strays = data.get("strays") or []
if strays:
lines.append(("", "normal"))
lines.append(("Stray sessions (fleet sockets, not in manifest):",
"dim"))
for stray in strays:
if not isinstance(stray, dict):
continue
idx = len(items)
items.append({"socket": stray.get("socket", "?"),
"session": stray.get("session", "?")})
items.append({"socket": _safe_str(stray.get("socket"), "?"),
"session": _safe_str(stray.get("session"), "?")})
line_of_item[idx] = len(lines)
marker = ">" if idx == self.rt_sel else " "
lines.append((
"%s%-25s %-8s %-5s %-5s %-11s %-10s %-7s %s" % (
marker, stray.get("session", "?")[:25],
marker, _safe_str(stray.get("session"), "?")[:25],
"stray",
"YES", stray.get("pane", NA)[:5],
stray.get("state", NA)[:11], "", "",
(stray.get("cmd", "") or "")[:20]), "yellow"))
"YES", _safe_str(stray.get("pane"), NA)[:5],
_safe_str(stray.get("state"), NA)[:11], "", "",
_safe_str(stray.get("cmd"))[:20]), "yellow"))
lines.append(("", "normal"))
lines.append(("Task queue: pending %d | claimed %s | done %d"
% (queue.get("pending", 0), claimed_txt[: w - 48],
% (queue.get("pending", 0), claimed_txt[: max(0, w - 48)],
queue.get("done", 0)), "cyan"))
plan_bits = []
for key in ("launch", "brief", "nudge", "failed"):
names = plan.get(key, []) or []
if names:
plan_bits.append("%s: %s" % (key, ", ".join(names)))
plan_bits.append("%s: %s" % (key, ", ".join(str(n) for n in names)))
lines.append(("", "normal"))
lines.append(("Reconcile plan (dry-run): %s"
% ("; ".join(plan_bits) or "steady state"), "cyan"))
for err in data.get("plan_errors", []) or []:
lines.append(("plan error: %s" % str(err)[: w - 14], "red"))
lines.append(("plan error: %s" % str(err)[: max(0, w - 14)], "red"))
if data.get("note"):
lines.append(("", "normal"))
lines.append(("note: %s" % data["note"][: w - 10], "yellow"))
lines.append(("note: %s" % _safe_str(data["note"])[: max(0, w - 10)], "yellow"))
self.rt_items = items
if self.rt_items:
self.rt_sel = max(0, min(self.rt_sel, len(self.rt_items) - 1))
@@ -1363,16 +1388,16 @@ class BoxFleetTUI:
]
for agent in FLEET_AGENTS:
st = cog.get(agent, {})
badge = st.get("badge") or st.get("status") or "UNKNOWN"
st = cog.get(agent) or {}
badge = _safe_str(st.get("badge") or st.get("status"), "UNKNOWN")
lock = "LOCKED" if st.get("cognitive_lock") else "OPEN"
scr = st.get("screen") or {}
url = scr.get("url") or "-"
title = scr.get("title") or "-"
url = _safe_str(scr.get("url"), "-")
title = _safe_str(scr.get("title"), "-")
lock_attr = "red" if lock == "LOCKED" else "green"
lines.append((
"%-6s %-16s %-8s %-24s %s" % (
agent, badge[:16], lock, url[:24], title[:w - 60]
agent, badge[:16], lock, url[:24], title[: max(0, w - 60)]
), lock_attr
))
@@ -1383,17 +1408,19 @@ class BoxFleetTUI:
if not issues:
lines.append(("(No recent build tickets found on tea.muse-dev.online)", "dim"))
else:
for idx, iss in enumerate(issues[:8]):
inum = "#%s" % iss.get("number")
istate = iss.get("state", "").upper()
asg = (iss.get("assignee") or {}).get("username") or "unassigned"
created = (iss.get("created_at") or "")[:10]
title = iss.get("title") or ""
for idx, iss in enumerate((issues or [])[:8]):
if not isinstance(iss, dict):
continue
inum = "#%s" % _safe_str(iss.get("number"), "?")
istate = _safe_str(iss.get("state"), "").upper()
asg = _safe_str((iss.get("assignee") or {}).get("username"), "unassigned")
created = _safe_str(iss.get("created_at"))[:10]
title = _safe_str(iss.get("title"), "")
marker = ">" if idx == self.work_sel else " "
i_attr = "green" if istate == "CLOSED" else "yellow"
lines.append((
"%s%-5s %-10s %-10s %-12s %s" % (
marker, inum, istate, asg[:10], created, title[:w - 45]
marker, inum, istate, asg[:10], created, title[: max(0, w - 45)]
), i_attr
))
@@ -1435,10 +1462,10 @@ class BoxFleetTUI:
self.status_msg = "Heal @%s: %s" % (agent.upper(), "Restored" if rc == 0 else "Alerts")
def _render_help(self, h: int, w: int) -> None:
modal_w = min(64, w - 6)
modal_h = 15
top = (h - modal_h) // 2
left = (w - modal_w) // 2
modal_w = max(10, min(64, w - 6))
modal_h = max(5, min(15, h - 2))
top = max(0, (h - modal_h) // 2)
left = max(0, (w - modal_w) // 2)
for y in range(top, top + modal_h):
self.safe_addstr(y, left, " " * modal_w, self._attr("row_sel"))
self.safe_addstr(top, left, "+" + "-" * (modal_w - 2) + "+",