diff --git a/.gitignore b/.gitignore index 1315e5eb..abc8e9c3 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ logs/sessions/ logs/agents/ logs/errors/ tests/artifacts/ +!tests/artifacts/manualslop_layout_default.ini dpg_layout.ini tests/temp_workspace sdm_report_refined.json diff --git a/scripts/run_tests_batched.py b/scripts/run_tests_batched.py index f4579bee..c08ebd2b 100644 --- a/scripts/run_tests_batched.py +++ b/scripts/run_tests_batched.py @@ -56,32 +56,33 @@ def run_tests(batch_size: int, timeout: int) -> int: start: float = time.perf_counter() try: subprocess.run(cmd, check=True, timeout=timeout) - batch_failed: bool = False except subprocess.TimeoutExpired: elapsed: float = time.perf_counter() - start batch_timings.append(elapsed) print(f" >>> Batch {batch_idx} TIMED OUT after {elapsed:.1f}s (limit {timeout}s)") - batch_failed = True + failed_files.extend(batch) except subprocess.CalledProcessError as e: elapsed = time.perf_counter() - start batch_timings.append(elapsed) print(f" >>> Batch {batch_idx} FAILED after {elapsed:.1f}s (pytest exit {e.returncode})") - batch_failed = True + failed_files.extend(batch) else: elapsed = time.perf_counter() - start batch_timings.append(elapsed) print(f" >>> Batch {batch_idx} passed in {elapsed:.1f}s") - if batch_failed: - failed_files.extend(batch) print() print("=" * 70) if failed_files: - print(f"Total batches: {len(batches)}; failed: {len(batches) - batch_timings[:len(batches)].count(...) if False else sum(1 for t, b in zip(batch_timings, batches) if any(f in failed_files for f in b))}") + failed_batch_count: int = sum( + 1 for batch in batches if any(f in failed_files for f in batch) + ) + print(f"Total batches: {len(batches)}; failed batches: {failed_batch_count}") print(f"Failed files: {len(failed_files)}") print("=" * 70) for f in failed_files: print(f" - {f}") + print("=" * 70) return 1 total_time: float = sum(batch_timings) avg: float = total_time / max(len(batch_timings), 1) @@ -92,8 +93,8 @@ def run_tests(batch_size: int, timeout: int) -> int: def main() -> None: ap: argparse.ArgumentParser = argparse.ArgumentParser(description=__doc__.split("\n\n")[0]) - ap.add_argument("--batch-size", type=int, default=64, help="tests per batch (default: 32)") - ap.add_argument("--timeout", type=int, default=1000, help="seconds per batch (default: 180)") + ap.add_argument("--batch-size", type=int, default=32, help="tests per batch (default: 32)") + ap.add_argument("--timeout", type=int, default=180, help="seconds per batch (default: 180)") args: argparse.Namespace = ap.parse_args() if args.batch_size <= 0: print("ERROR: --batch-size must be positive", file=sys.stderr) diff --git a/src/app_controller.py b/src/app_controller.py index 7992df0d..794bcdeb 100644 --- a/src/app_controller.py +++ b/src/app_controller.py @@ -1833,7 +1833,7 @@ class AppController: "Project Settings": True, "Files & Media": True, "AI Settings": True, - "MMA Dashboard": True, + "MMA Dashboard": False, "Task DAG": False, "Usage Analytics": False, "Tier 1": False, @@ -1851,7 +1851,8 @@ class AppController: "Tool Calls": False, "Text Viewer": False, "Theme": True, - "Log Management": False, + "Log Management": True, + "Diagnostics": True, } saved = self.config.get("gui", {}).get("show_windows", {}) self.show_windows = {k: saved.get(k, v) for k, v in _default_windows.items()} diff --git a/src/gui_2.py b/src/gui_2.py index d4698f6a..9ecead7f 100644 --- a/src/gui_2.py +++ b/src/gui_2.py @@ -530,7 +530,7 @@ class App: _STALE_WINDOW_NAMES = { "Projects", "Files", "Screenshots", "Discussion History", "Provider", "Message", "Response", "Tool Calls", - "Comms History", "System Prompts", "Theme", + "Comms History", "System Prompts", } _stale_found = [n for n in _STALE_WINDOW_NAMES if f"[Window][{n}]" in _ini_text] if _stale_found: diff --git a/tests/conftest.py b/tests/conftest.py index b1176e6e..ed628e0d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -407,13 +407,18 @@ def live_gui() -> Generator[tuple[subprocess.Popen, str], None, None]: cred_file = project_root / "credentials.toml" mcp_file = project_root / "mcp_env.toml" - # NOTE: do NOT copy repo-root manualslop_layout.ini to the test workspace. - # The repo-root layout is from a pre-hub-refactor era and references window - # names that no longer exist (Projects/Files/Screenshots/Provider/...). - # HelloImGui will silently drop them, causing missing panels in live_gui tests - # and in the user's interactive session. Let HelloImGui generate a fresh layout. - # The user can delete the stale repo-root manualslop_layout.ini or use the - # Reset Layout command (added in the Reset Layout track) to regenerate. + # Ship a pre-baked default layout into the test workspace so every live_gui + # session starts with a deterministic, well-organized layout (the user's + # preferred arrangement: Project/Files/AI/Operations on the left, Discussion/ + # Log Management/Diagnostics on the right). Without this, HelloImGui auto-docks + # on first launch in a non-deterministic way, and the user's saved repo-root + # layout references stale pre-hub-refactor window names. + # To iterate: open sloppy.py interactively, arrange the layout, quit + # (HelloImGui auto-saves to cwd), then copy manualslop_layout.ini over the + # artifact below. + _default_layout_src = project_root / "tests" / "artifacts" / "manualslop_layout_default.ini" + if _default_layout_src.exists(): + shutil.copy2(_default_layout_src, temp_workspace / "manualslop_layout.ini") # Link assets for fonts src_assets = project_root / "assets"