3939
4040from bernstein .cli .icons import get_agent_icon , get_icons , get_status_icon
4141from bernstein .cli .visual_theme import PALETTE , budget_color , model_color , role_color , sample_gradient , status_color
42+ from bernstein .tui .crt_shader import CRTMode , CRTShader
43+ from bernstein .tui .oscilloscope import OscilloscopeWidget
44+ from bernstein .tui .plasma import PlasmaCanvas
45+ from bernstein .tui .tracker_view import TrackerView
4246
4347logger = logging .getLogger (__name__ )
4448
@@ -1367,6 +1371,23 @@ class BernsteinApp(App[None]):
13671371 overflow-y: auto;
13681372 border-right: heavy $border;
13691373 }
1374+
1375+ #retro-bar {
1376+ height: auto;
1377+ max-height: 20;
1378+ }
1379+
1380+ #plasma-canvas {
1381+ height: 12;
1382+ }
1383+
1384+ #tracker-view {
1385+ height: 16;
1386+ }
1387+
1388+ #oscilloscope {
1389+ height: 16;
1390+ }
13701391 """
13711392
13721393 #: Resize debounce delay in seconds (TUI-001).
@@ -1385,6 +1406,10 @@ class BernsteinApp(App[None]):
13851406 Binding ("d" , "compare_task" , "Diff" ),
13861407 Binding ("v" , "compare_task" , "Diff" , show = False ),
13871408 Binding ("i" , "inspect_task" , "Open" , show = False ),
1409+ Binding ("C" , "toggle_crt" , "CRT" ),
1410+ Binding ("P" , "toggle_plasma" , "Plasma" ),
1411+ Binding ("T" , "toggle_tracker" , "Tracker" ),
1412+ Binding ("O" , "toggle_scope" , "Scope" ),
13881413 ]
13891414
13901415 def __init__ (self , ** kw : Any ) -> None :
@@ -1403,6 +1428,7 @@ def __init__(self, **kw: Any) -> None:
14031428 self ._last_activity : list [str ] = []
14041429 self ._compare_mark : str | None = None # first task ID for compare
14051430 self ._resize_timer : object | None = None # debounce timer handle (TUI-001)
1431+ self ._crt_shader = CRTShader (CRTMode .OFF )
14061432
14071433 def compose (self ) -> ComposeResult :
14081434 yield DashboardHeader (id = "header-bar" )
@@ -1416,6 +1442,10 @@ def compose(self) -> ComposeResult:
14161442 with Vertical (id = "activity-bar" ):
14171443 yield Static ("ACTIVITY" , classes = "col-header" )
14181444 yield RichLog (id = "activity-log" , wrap = True , markup = True , auto_scroll = True )
1445+ with Vertical (id = "retro-bar" ):
1446+ yield PlasmaCanvas (id = "plasma-canvas" )
1447+ yield TrackerView (id = "tracker-view" )
1448+ yield OscilloscopeWidget (id = "oscilloscope" )
14191449 with Horizontal (id = "expert-row" ):
14201450 yield ExpertCostPanel (id = "expert-cost" )
14211451 yield ExpertBanditPanel (id = "expert-bandit" )
@@ -1477,6 +1507,9 @@ def on_mount(self) -> None:
14771507 except Exception as exc :
14781508 logger .warning ("Failed to read evolve.json: %s" , exc )
14791509
1510+ # Retro-demoscene widgets hidden by default (toggled via keybindings)
1511+ self .query_one ("#retro-bar" ).display = False
1512+
14801513 # Write startup messages to activity log
14811514 log = self .query_one ("#activity-log" , RichLog )
14821515 log .write (_format_activity_line ("system" , "Bernstein starting..." ))
@@ -1529,6 +1562,7 @@ def _check_agents_file(self) -> None:
15291562 costs : dict [str , Any ] = {}
15301563 self ._update_agents (agents , costs )
15311564 self ._update_activity (agents )
1565+ self ._update_retro_widgets (agents )
15321566 except Exception :
15331567 pass
15341568
@@ -1644,6 +1678,7 @@ def _apply_data(self, data: dict[str, Any]) -> None:
16441678 }
16451679 self ._update_stats (data .get ("status" ), tasks , data .get ("agents" , []), costs , monitoring )
16461680 self ._update_activity (data .get ("agents" , []))
1681+ self ._update_retro_widgets (data .get ("agents" , []))
16471682
16481683 # -- Agents --
16491684
@@ -2223,6 +2258,66 @@ def action_toggle_expert(self) -> None:
22232258 else :
22242259 self .notify ("Novice mode [e] to toggle on" , severity = "information" , timeout = 3 )
22252260
2261+ def action_toggle_crt (self ) -> None :
2262+ """Cycle CRT phosphor shader mode."""
2263+ mode = self ._crt_shader .cycle_mode ()
2264+ self .notify (f"CRT: { mode .value } " , timeout = 2 )
2265+
2266+ def action_toggle_plasma (self ) -> None :
2267+ """Show/hide the demoscene plasma canvas."""
2268+ retro = self .query_one ("#retro-bar" )
2269+ plasma = self .query_one ("#plasma-canvas" , PlasmaCanvas )
2270+ plasma .display = not plasma .display
2271+ # Show retro bar if any retro widget is visible
2272+ retro .display = (
2273+ plasma .display
2274+ or self .query_one ("#tracker-view" , TrackerView ).display
2275+ or self .query_one ("#oscilloscope" , OscilloscopeWidget ).display
2276+ )
2277+
2278+ def action_toggle_tracker (self ) -> None :
2279+ """Show/hide the tracker-style task monitor."""
2280+ retro = self .query_one ("#retro-bar" )
2281+ tracker = self .query_one ("#tracker-view" , TrackerView )
2282+ tracker .display = not tracker .display
2283+ retro .display = (
2284+ self .query_one ("#plasma-canvas" , PlasmaCanvas ).display
2285+ or tracker .display
2286+ or self .query_one ("#oscilloscope" , OscilloscopeWidget ).display
2287+ )
2288+
2289+ def action_toggle_scope (self ) -> None :
2290+ """Show/hide the braille oscilloscope."""
2291+ retro = self .query_one ("#retro-bar" )
2292+ scope = self .query_one ("#oscilloscope" , OscilloscopeWidget )
2293+ scope .display = not scope .display
2294+ retro .display = (
2295+ self .query_one ("#plasma-canvas" , PlasmaCanvas ).display
2296+ or self .query_one ("#tracker-view" , TrackerView ).display
2297+ or scope .display
2298+ )
2299+
2300+ def _update_retro_widgets (self , agents : list [dict [str , Any ]]) -> None :
2301+ """Feed agent data to retro-demoscene widgets."""
2302+ plasma = self .query_one ("#plasma-canvas" , PlasmaCanvas )
2303+ if plasma .display :
2304+ plasma .update_activity (len (agents ))
2305+
2306+ tracker = self .query_one ("#tracker-view" , TrackerView )
2307+ if tracker .display :
2308+ tracker .update_agents (agents )
2309+
2310+ scope = self .query_one ("#oscilloscope" , OscilloscopeWidget )
2311+ if scope .display :
2312+ scope .update_agents (agents )
2313+ samples : dict [str , float ] = {}
2314+ for a in agents :
2315+ sid = a .get ("session_id" , a .get ("id" , "" ))
2316+ if sid :
2317+ samples [sid ] = a .get ("tokens_per_sec" , 0.0 )
2318+ if samples :
2319+ scope .add_samples (samples )
2320+
22262321 def action_stop_bernstein (self ) -> None :
22272322 """Backward-compatible stop -- delegates to drain."""
22282323 self .action_graceful_quit ()
0 commit comments