claude-mpm 3.7.4__py3-none-any.whl → 3.8.1__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.
Files changed (117) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_PM.md +0 -106
  3. claude_mpm/agents/INSTRUCTIONS.md +0 -78
  4. claude_mpm/agents/MEMORY.md +88 -0
  5. claude_mpm/agents/WORKFLOW.md +86 -0
  6. claude_mpm/agents/schema/agent_schema.json +1 -1
  7. claude_mpm/agents/templates/code_analyzer.json +26 -11
  8. claude_mpm/agents/templates/data_engineer.json +4 -7
  9. claude_mpm/agents/templates/documentation.json +2 -2
  10. claude_mpm/agents/templates/engineer.json +2 -2
  11. claude_mpm/agents/templates/ops.json +3 -8
  12. claude_mpm/agents/templates/qa.json +2 -3
  13. claude_mpm/agents/templates/research.json +2 -3
  14. claude_mpm/agents/templates/security.json +3 -6
  15. claude_mpm/agents/templates/ticketing.json +4 -9
  16. claude_mpm/agents/templates/version_control.json +3 -3
  17. claude_mpm/agents/templates/web_qa.json +4 -4
  18. claude_mpm/agents/templates/web_ui.json +4 -4
  19. claude_mpm/cli/__init__.py +2 -2
  20. claude_mpm/cli/commands/__init__.py +2 -1
  21. claude_mpm/cli/commands/agents.py +118 -1
  22. claude_mpm/cli/commands/tickets.py +596 -19
  23. claude_mpm/cli/parser.py +228 -5
  24. claude_mpm/config/__init__.py +30 -39
  25. claude_mpm/config/socketio_config.py +8 -5
  26. claude_mpm/constants.py +13 -0
  27. claude_mpm/core/__init__.py +8 -18
  28. claude_mpm/core/cache.py +596 -0
  29. claude_mpm/core/claude_runner.py +166 -622
  30. claude_mpm/core/config.py +5 -1
  31. claude_mpm/core/constants.py +339 -0
  32. claude_mpm/core/container.py +461 -22
  33. claude_mpm/core/exceptions.py +392 -0
  34. claude_mpm/core/framework_loader.py +208 -93
  35. claude_mpm/core/interactive_session.py +432 -0
  36. claude_mpm/core/interfaces.py +424 -0
  37. claude_mpm/core/lazy.py +467 -0
  38. claude_mpm/core/logging_config.py +444 -0
  39. claude_mpm/core/oneshot_session.py +465 -0
  40. claude_mpm/core/optimized_agent_loader.py +485 -0
  41. claude_mpm/core/optimized_startup.py +490 -0
  42. claude_mpm/core/service_registry.py +52 -26
  43. claude_mpm/core/socketio_pool.py +162 -5
  44. claude_mpm/core/types.py +292 -0
  45. claude_mpm/core/typing_utils.py +477 -0
  46. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +46 -2
  47. claude_mpm/dashboard/templates/index.html +5 -5
  48. claude_mpm/hooks/claude_hooks/hook_handler.py +213 -99
  49. claude_mpm/init.py +2 -1
  50. claude_mpm/services/__init__.py +78 -14
  51. claude_mpm/services/agent/__init__.py +24 -0
  52. claude_mpm/services/agent/deployment.py +2548 -0
  53. claude_mpm/services/agent/management.py +598 -0
  54. claude_mpm/services/agent/registry.py +813 -0
  55. claude_mpm/services/agents/deployment/agent_deployment.py +592 -269
  56. claude_mpm/services/agents/deployment/async_agent_deployment.py +5 -1
  57. claude_mpm/services/agents/management/agent_capabilities_generator.py +21 -11
  58. claude_mpm/services/agents/memory/agent_memory_manager.py +156 -1
  59. claude_mpm/services/async_session_logger.py +8 -3
  60. claude_mpm/services/communication/__init__.py +21 -0
  61. claude_mpm/services/communication/socketio.py +1933 -0
  62. claude_mpm/services/communication/websocket.py +479 -0
  63. claude_mpm/services/core/__init__.py +123 -0
  64. claude_mpm/services/core/base.py +247 -0
  65. claude_mpm/services/core/interfaces.py +951 -0
  66. claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +23 -23
  67. claude_mpm/services/framework_claude_md_generator.py +3 -2
  68. claude_mpm/services/health_monitor.py +4 -3
  69. claude_mpm/services/hook_service.py +64 -4
  70. claude_mpm/services/infrastructure/__init__.py +21 -0
  71. claude_mpm/services/infrastructure/logging.py +202 -0
  72. claude_mpm/services/infrastructure/monitoring.py +893 -0
  73. claude_mpm/services/memory/indexed_memory.py +648 -0
  74. claude_mpm/services/project/__init__.py +21 -0
  75. claude_mpm/services/project/analyzer.py +864 -0
  76. claude_mpm/services/project/registry.py +608 -0
  77. claude_mpm/services/project_analyzer.py +95 -2
  78. claude_mpm/services/recovery_manager.py +15 -9
  79. claude_mpm/services/socketio/__init__.py +25 -0
  80. claude_mpm/services/socketio/handlers/__init__.py +25 -0
  81. claude_mpm/services/socketio/handlers/base.py +121 -0
  82. claude_mpm/services/socketio/handlers/connection.py +198 -0
  83. claude_mpm/services/socketio/handlers/file.py +213 -0
  84. claude_mpm/services/socketio/handlers/git.py +723 -0
  85. claude_mpm/services/socketio/handlers/memory.py +27 -0
  86. claude_mpm/services/socketio/handlers/project.py +25 -0
  87. claude_mpm/services/socketio/handlers/registry.py +145 -0
  88. claude_mpm/services/socketio_client_manager.py +12 -7
  89. claude_mpm/services/socketio_server.py +156 -30
  90. claude_mpm/services/ticket_manager.py +377 -51
  91. claude_mpm/utils/agent_dependency_loader.py +66 -15
  92. claude_mpm/utils/error_handler.py +1 -1
  93. claude_mpm/utils/robust_installer.py +587 -0
  94. claude_mpm/validation/agent_validator.py +27 -14
  95. claude_mpm/validation/frontmatter_validator.py +231 -0
  96. {claude_mpm-3.7.4.dist-info → claude_mpm-3.8.1.dist-info}/METADATA +74 -41
  97. {claude_mpm-3.7.4.dist-info → claude_mpm-3.8.1.dist-info}/RECORD +101 -76
  98. claude_mpm/.claude-mpm/logs/hooks_20250728.log +0 -10
  99. claude_mpm/agents/agent-template.yaml +0 -83
  100. claude_mpm/cli/README.md +0 -108
  101. claude_mpm/cli_module/refactoring_guide.md +0 -253
  102. claude_mpm/config/async_logging_config.yaml +0 -145
  103. claude_mpm/core/.claude-mpm/logs/hooks_20250730.log +0 -34
  104. claude_mpm/dashboard/.claude-mpm/memories/README.md +0 -36
  105. claude_mpm/dashboard/README.md +0 -121
  106. claude_mpm/dashboard/static/js/dashboard.js.backup +0 -1973
  107. claude_mpm/dashboard/templates/.claude-mpm/memories/README.md +0 -36
  108. claude_mpm/dashboard/templates/.claude-mpm/memories/engineer_agent.md +0 -39
  109. claude_mpm/dashboard/templates/.claude-mpm/memories/version_control_agent.md +0 -38
  110. claude_mpm/hooks/README.md +0 -96
  111. claude_mpm/schemas/agent_schema.json +0 -435
  112. claude_mpm/services/framework_claude_md_generator/README.md +0 -92
  113. claude_mpm/services/version_control/VERSION +0 -1
  114. {claude_mpm-3.7.4.dist-info → claude_mpm-3.8.1.dist-info}/WHEEL +0 -0
  115. {claude_mpm-3.7.4.dist-info → claude_mpm-3.8.1.dist-info}/entry_points.txt +0 -0
  116. {claude_mpm-3.7.4.dist-info → claude_mpm-3.8.1.dist-info}/licenses/LICENSE +0 -0
  117. {claude_mpm-3.7.4.dist-info → claude_mpm-3.8.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,444 @@
1
+ """
2
+ Centralized logging configuration for Claude MPM.
3
+
4
+ This module provides a standardized logging infrastructure with:
5
+ - Consistent logger factory method
6
+ - Structured logging with context
7
+ - Performance logging decorators
8
+ - Context managers for operation tracking
9
+ - Standardized log levels and formatting
10
+
11
+ WHY: This centralized approach ensures consistent logging across the entire
12
+ codebase, making debugging and monitoring significantly easier. All components
13
+ use the same format, level hierarchy, and contextual information structure.
14
+
15
+ DESIGN DECISION: Built on top of existing logger.py but provides simplified
16
+ interface and enforces consistent patterns. This allows gradual migration
17
+ while maintaining backwards compatibility.
18
+ """
19
+
20
+ import functools
21
+ import json
22
+ import logging
23
+ import time
24
+ from contextlib import contextmanager
25
+ from pathlib import Path
26
+ from typing import Any, Dict, Optional, Union
27
+ from datetime import datetime
28
+
29
+ from claude_mpm.core.logger import (
30
+ setup_logging as _setup_logging,
31
+ get_logger as _get_logger,
32
+ log_performance,
33
+ log_async_performance,
34
+ JsonFormatter,
35
+ StreamingHandler,
36
+ finalize_streaming_logs
37
+ )
38
+
39
+
40
+ # Standard log format for consistency
41
+ STANDARD_FORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
42
+ DETAILED_FORMAT = '%(asctime)s - %(name)s - %(levelname)s - [%(filename)s:%(lineno)d] - %(funcName)s() - %(message)s'
43
+ SIMPLE_FORMAT = '%(levelname)s: %(message)s'
44
+
45
+ # Log level mapping for consistent usage
46
+ LOG_LEVELS = {
47
+ 'DEBUG': logging.DEBUG, # Detailed diagnostic information
48
+ 'INFO': logging.INFO, # Normal operations, significant events
49
+ 'WARNING': logging.WARNING, # Potentially harmful situations
50
+ 'ERROR': logging.ERROR, # Error events allowing continued operation
51
+ 'CRITICAL': logging.CRITICAL # Events that may cause abort
52
+ }
53
+
54
+
55
+ class LogContext:
56
+ """
57
+ Context manager for adding contextual information to log messages.
58
+
59
+ WHY: Provides consistent way to add context like operation IDs, user info,
60
+ or request IDs to all logs within a scope without modifying every log call.
61
+ """
62
+
63
+ _context: Dict[str, Any] = {}
64
+
65
+ @classmethod
66
+ def set(cls, **kwargs):
67
+ """Set context values."""
68
+ cls._context.update(kwargs)
69
+
70
+ @classmethod
71
+ def get(cls) -> Dict[str, Any]:
72
+ """Get current context."""
73
+ return cls._context.copy()
74
+
75
+ @classmethod
76
+ def clear(cls):
77
+ """Clear all context."""
78
+ cls._context.clear()
79
+
80
+ @classmethod
81
+ @contextmanager
82
+ def context(cls, **kwargs):
83
+ """Context manager for temporary context."""
84
+ old_context = cls._context.copy()
85
+ cls._context.update(kwargs)
86
+ try:
87
+ yield
88
+ finally:
89
+ cls._context = old_context
90
+
91
+
92
+ class ContextualLogger:
93
+ """
94
+ Logger wrapper that automatically includes context in all messages.
95
+
96
+ WHY: Ensures all log messages from a component include relevant context
97
+ without requiring manual addition to each log call.
98
+ """
99
+
100
+ def __init__(self, logger: logging.Logger):
101
+ self._logger = logger
102
+
103
+ def _log_with_context(self, level: int, msg: str, *args, **kwargs):
104
+ """Add context to log message."""
105
+ context = LogContext.get()
106
+ if context:
107
+ # Add context as extra fields for structured logging
108
+ kwargs['extra'] = kwargs.get('extra', {})
109
+ kwargs['extra'].update(context)
110
+
111
+ # For human-readable logs, prepend context
112
+ if not isinstance(self._logger.handlers[0].formatter, JsonFormatter):
113
+ context_str = ' '.join(f'[{k}={v}]' for k, v in context.items())
114
+ if context_str:
115
+ msg = f"{context_str} {msg}"
116
+
117
+ self._logger.log(level, msg, *args, **kwargs)
118
+
119
+ def debug(self, msg: str, *args, **kwargs):
120
+ """Log debug message with context."""
121
+ self._log_with_context(logging.DEBUG, msg, *args, **kwargs)
122
+
123
+ def info(self, msg: str, *args, **kwargs):
124
+ """Log info message with context."""
125
+ self._log_with_context(logging.INFO, msg, *args, **kwargs)
126
+
127
+ def warning(self, msg: str, *args, **kwargs):
128
+ """Log warning message with context."""
129
+ self._log_with_context(logging.WARNING, msg, *args, **kwargs)
130
+
131
+ def error(self, msg: str, *args, **kwargs):
132
+ """Log error message with context."""
133
+ self._log_with_context(logging.ERROR, msg, *args, **kwargs)
134
+
135
+ def critical(self, msg: str, *args, **kwargs):
136
+ """Log critical message with context."""
137
+ self._log_with_context(logging.CRITICAL, msg, *args, **kwargs)
138
+
139
+ def exception(self, msg: str, *args, **kwargs):
140
+ """Log exception with context."""
141
+ kwargs['exc_info'] = True
142
+ self._log_with_context(logging.ERROR, msg, *args, **kwargs)
143
+
144
+
145
+ def get_logger(name: str, with_context: bool = True) -> Union[ContextualLogger, logging.Logger]:
146
+ """
147
+ Get a configured logger instance.
148
+
149
+ WHY: Centralized logger creation ensures all loggers follow the same
150
+ naming convention and configuration patterns.
151
+
152
+ Args:
153
+ name: Logger name (typically __name__ from the calling module)
154
+ with_context: Whether to wrap with ContextualLogger for automatic context
155
+
156
+ Returns:
157
+ Configured logger instance
158
+
159
+ Example:
160
+ logger = get_logger(__name__)
161
+ logger.info("Processing request", extra={"request_id": "123"})
162
+ """
163
+ # Ensure consistent naming
164
+ if not name.startswith('claude_mpm'):
165
+ name = f'claude_mpm.{name}'
166
+
167
+ logger = _get_logger(name)
168
+
169
+ if with_context:
170
+ return ContextualLogger(logger)
171
+ return logger
172
+
173
+
174
+ def configure_logging(
175
+ level: str = "INFO",
176
+ log_dir: Optional[Path] = None,
177
+ console_output: bool = True,
178
+ file_output: bool = True,
179
+ json_format: bool = False,
180
+ use_streaming: bool = False
181
+ ) -> None:
182
+ """
183
+ Configure global logging settings.
184
+
185
+ WHY: Provides single entry point for configuring all logging behavior
186
+ across the application, ensuring consistency.
187
+
188
+ Args:
189
+ level: Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
190
+ log_dir: Directory for log files
191
+ console_output: Enable console output
192
+ file_output: Enable file output
193
+ json_format: Use JSON format for structured logging
194
+ use_streaming: Use streaming handler for progress messages
195
+ """
196
+ # Configure root logger for claude_mpm
197
+ _setup_logging(
198
+ name="claude_mpm",
199
+ level=level,
200
+ log_dir=log_dir,
201
+ console_output=console_output,
202
+ file_output=file_output,
203
+ json_format=json_format,
204
+ use_streaming=use_streaming
205
+ )
206
+
207
+
208
+ @contextmanager
209
+ def log_operation(logger: Union[ContextualLogger, logging.Logger],
210
+ operation: str,
211
+ **context):
212
+ """
213
+ Context manager for logging operation start/end with timing.
214
+
215
+ WHY: Provides consistent way to track operation execution including
216
+ timing, success/failure, and any relevant context.
217
+
218
+ Args:
219
+ logger: Logger instance
220
+ operation: Operation name/description
221
+ **context: Additional context to include in logs
222
+
223
+ Example:
224
+ with log_operation(logger, "database_query", query_type="select"):
225
+ # Perform database operation
226
+ pass
227
+ """
228
+ start_time = time.time()
229
+
230
+ # Add operation context
231
+ with LogContext.context(operation=operation, **context):
232
+ logger.info(f"Starting {operation}")
233
+
234
+ try:
235
+ yield
236
+ execution_time = time.time() - start_time
237
+ logger.info(f"Completed {operation}", extra={
238
+ "execution_time": execution_time,
239
+ "status": "success"
240
+ })
241
+ except Exception as e:
242
+ execution_time = time.time() - start_time
243
+ logger.error(f"Failed {operation}: {e}", extra={
244
+ "execution_time": execution_time,
245
+ "status": "failure",
246
+ "error": str(e)
247
+ })
248
+ raise
249
+
250
+
251
+ @contextmanager
252
+ def log_performance_context(logger: Union[ContextualLogger, logging.Logger],
253
+ operation: str,
254
+ warn_threshold: float = 1.0,
255
+ error_threshold: float = 5.0):
256
+ """
257
+ Context manager for performance monitoring with thresholds.
258
+
259
+ WHY: Automatically warns or errors when operations exceed performance
260
+ thresholds, helping identify performance issues early.
261
+
262
+ Args:
263
+ logger: Logger instance
264
+ operation: Operation being monitored
265
+ warn_threshold: Time in seconds to trigger warning
266
+ error_threshold: Time in seconds to trigger error
267
+
268
+ Example:
269
+ with log_performance_context(logger, "api_call", warn_threshold=0.5):
270
+ # Make API call
271
+ pass
272
+ """
273
+ start_time = time.time()
274
+
275
+ try:
276
+ yield
277
+ finally:
278
+ execution_time = time.time() - start_time
279
+
280
+ if execution_time > error_threshold:
281
+ logger.error(f"{operation} took {execution_time:.3f}s (threshold: {error_threshold}s)", extra={
282
+ "execution_time": execution_time,
283
+ "threshold_exceeded": "error"
284
+ })
285
+ elif execution_time > warn_threshold:
286
+ logger.warning(f"{operation} took {execution_time:.3f}s (threshold: {warn_threshold}s)", extra={
287
+ "execution_time": execution_time,
288
+ "threshold_exceeded": "warning"
289
+ })
290
+ else:
291
+ logger.debug(f"{operation} completed in {execution_time:.3f}s", extra={
292
+ "execution_time": execution_time
293
+ })
294
+
295
+
296
+ def log_function_call(func):
297
+ """
298
+ Decorator to log function calls with arguments and results.
299
+
300
+ WHY: Provides automatic logging of function entry/exit for debugging
301
+ without modifying function implementation.
302
+
303
+ Example:
304
+ @log_function_call
305
+ def process_data(data: dict) -> dict:
306
+ return {"processed": True}
307
+ """
308
+ @functools.wraps(func)
309
+ def wrapper(*args, **kwargs):
310
+ logger = get_logger(func.__module__)
311
+ func_name = func.__qualname__
312
+
313
+ # Log function entry
314
+ logger.debug(f"Calling {func_name}", extra={
315
+ "function": func_name,
316
+ "args_count": len(args),
317
+ "kwargs_keys": list(kwargs.keys())
318
+ })
319
+
320
+ start_time = time.time()
321
+ try:
322
+ result = func(*args, **kwargs)
323
+ execution_time = time.time() - start_time
324
+
325
+ logger.debug(f"{func_name} completed", extra={
326
+ "function": func_name,
327
+ "execution_time": execution_time,
328
+ "has_result": result is not None
329
+ })
330
+
331
+ return result
332
+
333
+ except Exception as e:
334
+ execution_time = time.time() - start_time
335
+ logger.exception(f"{func_name} failed", extra={
336
+ "function": func_name,
337
+ "execution_time": execution_time,
338
+ "error_type": type(e).__name__
339
+ })
340
+ raise
341
+
342
+ return wrapper
343
+
344
+
345
+ async def log_async_function_call(func):
346
+ """
347
+ Decorator to log async function calls with arguments and results.
348
+
349
+ WHY: Provides automatic logging for async functions, essential for
350
+ tracking async operation flow and performance.
351
+
352
+ Example:
353
+ @log_async_function_call
354
+ async def fetch_data(url: str) -> dict:
355
+ return {"data": "example"}
356
+ """
357
+ @functools.wraps(func)
358
+ async def wrapper(*args, **kwargs):
359
+ logger = get_logger(func.__module__)
360
+ func_name = func.__qualname__
361
+
362
+ # Log function entry
363
+ logger.debug(f"Calling async {func_name}", extra={
364
+ "function": func_name,
365
+ "args_count": len(args),
366
+ "kwargs_keys": list(kwargs.keys()),
367
+ "is_async": True
368
+ })
369
+
370
+ start_time = time.time()
371
+ try:
372
+ result = await func(*args, **kwargs)
373
+ execution_time = time.time() - start_time
374
+
375
+ logger.debug(f"Async {func_name} completed", extra={
376
+ "function": func_name,
377
+ "execution_time": execution_time,
378
+ "has_result": result is not None,
379
+ "is_async": True
380
+ })
381
+
382
+ return result
383
+
384
+ except Exception as e:
385
+ execution_time = time.time() - start_time
386
+ logger.exception(f"Async {func_name} failed", extra={
387
+ "function": func_name,
388
+ "execution_time": execution_time,
389
+ "error_type": type(e).__name__,
390
+ "is_async": True
391
+ })
392
+ raise
393
+
394
+ return wrapper
395
+
396
+
397
+ # Logging standards and guidelines as constants for reference
398
+ LOGGING_STANDARDS = {
399
+ "INFO": "Normal operations, significant events (e.g., service started, request completed)",
400
+ "DEBUG": "Detailed diagnostic information (e.g., variable values, execution flow)",
401
+ "WARNING": "Potentially harmful situations (e.g., deprecated API usage, retry attempts)",
402
+ "ERROR": "Error events that allow continued operation (e.g., single request failure)",
403
+ "CRITICAL": "Events that may cause abort (e.g., database connection lost, out of memory)"
404
+ }
405
+
406
+
407
+ def log_with_level(logger: Union[ContextualLogger, logging.Logger],
408
+ level: str,
409
+ message: str,
410
+ **extra):
411
+ """
412
+ Log a message with dynamic level selection.
413
+
414
+ WHY: Allows log level to be determined at runtime, useful for
415
+ configurable logging or conditional severity.
416
+
417
+ Args:
418
+ logger: Logger instance
419
+ level: Log level as string
420
+ message: Log message
421
+ **extra: Additional fields for structured logging
422
+ """
423
+ log_level = LOG_LEVELS.get(level.upper(), logging.INFO)
424
+ logger.log(log_level, message, extra=extra)
425
+
426
+
427
+ # Export main functions and decorators
428
+ __all__ = [
429
+ 'get_logger',
430
+ 'configure_logging',
431
+ 'log_operation',
432
+ 'log_performance_context',
433
+ 'log_function_call',
434
+ 'log_async_function_call',
435
+ 'log_with_level',
436
+ 'LogContext',
437
+ 'ContextualLogger',
438
+ 'LOGGING_STANDARDS',
439
+ 'LOG_LEVELS',
440
+ # Re-export from core.logger for backwards compatibility
441
+ 'log_performance',
442
+ 'log_async_performance',
443
+ 'finalize_streaming_logs'
444
+ ]