claude-mpm 3.9.11__py3-none-any.whl → 4.0.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- claude_mpm/VERSION +1 -1
- claude_mpm/__init__.py +2 -2
- claude_mpm/__main__.py +3 -2
- claude_mpm/agents/__init__.py +85 -79
- claude_mpm/agents/agent_loader.py +464 -1003
- claude_mpm/agents/agent_loader_integration.py +45 -45
- claude_mpm/agents/agents_metadata.py +29 -30
- claude_mpm/agents/async_agent_loader.py +156 -138
- claude_mpm/agents/base_agent.json +1 -1
- claude_mpm/agents/base_agent_loader.py +179 -151
- claude_mpm/agents/frontmatter_validator.py +229 -130
- claude_mpm/agents/schema/agent_schema.json +1 -1
- claude_mpm/agents/system_agent_config.py +213 -147
- claude_mpm/agents/templates/__init__.py +13 -13
- claude_mpm/agents/templates/code_analyzer.json +2 -2
- claude_mpm/agents/templates/data_engineer.json +1 -1
- claude_mpm/agents/templates/documentation.json +23 -11
- claude_mpm/agents/templates/engineer.json +22 -6
- claude_mpm/agents/templates/memory_manager.json +1 -1
- claude_mpm/agents/templates/ops.json +2 -2
- claude_mpm/agents/templates/project_organizer.json +1 -1
- claude_mpm/agents/templates/qa.json +1 -1
- claude_mpm/agents/templates/refactoring_engineer.json +222 -0
- claude_mpm/agents/templates/research.json +20 -14
- claude_mpm/agents/templates/security.json +1 -1
- claude_mpm/agents/templates/ticketing.json +2 -2
- claude_mpm/agents/templates/version_control.json +1 -1
- claude_mpm/agents/templates/web_qa.json +3 -1
- claude_mpm/agents/templates/web_ui.json +2 -2
- claude_mpm/cli/__init__.py +79 -51
- claude_mpm/cli/__main__.py +3 -2
- claude_mpm/cli/commands/__init__.py +20 -20
- claude_mpm/cli/commands/agents.py +279 -247
- claude_mpm/cli/commands/aggregate.py +138 -157
- claude_mpm/cli/commands/cleanup.py +147 -147
- claude_mpm/cli/commands/config.py +93 -76
- claude_mpm/cli/commands/info.py +17 -16
- claude_mpm/cli/commands/mcp.py +140 -905
- claude_mpm/cli/commands/mcp_command_router.py +139 -0
- claude_mpm/cli/commands/mcp_config_commands.py +20 -0
- claude_mpm/cli/commands/mcp_install_commands.py +20 -0
- claude_mpm/cli/commands/mcp_server_commands.py +175 -0
- claude_mpm/cli/commands/mcp_tool_commands.py +34 -0
- claude_mpm/cli/commands/memory.py +239 -203
- claude_mpm/cli/commands/monitor.py +330 -86
- claude_mpm/cli/commands/run.py +380 -429
- claude_mpm/cli/commands/run_config_checker.py +160 -0
- claude_mpm/cli/commands/socketio_monitor.py +235 -0
- claude_mpm/cli/commands/tickets.py +363 -220
- claude_mpm/cli/parser.py +24 -1156
- claude_mpm/cli/parsers/__init__.py +29 -0
- claude_mpm/cli/parsers/agents_parser.py +136 -0
- claude_mpm/cli/parsers/base_parser.py +331 -0
- claude_mpm/cli/parsers/config_parser.py +85 -0
- claude_mpm/cli/parsers/mcp_parser.py +152 -0
- claude_mpm/cli/parsers/memory_parser.py +138 -0
- claude_mpm/cli/parsers/monitor_parser.py +124 -0
- claude_mpm/cli/parsers/run_parser.py +147 -0
- claude_mpm/cli/parsers/tickets_parser.py +203 -0
- claude_mpm/cli/ticket_cli.py +7 -3
- claude_mpm/cli/utils.py +55 -37
- claude_mpm/cli_module/__init__.py +6 -6
- claude_mpm/cli_module/args.py +188 -140
- claude_mpm/cli_module/commands.py +79 -70
- claude_mpm/cli_module/migration_example.py +38 -60
- claude_mpm/config/__init__.py +32 -25
- claude_mpm/config/agent_config.py +151 -119
- claude_mpm/config/experimental_features.py +71 -73
- claude_mpm/config/paths.py +94 -208
- claude_mpm/config/socketio_config.py +84 -73
- claude_mpm/constants.py +35 -18
- claude_mpm/core/__init__.py +9 -6
- claude_mpm/core/agent_name_normalizer.py +68 -71
- claude_mpm/core/agent_registry.py +372 -521
- claude_mpm/core/agent_session_manager.py +74 -63
- claude_mpm/core/base_service.py +116 -87
- claude_mpm/core/cache.py +119 -153
- claude_mpm/core/claude_runner.py +425 -1120
- claude_mpm/core/config.py +263 -168
- claude_mpm/core/config_aliases.py +69 -61
- claude_mpm/core/config_constants.py +292 -0
- claude_mpm/core/constants.py +57 -99
- claude_mpm/core/container.py +211 -178
- claude_mpm/core/exceptions.py +233 -89
- claude_mpm/core/factories.py +92 -54
- claude_mpm/core/framework_loader.py +378 -220
- claude_mpm/core/hook_manager.py +198 -83
- claude_mpm/core/hook_performance_config.py +136 -0
- claude_mpm/core/injectable_service.py +61 -55
- claude_mpm/core/interactive_session.py +165 -155
- claude_mpm/core/interfaces.py +221 -195
- claude_mpm/core/lazy.py +96 -96
- claude_mpm/core/logger.py +133 -107
- claude_mpm/core/logging_config.py +185 -157
- claude_mpm/core/minimal_framework_loader.py +20 -15
- claude_mpm/core/mixins.py +30 -29
- claude_mpm/core/oneshot_session.py +215 -181
- claude_mpm/core/optimized_agent_loader.py +134 -138
- claude_mpm/core/optimized_startup.py +159 -157
- claude_mpm/core/pm_hook_interceptor.py +85 -72
- claude_mpm/core/service_registry.py +103 -101
- claude_mpm/core/session_manager.py +97 -87
- claude_mpm/core/socketio_pool.py +212 -158
- claude_mpm/core/tool_access_control.py +58 -51
- claude_mpm/core/types.py +46 -24
- claude_mpm/core/typing_utils.py +166 -82
- claude_mpm/core/unified_agent_registry.py +721 -0
- claude_mpm/core/unified_config.py +550 -0
- claude_mpm/core/unified_paths.py +549 -0
- claude_mpm/dashboard/index.html +1 -1
- claude_mpm/dashboard/open_dashboard.py +51 -17
- claude_mpm/dashboard/static/built/components/agent-inference.js +2 -0
- claude_mpm/dashboard/static/built/components/event-processor.js +2 -0
- claude_mpm/dashboard/static/built/components/event-viewer.js +2 -0
- claude_mpm/dashboard/static/built/components/export-manager.js +2 -0
- claude_mpm/dashboard/static/built/components/file-tool-tracker.js +2 -0
- claude_mpm/dashboard/static/built/components/hud-library-loader.js +2 -0
- claude_mpm/dashboard/static/built/components/hud-manager.js +2 -0
- claude_mpm/dashboard/static/built/components/hud-visualizer.js +2 -0
- claude_mpm/dashboard/static/built/components/module-viewer.js +2 -0
- claude_mpm/dashboard/static/built/components/session-manager.js +2 -0
- claude_mpm/dashboard/static/built/components/socket-manager.js +2 -0
- claude_mpm/dashboard/static/built/components/ui-state-manager.js +2 -0
- claude_mpm/dashboard/static/built/components/working-directory.js +2 -0
- claude_mpm/dashboard/static/built/dashboard.js +2 -0
- claude_mpm/dashboard/static/built/socket-client.js +2 -0
- claude_mpm/dashboard/static/css/dashboard.css +27 -8
- claude_mpm/dashboard/static/dist/components/agent-inference.js +2 -0
- claude_mpm/dashboard/static/dist/components/event-processor.js +2 -0
- claude_mpm/dashboard/static/dist/components/event-viewer.js +2 -0
- claude_mpm/dashboard/static/dist/components/export-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +2 -0
- claude_mpm/dashboard/static/dist/components/hud-library-loader.js +2 -0
- claude_mpm/dashboard/static/dist/components/hud-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/hud-visualizer.js +2 -0
- claude_mpm/dashboard/static/dist/components/module-viewer.js +2 -0
- claude_mpm/dashboard/static/dist/components/session-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/socket-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/ui-state-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/working-directory.js +2 -0
- claude_mpm/dashboard/static/dist/dashboard.js +2 -0
- claude_mpm/dashboard/static/dist/socket-client.js +2 -0
- claude_mpm/dashboard/static/js/components/agent-inference.js +80 -76
- claude_mpm/dashboard/static/js/components/event-processor.js +71 -67
- claude_mpm/dashboard/static/js/components/event-viewer.js +93 -72
- claude_mpm/dashboard/static/js/components/export-manager.js +31 -28
- claude_mpm/dashboard/static/js/components/file-tool-tracker.js +110 -96
- claude_mpm/dashboard/static/js/components/hud-library-loader.js +11 -11
- claude_mpm/dashboard/static/js/components/hud-manager.js +73 -73
- claude_mpm/dashboard/static/js/components/hud-visualizer.js +163 -163
- claude_mpm/dashboard/static/js/components/module-viewer.js +305 -233
- claude_mpm/dashboard/static/js/components/session-manager.js +32 -29
- claude_mpm/dashboard/static/js/components/socket-manager.js +27 -20
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +21 -18
- claude_mpm/dashboard/static/js/components/working-directory.js +74 -71
- claude_mpm/dashboard/static/js/dashboard.js +178 -453
- claude_mpm/dashboard/static/js/extension-error-handler.js +164 -0
- claude_mpm/dashboard/static/js/socket-client.js +133 -53
- claude_mpm/dashboard/templates/index.html +40 -50
- claude_mpm/experimental/cli_enhancements.py +60 -58
- claude_mpm/generators/__init__.py +1 -1
- claude_mpm/generators/agent_profile_generator.py +75 -65
- claude_mpm/hooks/__init__.py +1 -1
- claude_mpm/hooks/base_hook.py +33 -28
- claude_mpm/hooks/claude_hooks/__init__.py +1 -1
- claude_mpm/hooks/claude_hooks/connection_pool.py +120 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +743 -0
- claude_mpm/hooks/claude_hooks/hook_handler.py +415 -1331
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +4 -4
- claude_mpm/hooks/claude_hooks/memory_integration.py +221 -0
- claude_mpm/hooks/claude_hooks/response_tracking.py +348 -0
- claude_mpm/hooks/claude_hooks/tool_analysis.py +230 -0
- claude_mpm/hooks/memory_integration_hook.py +140 -100
- claude_mpm/hooks/tool_call_interceptor.py +89 -76
- claude_mpm/hooks/validation_hooks.py +57 -49
- claude_mpm/init.py +145 -121
- claude_mpm/models/__init__.py +9 -9
- claude_mpm/models/agent_definition.py +33 -23
- claude_mpm/models/agent_session.py +228 -200
- claude_mpm/scripts/__init__.py +1 -1
- claude_mpm/scripts/socketio_daemon.py +192 -75
- claude_mpm/scripts/socketio_server_manager.py +328 -0
- claude_mpm/scripts/start_activity_logging.py +25 -22
- claude_mpm/services/__init__.py +68 -43
- claude_mpm/services/agent_capabilities_service.py +271 -0
- claude_mpm/services/agents/__init__.py +23 -32
- claude_mpm/services/agents/deployment/__init__.py +3 -3
- claude_mpm/services/agents/deployment/agent_config_provider.py +310 -0
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +359 -0
- claude_mpm/services/agents/deployment/agent_definition_factory.py +84 -0
- claude_mpm/services/agents/deployment/agent_deployment.py +415 -2113
- claude_mpm/services/agents/deployment/agent_discovery_service.py +387 -0
- claude_mpm/services/agents/deployment/agent_environment_manager.py +293 -0
- claude_mpm/services/agents/deployment/agent_filesystem_manager.py +387 -0
- claude_mpm/services/agents/deployment/agent_format_converter.py +453 -0
- claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +161 -0
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +345 -495
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +279 -0
- claude_mpm/services/agents/deployment/agent_restore_handler.py +88 -0
- claude_mpm/services/agents/deployment/agent_template_builder.py +406 -0
- claude_mpm/services/agents/deployment/agent_validator.py +352 -0
- claude_mpm/services/agents/deployment/agent_version_manager.py +313 -0
- claude_mpm/services/agents/deployment/agent_versioning.py +6 -9
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +79 -0
- claude_mpm/services/agents/deployment/async_agent_deployment.py +298 -234
- claude_mpm/services/agents/deployment/config/__init__.py +13 -0
- claude_mpm/services/agents/deployment/config/deployment_config.py +182 -0
- claude_mpm/services/agents/deployment/config/deployment_config_manager.py +200 -0
- claude_mpm/services/agents/deployment/deployment_config_loader.py +54 -0
- claude_mpm/services/agents/deployment/deployment_type_detector.py +124 -0
- claude_mpm/services/agents/deployment/facade/__init__.py +18 -0
- claude_mpm/services/agents/deployment/facade/async_deployment_executor.py +159 -0
- claude_mpm/services/agents/deployment/facade/deployment_executor.py +73 -0
- claude_mpm/services/agents/deployment/facade/deployment_facade.py +270 -0
- claude_mpm/services/agents/deployment/facade/sync_deployment_executor.py +178 -0
- claude_mpm/services/agents/deployment/interface_adapter.py +227 -0
- claude_mpm/services/agents/deployment/lifecycle_health_checker.py +85 -0
- claude_mpm/services/agents/deployment/lifecycle_performance_tracker.py +100 -0
- claude_mpm/services/agents/deployment/pipeline/__init__.py +32 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +158 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +159 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +169 -0
- claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +19 -0
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +195 -0
- claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +119 -0
- claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +79 -0
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +90 -0
- claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +100 -0
- claude_mpm/services/agents/deployment/processors/__init__.py +15 -0
- claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +98 -0
- claude_mpm/services/agents/deployment/processors/agent_deployment_result.py +235 -0
- claude_mpm/services/agents/deployment/processors/agent_processor.py +258 -0
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +318 -0
- claude_mpm/services/agents/deployment/results/__init__.py +13 -0
- claude_mpm/services/agents/deployment/results/deployment_metrics.py +200 -0
- claude_mpm/services/agents/deployment/results/deployment_result_builder.py +249 -0
- claude_mpm/services/agents/deployment/strategies/__init__.py +25 -0
- claude_mpm/services/agents/deployment/strategies/base_strategy.py +119 -0
- claude_mpm/services/agents/deployment/strategies/project_strategy.py +150 -0
- claude_mpm/services/agents/deployment/strategies/strategy_selector.py +117 -0
- claude_mpm/services/agents/deployment/strategies/system_strategy.py +116 -0
- claude_mpm/services/agents/deployment/strategies/user_strategy.py +137 -0
- claude_mpm/services/agents/deployment/system_instructions_deployer.py +108 -0
- claude_mpm/services/agents/deployment/validation/__init__.py +19 -0
- claude_mpm/services/agents/deployment/validation/agent_validator.py +323 -0
- claude_mpm/services/agents/deployment/validation/deployment_validator.py +238 -0
- claude_mpm/services/agents/deployment/validation/template_validator.py +299 -0
- claude_mpm/services/agents/deployment/validation/validation_result.py +226 -0
- claude_mpm/services/agents/loading/__init__.py +2 -2
- claude_mpm/services/agents/loading/agent_profile_loader.py +259 -229
- claude_mpm/services/agents/loading/base_agent_manager.py +90 -81
- claude_mpm/services/agents/loading/framework_agent_loader.py +154 -129
- claude_mpm/services/agents/management/__init__.py +2 -2
- claude_mpm/services/agents/management/agent_capabilities_generator.py +72 -58
- claude_mpm/services/agents/management/agent_management_service.py +209 -156
- claude_mpm/services/agents/memory/__init__.py +9 -6
- claude_mpm/services/agents/memory/agent_memory_manager.py +218 -1152
- claude_mpm/services/agents/memory/agent_persistence_service.py +20 -16
- claude_mpm/services/agents/memory/analyzer.py +430 -0
- claude_mpm/services/agents/memory/content_manager.py +376 -0
- claude_mpm/services/agents/memory/template_generator.py +468 -0
- claude_mpm/services/agents/registry/__init__.py +7 -10
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +122 -97
- claude_mpm/services/agents/registry/modification_tracker.py +351 -285
- claude_mpm/services/async_session_logger.py +187 -153
- claude_mpm/services/claude_session_logger.py +87 -72
- claude_mpm/services/command_handler_service.py +217 -0
- claude_mpm/services/communication/__init__.py +3 -2
- claude_mpm/services/core/__init__.py +50 -97
- claude_mpm/services/core/base.py +60 -53
- claude_mpm/services/core/interfaces/__init__.py +188 -0
- claude_mpm/services/core/interfaces/agent.py +351 -0
- claude_mpm/services/core/interfaces/communication.py +343 -0
- claude_mpm/services/core/interfaces/infrastructure.py +413 -0
- claude_mpm/services/core/interfaces/service.py +434 -0
- claude_mpm/services/core/interfaces.py +19 -944
- claude_mpm/services/event_aggregator.py +208 -170
- claude_mpm/services/exceptions.py +387 -308
- claude_mpm/services/framework_claude_md_generator/__init__.py +75 -79
- claude_mpm/services/framework_claude_md_generator/content_assembler.py +69 -60
- claude_mpm/services/framework_claude_md_generator/content_validator.py +65 -61
- claude_mpm/services/framework_claude_md_generator/deployment_manager.py +68 -49
- claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +34 -34
- claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +25 -22
- claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +10 -10
- claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +6 -5
- claude_mpm/services/framework_claude_md_generator/section_generators/header.py +8 -7
- claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +6 -5
- claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +9 -8
- claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +5 -4
- claude_mpm/services/framework_claude_md_generator/section_manager.py +28 -27
- claude_mpm/services/framework_claude_md_generator/version_manager.py +30 -28
- claude_mpm/services/hook_service.py +106 -114
- claude_mpm/services/infrastructure/__init__.py +7 -5
- claude_mpm/services/infrastructure/context_preservation.py +233 -199
- claude_mpm/services/infrastructure/daemon_manager.py +279 -0
- claude_mpm/services/infrastructure/logging.py +83 -76
- claude_mpm/services/infrastructure/monitoring.py +547 -404
- claude_mpm/services/mcp_gateway/__init__.py +30 -13
- claude_mpm/services/mcp_gateway/config/__init__.py +2 -2
- claude_mpm/services/mcp_gateway/config/config_loader.py +61 -56
- claude_mpm/services/mcp_gateway/config/config_schema.py +50 -41
- claude_mpm/services/mcp_gateway/config/configuration.py +82 -75
- claude_mpm/services/mcp_gateway/core/__init__.py +13 -20
- claude_mpm/services/mcp_gateway/core/base.py +80 -67
- claude_mpm/services/mcp_gateway/core/exceptions.py +60 -46
- claude_mpm/services/mcp_gateway/core/interfaces.py +87 -84
- claude_mpm/services/mcp_gateway/main.py +287 -137
- claude_mpm/services/mcp_gateway/registry/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/registry/service_registry.py +97 -94
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +135 -126
- claude_mpm/services/mcp_gateway/server/__init__.py +2 -2
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +105 -110
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +105 -107
- claude_mpm/services/mcp_gateway/server/stdio_server.py +691 -0
- claude_mpm/services/mcp_gateway/tools/__init__.py +4 -2
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +109 -119
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +283 -215
- claude_mpm/services/mcp_gateway/tools/hello_world.py +122 -120
- claude_mpm/services/mcp_gateway/tools/ticket_tools.py +652 -0
- claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +606 -0
- claude_mpm/services/memory/__init__.py +2 -2
- claude_mpm/services/memory/builder.py +451 -362
- claude_mpm/services/memory/cache/__init__.py +2 -2
- claude_mpm/services/memory/cache/shared_prompt_cache.py +232 -194
- claude_mpm/services/memory/cache/simple_cache.py +107 -93
- claude_mpm/services/memory/indexed_memory.py +195 -193
- claude_mpm/services/memory/optimizer.py +267 -234
- claude_mpm/services/memory/router.py +571 -263
- claude_mpm/services/memory_hook_service.py +237 -0
- claude_mpm/services/port_manager.py +575 -0
- claude_mpm/services/project/__init__.py +3 -3
- claude_mpm/services/project/analyzer.py +451 -305
- claude_mpm/services/project/registry.py +262 -240
- claude_mpm/services/recovery_manager.py +287 -231
- claude_mpm/services/response_tracker.py +87 -67
- claude_mpm/services/runner_configuration_service.py +587 -0
- claude_mpm/services/session_management_service.py +304 -0
- claude_mpm/services/socketio/__init__.py +4 -4
- claude_mpm/services/socketio/client_proxy.py +174 -0
- claude_mpm/services/socketio/handlers/__init__.py +3 -3
- claude_mpm/services/socketio/handlers/base.py +44 -30
- claude_mpm/services/socketio/handlers/connection.py +166 -64
- claude_mpm/services/socketio/handlers/file.py +123 -108
- claude_mpm/services/socketio/handlers/git.py +607 -373
- claude_mpm/services/socketio/handlers/hook.py +185 -0
- claude_mpm/services/socketio/handlers/memory.py +4 -4
- claude_mpm/services/socketio/handlers/project.py +4 -4
- claude_mpm/services/socketio/handlers/registry.py +53 -38
- claude_mpm/services/socketio/server/__init__.py +18 -0
- claude_mpm/services/socketio/server/broadcaster.py +252 -0
- claude_mpm/services/socketio/server/core.py +399 -0
- claude_mpm/services/socketio/server/main.py +323 -0
- claude_mpm/services/socketio_client_manager.py +160 -133
- claude_mpm/services/socketio_server.py +36 -1885
- claude_mpm/services/subprocess_launcher_service.py +316 -0
- claude_mpm/services/system_instructions_service.py +258 -0
- claude_mpm/services/ticket_manager.py +19 -533
- claude_mpm/services/utility_service.py +285 -0
- claude_mpm/services/version_control/__init__.py +18 -21
- claude_mpm/services/version_control/branch_strategy.py +20 -10
- claude_mpm/services/version_control/conflict_resolution.py +37 -13
- claude_mpm/services/version_control/git_operations.py +52 -21
- claude_mpm/services/version_control/semantic_versioning.py +92 -53
- claude_mpm/services/version_control/version_parser.py +145 -125
- claude_mpm/services/version_service.py +270 -0
- claude_mpm/storage/__init__.py +2 -2
- claude_mpm/storage/state_storage.py +177 -181
- claude_mpm/ticket_wrapper.py +2 -2
- claude_mpm/utils/__init__.py +2 -2
- claude_mpm/utils/agent_dependency_loader.py +453 -243
- claude_mpm/utils/config_manager.py +157 -118
- claude_mpm/utils/console.py +1 -1
- claude_mpm/utils/dependency_cache.py +102 -107
- claude_mpm/utils/dependency_manager.py +52 -47
- claude_mpm/utils/dependency_strategies.py +131 -96
- claude_mpm/utils/environment_context.py +110 -102
- claude_mpm/utils/error_handler.py +75 -55
- claude_mpm/utils/file_utils.py +80 -67
- claude_mpm/utils/framework_detection.py +12 -11
- claude_mpm/utils/import_migration_example.py +12 -60
- claude_mpm/utils/imports.py +48 -45
- claude_mpm/utils/path_operations.py +100 -93
- claude_mpm/utils/robust_installer.py +172 -164
- claude_mpm/utils/session_logging.py +30 -23
- claude_mpm/utils/subprocess_utils.py +99 -61
- claude_mpm/validation/__init__.py +1 -1
- claude_mpm/validation/agent_validator.py +151 -111
- claude_mpm/validation/frontmatter_validator.py +92 -71
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/METADATA +90 -22
- claude_mpm-4.0.4.dist-info/RECORD +417 -0
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/entry_points.txt +1 -0
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/licenses/LICENSE +1 -1
- claude_mpm/cli/commands/run_guarded.py +0 -511
- claude_mpm/config/memory_guardian_config.py +0 -325
- claude_mpm/config/memory_guardian_yaml.py +0 -335
- claude_mpm/core/config_paths.py +0 -150
- claude_mpm/core/memory_aware_runner.py +0 -353
- claude_mpm/dashboard/static/js/dashboard-original.js +0 -4134
- claude_mpm/deployment_paths.py +0 -261
- claude_mpm/hooks/claude_hooks/hook_handler_fixed.py +0 -454
- claude_mpm/models/state_models.py +0 -433
- claude_mpm/services/agent/__init__.py +0 -24
- claude_mpm/services/agent/deployment.py +0 -2548
- claude_mpm/services/agent/management.py +0 -598
- claude_mpm/services/agent/registry.py +0 -813
- claude_mpm/services/agents/registry/agent_registry.py +0 -813
- claude_mpm/services/communication/socketio.py +0 -1935
- claude_mpm/services/communication/websocket.py +0 -479
- claude_mpm/services/framework_claude_md_generator.py +0 -624
- claude_mpm/services/health_monitor.py +0 -893
- claude_mpm/services/infrastructure/graceful_degradation.py +0 -616
- claude_mpm/services/infrastructure/health_monitor.py +0 -775
- claude_mpm/services/infrastructure/memory_dashboard.py +0 -479
- claude_mpm/services/infrastructure/memory_guardian.py +0 -944
- claude_mpm/services/infrastructure/restart_protection.py +0 -642
- claude_mpm/services/infrastructure/state_manager.py +0 -774
- claude_mpm/services/mcp_gateway/manager.py +0 -334
- claude_mpm/services/optimized_hook_service.py +0 -542
- claude_mpm/services/project_analyzer.py +0 -864
- claude_mpm/services/project_registry.py +0 -608
- claude_mpm/services/standalone_socketio_server.py +0 -1300
- claude_mpm/services/ticket_manager_di.py +0 -318
- claude_mpm/services/ticketing_service_original.py +0 -510
- claude_mpm/utils/paths.py +0 -395
- claude_mpm/utils/platform_memory.py +0 -524
- claude_mpm-3.9.11.dist-info/RECORD +0 -306
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/WHEEL +0 -0
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/top_level.txt +0 -0
| @@ -23,55 +23,55 @@ This service analyzes: | |
| 23 23 | 
             
            """
         | 
| 24 24 |  | 
| 25 25 | 
             
            import json
         | 
| 26 | 
            +
            import logging
         | 
| 26 27 | 
             
            import re
         | 
| 28 | 
            +
            from collections import Counter, defaultdict
         | 
| 29 | 
            +
            from dataclasses import asdict, dataclass
         | 
| 27 30 | 
             
            from pathlib import Path
         | 
| 28 | 
            -
            from typing import Dict, List, Optional,  | 
| 29 | 
            -
            import logging
         | 
| 30 | 
            -
            from dataclasses import dataclass, asdict
         | 
| 31 | 
            -
            from collections import defaultdict, Counter
         | 
| 31 | 
            +
            from typing import Any, Dict, List, Optional, Set, Tuple
         | 
| 32 32 |  | 
| 33 33 | 
             
            from claude_mpm.core.config import Config
         | 
| 34 | 
            -
            from claude_mpm.utils.paths import PathResolver
         | 
| 35 34 | 
             
            from claude_mpm.core.interfaces import ProjectAnalyzerInterface
         | 
| 35 | 
            +
            from claude_mpm.core.unified_paths import get_path_manager
         | 
| 36 36 |  | 
| 37 37 |  | 
| 38 38 | 
             
            @dataclass
         | 
| 39 39 | 
             
            class ProjectCharacteristics:
         | 
| 40 40 | 
             
                """Structured representation of project characteristics."""
         | 
| 41 | 
            -
             | 
| 41 | 
            +
             | 
| 42 42 | 
             
                # Core project info
         | 
| 43 43 | 
             
                project_name: str
         | 
| 44 44 | 
             
                primary_language: Optional[str]
         | 
| 45 45 | 
             
                languages: List[str]
         | 
| 46 46 | 
             
                frameworks: List[str]
         | 
| 47 | 
            -
             | 
| 47 | 
            +
             | 
| 48 48 | 
             
                # Architecture and structure
         | 
| 49 49 | 
             
                architecture_type: str
         | 
| 50 50 | 
             
                main_modules: List[str]
         | 
| 51 51 | 
             
                key_directories: List[str]
         | 
| 52 52 | 
             
                entry_points: List[str]
         | 
| 53 | 
            -
             | 
| 53 | 
            +
             | 
| 54 54 | 
             
                # Development practices
         | 
| 55 55 | 
             
                testing_framework: Optional[str]
         | 
| 56 56 | 
             
                test_patterns: List[str]
         | 
| 57 57 | 
             
                package_manager: Optional[str]
         | 
| 58 58 | 
             
                build_tools: List[str]
         | 
| 59 | 
            -
             | 
| 59 | 
            +
             | 
| 60 60 | 
             
                # Integrations and dependencies
         | 
| 61 61 | 
             
                databases: List[str]
         | 
| 62 62 | 
             
                web_frameworks: List[str]
         | 
| 63 63 | 
             
                api_patterns: List[str]
         | 
| 64 64 | 
             
                key_dependencies: List[str]
         | 
| 65 | 
            -
             | 
| 65 | 
            +
             | 
| 66 66 | 
             
                # Project-specific patterns
         | 
| 67 67 | 
             
                code_conventions: List[str]
         | 
| 68 68 | 
             
                configuration_patterns: List[str]
         | 
| 69 69 | 
             
                project_terminology: List[str]
         | 
| 70 | 
            -
             | 
| 70 | 
            +
             | 
| 71 71 | 
             
                # Documentation and structure
         | 
| 72 72 | 
             
                documentation_files: List[str]
         | 
| 73 73 | 
             
                important_configs: List[str]
         | 
| 74 | 
            -
             | 
| 74 | 
            +
             | 
| 75 75 | 
             
                def to_dict(self) -> Dict[str, Any]:
         | 
| 76 76 | 
             
                    """Convert to dictionary for JSON serialization."""
         | 
| 77 77 | 
             
                    return asdict(self)
         | 
| @@ -79,79 +79,83 @@ class ProjectCharacteristics: | |
| 79 79 |  | 
| 80 80 | 
             
            class ProjectAnalyzer(ProjectAnalyzerInterface):
         | 
| 81 81 | 
             
                """Analyzes project characteristics for context-aware memory creation.
         | 
| 82 | 
            -
             | 
| 82 | 
            +
             | 
| 83 83 | 
             
                WHY: Generic agent memories aren't helpful for specific projects. This analyzer
         | 
| 84 84 | 
             
                extracts project-specific characteristics that enable agents to create relevant,
         | 
| 85 85 | 
             
                actionable memories with proper context.
         | 
| 86 | 
            -
             | 
| 86 | 
            +
             | 
| 87 87 | 
             
                DESIGN DECISION: Uses a combination of file pattern analysis, content parsing,
         | 
| 88 88 | 
             
                and directory structure analysis to build comprehensive project understanding
         | 
| 89 89 | 
             
                without requiring external tools or API calls.
         | 
| 90 90 | 
             
                """
         | 
| 91 | 
            -
             | 
| 91 | 
            +
             | 
| 92 92 | 
             
                # Common configuration files and their indicators
         | 
| 93 93 | 
             
                CONFIG_FILE_PATTERNS = {
         | 
| 94 | 
            -
                     | 
| 95 | 
            -
                     | 
| 96 | 
            -
                     | 
| 97 | 
            -
                     | 
| 98 | 
            -
                     | 
| 99 | 
            -
                     | 
| 100 | 
            -
                     | 
| 101 | 
            -
                     | 
| 102 | 
            -
                     | 
| 103 | 
            -
                     | 
| 104 | 
            -
                     | 
| 105 | 
            -
                     | 
| 94 | 
            +
                    "package.json": "node_js",
         | 
| 95 | 
            +
                    "requirements.txt": "python",
         | 
| 96 | 
            +
                    "pyproject.toml": "python",
         | 
| 97 | 
            +
                    "setup.py": "python",
         | 
| 98 | 
            +
                    "Cargo.toml": "rust",
         | 
| 99 | 
            +
                    "pom.xml": "java",
         | 
| 100 | 
            +
                    "build.gradle": "java",
         | 
| 101 | 
            +
                    "composer.json": "php",
         | 
| 102 | 
            +
                    "Gemfile": "ruby",
         | 
| 103 | 
            +
                    "go.mod": "go",
         | 
| 104 | 
            +
                    "CMakeLists.txt": "cpp",
         | 
| 105 | 
            +
                    "Makefile": "c_cpp",
         | 
| 106 106 | 
             
                }
         | 
| 107 | 
            -
             | 
| 107 | 
            +
             | 
| 108 108 | 
             
                # Framework detection patterns
         | 
| 109 109 | 
             
                FRAMEWORK_PATTERNS = {
         | 
| 110 | 
            -
                     | 
| 111 | 
            -
                     | 
| 112 | 
            -
                     | 
| 113 | 
            -
                     | 
| 114 | 
            -
                     | 
| 115 | 
            -
                     | 
| 116 | 
            -
                     | 
| 117 | 
            -
                     | 
| 118 | 
            -
                     | 
| 110 | 
            +
                    "flask": ["from flask", "Flask(", "app.route"],
         | 
| 111 | 
            +
                    "django": ["from django", "DJANGO_SETTINGS", "django.contrib"],
         | 
| 112 | 
            +
                    "fastapi": ["from fastapi", "FastAPI(", "@app."],
         | 
| 113 | 
            +
                    "express": ["express()", "app.get(", "app.post("],
         | 
| 114 | 
            +
                    "react": ["import React", "from react", "ReactDOM"],
         | 
| 115 | 
            +
                    "vue": ["Vue.createApp", "new Vue(", "vue-"],
         | 
| 116 | 
            +
                    "angular": ["@Component", "@Injectable", "Angular"],
         | 
| 117 | 
            +
                    "spring": ["@SpringBootApplication", "@RestController", "Spring"],
         | 
| 118 | 
            +
                    "rails": ["Rails.application", "ApplicationController"],
         | 
| 119 119 | 
             
                }
         | 
| 120 | 
            -
             | 
| 120 | 
            +
             | 
| 121 121 | 
             
                # Database detection patterns
         | 
| 122 122 | 
             
                DATABASE_PATTERNS = {
         | 
| 123 | 
            -
                     | 
| 124 | 
            -
                     | 
| 125 | 
            -
                     | 
| 126 | 
            -
                     | 
| 127 | 
            -
                     | 
| 128 | 
            -
                     | 
| 123 | 
            +
                    "postgresql": ["psycopg2", "postgresql:", "postgres:", "pg_"],
         | 
| 124 | 
            +
                    "mysql": ["mysql-connector", "mysql:", "MySQLdb"],
         | 
| 125 | 
            +
                    "sqlite": ["sqlite3", "sqlite:", ".db", ".sqlite"],
         | 
| 126 | 
            +
                    "mongodb": ["pymongo", "mongodb:", "mongoose"],
         | 
| 127 | 
            +
                    "redis": ["redis:", "redis-py", "RedisClient"],
         | 
| 128 | 
            +
                    "elasticsearch": ["elasticsearch:", "elastic"],
         | 
| 129 129 | 
             
                }
         | 
| 130 | 
            -
             | 
| 131 | 
            -
                def __init__( | 
| 130 | 
            +
             | 
| 131 | 
            +
                def __init__(
         | 
| 132 | 
            +
                    self, config: Optional[Config] = None, working_directory: Optional[Path] = None
         | 
| 133 | 
            +
                ):
         | 
| 132 134 | 
             
                    """Initialize the project analyzer.
         | 
| 133 | 
            -
             | 
| 135 | 
            +
             | 
| 134 136 | 
             
                    Args:
         | 
| 135 137 | 
             
                        config: Optional Config object
         | 
| 136 138 | 
             
                        working_directory: Optional working directory path. If not provided, uses current.
         | 
| 137 139 | 
             
                    """
         | 
| 138 140 | 
             
                    self.config = config or Config()
         | 
| 139 | 
            -
                    self.working_directory =  | 
| 141 | 
            +
                    self.working_directory = (
         | 
| 142 | 
            +
                        working_directory or get_path_manager().get_project_root()
         | 
| 143 | 
            +
                    )
         | 
| 140 144 | 
             
                    self.logger = logging.getLogger(f"{__name__}.{self.__class__.__name__}")
         | 
| 141 | 
            -
             | 
| 145 | 
            +
             | 
| 142 146 | 
             
                    # Cache for analysis results
         | 
| 143 147 | 
             
                    self._analysis_cache: Optional[ProjectCharacteristics] = None
         | 
| 144 148 | 
             
                    self._cache_timestamp: Optional[float] = None
         | 
| 145 | 
            -
             | 
| 149 | 
            +
             | 
| 146 150 | 
             
                def analyze_project(self, force_refresh: bool = False) -> ProjectCharacteristics:
         | 
| 147 151 | 
             
                    """Analyze the current project and return characteristics.
         | 
| 148 | 
            -
             | 
| 152 | 
            +
             | 
| 149 153 | 
             
                    WHY: Comprehensive project analysis enables agents to create memories
         | 
| 150 154 | 
             
                    that are specific to the actual project context, tech stack, and patterns.
         | 
| 151 | 
            -
             | 
| 155 | 
            +
             | 
| 152 156 | 
             
                    Args:
         | 
| 153 157 | 
             
                        force_refresh: If True, ignores cache and performs fresh analysis
         | 
| 154 | 
            -
             | 
| 158 | 
            +
             | 
| 155 159 | 
             
                    Returns:
         | 
| 156 160 | 
             
                        ProjectCharacteristics: Structured project analysis results
         | 
| 157 161 | 
             
                    """
         | 
| @@ -160,12 +164,13 @@ class ProjectAnalyzer(ProjectAnalyzerInterface): | |
| 160 164 | 
             
                        if not force_refresh and self._analysis_cache and self._cache_timestamp:
         | 
| 161 165 | 
             
                            # Cache is valid for 5 minutes
         | 
| 162 166 | 
             
                            import time
         | 
| 167 | 
            +
             | 
| 163 168 | 
             
                            if time.time() - self._cache_timestamp < 300:
         | 
| 164 169 | 
             
                                self.logger.debug("Using cached project analysis")
         | 
| 165 170 | 
             
                                return self._analysis_cache
         | 
| 166 | 
            -
             | 
| 171 | 
            +
             | 
| 167 172 | 
             
                        self.logger.info(f"Analyzing project at: {self.working_directory}")
         | 
| 168 | 
            -
             | 
| 173 | 
            +
             | 
| 169 174 | 
             
                        # Initialize characteristics with basic info
         | 
| 170 175 | 
             
                        characteristics = ProjectCharacteristics(
         | 
| 171 176 | 
             
                            project_name=self.working_directory.name,
         | 
| @@ -188,9 +193,9 @@ class ProjectAnalyzer(ProjectAnalyzerInterface): | |
| 188 193 | 
             
                            configuration_patterns=[],
         | 
| 189 194 | 
             
                            project_terminology=[],
         | 
| 190 195 | 
             
                            documentation_files=[],
         | 
| 191 | 
            -
                            important_configs=[]
         | 
| 196 | 
            +
                            important_configs=[],
         | 
| 192 197 | 
             
                        )
         | 
| 193 | 
            -
             | 
| 198 | 
            +
             | 
| 194 199 | 
             
                        # Perform various analyses
         | 
| 195 200 | 
             
                        self._analyze_config_files(characteristics)
         | 
| 196 201 | 
             
                        self._analyze_directory_structure(characteristics)
         | 
| @@ -200,15 +205,18 @@ class ProjectAnalyzer(ProjectAnalyzerInterface): | |
| 200 205 | 
             
                        self._analyze_documentation(characteristics)
         | 
| 201 206 | 
             
                        self._infer_architecture_type(characteristics)
         | 
| 202 207 | 
             
                        self._extract_project_terminology(characteristics)
         | 
| 203 | 
            -
             | 
| 208 | 
            +
             | 
| 204 209 | 
             
                        # Cache the results
         | 
| 205 210 | 
             
                        self._analysis_cache = characteristics
         | 
| 206 211 | 
             
                        import time
         | 
| 212 | 
            +
             | 
| 207 213 | 
             
                        self._cache_timestamp = time.time()
         | 
| 208 | 
            -
             | 
| 209 | 
            -
                        self.logger.info( | 
| 214 | 
            +
             | 
| 215 | 
            +
                        self.logger.info(
         | 
| 216 | 
            +
                            f"Project analysis complete: {characteristics.primary_language} project with {len(characteristics.frameworks)} frameworks"
         | 
| 217 | 
            +
                        )
         | 
| 210 218 | 
             
                        return characteristics
         | 
| 211 | 
            -
             | 
| 219 | 
            +
             | 
| 212 220 | 
             
                    except Exception as e:
         | 
| 213 221 | 
             
                        self.logger.error(f"Error analyzing project: {e}")
         | 
| 214 222 | 
             
                        # Return minimal characteristics on error
         | 
| @@ -233,142 +241,174 @@ class ProjectAnalyzer(ProjectAnalyzerInterface): | |
| 233 241 | 
             
                            configuration_patterns=[],
         | 
| 234 242 | 
             
                            project_terminology=[],
         | 
| 235 243 | 
             
                            documentation_files=[],
         | 
| 236 | 
            -
                            important_configs=[]
         | 
| 244 | 
            +
                            important_configs=[],
         | 
| 237 245 | 
             
                        )
         | 
| 238 | 
            -
             | 
| 246 | 
            +
             | 
| 239 247 | 
             
                def _analyze_config_files(self, characteristics: ProjectCharacteristics) -> None:
         | 
| 240 248 | 
             
                    """Analyze configuration files to determine tech stack.
         | 
| 241 | 
            -
             | 
| 249 | 
            +
             | 
| 242 250 | 
             
                    WHY: Configuration files are the most reliable indicators of project
         | 
| 243 251 | 
             
                    technology stack and dependencies. They provide definitive information
         | 
| 244 252 | 
             
                    about what technologies are actually used.
         | 
| 245 | 
            -
             | 
| 253 | 
            +
             | 
| 246 254 | 
             
                    Args:
         | 
| 247 255 | 
             
                        characteristics: ProjectCharacteristics object to update
         | 
| 248 256 | 
             
                    """
         | 
| 249 257 | 
             
                    config_files = []
         | 
| 250 258 | 
             
                    languages_found = set()
         | 
| 251 | 
            -
             | 
| 259 | 
            +
             | 
| 252 260 | 
             
                    for config_file, language in self.CONFIG_FILE_PATTERNS.items():
         | 
| 253 261 | 
             
                        config_path = self.working_directory / config_file
         | 
| 254 262 | 
             
                        if config_path.exists():
         | 
| 255 263 | 
             
                            config_files.append(config_file)
         | 
| 256 264 | 
             
                            languages_found.add(language)
         | 
| 257 | 
            -
                            characteristics.important_configs.append( | 
| 258 | 
            -
             | 
| 265 | 
            +
                            characteristics.important_configs.append(
         | 
| 266 | 
            +
                                str(config_path.relative_to(self.working_directory))
         | 
| 267 | 
            +
                            )
         | 
| 268 | 
            +
             | 
| 259 269 | 
             
                            # Parse specific config files for more details
         | 
| 260 270 | 
             
                            try:
         | 
| 261 | 
            -
                                if config_file ==  | 
| 271 | 
            +
                                if config_file == "package.json":
         | 
| 262 272 | 
             
                                    self._parse_package_json(config_path, characteristics)
         | 
| 263 | 
            -
                                elif config_file in [ | 
| 273 | 
            +
                                elif config_file in ["requirements.txt", "pyproject.toml"]:
         | 
| 264 274 | 
             
                                    self._parse_python_dependencies(config_path, characteristics)
         | 
| 265 | 
            -
                                elif config_file ==  | 
| 275 | 
            +
                                elif config_file == "Cargo.toml":
         | 
| 266 276 | 
             
                                    self._parse_cargo_toml(config_path, characteristics)
         | 
| 267 277 | 
             
                            except Exception as e:
         | 
| 268 278 | 
             
                                self.logger.warning(f"Error parsing {config_file}: {e}")
         | 
| 269 | 
            -
             | 
| 279 | 
            +
             | 
| 270 280 | 
             
                    # Set primary language (prefer more specific indicators)
         | 
| 271 | 
            -
                    language_priority = [ | 
| 281 | 
            +
                    language_priority = ["python", "node_js", "rust", "java", "go", "php", "ruby"]
         | 
| 272 282 | 
             
                    for lang in language_priority:
         | 
| 273 283 | 
             
                        if lang in languages_found:
         | 
| 274 284 | 
             
                            characteristics.primary_language = lang
         | 
| 275 285 | 
             
                            break
         | 
| 276 | 
            -
             | 
| 286 | 
            +
             | 
| 277 287 | 
             
                    characteristics.languages = list(languages_found)
         | 
| 278 | 
            -
             | 
| 288 | 
            +
             | 
| 279 289 | 
             
                    # Determine package manager
         | 
| 280 | 
            -
                    if  | 
| 281 | 
            -
                        if (self.working_directory /  | 
| 282 | 
            -
                            characteristics.package_manager =  | 
| 283 | 
            -
                        elif (self.working_directory /  | 
| 284 | 
            -
                            characteristics.package_manager =  | 
| 290 | 
            +
                    if "package.json" in config_files:
         | 
| 291 | 
            +
                        if (self.working_directory / "yarn.lock").exists():
         | 
| 292 | 
            +
                            characteristics.package_manager = "yarn"
         | 
| 293 | 
            +
                        elif (self.working_directory / "pnpm-lock.yaml").exists():
         | 
| 294 | 
            +
                            characteristics.package_manager = "pnpm"
         | 
| 285 295 | 
             
                        else:
         | 
| 286 | 
            -
                            characteristics.package_manager =  | 
| 287 | 
            -
                    elif  | 
| 288 | 
            -
                        characteristics.package_manager =  | 
| 289 | 
            -
                    elif  | 
| 290 | 
            -
                        characteristics.package_manager =  | 
| 291 | 
            -
             | 
| 292 | 
            -
                def _parse_package_json( | 
| 296 | 
            +
                            characteristics.package_manager = "npm"
         | 
| 297 | 
            +
                    elif "requirements.txt" in config_files or "pyproject.toml" in config_files:
         | 
| 298 | 
            +
                        characteristics.package_manager = "pip"
         | 
| 299 | 
            +
                    elif "Cargo.toml" in config_files:
         | 
| 300 | 
            +
                        characteristics.package_manager = "cargo"
         | 
| 301 | 
            +
             | 
| 302 | 
            +
                def _parse_package_json(
         | 
| 303 | 
            +
                    self, package_path: Path, characteristics: ProjectCharacteristics
         | 
| 304 | 
            +
                ) -> None:
         | 
| 293 305 | 
             
                    """Parse package.json for Node.js project details."""
         | 
| 294 306 | 
             
                    try:
         | 
| 295 | 
            -
                        with open(package_path,  | 
| 307 | 
            +
                        with open(package_path, "r") as f:
         | 
| 296 308 | 
             
                            package_data = json.load(f)
         | 
| 297 | 
            -
             | 
| 309 | 
            +
             | 
| 298 310 | 
             
                        # Extract dependencies
         | 
| 299 311 | 
             
                        all_deps = {}
         | 
| 300 | 
            -
                        all_deps.update(package_data.get( | 
| 301 | 
            -
                        all_deps.update(package_data.get( | 
| 302 | 
            -
             | 
| 312 | 
            +
                        all_deps.update(package_data.get("dependencies", {}))
         | 
| 313 | 
            +
                        all_deps.update(package_data.get("devDependencies", {}))
         | 
| 314 | 
            +
             | 
| 303 315 | 
             
                        # Identify frameworks and tools
         | 
| 304 316 | 
             
                        for dep_name in all_deps.keys():
         | 
| 305 317 | 
             
                            dep_lower = dep_name.lower()
         | 
| 306 | 
            -
             | 
| 318 | 
            +
             | 
| 307 319 | 
             
                            # Web frameworks
         | 
| 308 | 
            -
                            if any(fw in dep_lower for fw in [ | 
| 320 | 
            +
                            if any(fw in dep_lower for fw in ["express", "koa", "hapi"]):
         | 
| 309 321 | 
             
                                characteristics.web_frameworks.append(dep_name)
         | 
| 310 | 
            -
                            elif any( | 
| 322 | 
            +
                            elif any(
         | 
| 323 | 
            +
                                fw in dep_lower for fw in ["react", "vue", "angular", "svelte"]
         | 
| 324 | 
            +
                            ):
         | 
| 311 325 | 
             
                                characteristics.frameworks.append(dep_name)
         | 
| 312 | 
            -
                            elif any( | 
| 326 | 
            +
                            elif any(
         | 
| 327 | 
            +
                                db in dep_lower for db in ["mysql", "postgres", "mongodb", "redis"]
         | 
| 328 | 
            +
                            ):
         | 
| 313 329 | 
             
                                characteristics.databases.append(dep_name)
         | 
| 314 | 
            -
                            elif any( | 
| 330 | 
            +
                            elif any(
         | 
| 331 | 
            +
                                test in dep_lower
         | 
| 332 | 
            +
                                for test in ["jest", "mocha", "cypress", "playwright"]
         | 
| 333 | 
            +
                            ):
         | 
| 315 334 | 
             
                                if not characteristics.testing_framework:
         | 
| 316 335 | 
             
                                    characteristics.testing_framework = dep_name
         | 
| 317 | 
            -
             | 
| 336 | 
            +
             | 
| 318 337 | 
             
                            characteristics.key_dependencies.append(dep_name)
         | 
| 319 | 
            -
             | 
| 338 | 
            +
             | 
| 320 339 | 
             
                        # Check scripts for build tools
         | 
| 321 | 
            -
                        scripts = package_data.get( | 
| 340 | 
            +
                        scripts = package_data.get("scripts", {})
         | 
| 322 341 | 
             
                        for script_name, script_cmd in scripts.items():
         | 
| 323 | 
            -
                            if any( | 
| 342 | 
            +
                            if any(
         | 
| 343 | 
            +
                                tool in script_cmd
         | 
| 344 | 
            +
                                for tool in ["webpack", "rollup", "vite", "parcel"]
         | 
| 345 | 
            +
                            ):
         | 
| 324 346 | 
             
                                characteristics.build_tools.append(script_name)
         | 
| 325 | 
            -
             | 
| 347 | 
            +
             | 
| 326 348 | 
             
                    except Exception as e:
         | 
| 327 349 | 
             
                        self.logger.warning(f"Error parsing package.json: {e}")
         | 
| 328 | 
            -
             | 
| 329 | 
            -
                def _parse_python_dependencies( | 
| 350 | 
            +
             | 
| 351 | 
            +
                def _parse_python_dependencies(
         | 
| 352 | 
            +
                    self, deps_path: Path, characteristics: ProjectCharacteristics
         | 
| 353 | 
            +
                ) -> None:
         | 
| 330 354 | 
             
                    """Parse Python dependency files."""
         | 
| 331 355 | 
             
                    try:
         | 
| 332 | 
            -
                        if deps_path.name ==  | 
| 356 | 
            +
                        if deps_path.name == "requirements.txt":
         | 
| 333 357 | 
             
                            content = deps_path.read_text()
         | 
| 334 | 
            -
                            deps = [ | 
| 335 | 
            -
             | 
| 336 | 
            -
             | 
| 337 | 
            -
             | 
| 358 | 
            +
                            deps = [
         | 
| 359 | 
            +
                                line.strip().split("=")[0].split(">")[0].split("<")[0]
         | 
| 360 | 
            +
                                for line in content.splitlines()
         | 
| 361 | 
            +
                                if line.strip() and not line.startswith("#")
         | 
| 362 | 
            +
                            ]
         | 
| 363 | 
            +
                        elif deps_path.name == "pyproject.toml":
         | 
| 338 364 | 
             
                            try:
         | 
| 339 365 | 
             
                                import tomllib
         | 
| 340 366 | 
             
                            except ImportError:
         | 
| 341 367 | 
             
                                try:
         | 
| 342 368 | 
             
                                    import tomli as tomllib
         | 
| 343 369 | 
             
                                except ImportError:
         | 
| 344 | 
            -
                                    self.logger.warning( | 
| 370 | 
            +
                                    self.logger.warning(
         | 
| 371 | 
            +
                                        f"TOML parsing not available for {deps_path}"
         | 
| 372 | 
            +
                                    )
         | 
| 345 373 | 
             
                                    return
         | 
| 346 | 
            -
                            with open(deps_path,  | 
| 374 | 
            +
                            with open(deps_path, "rb") as f:
         | 
| 347 375 | 
             
                                data = tomllib.load(f)
         | 
| 348 | 
            -
                            deps = list(data.get( | 
| 349 | 
            -
                            deps.extend( | 
| 376 | 
            +
                            deps = list(data.get("project", {}).get("dependencies", []))
         | 
| 377 | 
            +
                            deps.extend(
         | 
| 378 | 
            +
                                list(
         | 
| 379 | 
            +
                                    data.get("tool", {})
         | 
| 380 | 
            +
                                    .get("poetry", {})
         | 
| 381 | 
            +
                                    .get("dependencies", {})
         | 
| 382 | 
            +
                                    .keys()
         | 
| 383 | 
            +
                                )
         | 
| 384 | 
            +
                            )
         | 
| 350 385 | 
             
                        else:
         | 
| 351 386 | 
             
                            return
         | 
| 352 | 
            -
             | 
| 387 | 
            +
             | 
| 353 388 | 
             
                        # Identify frameworks and tools
         | 
| 354 389 | 
             
                        for dep in deps:
         | 
| 355 390 | 
             
                            dep_lower = dep.lower()
         | 
| 356 | 
            -
             | 
| 391 | 
            +
             | 
| 357 392 | 
             
                            # Web frameworks
         | 
| 358 | 
            -
                            if dep_lower in [ | 
| 393 | 
            +
                            if dep_lower in ["flask", "django", "fastapi", "tornado"]:
         | 
| 359 394 | 
             
                                characteristics.web_frameworks.append(dep)
         | 
| 360 | 
            -
                            elif dep_lower in [ | 
| 395 | 
            +
                            elif dep_lower in ["pytest", "unittest2", "nose"]:
         | 
| 361 396 | 
             
                                if not characteristics.testing_framework:
         | 
| 362 397 | 
             
                                    characteristics.testing_framework = dep
         | 
| 363 | 
            -
                            elif any( | 
| 398 | 
            +
                            elif any(
         | 
| 399 | 
            +
                                db in dep_lower
         | 
| 400 | 
            +
                                for db in ["psycopg2", "mysql", "sqlite", "redis", "mongo"]
         | 
| 401 | 
            +
                            ):
         | 
| 364 402 | 
             
                                characteristics.databases.append(dep)
         | 
| 365 | 
            -
             | 
| 403 | 
            +
             | 
| 366 404 | 
             
                            characteristics.key_dependencies.append(dep)
         | 
| 367 | 
            -
             | 
| 405 | 
            +
             | 
| 368 406 | 
             
                    except Exception as e:
         | 
| 369 407 | 
             
                        self.logger.warning(f"Error parsing Python dependencies: {e}")
         | 
| 370 | 
            -
             | 
| 371 | 
            -
                def _parse_cargo_toml( | 
| 408 | 
            +
             | 
| 409 | 
            +
                def _parse_cargo_toml(
         | 
| 410 | 
            +
                    self, cargo_path: Path, characteristics: ProjectCharacteristics
         | 
| 411 | 
            +
                ) -> None:
         | 
| 372 412 | 
             
                    """Parse Cargo.toml for Rust project details."""
         | 
| 373 413 | 
             
                    try:
         | 
| 374 414 | 
             
                        try:
         | 
| @@ -379,244 +419,309 @@ class ProjectAnalyzer(ProjectAnalyzerInterface): | |
| 379 419 | 
             
                            except ImportError:
         | 
| 380 420 | 
             
                                self.logger.warning(f"TOML parsing not available for {cargo_path}")
         | 
| 381 421 | 
             
                                return
         | 
| 382 | 
            -
                        with open(cargo_path,  | 
| 422 | 
            +
                        with open(cargo_path, "rb") as f:
         | 
| 383 423 | 
             
                            cargo_data = tomllib.load(f)
         | 
| 384 | 
            -
             | 
| 385 | 
            -
                        deps = cargo_data.get( | 
| 424 | 
            +
             | 
| 425 | 
            +
                        deps = cargo_data.get("dependencies", {})
         | 
| 386 426 | 
             
                        for dep_name in deps.keys():
         | 
| 387 427 | 
             
                            characteristics.key_dependencies.append(dep_name)
         | 
| 388 | 
            -
             | 
| 428 | 
            +
             | 
| 389 429 | 
             
                            # Identify common Rust frameworks
         | 
| 390 | 
            -
                            if dep_name in [ | 
| 430 | 
            +
                            if dep_name in ["actix-web", "warp", "rocket"]:
         | 
| 391 431 | 
             
                                characteristics.web_frameworks.append(dep_name)
         | 
| 392 | 
            -
                            elif dep_name in [ | 
| 432 | 
            +
                            elif dep_name in ["tokio", "async-std"]:
         | 
| 393 433 | 
             
                                characteristics.frameworks.append(dep_name)
         | 
| 394 | 
            -
             | 
| 434 | 
            +
             | 
| 395 435 | 
             
                    except Exception as e:
         | 
| 396 436 | 
             
                        self.logger.warning(f"Error parsing Cargo.toml: {e}")
         | 
| 397 | 
            -
             | 
| 398 | 
            -
                def _analyze_directory_structure( | 
| 437 | 
            +
             | 
| 438 | 
            +
                def _analyze_directory_structure(
         | 
| 439 | 
            +
                    self, characteristics: ProjectCharacteristics
         | 
| 440 | 
            +
                ) -> None:
         | 
| 399 441 | 
             
                    """Analyze directory structure for architecture patterns.
         | 
| 400 | 
            -
             | 
| 442 | 
            +
             | 
| 401 443 | 
             
                    WHY: Directory structure reveals architectural decisions and project
         | 
| 402 444 | 
             
                    organization patterns that agents should understand and follow.
         | 
| 403 | 
            -
             | 
| 445 | 
            +
             | 
| 404 446 | 
             
                    Args:
         | 
| 405 447 | 
             
                        characteristics: ProjectCharacteristics object to update
         | 
| 406 448 | 
             
                    """
         | 
| 407 449 | 
             
                    # Common important directories to look for
         | 
| 408 450 | 
             
                    important_dirs = [
         | 
| 409 | 
            -
                         | 
| 410 | 
            -
                         | 
| 411 | 
            -
                         | 
| 412 | 
            -
                         | 
| 413 | 
            -
                         | 
| 451 | 
            +
                        "src",
         | 
| 452 | 
            +
                        "lib",
         | 
| 453 | 
            +
                        "app",
         | 
| 454 | 
            +
                        "components",
         | 
| 455 | 
            +
                        "services",
         | 
| 456 | 
            +
                        "models",
         | 
| 457 | 
            +
                        "views",
         | 
| 458 | 
            +
                        "controllers",
         | 
| 459 | 
            +
                        "routes",
         | 
| 460 | 
            +
                        "api",
         | 
| 461 | 
            +
                        "web",
         | 
| 462 | 
            +
                        "static",
         | 
| 463 | 
            +
                        "templates",
         | 
| 464 | 
            +
                        "tests",
         | 
| 465 | 
            +
                        "test",
         | 
| 466 | 
            +
                        "__tests__",
         | 
| 467 | 
            +
                        "spec",
         | 
| 468 | 
            +
                        "docs",
         | 
| 469 | 
            +
                        "documentation",
         | 
| 470 | 
            +
                        "config",
         | 
| 471 | 
            +
                        "configs",
         | 
| 472 | 
            +
                        "settings",
         | 
| 473 | 
            +
                        "utils",
         | 
| 474 | 
            +
                        "helpers",
         | 
| 475 | 
            +
                        "core",
         | 
| 476 | 
            +
                        "modules",
         | 
| 477 | 
            +
                        "packages",
         | 
| 478 | 
            +
                        "plugins",
         | 
| 479 | 
            +
                        "extensions",
         | 
| 414 480 | 
             
                    ]
         | 
| 415 | 
            -
             | 
| 481 | 
            +
             | 
| 416 482 | 
             
                    # Check which directories exist
         | 
| 417 483 | 
             
                    existing_dirs = []
         | 
| 418 484 | 
             
                    for dir_name in important_dirs:
         | 
| 419 485 | 
             
                        dir_path = self.working_directory / dir_name
         | 
| 420 486 | 
             
                        if dir_path.exists() and dir_path.is_dir():
         | 
| 421 487 | 
             
                            existing_dirs.append(dir_name)
         | 
| 422 | 
            -
             | 
| 488 | 
            +
             | 
| 423 489 | 
             
                            # Special handling for certain directories
         | 
| 424 | 
            -
                            if dir_name in [ | 
| 490 | 
            +
                            if dir_name in ["src", "lib", "app"]:
         | 
| 425 491 | 
             
                                # These are likely main module directories
         | 
| 426 | 
            -
                                characteristics.main_modules.extend( | 
| 427 | 
            -
             | 
| 492 | 
            +
                                characteristics.main_modules.extend(
         | 
| 493 | 
            +
                                    self._get_subdirectories(dir_path)
         | 
| 494 | 
            +
                                )
         | 
| 495 | 
            +
             | 
| 428 496 | 
             
                    characteristics.key_directories = existing_dirs
         | 
| 429 | 
            -
             | 
| 497 | 
            +
             | 
| 430 498 | 
             
                    # Look for entry points
         | 
| 431 499 | 
             
                    entry_point_patterns = [
         | 
| 432 | 
            -
                         | 
| 433 | 
            -
                         | 
| 434 | 
            -
                         | 
| 500 | 
            +
                        "main.py",
         | 
| 501 | 
            +
                        "app.py",
         | 
| 502 | 
            +
                        "server.py",
         | 
| 503 | 
            +
                        "index.js",
         | 
| 504 | 
            +
                        "main.js",
         | 
| 505 | 
            +
                        "app.js",
         | 
| 506 | 
            +
                        "server.js",
         | 
| 507 | 
            +
                        "main.rs",
         | 
| 508 | 
            +
                        "lib.rs",
         | 
| 509 | 
            +
                        "Main.java",
         | 
| 510 | 
            +
                        "main.go",
         | 
| 511 | 
            +
                        "index.php",
         | 
| 512 | 
            +
                        "application.rb",
         | 
| 435 513 | 
             
                    ]
         | 
| 436 | 
            -
             | 
| 514 | 
            +
             | 
| 437 515 | 
             
                    for pattern in entry_point_patterns:
         | 
| 438 516 | 
             
                        entry_path = self.working_directory / pattern
         | 
| 439 517 | 
             
                        if entry_path.exists():
         | 
| 440 518 | 
             
                            characteristics.entry_points.append(pattern)
         | 
| 441 | 
            -
             | 
| 519 | 
            +
             | 
| 442 520 | 
             
                        # Also check in src/ directory
         | 
| 443 | 
            -
                        src_entry_path = self.working_directory /  | 
| 521 | 
            +
                        src_entry_path = self.working_directory / "src" / pattern
         | 
| 444 522 | 
             
                        if src_entry_path.exists():
         | 
| 445 | 
            -
                            characteristics.entry_points.append(f | 
| 446 | 
            -
             | 
| 523 | 
            +
                            characteristics.entry_points.append(f"src/{pattern}")
         | 
| 524 | 
            +
             | 
| 447 525 | 
             
                def _get_subdirectories(self, path: Path, max_depth: int = 2) -> List[str]:
         | 
| 448 526 | 
             
                    """Get subdirectory names up to a certain depth."""
         | 
| 449 527 | 
             
                    subdirs = []
         | 
| 450 528 | 
             
                    try:
         | 
| 451 529 | 
             
                        for item in path.iterdir():
         | 
| 452 | 
            -
                            if item.is_dir() and not item.name.startswith( | 
| 530 | 
            +
                            if item.is_dir() and not item.name.startswith("."):
         | 
| 453 531 | 
             
                                subdirs.append(item.name)
         | 
| 454 532 | 
             
                                if max_depth > 1:
         | 
| 455 533 | 
             
                                    for subitem in item.iterdir():
         | 
| 456 | 
            -
                                        if subitem.is_dir() and not subitem.name.startswith( | 
| 534 | 
            +
                                        if subitem.is_dir() and not subitem.name.startswith("."):
         | 
| 457 535 | 
             
                                            subdirs.append(f"{item.name}/{subitem.name}")
         | 
| 458 536 | 
             
                    except PermissionError:
         | 
| 459 537 | 
             
                        pass
         | 
| 460 538 | 
             
                    return subdirs[:10]  # Limit to prevent overwhelming output
         | 
| 461 | 
            -
             | 
| 539 | 
            +
             | 
| 462 540 | 
             
                def _analyze_source_code(self, characteristics: ProjectCharacteristics) -> None:
         | 
| 463 541 | 
             
                    """Analyze source code files for patterns and conventions.
         | 
| 464 | 
            -
             | 
| 542 | 
            +
             | 
| 465 543 | 
             
                    WHY: Source code contains the actual implementation patterns that agents
         | 
| 466 544 | 
             
                    should understand and follow. This analysis extracts coding conventions
         | 
| 467 545 | 
             
                    and architectural patterns from the codebase.
         | 
| 468 | 
            -
             | 
| 546 | 
            +
             | 
| 469 547 | 
             
                    Args:
         | 
| 470 548 | 
             
                        characteristics: ProjectCharacteristics object to update
         | 
| 471 549 | 
             
                    """
         | 
| 472 550 | 
             
                    source_extensions = {
         | 
| 473 | 
            -
                         | 
| 474 | 
            -
                         | 
| 475 | 
            -
                         | 
| 476 | 
            -
                         | 
| 477 | 
            -
                         | 
| 478 | 
            -
                         | 
| 479 | 
            -
                         | 
| 480 | 
            -
                         | 
| 481 | 
            -
                         | 
| 482 | 
            -
                         | 
| 483 | 
            -
                         | 
| 484 | 
            -
                         | 
| 485 | 
            -
                         | 
| 551 | 
            +
                        ".py": "python",
         | 
| 552 | 
            +
                        ".js": "javascript",
         | 
| 553 | 
            +
                        ".ts": "typescript",
         | 
| 554 | 
            +
                        ".jsx": "react",
         | 
| 555 | 
            +
                        ".tsx": "react",
         | 
| 556 | 
            +
                        ".rs": "rust",
         | 
| 557 | 
            +
                        ".java": "java",
         | 
| 558 | 
            +
                        ".go": "go",
         | 
| 559 | 
            +
                        ".php": "php",
         | 
| 560 | 
            +
                        ".rb": "ruby",
         | 
| 561 | 
            +
                        ".cpp": "cpp",
         | 
| 562 | 
            +
                        ".cc": "cpp",
         | 
| 563 | 
            +
                        ".c": "c",
         | 
| 486 564 | 
             
                    }
         | 
| 487 | 
            -
             | 
| 565 | 
            +
             | 
| 488 566 | 
             
                    # Find source files
         | 
| 489 567 | 
             
                    source_files = []
         | 
| 490 568 | 
             
                    languages_found = set()
         | 
| 491 | 
            -
             | 
| 569 | 
            +
             | 
| 492 570 | 
             
                    for ext, lang in source_extensions.items():
         | 
| 493 | 
            -
                        files = list(self.working_directory.rglob(f | 
| 571 | 
            +
                        files = list(self.working_directory.rglob(f"*{ext}"))
         | 
| 494 572 | 
             
                        # Filter out node_modules, .git, etc.
         | 
| 495 | 
            -
                        files = [ | 
| 496 | 
            -
             | 
| 573 | 
            +
                        files = [
         | 
| 574 | 
            +
                            f
         | 
| 575 | 
            +
                            for f in files
         | 
| 576 | 
            +
                            if not any(
         | 
| 577 | 
            +
                                part.startswith(".") or part == "node_modules" for part in f.parts
         | 
| 578 | 
            +
                            )
         | 
| 579 | 
            +
                        ]
         | 
| 497 580 | 
             
                        source_files.extend(files)
         | 
| 498 581 | 
             
                        if files:
         | 
| 499 582 | 
             
                            languages_found.add(lang)
         | 
| 500 | 
            -
             | 
| 583 | 
            +
             | 
| 501 584 | 
             
                    # Update languages found
         | 
| 502 | 
            -
                    characteristics.languages.extend( | 
| 503 | 
            -
             | 
| 504 | 
            -
                    
         | 
| 585 | 
            +
                    characteristics.languages.extend(
         | 
| 586 | 
            +
                        [lang for lang in languages_found if lang not in characteristics.languages]
         | 
| 587 | 
            +
                    )
         | 
| 588 | 
            +
             | 
| 505 589 | 
             
                    # Analyze a sample of source files for patterns
         | 
| 506 590 | 
             
                    sample_files = source_files[:20]  # Don't analyze too many files
         | 
| 507 | 
            -
             | 
| 591 | 
            +
             | 
| 508 592 | 
             
                    framework_mentions = Counter()
         | 
| 509 593 | 
             
                    pattern_mentions = Counter()
         | 
| 510 | 
            -
             | 
| 594 | 
            +
             | 
| 511 595 | 
             
                    for file_path in sample_files:
         | 
| 512 596 | 
             
                        try:
         | 
| 513 | 
            -
                            content = file_path.read_text(encoding= | 
| 514 | 
            -
             | 
| 597 | 
            +
                            content = file_path.read_text(encoding="utf-8", errors="ignore")
         | 
| 598 | 
            +
             | 
| 515 599 | 
             
                            # Look for framework patterns
         | 
| 516 600 | 
             
                            for framework, patterns in self.FRAMEWORK_PATTERNS.items():
         | 
| 517 601 | 
             
                                if any(pattern in content for pattern in patterns):
         | 
| 518 602 | 
             
                                    framework_mentions[framework] += 1
         | 
| 519 | 
            -
             | 
| 603 | 
            +
             | 
| 520 604 | 
             
                            # Look for database patterns
         | 
| 521 605 | 
             
                            for db, patterns in self.DATABASE_PATTERNS.items():
         | 
| 522 606 | 
             
                                if any(pattern in content for pattern in patterns):
         | 
| 523 607 | 
             
                                    if db not in characteristics.databases:
         | 
| 524 608 | 
             
                                        characteristics.databases.append(db)
         | 
| 525 | 
            -
             | 
| 609 | 
            +
             | 
| 526 610 | 
             
                            # Look for common patterns
         | 
| 527 | 
            -
                            if  | 
| 528 | 
            -
                                pattern_mentions[ | 
| 529 | 
            -
                            if  | 
| 530 | 
            -
                                pattern_mentions[ | 
| 531 | 
            -
                            if  | 
| 532 | 
            -
                                pattern_mentions[ | 
| 533 | 
            -
                            if  | 
| 534 | 
            -
                                pattern_mentions[ | 
| 535 | 
            -
             | 
| 611 | 
            +
                            if "class " in content and "def __init__" in content:
         | 
| 612 | 
            +
                                pattern_mentions["object_oriented"] += 1
         | 
| 613 | 
            +
                            if "@app.route" in content or "app.get(" in content:
         | 
| 614 | 
            +
                                pattern_mentions["web_routes"] += 1
         | 
| 615 | 
            +
                            if "async def" in content or "async function" in content:
         | 
| 616 | 
            +
                                pattern_mentions["async_programming"] += 1
         | 
| 617 | 
            +
                            if "import pytest" in content or "describe(" in content:
         | 
| 618 | 
            +
                                pattern_mentions["unit_testing"] += 1
         | 
| 619 | 
            +
             | 
| 536 620 | 
             
                        except Exception as e:
         | 
| 537 621 | 
             
                            self.logger.debug(f"Error analyzing {file_path}: {e}")
         | 
| 538 622 | 
             
                            continue
         | 
| 539 | 
            -
             | 
| 623 | 
            +
             | 
| 540 624 | 
             
                    # Add discovered frameworks
         | 
| 541 625 | 
             
                    for framework, count in framework_mentions.most_common(5):
         | 
| 542 626 | 
             
                        if framework not in characteristics.frameworks:
         | 
| 543 627 | 
             
                            characteristics.frameworks.append(framework)
         | 
| 544 | 
            -
             | 
| 628 | 
            +
             | 
| 545 629 | 
             
                    # Add coding conventions based on patterns found
         | 
| 546 630 | 
             
                    for pattern, count in pattern_mentions.most_common():
         | 
| 547 631 | 
             
                        if count >= 2:  # Pattern appears in multiple files
         | 
| 548 | 
            -
                            characteristics.code_conventions.append( | 
| 549 | 
            -
             | 
| 632 | 
            +
                            characteristics.code_conventions.append(
         | 
| 633 | 
            +
                                pattern.replace("_", " ").title()
         | 
| 634 | 
            +
                            )
         | 
| 635 | 
            +
             | 
| 550 636 | 
             
                def _analyze_dependencies(self, characteristics: ProjectCharacteristics) -> None:
         | 
| 551 637 | 
             
                    """Analyze dependencies for integration patterns.
         | 
| 552 | 
            -
             | 
| 638 | 
            +
             | 
| 553 639 | 
             
                    Args:
         | 
| 554 640 | 
             
                        characteristics: ProjectCharacteristics object to update
         | 
| 555 641 | 
             
                    """
         | 
| 556 642 | 
             
                    # This is partially covered by config file analysis
         | 
| 557 643 | 
             
                    # Here we can add more sophisticated dependency analysis
         | 
| 558 | 
            -
             | 
| 644 | 
            +
             | 
| 559 645 | 
             
                    # Look for common integration patterns in dependencies
         | 
| 560 646 | 
             
                    api_indicators = [
         | 
| 561 | 
            -
                         | 
| 562 | 
            -
                         | 
| 647 | 
            +
                        "requests",
         | 
| 648 | 
            +
                        "axios",
         | 
| 649 | 
            +
                        "fetch",
         | 
| 650 | 
            +
                        "http",
         | 
| 651 | 
            +
                        "urllib",
         | 
| 652 | 
            +
                        "rest",
         | 
| 653 | 
            +
                        "graphql",
         | 
| 654 | 
            +
                        "grpc",
         | 
| 655 | 
            +
                        "soap",
         | 
| 563 656 | 
             
                    ]
         | 
| 564 | 
            -
             | 
| 657 | 
            +
             | 
| 565 658 | 
             
                    for dep in characteristics.key_dependencies:
         | 
| 566 659 | 
             
                        dep_lower = dep.lower()
         | 
| 567 660 | 
             
                        for indicator in api_indicators:
         | 
| 568 661 | 
             
                            if indicator in dep_lower:
         | 
| 569 | 
            -
                                if  | 
| 570 | 
            -
                                    characteristics.api_patterns.append( | 
| 662 | 
            +
                                if "REST API" not in characteristics.api_patterns:
         | 
| 663 | 
            +
                                    characteristics.api_patterns.append("REST API")
         | 
| 571 664 | 
             
                                break
         | 
| 572 | 
            -
             | 
| 573 | 
            -
                def _analyze_testing_patterns( | 
| 665 | 
            +
             | 
| 666 | 
            +
                def _analyze_testing_patterns(
         | 
| 667 | 
            +
                    self, characteristics: ProjectCharacteristics
         | 
| 668 | 
            +
                ) -> None:
         | 
| 574 669 | 
             
                    """Analyze testing patterns and frameworks.
         | 
| 575 | 
            -
             | 
| 670 | 
            +
             | 
| 576 671 | 
             
                    Args:
         | 
| 577 672 | 
             
                        characteristics: ProjectCharacteristics object to update
         | 
| 578 673 | 
             
                    """
         | 
| 579 | 
            -
                    test_dirs = [ | 
| 674 | 
            +
                    test_dirs = ["tests", "test", "__tests__", "spec"]
         | 
| 580 675 | 
             
                    test_patterns = []
         | 
| 581 | 
            -
             | 
| 676 | 
            +
             | 
| 582 677 | 
             
                    for test_dir in test_dirs:
         | 
| 583 678 | 
             
                        test_path = self.working_directory / test_dir
         | 
| 584 679 | 
             
                        if test_path.exists() and test_path.is_dir():
         | 
| 585 680 | 
             
                            test_patterns.append(f"Tests in /{test_dir}/ directory")
         | 
| 586 | 
            -
             | 
| 681 | 
            +
             | 
| 587 682 | 
             
                            # Look for test files to understand patterns
         | 
| 588 | 
            -
                            test_files =  | 
| 589 | 
            -
             | 
| 683 | 
            +
                            test_files = (
         | 
| 684 | 
            +
                                list(test_path.rglob("*.py"))
         | 
| 685 | 
            +
                                + list(test_path.rglob("*.js"))
         | 
| 686 | 
            +
                                + list(test_path.rglob("*.ts"))
         | 
| 687 | 
            +
                            )
         | 
| 688 | 
            +
             | 
| 590 689 | 
             
                            for test_file in test_files[:5]:  # Sample a few test files
         | 
| 591 690 | 
             
                                try:
         | 
| 592 | 
            -
                                    content = test_file.read_text(encoding= | 
| 593 | 
            -
             | 
| 594 | 
            -
                                    if  | 
| 691 | 
            +
                                    content = test_file.read_text(encoding="utf-8", errors="ignore")
         | 
| 692 | 
            +
             | 
| 693 | 
            +
                                    if "def test_" in content:
         | 
| 595 694 | 
             
                                        test_patterns.append("Python unittest pattern")
         | 
| 596 | 
            -
                                    if  | 
| 695 | 
            +
                                    if "describe(" in content and "it(" in content:
         | 
| 597 696 | 
             
                                        test_patterns.append("BDD test pattern")
         | 
| 598 | 
            -
                                    if  | 
| 697 | 
            +
                                    if "@pytest.fixture" in content:
         | 
| 599 698 | 
             
                                        test_patterns.append("pytest fixtures")
         | 
| 600 | 
            -
                                    if  | 
| 699 | 
            +
                                    if "beforeEach(" in content or "beforeAll(" in content:
         | 
| 601 700 | 
             
                                        test_patterns.append("Setup/teardown patterns")
         | 
| 602 | 
            -
             | 
| 701 | 
            +
             | 
| 603 702 | 
             
                                except Exception:
         | 
| 604 703 | 
             
                                    continue
         | 
| 605 | 
            -
             | 
| 704 | 
            +
             | 
| 606 705 | 
             
                    characteristics.test_patterns = list(set(test_patterns))
         | 
| 607 | 
            -
             | 
| 706 | 
            +
             | 
| 608 707 | 
             
                def _analyze_documentation(self, characteristics: ProjectCharacteristics) -> None:
         | 
| 609 708 | 
             
                    """Analyze documentation files.
         | 
| 610 | 
            -
             | 
| 709 | 
            +
             | 
| 611 710 | 
             
                    Args:
         | 
| 612 711 | 
             
                        characteristics: ProjectCharacteristics object to update
         | 
| 613 712 | 
             
                    """
         | 
| 614 713 | 
             
                    doc_patterns = [
         | 
| 615 | 
            -
                         | 
| 616 | 
            -
                         | 
| 617 | 
            -
                         | 
| 714 | 
            +
                        "README.md",
         | 
| 715 | 
            +
                        "README.rst",
         | 
| 716 | 
            +
                        "README.txt",
         | 
| 717 | 
            +
                        "CONTRIBUTING.md",
         | 
| 718 | 
            +
                        "CHANGELOG.md",
         | 
| 719 | 
            +
                        "HISTORY.md",
         | 
| 720 | 
            +
                        "docs/",
         | 
| 721 | 
            +
                        "documentation/",
         | 
| 722 | 
            +
                        "wiki/",
         | 
| 618 723 | 
             
                    ]
         | 
| 619 | 
            -
             | 
| 724 | 
            +
             | 
| 620 725 | 
             
                    doc_files = []
         | 
| 621 726 | 
             
                    for pattern in doc_patterns:
         | 
| 622 727 | 
             
                        doc_path = self.working_directory / pattern
         | 
| @@ -625,214 +730,255 @@ class ProjectAnalyzer(ProjectAnalyzerInterface): | |
| 625 730 | 
             
                                doc_files.append(pattern)
         | 
| 626 731 | 
             
                            elif doc_path.is_dir():
         | 
| 627 732 | 
             
                                # Find markdown files in doc directories
         | 
| 628 | 
            -
                                md_files = list(doc_path.rglob( | 
| 629 | 
            -
                                doc_files.extend( | 
| 630 | 
            -
             | 
| 733 | 
            +
                                md_files = list(doc_path.rglob("*.md"))[:10]
         | 
| 734 | 
            +
                                doc_files.extend(
         | 
| 735 | 
            +
                                    [str(f.relative_to(self.working_directory)) for f in md_files]
         | 
| 736 | 
            +
                                )
         | 
| 737 | 
            +
             | 
| 631 738 | 
             
                    characteristics.documentation_files = doc_files
         | 
| 632 | 
            -
             | 
| 739 | 
            +
             | 
| 633 740 | 
             
                def _infer_architecture_type(self, characteristics: ProjectCharacteristics) -> None:
         | 
| 634 741 | 
             
                    """Infer architecture type based on discovered patterns.
         | 
| 635 | 
            -
             | 
| 742 | 
            +
             | 
| 636 743 | 
             
                    Args:
         | 
| 637 744 | 
             
                        characteristics: ProjectCharacteristics object to update
         | 
| 638 745 | 
             
                    """
         | 
| 639 746 | 
             
                    # Simple architecture inference based on patterns
         | 
| 640 | 
            -
                    if any( | 
| 641 | 
            -
                         | 
| 747 | 
            +
                    if any(
         | 
| 748 | 
            +
                        fw in characteristics.web_frameworks
         | 
| 749 | 
            +
                        for fw in ["flask", "django", "express", "fastapi"]
         | 
| 750 | 
            +
                    ):
         | 
| 751 | 
            +
                        if "api" in characteristics.key_directories:
         | 
| 642 752 | 
             
                            characteristics.architecture_type = "REST API Service"
         | 
| 643 753 | 
             
                        else:
         | 
| 644 754 | 
             
                            characteristics.architecture_type = "Web Application"
         | 
| 645 | 
            -
                    elif  | 
| 755 | 
            +
                    elif "services" in characteristics.key_directories:
         | 
| 646 756 | 
             
                        characteristics.architecture_type = "Service-Oriented Architecture"
         | 
| 647 | 
            -
                    elif  | 
| 757 | 
            +
                    elif (
         | 
| 758 | 
            +
                        "modules" in characteristics.key_directories
         | 
| 759 | 
            +
                        or "packages" in characteristics.key_directories
         | 
| 760 | 
            +
                    ):
         | 
| 648 761 | 
             
                        characteristics.architecture_type = "Modular Architecture"
         | 
| 649 | 
            -
                    elif  | 
| 762 | 
            +
                    elif (
         | 
| 763 | 
            +
                        characteristics.primary_language == "python"
         | 
| 764 | 
            +
                        and "cli" in characteristics.main_modules
         | 
| 765 | 
            +
                    ):
         | 
| 650 766 | 
             
                        characteristics.architecture_type = "CLI Application"
         | 
| 651 | 
            -
                    elif any( | 
| 767 | 
            +
                    elif any("react" in fw.lower() for fw in characteristics.frameworks):
         | 
| 652 768 | 
             
                        characteristics.architecture_type = "Single Page Application"
         | 
| 653 769 | 
             
                    else:
         | 
| 654 770 | 
             
                        characteristics.architecture_type = "Standard Application"
         | 
| 655 | 
            -
             | 
| 656 | 
            -
                def _extract_project_terminology( | 
| 771 | 
            +
             | 
| 772 | 
            +
                def _extract_project_terminology(
         | 
| 773 | 
            +
                    self, characteristics: ProjectCharacteristics
         | 
| 774 | 
            +
                ) -> None:
         | 
| 657 775 | 
             
                    """Extract project-specific terminology from various sources.
         | 
| 658 | 
            -
             | 
| 776 | 
            +
             | 
| 659 777 | 
             
                    WHY: Projects often have domain-specific terminology that agents should
         | 
| 660 778 | 
             
                    understand and use consistently.
         | 
| 661 | 
            -
             | 
| 779 | 
            +
             | 
| 662 780 | 
             
                    Args:
         | 
| 663 781 | 
             
                        characteristics: ProjectCharacteristics object to update
         | 
| 664 782 | 
             
                    """
         | 
| 665 783 | 
             
                    terminology = set()
         | 
| 666 | 
            -
             | 
| 784 | 
            +
             | 
| 667 785 | 
             
                    # Extract from project name
         | 
| 668 | 
            -
                    project_words = re.findall(r | 
| 786 | 
            +
                    project_words = re.findall(r"[A-Z][a-z]+|[a-z]+", characteristics.project_name)
         | 
| 669 787 | 
             
                    terminology.update(project_words)
         | 
| 670 | 
            -
             | 
| 788 | 
            +
             | 
| 671 789 | 
             
                    # Extract from directory names
         | 
| 672 790 | 
             
                    for dir_name in characteristics.key_directories:
         | 
| 673 | 
            -
                        words = re.findall(r | 
| 791 | 
            +
                        words = re.findall(r"[A-Z][a-z]+|[a-z]+", dir_name)
         | 
| 674 792 | 
             
                        terminology.update(words)
         | 
| 675 | 
            -
             | 
| 793 | 
            +
             | 
| 676 794 | 
             
                    # Extract from main modules
         | 
| 677 795 | 
             
                    for module in characteristics.main_modules:
         | 
| 678 | 
            -
                        words = re.findall(r | 
| 796 | 
            +
                        words = re.findall(r"[A-Z][a-z]+|[a-z]+", module)
         | 
| 679 797 | 
             
                        terminology.update(words)
         | 
| 680 | 
            -
             | 
| 798 | 
            +
             | 
| 681 799 | 
             
                    # Filter out common words and keep domain-specific terms
         | 
| 682 800 | 
             
                    common_words = {
         | 
| 683 | 
            -
                         | 
| 684 | 
            -
                         | 
| 685 | 
            -
                         | 
| 801 | 
            +
                        "src",
         | 
| 802 | 
            +
                        "lib",
         | 
| 803 | 
            +
                        "app",
         | 
| 804 | 
            +
                        "main",
         | 
| 805 | 
            +
                        "test",
         | 
| 806 | 
            +
                        "tests",
         | 
| 807 | 
            +
                        "docs",
         | 
| 808 | 
            +
                        "config",
         | 
| 809 | 
            +
                        "utils",
         | 
| 810 | 
            +
                        "helpers",
         | 
| 811 | 
            +
                        "core",
         | 
| 812 | 
            +
                        "base",
         | 
| 813 | 
            +
                        "common",
         | 
| 814 | 
            +
                        "shared",
         | 
| 815 | 
            +
                        "public",
         | 
| 816 | 
            +
                        "private",
         | 
| 817 | 
            +
                        "static",
         | 
| 818 | 
            +
                        "assets",
         | 
| 819 | 
            +
                        "build",
         | 
| 820 | 
            +
                        "dist",
         | 
| 821 | 
            +
                        "node",
         | 
| 822 | 
            +
                        "modules",
         | 
| 686 823 | 
             
                    }
         | 
| 687 | 
            -
             | 
| 688 | 
            -
                    domain_terms = [ | 
| 689 | 
            -
             | 
| 690 | 
            -
             | 
| 691 | 
            -
             | 
| 692 | 
            -
             | 
| 824 | 
            +
             | 
| 825 | 
            +
                    domain_terms = [
         | 
| 826 | 
            +
                        term
         | 
| 827 | 
            +
                        for term in terminology
         | 
| 828 | 
            +
                        if len(term) > 3 and term.lower() not in common_words
         | 
| 829 | 
            +
                    ]
         | 
| 830 | 
            +
             | 
| 831 | 
            +
                    characteristics.project_terminology = list(set(domain_terms))[
         | 
| 832 | 
            +
                        :10
         | 
| 833 | 
            +
                    ]  # Limit to most relevant
         | 
| 834 | 
            +
             | 
| 693 835 | 
             
                def get_project_context_summary(self) -> str:
         | 
| 694 836 | 
             
                    """Get a concise summary of project context for memory templates.
         | 
| 695 | 
            -
             | 
| 837 | 
            +
             | 
| 696 838 | 
             
                    WHY: Provides a formatted summary specifically designed for inclusion
         | 
| 697 839 | 
             
                    in agent memory templates, focusing on the most relevant characteristics.
         | 
| 698 | 
            -
             | 
| 840 | 
            +
             | 
| 699 841 | 
             
                    Returns:
         | 
| 700 842 | 
             
                        str: Formatted project context summary
         | 
| 701 843 | 
             
                    """
         | 
| 702 844 | 
             
                    characteristics = self.analyze_project()
         | 
| 703 | 
            -
             | 
| 845 | 
            +
             | 
| 704 846 | 
             
                    summary_parts = []
         | 
| 705 | 
            -
             | 
| 847 | 
            +
             | 
| 706 848 | 
             
                    # Basic project info
         | 
| 707 849 | 
             
                    lang_info = characteristics.primary_language or "mixed"
         | 
| 708 850 | 
             
                    if characteristics.languages and len(characteristics.languages) > 1:
         | 
| 709 | 
            -
                        lang_info =  | 
| 710 | 
            -
             | 
| 711 | 
            -
             | 
| 712 | 
            -
             | 
| 851 | 
            +
                        lang_info = (
         | 
| 852 | 
            +
                            f"{lang_info} (with {', '.join(characteristics.languages[1:3])})"
         | 
| 853 | 
            +
                        )
         | 
| 854 | 
            +
             | 
| 855 | 
            +
                    summary_parts.append(
         | 
| 856 | 
            +
                        f"{characteristics.project_name}: {lang_info} {characteristics.architecture_type.lower()}"
         | 
| 857 | 
            +
                    )
         | 
| 858 | 
            +
             | 
| 713 859 | 
             
                    # Key directories and modules
         | 
| 714 860 | 
             
                    if characteristics.main_modules:
         | 
| 715 861 | 
             
                        modules_str = ", ".join(characteristics.main_modules[:4])
         | 
| 716 862 | 
             
                        summary_parts.append(f"- Main modules: {modules_str}")
         | 
| 717 | 
            -
             | 
| 863 | 
            +
             | 
| 718 864 | 
             
                    # Frameworks and tools
         | 
| 719 865 | 
             
                    if characteristics.frameworks or characteristics.web_frameworks:
         | 
| 720 866 | 
             
                        all_frameworks = characteristics.frameworks + characteristics.web_frameworks
         | 
| 721 867 | 
             
                        frameworks_str = ", ".join(all_frameworks[:3])
         | 
| 722 868 | 
             
                        summary_parts.append(f"- Uses: {frameworks_str}")
         | 
| 723 | 
            -
             | 
| 869 | 
            +
             | 
| 724 870 | 
             
                    # Testing
         | 
| 725 871 | 
             
                    if characteristics.testing_framework:
         | 
| 726 872 | 
             
                        summary_parts.append(f"- Testing: {characteristics.testing_framework}")
         | 
| 727 873 | 
             
                    elif characteristics.test_patterns:
         | 
| 728 874 | 
             
                        summary_parts.append(f"- Testing: {characteristics.test_patterns[0]}")
         | 
| 729 | 
            -
             | 
| 875 | 
            +
             | 
| 730 876 | 
             
                    # Key patterns
         | 
| 731 877 | 
             
                    if characteristics.code_conventions:
         | 
| 732 878 | 
             
                        patterns_str = ", ".join(characteristics.code_conventions[:2])
         | 
| 733 879 | 
             
                        summary_parts.append(f"- Key patterns: {patterns_str}")
         | 
| 734 | 
            -
             | 
| 880 | 
            +
             | 
| 735 881 | 
             
                    return "\n".join(summary_parts)
         | 
| 736 | 
            -
             | 
| 882 | 
            +
             | 
| 737 883 | 
             
                def get_important_files_for_context(self) -> List[str]:
         | 
| 738 884 | 
             
                    """Get list of important files that should be considered for memory context.
         | 
| 739 | 
            -
             | 
| 885 | 
            +
             | 
| 740 886 | 
             
                    WHY: Instead of hardcoding which files to analyze for memory creation,
         | 
| 741 887 | 
             
                    this method dynamically determines the most relevant files based on
         | 
| 742 888 | 
             
                    the actual project structure.
         | 
| 743 | 
            -
             | 
| 889 | 
            +
             | 
| 744 890 | 
             
                    Returns:
         | 
| 745 891 | 
             
                        List[str]: List of file paths relative to project root
         | 
| 746 892 | 
             
                    """
         | 
| 747 893 | 
             
                    characteristics = self.analyze_project()
         | 
| 748 894 | 
             
                    important_files = []
         | 
| 749 | 
            -
             | 
| 895 | 
            +
             | 
| 750 896 | 
             
                    # Always include standard documentation
         | 
| 751 | 
            -
                    standard_docs = [ | 
| 897 | 
            +
                    standard_docs = ["README.md", "CONTRIBUTING.md", "CHANGELOG.md"]
         | 
| 752 898 | 
             
                    for doc in standard_docs:
         | 
| 753 899 | 
             
                        if (self.working_directory / doc).exists():
         | 
| 754 900 | 
             
                            important_files.append(doc)
         | 
| 755 | 
            -
             | 
| 901 | 
            +
             | 
| 756 902 | 
             
                    # Include configuration files
         | 
| 757 903 | 
             
                    important_files.extend(characteristics.important_configs)
         | 
| 758 | 
            -
             | 
| 904 | 
            +
             | 
| 759 905 | 
             
                    # Include project-specific documentation
         | 
| 760 906 | 
             
                    important_files.extend(characteristics.documentation_files[:5])
         | 
| 761 | 
            -
             | 
| 907 | 
            +
             | 
| 762 908 | 
             
                    # Include entry points
         | 
| 763 909 | 
             
                    important_files.extend(characteristics.entry_points)
         | 
| 764 | 
            -
             | 
| 910 | 
            +
             | 
| 765 911 | 
             
                    # Look for architecture documentation
         | 
| 766 | 
            -
                    arch_patterns = [ | 
| 912 | 
            +
                    arch_patterns = ["ARCHITECTURE.md", "docs/architecture.md", "docs/STRUCTURE.md"]
         | 
| 767 913 | 
             
                    for pattern in arch_patterns:
         | 
| 768 914 | 
             
                        if (self.working_directory / pattern).exists():
         | 
| 769 915 | 
             
                            important_files.append(pattern)
         | 
| 770 | 
            -
             | 
| 916 | 
            +
             | 
| 771 917 | 
             
                    # Remove duplicates and return
         | 
| 772 918 | 
             
                    return list(set(important_files))
         | 
| 773 | 
            -
             | 
| 919 | 
            +
             | 
| 774 920 | 
             
                # ================================================================================
         | 
| 775 921 | 
             
                # Interface Adapter Methods
         | 
| 776 922 | 
             
                # ================================================================================
         | 
| 777 923 | 
             
                # These methods adapt the existing implementation to comply with ProjectAnalyzerInterface
         | 
| 778 | 
            -
             | 
| 924 | 
            +
             | 
| 779 925 | 
             
                def detect_technology_stack(self) -> List[str]:
         | 
| 780 926 | 
             
                    """Detect technologies used in the project.
         | 
| 781 | 
            -
             | 
| 927 | 
            +
             | 
| 782 928 | 
             
                    WHY: This adapter method provides interface compliance by extracting
         | 
| 783 929 | 
             
                    technology information from the analyzed project characteristics.
         | 
| 784 | 
            -
             | 
| 930 | 
            +
             | 
| 785 931 | 
             
                    Returns:
         | 
| 786 932 | 
             
                        List of detected technologies
         | 
| 787 933 | 
             
                    """
         | 
| 788 934 | 
             
                    characteristics = self.analyze_project()
         | 
| 789 | 
            -
             | 
| 935 | 
            +
             | 
| 790 936 | 
             
                    technologies = []
         | 
| 791 937 | 
             
                    technologies.extend(characteristics.languages)
         | 
| 792 938 | 
             
                    technologies.extend(characteristics.frameworks)
         | 
| 793 939 | 
             
                    technologies.extend(characteristics.web_frameworks)
         | 
| 794 940 | 
             
                    technologies.extend(characteristics.databases)
         | 
| 795 | 
            -
             | 
| 941 | 
            +
             | 
| 796 942 | 
             
                    # Add package manager as technology
         | 
| 797 943 | 
             
                    if characteristics.package_manager:
         | 
| 798 944 | 
             
                        technologies.append(characteristics.package_manager)
         | 
| 799 | 
            -
             | 
| 945 | 
            +
             | 
| 800 946 | 
             
                    # Add build tools
         | 
| 801 947 | 
             
                    technologies.extend(characteristics.build_tools)
         | 
| 802 | 
            -
             | 
| 948 | 
            +
             | 
| 803 949 | 
             
                    # Remove duplicates
         | 
| 804 950 | 
             
                    return list(set(technologies))
         | 
| 805 | 
            -
             | 
| 951 | 
            +
             | 
| 806 952 | 
             
                def analyze_code_patterns(self) -> Dict[str, Any]:
         | 
| 807 953 | 
             
                    """Analyze code patterns and conventions.
         | 
| 808 | 
            -
             | 
| 954 | 
            +
             | 
| 809 955 | 
             
                    WHY: This adapter method provides interface compliance by extracting
         | 
| 810 956 | 
             
                    pattern information from the project characteristics.
         | 
| 811 | 
            -
             | 
| 957 | 
            +
             | 
| 812 958 | 
             
                    Returns:
         | 
| 813 959 | 
             
                        Dictionary of pattern analysis results
         | 
| 814 960 | 
             
                    """
         | 
| 815 961 | 
             
                    characteristics = self.analyze_project()
         | 
| 816 | 
            -
             | 
| 962 | 
            +
             | 
| 817 963 | 
             
                    return {
         | 
| 818 964 | 
             
                        "code_conventions": characteristics.code_conventions,
         | 
| 819 965 | 
             
                        "test_patterns": characteristics.test_patterns,
         | 
| 820 966 | 
             
                        "api_patterns": characteristics.api_patterns,
         | 
| 821 967 | 
             
                        "configuration_patterns": characteristics.configuration_patterns,
         | 
| 822 | 
            -
                        "architecture_type": characteristics.architecture_type
         | 
| 968 | 
            +
                        "architecture_type": characteristics.architecture_type,
         | 
| 823 969 | 
             
                    }
         | 
| 824 | 
            -
             | 
| 970 | 
            +
             | 
| 825 971 | 
             
                def get_project_structure(self) -> Dict[str, Any]:
         | 
| 826 972 | 
             
                    """Get project directory structure analysis.
         | 
| 827 | 
            -
             | 
| 973 | 
            +
             | 
| 828 974 | 
             
                    WHY: This adapter method provides interface compliance by organizing
         | 
| 829 975 | 
             
                    structural information from the project characteristics.
         | 
| 830 | 
            -
             | 
| 976 | 
            +
             | 
| 831 977 | 
             
                    Returns:
         | 
| 832 978 | 
             
                        Dictionary representing project structure
         | 
| 833 979 | 
             
                    """
         | 
| 834 980 | 
             
                    characteristics = self.analyze_project()
         | 
| 835 | 
            -
             | 
| 981 | 
            +
             | 
| 836 982 | 
             
                    return {
         | 
| 837 983 | 
             
                        "project_name": characteristics.project_name,
         | 
| 838 984 | 
             
                        "main_modules": characteristics.main_modules,
         | 
| @@ -840,25 +986,25 @@ class ProjectAnalyzer(ProjectAnalyzerInterface): | |
| 840 986 | 
             
                        "entry_points": characteristics.entry_points,
         | 
| 841 987 | 
             
                        "documentation_files": characteristics.documentation_files,
         | 
| 842 988 | 
             
                        "important_configs": characteristics.important_configs,
         | 
| 843 | 
            -
                        "architecture_type": characteristics.architecture_type
         | 
| 989 | 
            +
                        "architecture_type": characteristics.architecture_type,
         | 
| 844 990 | 
             
                    }
         | 
| 845 | 
            -
             | 
| 991 | 
            +
             | 
| 846 992 | 
             
                def identify_entry_points(self) -> List[Path]:
         | 
| 847 993 | 
             
                    """Identify project entry points.
         | 
| 848 | 
            -
             | 
| 994 | 
            +
             | 
| 849 995 | 
             
                    WHY: This adapter method provides interface compliance by converting
         | 
| 850 996 | 
             
                    string entry points to Path objects as expected by the interface.
         | 
| 851 | 
            -
             | 
| 997 | 
            +
             | 
| 852 998 | 
             
                    Returns:
         | 
| 853 999 | 
             
                        List of entry point paths
         | 
| 854 1000 | 
             
                    """
         | 
| 855 1001 | 
             
                    characteristics = self.analyze_project()
         | 
| 856 | 
            -
             | 
| 1002 | 
            +
             | 
| 857 1003 | 
             
                    # Convert string paths to Path objects
         | 
| 858 1004 | 
             
                    entry_paths = []
         | 
| 859 1005 | 
             
                    for entry_point in characteristics.entry_points:
         | 
| 860 1006 | 
             
                        entry_path = self.working_directory / entry_point
         | 
| 861 1007 | 
             
                        if entry_path.exists():
         | 
| 862 1008 | 
             
                            entry_paths.append(entry_path)
         | 
| 863 | 
            -
             | 
| 864 | 
            -
                    return entry_paths
         | 
| 1009 | 
            +
             | 
| 1010 | 
            +
                    return entry_paths
         |