codebase: cleaning cruft part 1
This commit is contained in:
@@ -65,7 +65,6 @@ class WorkerPool:
|
||||
"""
|
||||
Spawns a new worker thread if the pool is not full.
|
||||
Returns the thread object or None if full.
|
||||
[C: tests/test_parallel_execution.py:test_worker_pool_completion_cleanup, tests/test_parallel_execution.py:test_worker_pool_limit, tests/test_parallel_execution.py:test_worker_pool_tracking]
|
||||
"""
|
||||
with self._lock:
|
||||
if len(self._active) >= self.max_workers:
|
||||
@@ -86,9 +85,6 @@ class WorkerPool:
|
||||
return t
|
||||
|
||||
def join_all(self, timeout: float = None) -> None:
|
||||
"""
|
||||
[C: tests/test_parallel_execution.py:test_conductor_engine_pool_integration, tests/test_parallel_execution.py:test_worker_pool_limit, tests/test_parallel_execution.py:test_worker_pool_tracking]
|
||||
"""
|
||||
with self._lock:
|
||||
threads = list(self._active.values())
|
||||
for t in threads:
|
||||
@@ -97,22 +93,14 @@ class WorkerPool:
|
||||
self._active.clear()
|
||||
|
||||
def get_active_count(self) -> int:
|
||||
"""
|
||||
[C: tests/test_parallel_execution.py:test_conductor_engine_pool_integration, tests/test_parallel_execution.py:test_worker_pool_completion_cleanup, tests/test_parallel_execution.py:test_worker_pool_limit]
|
||||
"""
|
||||
with self._lock:
|
||||
return len(self._active)
|
||||
|
||||
def is_full(self) -> bool:
|
||||
"""
|
||||
[C: tests/test_parallel_execution.py:test_worker_pool_limit]
|
||||
"""
|
||||
return self.get_active_count() >= self.max_workers
|
||||
|
||||
class ConductorEngine:
|
||||
"""
|
||||
Orchestrates the execution of tickets within a track.
|
||||
"""
|
||||
"""Orchestrates the execution of tickets within a track."""
|
||||
|
||||
def __init__(self, track: Track, event_queue: Optional[events.AsyncEventQueue] = None, auto_queue: bool = False, max_workers: int = 4) -> None:
|
||||
self.track = track
|
||||
@@ -142,40 +130,25 @@ class ConductorEngine:
|
||||
self.tier_usage[tier]["output"] += output_tokens
|
||||
|
||||
def pause(self) -> None:
|
||||
"""
|
||||
Pauses the pipeline execution.
|
||||
[C: tests/test_pipeline_pause.py:test_pause_method, tests/test_pipeline_pause.py:test_resume_method]
|
||||
"""
|
||||
"""Pauses the pipeline execution."""
|
||||
self._pause_event.set()
|
||||
|
||||
def resume(self) -> None:
|
||||
"""
|
||||
Resumes the pipeline execution.
|
||||
[C: tests/test_pipeline_pause.py:test_resume_method]
|
||||
"""
|
||||
"""Resumes the pipeline execution."""
|
||||
self._pause_event.clear()
|
||||
|
||||
def approve_task(self, task_id: str) -> None:
|
||||
"""
|
||||
Manually transition todo to in_progress and mark engine dirty.
|
||||
[C: tests/test_execution_engine.py:test_execution_engine_approve_task, tests/test_execution_engine.py:test_execution_engine_step_mode]
|
||||
"""
|
||||
"""Manually transition todo to in_progress and mark engine dirty."""
|
||||
self.engine.approve_task(task_id)
|
||||
self._dirty = True
|
||||
|
||||
def update_task_status(self, task_id: str, status: str) -> None:
|
||||
"""
|
||||
Force-update ticket status and mark engine dirty.
|
||||
[C: tests/test_arch_boundary_phase3.py:TestArchBoundaryPhase3.test_manual_unblock_restores_todo, tests/test_execution_engine.py:test_execution_engine_auto_queue, tests/test_execution_engine.py:test_execution_engine_basic_flow, tests/test_execution_engine.py:test_execution_engine_status_persistence, tests/test_execution_engine.py:test_execution_engine_update_nonexistent_task]
|
||||
"""
|
||||
"""Force-update ticket status and mark engine dirty."""
|
||||
self.engine.update_task_status(task_id, status)
|
||||
self._dirty = True
|
||||
|
||||
def kill_worker(self, ticket_id: str) -> None:
|
||||
"""
|
||||
Sets the abort event for a worker and attempts to join its thread.
|
||||
[C: tests/test_conductor_engine_abort.py:test_kill_worker_sets_abort_and_joins_thread]
|
||||
"""
|
||||
"""Sets the abort event for a worker and attempts to join its thread."""
|
||||
if ticket_id in self._abort_events:
|
||||
print(f"[MMA] Setting abort event for {ticket_id}")
|
||||
self._abort_events[ticket_id].set()
|
||||
@@ -207,11 +180,8 @@ class ConductorEngine:
|
||||
|
||||
def parse_json_tickets(self, json_str: str) -> None:
|
||||
"""
|
||||
|
||||
|
||||
Parses a JSON string of ticket definitions (Godot ECS Flat List format)
|
||||
and populates the Track's ticket list.
|
||||
[C: tests/test_conductor_engine_v2.py:test_conductor_engine_dynamic_parsing_and_execution, tests/test_orchestration_logic.py:test_conductor_engine_parse_json_tickets]
|
||||
Parses a JSON string of ticket definitions (Godot ECS Flat List format)
|
||||
and populates the Track's ticket list.
|
||||
"""
|
||||
try:
|
||||
data = json.loads(json_str)
|
||||
@@ -239,13 +209,10 @@ class ConductorEngine:
|
||||
|
||||
def run(self, md_content: str = "", max_ticks: Optional[int] = None) -> None:
|
||||
"""
|
||||
|
||||
|
||||
Main execution loop using the DAG engine.
|
||||
Args:
|
||||
md_content: The full markdown context (history + files) for AI workers.
|
||||
max_ticks: Optional limit on number of iterations (for testing).
|
||||
[C: simulation/sim_base.py:run_sim, src/project_manager.py:get_git_commit, src/rag_engine.py:RAGEngine._search_mcp, src/shell_runner.py:run_powershell, tests/conftest.py:kill_process_tree, tests/conftest.py:live_gui, tests/test_conductor_abort_event.py:test_conductor_abort_event_populated, tests/test_conductor_engine_v2.py:test_conductor_engine_dynamic_parsing_and_execution, tests/test_conductor_engine_v2.py:test_conductor_engine_run_executes_tickets_in_order, tests/test_extended_sims.py:test_ai_settings_sim_live, tests/test_extended_sims.py:test_context_sim_live, tests/test_extended_sims.py:test_execution_sim_live, tests/test_extended_sims.py:test_tools_sim_live, tests/test_external_editor_gui.py:get_vscode_processes, tests/test_external_editor_gui.py:test_vscode_launches_with_diff_view, tests/test_gui_custom_window.py:test_app_window_is_borderless, tests/test_headless_simulation.py:module, tests/test_headless_verification.py:test_headless_verification_error_and_qa_interceptor, tests/test_headless_verification.py:test_headless_verification_full_run, tests/test_mock_gemini_cli.py:run_mock, tests/test_orchestration_logic.py:test_conductor_engine_run, tests/test_parallel_execution.py:test_conductor_engine_pool_integration, tests/test_sim_ai_settings.py:test_ai_settings_simulation_run, tests/test_sim_context.py:test_context_simulation_run, tests/test_sim_execution.py:test_execution_simulation_run, tests/test_sim_tools.py:test_tools_simulation_run]
|
||||
Main execution loop using the DAG engine.
|
||||
Args:
|
||||
md_content: The full markdown context (history + files) for AI workers.
|
||||
max_ticks: Optional limit on number of iterations (for testing).
|
||||
"""
|
||||
tick_count = 0
|
||||
while True:
|
||||
@@ -366,9 +333,7 @@ def _queue_put(event_queue: events.AsyncEventQueue, event_name: str, payload) ->
|
||||
|
||||
def confirm_execution(payload: str, event_queue: events.AsyncEventQueue, ticket_id: str) -> bool:
|
||||
"""
|
||||
|
||||
|
||||
Pushes an approval request to the GUI and waits for response.
|
||||
Pushes an approval request to the GUI and waits for response.
|
||||
"""
|
||||
dialog_container = [None]
|
||||
task = {
|
||||
@@ -390,11 +355,8 @@ def confirm_execution(payload: str, event_queue: events.AsyncEventQueue, ticket_
|
||||
|
||||
def confirm_spawn(role: str, prompt: str, context_md: str, event_queue: events.AsyncEventQueue, ticket_id: str) -> Tuple[bool, str, str]:
|
||||
"""
|
||||
|
||||
|
||||
Pushes a spawn approval request to the GUI and waits for response.
|
||||
Returns (approved, modified_prompt, modified_context)
|
||||
[C: tests/test_spawn_interception_v2.py:run_confirm]
|
||||
Pushes a spawn approval request to the GUI and waits for response.
|
||||
Returns (approved, modified_prompt, modified_context)
|
||||
"""
|
||||
dialog_container = [None]
|
||||
task = {
|
||||
@@ -432,18 +394,15 @@ def confirm_spawn(role: str, prompt: str, context_md: str, event_queue: events.A
|
||||
|
||||
def run_worker_lifecycle(ticket: Ticket, context: WorkerContext, context_files: List[str] | None = None, event_queue: events.AsyncEventQueue | None = None, engine: Optional['ConductorEngine'] = None, md_content: str = "") -> None:
|
||||
"""
|
||||
|
||||
|
||||
Simulates the lifecycle of a single agent working on a ticket.
|
||||
Calls the AI client and updates the ticket status based on the response.
|
||||
Args:
|
||||
ticket: The ticket to process.
|
||||
context: The worker context.
|
||||
context_files: List of files to include in the context.
|
||||
event_queue: Queue for pushing state updates and receiving approvals.
|
||||
engine: The conductor engine.
|
||||
md_content: The markdown context (history + files) for AI workers.
|
||||
[C: tests/test_conductor_engine_v2.py:test_run_worker_lifecycle_calls_ai_client_send, tests/test_conductor_engine_v2.py:test_run_worker_lifecycle_context_injection, tests/test_conductor_engine_v2.py:test_run_worker_lifecycle_handles_blocked_response, tests/test_conductor_engine_v2.py:test_run_worker_lifecycle_pushes_response_via_queue, tests/test_conductor_engine_v2.py:test_run_worker_lifecycle_step_mode_confirmation, tests/test_conductor_engine_v2.py:test_run_worker_lifecycle_step_mode_rejection, tests/test_conductor_engine_v2.py:test_run_worker_lifecycle_token_usage_from_comms_log, tests/test_context_pruner.py:test_token_reduction_logging, tests/test_orchestration_logic.py:test_run_worker_lifecycle_blocked, tests/test_phase6_engine.py:test_worker_streaming_intermediate, tests/test_run_worker_lifecycle_abort.py:TestRunWorkerLifecycleAbort.test_run_worker_lifecycle_returns_early_on_abort, tests/test_spawn_interception_v2.py:test_run_worker_lifecycle_approved, tests/test_spawn_interception_v2.py:test_run_worker_lifecycle_rejected, tests/test_tiered_aggregation.py:test_run_worker_lifecycle_uses_strategy]
|
||||
Simulates the lifecycle of a single agent working on a ticket.
|
||||
Calls the AI client and updates the ticket status based on the response.
|
||||
Args:
|
||||
ticket: The ticket to process.
|
||||
context: The worker context.
|
||||
context_files: List of files to include in the context.
|
||||
event_queue: Queue for pushing state updates and receiving approvals.
|
||||
engine: The conductor engine.
|
||||
md_content: The markdown context (history + files) for AI workers.
|
||||
"""
|
||||
# Enforce Context Amnesia: each ticket starts with a clean slate.
|
||||
ai_client.reset_session()
|
||||
@@ -660,4 +619,4 @@ def run_worker_lifecycle(ticket: Ticket, context: WorkerContext, context_files:
|
||||
|
||||
if event_queue:
|
||||
_queue_put(event_queue, "ticket_completed", {"ticket_id": ticket.id, "timestamp": time.time()})
|
||||
return response
|
||||
return response
|
||||
|
||||
@@ -14,10 +14,7 @@ from src.type_aliases import Metadata
|
||||
|
||||
|
||||
def get_track_history_summary() -> Result[str]:
|
||||
"""
|
||||
Scans conductor/archive/ and conductor/tracks/ to build a summary of past work.
|
||||
[C: tests/test_orchestrator_pm_history.py:TestOrchestratorPMHistory.test_get_track_history_summary, tests/test_orchestrator_pm_history.py:TestOrchestratorPMHistory.test_get_track_history_summary_missing_files]
|
||||
"""
|
||||
"""Scans conductor/archive/ and conductor/tracks/ to build a summary of past work."""
|
||||
summary_parts = []
|
||||
scan_errors: list[ErrorInfo] = []
|
||||
archive_path = paths.get_archive_dir()
|
||||
@@ -61,7 +58,6 @@ def generate_tracks(user_request: str, project_config: Metadata, file_items: lis
|
||||
"""
|
||||
Tier 1 (Strategic PM) call.
|
||||
Analyzes the project state and user request to generate a list of Tracks.
|
||||
[C: tests/test_orchestration_logic.py:test_generate_tracks, tests/test_orchestrator_pm.py:TestOrchestratorPM.test_generate_tracks_malformed_json, tests/test_orchestrator_pm.py:TestOrchestratorPM.test_generate_tracks_markdown_wrapped, tests/test_orchestrator_pm.py:TestOrchestratorPM.test_generate_tracks_success, tests/test_orchestrator_pm_history.py:TestOrchestratorPMHistory.test_generate_tracks_with_history]
|
||||
"""
|
||||
# 1. Build Repository Map (Summary View)
|
||||
repo_map = summarize.build_summary_markdown(file_items)
|
||||
|
||||
@@ -42,9 +42,6 @@ class CodeOutliner:
|
||||
pass
|
||||
|
||||
def outline(self, code: str) -> Result[str]:
|
||||
"""
|
||||
[C: tests/test_outline_tool.py:test_code_outliner_imgui_scopes, tests/test_outline_tool.py:test_code_outliner_nested_ifs, tests/test_outline_tool.py:test_code_outliner_type_hints]
|
||||
"""
|
||||
code = code.lstrip(chr(0xFEFF))
|
||||
try:
|
||||
tree = ast.parse(code)
|
||||
@@ -62,15 +59,9 @@ class CodeOutliner:
|
||||
|
||||
count = [0]
|
||||
def walk(node: ast.AST, indent: int = 0) -> None:
|
||||
"""
|
||||
[C: src/summarize.py:_summarise_python]
|
||||
"""
|
||||
count[0] += 1
|
||||
if count[0] > 100000:
|
||||
raise Exception("Infinite loop detected! " + str(type(node)))
|
||||
"""
|
||||
[C: src/summarize.py:_summarise_python]
|
||||
"""
|
||||
if isinstance(node, ast.ClassDef):
|
||||
start_line = node.lineno
|
||||
end_line = getattr(node, "end_lineno", start_line)
|
||||
|
||||
+1
-34
@@ -34,9 +34,6 @@ class PatchModalManager:
|
||||
self._on_reject_callback: Optional[Callable[[], None]] = None
|
||||
|
||||
def request_patch_approval(self, patch_text: str, file_paths: List[str], generated_by: str = "Tier 4 QA") -> bool:
|
||||
"""
|
||||
[C: tests/test_patch_modal.py:test_close_modal, tests/test_patch_modal.py:test_reject_patch, tests/test_patch_modal.py:test_request_patch_approval, tests/test_patch_modal.py:test_reset]
|
||||
"""
|
||||
from time import time
|
||||
self._pending_patch = PendingPatch(
|
||||
patch_text=patch_text,
|
||||
@@ -48,56 +45,32 @@ class PatchModalManager:
|
||||
return True
|
||||
|
||||
def get_pending_patch(self) -> "PendingPatch":
|
||||
"""
|
||||
[C: tests/test_patch_modal.py:test_patch_modal_manager_init, tests/test_patch_modal.py:test_reject_patch, tests/test_patch_modal.py:test_request_patch_approval, tests/test_patch_modal.py:test_reset]
|
||||
"""
|
||||
return self._pending_patch
|
||||
|
||||
def is_modal_shown(self) -> bool:
|
||||
"""
|
||||
[C: tests/test_patch_modal.py:test_close_modal, tests/test_patch_modal.py:test_patch_modal_manager_init, tests/test_patch_modal.py:test_reject_patch, tests/test_patch_modal.py:test_request_patch_approval, tests/test_patch_modal.py:test_reset]
|
||||
"""
|
||||
return self._show_modal
|
||||
|
||||
def set_apply_callback(self, callback: Callable[[str], bool]) -> None:
|
||||
"""
|
||||
[C: tests/test_patch_modal.py:test_apply_callback, tests/test_patch_modal.py:test_reset]
|
||||
"""
|
||||
self._on_apply_callback = callback
|
||||
|
||||
def set_reject_callback(self, callback: Callable[[], None]) -> None:
|
||||
"""
|
||||
[C: tests/test_patch_modal.py:test_reject_callback, tests/test_patch_modal.py:test_reset]
|
||||
"""
|
||||
self._on_reject_callback = callback
|
||||
|
||||
def apply_patch(self, patch_text: str) -> bool:
|
||||
"""
|
||||
[C: tests/test_patch_modal.py:test_apply_callback]
|
||||
"""
|
||||
if self._on_apply_callback:
|
||||
return self._on_apply_callback(patch_text)
|
||||
return False
|
||||
|
||||
def reject_patch(self) -> None:
|
||||
"""
|
||||
[C: tests/test_patch_modal.py:test_reject_callback, tests/test_patch_modal.py:test_reject_patch]
|
||||
"""
|
||||
self._pending_patch = EMPTY_PATCH
|
||||
self._show_modal = False
|
||||
if self._on_reject_callback:
|
||||
self._on_reject_callback()
|
||||
|
||||
def close_modal(self) -> None:
|
||||
"""
|
||||
[C: tests/test_patch_modal.py:test_close_modal]
|
||||
"""
|
||||
self._show_modal = False
|
||||
|
||||
def reset(self) -> None:
|
||||
"""
|
||||
[C: tests/test_patch_modal.py:test_reset]
|
||||
"""
|
||||
self._pending_patch = EMPTY_PATCH
|
||||
self._show_modal = False
|
||||
self._on_apply_callback = None
|
||||
@@ -106,19 +79,13 @@ class PatchModalManager:
|
||||
_patch_modal_manager: Optional[PatchModalManager] = None
|
||||
|
||||
def get_patch_modal_manager() -> PatchModalManager:
|
||||
"""
|
||||
[C: tests/test_patch_modal.py:test_get_patch_modal_manager_singleton]
|
||||
"""
|
||||
global _patch_modal_manager
|
||||
if _patch_modal_manager is None:
|
||||
_patch_modal_manager = PatchModalManager()
|
||||
return _patch_modal_manager
|
||||
|
||||
def reset_patch_modal_manager() -> None:
|
||||
"""
|
||||
[C: tests/test_patch_modal.py:test_get_patch_modal_manager_singleton]
|
||||
"""
|
||||
global _patch_modal_manager
|
||||
if _patch_modal_manager:
|
||||
_patch_modal_manager.reset()
|
||||
_patch_modal_manager = None
|
||||
_patch_modal_manager = None
|
||||
|
||||
+17
-47
@@ -51,8 +51,7 @@ from typing import Optional, Any
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class PathsConfig:
|
||||
"""Immutable snapshot of resolved paths. Created ONCE per process.
|
||||
[C: src/paths.py:initialize_paths, src/paths.py:_cfg]"""
|
||||
"""Immutable snapshot of resolved paths. Created ONCE per process."""
|
||||
config_path: Path
|
||||
presets: Path
|
||||
tool_presets: Path
|
||||
@@ -72,8 +71,7 @@ _PATHS_LOCK = threading.RLock()
|
||||
def _default_paths_config() -> PathsConfig:
|
||||
"""Build the default PathsConfig (no [paths] overrides, just defaults).
|
||||
Called once at module load to ensure _PATHS_CONFIG is never None for
|
||||
callers that don't explicitly initialize (e.g., subprocess imports).
|
||||
[C: src/paths.py:initialize_paths, src/paths.py:_module_init_default]"""
|
||||
callers that don't explicitly initialize (e.g., subprocess imports)."""
|
||||
root_dir = Path(__file__).resolve().parent.parent
|
||||
config_path = root_dir / "config.toml"
|
||||
cfg = PathsConfig(
|
||||
@@ -93,8 +91,7 @@ def _default_paths_config() -> PathsConfig:
|
||||
|
||||
def _module_init_default() -> None:
|
||||
"""Initialize _PATHS_CONFIG with defaults at module load.
|
||||
Idempotent. Subsequent calls to initialize_paths(<custom>) override this.
|
||||
[C: src/paths.py:initialize_paths, src/paths.py:reset_paths]"""
|
||||
Idempotent. Subsequent calls to initialize_paths(<custom>) override this."""
|
||||
global _PATHS_CONFIG
|
||||
if _PATHS_CONFIG is None:
|
||||
_PATHS_CONFIG = _default_paths_config()
|
||||
@@ -135,8 +132,7 @@ def initialize_paths(config_path: Optional[Path] = None) -> PathsConfig:
|
||||
TypeError: if config_path is not a Path
|
||||
|
||||
Returns:
|
||||
The newly installed PathsConfig snapshot.
|
||||
[C: src/paths.py:_cfg, tests/conftest.py:_setup_test_paths, sloppy.py:main]"""
|
||||
The newly installed PathsConfig snapshot."""
|
||||
global _PATHS_CONFIG
|
||||
if config_path is None:
|
||||
root_dir = Path(__file__).resolve().parent.parent
|
||||
@@ -174,89 +170,68 @@ def _cfg() -> PathsConfig:
|
||||
# === Trivial getters (single source of truth) ===
|
||||
|
||||
def get_config_path() -> Path:
|
||||
"""Active config.toml path. Frozen at initialize_paths() time.
|
||||
[C: src/app_controller.py:AppController.load_config,
|
||||
src/app_controller.py:AppController.init_state,
|
||||
src/models.py:_load_config_from_disk,
|
||||
tests/test_test_sandbox.py]"""
|
||||
"""Active config.toml path. Frozen at initialize_paths() time."""
|
||||
return _cfg().config_path
|
||||
|
||||
def get_global_presets_path() -> Path:
|
||||
"""Global presets file. Frozen at initialize_paths() time.
|
||||
[C: src/presets.py:PresetManager.__init__, src/presets.py:PresetManager.delete_preset, src/presets.py:PresetManager.get_preset_scope]"""
|
||||
"""Global presets file. Frozen at initialize_paths() time."""
|
||||
return _cfg().presets
|
||||
|
||||
def get_project_presets_path(project_root: Path) -> Path:
|
||||
"""Project-specific presets file. Computed from project_root (no cache).
|
||||
[C: src/presets.py:PresetManager.delete_preset, src/presets.py:PresetManager.get_preset_scope, src/presets.py:PresetManager.project_path]"""
|
||||
"""Project-specific presets file. Computed from project_root (no cache)."""
|
||||
return project_root / "project_presets.toml"
|
||||
|
||||
def get_global_tool_presets_path() -> Path:
|
||||
"""Global tool presets file. Frozen at initialize_paths() time.
|
||||
[C: src/tool_presets.py:ToolPresetManager._get_path, src/tool_presets.py:ToolPresetManager.load_all_bias_profiles, src/tool_presets.py:ToolPresetManager.load_all_presets]"""
|
||||
"""Global tool presets file. Frozen at initialize_paths() time."""
|
||||
return _cfg().tool_presets
|
||||
|
||||
def get_project_tool_presets_path(project_root: Path) -> Path:
|
||||
"""[C: src/tool_presets.py:ToolPresetManager._get_path, src/tool_presets.py:ToolPresetManager.load_all_bias_profiles, src/tool_presets.py:ToolPresetManager.load_all_presets]"""
|
||||
return project_root / "project_tool_presets.toml"
|
||||
|
||||
def get_global_personas_path() -> Path:
|
||||
"""Global personas file. Frozen at initialize_paths() time.
|
||||
[C: src/personas.py:PersonaManager._get_path, src/personas.py:PersonaManager.get_persona_scope, src/personas.py:PersonaManager.load_all]"""
|
||||
"""Global personas file. Frozen at initialize_paths() time."""
|
||||
return _cfg().personas
|
||||
|
||||
def get_project_personas_path(project_root: Path) -> Path:
|
||||
"""[C: src/personas.py:PersonaManager._get_path, src/personas.py:PersonaManager.get_persona_scope, src/personas.py:PersonaManager.load_all]"""
|
||||
return project_root / "project_personas.toml"
|
||||
|
||||
def get_global_themes_path() -> Path:
|
||||
"""Global themes directory. Frozen at initialize_paths() time.
|
||||
[C: src/theme_2.py:load_themes_from_disk]"""
|
||||
"""Global themes directory. Frozen at initialize_paths() time."""
|
||||
return _cfg().themes
|
||||
|
||||
def get_layouts_dir() -> Path:
|
||||
"""Global layouts directory. Frozen at initialize_paths() time.
|
||||
[C: src/layouts.py:load_layouts_from_disk]"""
|
||||
"""Global layouts directory. Frozen at initialize_paths() time."""
|
||||
return _cfg().layouts
|
||||
|
||||
def get_project_themes_path(project_root: Path) -> Path:
|
||||
"""[C: src/theme_2.py:load_themes_from_disk]"""
|
||||
return project_root / "project_themes.toml"
|
||||
|
||||
def get_global_workspace_profiles_path() -> Path:
|
||||
"""Global workspace profiles file. Frozen at initialize_paths() time.
|
||||
[C: src/workspace_manager.py:WorkspaceManager._get_path, src/workspace_manager.py:WorkspaceManager.load_all_profiles]"""
|
||||
"""Global workspace profiles file. Frozen at initialize_paths() time."""
|
||||
return _cfg().workspace_profiles
|
||||
|
||||
def get_project_workspace_profiles_path(project_root: Path) -> Path:
|
||||
"""[C: src/workspace_manager.py:WorkspaceManager._get_path, src/workspace_manager.py:WorkspaceManager.load_all_profiles]"""
|
||||
return project_root / ".ai" / "workspace_profiles.toml"
|
||||
|
||||
def get_credentials_path() -> Path:
|
||||
"""Global credentials file. Frozen at initialize_paths() time.
|
||||
[C: src/mcp_client.py:_is_allowed]"""
|
||||
"""Global credentials file. Frozen at initialize_paths() time."""
|
||||
return _cfg().credentials
|
||||
|
||||
def get_logs_dir() -> Path:
|
||||
"""Logs directory (contains session subdirs). Frozen at initialize_paths() time.
|
||||
[C: src/session_logger.py:close_session, src/session_logger.py:open_session, tests/test_paths.py:test_config_overrides, tests/test_paths.py:test_default_paths, tests/test_paths.py:test_env_var_overrides, tests/test_paths.py:test_precedence]"""
|
||||
"""Logs directory (contains session subdirs). Frozen at initialize_paths() time."""
|
||||
return _cfg().logs_dir
|
||||
|
||||
def get_scripts_dir() -> Path:
|
||||
"""Generated scripts directory. Frozen at initialize_paths() time.
|
||||
[C: src/session_logger.py:log_tool_call, src/session_logger.py:open_session, tests/test_paths.py:test_config_overrides, tests/test_paths.py:test_default_paths]"""
|
||||
"""Generated scripts directory. Frozen at initialize_paths() time."""
|
||||
return _cfg().scripts_dir
|
||||
|
||||
def get_tracks_dir(project_path: Optional[str] = None) -> Path:
|
||||
"""[C: src/project_manager.py:get_all_tracks, tests/test_paths.py:test_conductor_dir_project_relative]"""
|
||||
return get_conductor_dir(project_path) / "tracks"
|
||||
|
||||
def get_track_state_dir(track_id: str, project_path: Optional[str] = None) -> Path:
|
||||
"""[C: src/project_manager.py:load_track_state, src/project_manager.py:save_track_state, tests/test_paths.py:test_conductor_dir_project_relative]"""
|
||||
return get_tracks_dir(project_path) / track_id
|
||||
|
||||
def get_archive_dir(project_path: Optional[str] = None) -> Path:
|
||||
"""[C: tests/test_paths.py:test_conductor_dir_project_relative]"""
|
||||
return get_conductor_dir(project_path) / "archive"
|
||||
|
||||
|
||||
@@ -278,7 +253,6 @@ def _get_project_conductor_dir_from_toml(project_root: Path) -> Path:
|
||||
|
||||
|
||||
def get_conductor_dir(project_path: Optional[str] = None) -> Path:
|
||||
"""[C: tests/test_paths.py:test_conductor_dir_project_relative, tests/test_project_paths.py:test_get_conductor_dir_default, tests/test_project_paths.py:test_get_conductor_dir_project_specific_with_toml]"""
|
||||
if not project_path:
|
||||
return Path('conductor').resolve()
|
||||
project_root = Path(project_path).resolve()
|
||||
@@ -290,8 +264,7 @@ def get_conductor_dir(project_path: Optional[str] = None) -> Path:
|
||||
|
||||
def get_full_path_info() -> dict[str, dict[str, Any]]:
|
||||
"""Return the resolved paths + their source (env / config / default).
|
||||
For diagnostic UIs (e.g., the Session Hub's "show resolved paths" panel).
|
||||
[C: src/gui_2.py:App._render_path_field]"""
|
||||
For diagnostic UIs (e.g., the Session Hub's "show resolved paths" panel)."""
|
||||
cfg = _cfg()
|
||||
def info(value: Path) -> dict[str, Any]:
|
||||
return {'path': str(value), 'source': 'frozen_at_init'}
|
||||
@@ -311,10 +284,7 @@ def get_full_path_info() -> dict[str, dict[str, Any]]:
|
||||
def reset_paths() -> None:
|
||||
"""Clear the singleton. FOR TESTS ONLY — production code should never
|
||||
call this. After reset, the next path getter raises RuntimeError until
|
||||
initialize_paths() is called again.
|
||||
[C: tests/conftest.py:reset_paths, tests/test_paths.py:reset_paths,
|
||||
tests/test_app_controller_offloading.py:setup_function,
|
||||
tests/test_gui_phase3.py:setup]"""
|
||||
initialize_paths() is called again."""
|
||||
global _PATHS_CONFIG
|
||||
with _PATHS_LOCK:
|
||||
_PATHS_CONFIG = None
|
||||
@@ -79,9 +79,6 @@ class PerformanceScope:
|
||||
|
||||
|
||||
def get_monitor() -> PerformanceMonitor:
|
||||
"""
|
||||
[C: tests/test_perf_aggregate.py:test_build_tier3_context_scaling, tests/test_perf_dag.py:test_dag_performance]
|
||||
"""
|
||||
global _instance
|
||||
if _instance is None:
|
||||
_instance = PerformanceMonitor()
|
||||
@@ -160,9 +157,6 @@ class PerformanceMonitor:
|
||||
return self._history_sums[key] / len(h)
|
||||
|
||||
def start_frame(self) -> None:
|
||||
"""
|
||||
[C: tests/test_performance_monitor.py:test_perf_monitor_basic_timing]
|
||||
"""
|
||||
now = time.perf_counter()
|
||||
with self._lock:
|
||||
if self._last_frame_start_time > 0:
|
||||
@@ -174,9 +168,6 @@ class PerformanceMonitor:
|
||||
self._frame_count += 1
|
||||
|
||||
def end_frame(self) -> None:
|
||||
"""
|
||||
[C: tests/test_performance_monitor.py:test_perf_monitor_basic_timing]
|
||||
"""
|
||||
if self._start_time is None:
|
||||
return
|
||||
now = time.perf_counter()
|
||||
@@ -205,18 +196,12 @@ class PerformanceMonitor:
|
||||
self._fps_timer = 0.0
|
||||
|
||||
def start_component(self, name: str) -> None:
|
||||
"""
|
||||
[C: tests/test_performance_monitor.py:test_perf_monitor_component_timing, tests/test_performance_monitor.py:test_perf_monitor_extended_metrics]
|
||||
"""
|
||||
if not self.enabled: return
|
||||
now = time.perf_counter()
|
||||
with self._lock:
|
||||
self._component_starts[name] = now
|
||||
|
||||
def end_component(self, name: str) -> None:
|
||||
"""
|
||||
[C: tests/test_performance_monitor.py:test_perf_monitor_component_timing, tests/test_performance_monitor.py:test_perf_monitor_extended_metrics]
|
||||
"""
|
||||
if not self.enabled: return
|
||||
now = time.perf_counter()
|
||||
with self._lock:
|
||||
@@ -231,10 +216,7 @@ class PerformanceMonitor:
|
||||
self._add_to_history(f'comp_{name}', elapsed)
|
||||
|
||||
def get_metrics(self) -> dict[str, float]:
|
||||
"""
|
||||
Returns current metrics and their moving averages. Thread-safe.
|
||||
[C: tests/test_perf_aggregate.py:test_build_tier3_context_scaling, tests/test_perf_dag.py:test_dag_performance, tests/test_performance_monitor.py:test_perf_monitor_basic_timing, tests/test_performance_monitor.py:test_perf_monitor_component_timing, tests/test_performance_monitor.py:test_perf_monitor_extended_metrics, tests/test_performance_monitor.py:test_perf_monitor_scope_context_manager]
|
||||
"""
|
||||
"""Returns current metrics and their moving averages. Thread-safe."""
|
||||
with self._lock:
|
||||
fps = self._fps
|
||||
last_ft = self._last_frame_time
|
||||
@@ -267,10 +249,7 @@ class PerformanceMonitor:
|
||||
return metrics
|
||||
|
||||
def get_history(self, key: str) -> List[float]:
|
||||
"""
|
||||
Returns a snapshot of the full history buffer for a specific metric key.
|
||||
[C: tests/test_history.py:test_initial_state, tests/test_history.py:test_push_state, tests/test_history_manager.py:TestHistoryManager.test_get_history_returns_descriptions]
|
||||
"""
|
||||
"""Returns a snapshot of the full history buffer for a specific metric key."""
|
||||
with self._lock:
|
||||
if key in self._history:
|
||||
return list(self._history[key])
|
||||
@@ -279,16 +258,11 @@ class PerformanceMonitor:
|
||||
return []
|
||||
|
||||
def scope(self, name: str) -> PerformanceScope:
|
||||
"""
|
||||
Returns a context manager for timing a component.
|
||||
[C: tests/test_perf_aggregate.py:test_build_tier3_context_scaling, tests/test_performance_monitor.py:test_perf_monitor_scope_context_manager]
|
||||
"""
|
||||
"""Returns a context manager for timing a component."""
|
||||
return PerformanceScope(self, name)
|
||||
|
||||
def stop(self) -> None:
|
||||
"""
|
||||
[C: tests/test_performance_monitor.py:test_perf_monitor_basic_timing, tests/test_performance_monitor.py:test_perf_monitor_component_timing, tests/test_performance_monitor.py:test_perf_monitor_extended_metrics, tests/test_performance_monitor.py:test_perf_monitor_scope_context_manager, tests/test_websocket_server.py:test_websocket_subscription_and_broadcast]
|
||||
"""
|
||||
self._stop_event.set()
|
||||
if self._cpu_thread.is_alive():
|
||||
self._cpu_thread.join(timeout=2.0)
|
||||
self._cpu_thread.join(timeout=2.0)
|
||||
|
||||
+2
-17
@@ -22,10 +22,7 @@ class PresetManager:
|
||||
return get_project_presets_path(self.project_root) if self.project_root else Path("")
|
||||
|
||||
def load_all(self) -> Dict[str, Preset]:
|
||||
"""
|
||||
Merges global and project presets into a single dictionary.
|
||||
[C: tests/test_persona_manager.py:test_delete_persona, tests/test_persona_manager.py:test_load_all_merged, tests/test_persona_manager.py:test_save_persona, tests/test_preset_manager.py:test_delete_preset, tests/test_preset_manager.py:test_load_all_merged, tests/test_preset_manager.py:test_save_preset_global, tests/test_preset_manager.py:test_save_preset_project, tests/test_presets.py:TestPresetManager.test_delete_preset, tests/test_presets.py:TestPresetManager.test_project_overwrites_global, tests/test_presets.py:TestPresetManager.test_save_and_load_global, tests/test_presets.py:TestPresetManager.test_save_and_load_project]
|
||||
"""
|
||||
"""Merges global and project presets into a single dictionary."""
|
||||
presets: Dict[str, Preset] = {}
|
||||
|
||||
# Load global presets
|
||||
@@ -52,10 +49,7 @@ class PresetManager:
|
||||
def save_preset(self, preset: Preset, scope: str = "project") -> None:
|
||||
if scope == "project" and self.project_root is None:
|
||||
raise ValueError("Project scope requested but no project_root provided")
|
||||
"""
|
||||
Saves a preset to either the global or project-specific TOML file.
|
||||
[C: tests/test_preset_manager.py:test_save_preset_global, tests/test_preset_manager.py:test_save_preset_project, tests/test_preset_manager.py:test_save_preset_project_no_root, tests/test_presets.py:TestPresetManager.test_delete_preset, tests/test_presets.py:TestPresetManager.test_project_overwrites_global, tests/test_presets.py:TestPresetManager.test_save_and_load_global, tests/test_presets.py:TestPresetManager.test_save_and_load_project]
|
||||
"""
|
||||
"""Saves a preset to either the global or project-specific TOML file."""
|
||||
path = self.global_path if scope == "global" else self.project_path
|
||||
if not path:
|
||||
if scope == "project":
|
||||
@@ -70,9 +64,6 @@ class PresetManager:
|
||||
self._save_file(path, data)
|
||||
|
||||
def delete_preset(self, name: str, scope: str) -> None:
|
||||
"""
|
||||
[C: tests/test_preset_manager.py:test_delete_preset, tests/test_presets.py:TestPresetManager.test_delete_preset]
|
||||
"""
|
||||
if scope == "project" and self.project_root:
|
||||
path = get_project_presets_path(self.project_root)
|
||||
else:
|
||||
@@ -99,9 +90,6 @@ class PresetManager:
|
||||
return "project"
|
||||
|
||||
def _load_file(self, path: Path) -> Dict[str, Any]:
|
||||
"""
|
||||
[C: src/workspace_manager.py:WorkspaceManager.delete_profile, src/workspace_manager.py:WorkspaceManager.load_all_profiles, src/workspace_manager.py:WorkspaceManager.save_profile]
|
||||
"""
|
||||
if not path.exists():
|
||||
return {"presets": {}}
|
||||
try:
|
||||
@@ -117,9 +105,6 @@ class PresetManager:
|
||||
return {"presets": {}}
|
||||
|
||||
def _save_file(self, path: Path, data: Dict[str, Any]) -> None:
|
||||
"""
|
||||
[C: src/workspace_manager.py:WorkspaceManager.delete_profile, src/workspace_manager.py:WorkspaceManager.save_profile]
|
||||
"""
|
||||
if path.parent.exists() and path.parent.is_file():
|
||||
raise ValueError(f"Cannot save to {path}: Parent directory {path.parent} is a file.")
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
@@ -122,7 +122,6 @@ def load_config_from_disk() -> Metadata:
|
||||
disk I/O primitive that the controller owns. Direct callers in
|
||||
src/ are an architectural smell (bypassing the state owner) and
|
||||
will be flagged by scripts/audit_no_models_config_io.py.
|
||||
[C: src/app_controller.py:AppController.load_config, src/app_controller.py:AppController.__init__]
|
||||
"""
|
||||
with open(get_config_path(), "rb") as f:
|
||||
return tomllib.load(f)
|
||||
|
||||
@@ -49,9 +49,6 @@ class FileItem:
|
||||
self.custom_slices = normalized
|
||||
|
||||
def to_dict(self) -> Metadata:
|
||||
"""
|
||||
[C: src/personas.py:PersonaManager.save_persona, src/presets.py:PresetManager.save_preset, src/project_manager.py:save_project, src/project_manager.py:save_track_state, src/tool_presets.py:ToolPresetManager.save_bias_profile, src/tool_presets.py:ToolPresetManager.save_preset, src/workspace_manager.py:WorkspaceManager.save_profile, tests/test_bias_models.py:test_bias_profile_model, tests/test_bias_models.py:test_tool_model, tests/test_bias_models.py:test_tool_preset_extension, tests/test_context_presets_models.py:test_context_preset_serialization, tests/test_context_presets_models.py:test_file_view_preset_serialization, tests/test_custom_slices_annotations.py:test_file_item_custom_slices_round_trip_annotations, tests/test_custom_slices_annotations.py:test_file_item_custom_slices_serialization_with_annotations, tests/test_event_serialization.py:test_user_request_event_serialization, tests/test_external_editor.py:TestExternalEditorConfig.test_to_dict, tests/test_external_editor.py:TestTextEditorConfig.test_to_dict, tests/test_file_item_model.py:test_file_item_to_dict, tests/test_gui_events_v2.py:test_user_request_event_payload, tests/test_history_manager.py:TestHistoryManager.test_snapshot_roundtrip, tests/test_mcp_config.py:test_mcp_configuration_to_from_dict, tests/test_mcp_config.py:test_mcp_server_config_to_from_dict, tests/test_per_ticket_model.py:test_model_override_serialization, tests/test_persona_id.py:test_ticket_persona_id_serialization, tests/test_persona_models.py:test_persona_defaults, tests/test_persona_models.py:test_persona_serialization, tests/test_slice_editor_behavior.py:test_add_slice_with_annotations, tests/test_thinking_gui.py:test_thinking_segment_model_compatibility, tests/test_ticket_queue.py:test_ticket_to_dict_priority, tests/test_tiered_aggregation.py:test_persona_aggregation_strategy, tests/test_track_state_schema.py:test_track_state_to_dict, tests/test_track_state_schema.py:test_track_state_to_dict_with_none, tests/test_ui_summary_only_removal.py:test_file_item_serialization_with_flags]
|
||||
"""
|
||||
return {
|
||||
"path": self.path,
|
||||
"auto_aggregate": self.auto_aggregate,
|
||||
@@ -66,9 +63,6 @@ class FileItem:
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: Metadata) -> "FileItem":
|
||||
"""
|
||||
[C: src/personas.py:PersonaManager.load_all, src/presets.py:PresetManager.load_all, src/project_manager.py:load_project, src/project_manager.py:load_track_state, src/tool_presets.py:ToolPresetManager.load_all_bias_profiles, src/tool_presets.py:ToolPresetManager.load_all_presets, src/workspace_manager.py:WorkspaceManager.load_all_profiles, tests/test_bias_models.py:test_bias_profile_model, tests/test_bias_models.py:test_tool_model, tests/test_bias_models.py:test_tool_preset_extension, tests/test_context_presets_models.py:test_context_preset_from_dict_legacy, tests/test_context_presets_models.py:test_context_preset_serialization, tests/test_context_presets_models.py:test_file_view_preset_serialization, tests/test_custom_slices_annotations.py:test_file_item_custom_slices_deserialization_with_annotations, tests/test_custom_slices_annotations.py:test_file_item_custom_slices_round_trip_annotations, tests/test_external_editor.py:TestExternalEditorConfig.test_from_dict_with_dict_editors, tests/test_external_editor.py:TestExternalEditorConfig.test_from_dict_with_string_editors, tests/test_external_editor.py:TestTextEditorConfig.test_from_dict_with_diff_args, tests/test_external_editor.py:TestTextEditorConfig.test_from_dict_without_diff_args, tests/test_file_item_model.py:test_file_item_from_dict, tests/test_file_item_model.py:test_file_item_from_dict_defaults, tests/test_history_manager.py:TestHistoryManager.test_snapshot_roundtrip, tests/test_mcp_config.py:test_mcp_configuration_to_from_dict, tests/test_mcp_config.py:test_mcp_server_config_to_from_dict, tests/test_per_ticket_model.py:test_model_override_default_on_deserialize, tests/test_per_ticket_model.py:test_model_override_deserialization, tests/test_persona_id.py:test_ticket_persona_id_deserialization, tests/test_persona_models.py:test_persona_defaults, tests/test_persona_models.py:test_persona_deserialization, tests/test_project_serialization.py:TestProjectSerialization.test_backward_compatibility_strings, tests/test_slice_editor_behavior.py:test_add_slice_with_annotations, tests/test_ticket_queue.py:test_ticket_from_dict_default_priority, tests/test_ticket_queue.py:test_ticket_from_dict_priority, tests/test_tiered_aggregation.py:test_persona_aggregation_strategy, tests/test_track_state_schema.py:test_track_state_from_dict, tests/test_track_state_schema.py:test_track_state_from_dict_empty_and_missing, tests/test_ui_summary_only_removal.py:test_file_item_serialization_with_flags]
|
||||
"""
|
||||
return cls(
|
||||
path = data["path"],
|
||||
auto_aggregate = data.get("auto_aggregate", True),
|
||||
@@ -88,16 +82,10 @@ class Preset:
|
||||
system_prompt: str
|
||||
|
||||
def to_dict(self) -> Metadata:
|
||||
"""
|
||||
[C: src/personas.py:PersonaManager.save_persona, src/presets.py:PresetManager.save_preset, src/project_manager.py:save_project, src/project_manager.py:save_track_state, src/tool_presets.py:ToolPresetManager.save_bias_profile, src/tool_presets.py:ToolPresetManager.save_preset, src/workspace_manager.py:WorkspaceManager.save_profile, tests/test_bias_models.py:test_bias_profile_model, tests/test_bias_models.py:test_tool_model, tests/test_bias_models.py:test_tool_preset_extension, tests/test_context_presets_models.py:test_context_preset_serialization, tests/test_context_presets_models.py:test_file_view_preset_serialization, tests/test_custom_slices_annotations.py:test_file_item_custom_slices_round_trip_annotations, tests/test_custom_slices_annotations.py:test_file_item_custom_slices_serialization_with_annotations, tests/test_event_serialization.py:test_user_request_event_serialization, tests/test_external_editor.py:TestExternalEditorConfig.test_to_dict, tests/test_external_editor.py:TestTextEditorConfig.test_to_dict, tests/test_file_item_model.py:test_file_item_to_dict, tests/test_gui_events_v2.py:test_user_request_event_payload, tests/test_history_manager.py:TestHistoryManager.test_snapshot_roundtrip, tests/test_mcp_config.py:test_mcp_configuration_to_from_dict, tests/test_mcp_config.py:test_mcp_server_config_to_from_dict, tests/test_per_ticket_model.py:test_model_override_serialization, tests/test_persona_id.py:test_ticket_persona_id_serialization, tests/test_persona_models.py:test_persona_defaults, tests/test_persona_models.py:test_persona_serialization, tests/test_slice_editor_behavior.py:test_add_slice_with_annotations, tests/test_thinking_gui.py:test_thinking_segment_model_compatibility, tests/test_ticket_queue.py:test_ticket_to_dict_priority, tests/test_tiered_aggregation.py:test_persona_aggregation_strategy, tests/test_track_state_schema.py:test_track_state_to_dict, tests/test_track_state_schema.py:test_track_state_to_dict_with_none, tests/test_ui_summary_only_removal.py:test_file_item_serialization_with_flags]
|
||||
"""
|
||||
return {"system_prompt": self.system_prompt}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, name: str, data: Metadata) -> "Preset":
|
||||
"""
|
||||
[C: src/personas.py:PersonaManager.load_all, src/presets.py:PresetManager.load_all, src/project_manager.py:load_project, src/project_manager.py:load_track_state, src/tool_presets.py:ToolPresetManager.load_all_bias_profiles, src/tool_presets.py:ToolPresetManager.load_all_presets, src/workspace_manager.py:WorkspaceManager.load_all_profiles, tests/test_bias_models.py:test_bias_profile_model, tests/test_bias_models.py:test_tool_model, tests/test_bias_models.py:test_tool_preset_extension, tests/test_context_presets_models.py:test_context_preset_from_dict_legacy, tests/test_context_presets_models.py:test_context_preset_serialization, tests/test_context_presets_models.py:test_file_view_preset_serialization, tests/test_custom_slices_annotations.py:test_file_item_custom_slices_deserialization_with_annotations, tests/test_custom_slices_annotations.py:test_file_item_custom_slices_round_trip_annotations, tests/test_external_editor.py:TestExternalEditorConfig.test_from_dict_with_dict_editors, tests/test_external_editor.py:TestExternalEditorConfig.test_from_dict_with_string_editors, tests/test_external_editor.py:TestTextEditorConfig.test_from_dict_with_diff_args, tests/test_external_editor.py:TestTextEditorConfig.test_from_dict_without_diff_args, tests/test_file_item_model.py:test_file_item_from_dict, tests/test_file_item_model.py:test_file_item_from_dict_defaults, tests/test_history_manager.py:TestHistoryManager.test_snapshot_roundtrip, tests/test_mcp_config.py:test_mcp_configuration_to_from_dict, tests/test_mcp_config.py:test_mcp_server_config_to_from_dict, tests/test_per_ticket_model.py:test_model_override_default_on_deserialize, tests/test_per_ticket_model.py:test_model_override_deserialization, tests/test_persona_id.py:test_ticket_persona_id_deserialization, tests/test_persona_models.py:test_persona_defaults, tests/test_persona_models.py:test_persona_deserialization, tests/test_project_serialization.py:TestProjectSerialization.test_backward_compatibility_strings, tests/test_slice_editor_behavior.py:test_add_slice_with_annotations, tests/test_ticket_queue.py:test_ticket_from_dict_default_priority, tests/test_ticket_queue.py:test_ticket_from_dict_priority, tests/test_tiered_aggregation.py:test_persona_aggregation_strategy, tests/test_track_state_schema.py:test_track_state_from_dict, tests/test_track_state_schema.py:test_track_state_from_dict_empty_and_missing, tests/test_ui_summary_only_removal.py:test_file_item_serialization_with_flags]
|
||||
"""
|
||||
return cls(name=name, system_prompt=data.get("system_prompt", ""))
|
||||
|
||||
|
||||
@@ -111,16 +99,10 @@ class ContextFileEntry:
|
||||
ast_definitions: bool = False
|
||||
|
||||
def to_dict(self) -> Metadata:
|
||||
"""
|
||||
[C: src/personas.py:PersonaManager.save_persona, src/presets.py:PresetManager.save_preset, src/project_manager.py:save_project, src/project_manager.py:save_track_state, src/tool_presets.py:ToolPresetManager.save_bias_profile, src/tool_presets.py:ToolPresetManager.save_preset, src/workspace_manager.py:WorkspaceManager.save_profile, tests/test_bias_models.py:test_bias_profile_model, tests/test_bias_models.py:test_tool_model, tests/test_bias_models.py:test_tool_preset_extension, tests/test_context_presets_models.py:test_context_preset_serialization, tests/test_context_presets_models.py:test_file_view_preset_serialization, tests/test_custom_slices_annotations.py:test_file_item_custom_slices_round_trip_annotations, tests/test_custom_slices_annotations.py:test_file_item_custom_slices_serialization_with_annotations, tests/test_event_serialization.py:test_user_request_event_serialization, tests/test_external_editor.py:TestExternalEditorConfig.test_to_dict, tests/test_external_editor.py:TestTextEditorConfig.test_to_dict, tests/test_file_item_model.py:test_file_item_to_dict, tests/test_gui_events_v2.py:test_user_request_event_payload, tests/test_history_manager.py:TestHistoryManager.test_snapshot_roundtrip, tests/test_mcp_config.py:test_mcp_configuration_to_from_dict, tests/test_mcp_config.py:test_mcp_server_config_to_from_dict, tests/test_per_ticket_model.py:test_model_override_serialization, tests/test_persona_id.py:test_ticket_persona_id_serialization, tests/test_persona_models.py:test_persona_defaults, tests/test_persona_models.py:test_persona_serialization, tests/test_slice_editor_behavior.py:test_add_slice_with_annotations, tests/test_thinking_gui.py:test_thinking_segment_model_compatibility, tests/test_ticket_queue.py:test_ticket_to_dict_priority, tests/test_tiered_aggregation.py:test_persona_aggregation_strategy, tests/test_track_state_schema.py:test_track_state_to_dict, tests/test_track_state_schema.py:test_track_state_to_dict_with_none, tests/test_ui_summary_only_removal.py:test_file_item_serialization_with_flags]
|
||||
"""
|
||||
return {"path": self.path, "view_mode": self.view_mode, "custom_slices": self.custom_slices, "ast_mask": self.ast_mask, "ast_signatures": self.ast_signatures, "ast_definitions": self.ast_definitions}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: Metadata) -> "ContextFileEntry":
|
||||
"""
|
||||
[C: src/personas.py:PersonaManager.load_all, src/presets.py:PresetManager.load_all, src/project_manager.py:load_project, src/project_manager.py:load_track_state, src/tool_presets.py:ToolPresetManager.load_all_bias_profiles, src/tool_presets.py:ToolPresetManager.load_all_presets, src/workspace_manager.py:WorkspaceManager.load_all_profiles, tests/test_bias_models.py:test_bias_profile_model, tests/test_bias_models.py:test_tool_model, tests/test_bias_models.py:test_tool_preset_extension, tests/test_context_presets_models.py:test_context_preset_from_dict_legacy, tests/test_context_presets_models.py:test_context_preset_serialization, tests/test_context_presets_models.py:test_file_view_preset_serialization, tests/test_custom_slices_annotations.py:test_file_item_custom_slices_deserialization_with_annotations, tests/test_custom_slices_annotations.py:test_file_item_custom_slices_round_trip_annotations, tests/test_external_editor.py:TestExternalEditorConfig.test_from_dict_with_dict_editors, tests/test_external_editor.py:TestExternalEditorConfig.test_from_dict_with_string_editors, tests/test_external_editor.py:TestTextEditorConfig.test_from_dict_with_diff_args, tests/test_external_editor.py:TestTextEditorConfig.test_from_dict_without_diff_args, tests/test_file_item_model.py:test_file_item_from_dict, tests/test_file_item_model.py:test_file_item_from_dict_defaults, tests/test_history_manager.py:TestHistoryManager.test_snapshot_roundtrip, tests/test_mcp_config.py:test_mcp_configuration_to_from_dict, tests/test_mcp_config.py:test_mcp_server_config_to_from_dict, tests/test_per_ticket_model.py:test_model_override_default_on_deserialize, tests/test_per_ticket_model.py:test_model_override_deserialization, tests/test_persona_id.py:test_ticket_persona_id_deserialization, tests/test_persona_models.py:test_persona_defaults, tests/test_persona_models.py:test_persona_deserialization, tests/test_project_serialization.py:TestProjectSerialization.test_backward_compatibility_strings, tests/test_slice_editor_behavior.py:test_add_slice_with_annotations, tests/test_ticket_queue.py:test_ticket_from_dict_default_priority, tests/test_ticket_queue.py:test_ticket_from_dict_priority, tests/test_tiered_aggregation.py:test_persona_aggregation_strategy, tests/test_track_state_schema.py:test_track_state_from_dict, tests/test_track_state_schema.py:test_track_state_from_dict_empty_and_missing, tests/test_ui_summary_only_removal.py:test_file_item_serialization_with_flags]
|
||||
"""
|
||||
return cls(
|
||||
path = data.get("path", ""),
|
||||
view_mode = data.get("view_mode", "summary"),
|
||||
@@ -139,16 +121,10 @@ class NamedViewPreset:
|
||||
custom_slices: list = field(default_factory=list)
|
||||
|
||||
def to_dict(self) -> Metadata:
|
||||
"""
|
||||
[C: src/personas.py:PersonaManager.save_persona, src/presets.py:PresetManager.save_preset, src/project_manager.py:save_project, src/project_manager.py:save_track_state, src/tool_presets.py:ToolPresetManager.save_bias_profile, src/tool_presets.py:ToolPresetManager.save_preset, src/workspace_manager.py:WorkspaceManager.save_profile, tests/test_bias_models.py:test_bias_profile_model, tests/test_bias_models.py:test_tool_model, tests/test_bias_models.py:test_tool_preset_extension, tests/test_context_presets_models.py:test_context_preset_serialization, tests/test_context_presets_models.py:test_file_view_preset_serialization, tests/test_custom_slices_annotations.py:test_file_item_custom_slices_round_trip_annotations, tests/test_custom_slices_annotations.py:test_file_item_custom_slices_serialization_with_annotations, tests/test_event_serialization.py:test_user_request_event_serialization, tests/test_external_editor.py:TestExternalEditorConfig.test_to_dict, tests/test_external_editor.py:TestTextEditorConfig.test_to_dict, tests/test_file_item_model.py:test_file_item_to_dict, tests/test_gui_events_v2.py:test_user_request_event_payload, tests/test_history_manager.py:TestHistoryManager.test_snapshot_roundtrip, tests/test_mcp_config.py:test_mcp_configuration_to_from_dict, tests/test_mcp_config.py:test_mcp_server_config_to_from_dict, tests/test_per_ticket_model.py:test_model_override_serialization, tests/test_persona_id.py:test_ticket_persona_id_serialization, tests/test_persona_models.py:test_persona_defaults, tests/test_persona_models.py:test_persona_serialization, tests/test_slice_editor_behavior.py:test_add_slice_with_annotations, tests/test_thinking_gui.py:test_thinking_segment_model_compatibility, tests/test_ticket_queue.py:test_ticket_to_dict_priority, tests/test_tiered_aggregation.py:test_persona_aggregation_strategy, tests/test_track_state_schema.py:test_track_state_to_dict, tests/test_track_state_schema.py:test_track_state_to_dict_with_none, tests/test_ui_summary_only_removal.py:test_file_item_serialization_with_flags]
|
||||
"""
|
||||
return {"name": self.name, "view_mode": self.view_mode, "ast_mask": self.ast_mask, "custom_slices": self.custom_slices}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: Metadata) -> "NamedViewPreset":
|
||||
"""
|
||||
[C: src/personas.py:PersonaManager.load_all, src/presets.py:PresetManager.load_all, src/project_manager.py:load_project, src/project_manager.py:load_track_state, src/tool_presets.py:ToolPresetManager.load_all_bias_profiles, src/tool_presets.py:ToolPresetManager.load_all_presets, src/workspace_manager.py:WorkspaceManager.load_all_profiles, tests/test_bias_models.py:test_bias_profile_model, tests/test_bias_models.py:test_tool_model, tests/test_bias_models.py:test_tool_preset_extension, tests/test_context_presets_models.py:test_context_preset_from_dict_legacy, tests/test_context_presets_models.py:test_context_preset_serialization, tests/test_context_presets_models.py:test_file_view_preset_serialization, tests/test_custom_slices_annotations.py:test_file_item_custom_slices_deserialization_with_annotations, tests/test_custom_slices_annotations.py:test_file_item_custom_slices_round_trip_annotations, tests/test_external_editor.py:TestExternalEditorConfig.test_from_dict_with_dict_editors, tests/test_external_editor.py:TestExternalEditorConfig.test_from_dict_with_string_editors, tests/test_external_editor.py:TestTextEditorConfig.test_from_dict_with_diff_args, tests/test_external_editor.py:TestTextEditorConfig.test_from_dict_without_diff_args, tests/test_file_item_model.py:test_file_item_from_dict, tests/test_file_item_model.py:test_file_item_from_dict_defaults, tests/test_history_manager.py:TestHistoryManager.test_snapshot_roundtrip, tests/test_mcp_config.py:test_mcp_configuration_to_from_dict, tests/test_mcp_config.py:test_mcp_server_config_to_from_dict, tests/test_per_ticket_model.py:test_model_override_default_on_deserialize, tests/test_per_ticket_model.py:test_model_override_deserialization, tests/test_persona_id.py:test_ticket_persona_id_deserialization, tests/test_persona_models.py:test_persona_defaults, tests/test_persona_models.py:test_persona_deserialization, tests/test_project_serialization.py:TestProjectSerialization.test_backward_compatibility_strings, tests/test_slice_editor_behavior.py:test_add_slice_with_annotations, tests/test_ticket_queue.py:test_ticket_from_dict_default_priority, tests/test_ticket_queue.py:test_ticket_from_dict_priority, tests/test_tiered_aggregation.py:test_persona_aggregation_strategy, tests/test_track_state_schema.py:test_track_state_from_dict, tests/test_track_state_schema.py:test_track_state_from_dict_empty_and_missing, tests/test_ui_summary_only_removal.py:test_file_item_serialization_with_flags]
|
||||
"""
|
||||
return cls(
|
||||
name = data.get("name", ""),
|
||||
view_mode = data.get("view_mode", "summary"),
|
||||
@@ -165,9 +141,6 @@ class ContextPreset:
|
||||
description: str = ""
|
||||
|
||||
def to_dict(self) -> Metadata:
|
||||
"""
|
||||
[C: src/personas.py:PersonaManager.save_persona, src/presets.py:PresetManager.save_preset, src/project_manager.py:save_project, src/project_manager.py:save_track_state, src/tool_presets.py:ToolPresetManager.save_bias_profile, src/tool_presets.py:ToolPresetManager.save_preset, src/workspace_manager.py:WorkspaceManager.save_profile, tests/test_bias_models.py:test_bias_profile_model, tests/test_bias_models.py:test_tool_model, tests/test_bias_models.py:test_tool_preset_extension, tests/test_context_presets_models.py:test_context_preset_serialization, tests/test_context_presets_models.py:test_file_view_preset_serialization, tests/test_custom_slices_annotations.py:test_file_item_custom_slices_round_trip_annotations, tests/test_custom_slices_annotations.py:test_file_item_custom_slices_serialization_with_annotations, tests/test_event_serialization.py:test_user_request_event_serialization, tests/test_external_editor.py:TestExternalEditorConfig.test_to_dict, tests/test_external_editor.py:TestTextEditorConfig.test_to_dict, tests/test_file_item_model.py:test_file_item_to_dict, tests/test_gui_events_v2.py:test_user_request_event_payload, tests/test_history_manager.py:TestHistoryManager.test_snapshot_roundtrip, tests/test_mcp_config.py:test_mcp_configuration_to_from_dict, tests/test_mcp_config.py:test_mcp_server_config_to_from_dict, tests/test_per_ticket_model.py:test_model_override_serialization, tests/test_persona_id.py:test_ticket_persona_id_serialization, tests/test_persona_models.py:test_persona_defaults, tests/test_persona_models.py:test_persona_serialization, tests/test_slice_editor_behavior.py:test_add_slice_with_annotations, tests/test_thinking_gui.py:test_thinking_segment_model_compatibility, tests/test_ticket_queue.py:test_ticket_to_dict_priority, tests/test_tiered_aggregation.py:test_persona_aggregation_strategy, tests/test_track_state_schema.py:test_track_state_to_dict, tests/test_track_state_schema.py:test_track_state_to_dict_with_none, tests/test_ui_summary_only_removal.py:test_file_item_serialization_with_flags]
|
||||
"""
|
||||
return {
|
||||
"files": [f.to_dict() for f in self.files],
|
||||
"screenshots": self.screenshots,
|
||||
@@ -176,9 +149,6 @@ class ContextPreset:
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, name: str, data: Metadata) -> "ContextPreset":
|
||||
"""
|
||||
[C: src/personas.py:PersonaManager.load_all, src/presets.py:PresetManager.load_all, src/project_manager.py:load_project, src/project_manager.py:load_track_state, src/tool_presets.py:ToolPresetManager.load_all_bias_profiles, src/tool_presets.py:ToolPresetManager.load_all_presets, src/workspace_manager.py:WorkspaceManager.load_all_profiles, tests/test_bias_models.py:test_bias_profile_model, tests/test_bias_models.py:test_tool_model, tests/test_bias_models.py:test_tool_preset_extension, tests/test_context_presets_models.py:test_context_preset_from_dict_legacy, tests/test_context_presets_models.py:test_context_preset_serialization, tests/test_context_presets_models.py:test_file_view_preset_serialization, tests/test_custom_slices_annotations.py:test_file_item_custom_slices_deserialization_with_annotations, tests/test_custom_slices_annotations.py:test_file_item_custom_slices_round_trip_annotations, tests/test_external_editor.py:TestExternalEditorConfig.test_from_dict_with_dict_editors, tests/test_external_editor.py:TestExternalEditorConfig.test_from_dict_with_string_editors, tests/test_external_editor.py:TestTextEditorConfig.test_from_dict_with_diff_args, tests/test_external_editor.py:TestTextEditorConfig.test_from_dict_without_diff_args, tests/test_file_item_model.py:test_file_item_from_dict, tests/test_file_item_model.py:test_file_item_from_dict_defaults, tests/test_history_manager.py:TestHistoryManager.test_snapshot_roundtrip, tests/test_mcp_config.py:test_mcp_configuration_to_from_dict, tests/test_mcp_config.py:test_mcp_server_config_to_from_dict, tests/test_per_ticket_model.py:test_model_override_default_on_deserialize, tests/test_per_ticket_model.py:test_model_override_deserialization, tests/test_persona_id.py:test_ticket_persona_id_deserialization, tests/test_persona_models.py:test_persona_defaults, tests/test_persona_models.py:test_persona_deserialization, tests/test_project_serialization.py:TestProjectSerialization.test_backward_compatibility_strings, tests/test_slice_editor_behavior.py:test_add_slice_with_annotations, tests/test_ticket_queue.py:test_ticket_from_dict_default_priority, tests/test_ticket_queue.py:test_ticket_from_dict_priority, tests/test_tiered_aggregation.py:test_persona_aggregation_strategy, tests/test_track_state_schema.py:test_track_state_from_dict, tests/test_track_state_schema.py:test_track_state_from_dict_empty_and_missing, tests/test_ui_summary_only_removal.py:test_file_item_serialization_with_flags]
|
||||
"""
|
||||
files_data = data.get("files", [])
|
||||
return cls(
|
||||
name = name,
|
||||
|
||||
+4
-32
@@ -50,7 +50,6 @@ def parse_ts_result(s: str) -> Result[datetime.datetime]:
|
||||
def entry_to_str(entry: Metadata) -> str:
|
||||
"""
|
||||
Serialise a disc entry dict -> stored string.
|
||||
[C: tests/test_thinking_persistence.py:test_entry_to_str_with_thinking]
|
||||
"""
|
||||
ts = entry.get("ts", "")
|
||||
role = entry.get("role", "User")
|
||||
@@ -76,7 +75,6 @@ def format_discussion(entries: list[Metadata]) -> str:
|
||||
def str_to_entry(raw: str, roles: list[str]) -> Metadata:
|
||||
"""
|
||||
Parse a stored string back to a disc entry dict.
|
||||
[C: tests/test_thinking_persistence.py:test_str_to_entry_with_thinking]
|
||||
"""
|
||||
ts = ""
|
||||
rest = raw
|
||||
@@ -116,15 +114,9 @@ def get_git_commit(git_dir: str) -> str:
|
||||
# ── default structures ───────────────────────────────────────────────────────
|
||||
|
||||
def default_discussion() -> Metadata:
|
||||
"""
|
||||
[C: tests/test_discussion_takes.py:TestDiscussionTakes.test_promote_take_renames_discussion]
|
||||
"""
|
||||
return {"git_commit": "", "last_updated": now_ts(), "history": []}
|
||||
|
||||
def default_project(name: str = "unnamed") -> Metadata:
|
||||
"""
|
||||
[C: tests/test_deepseek_infra.py:test_default_project_includes_reasoning_role, tests/test_discussion_takes.py:TestDiscussionTakes.setUp, tests/test_history_management.py:test_history_persistence_across_turns, tests/test_history_management.py:test_save_separation, tests/test_project_manager_modes.py:test_default_project_execution_mode, tests/test_project_manager_modes.py:test_load_save_execution_mode, tests/test_project_serialization.py:TestProjectSerialization.test_default_roles_include_context, tests/test_project_serialization.py:TestProjectSerialization.test_fileitem_roundtrip]
|
||||
"""
|
||||
return {
|
||||
"project": {"name": name, "git_dir": "", "system_prompt": "", "execution_mode": "native"},
|
||||
"output": {"output_dir": "./md_gen"},
|
||||
@@ -177,10 +169,7 @@ def default_project(name: str = "unnamed") -> Metadata:
|
||||
# ── load / save ──────────────────────────────────────────────────────────────
|
||||
|
||||
def get_history_path(project_path: Union[str, Path]) -> Path:
|
||||
"""
|
||||
Return the Path to the sibling history TOML file for a given project.
|
||||
[C: tests/test_history_management.py:test_save_separation]
|
||||
"""
|
||||
"""Return the Path to the sibling history TOML file for a given project."""
|
||||
p = Path(project_path)
|
||||
return p.parent / f"{p.stem}_history.toml"
|
||||
|
||||
@@ -188,7 +177,6 @@ def load_project(path: Union[str, Path]) -> Metadata:
|
||||
"""
|
||||
Load a project TOML file.
|
||||
Automatically migrates legacy 'discussion' keys to a sibling history file.
|
||||
[C: tests/test_history_management.py:test_history_persistence_across_turns, tests/test_history_management.py:test_migration_on_load, tests/test_project_manager_modes.py:test_load_save_execution_mode, tests/test_project_serialization.py:TestProjectSerialization.test_backward_compatibility_strings, tests/test_project_serialization.py:TestProjectSerialization.test_fileitem_roundtrip]
|
||||
"""
|
||||
with open(path, "rb") as f: proj = tomllib.load(f)
|
||||
# Deserialise FileItems in files.paths
|
||||
@@ -208,10 +196,7 @@ def load_project(path: Union[str, Path]) -> Metadata:
|
||||
return proj
|
||||
|
||||
def load_history(project_path: Union[str, Path]) -> Metadata:
|
||||
"""
|
||||
Load the segregated discussion history from its dedicated TOML file.
|
||||
[C: tests/test_thinking_persistence.py:test_save_and_load_history_with_thinking_segments]
|
||||
"""
|
||||
"""Load the segregated discussion history from its dedicated TOML file."""
|
||||
hist_path = get_history_path(project_path)
|
||||
if hist_path.exists():
|
||||
with open(hist_path, "rb") as f:
|
||||
@@ -219,10 +204,7 @@ def load_history(project_path: Union[str, Path]) -> Metadata:
|
||||
return {}
|
||||
|
||||
def clean_nones(data: Any) -> Any:
|
||||
"""
|
||||
Recursively remove None values from a dictionary/list.
|
||||
[C: tests/test_thinking_persistence.py:test_clean_nones_removes_thinking]
|
||||
"""
|
||||
"""Recursively remove None values from a dictionary/list."""
|
||||
if isinstance(data, dict): return {k: clean_nones(v) for k, v in data.items() if v is not None}
|
||||
elif isinstance(data, list): return [clean_nones(v) for v in data if v is not None]
|
||||
return data
|
||||
@@ -231,7 +213,6 @@ def save_project(proj: Metadata, path: Union[str, Path], disc_data: Optional[Met
|
||||
"""
|
||||
Save the project TOML.
|
||||
If 'discussion' is present in proj, it is moved to the sibling history file.
|
||||
[C: tests/test_history_management.py:test_history_persistence_across_turns, tests/test_history_management.py:test_save_separation, tests/test_project_manager_modes.py:test_load_save_execution_mode, tests/test_project_serialization.py:TestProjectSerialization.test_fileitem_roundtrip, tests/test_thinking_persistence.py:test_save_and_load_history_with_thinking_segments]
|
||||
"""
|
||||
proj = clean_nones(proj)
|
||||
# Serialise FileItems
|
||||
@@ -305,10 +286,7 @@ def flat_config(proj: Metadata, disc_name: Optional[str] = None, track_id: Optio
|
||||
# ── track state persistence ─────────────────────────────────────────────────
|
||||
|
||||
def save_track_state(track_id: str, state: 'TrackState', base_dir: Union[str, Path] = ".") -> None:
|
||||
"""
|
||||
Saves a TrackState object to conductor/tracks/<track_id>/state.toml.
|
||||
[C: tests/test_project_manager_tracks.py:test_get_all_tracks_with_state, tests/test_track_state_persistence.py:test_track_state_persistence]
|
||||
"""
|
||||
"""Saves a TrackState object to conductor/tracks/<track_id>/state.toml."""
|
||||
track_dir = paths.get_track_state_dir(track_id, project_path=str(base_dir))
|
||||
track_dir.mkdir(parents=True, exist_ok=True)
|
||||
state_file = track_dir / "state.toml"
|
||||
@@ -319,7 +297,6 @@ def load_track_state(track_id: str, base_dir: Union[str, Path] = ".") -> "TrackS
|
||||
"""
|
||||
Loads a TrackState object from conductor/tracks/<track_id>/state.toml.
|
||||
Returns empty TrackState (zero-init) if not found.
|
||||
[C: tests/test_track_state_persistence.py:test_track_state_persistence]
|
||||
"""
|
||||
from src.mma import TrackState, EMPTY_TRACK_STATE
|
||||
state_file = paths.get_track_state_dir(track_id, project_path=str(base_dir)) / 'state.toml'
|
||||
@@ -368,8 +345,6 @@ def get_all_tracks(base_dir: Union[str, Path] = ".") -> list[Metadata]:
|
||||
Each returned dict includes an 'errors' list (list[ErrorInfo]) for any
|
||||
per-track metadata recovery that occurred. Callers can ignore the errors
|
||||
field for display purposes; the metadata is best-effort.
|
||||
|
||||
[C: tests/test_project_manager_tracks.py:test_get_all_tracks_empty, tests/test_project_manager_tracks.py:test_get_all_tracks_malformed, tests/test_project_manager_tracks.py:test_get_all_tracks_with_metadata_json, tests/test_project_manager_tracks.py:test_get_all_tracks_with_state, tests/test_project_paths.py:test_get_all_tracks_project_specific]
|
||||
"""
|
||||
tracks_dir = paths.get_tracks_dir(project_path=str(base_dir))
|
||||
if not tracks_dir.exists(): return []
|
||||
@@ -440,7 +415,6 @@ def calculate_track_progress(tickets: list) -> dict:
|
||||
"""
|
||||
Calculates track progress based on ticket statuses.
|
||||
percentage (float), completed (int), total (int), in_progress (int), blocked (int), todo (int)
|
||||
[C: tests/test_progress_viz.py:test_calculate_track_progress_all_completed, tests/test_progress_viz.py:test_calculate_track_progress_all_todo, tests/test_progress_viz.py:test_calculate_track_progress_empty, tests/test_progress_viz.py:test_calculate_track_progress_mixed]
|
||||
"""
|
||||
total = len(tickets)
|
||||
if total == 0:
|
||||
@@ -473,7 +447,6 @@ def branch_discussion(project_dict: dict, source_id: str, new_id: str, message_i
|
||||
"""
|
||||
Creates a new discussion in project_dict['discussion']['discussions'] by copying
|
||||
the history from source_id up to (and including) message_index, and sets active to new_id.
|
||||
[C: tests/test_discussion_takes.py:TestDiscussionTakes.test_branch_discussion_creates_new_take]
|
||||
"""
|
||||
if "discussion" not in project_dict or "discussions" not in project_dict["discussion"]: return
|
||||
if source_id not in project_dict["discussion"]["discussions"]: return
|
||||
@@ -490,7 +463,6 @@ def branch_discussion(project_dict: dict, source_id: str, new_id: str, message_i
|
||||
def promote_take(project_dict: dict, take_id: str, new_id: str) -> None:
|
||||
"""
|
||||
Renames a take_id to new_id in the discussions dict.
|
||||
[C: tests/test_discussion_takes.py:TestDiscussionTakes.test_promote_take_renames_discussion]
|
||||
"""
|
||||
if "discussion" not in project_dict or "discussions" not in project_dict["discussion"]: return
|
||||
if take_id not in project_dict["discussion"]["discussions"]: return
|
||||
|
||||
@@ -227,9 +227,6 @@ class RAGEngine:
|
||||
return self.collection.count() == 0
|
||||
|
||||
def add_documents(self, ids: List[str], texts: List[str], metadatas: Optional[List[Dict[str, Any]]] = None):
|
||||
"""
|
||||
[C: tests/test_rag_engine.py:test_rag_engine_chroma]
|
||||
"""
|
||||
if not self.config.enabled or self.collection == "mock":
|
||||
return
|
||||
embeddings = self.embedding_provider.embed(texts)
|
||||
@@ -389,9 +386,6 @@ class RAGEngine:
|
||||
return asyncio.run(_async_search_mcp())
|
||||
|
||||
def search(self, query: str, top_k: int = 5) -> List["RAGChunk"]:
|
||||
"""
|
||||
[C: tests/mock_concurrent_mma.py:main, tests/test_rag_engine.py:test_rag_engine_chroma]
|
||||
"""
|
||||
if not self.config.enabled: return []
|
||||
if self.config.vector_store.provider == 'mcp': return self._search_mcp(query, top_k)
|
||||
if self.collection == "mock": return []
|
||||
@@ -418,9 +412,6 @@ class RAGEngine:
|
||||
return ret
|
||||
|
||||
def delete_documents(self, ids: List[str]):
|
||||
"""
|
||||
[C: tests/test_rag_engine.py:test_rag_engine_chroma]
|
||||
"""
|
||||
if not self.config.enabled or self.collection == "mock":
|
||||
return
|
||||
self.collection.delete(ids=ids)
|
||||
|
||||
@@ -61,7 +61,6 @@ def open_session(label: Optional[str] = None) -> None:
|
||||
"""
|
||||
Called once at GUI startup. Creates the log directories if needed and
|
||||
opens the log files for this session within a sub-directory.
|
||||
[C: tests/test_app_controller_offloading.py:tmp_session_dir, tests/test_logging_e2e.py:test_logging_e2e, tests/test_session_logger_optimization.py:test_log_tool_call_saves_in_session_scripts, tests/test_session_logger_optimization.py:test_log_tool_output_saves_in_session_outputs, tests/test_session_logger_optimization.py:test_session_directory_and_subdirectories_creation, tests/test_session_logger_reset.py:test_reset_session, tests/test_session_logging.py:test_open_session_creates_subdir_and_registry]
|
||||
"""
|
||||
global _ts, _session_id, _session_dir, _comms_fh, _tool_fh, _api_fh, _cli_fh, _seq, _output_seq
|
||||
if _comms_fh is not None:
|
||||
@@ -103,10 +102,7 @@ def open_session(label: Optional[str] = None) -> None:
|
||||
atexit.register(close_session)
|
||||
|
||||
def close_session() -> None:
|
||||
"""
|
||||
Flush and close all log files. Called on clean exit.
|
||||
[C: tests/test_app_controller_offloading.py:tmp_session_dir, tests/test_logging_e2e.py:e2e_setup, tests/test_logging_e2e.py:test_logging_e2e, tests/test_session_logger_optimization.py:temp_session_setup, tests/test_session_logger_reset.py:temp_logs, tests/test_session_logging.py:temp_logs]
|
||||
"""
|
||||
"""Flush and close all log files. Called on clean exit."""
|
||||
global _comms_fh, _tool_fh, _api_fh, _cli_fh, _session_id
|
||||
if _comms_fh is None:
|
||||
return
|
||||
@@ -153,7 +149,6 @@ def log_comms(entry: dict[str, Any]) -> Result[bool]:
|
||||
"""
|
||||
Append one comms entry to the comms log file as a JSON-L line.
|
||||
Thread-safe (GIL + line-buffered file).
|
||||
[C: tests/test_logging_e2e.py:test_logging_e2e]
|
||||
"""
|
||||
if _comms_fh is None:
|
||||
return Result(data=False)
|
||||
@@ -167,7 +162,6 @@ def log_tool_call(script: str, result: str, script_path: Optional[str]) -> str:
|
||||
"""
|
||||
Append a tool-call record to the toolcalls log and write the PS1 script to
|
||||
the session's scripts directory. Returns the path of the written script file.
|
||||
[C: tests/test_session_logger_optimization.py:test_log_tool_call_saves_in_session_scripts]
|
||||
"""
|
||||
global _seq
|
||||
if _tool_fh is None:
|
||||
|
||||
@@ -63,7 +63,6 @@ def run_powershell(script: str, base_dir: str, qa_callback: Optional[Callable[[s
|
||||
If qa_callback is provided and the command fails or has stderr,
|
||||
the callback is called with the stderr content and its result is appended.
|
||||
If patch_callback is provided, it receives (error, file_context) and returns patch text.
|
||||
[C: tests/test_tier4_interceptor.py:test_run_powershell_no_qa_callback_on_success, tests/test_tier4_interceptor.py:test_run_powershell_optional_qa_callback, tests/test_tier4_interceptor.py:test_run_powershell_qa_callback_on_failure, tests/test_tier4_interceptor.py:test_run_powershell_qa_callback_on_stderr_only]
|
||||
"""
|
||||
safe_dir: str = str(base_dir).replace("'", "''")
|
||||
full_script: str = f"Set-Location -LiteralPath '{safe_dir}'\n{script}"
|
||||
|
||||
@@ -160,7 +160,6 @@ def summarise_file(path: Path, content: str) -> str:
|
||||
"""
|
||||
Return a compact markdown summary string for a single file.
|
||||
`content` is the already-read file text (or an error string).
|
||||
[C: tests/test_subagent_summarization.py:test_summarise_file_integration]
|
||||
"""
|
||||
content_hash = get_file_hash(content)
|
||||
cached = _summary_cache.get_summary(str(path), content_hash)
|
||||
|
||||
+5
-20
@@ -8,10 +8,7 @@ from src.result_types import Result, ErrorInfo, ErrorKind
|
||||
|
||||
|
||||
def get_file_hash(content: str) -> str:
|
||||
"""
|
||||
Returns SHA256 hash of the content.
|
||||
[C: tests/test_summary_cache.py:test_get_file_hash, tests/test_summary_cache.py:test_summary_cache]
|
||||
"""
|
||||
"""Returns SHA256 hash of the content."""
|
||||
return hashlib.sha256(content.encode("utf-8")).hexdigest()
|
||||
|
||||
class SummaryCache:
|
||||
@@ -30,10 +27,7 @@ class SummaryCache:
|
||||
self.load()
|
||||
|
||||
def load(self) -> Result[bool]:
|
||||
"""
|
||||
Loads cache from disk.
|
||||
[C: src/tool_presets.py:ToolPresetManager._read_raw, src/workspace_manager.py:WorkspaceManager._load_file, tests/test_gui_phase3.py:test_create_track, tests/test_history_management.py:test_save_separation, tests/test_session_logging.py:test_open_session_creates_subdir_and_registry]
|
||||
"""
|
||||
"""Loads cache from disk."""
|
||||
if not self.cache_file.exists():
|
||||
return Result(data=False)
|
||||
try:
|
||||
@@ -55,10 +49,7 @@ class SummaryCache:
|
||||
return Result(data=False, errors=[ErrorInfo(kind=ErrorKind.INTERNAL, message=str(e), source="summary_cache.save", original=e)])
|
||||
|
||||
def get_summary(self, file_path: str, content_hash: str) -> str:
|
||||
"""
|
||||
Returns cached summary if hash matches, otherwise "".
|
||||
[C: tests/test_summary_cache.py:test_summary_cache, tests/test_summary_cache.py:test_summary_cache_lru]
|
||||
"""
|
||||
"""Returns cached summary if hash matches, otherwise ""."""
|
||||
entry = self.cache.get(file_path)
|
||||
if entry and entry.get("hash") == content_hash:
|
||||
# LRU: move to end
|
||||
@@ -68,10 +59,7 @@ class SummaryCache:
|
||||
return ""
|
||||
|
||||
def set_summary(self, file_path: str, content_hash: str, summary: str) -> None:
|
||||
"""
|
||||
Stores summary in cache and saves to disk.
|
||||
[C: tests/test_summary_cache.py:test_summary_cache, tests/test_summary_cache.py:test_summary_cache_lru]
|
||||
"""
|
||||
"""Stores summary in cache and saves to disk."""
|
||||
if file_path in self.cache:
|
||||
self.cache.pop(file_path)
|
||||
self.cache[file_path] = {
|
||||
@@ -86,10 +74,7 @@ class SummaryCache:
|
||||
self.save()
|
||||
|
||||
def clear(self) -> Result[bool]:
|
||||
"""
|
||||
Clears the cache both in-memory and on disk.
|
||||
[C: tests/conftest.py:reset_ai_client]
|
||||
"""
|
||||
"""Clears the cache both in-memory and on disk."""
|
||||
self.cache.clear()
|
||||
if not self.cache_file.exists():
|
||||
return Result(data=True)
|
||||
|
||||
@@ -2,9 +2,6 @@ from src.type_aliases import HistoryMessage
|
||||
|
||||
|
||||
def format_takes_diff(takes: dict[str, list[dict]]) -> str:
|
||||
"""
|
||||
[C: tests/test_synthesis_formatter.py:test_format_takes_diff_common_prefix, tests/test_synthesis_formatter.py:test_format_takes_diff_empty, tests/test_synthesis_formatter.py:test_format_takes_diff_no_common_prefix, tests/test_synthesis_formatter.py:test_format_takes_diff_single_take]
|
||||
"""
|
||||
if not takes:
|
||||
return ""
|
||||
|
||||
|
||||
+1
-4
@@ -63,10 +63,7 @@ NERV_PALETTE = {
|
||||
}
|
||||
|
||||
def apply_nerv() -> None:
|
||||
"""
|
||||
Apply NERV theme with hard edges and specific palette.
|
||||
[C: tests/test_theme_nerv.py:test_apply_nerv_sets_rounding_and_colors]
|
||||
"""
|
||||
"""Apply NERV theme with hard edges and specific palette."""
|
||||
style = imgui.get_style()
|
||||
for col_enum, rgba in NERV_PALETTE.items():
|
||||
style.set_color_(col_enum, imgui.ImVec4(*rgba))
|
||||
|
||||
@@ -10,9 +10,6 @@ class CRTFilter:
|
||||
self.enabled = True
|
||||
|
||||
def render(self, width: float, height: float):
|
||||
"""
|
||||
[C: tests/test_theme_nerv_alert.py:test_alert_pulsing_render_active, tests/test_theme_nerv_alert.py:test_alert_pulsing_render_inactive, tests/test_theme_nerv_fx.py:TestThemeNervFx.test_alert_pulsing_render, tests/test_theme_nerv_fx.py:TestThemeNervFx.test_crt_filter_disabled, tests/test_theme_nerv_fx.py:TestThemeNervFx.test_crt_filter_render]
|
||||
"""
|
||||
if not self.enabled: return
|
||||
draw_list = imgui.get_foreground_draw_list()
|
||||
|
||||
@@ -67,9 +64,6 @@ class CRTFilter:
|
||||
class StatusFlicker:
|
||||
def get_alpha(self) -> float:
|
||||
# Modulate between 0.7 and 1.0 using sin wave
|
||||
"""
|
||||
[C: tests/test_theme_nerv_fx.py:TestThemeNervFx.test_status_flicker_get_alpha]
|
||||
"""
|
||||
return 0.85 + 0.15 * math.sin(time.time() * 20.0)
|
||||
|
||||
class AlertPulsing:
|
||||
@@ -77,15 +71,9 @@ class AlertPulsing:
|
||||
self.active = False
|
||||
|
||||
def update(self, status: str):
|
||||
"""
|
||||
[C: tests/test_spawn_interception_v2.py:MockDialog.wait, tests/test_theme_nerv_alert.py:test_alert_pulsing_update, tests/test_theme_nerv_fx.py:TestThemeNervFx.test_alert_pulsing_update]
|
||||
"""
|
||||
self.active = status.lower().startswith("error")
|
||||
|
||||
def render(self, width: float, height: float):
|
||||
"""
|
||||
[C: tests/test_theme_nerv_alert.py:test_alert_pulsing_render_active, tests/test_theme_nerv_alert.py:test_alert_pulsing_render_inactive, tests/test_theme_nerv_fx.py:TestThemeNervFx.test_alert_pulsing_render, tests/test_theme_nerv_fx.py:TestThemeNervFx.test_crt_filter_disabled, tests/test_theme_nerv_fx.py:TestThemeNervFx.test_crt_filter_render]
|
||||
"""
|
||||
if not self.active:
|
||||
return
|
||||
draw_list = imgui.get_foreground_draw_list()
|
||||
|
||||
@@ -10,7 +10,6 @@ def parse_thinking_trace(text: str) -> Tuple[List[ThinkingSegment], str]:
|
||||
Parses thinking segments from text and returns (segments, response_content).
|
||||
Support extraction of thinking traces from <thinking>...</thinking>, <thought>...</thought>,
|
||||
<think>...</think> (half-width form), and blocks prefixed with Thinking:.
|
||||
[C: tests/test_thinking_trace.py:test_parse_empty_response, tests/test_thinking_trace.py:test_parse_multiple_markers, tests/test_thinking_trace.py:test_parse_no_thinking, tests/test_thinking_trace.py:test_parse_text_thinking_prefix, tests/test_thinking_trace.py:test_parse_thinking_with_empty_response, tests/test_thinking_trace.py:test_parse_xml_thinking_tag, tests/test_thinking_trace.py:test_parse_xml_thought_tag, tests/test_thinking_trace.py:test_parse_half_width_think_tag]
|
||||
"""
|
||||
segments = []
|
||||
|
||||
|
||||
@@ -31,9 +31,6 @@ class BiasProfile:
|
||||
|
||||
class ToolBiasEngine:
|
||||
def apply_semantic_nudges(self, tool_definitions: List[Dict[str, Any]], preset: ToolPreset) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
[C: tests/test_tool_bias.py:test_apply_semantic_nudges, tests/test_tool_bias.py:test_parameter_bias_nudging]
|
||||
"""
|
||||
weight_map = {
|
||||
5: "[HIGH PRIORITY] ",
|
||||
4: "[PREFERRED] ",
|
||||
@@ -67,9 +64,6 @@ class ToolBiasEngine:
|
||||
return tool_definitions
|
||||
|
||||
def generate_tooling_strategy(self, preset: ToolPreset, global_bias: BiasProfile) -> str:
|
||||
"""
|
||||
[C: tests/test_tool_bias.py:test_generate_tooling_strategy]
|
||||
"""
|
||||
lines = ["### Tooling Strategy"]
|
||||
|
||||
preferred = []
|
||||
|
||||
+1
-25
@@ -60,9 +60,6 @@ class ToolPresetManager:
|
||||
self.project_root = Path(project_root) if project_root else None
|
||||
|
||||
def _get_path(self, scope: str) -> Path:
|
||||
"""
|
||||
[C: src/workspace_manager.py:WorkspaceManager.delete_profile, src/workspace_manager.py:WorkspaceManager.save_profile]
|
||||
"""
|
||||
if scope == "global":
|
||||
return paths.get_global_tool_presets_path()
|
||||
elif scope == "project":
|
||||
@@ -89,9 +86,6 @@ class ToolPresetManager:
|
||||
tomli_w.dump(data, f)
|
||||
|
||||
def load_all_presets(self) -> Dict[str, ToolPreset]:
|
||||
"""
|
||||
[C: tests/test_tool_preset_manager.py:test_load_all_presets_merged]
|
||||
"""
|
||||
global_path = paths.get_global_tool_presets_path()
|
||||
global_data = self._read_raw(global_path).get("presets", {})
|
||||
|
||||
@@ -110,16 +104,10 @@ class ToolPresetManager:
|
||||
return presets
|
||||
|
||||
def load_all(self) -> Dict[str, ToolPreset]:
|
||||
"""
|
||||
Backward compatibility for load_all().
|
||||
[C: tests/test_persona_manager.py:test_delete_persona, tests/test_persona_manager.py:test_load_all_merged, tests/test_persona_manager.py:test_save_persona, tests/test_preset_manager.py:test_delete_preset, tests/test_preset_manager.py:test_load_all_merged, tests/test_preset_manager.py:test_save_preset_global, tests/test_preset_manager.py:test_save_preset_project, tests/test_presets.py:TestPresetManager.test_delete_preset, tests/test_presets.py:TestPresetManager.test_project_overwrites_global, tests/test_presets.py:TestPresetManager.test_save_and_load_global, tests/test_presets.py:TestPresetManager.test_save_and_load_project]
|
||||
"""
|
||||
"""Backward compatibility for load_all()."""
|
||||
return self.load_all_presets()
|
||||
|
||||
def save_preset(self, preset: ToolPreset, scope: str = "project") -> None:
|
||||
"""
|
||||
[C: tests/test_preset_manager.py:test_save_preset_global, tests/test_preset_manager.py:test_save_preset_project, tests/test_preset_manager.py:test_save_preset_project_no_root, tests/test_presets.py:TestPresetManager.test_delete_preset, tests/test_presets.py:TestPresetManager.test_project_overwrites_global, tests/test_presets.py:TestPresetManager.test_save_and_load_global, tests/test_presets.py:TestPresetManager.test_save_and_load_project]
|
||||
"""
|
||||
path = self._get_path(scope)
|
||||
data = self._read_raw(path)
|
||||
if "presets" not in data:
|
||||
@@ -128,9 +116,6 @@ class ToolPresetManager:
|
||||
self._write_raw(path, data)
|
||||
|
||||
def delete_preset(self, name: str, scope: str = "project") -> None:
|
||||
"""
|
||||
[C: tests/test_preset_manager.py:test_delete_preset, tests/test_presets.py:TestPresetManager.test_delete_preset]
|
||||
"""
|
||||
path = self._get_path(scope)
|
||||
data = self._read_raw(path)
|
||||
if "presets" in data and name in data["presets"]:
|
||||
@@ -138,9 +123,6 @@ class ToolPresetManager:
|
||||
self._write_raw(path, data)
|
||||
|
||||
def load_all_bias_profiles(self) -> Dict[str, "BiasProfile"]:
|
||||
"""
|
||||
[C: tests/test_tool_preset_manager.py:test_bias_profiles_merged, tests/test_tool_preset_manager.py:test_delete_bias_profile, tests/test_tool_preset_manager.py:test_save_bias_profile]
|
||||
"""
|
||||
from src.tool_bias import BiasProfile
|
||||
global_path = paths.get_global_tool_presets_path()
|
||||
global_data = self._read_raw(global_path).get("bias_profiles", {})
|
||||
@@ -166,9 +148,6 @@ class ToolPresetManager:
|
||||
return profiles
|
||||
|
||||
def save_bias_profile(self, profile: BiasProfile, scope: str = "project") -> None:
|
||||
"""
|
||||
[C: tests/test_tool_preset_manager.py:test_save_bias_profile]
|
||||
"""
|
||||
path = self._get_path(scope)
|
||||
data = self._read_raw(path)
|
||||
if "bias_profiles" not in data:
|
||||
@@ -177,9 +156,6 @@ class ToolPresetManager:
|
||||
self._write_raw(path, data)
|
||||
|
||||
def delete_bias_profile(self, name: str, scope: str = "project") -> None:
|
||||
"""
|
||||
[C: tests/test_tool_preset_manager.py:test_delete_bias_profile]
|
||||
"""
|
||||
path = self._get_path(scope)
|
||||
data = self._read_raw(path)
|
||||
if "bias_profiles" in data and name in data["bias_profiles"]:
|
||||
|
||||
@@ -52,10 +52,7 @@ class WorkspaceManager:
|
||||
raise ValueError("Invalid scope, must be 'global' or 'project'")
|
||||
|
||||
def load_all_profiles(self) -> Dict[str, WorkspaceProfile]:
|
||||
"""
|
||||
Merges global and project profiles into a single dictionary.
|
||||
[C: tests/test_workspace_manager.py:test_delete_profile, tests/test_workspace_manager.py:test_load_all_profiles_merged, tests/test_workspace_manager.py:test_save_profile_global_and_project]
|
||||
"""
|
||||
"""Merges global and project profiles into a single dictionary."""
|
||||
profiles = {}
|
||||
|
||||
global_path = paths.get_global_workspace_profiles_path()
|
||||
@@ -72,9 +69,6 @@ class WorkspaceManager:
|
||||
return profiles
|
||||
|
||||
def save_profile(self, profile: WorkspaceProfile, scope: str = "project") -> None:
|
||||
"""
|
||||
[C: tests/test_workspace_manager.py:test_delete_profile, tests/test_workspace_manager.py:test_save_profile_global_and_project]
|
||||
"""
|
||||
path = self._get_path(scope)
|
||||
data = self._load_file(path)
|
||||
if "profiles" not in data:
|
||||
@@ -84,9 +78,6 @@ class WorkspaceManager:
|
||||
self._save_file(path, data)
|
||||
|
||||
def delete_profile(self, name: str, scope: str = "project") -> None:
|
||||
"""
|
||||
[C: tests/test_workspace_manager.py:test_delete_profile]
|
||||
"""
|
||||
path = self._get_path(scope)
|
||||
data = self._load_file(path)
|
||||
if "profiles" in data and name in data["profiles"]:
|
||||
|
||||
Reference in New Issue
Block a user