Private
Public Access
0
0
Commit Graph

2509 Commits

Author SHA1 Message Date
ed 9a6bcb2f34 docs(testing): add Known Gotchas section (live_gui non-determinism + early-render C crash) 2026-06-05 18:21:24 -04:00
ed 2f0c1eb3cc conductor(index): mark regression_fixes active, add multi_themes recently shipped 2026-06-05 18:18:27 -04:00
ed 8663498725 conductor(tracks): register multi_themes ship and regression_fixes checkpoint 2026-06-05 18:12:03 -04:00
ed fcb3f80ac8 docs(root): register guide_themes.md in Documentation and Subsystem tables 2026-06-05 18:09:45 -04:00
ed f63fe68565 docs(index): register guide_themes.md in guides table and file tree 2026-06-05 18:06:12 -04:00
ed db3490a70f conductor(plan): document imgui save_ini crash root cause and fix 2026-06-05 15:12:23 -04:00
ed d7487af424 fix(gui_2): defer save_ini_settings on first capture to avoid early-render crash 2026-06-05 14:57:32 -04:00
ed b0c8589f68 conductor(plan): document root cause - imgui-bundle C-level crash blocks live_gui 2026-06-05 13:47:55 -04:00
ed 1469ecac3a fix(gui_2): call DIR_COLORS/KIND_COLORS entries - they're callable functions 2026-06-05 13:19:48 -04:00
ed 1c6919aafc conductor(plan): update task status - 5 done, 6 deferred pending live_gui 2026-06-05 12:43:33 -04:00
ed c96bdb06ba test(rag_phase4): handle None status before .lower() in error check 2026-06-05 12:38:47 -04:00
ed ac08ee875c fix(log_pruner): shorter retry loop, smaller sleep to avoid blocking startup 2026-06-05 12:26:58 -04:00
ed 970f198ca6 test(view_presets): mock persona_manager in fixture 2026-06-05 11:52:49 -04:00
ed f829d1df17 test(prior_session): mock render_palette_modal, add ui_base_system_prompt fixture 2026-06-05 11:45:42 -04:00
ed df43f158b9 test(gui_phase4): patch markdown_helper imgui/imgui_md to avoid IM_ASSERT 2026-06-05 10:33:38 -04:00
ed 38abf2312f test(gui_progress): adapt to C_LBL/C_VAL function API + theme_2 mock 2026-06-05 10:25:25 -04:00
ed 07d35c9d39 conductor(plan): regression fixes - 21 failures from full suite run 2026-06-05 10:10:29 -04:00
ed a7c4bf01b1 feat(theme): standardize all themes with intelligent row backgrounds and human names 2026-06-05 01:05:17 -04:00
ed 3ed2b3966c fix(theme): robust get_color fallback and Solarized Dark table colors 2026-06-05 01:01:03 -04:00
ed 98acc12811 feat(theme): fix table row backgrounds and hub text contrast 2026-06-05 00:52:28 -04:00
ed e3f8a2b517 fix(theme): correct scope for internal imports in apply function 2026-06-05 00:39:31 -04:00
ed 4041782776 feat(theme): finalize semantic color lift and fix light theme UI elements 2026-06-05 00:29:27 -04:00
ed 7735b6cba7 feat(theme): lift all hardcoded colors and finalize semantic theming 2026-06-05 00:21:19 -04:00
ed 7ea52cbbe8 style(themes): compact TOML formatting and lift semantic colors 2026-06-05 00:02:46 -04:00
ed 06e305aba6 feat(theme): add tone mapping and fix missing palette colors 2026-06-04 23:44:43 -04:00
ed d9d0fea971 refactor(themes): remove hardcoded _PALETTES from theme_2.py 2026-06-04 23:24:19 -04:00
ed ece4d9b5f2 feat(themes): add TOML files for original built-in themes (10x Dark, Nord Dark, Monokai, Binks) 2026-06-04 23:19:12 -04:00
ed 269cdcc365 conductor(checkpoint): Theme & syntax modularization complete 2026-06-04 23:17:23 -04:00
ed 465396675d docs(themes): add authoring guide for TOML theme system 2026-06-04 23:16:21 -04:00
ed 1cb68e4e3f feat(markdown): apply active theme syntax palette to code blocks 2026-06-04 23:13:33 -04:00
ed df2e82a82d feat(themes): add Solarized Dark/Light, Gruvbox Dark, Moss TOML themes 2026-06-04 23:10:16 -04:00
ed dedc66d664 oops 2026-06-04 23:02:49 -04:00
ed e14b3c2ce0 feat(theme): load themes from TOML and apply syntax palette mapping 2026-06-04 22:59:59 -04:00
ed e2f698c4a3 feat(theme-models): add ThemePalette/ThemeFile schema with TOML loader 2026-06-04 22:31:22 -04:00
ed d21e96de8f feat(paths): add global and project theme path helpers 2026-06-04 22:25:29 -04:00
ed cd24c43f8f conductor(plan): theme + syntax modularization - 7-task plan 2026-06-04 22:20:58 -04:00
ed e86dacde8a conductor(plan): theme + syntax modularization plan/spec 2026-06-04 22:09:43 -04:00
ed 8d1fa18785 fix(project): Non-blocking project switch with stale-ui tint
When switching projects, the previous implementation ran the entire
save/load/refresh sequence on the main thread. With large project files
or slow disks, this caused the UI to freeze for several seconds.

Fix:
- _switch_project now returns immediately after setting flags; the
  actual work runs in a daemon thread (_do_project_switch)
- New is_project_stale() property returns True while a switch is queued
  or running; the GUI renders an amber/yellow tint overlay to signal
  the controller state lags the user's last click
- AI ops are gated: _api_generate returns HTTP 409, _handle_generate_send
  and _handle_md_only early-return with ai_status feedback, all when
  is_project_stale() is true
- Queued switches (clicking project A then B in rapid succession) are
  coalesced: B replaces A as the target; once A completes, B is
  triggered automatically via the finally branch in _do_project_switch
- New state fields: _project_switch_in_progress, _project_switch_pending_path,
  _project_switch_thread, _project_switch_lock
- AppController state class attributes use hasattr guard for _app to
  keep the controller usable standalone in tests/headless mode

UX:
- Render loop keeps drawing during the switch
- User can still scroll, switch tabs, browse files
- Amber tint + popup explains what's happening and that AI ops are paused
- ai_status shows the target project name

Tests:
- _wait_for_switch helper added for the new async switch flow
- All 7 existing switch tests updated to call _wait_for_switch
- 2 new tests:
  - test_switch_project_non_blocking: verifies _switch_project returns
    in <0.2s and is_project_stale() is True during the switch
  - test_api_generate_blocked_while_stale: verifies _api_generate
    raises HTTPException(409) while a switch is in progress

All 33 related tests pass.
2026-06-04 21:29:12 -04:00
ed 36f3292249 fix(project): Reload context_files from new project on project switch
When switching projects, the previous project's context_files remained
visible in the Context Composition panel because the controller's
self.context_files list was not reloaded from the new project's TOML
files.paths entry.

Fix in _refresh_from_project:
- After loading self.files from the project TOML, populate
  self.context_files with deep copies of those FileItem objects
- Reset self._app.ui_selected_context_files to match the new project's
  auto_aggregate set
- Guard the _app access with hasattr so the controller is usable
  standalone (in tests, headless mode, etc.) without an attached App

Test: 1 new test in tests/test_project_switch_persona_preset.py
- test_switch_project_resets_context_files: switches from project_a
  (forth + gte_hello files) to project_b (gencpp timing files) and
  asserts context_files contains ONLY project_b's files
2026-06-04 21:03:16 -04:00
ed 7df65dff14 fix(project): Create persona_manager in _load_active_project + handle missing context preset
Two fixes for the regression introduced in b92daef3 (and an additional
hardening for the persona->context_preset stale-reference class of bug):

1. Regression: persona_manager was missing on first project load.
   _load_active_project creates preset_manager and tool_preset_manager
   but did not create persona_manager, so the new
   self.personas = self.persona_manager.load_all() line in
   _refresh_from_project raised AttributeError on app startup before
   the post-_load_active_project persona_manager creation could run.
   Fix: create self.persona_manager in _load_active_project alongside
   the other managers, so the manager is available when
   _refresh_from_project runs.

2. Stale reference: persona's context_preset field pointed to a
   preset (e.g. 'GTE') that no longer exists in the project, causing
   load_context_preset to raise KeyError and crash the persona
   selector panel (which triggered the cascading 'Missing End()' imgui
   assertion).
   Fix: wrap the load_context_preset call in render_persona_selector_panel
   with try/except KeyError, surface the error in app.ai_status, and
   clear app.ui_active_context_preset to keep the GUI state consistent.

Tests: 2 new tests in tests/test_project_switch_persona_preset.py
- test_load_active_project_creates_persona_manager (regression guard)
- test_load_context_preset_missing_raises_keyerror (verifies the
  contract that load_context_preset raises for missing names; the
  GUI layer is now responsible for catching the error)
2026-06-04 20:45:55 -04:00
ed b92daef34f fix(project): Reload personas and validate active AI settings on project switch
When switching projects, the previous project's project-specific persona and
presets remained selected in the AI Settings panel because:
1. self.personas was not reloaded after switching project root
2. self.ui_active_persona / tool_preset / bias_profile / project_preset_name
   were not validated against the newly-loaded personas/presets

Fix:
- Reload self.personas from self.persona_manager in _refresh_from_project
- Validate each active selection and reset to None/empty if it does not
  exist in the newly-loaded manager dictionaries
- Push the active tool preset and bias profile to ai_client after the swap
- Initialize self.ui_active_bias_profile in class attribute block (was only
  set later in __init__, causing AttributeError on direct attribute access)

Tests: 4 new tests in tests/test_project_switch_persona_preset.py verify
the reset behavior for persona, preset, tool preset, and global preset
preservation.
2026-06-04 20:36:59 -04:00
ed ce211e76f8 straggler spec 2026-06-04 19:42:04 -04:00
ed ba7733b365 conductor(plan): Mark context_first_message_fix task complete 2026-06-04 18:47:42 -04:00
ed 0d4fade5ed fix(context): Only send context on first message in discussion
Previously, context (files, screenshots) was always sent with every message,
even on subsequent messages where the AI provider already had the context
from the first message via its history mechanism.

This change:
- Detects if the discussion has any AI responses already
- Only sends md_content (stable_md) on the first message
- Subsequent messages pass empty string for md_content to avoid redundant sending
- Context now properly goes in md_content parameter, not crammed into user_message

The fix is in _api_generate() in src/app_controller.py
2026-06-04 18:43:39 -04:00
Conductor 58cd759968 fix(markdown): strip blank between bullet and indented continuation paragraph
ROOT CAUSE: imgui_md (mekhontsev/imgui_md) BLOCK_P does NOT call ImGui::NewLine()
when m_list_stack is non-empty (verified in imgui_md.cpp). So a multi-paragraph
list item like:

    - bullet text (long, wraps to 2 lines)

        continuation paragraph

renders BOTH paragraphs at the same Y because the second BLOCK_P enters/exits
without advancing the cursor. The continuation crashes into the previous
paragraph's last wrapped line.

FIX: Add MarkdownRenderer._normalize_list_continuations preprocessor that
strips blank lines between a list item and its indented continuation. The
continuation then becomes a lazy continuation of the first paragraph (single
BLOCK_P in imgui_md, proper text wrapping, no overlap). Trade-off: users
cannot have separate paragraphs within a single list item. Acceptable.

Also: fixed a pre-existing bug in _normalize_nested_list_endings where a
duplicate conditional caused the function to return empty string (the
out.append(line) was inside the wrong scope). It was silently corrupting
all list content since fd5f4d0e.

TESTS: 23/23 markdown unit tests pass. 3 new tests for the new preprocessor
covering: blank-strip case, blank-preservation case, simple-list passthrough.
2026-06-03 21:48:12 -04:00
Conductor fd5f4d0eda fix(markdown): strip backticks in table cells + add nested-list overlap workaround
FIX 1 (src/markdown_table.py): Cells now use imgui_md.render(c) instead of
imgui.text_wrapped(c). imgui_md uses MD4C which strips backtick-delimited
inline code spans BEFORE rendering, so backticks no longer appear as
literal characters in cell content. Side benefit: inline emphasis
(*foo*, **bar**) now renders in cells too.

FIX 2 (src/markdown_helper.py): Added MarkdownRenderer._normalize_nested_list_endings.
Upstream imgui_md (mekhontsev/imgui_md) BLOCK_UL exit only calls
ImGui::NewLine() for top-level list endings. For nested list endings, no
NewLine is emitted, so the next text starts at the same Y as the last
list item, causing visual overlap. The preprocessor inserts a blank
line before any line that follows a list item with MORE indent than
itself, forcing a paragraph break. Cannot fix the C++ from Python.

Tests:
- test_markdown_table_wrapped.py: updated to assert imgui_md.render is
  called for cell content (not imgui.text_wrapped).
- test_markdown_helper_bullets.py: added 4 tests for the new preprocessors
  (nested-list blank insertion + bullet delimiter conversion + edge cases).

20/20 markdown unit tests pass. 1-space indentation throughout.

KNOWN LIMITATIONS (cannot fix without forking imgui_md C++):
- Inline code spans render as plain text (no monospace font in cells)
- The ' * ' bullet delimiter has a Y-overlap bug upstream
  (workaround: pre-convert to '- ' via _normalize_bullet_delimiters)
- Nested list ending overlap (workaround: insert blank line via
  _normalize_nested_list_endings)
2026-06-03 21:33:47 -04:00
Conductor feed18eb0f fix(markdown): remove table double-header + add imgui_md bullet workaround
Table fix (src/markdown_table.py):
- Add TableColumnFlags_.width_stretch to each table_setup_column call
  (was missing — columns had no width to wrap against, so text_wrapped
  couldn't grow row height → all rows squished together)
- Remove the explicit for-h-in-headers: table_next_column + text_wrapped(h)
  loop. table_headers_row() already renders the header from the
  table_setup_column() names; the explicit loop was drawing it AGAIN on
  top → double-rendered header rows.

Bullet fix (src/markdown_helper.py):
- Revert _render_md_no_bullet_overlap → simple imgui_md.render(chunk);
  imgui.spacing() (the original af0bbe97 approach). The complex
  workaround was stripping '- ' and rendering stripped text to imgui_md,
  which double-rendered '- 1. ...' content (imgui.bullet from my code +
  numbered list marker from imgui_md).
- Add MarkdownRenderer._normalize_bullet_delimiters: regex-converts
  '* ' markers to '- ' before passing to imgui_md. This works around
  the upstream bug in mekhontsev/imgui_md BLOCK_LI where the '*' case
  calls ImGui::Bullet() without ImGui::SameLine(), causing the bullet
  to render on its own Y with the text on the next Y. The '-' case
  uses Text+SameLine which is correct. Cannot fix from Python (we
  can't subclass the C++ class) — pre-conversion is the cheapest fix.

Tests:
- test_markdown_table_wrapped.py: updated to assert new behavior
  (text_wrapped count == cell count, not header+cell).
- test_markdown_table_columns.py: updated to assert exactly 6
  table_next_column calls (cells only, not 9).
- test_markdown_helper_bullets.py: rewrote for new public-API behavior
  (imgui_md.render called with the unstripped chunk).

16/16 markdown unit tests pass.
2026-06-03 21:14:16 -04:00
ed cd7a3c6384 cofnig 2026-06-03 18:29:47 -04:00
Conductor 919d28e950 test(markdown): add live_gui smoke test for markdown table + bullet rendering 2026-06-03 17:37:44 -04:00
Conductor d15fdcdb05 fix(markdown): revert table to simple form with text_wrapped + add regression tests 2026-06-03 17:31:50 -04:00