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
+52 -35
View File
@@ -2033,8 +2033,11 @@ class MuseTUI:
# Muse Conversational View (Split Sidebar + Transcript)
# -----------------------------------------------------------------------
def _render_muse_view(self, y: int, x: int, h: int, w: int):
sidebar_w = min(36, max(26, w // 4))
chat_w = w - sidebar_w - 1
if w < 40:
sidebar_w = min(20, max(10, w // 2))
else:
sidebar_w = min(36, max(24, w // 4))
chat_w = max(0, w - sidebar_w - 1)
is_sidebar_focused = (self.focus_pane in ("sidebar", "sidechats", "fleet") and self.editor_mode == "NORMAL")
is_transcript_focused = (self.focus_pane == "transcript" and self.editor_mode == "NORMAL")
@@ -2878,7 +2881,7 @@ class MuseTUI:
break
node = self.data.nodes[idx]
is_sel = (idx == self.fleet_sel_idx)
st = statuses.get(node, {})
st = statuses.get(node) or {}
status_text = st.get("status", "ACTIVE")
is_blocked = st.get("blocked", False)
if is_blocked:
@@ -2890,7 +2893,7 @@ class MuseTUI:
tab_name = st.get("tab") or "-"
# Cognitive state & Lock
cog = cog_cache.get(node, {})
cog = cog_cache.get(node) or {}
c_st = cog.get("status") or ("INPUT_WAIT" if is_blocked else ("ACTIVE" if status_text == "ACTIVE" else "IDLE"))
c_locked = cog.get("cognitive_lock", False)
lock_str = "LOCKED" if c_locked else "OPEN"
@@ -2899,8 +2902,10 @@ class MuseTUI:
# Assigned build ticket
assigned = None
for iss in work_issues:
if iss.get("assignee", {}).get("username") == node and iss.get("state") == "open":
assigned = f"#{iss.get('number')} {iss.get('title', '')[:28]}"
if not isinstance(iss, dict):
continue
if (iss.get("assignee") or {}).get("username") == node and iss.get("state") == "open":
assigned = f"#{iss.get('number')} {(iss.get('title') or '')[:28]}"
break
work_txt = assigned or tab_name
@@ -2976,7 +2981,7 @@ class MuseTUI:
tun = "UP" if node in ("opm", "646", "dev", "muse-main", "muse") else "DARK"
tun_attr = self._attr("success") if tun == "UP" else self._attr("dim")
cog = cog_cache.get(node, {})
cog = cog_cache.get(node) or {}
c_st = cog.get("status") or "IDLE"
if node == "muse-main":
c_st = "HOST"
@@ -2986,8 +2991,10 @@ class MuseTUI:
assigned = None
for iss in issues:
if iss.get("assignee", {}).get("username") == node and iss.get("state") == "open":
assigned = f"#{iss.get('number')} {iss.get('title', '')[:30]}"
if not isinstance(iss, dict):
continue
if (iss.get("assignee") or {}).get("username") == node and iss.get("state") == "open":
assigned = f"#{iss.get('number')} {(iss.get('title') or '')[:30]}"
break
work_txt = assigned or ("Ready for assignment" if not c_locked else "Busy in thread")
@@ -3014,11 +3021,13 @@ class MuseTUI:
row_y += 1
else:
for iss in issues[:6]:
num = f"#{iss.get('number')}"
st = iss.get("state", "").upper()
asg = iss.get("assignee", {}).get("username", "-") if iss.get("assignee") else "-"
tit = iss.get("title", "")[:44]
lbls = ", ".join(l.get("name") for l in iss.get("labels", []))
if not isinstance(iss, dict):
continue
num = f"#{iss.get('number') or '?'}"
st = (iss.get("state") or "").upper()
asg = (iss.get("assignee") or {}).get("username") or "-"
tit = (iss.get("title") or "")[:44]
lbls = ", ".join(((l or {}).get("name") or "") for l in (iss.get("labels") or []))
st_attr = self._attr("dim") if st == "CLOSED" else self._attr("success")
self.safe_addstr(self.stdscr, row_y, x + 3, f"{num:<8}", self._attr("bold"))
@@ -3041,11 +3050,13 @@ class MuseTUI:
row_y += 1
else:
for pr in prs[:3]:
pnum = f"#{pr.get('number')}"
if not isinstance(pr, dict):
continue
pnum = f"#{pr.get('number') or '?'}"
merged = pr.get("merged", False)
p_st = "MERGED" if merged else pr.get("state", "").upper()
p_head = pr.get("head", {}).get("ref", "-")[:32]
p_tit = pr.get("title", "")[:42]
p_st = "MERGED" if merged else (pr.get("state") or "").upper()
p_head = ((pr.get("head") or {}).get("ref") or "-")[:32]
p_tit = (pr.get("title") or "")[:42]
st_attr = self._attr("success") if merged else self._attr("warn_banner")
self.safe_addstr(self.stdscr, row_y, x + 3, f"{pnum:<8}", self._attr("bold"))
@@ -3081,17 +3092,19 @@ class MuseTUI:
row_y = y + 3
for idx, it in enumerate(apps):
if not isinstance(it, dict):
continue
if row_y >= y + h - 2:
break
n = it.get("node", "-")
st = it.get("status", "CLEAR")
n = it.get("node") or "-"
st = it.get("status") or "CLEAR"
is_sel = (idx == self.approvals_sel_idx)
tgt = it.get("target") or it.get("purpose") or it.get("title") or "-"
if st == "INPUT_WAIT":
waits = it.get("input_waits") or []
if waits:
tgt = "; ".join(f"{w.get('task')}" for w in waits)
tgt = "; ".join(f"{(w or {}).get('task')}" for w in waits)
else:
tgt = "Subagent waiting for operator input"
@@ -3114,7 +3127,7 @@ class MuseTUI:
row_y += 1
hint_y = y + h - 1
sel_node = apps[self.approvals_sel_idx].get("node", "").upper() if apps else "-"
sel_node = (apps[self.approvals_sel_idx].get("node") or "").upper() if apps else "-"
hints = f"Selected: [{sel_node}] [j/k]: Head [1/2/3]: Allow/Always/Deny [r]: Proceed [x]: Dismiss [c]: Clear All [Enter]: Chat"
self.safe_addstr(self.stdscr, hint_y, x + 1, hints[:w - 2], self._attr("dim"))
@@ -3150,12 +3163,14 @@ class MuseTUI:
if idx >= len(jobs):
break
j = jobs[idx]
if not isinstance(j, dict):
continue
is_sel = (idx == self.jobs_sel_idx)
name = j.get("name", "")
agent = j.get("agent", "-")
sched = j.get("schedule", "-")
timeout = f"{j.get('timeout', '-')}s"
desc = j.get("description", "-") or "-"
name = j.get("name") or ""
agent = j.get("agent") or "-"
sched = j.get("schedule") or "-"
timeout = f"{j.get('timeout') or '-'}s"
desc = j.get("description") or "-"
head = "▶ " if is_sel else " "
row_attr = self._attr("selected") if is_sel else self._attr("normal")
@@ -3203,7 +3218,7 @@ class MuseTUI:
self.tmux_sel_idx = max(0, len(sessions) - 1)
row_y = y + 3
for idx, s in enumerate(sessions[:h - 5]):
for idx, s in enumerate(sessions[:max(0, h - 5)]):
is_sel = (idx == self.tmux_sel_idx)
head = "▶ " if is_sel else " "
row_attr = self._attr("selected") if is_sel else self._attr("normal")
@@ -3226,13 +3241,15 @@ class MuseTUI:
logs = list(self.data.dm_logs_cache)
row_y = y + 2
for it in logs[:h - 4]:
l_type = it.get("type", "")
agent = it.get("agent", "")
to = it.get("to", "")
target = it.get("target", "")
ts = it.get("ts", "")[:19].replace("T", " ")
mid = it.get("id", "")
for it in logs[:max(0, h - 4)]:
if not isinstance(it, dict):
continue
l_type = it.get("type") or ""
agent = it.get("agent") or ""
to = it.get("to") or ""
target = it.get("target") or ""
ts = (it.get("ts") or "")[:19].replace("T", " ")
mid = it.get("id") or ""
color = self._attr("success") if l_type == "verified" else (self._attr("user") if l_type == "sent" else self._attr("dim"))
line_str = f"[{ts}] {l_type:<9} {agent} -> {to} ({target}) [{mid}]"