codebase: cleaning cruft part 1

This commit is contained in:
ed
2026-07-05 13:46:35 -04:00
parent deae250019
commit 27f2c25f1c
22 changed files with 64 additions and 371 deletions
+24 -65
View File
@@ -65,7 +65,6 @@ class WorkerPool:
""" """
Spawns a new worker thread if the pool is not full. Spawns a new worker thread if the pool is not full.
Returns the thread object or None if 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: with self._lock:
if len(self._active) >= self.max_workers: if len(self._active) >= self.max_workers:
@@ -86,9 +85,6 @@ class WorkerPool:
return t return t
def join_all(self, timeout: float = None) -> None: 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: with self._lock:
threads = list(self._active.values()) threads = list(self._active.values())
for t in threads: for t in threads:
@@ -97,22 +93,14 @@ class WorkerPool:
self._active.clear() self._active.clear()
def get_active_count(self) -> int: 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: with self._lock:
return len(self._active) return len(self._active)
def is_full(self) -> bool: def is_full(self) -> bool:
"""
[C: tests/test_parallel_execution.py:test_worker_pool_limit]
"""
return self.get_active_count() >= self.max_workers return self.get_active_count() >= self.max_workers
class ConductorEngine: 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: def __init__(self, track: Track, event_queue: Optional[events.AsyncEventQueue] = None, auto_queue: bool = False, max_workers: int = 4) -> None:
self.track = track self.track = track
@@ -142,40 +130,25 @@ class ConductorEngine:
self.tier_usage[tier]["output"] += output_tokens self.tier_usage[tier]["output"] += output_tokens
def pause(self) -> None: def pause(self) -> None:
""" """Pauses the pipeline execution."""
Pauses the pipeline execution.
[C: tests/test_pipeline_pause.py:test_pause_method, tests/test_pipeline_pause.py:test_resume_method]
"""
self._pause_event.set() self._pause_event.set()
def resume(self) -> None: def resume(self) -> None:
""" """Resumes the pipeline execution."""
Resumes the pipeline execution.
[C: tests/test_pipeline_pause.py:test_resume_method]
"""
self._pause_event.clear() self._pause_event.clear()
def approve_task(self, task_id: str) -> None: def approve_task(self, task_id: str) -> None:
""" """Manually transition todo to in_progress and mark engine dirty."""
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]
"""
self.engine.approve_task(task_id) self.engine.approve_task(task_id)
self._dirty = True self._dirty = True
def update_task_status(self, task_id: str, status: str) -> None: def update_task_status(self, task_id: str, status: str) -> None:
""" """Force-update ticket status and mark engine dirty."""
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]
"""
self.engine.update_task_status(task_id, status) self.engine.update_task_status(task_id, status)
self._dirty = True self._dirty = True
def kill_worker(self, ticket_id: str) -> None: def kill_worker(self, ticket_id: str) -> None:
""" """Sets the abort event for a worker and attempts to join its thread."""
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]
"""
if ticket_id in self._abort_events: if ticket_id in self._abort_events:
print(f"[MMA] Setting abort event for {ticket_id}") print(f"[MMA] Setting abort event for {ticket_id}")
self._abort_events[ticket_id].set() self._abort_events[ticket_id].set()
@@ -207,11 +180,8 @@ class ConductorEngine:
def parse_json_tickets(self, json_str: str) -> None: 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.
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]
""" """
try: try:
data = json.loads(json_str) data = json.loads(json_str)
@@ -239,13 +209,10 @@ class ConductorEngine:
def run(self, md_content: str = "", max_ticks: Optional[int] = None) -> None: def run(self, md_content: str = "", max_ticks: Optional[int] = None) -> None:
""" """
Main execution loop using the DAG engine.
Args:
Main execution loop using the DAG engine. md_content: The full markdown context (history + files) for AI workers.
Args: max_ticks: Optional limit on number of iterations (for testing).
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]
""" """
tick_count = 0 tick_count = 0
while True: 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: 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] dialog_container = [None]
task = { 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]: 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)
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]
""" """
dialog_container = [None] dialog_container = [None]
task = { 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: 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.
Simulates the lifecycle of a single agent working on a ticket. Args:
Calls the AI client and updates the ticket status based on the response. ticket: The ticket to process.
Args: context: The worker context.
ticket: The ticket to process. context_files: List of files to include in the context.
context: The worker context. event_queue: Queue for pushing state updates and receiving approvals.
context_files: List of files to include in the context. engine: The conductor engine.
event_queue: Queue for pushing state updates and receiving approvals. md_content: The markdown context (history + files) for AI workers.
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]
""" """
# Enforce Context Amnesia: each ticket starts with a clean slate. # Enforce Context Amnesia: each ticket starts with a clean slate.
ai_client.reset_session() ai_client.reset_session()
+1 -5
View File
@@ -14,10 +14,7 @@ from src.type_aliases import Metadata
def get_track_history_summary() -> Result[str]: def get_track_history_summary() -> Result[str]:
""" """Scans conductor/archive/ and conductor/tracks/ to build a summary of past work."""
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]
"""
summary_parts = [] summary_parts = []
scan_errors: list[ErrorInfo] = [] scan_errors: list[ErrorInfo] = []
archive_path = paths.get_archive_dir() 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. Tier 1 (Strategic PM) call.
Analyzes the project state and user request to generate a list of Tracks. 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) # 1. Build Repository Map (Summary View)
repo_map = summarize.build_summary_markdown(file_items) repo_map = summarize.build_summary_markdown(file_items)
-9
View File
@@ -42,9 +42,6 @@ class CodeOutliner:
pass pass
def outline(self, code: str) -> Result[str]: 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)) code = code.lstrip(chr(0xFEFF))
try: try:
tree = ast.parse(code) tree = ast.parse(code)
@@ -62,15 +59,9 @@ class CodeOutliner:
count = [0] count = [0]
def walk(node: ast.AST, indent: int = 0) -> None: def walk(node: ast.AST, indent: int = 0) -> None:
"""
[C: src/summarize.py:_summarise_python]
"""
count[0] += 1 count[0] += 1
if count[0] > 100000: if count[0] > 100000:
raise Exception("Infinite loop detected! " + str(type(node))) raise Exception("Infinite loop detected! " + str(type(node)))
"""
[C: src/summarize.py:_summarise_python]
"""
if isinstance(node, ast.ClassDef): if isinstance(node, ast.ClassDef):
start_line = node.lineno start_line = node.lineno
end_line = getattr(node, "end_lineno", start_line) end_line = getattr(node, "end_lineno", start_line)
-33
View File
@@ -34,9 +34,6 @@ class PatchModalManager:
self._on_reject_callback: Optional[Callable[[], None]] = None 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: 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 from time import time
self._pending_patch = PendingPatch( self._pending_patch = PendingPatch(
patch_text=patch_text, patch_text=patch_text,
@@ -48,56 +45,32 @@ class PatchModalManager:
return True return True
def get_pending_patch(self) -> "PendingPatch": 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 return self._pending_patch
def is_modal_shown(self) -> bool: 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 return self._show_modal
def set_apply_callback(self, callback: Callable[[str], bool]) -> None: 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 self._on_apply_callback = callback
def set_reject_callback(self, callback: Callable[[], None]) -> None: 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 self._on_reject_callback = callback
def apply_patch(self, patch_text: str) -> bool: def apply_patch(self, patch_text: str) -> bool:
"""
[C: tests/test_patch_modal.py:test_apply_callback]
"""
if self._on_apply_callback: if self._on_apply_callback:
return self._on_apply_callback(patch_text) return self._on_apply_callback(patch_text)
return False return False
def reject_patch(self) -> None: 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._pending_patch = EMPTY_PATCH
self._show_modal = False self._show_modal = False
if self._on_reject_callback: if self._on_reject_callback:
self._on_reject_callback() self._on_reject_callback()
def close_modal(self) -> None: def close_modal(self) -> None:
"""
[C: tests/test_patch_modal.py:test_close_modal]
"""
self._show_modal = False self._show_modal = False
def reset(self) -> None: def reset(self) -> None:
"""
[C: tests/test_patch_modal.py:test_reset]
"""
self._pending_patch = EMPTY_PATCH self._pending_patch = EMPTY_PATCH
self._show_modal = False self._show_modal = False
self._on_apply_callback = None self._on_apply_callback = None
@@ -106,18 +79,12 @@ class PatchModalManager:
_patch_modal_manager: Optional[PatchModalManager] = None _patch_modal_manager: Optional[PatchModalManager] = None
def get_patch_modal_manager() -> PatchModalManager: def get_patch_modal_manager() -> PatchModalManager:
"""
[C: tests/test_patch_modal.py:test_get_patch_modal_manager_singleton]
"""
global _patch_modal_manager global _patch_modal_manager
if _patch_modal_manager is None: if _patch_modal_manager is None:
_patch_modal_manager = PatchModalManager() _patch_modal_manager = PatchModalManager()
return _patch_modal_manager return _patch_modal_manager
def reset_patch_modal_manager() -> None: def reset_patch_modal_manager() -> None:
"""
[C: tests/test_patch_modal.py:test_get_patch_modal_manager_singleton]
"""
global _patch_modal_manager global _patch_modal_manager
if _patch_modal_manager: if _patch_modal_manager:
_patch_modal_manager.reset() _patch_modal_manager.reset()
+17 -47
View File
@@ -51,8 +51,7 @@ from typing import Optional, Any
@dataclass(frozen=True) @dataclass(frozen=True)
class PathsConfig: class PathsConfig:
"""Immutable snapshot of resolved paths. Created ONCE per process. """Immutable snapshot of resolved paths. Created ONCE per process."""
[C: src/paths.py:initialize_paths, src/paths.py:_cfg]"""
config_path: Path config_path: Path
presets: Path presets: Path
tool_presets: Path tool_presets: Path
@@ -72,8 +71,7 @@ _PATHS_LOCK = threading.RLock()
def _default_paths_config() -> PathsConfig: def _default_paths_config() -> PathsConfig:
"""Build the default PathsConfig (no [paths] overrides, just defaults). """Build the default PathsConfig (no [paths] overrides, just defaults).
Called once at module load to ensure _PATHS_CONFIG is never None for Called once at module load to ensure _PATHS_CONFIG is never None for
callers that don't explicitly initialize (e.g., subprocess imports). callers that don't explicitly initialize (e.g., subprocess imports)."""
[C: src/paths.py:initialize_paths, src/paths.py:_module_init_default]"""
root_dir = Path(__file__).resolve().parent.parent root_dir = Path(__file__).resolve().parent.parent
config_path = root_dir / "config.toml" config_path = root_dir / "config.toml"
cfg = PathsConfig( cfg = PathsConfig(
@@ -93,8 +91,7 @@ def _default_paths_config() -> PathsConfig:
def _module_init_default() -> None: def _module_init_default() -> None:
"""Initialize _PATHS_CONFIG with defaults at module load. """Initialize _PATHS_CONFIG with defaults at module load.
Idempotent. Subsequent calls to initialize_paths(<custom>) override this. Idempotent. Subsequent calls to initialize_paths(<custom>) override this."""
[C: src/paths.py:initialize_paths, src/paths.py:reset_paths]"""
global _PATHS_CONFIG global _PATHS_CONFIG
if _PATHS_CONFIG is None: if _PATHS_CONFIG is None:
_PATHS_CONFIG = _default_paths_config() _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 TypeError: if config_path is not a Path
Returns: Returns:
The newly installed PathsConfig snapshot. The newly installed PathsConfig snapshot."""
[C: src/paths.py:_cfg, tests/conftest.py:_setup_test_paths, sloppy.py:main]"""
global _PATHS_CONFIG global _PATHS_CONFIG
if config_path is None: if config_path is None:
root_dir = Path(__file__).resolve().parent.parent root_dir = Path(__file__).resolve().parent.parent
@@ -174,89 +170,68 @@ def _cfg() -> PathsConfig:
# === Trivial getters (single source of truth) === # === Trivial getters (single source of truth) ===
def get_config_path() -> Path: def get_config_path() -> Path:
"""Active config.toml path. Frozen at initialize_paths() time. """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]"""
return _cfg().config_path return _cfg().config_path
def get_global_presets_path() -> Path: def get_global_presets_path() -> Path:
"""Global presets file. Frozen at initialize_paths() time. """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]"""
return _cfg().presets return _cfg().presets
def get_project_presets_path(project_root: Path) -> Path: def get_project_presets_path(project_root: Path) -> Path:
"""Project-specific presets file. Computed from project_root (no cache). """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]"""
return project_root / "project_presets.toml" return project_root / "project_presets.toml"
def get_global_tool_presets_path() -> Path: def get_global_tool_presets_path() -> Path:
"""Global tool presets file. Frozen at initialize_paths() time. """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]"""
return _cfg().tool_presets return _cfg().tool_presets
def get_project_tool_presets_path(project_root: Path) -> Path: 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" return project_root / "project_tool_presets.toml"
def get_global_personas_path() -> Path: def get_global_personas_path() -> Path:
"""Global personas file. Frozen at initialize_paths() time. """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]"""
return _cfg().personas return _cfg().personas
def get_project_personas_path(project_root: Path) -> Path: 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" return project_root / "project_personas.toml"
def get_global_themes_path() -> Path: def get_global_themes_path() -> Path:
"""Global themes directory. Frozen at initialize_paths() time. """Global themes directory. Frozen at initialize_paths() time."""
[C: src/theme_2.py:load_themes_from_disk]"""
return _cfg().themes return _cfg().themes
def get_layouts_dir() -> Path: def get_layouts_dir() -> Path:
"""Global layouts directory. Frozen at initialize_paths() time. """Global layouts directory. Frozen at initialize_paths() time."""
[C: src/layouts.py:load_layouts_from_disk]"""
return _cfg().layouts return _cfg().layouts
def get_project_themes_path(project_root: Path) -> Path: def get_project_themes_path(project_root: Path) -> Path:
"""[C: src/theme_2.py:load_themes_from_disk]"""
return project_root / "project_themes.toml" return project_root / "project_themes.toml"
def get_global_workspace_profiles_path() -> Path: def get_global_workspace_profiles_path() -> Path:
"""Global workspace profiles file. Frozen at initialize_paths() time. """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]"""
return _cfg().workspace_profiles return _cfg().workspace_profiles
def get_project_workspace_profiles_path(project_root: Path) -> Path: 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" return project_root / ".ai" / "workspace_profiles.toml"
def get_credentials_path() -> Path: def get_credentials_path() -> Path:
"""Global credentials file. Frozen at initialize_paths() time. """Global credentials file. Frozen at initialize_paths() time."""
[C: src/mcp_client.py:_is_allowed]"""
return _cfg().credentials return _cfg().credentials
def get_logs_dir() -> Path: def get_logs_dir() -> Path:
"""Logs directory (contains session subdirs). Frozen at initialize_paths() time. """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]"""
return _cfg().logs_dir return _cfg().logs_dir
def get_scripts_dir() -> Path: def get_scripts_dir() -> Path:
"""Generated scripts directory. Frozen at initialize_paths() time. """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]"""
return _cfg().scripts_dir return _cfg().scripts_dir
def get_tracks_dir(project_path: Optional[str] = None) -> Path: 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" return get_conductor_dir(project_path) / "tracks"
def get_track_state_dir(track_id: str, project_path: Optional[str] = None) -> Path: 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 return get_tracks_dir(project_path) / track_id
def get_archive_dir(project_path: Optional[str] = None) -> Path: 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" 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: 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: if not project_path:
return Path('conductor').resolve() return Path('conductor').resolve()
project_root = Path(project_path).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]]: def get_full_path_info() -> dict[str, dict[str, Any]]:
"""Return the resolved paths + their source (env / config / default). """Return the resolved paths + their source (env / config / default).
For diagnostic UIs (e.g., the Session Hub's "show resolved paths" panel). For diagnostic UIs (e.g., the Session Hub's "show resolved paths" panel)."""
[C: src/gui_2.py:App._render_path_field]"""
cfg = _cfg() cfg = _cfg()
def info(value: Path) -> dict[str, Any]: def info(value: Path) -> dict[str, Any]:
return {'path': str(value), 'source': 'frozen_at_init'} 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: def reset_paths() -> None:
"""Clear the singleton. FOR TESTS ONLY — production code should never """Clear the singleton. FOR TESTS ONLY — production code should never
call this. After reset, the next path getter raises RuntimeError until call this. After reset, the next path getter raises RuntimeError until
initialize_paths() is called again. 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]"""
global _PATHS_CONFIG global _PATHS_CONFIG
with _PATHS_LOCK: with _PATHS_LOCK:
_PATHS_CONFIG = None _PATHS_CONFIG = None
+4 -30
View File
@@ -79,9 +79,6 @@ class PerformanceScope:
def get_monitor() -> PerformanceMonitor: 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 global _instance
if _instance is None: if _instance is None:
_instance = PerformanceMonitor() _instance = PerformanceMonitor()
@@ -160,9 +157,6 @@ class PerformanceMonitor:
return self._history_sums[key] / len(h) return self._history_sums[key] / len(h)
def start_frame(self) -> None: def start_frame(self) -> None:
"""
[C: tests/test_performance_monitor.py:test_perf_monitor_basic_timing]
"""
now = time.perf_counter() now = time.perf_counter()
with self._lock: with self._lock:
if self._last_frame_start_time > 0: if self._last_frame_start_time > 0:
@@ -174,9 +168,6 @@ class PerformanceMonitor:
self._frame_count += 1 self._frame_count += 1
def end_frame(self) -> None: def end_frame(self) -> None:
"""
[C: tests/test_performance_monitor.py:test_perf_monitor_basic_timing]
"""
if self._start_time is None: if self._start_time is None:
return return
now = time.perf_counter() now = time.perf_counter()
@@ -205,18 +196,12 @@ class PerformanceMonitor:
self._fps_timer = 0.0 self._fps_timer = 0.0
def start_component(self, name: str) -> None: 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 if not self.enabled: return
now = time.perf_counter() now = time.perf_counter()
with self._lock: with self._lock:
self._component_starts[name] = now self._component_starts[name] = now
def end_component(self, name: str) -> None: 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 if not self.enabled: return
now = time.perf_counter() now = time.perf_counter()
with self._lock: with self._lock:
@@ -231,10 +216,7 @@ class PerformanceMonitor:
self._add_to_history(f'comp_{name}', elapsed) self._add_to_history(f'comp_{name}', elapsed)
def get_metrics(self) -> dict[str, float]: def get_metrics(self) -> dict[str, float]:
""" """Returns current metrics and their moving averages. Thread-safe."""
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]
"""
with self._lock: with self._lock:
fps = self._fps fps = self._fps
last_ft = self._last_frame_time last_ft = self._last_frame_time
@@ -267,10 +249,7 @@ class PerformanceMonitor:
return metrics return metrics
def get_history(self, key: str) -> List[float]: def get_history(self, key: str) -> List[float]:
""" """Returns a snapshot of the full history buffer for a specific metric key."""
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]
"""
with self._lock: with self._lock:
if key in self._history: if key in self._history:
return list(self._history[key]) return list(self._history[key])
@@ -279,16 +258,11 @@ class PerformanceMonitor:
return [] return []
def scope(self, name: str) -> PerformanceScope: def scope(self, name: str) -> PerformanceScope:
""" """Returns a context manager for timing a component."""
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]
"""
return PerformanceScope(self, name) return PerformanceScope(self, name)
def stop(self) -> None: 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() self._stop_event.set()
if self._cpu_thread.is_alive(): if self._cpu_thread.is_alive():
self._cpu_thread.join(timeout=2.0) self._cpu_thread.join(timeout=2.0)
+2 -17
View File
@@ -22,10 +22,7 @@ class PresetManager:
return get_project_presets_path(self.project_root) if self.project_root else Path("") return get_project_presets_path(self.project_root) if self.project_root else Path("")
def load_all(self) -> Dict[str, Preset]: def load_all(self) -> Dict[str, Preset]:
""" """Merges global and project presets into a single dictionary."""
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]
"""
presets: Dict[str, Preset] = {} presets: Dict[str, Preset] = {}
# Load global presets # Load global presets
@@ -52,10 +49,7 @@ class PresetManager:
def save_preset(self, preset: Preset, scope: str = "project") -> None: def save_preset(self, preset: Preset, scope: str = "project") -> None:
if scope == "project" and self.project_root is None: if scope == "project" and self.project_root is None:
raise ValueError("Project scope requested but no project_root provided") raise ValueError("Project scope requested but no project_root provided")
""" """Saves a preset to either the global or project-specific TOML file."""
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]
"""
path = self.global_path if scope == "global" else self.project_path path = self.global_path if scope == "global" else self.project_path
if not path: if not path:
if scope == "project": if scope == "project":
@@ -70,9 +64,6 @@ class PresetManager:
self._save_file(path, data) self._save_file(path, data)
def delete_preset(self, name: str, scope: str) -> None: 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: if scope == "project" and self.project_root:
path = get_project_presets_path(self.project_root) path = get_project_presets_path(self.project_root)
else: else:
@@ -99,9 +90,6 @@ class PresetManager:
return "project" return "project"
def _load_file(self, path: Path) -> Dict[str, Any]: 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(): if not path.exists():
return {"presets": {}} return {"presets": {}}
try: try:
@@ -117,9 +105,6 @@ class PresetManager:
return {"presets": {}} return {"presets": {}}
def _save_file(self, path: Path, data: Dict[str, Any]) -> None: 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(): if path.parent.exists() and path.parent.is_file():
raise ValueError(f"Cannot save to {path}: Parent directory {path.parent} is a file.") raise ValueError(f"Cannot save to {path}: Parent directory {path.parent} is a file.")
path.parent.mkdir(parents=True, exist_ok=True) path.parent.mkdir(parents=True, exist_ok=True)
-1
View File
@@ -122,7 +122,6 @@ def load_config_from_disk() -> Metadata:
disk I/O primitive that the controller owns. Direct callers in disk I/O primitive that the controller owns. Direct callers in
src/ are an architectural smell (bypassing the state owner) and src/ are an architectural smell (bypassing the state owner) and
will be flagged by scripts/audit_no_models_config_io.py. 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: with open(get_config_path(), "rb") as f:
return tomllib.load(f) return tomllib.load(f)
-30
View File
@@ -49,9 +49,6 @@ class FileItem:
self.custom_slices = normalized self.custom_slices = normalized
def to_dict(self) -> Metadata: 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 { return {
"path": self.path, "path": self.path,
"auto_aggregate": self.auto_aggregate, "auto_aggregate": self.auto_aggregate,
@@ -66,9 +63,6 @@ class FileItem:
@classmethod @classmethod
def from_dict(cls, data: Metadata) -> "FileItem": 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( return cls(
path = data["path"], path = data["path"],
auto_aggregate = data.get("auto_aggregate", True), auto_aggregate = data.get("auto_aggregate", True),
@@ -88,16 +82,10 @@ class Preset:
system_prompt: str system_prompt: str
def to_dict(self) -> Metadata: 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} return {"system_prompt": self.system_prompt}
@classmethod @classmethod
def from_dict(cls, name: str, data: Metadata) -> "Preset": 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", "")) return cls(name=name, system_prompt=data.get("system_prompt", ""))
@@ -111,16 +99,10 @@ class ContextFileEntry:
ast_definitions: bool = False ast_definitions: bool = False
def to_dict(self) -> Metadata: 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} 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 @classmethod
def from_dict(cls, data: Metadata) -> "ContextFileEntry": 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( return cls(
path = data.get("path", ""), path = data.get("path", ""),
view_mode = data.get("view_mode", "summary"), view_mode = data.get("view_mode", "summary"),
@@ -139,16 +121,10 @@ class NamedViewPreset:
custom_slices: list = field(default_factory=list) custom_slices: list = field(default_factory=list)
def to_dict(self) -> Metadata: 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} return {"name": self.name, "view_mode": self.view_mode, "ast_mask": self.ast_mask, "custom_slices": self.custom_slices}
@classmethod @classmethod
def from_dict(cls, data: Metadata) -> "NamedViewPreset": 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( return cls(
name = data.get("name", ""), name = data.get("name", ""),
view_mode = data.get("view_mode", "summary"), view_mode = data.get("view_mode", "summary"),
@@ -165,9 +141,6 @@ class ContextPreset:
description: str = "" description: str = ""
def to_dict(self) -> Metadata: 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 { return {
"files": [f.to_dict() for f in self.files], "files": [f.to_dict() for f in self.files],
"screenshots": self.screenshots, "screenshots": self.screenshots,
@@ -176,9 +149,6 @@ class ContextPreset:
@classmethod @classmethod
def from_dict(cls, name: str, data: Metadata) -> "ContextPreset": 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", []) files_data = data.get("files", [])
return cls( return cls(
name = name, name = name,
+4 -32
View File
@@ -50,7 +50,6 @@ def parse_ts_result(s: str) -> Result[datetime.datetime]:
def entry_to_str(entry: Metadata) -> str: def entry_to_str(entry: Metadata) -> str:
""" """
Serialise a disc entry dict -> stored string. Serialise a disc entry dict -> stored string.
[C: tests/test_thinking_persistence.py:test_entry_to_str_with_thinking]
""" """
ts = entry.get("ts", "") ts = entry.get("ts", "")
role = entry.get("role", "User") 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: def str_to_entry(raw: str, roles: list[str]) -> Metadata:
""" """
Parse a stored string back to a disc entry dict. Parse a stored string back to a disc entry dict.
[C: tests/test_thinking_persistence.py:test_str_to_entry_with_thinking]
""" """
ts = "" ts = ""
rest = raw rest = raw
@@ -116,15 +114,9 @@ def get_git_commit(git_dir: str) -> str:
# ── default structures ─────────────────────────────────────────────────────── # ── default structures ───────────────────────────────────────────────────────
def default_discussion() -> Metadata: def default_discussion() -> Metadata:
"""
[C: tests/test_discussion_takes.py:TestDiscussionTakes.test_promote_take_renames_discussion]
"""
return {"git_commit": "", "last_updated": now_ts(), "history": []} return {"git_commit": "", "last_updated": now_ts(), "history": []}
def default_project(name: str = "unnamed") -> Metadata: 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 { return {
"project": {"name": name, "git_dir": "", "system_prompt": "", "execution_mode": "native"}, "project": {"name": name, "git_dir": "", "system_prompt": "", "execution_mode": "native"},
"output": {"output_dir": "./md_gen"}, "output": {"output_dir": "./md_gen"},
@@ -177,10 +169,7 @@ def default_project(name: str = "unnamed") -> Metadata:
# ── load / save ────────────────────────────────────────────────────────────── # ── load / save ──────────────────────────────────────────────────────────────
def get_history_path(project_path: Union[str, Path]) -> Path: def get_history_path(project_path: Union[str, Path]) -> Path:
""" """Return the Path to the sibling history TOML file for a given project."""
Return the Path to the sibling history TOML file for a given project.
[C: tests/test_history_management.py:test_save_separation]
"""
p = Path(project_path) p = Path(project_path)
return p.parent / f"{p.stem}_history.toml" 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. Load a project TOML file.
Automatically migrates legacy 'discussion' keys to a sibling history 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) with open(path, "rb") as f: proj = tomllib.load(f)
# Deserialise FileItems in files.paths # Deserialise FileItems in files.paths
@@ -208,10 +196,7 @@ def load_project(path: Union[str, Path]) -> Metadata:
return proj return proj
def load_history(project_path: Union[str, Path]) -> Metadata: def load_history(project_path: Union[str, Path]) -> Metadata:
""" """Load the segregated discussion history from its dedicated TOML file."""
Load the segregated discussion history from its dedicated TOML file.
[C: tests/test_thinking_persistence.py:test_save_and_load_history_with_thinking_segments]
"""
hist_path = get_history_path(project_path) hist_path = get_history_path(project_path)
if hist_path.exists(): if hist_path.exists():
with open(hist_path, "rb") as f: with open(hist_path, "rb") as f:
@@ -219,10 +204,7 @@ def load_history(project_path: Union[str, Path]) -> Metadata:
return {} return {}
def clean_nones(data: Any) -> Any: def clean_nones(data: Any) -> Any:
""" """Recursively remove None values from a dictionary/list."""
Recursively remove None values from a dictionary/list.
[C: tests/test_thinking_persistence.py:test_clean_nones_removes_thinking]
"""
if isinstance(data, dict): return {k: clean_nones(v) for k, v in data.items() if v is not None} 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] elif isinstance(data, list): return [clean_nones(v) for v in data if v is not None]
return data return data
@@ -231,7 +213,6 @@ def save_project(proj: Metadata, path: Union[str, Path], disc_data: Optional[Met
""" """
Save the project TOML. Save the project TOML.
If 'discussion' is present in proj, it is moved to the sibling history file. 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) proj = clean_nones(proj)
# Serialise FileItems # Serialise FileItems
@@ -305,10 +286,7 @@ def flat_config(proj: Metadata, disc_name: Optional[str] = None, track_id: Optio
# ── track state persistence ───────────────────────────────────────────────── # ── track state persistence ─────────────────────────────────────────────────
def save_track_state(track_id: str, state: 'TrackState', base_dir: Union[str, Path] = ".") -> None: 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."""
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]
"""
track_dir = paths.get_track_state_dir(track_id, project_path=str(base_dir)) track_dir = paths.get_track_state_dir(track_id, project_path=str(base_dir))
track_dir.mkdir(parents=True, exist_ok=True) track_dir.mkdir(parents=True, exist_ok=True)
state_file = track_dir / "state.toml" 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. Loads a TrackState object from conductor/tracks/<track_id>/state.toml.
Returns empty TrackState (zero-init) if not found. 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 from src.mma import TrackState, EMPTY_TRACK_STATE
state_file = paths.get_track_state_dir(track_id, project_path=str(base_dir)) / 'state.toml' 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 Each returned dict includes an 'errors' list (list[ErrorInfo]) for any
per-track metadata recovery that occurred. Callers can ignore the errors per-track metadata recovery that occurred. Callers can ignore the errors
field for display purposes; the metadata is best-effort. 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)) tracks_dir = paths.get_tracks_dir(project_path=str(base_dir))
if not tracks_dir.exists(): return [] if not tracks_dir.exists(): return []
@@ -440,7 +415,6 @@ def calculate_track_progress(tickets: list) -> dict:
""" """
Calculates track progress based on ticket statuses. Calculates track progress based on ticket statuses.
percentage (float), completed (int), total (int), in_progress (int), blocked (int), todo (int) 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) total = len(tickets)
if total == 0: 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 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. 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 "discussion" not in project_dict or "discussions" not in project_dict["discussion"]: return
if source_id not in project_dict["discussion"]["discussions"]: 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: def promote_take(project_dict: dict, take_id: str, new_id: str) -> None:
""" """
Renames a take_id to new_id in the discussions dict. 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 "discussion" not in project_dict or "discussions" not in project_dict["discussion"]: return
if take_id not in project_dict["discussion"]["discussions"]: return if take_id not in project_dict["discussion"]["discussions"]: return
-9
View File
@@ -227,9 +227,6 @@ class RAGEngine:
return self.collection.count() == 0 return self.collection.count() == 0
def add_documents(self, ids: List[str], texts: List[str], metadatas: Optional[List[Dict[str, Any]]] = None): 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": if not self.config.enabled or self.collection == "mock":
return return
embeddings = self.embedding_provider.embed(texts) embeddings = self.embedding_provider.embed(texts)
@@ -389,9 +386,6 @@ class RAGEngine:
return asyncio.run(_async_search_mcp()) return asyncio.run(_async_search_mcp())
def search(self, query: str, top_k: int = 5) -> List["RAGChunk"]: 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 not self.config.enabled: return []
if self.config.vector_store.provider == 'mcp': return self._search_mcp(query, top_k) if self.config.vector_store.provider == 'mcp': return self._search_mcp(query, top_k)
if self.collection == "mock": return [] if self.collection == "mock": return []
@@ -418,9 +412,6 @@ class RAGEngine:
return ret return ret
def delete_documents(self, ids: List[str]): 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": if not self.config.enabled or self.collection == "mock":
return return
self.collection.delete(ids=ids) self.collection.delete(ids=ids)
+1 -7
View File
@@ -61,7 +61,6 @@ def open_session(label: Optional[str] = None) -> None:
""" """
Called once at GUI startup. Creates the log directories if needed and Called once at GUI startup. Creates the log directories if needed and
opens the log files for this session within a sub-directory. 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 global _ts, _session_id, _session_dir, _comms_fh, _tool_fh, _api_fh, _cli_fh, _seq, _output_seq
if _comms_fh is not None: if _comms_fh is not None:
@@ -103,10 +102,7 @@ def open_session(label: Optional[str] = None) -> None:
atexit.register(close_session) atexit.register(close_session)
def close_session() -> None: def close_session() -> None:
""" """Flush and close all log files. Called on clean exit."""
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]
"""
global _comms_fh, _tool_fh, _api_fh, _cli_fh, _session_id global _comms_fh, _tool_fh, _api_fh, _cli_fh, _session_id
if _comms_fh is None: if _comms_fh is None:
return 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. Append one comms entry to the comms log file as a JSON-L line.
Thread-safe (GIL + line-buffered file). Thread-safe (GIL + line-buffered file).
[C: tests/test_logging_e2e.py:test_logging_e2e]
""" """
if _comms_fh is None: if _comms_fh is None:
return Result(data=False) 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 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. 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 global _seq
if _tool_fh is None: if _tool_fh is None:
-1
View File
@@ -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, 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. 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. 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("'", "''") safe_dir: str = str(base_dir).replace("'", "''")
full_script: str = f"Set-Location -LiteralPath '{safe_dir}'\n{script}" full_script: str = f"Set-Location -LiteralPath '{safe_dir}'\n{script}"
-1
View File
@@ -160,7 +160,6 @@ def summarise_file(path: Path, content: str) -> str:
""" """
Return a compact markdown summary string for a single file. Return a compact markdown summary string for a single file.
`content` is the already-read file text (or an error string). `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) content_hash = get_file_hash(content)
cached = _summary_cache.get_summary(str(path), content_hash) cached = _summary_cache.get_summary(str(path), content_hash)
+5 -20
View File
@@ -8,10 +8,7 @@ from src.result_types import Result, ErrorInfo, ErrorKind
def get_file_hash(content: str) -> str: def get_file_hash(content: str) -> str:
""" """Returns SHA256 hash of the content."""
Returns SHA256 hash of the content.
[C: tests/test_summary_cache.py:test_get_file_hash, tests/test_summary_cache.py:test_summary_cache]
"""
return hashlib.sha256(content.encode("utf-8")).hexdigest() return hashlib.sha256(content.encode("utf-8")).hexdigest()
class SummaryCache: class SummaryCache:
@@ -30,10 +27,7 @@ class SummaryCache:
self.load() self.load()
def load(self) -> Result[bool]: def load(self) -> Result[bool]:
""" """Loads cache from disk."""
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]
"""
if not self.cache_file.exists(): if not self.cache_file.exists():
return Result(data=False) return Result(data=False)
try: 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)]) 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: def get_summary(self, file_path: str, content_hash: str) -> str:
""" """Returns cached summary if hash matches, otherwise ""."""
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]
"""
entry = self.cache.get(file_path) entry = self.cache.get(file_path)
if entry and entry.get("hash") == content_hash: if entry and entry.get("hash") == content_hash:
# LRU: move to end # LRU: move to end
@@ -68,10 +59,7 @@ class SummaryCache:
return "" return ""
def set_summary(self, file_path: str, content_hash: str, summary: str) -> None: def set_summary(self, file_path: str, content_hash: str, summary: str) -> None:
""" """Stores summary in cache and saves to disk."""
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]
"""
if file_path in self.cache: if file_path in self.cache:
self.cache.pop(file_path) self.cache.pop(file_path)
self.cache[file_path] = { self.cache[file_path] = {
@@ -86,10 +74,7 @@ class SummaryCache:
self.save() self.save()
def clear(self) -> Result[bool]: def clear(self) -> Result[bool]:
""" """Clears the cache both in-memory and on disk."""
Clears the cache both in-memory and on disk.
[C: tests/conftest.py:reset_ai_client]
"""
self.cache.clear() self.cache.clear()
if not self.cache_file.exists(): if not self.cache_file.exists():
return Result(data=True) return Result(data=True)
-3
View File
@@ -2,9 +2,6 @@ from src.type_aliases import HistoryMessage
def format_takes_diff(takes: dict[str, list[dict]]) -> str: 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: if not takes:
return "" return ""
+1 -4
View File
@@ -63,10 +63,7 @@ NERV_PALETTE = {
} }
def apply_nerv() -> None: def apply_nerv() -> None:
""" """Apply NERV theme with hard edges and specific palette."""
Apply NERV theme with hard edges and specific palette.
[C: tests/test_theme_nerv.py:test_apply_nerv_sets_rounding_and_colors]
"""
style = imgui.get_style() style = imgui.get_style()
for col_enum, rgba in NERV_PALETTE.items(): for col_enum, rgba in NERV_PALETTE.items():
style.set_color_(col_enum, imgui.ImVec4(*rgba)) style.set_color_(col_enum, imgui.ImVec4(*rgba))
-12
View File
@@ -10,9 +10,6 @@ class CRTFilter:
self.enabled = True self.enabled = True
def render(self, width: float, height: float): 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 if not self.enabled: return
draw_list = imgui.get_foreground_draw_list() draw_list = imgui.get_foreground_draw_list()
@@ -67,9 +64,6 @@ class CRTFilter:
class StatusFlicker: class StatusFlicker:
def get_alpha(self) -> float: def get_alpha(self) -> float:
# Modulate between 0.7 and 1.0 using sin wave # 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) return 0.85 + 0.15 * math.sin(time.time() * 20.0)
class AlertPulsing: class AlertPulsing:
@@ -77,15 +71,9 @@ class AlertPulsing:
self.active = False self.active = False
def update(self, status: str): 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") self.active = status.lower().startswith("error")
def render(self, width: float, height: float): 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: if not self.active:
return return
draw_list = imgui.get_foreground_draw_list() draw_list = imgui.get_foreground_draw_list()
-1
View File
@@ -10,7 +10,6 @@ def parse_thinking_trace(text: str) -> Tuple[List[ThinkingSegment], str]:
Parses thinking segments from text and returns (segments, response_content). Parses thinking segments from text and returns (segments, response_content).
Support extraction of thinking traces from <thinking>...</thinking>, <thought>...</thought>, Support extraction of thinking traces from <thinking>...</thinking>, <thought>...</thought>,
<think>...</think> (half-width form), and blocks prefixed with Thinking:. <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 = [] segments = []
-6
View File
@@ -31,9 +31,6 @@ class 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]]:
"""
[C: tests/test_tool_bias.py:test_apply_semantic_nudges, tests/test_tool_bias.py:test_parameter_bias_nudging]
"""
weight_map = { weight_map = {
5: "[HIGH PRIORITY] ", 5: "[HIGH PRIORITY] ",
4: "[PREFERRED] ", 4: "[PREFERRED] ",
@@ -67,9 +64,6 @@ class ToolBiasEngine:
return tool_definitions return tool_definitions
def generate_tooling_strategy(self, preset: ToolPreset, global_bias: BiasProfile) -> str: def generate_tooling_strategy(self, preset: ToolPreset, global_bias: BiasProfile) -> str:
"""
[C: tests/test_tool_bias.py:test_generate_tooling_strategy]
"""
lines = ["### Tooling Strategy"] lines = ["### Tooling Strategy"]
preferred = [] preferred = []
+1 -25
View File
@@ -60,9 +60,6 @@ class ToolPresetManager:
self.project_root = Path(project_root) if project_root else None self.project_root = Path(project_root) if project_root else None
def _get_path(self, scope: str) -> Path: 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": if scope == "global":
return paths.get_global_tool_presets_path() return paths.get_global_tool_presets_path()
elif scope == "project": elif scope == "project":
@@ -89,9 +86,6 @@ class ToolPresetManager:
tomli_w.dump(data, f) tomli_w.dump(data, f)
def load_all_presets(self) -> Dict[str, ToolPreset]: 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_path = paths.get_global_tool_presets_path()
global_data = self._read_raw(global_path).get("presets", {}) global_data = self._read_raw(global_path).get("presets", {})
@@ -110,16 +104,10 @@ class ToolPresetManager:
return presets return presets
def load_all(self) -> Dict[str, ToolPreset]: def load_all(self) -> Dict[str, ToolPreset]:
""" """Backward compatibility for load_all()."""
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]
"""
return self.load_all_presets() return self.load_all_presets()
def save_preset(self, preset: ToolPreset, scope: str = "project") -> None: 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) path = self._get_path(scope)
data = self._read_raw(path) data = self._read_raw(path)
if "presets" not in data: if "presets" not in data:
@@ -128,9 +116,6 @@ class ToolPresetManager:
self._write_raw(path, data) self._write_raw(path, data)
def delete_preset(self, name: str, scope: str = "project") -> None: 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) path = self._get_path(scope)
data = self._read_raw(path) data = self._read_raw(path)
if "presets" in data and name in data["presets"]: if "presets" in data and name in data["presets"]:
@@ -138,9 +123,6 @@ class ToolPresetManager:
self._write_raw(path, data) self._write_raw(path, data)
def load_all_bias_profiles(self) -> Dict[str, "BiasProfile"]: 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 from src.tool_bias import BiasProfile
global_path = paths.get_global_tool_presets_path() global_path = paths.get_global_tool_presets_path()
global_data = self._read_raw(global_path).get("bias_profiles", {}) global_data = self._read_raw(global_path).get("bias_profiles", {})
@@ -166,9 +148,6 @@ class ToolPresetManager:
return profiles return profiles
def save_bias_profile(self, profile: BiasProfile, scope: str = "project") -> None: 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) path = self._get_path(scope)
data = self._read_raw(path) data = self._read_raw(path)
if "bias_profiles" not in data: if "bias_profiles" not in data:
@@ -177,9 +156,6 @@ class ToolPresetManager:
self._write_raw(path, data) self._write_raw(path, data)
def delete_bias_profile(self, name: str, scope: str = "project") -> None: 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) path = self._get_path(scope)
data = self._read_raw(path) data = self._read_raw(path)
if "bias_profiles" in data and name in data["bias_profiles"]: if "bias_profiles" in data and name in data["bias_profiles"]:
+1 -10
View File
@@ -52,10 +52,7 @@ class WorkspaceManager:
raise ValueError("Invalid scope, must be 'global' or 'project'") raise ValueError("Invalid scope, must be 'global' or 'project'")
def load_all_profiles(self) -> Dict[str, WorkspaceProfile]: def load_all_profiles(self) -> Dict[str, WorkspaceProfile]:
""" """Merges global and project profiles into a single dictionary."""
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]
"""
profiles = {} profiles = {}
global_path = paths.get_global_workspace_profiles_path() global_path = paths.get_global_workspace_profiles_path()
@@ -72,9 +69,6 @@ class WorkspaceManager:
return profiles return profiles
def save_profile(self, profile: WorkspaceProfile, scope: str = "project") -> None: 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) path = self._get_path(scope)
data = self._load_file(path) data = self._load_file(path)
if "profiles" not in data: if "profiles" not in data:
@@ -84,9 +78,6 @@ class WorkspaceManager:
self._save_file(path, data) self._save_file(path, data)
def delete_profile(self, name: str, scope: str = "project") -> None: def delete_profile(self, name: str, scope: str = "project") -> None:
"""
[C: tests/test_workspace_manager.py:test_delete_profile]
"""
path = self._get_path(scope) path = self._get_path(scope)
data = self._load_file(path) data = self._load_file(path)
if "profiles" in data and name in data["profiles"]: if "profiles" in data and name in data["profiles"]: