feat(cli): show session titles in status bars

This commit is contained in:
Teknium
2026-08-08 12:01:54 -07:00
parent 05330e804a
commit 5a16635f40
12 changed files with 160 additions and 7 deletions
+90 -3
View File
@@ -5271,6 +5271,7 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin, CLIBillingMixin):
"model_name": model_name,
"model_short": model_short,
"duration": format_duration_compact(elapsed_seconds),
"session_title": self._get_status_bar_session_title(),
"prompt_elapsed": self._format_prompt_elapsed(
getattr(self, "_prompt_start_time", None),
getattr(self, "_prompt_duration", 0.0),
@@ -5407,6 +5408,34 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin, CLIBillingMixin):
return snapshot
def _get_status_bar_session_title(self) -> str:
"""Return the current title without polling state.db on every repaint."""
pending = str(getattr(self, "_pending_title", None) or "").strip()
session_id = str(getattr(self, "session_id", "") or "")
if pending:
self._status_bar_title_session_id = session_id
self._status_bar_title_cache = pending
self._status_bar_title_checked_at = time.monotonic()
return pending
now = time.monotonic()
cached_session_id = getattr(self, "_status_bar_title_session_id", None)
checked_at = float(getattr(self, "_status_bar_title_checked_at", 0.0) or 0.0)
if cached_session_id == session_id and now - checked_at < 1.5:
return str(getattr(self, "_status_bar_title_cache", "") or "")
title = ""
db = getattr(self, "_session_db", None)
if db is not None and session_id:
try:
title = str(db.get_session_title(session_id) or "").strip()
except Exception:
title = ""
self._status_bar_title_session_id = session_id
self._status_bar_title_cache = title
self._status_bar_title_checked_at = now
return title
@staticmethod
def _status_bar_display_width(text: str) -> int:
"""Return terminal cell width for status-bar text.
@@ -5450,6 +5479,57 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin, CLIBillingMixin):
width += ch_width
return "".join(out).rstrip() + ellipsis
@classmethod
def _right_align_status_title(cls, text: str, title: str, width: int) -> str:
"""Pin a bounded session-title badge to the far-right status-bar edge."""
title = str(title or "").strip()
if not title or width < 24:
return cls._trim_status_bar_text(text, width)
title_width = max(6, min(30, width // 3))
badge = f" {cls._trim_status_bar_text(title, title_width - 2)} "
suffix = f" ─{badge}"
left_width = max(0, width - cls._status_bar_display_width(suffix))
left = cls._trim_status_bar_text(text.rstrip(), left_width)
padding = " " * max(0, left_width - cls._status_bar_display_width(left))
return f"{left}{padding}{suffix}"
@classmethod
def _right_align_status_title_fragments(cls, frags, title: str, width: int):
"""Styled counterpart to :meth:`_right_align_status_title`."""
title = str(title or "").strip()
if not title or width < 24:
return frags
title_width = max(6, min(30, width // 3))
badge = f" {cls._trim_status_bar_text(title, title_width - 2)} "
suffix_width = cls._status_bar_display_width(" ─") + cls._status_bar_display_width(badge)
left_width = max(0, width - suffix_width)
trimmed = []
used = 0
for style, value in frags:
remaining = left_width - used
if remaining <= 0:
break
value_width = cls._status_bar_display_width(value)
if value_width <= remaining:
trimmed.append((style, value))
used += value_width
continue
clipped = cls._trim_status_bar_text(value, remaining)
if clipped:
trimmed.append((style, clipped))
used += cls._status_bar_display_width(clipped)
break
if used < left_width:
trimmed.append(("class:status-bar-dim", " " * (left_width - used)))
trimmed.extend([
("class:status-bar-dim", " ─"),
("class:status-bar-session-title", badge),
])
return trimmed
@staticmethod
def _get_tui_terminal_width(default: tuple[int, int] = (80, 24)) -> int:
"""Return the live prompt_toolkit width, falling back to ``shutil``.
@@ -5934,6 +6014,7 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin, CLIBillingMixin):
battery_label = snapshot.get("battery_label") or ""
battery_prefix = f"{battery_label} │ " if battery_label else ""
focus_label = snapshot.get("focus_label") or ""
session_title = snapshot.get("session_title") or ""
yolo_active = self._is_session_yolo_active()
goal_segment = self._status_bar_goal_segment(snapshot)
@@ -5945,7 +6026,7 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin, CLIBillingMixin):
text += f" · {focus_label}"
if yolo_active:
text += " · ⚠ YOLO"
return self._trim_status_bar_text(text, width)
return self._right_align_status_title(text, session_title, width)
if width < 76:
parts = [f"⚕ {snapshot['model_short']}", percent_label]
if battery_label:
@@ -5969,7 +6050,7 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin, CLIBillingMixin):
parts.append(focus_label)
if yolo_active:
parts.append("⚠ YOLO")
return self._trim_status_bar_text(" · ".join(parts), width)
return self._right_align_status_title(" · ".join(parts), session_title, width)
if snapshot["context_length"]:
ctx_total = _format_context_length(snapshot["context_length"])
@@ -6006,7 +6087,7 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin, CLIBillingMixin):
parts.append(focus_label)
if yolo_active:
parts.append("⚠ YOLO")
return self._trim_status_bar_text(" │ ".join(parts), width)
return self._right_align_status_title(" │ ".join(parts), session_title, width)
except Exception:
return f"⚕ {self.model if getattr(self, 'model', None) else 'Hermes'}"
@@ -6027,6 +6108,7 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin, CLIBillingMixin):
battery_label = snapshot.get("battery_label") or ""
battery_style = self._battery_status_style(snapshot.get("battery_category", "dim"))
focus_label = snapshot.get("focus_label") or ""
session_title = snapshot.get("session_title") or ""
if width < 52:
frags = [
@@ -6177,6 +6259,8 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin, CLIBillingMixin):
("class:status-bar-dim", " │"),
]
frags = self._right_align_status_title_fragments(frags, session_title, width)
total_width = sum(self._status_bar_display_width(text) for _, text in frags)
if total_width > width:
plain_text = "".join(text for _, text in frags)
@@ -8297,6 +8381,7 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin, CLIBillingMixin):
try:
self._session_db.set_session_title(self.session_id, sanitized)
self._pending_title = None
self._status_bar_title_checked_at = 0.0
title = sanitized
except ValueError as e:
_cprint(f" {e} — session started untitled.")
@@ -10015,6 +10100,7 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin, CLIBillingMixin):
# Session exists in DB — set title directly
try:
if self._session_db.set_session_title(self.session_id, new_title):
self._status_bar_title_checked_at = 0.0
_cprint(f" Session title set: {new_title}")
else:
_cprint(" Session not found in database.")
@@ -17224,6 +17310,7 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin, CLIBillingMixin):
'status-bar-bad': 'bg:#1a1a2e #FF8C00 bold',
'status-bar-critical': 'bg:#1a1a2e #FF6B6B bold',
'status-bar-yolo': 'bg:#1a1a2e #FF4444 bold',
'status-bar-session-title': 'bg:#FFD700 #1a1a2e bold',
# Bronze horizontal rules around the input area
'input-rule': '#CD7F32',
# Clipboard image attachment badges