claude-mpm 4.1.1__py3-none-any.whl → 4.1.2__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/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 +271 -268
- 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 +192 -141
- claude_mpm/cli/commands/monitor.py +117 -88
- claude_mpm/cli/commands/run.py +120 -84
- claude_mpm/cli/commands/run_config_checker.py +4 -5
- 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 +204 -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 +20 -23
- 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 +581 -280
- 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 -15
- 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 +93 -38
- claude_mpm/hooks/claude_hooks/hook_handler.py +130 -76
- claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +104 -77
- 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/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 +136 -106
- 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/config/__init__.py +1 -1
- claude_mpm/services/agents/deployment/config/deployment_config.py +7 -8
- 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/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 +280 -160
- 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/template_generator.py +4 -6
- claude_mpm/services/agents/registry/__init__.py +10 -6
- 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/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/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/diagnostics/__init__.py +1 -1
- claude_mpm/services/diagnostics/checks/__init__.py +6 -6
- claude_mpm/services/diagnostics/checks/agent_check.py +89 -80
- 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.2.dist-info}/METADATA +1 -1
- claude_mpm-4.1.2.dist-info/RECORD +498 -0
- claude_mpm-4.1.1.dist-info/RECORD +0 -494
- {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.2.dist-info}/WHEEL +0 -0
- {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.2.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.2.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.2.dist-info}/top_level.txt +0 -0
|
@@ -94,7 +94,7 @@ class AgentDependencyLoader:
|
|
|
94
94
|
config_file = config_dir / f"{agent_id}.json"
|
|
95
95
|
if config_file.exists():
|
|
96
96
|
try:
|
|
97
|
-
with open(config_file
|
|
97
|
+
with open(config_file) as f:
|
|
98
98
|
config = json.load(f)
|
|
99
99
|
if "dependencies" in config:
|
|
100
100
|
agent_dependencies[agent_id] = config["dependencies"]
|
|
@@ -141,11 +141,10 @@ class AgentDependencyLoader:
|
|
|
141
141
|
# Check if version satisfies requirement
|
|
142
142
|
if req.specifier.contains(version):
|
|
143
143
|
return True, version
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
return False, version
|
|
144
|
+
logger.debug(
|
|
145
|
+
f"{package_name} {version} does not satisfy {req.specifier}"
|
|
146
|
+
)
|
|
147
|
+
return False, version
|
|
149
148
|
|
|
150
149
|
except importlib.metadata.PackageNotFoundError:
|
|
151
150
|
return False, None
|
|
@@ -160,8 +159,7 @@ class AgentDependencyLoader:
|
|
|
160
159
|
|
|
161
160
|
if req.specifier.contains(version):
|
|
162
161
|
return True, version
|
|
163
|
-
|
|
164
|
-
return False, version
|
|
162
|
+
return False, version
|
|
165
163
|
|
|
166
164
|
except pkg_resources.DistributionNotFound:
|
|
167
165
|
return False, None
|
|
@@ -277,8 +275,6 @@ class AgentDependencyLoader:
|
|
|
277
275
|
"re",
|
|
278
276
|
"difflib",
|
|
279
277
|
"textwrap",
|
|
280
|
-
"unicodedata",
|
|
281
|
-
"stringprep",
|
|
282
278
|
"calendar",
|
|
283
279
|
"locale",
|
|
284
280
|
"gettext",
|
|
@@ -335,7 +331,11 @@ class AgentDependencyLoader:
|
|
|
335
331
|
"""
|
|
336
332
|
try:
|
|
337
333
|
result = subprocess.run(
|
|
338
|
-
["which", command],
|
|
334
|
+
["which", command],
|
|
335
|
+
capture_output=True,
|
|
336
|
+
text=True,
|
|
337
|
+
timeout=5,
|
|
338
|
+
check=False,
|
|
339
339
|
)
|
|
340
340
|
return result.returncode == 0
|
|
341
341
|
except Exception:
|
|
@@ -374,15 +374,14 @@ class AgentDependencyLoader:
|
|
|
374
374
|
agent_result["python"]["satisfied"].append(dep_spec)
|
|
375
375
|
if dep_spec not in results["summary"]["satisfied_python"]:
|
|
376
376
|
results["summary"]["satisfied_python"].append(dep_spec)
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
results["summary"]["missing_python"].append(dep_spec)
|
|
377
|
+
elif version: # Installed but wrong version
|
|
378
|
+
agent_result["python"]["outdated"].append(
|
|
379
|
+
f"{dep_spec} (have {version})"
|
|
380
|
+
)
|
|
381
|
+
else: # Not installed
|
|
382
|
+
agent_result["python"]["missing"].append(dep_spec)
|
|
383
|
+
if dep_spec not in results["summary"]["missing_python"]:
|
|
384
|
+
results["summary"]["missing_python"].append(dep_spec)
|
|
386
385
|
|
|
387
386
|
# Check system dependencies
|
|
388
387
|
if "system" in deps:
|
|
@@ -416,7 +415,6 @@ class AgentDependencyLoader:
|
|
|
416
415
|
"""
|
|
417
416
|
import sys
|
|
418
417
|
|
|
419
|
-
current_version = f"{sys.version_info.major}.{sys.version_info.minor}"
|
|
420
418
|
compatible = []
|
|
421
419
|
incompatible = []
|
|
422
420
|
|
|
@@ -428,10 +426,10 @@ class AgentDependencyLoader:
|
|
|
428
426
|
|
|
429
427
|
# Known Python 3.13 incompatibilities
|
|
430
428
|
if sys.version_info >= (3, 13):
|
|
431
|
-
if
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
429
|
+
if (
|
|
430
|
+
package_name in ["ydata-profiling", "pandas-profiling"]
|
|
431
|
+
or package_name == "apache-airflow"
|
|
432
|
+
):
|
|
435
433
|
incompatible.append(f"{dep} (requires Python <3.13)")
|
|
436
434
|
continue
|
|
437
435
|
|
|
@@ -532,10 +530,27 @@ class AgentDependencyLoader:
|
|
|
532
530
|
"Robust installer not available, falling back to simple installation"
|
|
533
531
|
)
|
|
534
532
|
try:
|
|
535
|
-
cmd = [sys.executable, "-m", "pip", "install"]
|
|
533
|
+
cmd = [sys.executable, "-m", "pip", "install"]
|
|
534
|
+
|
|
535
|
+
# Check for PEP 668 managed environment
|
|
536
|
+
import sysconfig
|
|
537
|
+
|
|
538
|
+
stdlib_path = sysconfig.get_path("stdlib")
|
|
539
|
+
marker_file = Path(stdlib_path) / "EXTERNALLY-MANAGED"
|
|
540
|
+
parent_marker = marker_file.parent.parent / "EXTERNALLY-MANAGED"
|
|
541
|
+
|
|
542
|
+
if marker_file.exists() or parent_marker.exists():
|
|
543
|
+
logger.warning(
|
|
544
|
+
"PEP 668 managed environment detected. "
|
|
545
|
+
"Installing with --break-system-packages --user flags. "
|
|
546
|
+
"Consider using a virtual environment instead."
|
|
547
|
+
)
|
|
548
|
+
cmd.extend(["--break-system-packages", "--user"])
|
|
549
|
+
|
|
550
|
+
cmd.extend(compatible)
|
|
536
551
|
|
|
537
552
|
result = subprocess.run(
|
|
538
|
-
cmd, capture_output=True, text=True, timeout=300
|
|
553
|
+
cmd, capture_output=True, text=True, timeout=300, check=False
|
|
539
554
|
)
|
|
540
555
|
|
|
541
556
|
if result.returncode == 0:
|
|
@@ -546,10 +561,9 @@ class AgentDependencyLoader:
|
|
|
546
561
|
f"Installed {len(compatible)} packages, skipped {len(incompatible)} incompatible",
|
|
547
562
|
)
|
|
548
563
|
return True, ""
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
return False, error_msg
|
|
564
|
+
error_msg = f"Installation failed: {result.stderr}"
|
|
565
|
+
logger.error(error_msg)
|
|
566
|
+
return False, error_msg
|
|
553
567
|
|
|
554
568
|
except Exception as e:
|
|
555
569
|
error_msg = f"Failed to install dependencies: {e}"
|
|
@@ -765,7 +779,7 @@ class AgentDependencyLoader:
|
|
|
765
779
|
except Exception as e:
|
|
766
780
|
logger.debug(f"Could not hash agent file {agent_path}: {e}")
|
|
767
781
|
# Include error in hash to force recheck on next run
|
|
768
|
-
hash_obj.update(f"error:{agent_id}:{e}".encode(
|
|
782
|
+
hash_obj.update(f"error:{agent_id}:{e}".encode())
|
|
769
783
|
|
|
770
784
|
return hash_obj.hexdigest()
|
|
771
785
|
|
|
@@ -780,7 +794,7 @@ class AgentDependencyLoader:
|
|
|
780
794
|
return {}
|
|
781
795
|
|
|
782
796
|
try:
|
|
783
|
-
with open(self.deployment_state_file
|
|
797
|
+
with open(self.deployment_state_file) as f:
|
|
784
798
|
return json.load(f)
|
|
785
799
|
except Exception as e:
|
|
786
800
|
logger.debug(f"Could not load deployment state: {e}")
|
|
@@ -6,7 +6,6 @@ configurations across different file formats (JSON, YAML, TOML).
|
|
|
6
6
|
|
|
7
7
|
import json
|
|
8
8
|
import os
|
|
9
|
-
from functools import lru_cache
|
|
10
9
|
from pathlib import Path
|
|
11
10
|
from typing import Any, Dict, List, Optional, Union
|
|
12
11
|
|
|
@@ -56,7 +55,7 @@ class ConfigurationManager:
|
|
|
56
55
|
try:
|
|
57
56
|
cache_key = self._get_cache_key(file_path)
|
|
58
57
|
return self._cache.get(cache_key)
|
|
59
|
-
except
|
|
58
|
+
except OSError:
|
|
60
59
|
return None
|
|
61
60
|
|
|
62
61
|
def _update_cache(self, file_path: Union[str, Path], config: Dict[str, Any]):
|
|
@@ -67,7 +66,7 @@ class ConfigurationManager:
|
|
|
67
66
|
try:
|
|
68
67
|
cache_key = self._get_cache_key(file_path)
|
|
69
68
|
self._cache[cache_key] = config
|
|
70
|
-
except
|
|
69
|
+
except OSError:
|
|
71
70
|
pass
|
|
72
71
|
|
|
73
72
|
def clear_cache(self):
|
|
@@ -100,7 +99,7 @@ class ConfigurationManager:
|
|
|
100
99
|
|
|
101
100
|
logger.debug(f"Loading JSON configuration from {file_path}")
|
|
102
101
|
try:
|
|
103
|
-
with open(file_path,
|
|
102
|
+
with open(file_path, encoding="utf-8") as f:
|
|
104
103
|
config = json.load(f)
|
|
105
104
|
self._update_cache(file_path, config)
|
|
106
105
|
return config
|
|
@@ -143,7 +142,7 @@ class ConfigurationManager:
|
|
|
143
142
|
|
|
144
143
|
logger.debug(f"Loading YAML configuration from {file_path}")
|
|
145
144
|
try:
|
|
146
|
-
with open(file_path,
|
|
145
|
+
with open(file_path, encoding="utf-8") as f:
|
|
147
146
|
config = yaml.safe_load(f) or {}
|
|
148
147
|
self._update_cache(file_path, config)
|
|
149
148
|
return config
|
|
@@ -186,7 +185,7 @@ class ConfigurationManager:
|
|
|
186
185
|
|
|
187
186
|
logger.debug(f"Loading TOML configuration from {file_path}")
|
|
188
187
|
try:
|
|
189
|
-
with open(file_path,
|
|
188
|
+
with open(file_path, encoding="utf-8") as f:
|
|
190
189
|
config = toml.load(f)
|
|
191
190
|
self._update_cache(file_path, config)
|
|
192
191
|
return config
|
|
@@ -215,12 +214,11 @@ class ConfigurationManager:
|
|
|
215
214
|
|
|
216
215
|
if suffix in [".json"]:
|
|
217
216
|
return self.load_json(file_path)
|
|
218
|
-
|
|
217
|
+
if suffix in [".yaml", ".yml"]:
|
|
219
218
|
return self.load_yaml(file_path)
|
|
220
|
-
|
|
219
|
+
if suffix in [".toml"]:
|
|
221
220
|
return self.load_toml(file_path)
|
|
222
|
-
|
|
223
|
-
raise ValueError(f"Unsupported configuration format: {suffix}")
|
|
221
|
+
raise ValueError(f"Unsupported configuration format: {suffix}")
|
|
224
222
|
|
|
225
223
|
def save_json(
|
|
226
224
|
self,
|
|
@@ -461,12 +459,11 @@ class ConfigurationManager:
|
|
|
461
459
|
result = result.replace(placeholder, env_value)
|
|
462
460
|
|
|
463
461
|
return result
|
|
464
|
-
|
|
462
|
+
if isinstance(value, dict):
|
|
465
463
|
return {k: _interpolate_value(v) for k, v in value.items()}
|
|
466
|
-
|
|
464
|
+
if isinstance(value, list):
|
|
467
465
|
return [_interpolate_value(item) for item in value]
|
|
468
|
-
|
|
469
|
-
return value
|
|
466
|
+
return value
|
|
470
467
|
|
|
471
468
|
return _interpolate_value(config)
|
|
472
469
|
|
|
@@ -9,7 +9,6 @@ DESIGN DECISION: We use subprocess to install packages in the same environment
|
|
|
9
9
|
that's running claude-mpm, respecting virtual environments and user setups.
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
|
-
import importlib
|
|
13
12
|
import subprocess
|
|
14
13
|
import sys
|
|
15
14
|
from typing import List, Optional, Tuple
|
|
@@ -70,7 +69,7 @@ def install_packages(packages: List[str], logger=None) -> Tuple[bool, str]:
|
|
|
70
69
|
|
|
71
70
|
try:
|
|
72
71
|
# Use the same Python executable that's running this script
|
|
73
|
-
cmd = [sys.executable, "-m", "pip", "install"
|
|
72
|
+
cmd = [sys.executable, "-m", "pip", "install", *packages]
|
|
74
73
|
|
|
75
74
|
logger.info(f"Installing packages: {packages}")
|
|
76
75
|
logger.debug(f"Running command: {' '.join(cmd)}")
|
|
@@ -80,18 +79,18 @@ def install_packages(packages: List[str], logger=None) -> Tuple[bool, str]:
|
|
|
80
79
|
cmd,
|
|
81
80
|
capture_output=True,
|
|
82
81
|
text=True,
|
|
83
|
-
timeout=300,
|
|
82
|
+
timeout=300,
|
|
83
|
+
check=False, # 5 minute timeout for installation
|
|
84
84
|
)
|
|
85
85
|
|
|
86
86
|
if result.returncode == 0:
|
|
87
87
|
logger.info(f"Successfully installed packages: {packages}")
|
|
88
88
|
return True, ""
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
return False, error_msg
|
|
89
|
+
error_msg = f"pip install failed with return code {result.returncode}"
|
|
90
|
+
if result.stderr:
|
|
91
|
+
error_msg += f": {result.stderr.strip()}"
|
|
92
|
+
logger.error(error_msg)
|
|
93
|
+
return False, error_msg
|
|
95
94
|
|
|
96
95
|
except subprocess.TimeoutExpired:
|
|
97
96
|
error_msg = "Package installation timed out after 5 minutes"
|
|
@@ -163,8 +162,7 @@ def ensure_socketio_dependencies(logger=None) -> Tuple[bool, str]:
|
|
|
163
162
|
|
|
164
163
|
logger.info("Socket.IO dependencies installed and verified successfully")
|
|
165
164
|
return True, ""
|
|
166
|
-
|
|
167
|
-
return False, error_msg
|
|
165
|
+
return False, error_msg
|
|
168
166
|
|
|
169
167
|
|
|
170
168
|
def get_pip_freeze_output() -> List[str]:
|
|
@@ -183,12 +181,12 @@ def get_pip_freeze_output() -> List[str]:
|
|
|
183
181
|
capture_output=True,
|
|
184
182
|
text=True,
|
|
185
183
|
timeout=30,
|
|
184
|
+
check=False,
|
|
186
185
|
)
|
|
187
186
|
|
|
188
187
|
if result.returncode == 0:
|
|
189
188
|
return result.stdout.strip().split("\n")
|
|
190
|
-
|
|
191
|
-
return [f"pip freeze failed: {result.stderr}"]
|
|
189
|
+
return [f"pip freeze failed: {result.stderr}"]
|
|
192
190
|
|
|
193
191
|
except Exception as e:
|
|
194
192
|
return [f"Failed to get pip freeze output: {e}"]
|
|
@@ -206,8 +204,7 @@ def check_virtual_environment() -> Tuple[bool, str]:
|
|
|
206
204
|
"""
|
|
207
205
|
# Check for virtual environment indicators
|
|
208
206
|
in_venv = (
|
|
209
|
-
hasattr(sys, "base_prefix")
|
|
210
|
-
and sys.base_prefix != sys.prefix
|
|
207
|
+
(hasattr(sys, "base_prefix") and sys.base_prefix != sys.prefix)
|
|
211
208
|
or hasattr(sys, "real_prefix")
|
|
212
209
|
or (hasattr(sys, "prefix") and "conda" in sys.prefix.lower())
|
|
213
210
|
)
|
|
@@ -215,5 +212,4 @@ def check_virtual_environment() -> Tuple[bool, str]:
|
|
|
215
212
|
if in_venv:
|
|
216
213
|
venv_path = getattr(sys, "prefix", "unknown")
|
|
217
214
|
return True, f"Virtual environment: {venv_path}"
|
|
218
|
-
|
|
219
|
-
return False, f"System Python: {sys.prefix}"
|
|
215
|
+
return False, f"System Python: {sys.prefix}"
|
|
@@ -10,7 +10,6 @@ based on the execution context and user preferences.
|
|
|
10
10
|
import json
|
|
11
11
|
import os
|
|
12
12
|
import sys
|
|
13
|
-
import time
|
|
14
13
|
from datetime import datetime, timedelta
|
|
15
14
|
from enum import Enum
|
|
16
15
|
from typing import Any, Dict, Optional, Tuple
|
|
@@ -256,16 +255,15 @@ class DependencyStrategy:
|
|
|
256
255
|
|
|
257
256
|
if response in ["y", "yes"]:
|
|
258
257
|
return "yes"
|
|
259
|
-
|
|
258
|
+
if response in ["n", "no", ""]:
|
|
260
259
|
return "no"
|
|
261
|
-
|
|
260
|
+
if response == "always":
|
|
262
261
|
self._save_preference(DependencyMode.AUTO)
|
|
263
262
|
return "yes"
|
|
264
|
-
|
|
263
|
+
if response == "never":
|
|
265
264
|
self._save_preference(DependencyMode.OFF)
|
|
266
265
|
return "no"
|
|
267
|
-
|
|
268
|
-
print("Invalid choice. Please enter: y, n, always, or never")
|
|
266
|
+
print("Invalid choice. Please enter: y, n, always, or never")
|
|
269
267
|
|
|
270
268
|
def _save_preference(self, mode: DependencyMode) -> None:
|
|
271
269
|
"""
|
|
@@ -366,13 +364,13 @@ def lazy_check_agent_dependency(agent_id: str) -> bool:
|
|
|
366
364
|
success, _ = loader.install_missing_dependencies(missing)
|
|
367
365
|
return success
|
|
368
366
|
|
|
369
|
-
|
|
367
|
+
if strategy.mode == DependencyMode.INTERACTIVE:
|
|
370
368
|
choice = strategy.prompt_for_installation(missing)
|
|
371
369
|
if choice in ["yes"]:
|
|
372
370
|
success, _ = loader.install_missing_dependencies(missing)
|
|
373
371
|
return success
|
|
374
372
|
return False
|
|
375
373
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
374
|
+
# CHECK or OFF
|
|
375
|
+
logger.warning(f"Agent {agent_id} missing {len(missing)} dependencies")
|
|
376
|
+
return False # Proceed anyway
|
|
@@ -127,10 +127,7 @@ class EnvironmentContext:
|
|
|
127
127
|
return True
|
|
128
128
|
|
|
129
129
|
# Additional heuristics for CI detection
|
|
130
|
-
|
|
131
|
-
return True
|
|
132
|
-
|
|
133
|
-
return False
|
|
130
|
+
return bool(os.environ.get("BUILD_ID") or os.environ.get("BUILD_NUMBER"))
|
|
134
131
|
|
|
135
132
|
@classmethod
|
|
136
133
|
def _detect_docker(cls) -> bool:
|
|
@@ -152,7 +149,7 @@ class EnvironmentContext:
|
|
|
152
149
|
|
|
153
150
|
# Check cgroup for docker/containerd references
|
|
154
151
|
try:
|
|
155
|
-
with open("/proc/1/cgroup"
|
|
152
|
+
with open("/proc/1/cgroup") as f:
|
|
156
153
|
cgroup_content = f.read()
|
|
157
154
|
if "docker" in cgroup_content or "containerd" in cgroup_content:
|
|
158
155
|
return True
|
|
@@ -196,10 +193,7 @@ class EnvironmentContext:
|
|
|
196
193
|
pass
|
|
197
194
|
|
|
198
195
|
# Check for Jupyter-specific environment variables
|
|
199
|
-
|
|
200
|
-
return True
|
|
201
|
-
|
|
202
|
-
return False
|
|
196
|
+
return "JPY_PARENT_PID" in os.environ
|
|
203
197
|
|
|
204
198
|
@classmethod
|
|
205
199
|
def _detect_ssh(cls) -> bool:
|
|
@@ -6,7 +6,6 @@ Inspired by awesome-claude-code's comprehensive error handling approach.
|
|
|
6
6
|
|
|
7
7
|
import logging
|
|
8
8
|
import sys
|
|
9
|
-
import traceback
|
|
10
9
|
from datetime import datetime
|
|
11
10
|
from functools import wraps
|
|
12
11
|
from typing import Any, Callable, Dict, List, Optional, Type
|
|
@@ -31,7 +30,7 @@ class MPMError(Exception):
|
|
|
31
30
|
|
|
32
31
|
def get_user_friendly_message(self) -> str:
|
|
33
32
|
"""Get a user-friendly error message."""
|
|
34
|
-
lines = [f"❌ Error: {
|
|
33
|
+
lines = [f"❌ Error: {self!s}"]
|
|
35
34
|
|
|
36
35
|
if self.details:
|
|
37
36
|
lines.append("\nDetails:")
|
|
@@ -49,26 +48,18 @@ class MPMError(Exception):
|
|
|
49
48
|
class AgentLoadError(MPMError):
|
|
50
49
|
"""Raised when agent loading fails."""
|
|
51
50
|
|
|
52
|
-
pass
|
|
53
|
-
|
|
54
51
|
|
|
55
52
|
class ValidationError(MPMError):
|
|
56
53
|
"""Raised when validation fails."""
|
|
57
54
|
|
|
58
|
-
pass
|
|
59
|
-
|
|
60
55
|
|
|
61
56
|
class ExecutionError(MPMError):
|
|
62
57
|
"""Raised when agent execution fails."""
|
|
63
58
|
|
|
64
|
-
pass
|
|
65
|
-
|
|
66
59
|
|
|
67
60
|
class ConfigurationError(MPMError):
|
|
68
61
|
"""Raised when configuration is invalid."""
|
|
69
62
|
|
|
70
|
-
pass
|
|
71
|
-
|
|
72
63
|
|
|
73
64
|
def handle_errors(
|
|
74
65
|
error_type: Type[Exception] = Exception,
|
|
@@ -131,7 +122,7 @@ class ErrorContext:
|
|
|
131
122
|
"""Exit the context, handling any errors."""
|
|
132
123
|
if exc_type is None:
|
|
133
124
|
logger.debug(f"Completed operation: {self.operation}")
|
|
134
|
-
return
|
|
125
|
+
return None
|
|
135
126
|
|
|
136
127
|
# Log the error with context
|
|
137
128
|
logger.error(
|
|
@@ -216,8 +207,7 @@ def retry_on_error(
|
|
|
216
207
|
|
|
217
208
|
if asyncio.iscoroutinefunction(func):
|
|
218
209
|
return async_wrapper
|
|
219
|
-
|
|
220
|
-
return sync_wrapper
|
|
210
|
+
return sync_wrapper
|
|
221
211
|
|
|
222
212
|
return decorator
|
|
223
213
|
|
claude_mpm/utils/file_utils.py
CHANGED
|
@@ -61,7 +61,7 @@ def safe_read_file(path: Union[str, Path], encoding: str = "utf-8") -> str:
|
|
|
61
61
|
path = Path(path)
|
|
62
62
|
try:
|
|
63
63
|
return path.read_text(encoding=encoding)
|
|
64
|
-
except FileNotFoundError
|
|
64
|
+
except FileNotFoundError:
|
|
65
65
|
raise FileOperationError(
|
|
66
66
|
f"File not found: {path}",
|
|
67
67
|
context={
|
|
@@ -135,7 +135,7 @@ class PathOperations:
|
|
|
135
135
|
logger.warning(f"File not readable: {path}")
|
|
136
136
|
return default
|
|
137
137
|
|
|
138
|
-
with open(path_obj,
|
|
138
|
+
with open(path_obj, encoding=encoding) as f:
|
|
139
139
|
return f.read()
|
|
140
140
|
except Exception as e:
|
|
141
141
|
logger.error(f"Error reading file {path}: {e}")
|
|
@@ -307,13 +307,12 @@ class PathOperations:
|
|
|
307
307
|
|
|
308
308
|
if path_obj.is_file():
|
|
309
309
|
return path_obj.stat().st_size
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
return total
|
|
310
|
+
# Calculate total size for directory
|
|
311
|
+
total = 0
|
|
312
|
+
for item in path_obj.rglob("*"):
|
|
313
|
+
if item.is_file():
|
|
314
|
+
total += item.stat().st_size
|
|
315
|
+
return total
|
|
317
316
|
|
|
318
317
|
except Exception as e:
|
|
319
318
|
logger.error(f"Error getting size of {path}: {e}")
|
|
@@ -343,10 +342,7 @@ class PathOperations:
|
|
|
343
342
|
logger.error(f"Not a directory: {path}")
|
|
344
343
|
return []
|
|
345
344
|
|
|
346
|
-
if recursive
|
|
347
|
-
items = path_obj.rglob(pattern)
|
|
348
|
-
else:
|
|
349
|
-
items = path_obj.glob(pattern)
|
|
345
|
+
items = path_obj.rglob(pattern) if recursive else path_obj.glob(pattern)
|
|
350
346
|
|
|
351
347
|
results = []
|
|
352
348
|
for item in items:
|