feat(cli): show live background terminal-process count in status bar (#32061)

The CLI status bar tracked /background agent tasks (▶ N) but not shell
processes spawned via terminal(background=true). Both kinds of work can
run concurrently and a user has no in-bar signal for shell processes.

Add an independent indicator (⚙ N) sourced from
tools.process_registry.process_registry._running. The two indicators
render side-by-side when both are active (▶ 1 │ ⚙ 2), hidden when their
count is zero. Renders at all four status-bar tiers (text fallback +
prompt_toolkit fragments, narrow + wide widths). The narrow <52 tier
still drops both for space — unchanged.

New ProcessRegistry.count_running() returns len(_running) without
acquiring _lock; CPython dict len is atomic and we're polling on every
status-bar tick, so lock-free is the right tradeoff.
This commit is contained in:
Teknium 2026-05-25 05:35:02 -07:00 committed by GitHub
parent 2b16de0ec3
commit 1c3c364287
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 123 additions and 0 deletions

23
cli.py
View file

@ -3503,6 +3503,7 @@ class HermesCLI:
"session_api_calls": 0,
"compressions": 0,
"active_background_tasks": 0,
"active_background_processes": 0,
}
# Count live /background tasks. The dict entry is removed in the
@ -3515,6 +3516,14 @@ class HermesCLI:
except Exception:
pass
# Count live background terminal processes (terminal tool background
# sessions tracked by tools.process_registry). Cheap O(1) read.
try:
from tools.process_registry import process_registry
snapshot["active_background_processes"] = process_registry.count_running()
except Exception:
pass
if not agent:
return snapshot
@ -3753,6 +3762,9 @@ class HermesCLI:
bg_count = snapshot.get("active_background_tasks", 0)
if bg_count:
parts.append(f"{bg_count}")
bg_proc_count = snapshot.get("active_background_processes", 0)
if bg_proc_count:
parts.append(f"{bg_proc_count}")
parts.append(duration_label)
if yolo_active:
parts.append("⚠ YOLO")
@ -3772,6 +3784,9 @@ class HermesCLI:
bg_count = snapshot.get("active_background_tasks", 0)
if bg_count:
parts.append(f"{bg_count}")
bg_proc_count = snapshot.get("active_background_processes", 0)
if bg_proc_count:
parts.append(f"{bg_proc_count}")
parts.append(duration_label)
prompt_elapsed = snapshot.get("prompt_elapsed")
if prompt_elapsed:
@ -3813,6 +3828,7 @@ class HermesCLI:
if width < 76:
compressions = snapshot.get("compressions", 0)
bg_count = snapshot.get("active_background_tasks", 0)
bg_proc_count = snapshot.get("active_background_processes", 0)
frags = [
("class:status-bar", ""),
("class:status-bar-strong", snapshot["model_short"]),
@ -3825,6 +3841,9 @@ class HermesCLI:
if bg_count:
frags.append(("class:status-bar-dim", " · "))
frags.append(("class:status-bar-strong", f"{bg_count}"))
if bg_proc_count:
frags.append(("class:status-bar-dim", " · "))
frags.append(("class:status-bar-strong", f"{bg_proc_count}"))
frags.extend([
("class:status-bar-dim", " · "),
("class:status-bar-dim", duration_label),
@ -3844,6 +3863,7 @@ class HermesCLI:
bar_style = self._status_bar_context_style(percent)
compressions = snapshot.get("compressions", 0)
bg_count = snapshot.get("active_background_tasks", 0)
bg_proc_count = snapshot.get("active_background_processes", 0)
frags = [
("class:status-bar", ""),
("class:status-bar-strong", snapshot["model_short"]),
@ -3860,6 +3880,9 @@ class HermesCLI:
if bg_count:
frags.append(("class:status-bar-dim", ""))
frags.append(("class:status-bar-strong", f"{bg_count}"))
if bg_proc_count:
frags.append(("class:status-bar-dim", ""))
frags.append(("class:status-bar-strong", f"{bg_proc_count}"))
frags.extend([
("class:status-bar-dim", ""),
("class:status-bar-dim", duration_label),