From f439b5c525f9ad13c19f7af6ffeac35751b2c48b Mon Sep 17 00:00:00 2001 From: Ed_ Date: Fri, 6 Mar 2026 19:24:08 -0500 Subject: [PATCH] wip fixing regressions, removing hardcoded paths --- src/app_controller.py | 13 +++++-------- src/gui_2.py | 14 +++++--------- src/mcp_client.py | 18 ++++++++++++++---- src/models.py | 32 +++++++------------------------- src/orchestrator_pm.py | 19 ++++++++++++------- 5 files changed, 43 insertions(+), 53 deletions(-) diff --git a/src/app_controller.py b/src/app_controller.py index 1ceb5f4..95612e0 100644 --- a/src/app_controller.py +++ b/src/app_controller.py @@ -32,10 +32,6 @@ from src import conductor_tech_lead from src import multi_agent_conductor from src import theme -def save_config(config: dict[str, Any]) -> None: - with open(models.CONFIG_PATH, "wb") as f: - tomli_w.dump(config, f) - def hide_tk_root() -> Tk: root = Tk() root.withdraw() @@ -1298,7 +1294,7 @@ class AppController: self._flush_to_project() self._save_active_project() self._flush_to_config() - save_config(self.config) + models.save_config(self.config) self._set_status("config saved") def _cb_disc_create(self) -> None: @@ -1696,7 +1692,7 @@ class AppController: self._flush_to_project() self._save_active_project() self._flush_to_config() - save_config(self.config) + models.save_config(self.config) track_id = self.active_track.id if self.active_track else None flat = project_manager.flat_config(self.project, self.active_discussion, track_id=track_id) full_md, path, file_items = aggregate.run(flat) @@ -1720,8 +1716,9 @@ class AppController: sys.stderr.write(f"[DEBUG] History summary length: {len(history)}\n") sys.stderr.flush() proj = project_manager.load_project(self.active_project_path) - flat = project_manager.flat_config(proj) - file_items = aggregate.build_file_items(Path("."), flat.get("files", {}).get("paths", [])) + flat = project_manager.flat_config(self.project) + file_items = aggregate.build_file_items(Path(self.ui_files_base_dir), flat.get("files", {}).get("paths", [])) + _t1_baseline = len(ai_client.get_comms_log()) tracks = orchestrator_pm.generate_tracks(self.ui_epic_input, flat, file_items, history_summary=history) _t1_new = ai_client.get_comms_log()[_t1_baseline:] diff --git a/src/gui_2.py b/src/gui_2.py index 75265a1..93e8aa7 100644 --- a/src/gui_2.py +++ b/src/gui_2.py @@ -28,10 +28,6 @@ from imgui_bundle import imgui, hello_imgui, immapp, imgui_node_editor as ed PROVIDERS: list[str] = ["gemini", "anthropic", "gemini_cli", "deepseek"] COMMS_CLAMP_CHARS: int = 300 -def save_config(config: dict[str, Any]) -> None: - with open(models.CONFIG_PATH, "wb") as f: - tomli_w.dump(config, f) - def hide_tk_root() -> Tk: root = Tk() root.withdraw() @@ -208,7 +204,7 @@ class App: self._flush_to_project() self._save_active_project() self._flush_to_config() - save_config(self.config) + models.save_config(self.config) self.ai_status = "config saved" if imgui.menu_item("Reset Session", "", False)[0]: ai_client.reset_session() @@ -248,7 +244,7 @@ class App: self._flush_to_project() self._save_active_project() self._flush_to_config() - save_config(self.config) + models.save_config(self.config) except Exception: pass # silent — don't disrupt the GUI loop # Sync pending comms @@ -721,7 +717,7 @@ class App: self._flush_to_project() self._save_active_project() self._flush_to_config() - save_config(self.config) + models.save_config(self.config) self.ai_status = "config saved" ch, self.ui_word_wrap = imgui.checkbox("Word-Wrap (Read-only panels)", self.ui_word_wrap) ch, self.ui_summary_only = imgui.checkbox("Summary Only (send file structure, not full content)", self.ui_summary_only) @@ -1019,7 +1015,7 @@ class App: self._flush_to_project() self._save_active_project() self._flush_to_config() - save_config(self.config) + models.save_config(self.config) self.ai_status = "discussion saved" ch, self.ui_auto_add_history = imgui.checkbox("Auto-add message & response to history", self.ui_auto_add_history) # Truncation controls @@ -1994,7 +1990,7 @@ class App: imgui.same_line() if imgui.button("Apply Font (Requires Restart)"): self._flush_to_config() - save_config(self.config) + models.save_config(self.config) self.ai_status = "Font settings saved. Restart required." imgui.separator() imgui.text("UI Scale (DPI)") diff --git a/src/mcp_client.py b/src/mcp_client.py index 8d3fded..df2c5ca 100644 --- a/src/mcp_client.py +++ b/src/mcp_client.py @@ -105,14 +105,24 @@ def _is_allowed(path: Path) -> bool: CRITICAL: Blacklisted files (history) are NEVER allowed. """ - # Blacklist check - name = path.name.lower() - if name in ("history.toml", "config.toml", "credentials.toml") or name.endswith("_history.toml"): - return False + from src.paths import get_config_path + from src.ai_client import get_credentials_path + try: rp = path.resolve(strict=True) except (OSError, ValueError): rp = path.resolve() + + # Blacklist check by resolved path + if rp == get_config_path().resolve(): + return False + if rp == get_credentials_path().resolve(): + return False + + name = path.name.lower() + if name == "history.toml" or name.endswith("_history.toml"): + return False + if rp in _allowed_paths: return True # Allow current working directory and subpaths by default if no base_dirs diff --git a/src/models.py b/src/models.py index dd13635..9844a4c 100644 --- a/src/models.py +++ b/src/models.py @@ -1,16 +1,21 @@ from __future__ import annotations import tomllib -import os from dataclasses import dataclass, field from typing import List, Optional, Dict, Any, Union from pathlib import Path +from src.paths import get_config_path -CONFIG_PATH = Path(os.environ.get("SLOP_CONFIG", "config.toml")) +CONFIG_PATH = get_config_path() def load_config() -> dict[str, Any]: with open(CONFIG_PATH, "rb") as f: return tomllib.load(f) +def save_config(config: dict[str, Any]) -> None: + import tomli_w + with open(CONFIG_PATH, "wb") as f: + tomli_w.dump(config, f) + # Global constants for agent tools AGENT_TOOL_NAMES = [ "read_file", @@ -32,29 +37,6 @@ AGENT_TOOL_NAMES = [ "py_get_hierarchy" ] -def parse_history_entries(history_strings: list[str], roles: list[str]) -> list[dict[str, Any]]: - """Parse stored history strings back to disc entry dicts.""" - import re - entries = [] - for raw in history_strings: - ts = "" - rest = raw - if rest.startswith("@"): - nl = rest.find("\n") - if nl != -1: - ts = rest[1:nl] - rest = rest[nl + 1:] - known = roles or ["User", "AI"] - role_pat = re.compile(r"^(" + "|".join(re.escape(r) for r in known) + r"):", re.IGNORECASE) - match = role_pat.match(rest) - role = match.group(1) if match else "User" - if match: - content = rest[match.end():].strip() - else: - content = rest - entries.append({"role": role, "content": content, "collapsed": False, "ts": ts}) - return entries - @dataclass class Ticket: """ diff --git a/src/orchestrator_pm.py b/src/orchestrator_pm.py index 074756e..2091656 100644 --- a/src/orchestrator_pm.py +++ b/src/orchestrator_pm.py @@ -113,10 +113,15 @@ def generate_tracks(user_request: str, project_config: dict[str, Any], file_item if __name__ == "__main__": # Quick CLI test import project_manager - proj = project_manager.load_project("manual_slop.toml") - flat = project_manager.flat_config(proj) - file_items = aggregate.build_file_items(Path("."), flat.get("files", {}).get("paths", [])) - print("Testing Tier 1 Track Generation...") - history = get_track_history_summary() - tracks = generate_tracks("Implement a basic unit test for the ai_client.py module.", flat, file_items, history_summary=history) - print(json.dumps(tracks, indent=2)) + from src import aggregate + test_project = Path("manual_slop.toml") + if not test_project.exists(): + print(f"Error: {test_project} not found for testing.") + else: + proj = project_manager.load_project(str(test_project)) + flat = project_manager.flat_config(proj) + file_items = aggregate.build_file_items(Path("."), flat.get("files", {}).get("paths", [])) + print("Testing Tier 1 Track Generation...") + history = get_track_history_summary() + tracks = generate_tracks("Implement a basic unit test for the ai_client.py module.", flat, file_items, history_summary=history) + print(json.dumps(tracks, indent=2))