@@ -140,7 +140,7 @@ def command_check(ctx: CLIContext) -> int:
140140 entries = _load_metrics (ctx .logs_dir )
141141 metrics_summary = _summarize_metrics (entries )
142142
143- # Get Pro plan usage info with threshold
143+ # Get Pro plan usage info with threshold (only show if usage > 0)
144144 pro_plan_usage_info = ""
145145 try :
146146 from sleepless_agent .monitoring .pro_plan_usage import ProPlanUsageChecker
@@ -149,8 +149,9 @@ def command_check(ctx: CLIContext) -> int:
149149 command = config .claude_code .usage_command ,
150150 )
151151 usage_percent , _ = checker .get_usage ()
152- threshold = config .claude_code .threshold_night if is_nighttime (night_start_hour = config .claude_code .night_start_hour , night_end_hour = config .claude_code .night_end_hour ) else config .claude_code .threshold_day
153- pro_plan_usage_info = f" • Pro Usage: { usage_percent :.0f} % / { threshold :.0f} % limit"
152+ if usage_percent > 0 :
153+ threshold = config .claude_code .threshold_night if is_nighttime (night_start_hour = config .claude_code .night_start_hour , night_end_hour = config .claude_code .night_end_hour ) else config .claude_code .threshold_day
154+ pro_plan_usage_info = f" • Pro Usage: { usage_percent :.0f} % / { threshold :.0f} % limit"
154155 except Exception as exc :
155156 logger .debug (f"Could not fetch Pro plan usage for dashboard: { exc } " )
156157
@@ -172,16 +173,9 @@ def command_check(ctx: CLIContext) -> int:
172173 storage = health .get ("storage" , {})
173174
174175 header_text = Text ()
175- header_text .append (f"{ status_emoji } Sleepless Agent Dashboard\n " , style = "bold bright_magenta" )
176- header_text .append (
177- f"Status: { str (status ).upper ()} • "
178- f"Uptime: { health .get ('uptime_human' , 'N/A' )} • "
179- f"CPU: { system .get ('cpu_percent' , 'N/A' )} % • "
180- f"Memory: { system .get ('memory_percent' , 'N/A' )} % • "
181- f"Queue: { queue_status ['pending' ]} pending / { queue_status ['in_progress' ]} running"
182- f"{ pro_plan_usage_info } " ,
183- style = "dim" ,
184- )
176+ header_text .append (f"{ status_emoji } Sleepless Agent Dashboard" , style = "bold bright_magenta" )
177+ if pro_plan_usage_info :
178+ header_text .append (f"{ pro_plan_usage_info } " , style = "dim" )
185179 header_panel = Panel (Align .center (header_text ), border_style = status_style )
186180
187181 health_table = Table .grid (padding = (0 , 2 ))
@@ -261,134 +255,44 @@ def command_check(ctx: CLIContext) -> int:
261255
262256 metrics_panel = Panel (metrics_table , border_style = "yellow" )
263257
264- live_entries = []
265- try :
266- tracker = LiveStatusTracker (ctx .db_path .parent / "live_status.json" )
267- live_entries = tracker .entries ()
268- except Exception as exc : # pragma: no cover - best effort
269- logger .debug (f"Live status unavailable: { exc } " )
270- live_entries = []
271-
272- live_table = Table (
273- box = box .MINIMAL_DOUBLE_HEAD ,
274- expand = True ,
275- title = f"Live Sessions ({ len (live_entries )} )" ,
276- )
277- live_table .add_column ("Task" , style = "bold" )
278- live_table .add_column ("Phase" , style = "cyan" )
279- live_table .add_column ("Query" , overflow = "fold" )
280- live_table .add_column ("Answer" , overflow = "fold" )
281- live_table .add_column ("Updated" , justify = "right" )
282-
283- for entry in live_entries :
284- updated_dt = _parse_timestamp (entry .updated_at )
285- updated_text = relative_time (updated_dt ) if updated_dt else "—"
286- live_table .add_row (
287- f"#{ entry .task_id } " ,
288- entry .phase .title (),
289- shorten (entry .prompt_preview , limit = 60 ) if entry .prompt_preview else "—" ,
290- shorten (entry .answer_preview , limit = 60 ) if entry .answer_preview else "—" ,
291- updated_text ,
292- )
293-
294- if live_entries :
295- live_panel = Panel (live_table , border_style = "bright_cyan" )
258+ # Live Status: Show daemon and executor info
259+ in_progress_tasks = ctx .task_queue .get_in_progress_tasks ()
260+ workspace_path = Path (config .agent .workspace_root ).resolve ()
261+
262+ # Get last activity from most recent task
263+ recent_for_activity = ctx .task_queue .get_recent_tasks (limit = 1 )
264+ last_activity = None
265+ if recent_for_activity :
266+ task = recent_for_activity [0 ]
267+ last_activity = task .completed_at or task .started_at or task .created_at
268+
269+ live_table = Table .grid (padding = (0 , 2 ))
270+ live_table .add_column (justify = "right" , style = "bold cyan" )
271+ live_table .add_column (justify = "left" )
272+
273+ # Daemon info
274+ daemon_status = "🔄 Running" if in_progress_tasks else "⏸️ Idle"
275+ daemon_status_color = "green" if in_progress_tasks else "yellow"
276+ live_table .add_row ("Daemon Status" , f"[{ daemon_status_color } ]{ daemon_status } [/]" )
277+
278+ if in_progress_tasks :
279+ current_task = in_progress_tasks [0 ]
280+ live_table .add_row ("Current Task" , f"#{ current_task .id } : { shorten (current_task .description , limit = 80 )} " )
281+ if current_task .started_at :
282+ now = datetime .utcnow ()
283+ elapsed = (now - current_task .started_at ).total_seconds ()
284+ live_table .add_row ("Task Runtime" , format_duration (elapsed ))
296285 else :
297- live_panel = Panel (
298- Align .center (Text ("No active Claude sessions." , style = "dim" )),
299- title = "Live Sessions" ,
300- border_style = "bright_cyan" ,
301- )
302-
303- running_tasks = ctx .task_queue .get_in_progress_tasks ()
304- running_table = Table (
305- box = box .MINIMAL_DOUBLE_HEAD ,
306- expand = True ,
307- title = f"Active Tasks ({ len (running_tasks )} )" ,
308- )
309- running_table .add_column ("ID" , style = "bold" )
310- running_table .add_column ("Project" , style = "cyan" )
311- running_table .add_column ("Description" , overflow = "fold" )
312- running_table .add_column ("Owner" )
313- running_table .add_column ("Started" )
314- running_table .add_column ("Elapsed" , justify = "right" )
315-
316- now = datetime .utcnow ()
317- for task in running_tasks :
318- elapsed_str = "—"
319- if task .started_at :
320- elapsed = (now - task .started_at ).total_seconds ()
321- if elapsed < 1800 :
322- elapsed_str = f"[green]{ format_duration (elapsed )} [/]"
323- elif elapsed < 3600 :
324- elapsed_str = f"[yellow]{ format_duration (elapsed )} [/]"
325- else :
326- elapsed_str = f"[red bold]⚠️ { format_duration (elapsed )} [/]"
327- running_table .add_row (
328- str (task .id ),
329- task .project_name or task .project_id or "—" ,
330- shorten (task .description ),
331- task .assigned_to or "—" ,
332- task .started_at .isoformat (sep = " " , timespec = "minutes" ) if task .started_at else "—" ,
333- elapsed_str ,
334- )
286+ live_table .add_row ("Current Task" , "—" )
335287
336- if running_tasks :
337- running_panel = Panel (running_table , border_style = "magenta" )
288+ # Executor info
289+ live_table .add_row ("Active Workspace" , str (workspace_path ))
290+ if last_activity :
291+ live_table .add_row ("Last Activity" , relative_time (last_activity ))
338292 else :
339- running_panel = Panel (
340- Align .center (Text ("No tasks currently running." , style = "dim" )),
341- title = "Active Tasks" ,
342- border_style = "magenta" ,
343- )
293+ live_table .add_row ("Last Activity" , "—" )
344294
345- pending_tasks = ctx .task_queue .get_pending_tasks (limit = 5 )
346- pending_table = Table (
347- box = box .MINIMAL_DOUBLE_HEAD ,
348- expand = True ,
349- title = f"Next Up ({ len (pending_tasks )} shown)" ,
350- )
351- pending_table .add_column ("ID" , style = "bold" )
352- pending_table .add_column ("Priority" )
353- pending_table .add_column ("Project" , style = "cyan" )
354- pending_table .add_column ("Created" )
355- pending_table .add_column ("Age" )
356- pending_table .add_column ("Summary" , overflow = "fold" )
357-
358- for task in pending_tasks :
359- age_seconds = (now - task .created_at ).total_seconds ()
360- age_str = relative_time (task .created_at )
361- if age_seconds < 3600 :
362- age_display = age_str
363- elif age_seconds < 86400 :
364- age_display = f"[yellow]{ age_str } [/]"
365- else :
366- age_display = f"[red bold]⚠️ { age_str } [/]"
367-
368- if task .priority .value == TaskPriority .SERIOUS .value :
369- priority_display = f"[red bold]{ task .priority .value } [/]"
370- elif task .priority .value == TaskPriority .RANDOM .value :
371- priority_display = f"[cyan]{ task .priority .value } [/]"
372- else :
373- priority_display = f"[magenta]{ task .priority .value } [/]"
374-
375- pending_table .add_row (
376- str (task .id ),
377- priority_display ,
378- task .project_name or task .project_id or "—" ,
379- task .created_at .isoformat (sep = " " , timespec = "minutes" ),
380- age_display ,
381- shorten (task .description ),
382- )
383-
384- if pending_tasks :
385- pending_panel = Panel (pending_table , border_style = "green" )
386- else :
387- pending_panel = Panel (
388- Align .center (Text ("Queue is clear. 🎉" , style = "dim" )),
389- title = "Next Up" ,
390- border_style = "green" ,
391- )
295+ live_panel = Panel (live_table , title = "Live Status" , border_style = "bright_cyan" )
392296
393297 projects = ctx .task_queue .get_projects ()
394298 project_panel = None
@@ -414,28 +318,69 @@ def command_check(ctx: CLIContext) -> int:
414318 )
415319 project_panel = Panel (project_table , border_style = "bright_blue" )
416320
321+ # Adaptive Details panel: show errors if present, otherwise recent tasks
417322 failed_tasks = ctx .task_queue .get_failed_tasks (limit = 5 )
418- errors_panel = None
323+ details_panel = None
419324 if failed_tasks :
420- errors_table = Table (
421- title = f"Recent Errors ({ len (failed_tasks )} )" ,
422- box = box .SIMPLE_HEAVY ,
325+ # Show errors
326+ details_table = Table (
327+ title = f"Details (Errors: { len (failed_tasks )} )" ,
328+ box = box .MINIMAL_DOUBLE_HEAD ,
423329 expand = True ,
424330 )
425- errors_table .add_column ("ID" , style = "bold red" )
426- errors_table .add_column ("When" , style = "dim" )
427- errors_table .add_column ("Task" , overflow = "fold" )
428- errors_table .add_column ("Error" , overflow = "fold" , style = "red" )
331+ details_table .add_column ("ID" , style = "bold red" )
332+ details_table .add_column ("When" , style = "dim" )
333+ details_table .add_column ("Task" , overflow = "fold" )
334+ details_table .add_column ("Error" , overflow = "fold" , style = "red" )
429335
430336 for task in failed_tasks :
431- error_preview = shorten (task .error_message , limit = 50 ) if task .error_message else "Unknown error"
432- errors_table .add_row (
337+ error_preview = shorten (task .error_message , limit = 100 ) if task .error_message else "Unknown error"
338+ details_table .add_row (
433339 str (task .id ),
434340 relative_time (task .created_at ),
435- shorten (task .description , limit = 40 ),
341+ shorten (task .description , limit = 80 ),
436342 error_preview ,
437343 )
438- errors_panel = Panel (errors_table , border_style = "red" )
344+ details_panel = Panel (details_table , border_style = "red" )
345+ else :
346+ # Show recent tasks (any status)
347+ detail_tasks = ctx .task_queue .get_recent_tasks (limit = 5 )
348+ if detail_tasks :
349+ details_table = Table (
350+ title = f"Details (Recent: { len (detail_tasks )} )" ,
351+ box = box .MINIMAL_DOUBLE_HEAD ,
352+ expand = True ,
353+ )
354+ details_table .add_column ("ID" , style = "bold" )
355+ details_table .add_column ("Status" )
356+ details_table .add_column ("When" , style = "dim" )
357+ details_table .add_column ("Task" , overflow = "fold" )
358+
359+ status_icons = {
360+ TaskStatus .COMPLETED : "✅" ,
361+ TaskStatus .IN_PROGRESS : "🔄" ,
362+ TaskStatus .PENDING : "🕒" ,
363+ TaskStatus .FAILED : "❌" ,
364+ TaskStatus .CANCELLED : "🗑️" ,
365+ }
366+ status_colors = {
367+ TaskStatus .COMPLETED : "green" ,
368+ TaskStatus .IN_PROGRESS : "cyan" ,
369+ TaskStatus .PENDING : "yellow" ,
370+ TaskStatus .FAILED : "red" ,
371+ TaskStatus .CANCELLED : "dim" ,
372+ }
373+
374+ for task in detail_tasks :
375+ icon = status_icons .get (task .status , "•" )
376+ status_color = status_colors .get (task .status , "white" )
377+ details_table .add_row (
378+ str (task .id ),
379+ f"[{ status_color } ]{ icon } { task .status .value } [/]" ,
380+ relative_time (task .created_at ),
381+ shorten (task .description , limit = 100 ),
382+ )
383+ details_panel = Panel (details_table , border_style = "blue" )
439384
440385 recent_tasks = ctx .task_queue .get_recent_tasks (limit = 8 )
441386 status_icons = {
@@ -447,7 +392,7 @@ def command_check(ctx: CLIContext) -> int:
447392 }
448393 recent_table = Table (
449394 title = "Recent Activity" ,
450- box = box .SIMPLE_HEAVY ,
395+ box = box .MINIMAL_DOUBLE_HEAD ,
451396 expand = True ,
452397 )
453398 recent_table .add_column ("ID" , style = "bold" )
@@ -499,10 +444,9 @@ def command_check(ctx: CLIContext) -> int:
499444 # Create hierarchical layout with regions
500445 layout = Layout (name = "root" )
501446 layout .split_column (
502- Layout (name = "header" , size = 5 ),
503- Layout (name = "top_section" , size = 10 ),
504- Layout (name = "middle_section" , size = 12 ),
505- Layout (name = "tasks_section" ),
447+ Layout (name = "header" , size = 3 ),
448+ Layout (name = "top_section" , size = 8 ),
449+ Layout (name = "middle_section" , size = 10 ),
506450 )
507451
508452 layout ["header" ].update (header_panel )
@@ -528,13 +472,9 @@ def command_check(ctx: CLIContext) -> int:
528472 # Print tasks panels sequentially (auto-sized by Rich, no truncation)
529473 console .print ()
530474 console .print (live_panel )
531- console .print ()
532- console .print (running_panel )
533- console .print ()
534- console .print (pending_panel )
535- if errors_panel :
475+ if details_panel :
536476 console .print ()
537- console .print (errors_panel )
477+ console .print (details_panel )
538478 if project_panel :
539479 console .print ()
540480 console .print (project_panel )
0 commit comments