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:
@@ -16,14 +16,18 @@ import glob
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import tomllib
|
import tomllib
|
||||||
|
|
||||||
from pathlib import Path, PureWindowsPath
|
from pathlib import Path, PureWindowsPath
|
||||||
from typing import Any, cast
|
from typing import Any, cast
|
||||||
|
|
||||||
from src import beads_client
|
from src import beads_client
|
||||||
from src import project_manager
|
from src import project_manager
|
||||||
from src import summarize
|
from src import summarize
|
||||||
|
|
||||||
from src.file_cache import ASTParser
|
from src.file_cache import ASTParser
|
||||||
from src.performance_monitor import get_monitor
|
from src.performance_monitor import get_monitor
|
||||||
|
|
||||||
|
|
||||||
def find_next_increment(output_dir: Path, namespace: str) -> int:
|
def find_next_increment(output_dir: Path, namespace: str) -> int:
|
||||||
pattern = re.compile(rf"^{re.escape(namespace)}_(\d+)\.md$")
|
pattern = re.compile(rf"^{re.escape(namespace)}_(\d+)\.md$")
|
||||||
max_num = 0
|
max_num = 0
|
||||||
|
|||||||
+14
-7
@@ -16,34 +16,41 @@ import anthropic
|
|||||||
from google import genai
|
from google import genai
|
||||||
from google.genai import types
|
from google.genai import types
|
||||||
from openai import OpenAI
|
from openai import OpenAI
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import datetime
|
import datetime
|
||||||
import difflib
|
import difflib
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
from pathlib import Path as _P
|
|
||||||
import requests # type: ignore[import-untyped]
|
import requests # type: ignore[import-untyped]
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import tomllib
|
import tomllib
|
||||||
|
|
||||||
|
# TODO(Ed): Eliminate These?
|
||||||
from collections import deque
|
from collections import deque
|
||||||
from typing import Optional, Callable, Any, List, Union, cast, Iterable
|
from pathlib import Path as _P
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from src.events import EventEmitter
|
from typing import Optional, Callable, Any, List, Union, cast, Iterable
|
||||||
|
|
||||||
from src import project_manager
|
from src import project_manager
|
||||||
from src import file_cache
|
from src import file_cache
|
||||||
from src import mcp_client
|
from src import mcp_client
|
||||||
from src import mma_prompts
|
from src import mma_prompts
|
||||||
from src import performance_monitor
|
from src import performance_monitor
|
||||||
from src import project_manager
|
from src import project_manager
|
||||||
from src.paths import get_credentials_path
|
|
||||||
from src.tool_bias import ToolBiasEngine
|
# TODO(Ed): Eliminate these?
|
||||||
from src.models import ToolPreset, BiasProfile, Tool
|
from src.events import EventEmitter
|
||||||
from src.gemini_cli_adapter import GeminiCliAdapter
|
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
|
from src.tool_presets import ToolPresetManager
|
||||||
|
|
||||||
|
|
||||||
_provider: str = "gemini"
|
_provider: str = "gemini"
|
||||||
_model: str = "gemini-2.5-flash-lite"
|
_model: str = "gemini-2.5-flash-lite"
|
||||||
_temperature: float = 0.0
|
_temperature: float = 0.0
|
||||||
|
|||||||
@@ -32,11 +32,14 @@ See Also:
|
|||||||
- docs/guide_tools.md for Hook API documentation
|
- docs/guide_tools.md for Hook API documentation
|
||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import requests # type: ignore[import-untyped]
|
import requests # type: ignore[import-untyped]
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
class ApiHookClient:
|
class ApiHookClient:
|
||||||
def __init__(self, base_url: str = "http://127.0.0.1:8999", api_key: str | None = None):
|
def __init__(self, base_url: str = "http://127.0.0.1:8999", api_key: str | None = None):
|
||||||
"""
|
"""
|
||||||
|
|||||||
+13
-7
@@ -1,16 +1,22 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import asyncio
|
||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import uuid
|
import uuid
|
||||||
import sys
|
|
||||||
import asyncio
|
|
||||||
from http.server import ThreadingHTTPServer, BaseHTTPRequestHandler
|
|
||||||
from typing import Any
|
|
||||||
import logging
|
|
||||||
import websockets
|
import websockets
|
||||||
|
|
||||||
|
# TODO(Ed): Eliminate these?
|
||||||
|
from http.server import ThreadingHTTPServer, BaseHTTPRequestHandler
|
||||||
|
from typing import Any
|
||||||
from websockets.asyncio.server import serve
|
from websockets.asyncio.server import serve
|
||||||
from src import session_logger
|
|
||||||
from src import cost_tracker
|
from src import cost_tracker
|
||||||
|
from src import session_logger
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
API Hooks - REST API for external automation and state inspection.
|
API Hooks - REST API for external automation and state inspection.
|
||||||
|
|
||||||
@@ -820,4 +826,4 @@ class WebSocketServer:
|
|||||||
return
|
return
|
||||||
message = json.dumps({"channel": channel, "payload": payload})
|
message = json.dumps({"channel": channel, "payload": payload})
|
||||||
for ws in list(self.clients[channel]):
|
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
@@ -10,15 +10,18 @@ import time
|
|||||||
import tomli_w
|
import tomli_w
|
||||||
import traceback
|
import traceback
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
# TODO(Ed): Eliminate these?
|
||||||
from dataclasses import asdict
|
from dataclasses import asdict
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from fastapi import FastAPI, Depends, HTTPException
|
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 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 aggregate
|
||||||
from src import models
|
from src import models
|
||||||
from src.models import GenerateRequest, ConfirmRequest
|
|
||||||
from src import ai_client
|
from src import ai_client
|
||||||
from src import conductor_tech_lead
|
from src import conductor_tech_lead
|
||||||
from src import events
|
from src import events
|
||||||
@@ -35,8 +38,11 @@ from src import shell_runner
|
|||||||
from src import theme_2 as theme
|
from src import theme_2 as theme
|
||||||
from src import thinking_parser
|
from src import thinking_parser
|
||||||
from src import tool_presets
|
from src import tool_presets
|
||||||
|
|
||||||
from src.context_presets import ContextPresetManager
|
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]:
|
def parse_symbols(text: str) -> list[str]:
|
||||||
"""
|
"""
|
||||||
|
|||||||
+5
-3
@@ -1,8 +1,10 @@
|
|||||||
from dataclasses import dataclass
|
|
||||||
from typing import List, Optional
|
|
||||||
from pathlib import Path
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import List, Optional
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Bead:
|
class Bead:
|
||||||
id: str
|
id: str
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from typing import Optional, Callable, List, Dict, Any
|
from typing import Optional, Callable, List, Dict, Any
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import TYPE_CHECKING, Callable
|
from typing import TYPE_CHECKING, Callable
|
||||||
|
|
||||||
from src.command_palette import CommandRegistry
|
from src.command_palette import CommandRegistry
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
|||||||
@@ -34,10 +34,13 @@ See Also:
|
|||||||
- src/dag_engine.py for TrackDAG
|
- src/dag_engine.py for TrackDAG
|
||||||
"""
|
"""
|
||||||
import json
|
import json
|
||||||
|
import re
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from src import ai_client
|
from src import ai_client
|
||||||
from src import mma_prompts
|
from src import mma_prompts
|
||||||
import re
|
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
def generate_tickets(track_brief: str, module_skeletons: str) -> list[dict[str, Any]]:
|
def generate_tickets(track_brief: str, module_skeletons: str) -> list[dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from typing import Dict, Any
|
from typing import Dict, Any
|
||||||
|
|
||||||
from src.models import ContextPreset
|
from src.models import ContextPreset
|
||||||
|
|
||||||
|
|
||||||
class ContextPresetManager:
|
class ContextPresetManager:
|
||||||
"""Manages context presets within the project dictionary (manual_slop.toml)."""
|
"""Manages context presets within the project dictionary (manual_slop.toml)."""
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ See Also:
|
|||||||
"""
|
"""
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
||||||
# Pricing per 1M tokens in USD
|
# Pricing per 1M tokens in USD
|
||||||
MODEL_PRICING = [
|
MODEL_PRICING = [
|
||||||
(r"gemini-2\.5-flash-lite", {"input_per_mtok": 0.075, "output_per_mtok": 0.30}),
|
(r"gemini-2\.5-flash-lite", {"input_per_mtok": 0.075, "output_per_mtok": 0.30}),
|
||||||
|
|||||||
@@ -27,9 +27,11 @@ See Also:
|
|||||||
- src/multi_agent_conductor.py for ConductorEngine integration
|
- src/multi_agent_conductor.py for ConductorEngine integration
|
||||||
"""
|
"""
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from src.models import Ticket
|
from src.models import Ticket
|
||||||
from src.performance_monitor import get_monitor
|
from src.performance_monitor import get_monitor
|
||||||
|
|
||||||
|
|
||||||
class TrackDAG:
|
class TrackDAG:
|
||||||
"""
|
"""
|
||||||
Manages a Directed Acyclic Graph of implementation tickets.
|
Manages a Directed Acyclic Graph of implementation tickets.
|
||||||
|
|||||||
+5
-3
@@ -1,8 +1,10 @@
|
|||||||
from typing import List, Dict, Optional, Tuple
|
|
||||||
from dataclasses import dataclass
|
|
||||||
import shutil
|
import shutil
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import List, Dict, Optional, Tuple
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class DiffHunk:
|
class DiffHunk:
|
||||||
|
|||||||
+3
-1
@@ -30,8 +30,10 @@ Thread Safety:
|
|||||||
- UserRequestEvent: Immutable, safe for concurrent access
|
- UserRequestEvent: Immutable, safe for concurrent access
|
||||||
"""
|
"""
|
||||||
import queue
|
import queue
|
||||||
from typing import Callable, Any, Dict, List, Tuple, Optional
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Callable, Any, Dict, List, Tuple, Optional
|
||||||
|
|
||||||
|
|
||||||
class EventEmitter:
|
class EventEmitter:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -4,8 +4,10 @@ from __future__ import annotations
|
|||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
|
# TODO(Ed): Eliminate these?
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional, List
|
from typing import Optional, List
|
||||||
|
|
||||||
from src.models import ExternalEditorConfig, TextEditorConfig
|
from src.models import ExternalEditorConfig, TextEditorConfig
|
||||||
|
|
||||||
|
|||||||
+6
-3
@@ -34,13 +34,16 @@ See Also:
|
|||||||
- docs/guide_tools.md for AST tool documentation
|
- docs/guide_tools.md for AST tool documentation
|
||||||
- src/summarize.py for heuristic summaries
|
- src/summarize.py for heuristic summaries
|
||||||
"""
|
"""
|
||||||
from pathlib import Path
|
import re
|
||||||
from typing import Optional, Any, List, Tuple, Dict
|
|
||||||
import tree_sitter
|
import tree_sitter
|
||||||
import tree_sitter_python
|
import tree_sitter_python
|
||||||
import tree_sitter_cpp
|
import tree_sitter_cpp
|
||||||
import tree_sitter_c
|
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]] = {}
|
_ast_cache: Dict[str, Tuple[float, tree_sitter.Tree]] = {}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import hashlib
|
import hashlib
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from typing import Optional, Tuple
|
from typing import Optional, Tuple
|
||||||
|
|
||||||
|
|
||||||
class FuzzyAnchor:
|
class FuzzyAnchor:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_context(lines: list[str], index: int, count: int, direction: int) -> list[str]:
|
def get_context(lines: list[str], index: int, count: int, direction: int) -> list[str]:
|
||||||
|
|||||||
@@ -33,14 +33,16 @@ See Also:
|
|||||||
- docs/guide_architecture.md for CLI adapter integration
|
- docs/guide_architecture.md for CLI adapter integration
|
||||||
- src/ai_client.py for provider dispatch
|
- src/ai_client.py for provider dispatch
|
||||||
"""
|
"""
|
||||||
import subprocess
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import time
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
from src import session_logger
|
import time
|
||||||
|
|
||||||
from typing import Optional, Callable, Any
|
from typing import Optional, Callable, Any
|
||||||
|
|
||||||
|
from src import session_logger
|
||||||
|
|
||||||
|
|
||||||
class GeminiCliAdapter:
|
class GeminiCliAdapter:
|
||||||
"""
|
"""
|
||||||
|
|||||||
+133
-134
@@ -17,7 +17,6 @@ import threading
|
|||||||
import time
|
import time
|
||||||
import tomli_w
|
import tomli_w
|
||||||
import typing
|
import typing
|
||||||
from contextlib import ExitStack, nullcontext
|
|
||||||
|
|
||||||
# Ensure thirdparty is in sys.path for defer
|
# Ensure thirdparty is in sys.path for defer
|
||||||
_project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
_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:
|
if _thirdparty not in sys.path:
|
||||||
sys.path.insert(0, _thirdparty)
|
sys.path.insert(0, _thirdparty)
|
||||||
|
|
||||||
from defer import defer
|
from contextlib import ExitStack, nullcontext
|
||||||
from imgui_bundle import imgui, hello_imgui, immapp, imgui_node_editor as ed, imgui_color_text_edit as ced
|
# from defer import defer
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from tkinter import filedialog, Tk
|
from tkinter import filedialog, Tk
|
||||||
from typing import Optional, Any
|
from typing import Optional, Any
|
||||||
from defer import defer
|
|
||||||
from imgui_bundle import imgui, hello_imgui, immapp, imgui_node_editor as ed, imgui_color_text_edit as ced
|
from imgui_bundle import imgui, hello_imgui, immapp, imgui_node_editor as ed, imgui_color_text_edit as ced
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from tkinter import filedialog, Tk
|
from tkinter import filedialog, Tk
|
||||||
from typing import Optional, Any
|
from typing import Optional, Any
|
||||||
|
|
||||||
from src.diff_viewer import apply_patch_to_file
|
from src.diff_viewer import apply_patch_to_file
|
||||||
from src import ai_client
|
from src import ai_client
|
||||||
from src import aggregate
|
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 thinking_parser
|
||||||
from src import workspace_manager
|
from src import workspace_manager
|
||||||
from src.hot_reloader import HotReloader
|
from src.hot_reloader import HotReloader
|
||||||
|
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
import win32gui
|
import win32gui
|
||||||
import win32con
|
import win32con
|
||||||
@@ -2784,8 +2784,6 @@ def render_files_and_media(app: App) -> None:
|
|||||||
if p not in app.screenshots: app.screenshots.append(p)
|
if p not in app.screenshots: app.screenshots.append(p)
|
||||||
return
|
return
|
||||||
|
|
||||||
#endregion: Context Management
|
|
||||||
|
|
||||||
def render_context_batch_actions(app: App, total_lines: int, total_ast: int) -> None:
|
def render_context_batch_actions(app: App, total_lines: int, total_ast: int) -> None:
|
||||||
imgui.text("Batch:")
|
imgui.text("Batch:")
|
||||||
for mode in ["full", "summary", "skeleton", "outline", "masked", "none"]:
|
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):
|
with imscope.child("last_sys_prompt", 0, 0, True):
|
||||||
markdown_helper.render(app.last_resolved_system_prompt, context_id="snapshot_sys")
|
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
|
#endregion: Context Management
|
||||||
|
|
||||||
#region: Discussions
|
#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}")
|
imgui.text(f"Session Cost: ${insights.get('session_cost', 0):.4f}")
|
||||||
completed = insights.get('completed_tickets', 0)
|
completed = insights.get('completed_tickets', 0)
|
||||||
efficiency = insights.get('efficiency', 0)
|
efficiency = insights.get('efficiency', 0)
|
||||||
|
|
||||||
def render_prior_session_view(app: App) -> None:
|
def render_prior_session_view(app: App) -> None:
|
||||||
with imscope.style_color(imgui.Col_.child_bg, theme.get_color("bubble_vendor")):
|
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
|
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():
|
with theme.ai_text_style():
|
||||||
markdown_helper.render(content, context_id=f'prior_disc_{idx}')
|
markdown_helper.render(content, context_id=f'prior_disc_{idx}')
|
||||||
imgui.separator()
|
imgui.separator()
|
||||||
|
|
||||||
def render_thinking_indicator(app: App) -> None:
|
def render_thinking_indicator(app: App) -> None:
|
||||||
is_thinking = app.ai_status in ['sending...', 'streaming...', 'running powershell...']
|
is_thinking = app.ai_status in ['sending...', 'streaming...', 'running powershell...']
|
||||||
if is_thinking:
|
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
|
if app.ui_focus_agent and imgui.button("x##clear_focus"): app.ui_focus_agent = None
|
||||||
|
|
||||||
#endregion: MMA
|
#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
@@ -1,7 +1,9 @@
|
|||||||
import typing
|
|
||||||
import time
|
import time
|
||||||
|
import typing
|
||||||
|
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class UISnapshot:
|
class UISnapshot:
|
||||||
"""Capture of restorable UI state."""
|
"""Capture of restorable UI state."""
|
||||||
|
|||||||
+5
-2
@@ -1,9 +1,12 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from dataclasses import dataclass, field
|
|
||||||
from typing import Any
|
|
||||||
import copy
|
import copy
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class HotModule:
|
class HotModule:
|
||||||
name: str
|
name: str
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from imgui_bundle import imgui
|
from imgui_bundle import imgui
|
||||||
from imgui_bundle import imgui_node_editor
|
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)
|
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:
|
class _ScopeChild:
|
||||||
def __init__(self, id_str: str, size_x: float | imgui.ImVec2, size_y: float, flags: int):
|
def __init__(self, id_str: str, size_x: float | imgui.ImVec2, size_y: float, flags: int):
|
||||||
|
|||||||
@@ -2,9 +2,12 @@ import os
|
|||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
from src.log_registry import LogRegistry
|
from src.log_registry import LogRegistry
|
||||||
|
|
||||||
|
|
||||||
class LogPruner:
|
class LogPruner:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|||||||
+4
-2
@@ -38,11 +38,13 @@ See Also:
|
|||||||
- src/paths.py for registry path resolution
|
- src/paths.py for registry path resolution
|
||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
import tomli_w
|
import tomli_w
|
||||||
import tomllib
|
import tomllib
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import os
|
from typing import Any
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
|
|
||||||
class LogRegistry:
|
class LogRegistry:
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
# src/markdown_helper.py
|
# src/markdown_helper.py
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from imgui_bundle import imgui_md, imgui, immapp, imgui_color_text_edit as ed
|
|
||||||
import webbrowser
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import webbrowser
|
||||||
|
|
||||||
|
from imgui_bundle import imgui_md, imgui, immapp, imgui_color_text_edit as ed
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional, Dict, Callable
|
from typing import Optional, Dict, Callable
|
||||||
|
|
||||||
|
|
||||||
def _get_language_id(name: str):
|
def _get_language_id(name: str):
|
||||||
"""Get a language identifier for ImGuiColorTextEdit.
|
"""Get a language identifier for ImGuiColorTextEdit.
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import re
|
import re
|
||||||
from dataclasses import dataclass
|
|
||||||
|
from dataclasses import dataclass
|
||||||
from imgui_bundle import imgui, imgui_md
|
from imgui_bundle import imgui, imgui_md
|
||||||
|
|
||||||
|
|
||||||
_TABLE_SEPARATOR = re.compile(r"^\|?\s*:?-{2,}:?\s*(\|\s*:?-{2,}:?\s*)+\|?\s*$")
|
_TABLE_SEPARATOR = re.compile(r"^\|?\s*:?-{2,}:?\s*(\|\s*:?-{2,}:?\s*)+\|?\s*$")
|
||||||
|
|
||||||
def render_table(block: "TableBlock") -> None:
|
def render_table(block: "TableBlock") -> None:
|
||||||
|
|||||||
+9
-4
@@ -52,22 +52,27 @@ See Also:
|
|||||||
#MCP-style file context tools for manual_slop.
|
#MCP-style file context tools for manual_slop.
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import ast
|
import ast
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import re as _re
|
import re as _re
|
||||||
import subprocess
|
import subprocess
|
||||||
from html.parser import HTMLParser
|
|
||||||
from pathlib import Path
|
|
||||||
from typing import Optional, Callable, Any, cast
|
|
||||||
import urllib.request
|
import urllib.request
|
||||||
import urllib.parse
|
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 beads_client
|
||||||
from src import models
|
from src import models
|
||||||
from src import outline_tool
|
from src import outline_tool
|
||||||
from src import summarize
|
from src import summarize
|
||||||
from scripts import py_struct_tools
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------ mutating tools sentinel
|
# ------------------------------------------------------------------ mutating tools sentinel
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ Contains templates and static strings for hierarchical orchestration.
|
|||||||
|
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
||||||
|
|
||||||
# --- Tier 1 (Strategic/Orchestration: PM) ---
|
# --- Tier 1 (Strategic/Orchestration: PM) ---
|
||||||
|
|
||||||
TIER1_BASE_SYSTEM: str = """
|
TIER1_BASE_SYSTEM: str = """
|
||||||
|
|||||||
+9
-5
@@ -37,16 +37,20 @@ See Also:
|
|||||||
- src/project_manager.py for persistence layer
|
- src/project_manager.py for persistence layer
|
||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
from dataclasses import dataclass, field
|
|
||||||
from pathlib import Path
|
|
||||||
from typing import Any, Dict, List, Optional, Union
|
|
||||||
import tomllib
|
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
|
from src.paths import get_config_path
|
||||||
|
|
||||||
|
|
||||||
#region: Constants
|
#region: Constants
|
||||||
|
|
||||||
PROVIDERS: List[str] = ["gemini", "anthropic", "gemini_cli", "deepseek", "minimax"]
|
PROVIDERS: List[str] = ["gemini", "anthropic", "gemini_cli", "deepseek", "minimax"]
|
||||||
@@ -1040,4 +1044,4 @@ def load_mcp_config(path: str) -> MCPConfiguration:
|
|||||||
except Exception:
|
except Exception:
|
||||||
return MCPConfiguration()
|
return MCPConfiguration()
|
||||||
|
|
||||||
#endregion: MCP Config
|
#endregion: MCP Config
|
||||||
|
|||||||
@@ -27,23 +27,26 @@ See Also:
|
|||||||
- src/dag_engine.py for TrackDAG and ExecutionEngine
|
- src/dag_engine.py for TrackDAG and ExecutionEngine
|
||||||
- src/models.py for Ticket, Track, WorkerContext
|
- src/models.py for Ticket, Track, WorkerContext
|
||||||
"""
|
"""
|
||||||
from src import ai_client
|
|
||||||
from src import summarize
|
|
||||||
import json
|
import json
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
from typing import List, Optional, Tuple, Callable
|
|
||||||
from dataclasses import asdict
|
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 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 paths
|
||||||
|
from src import summarize
|
||||||
|
|
||||||
from src.dag_engine import TrackDAG, ExecutionEngine
|
from src.dag_engine import TrackDAG, ExecutionEngine
|
||||||
|
from src.models import Ticket, Track, WorkerContext
|
||||||
|
from src.personas import PersonaManager
|
||||||
|
|
||||||
|
|
||||||
class WorkerPool:
|
class WorkerPool:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
|
|
||||||
import json
|
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 pathlib import Path
|
||||||
from typing import Any, Optional
|
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 paths
|
||||||
|
from src import summarize
|
||||||
|
|
||||||
|
|
||||||
def get_track_history_summary() -> str:
|
def get_track_history_summary() -> str:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ See Also:
|
|||||||
- src/summarize.py for heuristic file summaries
|
- src/summarize.py for heuristic file summaries
|
||||||
"""
|
"""
|
||||||
import ast
|
import ast
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -1,5 +1,6 @@
|
|||||||
from typing import Optional, Callable, List
|
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
|
from typing import Optional, Callable, List
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class PendingPatch:
|
class PendingPatch:
|
||||||
|
|||||||
+6
-3
@@ -40,10 +40,12 @@ See Also:
|
|||||||
- src/session_logger.py for logging paths
|
- src/session_logger.py for logging paths
|
||||||
- src/project_manager.py for project paths
|
- src/project_manager.py for project paths
|
||||||
"""
|
"""
|
||||||
from pathlib import Path
|
|
||||||
import os
|
import os
|
||||||
import tomllib
|
import tomllib
|
||||||
from typing import Optional, Any
|
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Optional, Any
|
||||||
|
|
||||||
|
|
||||||
_RESOLVED: dict[str, Path] = {}
|
_RESOLVED: dict[str, Path] = {}
|
||||||
|
|
||||||
@@ -237,4 +239,5 @@ def reset_resolved() -> None:
|
|||||||
For testing only - clear cached resolutions.
|
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]
|
[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()
|
||||||
|
|
||||||
@@ -53,12 +53,15 @@ Integration:
|
|||||||
- Exposed via Hook API at /api/performance
|
- Exposed via Hook API at /api/performance
|
||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import psutil
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import psutil
|
|
||||||
import threading
|
import threading
|
||||||
from typing import Any, Optional, Callable, Dict, List
|
|
||||||
from collections import deque
|
from collections import deque
|
||||||
|
from typing import Any, Optional, Callable, Dict, List
|
||||||
|
|
||||||
|
|
||||||
_instance: Optional[PerformanceMonitor] = None
|
_instance: Optional[PerformanceMonitor] = None
|
||||||
|
|
||||||
|
|||||||
+4
-2
@@ -1,9 +1,11 @@
|
|||||||
import tomllib
|
import tomllib
|
||||||
import tomli_w
|
import tomli_w
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, Any, Optional
|
from typing import Dict, Any, Optional
|
||||||
|
|
||||||
from src.models import Persona
|
from src.models import Persona
|
||||||
from src import paths
|
from src import paths
|
||||||
|
|
||||||
class PersonaManager:
|
class PersonaManager:
|
||||||
"""Manages Persona profiles across global and project-specific files."""
|
"""Manages Persona profiles across global and project-specific files."""
|
||||||
|
|||||||
+5
-2
@@ -1,10 +1,13 @@
|
|||||||
import sys
|
import sys
|
||||||
import tomllib
|
import tomllib
|
||||||
import tomli_w
|
import tomli_w
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, Any, Optional
|
from typing import Dict, Any, Optional
|
||||||
|
|
||||||
from src.models import Preset
|
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:
|
class PresetManager:
|
||||||
"""Manages system prompt presets across global and project-specific files."""
|
"""Manages system prompt presets across global and project-specific files."""
|
||||||
|
|||||||
@@ -5,19 +5,24 @@ Handles loading/saving of project .toml configurations.
|
|||||||
Also handles serializing the discussion history into the TOML format using a special
|
Also handles serializing the discussion history into the TOML format using a special
|
||||||
@timestamp prefix to preserve the exact sequence of events.
|
@timestamp prefix to preserve the exact sequence of events.
|
||||||
"""
|
"""
|
||||||
import subprocess
|
|
||||||
import datetime
|
import datetime
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
import tomllib
|
import tomllib
|
||||||
import tomli_w
|
import tomli_w
|
||||||
import re
|
|
||||||
import json
|
|
||||||
from typing import Any, Optional, TYPE_CHECKING, Union
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Any, Optional, TYPE_CHECKING, Union
|
||||||
|
|
||||||
from src import paths
|
from src import paths
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from src.models import TrackState
|
from src.models import TrackState
|
||||||
|
|
||||||
TS_FMT: str = "%Y-%m-%dT%H:%M:%S"
|
TS_FMT: str = "%Y-%m-%dT%H:%M:%S"
|
||||||
|
|
||||||
|
|
||||||
def now_ts() -> str:
|
def now_ts() -> str:
|
||||||
return datetime.datetime.now().strftime(TS_FMT)
|
return datetime.datetime.now().strftime(TS_FMT)
|
||||||
|
|
||||||
|
|||||||
+6
-3
@@ -1,9 +1,11 @@
|
|||||||
|
import asyncio
|
||||||
|
import copy
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import asyncio
|
|
||||||
import json
|
|
||||||
import copy
|
|
||||||
from typing import List, Dict, Any, Optional
|
from typing import List, Dict, Any, Optional
|
||||||
|
|
||||||
from src import models
|
from src import models
|
||||||
from src import mcp_client
|
from src import mcp_client
|
||||||
|
|
||||||
@@ -11,6 +13,7 @@ _SENTENCE_TRANSFORMERS = None
|
|||||||
_GOOGLE_GENAI = None
|
_GOOGLE_GENAI = None
|
||||||
_CHROMADB = None
|
_CHROMADB = None
|
||||||
|
|
||||||
|
|
||||||
def _get_sentence_transformers():
|
def _get_sentence_transformers():
|
||||||
global _SENTENCE_TRANSFORMERS
|
global _SENTENCE_TRANSFORMERS
|
||||||
if _SENTENCE_TRANSFORMERS is None:
|
if _SENTENCE_TRANSFORMERS is None:
|
||||||
|
|||||||
@@ -20,11 +20,13 @@ import atexit
|
|||||||
import datetime
|
import datetime
|
||||||
import json
|
import json
|
||||||
import threading
|
import threading
|
||||||
from typing import Any, Optional, TextIO
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Any, Optional, TextIO
|
||||||
|
|
||||||
from src import paths
|
from src import paths
|
||||||
|
|
||||||
|
|
||||||
_ts: str = "" # session timestamp string e.g. "20260301_142233"
|
_ts: str = "" # session timestamp string e.g. "20260301_142233"
|
||||||
_session_id: str = "" # YYYYMMDD_HHMMSS[_Label]
|
_session_id: str = "" # YYYYMMDD_HHMMSS[_Label]
|
||||||
_session_dir: Optional[Path] = None # Path to the sub-directory for this session
|
_session_dir: Optional[Path] = None # Path to the sub-directory for this session
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from imgui_bundle import imgui
|
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:
|
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
@@ -7,10 +7,11 @@ configuring the environment via mcp_env.toml. It handles timeouts,
|
|||||||
logging, and optional QA/patch callbacks for error recovery.
|
logging, and optional QA/patch callbacks for error recovery.
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import subprocess
|
|
||||||
import shutil
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Callable, Optional
|
from typing import Callable, Optional
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import tomllib
|
import tomllib
|
||||||
@@ -20,6 +21,7 @@ except ImportError:
|
|||||||
TIMEOUT_SECONDS: int = 60
|
TIMEOUT_SECONDS: int = 60
|
||||||
_ENV_CONFIG: dict = {}
|
_ENV_CONFIG: dict = {}
|
||||||
|
|
||||||
|
|
||||||
def _load_env_config() -> dict:
|
def _load_env_config() -> dict:
|
||||||
"""Load mcp_env.toml from project root or environment variable."""
|
"""Load mcp_env.toml from project root or environment variable."""
|
||||||
env_path = os.environ.get("SLOP_MCP_ENV")
|
env_path = os.environ.get("SLOP_MCP_ENV")
|
||||||
|
|||||||
+5
-1
@@ -24,12 +24,16 @@ context block that replaces full file contents in the initial <context> send.
|
|||||||
"""
|
"""
|
||||||
import ast
|
import ast
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Callable, Any
|
from typing import Callable, Any
|
||||||
|
|
||||||
from src.summary_cache import SummaryCache, get_file_hash
|
from src.summary_cache import SummaryCache, get_file_hash
|
||||||
|
|
||||||
|
|
||||||
_summary_cache = SummaryCache()
|
_summary_cache = SummaryCache()
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------ per-type extractors
|
# ------------------------------------------------------------------ per-type extractors
|
||||||
|
|
||||||
def _summarise_python(path: Path, content: str) -> str:
|
def _summarise_python(path: Path, content: str) -> str:
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional, Dict
|
from typing import Optional, Dict
|
||||||
|
|
||||||
|
|
||||||
def get_file_hash(content: str) -> str:
|
def get_file_hash(content: str) -> str:
|
||||||
"""
|
"""
|
||||||
|
|||||||
+11
-7
@@ -8,16 +8,20 @@ Font loading uses hello_imgui.load_font().
|
|||||||
Scale uses imgui.get_style().font_scale_main.
|
Scale uses imgui.get_style().font_scale_main.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from imgui_bundle import imgui, hello_imgui
|
|
||||||
from typing import Any, Optional
|
|
||||||
import typing
|
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
|
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.theme_nerv_fx import CRTFilter, AlertPulsing, StatusFlicker
|
||||||
from src.paths import get_global_themes_path
|
from src.paths import get_global_themes_path
|
||||||
from src.theme_models import ThemeFile, load_themes_from_dir, load_themes_from_toml
|
from src.theme_models import ThemeFile, load_themes_from_dir, load_themes_from_toml
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------ palettes
|
# ------------------------------------------------------------------ palettes
|
||||||
|
|
||||||
|
|||||||
+4
-2
@@ -1,9 +1,11 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import tomllib
|
import tomllib
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
VALID_SYNTAX_PALETTES: tuple[str, ...] = ("dark", "light", "mariana", "retro_blue")
|
VALID_SYNTAX_PALETTES: tuple[str, ...] = ("dark", "light", "mariana", "retro_blue")
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from imgui_bundle import imgui
|
from imgui_bundle import imgui
|
||||||
|
|
||||||
|
|
||||||
def _c(r: int, g: int, b: int, a: int = 255) -> tuple[float, float, float, float]:
|
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."""
|
"""Convert 0-255 RGBA to 0.0-1.0 floats."""
|
||||||
return (r / 255.0, g / 255.0, b / 255.0, a / 255.0)
|
return (r / 255.0, g / 255.0, b / 255.0, a / 255.0)
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import time
|
|
||||||
import math
|
import math
|
||||||
import random
|
import random
|
||||||
|
import time
|
||||||
|
|
||||||
from imgui_bundle import imgui
|
from imgui_bundle import imgui
|
||||||
|
|
||||||
|
|
||||||
class CRTFilter:
|
class CRTFilter:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.enabled = True
|
self.enabled = True
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from typing import List, Tuple
|
from typing import List, Tuple
|
||||||
|
|
||||||
from src.models import ThinkingSegment
|
from src.models import ThinkingSegment
|
||||||
|
|
||||||
|
|
||||||
def parse_thinking_trace(text: str) -> Tuple[List[ThinkingSegment], str]:
|
def parse_thinking_trace(text: str) -> Tuple[List[ThinkingSegment], str]:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from typing import List, Dict, Any, Optional
|
from typing import List, Dict, Any, Optional
|
||||||
|
|
||||||
from src.models import Tool, ToolPreset, BiasProfile
|
from src.models import Tool, ToolPreset, BiasProfile
|
||||||
|
|
||||||
|
|
||||||
class ToolBiasEngine:
|
class ToolBiasEngine:
|
||||||
def apply_semantic_nudges(self, tool_definitions: List[Dict[str, Any]], preset: ToolPreset) -> List[Dict[str, Any]]:
|
def apply_semantic_nudges(self, tool_definitions: List[Dict[str, Any]], preset: ToolPreset) -> List[Dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
|
|||||||
+5
-2
@@ -1,10 +1,13 @@
|
|||||||
import tomllib
|
import tomllib
|
||||||
import tomli_w
|
import tomli_w
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, List, Optional, Union, Any
|
from typing import Dict, List, Optional, Union, Any
|
||||||
from src import paths
|
|
||||||
|
from src import paths
|
||||||
from src.models import ToolPreset, BiasProfile
|
from src.models import ToolPreset, BiasProfile
|
||||||
|
|
||||||
|
|
||||||
class ToolPresetManager:
|
class ToolPresetManager:
|
||||||
def __init__(self, project_root: Optional[Union[str, Path]] = None):
|
def __init__(self, project_root: Optional[Union[str, Path]] = None):
|
||||||
self.project_root = Path(project_root) if project_root else None
|
self.project_root = Path(project_root) if project_root else None
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class VendorMetric:
|
class VendorMetric:
|
||||||
"""Atomic vendor-state metric.
|
"""Atomic vendor-state metric.
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
import tomllib
|
import tomllib
|
||||||
import tomli_w
|
import tomli_w
|
||||||
|
|
||||||
from pathlib import Path
|
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.models import WorkspaceProfile
|
||||||
from src import paths
|
from src import paths
|
||||||
|
|
||||||
|
|
||||||
class WorkspaceManager:
|
class WorkspaceManager:
|
||||||
"""Manages Workspace profiles across global and project-specific files."""
|
"""Manages Workspace profiles across global and project-specific files."""
|
||||||
|
|||||||
Reference in New Issue
Block a user