Skip to main content

ghostscope_ui/components/app/
runtime_status.rs

1use super::App;
2use crate::action::Action;
3use crate::components::loading::LoadingState;
4
5impl App {
6    pub fn add_module_to_loading(&mut self, module_path: String) {
7        self.state.loading_ui.progress.add_module(module_path);
8    }
9
10    /// Start loading a specific module
11    pub fn start_module_loading(&mut self, module_path: &str) {
12        self.state
13            .loading_ui
14            .progress
15            .start_module_loading(module_path);
16    }
17
18    /// Complete loading of a module with stats
19    pub fn complete_module_loading(
20        &mut self,
21        module_path: &str,
22        functions: usize,
23        variables: usize,
24        types: usize,
25    ) {
26        use crate::components::loading::ModuleStats;
27        let stats = ModuleStats {
28            functions,
29            variables,
30            types,
31            debug_source: "unknown".to_string(),
32            debug_source_path: None,
33        };
34        self.state
35            .loading_ui
36            .progress
37            .complete_module(module_path, stats);
38    }
39
40    /// Fail loading of a module
41    pub fn fail_module_loading(&mut self, module_path: &str, error: String) {
42        self.state
43            .loading_ui
44            .progress
45            .fail_module(module_path, error);
46    }
47
48    /// Set target PID for display
49    pub fn set_target_pid(&mut self, pid: u32) {
50        self.state.target_pid = Some(pid);
51    }
52
53    /// Transition to ready state with completion summary (after successful loading)
54    pub fn transition_to_ready_with_completion(&mut self) {
55        self.add_loading_completion_summary();
56        self.state.set_loading_state(LoadingState::Ready);
57    }
58
59    /// Sync file list to command panel for file completion
60    fn sync_files_to_command_panel(&mut self, files: Vec<String>) {
61        tracing::debug!(
62            "Syncing {} files to command panel completion cache",
63            files.len()
64        );
65        if !files.is_empty() {
66            tracing::debug!(
67                "First 5 files: {:?}",
68                files.iter().take(5).collect::<Vec<_>>()
69            );
70        }
71
72        // Create or update file completion cache
73        if let Some(cache) = &mut self.state.command_panel.file_completion_cache {
74            // Update existing cache
75            let updated = cache.sync_from_source_panel(&files);
76            tracing::debug!("Updated existing file completion cache: {}", updated);
77        } else {
78            // Create new cache only if there are files
79            if !files.is_empty() {
80                tracing::debug!(
81                    "Creating new file completion cache with {} files",
82                    files.len()
83                );
84                self.state.command_panel.file_completion_cache = Some(
85                    crate::components::command_panel::file_completion::FileCompletionCache::new(
86                        &files,
87                    ),
88                );
89                tracing::debug!("File completion cache created successfully");
90            } else {
91                tracing::debug!("No files to create cache with");
92            }
93        }
94    }
95
96    /// Generate and add completion summary to command panel
97    pub fn add_loading_completion_summary(&mut self) {
98        let total_time = self.state.loading_ui.progress.elapsed_time();
99
100        // Get styled welcome message lines
101        let mut styled_lines = self.state.loading_ui.create_welcome_message(total_time);
102
103        // Add process-specific information if available
104        if let Some(pid) = self.state.target_pid {
105            use ratatui::style::{Color, Style};
106            use ratatui::text::{Line, Span};
107
108            // Insert process info after the DWARF statistics line
109            let mut enhanced_lines = Vec::new();
110            let mut found_dwarf_stats = false;
111            for line in styled_lines {
112                enhanced_lines.push(line.clone());
113                // Look for the DWARF statistics line (contains "indexed")
114                let line_text: String = line
115                    .spans
116                    .iter()
117                    .map(|span| span.content.as_ref())
118                    .collect();
119                if !found_dwarf_stats && line_text.starts_with("•") && line_text.contains("indexed")
120                {
121                    found_dwarf_stats = true;
122                    enhanced_lines.push(Line::from("")); // Empty line
123                    enhanced_lines.push(Line::from(Span::styled(
124                        format!("Attached to process {pid}"),
125                        Style::default().fg(Color::White),
126                    )));
127                    // TODO: Add process name when available
128                }
129            }
130            styled_lines = enhanced_lines;
131        }
132
133        // Removed complex mapping - now using direct styled content approach
134
135        // Use new simplified direct styled approach
136        let action = Action::AddStyledWelcomeMessage {
137            styled_lines,
138            response_type: crate::action::ResponseType::Info,
139        };
140        if let Err(e) = self.handle_action(action) {
141            tracing::error!("Failed to add completion summary: {}", e);
142        }
143    }
144
145    pub(super) async fn handle_runtime_status(&mut self, status: crate::events::RuntimeStatus) {
146        use crate::components::loading::LoadingState;
147        use crate::events::RuntimeStatus;
148
149        // Update loading state based on runtime status
150        match &status {
151            RuntimeStatus::DwarfLoadingStarted => {
152                self.state.set_loading_state(LoadingState::LoadingSymbols {
153                    progress: Some(0.0),
154                });
155            }
156            RuntimeStatus::DwarfLoadingCompleted { .. } => {
157                if self.state.ui.config.show_source_panel {
158                    self.state
159                        .set_loading_state(LoadingState::LoadingSourceCode);
160                } else {
161                    // If source panel is disabled, we're effectively ready after symbols
162                    self.transition_to_ready_with_completion();
163                    // But we still need file info to power command panel completion/search
164                    tracing::debug!(
165                        "Source panel hidden on startup; requesting file list for completion cache"
166                    );
167                    if let Err(e) = self
168                        .state
169                        .event_registry
170                        .command_sender
171                        .send(crate::events::RuntimeCommand::InfoSource)
172                    {
173                        tracing::warn!("Failed to auto-request file list: {}", e);
174                    }
175                }
176            }
177            RuntimeStatus::DwarfLoadingFailed(error) => {
178                self.state
179                    .set_loading_state(LoadingState::Failed(error.clone()));
180            }
181            // Module-level progress handling
182            RuntimeStatus::DwarfModuleDiscovered {
183                module_path,
184                total_modules: _,
185            } => {
186                // Add module to progress tracking
187                self.state
188                    .loading_ui
189                    .progress
190                    .add_module(module_path.clone());
191            }
192            RuntimeStatus::DwarfModuleLoadingStarted {
193                module_path,
194                current,
195                total,
196            } => {
197                // Start loading specific module
198                self.state
199                    .loading_ui
200                    .progress
201                    .start_module_loading(module_path);
202                // Update overall progress based on current/total
203                let progress = (*current as f64) / (*total as f64);
204                self.state.set_loading_state(LoadingState::LoadingSymbols {
205                    progress: Some(progress),
206                });
207            }
208            RuntimeStatus::DwarfModuleLoadingCompleted {
209                module_path,
210                stats,
211                current,
212                total,
213            } => {
214                // Complete module loading with stats
215                let module_stats = crate::components::loading::ModuleStats {
216                    functions: stats.functions,
217                    variables: stats.variables,
218                    types: stats.types,
219                    debug_source: stats.debug_source.clone(),
220                    debug_source_path: stats.debug_source_path.clone(),
221                };
222                self.state
223                    .loading_ui
224                    .progress
225                    .complete_module(module_path, module_stats);
226                // Update overall progress
227                let progress = (*current as f64) / (*total as f64);
228                self.state.set_loading_state(LoadingState::LoadingSymbols {
229                    progress: Some(progress),
230                });
231            }
232            RuntimeStatus::DwarfModuleLoadingFailed {
233                module_path,
234                error,
235                current: _,
236                total: _,
237            } => {
238                // Mark module as failed
239                self.state
240                    .loading_ui
241                    .progress
242                    .fail_module(module_path, error.clone());
243            }
244            RuntimeStatus::SourceCodeLoaded(_) => {
245                // Transition to ready state with completion summary
246                self.transition_to_ready_with_completion();
247            }
248            RuntimeStatus::SourceCodeLoadFailed(error) => {
249                self.state
250                    .set_loading_state(LoadingState::Failed(error.clone()));
251
252                // Also display the error in the source panel
253                crate::components::source_panel::SourceNavigation::show_error_message(
254                    &mut self.state.source_panel,
255                    error.clone(),
256                );
257            }
258            _ => {
259                // For other status messages, if we're still initializing, move to connecting state
260                if matches!(self.state.loading_state, LoadingState::Initializing) {
261                    self.state
262                        .set_loading_state(LoadingState::ConnectingToRuntime);
263                }
264            }
265        }
266
267        match status {
268            RuntimeStatus::SourceCodeLoaded(source_info) => {
269                // Load source code into source panel
270                let actions = crate::components::source_panel::SourceNavigation::load_source(
271                    &mut self.state.source_panel,
272                    source_info.file_path,
273                    source_info.current_line,
274                );
275                for action in actions {
276                    let _ = self.handle_action(action);
277                }
278
279                // Auto-request file list for both file completion and source panel search
280                tracing::debug!("Auto-requesting file list after source code loaded");
281                if let Err(e) = self
282                    .state
283                    .event_registry
284                    .command_sender
285                    .send(crate::events::RuntimeCommand::InfoSource)
286                {
287                    tracing::warn!("Failed to auto-request file list: {}", e);
288                }
289            }
290            RuntimeStatus::FileInfo { groups } => {
291                // Convert file groups to flat file list
292                let mut files = Vec::new();
293                for group in &groups {
294                    for file in &group.files {
295                        // Combine directory and filename for full path
296                        let full_path = if file.directory.is_empty() {
297                            file.path.clone()
298                        } else {
299                            format!("{}/{}", file.directory, file.path)
300                        };
301                        files.push(full_path);
302                    }
303                }
304
305                // Always sync file list to command panel first
306                self.sync_files_to_command_panel(files.clone());
307
308                if self.state.route_file_info_to_file_search {
309                    // Route to source panel file search
310                    if let Some(ref mut cache) = self.state.command_panel.file_completion_cache {
311                        let actions =
312                            crate::components::source_panel::SourceSearch::set_file_search_files(
313                                &mut self.state.source_panel,
314                                cache,
315                                files.clone(),
316                            );
317                        for action in actions {
318                            let _ = self.handle_action(action);
319                        }
320                    }
321
322                    // Reset routing flag
323                    self.state.route_file_info_to_file_search = false;
324                } else {
325                    // Handle as command response (display in command panel)
326                    self.clear_waiting_state();
327                    let response =
328                        crate::components::command_panel::ResponseFormatter::format_file_info(
329                            &groups, false,
330                        );
331                    let styled_lines = crate::components::command_panel::ResponseFormatter::format_file_info_styled(
332                        &groups, false,
333                    );
334                    let action = Action::AddResponseWithStyle {
335                        content: response,
336                        styled_lines: Some(styled_lines),
337                        response_type: crate::action::ResponseType::Info,
338                    };
339                    let _ = self.handle_action(action);
340                }
341            }
342            RuntimeStatus::FileInfoFailed { error } => {
343                if self.state.route_file_info_to_file_search {
344                    let actions =
345                        crate::components::source_panel::SourceSearch::set_file_search_error(
346                            &mut self.state.source_panel,
347                            error,
348                        );
349                    for action in actions {
350                        let _ = self.handle_action(action);
351                    }
352                    self.state.route_file_info_to_file_search = false;
353                } else {
354                    self.clear_waiting_state();
355                    let plain = format!("✗ Failed to get file information: {error}");
356                    let styled = vec![
357                        crate::components::command_panel::style_builder::StyledLineBuilder::new()
358                            .styled(plain.clone(), crate::components::command_panel::style_builder::StylePresets::ERROR)
359                            .build(),
360                    ];
361                    let action = Action::AddResponseWithStyle {
362                        content: plain,
363                        styled_lines: Some(styled),
364                        response_type: crate::action::ResponseType::Error,
365                    };
366                    let _ = self.handle_action(action);
367                }
368            }
369            RuntimeStatus::InfoFunctionResult {
370                target: _,
371                info,
372                verbose,
373            } => {
374                // Mark command as completed
375                self.clear_waiting_state();
376                // Format and display function debug info
377                let formatted_info = info.format_for_display(verbose);
378                let styled_lines = info.format_for_display_styled(verbose);
379                let action = Action::AddResponseWithStyle {
380                    content: formatted_info,
381                    styled_lines: Some(styled_lines),
382                    response_type: crate::action::ResponseType::Success,
383                };
384                let _ = self.handle_action(action);
385            }
386            RuntimeStatus::InfoFunctionFailed { target, error } => {
387                self.clear_waiting_state();
388                let text = format!("✗ Failed to get debug info for function '{target}': {error}");
389                let styled = crate::components::command_panel::ResponseFormatter::style_generic_message_lines(&text);
390                let action = Action::AddResponseWithStyle {
391                    content: text,
392                    styled_lines: Some(styled),
393                    response_type: crate::action::ResponseType::Error,
394                };
395                let _ = self.handle_action(action);
396            }
397            RuntimeStatus::InfoLineResult {
398                target: _,
399                info,
400                verbose,
401            } => {
402                // Mark command as completed
403                self.clear_waiting_state();
404                // Format and display line debug info
405                let formatted_info = info.format_for_display(verbose);
406                let styled_lines = info.format_for_display_styled(verbose);
407                let action = Action::AddResponseWithStyle {
408                    content: formatted_info,
409                    styled_lines: Some(styled_lines),
410                    response_type: crate::action::ResponseType::Success,
411                };
412                let _ = self.handle_action(action);
413            }
414            RuntimeStatus::InfoLineFailed { target, error } => {
415                self.clear_waiting_state();
416                let text = format!("✗ Failed to get debug info for line '{target}': {error}");
417                let styled = crate::components::command_panel::ResponseFormatter::style_generic_message_lines(&text);
418                let action = Action::AddResponseWithStyle {
419                    content: text,
420                    styled_lines: Some(styled),
421                    response_type: crate::action::ResponseType::Error,
422                };
423                let _ = self.handle_action(action);
424            }
425            RuntimeStatus::InfoAddressResult {
426                target: _,
427                info,
428                verbose,
429            } => {
430                // Mark command as completed
431                self.clear_waiting_state();
432                // Format and display address debug info
433                let formatted_info = info.format_for_display(verbose);
434                let styled_lines = info.format_for_display_styled(verbose);
435                let action = Action::AddResponseWithStyle {
436                    content: formatted_info,
437                    styled_lines: Some(styled_lines),
438                    response_type: crate::action::ResponseType::Success,
439                };
440                let _ = self.handle_action(action);
441            }
442            RuntimeStatus::InfoAddressFailed { target, error } => {
443                self.clear_waiting_state();
444                let text = format!("✗ Failed to get debug info for address '{target}': {error}");
445                let styled = crate::components::command_panel::ResponseFormatter::style_generic_message_lines(&text);
446                let action = Action::AddResponseWithStyle {
447                    content: text,
448                    styled_lines: Some(styled),
449                    response_type: crate::action::ResponseType::Error,
450                };
451                let _ = self.handle_action(action);
452            }
453            RuntimeStatus::ShareInfo { libraries } => {
454                // Determine whether to show all libraries or only those with debug info
455                let show_all = matches!(
456                    self.state.command_panel.input_state,
457                    crate::model::panel_state::InputState::WaitingResponse {
458                        command_type: crate::model::panel_state::CommandType::InfoShareAll,
459                        ..
460                    }
461                );
462
463                self.clear_waiting_state();
464
465                let total = libraries.len();
466                let display_libs: Vec<_> = if show_all {
467                    libraries
468                } else {
469                    libraries
470                        .into_iter()
471                        .filter(|l| l.debug_info_available)
472                        .collect()
473                };
474
475                // If filtering removed all entries, avoid misleading "No shared libraries" message
476                if !show_all && display_libs.is_empty() && total > 0 {
477                    let content = format!(
478                        "📚 Shared Libraries ({total} total)\n\n⚠️  No libraries with debug info found. Use 'info share all' to view all libraries."
479                    );
480                    let styled = crate::components::command_panel::ResponseFormatter::style_generic_message_lines(&content);
481                    let action = Action::AddResponseWithStyle {
482                        content,
483                        styled_lines: Some(styled),
484                        response_type: crate::action::ResponseType::Success,
485                    };
486                    let _ = self.handle_action(action);
487                } else {
488                    let formatted_info =
489                        crate::components::command_panel::ResponseFormatter::format_shared_library_info(
490                            &display_libs, false,
491                        );
492                    let styled_lines =
493                        crate::components::command_panel::ResponseFormatter::format_shared_library_info_styled(
494                            &display_libs,
495                            false,
496                        );
497                    let action = Action::AddResponseWithStyle {
498                        content: formatted_info,
499                        styled_lines: Some(styled_lines),
500                        response_type: crate::action::ResponseType::Success,
501                    };
502                    let _ = self.handle_action(action);
503                }
504            }
505            RuntimeStatus::ShareInfoFailed { error } => {
506                self.clear_waiting_state();
507                let text = format!("✗ Failed to get shared library information: {error}");
508                let styled = crate::components::command_panel::ResponseFormatter::style_generic_message_lines(&text);
509                let action = Action::AddResponseWithStyle {
510                    content: text,
511                    styled_lines: Some(styled),
512                    response_type: crate::action::ResponseType::Error,
513                };
514                let _ = self.handle_action(action);
515            }
516            RuntimeStatus::ExecutableFileInfo {
517                file_path,
518                file_type,
519                entry_point,
520                has_symbols,
521                has_debug_info,
522                debug_file_path,
523                text_section,
524                data_section,
525                mode_description,
526            } => {
527                self.clear_waiting_state();
528                let info_display =
529                    crate::components::command_panel::response_formatter::ExecutableFileInfoDisplay {
530                        file_path: &file_path,
531                        file_type: &file_type,
532                        entry_point,
533                        has_symbols,
534                        has_debug_info,
535                        debug_file_path: &debug_file_path,
536                        text_section: &text_section,
537                        data_section: &data_section,
538                        mode_description: &mode_description,
539                    };
540                let formatted_info =
541                    crate::components::command_panel::ResponseFormatter::format_executable_file_info(
542                        &info_display,
543                    );
544                let styled_lines =
545                    crate::components::command_panel::ResponseFormatter::format_executable_file_info_styled(
546                        &info_display,
547                    );
548                let action = Action::AddResponseWithStyle {
549                    content: formatted_info,
550                    styled_lines: Some(styled_lines),
551                    response_type: crate::action::ResponseType::Success,
552                };
553                let _ = self.handle_action(action);
554            }
555            RuntimeStatus::ExecutableFileInfoFailed { error } => {
556                self.clear_waiting_state();
557                let text = format!("✗ Failed to get executable file information: {error}");
558                let styled = crate::components::command_panel::ResponseFormatter::style_generic_message_lines(&text);
559                let action = Action::AddResponseWithStyle {
560                    content: text,
561                    styled_lines: Some(styled),
562                    response_type: crate::action::ResponseType::Error,
563                };
564                let _ = self.handle_action(action);
565            }
566            RuntimeStatus::SrcPathInfo { info } => {
567                self.clear_waiting_state();
568                let formatted = info.format_for_display();
569                let styled_lines = info.format_for_display_styled();
570                let action = Action::AddResponseWithStyle {
571                    content: formatted,
572                    styled_lines: Some(styled_lines),
573                    response_type: crate::action::ResponseType::Info,
574                };
575                let _ = self.handle_action(action);
576            }
577            RuntimeStatus::SrcPathUpdated { message } => {
578                self.clear_waiting_state();
579
580                // Set flag to route upcoming FileInfo to file search panel
581                // This ensures file search list is updated with new path mappings
582                self.state.route_file_info_to_file_search = true;
583
584                let plain = format!("✅ {message}\n💡 Source code and file list reloading...");
585                let styled = vec![
586                    crate::components::command_panel::style_builder::StyledLineBuilder::new()
587                        .styled(
588                            format!("✅ {message}"),
589                            crate::components::command_panel::style_builder::StylePresets::SUCCESS,
590                        )
591                        .build(),
592                    crate::components::command_panel::style_builder::StyledLineBuilder::new()
593                        .styled(
594                            "💡 Source code and file list reloading...",
595                            crate::components::command_panel::style_builder::StylePresets::TIP,
596                        )
597                        .build(),
598                ];
599                let action = Action::AddResponseWithStyle {
600                    content: plain,
601                    styled_lines: Some(styled),
602                    response_type: crate::action::ResponseType::Success,
603                };
604                let _ = self.handle_action(action);
605            }
606            RuntimeStatus::SrcPathFailed { error } => {
607                self.clear_waiting_state();
608                let text = format!(
609                    "✗ {error}\n\n📘 No source available? You can hide the Source panel:\n  ui source off            # in UI command mode\n  --no-source-panel        # CLI flag\n  [ui].show_source_panel=false  # in config.toml"
610                );
611                let styled = crate::components::command_panel::ResponseFormatter::style_generic_message_lines(&text);
612                let action = Action::AddResponseWithStyle {
613                    content: text,
614                    styled_lines: Some(styled),
615                    response_type: crate::action::ResponseType::Error,
616                };
617                let _ = self.handle_action(action);
618            }
619            RuntimeStatus::TraceInfo {
620                trace_id,
621                target,
622                status,
623                pid,
624                host_pid,
625                binary,
626                script_preview,
627                pc,
628            } => {
629                self.clear_waiting_state();
630
631                // Extract source location from target (could be "file:line" or "function_name")
632                // TODO: For function traces, we need source_file and source_line fields in TraceInfo
633                // Currently only file:line format works for source panel updates
634                if let Some(colon_pos) = target.rfind(':') {
635                    let file_part = &target[..colon_pos];
636                    if let Ok(line_num) = target[colon_pos + 1..].parse::<usize>() {
637                        // Store the trace location
638                        self.state
639                            .source_panel
640                            .trace_locations
641                            .insert(trace_id, (file_part.to_string(), line_num));
642
643                        // Update line colors if this is the current file
644                        if self.state.source_panel.file_path.as_ref()
645                            == Some(&file_part.to_string())
646                        {
647                            // Clear pending status if it exists
648                            if self.state.source_panel.pending_trace_line == Some(line_num) {
649                                self.state.source_panel.pending_trace_line = None;
650                            }
651
652                            // Update line color based on trace status
653                            match status {
654                                crate::events::TraceStatus::Active => {
655                                    self.state.source_panel.disabled_lines.remove(&line_num);
656                                    self.state.source_panel.traced_lines.insert(line_num);
657                                }
658                                crate::events::TraceStatus::Disabled => {
659                                    self.state.source_panel.traced_lines.remove(&line_num);
660                                    self.state.source_panel.disabled_lines.insert(line_num);
661                                }
662                                _ => {
663                                    // For other statuses, don't color the line
664                                    self.state.source_panel.traced_lines.remove(&line_num);
665                                    self.state.source_panel.disabled_lines.remove(&line_num);
666                                }
667                            }
668                        }
669                    }
670                }
671
672                // Format trace info with enhanced display
673                let mut response = format!("🔍 Trace {trace_id} Info:\n");
674                response.push_str(&format!("  Target: {target}\n"));
675                response.push_str(&format!("  Status: {status}\n"));
676                response.push_str(&format!("  Binary: {binary}\n"));
677                response.push_str(&format!("  PC: 0x{pc:x}\n"));
678                match (pid, host_pid) {
679                    (Some(proc_pid), Some(host_pid_val)) if proc_pid != host_pid_val => {
680                        response.push_str(&format!("  PID(proc): {proc_pid}\n"));
681                        response.push_str(&format!("  PID(host): {host_pid_val}\n"));
682                    }
683                    (Some(proc_pid), _) => {
684                        response.push_str(&format!("  PID: {proc_pid}\n"));
685                    }
686                    (None, Some(host_pid_val)) => {
687                        response.push_str(&format!("  PID(host): {host_pid_val}\n"));
688                    }
689                    (None, None) => {}
690                }
691                if let Some(ref preview) = script_preview {
692                    response.push_str(&format!("  Script:\n{preview}\n"));
693                }
694                // Also create styled version
695                let styled_lines = {
696                    let temp = crate::events::RuntimeStatus::TraceInfo {
697                        trace_id,
698                        target: target.clone(),
699                        status: status.clone(),
700                        pid,
701                        host_pid,
702                        binary: binary.clone(),
703                        script_preview: None,
704                        pc,
705                    };
706                    if let Some(mut base) = temp.format_trace_info_styled() {
707                        if let Some(ref preview) = script_preview {
708                            use crate::components::command_panel::style_builder::StyledLineBuilder;
709                            use ratatui::text::Line;
710                            base.push(Line::from(""));
711                            base.push(StyledLineBuilder::new().key("📝 Script:").build());
712                            for line in preview.lines() {
713                                base.push(StyledLineBuilder::new().text("  ").value(line).build());
714                            }
715                        }
716                        Some(base)
717                    } else {
718                        None
719                    }
720                };
721
722                let action = Action::AddResponseWithStyle {
723                    content: response,
724                    styled_lines,
725                    response_type: crate::action::ResponseType::Info,
726                };
727                let _ = self.handle_action(action);
728            }
729            RuntimeStatus::TraceInfoAll { summary, traces } => {
730                self.clear_waiting_state();
731
732                // Update source panel line colors based on trace status
733                for trace in &traces {
734                    // Try to extract file and line from target_display (format: "file:line" or "function_name")
735                    // TODO: Need source_file and source_line fields for function traces
736                    if let Some(colon_pos) = trace.target_display.rfind(':') {
737                        let file_part = &trace.target_display[..colon_pos];
738                        if let Ok(line_num) = trace.target_display[colon_pos + 1..].parse::<usize>()
739                        {
740                            // Store the trace location
741                            self.state
742                                .source_panel
743                                .trace_locations
744                                .insert(trace.trace_id, (file_part.to_string(), line_num));
745
746                            // Update line colors if this is the current file
747                            if self.state.source_panel.file_path.as_ref()
748                                == Some(&file_part.to_string())
749                            {
750                                match trace.status {
751                                    crate::events::TraceStatus::Active => {
752                                        self.state.source_panel.disabled_lines.remove(&line_num);
753                                        self.state.source_panel.traced_lines.insert(line_num);
754                                    }
755                                    crate::events::TraceStatus::Disabled => {
756                                        self.state.source_panel.traced_lines.remove(&line_num);
757                                        self.state.source_panel.disabled_lines.insert(line_num);
758                                    }
759                                    crate::events::TraceStatus::Failed => {
760                                        self.state.source_panel.traced_lines.remove(&line_num);
761                                        self.state.source_panel.disabled_lines.remove(&line_num);
762                                    }
763                                }
764                            }
765                        }
766                    }
767                }
768
769                let mut response = format!(
770                    "🔍 All Traces ({} total, {} active):\n\n",
771                    summary.total, summary.active
772                );
773                for trace in &traces {
774                    // Use format_line() to show detailed info including address and module
775                    response.push_str(&format!("  {}\n", trace.format_line()));
776                }
777                // Styled version
778                let styled_lines = (crate::events::RuntimeStatus::TraceInfoAll {
779                    summary: summary.clone(),
780                    traces: traces.clone(),
781                })
782                .format_trace_info_styled()
783                .unwrap_or_default();
784                let action = Action::AddResponseWithStyle {
785                    content: response,
786                    styled_lines: if styled_lines.is_empty() {
787                        None
788                    } else {
789                        Some(styled_lines)
790                    },
791                    response_type: crate::action::ResponseType::Info,
792                };
793                let _ = self.handle_action(action);
794            }
795            RuntimeStatus::TraceInfoFailed { trace_id, error } => {
796                self.clear_waiting_state();
797                let text = format!("✗ Failed to get info for trace {trace_id}: {error}");
798                let styled = crate::components::command_panel::ResponseFormatter::style_generic_message_lines(&text);
799                let action = Action::AddResponseWithStyle {
800                    content: text,
801                    styled_lines: Some(styled),
802                    response_type: crate::action::ResponseType::Error,
803                };
804                let _ = self.handle_action(action);
805            }
806            RuntimeStatus::TraceEnabled { trace_id } => {
807                self.clear_waiting_state();
808
809                // Update source panel line color
810                if let Some((file_path, line_num)) =
811                    self.state.source_panel.trace_locations.get(&trace_id)
812                {
813                    if self.state.source_panel.file_path.as_ref() == Some(file_path) {
814                        self.state.source_panel.disabled_lines.remove(line_num);
815                        self.state.source_panel.traced_lines.insert(*line_num);
816                    }
817                }
818
819                let text = format!("✅ Trace {trace_id} enabled");
820                let styled = vec![
821                    crate::components::command_panel::style_builder::StyledLineBuilder::new()
822                        .styled(
823                            text.clone(),
824                            crate::components::command_panel::style_builder::StylePresets::SUCCESS,
825                        )
826                        .build(),
827                ];
828                let action = Action::AddResponseWithStyle {
829                    content: text,
830                    styled_lines: Some(styled),
831                    response_type: crate::action::ResponseType::Success,
832                };
833                let _ = self.handle_action(action);
834            }
835            RuntimeStatus::TraceDisabled { trace_id } => {
836                self.clear_waiting_state();
837
838                // Update source panel line color
839                if let Some((file_path, line_num)) =
840                    self.state.source_panel.trace_locations.get(&trace_id)
841                {
842                    if self.state.source_panel.file_path.as_ref() == Some(file_path) {
843                        self.state.source_panel.traced_lines.remove(line_num);
844                        self.state.source_panel.disabled_lines.insert(*line_num);
845                    }
846                }
847
848                let text = format!("✅ Trace {trace_id} disabled");
849                let styled = vec![
850                    crate::components::command_panel::style_builder::StyledLineBuilder::new()
851                        .styled(
852                            text.clone(),
853                            crate::components::command_panel::style_builder::StylePresets::SUCCESS,
854                        )
855                        .build(),
856                ];
857                let action = Action::AddResponseWithStyle {
858                    content: text,
859                    styled_lines: Some(styled),
860                    response_type: crate::action::ResponseType::Success,
861                };
862                let _ = self.handle_action(action);
863            }
864            RuntimeStatus::AllTracesEnabled { count, error } => {
865                self.clear_waiting_state();
866
867                if error.is_none() {
868                    // Move all known traces from disabled to enabled
869                    for (file_path, line_num) in self.state.source_panel.trace_locations.values() {
870                        if self.state.source_panel.file_path.as_ref() == Some(file_path) {
871                            self.state.source_panel.disabled_lines.remove(line_num);
872                            self.state.source_panel.traced_lines.insert(*line_num);
873                        }
874                    }
875                }
876
877                let (plain, rtype, style) = if let Some(ref err) = error {
878                    (
879                        format!("✗ Failed to enable traces: {err}"),
880                        crate::action::ResponseType::Error,
881                        crate::components::command_panel::style_builder::StylePresets::ERROR,
882                    )
883                } else {
884                    (
885                        format!("✅ All traces enabled ({count} traces)"),
886                        crate::action::ResponseType::Success,
887                        crate::components::command_panel::style_builder::StylePresets::SUCCESS,
888                    )
889                };
890                let styled = vec![
891                    crate::components::command_panel::style_builder::StyledLineBuilder::new()
892                        .styled(plain.clone(), style)
893                        .build(),
894                ];
895                let action = Action::AddResponseWithStyle {
896                    content: plain,
897                    styled_lines: Some(styled),
898                    response_type: rtype,
899                };
900                let _ = self.handle_action(action);
901            }
902            RuntimeStatus::AllTracesDisabled { count, error } => {
903                self.clear_waiting_state();
904
905                if error.is_none() {
906                    // Move all known traces from enabled to disabled
907                    for (file_path, line_num) in self.state.source_panel.trace_locations.values() {
908                        if self.state.source_panel.file_path.as_ref() == Some(file_path) {
909                            self.state.source_panel.traced_lines.remove(line_num);
910                            self.state.source_panel.disabled_lines.insert(*line_num);
911                        }
912                    }
913                }
914
915                let (plain, rtype, style) = if let Some(ref err) = error {
916                    (
917                        format!("✗ Failed to disable traces: {err}"),
918                        crate::action::ResponseType::Error,
919                        crate::components::command_panel::style_builder::StylePresets::ERROR,
920                    )
921                } else {
922                    (
923                        format!("✅ All traces disabled ({count} traces)"),
924                        crate::action::ResponseType::Success,
925                        crate::components::command_panel::style_builder::StylePresets::SUCCESS,
926                    )
927                };
928                let styled = vec![
929                    crate::components::command_panel::style_builder::StyledLineBuilder::new()
930                        .styled(plain.clone(), style)
931                        .build(),
932                ];
933                let action = Action::AddResponseWithStyle {
934                    content: plain,
935                    styled_lines: Some(styled),
936                    response_type: rtype,
937                };
938                let _ = self.handle_action(action);
939            }
940            RuntimeStatus::TraceEnableFailed { trace_id, error } => {
941                self.clear_waiting_state();
942                let text = format!("✗ Failed to enable trace {trace_id}: {error}");
943                let styled = crate::components::command_panel::ResponseFormatter::style_generic_message_lines(&text);
944                let action = Action::AddResponseWithStyle {
945                    content: text,
946                    styled_lines: Some(styled),
947                    response_type: crate::action::ResponseType::Error,
948                };
949                let _ = self.handle_action(action);
950            }
951            RuntimeStatus::TraceDisableFailed { trace_id, error } => {
952                self.clear_waiting_state();
953                let text = format!("✗ Failed to disable trace {trace_id}: {error}");
954                let styled = crate::components::command_panel::ResponseFormatter::style_generic_message_lines(&text);
955                let action = Action::AddResponseWithStyle {
956                    content: text,
957                    styled_lines: Some(styled),
958                    response_type: crate::action::ResponseType::Error,
959                };
960                let _ = self.handle_action(action);
961            }
962            RuntimeStatus::TraceDeleted { trace_id } => {
963                self.clear_waiting_state();
964
965                // Remove from source panel line colors
966                if let Some((file_path, line_num)) =
967                    self.state.source_panel.trace_locations.remove(&trace_id)
968                {
969                    if self.state.source_panel.file_path.as_ref() == Some(&file_path) {
970                        self.state.source_panel.traced_lines.remove(&line_num);
971                        self.state.source_panel.disabled_lines.remove(&line_num);
972                    }
973                }
974
975                let text = format!("✅ Trace {trace_id} deleted");
976                let styled = vec![
977                    crate::components::command_panel::style_builder::StyledLineBuilder::new()
978                        .styled(
979                            text.clone(),
980                            crate::components::command_panel::style_builder::StylePresets::SUCCESS,
981                        )
982                        .build(),
983                ];
984                let action = Action::AddResponseWithStyle {
985                    content: text,
986                    styled_lines: Some(styled),
987                    response_type: crate::action::ResponseType::Success,
988                };
989                let _ = self.handle_action(action);
990            }
991            RuntimeStatus::AllTracesDeleted { count, error } => {
992                self.clear_waiting_state();
993
994                if error.is_none() {
995                    // Clear all trace locations and colors
996                    self.state.source_panel.traced_lines.clear();
997                    self.state.source_panel.disabled_lines.clear();
998                    self.state.source_panel.trace_locations.clear();
999                }
1000
1001                let (plain, rtype, style) = if let Some(ref err) = error {
1002                    (
1003                        format!("✗ Failed to delete traces: {err}"),
1004                        crate::action::ResponseType::Error,
1005                        crate::components::command_panel::style_builder::StylePresets::ERROR,
1006                    )
1007                } else {
1008                    (
1009                        format!("✅ All traces deleted ({count} traces)"),
1010                        crate::action::ResponseType::Success,
1011                        crate::components::command_panel::style_builder::StylePresets::SUCCESS,
1012                    )
1013                };
1014                let styled = vec![
1015                    crate::components::command_panel::style_builder::StyledLineBuilder::new()
1016                        .styled(plain.clone(), style)
1017                        .build(),
1018                ];
1019                let action = Action::AddResponseWithStyle {
1020                    content: plain,
1021                    styled_lines: Some(styled),
1022                    response_type: rtype,
1023                };
1024                let _ = self.handle_action(action);
1025            }
1026            RuntimeStatus::TraceDeleteFailed { trace_id, error } => {
1027                self.clear_waiting_state();
1028                let text = format!("✗ Failed to delete trace {trace_id}: {error}");
1029                let styled = crate::components::command_panel::ResponseFormatter::style_generic_message_lines(&text);
1030                let action = Action::AddResponseWithStyle {
1031                    content: text,
1032                    styled_lines: Some(styled),
1033                    response_type: crate::action::ResponseType::Error,
1034                };
1035                let _ = self.handle_action(action);
1036            }
1037            RuntimeStatus::TracesSaved {
1038                filename,
1039                saved_count,
1040                total_count,
1041            } => {
1042                self.clear_waiting_state();
1043                let mut text =
1044                    format!("✅ Saved {saved_count} of {total_count} traces to {filename}\n");
1045                text.push_str("   • Selected indices are preserved in the save file\n");
1046
1047                use crate::components::command_panel::style_builder::{
1048                    StylePresets, StyledLineBuilder,
1049                };
1050                let styled = vec![
1051                    StyledLineBuilder::new()
1052                        .styled(
1053                            format!("✅ Saved {saved_count} of {total_count} traces to {filename}"),
1054                            StylePresets::SUCCESS,
1055                        )
1056                        .build(),
1057                    StyledLineBuilder::new()
1058                        .text("   • ")
1059                        .styled(
1060                            "Selected indices are preserved in the save file",
1061                            StylePresets::TIP,
1062                        )
1063                        .build(),
1064                ];
1065                let action = Action::AddResponseWithStyle {
1066                    content: text,
1067                    styled_lines: Some(styled),
1068                    response_type: crate::action::ResponseType::Success,
1069                };
1070                let _ = self.handle_action(action);
1071            }
1072            RuntimeStatus::TracesSaveFailed { error } => {
1073                self.clear_waiting_state();
1074                let text = format!("✗ Failed to save traces: {error}");
1075                let styled = crate::components::command_panel::ResponseFormatter::style_generic_message_lines(&text);
1076                let action = Action::AddResponseWithStyle {
1077                    content: text,
1078                    styled_lines: Some(styled),
1079                    response_type: crate::action::ResponseType::Error,
1080                };
1081                let _ = self.handle_action(action);
1082            }
1083            RuntimeStatus::TracesLoaded {
1084                filename,
1085                total_count,
1086                success_count,
1087                failed_count,
1088                disabled_count,
1089                details,
1090            } => {
1091                self.clear_waiting_state();
1092
1093                // Build response message
1094                let mut response = String::new();
1095
1096                if failed_count == 0 {
1097                    // All traces loaded successfully
1098                    response.push_str(&format!(
1099                        "✓ Loaded {} traces from {} ({} enabled, {} disabled)",
1100                        total_count,
1101                        filename,
1102                        success_count - disabled_count,
1103                        disabled_count
1104                    ));
1105                    response.push('\n');
1106                    response.push_str("   • Selected indices from the file are restored\n");
1107                } else {
1108                    // Some traces failed
1109                    response.push_str(&format!("⚠️ Partially loaded traces from {filename}\n"));
1110                    response.push_str(&format!(
1111                        "  ✓ {} traces created ({} enabled, {} disabled)\n",
1112                        success_count,
1113                        success_count - disabled_count,
1114                        disabled_count
1115                    ));
1116                    response
1117                        .push_str("  • Selected indices from the file are restored when present\n");
1118
1119                    // Show failed traces
1120                    for detail in &details {
1121                        if let crate::events::LoadStatus::Failed = detail.status {
1122                            if let Some(ref error) = detail.error {
1123                                response.push_str(&format!("  ✗ {} - {}\n", detail.target, error));
1124                            }
1125                        }
1126                    }
1127                }
1128
1129                // Styled version
1130                let mut styled = Vec::new();
1131                use crate::components::command_panel::style_builder::{
1132                    StylePresets, StyledLineBuilder,
1133                };
1134                if failed_count == 0 {
1135                    styled.push(
1136                        StyledLineBuilder::new()
1137                            .styled(
1138                                format!(
1139                                    "✅ Loaded {} traces from {} ({} enabled, {} disabled)",
1140                                    total_count,
1141                                    filename,
1142                                    success_count - disabled_count,
1143                                    disabled_count
1144                                ),
1145                                StylePresets::SUCCESS,
1146                            )
1147                            .build(),
1148                    );
1149                    styled.push(
1150                        StyledLineBuilder::new()
1151                            .text("   • ")
1152                            .styled(
1153                                "Selected indices from the file are restored",
1154                                StylePresets::TIP,
1155                            )
1156                            .build(),
1157                    );
1158                } else {
1159                    styled.push(
1160                        StyledLineBuilder::new()
1161                            .styled(
1162                                format!("⚠️ Partially loaded traces from {filename}"),
1163                                StylePresets::WARNING,
1164                            )
1165                            .build(),
1166                    );
1167                    styled.push(
1168                        StyledLineBuilder::new()
1169                            .text("  ")
1170                            .styled(
1171                                format!(
1172                                    "✅ {} traces created ({} enabled, {} disabled)",
1173                                    success_count,
1174                                    success_count - disabled_count,
1175                                    disabled_count
1176                                ),
1177                                StylePresets::SUCCESS,
1178                            )
1179                            .build(),
1180                    );
1181                    styled.push(
1182                        StyledLineBuilder::new()
1183                            .text("  • ")
1184                            .styled(
1185                                "Selected indices from the file are restored when present",
1186                                StylePresets::TIP,
1187                            )
1188                            .build(),
1189                    );
1190                    for detail in &details {
1191                        if let crate::events::LoadStatus::Failed = detail.status {
1192                            if let Some(ref err) = detail.error {
1193                                styled.push(
1194                                    StyledLineBuilder::new()
1195                                        .text("  ")
1196                                        .styled(
1197                                            format!("✗ {} - {}", detail.target, err),
1198                                            StylePresets::ERROR,
1199                                        )
1200                                        .build(),
1201                                );
1202                            }
1203                        }
1204                    }
1205                }
1206
1207                let action = Action::AddResponseWithStyle {
1208                    content: response,
1209                    styled_lines: Some(styled),
1210                    response_type: if failed_count == 0 {
1211                        crate::action::ResponseType::Success
1212                    } else {
1213                        crate::action::ResponseType::Warning
1214                    },
1215                };
1216                let _ = self.handle_action(action);
1217            }
1218            RuntimeStatus::TracesLoadFailed { filename, error } => {
1219                self.clear_waiting_state();
1220                let text = format!("✗ Failed to load {filename}: {error}");
1221                let styled = crate::components::command_panel::ResponseFormatter::style_generic_message_lines(&text);
1222                let action = Action::AddResponseWithStyle {
1223                    content: text,
1224                    styled_lines: Some(styled),
1225                    response_type: crate::action::ResponseType::Error,
1226                };
1227                let _ = self.handle_action(action);
1228            }
1229            RuntimeStatus::TraceBackpressure {
1230                dropped_since_last,
1231                dropped_total,
1232                queue_capacity,
1233            } => {
1234                self.show_trace_backpressure_alert(
1235                    dropped_since_last,
1236                    dropped_total,
1237                    queue_capacity,
1238                );
1239            }
1240            RuntimeStatus::EbpfOutputLoss {
1241                trace_id,
1242                target_display,
1243                lost_since_last,
1244                lost_total,
1245            } => {
1246                self.show_ebpf_output_loss_alert(
1247                    trace_id,
1248                    target_display,
1249                    lost_since_last,
1250                    lost_total,
1251                );
1252            }
1253            _ => {
1254                // Handle other runtime status messages (delegate to command panel or other components)
1255                // For now, pass them to command panel for display
1256
1257                // Check if this is an error status or completed status that should clear waiting state
1258                let should_clear_waiting = matches!(
1259                    status,
1260                    RuntimeStatus::AllTracesEnabled { .. }
1261                        | RuntimeStatus::AllTracesDisabled { .. }
1262                        | RuntimeStatus::AllTracesDeleted { .. }
1263                        | RuntimeStatus::ScriptCompilationCompleted { .. }
1264                        | RuntimeStatus::TraceInfoFailed { .. }
1265                        | RuntimeStatus::FileInfoFailed { .. }
1266                        | RuntimeStatus::ShareInfoFailed { .. }
1267                        | RuntimeStatus::ExecutableFileInfoFailed { .. }
1268                        | RuntimeStatus::SrcPathFailed { .. }
1269                );
1270
1271                if should_clear_waiting {
1272                    self.clear_waiting_state();
1273                }
1274
1275                if let Some(content) = self.format_runtime_status_for_display(&status) {
1276                    // Don't use styled_lines if content contains ANSI color codes
1277                    // Let the renderer handle ANSI parsing instead
1278                    let styled_lines = if content.contains("\x1b[") {
1279                        None
1280                    } else {
1281                        Some(crate::components::command_panel::ResponseFormatter::style_generic_message_lines(&content))
1282                    };
1283                    let action = Action::AddResponseWithStyle {
1284                        content,
1285                        styled_lines,
1286                        response_type: self.get_response_type_for_status(&status),
1287                    };
1288                    let _ = self.handle_action(action);
1289                }
1290            }
1291        }
1292    }
1293
1294    /// Handle trace events
1295    pub(super) async fn handle_trace_event(&mut self, trace_event: crate::events::UiTraceEvent) {
1296        tracing::debug!("Trace event: {:?}", trace_event);
1297
1298        // Realtime logging: write eBPF event to file if enabled
1299        if self.state.realtime_output_logger.enabled {
1300            if let Err(e) = self.write_ebpf_event_to_output_log(&trace_event) {
1301                tracing::error!("Failed to write eBPF event to output log: {}", e);
1302            }
1303        }
1304
1305        self.state.ebpf_panel.add_trace_event(trace_event);
1306    }
1307
1308    fn add_ebpf_runtime_warning(&mut self, content: String) {
1309        let event = crate::model::panel_state::EbpfPanelState::runtime_warning_event(
1310            content,
1311            current_boot_timestamp_ns(),
1312        );
1313
1314        if self.state.realtime_output_logger.enabled {
1315            if let Err(e) = self.write_ebpf_event_to_output_log(&event) {
1316                tracing::error!("Failed to write eBPF runtime warning to output log: {}", e);
1317            }
1318        }
1319
1320        self.state.ebpf_panel.add_trace_event(event);
1321    }
1322
1323    fn show_trace_backpressure_alert(
1324        &mut self,
1325        dropped_since_last: u64,
1326        dropped_total: u64,
1327        queue_capacity: usize,
1328    ) {
1329        let content = format!(
1330            "⚠ Trace queue saturated: dropped {dropped_since_last} events in last 1s (total {dropped_total}, capacity {queue_capacity})"
1331        );
1332        let styled_lines =
1333            crate::components::command_panel::ResponseFormatter::style_generic_message_lines(
1334                &content,
1335            );
1336        crate::components::command_panel::ResponseFormatter::upsert_runtime_alert_with_style(
1337            &mut self.state.command_panel,
1338            content,
1339            Some(styled_lines),
1340            crate::action::ResponseType::Warning,
1341        );
1342        self.state.command_renderer.mark_pending_updates();
1343
1344        self.add_ebpf_runtime_warning(format!(
1345            "Warning: TUI trace queue saturated; dropped {dropped_since_last} events before display in last 1s (total {dropped_total}, capacity {queue_capacity})"
1346        ));
1347    }
1348
1349    fn show_ebpf_output_loss_alert(
1350        &mut self,
1351        trace_id: u32,
1352        target_display: String,
1353        lost_since_last: u64,
1354        lost_total: u64,
1355    ) {
1356        let content = format!(
1357            "⚠ eBPF output helper failed: trace #{trace_id} ({target_display}) lost {lost_since_last} events in kernel before userspace delivery (total {lost_total})"
1358        );
1359        let styled_lines =
1360            crate::components::command_panel::ResponseFormatter::style_generic_message_lines(
1361                &content,
1362            );
1363        crate::components::command_panel::ResponseFormatter::upsert_runtime_alert_with_style(
1364            &mut self.state.command_panel,
1365            content,
1366            Some(styled_lines),
1367            crate::action::ResponseType::Warning,
1368        );
1369        self.state.command_renderer.mark_pending_updates();
1370
1371        self.add_ebpf_runtime_warning(format!(
1372            "Warning: eBPF output helper failed; trace #{trace_id} ({target_display}) lost {lost_since_last} events in kernel before userspace delivery (total {lost_total})"
1373        ));
1374    }
1375
1376    /// Format runtime status for display in command panel
1377    fn format_runtime_status_for_display(
1378        &mut self,
1379        status: &crate::events::RuntimeStatus,
1380    ) -> Option<String> {
1381        use crate::events::RuntimeStatus;
1382
1383        match status {
1384            RuntimeStatus::ScriptCompilationCompleted { details } => {
1385                // Check if this is part of a batch load operation
1386                if let Some(ref mut batch) = self.state.command_panel.batch_loading {
1387                    batch.record_script_compilation(details);
1388
1389                    // Check if all traces have been processed
1390                    if batch.completed_count >= batch.total_count {
1391                        // All traces processed, show summary
1392                        let filename = batch.filename.clone();
1393                        let total_count = batch.total_count;
1394                        let success_count = batch.success_count;
1395                        let failed_count = batch.failed_count;
1396                        let disabled_count = batch.disabled_count;
1397                        let details = batch.details.clone();
1398
1399                        // Clear batch loading state
1400                        self.state.command_panel.batch_loading = None;
1401
1402                        // Clear waiting state
1403                        self.clear_waiting_state();
1404
1405                        // Show summary response
1406                        let mut response = format!("📂 Loaded traces from {filename}\n");
1407                        response.push_str(&format!(
1408                            "  Total: {total_count}, Success: {success_count}, Failed: {failed_count}"
1409                        ));
1410                        if disabled_count > 0 {
1411                            response.push_str(&format!(", Disabled: {disabled_count}"));
1412                        }
1413                        response.push('\n');
1414
1415                        // Show details
1416                        if !details.is_empty() {
1417                            response.push_str("\n📊 Details:\n");
1418                            for detail in &details {
1419                                match detail.status {
1420                                    crate::events::LoadStatus::Created => {
1421                                        if let Some(id) = detail.trace_id {
1422                                            response.push_str(&format!(
1423                                                "  ✓ {} → trace #{}\n",
1424                                                detail.target, id
1425                                            ));
1426                                        } else {
1427                                            response.push_str(&format!("  ✓ {}\n", detail.target));
1428                                        }
1429                                    }
1430                                    crate::events::LoadStatus::CreatedDisabled => {
1431                                        if let Some(id) = detail.trace_id {
1432                                            response.push_str(&format!(
1433                                                "  ⊘ {} → trace #{} (disabled)\n",
1434                                                detail.target, id
1435                                            ));
1436                                        } else {
1437                                            response.push_str(&format!(
1438                                                "  ⊘ {} (disabled)\n",
1439                                                detail.target
1440                                            ));
1441                                        }
1442                                    }
1443                                    crate::events::LoadStatus::Failed => {
1444                                        if let Some(ref error) = detail.error {
1445                                            response.push_str(&format!(
1446                                                "  ✗ {}: {}\n",
1447                                                detail.target, error
1448                                            ));
1449                                        } else {
1450                                            response.push_str(&format!("  ✗ {}\n", detail.target));
1451                                        }
1452                                    }
1453                                    _ => {}
1454                                }
1455                            }
1456                        }
1457
1458                        // Create styled version using helper method
1459                        let styled_lines =
1460                            crate::components::command_panel::ResponseFormatter::format_batch_load_summary_styled(
1461                                &filename,
1462                                total_count,
1463                                success_count,
1464                                failed_count,
1465                                disabled_count,
1466                                &details,
1467                            );
1468
1469                        let action = Action::AddResponseWithStyle {
1470                            content: response,
1471                            styled_lines: Some(styled_lines),
1472                            response_type: if failed_count > 0 {
1473                                crate::action::ResponseType::Warning
1474                            } else {
1475                                crate::action::ResponseType::Success
1476                            },
1477                        };
1478                        let _ = self.handle_action(action);
1479
1480                        // Don't return - continue to allow individual trace display to be suppressed
1481                        return None;
1482                    } else {
1483                        // Still waiting for more traces, suppress individual response
1484                        return None;
1485                    }
1486                }
1487
1488                // Not batch loading, handle normally
1489                // Clear waiting state for non-batch trace commands
1490                self.clear_waiting_state();
1491
1492                // Check if compilation actually succeeded
1493                if details.success_count > 0 || details.failed_count > 0 {
1494                    // Get script content from the current cache for better display
1495                    let script_content = self
1496                        .state
1497                        .command_panel
1498                        .script_cache
1499                        .as_ref()
1500                        .map(|cache| cache.lines.join("\n"));
1501
1502                    // Use new format_compilation_results to show all traces
1503                    Some(crate::components::command_panel::script_editor::ScriptEditor::format_compilation_results(
1504                        details,
1505                        script_content.as_deref(),
1506                        &self.state.emoji_config,
1507                    ))
1508                } else {
1509                    // All compilations failed - find the first failed result for error details
1510                    let first_failed = details.results.first();
1511                    if let Some(result) = first_failed {
1512                        if let crate::events::ExecutionStatus::Failed(error) = &result.status {
1513                            let error_details = crate::components::command_panel::script_editor::TraceErrorDetails {
1514                                compilation_errors: None,
1515                                uprobe_error: Some(error.clone()),
1516                                suggestion: Some("Check function name and ensure binary has debug symbols".to_string()),
1517                            };
1518
1519                            // Get script content for error display
1520                            let script_content = self
1521                                .state
1522                                .command_panel
1523                                .script_cache
1524                                .as_ref()
1525                                .map(|cache| cache.lines.join("\n"));
1526
1527                            Some(crate::components::command_panel::script_editor::ScriptEditor::format_trace_error_response_with_script(
1528                                &result.target_name,
1529                                error,
1530                                Some(&error_details),
1531                                script_content.as_deref(),
1532                                &self.state.emoji_config,
1533                            ))
1534                        } else {
1535                            None
1536                        }
1537                    } else {
1538                        None
1539                    }
1540                }
1541            }
1542            RuntimeStatus::AllTracesEnabled { count, error } => {
1543                if let Some(ref err) = error {
1544                    let error_emoji = self
1545                        .state
1546                        .emoji_config
1547                        .get_script_status(crate::ui::emoji::ScriptStatus::Error);
1548                    Some(format!("{error_emoji} {err}"))
1549                } else if *count > 0 {
1550                    let success_emoji = self
1551                        .state
1552                        .emoji_config
1553                        .get_trace_status(crate::ui::emoji::TraceStatusType::Active);
1554                    Some(format!("{success_emoji} Enabled {count} traces"))
1555                } else {
1556                    None
1557                }
1558            }
1559            RuntimeStatus::AllTracesDisabled { count, error } => {
1560                if let Some(ref err) = error {
1561                    let error_emoji = self
1562                        .state
1563                        .emoji_config
1564                        .get_script_status(crate::ui::emoji::ScriptStatus::Error);
1565                    Some(format!("{error_emoji} {err}"))
1566                } else if *count > 0 {
1567                    let disabled_emoji = self
1568                        .state
1569                        .emoji_config
1570                        .get_trace_status(crate::ui::emoji::TraceStatusType::Disabled);
1571                    Some(format!("{disabled_emoji} Disabled {count} traces"))
1572                } else {
1573                    None
1574                }
1575            }
1576            RuntimeStatus::AllTracesDeleted { count, error } => {
1577                if let Some(ref err) = error {
1578                    let error_emoji = self
1579                        .state
1580                        .emoji_config
1581                        .get_script_status(crate::ui::emoji::ScriptStatus::Error);
1582                    Some(format!("{error_emoji} {err}"))
1583                } else if *count > 0 {
1584                    Some(format!("✓ Deleted {count} traces"))
1585                } else {
1586                    None
1587                }
1588            }
1589            RuntimeStatus::TraceEnabled { trace_id } => {
1590                let success_emoji = self
1591                    .state
1592                    .emoji_config
1593                    .get_trace_status(crate::ui::emoji::TraceStatusType::Active);
1594                Some(format!("{success_emoji} Trace {trace_id} enabled"))
1595            }
1596            RuntimeStatus::TraceDisabled { trace_id } => {
1597                let disabled_emoji = self
1598                    .state
1599                    .emoji_config
1600                    .get_trace_status(crate::ui::emoji::TraceStatusType::Disabled);
1601                Some(format!("{disabled_emoji} Trace {trace_id} disabled"))
1602            }
1603            _ => None, // Don't display other status types in command panel
1604        }
1605    }
1606
1607    /// Get response type for runtime status
1608    fn get_response_type_for_status(
1609        &self,
1610        status: &crate::events::RuntimeStatus,
1611    ) -> crate::action::ResponseType {
1612        use crate::events::RuntimeStatus;
1613
1614        match status {
1615            RuntimeStatus::ScriptCompilationCompleted { details } => {
1616                // Check if compilation actually succeeded
1617                if details.success_count > 0 {
1618                    crate::action::ResponseType::Success
1619                } else {
1620                    crate::action::ResponseType::Error
1621                }
1622            }
1623            RuntimeStatus::AllTracesEnabled { error, .. }
1624            | RuntimeStatus::AllTracesDisabled { error, .. }
1625            | RuntimeStatus::AllTracesDeleted { error, .. } => {
1626                if error.is_some() {
1627                    crate::action::ResponseType::Error
1628                } else {
1629                    crate::action::ResponseType::Success
1630                }
1631            }
1632            _ => crate::action::ResponseType::Info,
1633        }
1634    }
1635
1636    /// Clear waiting state to return to ready input mode
1637    pub(super) fn clear_waiting_state(&mut self) {
1638        self.state.command_panel.input_state = crate::model::panel_state::InputState::Ready;
1639    }
1640}
1641
1642fn current_boot_timestamp_ns() -> u64 {
1643    std::fs::read_to_string("/proc/uptime")
1644        .ok()
1645        .and_then(|contents| {
1646            contents
1647                .split_whitespace()
1648                .next()
1649                .and_then(|secs| secs.parse::<f64>().ok())
1650        })
1651        .map(|secs| (secs * 1_000_000_000.0) as u64)
1652        .unwrap_or(0)
1653}