claude-mpm 4.3.12__py3-none-any.whl → 4.3.14__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/agents/PM_INSTRUCTIONS.md +414 -28
- claude_mpm/agents/templates/data_engineer.json +39 -14
- claude_mpm/agents/templates/engineer.json +11 -3
- claude_mpm/cli/commands/agent_manager.py +3 -3
- claude_mpm/cli/commands/agents.py +2 -2
- claude_mpm/cli/commands/aggregate.py +1 -1
- claude_mpm/cli/commands/config.py +2 -2
- claude_mpm/cli/commands/configure.py +5 -5
- claude_mpm/cli/commands/configure_tui.py +7 -7
- claude_mpm/cli/commands/dashboard.py +1 -1
- claude_mpm/cli/commands/debug.py +5 -5
- claude_mpm/cli/commands/mcp.py +1 -1
- claude_mpm/cli/commands/mcp_command_router.py +1 -1
- claude_mpm/cli/commands/mcp_config.py +7 -10
- claude_mpm/cli/commands/mcp_external_commands.py +40 -32
- claude_mpm/cli/commands/mcp_install_commands.py +38 -10
- claude_mpm/cli/commands/mcp_setup_external.py +143 -102
- claude_mpm/cli/commands/monitor.py +2 -2
- claude_mpm/cli/commands/mpm_init_handler.py +1 -1
- claude_mpm/cli/commands/run.py +54 -2
- claude_mpm/cli/commands/search.py +41 -34
- claude_mpm/cli/interactive/agent_wizard.py +6 -2
- claude_mpm/cli/parsers/mcp_parser.py +1 -3
- claude_mpm/cli/parsers/search_parser.py +10 -4
- claude_mpm/cli/startup_logging.py +158 -5
- claude_mpm/cli/utils.py +1 -1
- claude_mpm/core/agent_registry.py +2 -2
- claude_mpm/core/agent_session_manager.py +8 -8
- claude_mpm/core/api_validator.py +6 -4
- claude_mpm/core/base_service.py +10 -10
- claude_mpm/core/cache.py +5 -5
- claude_mpm/core/config_constants.py +1 -1
- claude_mpm/core/container.py +1 -1
- claude_mpm/core/error_handler.py +2 -2
- claude_mpm/core/file_utils.py +1 -1
- claude_mpm/core/framework_loader.py +3 -3
- claude_mpm/core/hook_manager.py +8 -6
- claude_mpm/core/instruction_reinforcement_hook.py +2 -2
- claude_mpm/core/interactive_session.py +3 -1
- claude_mpm/core/lazy.py +3 -3
- claude_mpm/core/log_manager.py +16 -12
- claude_mpm/core/logger.py +16 -11
- claude_mpm/core/optimized_agent_loader.py +6 -6
- claude_mpm/core/output_style_manager.py +1 -1
- claude_mpm/core/pm_hook_interceptor.py +3 -3
- claude_mpm/core/service_registry.py +1 -1
- claude_mpm/core/session_manager.py +11 -9
- claude_mpm/core/socketio_pool.py +13 -13
- claude_mpm/core/types.py +2 -2
- claude_mpm/core/unified_agent_registry.py +2 -2
- claude_mpm/core/unified_paths.py +1 -1
- claude_mpm/dashboard/analysis_runner.py +4 -4
- claude_mpm/dashboard/api/simple_directory.py +1 -1
- claude_mpm/generators/agent_profile_generator.py +4 -2
- claude_mpm/hooks/base_hook.py +2 -2
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/connection_pool.py +4 -4
- claude_mpm/hooks/claude_hooks/event_handlers.py +12 -12
- claude_mpm/hooks/claude_hooks/hook_handler.py +4 -4
- claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +3 -3
- claude_mpm/hooks/claude_hooks/hook_handler_original.py +15 -14
- claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +4 -4
- claude_mpm/hooks/claude_hooks/installer.py +3 -3
- claude_mpm/hooks/claude_hooks/memory_integration.py +3 -3
- claude_mpm/hooks/claude_hooks/response_tracking.py +3 -3
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +8 -5
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +3 -3
- claude_mpm/hooks/claude_hooks/services/state_manager.py +8 -7
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +3 -3
- claude_mpm/hooks/claude_hooks/tool_analysis.py +2 -2
- claude_mpm/hooks/memory_integration_hook.py +1 -1
- claude_mpm/hooks/tool_call_interceptor.py +2 -2
- claude_mpm/models/agent_session.py +7 -5
- claude_mpm/scripts/mcp_server.py +0 -0
- claude_mpm/scripts/start_activity_logging.py +0 -0
- claude_mpm/services/__init__.py +1 -1
- claude_mpm/services/agent_capabilities_service.py +1 -1
- claude_mpm/services/agents/agent_builder.py +3 -3
- claude_mpm/services/agents/deployment/agent_deployment.py +2 -1
- claude_mpm/services/agents/deployment/agent_discovery_service.py +9 -3
- claude_mpm/services/agents/deployment/agent_filesystem_manager.py +5 -5
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +3 -1
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +1 -1
- claude_mpm/services/agents/deployment/agent_operation_service.py +2 -2
- claude_mpm/services/agents/deployment/agent_state_service.py +2 -2
- claude_mpm/services/agents/deployment/agent_template_builder.py +1 -1
- claude_mpm/services/agents/deployment/agent_versioning.py +1 -1
- claude_mpm/services/agents/deployment/deployment_wrapper.py +2 -3
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +1 -1
- claude_mpm/services/agents/loading/agent_profile_loader.py +5 -3
- claude_mpm/services/agents/loading/base_agent_manager.py +2 -2
- claude_mpm/services/agents/local_template_manager.py +6 -6
- claude_mpm/services/agents/management/agent_management_service.py +3 -3
- claude_mpm/services/agents/memory/content_manager.py +3 -3
- claude_mpm/services/agents/memory/memory_format_service.py +2 -2
- claude_mpm/services/agents/memory/template_generator.py +3 -3
- claude_mpm/services/agents/registry/modification_tracker.py +2 -2
- claude_mpm/services/async_session_logger.py +3 -3
- claude_mpm/services/claude_session_logger.py +4 -4
- claude_mpm/services/cli/agent_listing_service.py +3 -1
- claude_mpm/services/cli/agent_validation_service.py +2 -0
- claude_mpm/services/cli/memory_crud_service.py +11 -6
- claude_mpm/services/cli/memory_output_formatter.py +1 -1
- claude_mpm/services/cli/session_manager.py +15 -11
- claude_mpm/services/core/memory_manager.py +81 -23
- claude_mpm/services/core/path_resolver.py +1 -1
- claude_mpm/services/diagnostics/checks/installation_check.py +1 -1
- claude_mpm/services/event_aggregator.py +4 -2
- claude_mpm/services/event_bus/direct_relay.py +5 -3
- claude_mpm/services/event_bus/event_bus.py +3 -3
- claude_mpm/services/event_bus/relay.py +6 -4
- claude_mpm/services/events/consumers/dead_letter.py +5 -3
- claude_mpm/services/events/core.py +3 -3
- claude_mpm/services/events/producers/hook.py +6 -6
- claude_mpm/services/events/producers/system.py +8 -8
- claude_mpm/services/exceptions.py +5 -5
- claude_mpm/services/framework_claude_md_generator/content_assembler.py +3 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +2 -2
- claude_mpm/services/hook_installer_service.py +1 -1
- claude_mpm/services/infrastructure/context_preservation.py +6 -4
- claude_mpm/services/infrastructure/daemon_manager.py +2 -2
- claude_mpm/services/infrastructure/logging.py +2 -2
- claude_mpm/services/mcp_config_manager.py +175 -30
- claude_mpm/services/mcp_gateway/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/auto_configure.py +3 -3
- claude_mpm/services/mcp_gateway/config/config_loader.py +1 -1
- claude_mpm/services/mcp_gateway/config/configuration.py +1 -1
- claude_mpm/services/mcp_gateway/core/base.py +2 -2
- claude_mpm/services/mcp_gateway/main.py +21 -7
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +10 -8
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +4 -4
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +1 -1
- claude_mpm/services/mcp_gateway/server/stdio_server.py +5 -2
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +15 -15
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +7 -5
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +190 -137
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +5 -5
- claude_mpm/services/mcp_gateway/tools/hello_world.py +9 -9
- claude_mpm/services/mcp_gateway/tools/ticket_tools.py +16 -16
- claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +16 -16
- claude_mpm/services/memory/builder.py +7 -5
- claude_mpm/services/memory/indexed_memory.py +4 -4
- claude_mpm/services/memory/optimizer.py +6 -6
- claude_mpm/services/memory/router.py +3 -3
- claude_mpm/services/monitor/daemon.py +1 -1
- claude_mpm/services/monitor/daemon_manager.py +6 -6
- claude_mpm/services/monitor/event_emitter.py +2 -2
- claude_mpm/services/monitor/management/lifecycle.py +3 -1
- claude_mpm/services/monitor/server.py +4 -4
- claude_mpm/services/monitor_build_service.py +2 -2
- claude_mpm/services/port_manager.py +3 -1
- claude_mpm/services/response_tracker.py +2 -2
- claude_mpm/services/session_management_service.py +3 -2
- claude_mpm/services/socketio/client_proxy.py +2 -2
- claude_mpm/services/socketio/dashboard_server.py +4 -3
- claude_mpm/services/socketio/event_normalizer.py +11 -7
- claude_mpm/services/socketio/handlers/base.py +2 -2
- claude_mpm/services/socketio/handlers/connection.py +10 -10
- claude_mpm/services/socketio/handlers/connection_handler.py +13 -10
- claude_mpm/services/socketio/handlers/hook.py +16 -15
- claude_mpm/services/socketio/migration_utils.py +1 -1
- claude_mpm/services/socketio/monitor_client.py +5 -5
- claude_mpm/services/socketio/server/broadcaster.py +9 -7
- claude_mpm/services/socketio/server/connection_manager.py +2 -2
- claude_mpm/services/socketio/server/core.py +7 -5
- claude_mpm/services/socketio/server/eventbus_integration.py +18 -12
- claude_mpm/services/socketio/server/main.py +13 -13
- claude_mpm/services/socketio_client_manager.py +4 -4
- claude_mpm/services/system_instructions_service.py +2 -2
- claude_mpm/services/utility_service.py +5 -2
- claude_mpm/services/version_control/branch_strategy.py +2 -2
- claude_mpm/services/version_control/git_operations.py +22 -20
- claude_mpm/services/version_control/semantic_versioning.py +3 -3
- claude_mpm/services/version_control/version_parser.py +7 -5
- claude_mpm/services/visualization/mermaid_generator.py +3 -1
- claude_mpm/storage/state_storage.py +1 -1
- claude_mpm/tools/code_tree_analyzer.py +23 -18
- claude_mpm/tools/code_tree_builder.py +2 -2
- claude_mpm/tools/code_tree_events.py +10 -8
- claude_mpm/tools/socketio_debug.py +3 -3
- claude_mpm/utils/agent_dependency_loader.py +6 -2
- claude_mpm/utils/dependency_strategies.py +8 -3
- claude_mpm/utils/environment_context.py +1 -1
- claude_mpm/utils/error_handler.py +2 -2
- claude_mpm/utils/file_utils.py +1 -1
- claude_mpm/utils/log_cleanup.py +21 -7
- claude_mpm/validation/agent_validator.py +2 -2
- {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.14.dist-info}/METADATA +1 -1
- {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.14.dist-info}/RECORD +204 -191
- {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.14.dist-info}/WHEEL +0 -0
- {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.14.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.14.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.14.dist-info}/top_level.txt +0 -0
claude_mpm/core/base_service.py
CHANGED
|
@@ -26,7 +26,7 @@ import traceback
|
|
|
26
26
|
from abc import ABC, abstractmethod
|
|
27
27
|
from contextlib import asynccontextmanager
|
|
28
28
|
from dataclasses import dataclass, field
|
|
29
|
-
from datetime import datetime, timedelta
|
|
29
|
+
from datetime import datetime, timedelta, timezone
|
|
30
30
|
from pathlib import Path
|
|
31
31
|
from typing import Any, Dict, List, Optional
|
|
32
32
|
|
|
@@ -144,7 +144,7 @@ class BaseService(LoggerMixin, ABC):
|
|
|
144
144
|
self._health = ServiceHealth(
|
|
145
145
|
status="unknown",
|
|
146
146
|
message="Service not started",
|
|
147
|
-
timestamp=datetime.now().isoformat(),
|
|
147
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
148
148
|
)
|
|
149
149
|
self._metrics = ServiceMetrics()
|
|
150
150
|
self._last_health_check: Optional[float] = None
|
|
@@ -199,7 +199,7 @@ class BaseService(LoggerMixin, ABC):
|
|
|
199
199
|
def uptime(self) -> Optional[float]:
|
|
200
200
|
"""Get service uptime in seconds."""
|
|
201
201
|
if self._start_time and self._running:
|
|
202
|
-
return (datetime.now() - self._start_time).total_seconds()
|
|
202
|
+
return (datetime.now(timezone.utc) - self._start_time).total_seconds()
|
|
203
203
|
return None
|
|
204
204
|
|
|
205
205
|
@property
|
|
@@ -237,7 +237,7 @@ class BaseService(LoggerMixin, ABC):
|
|
|
237
237
|
self._health = ServiceHealth(
|
|
238
238
|
status="unhealthy",
|
|
239
239
|
message=f"Startup failed: {e!s}",
|
|
240
|
-
timestamp=datetime.now().isoformat(),
|
|
240
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
241
241
|
checks={"startup": False},
|
|
242
242
|
)
|
|
243
243
|
|
|
@@ -268,13 +268,13 @@ class BaseService(LoggerMixin, ABC):
|
|
|
268
268
|
|
|
269
269
|
# Mark as running
|
|
270
270
|
self._running = True
|
|
271
|
-
self._start_time = datetime.now()
|
|
271
|
+
self._start_time = datetime.now(timezone.utc)
|
|
272
272
|
|
|
273
273
|
# Update health status
|
|
274
274
|
self._health = ServiceHealth(
|
|
275
275
|
status="healthy",
|
|
276
276
|
message="Service started successfully",
|
|
277
|
-
timestamp=datetime.now().isoformat(),
|
|
277
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
278
278
|
checks={"startup": True},
|
|
279
279
|
metrics=self._get_health_metrics() if self._enable_enhanced else {},
|
|
280
280
|
)
|
|
@@ -338,7 +338,7 @@ class BaseService(LoggerMixin, ABC):
|
|
|
338
338
|
self._health = ServiceHealth(
|
|
339
339
|
status="unknown",
|
|
340
340
|
message="Service stopped",
|
|
341
|
-
timestamp=datetime.now().isoformat(),
|
|
341
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
342
342
|
checks={"running": False},
|
|
343
343
|
)
|
|
344
344
|
|
|
@@ -388,7 +388,7 @@ class BaseService(LoggerMixin, ABC):
|
|
|
388
388
|
self._health = ServiceHealth(
|
|
389
389
|
status=status,
|
|
390
390
|
message=message,
|
|
391
|
-
timestamp=datetime.now().isoformat(),
|
|
391
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
392
392
|
checks=checks,
|
|
393
393
|
metrics={
|
|
394
394
|
"uptime": self.uptime,
|
|
@@ -404,7 +404,7 @@ class BaseService(LoggerMixin, ABC):
|
|
|
404
404
|
self._health = ServiceHealth(
|
|
405
405
|
status="unhealthy",
|
|
406
406
|
message=f"Health check error: {e!s}",
|
|
407
|
-
timestamp=datetime.now().isoformat(),
|
|
407
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
408
408
|
checks={"health_check_error": True},
|
|
409
409
|
)
|
|
410
410
|
return self._health
|
|
@@ -586,7 +586,7 @@ class BaseService(LoggerMixin, ABC):
|
|
|
586
586
|
return ServiceHealth(
|
|
587
587
|
status="degraded",
|
|
588
588
|
message="Service circuit breaker is open",
|
|
589
|
-
timestamp=datetime.now().isoformat(),
|
|
589
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
590
590
|
checks={"circuit_breaker": False},
|
|
591
591
|
metrics=self._get_health_metrics(),
|
|
592
592
|
)
|
claude_mpm/core/cache.py
CHANGED
|
@@ -19,7 +19,7 @@ import pickle
|
|
|
19
19
|
import threading
|
|
20
20
|
from collections import OrderedDict
|
|
21
21
|
from dataclasses import dataclass, field
|
|
22
|
-
from datetime import datetime
|
|
22
|
+
from datetime import datetime, timezone
|
|
23
23
|
from typing import Any, Callable, Dict, Optional, TypeVar, Union
|
|
24
24
|
|
|
25
25
|
from ..core.logger import get_logger
|
|
@@ -43,12 +43,12 @@ class CacheEntry:
|
|
|
43
43
|
"""Check if entry has expired based on TTL."""
|
|
44
44
|
if self.ttl is None:
|
|
45
45
|
return False
|
|
46
|
-
age = (datetime.now() - self.created_at).total_seconds()
|
|
46
|
+
age = (datetime.now(timezone.utc) - self.created_at).total_seconds()
|
|
47
47
|
return age > self.ttl
|
|
48
48
|
|
|
49
49
|
def touch(self):
|
|
50
50
|
"""Update last access time and increment counter."""
|
|
51
|
-
self.last_accessed = datetime.now()
|
|
51
|
+
self.last_accessed = datetime.now(timezone.utc)
|
|
52
52
|
self.access_count += 1
|
|
53
53
|
|
|
54
54
|
|
|
@@ -129,13 +129,13 @@ class FileSystemCache:
|
|
|
129
129
|
# Rough estimate using JSON serialization
|
|
130
130
|
try:
|
|
131
131
|
return len(json.dumps(value))
|
|
132
|
-
except:
|
|
132
|
+
except Exception:
|
|
133
133
|
return 1000 # Default estimate
|
|
134
134
|
else:
|
|
135
135
|
# Use pickle for size estimation
|
|
136
136
|
try:
|
|
137
137
|
return len(pickle.dumps(value))
|
|
138
|
-
except:
|
|
138
|
+
except Exception:
|
|
139
139
|
return 100 # Default small size
|
|
140
140
|
|
|
141
141
|
def _evict_lru(self):
|
claude_mpm/core/container.py
CHANGED
|
@@ -636,7 +636,7 @@ class DIContainer(IServiceContainer):
|
|
|
636
636
|
if reg_type.__name__ == param_type:
|
|
637
637
|
param_type = reg_type
|
|
638
638
|
break
|
|
639
|
-
except:
|
|
639
|
+
except Exception:
|
|
640
640
|
# If we can't resolve, skip this parameter
|
|
641
641
|
if param.default != param.empty:
|
|
642
642
|
kwargs[param_name] = param.default
|
claude_mpm/core/error_handler.py
CHANGED
|
@@ -384,7 +384,7 @@ def with_error_handling(
|
|
|
384
384
|
if callable(fallback_value):
|
|
385
385
|
try:
|
|
386
386
|
fb_value = fallback_value(*args, **kwargs)
|
|
387
|
-
except:
|
|
387
|
+
except Exception:
|
|
388
388
|
fb_value = None
|
|
389
389
|
|
|
390
390
|
return handle_error(
|
|
@@ -428,7 +428,7 @@ def safe_operation(
|
|
|
428
428
|
if callable(fallback_value):
|
|
429
429
|
try:
|
|
430
430
|
return fallback_value(*args, **kwargs)
|
|
431
|
-
except:
|
|
431
|
+
except Exception:
|
|
432
432
|
return None
|
|
433
433
|
return fallback_value
|
|
434
434
|
|
claude_mpm/core/file_utils.py
CHANGED
|
@@ -6,7 +6,7 @@ import logging
|
|
|
6
6
|
import os
|
|
7
7
|
import platform
|
|
8
8
|
import time
|
|
9
|
-
from datetime import datetime
|
|
9
|
+
from datetime import datetime, timezone
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
from typing import Any, Dict, Optional
|
|
12
12
|
|
|
@@ -1432,7 +1432,7 @@ Extract tickets from these patterns:
|
|
|
1432
1432
|
|
|
1433
1433
|
try:
|
|
1434
1434
|
# Get current datetime with timezone awareness
|
|
1435
|
-
now = datetime.now()
|
|
1435
|
+
now = datetime.now(timezone.utc)
|
|
1436
1436
|
|
|
1437
1437
|
# Try to get timezone info - fallback to UTC offset if timezone name not available
|
|
1438
1438
|
try:
|
|
@@ -1470,7 +1470,7 @@ Extract tickets from these patterns:
|
|
|
1470
1470
|
# Fallback to basic date if enhanced datetime fails
|
|
1471
1471
|
self.logger.debug(f"Error generating enhanced datetime context: {e}")
|
|
1472
1472
|
context_lines.append(
|
|
1473
|
-
f"**Today's Date**: {datetime.now().strftime('%Y-%m-%d')}\n"
|
|
1473
|
+
f"**Today's Date**: {datetime.now(timezone.utc).strftime('%Y-%m-%d')}\n"
|
|
1474
1474
|
)
|
|
1475
1475
|
|
|
1476
1476
|
try:
|
claude_mpm/core/hook_manager.py
CHANGED
|
@@ -19,7 +19,7 @@ import queue
|
|
|
19
19
|
import subprocess
|
|
20
20
|
import threading
|
|
21
21
|
import uuid
|
|
22
|
-
from datetime import datetime
|
|
22
|
+
from datetime import datetime, timezone
|
|
23
23
|
from typing import Any, Dict, Optional
|
|
24
24
|
|
|
25
25
|
from ..core.logger import get_logger
|
|
@@ -106,7 +106,9 @@ class HookManager:
|
|
|
106
106
|
hook_event = {
|
|
107
107
|
"hook_event_name": hook_type,
|
|
108
108
|
"session_id": self.session_id,
|
|
109
|
-
"timestamp": hook_data.get(
|
|
109
|
+
"timestamp": hook_data.get(
|
|
110
|
+
"timestamp", datetime.now(timezone.utc).isoformat()
|
|
111
|
+
),
|
|
110
112
|
**event_data,
|
|
111
113
|
}
|
|
112
114
|
|
|
@@ -182,7 +184,7 @@ class HookManager:
|
|
|
182
184
|
{
|
|
183
185
|
"tool_name": tool_name,
|
|
184
186
|
"tool_args": tool_args or {},
|
|
185
|
-
"timestamp": datetime.
|
|
187
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
186
188
|
},
|
|
187
189
|
)
|
|
188
190
|
|
|
@@ -205,7 +207,7 @@ class HookManager:
|
|
|
205
207
|
"tool_name": tool_name,
|
|
206
208
|
"exit_code": exit_code,
|
|
207
209
|
"result": str(result) if result is not None else None,
|
|
208
|
-
"timestamp": datetime.
|
|
210
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
209
211
|
},
|
|
210
212
|
)
|
|
211
213
|
|
|
@@ -220,7 +222,7 @@ class HookManager:
|
|
|
220
222
|
"""
|
|
221
223
|
return self._trigger_hook_event(
|
|
222
224
|
"UserPromptSubmit",
|
|
223
|
-
{"prompt": prompt, "timestamp": datetime.
|
|
225
|
+
{"prompt": prompt, "timestamp": datetime.now(timezone.utc).isoformat()},
|
|
224
226
|
)
|
|
225
227
|
|
|
226
228
|
def _trigger_hook_event(self, hook_type: str, event_data: Dict[str, Any]) -> bool:
|
|
@@ -250,7 +252,7 @@ class HookManager:
|
|
|
250
252
|
hook_data = {
|
|
251
253
|
"hook_type": hook_type,
|
|
252
254
|
"event_data": event_data,
|
|
253
|
-
"timestamp": datetime.
|
|
255
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
254
256
|
}
|
|
255
257
|
|
|
256
258
|
# Try to queue without blocking
|
|
@@ -18,7 +18,7 @@ The hook works by:
|
|
|
18
18
|
"""
|
|
19
19
|
|
|
20
20
|
import threading
|
|
21
|
-
from datetime import datetime
|
|
21
|
+
from datetime import datetime, timezone
|
|
22
22
|
from typing import Any, Dict, List, Optional
|
|
23
23
|
|
|
24
24
|
from ..core.logger import get_logger
|
|
@@ -197,7 +197,7 @@ class InstructionReinforcementHook:
|
|
|
197
197
|
"enabled": self.enabled,
|
|
198
198
|
"test_mode": self.test_mode,
|
|
199
199
|
"injection_interval": self.injection_interval,
|
|
200
|
-
"timestamp": datetime.
|
|
200
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
201
201
|
}
|
|
202
202
|
|
|
203
203
|
def reset_counters(self):
|
|
@@ -154,7 +154,9 @@ class InteractiveSession:
|
|
|
154
154
|
self.logger.error(error_msg)
|
|
155
155
|
return False, {}
|
|
156
156
|
|
|
157
|
-
def handle_interactive_input(
|
|
157
|
+
def handle_interactive_input(
|
|
158
|
+
self, environment: Dict[str, Any]
|
|
159
|
+
) -> bool:
|
|
158
160
|
"""Handle the interactive input/output loop.
|
|
159
161
|
|
|
160
162
|
Launches Claude and manages the interactive session using either
|
claude_mpm/core/lazy.py
CHANGED
|
@@ -16,7 +16,7 @@ import functools
|
|
|
16
16
|
import threading
|
|
17
17
|
import time
|
|
18
18
|
from dataclasses import dataclass, field
|
|
19
|
-
from datetime import datetime
|
|
19
|
+
from datetime import datetime, timezone
|
|
20
20
|
from typing import Any, Callable, Dict, Generic, Optional, Type, TypeVar
|
|
21
21
|
|
|
22
22
|
from ..core.logger import get_logger
|
|
@@ -121,7 +121,7 @@ class LazyService(Generic[T]):
|
|
|
121
121
|
# Track initialization
|
|
122
122
|
start_time = time.time()
|
|
123
123
|
if self._metrics.first_access is None:
|
|
124
|
-
self._metrics.first_access = datetime.now()
|
|
124
|
+
self._metrics.first_access = datetime.now(timezone.utc)
|
|
125
125
|
|
|
126
126
|
try:
|
|
127
127
|
self._logger.debug(f"Initializing lazy service: {self._name}")
|
|
@@ -417,7 +417,7 @@ class AsyncLazyService(Generic[T]):
|
|
|
417
417
|
|
|
418
418
|
start_time = time.time()
|
|
419
419
|
if self._metrics.first_access is None:
|
|
420
|
-
self._metrics.first_access = datetime.now()
|
|
420
|
+
self._metrics.first_access = datetime.now(timezone.utc)
|
|
421
421
|
|
|
422
422
|
try:
|
|
423
423
|
self._logger.debug(f"Async initializing: {self._name}")
|
claude_mpm/core/log_manager.py
CHANGED
|
@@ -18,7 +18,7 @@ import asyncio
|
|
|
18
18
|
import json
|
|
19
19
|
import logging
|
|
20
20
|
import os
|
|
21
|
-
from datetime import datetime, timedelta
|
|
21
|
+
from datetime import datetime, timedelta, timezone
|
|
22
22
|
from pathlib import Path
|
|
23
23
|
from queue import Full, Queue
|
|
24
24
|
from threading import Lock, Thread
|
|
@@ -191,7 +191,7 @@ class LogManager:
|
|
|
191
191
|
finally:
|
|
192
192
|
self.write_queue.task_done()
|
|
193
193
|
|
|
194
|
-
except:
|
|
194
|
+
except Exception:
|
|
195
195
|
continue # Timeout or other error, continue loop
|
|
196
196
|
|
|
197
197
|
def _process_cleanup_queue(self):
|
|
@@ -211,7 +211,7 @@ class LogManager:
|
|
|
211
211
|
finally:
|
|
212
212
|
self.cleanup_queue.task_done()
|
|
213
213
|
|
|
214
|
-
except:
|
|
214
|
+
except Exception:
|
|
215
215
|
continue # Timeout or other error, continue loop
|
|
216
216
|
|
|
217
217
|
async def setup_logging(self, log_type: str) -> Path:
|
|
@@ -296,7 +296,7 @@ class LogManager:
|
|
|
296
296
|
return 0
|
|
297
297
|
|
|
298
298
|
# Calculate cutoff time
|
|
299
|
-
cutoff_time = datetime.now() - timedelta(hours=retention_hours)
|
|
299
|
+
cutoff_time = datetime.now(timezone.utc) - timedelta(hours=retention_hours)
|
|
300
300
|
|
|
301
301
|
# Schedule async cleanup
|
|
302
302
|
deleted_count = await self._async_cleanup(directory, pattern, cutoff_time)
|
|
@@ -337,7 +337,9 @@ class LogManager:
|
|
|
337
337
|
|
|
338
338
|
try:
|
|
339
339
|
# Check file modification time
|
|
340
|
-
mtime = datetime.fromtimestamp(
|
|
340
|
+
mtime = datetime.fromtimestamp(
|
|
341
|
+
file_path.stat().st_mtime, tz=timezone.utc
|
|
342
|
+
)
|
|
341
343
|
if mtime < cutoff_time:
|
|
342
344
|
file_path.unlink()
|
|
343
345
|
deleted_count += 1
|
|
@@ -370,7 +372,7 @@ class LogManager:
|
|
|
370
372
|
return 0
|
|
371
373
|
|
|
372
374
|
# Calculate cutoff time
|
|
373
|
-
cutoff_time = datetime.now() - timedelta(hours=retention_hours)
|
|
375
|
+
cutoff_time = datetime.now(timezone.utc) - timedelta(hours=retention_hours)
|
|
374
376
|
deleted_count = 0
|
|
375
377
|
|
|
376
378
|
try:
|
|
@@ -386,7 +388,9 @@ class LogManager:
|
|
|
386
388
|
|
|
387
389
|
try:
|
|
388
390
|
# Check file modification time
|
|
389
|
-
mtime = datetime.fromtimestamp(
|
|
391
|
+
mtime = datetime.fromtimestamp(
|
|
392
|
+
file_path.stat().st_mtime, tz=timezone.utc
|
|
393
|
+
)
|
|
390
394
|
if mtime < cutoff_time:
|
|
391
395
|
file_path.unlink()
|
|
392
396
|
deleted_count += 1
|
|
@@ -468,7 +472,7 @@ class LogManager:
|
|
|
468
472
|
prompts_dir = await self.setup_logging("prompts")
|
|
469
473
|
|
|
470
474
|
# Generate filename with timestamp
|
|
471
|
-
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S_%f")[
|
|
475
|
+
timestamp = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S_%f")[
|
|
472
476
|
:-3
|
|
473
477
|
] # Microseconds to milliseconds
|
|
474
478
|
|
|
@@ -494,7 +498,7 @@ class LogManager:
|
|
|
494
498
|
|
|
495
499
|
# Prepare prompt data
|
|
496
500
|
prompt_data = {
|
|
497
|
-
"timestamp": datetime.now().isoformat(),
|
|
501
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
498
502
|
"type": prompt_type,
|
|
499
503
|
"content": content,
|
|
500
504
|
"metadata": metadata or {},
|
|
@@ -567,12 +571,12 @@ class LogManager:
|
|
|
567
571
|
message: Log message to write
|
|
568
572
|
level: Log level (INFO, WARNING, ERROR, DEBUG)
|
|
569
573
|
"""
|
|
570
|
-
timestamp = datetime.now().isoformat()
|
|
574
|
+
timestamp = datetime.now(timezone.utc).isoformat()
|
|
571
575
|
log_entry = f"[{timestamp}] [{level}] {message}\n"
|
|
572
576
|
|
|
573
577
|
# Get appropriate log file based on context
|
|
574
578
|
log_dir = self._get_log_directory("mpm")
|
|
575
|
-
log_file = log_dir / f"mpm_{datetime.now().strftime('%Y%m%d')}.log"
|
|
579
|
+
log_file = log_dir / f"mpm_{datetime.now(timezone.utc).strftime('%Y%m%d')}.log"
|
|
576
580
|
|
|
577
581
|
def write_task():
|
|
578
582
|
try:
|
|
@@ -652,7 +656,7 @@ class LogManager:
|
|
|
652
656
|
try:
|
|
653
657
|
self.write_queue.put_nowait(None)
|
|
654
658
|
self.cleanup_queue.put_nowait(None)
|
|
655
|
-
except:
|
|
659
|
+
except Exception:
|
|
656
660
|
pass
|
|
657
661
|
|
|
658
662
|
# Wait for threads to finish
|
claude_mpm/core/logger.py
CHANGED
|
@@ -14,7 +14,7 @@ import sys
|
|
|
14
14
|
import threading
|
|
15
15
|
import time
|
|
16
16
|
from collections import defaultdict
|
|
17
|
-
from datetime import datetime
|
|
17
|
+
from datetime import datetime, timezone
|
|
18
18
|
from enum import Enum
|
|
19
19
|
from pathlib import Path
|
|
20
20
|
from typing import Any, Dict, Optional
|
|
@@ -84,7 +84,7 @@ class StreamingHandler(logging.StreamHandler):
|
|
|
84
84
|
|
|
85
85
|
except (KeyboardInterrupt, SystemExit):
|
|
86
86
|
raise
|
|
87
|
-
except:
|
|
87
|
+
except Exception:
|
|
88
88
|
self.handleError(record)
|
|
89
89
|
|
|
90
90
|
def finalize_info_line(self):
|
|
@@ -237,7 +237,7 @@ def setup_logging(
|
|
|
237
237
|
log_dir.mkdir(parents=True, exist_ok=True)
|
|
238
238
|
|
|
239
239
|
# Create timestamped log file
|
|
240
|
-
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
240
|
+
timestamp = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
|
|
241
241
|
log_file = log_dir / f"mpm_{timestamp}.log"
|
|
242
242
|
|
|
243
243
|
file_handler = logging.FileHandler(log_file)
|
|
@@ -485,8 +485,8 @@ class ProjectLogger:
|
|
|
485
485
|
path.mkdir(parents=True, exist_ok=True)
|
|
486
486
|
|
|
487
487
|
# Create session directory
|
|
488
|
-
self.session_id = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
489
|
-
self.session_start_time = datetime.now()
|
|
488
|
+
self.session_id = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
|
|
489
|
+
self.session_start_time = datetime.now(timezone.utc)
|
|
490
490
|
self.session_dir = self.dirs["logs_sessions"] / self.session_id
|
|
491
491
|
self.session_dir.mkdir(parents=True, exist_ok=True)
|
|
492
492
|
|
|
@@ -513,7 +513,7 @@ class ProjectLogger:
|
|
|
513
513
|
if self.log_level == LogLevel.OFF:
|
|
514
514
|
return
|
|
515
515
|
|
|
516
|
-
timestamp = datetime.now().isoformat()
|
|
516
|
+
timestamp = datetime.now(timezone.utc).isoformat()
|
|
517
517
|
log_entry = {
|
|
518
518
|
"timestamp": timestamp,
|
|
519
519
|
"level": level,
|
|
@@ -523,7 +523,8 @@ class ProjectLogger:
|
|
|
523
523
|
|
|
524
524
|
# Write to daily log file
|
|
525
525
|
log_file = (
|
|
526
|
-
self.dirs["logs_system"]
|
|
526
|
+
self.dirs["logs_system"]
|
|
527
|
+
/ f"{datetime.now(timezone.utc).strftime('%Y%m%d')}.jsonl"
|
|
527
528
|
)
|
|
528
529
|
with open(log_file, "a") as f:
|
|
529
530
|
f.write(json.dumps(log_entry) + "\n")
|
|
@@ -543,10 +544,10 @@ class ProjectLogger:
|
|
|
543
544
|
if self.log_level == LogLevel.OFF:
|
|
544
545
|
return
|
|
545
546
|
|
|
546
|
-
timestamp = datetime.now().isoformat()
|
|
547
|
+
timestamp = datetime.now(timezone.utc).isoformat()
|
|
547
548
|
|
|
548
549
|
# Update statistics
|
|
549
|
-
today = datetime.now().strftime("%Y-%m-%d")
|
|
550
|
+
today = datetime.now(timezone.utc).strftime("%Y-%m-%d")
|
|
550
551
|
self.stats[today]["total_calls"] += 1
|
|
551
552
|
self.stats[today]["total_tokens"] += tokens
|
|
552
553
|
self.stats[today]["total_time_seconds"] += execution_time
|
|
@@ -576,7 +577,9 @@ class ProjectLogger:
|
|
|
576
577
|
agent_log_dir = self.dirs["logs_agents"] / agent.lower()
|
|
577
578
|
agent_log_dir.mkdir(exist_ok=True)
|
|
578
579
|
|
|
579
|
-
daily_log =
|
|
580
|
+
daily_log = (
|
|
581
|
+
agent_log_dir / f"{datetime.now(timezone.utc).strftime('%Y%m%d')}.jsonl"
|
|
582
|
+
)
|
|
580
583
|
with open(daily_log, "a") as f:
|
|
581
584
|
f.write(json.dumps(log_entry) + "\n")
|
|
582
585
|
|
|
@@ -586,7 +589,9 @@ class ProjectLogger:
|
|
|
586
589
|
"session_id": self.session_id,
|
|
587
590
|
"session_dir": str(self.session_dir),
|
|
588
591
|
"start_time": self.session_id,
|
|
589
|
-
"stats": self.stats.get(
|
|
592
|
+
"stats": self.stats.get(
|
|
593
|
+
datetime.now(timezone.utc).strftime("%Y-%m-%d"), {}
|
|
594
|
+
),
|
|
590
595
|
}
|
|
591
596
|
|
|
592
597
|
|
|
@@ -22,7 +22,7 @@ import threading
|
|
|
22
22
|
import time
|
|
23
23
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
24
24
|
from dataclasses import dataclass
|
|
25
|
-
from datetime import datetime
|
|
25
|
+
from datetime import datetime, timezone
|
|
26
26
|
from typing import Any, Dict, List, Optional
|
|
27
27
|
|
|
28
28
|
try:
|
|
@@ -111,7 +111,7 @@ class OptimizedAgentLoader:
|
|
|
111
111
|
try:
|
|
112
112
|
mtime = file_path.stat().st_mtime
|
|
113
113
|
return f"agent:{file_path}:{mtime}"
|
|
114
|
-
except:
|
|
114
|
+
except Exception:
|
|
115
115
|
return f"agent:{file_path}"
|
|
116
116
|
|
|
117
117
|
def _load_agent_file(self, file_path: Path) -> Optional[Dict[str, Any]]:
|
|
@@ -154,7 +154,7 @@ class OptimizedAgentLoader:
|
|
|
154
154
|
|
|
155
155
|
# Add metadata
|
|
156
156
|
agent_data["_file_path"] = str(file_path)
|
|
157
|
-
agent_data["_loaded_at"] = datetime.now().isoformat()
|
|
157
|
+
agent_data["_loaded_at"] = datetime.now(timezone.utc).isoformat()
|
|
158
158
|
|
|
159
159
|
# Cache the result
|
|
160
160
|
self.cache.put(cache_key, agent_data, ttl=self.cache_ttl)
|
|
@@ -188,7 +188,7 @@ class OptimizedAgentLoader:
|
|
|
188
188
|
data = yaml.safe_load(frontmatter) or {}
|
|
189
189
|
data["instructions"] = body
|
|
190
190
|
return data
|
|
191
|
-
except:
|
|
191
|
+
except Exception:
|
|
192
192
|
pass
|
|
193
193
|
|
|
194
194
|
# No frontmatter, treat as pure instructions
|
|
@@ -322,7 +322,7 @@ class OptimizedAgentLoader:
|
|
|
322
322
|
|
|
323
323
|
# Add metadata
|
|
324
324
|
agent_data["_file_path"] = str(file_path)
|
|
325
|
-
agent_data["_loaded_at"] = datetime.now().isoformat()
|
|
325
|
+
agent_data["_loaded_at"] = datetime.now(timezone.utc).isoformat()
|
|
326
326
|
|
|
327
327
|
# Cache the result
|
|
328
328
|
self.cache.put(cache_key, agent_data, ttl=self.cache_ttl)
|
|
@@ -366,7 +366,7 @@ class OptimizedAgentLoader:
|
|
|
366
366
|
"template": template,
|
|
367
367
|
"variables": self._extract_variables(template),
|
|
368
368
|
"sections": self._extract_sections(template),
|
|
369
|
-
"compiled_at": datetime.now().isoformat(),
|
|
369
|
+
"compiled_at": datetime.now(timezone.utc).isoformat(),
|
|
370
370
|
}
|
|
371
371
|
|
|
372
372
|
# Cache compiled template
|
|
@@ -42,7 +42,7 @@ class OutputStyleManager:
|
|
|
42
42
|
Path(__file__).parent.parent / "agents" / "OUTPUT_STYLE.md"
|
|
43
43
|
)
|
|
44
44
|
|
|
45
|
-
def _detect_claude_version(self) -> Optional[str]:
|
|
45
|
+
def _detect_claude_version(self) -> Optional[str]: # noqa: PLR0911
|
|
46
46
|
"""
|
|
47
47
|
Detect Claude Code version by running 'claude --version'.
|
|
48
48
|
Uses global cache to avoid duplicate detection and logging.
|
|
@@ -14,7 +14,7 @@ WHY this is needed:
|
|
|
14
14
|
import functools
|
|
15
15
|
import threading
|
|
16
16
|
import time
|
|
17
|
-
from datetime import datetime
|
|
17
|
+
from datetime import datetime, timezone
|
|
18
18
|
from typing import Any, Dict, List, Optional
|
|
19
19
|
|
|
20
20
|
from ..core.hook_manager import get_hook_manager
|
|
@@ -195,7 +195,7 @@ class PMHookInterceptor:
|
|
|
195
195
|
{
|
|
196
196
|
"todos": todos,
|
|
197
197
|
"source": "PM_Manual",
|
|
198
|
-
"timestamp": datetime.
|
|
198
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
199
199
|
},
|
|
200
200
|
)
|
|
201
201
|
|
|
@@ -210,7 +210,7 @@ class PMHookInterceptor:
|
|
|
210
210
|
"todos_count": len(todos),
|
|
211
211
|
"source": "PM_Manual",
|
|
212
212
|
"success": True,
|
|
213
|
-
"timestamp": datetime.
|
|
213
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
214
214
|
},
|
|
215
215
|
)
|
|
216
216
|
|
|
@@ -160,7 +160,7 @@ class ServiceRegistry:
|
|
|
160
160
|
try:
|
|
161
161
|
# Use the enhanced container's named resolution
|
|
162
162
|
return self.container.get(BaseService, name=service_type)
|
|
163
|
-
except:
|
|
163
|
+
except Exception:
|
|
164
164
|
# Fall back to looking up class and resolving
|
|
165
165
|
if service_type not in self._services:
|
|
166
166
|
raise KeyError(f"Service '{service_type}' not registered")
|