diff --git a/sloppy.py b/sloppy.py index ee725162..33c391ba 100644 --- a/sloppy.py +++ b/sloppy.py @@ -12,11 +12,11 @@ _SLOPPY_COLD_START_TS: float = time.time() project_root = os.path.dirname(os.path.abspath(__file__)) if project_root not in sys.path: - sys.path.insert(0, project_root) + sys.path.insert(0, project_root) thirdparty = os.path.join(project_root, "thirdparty") if thirdparty not in sys.path: - sys.path.insert(0, thirdparty) + sys.path.insert(0, thirdparty) os.environ["HF_HUB_DISABLE_SYMLINKS_WARNING"] = "1" os.environ["HF_HUB_DISABLE_PROGRESS_BARS"] = "1" @@ -33,38 +33,43 @@ parser.add_argument("--headless", action="store_true", help="Run in headless mod parser.add_argument("--web-host", default=None, help="Enable web mode and bind to this host (e.g., 0.0.0.0)") parser.add_argument("--web-port", type=int, default=8080, help="Web mode port (default: 8080)") parser.add_argument("--enable-test-hooks", action="store_true", help="Enable the HookServer on :8999 for external automation") -args = parser.parse_args() +# Defer parse_args() so `import sloppy` (for _SLOPPY_COLD_START_TS) doesn't +# require CLI args. parse_args() runs at the start of __main__ only. +args: argparse.Namespace = argparse.Namespace() # type: ignore[assignment] -if args.web_host is not None: - with startup_profiler.phase("web_host_imports"): - from imgui_bundle import hello_imgui - from src.api_hooks import HookServer - with startup_profiler.phase("gui_2_import_webhost"): - from src.gui_2 import App - with startup_profiler.phase("app_construct"): - app = App() - if args.enable_test_hooks: - hook_server = HookServer(app) - hook_server.start() +if __name__ == "__main__": + args = parser.parse_args() + if args.web_host is not None: + with startup_profiler.phase("web_host_imports"): + from imgui_bundle import hello_imgui + from src.api_hooks import HookServer + with startup_profiler.phase("gui_2_import_webhost"): + from src.gui_2 import App + with startup_profiler.phase("app_construct"): + app = App() - runner_params = hello_imgui.RunnerParams() - runner_params.app_window_params.window_title = "Manual Slop (Web)" - runner_params.app_window_params.borderless = True - runner_params.imgui_window_params.default_imgui_window_type = hello_imgui.DefaultImGuiWindowType.provide_full_screen_docker_space - runner_params.app_window_params.restore_previous_window_size = True + if args.enable_test_hooks: + hook_server = HookServer(app) + hook_server.start() - with startup_profiler.phase("hello_imgui_run"): - hello_imgui.run(runner_params, lambda: app.render_frame()) -elif args.headless: - with startup_profiler.phase("headless_imports"): - from src.app_controller import AppController - with startup_profiler.phase("appcontroller_construct_headless"): - controller = AppController(headless=True) - with startup_profiler.phase("appcontroller_run"): - controller.run() -else: - with startup_profiler.phase("gui_2_main_import"): - from src.gui_2 import main - with startup_profiler.phase("main_call"): - main() \ No newline at end of file + runner_params = hello_imgui.RunnerParams() + runner_params.app_window_params.window_title = "Manual Slop (Web)" + runner_params.app_window_params.borderless = True + runner_params.imgui_window_params.default_imgui_window_type = hello_imgui.DefaultImGuiWindowType.provide_full_screen_dock_space + runner_params.app_window_params.restore_previous_window_size = True + + with startup_profiler.phase("hello_imgui_run"): + hello_imgui.run(runner_params, lambda: app.render_frame()) + elif args.headless: + with startup_profiler.phase("headless_imports"): + from src.app_controller import AppController + with startup_profiler.phase("appcontroller_construct_headless"): + controller = AppController(headless=True) + with startup_profiler.phase("appcontroller_run"): + controller.run() + else: + with startup_profiler.phase("gui_2_main_import"): + from src.gui_2 import main + with startup_profiler.phase("main_call"): + main() diff --git a/src/gui_2.py b/src/gui_2.py index 1b64c575..945d3039 100644 --- a/src/gui_2.py +++ b/src/gui_2.py @@ -170,11 +170,14 @@ class App: [C: src/mcp_client.py:_DDGParser.__init__, src/mcp_client.py:_TextExtractor.__init__] """ # --- Core Dependencies & State --- - self.controller = app_controller.AppController() + from src.startup_profiler import startup_profiler + with startup_profiler.phase("app_init_AppController"): + self.controller = app_controller.AppController() self.controller._app = self - from src import history, performance_monitor - self.perf_monitor = performance_monitor.PerformanceMonitor() - self.history = history.HistoryManager(max_capacity=100) + with startup_profiler.phase("app_init_history_perfmon"): + from src import history, performance_monitor + self.perf_monitor = performance_monitor.PerformanceMonitor() + self.history = history.HistoryManager(max_capacity=100) # --- Undo/Redo & Snapshot State --- self._last_ui_snapshot: Optional[history.UISnapshot] = None self._snapshot_timer: float = 0.0 @@ -413,7 +416,7 @@ class App: def run(self) -> None: """ - + Initializes the ImGui runner and starts the main application loop. [C: simulation/sim_base.py:run_sim, src/mcp_client.py:get_git_diff, src/project_manager.py:get_git_commit, src/rag_engine.py:RAGEngine._search_mcp, src/shell_runner.py:run_powershell, tests/conftest.py:kill_process_tree, tests/conftest.py:live_gui, tests/test_conductor_abort_event.py:test_conductor_abort_event_populated, tests/test_conductor_engine_v2.py:test_conductor_engine_dynamic_parsing_and_execution, tests/test_conductor_engine_v2.py:test_conductor_engine_run_executes_tickets_in_order, tests/test_extended_sims.py:test_ai_settings_sim_live, tests/test_extended_sims.py:test_context_sim_live, tests/test_extended_sims.py:test_execution_sim_live, tests/test_extended_sims.py:test_tools_sim_live, tests/test_external_editor_gui.py:get_vscode_processes, tests/test_external_editor_gui.py:test_vscode_launches_with_diff_view, tests/test_gui_custom_window.py:test_app_window_is_borderless, tests/test_headless_simulation.py:module, tests/test_headless_verification.py:test_headless_verification_error_and_qa_interceptor, tests/test_headless_verification.py:test_headless_verification_full_run, tests/test_mock_gemini_cli.py:run_mock, tests/test_orchestration_logic.py:test_conductor_engine_run, tests/test_parallel_execution.py:test_conductor_engine_pool_integration, tests/test_sim_ai_settings.py:test_ai_settings_simulation_run, tests/test_sim_context.py:test_context_simulation_run, tests/test_sim_execution.py:test_execution_simulation_run, tests/test_sim_tools.py:test_tools_simulation_run] """ @@ -426,10 +429,18 @@ class App: api = self.create_api() uvicorn.run(api, host="0.0.0.0", port=port) else: - theme.load_from_config(self.config) - self.runner_params = hello_imgui.RunnerParams() - self.runner_params.app_window_params.window_title = "manual slop" - + from src.startup_profiler import startup_profiler + if hasattr(self, "controller") and hasattr(self.controller, "mark_gui_run_started"): + self.controller.mark_gui_run_started() + with startup_profiler.phase("theme_load_from_config"): + theme.load_from_config(self.config) + with startup_profiler.phase("imgui_bundle_import"): + from imgui_bundle import hello_imgui as _hi + with startup_profiler.phase("RunnerParams_init"): + self.runner_params = _hi.RunnerParams() + self.runner_params.app_window_params.window_title = "manual slop" + print(f"[startup] RunnerParams() init: {(time.time()-_t)*1000:.1f}ms", file=sys.stderr) + if sys.platform == "win32": self.runner_params.app_window_params.borderless = True self.runner_params.app_window_params.borderless_closable = False