claude-mpm 4.1.1__py3-none-any.whl → 4.1.3__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/BUILD_NUMBER +1 -1
- claude_mpm/VERSION +1 -1
- claude_mpm/__main__.py +1 -1
- claude_mpm/agents/BASE_PM.md +74 -46
- claude_mpm/agents/INSTRUCTIONS.md +11 -153
- claude_mpm/agents/WORKFLOW.md +61 -321
- claude_mpm/agents/__init__.py +11 -11
- claude_mpm/agents/agent_loader.py +23 -20
- claude_mpm/agents/agent_loader_integration.py +1 -1
- claude_mpm/agents/agents_metadata.py +27 -0
- claude_mpm/agents/async_agent_loader.py +5 -8
- claude_mpm/agents/base_agent_loader.py +36 -25
- claude_mpm/agents/frontmatter_validator.py +6 -6
- claude_mpm/agents/schema/agent_schema.json +1 -1
- claude_mpm/agents/system_agent_config.py +9 -9
- claude_mpm/agents/templates/api_qa.json +47 -2
- claude_mpm/agents/templates/engineer.json +33 -11
- claude_mpm/agents/templates/imagemagick.json +256 -0
- claude_mpm/agents/templates/qa.json +41 -2
- claude_mpm/agents/templates/ticketing.json +5 -5
- claude_mpm/agents/templates/web_qa.json +50 -2
- claude_mpm/cli/__init__.py +51 -46
- claude_mpm/cli/__main__.py +1 -1
- claude_mpm/cli/commands/__init__.py +10 -12
- claude_mpm/cli/commands/agent_manager.py +186 -181
- claude_mpm/cli/commands/agents.py +648 -1098
- claude_mpm/cli/commands/aggregate.py +30 -29
- claude_mpm/cli/commands/cleanup.py +50 -44
- claude_mpm/cli/commands/cleanup_orphaned_agents.py +25 -25
- claude_mpm/cli/commands/config.py +162 -127
- claude_mpm/cli/commands/doctor.py +52 -62
- claude_mpm/cli/commands/info.py +37 -25
- claude_mpm/cli/commands/mcp.py +3 -7
- claude_mpm/cli/commands/mcp_command_router.py +14 -18
- claude_mpm/cli/commands/mcp_install_commands.py +28 -23
- claude_mpm/cli/commands/mcp_pipx_config.py +58 -49
- claude_mpm/cli/commands/mcp_server_commands.py +23 -17
- claude_mpm/cli/commands/memory.py +339 -967
- claude_mpm/cli/commands/monitor.py +117 -88
- claude_mpm/cli/commands/run.py +233 -542
- claude_mpm/cli/commands/socketio_monitor.py +17 -19
- claude_mpm/cli/commands/tickets.py +92 -92
- claude_mpm/cli/parser.py +1 -5
- claude_mpm/cli/parsers/__init__.py +1 -1
- claude_mpm/cli/parsers/agent_manager_parser.py +50 -98
- claude_mpm/cli/parsers/agents_parser.py +2 -3
- claude_mpm/cli/parsers/base_parser.py +7 -5
- claude_mpm/cli/parsers/mcp_parser.py +4 -2
- claude_mpm/cli/parsers/monitor_parser.py +26 -18
- claude_mpm/cli/shared/__init__.py +10 -10
- claude_mpm/cli/shared/argument_patterns.py +57 -71
- claude_mpm/cli/shared/base_command.py +61 -53
- claude_mpm/cli/shared/error_handling.py +62 -58
- claude_mpm/cli/shared/output_formatters.py +78 -77
- claude_mpm/cli/startup_logging.py +280 -172
- claude_mpm/cli/utils.py +10 -11
- claude_mpm/cli_module/__init__.py +1 -1
- claude_mpm/cli_module/args.py +1 -1
- claude_mpm/cli_module/migration_example.py +5 -5
- claude_mpm/config/__init__.py +9 -9
- claude_mpm/config/agent_config.py +15 -14
- claude_mpm/config/experimental_features.py +4 -4
- claude_mpm/config/paths.py +0 -1
- claude_mpm/config/socketio_config.py +5 -6
- claude_mpm/constants.py +1 -2
- claude_mpm/core/__init__.py +8 -8
- claude_mpm/core/agent_name_normalizer.py +1 -1
- claude_mpm/core/agent_registry.py +22 -29
- claude_mpm/core/agent_session_manager.py +3 -3
- claude_mpm/core/base_service.py +7 -15
- claude_mpm/core/cache.py +4 -6
- claude_mpm/core/claude_runner.py +85 -113
- claude_mpm/core/config.py +43 -28
- claude_mpm/core/config_aliases.py +0 -9
- claude_mpm/core/config_constants.py +52 -30
- claude_mpm/core/constants.py +0 -1
- claude_mpm/core/container.py +18 -27
- claude_mpm/core/exceptions.py +2 -2
- claude_mpm/core/factories.py +10 -12
- claude_mpm/core/framework_loader.py +500 -680
- claude_mpm/core/hook_manager.py +26 -22
- claude_mpm/core/hook_performance_config.py +58 -47
- claude_mpm/core/injectable_service.py +1 -1
- claude_mpm/core/interactive_session.py +61 -152
- claude_mpm/core/interfaces.py +1 -100
- claude_mpm/core/lazy.py +5 -5
- claude_mpm/core/log_manager.py +587 -0
- claude_mpm/core/logger.py +125 -8
- claude_mpm/core/logging_config.py +15 -17
- claude_mpm/core/minimal_framework_loader.py +5 -8
- claude_mpm/core/oneshot_session.py +15 -33
- claude_mpm/core/optimized_agent_loader.py +4 -6
- claude_mpm/core/optimized_startup.py +2 -1
- claude_mpm/core/output_style_manager.py +147 -106
- claude_mpm/core/pm_hook_interceptor.py +0 -1
- claude_mpm/core/service_registry.py +11 -8
- claude_mpm/core/session_manager.py +1 -2
- claude_mpm/core/shared/__init__.py +1 -1
- claude_mpm/core/shared/config_loader.py +101 -97
- claude_mpm/core/shared/path_resolver.py +72 -68
- claude_mpm/core/shared/singleton_manager.py +56 -50
- claude_mpm/core/socketio_pool.py +26 -6
- claude_mpm/core/tool_access_control.py +4 -5
- claude_mpm/core/typing_utils.py +50 -59
- claude_mpm/core/unified_agent_registry.py +14 -19
- claude_mpm/core/unified_config.py +4 -6
- claude_mpm/core/unified_paths.py +197 -109
- claude_mpm/dashboard/open_dashboard.py +2 -4
- claude_mpm/experimental/cli_enhancements.py +51 -36
- claude_mpm/generators/agent_profile_generator.py +2 -4
- claude_mpm/hooks/base_hook.py +1 -2
- claude_mpm/hooks/claude_hooks/connection_pool.py +72 -26
- claude_mpm/hooks/claude_hooks/event_handlers.py +99 -154
- claude_mpm/hooks/claude_hooks/hook_handler.py +110 -720
- claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +104 -77
- claude_mpm/hooks/claude_hooks/hook_handler_original.py +1040 -0
- claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +347 -0
- claude_mpm/hooks/claude_hooks/memory_integration.py +2 -4
- claude_mpm/hooks/claude_hooks/response_tracking.py +15 -11
- claude_mpm/hooks/claude_hooks/services/__init__.py +13 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +190 -0
- claude_mpm/hooks/claude_hooks/services/duplicate_detector.py +106 -0
- claude_mpm/hooks/claude_hooks/services/state_manager.py +282 -0
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +374 -0
- claude_mpm/hooks/claude_hooks/tool_analysis.py +12 -18
- claude_mpm/hooks/memory_integration_hook.py +5 -5
- claude_mpm/hooks/tool_call_interceptor.py +1 -1
- claude_mpm/hooks/validation_hooks.py +4 -4
- claude_mpm/init.py +4 -9
- claude_mpm/models/__init__.py +2 -2
- claude_mpm/models/agent_session.py +11 -14
- claude_mpm/scripts/mcp_server.py +20 -11
- claude_mpm/scripts/mcp_wrapper.py +5 -5
- claude_mpm/scripts/mpm_doctor.py +321 -0
- claude_mpm/scripts/socketio_daemon.py +28 -25
- claude_mpm/scripts/socketio_daemon_hardened.py +298 -258
- claude_mpm/scripts/socketio_server_manager.py +116 -95
- claude_mpm/services/__init__.py +49 -49
- claude_mpm/services/agent_capabilities_service.py +12 -18
- claude_mpm/services/agents/__init__.py +22 -22
- claude_mpm/services/agents/agent_builder.py +140 -119
- claude_mpm/services/agents/deployment/__init__.py +3 -3
- claude_mpm/services/agents/deployment/agent_config_provider.py +9 -9
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +19 -20
- claude_mpm/services/agents/deployment/agent_definition_factory.py +1 -5
- claude_mpm/services/agents/deployment/agent_deployment.py +129 -511
- claude_mpm/services/agents/deployment/agent_discovery_service.py +4 -8
- claude_mpm/services/agents/deployment/agent_environment_manager.py +2 -7
- claude_mpm/services/agents/deployment/agent_filesystem_manager.py +6 -10
- claude_mpm/services/agents/deployment/agent_format_converter.py +11 -15
- claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +2 -3
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +5 -5
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +13 -19
- claude_mpm/services/agents/deployment/agent_restore_handler.py +0 -1
- claude_mpm/services/agents/deployment/agent_template_builder.py +26 -35
- claude_mpm/services/agents/deployment/agent_validator.py +0 -1
- claude_mpm/services/agents/deployment/agent_version_manager.py +7 -9
- claude_mpm/services/agents/deployment/agent_versioning.py +3 -3
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +6 -7
- claude_mpm/services/agents/deployment/async_agent_deployment.py +51 -38
- claude_mpm/services/agents/deployment/base_agent_locator.py +132 -0
- claude_mpm/services/agents/deployment/config/__init__.py +1 -1
- claude_mpm/services/agents/deployment/config/deployment_config.py +7 -8
- claude_mpm/services/agents/deployment/deployment_results_manager.py +185 -0
- claude_mpm/services/agents/deployment/deployment_type_detector.py +1 -1
- claude_mpm/services/agents/deployment/deployment_wrapper.py +18 -18
- claude_mpm/services/agents/deployment/facade/__init__.py +1 -1
- claude_mpm/services/agents/deployment/facade/deployment_executor.py +0 -3
- claude_mpm/services/agents/deployment/facade/deployment_facade.py +3 -4
- claude_mpm/services/agents/deployment/interface_adapter.py +5 -7
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +345 -276
- claude_mpm/services/agents/deployment/pipeline/__init__.py +2 -2
- claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +6 -4
- claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +3 -3
- claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +2 -2
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +14 -13
- claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +0 -1
- claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +8 -9
- claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +1 -1
- claude_mpm/services/agents/deployment/processors/__init__.py +1 -1
- claude_mpm/services/agents/deployment/processors/agent_processor.py +20 -16
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +5 -12
- claude_mpm/services/agents/deployment/results/__init__.py +1 -1
- claude_mpm/services/agents/deployment/results/deployment_result_builder.py +1 -1
- claude_mpm/services/agents/deployment/single_agent_deployer.py +315 -0
- claude_mpm/services/agents/deployment/strategies/__init__.py +2 -2
- claude_mpm/services/agents/deployment/strategies/base_strategy.py +1 -7
- claude_mpm/services/agents/deployment/strategies/project_strategy.py +1 -4
- claude_mpm/services/agents/deployment/strategies/system_strategy.py +2 -3
- claude_mpm/services/agents/deployment/strategies/user_strategy.py +3 -7
- claude_mpm/services/agents/deployment/validation/__init__.py +1 -1
- claude_mpm/services/agents/deployment/validation/agent_validator.py +1 -1
- claude_mpm/services/agents/deployment/validation/template_validator.py +2 -2
- claude_mpm/services/agents/deployment/validation/validation_result.py +2 -6
- claude_mpm/services/agents/loading/__init__.py +1 -1
- claude_mpm/services/agents/loading/agent_profile_loader.py +6 -12
- claude_mpm/services/agents/loading/base_agent_manager.py +5 -5
- claude_mpm/services/agents/loading/framework_agent_loader.py +2 -4
- claude_mpm/services/agents/management/__init__.py +1 -1
- claude_mpm/services/agents/management/agent_capabilities_generator.py +1 -3
- claude_mpm/services/agents/management/agent_management_service.py +5 -9
- claude_mpm/services/agents/memory/__init__.py +4 -4
- claude_mpm/services/agents/memory/agent_memory_manager.py +157 -503
- claude_mpm/services/agents/memory/agent_persistence_service.py +0 -2
- claude_mpm/services/agents/memory/content_manager.py +44 -38
- claude_mpm/services/agents/memory/memory_categorization_service.py +165 -0
- claude_mpm/services/agents/memory/memory_file_service.py +103 -0
- claude_mpm/services/agents/memory/memory_format_service.py +201 -0
- claude_mpm/services/agents/memory/memory_limits_service.py +99 -0
- claude_mpm/services/agents/memory/template_generator.py +4 -6
- claude_mpm/services/agents/registry/__init__.py +11 -7
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +30 -27
- claude_mpm/services/agents/registry/modification_tracker.py +3 -6
- claude_mpm/services/async_session_logger.py +1 -2
- claude_mpm/services/claude_session_logger.py +1 -2
- claude_mpm/services/cli/__init__.py +18 -0
- claude_mpm/services/cli/agent_cleanup_service.py +407 -0
- claude_mpm/services/cli/agent_dependency_service.py +395 -0
- claude_mpm/services/cli/agent_listing_service.py +463 -0
- claude_mpm/services/cli/agent_output_formatter.py +605 -0
- claude_mpm/services/cli/agent_validation_service.py +589 -0
- claude_mpm/services/cli/dashboard_launcher.py +424 -0
- claude_mpm/services/cli/memory_crud_service.py +617 -0
- claude_mpm/services/cli/memory_output_formatter.py +604 -0
- claude_mpm/services/cli/session_manager.py +513 -0
- claude_mpm/services/cli/socketio_manager.py +498 -0
- claude_mpm/services/cli/startup_checker.py +370 -0
- claude_mpm/services/command_deployment_service.py +173 -0
- claude_mpm/services/command_handler_service.py +20 -22
- claude_mpm/services/core/__init__.py +25 -25
- claude_mpm/services/core/base.py +0 -5
- claude_mpm/services/core/cache_manager.py +311 -0
- claude_mpm/services/core/interfaces/__init__.py +32 -32
- claude_mpm/services/core/interfaces/agent.py +0 -21
- claude_mpm/services/core/interfaces/communication.py +0 -27
- claude_mpm/services/core/interfaces/infrastructure.py +0 -56
- claude_mpm/services/core/interfaces/service.py +0 -29
- claude_mpm/services/core/memory_manager.py +637 -0
- claude_mpm/services/core/path_resolver.py +498 -0
- claude_mpm/services/core/service_container.py +520 -0
- claude_mpm/services/core/service_interfaces.py +436 -0
- claude_mpm/services/diagnostics/__init__.py +1 -1
- claude_mpm/services/diagnostics/checks/__init__.py +6 -6
- claude_mpm/services/diagnostics/checks/agent_check.py +152 -97
- claude_mpm/services/diagnostics/checks/base_check.py +12 -16
- claude_mpm/services/diagnostics/checks/claude_desktop_check.py +84 -81
- claude_mpm/services/diagnostics/checks/common_issues_check.py +99 -91
- claude_mpm/services/diagnostics/checks/configuration_check.py +82 -77
- claude_mpm/services/diagnostics/checks/filesystem_check.py +67 -68
- claude_mpm/services/diagnostics/checks/installation_check.py +254 -94
- claude_mpm/services/diagnostics/checks/mcp_check.py +90 -88
- claude_mpm/services/diagnostics/checks/monitor_check.py +75 -76
- claude_mpm/services/diagnostics/checks/startup_log_check.py +67 -73
- claude_mpm/services/diagnostics/diagnostic_runner.py +67 -59
- claude_mpm/services/diagnostics/doctor_reporter.py +107 -70
- claude_mpm/services/diagnostics/models.py +21 -19
- claude_mpm/services/event_aggregator.py +10 -17
- claude_mpm/services/event_bus/__init__.py +1 -1
- claude_mpm/services/event_bus/config.py +54 -35
- claude_mpm/services/event_bus/event_bus.py +76 -71
- claude_mpm/services/event_bus/relay.py +74 -64
- claude_mpm/services/events/__init__.py +11 -11
- claude_mpm/services/events/consumers/__init__.py +3 -3
- claude_mpm/services/events/consumers/dead_letter.py +71 -63
- claude_mpm/services/events/consumers/logging.py +39 -37
- claude_mpm/services/events/consumers/metrics.py +56 -57
- claude_mpm/services/events/consumers/socketio.py +82 -81
- claude_mpm/services/events/core.py +110 -99
- claude_mpm/services/events/interfaces.py +56 -72
- claude_mpm/services/events/producers/__init__.py +1 -1
- claude_mpm/services/events/producers/hook.py +38 -38
- claude_mpm/services/events/producers/system.py +46 -44
- claude_mpm/services/exceptions.py +81 -80
- claude_mpm/services/framework_claude_md_generator/__init__.py +2 -4
- claude_mpm/services/framework_claude_md_generator/content_assembler.py +3 -5
- claude_mpm/services/framework_claude_md_generator/content_validator.py +1 -1
- claude_mpm/services/framework_claude_md_generator/deployment_manager.py +4 -4
- claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +0 -1
- claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +0 -2
- claude_mpm/services/framework_claude_md_generator/version_manager.py +4 -5
- claude_mpm/services/hook_service.py +6 -9
- claude_mpm/services/infrastructure/__init__.py +1 -1
- claude_mpm/services/infrastructure/context_preservation.py +8 -12
- claude_mpm/services/infrastructure/monitoring.py +21 -23
- claude_mpm/services/mcp_gateway/__init__.py +37 -37
- claude_mpm/services/mcp_gateway/auto_configure.py +95 -103
- claude_mpm/services/mcp_gateway/config/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/config/config_loader.py +23 -25
- claude_mpm/services/mcp_gateway/config/config_schema.py +5 -5
- claude_mpm/services/mcp_gateway/config/configuration.py +9 -6
- claude_mpm/services/mcp_gateway/core/__init__.py +10 -10
- claude_mpm/services/mcp_gateway/core/base.py +0 -3
- claude_mpm/services/mcp_gateway/core/interfaces.py +1 -38
- claude_mpm/services/mcp_gateway/core/process_pool.py +99 -93
- claude_mpm/services/mcp_gateway/core/singleton_manager.py +65 -62
- claude_mpm/services/mcp_gateway/core/startup_verification.py +75 -74
- claude_mpm/services/mcp_gateway/main.py +2 -1
- claude_mpm/services/mcp_gateway/registry/service_registry.py +5 -8
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +1 -1
- claude_mpm/services/mcp_gateway/server/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +12 -19
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +4 -3
- claude_mpm/services/mcp_gateway/server/stdio_server.py +79 -71
- claude_mpm/services/mcp_gateway/tools/__init__.py +2 -2
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +5 -6
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +13 -22
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +79 -78
- claude_mpm/services/mcp_gateway/tools/hello_world.py +12 -14
- claude_mpm/services/mcp_gateway/tools/ticket_tools.py +42 -49
- claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +51 -55
- claude_mpm/services/memory/__init__.py +3 -3
- claude_mpm/services/memory/builder.py +3 -6
- claude_mpm/services/memory/cache/__init__.py +1 -1
- claude_mpm/services/memory/cache/shared_prompt_cache.py +3 -5
- claude_mpm/services/memory/cache/simple_cache.py +1 -1
- claude_mpm/services/memory/indexed_memory.py +5 -7
- claude_mpm/services/memory/optimizer.py +7 -10
- claude_mpm/services/memory/router.py +8 -9
- claude_mpm/services/memory_hook_service.py +48 -34
- claude_mpm/services/monitor_build_service.py +77 -73
- claude_mpm/services/port_manager.py +130 -108
- claude_mpm/services/project/analyzer.py +12 -10
- claude_mpm/services/project/registry.py +11 -11
- claude_mpm/services/recovery_manager.py +10 -19
- claude_mpm/services/response_tracker.py +0 -1
- claude_mpm/services/runner_configuration_service.py +19 -20
- claude_mpm/services/session_management_service.py +7 -11
- claude_mpm/services/shared/__init__.py +1 -1
- claude_mpm/services/shared/async_service_base.py +58 -50
- claude_mpm/services/shared/config_service_base.py +73 -67
- claude_mpm/services/shared/lifecycle_service_base.py +82 -78
- claude_mpm/services/shared/manager_base.py +94 -82
- claude_mpm/services/shared/service_factory.py +96 -98
- claude_mpm/services/socketio/__init__.py +3 -3
- claude_mpm/services/socketio/client_proxy.py +5 -5
- claude_mpm/services/socketio/event_normalizer.py +199 -181
- claude_mpm/services/socketio/handlers/__init__.py +3 -3
- claude_mpm/services/socketio/handlers/base.py +5 -4
- claude_mpm/services/socketio/handlers/connection.py +163 -136
- claude_mpm/services/socketio/handlers/file.py +13 -14
- claude_mpm/services/socketio/handlers/git.py +12 -7
- claude_mpm/services/socketio/handlers/hook.py +49 -44
- claude_mpm/services/socketio/handlers/memory.py +0 -1
- claude_mpm/services/socketio/handlers/project.py +0 -1
- claude_mpm/services/socketio/handlers/registry.py +37 -19
- claude_mpm/services/socketio/migration_utils.py +98 -84
- claude_mpm/services/socketio/server/__init__.py +1 -1
- claude_mpm/services/socketio/server/broadcaster.py +81 -87
- claude_mpm/services/socketio/server/core.py +65 -54
- claude_mpm/services/socketio/server/eventbus_integration.py +95 -56
- claude_mpm/services/socketio/server/main.py +64 -38
- claude_mpm/services/socketio_client_manager.py +10 -12
- claude_mpm/services/subprocess_launcher_service.py +4 -7
- claude_mpm/services/system_instructions_service.py +13 -14
- claude_mpm/services/ticket_manager.py +2 -2
- claude_mpm/services/utility_service.py +5 -13
- claude_mpm/services/version_control/__init__.py +16 -16
- claude_mpm/services/version_control/branch_strategy.py +5 -8
- claude_mpm/services/version_control/conflict_resolution.py +9 -23
- claude_mpm/services/version_control/git_operations.py +5 -7
- claude_mpm/services/version_control/semantic_versioning.py +16 -17
- claude_mpm/services/version_control/version_parser.py +13 -18
- claude_mpm/services/version_service.py +10 -11
- claude_mpm/storage/__init__.py +1 -1
- claude_mpm/storage/state_storage.py +22 -28
- claude_mpm/utils/__init__.py +6 -6
- claude_mpm/utils/agent_dependency_loader.py +47 -33
- claude_mpm/utils/config_manager.py +11 -14
- claude_mpm/utils/dependency_cache.py +1 -1
- claude_mpm/utils/dependency_manager.py +13 -17
- claude_mpm/utils/dependency_strategies.py +8 -10
- claude_mpm/utils/environment_context.py +3 -9
- claude_mpm/utils/error_handler.py +3 -13
- claude_mpm/utils/file_utils.py +1 -1
- claude_mpm/utils/path_operations.py +8 -12
- claude_mpm/utils/robust_installer.py +110 -33
- claude_mpm/utils/subprocess_utils.py +5 -6
- claude_mpm/validation/agent_validator.py +3 -6
- claude_mpm/validation/frontmatter_validator.py +1 -1
- {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/METADATA +1 -1
- claude_mpm-4.1.3.dist-info/RECORD +528 -0
- claude_mpm/cli/commands/run_config_checker.py +0 -160
- claude_mpm-4.1.1.dist-info/RECORD +0 -494
- {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/WHEEL +0 -0
- {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/top_level.txt +0 -0
|
@@ -65,12 +65,10 @@ class AgentPersistenceService:
|
|
|
65
65
|
async def start(self) -> None:
|
|
66
66
|
"""Start the persistence service."""
|
|
67
67
|
# No-op for stub
|
|
68
|
-
pass
|
|
69
68
|
|
|
70
69
|
async def stop(self) -> None:
|
|
71
70
|
"""Stop the persistence service."""
|
|
72
71
|
# No-op for stub
|
|
73
|
-
pass
|
|
74
72
|
|
|
75
73
|
async def persist_agent(
|
|
76
74
|
self,
|
|
@@ -67,7 +67,7 @@ class MemoryContentManager:
|
|
|
67
67
|
item_indices.append(i)
|
|
68
68
|
existing_item = line.strip()[2:] # Remove "- " prefix
|
|
69
69
|
similarity = self._calculate_similarity(existing_item, new_item)
|
|
70
|
-
|
|
70
|
+
|
|
71
71
|
# If highly similar (>80%), mark for removal
|
|
72
72
|
if similarity > 0.8:
|
|
73
73
|
items_to_remove.append(i)
|
|
@@ -99,7 +99,7 @@ class MemoryContentManager:
|
|
|
99
99
|
if lines[i].strip():
|
|
100
100
|
insert_point = i + 1
|
|
101
101
|
break
|
|
102
|
-
|
|
102
|
+
|
|
103
103
|
lines.insert(insert_point, f"- {new_item}")
|
|
104
104
|
|
|
105
105
|
# Update timestamp
|
|
@@ -108,12 +108,12 @@ class MemoryContentManager:
|
|
|
108
108
|
|
|
109
109
|
def add_item_to_section(self, content: str, section: str, new_item: str) -> str:
|
|
110
110
|
"""Legacy method for backward compatibility - delegates to add_item_to_list.
|
|
111
|
-
|
|
111
|
+
|
|
112
112
|
Args:
|
|
113
113
|
content: Current memory file content
|
|
114
114
|
section: Section name (ignored in simple list format)
|
|
115
115
|
new_item: Item to add
|
|
116
|
-
|
|
116
|
+
|
|
117
117
|
Returns:
|
|
118
118
|
str: Updated content with new item added
|
|
119
119
|
"""
|
|
@@ -172,12 +172,12 @@ class MemoryContentManager:
|
|
|
172
172
|
# Also check max_items limit
|
|
173
173
|
max_items = limits.get("max_items", 100)
|
|
174
174
|
item_count = sum(1 for line in lines if line.strip().startswith("- "))
|
|
175
|
-
|
|
175
|
+
|
|
176
176
|
if item_count > max_items:
|
|
177
177
|
# Remove oldest items to fit within max_items
|
|
178
178
|
items_removed = 0
|
|
179
179
|
target_removals = item_count - max_items
|
|
180
|
-
|
|
180
|
+
|
|
181
181
|
i = 0
|
|
182
182
|
while i < len(lines) and items_removed < target_removals:
|
|
183
183
|
if lines[i].strip().startswith("- "):
|
|
@@ -187,7 +187,7 @@ class MemoryContentManager:
|
|
|
187
187
|
i += 1
|
|
188
188
|
|
|
189
189
|
return "\n".join(lines)
|
|
190
|
-
|
|
190
|
+
|
|
191
191
|
def truncate_to_limits(
|
|
192
192
|
self, content: str, agent_limits: Optional[Dict[str, Any]] = None
|
|
193
193
|
) -> str:
|
|
@@ -211,12 +211,11 @@ class MemoryContentManager:
|
|
|
211
211
|
content,
|
|
212
212
|
)
|
|
213
213
|
# Also handle legacy format
|
|
214
|
-
|
|
214
|
+
return re.sub(
|
|
215
215
|
r"<!-- Last Updated: .+ \| Auto-updated by: .+ -->",
|
|
216
216
|
f"<!-- Last Updated: {timestamp} -->",
|
|
217
217
|
content,
|
|
218
218
|
)
|
|
219
|
-
return content
|
|
220
219
|
|
|
221
220
|
def validate_and_repair(self, content: str, agent_id: str) -> str:
|
|
222
221
|
"""Validate memory file and repair if needed.
|
|
@@ -232,22 +231,23 @@ class MemoryContentManager:
|
|
|
232
231
|
str: Validated and repaired content
|
|
233
232
|
"""
|
|
234
233
|
lines = content.split("\n")
|
|
235
|
-
|
|
234
|
+
|
|
236
235
|
# Ensure proper header format
|
|
237
236
|
has_header = False
|
|
238
237
|
has_timestamp = False
|
|
239
|
-
|
|
240
|
-
for
|
|
238
|
+
|
|
239
|
+
for _i, line in enumerate(lines[:5]): # Check first 5 lines
|
|
241
240
|
if line.startswith("# Agent Memory:"):
|
|
242
241
|
has_header = True
|
|
243
242
|
elif line.startswith("<!-- Last Updated:"):
|
|
244
243
|
has_timestamp = True
|
|
245
|
-
|
|
244
|
+
|
|
246
245
|
# Add missing header or timestamp
|
|
247
246
|
if not has_header or not has_timestamp:
|
|
248
247
|
from datetime import datetime
|
|
248
|
+
|
|
249
249
|
new_lines = []
|
|
250
|
-
|
|
250
|
+
|
|
251
251
|
if not has_header:
|
|
252
252
|
new_lines.append(f"# Agent Memory: {agent_id}")
|
|
253
253
|
else:
|
|
@@ -257,9 +257,11 @@ class MemoryContentManager:
|
|
|
257
257
|
new_lines.append(line)
|
|
258
258
|
lines.remove(line)
|
|
259
259
|
break
|
|
260
|
-
|
|
260
|
+
|
|
261
261
|
if not has_timestamp:
|
|
262
|
-
new_lines.append(
|
|
262
|
+
new_lines.append(
|
|
263
|
+
f"<!-- Last Updated: {datetime.now().isoformat()}Z -->"
|
|
264
|
+
)
|
|
263
265
|
new_lines.append("")
|
|
264
266
|
else:
|
|
265
267
|
# Keep existing timestamp
|
|
@@ -268,14 +270,16 @@ class MemoryContentManager:
|
|
|
268
270
|
new_lines.append(line)
|
|
269
271
|
lines.remove(line)
|
|
270
272
|
break
|
|
271
|
-
|
|
273
|
+
|
|
272
274
|
# Add remaining content
|
|
273
275
|
for line in lines:
|
|
274
|
-
if not line.startswith("# ") and not line.startswith(
|
|
276
|
+
if not line.startswith("# ") and not line.startswith(
|
|
277
|
+
"<!-- Last Updated:"
|
|
278
|
+
):
|
|
275
279
|
new_lines.append(line)
|
|
276
|
-
|
|
280
|
+
|
|
277
281
|
return "\n".join(new_lines)
|
|
278
|
-
|
|
282
|
+
|
|
279
283
|
return "\n".join(lines)
|
|
280
284
|
|
|
281
285
|
def parse_memory_content_to_list(self, content: str) -> List[str]:
|
|
@@ -296,7 +300,7 @@ class MemoryContentManager:
|
|
|
296
300
|
line = line.strip()
|
|
297
301
|
|
|
298
302
|
# Skip empty lines, headers, and metadata
|
|
299
|
-
if not line or line.startswith("#"
|
|
303
|
+
if not line or line.startswith(("#", "<!--")):
|
|
300
304
|
continue
|
|
301
305
|
|
|
302
306
|
if line.startswith("- "):
|
|
@@ -306,15 +310,15 @@ class MemoryContentManager:
|
|
|
306
310
|
items.append(item)
|
|
307
311
|
|
|
308
312
|
return items
|
|
309
|
-
|
|
313
|
+
|
|
310
314
|
def parse_memory_content_to_dict(self, content: str) -> Dict[str, List[str]]:
|
|
311
315
|
"""Legacy method for backward compatibility.
|
|
312
|
-
|
|
316
|
+
|
|
313
317
|
Returns a dict with single key 'memories' containing all items.
|
|
314
|
-
|
|
318
|
+
|
|
315
319
|
Args:
|
|
316
320
|
content: Raw memory file content
|
|
317
|
-
|
|
321
|
+
|
|
318
322
|
Returns:
|
|
319
323
|
Dict with 'memories' key mapping to list of items
|
|
320
324
|
"""
|
|
@@ -344,23 +348,23 @@ class MemoryContentManager:
|
|
|
344
348
|
# Normalize strings for comparison
|
|
345
349
|
str1_normalized = str1.lower().strip()
|
|
346
350
|
str2_normalized = str2.lower().strip()
|
|
347
|
-
|
|
351
|
+
|
|
348
352
|
# Handle exact matches quickly
|
|
349
353
|
if str1_normalized == str2_normalized:
|
|
350
354
|
return 1.0
|
|
351
|
-
|
|
355
|
+
|
|
352
356
|
# Use SequenceMatcher for fuzzy matching
|
|
353
357
|
# None as first param tells it to use automatic junk heuristic
|
|
354
358
|
matcher = SequenceMatcher(None, str1_normalized, str2_normalized)
|
|
355
359
|
similarity = matcher.ratio()
|
|
356
|
-
|
|
360
|
+
|
|
357
361
|
# Additional check: if one string contains the other (substring match)
|
|
358
362
|
# This catches cases where one item is a more detailed version of another
|
|
359
363
|
if len(str1_normalized) > 20 and len(str2_normalized) > 20:
|
|
360
364
|
if str1_normalized in str2_normalized or str2_normalized in str1_normalized:
|
|
361
365
|
# Boost similarity for substring matches
|
|
362
366
|
similarity = max(similarity, 0.85)
|
|
363
|
-
|
|
367
|
+
|
|
364
368
|
return similarity
|
|
365
369
|
|
|
366
370
|
def deduplicate_list(self, content: str) -> Tuple[str, int]:
|
|
@@ -377,7 +381,7 @@ class MemoryContentManager:
|
|
|
377
381
|
Tuple of (updated content, number of items removed)
|
|
378
382
|
"""
|
|
379
383
|
lines = content.split("\n")
|
|
380
|
-
|
|
384
|
+
|
|
381
385
|
# Collect all items in the list
|
|
382
386
|
items = []
|
|
383
387
|
item_indices = []
|
|
@@ -385,7 +389,7 @@ class MemoryContentManager:
|
|
|
385
389
|
if line.strip().startswith("- "):
|
|
386
390
|
items.append(line.strip()[2:]) # Remove "- " prefix
|
|
387
391
|
item_indices.append(i)
|
|
388
|
-
|
|
392
|
+
|
|
389
393
|
# Find duplicates using pairwise comparison
|
|
390
394
|
duplicates_to_remove = set()
|
|
391
395
|
for i in range(len(items)):
|
|
@@ -403,21 +407,21 @@ class MemoryContentManager:
|
|
|
403
407
|
f"(keeping newer: '{items[j][:50]}...')"
|
|
404
408
|
)
|
|
405
409
|
break # Move to next item
|
|
406
|
-
|
|
410
|
+
|
|
407
411
|
# Remove duplicates (in reverse order to maintain indices)
|
|
408
412
|
removed_count = len(duplicates_to_remove)
|
|
409
413
|
for idx in sorted(duplicates_to_remove, reverse=True):
|
|
410
414
|
lines.pop(item_indices[idx])
|
|
411
|
-
|
|
415
|
+
|
|
412
416
|
return "\n".join(lines), removed_count
|
|
413
|
-
|
|
417
|
+
|
|
414
418
|
def deduplicate_section(self, content: str, section: str) -> Tuple[str, int]:
|
|
415
419
|
"""Legacy method for backward compatibility - delegates to deduplicate_list.
|
|
416
|
-
|
|
420
|
+
|
|
417
421
|
Args:
|
|
418
422
|
content: Current memory file content
|
|
419
423
|
section: Section name (ignored in simple list format)
|
|
420
|
-
|
|
424
|
+
|
|
421
425
|
Returns:
|
|
422
426
|
Tuple of (updated content, number of items removed)
|
|
423
427
|
"""
|
|
@@ -444,7 +448,9 @@ class MemoryContentManager:
|
|
|
444
448
|
)
|
|
445
449
|
|
|
446
450
|
# Check item count
|
|
447
|
-
items = sum(
|
|
451
|
+
items = sum(
|
|
452
|
+
1 for line in content.split("\n") if line.strip().startswith("- ")
|
|
453
|
+
)
|
|
448
454
|
max_items = self.memory_limits.get("max_items", 100)
|
|
449
455
|
|
|
450
456
|
if items > max_items:
|
|
@@ -453,4 +459,4 @@ class MemoryContentManager:
|
|
|
453
459
|
return True, None
|
|
454
460
|
|
|
455
461
|
except Exception as e:
|
|
456
|
-
return False, f"Validation error: {
|
|
462
|
+
return False, f"Validation error: {e!s}"
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Memory Categorization Service - Categorizes learnings into appropriate sections."""
|
|
3
|
+
|
|
4
|
+
import logging
|
|
5
|
+
from typing import List
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class MemoryCategorizationService:
|
|
9
|
+
"""Service for categorizing memory learnings."""
|
|
10
|
+
|
|
11
|
+
# Category keywords for automatic categorization
|
|
12
|
+
CATEGORY_KEYWORDS = {
|
|
13
|
+
"Project Architecture": [
|
|
14
|
+
"architecture",
|
|
15
|
+
"structure",
|
|
16
|
+
"design",
|
|
17
|
+
"pattern",
|
|
18
|
+
"framework",
|
|
19
|
+
"component",
|
|
20
|
+
"module",
|
|
21
|
+
"service",
|
|
22
|
+
"interface",
|
|
23
|
+
"api",
|
|
24
|
+
"endpoint",
|
|
25
|
+
"schema",
|
|
26
|
+
"model",
|
|
27
|
+
"database",
|
|
28
|
+
"microservice",
|
|
29
|
+
],
|
|
30
|
+
"Implementation Guidelines": [
|
|
31
|
+
"implement",
|
|
32
|
+
"code",
|
|
33
|
+
"function",
|
|
34
|
+
"method",
|
|
35
|
+
"class",
|
|
36
|
+
"algorithm",
|
|
37
|
+
"logic",
|
|
38
|
+
"process",
|
|
39
|
+
"workflow",
|
|
40
|
+
"feature",
|
|
41
|
+
"requirement",
|
|
42
|
+
"specification",
|
|
43
|
+
"standard",
|
|
44
|
+
"convention",
|
|
45
|
+
"practice",
|
|
46
|
+
],
|
|
47
|
+
"Common Mistakes to Avoid": [
|
|
48
|
+
"mistake",
|
|
49
|
+
"error",
|
|
50
|
+
"bug",
|
|
51
|
+
"issue",
|
|
52
|
+
"problem",
|
|
53
|
+
"avoid",
|
|
54
|
+
"don't",
|
|
55
|
+
"never",
|
|
56
|
+
"warning",
|
|
57
|
+
"caution",
|
|
58
|
+
"gotcha",
|
|
59
|
+
"pitfall",
|
|
60
|
+
"trap",
|
|
61
|
+
"wrong",
|
|
62
|
+
"incorrect",
|
|
63
|
+
],
|
|
64
|
+
"Current Technical Context": [
|
|
65
|
+
"current",
|
|
66
|
+
"status",
|
|
67
|
+
"context",
|
|
68
|
+
"environment",
|
|
69
|
+
"configuration",
|
|
70
|
+
"setup",
|
|
71
|
+
"version",
|
|
72
|
+
"dependency",
|
|
73
|
+
"tool",
|
|
74
|
+
"library",
|
|
75
|
+
"package",
|
|
76
|
+
"integration",
|
|
77
|
+
"deployment",
|
|
78
|
+
"infrastructure",
|
|
79
|
+
"state",
|
|
80
|
+
],
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
def __init__(self):
|
|
84
|
+
"""Initialize the categorization service."""
|
|
85
|
+
self.logger = logging.getLogger(__name__)
|
|
86
|
+
|
|
87
|
+
def categorize_learning(self, learning: str) -> str:
|
|
88
|
+
"""Categorize a learning item based on its content.
|
|
89
|
+
|
|
90
|
+
WHY: Learnings are automatically organized into categories to make them
|
|
91
|
+
easier to find and review. This uses keyword matching to determine the
|
|
92
|
+
most appropriate category.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
learning: The learning content to categorize
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
Category name (defaults to "Current Technical Context")
|
|
99
|
+
"""
|
|
100
|
+
if not learning:
|
|
101
|
+
return "Current Technical Context"
|
|
102
|
+
|
|
103
|
+
learning_lower = learning.lower()
|
|
104
|
+
category_scores = {}
|
|
105
|
+
|
|
106
|
+
# Score each category based on keyword matches
|
|
107
|
+
for category, keywords in self.CATEGORY_KEYWORDS.items():
|
|
108
|
+
score = sum(1 for keyword in keywords if keyword in learning_lower)
|
|
109
|
+
if score > 0:
|
|
110
|
+
category_scores[category] = score
|
|
111
|
+
|
|
112
|
+
# Return category with highest score, or default
|
|
113
|
+
if category_scores:
|
|
114
|
+
return max(category_scores, key=category_scores.get)
|
|
115
|
+
|
|
116
|
+
return "Current Technical Context"
|
|
117
|
+
|
|
118
|
+
def categorize_learnings_batch(self, learnings: List[str]) -> dict:
|
|
119
|
+
"""Categorize multiple learnings at once.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
learnings: List of learning items to categorize
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
Dictionary mapping categories to lists of learnings
|
|
126
|
+
"""
|
|
127
|
+
categorized = {}
|
|
128
|
+
|
|
129
|
+
for learning in learnings:
|
|
130
|
+
category = self.categorize_learning(learning)
|
|
131
|
+
if category not in categorized:
|
|
132
|
+
categorized[category] = []
|
|
133
|
+
categorized[category].append(learning)
|
|
134
|
+
|
|
135
|
+
return categorized
|
|
136
|
+
|
|
137
|
+
def merge_categorized_learnings(
|
|
138
|
+
self, existing: dict, new: dict, max_per_category: int = 15
|
|
139
|
+
) -> dict:
|
|
140
|
+
"""Merge new categorized learnings with existing ones.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
existing: Existing categorized learnings
|
|
144
|
+
new: New categorized learnings to add
|
|
145
|
+
max_per_category: Maximum items per category
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
Merged categorized learnings with limits applied
|
|
149
|
+
"""
|
|
150
|
+
merged = existing.copy()
|
|
151
|
+
|
|
152
|
+
for category, items in new.items():
|
|
153
|
+
if category not in merged:
|
|
154
|
+
merged[category] = []
|
|
155
|
+
|
|
156
|
+
# Add new items, avoiding duplicates
|
|
157
|
+
for item in items:
|
|
158
|
+
if item not in merged[category]:
|
|
159
|
+
merged[category].append(item)
|
|
160
|
+
|
|
161
|
+
# Apply limit (keep most recent)
|
|
162
|
+
if len(merged[category]) > max_per_category:
|
|
163
|
+
merged[category] = merged[category][-max_per_category:]
|
|
164
|
+
|
|
165
|
+
return merged
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Memory File Service - Handles file operations for agent memories."""
|
|
3
|
+
|
|
4
|
+
import logging
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class MemoryFileService:
|
|
9
|
+
"""Service for handling memory file operations."""
|
|
10
|
+
|
|
11
|
+
def __init__(self, memories_dir: Path):
|
|
12
|
+
"""Initialize the memory file service.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
memories_dir: Directory where memory files are stored
|
|
16
|
+
"""
|
|
17
|
+
self.memories_dir = memories_dir
|
|
18
|
+
self.logger = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
def get_memory_file_with_migration(self, directory: Path, agent_id: str) -> Path:
|
|
21
|
+
"""Get memory file path with migration support.
|
|
22
|
+
|
|
23
|
+
Migrates from old naming convention if needed.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
directory: Directory to check for memory file
|
|
27
|
+
agent_id: Agent identifier
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
Path to the memory file
|
|
31
|
+
"""
|
|
32
|
+
new_file = directory / f"{agent_id}_memories.md"
|
|
33
|
+
old_file = directory / f"{agent_id}_memory.md"
|
|
34
|
+
|
|
35
|
+
# Migrate from old naming convention if needed
|
|
36
|
+
if old_file.exists() and not new_file.exists():
|
|
37
|
+
try:
|
|
38
|
+
old_file.rename(new_file)
|
|
39
|
+
self.logger.info(f"Migrated memory file: {old_file} -> {new_file}")
|
|
40
|
+
except Exception as e:
|
|
41
|
+
self.logger.warning(f"Could not migrate memory file: {e}")
|
|
42
|
+
return old_file
|
|
43
|
+
|
|
44
|
+
return new_file
|
|
45
|
+
|
|
46
|
+
def save_memory_file(self, file_path: Path, content: str) -> bool:
|
|
47
|
+
"""Save content to a memory file.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
file_path: Path to the memory file
|
|
51
|
+
content: Content to save
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
True if saved successfully, False otherwise
|
|
55
|
+
"""
|
|
56
|
+
try:
|
|
57
|
+
# Ensure directory exists
|
|
58
|
+
file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
59
|
+
|
|
60
|
+
# Write content
|
|
61
|
+
file_path.write_text(content)
|
|
62
|
+
|
|
63
|
+
self.logger.debug(f"Saved memory file: {file_path}")
|
|
64
|
+
return True
|
|
65
|
+
|
|
66
|
+
except Exception as e:
|
|
67
|
+
self.logger.error(f"Failed to save memory file {file_path}: {e}")
|
|
68
|
+
return False
|
|
69
|
+
|
|
70
|
+
def ensure_memories_directory(self) -> None:
|
|
71
|
+
"""Ensure the memories directory exists with README."""
|
|
72
|
+
try:
|
|
73
|
+
# Create directory if it doesn't exist
|
|
74
|
+
self.memories_dir.mkdir(parents=True, exist_ok=True)
|
|
75
|
+
|
|
76
|
+
# Create README if it doesn't exist
|
|
77
|
+
readme_path = self.memories_dir / "README.md"
|
|
78
|
+
if not readme_path.exists():
|
|
79
|
+
readme_content = """# Agent Memories Directory
|
|
80
|
+
|
|
81
|
+
This directory contains memory files for various agents used in the project.
|
|
82
|
+
|
|
83
|
+
## File Format
|
|
84
|
+
|
|
85
|
+
Memory files follow the naming convention: `{agent_id}_memories.md`
|
|
86
|
+
|
|
87
|
+
Each file contains:
|
|
88
|
+
- Agent metadata (name, type, version)
|
|
89
|
+
- Project-specific learnings organized by category
|
|
90
|
+
- Timestamps for tracking updates
|
|
91
|
+
|
|
92
|
+
## Auto-generated
|
|
93
|
+
|
|
94
|
+
These files are managed automatically by the agent memory system.
|
|
95
|
+
Manual edits should be done carefully to preserve the format.
|
|
96
|
+
"""
|
|
97
|
+
readme_path.write_text(readme_content)
|
|
98
|
+
self.logger.debug(
|
|
99
|
+
f"Created README in memories directory: {readme_path}"
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
except Exception as e:
|
|
103
|
+
self.logger.error(f"Failed to ensure memories directory: {e}")
|