Private
Public Access
0
0

style(themes): compact TOML formatting and lift semantic colors

This commit is contained in:
2026-06-05 00:02:46 -04:00
parent 06e305aba6
commit 7ea52cbbe8
16 changed files with 915 additions and 516 deletions
+104 -104
View File
@@ -80,22 +80,23 @@ def hide_tk_root() -> Tk:
def vec4(r: float, g: float, b: float, a: float = 1.0) -> imgui.ImVec4:
return imgui.ImVec4(r/255.0, g/255.0, b/255.0, a)
C_OUT: imgui.ImVec4 = vec4(100, 200, 255)
C_IN: imgui.ImVec4 = vec4(140, 255, 160)
C_REQ: imgui.ImVec4 = vec4(255, 220, 100)
C_RES: imgui.ImVec4 = vec4(180, 255, 180)
C_TC: imgui.ImVec4 = vec4(255, 180, 80)
C_TR: imgui.ImVec4 = vec4(180, 220, 255)
C_TRS: imgui.ImVec4 = vec4(200, 180, 255)
C_LBL: imgui.ImVec4 = vec4(180, 180, 180)
C_VAL: imgui.ImVec4 = vec4(220, 220, 220)
C_KEY: imgui.ImVec4 = vec4(140, 200, 255)
C_NUM: imgui.ImVec4 = vec4(180, 255, 180)
C_TRM: imgui.ImVec4 = vec4(160, 160, 150) # Trimmed/Cruft
C_SUB: imgui.ImVec4 = vec4(220, 200, 120)
# Standard Color Constants (now bound to the theming system)
def C_OUT() -> imgui.ImVec4: return theme.get_color("status_info")
def C_IN() -> imgui.ImVec4: return theme.get_color("status_success")
def C_REQ() -> imgui.ImVec4: return theme.get_color("status_warning")
def C_RES() -> imgui.ImVec4: return theme.get_color("status_success")
def C_TC() -> imgui.ImVec4: return theme.get_color("status_warning")
def C_TR() -> imgui.ImVec4: return theme.get_color("status_info")
def C_TRS() -> imgui.ImVec4: return theme.get_color("status_info")
def C_LBL() -> imgui.ImVec4: return theme.get_color("text_disabled")
def C_VAL() -> imgui.ImVec4: return theme.get_color("text")
def C_KEY() -> imgui.ImVec4: return theme.get_color("status_info")
def C_NUM() -> imgui.ImVec4: return theme.get_color("status_success")
def C_TRM() -> imgui.ImVec4: return theme.get_color("text_disabled")
def C_SUB() -> imgui.ImVec4: return theme.get_color("text_disabled")
DIR_COLORS: dict[str, imgui.ImVec4] = {"OUT": C_OUT, "IN": C_IN}
KIND_COLORS: dict[str, imgui.ImVec4] = {"request": C_REQ, "response": C_RES, "tool_call": C_TC, "tool_result": C_TR, "tool_result_send": C_TRS}
DIR_COLORS: dict[str, typing.Callable[[], imgui.ImVec4]] = {"OUT": C_OUT, "IN": C_IN}
KIND_COLORS: dict[str, typing.Callable[[], imgui.ImVec4]] = {"request": C_REQ, "response": C_RES, "tool_call": C_TC, "tool_result": C_TR, "tool_result_send": C_TRS}
HEAVY_KEYS: set[str] = {"message", "text", "script", "output", "content"}
def render_text_viewer(app: App, label: str, content: str, text_type: str = 'text', force_open: bool = False, id_suffix: str = "") -> None:
@@ -783,7 +784,7 @@ class App:
if self.perf_profiling_enabled: self.perf_monitor.start_component("_gui_func")
try:
if self.is_viewing_prior_session:
with imscope.style_color(imgui.Col_.window_bg, vec4(50, 40, 20)):
with imscope.style_color(imgui.Col_.window_bg, theme.get_color("bubble_vendor")):
render_main_interface(self)
else:
render_main_interface(self)
@@ -1378,9 +1379,9 @@ def render_usage_analytics_panel(app: App) -> None:
if app.controller.rag_config and app.controller.rag_config.enabled:
# imgui.same_line()
status = app.controller.rag_status
if status == "indexing...": color = vec4(100, 255, 100)
elif status == "error": color = vec4(255, 100, 100)
else: color = vec4(180, 180, 180)
if status == "indexing...": color = theme.get_color("status_success")
elif status == "error": color = theme.get_color("status_error")
else: color = theme.get_color("text_disabled")
imgui.text_colored(color, f"[RAG: {status}]")
if imgui.is_item_hovered(): imgui.set_tooltip(f"RAG is enabled. Status: {status}. Click to rebuild index.")
@@ -1448,7 +1449,7 @@ def render_diagnostics_panel(app: App) -> None:
imgui.text(comp_name)
imgui.table_next_column()
if avg_val > 10.0:
imgui.text_colored(imgui.ImVec4(1.0, 0.2, 0.2, 1.0), f"{avg_val:.2f}")
imgui.text_colored(theme.get_color("status_error"), f"{avg_val:.2f}")
else:
imgui.text(f"{avg_val:.2f}")
imgui.table_next_column()
@@ -1512,7 +1513,7 @@ def render_cache_panel(app: App) -> None:
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)
color = theme.get_color("status_success")
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)
@@ -1558,7 +1559,7 @@ def render_tool_analytics_panel(app: App) -> None:
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}%")
if fail_pct > 0: imgui.text_colored(theme.get_color("status_error"), f"{fail_pct:.0f}%")
else: imgui.text("0%")
imgui.end_table()
if app.perf_profiling_enabled: app.perf_monitor.end_component("_render_tool_analytics_panel")
@@ -1588,9 +1589,9 @@ def render_token_budget_panel(app: App) -> None:
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 = theme.get_color("status_success")
elif pct < 80.0: color = theme.get_color("status_warning")
else: color = theme.get_color("status_error")
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()
@@ -1629,14 +1630,14 @@ def render_token_budget_panel(app: App) -> None:
imgui.table_set_column_index(0); render_selectable_label(app, f"tier_{tier}", tier, width=-1)
imgui.table_set_column_index(1); render_selectable_label(app, f"model_{tier}", model.split("-")[0], width=-1)
imgui.table_set_column_index(2); render_selectable_label(app, f"tokens_{tier}", f"{tokens:,}", width=-1)
imgui.table_set_column_index(3); render_selectable_label(app, f"cost_{tier}", f"${cost:.4f}", width=-1, color=imgui.ImVec4(0.2, 0.9, 0.2, 1))
imgui.table_set_column_index(3); render_selectable_label(app, f"cost_{tier}", f"${cost:.4f}", width=-1, color=theme.get_color("status_success"))
imgui.end_table()
tier_total = sum(cost_tracker.estimate_cost(stats.get('model', ''), stats.get('input', 0), stats.get('output', 0)) for stats in app.mma_tier_usage.values())
render_selectable_label(app, "session_total_cost", f"Session Total: ${tier_total:.4f}", width=-1, color=imgui.ImVec4(0, 1, 0, 1))
render_selectable_label(app, "session_total_cost", f"Session Total: ${tier_total:.4f}", width=-1, color=theme.get_color("status_success"))
else:
imgui.text_disabled("No MMA tier usage data")
if stats.get("would_trim"):
imgui.text_colored(imgui.ImVec4(1.0, 0.3, 0.0, 1.0), "WARNING: Next call will trim history")
imgui.text_colored(theme.get_color("status_warning"), "WARNING: Next call will trim history")
trimmable = stats.get("trimmable_turns", 0)
if trimmable: imgui.text_disabled(f"Trimmable turns: {trimmable}")
msgs = stats.get("messages")
@@ -1704,7 +1705,7 @@ def render_log_management(app: App) -> None:
imgui.table_next_column()
whitelisted = s_data.get("whitelisted", False)
if whitelisted:
imgui.text_colored(vec4(255, 215, 0), "YES")
imgui.text_colored(theme.get_color("status_warning"), "YES")
else:
imgui.text("NO")
metadata = s_data.get("metadata") or {}
@@ -2015,10 +2016,10 @@ def render_agent_tools_panel(app: App) -> None:
if app.ui_tool_filter_category != "All" and app.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(theme.get_color("status_error"), "[HIGH]"); imgui.same_line()
elif tool.weight == 4: imgui.text_colored(theme.get_color("status_warning"), "[PREF]"); imgui.same_line()
elif tool.weight == 2: imgui.text_colored(theme.get_color("status_warning"), "[REJECT]"); imgui.same_line()
elif tool.weight <= 1: imgui.text_colored(theme.get_color("text_disabled"), "[LOW]"); imgui.same_line()
imgui.text(tool.name); imgui.same_line(180)
@@ -2197,9 +2198,9 @@ def render_base_prompt_diff_modal(app: App) -> None:
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())
if line.startswith("+++") or line.startswith("---") or line.startswith("@@"): imgui.text_colored(theme.get_color("diff_header"), line.rstrip())
elif line.startswith("+"): imgui.text_colored(theme.get_color("diff_added"), line.rstrip())
elif line.startswith("-"): imgui.text_colored(theme.get_color("diff_removed"), line.rstrip())
else: imgui.text(line.rstrip())
imgui.end_child()
@@ -2740,9 +2741,9 @@ def render_files_and_media(app: App) -> None:
imgui.table_set_column_index(2)
if in_context:
imgui.text_colored(imgui.ImVec4(0.3, 0.8, 0.3, 1), "Active")
imgui.text_colored(theme.get_color("status_success"), "Active")
elif is_cached:
imgui.text_colored(imgui.ImVec4(0.3, 0.8, 1, 1), "Cached")
imgui.text_colored(theme.get_color("status_info"), "Cached")
else:
imgui.text_disabled(" - ")
imgui.end_table()
@@ -3048,23 +3049,23 @@ def render_ast_inspector_modal(app: App) -> None:
mode = 'hide'
if deepest_node: mode = getattr(f_item, 'ast_mask', {}).get(deepest_node['full_path'], 'hide')
if mode == 'def':
draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + avail_width, pos.y + line_height), imgui.get_color_u32(imgui.ImVec4(0, 1.0, 0, 0.15)))
draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + avail_width, pos.y + line_height), imgui.get_color_u32(theme.get_color("slice_auto", alpha=0.15)))
elif mode == 'sig':
draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + avail_width, pos.y + line_height), imgui.get_color_u32(imgui.ImVec4(0, 0, 1.0, 0.15)))
draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + avail_width, pos.y + line_height), imgui.get_color_u32(theme.get_color("slice_selection", alpha=0.15)))
elif deepest_node and deepest_node['full_path'] == getattr(app, '_hovered_ast_node', None):
draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + avail_width, pos.y + line_height), imgui.get_color_u32(imgui.ImVec4(1.0, 1.0, 0, 0.2)))
draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + avail_width, pos.y + line_height), imgui.get_color_u32(theme.get_color("status_warning", alpha=0.2)))
# 2. Slice Highlight
if hasattr(f_item, 'custom_slices'):
is_auto = any(slc['start_line'] <= line_num <= slc['end_line'] for slc in f_item.custom_slices if slc.get('tag') == 'auto-ast')
is_man = any(slc['start_line'] <= line_num <= slc['end_line'] for slc in f_item.custom_slices if slc.get('tag') != 'auto-ast')
if is_man: draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + avail_width, pos.y + line_height), imgui.get_color_u32(imgui.ImVec4(1.0, 0.65, 0, 0.2)))
elif is_auto and mode == 'hide': draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + avail_width, pos.y + line_height), imgui.get_color_u32(imgui.ImVec4(0, 1.0, 0, 0.1)))
if is_man: draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + avail_width, pos.y + line_height), imgui.get_color_u32(theme.get_color("slice_manual", alpha=0.2)))
elif is_auto and mode == 'hide': draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + avail_width, pos.y + line_height), imgui.get_color_u32(theme.get_color("slice_auto", alpha=0.1)))
# 3. Active Selection Highlight
if getattr(app, '_slice_sel_start', -1) != -1 and getattr(app, '_slice_sel_end', -1) != -1:
s, e = min(app._slice_sel_start, app._slice_sel_end), max(app._slice_sel_start, app._slice_sel_end)
if s <= line_num <= e: draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + avail_width, pos.y + line_height), imgui.get_color_u32(imgui.ImVec4(0.4, 0.4, 1.0, 0.3)))
if s <= line_num <= e: draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + avail_width, pos.y + line_height), imgui.get_color_u32(theme.get_color("slice_selection", alpha=0.3)))
imgui.selectable(f"{line_num:4} | {line_text}##ln{line_num}", False)
if imgui.is_item_clicked(): app._slice_sel_start = line_num; app._slice_sel_end = line_num
@@ -3234,7 +3235,7 @@ def render_context_files_table(app: App) -> None:
imgui.end_popup()
if hasattr(f_item, "custom_slices") and f_item.custom_slices:
imgui.same_line()
imgui.text_colored(imgui.ImVec4(1.0, 0.5, 0.0, 1.0), "[Slices Active]")
imgui.text_colored(theme.get_color("status_warning"), "[Slices Active]")
def render_context_presets(app: App) -> None:
presets = app.controller.project.get('context_presets', {})
@@ -3389,7 +3390,7 @@ def render_thinking_trace(app: App, entry: dict, segments: list[dict], entry_ind
if not segments:
return
# Tint thinking trace background slightly differently
with imscope.style_color(imgui.Col_.child_bg, imgui.ImVec4(0.15, 0.14, 0.10, 0.7)), \
with imscope.style_color(imgui.Col_.child_bg, theme.get_color("bubble_vendor", alpha=0.7)), \
theme.ai_text_style():
with imscope.indent():
show_content = True
@@ -3458,7 +3459,7 @@ def render_discussion_entry(app: App, entry: dict, index: int) -> None:
if usage:
inp, out, cache = usage.get("input_tokens", 0), usage.get("output_tokens", 0), usage.get("cache_read_input_tokens", 0)
u_str = f" in:{inp} out:{out}" + (f" cache:{cache}" if cache else "")
imgui.same_line(); imgui.text_colored(imgui.ImVec4(0.4, 0.6, 0.7, 1.0), u_str)
imgui.same_line(); imgui.text_colored(theme.get_color("status_info"), u_str)
if collapsed:
imgui.same_line()
@@ -3584,10 +3585,10 @@ def render_session_insights_panel(app: App) -> None:
completed = insights.get('completed_tickets', 0)
efficiency = insights.get('efficiency', 0)
def render_prior_session_view(app: App) -> None:
with imscope.style_color(imgui.Col_.child_bg, vec4(50, 40, 20)):
with imscope.style_color(imgui.Col_.child_bg, theme.get_color("bubble_vendor")):
if imgui.button("Exit Prior Session"): app.controller.cb_exit_prior_session(); app._comms_log_dirty = True
imgui.same_line()
imgui.text_colored(vec4(200, 180, 100), f"({len(app.prior_disc_entries)} entries)")
imgui.text_colored(theme.get_color("status_warning"), f"({len(app.prior_disc_entries)} entries)")
imgui.separator()
avail = imgui.get_content_region_avail()
with imscope.child("prior_scroll", imgui.ImVec2(avail.x, avail.y), imgui.WindowFlags_.horizontal_scrollbar):
@@ -3597,12 +3598,12 @@ def render_prior_session_view(app: App) -> None:
if imgui.button("+" if collapsed else "-"): entry["collapsed"] = not collapsed
imgui.same_line(); role, ts = entry.get("role", "??"), entry.get("ts", "")
imgui.text_colored(C_LBL, f"[{role}]")
if ts: imgui.same_line(); imgui.text_colored(vec4(160, 160, 160), str(ts))
if ts: imgui.same_line(); imgui.text_colored(theme.get_color("text_disabled"), str(ts))
content = entry.get("content", "")
if collapsed:
imgui.same_line(); preview = content.replace("\n", " ")[:80]
if len(content) > 80: preview += "..."
imgui.text_colored(vec4(180, 180, 180), preview)
imgui.text_colored(theme.get_color("text_disabled"), preview)
else:
with theme.ai_text_style():
markdown_helper.render(content, context_id=f'prior_disc_{idx}')
@@ -3649,8 +3650,8 @@ def render_synthesis_panel(app: App) -> None:
def render_comms_history_panel(app: App) -> None:
if app.perf_profiling_enabled: app.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
st_col = theme.get_color("text_disabled")
if theme.is_nerv_active(): st_col = theme.get_color("status_success") # DATA_GREEN for status in NERV
imgui.text_colored(st_col, f"Status: {app.ai_status}")
imgui.same_line()
if imgui.button("Clear##comms"):
@@ -3693,7 +3694,7 @@ def render_comms_history_panel(app: App) -> None:
# Row 1: #Idx TS DIR KIND Provider/Model [Tier]
imgui.text_colored(C_LBL, f"#{i_display}"); imgui.same_line()
imgui.text_colored(vec4(160, 160, 160), ts)
imgui.text_colored(theme.get_color("text_disabled"), ts)
latency = entry.get("latency") or entry.get("metadata", {}).get("latency")
if latency:
@@ -3703,7 +3704,7 @@ def render_comms_history_panel(app: App) -> None:
ticket_id = entry.get("mma_ticket_id")
if ticket_id:
imgui.same_line()
imgui.text_colored(vec4(255, 120, 120), f"[{ticket_id}]")
imgui.text_colored(theme.get_color("status_error"), f"[{ticket_id}]")
imgui.same_line()
d_col = DIR_COLORS.get(direction, C_VAL)
imgui.text_colored(d_col, direction); imgui.same_line()
@@ -3857,7 +3858,7 @@ def render_discussion_metadata(app: App) -> None:
total_out += entry["usage"].get("output_tokens", 0)
total_cache += entry["usage"].get("cache_read_input_tokens", 0)
if total_in > 0 or total_out > 0:
imgui.text_colored(vec4(100, 150, 180), f"Discussion Tokens: {total_in} In | {total_out} Out | {total_cache} Cache")
imgui.text_colored(theme.get_color("status_info"), f"Discussion Tokens: {total_in} In | {total_out} Out | {total_cache} Cache")
imgui.separator()
imgui.text_colored(C_LBL, "commit:"); imgui.same_line()
@@ -4053,7 +4054,7 @@ def render_vendor_state(app: App) -> None:
imgui.table_setup_column("Value", imgui.TableColumnFlags_.width_stretch)
imgui.table_setup_column("State", imgui.TableColumnFlags_.width_fixed, 60)
imgui.table_headers_row()
state_colors = {"ok": vec4(120, 220, 120), "warn": vec4(240, 200, 80), "error": vec4(240, 80, 80), "info": vec4(180, 180, 180)}
state_colors = {"ok": theme.get_color("status_success"), "warn": theme.get_color("status_warning"), "error": theme.get_color("status_error"), "info": theme.get_color("text_disabled")}
for m in metrics:
imgui.table_next_row()
imgui.table_next_column(); imgui.text(m.label)
@@ -4061,7 +4062,7 @@ def render_vendor_state(app: App) -> None:
imgui.text(m.value)
if imgui.is_item_hovered(): imgui.set_tooltip(m.tooltip)
imgui.table_next_column()
imgui.text_colored(state_colors.get(m.state, vec4(180, 180, 180)), m.state)
imgui.text_colored(state_colors.get(m.state, theme.get_color("text_disabled")), m.state)
imgui.end_table()
def render_message_panel(app: App) -> None:
@@ -4071,8 +4072,7 @@ def render_message_panel(app: App) -> None:
if is_live:
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 = theme.get_color("status_success", alpha=alpha)
imgui.text_colored(c, "LIVE")
imgui.separator()
ch, app.ui_ai_input = imgui.input_text_multiline("##ai_in", app.ui_ai_input, imgui.ImVec2(-1, -40))
@@ -4323,12 +4323,12 @@ def render_text_viewer_window(app: App) -> None:
is_auto_sliced = any(slc['start_line'] <= line_num <= slc['end_line'] for slc in app.ui_editing_slices_file.custom_slices if slc.get('tag') == 'auto-ast')
is_manual_sliced = any(slc['start_line'] <= line_num <= slc['end_line'] for slc in app.ui_editing_slices_file.custom_slices if slc.get('tag') != 'auto-ast')
if is_manual_sliced: draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + imgui.get_content_region_avail().x, pos.y + line_height), imgui.get_color_u32(vec4(255, 165, 0, 0.2)))
elif is_auto_sliced: draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + imgui.get_content_region_avail().x, pos.y + line_height), imgui.get_color_u32(vec4(0, 255, 0, 0.15)))
if is_manual_sliced: draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + imgui.get_content_region_avail().x, pos.y + line_height), imgui.get_color_u32(theme.get_color("slice_manual", alpha=0.2)))
elif is_auto_sliced: draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + imgui.get_content_region_avail().x, pos.y + line_height), imgui.get_color_u32(theme.get_color("slice_auto", alpha=0.15)))
if app._slice_sel_start != -1 and app._slice_sel_end != -1:
s, e = min(app._slice_sel_start, app._slice_sel_end), max(app._slice_sel_start, app._slice_sel_end)
if s <= line_num <= e: draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + imgui.get_content_region_avail().x, pos.y + line_height), imgui.get_color_u32(vec4(100, 100, 255, 0.3)))
if s <= line_num <= e: draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + imgui.get_content_region_avail().x, pos.y + line_height), imgui.get_color_u32(theme.get_color("slice_selection", alpha=0.3)))
imgui.selectable(f"{line_num:4} | {line_text}##ln{line_num}", False)
if imgui.is_item_clicked(): app._slice_sel_start = line_num; app._slice_sel_end = line_num
if imgui.is_item_hovered(imgui.HoveredFlags_.allow_when_blocked_by_active_item) and imgui.is_mouse_down(0): app._slice_sel_end = line_num
@@ -4340,7 +4340,7 @@ def render_text_viewer_window(app: App) -> None:
if app.perf_profiling_enabled: app.perf_monitor.start_component("_render_text_viewer_ced")
app._text_viewer_editor.render(f"##ced_{app.text_viewer_title}", imgui.ImVec2(-1, -1))
if app.perf_profiling_enabled: app.perf_monitor.end_component("_render_text_viewer_ced")
except Exception as e: imgui.text_colored(vec4(255, 100, 100), f"CED Error: {e}"); imgui.text_unformatted(app.text_viewer_content)
except Exception as e: imgui.text_colored(theme.get_color("status_error"), f"CED Error: {e}"); imgui.text_unformatted(app.text_viewer_content)
else:
with imscope.child("tv_scroll", -1, -1, True):
if app.text_viewer_wrap: imgui.push_text_wrap_pos(imgui.get_content_region_avail().x)
@@ -4358,23 +4358,23 @@ def render_patch_modal(app: App) -> None:
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)
imgui.text_colored(vec4(255, 230, 77), "Tier 4 QA Generated a Patch")
imgui.text_colored(theme.get_color("status_warning"), "Tier 4 QA Generated a Patch")
imgui.separator()
if app._pending_patch_files:
imgui.text("Files to modify:")
for f in app._pending_patch_files: imgui.text(f" - {f}")
imgui.separator()
if app._patch_error_message:
imgui.text_colored(vec4(255, 77, 77), f"Error: {app._patch_error_message}")
imgui.text_colored(theme.get_color("status_error"), f"Error: {app._patch_error_message}")
imgui.separator()
imgui.text("Diff Preview:")
imgui.begin_child("patch_diff_scroll", imgui.ImVec2(-1, 280), True)
if app._pending_patch_text:
diff_lines = app._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)
if line.startswith("+++") or line.startswith("---") or line.startswith("@@"): imgui.text_colored(theme.get_color("diff_header"), line)
elif line.startswith("+"): imgui.text_colored(theme.get_color("diff_added"), line)
elif line.startswith("-"): imgui.text_colored(theme.get_color("diff_removed"), line)
else: imgui.text(line)
imgui.end_child()
imgui.separator()
@@ -4454,7 +4454,7 @@ def render_approve_script_modal(app: App) -> None:
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}")
imgui.text_colored(theme.get_color("status_warning"), f"base_dir: {dlg._base_dir}")
imgui.separator()
# Checkbox to toggle full preview inside modal
if not hasattr(app, 'ui_approve_modal_preview'): app.ui_approve_modal_preview = False
@@ -4632,13 +4632,13 @@ def render_error_tint(app: App) -> None:
if not HotReloader.is_error_state: return
draw_list = imgui.get_background_draw_list()
display_size = imgui.get_io().display_size
# Translucent red: (1.0, 0.0, 0.0, 0.2)
tint_col = imgui.get_color_u32(imgui.ImVec4(1.0, 0.0, 0.0, 0.2))
# Translucent red
tint_col = imgui.get_color_u32(theme.get_color("status_error", alpha=0.2))
draw_list.add_rect_filled(imgui.ImVec2(0, 0), display_size, tint_col)
if app.perf_profiling_enabled:
imgui.set_next_window_pos(imgui.ImVec2(10, 50))
with imscope.window("Hot Reload Error", None, imgui.WindowFlags_.always_auto_resize | imgui.WindowFlags_.no_title_bar):
imgui.text_colored(imgui.ImVec4(1, 0, 0, 1), "HOT RELOAD ERROR")
imgui.text_colored(theme.get_color("status_error"), "HOT RELOAD ERROR")
imgui.text_wrapped(HotReloader.last_error or "Unknown error")
@@ -4651,14 +4651,14 @@ def render_project_stale_tint(app: App) -> None:
if not app.controller.is_project_stale(): return
draw_list = imgui.get_background_draw_list()
display_size = imgui.get_io().display_size
tint_col = imgui.get_color_u32(imgui.ImVec4(1.0, 0.85, 0.2, 0.15))
tint_col = imgui.get_color_u32(theme.get_color("status_warning", alpha=0.15))
draw_list.add_rect_filled(imgui.ImVec2(0, 0), display_size, tint_col)
pending = app.controller._project_switch_pending_path or app.controller.active_project_path
imgui.set_next_window_pos(imgui.ImVec2(10, 50))
with imscope.window("Project Stale", None,
imgui.WindowFlags_.always_auto_resize | imgui.WindowFlags_.no_title_bar |
imgui.WindowFlags_.no_resize | imgui.WindowFlags_.no_move):
imgui.text_colored(imgui.ImVec4(1.0, 0.85, 0.2, 1.0), "PROJECT SWITCHING")
imgui.text_colored(theme.get_color("status_warning"), "PROJECT SWITCHING")
imgui.text_wrapped(f"Loading: {Path(pending).stem if pending else '?'}")
imgui.text_wrapped("UI is read-only until the switch completes. You can still browse tabs.")
@@ -4701,7 +4701,7 @@ def render_mma_dashboard(app: App) -> None:
render_mma_focus_selector(app)
imgui.separator()
if app.is_viewing_prior_session:
c = vec4(255, 152, 48) if theme.is_nerv_active() else vec4(255, 200, 100)
c = theme.get_color("status_warning") if theme.is_nerv_active() else theme.get_color("status_warning")
imgui.text_colored(c, "HISTORICAL VIEW - READ ONLY")
if app.perf_profiling_enabled: app.perf_monitor.end_component("_render_mma_dashboard")
return
@@ -4739,7 +4739,7 @@ def render_mma_modals(app: App) -> None:
if not app._pending_ask_dialog or app._ask_tool_data is None: imgui.close_current_popup()
else:
tool_name = app._ask_tool_data.get("tool", "unknown"); tool_args = app._ask_tool_data.get("args", {})
imgui.text("The AI wants to execute a tool:"); imgui.text_colored(vec4(200, 200, 100), f"Tool: {tool_name}"); imgui.separator()
imgui.text("The AI wants to execute a tool:"); imgui.text_colored(theme.get_color("status_warning"), f"Tool: {tool_name}"); imgui.separator()
imgui.text("Arguments:"); imgui.begin_child("ask_args_child", imgui.ImVec2(400, 200), True); imgui.text_unformatted(json.dumps(tool_args, indent=2)); imgui.end_child()
imgui.separator()
if imgui.button("Approve", imgui.ImVec2(120, 0)): app._handle_approve_ask(); imgui.close_current_popup()
@@ -4796,7 +4796,7 @@ def render_mma_modals(app: App) -> None:
imgui.end_popup()
# Cycle Detection
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_colored(theme.get_color("status_error", alpha=1), "The dependency graph contains a cycle!")
imgui.text("Please remove the circular dependency.")
if imgui.button("OK"): imgui.close_current_popup()
imgui.end_popup()
@@ -4812,16 +4812,16 @@ def render_mma_track_summary(app: App) -> None:
total_cost = sum(cost_tracker.estimate_cost(u.get('model','unknown'), u.get('input',0), u.get('output',0)) for u in app.mma_tier_usage.values())
imgui.text("Track:"); imgui.same_line(); imgui.text_colored(C_VAL, track_name); imgui.same_line(); imgui.text(" | Status:"); imgui.same_line()
if app.mma_status == "paused":
imgui.text_colored(vec4(255, 152, 48) if is_nerv else imgui.ImVec4(1, 0.5, 0, 1), "PIPELINE PAUSED"); imgui.same_line()
imgui.text_colored(theme.get_color("status_warning") if is_nerv else theme.get_color("status_warning"), "PIPELINE PAUSED"); imgui.same_line()
status_col = imgui.ImVec4(1, 1, 1, 1)
if app.mma_status == "idle": status_col = imgui.ImVec4(0.7, 0.7, 0.7, 1)
elif app.mma_status == "running": status_col = vec4(80, 255, 80) if is_nerv else imgui.ImVec4(1, 1, 0, 1)
elif app.mma_status == "done": status_col = imgui.ImVec4(0, 1, 0, 1)
elif app.mma_status == "error": status_col = vec4(255, 72, 64) if is_nerv else imgui.ImVec4(1, 0, 0, 1)
elif app.mma_status == "paused": status_col = imgui.ImVec4(1, 0.5, 0, 1)
imgui.text_colored(status_col, app.mma_status.upper()); imgui.same_line(); imgui.text(" | Cost:"); imgui.same_line(); imgui.text_colored(imgui.ImVec4(0, 1, 0, 1), f"${total_cost:,.4f}")
if app.mma_status == "idle": status_col = theme.get_color("text_disabled")
elif app.mma_status == "running": status_col = theme.get_color("status_success") if is_nerv else theme.get_color("status_warning")
elif app.mma_status == "done": status_col = theme.get_color("status_success")
elif app.mma_status == "error": status_col = theme.get_color("status_error") if is_nerv else theme.get_color("status_error")
elif app.mma_status == "paused": status_col = theme.get_color("status_warning")
imgui.text_colored(status_col, app.mma_status.upper()); imgui.same_line(); imgui.text(" | Cost:"); imgui.same_line(); imgui.text_colored(theme.get_color("status_success"), f"${total_cost:,.4f}")
perc = track_stats["percentage"] / 100.0
p_color = imgui.ImVec4(1, 0, 0, 1) if track_stats["percentage"] < 33 else (imgui.ImVec4(1, 1, 0, 1) if track_stats["percentage"] < 66 else imgui.ImVec4(0, 1, 0, 1))
p_color = theme.get_color("status_error") if track_stats["percentage"] < 33 else (theme.get_color("status_warning") if track_stats["percentage"] < 66 else theme.get_color("status_success"))
imgui.push_style_color(imgui.Col_.plot_histogram, p_color); imgui.progress_bar(perc, imgui.ImVec2(-1, 0), f"{track_stats['percentage']:.1f}%"); imgui.pop_style_color()
if imgui.begin_table("ticket_stats_breakdown", 4):
for lbl, val in [("Completed:", track_stats["completed"]), ("In Progress:", track_stats["in_progress"]), ("Blocked:", track_stats["blocked"]), ("Todo:", track_stats["todo"])]:
@@ -4857,10 +4857,10 @@ def render_mma_track_browser(app: App) -> None:
for track in app.tracks:
imgui.table_next_row(); imgui.table_next_column(); imgui.text(track.get("title", "Untitled")); imgui.table_next_column()
status = track.get("status", "unknown").lower()
c = imgui.ImVec4(0.7, 0.7, 0.7, 1) if status == "new" else (vec4(80, 255, 80) if status == "active" and theme.is_nerv_active() else (imgui.ImVec4(1, 1, 0, 1) if status == "active" else (imgui.ImVec4(0, 1, 0, 1) if status == "done" else (imgui.ImVec4(1, 0, 0, 1) if status == "blocked" else imgui.ImVec4(1, 1, 1, 1)))))
c = theme.get_color("text_disabled") if status == "new" else (theme.get_color("status_success") if status == "active" and theme.is_nerv_active() else (theme.get_color("status_warning") if status == "active" else (theme.get_color("status_success") if status == "done" else (theme.get_color("status_error") if status == "blocked" else imgui.ImVec4(1, 1, 1, 1)))))
imgui.text_colored(c, status.upper()); imgui.table_next_column()
prog = track.get("progress", 0.0)
p_c = imgui.ImVec4(1, 0, 0, 1) if prog < 0.33 else (imgui.ImVec4(1, 1, 0, 1) if prog < 0.66 else imgui.ImVec4(0, 1, 0, 1))
p_c = theme.get_color("status_error") if prog < 0.33 else (theme.get_color("status_warning") if prog < 0.66 else theme.get_color("status_success"))
imgui.push_style_color(imgui.Col_.plot_histogram, p_c); imgui.progress_bar(prog, imgui.ImVec2(-1, 0), f"{int(prog*100)}%"); imgui.pop_style_color(); imgui.table_next_column()
if imgui.button(f"Load##{track.get('id')}"): app._cb_load_track(str(track.get("id") or ""))
imgui.end_table()
@@ -4902,9 +4902,9 @@ def render_mma_global_controls(app: App) -> None:
if imgui.button("Reload GUI"):
success = app._trigger_hot_reload()
if success:
imgui.text_colored(imgui.ImVec4(0, 1, 0, 1), "Reloaded!")
imgui.text_colored(theme.get_color("status_success"), "Reloaded!")
else:
imgui.text_colored(imgui.ImVec4(1, 0, 0, 1), f"Error: {app._hot_reload_error or 'Unknown'}")
imgui.text_colored(theme.get_color("status_error"), f"Error: {app._hot_reload_error or 'Unknown'}")
imgui.same_line(); imgui.text_disabled("(Ctrl+Alt+R)")
def render_mma_usage_section(app: App) -> None:
@@ -4999,7 +4999,7 @@ def render_tier_stream_panel(app: App, tier_key: str, stream_key: str | None) ->
"""
if app.perf_profiling_enabled: app.perf_monitor.start_component("_render_tier_stream_panel")
if app.is_viewing_prior_session:
imgui.text_colored(vec4(255, 200, 100), "HISTORICAL VIEW - READ ONLY")
imgui.text_colored(theme.get_color("status_warning"), "HISTORICAL VIEW - READ ONLY")
if app.perf_profiling_enabled: app.perf_monitor.end_component("_render_tier_stream_panel")
return
if stream_key is not None:
@@ -5024,11 +5024,11 @@ def render_tier_stream_panel(app: App, tier_key: str, stream_key: str | None) ->
ticket_id = key.split(": ", 1)[-1] if ": " in key else key
status = worker_status.get(key, "unknown")
if status == "running":
imgui.text_colored(imgui.ImVec4(1, 1, 0, 1), f"{ticket_id} [{status}]")
imgui.text_colored(theme.get_color("status_warning"), f"{ticket_id} [{status}]")
elif status == "completed":
imgui.text_colored(imgui.ImVec4(0, 1, 0, 1), f"{ticket_id} [{status}]")
imgui.text_colored(theme.get_color("status_success"), f"{ticket_id} [{status}]")
elif status == "failed":
imgui.text_colored(imgui.ImVec4(1, 0, 0, 1), f"{ticket_id} [{status}]")
imgui.text_colored(theme.get_color("status_error"), f"{ticket_id} [{status}]")
else:
imgui.text(f"{ticket_id} [{status}]")
imgui.begin_child(f"##tier3_{ticket_id}_scroll", imgui.ImVec2(-1, 150), True)
@@ -5156,9 +5156,9 @@ def render_ticket_queue(app: App) -> None:
imgui.table_next_column()
prio = t.get('priority', 'medium')
p_col = vec4(180, 180, 180) # gray
if prio == 'high': _col = vec4(255, 100, 100) # red
elif prio == 'medium': p_col = vec4(255, 255, 100) # yellow
p_col = theme.get_color("text_disabled") # gray
if prio == 'high': _col = theme.get_color("status_error") # red
elif prio == 'medium': p_col = theme.get_color("status_warning") # yellow
imgui.push_style_color(imgui.Col_.text, p_col)
if imgui.begin_combo(f"##prio_{tid}", prio, imgui.ComboFlags_.height_small):
@@ -5184,7 +5184,7 @@ def render_ticket_queue(app: App) -> None:
# Status
imgui.table_next_column()
status = t.get('status', 'todo')
if t.get('model_override'): imgui.text_colored(imgui.ImVec4(1, 0.5, 0, 1), f"{status} [{t.get('model_override')}]")
if t.get('model_override'): imgui.text_colored(theme.get_color("status_warning"), f"{status} [{t.get('model_override')}]")
else: imgui.text(t.get('status', 'todo'))
# Description
@@ -5223,14 +5223,14 @@ def render_task_dag_panel(app: App) -> None: # 4. Task DAG Visualizer
int_id = abs(hash(tid))
ed.begin_node(ed.NodeId(int_id))
if getattr(app, "ui_project_execution_mode", "native") == "beads":
imgui.text_colored(imgui.ImVec4(0, 1, 1, 1), "[B] ")
imgui.text_colored(theme.get_color("status_info"), "[B] ")
imgui.same_line()
imgui.text_colored(C_KEY, f"Ticket: {tid}")
status = t.get('status', 'todo')
s_col = C_VAL
if status == 'done' or status == 'complete': s_col = C_IN
elif status == 'in_progress' or status == 'running': s_col = C_OUT
elif status == 'error': s_col = imgui.ImVec4(1, 0.4, 0.4, 1)
elif status == 'error': s_col = theme.get_color("status_error")
imgui.text("Status: ")
imgui.same_line()
imgui.text_colored(s_col, status)
@@ -5359,7 +5359,7 @@ def render_beads_tab(app: App) -> None:
missing = []
if not dolt_path: missing.append("'dolt'")
if not bd_path: missing.append("'bd'")
imgui.text_colored(imgui.ImVec4(1, 0.5, 0, 1), f"Warning: {', '.join(missing)} not found in PATH.")
imgui.text_colored(theme.get_color("status_warning"), f"Warning: {', '.join(missing)} not found in PATH.")
imgui.text_wrapped("Beads mode requires Dolt and the Beads (bd) CLI tools.")
if getattr(app, "ui_project_execution_mode", "native") == "beads":
@@ -5385,7 +5385,7 @@ def render_beads_tab(app: App) -> None:
imgui.text(str(b.title))
imgui.end_table()
except Exception as e:
imgui.text_colored(imgui.ImVec4(1, 0, 0, 1), f"Error loading beads: {e}")
imgui.text_colored(theme.get_color("status_error"), f"Error loading beads: {e}")
def render_mma_focus_selector(app: App) -> None:
"""
@@ -5409,7 +5409,7 @@ def render_empty_context_modal(app: App) -> None:
app.show_empty_context_modal = False
if imgui.begin_popup_modal("Empty Context Warning", True, imgui.WindowFlags_.always_auto_resize)[0]:
imgui.text_colored(imgui.ImVec4(1.0, 1.0, 0.0, 1.0), "WARNING: Empty Context Composition")
imgui.text_colored(theme.get_color("status_warning"), "WARNING: Empty Context Composition")
imgui.text("You are attempting to generate a response without any files selected.")
imgui.text("This may result in poor AI performance or loss of project context.")
imgui.separator()
@@ -5436,7 +5436,7 @@ def render_context_modals(app: App) -> None:
imgui.separator()
imgui.begin_child("missing_files_list", imgui.ImVec2(0, 150), True)
for f in app.missing_context_files:
imgui.text_colored(imgui.ImVec4(1, 0.4, 0.4, 1), f)
imgui.text_colored(theme.get_color("status_error"), f)
imgui.end_child()
imgui.separator()