diff --git a/src/gui_2.py b/src/gui_2.py index 78b4a6c..09620c4 100644 --- a/src/gui_2.py +++ b/src/gui_2.py @@ -1,6 +1,7 @@ # gui_2.py # defer: parse from __future__ import annotations +import copy import datetime import difflib import json @@ -23,6 +24,7 @@ from pathlib import Path from pydantic import BaseModel from tkinter import filedialog, Tk from typing import Optional, Any +from src.diff_viewer import apply_patch_to_file from src import ai_client from src import aggregate from src import api_hooks @@ -40,6 +42,8 @@ from src import log_pruner from src import models from src import mcp_client from src import markdown_helper +from src import shaders +from src import synthesis_formatter from src import theme_2 as theme from src import theme_nerv_fx as theme_fx from src import thinking_parser @@ -1240,19 +1244,17 @@ class App: imgui.text_disabled("No active cache") if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_cache_panel") return - age_sec = stats.get("cache_age_seconds", 0) + age_sec = stats.get("cache_age_seconds", 0) ttl_remaining = stats.get("ttl_remaining", 0) - ttl_total = stats.get("ttl_seconds", 3600) - age_str = f"{age_sec/60:.0f}m {age_sec%60:.0f}s" + ttl_total = stats.get("ttl_seconds", 3600) + age_str = f"{age_sec/60:.0f}m {age_sec%60:.0f}s" remaining_str = f"{ttl_remaining/60:.0f}m {ttl_remaining%60:.0f}s" ttl_pct = (ttl_remaining / ttl_total * 100) if ttl_total > 0 else 0 imgui.text(f"Age: {age_str}") imgui.text(f"TTL: {remaining_str} ({ttl_pct:.0f}%)") color = imgui.ImVec4(0.2, 0.8, 0.2, 1.0) - if ttl_pct < 20: - color = imgui.ImVec4(1.0, 0.2, 0.2, 1.0) - elif ttl_pct < 50: - color = imgui.ImVec4(1.0, 0.8, 0.0, 1.0) + if ttl_pct < 20: color = imgui.ImVec4(1.0, 0.2, 0.2, 1.0) + elif ttl_pct < 50: color = imgui.ImVec4(1.0, 0.8, 0.0, 1.0) imgui.push_style_color(imgui.Col_.plot_histogram, color) imgui.progress_bar(ttl_pct / 100.0, imgui.ImVec2(-1, 0), f"{ttl_pct:.0f}%") imgui.pop_style_color() @@ -1388,11 +1390,11 @@ class App: imgui.table_headers_row() sorted_tools = sorted(tool_stats.items(), key=lambda x: -x[1].get("count", 0)) for tool_name, stats in sorted_tools: - count = stats.get("count", 0) + count = stats.get("count", 0) total_time = stats.get("total_time_ms", 0) - failures = stats.get("failures", 0) - avg_time = total_time / count if count > 0 else 0 - fail_pct = (failures / count * 100) if count > 0 else 0 + failures = stats.get("failures", 0) + avg_time = total_time / count if count > 0 else 0 + fail_pct = (failures / count * 100) if count > 0 else 0 imgui.table_next_row() imgui.table_set_column_index(0) imgui.text(tool_name) @@ -1401,10 +1403,8 @@ class App: imgui.table_set_column_index(2) imgui.text(f"{avg_time:.0f}") imgui.table_set_column_index(3) - if fail_pct > 0: - imgui.text_colored(imgui.ImVec4(1.0, 0.2, 0.2, 1.0), f"{fail_pct:.0f}%") - else: - imgui.text("0%") + if fail_pct > 0: imgui.text_colored(imgui.ImVec4(1.0, 0.2, 0.2, 1.0), f"{fail_pct:.0f}%") + else: imgui.text("0%") imgui.end_table() if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_tool_analytics_panel") @@ -1413,15 +1413,11 @@ class App: imgui.text_colored(C_LBL, 'Prompt Utilization') usage = self.session_usage total = usage["input_tokens"] + usage["output_tokens"] - if total == 0 and usage.get("total_tokens", 0) > 0: - total = usage["total_tokens"] + if total == 0 and usage.get("total_tokens", 0) > 0: total = usage["total_tokens"] self._render_selectable_label("session_telemetry_tokens", f"Tokens: {total:,} (In: {usage['input_tokens']:,} Out: {usage['output_tokens']:,})", width=-1, color=C_RES) - if usage.get("last_latency", 0.0) > 0: - imgui.text_colored(C_LBL, f" Last Latency: {usage['last_latency']:.2f}s") - if usage["cache_read_input_tokens"]: - imgui.text_colored(C_LBL, f" Cache Read: {usage['cache_read_input_tokens']:,} Creation: {usage['cache_creation_input_tokens']:,}") - if self._gemini_cache_text: - imgui.text_colored(C_SUB, self._gemini_cache_text) + if usage.get("last_latency", 0.0) > 0: imgui.text_colored(C_LBL, f" Last Latency: {usage['last_latency']:.2f}s") + if usage["cache_read_input_tokens"]: imgui.text_colored(C_LBL, f" Cache Read: {usage['cache_read_input_tokens']:,} Creation: {usage['cache_creation_input_tokens']:,}") + if self._gemini_cache_text: imgui.text_colored(C_SUB, self._gemini_cache_text) imgui.separator() if self._token_stats_dirty: @@ -1433,23 +1429,20 @@ class App: imgui.text_disabled("Token stats unavailable") if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_token_budget_panel") return - pct = stats.get("utilization_pct", 0.0) - current = stats.get("estimated_prompt_tokens", stats.get("total_tokens", 0)) - limit = stats.get("max_prompt_tokens", 0) + pct = stats.get("utilization_pct", 0.0) + current = stats.get("estimated_prompt_tokens", stats.get("total_tokens", 0)) + limit = stats.get("max_prompt_tokens", 0) headroom = stats.get("headroom_tokens", max(0, limit - current)) - if pct < 50.0: - color = imgui.ImVec4(0.2, 0.8, 0.2, 1.0) - elif pct < 80.0: - color = imgui.ImVec4(1.0, 0.8, 0.0, 1.0) - else: - color = imgui.ImVec4(1.0, 0.2, 0.2, 1.0) + if pct < 50.0: color = imgui.ImVec4(0.2, 0.8, 0.2, 1.0) + elif pct < 80.0: color = imgui.ImVec4(1.0, 0.8, 0.0, 1.0) + else: color = imgui.ImVec4(1.0, 0.2, 0.2, 1.0) imgui.push_style_color(imgui.Col_.plot_histogram, color) imgui.progress_bar(pct / 100.0, imgui.ImVec2(-1, 0), f"{pct:.1f}%") imgui.pop_style_color() imgui.text_disabled(f"{current:,} / {limit:,} tokens ({headroom:,} remaining)") - sys_tok = stats.get("system_tokens", 0) - tool_tok = stats.get("tools_tokens", 0) - hist_tok = stats.get("history_tokens", 0) + sys_tok = stats.get("system_tokens", 0) + tool_tok = stats.get("tools_tokens", 0) + hist_tok = stats.get("history_tokens", 0) total_tok = sys_tok + tool_tok + hist_tok or 1 if imgui.begin_table("token_breakdown", 3, imgui.TableFlags_.borders_inner_h | imgui.TableFlags_.sizing_fixed_fit): imgui.table_setup_column("Component") @@ -1472,11 +1465,11 @@ class App: imgui.table_setup_column("Est. Cost") imgui.table_headers_row() for tier, stats in self.mma_tier_usage.items(): - model = stats.get('model', 'unknown') - in_t = stats.get('input', 0) - out_t = stats.get('output', 0) + model = stats.get('model', 'unknown') + in_t = stats.get('input', 0) + out_t = stats.get('output', 0) tokens = in_t + out_t - cost = cost_tracker.estimate_cost(model, in_t, out_t) + cost = cost_tracker.estimate_cost(model, in_t, out_t) imgui.table_next_row() imgui.table_set_column_index(0); self._render_selectable_label(f"tier_{tier}", tier, width=-1) imgui.table_set_column_index(1); self._render_selectable_label(f"model_{tier}", model.split("-")[0], width=-1) @@ -1490,14 +1483,12 @@ class App: if stats.get("would_trim"): imgui.text_colored(imgui.ImVec4(1.0, 0.3, 0.0, 1.0), "WARNING: Next call will trim history") trimmable = stats.get("trimmable_turns", 0) - if trimmable: - imgui.text_disabled(f"Trimmable turns: {trimmable}") + if trimmable: imgui.text_disabled(f"Trimmable turns: {trimmable}") msgs = stats.get("messages") if msgs: shown = 0 for msg in msgs: - if shown >= 3: - break + if shown >= 3: break if msg.get("trimmable"): role = msg.get("role", "?") toks = msg.get("tokens", 0) @@ -1522,7 +1513,7 @@ class App: imgui.text(f"API Calls: {insights.get('call_count', 0)}") imgui.text(f"Burn Rate: {insights.get('burn_rate', 0):.0f} tokens/min") imgui.text(f"Session Cost: ${insights.get('session_cost', 0):.4f}") - completed = insights.get('completed_tickets', 0) + completed = insights.get('completed_tickets', 0) efficiency = insights.get('efficiency', 0) imgui.text(f"Completed: {completed}") imgui.text(f"Tokens/Ticket: {efficiency:.0f}" if efficiency > 0 else "Tokens/Ticket: N/A") @@ -1634,8 +1625,7 @@ class App: modes = ["native", "beads"] current_idx = modes.index(self.ui_project_execution_mode) if self.ui_project_execution_mode in modes else 0 ch, new_idx = imgui.combo("##exec_mode", current_idx, modes) - if ch: - self.ui_project_execution_mode = modes[new_idx] + if ch: self.ui_project_execution_mode = modes[new_idx] imgui.separator() imgui.text("Git Directory") ch, self.ui_project_git_dir = imgui.input_text("##git_dir", self.ui_project_git_dir) @@ -1670,14 +1660,12 @@ class App: is_active = (pp == self.active_project_path) if imgui.button(f"x##p{i}"): removed = self.project_paths.pop(i) - if removed == self.active_project_path and self.project_paths: - self._switch_project(self.project_paths[0]) + if removed == self.active_project_path and self.project_paths: self._switch_project(self.project_paths[0]) break imgui.same_line() marker = " *" if is_active else "" if is_active: imgui.push_style_color(imgui.Col_.text, C_IN) - if imgui.button(f"{Path(pp).stem}{marker}##ps{i}"): - self._switch_project(pp) + if imgui.button(f"{Path(pp).stem}{marker}##ps{i}"): self._switch_project(pp) if is_active: imgui.pop_style_color() imgui.same_line() imgui.text_colored(C_LBL, pp) @@ -1700,8 +1688,7 @@ class App: name = Path(p).stem proj = project_manager.default_project(name) project_manager.save_project(proj, p) - if p not in self.project_paths: - self.project_paths.append(p) + if p not in self.project_paths: self.project_paths.append(p) self._switch_project(p) imgui.same_line() if imgui.button("Save All"): @@ -1709,8 +1696,8 @@ class App: self._flush_to_config() models.save_config(self.config) self.ai_status = "config saved" - ch, self.ui_word_wrap = imgui.checkbox("Word-Wrap (Read-only panels)", self.ui_word_wrap) - ch, self.ui_auto_scroll_comms = imgui.checkbox("Auto-scroll Comms History", self.ui_auto_scroll_comms) + ch, self.ui_word_wrap = imgui.checkbox("Word-Wrap (Read-only panels)", self.ui_word_wrap) + ch, self.ui_auto_scroll_comms = imgui.checkbox("Auto-scroll Comms History", self.ui_auto_scroll_comms) ch, self.ui_auto_scroll_tool_calls = imgui.checkbox("Auto-scroll Tool History", self.ui_auto_scroll_tool_calls) if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_projects_panel") @@ -1721,33 +1708,32 @@ class App: imgui.text_colored(C_IN, "System Path Configuration") imgui.separator() - def render_path_field(label: str, attr: str, key: str, tooltip: str): - info = path_info.get(key, {'source': 'unknown'}) - imgui.text(label) - if imgui.is_item_hovered(): imgui.set_tooltip(tooltip) - imgui.same_line() - imgui.text_disabled(f"(Source: {info['source']})") - - val = getattr(self, attr) - changed, new_val = imgui.input_text(f"##{key}", val) - if imgui.is_item_hovered(): imgui.set_tooltip(tooltip) - if changed: setattr(self, attr, new_val) - imgui.same_line() - if imgui.button(f"Browse##{key}"): - r = hide_tk_root() - d = filedialog.askdirectory(title=f"Select {label}") - r.destroy() - if d: setattr(self, attr, d) + def _render_path_field(label: str, attr: str, key: str, tooltip: str): + info = path_info.get(key, {'source': 'unknown'}) + imgui.text(label) + if imgui.is_item_hovered(): imgui.set_tooltip(tooltip) + imgui.same_line() + imgui.text_disabled(f"(Source: {info['source']})") + + val = getattr(self, attr) + changed, new_val = imgui.input_text(f"##{key}", val) + if imgui.is_item_hovered(): imgui.set_tooltip(tooltip) + if changed: setattr(self, attr, new_val) + imgui.same_line() + if imgui.button(f"Browse##{key}"): + r = hide_tk_root() + d = filedialog.askdirectory(title=f"Select {label}") + r.destroy() + if d: setattr(self, attr, d) def _render_external_tools_panel(self) -> None: - if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_external_tools_panel") - if imgui.button("Refresh External MCPs"): - self.event_queue.put("refresh_external_mcps", None) + if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_external_tools_panel") + if imgui.button("Refresh External MCPs"): self.event_queue.put("refresh_external_mcps", None) imgui.separator() # Server status indicators - manager = mcp_client.get_external_mcp_manager() + manager = mcp_client.get_external_mcp_manager() statuses = manager.get_servers_status() if statuses: imgui.text("Servers:") @@ -1755,12 +1741,9 @@ class App: imgui.same_line() # Green for running, Yellow for starting, Red for error, Gray for idle col = (0.5, 0.5, 0.5, 1.0) - if status == 'running': - col = (0.0, 1.0, 0.0, 1.0) - elif status == 'starting': - col = (1.0, 1.0, 0.0, 1.0) - elif status == 'error': - col = (1.0, 0.0, 0.0, 1.0) + if status == 'running': col = (0.0, 1.0, 0.0, 1.0) + elif status == 'starting': col = (1.0, 1.0, 0.0, 1.0) + elif status == 'error': col = (1.0, 0.0, 0.0, 1.0) imgui.color_button(f"##status_{sname}", col) imgui.same_line() imgui.text(sname) @@ -1794,14 +1777,12 @@ class App: self.config["tools"]["default_editor"]["default_editor"] = editor_name models.save_config(self.config) self.ai_status = f"Default editor set to: {editor_name}" - - - render_path_field("Logs Directory", "ui_logs_dir", "logs_dir", "Directory where session JSON-L logs and artifacts are stored.") - render_path_field("Scripts Directory", "ui_scripts_dir", "scripts_dir", "Directory for AI-generated PowerShell scripts.") + + _render_path_field("Logs Directory", "ui_logs_dir", "logs_dir", "Directory where session JSON-L logs and artifacts are stored.") + _render_path_field("Scripts Directory", "ui_scripts_dir", "scripts_dir", "Directory for AI-generated PowerShell scripts.") imgui.separator() - if imgui.button("Apply", imgui.ImVec2(120, 0)): - self._save_paths() + if imgui.button("Apply", imgui.ImVec2(120, 0)): self._save_paths() imgui.same_line() if imgui.button("Reset", imgui.ImVec2(120, 0)): self.init_state() @@ -1818,8 +1799,7 @@ class App: "scripts_dir": self.ui_scripts_dir } cfg_path = paths.get_config_path() - if cfg_path.exists(): - shutil.copy(cfg_path, str(cfg_path) + ".bak") + if cfg_path.exists(): shutil.copy(cfg_path, str(cfg_path) + ".bak") models.save_config(self.config) paths.reset_resolved() self.init_state() @@ -1871,8 +1851,7 @@ class App: imgui.separator() imgui.text(f"Status: {self.controller.rag_status}") - if imgui.button("Rebuild Index"): - self.controller.event_queue.put('click', 'btn_rebuild_rag_index') + if imgui.button("Rebuild Index"): self.controller.event_queue.put('click', 'btn_rebuild_rag_index') def _render_system_prompts_panel(self) -> None: imgui.text("Global System Prompt (all projects)") @@ -1882,24 +1861,19 @@ class App: if imgui.begin_combo("##global_preset", current_global): for name in preset_names: is_sel = (name == current_global) - if imgui.selectable(name, is_sel)[0]: - self.controller._apply_preset(name, "global") - if is_sel: - imgui.set_item_default_focus() + if imgui.selectable(name, is_sel)[0]: self.controller._apply_preset(name, "global") + if is_sel: imgui.set_item_default_focus() imgui.end_combo() imgui.same_line(0, 8) - if imgui.button("Manage Presets##global"): - self.show_preset_manager_window = True + if imgui.button("Manage Presets##global"): self.show_preset_manager_window = True imgui.set_item_tooltip("Open preset management modal") ch, self.ui_global_system_prompt = imgui.input_text_multiline("##gsp", self.ui_global_system_prompt, imgui.ImVec2(-1, 100)) imgui.separator() _, self.ui_use_default_base_prompt = imgui.checkbox("Use Default Base System Prompt", self.ui_use_default_base_prompt) imgui.same_line() - if imgui.button("Reset to Default##btn_reset_base_prompt"): - self.controller._cb_reset_base_prompt() + if imgui.button("Reset to Default##btn_reset_base_prompt"): self.controller._cb_reset_base_prompt() imgui.same_line() - if imgui.button("Show Diff##btn_show_base_prompt_diff"): - self.controller._cb_show_base_prompt_diff() + if imgui.button("Show Diff##btn_show_base_prompt_diff"): self.controller._cb_show_base_prompt_diff() imgui.set_item_tooltip("Compare current base prompt with the default.") imgui.same_line() @@ -1923,21 +1897,18 @@ class App: if imgui.begin_combo("##project_preset", current_project): for name in preset_names: is_sel = (name == current_project) - if imgui.selectable(name, is_sel)[0]: - self.controller._apply_preset(name, "project") - if is_sel: - imgui.set_item_default_focus() + if imgui.selectable(name, is_sel)[0]: self.controller._apply_preset(name, "project") + if is_sel: imgui.set_item_default_focus() imgui.end_combo() imgui.same_line(0, 8) - if imgui.button("Manage Presets##project"): - self.show_preset_manager_window = True + if imgui.button("Manage Presets##project"): self.show_preset_manager_window = True imgui.set_item_tooltip("Open preset management modal") ch, self.ui_project_system_prompt = imgui.input_text_multiline("##psp", self.ui_project_system_prompt, imgui.ImVec2(-1, 100)) def _render_agent_tools_panel(self) -> None: if imgui.collapsing_header("Active Tool Presets & Biases", imgui.TreeNodeFlags_.default_open): imgui.text("Tool Preset") - presets = self.controller.tool_presets + presets = self.controller.tool_presets preset_names = [""] + sorted(list(presets.keys())) active = getattr(self, "ui_active_tool_preset", "") @@ -1952,10 +1923,8 @@ class App: self.ui_active_tool_preset = preset_names[new_idx] imgui.same_line() - if imgui.button("Manage Presets##tools"): - self.show_tool_preset_manager_window = True - if imgui.is_item_hovered(): - imgui.set_tooltip("Configure tool availability and default modes.") + if imgui.button("Manage Presets##tools"): self.show_tool_preset_manager_window = True + if imgui.is_item_hovered(): imgui.set_tooltip("Configure tool availability and default modes.") imgui.dummy(imgui.ImVec2(0, 4)) imgui.text("Bias Profile") @@ -1964,8 +1933,7 @@ class App: self.ui_active_bias_profile = "" ai_client.set_bias_profile(None) for bname in sorted(self.controller.bias_profiles.keys()): - if not bname: - continue + if not bname: continue if imgui.selectable(bname, bname == getattr(self, 'ui_active_bias_profile', ""))[0]: self.ui_active_bias_profile = bname ai_client.set_bias_profile(bname) @@ -1989,14 +1957,10 @@ class App: if self.ui_tool_filter_category != "All" and self.ui_tool_filter_category != cat_name: continue if imgui.tree_node(cat_name): for tool in tools: - if tool.weight >= 5: - imgui.text_colored(vec4(255, 100, 100), "[HIGH]"); imgui.same_line() - elif tool.weight == 4: - imgui.text_colored(vec4(255, 255, 100), "[PREF]"); imgui.same_line() - elif tool.weight == 2: - imgui.text_colored(vec4(255, 150, 50), "[REJECT]"); imgui.same_line() - elif tool.weight <= 1: - imgui.text_colored(vec4(180, 180, 180), "[LOW]"); imgui.same_line() + if tool.weight >= 5: imgui.text_colored(vec4(255, 100, 100), "[HIGH]"); imgui.same_line() + elif tool.weight == 4: imgui.text_colored(vec4(255, 255, 100), "[PREF]"); imgui.same_line() + elif tool.weight == 2: imgui.text_colored(vec4(255, 150, 50), "[REJECT]"); imgui.same_line() + elif tool.weight <= 1: imgui.text_colored(vec4(180, 180, 180), "[LOW]"); imgui.same_line() imgui.text(tool.name); imgui.same_line(180) @@ -2090,8 +2054,7 @@ class App: self._selected_preset_idx = -1 if not is_embedded: imgui.same_line() - if imgui.button("Close##p", imgui.ImVec2(100, 0)): - self.show_preset_manager_window = False + if imgui.button("Close##p", imgui.ImVec2(100, 0)): self.show_preset_manager_window = False imgui.end_table() def _render_preset_manager_window(self, is_embedded: bool = False) -> None: @@ -2100,19 +2063,18 @@ class App: imgui.set_next_window_size(imgui.ImVec2(1000, 800), imgui.Cond_.first_use_ever) with imscope.window("Prompt Presets Manager", self.show_preset_manager_window) as (opened, visible): self.show_preset_manager_window = visible - if opened: - self._render_preset_manager_content(is_embedded=is_embedded) + if opened: self._render_preset_manager_content(is_embedded=is_embedded) else: self._render_preset_manager_content(is_embedded=is_embedded) def _render_tool_preset_manager_content(self, is_embedded: bool = False) -> None: avail = imgui.get_content_region_avail() - if not hasattr(self, "_tool_split_v"): self._tool_split_v = 0.4 - if not hasattr(self, "_bias_split_v"): self._bias_split_v = 0.6 - if not hasattr(self, "_tool_list_open"): self._tool_list_open = True - if not hasattr(self, "_bias_list_open"): self._bias_list_open = True + if not hasattr(self, "_tool_split_v"): self._tool_split_v = 0.4 + if not hasattr(self, "_bias_split_v"): self._bias_split_v = 0.6 + if not hasattr(self, "_tool_list_open"): self._tool_list_open = True + if not hasattr(self, "_bias_list_open"): self._bias_list_open = True if not hasattr(self, "_bias_weights_open"): self._bias_weights_open = True - if not hasattr(self, "_bias_cats_open"): self._bias_cats_open = True + if not hasattr(self, "_bias_cats_open"): self._bias_cats_open = True if imgui.begin_table("tp_main_split", 2, imgui.TableFlags_.resizable | imgui.TableFlags_.borders_inner_v): imgui.table_setup_column("List", imgui.TableColumnFlags_.width_fixed, 200) @@ -2151,7 +2113,7 @@ class App: imgui.end_table() rem_y = imgui.get_content_region_avail().y - 80 - if self._tool_list_open and self._bias_list_open: h1, h2 = rem_y * self._tool_split_v, rem_y - (rem_y * self._tool_split_v) - 10 + if self._tool_list_open and self._bias_list_open: h1, h2 = rem_y * self._tool_split_v, rem_y - (rem_y * self._tool_split_v) - 10 elif self._tool_list_open: h1, h2 = rem_y, 0 elif self._bias_list_open: h1, h2 = 0, rem_y else: h1, h2 = 0, 0 @@ -2284,8 +2246,7 @@ class App: imgui.set_next_window_size(imgui.ImVec2(1000, 800), imgui.Cond_.first_use_ever) with imscope.window("Tool Preset Manager", self.show_tool_preset_manager_window) as (opened, visible): self.show_tool_preset_manager_window = visible - if opened: - self._render_tool_preset_manager_content(is_embedded=is_embedded) + if opened: self._render_tool_preset_manager_content(is_embedded=is_embedded) else: self._render_preset_manager_content(is_embedded=is_embedded) @@ -2523,15 +2484,12 @@ class App: def _render_persona_selector_panel(self) -> None: if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_persona_selector_panel") imgui.text("Persona") - if not hasattr(self, 'ui_active_persona'): - self.ui_active_persona = "" + if not hasattr(self, 'ui_active_persona'): self.ui_active_persona = "" personas = getattr(self.controller, 'personas', {}) if imgui.begin_combo("##persona", self.ui_active_persona or "None"): - if imgui.selectable("None", not self.ui_active_persona)[0]: - self.ui_active_persona = "" + if imgui.selectable("None", not self.ui_active_persona)[0]: self.ui_active_persona = "" for pname in sorted(personas.keys()): - if not pname: - continue + if not pname: continue if imgui.selectable(pname, pname == self.ui_active_persona)[0]: self.ui_active_persona = pname if pname in personas: @@ -2542,7 +2500,6 @@ class App: self._editing_persona_bias_profile_id = persona.bias_profile or "" self._editing_persona_context_preset_id = getattr(persona, 'context_preset', '') or "" self._editing_persona_aggregation_strategy = getattr(persona, 'aggregation_strategy', '') or "" - import copy self._editing_persona_preferred_models_list = copy.deepcopy(persona.preferred_models) if persona.preferred_models else [] self._editing_persona_is_new = False @@ -2559,11 +2516,10 @@ class App: if first_model.get("max_output_tokens"): ai_client.max_output_tokens = first_model.get("max_output_tokens") self.max_tokens = first_model.get("max_output_tokens") - if first_model.get("history_trunc_limit"): + if first_model.get("history_trunc_limit"): self.history_trunc_limit = first_model.get("history_trunc_limit") - if persona.system_prompt: - self.ui_project_system_prompt = persona.system_prompt + if persona.system_prompt: self.ui_project_system_prompt = persona.system_prompt if persona.tool_preset: self.ui_active_tool_preset = persona.tool_preset ai_client.set_tool_preset(persona.tool_preset) @@ -2585,7 +2541,6 @@ class App: self._editing_persona_bias_profile_id = persona.bias_profile or "" self._editing_persona_context_preset_id = getattr(persona, 'context_preset', '') or "" self._editing_persona_aggregation_strategy = getattr(persona, 'aggregation_strategy', '') or "" - import copy self._editing_persona_preferred_models_list = copy.deepcopy(persona.preferred_models) if persona.preferred_models else [] self._editing_persona_scope = self.controller.persona_manager.get_persona_scope(persona.name) self._editing_persona_is_new = False @@ -2863,12 +2818,9 @@ class App: if f_path != self._cached_ast_file_path: outline = "" try: - if f_path.lower().endswith('.py'): - outline = mcp_client.py_get_code_outline(f_path) - elif f_path.lower().endswith(('.c', '.h')): - outline = mcp_client.ts_c_get_code_outline(f_path) - else: - outline = mcp_client.ts_cpp_get_code_outline(f_path) + if f_path.lower().endswith('.py'): outline = mcp_client.py_get_code_outline(f_path) + elif f_path.lower().endswith(('.c', '.h')): outline = mcp_client.ts_c_get_code_outline(f_path) + else: outline = mcp_client.ts_cpp_get_code_outline(f_path) except Exception as e: outline = f"Error fetching outline: {e}" @@ -2881,8 +2833,7 @@ class App: if m: indent_str, kind, name, start_ln, end_ln = m.groups() indent = len(indent_str) - while stack and stack[-1][0] >= indent: - stack.pop() + while stack and stack[-1][0] >= indent: stack.pop() stack.append((indent, name)) full_path = '::'.join([s[1] for s in stack]) self._cached_ast_nodes.append({ @@ -2909,13 +2860,12 @@ class App: #region: LEFT COLUMN (Tree) --- if imgui.begin_child("ast_tree_scroll", imgui.ImVec2(0, 600), True): - if not self._cached_ast_nodes: - imgui.text("No AST nodes found or error fetching outline.") + if not self._cached_ast_nodes: imgui.text("No AST nodes found or error fetching outline.") else: for node in self._cached_ast_nodes: - indent = node['indent'] - kind = node['kind'] - name = node['name'] + indent = node['indent'] + kind = node['kind'] + name = node['name'] full_path = node['full_path'] imgui.dummy(imgui.ImVec2(indent * 10, 0)) @@ -2926,14 +2876,11 @@ class App: current_mode = f_item.ast_mask.get(full_path, 'hide') imgui.push_id(full_path) - if imgui.radio_button("Def", current_mode == 'def'): - f_item.ast_mask[full_path] = 'def' + if imgui.radio_button("Def", current_mode == 'def'): f_item.ast_mask[full_path] = 'def' imgui.same_line() - if imgui.radio_button("Sig", current_mode == 'sig'): - f_item.ast_mask[full_path] = 'sig' + if imgui.radio_button("Sig", current_mode == 'sig'): f_item.ast_mask[full_path] = 'sig' imgui.same_line() - if imgui.radio_button("Hide", current_mode == 'hide'): - f_item.ast_mask[full_path] = 'hide' + if imgui.radio_button("Hide", current_mode == 'hide'): f_item.ast_mask[full_path] = 'hide' imgui.pop_id() imgui.end_child() #endregion: LEFT COLUMN (Tree) @@ -2953,14 +2900,12 @@ class App: deepest_node = None for node in self._cached_ast_nodes: if node['start_line'] <= line_num <= node['end_line']: - if deepest_node is None or node['indent'] > deepest_node['indent']: - deepest_node = node + if deepest_node is None or node['indent'] > deepest_node['indent']: deepest_node = node mode = 'hide' - if deepest_node: - mode = f_item.ast_mask.get(deepest_node['full_path'], 'hide') + if deepest_node: mode = f_item.ast_mask.get(deepest_node['full_path'], 'hide') - pos = imgui.get_cursor_screen_pos() + pos = imgui.get_cursor_screen_pos() line_height = imgui.get_text_line_height() if mode == 'def': @@ -2986,8 +2931,7 @@ class App: #endregion: AST Inspector - if not opened: - self.ui_inspecting_ast_file = None + if not opened: self.ui_inspecting_ast_file = None def _render_add_context_files_modal(self) -> None: if imgui.begin_popup_modal("Select Context Files", None, imgui.WindowFlags_.always_auto_resize)[0]: @@ -3034,11 +2978,9 @@ class App: _, self._new_workspace_profile_name = imgui.input_text("##profile_name", self._new_workspace_profile_name) imgui.text("Scope:") - if imgui.radio_button("Project", self._new_workspace_profile_scope == "project"): - self._new_workspace_profile_scope = "project" + if imgui.radio_button("Project", self._new_workspace_profile_scope == "project"): self._new_workspace_profile_scope = "project" imgui.same_line() - if imgui.radio_button("Global", self._new_workspace_profile_scope == "global"): - self._new_workspace_profile_scope = "global" + if imgui.radio_button("Global", self._new_workspace_profile_scope == "global"): self._new_workspace_profile_scope = "global" imgui.separator() if imgui.button("Save", (120, 0)): @@ -3067,7 +3009,7 @@ class App: imgui.separator() presets = self.controller.project.get('context_presets', {}) for name in sorted(presets.keys()): - preset = presets[name] + preset = presets[name] n_files = len(preset.get('files', [])) n_shots = len(preset.get('screenshots', [])) imgui.text(f"{name} ({n_files} files, {n_shots} shots)") @@ -3108,8 +3050,7 @@ class App: f_item.custom_slices.append(slice_data) def _render_context_screenshots(self) -> None: - for i, s in enumerate(self.screenshots): - imgui.text(s) + for i, s in enumerate(self.screenshots): imgui.text(s) def _render_context_batch_actions(self, total_lines: int, total_ast: int) -> None: imgui.text("Batch:") @@ -3117,22 +3058,18 @@ class App: if imgui.button(f"{mode.capitalize()}##batch"): for f in self.context_files: f_path = f.path if hasattr(f, "path") else str(f) - if f_path in self.ui_selected_context_files: - f.view_mode = mode + if f_path in self.ui_selected_context_files: f.view_mode = mode imgui.same_line() if imgui.button("Sel All##selall"): for f in self.context_files: f_path = f.path if hasattr(f, "path") else str(f) self.ui_selected_context_files.add(f_path) imgui.same_line() - if imgui.button("Unsel All##unselall"): - self.ui_selected_context_files.clear() + if imgui.button("Unsel All##unselall"): self.ui_selected_context_files.clear() imgui.same_line() - if imgui.button("Add Files"): - imgui.open_popup("Select Context Files") + if imgui.button("Add Files"): imgui.open_popup("Select Context Files") imgui.same_line() if imgui.button("Add All##addall"): - import copy context_paths = {f.path if hasattr(f, "path") else str(f) for f in self.context_files} for f in self.files: f_path = f.path if hasattr(f, "path") else str(f) @@ -3145,8 +3082,7 @@ class App: new_files = [] for f in self.context_files: f_path = f.path if hasattr(f, "path") else str(f) - if f_path not in self.ui_selected_context_files: - new_files.append(f) + if f_path not in self.ui_selected_context_files: new_files.append(f) self.context_files = new_files self.ui_selected_context_files.clear() imgui.same_line() @@ -3185,22 +3121,18 @@ class App: for idx in range(start, end + 1): item = self.context_files[idx] item_path = item.path if hasattr(item, "path") else str(item) - if is_sel: - self.ui_selected_context_files.add(item_path) - else: - self.ui_selected_context_files.discard(item_path) + if is_sel: self.ui_selected_context_files.add(item_path) + else: self.ui_selected_context_files.discard(item_path) else: - if is_sel: - self.ui_selected_context_files.add(f_path) - else: - self.ui_selected_context_files.discard(f_path) + if is_sel: self.ui_selected_context_files.add(f_path) + else: self.ui_selected_context_files.discard(f_path) self._last_selected_context_index = i imgui.same_line() - mtime = os.path.getmtime(f_path) if os.path.exists(f_path) else 0 + mtime = os.path.getmtime(f_path) if os.path.exists(f_path) else 0 cache_key = f"{f_path}_{mtime}" - stats = self._file_stats_cache.get(cache_key, {"lines": 0, "ast_elements": 0}) - f_name = os.path.basename(f_path) + stats = self._file_stats_cache.get(cache_key, {"lines": 0, "ast_elements": 0}) + f_name = os.path.basename(f_path) imgui.text(f"{f_name} (L: {stats.get('lines', 0)}, AST: {stats.get('ast_elements', 0)})") if f_path.lower().endswith(('.c', '.cpp', '.h', '.hpp', '.cxx', '.cc')): @@ -3222,8 +3154,7 @@ class App: self.show_text_viewer = True imgui.table_set_column_index(1) - if not hasattr(f_item, "view_mode"): - f_item.view_mode = "summary" + if not hasattr(f_item, "view_mode"): f_item.view_mode = "summary" view_modes = ["full", "summary", "skeleton", "outline", "masked", "none"] try: current_idx = view_modes.index(f_item.view_mode) @@ -3232,12 +3163,10 @@ class App: f_item.view_mode = "summary" imgui.set_next_item_width(120) changed_vm, new_idx = imgui.combo(f"##vm{i}", current_idx, view_modes) - if changed_vm: - f_item.view_mode = view_modes[new_idx] + if changed_vm: f_item.view_mode = view_modes[new_idx] imgui.same_line() - if imgui.button(f"[Save]##vpsave{i}"): - imgui.open_popup(f"save_vp_popup{i}") + if imgui.button(f"[Save]##vpsave{i}"): imgui.open_popup(f"save_vp_popup{i}") if imgui.begin_popup(f"save_vp_popup{i}"): imgui.text("Preset Name:") @@ -3250,13 +3179,11 @@ class App: imgui.end_popup() imgui.same_line() - if imgui.button(f"[Load]##vpload{i}"): - imgui.open_popup(f"load_vp_popup{i}") + if imgui.button(f"[Load]##vpload{i}"): imgui.open_popup(f"load_vp_popup{i}") if imgui.begin_popup(f"load_vp_popup{i}"): vp_names = sorted([vp.name for vp in self.controller.view_presets]) - if not vp_names: - imgui.text("No presets saved.") + if not vp_names: imgui.text("No presets saved.") for vp_name in vp_names: if imgui.selectable(vp_name): self.controller._cb_apply_view_preset(vp_name, f_item) @@ -3268,11 +3195,10 @@ class App: def _render_context_presets(self) -> None: imgui.text("Presets") - presets = self.controller.project.get('context_presets', {}) + presets = self.controller.project.get('context_presets', {}) preset_names = [""] + sorted(presets.keys()) active = getattr(self, "ui_active_context_preset", "") - if active not in preset_names: - active = "" + if active not in preset_names: active = "" try: idx = preset_names.index(active) except ValueError: @@ -3280,12 +3206,10 @@ class App: ch, new_idx = imgui.combo("##ctx_preset", idx, preset_names) if ch: self.ui_active_context_preset = preset_names[new_idx] - if preset_names[new_idx]: - self.load_context_preset(preset_names[new_idx]) + if preset_names[new_idx]: self.load_context_preset(preset_names[new_idx]) imgui.same_line() changed, new_name = imgui.input_text("##new_preset", getattr(self, "ui_new_context_preset_name", "")) - if changed: - self.ui_new_context_preset_name = new_name + if changed: self.ui_new_context_preset_name = new_name imgui.same_line() if imgui.button("Save##ctx"): if getattr(self, "ui_new_context_preset_name", "").strip(): @@ -3298,27 +3222,22 @@ class App: self.ui_active_context_preset = "" def _update_context_file_stats(self) -> tuple[int, int]: - if not hasattr(self, '_file_stats_cache'): - self._file_stats_cache = {} - if not hasattr(self, '_file_stats_queue'): - self._file_stats_queue = [] - if not hasattr(self, '_file_stats_worker_active'): - self._file_stats_worker_active = False - + if not hasattr(self, '_file_stats_cache'): self._file_stats_cache = {} + if not hasattr(self, '_file_stats_queue'): self._file_stats_queue = [] + if not hasattr(self, '_file_stats_worker_active'): self._file_stats_worker_active = False total_lines = 0 - total_ast = 0 + total_ast = 0 missing_keys = [] for f in self.context_files: - f_path = f.path if hasattr(f, "path") else str(f) - mtime = os.path.getmtime(f_path) if os.path.exists(f_path) else 0 + f_path = f.path if hasattr(f, "path") else str(f) + mtime = os.path.getmtime(f_path) if os.path.exists(f_path) else 0 cache_key = f"{f_path}_{mtime}" - if cache_key not in self._file_stats_cache: - missing_keys.append((f_path, cache_key)) + if cache_key not in self._file_stats_cache: missing_keys.append((f_path, cache_key)) else: - stats = self._file_stats_cache[cache_key] + stats = self._file_stats_cache[cache_key] total_lines += stats.get("lines", 0) - total_ast += stats.get("ast_elements", 0) + total_ast += stats.get("ast_elements", 0) if missing_keys and not self._file_stats_worker_active: def _stats_worker(): @@ -3330,7 +3249,6 @@ class App: self._file_stats_worker_active = False threading.Thread(target=_stats_worker, daemon=True).start() - return total_lines, total_ast #endregion: Context Management @@ -3691,9 +3609,9 @@ class App: def _render_thinking_indicator(self) -> None: is_thinking = self.ai_status in ['sending...', 'streaming...', 'running powershell...'] if is_thinking: - val = math.sin(time.time() * 10 * math.pi) + val = math.sin(time.time() * 10 * math.pi) alpha = 1.0 if val > 0 else 0.0 - c = vec4(255, 50, 50, alpha) if theme.is_nerv_active() else vec4(255, 100, 100, alpha) + c = vec4(255, 50, 50, alpha) if theme.is_nerv_active() else vec4(255, 100, 100, alpha) imgui.text_colored(c, "THINKING..."); imgui.same_line() def _render_message_panel(self) -> None: @@ -3701,46 +3619,38 @@ class App: # LIVE indicator is_live = self.ai_status in ["running powershell...", "fetching url...", "searching web...", "powershell done, awaiting AI..."] if is_live: - val = math.sin(time.time() * 10 * math.pi) + val = math.sin(time.time() * 10 * math.pi) alpha = 1.0 if val > 0 else 0.0 - c = imgui.ImVec4(0.39, 1.0, 0.39, alpha) - if theme.is_nerv_active(): - c = vec4(80, 255, 80, alpha) # DATA_GREEN for LIVE in NERV + c = imgui.ImVec4(0.39, 1.0, 0.39, alpha) + if theme.is_nerv_active(): c = vec4(80, 255, 80, alpha) # DATA_GREEN for LIVE in NERV imgui.text_colored(c, "LIVE") imgui.separator() ch, self.ui_ai_input = imgui.input_text_multiline("##ai_in", self.ui_ai_input, imgui.ImVec2(-1, -40)) # Keyboard shortcuts io = imgui.get_io() ctrl_l = io.key_ctrl and imgui.is_key_pressed(imgui.Key.l) - if ctrl_l: - self.ui_ai_input = "" + if ctrl_l: self.ui_ai_input = "" imgui.separator() is_busy = self.ai_status in ['sending...', 'streaming...'] send_busy = False with self._send_thread_lock: - if self.send_thread and self.send_thread.is_alive(): - send_busy = True + if self.send_thread and self.send_thread.is_alive(): send_busy = True if is_busy: send_busy = True imgui.begin_disabled(send_busy) ctrl_enter = io.key_ctrl and imgui.is_key_pressed(imgui.Key.enter) label = "Gen + Send (Busy)" if send_busy else "Gen + Send" - if (imgui.button(label) or ctrl_enter) and not send_busy: - self._handle_generate_send() + if (imgui.button(label) or ctrl_enter) and not send_busy: self._handle_generate_send() imgui.end_disabled() imgui.same_line() - if imgui.button("MD Only"): - self._handle_md_only() + if imgui.button("MD Only"): self._handle_md_only() imgui.same_line() - if imgui.button("Inject File"): - self.show_inject_modal = True + if imgui.button("Inject File"): self.show_inject_modal = True imgui.same_line() - if imgui.button("-> History"): - if self.ui_ai_input: - self.disc_entries.append({"role": "User", "content": self.ui_ai_input, "collapsed": False, "ts": project_manager.now_ts()}) + if imgui.button("-> History"): + if self.ui_ai_input: self.disc_entries.append({"role": "User", "content": self.ui_ai_input, "collapsed": False, "ts": project_manager.now_ts()}) imgui.same_line() - if imgui.button("Reset"): - self._handle_reset_session() + if imgui.button("Reset"): self._handle_reset_session() if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_message_panel") def _render_synthesis_panel(self) -> None: @@ -3750,19 +3660,15 @@ class App: """ imgui.text("Select takes to synthesize:") discussions = self.project.get('discussion', {}).get('discussions', {}) - if not hasattr(self, 'ui_synthesis_selected_takes'): - self.ui_synthesis_selected_takes = {name: False for name in discussions} - if not hasattr(self, 'ui_synthesis_prompt'): - self.ui_synthesis_prompt = "" - for name in discussions: - _, self.ui_synthesis_selected_takes[name] = imgui.checkbox(name, self.ui_synthesis_selected_takes.get(name, False)) + if not hasattr(self, 'ui_synthesis_selected_takes'): self.ui_synthesis_selected_takes = {name: False for name in discussions} + if not hasattr(self, 'ui_synthesis_prompt'): self.ui_synthesis_prompt = "" + for name in discussions: _, self.ui_synthesis_selected_takes[name] = imgui.checkbox(name, self.ui_synthesis_selected_takes.get(name, False)) imgui.spacing() imgui.text("Synthesis Prompt:") _, self.ui_synthesis_prompt = imgui.input_text_multiline("##synthesis_prompt", self.ui_synthesis_prompt, imgui.ImVec2(-1, 100)) if imgui.button("Generate Synthesis"): selected = [name for name, sel in self.ui_synthesis_selected_takes.items() if sel] if len(selected) > 1: - from src import synthesis_formatter discussions_dict = self.project.get('discussion', {}).get('discussions', {}) takes_dict = {name: discussions_dict.get(name, {}).get('history', []) for name in selected} diff_text = synthesis_formatter.format_takes_diff(takes_dict) @@ -3801,15 +3707,13 @@ class App: full_md, _, _ = src.aggregate.run(flat) self._focus_md_cache[cp_name] = full_md display_md = full_md - if imgui.button("Copy"): - imgui.set_clipboard_text(display_md) + if imgui.button("Copy"): imgui.set_clipboard_text(display_md) imgui.begin_child("last_agg_md", imgui.ImVec2(0, 0), True) markdown_helper.render(display_md, context_id="snapshot_agg") imgui.end_child() imgui.end_tab_item() if imgui.begin_tab_item("System Prompt")[0]: - if imgui.button("Copy"): - imgui.set_clipboard_text(self.last_resolved_system_prompt) + if imgui.button("Copy"): imgui.set_clipboard_text(self.last_resolved_system_prompt) imgui.begin_child("last_sys_prompt", imgui.ImVec2(0, 0), True) markdown_helper.render(self.last_resolved_system_prompt, context_id="snapshot_sys") imgui.end_child() @@ -3852,8 +3756,7 @@ class App: if self.ai_response: segments, response = thinking_parser.parse_thinking_trace(self.ai_response) entry = {"role": "AI", "content": response, "collapsed": True, "ts": project_manager.now_ts()} - if segments: - entry["thinking_segments"] = [{"content": s.content, "marker": s.marker} for s in segments] + if segments: entry["thinking_segments"] = [{"content": s.content, "marker": s.marker} for s in segments] self.disc_entries.append(entry) if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_response_panel") @@ -3969,8 +3872,7 @@ class App: def _render_comms_history_panel(self) -> None: if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_comms_history_panel") st_col = vec4(200, 220, 160) - if theme.is_nerv_active(): - st_col = vec4(80, 255, 80) # DATA_GREEN for status in NERV + if theme.is_nerv_active(): st_col = vec4(80, 255, 80) # DATA_GREEN for status in NERV imgui.text_colored(st_col, f"Status: {self.ai_status}") imgui.same_line() if imgui.button("Clear##comms"): @@ -4082,8 +3984,7 @@ class App: self._scroll_comms_to_bottom = False imgui.end_child() - if self.is_viewing_prior_session: - imgui.pop_style_color() + if self.is_viewing_prior_session: imgui.pop_style_color() if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_comms_history_panel") #endregion: Operations Monitor @@ -4228,10 +4129,10 @@ class App: else: imgui.begin_child("base_prompt_diff_scroll", imgui.ImVec2(800, 500), True) for line in diff: - if line.startswith("+++") or line.startswith("---") or line.startswith("@@"): imgui.text_colored(vec4(77, 178, 255), line.rstrip()) - elif line.startswith("+"): imgui.text_colored(vec4(51, 230, 51), line.rstrip()) - elif line.startswith("-"): imgui.text_colored(vec4(230, 51, 51), line.rstrip()) - else: imgui.text(line.rstrip()) + if line.startswith("+++") or line.startswith("---") or line.startswith("@@"): imgui.text_colored(vec4(77, 178, 255), line.rstrip()) + elif line.startswith("+"): imgui.text_colored(vec4(51, 230, 51), line.rstrip()) + elif line.startswith("-"): imgui.text_colored(vec4(230, 51, 51), line.rstrip()) + else: imgui.text(line.rstrip()) imgui.end_child() imgui.separator() @@ -4254,7 +4155,6 @@ class App: imgui.open_popup("Apply Patch?") with imscope.popup_modal("Apply Patch?", True, imgui.WindowFlags_.always_auto_resize) as (opened, _): if opened: - from src import shaders p_min = imgui.get_window_pos() p_max = imgui.ImVec2(p_min.x + imgui.get_window_size().x, p_min.y + imgui.get_window_size().y) shaders.draw_soft_shadow(imgui.get_background_draw_list(), p_min, p_max, imgui.ImVec4(0, 0, 0, 0.6), 25.0, 6.0) @@ -4263,8 +4163,7 @@ class App: imgui.separator() if self._pending_patch_files: imgui.text("Files to modify:") - for f in self._pending_patch_files: - imgui.text(f" - {f}") + for f in self._pending_patch_files: imgui.text(f" - {f}") imgui.separator() if self._patch_error_message: imgui.text_colored(vec4(255, 77, 77), f"Error: {self._patch_error_message}") @@ -4274,18 +4173,13 @@ class App: if self._pending_patch_text: diff_lines = self._pending_patch_text.split("\n") for line in diff_lines: - if line.startswith("+++") or line.startswith("---") or line.startswith("@@"): - imgui.text_colored(vec4(77, 178, 255), line) - elif line.startswith("+"): - imgui.text_colored(vec4(51, 230, 51), line) - elif line.startswith("-"): - imgui.text_colored(vec4(230, 51, 51), line) - else: - imgui.text(line) + if line.startswith("+++") or line.startswith("---") or line.startswith("@@"): imgui.text_colored(vec4(77, 178, 255), line) + elif line.startswith("+"): imgui.text_colored(vec4(51, 230, 51), line) + elif line.startswith("-"): imgui.text_colored(vec4(230, 51, 51), line) + else: imgui.text(line) imgui.end_child() imgui.separator() - if imgui.button("Open in External Editor"): - self._open_patch_in_external_editor() + if imgui.button("Open in External Editor"): self._open_patch_in_external_editor() imgui.same_line() if imgui.button("Apply Patch"): self._apply_pending_patch() @@ -4304,7 +4198,6 @@ class App: self._patch_error_message = "No patch to apply" return try: - from src.diff_viewer import apply_patch_to_file base_dir = str(self.controller.current_project_dir) if hasattr(self.controller, 'current_project_dir') else "." success, msg = apply_patch_to_file(self._pending_patch_text, base_dir) if success: @@ -4337,8 +4230,7 @@ class App: return temp_path = create_temp_modified_file(self._pending_patch_text) result = launcher.launch_diff(None, original_path, temp_path) - if result is None: - self._patch_error_message = "Failed to launch external editor" + if result is None: self._patch_error_message = "Failed to launch external editor" else: self._patch_error_message = None self._vscode_diff_process = result @@ -4369,29 +4261,22 @@ class App: else: imgui.text("Default Editor:") editor_names = sorted(list(editors.keys())) - if default_name and default_name in editor_names: - current_idx = editor_names.index(default_name) - else: - current_idx = 0 + if default_name and default_name in editor_names: current_idx = editor_names.index(default_name) + else: current_idx = 0 changed, new_idx = imgui.combo("##editor_combo", current_idx, editor_names) - if changed: - self._set_external_editor_default(editor_names[new_idx]) + if changed: self._set_external_editor_default(editor_names[new_idx]) imgui.text("") imgui.text("Configured Editors:") imgui.separator() for name in editor_names: editor = editors.get(name) - if not editor: - continue + if not editor: continue is_default = name == default_name marker = " (default)" if is_default else "" - if is_default: - imgui.text_colored(C_IN, f" {name}{marker}") - else: - imgui.text(f" {name}{marker}") + if is_default: imgui.text_colored(C_IN, f" {name}{marker}") + else: imgui.text(f" {name}{marker}") imgui.text(f" {editor.path}") - if editor.diff_args: - imgui.textDisabled(f" diff: {editor.diff_args}") + if editor.diff_args: imgui.textDisabled(f" diff: {editor.diff_args}") imgui.text("") imgui.text("Config: config.toml [tools.text_editors]") imgui.text("Override: manual_slop.toml default_editor") @@ -4410,8 +4295,7 @@ class App: self._pending_dialog_open = False if imgui.begin_popup_modal("Approve PowerShell Command", None, imgui.WindowFlags_.always_auto_resize)[0]: - if not dlg: - imgui.close_current_popup() + if not dlg: imgui.close_current_popup() else: imgui.text("The AI wants to run the following PowerShell script:") imgui.text_colored(vec4(200, 200, 100), f"base_dir: {dlg._base_dir}") @@ -4430,8 +4314,7 @@ class App: dlg._approved = True dlg._done = True dlg._condition.notify_all() - with self._pending_dialog_lock: - self._pending_dialog = None + with self._pending_dialog_lock: self._pending_dialog = None imgui.close_current_popup() imgui.same_line() if imgui.button("Reject", imgui.ImVec2(120, 0)): @@ -4439,8 +4322,7 @@ class App: dlg._approved = False dlg._done = True dlg._condition.notify_all() - with self._pending_dialog_lock: - self._pending_dialog = None + with self._pending_dialog_lock: self._pending_dialog = None imgui.close_current_popup() imgui.end_popup() @@ -4750,8 +4632,7 @@ def hello(): self._show_add_ticket_form = False self._push_mma_state_update() imgui.same_line() - if imgui.button("Cancel"): - self._show_add_ticket_form = False + if imgui.button("Cancel"): self._show_add_ticket_form = False imgui.end_child() else: imgui.text_disabled("No active MMA track or tickets.") @@ -4911,8 +4792,7 @@ def hello(): if imgui.begin_popup_modal("Cycle Detected!", None, imgui.WindowFlags_.always_auto_resize)[0]: imgui.text_colored(imgui.ImVec4(1, 0.3, 0.3, 1), "The dependency graph contains a cycle!") imgui.text("Please remove the circular dependency.") - if imgui.button("OK"): - imgui.close_current_popup() + if imgui.button("OK"): imgui.close_current_popup() imgui.end_popup() def _render_mma_track_summary(self) -> None: