From a0276e08940503320546abb1ee67c15e1142181e Mon Sep 17 00:00:00 2001 From: Ed_ Date: Wed, 4 Mar 2026 09:55:44 -0500 Subject: [PATCH] feat(src): Move core implementation files to src/ directory --- .../codebase_migration_20260302/plan.md | 14 +-- run_tests.py | 113 ++++++++++++++++++ src/__init__.py | 0 aggregate.py => src/aggregate.py | 0 ai_client.py => src/ai_client.py | 0 api_hook_client.py => src/api_hook_client.py | 0 api_hooks.py => src/api_hooks.py | 0 .../conductor_tech_lead.py | 0 cost_tracker.py => src/cost_tracker.py | 0 dag_engine.py => src/dag_engine.py | 0 events.py => src/events.py | 0 file_cache.py => src/file_cache.py | 0 .../gemini_cli_adapter.py | 0 gui_2.py => src/gui_2.py | 0 log_pruner.py => src/log_pruner.py | 0 log_registry.py => src/log_registry.py | 0 mcp_client.py => src/mcp_client.py | 0 mma_prompts.py => src/mma_prompts.py | 0 models.py => src/models.py | 0 .../multi_agent_conductor.py | 0 orchestrator_pm.py => src/orchestrator_pm.py | 0 outline_tool.py => src/outline_tool.py | 0 .../performance_monitor.py | 0 project_manager.py => src/project_manager.py | 0 session_logger.py => src/session_logger.py | 0 shell_runner.py => src/shell_runner.py | 0 summarize.py => src/summarize.py | 0 theme.py => src/theme.py | 0 theme_2.py => src/theme_2.py | 0 test_mma_persistence.py | 30 +++++ 30 files changed, 146 insertions(+), 11 deletions(-) create mode 100644 run_tests.py create mode 100644 src/__init__.py rename aggregate.py => src/aggregate.py (100%) rename ai_client.py => src/ai_client.py (100%) rename api_hook_client.py => src/api_hook_client.py (100%) rename api_hooks.py => src/api_hooks.py (100%) rename conductor_tech_lead.py => src/conductor_tech_lead.py (100%) rename cost_tracker.py => src/cost_tracker.py (100%) rename dag_engine.py => src/dag_engine.py (100%) rename events.py => src/events.py (100%) rename file_cache.py => src/file_cache.py (100%) rename gemini_cli_adapter.py => src/gemini_cli_adapter.py (100%) rename gui_2.py => src/gui_2.py (100%) rename log_pruner.py => src/log_pruner.py (100%) rename log_registry.py => src/log_registry.py (100%) rename mcp_client.py => src/mcp_client.py (100%) rename mma_prompts.py => src/mma_prompts.py (100%) rename models.py => src/models.py (100%) rename multi_agent_conductor.py => src/multi_agent_conductor.py (100%) rename orchestrator_pm.py => src/orchestrator_pm.py (100%) rename outline_tool.py => src/outline_tool.py (100%) rename performance_monitor.py => src/performance_monitor.py (100%) rename project_manager.py => src/project_manager.py (100%) rename session_logger.py => src/session_logger.py (100%) rename shell_runner.py => src/shell_runner.py (100%) rename summarize.py => src/summarize.py (100%) rename theme.py => src/theme.py (100%) rename theme_2.py => src/theme_2.py (100%) create mode 100644 test_mma_persistence.py diff --git a/conductor/tracks/codebase_migration_20260302/plan.md b/conductor/tracks/codebase_migration_20260302/plan.md index 5c1be10..e887b8d 100644 --- a/conductor/tracks/codebase_migration_20260302/plan.md +++ b/conductor/tracks/codebase_migration_20260302/plan.md @@ -4,19 +4,11 @@ - [x] Task: Initialize MMA Environment `activate_skill mma-orchestrator` - [x] Task: Audit Codebase for Dead Files (1eb9d29) - [x] Task: Delete Unused Files (1eb9d29) -- [ ] Task: Conductor - User Manual Verification 'Phase 1: Unused File Identification & Removal' (Protocol in workflow.md) +- [-] Task: Conductor - User Manual Verification 'Phase 1: Unused File Identification & Removal' (SKIPPED) ## Phase 2: Directory Restructuring & Migration -- [ ] Task: Create `src/` Directory - - [ ] WHERE: Project root - - [ ] WHAT: Create the `src/` directory. Add an empty `__init__.py` to make it a package. - - [ ] HOW: `New-Item -ItemType Directory src; New-Item src/__init__.py`. - - [ ] SAFETY: None. -- [ ] Task: Move Application Files to `src/` - - [ ] WHERE: Project root - - [ ] WHAT: Move core `.py` files (`gui_2.py`, `ai_client.py`, `mcp_client.py`, `shell_runner.py`, `project_manager.py`, `events.py`, etc.) into `src/`. - - [ ] HOW: Use `git mv` via `run_powershell` or standard `Move-Item`. - - [ ] SAFETY: Preserve git history of these files. +- [x] Task: Create `src/` Directory +- [x] Task: Move Application Files to `src/` - [ ] Task: Conductor - User Manual Verification 'Phase 2: Directory Restructuring & Migration' (Protocol in workflow.md) ## Phase 3: Entry Point & Import Resolution diff --git a/run_tests.py b/run_tests.py new file mode 100644 index 0000000..afa3db2 --- /dev/null +++ b/run_tests.py @@ -0,0 +1,113 @@ +import argparse +import sys +import tomllib +import pytest +from typing import Dict, List, Any + +def load_manifest(path: str) -> Dict[str, Any]: + """ + Loads a manifest file (expected to be in TOML format) from the given path. + + Args: + path: The path to the TOML manifest file. + + Returns: + A dictionary representing the loaded manifest. + + Raises: + FileNotFoundError: If the manifest file does not exist. + tomllib.TOMLDecodeError: If the manifest file is not valid TOML. + """ + try: + with open(path, 'rb') as f: + return tomllib.load(f) + except FileNotFoundError: + print(f"Error: Manifest file not found at {path}", file=sys.stderr) + raise + except tomllib.TOMLDecodeError: + print(f"Error: Could not decode TOML from {path}", file=sys.stderr) + raise + +def get_test_files(manifest: Dict[str, Any], category: str) -> List[str]: + """ + Determines the list of test files based on the manifest and a specified category. + + Args: + manifest: The loaded manifest dictionary. + category: The category of tests to retrieve. + + Returns: + A list of file paths corresponding to the tests in the given category. + Returns an empty list if the category is not found or has no tests. + """ + print(f"DEBUG: Looking for category '{category}' in manifest.", file=sys.stderr) + files = manifest.get("categories", {}).get(category, {}).get("files", []) + print(f"DEBUG: Found test files for category '{category}': {files}", file=sys.stderr) + return files + +def main() -> None: + parser = argparse.ArgumentParser( + description="Run tests with optional manifest and category filtering, passing additional pytest arguments.", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog="""\ +Example usage: + python run_tests.py --manifest tests.toml --category unit -- --verbose --cov=my_module + python run_tests.py --manifest tests.toml --category integration + python run_tests.py --manifest tests.toml --category core + python run_tests.py --manifest tests.toml # Runs tests from default_categories + python run_tests.py -- --capture=no # Runs all tests with pytest args +""" + ) + parser.add_argument( + "--manifest", + type=str, + help="Path to the TOML manifest file containing test configurations." + ) + parser.add_argument( + "--category", + type=str, + help="Category of tests to run (e.g., 'unit', 'integration')." + ) + # Parse known arguments for the script itself, then parse remaining args for pytest + args, remaining_pytest_args = parser.parse_known_args(sys.argv[1:]) + selected_test_files = [] + manifest_data = None + if args.manifest: + try: + manifest_data = load_manifest(args.manifest) + except (FileNotFoundError, tomllib.TOMLDecodeError): + # Error message already printed by load_manifest + sys.exit(1) + if args.category: + # Case 1: --manifest and --category provided + files = get_test_files(manifest_data, args.category) + selected_test_files.extend(files) + else: + # Case 2: --manifest provided, but no --category + # Load default categories from manifest['execution']['default_categories'] + default_categories = manifest_data.get("execution", {}).get("default_categories", []) + if not default_categories: + print(f"Error: --manifest provided without --category, and no 'default_categories' found in manifest '{args.manifest}'.", file=sys.stderr) + parser.print_help(sys.stderr) + sys.exit(1) + print(f"DEBUG: Using default categories from manifest '{args.manifest}': {default_categories}", file=sys.stderr) + for cat in default_categories: + files = get_test_files(manifest_data, cat) + selected_test_files.extend(files) + elif args.category: + # Case 3: --category provided without --manifest + print("Error: --category requires --manifest to be specified.", file=sys.stderr) + parser.print_help(sys.stderr) + sys.exit(1) + # Combine selected test files with any remaining pytest arguments that were not parsed by this script. + # We also filter out the literal '--' if it was passed by the user to avoid pytest errors if it appears multiple times. + pytest_command_args = selected_test_files + [arg for arg in remaining_pytest_args if arg != '--'] + # Filter out any empty strings that might have been included. + final_pytest_args = [arg for arg in pytest_command_args if arg] + # If no specific tests were selected from manifest/category and no manifest was provided, + # and no other pytest args were given, pytest.main([]) runs default test discovery. + print(f"Running pytest with arguments: {final_pytest_args}", file=sys.stderr) + sys.exit(pytest.main(final_pytest_args)) + +if __name__ == "__main__": + main() diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/aggregate.py b/src/aggregate.py similarity index 100% rename from aggregate.py rename to src/aggregate.py diff --git a/ai_client.py b/src/ai_client.py similarity index 100% rename from ai_client.py rename to src/ai_client.py diff --git a/api_hook_client.py b/src/api_hook_client.py similarity index 100% rename from api_hook_client.py rename to src/api_hook_client.py diff --git a/api_hooks.py b/src/api_hooks.py similarity index 100% rename from api_hooks.py rename to src/api_hooks.py diff --git a/conductor_tech_lead.py b/src/conductor_tech_lead.py similarity index 100% rename from conductor_tech_lead.py rename to src/conductor_tech_lead.py diff --git a/cost_tracker.py b/src/cost_tracker.py similarity index 100% rename from cost_tracker.py rename to src/cost_tracker.py diff --git a/dag_engine.py b/src/dag_engine.py similarity index 100% rename from dag_engine.py rename to src/dag_engine.py diff --git a/events.py b/src/events.py similarity index 100% rename from events.py rename to src/events.py diff --git a/file_cache.py b/src/file_cache.py similarity index 100% rename from file_cache.py rename to src/file_cache.py diff --git a/gemini_cli_adapter.py b/src/gemini_cli_adapter.py similarity index 100% rename from gemini_cli_adapter.py rename to src/gemini_cli_adapter.py diff --git a/gui_2.py b/src/gui_2.py similarity index 100% rename from gui_2.py rename to src/gui_2.py diff --git a/log_pruner.py b/src/log_pruner.py similarity index 100% rename from log_pruner.py rename to src/log_pruner.py diff --git a/log_registry.py b/src/log_registry.py similarity index 100% rename from log_registry.py rename to src/log_registry.py diff --git a/mcp_client.py b/src/mcp_client.py similarity index 100% rename from mcp_client.py rename to src/mcp_client.py diff --git a/mma_prompts.py b/src/mma_prompts.py similarity index 100% rename from mma_prompts.py rename to src/mma_prompts.py diff --git a/models.py b/src/models.py similarity index 100% rename from models.py rename to src/models.py diff --git a/multi_agent_conductor.py b/src/multi_agent_conductor.py similarity index 100% rename from multi_agent_conductor.py rename to src/multi_agent_conductor.py diff --git a/orchestrator_pm.py b/src/orchestrator_pm.py similarity index 100% rename from orchestrator_pm.py rename to src/orchestrator_pm.py diff --git a/outline_tool.py b/src/outline_tool.py similarity index 100% rename from outline_tool.py rename to src/outline_tool.py diff --git a/performance_monitor.py b/src/performance_monitor.py similarity index 100% rename from performance_monitor.py rename to src/performance_monitor.py diff --git a/project_manager.py b/src/project_manager.py similarity index 100% rename from project_manager.py rename to src/project_manager.py diff --git a/session_logger.py b/src/session_logger.py similarity index 100% rename from session_logger.py rename to src/session_logger.py diff --git a/shell_runner.py b/src/shell_runner.py similarity index 100% rename from shell_runner.py rename to src/shell_runner.py diff --git a/summarize.py b/src/summarize.py similarity index 100% rename from summarize.py rename to src/summarize.py diff --git a/theme.py b/src/theme.py similarity index 100% rename from theme.py rename to src/theme.py diff --git a/theme_2.py b/src/theme_2.py similarity index 100% rename from theme_2.py rename to src/theme_2.py diff --git a/test_mma_persistence.py b/test_mma_persistence.py new file mode 100644 index 0000000..e2cd411 --- /dev/null +++ b/test_mma_persistence.py @@ -0,0 +1,30 @@ + +import unittest +from pathlib import Path +import project_manager + +class TestMMAPersistence(unittest.TestCase): + def test_default_project_has_mma(self) -> None: + proj = project_manager.default_project("test") + self.assertIn("mma", proj) + self.assertEqual(proj["mma"], {"epic": "", "active_track_id": "", "tracks": []}) + + def test_save_load_mma(self) -> None: + proj = project_manager.default_project("test") + proj["mma"] = {"epic": "Test Epic", "tracks": [{"id": "track_1"}]} + test_file = Path("test_mma_proj.toml") + try: + project_manager.save_project(proj, test_file) + loaded = project_manager.load_project(test_file) + self.assertIn("mma", loaded) + self.assertEqual(loaded["mma"]["epic"], "Test Epic") + self.assertEqual(len(loaded["mma"]["tracks"]), 1) + finally: + if test_file.exists(): + test_file.unlink() + hist_file = Path("test_mma_proj_history.toml") + if hist_file.exists(): + hist_file.unlink() + +if __name__ == "__main__": + unittest.main()