diff --git a/src/commands.py b/src/commands.py index 44fc5f06..6c4c4b55 100644 --- a/src/commands.py +++ b/src/commands.py @@ -241,6 +241,37 @@ def hide_all_panels(app: "App") -> None: app.show_windows[name] = False +@registry.register +def reset_layout(app: "App") -> None: + """Reset Layout — Restore the default window layout and clear the stale dock-state cache. + + Useful when a previously-saved manualslop_layout.ini references + window names that no longer exist (e.g. after a refactor renames + windows) and the dock space appears empty / non-recoverable via + the Windows menu. Sets every show_windows entry to True and + deletes manualslop_layout.ini so hello_imgui regenerates a fresh + dock layout on the next frame (and the next process shutdown saves + the new layout in place of the stale one). The user will need to + restart sloppy.py for the dock layout to fully take effect; the + show_windows toggles take effect immediately. + """ + if hasattr(app, "show_windows") and isinstance(app.show_windows, dict): + for name in app.show_windows.keys(): + app.show_windows[name] = True + try: + import os + layout_paths = [ + "manualslop_layout.ini", + os.path.join("tests", "artifacts", "live_gui_workspace", "manualslop_layout.ini"), + ] + for p in layout_paths: + if os.path.exists(p): + os.remove(p) + if hasattr(app, "ai_status"): app.ai_status = f"layout reset: removed {p}" + except Exception as e: + if hasattr(app, "ai_status"): app.ai_status = f"layout reset partial: {e}" + + # -------------------------------------------------------------------------- # Layout — Workspace Profiles # -------------------------------------------------------------------------- diff --git a/src/models.py b/src/models.py index b64570c3..05e2f181 100644 --- a/src/models.py +++ b/src/models.py @@ -145,7 +145,14 @@ DEFAULT_TOOL_CATEGORIES: Dict[str, List[str]] = { "Beads": ["bd_create", "bd_update", "bd_list", "bd_ready"], } -CONFIG_PATH = get_config_path() +# CONFIG_PATH was a module-level constant. REMOVED: it cached the +# repo-root config.toml at import time, so any test calling +# save_config() or load_config() after import wrote/read the +# user's actual config — corrupting the user's settings every test +# run. The path is now re-resolved on every call, so the SLOP_CONFIG +# env var (or a set_config_path() helper from test fixtures) can +# redirect reads/writes to a temp_workspace without reimporting. +# See tests/conftest.py:reset_paths for the test-side mechanism. #region: Config Utilities @@ -160,7 +167,7 @@ def load_config() -> dict[str, Any]: """ [C: src/multi_agent_conductor.py:ConductorEngine.__init__] """ - with open(CONFIG_PATH, "rb") as f: + with open(get_config_path(), "rb") as f: return tomllib.load(f) def save_config(config: dict[str, Any]) -> None: @@ -172,11 +179,14 @@ def save_config(config: dict[str, Any]) -> None: config = _clean_nones(config) sys.stderr.write(f"[DEBUG] Saving config. Theme: {config.get('theme')}\n") sys.stderr.flush() - with open(CONFIG_PATH, "wb") as f: + with open(get_config_path(), "wb") as f: tomli_w.dump(config, f) #region: History Utilities + +#region: History Utilities + def parse_history_entries(history_strings: list[str], roles: list[str]) -> list[dict[str, Any]]: import re from src import thinking_parser diff --git a/tests/test_mma_step_mode_sim.py b/tests/test_mma_step_mode_sim.py index e6f5617d..a7bc0798 100644 --- a/tests/test_mma_step_mode_sim.py +++ b/tests/test_mma_step_mode_sim.py @@ -21,7 +21,10 @@ def _poll_mma_status(client: api_hook_client.ApiHookClient, timeout: int, condit @pytest.mark.integration @pytest.mark.timeout(300) -@pytest.mark.skip(reason="Pre-existing test: integration test that requires a real gemini_cli provider to reach 'Awaiting Approval' state. Skipped in the default suite; run live_gui tests against a working provider to exercise this path. Tracked as pre-existing.") +@pytest.mark.skipif( + not os.environ.get("RUN_MMA_INTEGRATION"), + reason="Integration test that requires a working gemini_cli provider AND the live MMA pipeline to reach 'Awaiting Approval' state. The current mock CLI path in this test does not kick the pipeline out of 'idle' (verified: mma=idle for 60s after btn_mma_plan_epic click). Set RUN_MMA_INTEGRATION=1 to run this test against a real provider.", +) def test_mma_step_mode_approval_flow(live_gui) -> None: """