Private
Public Access
0
0

began to go through the files and organize imports and gui_2.py's new context defs

still a bunch to sift through after the last ai passes
This commit is contained in:
2026-06-05 21:44:41 -04:00
parent 1d89fcaf8a
commit 873edf42cf
53 changed files with 375 additions and 238 deletions
+4
View File
@@ -16,14 +16,18 @@ import glob
import os
import re
import tomllib
from pathlib import Path, PureWindowsPath
from typing import Any, cast
from src import beads_client
from src import project_manager
from src import summarize
from src.file_cache import ASTParser
from src.performance_monitor import get_monitor
def find_next_increment(output_dir: Path, namespace: str) -> int:
pattern = re.compile(rf"^{re.escape(namespace)}_(\d+)\.md$")
max_num = 0
+14 -7
View File
@@ -16,34 +16,41 @@ import anthropic
from google import genai
from google.genai import types
from openai import OpenAI
import asyncio
import datetime
import difflib
import hashlib
import json
import os
from pathlib import Path as _P
import requests # type: ignore[import-untyped]
import sys
import threading
import time
import tomllib
# TODO(Ed): Eliminate These?
from collections import deque
from typing import Optional, Callable, Any, List, Union, cast, Iterable
from pathlib import Path
from src.events import EventEmitter
from pathlib import Path as _P
from pathlib import Path
from typing import Optional, Callable, Any, List, Union, cast, Iterable
from src import project_manager
from src import file_cache
from src import mcp_client
from src import mma_prompts
from src import performance_monitor
from src import project_manager
from src.paths import get_credentials_path
from src.tool_bias import ToolBiasEngine
from src.models import ToolPreset, BiasProfile, Tool
# TODO(Ed): Eliminate these?
from src.events import EventEmitter
from src.gemini_cli_adapter import GeminiCliAdapter
from src.models import ToolPreset, BiasProfile, Tool
from src.paths import get_credentials_path
from src.tool_bias import ToolBiasEngine
from src.tool_presets import ToolPresetManager
_provider: str = "gemini"
_model: str = "gemini-2.5-flash-lite"
_temperature: float = 0.0
+3
View File
@@ -32,11 +32,14 @@ See Also:
- docs/guide_tools.md for Hook API documentation
"""
from __future__ import annotations
import requests # type: ignore[import-untyped]
import sys
import time
from typing import Any
class ApiHookClient:
def __init__(self, base_url: str = "http://127.0.0.1:8999", api_key: str | None = None):
"""
+13 -7
View File
@@ -1,16 +1,22 @@
from __future__ import annotations
import asyncio
import json
import logging
import sys
import threading
import uuid
import sys
import asyncio
from http.server import ThreadingHTTPServer, BaseHTTPRequestHandler
from typing import Any
import logging
import websockets
# TODO(Ed): Eliminate these?
from http.server import ThreadingHTTPServer, BaseHTTPRequestHandler
from typing import Any
from websockets.asyncio.server import serve
from src import session_logger
from src import cost_tracker
from src import session_logger
"""
API Hooks - REST API for external automation and state inspection.
@@ -820,4 +826,4 @@ class WebSocketServer:
return
message = json.dumps({"channel": channel, "payload": payload})
for ws in list(self.clients[channel]):
asyncio.run_coroutine_threadsafe(ws.send(message), self.loop)
asyncio.run_coroutine_threadsafe(ws.send(message), self.loop)
+12 -6
View File
@@ -10,15 +10,18 @@ import time
import tomli_w
import traceback
import uuid
# TODO(Ed): Eliminate these?
from dataclasses import asdict
from datetime import datetime
from fastapi import FastAPI, Depends, HTTPException
from datetime import datetime
from fastapi import FastAPI, Depends, HTTPException
from pathlib import Path
from typing import Any, List, Dict, Optional, Callable
from fastapi.security.api_key import APIKeyHeader
from pathlib import Path
from typing import Any, List, Dict, Optional, Callable
from src import aggregate
from src import models
from src.models import GenerateRequest, ConfirmRequest
from src import ai_client
from src import conductor_tech_lead
from src import events
@@ -35,8 +38,11 @@ from src import shell_runner
from src import theme_2 as theme
from src import thinking_parser
from src import tool_presets
from src.context_presets import ContextPresetManager
from src.file_cache import ASTParser
from src.file_cache import ASTParser
from src.models import GenerateRequest, ConfirmRequest
def parse_symbols(text: str) -> list[str]:
"""
+5 -3
View File
@@ -1,8 +1,10 @@
from dataclasses import dataclass
from typing import List, Optional
from pathlib import Path
import json
from dataclasses import dataclass
from typing import List, Optional
from pathlib import Path
@dataclass
class Bead:
id: str
+2 -1
View File
@@ -1,6 +1,7 @@
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Optional, Callable, List, Dict, Any
from typing import Optional, Callable, List, Dict, Any
@dataclass
+2
View File
@@ -1,5 +1,7 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Callable
from src.command_palette import CommandRegistry
if TYPE_CHECKING:
+5 -2
View File
@@ -34,10 +34,13 @@ See Also:
- src/dag_engine.py for TrackDAG
"""
import json
import re
from typing import Any
from src import ai_client
from src import mma_prompts
import re
from typing import Any
def generate_tickets(track_brief: str, module_skeletons: str) -> list[dict[str, Any]]:
"""
+2
View File
@@ -1,6 +1,8 @@
from typing import Dict, Any
from src.models import ContextPreset
class ContextPresetManager:
"""Manages context presets within the project dictionary (manual_slop.toml)."""
+1
View File
@@ -33,6 +33,7 @@ See Also:
"""
import re
# Pricing per 1M tokens in USD
MODEL_PRICING = [
(r"gemini-2\.5-flash-lite", {"input_per_mtok": 0.075, "output_per_mtok": 0.30}),
+2
View File
@@ -27,9 +27,11 @@ See Also:
- src/multi_agent_conductor.py for ConductorEngine integration
"""
from typing import List
from src.models import Ticket
from src.performance_monitor import get_monitor
class TrackDAG:
"""
Manages a Directed Acyclic Graph of implementation tickets.
+5 -3
View File
@@ -1,8 +1,10 @@
from typing import List, Dict, Optional, Tuple
from dataclasses import dataclass
import shutil
import os
from pathlib import Path
from dataclasses import dataclass
from pathlib import Path
from typing import List, Dict, Optional, Tuple
@dataclass
class DiffHunk:
+3 -1
View File
@@ -30,8 +30,10 @@ Thread Safety:
- UserRequestEvent: Immutable, safe for concurrent access
"""
import queue
from typing import Callable, Any, Dict, List, Tuple, Optional
from pathlib import Path
from typing import Callable, Any, Dict, List, Tuple, Optional
class EventEmitter:
"""
+3 -1
View File
@@ -4,8 +4,10 @@ from __future__ import annotations
import os
import subprocess
import tempfile
# TODO(Ed): Eliminate these?
from pathlib import Path
from typing import Optional, List
from typing import Optional, List
from src.models import ExternalEditorConfig, TextEditorConfig
+6 -3
View File
@@ -34,13 +34,16 @@ See Also:
- docs/guide_tools.md for AST tool documentation
- src/summarize.py for heuristic summaries
"""
from pathlib import Path
from typing import Optional, Any, List, Tuple, Dict
import re
import tree_sitter
import tree_sitter_python
import tree_sitter_cpp
import tree_sitter_c
import re
# TODO(Ed): Eliminate these?
from pathlib import Path
from typing import Optional, Any, List, Tuple, Dict
_ast_cache: Dict[str, Tuple[float, tree_sitter.Tree]] = {}
+2
View File
@@ -1,7 +1,9 @@
import hashlib
import re
from typing import Optional, Tuple
class FuzzyAnchor:
@staticmethod
def get_context(lines: list[str], index: int, count: int, direction: int) -> list[str]:
+5 -3
View File
@@ -33,14 +33,16 @@ See Also:
- docs/guide_architecture.md for CLI adapter integration
- src/ai_client.py for provider dispatch
"""
import subprocess
import json
import os
import time
import subprocess
import sys
from src import session_logger
import time
from typing import Optional, Callable, Any
from src import session_logger
class GeminiCliAdapter:
"""
+133 -134
View File
@@ -17,7 +17,6 @@ import threading
import time
import tomli_w
import typing
from contextlib import ExitStack, nullcontext
# Ensure thirdparty is in sys.path for defer
_project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@@ -25,16 +24,16 @@ _thirdparty = os.path.join(_project_root, "thirdparty")
if _thirdparty not in sys.path:
sys.path.insert(0, _thirdparty)
from defer import defer
from imgui_bundle import imgui, hello_imgui, immapp, imgui_node_editor as ed, imgui_color_text_edit as ced
from pathlib import Path
from tkinter import filedialog, Tk
from typing import Optional, Any
from defer import defer
from contextlib import ExitStack, nullcontext
# from defer import defer
from pathlib import Path
from tkinter import filedialog, Tk
from typing import Optional, Any
from imgui_bundle import imgui, hello_imgui, immapp, imgui_node_editor as ed, imgui_color_text_edit as ced
from pathlib import Path
from tkinter import filedialog, Tk
from typing import Optional, Any
from src.diff_viewer import apply_patch_to_file
from src import ai_client
from src import aggregate
@@ -61,6 +60,7 @@ from src import theme_nerv_fx as theme_fx
from src import thinking_parser
from src import workspace_manager
from src.hot_reloader import HotReloader
if sys.platform == "win32":
import win32gui
import win32con
@@ -2784,8 +2784,6 @@ def render_files_and_media(app: App) -> None:
if p not in app.screenshots: app.screenshots.append(p)
return
#endregion: Context Management
def render_context_batch_actions(app: App, total_lines: int, total_ast: int) -> None:
imgui.text("Batch:")
for mode in ["full", "summary", "skeleton", "outline", "masked", "none"]:
@@ -3361,6 +3359,130 @@ def render_snapshot_tab(app: App) -> None:
with imscope.child("last_sys_prompt", 0, 0, True):
markdown_helper.render(app.last_resolved_system_prompt, context_id="snapshot_sys")
def render_empty_context_modal(app: App) -> None:
if app.show_empty_context_modal:
imgui.open_popup("Empty Context Warning")
app.show_empty_context_modal = False
if imgui.begin_popup_modal("Empty Context Warning", True, imgui.WindowFlags_.always_auto_resize)[0]:
imgui.text_colored(theme.get_color("status_warning"), "WARNING: Empty Context Composition")
imgui.text("You are attempting to generate a response without any files selected.")
imgui.text("This may result in poor AI performance or loss of project context.")
imgui.separator()
if imgui.button("Proceed Anyway", imgui.ImVec2(150, 0)):
if app._pending_generation_action == 'generate': app.controller._handle_generate_send()
elif app._pending_generation_action == 'md_only': app.controller._handle_md_only()
app._pending_generation_action = None
imgui.close_current_popup()
imgui.same_line()
if imgui.button("Cancel", imgui.ImVec2(120, 0)):
imgui.close_current_popup()
imgui.end_popup()
def render_context_modals(app: App) -> None:
render_empty_context_modal(app)
render_add_context_files_modal(app)
if app.show_missing_files_modal:
imgui.open_popup("Missing Files Warning")
app.show_missing_files_modal = False
if imgui.begin_popup_modal("Missing Files Warning", True, imgui.WindowFlags_.always_auto_resize)[0]:
imgui.text("The following files are missing from disk:")
imgui.separator()
imgui.begin_child("missing_files_list", imgui.ImVec2(0, 150), True)
for f in app.missing_context_files:
imgui.text_colored(theme.get_color("status_error"), f)
imgui.end_child()
imgui.separator()
if imgui.button("Save Anyway") or getattr(app, "_pending_save_anyway_click", False):
app._pending_save_anyway_click = False
name = app.target_context_preset_name
preset_files = []
for f in app.context_files:
import copy
from src import models
p = f.path if hasattr(f, 'path') else str(f)
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
slc = copy.deepcopy(f.custom_slices) if hasattr(f, 'custom_slices') else []
msk = copy.deepcopy(f.ast_mask) if hasattr(f, 'ast_mask') else {}
sig = f.ast_signatures if hasattr(f, 'ast_signatures') else False
dfn = f.ast_definitions if hasattr(f, 'ast_definitions') else False
preset_files.append(models.ContextFileEntry(path=p, view_mode=vm, custom_slices=slc, ast_mask=msk, ast_signatures=sig, ast_definitions=dfn))
preset = models.ContextPreset(name=name, files=preset_files, screenshots=list(app.screenshots))
app.controller.save_context_preset(preset)
app.ui_new_context_preset_name = ""
imgui.close_current_popup()
imgui.same_line()
if imgui.button("Cancel"):
imgui.close_current_popup()
imgui.end_popup()
render_ast_inspector_modal(app)
def _get_context_composition_state(app: App) -> tuple:
files_state = []
for f in app.context_files:
p = f.path if hasattr(f, 'path') else str(f)
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
agg = f.auto_aggregate if hasattr(f, 'auto_aggregate') else False
slc = tuple((s.get('start_line'), s.get('end_line'), s.get('tag'), s.get('comment')) for s in getattr(f, 'custom_slices', []))
mask = tuple(sorted(getattr(f, 'ast_mask', {}).items()))
files_state.append((p, vm, agg, slc, mask))
screenshots_state = tuple(app.screenshots)
return (tuple(files_state), screenshots_state)
def _check_auto_refresh_context_preview(app: App) -> None:
current_state = _get_context_composition_state(app)
if not hasattr(app, "_last_context_preview_state") or app._last_context_preview_state != current_state:
app._last_context_preview_state = current_state
if not any(getattr(f, 'auto_aggregate', False) for f in app.context_files) and not app.screenshots:
app.context_preview_text = "# Context Composition Empty\n\nNo files or screenshots have been selected for aggregation."
return
if getattr(app, "_is_generating_preview", False):
app._pending_preview_refresh = True
return
app._is_generating_preview = True
def worker():
try:
app.controller.context_files = app.context_files
res = app.controller._do_generate()
app.context_preview_text = res[0]
except Exception:
app.context_preview_text = "Error generating context preview."
finally:
app._is_generating_preview = False
if getattr(app, "_pending_preview_refresh", False):
app._pending_preview_refresh = False
# This will trigger again on next GUI frame because _last_context_preview_state
# will be slightly behind if another change happened during the thread.
# Or we just clear the state so it re-triggers.
app._last_context_preview_state = None
import threading
threading.Thread(target=worker, daemon=True).start()
def render_context_preview_window(app: App) -> None:
_check_auto_refresh_context_preview(app)
with imscope.window("Context Preview", app.show_windows["Context Preview"]) as (exp, opened):
app.show_windows["Context Preview"] = bool(opened)
if not opened:
app.ui_separate_context_preview = False
if exp:
if imgui.button("Close"):
app.show_windows["Context Preview"] = False
app.ui_separate_context_preview = False
imgui.same_line()
if imgui.button("Copy to Clipboard"):
imgui.set_clipboard_text(app.context_preview_text)
with imscope.child("ctx_preview_scroll", 0, 0, True):
markdown_helper.render(app.context_preview_text, context_id="ctx_preview")
#endregion: Context Management
#region: Discussions
@@ -3587,6 +3709,7 @@ def render_session_insights_panel(app: App) -> None:
imgui.text(f"Session Cost: ${insights.get('session_cost', 0):.4f}")
completed = insights.get('completed_tickets', 0)
efficiency = insights.get('efficiency', 0)
def render_prior_session_view(app: App) -> None:
with imscope.style_color(imgui.Col_.child_bg, theme.get_color("bubble_vendor")):
if imgui.button("Exit Prior Session"): app.controller.cb_exit_prior_session(); app._comms_log_dirty = True
@@ -3611,6 +3734,7 @@ def render_prior_session_view(app: App) -> None:
with theme.ai_text_style():
markdown_helper.render(content, context_id=f'prior_disc_{idx}')
imgui.separator()
def render_thinking_indicator(app: App) -> None:
is_thinking = app.ai_status in ['sending...', 'streaming...', 'running powershell...']
if is_thinking:
@@ -5406,128 +5530,3 @@ def render_mma_focus_selector(app: App) -> None:
if app.ui_focus_agent and imgui.button("x##clear_focus"): app.ui_focus_agent = None
#endregion: MMA
def render_empty_context_modal(app: App) -> None:
if app.show_empty_context_modal:
imgui.open_popup("Empty Context Warning")
app.show_empty_context_modal = False
if imgui.begin_popup_modal("Empty Context Warning", True, imgui.WindowFlags_.always_auto_resize)[0]:
imgui.text_colored(theme.get_color("status_warning"), "WARNING: Empty Context Composition")
imgui.text("You are attempting to generate a response without any files selected.")
imgui.text("This may result in poor AI performance or loss of project context.")
imgui.separator()
if imgui.button("Proceed Anyway", imgui.ImVec2(150, 0)):
if app._pending_generation_action == 'generate': app.controller._handle_generate_send()
elif app._pending_generation_action == 'md_only': app.controller._handle_md_only()
app._pending_generation_action = None
imgui.close_current_popup()
imgui.same_line()
if imgui.button("Cancel", imgui.ImVec2(120, 0)):
imgui.close_current_popup()
imgui.end_popup()
def render_context_modals(app: App) -> None:
render_empty_context_modal(app)
render_add_context_files_modal(app)
if app.show_missing_files_modal:
imgui.open_popup("Missing Files Warning")
app.show_missing_files_modal = False
if imgui.begin_popup_modal("Missing Files Warning", True, imgui.WindowFlags_.always_auto_resize)[0]:
imgui.text("The following files are missing from disk:")
imgui.separator()
imgui.begin_child("missing_files_list", imgui.ImVec2(0, 150), True)
for f in app.missing_context_files:
imgui.text_colored(theme.get_color("status_error"), f)
imgui.end_child()
imgui.separator()
if imgui.button("Save Anyway") or getattr(app, "_pending_save_anyway_click", False):
app._pending_save_anyway_click = False
name = app.target_context_preset_name
preset_files = []
for f in app.context_files:
import copy
from src import models
p = f.path if hasattr(f, 'path') else str(f)
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
slc = copy.deepcopy(f.custom_slices) if hasattr(f, 'custom_slices') else []
msk = copy.deepcopy(f.ast_mask) if hasattr(f, 'ast_mask') else {}
sig = f.ast_signatures if hasattr(f, 'ast_signatures') else False
dfn = f.ast_definitions if hasattr(f, 'ast_definitions') else False
preset_files.append(models.ContextFileEntry(path=p, view_mode=vm, custom_slices=slc, ast_mask=msk, ast_signatures=sig, ast_definitions=dfn))
preset = models.ContextPreset(name=name, files=preset_files, screenshots=list(app.screenshots))
app.controller.save_context_preset(preset)
app.ui_new_context_preset_name = ""
imgui.close_current_popup()
imgui.same_line()
if imgui.button("Cancel"):
imgui.close_current_popup()
imgui.end_popup()
render_ast_inspector_modal(app)
def _get_context_composition_state(app: App) -> tuple:
files_state = []
for f in app.context_files:
p = f.path if hasattr(f, 'path') else str(f)
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
agg = f.auto_aggregate if hasattr(f, 'auto_aggregate') else False
slc = tuple((s.get('start_line'), s.get('end_line'), s.get('tag'), s.get('comment')) for s in getattr(f, 'custom_slices', []))
mask = tuple(sorted(getattr(f, 'ast_mask', {}).items()))
files_state.append((p, vm, agg, slc, mask))
screenshots_state = tuple(app.screenshots)
return (tuple(files_state), screenshots_state)
def _check_auto_refresh_context_preview(app: App) -> None:
current_state = _get_context_composition_state(app)
if not hasattr(app, "_last_context_preview_state") or app._last_context_preview_state != current_state:
app._last_context_preview_state = current_state
if not any(getattr(f, 'auto_aggregate', False) for f in app.context_files) and not app.screenshots:
app.context_preview_text = "# Context Composition Empty\n\nNo files or screenshots have been selected for aggregation."
return
if getattr(app, "_is_generating_preview", False):
app._pending_preview_refresh = True
return
app._is_generating_preview = True
def worker():
try:
app.controller.context_files = app.context_files
res = app.controller._do_generate()
app.context_preview_text = res[0]
except Exception:
app.context_preview_text = "Error generating context preview."
finally:
app._is_generating_preview = False
if getattr(app, "_pending_preview_refresh", False):
app._pending_preview_refresh = False
# This will trigger again on next GUI frame because _last_context_preview_state
# will be slightly behind if another change happened during the thread.
# Or we just clear the state so it re-triggers.
app._last_context_preview_state = None
import threading
threading.Thread(target=worker, daemon=True).start()
def render_context_preview_window(app: App) -> None:
_check_auto_refresh_context_preview(app)
with imscope.window("Context Preview", app.show_windows["Context Preview"]) as (exp, opened):
app.show_windows["Context Preview"] = bool(opened)
if not opened:
app.ui_separate_context_preview = False
if exp:
if imgui.button("Close"):
app.show_windows["Context Preview"] = False
app.ui_separate_context_preview = False
imgui.same_line()
if imgui.button("Copy to Clipboard"):
imgui.set_clipboard_text(app.context_preview_text)
with imscope.child("ctx_preview_scroll", 0, 0, True):
markdown_helper.render(app.context_preview_text, context_id="ctx_preview")
+3 -1
View File
@@ -1,7 +1,9 @@
import typing
import time
import typing
from dataclasses import dataclass, field
@dataclass
class UISnapshot:
"""Capture of restorable UI state."""
+5 -2
View File
@@ -1,9 +1,12 @@
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Any
import copy
import traceback
from dataclasses import dataclass, field
from typing import Any
@dataclass
class HotModule:
name: str
+3
View File
@@ -1,8 +1,11 @@
from __future__ import annotations
from typing import Any
from imgui_bundle import imgui
from imgui_bundle import imgui_node_editor
def child(id_str: str, size_x: float = 0, size_y: float = 0, flags: int = 0): return _ScopeChild(id_str, size_x, size_y, flags)
class _ScopeChild:
def __init__(self, id_str: str, size_x: float | imgui.ImVec2, size_y: float, flags: int):
+3
View File
@@ -2,9 +2,12 @@ import os
import shutil
import sys
import time
from datetime import datetime, timedelta
from src.log_registry import LogRegistry
class LogPruner:
"""
+4 -2
View File
@@ -38,11 +38,13 @@ See Also:
- src/paths.py for registry path resolution
"""
from __future__ import annotations
import os
import tomli_w
import tomllib
from datetime import datetime
import os
from typing import Any
from typing import Any
class LogRegistry:
+7 -3
View File
@@ -1,11 +1,15 @@
# src/markdown_helper.py
from __future__ import annotations
from imgui_bundle import imgui_md, imgui, immapp, imgui_color_text_edit as ed
import webbrowser
import os
import re
import webbrowser
from imgui_bundle import imgui_md, imgui, immapp, imgui_color_text_edit as ed
from pathlib import Path
from typing import Optional, Dict, Callable
from typing import Optional, Dict, Callable
def _get_language_id(name: str):
"""Get a language identifier for ImGuiColorTextEdit.
+3 -1
View File
@@ -1,7 +1,9 @@
import re
from dataclasses import dataclass
from dataclasses import dataclass
from imgui_bundle import imgui, imgui_md
_TABLE_SEPARATOR = re.compile(r"^\|?\s*:?-{2,}:?\s*(\|\s*:?-{2,}:?\s*)+\|?\s*$")
def render_table(block: "TableBlock") -> None:
+9 -4
View File
@@ -52,22 +52,27 @@ See Also:
#MCP-style file context tools for manual_slop.
from __future__ import annotations
import ast
import asyncio
import json
import os
import re as _re
import subprocess
from html.parser import HTMLParser
from pathlib import Path
from typing import Optional, Callable, Any, cast
import urllib.request
import urllib.parse
from html.parser import HTMLParser
from pathlib import Path
from typing import Optional, Callable, Any, cast
from scripts import py_struct_tools
from src import beads_client
from src import models
from src import outline_tool
from src import summarize
from scripts import py_struct_tools
# ------------------------------------------------------------------ mutating tools sentinel
+1
View File
@@ -5,6 +5,7 @@ Contains templates and static strings for hierarchical orchestration.
from typing import Dict
# --- Tier 1 (Strategic/Orchestration: PM) ---
TIER1_BASE_SYSTEM: str = """
+9 -5
View File
@@ -37,16 +37,20 @@ See Also:
- src/project_manager.py for persistence layer
"""
from __future__ import annotations
import datetime
import json
import os
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any, Dict, List, Optional, Union
import tomllib
from pydantic import BaseModel
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any, Dict, List, Optional, Union
from pydantic import BaseModel
from src.paths import get_config_path
#region: Constants
PROVIDERS: List[str] = ["gemini", "anthropic", "gemini_cli", "deepseek", "minimax"]
@@ -1040,4 +1044,4 @@ def load_mcp_config(path: str) -> MCPConfiguration:
except Exception:
return MCPConfiguration()
#endregion: MCP Config
#endregion: MCP Config
+11 -8
View File
@@ -27,23 +27,26 @@ See Also:
- src/dag_engine.py for TrackDAG and ExecutionEngine
- src/models.py for Ticket, Track, WorkerContext
"""
from src import ai_client
from src import summarize
import json
import threading
import time
import traceback
from typing import List, Optional, Tuple, Callable
from dataclasses import asdict
from src import events
from src import models
from src.models import Ticket, Track, WorkerContext
from src.file_cache import ASTParser
from pathlib import Path
from src.personas import PersonaManager
from typing import List, Optional, Tuple, Callable
from src import ai_client
from src import events
from src.file_cache import ASTParser
from src import models
from src import paths
from src import summarize
from src.dag_engine import TrackDAG, ExecutionEngine
from src.models import Ticket, Track, WorkerContext
from src.personas import PersonaManager
class WorkerPool:
"""
+6 -5
View File
@@ -1,13 +1,14 @@
import json
from src import ai_client
from src import mma_prompts
from src import aggregate
from src import summarize
from pathlib import Path
from typing import Any, Optional
from src import aggregate
from src import ai_client
from src import mma_prompts
from src import paths
from src import summarize
def get_track_history_summary() -> str:
"""
+1
View File
@@ -31,6 +31,7 @@ See Also:
- src/summarize.py for heuristic file summaries
"""
import ast
from pathlib import Path
+2 -1
View File
@@ -1,5 +1,6 @@
from typing import Optional, Callable, List
from dataclasses import dataclass, field
from typing import Optional, Callable, List
@dataclass
class PendingPatch:
+6 -3
View File
@@ -40,10 +40,12 @@ See Also:
- src/session_logger.py for logging paths
- src/project_manager.py for project paths
"""
from pathlib import Path
import os
import tomllib
from typing import Optional, Any
from pathlib import Path
from typing import Optional, Any
_RESOLVED: dict[str, Path] = {}
@@ -237,4 +239,5 @@ def reset_resolved() -> None:
For testing only - clear cached resolutions.
[C: tests/conftest.py:reset_paths, tests/test_app_controller_offloading.py:tmp_session_dir, tests/test_gui_phase3.py:test_conductor_setup_scan, tests/test_paths.py:reset_paths, tests/test_project_paths.py:test_get_all_tracks_project_specific, tests/test_project_paths.py:test_get_conductor_dir_default, tests/test_project_paths.py:test_get_conductor_dir_project_specific_with_toml]
"""
_RESOLVED.clear()
_RESOLVED.clear()
+5 -2
View File
@@ -53,12 +53,15 @@ Integration:
- Exposed via Hook API at /api/performance
"""
from __future__ import annotations
import psutil
import sys
import time
import psutil
import threading
from typing import Any, Optional, Callable, Dict, List
from collections import deque
from typing import Any, Optional, Callable, Dict, List
_instance: Optional[PerformanceMonitor] = None
+4 -2
View File
@@ -1,9 +1,11 @@
import tomllib
import tomli_w
from pathlib import Path
from typing import Dict, Any, Optional
from typing import Dict, Any, Optional
from src.models import Persona
from src import paths
from src import paths
class PersonaManager:
"""Manages Persona profiles across global and project-specific files."""
+5 -2
View File
@@ -1,10 +1,13 @@
import sys
import tomllib
import tomli_w
from pathlib import Path
from typing import Dict, Any, Optional
from typing import Dict, Any, Optional
from src.models import Preset
from src.paths import get_global_presets_path, get_project_presets_path
from src.paths import get_global_presets_path, get_project_presets_path
class PresetManager:
"""Manages system prompt presets across global and project-specific files."""
+9 -4
View File
@@ -5,19 +5,24 @@ Handles loading/saving of project .toml configurations.
Also handles serializing the discussion history into the TOML format using a special
@timestamp prefix to preserve the exact sequence of events.
"""
import subprocess
import datetime
import json
import re
import subprocess
import tomllib
import tomli_w
import re
import json
from typing import Any, Optional, TYPE_CHECKING, Union
from pathlib import Path
from typing import Any, Optional, TYPE_CHECKING, Union
from src import paths
if TYPE_CHECKING:
from src.models import TrackState
TS_FMT: str = "%Y-%m-%dT%H:%M:%S"
def now_ts() -> str:
return datetime.datetime.now().strftime(TS_FMT)
+6 -3
View File
@@ -1,9 +1,11 @@
import asyncio
import copy
import json
import os
import sys
import asyncio
import json
import copy
from typing import List, Dict, Any, Optional
from src import models
from src import mcp_client
@@ -11,6 +13,7 @@ _SENTENCE_TRANSFORMERS = None
_GOOGLE_GENAI = None
_CHROMADB = None
def _get_sentence_transformers():
global _SENTENCE_TRANSFORMERS
if _SENTENCE_TRANSFORMERS is None:
+3 -1
View File
@@ -20,11 +20,13 @@ import atexit
import datetime
import json
import threading
from typing import Any, Optional, TextIO
from pathlib import Path
from typing import Any, Optional, TextIO
from src import paths
_ts: str = "" # session timestamp string e.g. "20260301_142233"
_session_id: str = "" # YYYYMMDD_HHMMSS[_Label]
_session_dir: Optional[Path] = None # Path to the sub-directory for this session
+1
View File
@@ -1,5 +1,6 @@
from imgui_bundle import imgui
def draw_soft_shadow(draw_list: imgui.ImDrawList, p_min: imgui.ImVec2, p_max: imgui.ImVec2, color: imgui.ImVec4, shadow_size: float = 10.0, rounding: float = 0.0) -> None:
"""
+4 -2
View File
@@ -7,10 +7,11 @@ configuring the environment via mcp_env.toml. It handles timeouts,
logging, and optional QA/patch callbacks for error recovery.
"""
import os
import subprocess
import shutil
import subprocess
from pathlib import Path
from typing import Callable, Optional
from typing import Callable, Optional
try:
import tomllib
@@ -20,6 +21,7 @@ except ImportError:
TIMEOUT_SECONDS: int = 60
_ENV_CONFIG: dict = {}
def _load_env_config() -> dict:
"""Load mcp_env.toml from project root or environment variable."""
env_path = os.environ.get("SLOP_MCP_ENV")
+5 -1
View File
@@ -24,12 +24,16 @@ context block that replaces full file contents in the initial <context> send.
"""
import ast
import re
from pathlib import Path
from typing import Callable, Any
from typing import Callable, Any
from src.summary_cache import SummaryCache, get_file_hash
_summary_cache = SummaryCache()
# ------------------------------------------------------------------ per-type extractors
def _summarise_python(path: Path, content: str) -> str:
+3 -1
View File
@@ -1,7 +1,9 @@
import hashlib
import json
from pathlib import Path
from typing import Optional, Dict
from typing import Optional, Dict
def get_file_hash(content: str) -> str:
"""
+11 -7
View File
@@ -8,16 +8,20 @@ Font loading uses hello_imgui.load_font().
Scale uses imgui.get_style().font_scale_main.
"""
from imgui_bundle import imgui, hello_imgui
from typing import Any, Optional
import typing
from contextlib import nullcontext
from src import imgui_scopes as imscope
from contextlib import nullcontext
from imgui_bundle import imgui, hello_imgui
from typing import Any, Optional
import src.theme_nerv
from src.theme_nerv import DATA_GREEN
from src import imgui_scopes as imscope
from src.theme_nerv import DATA_GREEN
from src.theme_nerv_fx import CRTFilter, AlertPulsing, StatusFlicker
from src.paths import get_global_themes_path
from src.theme_models import ThemeFile, load_themes_from_dir, load_themes_from_toml
from src.paths import get_global_themes_path
from src.theme_models import ThemeFile, load_themes_from_dir, load_themes_from_toml
# ------------------------------------------------------------------ palettes
+4 -2
View File
@@ -1,9 +1,11 @@
from __future__ import annotations
import sys
import tomllib
from dataclasses import dataclass
from pathlib import Path
from typing import Any
from pathlib import Path
from typing import Any
VALID_SYNTAX_PALETTES: tuple[str, ...] = ("dark", "light", "mariana", "retro_blue")
+1
View File
@@ -1,5 +1,6 @@
from imgui_bundle import imgui
def _c(r: int, g: int, b: int, a: int = 255) -> tuple[float, float, float, float]:
"""Convert 0-255 RGBA to 0.0-1.0 floats."""
return (r / 255.0, g / 255.0, b / 255.0, a / 255.0)
+3 -1
View File
@@ -1,8 +1,10 @@
import time
import math
import random
import time
from imgui_bundle import imgui
class CRTFilter:
def __init__(self):
self.enabled = True
+3
View File
@@ -1,7 +1,10 @@
import re
from typing import List, Tuple
from src.models import ThinkingSegment
def parse_thinking_trace(text: str) -> Tuple[List[ThinkingSegment], str]:
"""
+2
View File
@@ -1,6 +1,8 @@
from typing import List, Dict, Any, Optional
from src.models import Tool, ToolPreset, BiasProfile
class ToolBiasEngine:
def apply_semantic_nudges(self, tool_definitions: List[Dict[str, Any]], preset: ToolPreset) -> List[Dict[str, Any]]:
"""
+5 -2
View File
@@ -1,10 +1,13 @@
import tomllib
import tomli_w
from pathlib import Path
from typing import Dict, List, Optional, Union, Any
from src import paths
from typing import Dict, List, Optional, Union, Any
from src import paths
from src.models import ToolPreset, BiasProfile
class ToolPresetManager:
def __init__(self, project_root: Optional[Union[str, Path]] = None):
self.project_root = Path(project_root) if project_root else None
+1
View File
@@ -1,5 +1,6 @@
from dataclasses import dataclass
@dataclass(frozen=True)
class VendorMetric:
"""Atomic vendor-state metric.
+5 -2
View File
@@ -1,9 +1,12 @@
import tomllib
import tomli_w
from pathlib import Path
from typing import Dict, Any, Optional, Union
from typing import Dict, Any, Optional, Union
from src.models import WorkspaceProfile
from src import paths
from src import paths
class WorkspaceManager:
"""Manages Workspace profiles across global and project-specific files."""