claude-mpm 4.3.20__py3-none-any.whl → 4.3.22__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 (75) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/agent_loader.py +2 -2
  3. claude_mpm/agents/agent_loader_integration.py +2 -2
  4. claude_mpm/agents/async_agent_loader.py +2 -2
  5. claude_mpm/agents/base_agent_loader.py +2 -2
  6. claude_mpm/agents/frontmatter_validator.py +2 -2
  7. claude_mpm/agents/system_agent_config.py +2 -2
  8. claude_mpm/agents/templates/data_engineer.json +1 -2
  9. claude_mpm/cli/commands/doctor.py +2 -2
  10. claude_mpm/cli/commands/mpm_init.py +560 -47
  11. claude_mpm/cli/commands/mpm_init_handler.py +6 -0
  12. claude_mpm/cli/parsers/mpm_init_parser.py +39 -1
  13. claude_mpm/cli/startup_logging.py +11 -9
  14. claude_mpm/commands/mpm-init.md +76 -12
  15. claude_mpm/config/agent_config.py +2 -2
  16. claude_mpm/config/paths.py +2 -2
  17. claude_mpm/core/agent_name_normalizer.py +2 -2
  18. claude_mpm/core/config.py +2 -1
  19. claude_mpm/core/config_aliases.py +2 -2
  20. claude_mpm/core/file_utils.py +1 -0
  21. claude_mpm/core/log_manager.py +2 -2
  22. claude_mpm/core/tool_access_control.py +2 -2
  23. claude_mpm/core/unified_agent_registry.py +2 -2
  24. claude_mpm/core/unified_paths.py +2 -2
  25. claude_mpm/experimental/cli_enhancements.py +3 -2
  26. claude_mpm/hooks/base_hook.py +2 -2
  27. claude_mpm/hooks/instruction_reinforcement.py +2 -2
  28. claude_mpm/hooks/validation_hooks.py +2 -2
  29. claude_mpm/scripts/mpm_doctor.py +2 -2
  30. claude_mpm/services/agents/loading/agent_profile_loader.py +2 -2
  31. claude_mpm/services/agents/loading/base_agent_manager.py +2 -2
  32. claude_mpm/services/agents/loading/framework_agent_loader.py +2 -2
  33. claude_mpm/services/agents/management/agent_capabilities_generator.py +2 -2
  34. claude_mpm/services/agents/management/agent_management_service.py +2 -2
  35. claude_mpm/services/agents/memory/memory_categorization_service.py +5 -2
  36. claude_mpm/services/agents/memory/memory_file_service.py +27 -6
  37. claude_mpm/services/agents/memory/memory_format_service.py +5 -2
  38. claude_mpm/services/agents/memory/memory_limits_service.py +3 -2
  39. claude_mpm/services/agents/registry/deployed_agent_discovery.py +2 -2
  40. claude_mpm/services/agents/registry/modification_tracker.py +4 -4
  41. claude_mpm/services/async_session_logger.py +2 -1
  42. claude_mpm/services/claude_session_logger.py +2 -2
  43. claude_mpm/services/core/path_resolver.py +3 -2
  44. claude_mpm/services/diagnostics/diagnostic_runner.py +4 -3
  45. claude_mpm/services/event_bus/direct_relay.py +2 -1
  46. claude_mpm/services/event_bus/event_bus.py +2 -1
  47. claude_mpm/services/event_bus/relay.py +2 -2
  48. claude_mpm/services/framework_claude_md_generator/content_assembler.py +2 -2
  49. claude_mpm/services/infrastructure/daemon_manager.py +2 -2
  50. claude_mpm/services/memory/cache/simple_cache.py +2 -2
  51. claude_mpm/services/project/archive_manager.py +981 -0
  52. claude_mpm/services/project/documentation_manager.py +536 -0
  53. claude_mpm/services/project/enhanced_analyzer.py +491 -0
  54. claude_mpm/services/project/project_organizer.py +904 -0
  55. claude_mpm/services/response_tracker.py +2 -2
  56. claude_mpm/services/socketio/handlers/connection.py +14 -33
  57. claude_mpm/services/socketio/server/eventbus_integration.py +2 -2
  58. claude_mpm/services/version_control/version_parser.py +5 -4
  59. claude_mpm/storage/state_storage.py +2 -2
  60. claude_mpm/utils/agent_dependency_loader.py +49 -0
  61. claude_mpm/utils/common.py +542 -0
  62. claude_mpm/utils/database_connector.py +298 -0
  63. claude_mpm/utils/error_handler.py +2 -1
  64. claude_mpm/utils/log_cleanup.py +2 -2
  65. claude_mpm/utils/path_operations.py +2 -2
  66. claude_mpm/utils/robust_installer.py +56 -0
  67. claude_mpm/utils/session_logging.py +2 -2
  68. claude_mpm/utils/subprocess_utils.py +2 -2
  69. claude_mpm/validation/agent_validator.py +2 -2
  70. {claude_mpm-4.3.20.dist-info → claude_mpm-4.3.22.dist-info}/METADATA +1 -1
  71. {claude_mpm-4.3.20.dist-info → claude_mpm-4.3.22.dist-info}/RECORD +75 -69
  72. {claude_mpm-4.3.20.dist-info → claude_mpm-4.3.22.dist-info}/WHEEL +0 -0
  73. {claude_mpm-4.3.20.dist-info → claude_mpm-4.3.22.dist-info}/entry_points.txt +0 -0
  74. {claude_mpm-4.3.20.dist-info → claude_mpm-4.3.22.dist-info}/licenses/LICENSE +0 -0
  75. {claude_mpm-4.3.20.dist-info → claude_mpm-4.3.22.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,298 @@
1
+ """
2
+ Database Connector with Fallback Support
3
+ =========================================
4
+
5
+ WHY: Database connectivity packages often have compilation requirements that
6
+ can fail on certain systems. This module provides intelligent fallback to
7
+ pure Python alternatives when native packages are unavailable.
8
+
9
+ DESIGN DECISION: We prioritize pure Python implementations over native ones
10
+ for better cross-platform compatibility, even if they might be slightly slower.
11
+ """
12
+
13
+ import logging
14
+ from typing import Any, Dict, Optional, Tuple
15
+
16
+ from ..core.logger import get_logger
17
+
18
+ logger = get_logger(__name__)
19
+
20
+
21
+ class DatabaseConnector:
22
+ """
23
+ Manages database connections with automatic fallback to alternative drivers.
24
+
25
+ WHY: Provides a unified interface for database connections that automatically
26
+ handles missing or failed driver installations by falling back to alternatives.
27
+ """
28
+
29
+ # Database drivers in order of preference (first is preferred)
30
+ MYSQL_DRIVERS = [
31
+ ("pymysql", "pymysql"), # Pure Python, no compilation required
32
+ ("mysqlclient", "MySQLdb"), # Faster but requires MySQL dev headers
33
+ ("mysql-connector-python", "mysql.connector"), # Oracle's pure Python driver
34
+ ]
35
+
36
+ POSTGRESQL_DRIVERS = [
37
+ ("psycopg2-binary", "psycopg2"), # Binary wheel, no compilation
38
+ ("psycopg2", "psycopg2"), # Requires PostgreSQL dev headers
39
+ ("pg8000", "pg8000"), # Pure Python alternative
40
+ ]
41
+
42
+ ORACLE_DRIVERS = [
43
+ ("cx_Oracle", "cx_Oracle"), # Requires Oracle client libraries
44
+ ("oracledb", "oracledb"), # Pure Python Oracle driver (newer)
45
+ ]
46
+
47
+ def __init__(self):
48
+ """Initialize the database connector."""
49
+ self.available_drivers: Dict[str, Tuple[str, Any]] = {}
50
+ self._scan_available_drivers()
51
+
52
+ def _scan_available_drivers(self) -> None:
53
+ """
54
+ Scan for available database drivers and cache them.
55
+
56
+ WHY: Pre-scanning allows us to know what's available without
57
+ repeatedly trying imports, improving performance.
58
+ """
59
+ # Check MySQL drivers
60
+ for package_name, import_name in self.MYSQL_DRIVERS:
61
+ driver = self._try_import(import_name)
62
+ if driver:
63
+ if "mysql" not in self.available_drivers:
64
+ self.available_drivers["mysql"] = (package_name, driver)
65
+ logger.info(f"MySQL driver available: {package_name}")
66
+
67
+ # Check PostgreSQL drivers
68
+ for package_name, import_name in self.POSTGRESQL_DRIVERS:
69
+ driver = self._try_import(import_name)
70
+ if driver:
71
+ if "postgresql" not in self.available_drivers:
72
+ self.available_drivers["postgresql"] = (package_name, driver)
73
+ logger.info(f"PostgreSQL driver available: {package_name}")
74
+
75
+ # Check Oracle drivers
76
+ for package_name, import_name in self.ORACLE_DRIVERS:
77
+ driver = self._try_import(import_name)
78
+ if driver:
79
+ if "oracle" not in self.available_drivers:
80
+ self.available_drivers["oracle"] = (package_name, driver)
81
+ logger.info(f"Oracle driver available: {package_name}")
82
+
83
+ def _try_import(self, module_name: str) -> Optional[Any]:
84
+ """
85
+ Try to import a module and return it if successful.
86
+
87
+ Args:
88
+ module_name: Name of the module to import
89
+
90
+ Returns:
91
+ The imported module or None if import fails
92
+ """
93
+ try:
94
+ import importlib
95
+ return importlib.import_module(module_name)
96
+ except ImportError:
97
+ return None
98
+
99
+ def get_mysql_connection_string(self, host: str, database: str, user: str,
100
+ password: str, port: int = 3306) -> Optional[str]:
101
+ """
102
+ Get a SQLAlchemy connection string for MySQL with automatic driver selection.
103
+
104
+ WHY: SQLAlchemy needs different connection string formats depending on the driver.
105
+ This method automatically selects the best available driver.
106
+
107
+ Args:
108
+ host: Database host
109
+ database: Database name
110
+ user: Username
111
+ password: Password
112
+ port: Port number (default 3306)
113
+
114
+ Returns:
115
+ SQLAlchemy connection string or None if no driver available
116
+ """
117
+ if "mysql" not in self.available_drivers:
118
+ logger.error(
119
+ "No MySQL driver available. Install one of: pymysql, mysqlclient, or mysql-connector-python"
120
+ )
121
+ return None
122
+
123
+ package_name, _ = self.available_drivers["mysql"]
124
+
125
+ # Format connection string based on driver
126
+ if package_name == "pymysql":
127
+ return f"mysql+pymysql://{user}:{password}@{host}:{port}/{database}"
128
+ elif package_name == "mysqlclient":
129
+ return f"mysql+mysqldb://{user}:{password}@{host}:{port}/{database}"
130
+ elif package_name == "mysql-connector-python":
131
+ return f"mysql+mysqlconnector://{user}:{password}@{host}:{port}/{database}"
132
+
133
+ return None
134
+
135
+ def get_postgresql_connection_string(self, host: str, database: str, user: str,
136
+ password: str, port: int = 5432) -> Optional[str]:
137
+ """
138
+ Get a SQLAlchemy connection string for PostgreSQL with automatic driver selection.
139
+
140
+ Args:
141
+ host: Database host
142
+ database: Database name
143
+ user: Username
144
+ password: Password
145
+ port: Port number (default 5432)
146
+
147
+ Returns:
148
+ SQLAlchemy connection string or None if no driver available
149
+ """
150
+ if "postgresql" not in self.available_drivers:
151
+ logger.error(
152
+ "No PostgreSQL driver available. Install one of: psycopg2-binary, psycopg2, or pg8000"
153
+ )
154
+ return None
155
+
156
+ package_name, _ = self.available_drivers["postgresql"]
157
+
158
+ # Format connection string based on driver
159
+ if package_name in ["psycopg2-binary", "psycopg2"]:
160
+ return f"postgresql+psycopg2://{user}:{password}@{host}:{port}/{database}"
161
+ elif package_name == "pg8000":
162
+ return f"postgresql+pg8000://{user}:{password}@{host}:{port}/{database}"
163
+
164
+ return None
165
+
166
+ def get_oracle_connection_string(self, host: str, database: str, user: str,
167
+ password: str, port: int = 1521) -> Optional[str]:
168
+ """
169
+ Get a SQLAlchemy connection string for Oracle with automatic driver selection.
170
+
171
+ Args:
172
+ host: Database host
173
+ database: Database name/SID
174
+ user: Username
175
+ password: Password
176
+ port: Port number (default 1521)
177
+
178
+ Returns:
179
+ SQLAlchemy connection string or None if no driver available
180
+ """
181
+ if "oracle" not in self.available_drivers:
182
+ logger.error(
183
+ "No Oracle driver available. Install one of: cx_Oracle or oracledb"
184
+ )
185
+ return None
186
+
187
+ package_name, _ = self.available_drivers["oracle"]
188
+
189
+ # Format connection string based on driver
190
+ if package_name == "cx_Oracle":
191
+ return f"oracle+cx_oracle://{user}:{password}@{host}:{port}/{database}"
192
+ elif package_name == "oracledb":
193
+ return f"oracle+oracledb://{user}:{password}@{host}:{port}/{database}"
194
+
195
+ return None
196
+
197
+ def get_available_drivers(self) -> Dict[str, str]:
198
+ """
199
+ Get a summary of available database drivers.
200
+
201
+ Returns:
202
+ Dictionary mapping database type to driver package name
203
+ """
204
+ return {
205
+ db_type: driver_info[0]
206
+ for db_type, driver_info in self.available_drivers.items()
207
+ }
208
+
209
+ def suggest_missing_drivers(self) -> Dict[str, str]:
210
+ """
211
+ Suggest drivers to install for databases without drivers.
212
+
213
+ Returns:
214
+ Dictionary mapping database type to recommended package
215
+ """
216
+ suggestions = {}
217
+
218
+ if "mysql" not in self.available_drivers:
219
+ suggestions["mysql"] = "pymysql" # Pure Python, always works
220
+
221
+ if "postgresql" not in self.available_drivers:
222
+ suggestions["postgresql"] = "psycopg2-binary" # No compilation needed
223
+
224
+ if "oracle" not in self.available_drivers:
225
+ suggestions["oracle"] = "oracledb" # Pure Python, newer
226
+
227
+ return suggestions
228
+
229
+ @staticmethod
230
+ def get_installation_help() -> str:
231
+ """
232
+ Get helpful installation instructions for database drivers.
233
+
234
+ Returns:
235
+ Formatted help text
236
+ """
237
+ return """
238
+ Database Driver Installation Help
239
+ =================================
240
+
241
+ For MySQL:
242
+ Recommended: pip install pymysql (pure Python, no compilation)
243
+ Alternative: pip install mysql-connector-python (Oracle's pure Python)
244
+ Fastest (requires MySQL dev headers):
245
+ macOS: brew install mysql && pip install mysqlclient
246
+ Ubuntu: sudo apt-get install libmysqlclient-dev && pip install mysqlclient
247
+
248
+ For PostgreSQL:
249
+ Recommended: pip install psycopg2-binary (pre-compiled, no headers needed)
250
+ Alternative: pip install pg8000 (pure Python, slightly slower)
251
+ Fastest (requires PostgreSQL dev headers):
252
+ macOS: brew install postgresql && pip install psycopg2
253
+ Ubuntu: sudo apt-get install libpq-dev && pip install psycopg2
254
+
255
+ For Oracle:
256
+ Recommended: pip install oracledb (pure Python, no Oracle client needed)
257
+ Alternative (requires Oracle Instant Client):
258
+ 1. Download Oracle Instant Client from oracle.com
259
+ 2. Set environment variables (LD_LIBRARY_PATH, etc.)
260
+ 3. pip install cx_Oracle
261
+
262
+ Note: Pure Python drivers are slightly slower but much easier to install
263
+ and maintain. They're recommended unless you have specific performance needs.
264
+ """
265
+
266
+
267
+ def test_database_connectivity() -> None:
268
+ """
269
+ Test database connectivity and report available drivers.
270
+
271
+ WHY: Helps users understand what database drivers are available and
272
+ what they might need to install.
273
+ """
274
+ connector = DatabaseConnector()
275
+
276
+ print("Database Driver Status")
277
+ print("=" * 50)
278
+
279
+ available = connector.get_available_drivers()
280
+ if available:
281
+ print("\nAvailable Drivers:")
282
+ for db_type, driver in available.items():
283
+ print(f" {db_type:12} -> {driver}")
284
+ else:
285
+ print("\nNo database drivers found!")
286
+
287
+ suggestions = connector.suggest_missing_drivers()
288
+ if suggestions:
289
+ print("\nRecommended installations for missing drivers:")
290
+ for db_type, package in suggestions.items():
291
+ print(f" {db_type:12} -> pip install {package}")
292
+
293
+ print("\n" + connector.get_installation_help())
294
+
295
+
296
+ if __name__ == "__main__":
297
+ # Run connectivity test when module is executed directly
298
+ test_database_connectivity()
@@ -10,7 +10,8 @@ from datetime import datetime, timezone
10
10
  from functools import wraps
11
11
  from typing import Any, Callable, Dict, List, Optional, Type
12
12
 
13
- logger = logging.getLogger(__name__)
13
+ from claude_mpm.core.logging_utils import get_logger
14
+ logger = get_logger(__name__)
14
15
 
15
16
 
16
17
  class MPMError(Exception):
@@ -6,14 +6,14 @@ including session directory cleanup, archived log removal, and rotation manageme
6
6
  """
7
7
 
8
8
  import gzip
9
- import logging
10
9
  import os
11
10
  import shutil
12
11
  from datetime import datetime, timedelta, timezone
13
12
  from pathlib import Path
14
13
  from typing import Dict, Optional, Tuple
15
14
 
16
- logger = logging.getLogger(__name__)
15
+ from claude_mpm.core.logging_utils import get_logger
16
+ logger = get_logger(__name__)
17
17
 
18
18
 
19
19
  class LogCleanupConfig:
@@ -4,14 +4,14 @@ This module provides a centralized PathOperations class for common path validati
4
4
  and file operations, reducing code duplication across the codebase.
5
5
  """
6
6
 
7
- import logging
8
7
  import os
9
8
  import shutil
10
9
  import tempfile
11
10
  from pathlib import Path
12
11
  from typing import Callable, List, Optional, Union
13
12
 
14
- logger = logging.getLogger(__name__)
13
+ from claude_mpm.core.logging_utils import get_logger
14
+ logger = get_logger(__name__)
15
15
 
16
16
 
17
17
  class PathOperations:
@@ -340,6 +340,12 @@ class RobustPackageInstaller:
340
340
  "tree-sitter-java",
341
341
  "tree-sitter-cpp",
342
342
  "tree-sitter-c",
343
+ # Database packages that require compilation
344
+ "mysqlclient", # Requires MySQL development headers
345
+ "psycopg2", # Requires PostgreSQL development headers
346
+ "cx_oracle", # Requires Oracle client libraries
347
+ "pycairo", # Requires Cairo development headers
348
+ "lxml", # Requires libxml2 development headers
343
349
  }
344
350
 
345
351
  return package_name.lower() in special_packages
@@ -363,6 +369,35 @@ class RobustPackageInstaller:
363
369
  InstallStrategy.PIP_NO_DEPS,
364
370
  ]
365
371
 
372
+ # Database packages that require compilation
373
+ compilation_packages = {
374
+ "mysqlclient": ["pymysql"], # Pure Python alternative
375
+ "psycopg2": ["psycopg2-binary"], # Binary wheel alternative
376
+ "cx_oracle": [], # No good alternative
377
+ "pycairo": [], # No good alternative
378
+ "lxml": [], # Usually works with binary wheels
379
+ }
380
+
381
+ package_lower = package_name.lower()
382
+ if package_lower in compilation_packages:
383
+ # Try normal install first, but with limited retries
384
+ strategies = [InstallStrategy.PIP]
385
+
386
+ # If there are alternatives, log suggestion
387
+ alternatives = compilation_packages[package_lower]
388
+ if alternatives:
389
+ logger.info(
390
+ f"Package {package_name} requires compilation. "
391
+ f"Consider using alternative: {', '.join(alternatives)}"
392
+ )
393
+ else:
394
+ logger.warning(
395
+ f"Package {package_name} requires compilation and may fail on systems "
396
+ f"without development headers installed."
397
+ )
398
+
399
+ return strategies
400
+
366
401
  return [InstallStrategy.PIP, InstallStrategy.PIP_UPGRADE]
367
402
 
368
403
  def _verify_installation(self, package_spec: str) -> bool:
@@ -459,6 +494,27 @@ class RobustPackageInstaller:
459
494
  if not stderr:
460
495
  return "Unknown error"
461
496
 
497
+ # Check for specific compilation errors
498
+ stderr_lower = stderr.lower()
499
+
500
+ if "mysql_config" in stderr_lower or "mysql.h" in stderr_lower:
501
+ return (
502
+ "mysqlclient compilation failed (missing MySQL development headers). "
503
+ "Use 'pip install pymysql' for a pure Python alternative that doesn't require compilation."
504
+ )
505
+
506
+ if "pg_config" in stderr_lower or "libpq-fe.h" in stderr_lower:
507
+ return (
508
+ "psycopg2 compilation failed (missing PostgreSQL development headers). "
509
+ "Use 'pip install psycopg2-binary' for a pre-compiled version."
510
+ )
511
+
512
+ if "oracle" in stderr_lower and "client" in stderr_lower:
513
+ return (
514
+ "cx_Oracle compilation failed (missing Oracle client libraries). "
515
+ "Use 'pip install oracledb' for a pure Python alternative."
516
+ )
517
+
462
518
  # Look for ERROR: lines
463
519
  error_lines = []
464
520
  for line in stderr.splitlines():
@@ -6,13 +6,13 @@ Session Logging Utilities
6
6
  Convenience functions for session-based response logging.
7
7
  """
8
8
 
9
- import logging
10
9
  import os
11
10
  from typing import Any, Dict, Optional
12
11
 
13
12
  from claude_mpm.services.claude_session_logger import get_session_logger
14
13
 
15
- logger = logging.getLogger(__name__)
14
+ from claude_mpm.core.logging_utils import get_logger
15
+ logger = get_logger(__name__)
16
16
 
17
17
 
18
18
  def is_session_logging_enabled() -> bool:
@@ -8,7 +8,6 @@ with proper error handling, timeouts, and process cleanup.
8
8
 
9
9
  import asyncio
10
10
  import contextlib
11
- import logging
12
11
  import shlex
13
12
  import subprocess
14
13
  import time
@@ -16,7 +15,8 @@ from typing import Any, Dict, List, Optional
16
15
 
17
16
  import psutil
18
17
 
19
- logger = logging.getLogger(__name__)
18
+ from claude_mpm.core.logging_utils import get_logger
19
+ logger = get_logger(__name__)
20
20
 
21
21
 
22
22
  class SubprocessError(Exception):
@@ -20,7 +20,6 @@ Security Considerations:
20
20
  """
21
21
 
22
22
  import json
23
- import logging
24
23
  from dataclasses import dataclass, field
25
24
  from datetime import datetime, timezone
26
25
  from pathlib import Path
@@ -36,7 +35,8 @@ from claude_mpm.core.constants import (
36
35
  TimeoutConfig,
37
36
  )
38
37
 
39
- logger = logging.getLogger(__name__)
38
+ from claude_mpm.core.logging_utils import get_logger
39
+ logger = get_logger(__name__)
40
40
 
41
41
 
42
42
  @dataclass
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-mpm
3
- Version: 4.3.20
3
+ Version: 4.3.22
4
4
  Summary: Claude Multi-Agent Project Manager - Orchestrate Claude with agent delegation and ticket tracking
5
5
  Author-email: Bob Matsuoka <bob@matsuoka.com>
6
6
  Maintainer: Claude MPM Team